diff options
Diffstat (limited to 'hicn-light')
333 files changed, 22267 insertions, 34060 deletions
diff --git a/hicn-light/src/hicn/command_line/daemon/CMakeLists.txt b/hicn-light/.clang-format index 1ab8a4e6f..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,15 +11,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -list(APPEND DAEMON_SRC - hicnLightDaemon_main.c -) -if (NOT DISABLE_EXECUTABLES) - build_executable(${HICN_LIGHT_DAEMON} - SOURCES ${DAEMON_SRC} - LINK_LIBRARIES ${HICN_LIGHT_LINK_LIBRARIES} - 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 db56feff7..e82100a91 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,110 +11,104 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) - +############################################################## +# 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) +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) + + +############################################################## +# 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 () - -if(${CMAKE_SYSTEM_NAME} STREQUAL "Android") - message("############ Detected cross compile for $ENV{CMAKE_SYSTEM_NAME}") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ANDROID_C_FLAGS}") -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_wrapper(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_wrapper(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(HICN_LIGHT_LINK_LIBRARIES - ${LIBHICN_LIGHT_STATIC} - ${HICN_LIBRARIES} - ${LIBPARC_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} - ${WINDOWS_LIBRARIES} -) - - -# Include dirs -- Order does matter! -list(APPEND HICN_LIGHT_INCLUDE_DIRS - ${HICN_INCLUDE_DIRS} - ${LIBPARC_INCLUDE_DIRS} - ${WINDOWS_INCLUDE_DIRS} -) - -if (UNIX) - list(APPEND HICN_LIGHT_LINK_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..97b3e0dbf 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), libevent-2.1-7 (= 2.1.11-stable-1)" 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 dced2a093..f2f566426 100755 --- a/hicn-light/config/post +++ b/hicn-light/config/post @@ -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/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 82de74ac7..feaac5c39 100644 --- a/hicn-light/src/hicn/CMakeLists.txt +++ b/hicn-light/src/hicn/CMakeLists.txt @@ -1,62 +1,145 @@ -# 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 + PRIVATE ${DEFAULT_COMPILER_OPTIONS} + #PRIVATE "-Wno-address-of-packed-member" ) +############################################################## +# 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} DEPENDS ${DEPENDENCIES} COMPONENT ${HICN_LIGHT} INCLUDE_DIRS ${HICN_LIGHT_INCLUDE_DIRS} - INSTALL_ROOT_DIR hicn - DEFINITIONS ${COMPILER_DEFINITIONS} + HEADER_ROOT_DIR hicn + DEFINITIONS PUBLIC ${COMPILER_DEFINITIONS} + COMPILE_OPTIONS ${COMPILER_OPTIONS} ) + +############################################################## +# Build tests +############################################################## +if (BUILD_TESTS) + add_subdirectory(test) +endif() diff --git a/hicn-light/src/hicn/command_line/controller/CMakeLists.txt b/hicn-light/src/hicn/base/CMakeLists.txt index 949cace28..2541ed830 100644 --- a/hicn-light/src/hicn/command_line/controller/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: @@ -11,15 +11,19 @@ # See the License for the specific language governing permissions and # limitations under the License. -list(APPEND CONTROLLER_SRC - hicnLightControl_main.c +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/loop.h +) + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/loop.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 ) -if (NOT DISABLE_EXECUTABLES) - build_executable(${HICN_LIGHT_CONTROL} - SOURCES ${CONTROLLER_SRC} - LINK_LIBRARIES ${HICN_LIGHT_LINK_LIBRARIES} - DEPENDS ${LIBHICN_LIGHT_STATIC} - COMPONENT ${HICN_LIGHT} - DEFINITIONS ${COMPILER_DEFINITIONS} - ) -endif () diff --git a/hicn-light/src/hicn/base/loop.c b/hicn-light/src/hicn/base/loop.c new file mode 100644 index 000000000..3407bfc1c --- /dev/null +++ b/hicn-light/src/hicn/base/loop.c @@ -0,0 +1,205 @@ +/* + * 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; + unsigned id; + 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->id, + 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, unsigned id, + void *callback_data) { + *event = malloc(sizeof(event_t)); + (*event)->callback = (cb_wrapper_args_t){ + .owner = callback_owner, + .callback = callback, + .id = id, + .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, + unsigned id, void *callback_data) { + _event_create(event, loop, EVTYPE_FD, callback_owner, callback, id, + 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, 0, + 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..0eecb60fe --- /dev/null +++ b/hicn-light/src/hicn/base/loop.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 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, unsigned id, void *data); + +typedef struct { + int fd; + void *owner; + fd_callback_t callback; + unsigned id; + 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] id - User parameter to pass alongside callback invocation, + * allowing to pass an id without allocating memory. + * \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, + unsigned id, 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/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..ed8d4ed97 --- /dev/null +++ b/hicn-light/src/hicn/cli/hicnc.c @@ -0,0 +1,237 @@ +/* + * 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 <hicn/ctrl/parse.h> +#include <hicn/ctrl/hicn-light.h> +#include <hicn/util/log.h> +#include <hicn/util/sstrncpy.h> + +#define PORT 9695 + +/* + * Duplicated from hicn_light_ng_api.c while is only available as a module in + * libhicnctrl + */ +const char *command_type_str[] = { +#define _(l, u) [COMMAND_TYPE_##u] = STRINGIZE(u), + foreach_command_type +#undef _ +}; + +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, "dhS:P:", longFormOptions, &optind); + if (c == -1) break; + + switch (c) { + case 'd': + log_conf.log_level = LOG_DEBUG; + break; + 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_TYPE_HICNLIGHT, url); + } else { + s = hc_sock_create(FORWARDER_TYPE_HICNLIGHT, NULL); + } + if (!s) { + fprintf(stderr, "Could not create socket.\n"); + goto ERR_SOCKET; + } + + 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; + + rc = hc_execute(s, command.action, command.object_type, &command.object, + &data); + + if (rc < 0) { + switch (rc) { + case INPUT_ERROR: + ERROR("Wrong input parameters"); + break; + case UNSUPPORTED_CMD_ERROR: + ERROR("Unsupported command"); + break; + default: + ERROR("Error executing command"); + break; + } + goto ERR_COMMAND; + } + + if (!data) goto ERR_QUERY; + if (!hc_data_get_result(data)) goto ERR_DATA; + + if (command.action == ACTION_LIST) { + char buf[MAXSZ_HC_OBJECT]; + hc_data_foreach(data, obj, { + rc = hc_object_snprintf(buf, MAXSZ_HC_OBJECT, command.object_type, obj); + if (rc < 0) + WARN("Display error"); + else if (rc >= MAXSZ_HC_OBJECT) + WARN("Output truncated"); + else + printf("%s\n", buf); + }); + } + + hc_data_free(data); + hc_sock_free(s); + return EXIT_SUCCESS; + +ERR_DATA: + hc_data_free(data); +ERR_QUERY: +ERR_COMMAND: +ERR_CONNECT: + hc_sock_free(s); +ERR_SOCKET: +ERR_PARSE: +ERR_PARAM: + ERROR("Error"); + return 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..fa1b1c024 --- /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 <hicn/base/loop.h> + +#include "logo.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..c03fa8599 --- /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 <hicn/ctrl/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 (line != NULL && (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_TYPE_HICNLIGHT, url); + } else { + s = hc_sock_create(FORWARDER_TYPE_HICNLIGHT, NULL); + } + 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/hicnLightControl_main.c b/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c deleted file mode 100644 index 31b9674ca..000000000 --- a/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c +++ /dev/null @@ -1,381 +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 89a80d0b1..000000000 --- a/hicn-light/src/hicn/command_line/daemon/hicnLightDaemon_main.c +++ /dev/null @@ -1,413 +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?"); - 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 45f36e8ff..8e9415f7d 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-2023 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: @@ -11,98 +11,36 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) - 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}/commands.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}/../../../../ctrl/libhicnctrl/src/module_object.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/modules/hicn_light.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/modules/hicn_light/connection.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/modules/hicn_light/listener.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/modules/hicn_light/face.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/modules/hicn_light/mapme.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/modules/hicn_light/route.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/modules/hicn_light/stats.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/modules/hicn_light/strategy.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/modules/hicn_light/subscription.c + ${CMAKE_CURRENT_SOURCE_DIR}/configuration.c + ${CMAKE_CURRENT_SOURCE_DIR}/configuration_file.c + #${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/commands/command_cache.c + #${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/commands/command_connection.c + #${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/commands/command_face.c + #${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/commands/command_listener.c + #${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/commands/command_mapme.c + #${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/commands/command_policy.c + #${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/commands/command_punting.c + #${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/commands/command_route.c + #${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/commands/command_stats.c + #${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/commands/command_strategy.c + #${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/commands/command_subscription.c + ${CMAKE_CURRENT_SOURCE_DIR}/commands.c ) set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) 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/commands.c b/hicn-light/src/hicn/config/commands.c new file mode 100644 index 000000000..47ea23a8a --- /dev/null +++ b/hicn-light/src/hicn/config/commands.c @@ -0,0 +1,1737 @@ +/* + * Copyright (c) 2021-2023 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * + * 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.h> +//#include <hicn/utils/utils.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) \ + do { \ + ((msg_header_t *)msg)->header.message_type = ACK_LIGHT; \ + ((msg_header_t *)msg)->header.length = 0; \ + } while (0) + +#define make_nack(msg) \ + do { \ + ((msg_header_t *)msg)->header.message_type = NACK_LIGHT; \ + ((msg_header_t *)msg)->header.length = 0; \ + } while (0) + +#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 = (unsigned int)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; + case FACE_TYPE_UDP: + case FACE_TYPE_TCP: + case FACE_TYPE_HICN: + ERROR("Wrong listener type"); + 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; + memset(&address, 0, sizeof(address_t)); + 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 = (unsigned int)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 = + (unsigned)connection_table_get_connection_id(table, connection); + + /* Remove connection from the FIB */ + // XXX TODO get entries, raise notifications... + // XXX isn't it possible to implement this in the forwarder ????? + 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(const listener_t *listener, + cmd_listener_list_item_t *cmd) { + 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 = (uint8_t)AF_INET; + cmd->local_addr.v4.as_inaddr = sin->sin_addr; + cmd->local_port = sin->sin_port; + break; + case AF_INET6: + sin6 = (struct sockaddr_in6 *)addr; + cmd->family = (uint8_t)AF_INET6; + cmd->local_addr.v6.as_in6addr = sin6->sin6_addr; + cmd->local_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; + INFO("listener list seq num %d", msg_received->header.seq_num); + uint32_t seq_num = msg_received->header.seq_num; + + msg_listener_list_reply_t *msg = NULL; + msg_malloc_list(msg, command_id, n, seq_num); + if (!msg) goto NACK; + + cmd_listener_list_item_t *payload = &msg->payload; + listener_table_foreach(table, listener, { + fill_listener_command(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; + case FACE_TYPE_UDP_LISTENER: + case FACE_TYPE_TCP_LISTENER: + case FACE_TYPE_HICN_LISTENER: + case FACE_TYPE_UNDEFINED: + case FACE_TYPE_N: + goto NACK; + } + + if (!face_type_is_defined(control->type)) goto NACK; + + connection_table_t *table = forwarder_get_connection_table(forwarder); + char *symbolic_name = control->symbolic; + + // Generate connection name if not specified + if (symbolic_name[0] == '\0') { + int rc = connection_table_get_random_name(table, symbolic_name); + if (rc < 0) { + ERROR("Unable to generate new connection name"); + goto NACK; + } + } else { + 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; + + if (forwarder_add_connection(forwarder, symbolic_name, control->type, &pair, + control->tags, control->priority, + control->admin_state) < 0) + goto NACK; + + 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; + } + + /* + * + * Don't close the fd for SELF otherwise it won't be possible + * to send the reply back. The connection is finalized later in + * _forwarder_finalize_connection_if_self + */ + bool finalize = (strcmp(control->symbolic_or_connid, "SELF") != 0); + + if (forwarder_remove_connection(forwarder, conn_id, finalize) < 0) goto NACK; + + WITH_DEBUG({ + connection_table_t *table = forwarder_get_connection_table(forwarder); + connection_table_print_by_pair(table); + }) + + 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(const connection_t *connection, + cmd_connection_list_item_t *cmd) { + 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 = (uint8_t)connection_get_state(connection), + cmd->admin_state = (uint8_t)connection_get_admin_state(connection), + cmd->type = (uint8_t)connection_get_type(connection), +#ifdef WITH_POLICY + cmd->priority = connection_get_priority(connection), + cmd->tags = (uint8_t)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 = (uint8_t)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 = (uint8_t)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 = NULL; + msg_malloc_list(msg, command_id, n, seq_num); + if (!msg) goto NACK; + + cmd_connection_list_item_t *payload = &msg->payload; + connection_table_foreach_new(table, connection, { + if (connection->id == ingress_id) continue; + fill_connections_command(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; +} + +#if 0 +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); + + /* Hook: connection event */ + forwarder_on_connection_event(forwarder, conn, + control->admin_state == FACE_STATE_UP + ? CONNECTION_EVENT_SET_UP + : CONNECTION_EVENT_SET_DOWN); + + make_ack(msg); + return (uint8_t *)msg; + +NACK: + make_nack(msg); + return (uint8_t *)msg; +} + +#endif +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; +} + +#if 0 + +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); + + /* Hook: connection event */ + forwarder_on_connection_event(forwarder, conn, + CONNECTION_EVENT_PRIORITY_CHANGED); + + 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); + + /* Hook: connection event */ + forwarder_on_connection_event(forwarder, conn, CONNECTION_EVENT_TAGS_CHANGED); + + make_ack(msg); + return (uint8_t *)msg; + +NACK: +#endif /* WITH_POLICY */ + make_nack(msg); + return (uint8_t *)msg; +} + +#endif + +/* 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); + + /* We accept routes without conn_id */ +#if 0 + if (!connection_id_is_valid(conn_id)) goto NACK; +#endif + + hicn_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; + + hicn_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; +} + +static inline off_t fill_route_command(const fib_entry_t *entry, + cmd_route_list_item_t *cmd) { + 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); + off_t pos = 0; + + if (num_nexthops == 0) return 0; + + const hicn_prefix_t *prefix = fib_entry_get_prefix(entry); + const hicn_ip_address_t *address = hicn_prefix_get_ip_address(prefix); + int family = hicn_ip_address_get_family(address); + + nexthops_foreach(nexthops, nexthop, { + cmd->family = family; + cmd->remote_addr = *address; + cmd->face_id = nexthop; + cmd->len = hicn_prefix_get_len(prefix); + cmd->cost = DEFAULT_COST; + + pos++; + cmd++; + }); + return pos; +} + +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); + + /* + * 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 = NULL; + msg_malloc_list(msg, command_id, n, seq_num); + if (!msg) goto NACK; + + cmd_route_list_item_t *payload = &msg->payload; + off_t pos = 0; + fib_foreach_entry(fib, entry, + { pos += fill_route_command(entry, payload + pos); }); + + *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 = (unsigned int)forwarder_cs_get_size(forwarder), + .num_stale_entries = + (unsigned int)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]; + hicn_ip_prefix_t prefix = { + .family = control->family, + .address = control->address, + .len = control->len, + }; + int rc = hicn_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; + + // XXX check control->family + hicn_prefix_t name_prefix = HICN_PREFIX_EMPTY; + hicn_prefix_create_from_ip_address_len(&control->address, control->len, + &name_prefix); + + // 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 buf[MAXSZ_HICN_PREFIX]; + hicn_prefix_snprintf(buf, MAXSZ_HICN_PREFIX, &name_prefix); + WARN("Strategy for prefix %s not updated", buf); + }) + } + + 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]; + hicn_ip_prefix_t prefix = { + .family = control->family, + .address = control->address, + .len = control->len, + }; + int rc = hicn_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; + + hicn_prefix_t name_prefix = HICN_PREFIX_EMPTY; + hicn_prefix_create_from_ip_address_len(&control->address, control->len, + &name_prefix); + + strategy_options_t options; + hicn_prefix_t local_prefix = HICN_PREFIX_EMPTY; + hicn_prefix_create_from_ip_address_len(&control->address, control->len, + &local_prefix); + + // 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; +} + +/* Statistics */ + +uint8_t *configuration_on_stats_list(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size) { + assert(forwarder && packet); + INFO("CMD: stats list (ingress=%d)", ingress_id); + + size_t n = 1; + msg_stats_list_t *msg_received = (msg_stats_list_t *)packet; + uint8_t command_id = msg_received->header.command_id; + uint32_t seq_num = msg_received->header.seq_num; + + msg_stats_list_reply_t *msg = NULL; + msg_malloc_list(msg, command_id, n, seq_num); + if (!msg) goto NACK; + + cmd_stats_list_item_t *payload = &msg->payload; + payload->stats.forwarder = forwarder_get_stats(forwarder); + payload->stats.pkt_cache = + pkt_cache_get_stats(forwarder_get_pkt_cache(forwarder)); + + *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_face_stats_list(forwarder_t *forwarder, + uint8_t *packet, unsigned ingress_id, + size_t *reply_size) { + assert(forwarder && packet); + INFO("CMD: face stats list (ingress=%d)", ingress_id); + + 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_face_stats_list_t *msg_received = (msg_face_stats_list_t *)packet; + uint8_t command_id = msg_received->header.command_id; + uint32_t seq_num = msg_received->header.seq_num; + + msg_face_stats_list_reply_t *msg = NULL; + msg_malloc_list(msg, command_id, n, seq_num); + if (!msg) goto NACK; + + cmd_face_stats_list_item_t *payload = &msg->payload; + connection_t *connection; + connection_table_foreach(table, connection, { + if (connection->id == ingress_id) continue; + payload->stats = connection->stats; + 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; +} + +/* 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 (hicn_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; + } + + hicn_ip_prefix_t prefix = {.family = control->family, + .address = control->address, + .len = control->len}; + char prefix_s[MAXSZ_IP_PREFIX]; + int rc = hicn_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_add(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size) { + assert(forwarder); + assert(packet); + + /* Check ingress is local (for now this is only used locally) */ + connection_table_t *table = forwarder_get_connection_table(forwarder); + const connection_t *connection = connection_table_at(table, ingress_id); + + msg_mapme_add_t *msg = (msg_mapme_add_t *)packet; + + if (!connection_is_local(connection)) goto NACK; + + *reply_size = sizeof(msg_header_t); + + fib_t *fib = forwarder_get_fib(forwarder); + if (!fib) goto NACK; + + mapme_t *mapme = forwarder_get_mapme(forwarder); + + cmd_mapme_add_t *control = &msg->payload; + /* If the message comes from the producer, address, family, len and + * face_id will be NULL + */ + if (hicn_ip_address_empty(&control->address) && (control->len == 0) && + (control->family == 0) && (control->face_id == 0)) { + /* + * The command triggers a mapme update for all prefixes produced on this + * face + * + * XXX This should in fact be an UPDATE command + */ + + fib_foreach_entry(fib, entry, { + const nexthops_t *nexthops = fib_entry_get_nexthops(entry); + nexthops_foreach(nexthops, nexthop, { + if (nexthop != ingress_id) continue; + /* This entry points to the producer face */ + mapme_set_all_adjacencies(mapme, entry); + break; + }); + }); + + goto END; + } + + /* Control plane triggered + * + * We might not only receive MAP-Me update requests for prefixes we own, + * but also for more specific ones (for instance, we have a /64 and + * want to send an update on a /128). This requires a FIB lookup. + * + * NOTE: we need to avoid modifying the FIB because of this. + * + * TODO: + * - assert face_id is valid and exists + * - assert family is correct + */ + + hicn_prefix_t name_prefix = HICN_PREFIX_EMPTY; + hicn_prefix_create_from_ip_address_len(&control->address, control->len, + &name_prefix); + +#ifdef HICN_MAPME_ALLOW_NONEXISTING_FIB_ENTRY + fib_entry_t *entry = fib_contains(fib, &name_prefix); + if (!entry) { + entry = mapme_create_fib_entry(mapme, &name_prefix, INVALID_FACE_ID); + if (!entry) goto NACK; // we could also perform as in the other branch + } + mapme_set_adjacency(mapme, entry, control->face_id, NULL); + +#else + fib_entry_t *entry = fib_match_prefix(fib, &name_prefix); + + const hicn_prefix_t *prefix = fib_entry_get_prefix(entry); + if (hicn_prefix_get_len(prefix) == control->len) { + mapme_set_adjacency(mapme, entry, control->face_id, NULL); + } else { + mapme_set_adjacency(mapme, NULL, control->face_id, prefix); + } +#endif + +END: + 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; + + hicn_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; + + hicn_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; +} + +static inline void fill_policy_command(const fib_entry_t *entry, + cmd_policy_list_item_t *cmd) { + const hicn_prefix_t *prefix = fib_entry_get_prefix(entry); + const hicn_ip_address_t *ip_address = hicn_prefix_get_ip_address(prefix); + cmd->remote_addr = *ip_address; + cmd->family = hicn_ip_address_get_family(ip_address); + cmd->len = hicn_prefix_get_len(prefix); + + hicn_policy_t policy = fib_entry_get_policy(entry); + _hicn_policy_t _policy = { + .stats = { + .wired = {.throughput = htonf(policy.stats.wired.throughput), + .latency = htonf(policy.stats.wired.latency), + .loss_rate = htonf(policy.stats.wired.loss_rate)}, + .wifi = {.throughput = htonf(policy.stats.wifi.throughput), + .latency = htonf(policy.stats.wifi.latency), + .loss_rate = htonf(policy.stats.wifi.loss_rate)}, + .cellular = {.throughput = htonf(policy.stats.cellular.throughput), + .latency = htonf(policy.stats.cellular.latency), + .loss_rate = htonf(policy.stats.cellular.loss_rate)}, + .all = {.throughput = htonf(policy.stats.all.throughput), + .latency = htonf(policy.stats.all.latency), + .loss_rate = htonf(policy.stats.all.loss_rate)}}}; + for (unsigned i = 0; i < POLICY_TAG_N; i++) { + _policy.tags[i] = (_policy_tag_state_t){ + .state = policy.tags[i].state, + .disabled = policy.tags[i].disabled, + }; + } + memcpy(_policy.app_name, policy.app_name, APP_NAME_LEN); + memcpy(cmd->policy, &_policy, sizeof(_policy)); +} + +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 = NULL; + msg_malloc_list(msg, command_id, n, seq_num); + if (!msg) goto NACK; + + cmd_policy_list_item_t *payload = &msg->payload; + + fib_foreach_entry(fib, entry, { + fill_policy_command(entry, payload); + 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 *configuration_on_active_interface_update(forwarder_t *forwarder, + uint8_t *packet, + unsigned ingress_id, + size_t *reply_size) { + msg_active_interface_update_t *msg = (msg_active_interface_update_t *)packet; + make_nack(msg); + return (uint8_t *)msg; +} + +uint8_t *command_process(forwarder_t *forwarder, uint8_t *packet, + 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. + */ + command_type_t command_type = ((msg_header_t *)packet)->header.command_id; + 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; + + reply = command_process(forwarder, packet, 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); + } + + /* Free allocated replies */ + if (reply != packet) free(reply); + return msgbuf_get_len(msgbuf); +} + +void commands_notify(const forwarder_t *forwarder, hc_topic_t topic, + uint8_t *msg, size_t size) { + // Retrieve subscribed connections + subscription_table_t *subscriptions = forwarder_get_subscriptions(forwarder); + unsigned *subscribed_conn_ids = + subscription_table_get_connections_for_topic(subscriptions, topic); + + // Send notification to subscribed connections + const connection_table_t *table = forwarder_get_connection_table(forwarder); + for (int i = 0; i < vector_len(subscribed_conn_ids); i++) { + const connection_t *conn = + connection_table_at(table, subscribed_conn_ids[i]); + connection_send_packet(conn, msg, size); + } +} + +void commands_notify_connection(const forwarder_t *forwarder, + connection_event_t event, + const connection_t *connection) { +#if 0 + uint8_t command_id; + switch (event) { + case CONNECTION_EVENT_CREATE: + command_id = COMMAND_TYPE_CONNECTION_ADD; + break; + case CONNECTION_EVENT_DELETE: + command_id = COMMAND_TYPE_CONNECTION_REMOVE; + break; + case CONNECTION_EVENT_UPDATE: + case CONNECTION_EVENT_SET_UP: + case CONNECTION_EVENT_SET_DOWN: + case CONNECTION_EVENT_PRIORITY_CHANGED: + case CONNECTION_EVENT_TAGS_CHANGED: + command_id = COMMAND_TYPE_CONNECTION_UPDATE; + break; + case CONNECTION_EVENT_UNDEFINED: + case CONNECTION_EVENT_N: + default: + return; + } +#endif + + msg_connection_notify_t msg = {.header = { + .message_type = NOTIFICATION_LIGHT, + .command_id = OBJECT_TYPE_CONNECTION, + .length = 1, + .seq_num = 0, + }}; + fill_connections_command(connection, &msg.payload); + + commands_notify(forwarder, TOPIC_CONNECTION, (uint8_t *)&msg, sizeof(msg)); +} + +void commands_notify_route(const forwarder_t *forwarder, + const fib_entry_t *entry) { + const nexthops_t *nexthops = fib_entry_get_nexthops(entry); + size_t n = nexthops_get_len(nexthops); + msg_route_notify_t *msg = NULL; + msg_malloc_list(msg, OBJECT_TYPE_ROUTE, n, 0); + if (!msg) return; + + fill_route_command(entry, &msg->payload); + + commands_notify(forwarder, TOPIC_ROUTE, (uint8_t *)&msg, sizeof(msg)); + free(msg); +} + +void commands_notify_active_interface_update(const forwarder_t *forwarder, + hicn_ip_prefix_t *prefix, + netdevice_flags_t flags) { + struct { + cmd_header_t header; + hc_active_interface_t payload; + } msg = {.header = + { + .message_type = NOTIFICATION_LIGHT, + .command_id = OBJECT_TYPE_ACTIVE_INTERFACE, + .length = 1, + .seq_num = 0, + }, + .payload = {.prefix = *prefix, .interface_types = flags}}; + + INFO("Notify active interface"); + commands_notify(forwarder, TOPIC_ACTIVE_INTERFACE, (uint8_t *)&msg, + sizeof(msg)); +} diff --git a/hicn-light/src/hicn/config/commands.h b/hicn-light/src/hicn/config/commands.h new file mode 100644 index 000000000..f212c1b0b --- /dev/null +++ b/hicn-light/src/hicn/config/commands.h @@ -0,0 +1,165 @@ +/* + * 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.h> + +uint8_t *command_process(forwarder_t *forwarder, uint8_t *packet, + 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); + +uint8_t *configuration_on_stats_list(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size); + +void commands_notify_connection(const forwarder_t *forwarder, + connection_event_t event, + const connection_t *connection); + +void commands_notify_route(const forwarder_t *forwarder, + const fib_entry_t *entry); + +void commands_notify_active_interface_update(const forwarder_t *forwarder, + hicn_ip_prefix_t *prefix, + netdevice_flags_t flags); + +#endif // HICNLIGHT_COMMANDS_H diff --git a/hicn-light/src/hicn/config/configuration.c b/hicn-light/src/hicn/config/configuration.c index 39d327165..b7e931e53 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,1484 +26,202 @@ #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.h> +//#include <hicn/utils/utils.h> +#include <hicn/utils/punting.h> +#include <hicn/util/log.h> +#include <hicn/face.h> +#include <hicn/util/slab.h> +#include <hicn/util/sstrncpy.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); + +typedef struct { + char prefix[MAXSZ_HICN_PREFIX]; +} prefix_key_t; + +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; + slab_t *prefix_keys; + + size_t n_suffixes_per_split; + int_manifest_split_strategy_t split_strategy; }; -// ======================================================================================== - -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); +configuration_t *configuration_create() { + configuration_t *config = malloc(sizeof(configuration_t)); + if (!config) return NULL; - 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 */ - - 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)); - } + 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(); + config->prefix_keys = slab_create(prefix_key_t, SLAB_INIT_SIZE); + config->n_suffixes_per_split = DEFAULT_N_SUFFIXES_PER_SPLIT; + config->split_strategy = DEFAULT_DISAGGREGATION_STRATEGY; - return response; + return config; } -struct iovec *configuration_ProcessCacheClear(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; +void configuration_free(configuration_t *config) { + assert(config); - forwarder_ClearCache(config->forwarder); + kh_destroy_strategy_map(config->strategy_map); + slab_free(config->prefix_keys); - struct iovec *response = utils_CreateAck(header, NULL, 0); - return response; + free(config); } -size_t configuration_GetObjectStoreSize(Configuration *config) { - return config->maximumContentObjectStoreSize; +size_t configuration_get_cs_size(const configuration_t *config) { + return config->cs_capacity; } -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); +void configuration_set_cs_size(configuration_t *config, size_t size) { + config->cs_capacity = size; } -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; - - const char *symbolicOrConnid = control->symbolicOrConnid; - - 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 - } - } - - // 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; +const char *configuration_get_fn_config(const configuration_t *config) { + return config->fn_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; - } +void configuration_set_fn_config(configuration_t *config, + const char *fn_config) { + config->fn_config = fn_config; } -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_suffixes_per_split(configuration_t *config, + size_t n_suffixes_per_split) { + config->n_suffixes_per_split = n_suffixes_per_split; } -void configuration_SetObjectStoreSize(Configuration *config, - size_t maximumObjectCount) { - config->maximumContentObjectStoreSize = maximumObjectCount; - - forwarder_SetContentObjectStoreSize(config->forwarder, - config->maximumContentObjectStoreSize); +size_t configuration_get_suffixes_per_split(const configuration_t *config) { + return config->n_suffixes_per_split; } -Forwarder *configuration_GetForwarder(const Configuration *config) { - return config->forwarder; +void configuration_set_split_strategy( + configuration_t *config, int_manifest_split_strategy_t split_strategy) { + config->split_strategy = split_strategy; } -Logger *configuration_GetLogger(const Configuration *config) { - return config->logger; +int_manifest_split_strategy_t configuration_get_split_strategy( + const configuration_t *config) { + return config->split_strategy; } -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)); +void configuration_set_port(configuration_t *config, uint16_t port) { + config->port = 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)); +uint16_t configuration_get_port(const configuration_t *config) { + return config->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)); +void configuration_set_configuration_port(configuration_t *config, + uint16_t configuration_port) { + config->configuration_port = configuration_port; } -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); +void configuration_set_strategy(configuration_t *config, const char *prefix, + strategy_type_t strategy_type) { + int res; + prefix_key_t *prefix_copy = slab_get(prefix_key_t, config->prefix_keys); + strcpy_s(prefix_copy->prefix, sizeof(prefix_key_t), prefix); - return utils_CreateAck(header, control, sizeof(update_connection_command)); + khiter_t k = + kh_put_strategy_map(config->strategy_map, prefix_copy->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); - - switch (command) { - case LIST_CONNECTIONS: - case LIST_ROUTES: // case LIST_INTERFACES: case ETC...: - case LIST_LISTENERS: - parcMemory_Deallocate( - &response[1] - .iov_base); // deallocate payload only if generated at fwd side - break; - default: - break; - } - - // deallocate received request. It coincides with response[0].iov_base memory - // parcMemory_Deallocate(&request); //deallocate header and payload (if - // same sent by controller) - parcMemory_Deallocate(&response); // deallocate iovec pointer +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..0d1a2b8e7 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,19 @@ * */ -#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 <hicn/util/khash.h> +#include "../core/msgbuf.h" +#include "../core/strategy.h" +#include <hicn/ctrl/api.h> +#include <hicn/ctrl/hicn-light.h> +#include <hicn/interest_manifest.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 +51,7 @@ typedef struct forwarder Forwarder; * <#example#> * @endcode */ -Configuration *configuration_Create(Forwarder *forwarder); +configuration_t *configuration_create(); /** * <#One Line Description#> @@ -65,13 +67,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 +83,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 +97,54 @@ 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_suffixes_per_split(configuration_t *config, + size_t n_suffixes_per_split); + +size_t configuration_get_suffixes_per_split(const configuration_t *config); + +void configuration_set_split_strategy( + configuration_t *config, + int_manifest_split_strategy_t n_suffixes_per_split); + +int_manifest_split_strategy_t configuration_get_split_strategy( + const configuration_t *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 21bfe7640..000000000 --- a/hicn-light/src/hicn/config/configurationListeners.c +++ /dev/null @@ -1,627 +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)) { - logger_Log(configuration_GetLogger(config), LoggerFacility_Config, - PARCLogLevel_Info, __func__, - "Setup hicn listener on address %s", - addressToString(localAddress)); - } - } - - 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]; -#ifdef __ANDROID__ - 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..8649e0143 --- /dev/null +++ b/hicn-light/src/hicn/config/configuration_file.c @@ -0,0 +1,135 @@ +/* + * 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/ctrl/hicn-light.h> +#include <hicn/config/configuration_file.h> +#include <hicn/util/sstrncpy.h> + +#include "commands.h" +#include <hicn/ctrl/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; + +#if 0 + // TODO(eloparco): We could use a fake socket since we only need the vft + hc_sock_t *s = hc_sock_create(FORWARDER_TYPE_HICNLIGHT, NULL); + if (!s) { + ERROR("Could not create socket"); + goto ERR_SOCK; + } +#else + hc_sock_initialize_module(NULL); +#endif + + 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; + } + + /* Serialize request into message */ + // hc_msg_t msg; + uint8_t msg[1024]; + ssize_t msg_len = hc_light_command_serialize( + command.action, command.object_type, &command.object, msg); + switch (msg_len) { + case -1: + case -2: + ERROR("Command '%s' not supported", cmd); + continue; + case -3: + ERROR("Error during command serialization '%s'", cmd); + continue; + default: + break; + } + + size_t _unused; + command_process(forwarder, (uint8_t *)msg, CONNECTION_ID_UNDEFINED, + &_unused); + } + +#if 0 + hc_sock_free(s); +#endif + + 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; + +#if 0 +ERR_SOCK: + hc_sock_free(s); +#endif +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..03599d4f4 --- /dev/null +++ b/hicn-light/src/hicn/config/configuration_file.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. + */ + +/** + * @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> +#include <hicn/ctrl/hicn-light.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 8618c6246..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; - - 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/controlRemovePunting.h b/hicn-light/src/hicn/config/controlRemovePunting.h deleted file mode 100644 index 858d6f969..000000000 --- a/hicn-light/src/hicn/config/controlRemovePunting.h +++ /dev/null @@ -1,27 +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_RemovePunting.h - * - */ - -#ifndef Control_RemovePunting_h -#define Control_RemovePunting_h - -#include <hicn/config/controlState.h> -CommandOps *controlRemovePunting_Create(ControlState *state); -CommandOps *controlRemovePunting_HelpCreate(ControlState *state); -#endif // Control_RemovePunting_h 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 3229c1864..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 = 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/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 85643cf5e..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: @@ -11,23 +11,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) - 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 5e2b696d7..94295bdf1 100644 --- a/hicn-light/src/hicn/core/CMakeLists.txt +++ b/hicn-light/src/hicn/core/CMakeLists.txt @@ -1,9 +1,9 @@ -# 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: # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -11,52 +11,60 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) - 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}/name.h + ${CMAKE_CURRENT_SOURCE_DIR}/nexthops.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}/msgbuf.c + ${CMAKE_CURRENT_SOURCE_DIR}/msgbuf_pool.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 - ${CMAKE_CURRENT_SOURCE_DIR}/nameBitvector.c - ${CMAKE_CURRENT_SOURCE_DIR}/name.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..65664fa17 --- /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, + hicn_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..38cd1e87c --- /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, + hicn_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..c4f8b397b --- /dev/null +++ b/hicn-light/src/hicn/core/address_pair.c @@ -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. + */ + +/** + * \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, + hicn_ip_address_t* local_addr, + uint16_t local_port, + hicn_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..b2872ad35 --- /dev/null +++ b/hicn-light/src/hicn/core/address_pair.h @@ -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_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, + hicn_ip_address_t* local_addr, + uint16_t local_port, + hicn_ip_address_t* remote_addr, + uint16_t remote_port); + +static inline int address_pair_equals(const address_pair_t* pair1, + const address_pair_t* pair2) { + return address_equals(&pair1->local, &pair2->local) && + address_equals(&pair1->remote, &pair2->remote); +} + +#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..a9d632d52 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-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: @@ -13,347 +13,358 @@ * 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/core/forwarder.h> +#include <hicn/core/listener.h> +#include <hicn/core/wldr.h> #include <hicn/policy.h> -#endif /* WITH_POLICY */ +#include <hicn/util/log.h> + +#include "connection.h" +#include "connection_vft.h" + +// This is called by configuration +connection_t *connection_create(face_type_t type, const char *name, + const address_pair_t *pair, + const forwarder_t *forwarder) { + assert(face_type_is_valid(type)); + assert(pair); + assert(forwarder); + + /* initialized so that gcc-9 does not complain */ + face_type_t listener_type = FACE_TYPE_UNDEFINED; + switch (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: + return NULL; /* Not implemented */ + case FACE_TYPE_HICN_LISTENER: + case FACE_TYPE_UDP_LISTENER: + case FACE_TYPE_TCP_LISTENER: + case FACE_TYPE_UNDEFINED: + case FACE_TYPE_N: + return NULL; + } -struct connection { + listener_table_t *ltable = forwarder_get_listener_table(forwarder); + listener_key_t key = listener_key_factory(pair->local, listener_type); - const AddressPair *addressPair; - IoOperations *ops; + 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 refCount; + return NULL; + } - unsigned counter; + 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); +} - 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; +netdevice_type_t connection_get_netdevice_type(const char *interface_name) { + if (strncmp(interface_name, "lo", 2) == 0) { + return NETDEVICE_TYPE_LOOPBACK; + } + if ((strncmp(interface_name, "eth", 3) == 0) || + (strncmp(interface_name, "en", 2) == 0)) { + /* eth* en* enx* */ + return NETDEVICE_TYPE_WIRED; + } + if (strncmp(interface_name, "wl", 2) == 0) { + /* wlan* wlp* wlx* */ + return NETDEVICE_TYPE_WIFI; + } + if (strncmp(interface_name, "rmnet_ipa", 9) == 0) { + /* Qualcomm IPA driver */ + return NETDEVICE_TYPE_UNDEFINED; + } + if ((strncmp(interface_name, "rmnet", 5) == 0) || + (strncmp(interface_name, "rev_rmnet", 9) == 0) || + (strncmp(interface_name, "ccmni", 5) == 0)) { + /* + * rmnet* (Qualcomm) ccmni* (MediaTek) + */ + return NETDEVICE_TYPE_CELLULAR; + } + /* usb0 might be cellular (eg Zenfone2) */ + /* what about tethering */ + /* tun* dummy* ... */ + /* bnet* pan* hci* for bluetooth */ + return NETDEVICE_TYPE_UNDEFINED; +} +/** + * @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 */ -}; - -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; + .listener = listener, + .closed = false, - conn->wldrAutoStart = true; - conn->counter = 0; + /* WLDR */ + .wldr = NULL, + .wldr_autostart = true, + }; + connection->stats.conn_id = connection_id; - /* By default, a connection will aim at the UP state */ - connection_SetAdminState(conn, CONNECTION_STATE_UP); + connection->interface_type = + connection_get_netdevice_type(connection->interface_name); #ifdef WITH_POLICY - conn->tags = POLICY_TAGS_EMPTY; -#endif /* WITH_POLICY */ + connection_clear_tags(connection); + switch (connection->interface_type) { +#if 0 + case NETDEVICE_TYPE_LOOPBACK: + connection_add_tag(connection, POLICY_TAG_LOOPBACK); + break; +#endif + case NETDEVICE_TYPE_WIRED: + connection_add_tag(connection, POLICY_TAG_WIRED); + break; + case NETDEVICE_TYPE_WIFI: + connection_add_tag(connection, POLICY_TAG_WIFI); + break; + case NETDEVICE_TYPE_CELLULAR: + connection_add_tag(connection, POLICY_TAG_CELLULAR); + default: + break; + } +#endif - return conn; -} + connection->data = + malloc(connection_vft[get_protocol(connection->type)]->data_size); + if (!connection->data) goto ERR_DATA; -Connection *connection_Acquire(Connection *connection) { - parcAssertNotNull(connection, "Parameter conn must be non-null"); - connection->refCount++; - return connection; -} + assert(connection_has_valid_id(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, connection->id, + 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; -} +bool 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(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(connection_t *connection) { + return connection_vft[get_protocol(connection->type)]->flush(connection); } -bool connection_WldrAutoStartAllowed(const Connection *conn) { - return conn->wldrAutoStart; -} +bool connection_send(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 0 + if (connection->wldr) + wldr_set_label(connection->wldr, msgbuf); + else + msgbuf_reset_wldr_label(msgbuf); +#endif -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(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..e177e2039 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-2023 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -15,184 +15,230 @@ /** * @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 -#ifdef WITH_MAPME -typedef enum { - CONNECTION_EVENT_CREATE, - CONNECTION_EVENT_DELETE, - CONNECTION_EVENT_UPDATE, - CONNECTION_EVENT_SET_UP, - CONNECTION_EVENT_SET_DOWN, - CONNECTION_EVENT_PRIORITY_CHANGED, - CONNECTION_EVENT_TAGS_CHANGED, -} connection_event_t; +#include <hicn/face.h> -#endif /* WITH_MAPME */ +#include "address_pair.h" +#include "listener.h" +#include "msgbuf.h" #ifdef WITH_POLICY #include <hicn/policy.h> #endif /* WITH_POLICY */ -struct connection; -typedef struct connection Connection; +#define CONNECTION_ID_UNDEFINED INVALID_FACE_ID -/** - * Creates a connection object. - */ -Connection *connection_Create(IoOperations *ops); +#define foreach_connection_event \ + _(UNDEFINED) \ + _(CREATE) \ + _(DELETE) \ + _(UPDATE) \ + _(SET_UP) \ + _(SET_DOWN) \ + _(PRIORITY_CHANGED) \ + _(TAGS_CHANGED) \ + _(N) -/** - * @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); +typedef enum { +#define _(x) CONNECTION_EVENT_##x, + foreach_connection_event +#undef _ +} connection_event_t; -/** - * @function connection_Acquire - * @abstract A reference counted copy. - * @discussion - * A shallow copy, they share the same memory. - */ -Connection *connection_Acquire(Connection *connection); +struct wldr_s; + +typedef struct { + unsigned id; + char* name; + char* interface_name; + netdevice_type_t interface_type; + face_type_t type; + address_pair_t pair; + // bool up; + bool local; + face_state_t state; + face_state_t admin_state; +#ifdef WITH_POLICY + policy_tags_t tags; + uint32_t priority; +#endif /* WITH_POLICY */ -/** - * @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); + 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_stats_t stats; +} 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) +#define connection_get_interface_type(C) ((C)->interface_type) -/** - * @function connection_SendIOVBuffer - * @abstract Sends an IOV buffer - */ -bool connection_SendIOVBuffer(const Connection *conn, struct iovec *msg, - size_t size); +#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(C), 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_SendBuffer - * @abstract Sends a buffer - */ -bool connection_SendBuffer(const Connection *conn, u8 * buffer, size_t length); +#endif /* WITH_POLICY */ -/** - * 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); +#else -/** - * 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); +/* Accessors */ +static inline unsigned connection_get_id(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_id_is_valid(id) (id != CONNECTION_ID_UNDEFINED) +#define connection_has_valid_id(C) (connection_id_is_valid(connection_get_id(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 char* connection_get_name(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 face_type_t connection_get_type(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 address_pair_t* connection_get_pair( + const connection_t* connection); -bool connection_ReSend(const Connection *conn, Message *message, - bool notification); +#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))) -void connection_Probe(Connection *conn, uint8_t *probe); +static inline bool connection_is_up(const connection_t* connection); -void connection_HandleProbe(Connection *conn, uint8_t *message); +static inline bool connection_is_local(const connection_t* connection); -void connection_AllowWldrAutoStart(Connection *conn, bool allow); +static inline face_state_t connection_get_state(const connection_t* connection); -void connection_EnableWldr(Connection *conn); +static inline void connection_set_state(connection_t* connection, + face_state_t state); -void connection_DisableWldr(Connection *conn); +static inline face_state_t connection_get_admin_state( + const connection_t* connection); -bool connection_HasWldr(const Connection *conn); +static inline void connection_set_admin_state(connection_t* connection, + face_state_t state); -bool connection_WldrAutoStartAllowed(const Connection *conn); +static inline const char* connection_get_interface_name( + const connection_t* connection); -void connection_DetectLosses(Connection *conn, Message *message); +#ifdef WITH_POLICY -void connection_HandleWldrNotification(Connection *conn, Message *message); +static inline uint32_t connection_get_priority(const connection_t* connection); -connection_state_t connection_GetState(const Connection *conn); +static inline void connection_set_priority(connection_t* connection, + uint32_t priority); -void connection_SetState(Connection *conn, connection_state_t state); +static inline policy_tags_t connection_get_tags(const connection_t* connection); -connection_state_t connection_GetAdminState(const Connection *conn); +static inline void connection_set_tags(connection_t* connection, + policy_tags_t tags); -void connection_SetAdminState(Connection *conn, connection_state_t admin_state); +#define connection_has_tag(C, TAG) policy_tags_has(connection_get_tags(C), TAG) -#ifdef WITH_POLICY -uint32_t connection_GetPriority(const Connection *conn); +#define connection_add_tag(C, TAG) policy_tags_add(connection_get_tags(X), TAG) -void connection_SetPriority(Connection *conn, uint32_t priority); -#endif /* WITH_POLICY */ +#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) -const char * connection_GetInterfaceName(const Connection * conn); +#define connection_clear_tags(C) connection_set_tags(C, POLICY_TAGS_EMPTY) -#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 */ -#endif // connection_h +#endif + +connection_t* connection_create(face_type_t type, const char* name, + const address_pair_t* pair, + const struct forwarder_s* forwarder); + +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 connection_finalize(connection_t* connection); + +bool connection_send_packet(const connection_t* connection, + const uint8_t* packet, size_t size); + +bool connection_flush(connection_t* connection); + +bool connection_send(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 /* 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..a6b114c01 --- /dev/null +++ b/hicn-light/src/hicn/core/connection_table.c @@ -0,0 +1,240 @@ +/* + * 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. + */ + +/** + * \file connection_table.c + * \brief Implementation of hICN connection table + */ + +#include <hicn/util/log.h> +#include <hicn/util/sstrncpy.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 + +typedef struct { + char name[SYMBOLIC_NAME_LEN]; +} name_key_t; + +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->pair_keys = slab_create(address_pair_t, SLAB_INIT_SIZE); + table->id_by_name = kh_init_ct_name(); + table->name_keys = slab_create(name_key_t, SLAB_INIT_SIZE); + + /* + * 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) { + unsigned conn_id; + kh_foreach_value(table->id_by_name, conn_id, { + connection_t *connection = connection_table_get_by_id(table, conn_id); + const char *name = connection_get_name(connection); + + INFO("Removing connection %s [%d]", name, connection->fd); + connection_finalize(connection); + }); + + kh_destroy_ct_pair(table->id_by_pair); + slab_free(table->pair_keys); + kh_destroy_ct_name(table->id_by_name); + slab_free(table->name_keys); + + pool_free(table->connections); + free(table); +} + +connection_t *connection_table_allocate(const connection_table_t *table, + const address_pair_t *pair, + const char *name) { + connection_t *conn = NULL; + pool_get(table->connections, conn); + if (!conn) return NULL; + +#ifdef __APPLE__ + // set __uint8_t sin_len to 0 + uint8_t *ptr = (uint8_t *)address_pair_get_local(pair); + *ptr = 0x0; + ptr = (uint8_t *)address_pair_get_remote(pair); + *ptr = 0x0; +#endif /* __APPLE__ */ + + off_t id = conn - table->connections; + int rc; + + // Add in name hash table + name_key_t *name_copy = slab_get(name_key_t, table->name_keys); + strcpy_s(name_copy->name, sizeof(name_key_t), name); + + khiter_t k = kh_put_ct_name(table->id_by_name, name_copy->name, &rc); + assert(rc == KH_ADDED || rc == KH_RESET); + kh_value(table->id_by_name, k) = (unsigned int)id; + + // Add in pair hash table + address_pair_t *pair_copy = slab_get(address_pair_t, table->pair_keys); + memcpy(pair_copy, pair, sizeof(address_pair_t)); + + k = kh_put_ct_pair(table->id_by_pair, pair_copy, &rc); + assert(rc == KH_ADDED || rc == KH_RESET); + kh_value(table->id_by_pair, k) = (unsigned int)id; + + assert(kh_size(table->id_by_name) == kh_size(table->id_by_pair)); + return conn; +} + +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); + +#ifdef __APPLE__ + // set __uint8_t sin_len to 0 + uint8_t *ptr = (uint8_t *)address_pair_get_local(pair); + *ptr = 0x0; + ptr = (uint8_t *)address_pair_get_remote(pair); + *ptr = 0x0; +#endif /* __APPLE__ */ + + // Remove from name hash table + khiter_t k = kh_get_ct_name(table->id_by_name, name); + assert(k != kh_end(table->id_by_name)); + kh_del_ct_name(table->id_by_name, k); + slab_put(table->name_keys, kh_key(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)); + kh_del_ct_pair(table->id_by_pair, k); + slab_put(table->pair_keys, kh_key(table->id_by_pair, k)); + + assert(kh_size(table->id_by_name) == kh_size(table->id_by_pair)); + pool_put(table->connections, conn); +} + +connection_t *connection_table_get_by_pair(const connection_table_t *table, + const address_pair_t *pair) { +#ifdef __APPLE__ + // set __uint8_t sin_len to 0 + uint8_t *ptr = (uint8_t *)address_pair_get_local(pair); + *ptr = 0x0; + ptr = (uint8_t *)address_pair_get_remote(pair); + *ptr = 0x0; +#endif /* __APPLE__ */ + + 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 = (unsigned int)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); +} + +static inline u16 RAND16() { return rand() & 0xFFFF; } + +int connection_table_get_random_name(const connection_table_t *table, + char *name) { + int i, n_attempts = 2 * USHRT_MAX; + for (i = 0; i < n_attempts; i++) { + int rc = snprintf(name, SYMBOLIC_NAME_LEN, "conn%u", RAND16()); + if (rc < 0 || rc >= SYMBOLIC_NAME_LEN) continue; + + // Check if generated connection name is a duplicate + khiter_t k = kh_get_ct_name(table->id_by_name, name); + if (k == kh_end(table->id_by_name)) break; + } + + if (i == n_attempts) { + ERROR("Unable to generate new unique connection name"); + return -1; + } + + return 0; +} 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..dcfb1e1dd --- /dev/null +++ b/hicn-light/src/hicn/core/connection_table.h @@ -0,0 +1,257 @@ +/* + * 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 <hicn/util/khash.h> +#include <hicn/util/hash.h> +#include <hicn/util/slab.h> +#include "address_pair.h" +#include "connection.h" +#include <hicn/util/pool.h> + +/* Hash functions for indices. */ +#define address_pair_hash(pair) (hash_struct(pair)) + +/* Hash table types for indices. */ +KHASH_INIT(ct_pair, const address_pair_t *, unsigned, 1, address_pair_hash, + address_pair_equals); +KHASH_MAP_INIT_STR(ct_name, unsigned); + +typedef struct { + size_t max_size; + + kh_ct_pair_t *id_by_pair; + slab_t *pair_keys; + kh_ct_name_t *id_by_name; + slab_t *name_keys; + + 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. + */ +connection_t *connection_table_allocate(const connection_table_t *table, + const address_pair_t *pair, + const char *name); +/** + * @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. + */ +void connection_table_deallocate(const connection_table_t *table, + const connection_t *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) \ + (unsigned)(conn - table->connections) + +#define connection_table_foreach(table, conn, BODY) \ + pool_foreach(table->connections, (conn), BODY) + +#define connection_table_foreach_new(table, CONN, BODY) \ + pool_foreach_typed(table->connections, connection_t *, 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); + +int connection_table_get_random_name(const connection_table_t *table, + char *name); + +#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..cc736905c --- /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)(connection_t* connection); + bool (*send)(connection_t* connection, msgbuf_t* msgbuf, bool queue); + bool (*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..360e6d333 --- /dev/null +++ b/hicn-light/src/hicn/core/content_store.c @@ -0,0 +1,88 @@ +/* + * 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); +} + +cs_lru_stats_t cs_get_lru_stats(cs_t *cs) { return cs->stats.lru; } 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..ceaf05e6b --- /dev/null +++ b/hicn-light/src/hicn/core/content_store.h @@ -0,0 +1,108 @@ +#ifndef HICNLIGHT_CS_H +#define HICNLIGHT_CS_H + +#include <hicn/util/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); + +cs_lru_stats_t cs_get_lru_stats(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..c44d2daf0 --- /dev/null +++ b/hicn-light/src/hicn/core/fib.c @@ -0,0 +1,743 @@ +/* + * Copyright (c) 2021-2023 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <hicn/hicn-light/config.h> +#include <stdio.h> + +#include <hicn/core/fib.h> + +typedef struct fib_node_s { + struct fib_node_s *child[2]; /* 0: left, 1: right */ + fib_entry_t *entry; + bool is_used; +} fib_node_t; + +#define ZERO 0 +#define ONE 1 + +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){ + .child = {left, 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->child[ZERO]); + fib_node_free(node->child[ONE]); + + 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; +} + +/* + * This struct will hold various information related to the returned node such + * as its parent and grandparent if any, as well as some already computed + * information about the prefix. + */ +typedef struct { + /* Result node ancestors (NULL if not applicable) */ + fib_node_t *parent; + fib_node_t *gparent; + fib_node_t *lpm; + /* Information related to the result node */ + hicn_prefix_t *prefix; + uint32_t prefix_len; + uint32_t match_len; +} fib_search_t; +/* + * @brief Search for longest subprefix (helper function) + * @param [in] fib - Pointer to the FIB to search + * @param [in] prefix - The prefix used for search + * @param [out] search - A pointer to a structure that will hold related search + * information, that can be NULL if this is not needed. + * + * @returns The node whose entry corresponds to the longest subprefix of the + * prefix passed in parameter, or NULL if not found. The longest prefix match is + * thus the resulting node if curr_len == prefix_len, and its parent + * otherwise. + * + * Implementation details: + * + * This function performs a descent in the tree, following branches + * corresponding to the value of the next bit, until reaching past a leaf, or + * either the current node prefix: + * when one of the two following conditions is met: + * - is not a prefix of the searched one (match_len < curr_len), or + * - is longer or equal than the inserted one (curr_len >= prefix_len) + */ +fib_node_t *fib_search(const fib_t *fib, const hicn_prefix_t *prefix, + fib_search_t *search) { + uint32_t prefix_len = hicn_prefix_get_len(prefix); + uint32_t curr_len; + uint32_t match_len; + + WITH_DEBUG({ + char buf[MAXSZ_HICN_PREFIX]; + int rc = hicn_prefix_snprintf(buf, MAXSZ_HICN_PREFIX, prefix); + if (rc < 0 || rc >= MAXSZ_HICN_PREFIX) + snprintf(buf, MAXSZ_HICN_PREFIX, "%s", "(error)"); + DEBUG("[fib_search] prefix=%s prefix_len=%d\n", buf, prefix_len); + }); + + fib_node_t *parent = NULL; + fib_node_t *gparent = NULL; + fib_node_t *lpm = NULL; + fib_node_t *curr = fib->root; + while (curr) { + const hicn_prefix_t *curr_prefix = fib_entry_get_prefix(curr->entry); + + curr_len = hicn_prefix_get_len(curr_prefix); + match_len = hicn_prefix_lpm(prefix, curr_prefix); + + // store the lpm + if (match_len == curr_len && curr->is_used) lpm = curr; + + // curr_len >= prefix_len l >= L + // L is a prefix of l + // > means we did not find + // = means we could have found + if (match_len < curr_len || curr_len >= prefix_len) break; + + gparent = parent; + parent = curr; + + /* The following lookup won't fail since curr_len < prefix_len */ + uint8_t next_bit = hicn_prefix_get_bit(prefix, curr_len); + curr = curr->child[next_bit]; + } + + if (search) { + search->parent = parent; + search->gparent = gparent; + search->lpm = lpm; + if (curr) { + search->prefix_len = curr_len; + search->match_len = match_len; + } + } + return curr; +} + +/* + * Helper: insert a new node between parent and child. + * + * parent == NULL means we set the root of the FIB + * child == NULL means our node has no child + */ +fib_node_t *_fib_insert(fib_t *fib, fib_entry_t *entry, fib_node_t *parent, + fib_node_t *child, bool is_used) { + fib_node_t *new_node = fib_node_create(NULL, NULL, entry, is_used); + const hicn_prefix_t *prefix = fib_entry_get_prefix(entry); + + if (!parent) { + fib->root = new_node; + } else { + const hicn_prefix_t *parent_prefix = fib_entry_get_prefix(parent->entry); + uint32_t parent_prefix_len = hicn_prefix_get_len(parent_prefix); + uint8_t next_bit = hicn_prefix_get_bit(prefix, parent_prefix_len); + parent->child[next_bit] = new_node; + } + + if (child) { + const hicn_prefix_t *child_prefix = fib_entry_get_prefix(child->entry); + uint32_t match_len = hicn_prefix_lpm(prefix, child_prefix); + uint8_t next_bit = hicn_prefix_get_bit(child_prefix, match_len); + new_node->child[next_bit] = child; + } + + if (is_used) fib->size++; + return new_node; +} + +/* + * Helper: remove a node from parent + */ +void _fib_remove(fib_t *fib, fib_node_t *curr, fib_node_t *parent) { + /* + * If we remove the node, curr has either 0 or 1 child. In the latter case, + * we attach it to parent + */ + fib_node_t *child = curr->child[ZERO] ? curr->child[ZERO] : curr->child[ONE]; + if (!parent) { + fib->root = child; + } else { + if (parent->child[ZERO] == curr) + parent->child[ZERO] = child; + else + parent->child[ONE] = child; + } + if (curr->is_used) fib->size--; + fib_node_free(curr); +} + +/* + * - Stop condition: curr == NULL. This corresponds to: + * + * (CASE 1) Our parent is a strict prefix and we simply have to create a new + * leaf child in the correct branch based on the next bit following the parent + * prefix. + * + * Otherwise, our parent node exist. Based on the stop condition, we + * either have: + * + * - Stop condition 1 : curr_len == match_len AND curr_len >= + * prefix_len l == m && l >= L + * + * 2 sub-cases: + * - l = m > L : IMPOSSIBLE L < m since m = LPM(l, L) means L >= m + * - l = m = L : insert the current node, either it exists or not + * + * We thus have: + * + * (CASE 2) The node already exist. If is not in use we turn it on and we set + * the right fib entry. + * + * The case when it is used should never occur because of the way we add + * entries in the FIB... but let's add the nexthops we wish to insert into + * the existing FIB entry. + * + * - Stop condition 2: curr_len != match_len + * l != m => l > m + * + * We have two possibilities: + * - Only one is bigger than m (case 3) + * - They are both bigger than m (case 4) + * + * (CASE 3) Only one is bigger than m + * L == m => L < l (since l != m and l >= m) + * l > L = m + * + * This means L is a prefix of l. + * l' + * / + * L + * / + * l + * + * (CASE 4) They are both bigger than m + * - l > L > m + * - L > l > m + * - L = l > m + * + * Both share L and l share l' as a common prefix, and this is not l' since + * they share the name next bit. + * + * So this case is impossible and we would have taken the other branch during + * the descent: + * + * l' + * / \ + * l L + * + * We are in a situation where e need to insert an internal node: + * + * l' + * | + * X <------ internal node + * / \ + * l L + */ +fib_entry_t *fib_add(fib_t *fib, fib_entry_t *entry) { + assert(fib); + assert(entry); + + const hicn_prefix_t *prefix = fib_entry_get_prefix(entry); + uint32_t prefix_len = hicn_prefix_get_len(prefix); + + fib_search_t search; + fib_node_t *curr = fib_search(fib, prefix, &search); + + char buf[MAXSZ_HICN_PREFIX]; + char buf2[MAXSZ_HICN_PREFIX]; + int rc; + + rc = hicn_prefix_snprintf(buf, MAXSZ_HICN_PREFIX, prefix); + if (rc < 0 || rc >= MAXSZ_HICN_PREFIX) + snprintf(buf, MAXSZ_HICN_PREFIX, "%s", "(error)"); + if (curr) { + rc = hicn_prefix_snprintf(buf2, MAXSZ_HICN_PREFIX, + fib_entry_get_prefix(curr->entry)); + if (rc < 0 || rc >= MAXSZ_HICN_PREFIX) + snprintf(buf2, MAXSZ_HICN_PREFIX, "%s", "(error)"); + } else { + snprintf(buf2, MAXSZ_HICN_PREFIX, "%s", "(null)"); + search.prefix_len = 0; + search.match_len = 0; + } + DEBUG("fib_search(%s) result: curr=%s, prefix_len=%d; match_len=%d\n", buf, + buf2, search.prefix_len, search.match_len); + + /* Case 1 */ + if (!curr) { + _fib_insert(fib, entry, search.parent, NULL, true); + goto END; + } + + /* Case 2 */ + if (search.prefix_len == search.match_len && prefix_len == search.match_len) { + const nexthops_t *nexthops = fib_entry_get_nexthops(entry); + nexthops_foreach(nexthops, nexthop, + { fib_entry_nexthops_add(curr->entry, nexthop); }); + fib_entry_free(entry); + entry = curr->entry; + curr->is_used = true; + goto END; + } + + /* Case 3 */ + if (prefix_len == search.match_len) { + _fib_insert(fib, entry, search.parent, curr, true); + goto END; + } + + /* Case 4 */ + hicn_prefix_t inner_prefix; /* dup'ed in fib_entry_create */ + hicn_prefix_copy(&inner_prefix, prefix); + + hicn_prefix_truncate(&inner_prefix, search.match_len); + + fib_entry_t *inner_entry = fib_entry_create( + &inner_prefix, STRATEGY_TYPE_UNDEFINED, NULL, fib->forwarder); + + fib_node_t *new_node = + _fib_insert(fib, inner_entry, search.parent, curr, false); + _fib_insert(fib, entry, new_node, NULL, true); + +END: +#if 0 + fib_dump(fib); +#endif + return entry; +} + +/* + * Implementation details: + * + * To find whether the fib contains a prefix, we issue a search, and based on + * the stopping conditions, we return the fib note if and only if curr + * is not NULL, and prefix_len == curr_len (== match_len) + */ +fib_node_t *fib_contains_node(const fib_t *fib, const hicn_prefix_t *prefix) { + assert(fib); + assert(prefix); + + uint32_t prefix_len = hicn_prefix_get_len(prefix); + + fib_search_t search; + fib_node_t *curr = fib_search(fib, prefix, &search); + + if (!curr) return NULL; + if (search.match_len != prefix_len) return NULL; + if (prefix_len != search.prefix_len) return NULL; + + return curr->is_used ? curr : NULL; +} + +fib_entry_t *fib_contains(const fib_t *fib, const hicn_prefix_t *prefix) { + fib_node_t *node = fib_contains_node(fib, prefix); + if (!node) return NULL; + return node->entry; +} + +/* + * @brief Remove a prefix (and the associated node) from FIB + * + * We search for + * + * Actions depend on N, the number of children of the node to remove + * Examples are build using 'left' children only, but the cases with 'right' + * children are symmetrical. + * + * Legend: + * (empty) : no children + * * : 0 or more children + * + : at least one children + * + * N == 2 - Mark the node as unused + * + * parent parent + * / \ / \ + * curr ... ==> (curr) ... + * / \ / \ + * L R L R + * + * N == 1 - Attach the child to the parent node (whether parent is used or not) + * + * a) curr has no parent (curr is the root) + * + * curr + + * / ==> + * + + * + * b) curr has a parent + * parent parent + * / \ / \ + * curr * ==> L * + * / \ + * L + * + * (parent) (parent) + * / \ / \ + * curr + ==> L + + * / \ + * L + * + * N == 0 + * + * a) curr has no parent (curr is the root) + * + * curr + * / \ ==> + * + * b) parent is unused. + * + * Assuming curr is the left child, then parent must have a + * right child, and the grand-parent must be used. + * + * gp gp gp + * / / / + * (parent) ==> (parent) ==> + + * / \ / \ + * curr + + + * / \ + * + * c) parent is used. + * + * Assuming curr is the left child, we simply remove it from + * parent, leaving parent unchanged whether it has a right child or not. + * + * parent parent + * / \ / \ + * curr * ==> * + * / \ + * + * + */ +static void fib_node_remove(fib_t *fib, const hicn_prefix_t *prefix) { + assert(fib); + assert(prefix); + + uint32_t prefix_len = hicn_prefix_get_len(prefix); + + fib_search_t search; + fib_node_t *curr = fib_search(fib, prefix, &search); + + /* + * If we reach a NULL, unused node, or a node not matching, that means the + * node does not exist + */ + if (!curr || !curr->is_used || (search.prefix_len != prefix_len)) return; + + uint8_t N = 0; + if (curr->child[ZERO]) N++; + if (curr->child[ONE]) N++; + + switch (N) { + case 2: + curr->is_used = false; + break; + + case 1: + _fib_remove(fib, curr, search.parent); + break; + + case 0: + _fib_remove(fib, curr, search.parent); + if (search.parent && !search.parent->is_used) + _fib_remove(fib, search.parent, search.gparent); + break; + } +} + +void fib_remove(fib_t *fib, const hicn_prefix_t *prefix, unsigned conn_id) { + assert(fib); + assert(prefix); + + fib_node_t *node = fib_contains_node(fib, prefix); + if (!node) return; + + fib_entry_nexthops_remove(node->entry, conn_id); + if (fib_entry_nexthops_len(node->entry) == 0) + /* When using MAP-Me, we keep empty FIB entries but we mark them as unused*/ +#ifdef WITH_MAPME + node->is_used = false; +#else + 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); + + /* When using MAP-Me, we keep empty FIB entries but we mark them as unused*/ + if (fib_entry_nexthops_len(node->entry) == 0) +#ifdef WITH_MAPME + node->is_used = false; +#else + array[pos++] = node->entry; +#endif /* WITH_MAPME */ + } + pos = fib_node_remove_connection_id(node->child[ONE], conn_id, array, pos); + pos = fib_node_remove_connection_id(node->child[ZERO], conn_id, array, pos); + return pos; +} + +void fib_remove_entry(fib_t *fib, fib_entry_t *entry) { + fib_node_remove(fib, fib_entry_get_prefix(entry)); +} + +void fib_remove_connection(fib_t *fib, unsigned conn_id, + fib_entry_t ***removed_entries, + size_t *num_removed_entries) { + 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); + + if (removed_entries) { + /* + * The caller is taking charge of releasing entries (as well as the returned + * array + */ + assert(num_removed_entries); + + *removed_entries = array; + *num_removed_entries = pos; + + } else { + for (int i = 0; i < pos; i++) + fib_node_remove(fib, fib_entry_get_prefix(array[i])); + } + free(array); +} + +fib_entry_t *fib_match_msgbuf(const fib_t *fib, const msgbuf_t *msgbuf) { + assert(fib); + assert(msgbuf); + + return fib_match_name(fib, msgbuf_get_name(msgbuf)); +} + +/* + * fib_search returns the longest non-strict subprefix. + * the LPM is stored in search if it exists + */ +fib_entry_t *fib_match_prefix(const fib_t *fib, const hicn_prefix_t *prefix) { + assert(fib); + assert(prefix); + + fib_search_t search; + fib_search(fib, prefix, &search); + if (!search.lpm) return NULL; + return search.lpm->entry; +} + +fib_entry_t *fib_match_name(const fib_t *fib, const hicn_name_t *name) { + hicn_prefix_t prefix; + const hicn_name_prefix_t *name_prefix = hicn_name_get_prefix(name); + prefix.name = *name_prefix; + prefix.len = hicn_name_prefix_get_len_bits(name_prefix); + return fib_match_prefix(fib, &prefix); +} + +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->child[ONE], array, pos); + pos = fib_node_collect_entries(node->child[ZERO], 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; +} + +bool _fib_is_valid(const fib_node_t *node) { + if (!node) return true; + + const hicn_prefix_t *prefix = fib_entry_get_prefix(node->entry); + uint32_t prefix_len = hicn_prefix_get_len(prefix); + + for (unsigned i = 0; i < 2; i++) { + const fib_node_t *child = node->child[i]; + if (!child) continue; + const hicn_prefix_t *child_prefix = fib_entry_get_prefix(child->entry); + + uint32_t match_len = hicn_prefix_lpm(prefix, child_prefix); + if (match_len != prefix_len) return false; + if (hicn_prefix_get_bit(child_prefix, match_len) != i) return false; + if (!_fib_is_valid(child)) return false; + } + return true; +} + +/* + * @brief Check that the structure of the FIB is correct : prefixes are + * correctly nested, 0 are on the left, 1 on the right, and that we have no + * more than 1 unused prefix as parents. + */ +bool fib_is_valid(const fib_t *fib) { return _fib_is_valid(fib->root); } + +/* + * Checks whether the preorder traversal of the sub-tree corresponds to the + * prefix and used arrays, starting from pos (helper) + */ +bool __fib_check_preorder(const fib_node_t *node, + const hicn_prefix_t **prefix_array, bool *used_array, + size_t size, size_t *pos) { + /* Check left subtree... */ + fib_node_t *left = node->child[ZERO]; + if (left && !__fib_check_preorder(left, prefix_array, used_array, size, pos)) + return false; + + /* ... then current node ... */ + if (*pos > size) { + ERROR("size error"); + return false; + } + + const hicn_prefix_t *prefix = fib_entry_get_prefix(node->entry); + + if (!hicn_prefix_equals(prefix, prefix_array[*pos])) { + char buf[MAXSZ_HICN_PREFIX]; + char buf2[MAXSZ_HICN_PREFIX]; + int rc; + + rc = hicn_prefix_snprintf(buf, MAXSZ_HICN_PREFIX, prefix); + if (rc < 0 || rc >= MAXSZ_HICN_PREFIX) + snprintf(buf, MAXSZ_HICN_PREFIX, "%s", "(error)"); + rc = hicn_prefix_snprintf(buf2, MAXSZ_HICN_PREFIX, prefix_array[*pos]); + if (rc < 0 || rc >= MAXSZ_HICN_PREFIX) + snprintf(buf2, MAXSZ_HICN_PREFIX, "%s", "(error)"); + ERROR("Prefix mismatch in position %ld %s != %s", *pos, buf, buf2); + return false; + } + + (*pos)++; + + /* ... then right subtree */ + fib_node_t *right = node->child[ONE]; + if (right && + !__fib_check_preorder(right, prefix_array, used_array, size, pos)) + return false; + + return true; +} + +/* + * Checks whether the preorder traversal of the trie + * corresponds to the prefix and used arrays. + */ +bool _fib_check_preorder(const fib_t *fib, const hicn_prefix_t **prefix_array, + bool *used_array, size_t size) { + if (!fib->root) return true; + size_t pos = 0; + if (!__fib_check_preorder(fib->root, prefix_array, used_array, size, &pos)) + return false; + /* We need to check that we don't miss elements */ + return pos == size; +} + +// XXX print empty node but not recurse +void _fib_dump(const fib_node_t *node, int start, int indent, int location) { + char buf[MAXSZ_HICN_PREFIX]; + + if (node) { + const hicn_prefix_t *prefix = fib_entry_get_prefix(node->entry); + int rc = hicn_prefix_snprintf(buf, MAXSZ_HICN_PREFIX, prefix); + if (rc < 0 || rc >= MAXSZ_HICN_PREFIX) + snprintf(buf, MAXSZ_HICN_PREFIX, "%s %d", "(error)", rc); + } else { + snprintf(buf, MAXSZ_HICN_PREFIX, "%s", "(null)"); + } + + if (indent > 0) { + for (int i = 0; i < start; i++) printf(" "); + for (int i = 0; i < indent - start - 1; i++) printf("| "); + printf("|_ "); + } + printf("%s", buf); + if (node && !node->is_used) printf(" [inner]"); + printf("\n"); + + if (!node) return; + + if (location == 2) { + start++; + location = 0; + } + _fib_dump(node->child[ZERO], start, indent + 1, + (location == 0) ? 1 : location); + _fib_dump(node->child[ONE], start, indent + 1, + (location == 0) ? 2 : location); +} + +void fib_dump(const fib_t *fib) { _fib_dump(fib->root, 0, 0, 0); } diff --git a/hicn-light/src/hicn/core/fib.h b/hicn-light/src/hicn/core/fib.h new file mode 100644 index 000000000..4fb5009f5 --- /dev/null +++ b/hicn-light/src/hicn/core/fib.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021-2023 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HICNLIGHT_FIB_H +#define HICNLIGHT_FIB_H + +#include "fib_entry.h" +#include "msgbuf.h" +#include <hicn/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); + +fib_entry_t *fib_add(fib_t *fib, fib_entry_t *node); + +fib_entry_t *fib_contains(const fib_t *fib, const hicn_prefix_t *prefix); + +void fib_remove(fib_t *fib, const hicn_prefix_t *prefix, unsigned conn_id); + +void fib_remove_entry_connection(fib_t *fib, fib_entry_t *entry, + unsigned conn_id, fib_entry_t **removed_entry); + +void fib_remove_name_connection(fib_t *fib, const hicn_prefix_t *prefix, + unsigned conn_id); + +void fib_remove_entry(fib_t *fib, fib_entry_t *entry); + +void fib_remove_connection(fib_t *fib, unsigned conn_id, + fib_entry_t ***removed_entries, + size_t *num_removed_entries); + +fib_entry_t *fib_match_msgbuf(const fib_t *fib, const msgbuf_t *msgbuf); + +fib_entry_t *fib_match_prefix(const fib_t *fib, const hicn_prefix_t *prefix); + +fib_entry_t *fib_match_name(const fib_t *fib, const hicn_name_t *name); + +size_t fib_get_entry_array(const fib_t *fib, fib_entry_t ***array_p); + +/* + * NOTE : do not use return on the loop body to avoid leaking memory + */ +#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); \ + fib_entry_t *ENTRY; \ + 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) + +bool fib_is_valid(const fib_t *fib); +bool _fib_check_preorder(const fib_t *fib, const hicn_prefix_t **prefix_array, + bool *used_array, size_t size); + +#define fib_check_preorder(F, PA, UA) \ + _fib_check_preorder(F, PA, UA, sizeof(PA) / sizeof(hicn_prefix_t *)) + +void fib_dump(const fib_t *fib); + +#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..b510b68b4 --- /dev/null +++ b/hicn-light/src/hicn/core/fib_entry.c @@ -0,0 +1,667 @@ +/* + * Copyright (c) 2021-2023 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> + +#include <hicn/hicn-light/config.h> +#include <hicn/core/fib_entry.h> +#include <hicn/core/strategy.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(const hicn_prefix_t *prefix, + strategy_type_t strategy_type, + strategy_options_t *strategy_options, + const forwarder_t *forwarder) { + assert(prefix); + /* + * For tests, we allow forwarder to be NULL, some + * functions cannot be called but otherwise we need a main loop, etc. + */ + // assert(forwarder); + + fib_entry_t *entry = malloc(sizeof(fib_entry_t)); + if (!entry) goto ERR_MALLOC; + + memset(entry, 0, sizeof(*entry)); + hicn_prefix_copy(&entry->prefix, prefix); + 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); +} + +/* + * Filters the set of nexthops passed as parameters (and not the one stored in + * the FIB entry + */ +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; + 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))); + +#ifdef WITH_POLICY + /* 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))); +#endif /* WITH_POLICY */ + }); + + 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 */ + +#ifdef WITH_POLICY + /* + * 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; + } +// XXX backup curlen ??? +#endif /* WITH_POLICY */ + + 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)); + + /* Nexthop priority */ + + /* + * Filter out nexthops with lowest strategy priority. + * Initializing at 0 allows to disable nexthops with a negative priority + */ + max_priority = 0; + 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. + */ + 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); + } + + return nexthops; +} + +/* + * Retrieve all candidate nexthops for sending mapme updates == all non local + * connections. We don't apply the policy at this stage. + */ +nexthops_t *fib_entry_get_mapme_nexthops(fib_entry_t *entry, + nexthops_t *new_nexthops) { + assert(new_nexthops); + + const connection_table_t *table = + forwarder_get_connection_table(entry->forwarder); + + /* 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); + }); + + return new_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)] = + (unsigned int)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 +} + +#ifdef WITH_POLICY + +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) { + INFO("fib_entry_set_policy"); + entry->policy = policy; + + forwarder_on_route_event(entry->forwarder, entry); + + // XXX generic mechanism to perform a mapme update +#if 0 +#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); +#endif /* WITH_MAPME */ +#endif +} + +#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; + nexthops_enumerate(nexthops, i, 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 hicn_prefix_t *fib_entry_get_prefix(const fib_entry_t *entry) { + assert(entry); + return &(entry->prefix); +} + +/* + * 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); + + 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; +} + +bool fib_entry_has_all_local_nexthops(const fib_entry_t *entry) { + connection_table_t *table = forwarder_get_connection_table(entry->forwarder); + + int count = 0; + 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)) return false; + count++; + }); + return (count > 0); +} + +#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..e1e48c871 --- /dev/null +++ b/hicn-light/src/hicn/core/fib_entry.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2021-2023 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @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 <hicn/name.h> +#include "strategy.h" +#include "msgbuf.h" +#include "nexthops.h" +#include "policy_stats.h" + +typedef struct { + hicn_prefix_t prefix; + unsigned refcount; + nexthops_t nexthops; + + /* This is used for producer prefixes only */ + uint32_t nexthops_hash; + + 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 +#if 0 + /* 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; +#endif + 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_get_nexthops_hash(E) ((E)->nexthops_hash) +#define fib_entry_set_nexthops_hash(E, H) (E)->nexthops_hash = (H) + +static inline void fib_entry_set_nexthops(fib_entry_t *entry, + nexthops_t *nexthops) { + entry->nexthops = *nexthops; +} + +static inline void fib_entry_initialize_nexthops(fib_entry_t *entry) { + entry->nexthops = NEXTHOPS_EMPTY; +} + +static inline bool fib_entry_nexthops_changed(fib_entry_t *entry, + nexthops_t *nexthops) { + uint32_t old_hash = fib_entry_get_nexthops_hash(entry); + uint32_t hash = nexthops_get_hash(nexthops); + if (hash != old_hash) { + fib_entry_set_nexthops_hash(entry, hash); + return true; + } + return false; +}; + +struct forwarder_s; + +/* + * This does a copy of the name passed as parameter + */ +fib_entry_t *fib_entry_create(const hicn_prefix_t *prefix, + 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); + +/** + * @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_filter_nexthops(fib_entry_t *entry, nexthops_t *nexthops, + unsigned ingress_id, bool prefer_local); + +nexthops_t *fib_entry_get_mapme_nexthops(fib_entry_t *entry, + nexthops_t *new_nexthops); + +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 + * @return The FIB entry prefix + */ +const hicn_prefix_t *fib_entry_get_prefix(const fib_entry_t *fib_entry); + +bool fib_entry_has_local_nexthop(const fib_entry_t *entry); +bool fib_entry_has_all_local_nexthops(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 f7b0af2c2..8c276bfef 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-2023 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -23,6 +23,20 @@ * 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 + +/* Shall we send mapme updates to advertise all local prefixes on newly created + * faces + */ +//#define ADVERTISE_PREFIXES_ON_NEW_FACES + #ifndef _WIN32 #include <arpa/inet.h> #include <sys/socket.h> @@ -30,8 +44,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 +54,71 @@ #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/interest_manifest.h> +#include <hicn/util/log.h> -#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_s { + // uint16_t server_port; -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; -#if !defined(__APPLE__) - hicn_socket_helper_t - *hicnSocketHelper; // state required to manage hicn connections -#endif - // used by seed48 and nrand48 - unsigned short seed[3]; + subscription_table_t *subscriptions; -#ifdef WITH_MAPME - MapMe *mapme; -#endif /* WITH_MAPME */ + // Used to store the msgbufs that need to be released + off_t *acquired_msgbuf_ids; }; -// 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,444 +144,1533 @@ 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__ */ - -#ifdef WITH_MAPME - if (!(mapme_create(&forwarder->mapme, forwarder))) - goto ERR_MAPME; -#endif /* WITH_MAPME */ + forwarder->msgbuf_pool = msgbuf_pool_create(); + if (!forwarder->msgbuf_pool) goto ERR_PACKET_POOL; + size_t objectStoreSize = configuration_get_cs_size(configuration); + forwarder->pkt_cache = pkt_cache_create(objectStoreSize); + if (!forwarder->pkt_cache) goto ERR_PKT_CACHE; - /* ignore child */ -#ifndef _WIN32 - signal(SIGCHLD, SIG_IGN); + forwarder->subscriptions = subscription_table_create(); + if (!forwarder->subscriptions) goto ERR_SUBSCRIPTION; - /* 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)); + vector_init(forwarder->pending_conn, MAX_MSG, 0); + vector_init(forwarder->acquired_msgbuf_ids, MAX_MSG, 0); - 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); + char *n_suffixes_per_split_str = getenv("N_SUFFIXES_PER_SPLIT"); + if (n_suffixes_per_split_str) + configuration_set_suffixes_per_split(forwarder_get_configuration(forwarder), + atoi(n_suffixes_per_split_str)); 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)); - - listenerSet_Destroy(&(forwarder->listenerSet)); - connectionManager_Destroy(&(forwarder->connectionManager)); - connectionTable_Destroy(&(forwarder->connectionTable)); - messageProcessor_Destroy(&(forwarder->processor)); - configuration_Destroy(&(forwarder->config)); +void forwarder_free(forwarder_t *forwarder) { + assert(forwarder); - // 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); + vector_free(forwarder->pending_conn); + vector_free(forwarder->acquired_msgbuf_ids); + free(forwarder); +} + +/* + * An event occurred that might trigger an update of the FIB cache. It is + * possible that the flags have been reset following a connection add or remote. + * The objective of this function is to prepare the cache entry, and to alert of + * any change for both consumer and producer prefixes. + */ +void forwarder_on_route_event(const forwarder_t *forwarder, + fib_entry_t *entry) { + commands_notify_route(forwarder, entry); + +#ifdef ADVERTISE_PREFIXES_ON_NEW_FACES + nexthops_t new_nexthops = NEXTHOPS_EMPTY; +#endif /* ADVERTISE_PREFIXES_ON_NEW_FACES */ + + nexthops_t *nexthops = NULL; + char *prefix_type_s; + + const connection_table_t *table = + forwarder_get_connection_table(entry->forwarder); + + const hicn_prefix_t *prefix = fib_entry_get_prefix(entry); + + WITH_INFO({ + char buf[MAXSZ_HICN_PREFIX]; + hicn_prefix_snprintf(buf, MAXSZ_HICN_NAME, prefix); + INFO("fib_entry_on_event: %s", buf); + )}; + + if (!fib_entry_has_local_nexthop(entry)) { + /* Recompute FIB cache, then check whether it has changed based on hash */ + prefix_type_s = "consumer"; + nexthops = fib_entry_get_nexthops(entry); + nexthops_reset(nexthops); + fib_entry_filter_nexthops(entry, nexthops, ~0, false); +#ifdef ADVERTISE_PREFIXES_ON_NEW_FACES + } else { + /* Check available non-local connections (on which we would send MAP-Me + * updates */ + prefix_type_s = "producer"; + + nexthops = fib_entry_get_mapme_nexthops(entry, &new_nexthops); + fib_entry_filter_nexthops(entry, nexthops, ~0, true); + +#ifdef WITH_MAPME + mapme_set_adjacencies(forwarder->mapme, entry, nexthops, NULL); +#endif /* WITH_MAPME */ +#endif /* ADVERTISE_PREFIXES_ON_NEW_FACES */ + } + + if (!nexthops) + return; - parcClock_Release(&forwarder->clock); - logger_Release(&forwarder->logger); + if (!fib_entry_nexthops_changed(entry, nexthops)) return; - // do the dispatcher last - dispatcher_Destroy(&(forwarder->dispatcher)); + /* Send notification */ + WITH_INFO({ + char buf[MAXSZ_HICN_PREFIX]; + hicn_prefix_snprintf(buf, MAXSZ_HICN_NAME, prefix); + INFO("Active interfaces changed for %s prefix %s", prefix_type_s, buf); + }); - parcMemory_Deallocate((void **)&forwarder); - *ptr = NULL; + netdevice_flags_t flags = NETDEVICE_FLAGS_EMPTY; + nexthops_foreach(nexthops, nh, { + connection_t *connection = connection_table_get_by_id(table, nh); + netdevice_flags_add(flags, connection_get_interface_type(connection)); + }); + + hicn_ip_prefix_t ip_prefix; + hicn_prefix_get_ip_prefix(prefix, &ip_prefix); + commands_notify_active_interface_update(forwarder, &ip_prefix, flags); } -void forwarder_SetupAllListeners(Forwarder *forwarder, uint16_t port, - const char *localPath) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); +int forwarder_add_connection(const forwarder_t *forwarder, + const char *symbolic_name, face_type_t type, + address_pair_t *pair, policy_tags_t tags, + int priority, face_state_t admin_state) { + connection_table_t *table = forwarder_get_connection_table(forwarder); + connection_t *connection = connection_table_get_by_pair(table, pair); + + if (!connection) { + connection = connection_create(type, symbolic_name, pair, forwarder); + if (!connection) { + ERROR("Failed to create %s connection", face_type_str(type)); + return -1; + } + + } else { + WARN("Connection already exists"); + } + +#ifdef WITH_POLICY + connection_set_tags(connection, tags); + connection_set_priority(connection, priority); +#endif /* WITH_POLICY */ - configurationListeners_SetupAll(forwarder->config, port, localPath); + connection_set_admin_state(connection, admin_state); + return 0; } -void forwarder_SetupLocalListeners(Forwarder *forwarder, uint16_t port) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - configurationListeners_SetutpLocalIPv4(forwarder->config, port); +int forwarder_remove_connection(const forwarder_t *forwarder, + unsigned connection_id, bool finalize) { + /* Remove connection from the FIB */ + forwarder_remove_connection_id_from_routes(forwarder, connection_id); + + /* Remove connection */ + connection_table_t *table = forwarder_get_connection_table(forwarder); + + /* Hook: connection deleted through the control protocol */ + connection_t *connection = connection_table_at(table, connection_id); + forwarder_on_connection_event(forwarder, connection, CONNECTION_EVENT_DELETE); + + connection_table_remove_by_id(table, connection_id); + if (finalize) connection_finalize(connection); + + return 0; } -void forwarder_SetupFromConfigFile(Forwarder *forwarder, const char *filename) { - ConfigurationFile *configFile = configurationFile_Create(forwarder, filename); - if (configFile) { - configurationFile_Process(configFile); - configurationFile_Release(&configFile); - } +/* + * This is currently called from commands.c for every command sent to update + * a connection. + */ +void forwarder_on_connection_event(const forwarder_t *forwarder, + const connection_t *connection, + connection_event_t event) { + assert(connection); + + commands_notify_connection(forwarder, event, connection); + + unsigned conn_id = connection_get_id(connection); + + /* We need to send a MapMe update on the newly selected connections for + * each concerned fib_entry : connection is involved, or no more involved */ + fib_t *fib = forwarder_get_fib(forwarder); + fib_foreach_entry(fib, entry, { + const nexthops_t *nexthops = fib_entry_get_nexthops(entry); + + if (!fib_entry_has_local_nexthop(entry)) { + /* Consumer prefix */ + /* + * A new connection has no impact until it is added to FIB, which will + * be handled in a route event + */ + if (event == CONNECTION_EVENT_CREATE) break; + + /* + * For each FIB entry, trigger an event only if the connection is part + * of nexthops */ + // XXX Replace this by a function + nexthops_foreach(nexthops, nexthop, { + if (nexthop != conn_id) continue; + forwarder_on_route_event(forwarder, entry); + break; + }); + } else { + /* Producer prefix */ + if (connection_is_local(connection)) break; + + // XXX we could optimize event more + forwarder_on_route_event(forwarder, entry); + } + }); +} + +void forwarder_setup_local_listeners(forwarder_t *forwarder, uint16_t port) { + assert(forwarder); + listener_setup_local(forwarder, port); } -Configuration *forwarder_GetConfiguration(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); +configuration_t *forwarder_get_configuration(forwarder_t *forwarder) { + assert(forwarder); return forwarder->config; } -// ============================================================================ +subscription_table_t *forwarder_get_subscriptions( + const forwarder_t *forwarder) { + return forwarder->subscriptions; +} + +connection_table_t *forwarder_get_connection_table( + const forwarder_t *forwarder) { + assert(forwarder); + return forwarder->connection_table; +} -unsigned forwarder_GetNextConnectionId(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->nextConnectionid++; +listener_table_t *forwarder_get_listener_table(const forwarder_t *forwarder) { + assert(forwarder); + return forwarder->listener_table; } -Messenger *forwarder_GetMessenger(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->messenger; +pkt_cache_t *forwarder_get_pkt_cache(const forwarder_t *forwarder) { + assert(forwarder); + return forwarder->pkt_cache; } -Dispatcher *forwarder_GetDispatcher(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->dispatcher; +void forwarder_cs_set_store(forwarder_t *forwarder, bool val) { + assert(forwarder); + forwarder->store_in_cs = val; } -#ifdef WITH_POLICY -ConnectionTable *forwarder_GetConnectionTable(const Forwarder *forwarder) { -#else -ConnectionTable *forwarder_GetConnectionTable(Forwarder *forwarder) { -#endif /* WITH_POLICY */ - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->connectionTable; +bool forwarder_cs_get_store(forwarder_t *forwarder) { + assert(forwarder); + return forwarder->store_in_cs; } -ListenerSet *forwarder_GetListenerSet(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->listenerSet; +void forwarder_cs_set_serve(forwarder_t *forwarder, bool val) { + assert(forwarder); + forwarder->serve_from_cs = val; } -void forwarder_SetChacheStoreFlag(Forwarder *forwarder, bool val) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - messageProcessor_SetCacheStoreFlag(forwarder->processor, val); +bool forwarder_cs_get_serve(forwarder_t *forwarder) { + assert(forwarder); + return forwarder->serve_from_cs; } -bool forwarder_GetChacheStoreFlag(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return messageProcessor_GetCacheStoreFlag(forwarder->processor); +void forwarder_cs_set_size(forwarder_t *forwarder, size_t size) { + assert(forwarder); + + 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)); + } } -void forwarder_SetChacheServeFlag(Forwarder *forwarder, bool val) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - messageProcessor_SetCacheServeFlag(forwarder->processor, val); +size_t forwarder_cs_get_size(forwarder_t *forwarder) { + assert(forwarder); + return pkt_cache_get_cs_size(forwarder->pkt_cache); } -bool forwarder_GetChacheServeFlag(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return messageProcessor_GetCacheServeFlag(forwarder->processor); +size_t forwarder_cs_get_num_stale_entries(forwarder_t *forwarder) { + assert(forwarder); + return pkt_cache_get_num_cs_stale_entries(forwarder->pkt_cache); } -void forwarder_ReceiveCommand(Forwarder *forwarder, command_id command, - struct iovec *message, unsigned ingressId) { - configuration_ReceiveCommand(forwarder->config, command, message, ingressId); +void forwarder_cs_clear(forwarder_t *forwarder) { + assert(forwarder); + + pkt_cache_cs_clear(forwarder->pkt_cache); } -void forwarder_Receive(Forwarder *forwarder, Message *message) { - parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); +/** + * @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); - // this takes ownership of the message, so we're done here + switch (msgbuf_get_type(msgbuf)) { + case HICN_PACKET_TYPE_INTEREST: + forwarder->stats.countInterestsDropped++; + break; - // 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. - // 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)); + case HICN_PACKET_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); + + connection_t *conn = connection_table_get_by_id(table, conn_id); if (!conn) { - return; + 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); } - if (message_HasWldr(message)) { - if (connection_HasWldr(conn)) { + /* 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) == HICN_PACKET_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 + + // 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 */ + if (!vector_contains(forwarder->pending_conn, conn_id)) + vector_push(forwarder->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 HICN_PACKET_TYPE_INTEREST: + forwarder->stats.countInterestForwarded++; + break; + + case HICN_PACKET_TYPE_DATA: + forwarder->stats.countObjectsForwarded++; + break; + + default: + break; + } + + TRACE("forward msgbuf %p (size=%u) to interface %u", msgbuf, + msgbuf_get_len(msgbuf), conn_id); + return msgbuf_get_len(msgbuf); +} + +/** + * @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); + + 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; +} + +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 && entry && msgbuf_id_is_valid(msgbuf_id)); + + bool ret = true; + + 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) == HICN_PACKET_TYPE_INTEREST); + + fib_entry_t *fib_entry = fib_match_msgbuf(forwarder->fib, msgbuf); + if (!fib_entry) return false; + + nexthops_t *nexthops = fib_entry_get_nexthops(fib_entry); + + /* Backup flags and cur_len*/ + uint_fast32_t flags = nexthops->flags; + size_t cur_len = nexthops_get_curlen(nexthops); + + /* This affects the nexthops */ + nexthops = strategy_lookup_nexthops(&fib_entry->strategy, nexthops, msgbuf); + + if (nexthops_get_curlen(nexthops) == 0) { + ERROR("Message %p returned an empty next hop set", msgbuf); + ret = false; + goto END; + } + + pit_entry_t *pit_entry = &entry->u.pit_entry; + if (!pit_entry) { + ret = false; + goto END; + } + + 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) + 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) { + ERROR("Error forwarding mMessage %p to next hops", msgbuf); + ret = false; + } + +END: + /* Restore flags & curlen */ + nexthops->flags = flags; + nexthops->cur_elts = cur_len; + + return ret; +} + +#endif /* ! BYPASS_FIB */ + +int _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, bool is_aggregated) { + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, interest_msgbuf_id); + + // - Aggregation can be perfomed, do not forward + if (verdict == PKT_CACHE_VERDICT_AGGREGATE_INTEREST) { + forwarder_drop(forwarder, interest_msgbuf_id); + return (int)msgbuf_get_len(msgbuf); + } + + // - Data packet matching the interest was found, forward reply + 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)); + return (int)msgbuf_get_len(msgbuf); + } + + // - For aggregated interest, the interest forwarding is done in + // `_forwarder_forward_aggregated_interest()` + if (is_aggregated) return (int)msgbuf_get_len(msgbuf); + + // - Try to forward the interest + int rc = + forwarder_forward_via_fib(forwarder, interest_msgbuf_id, verdict, entry); + if (!rc) { + // - Not able to forward, drop the packet + forwarder->stats.countDroppedNoRoute++; + INFO("Message %lu did not match FIB, no route (count %u)", + interest_msgbuf_id, forwarder->stats.countDroppedNoRoute); + + forwarder_drop(forwarder, interest_msgbuf_id); + return -1; + } + + return (int)msgbuf_get_len(msgbuf); +} + +static void _forwarder_update_interest_stats(forwarder_t *forwarder, + pkt_cache_verdict_t verdict, + msgbuf_t *msgbuf, + bool has_expire_ts, + uint64_t expire_ts) { + long expiration = has_expire_ts ? expire_ts : -1; + switch (verdict) { + case PKT_CACHE_VERDICT_FORWARD_INTEREST: + DEBUG("Message added to PIT (expiration=%ld)", 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("Invalid packet cache content"); + break; + + default: + break; + } +} + +/** + * Return the interest manifest from the interest payload + */ +static int _forwarder_get_interest_manifest( + msgbuf_t *msgbuf, interest_manifest_header_t **int_manifest_header, + size_t *payload_size) { + uint8_t *payload; + + hicn_packet_buffer_t *pkbuf = msgbuf_get_pkbuf(msgbuf); + + hicn_payload_type_t payload_type; + HICN_UNUSED(int rc) = hicn_packet_get_payload_type(pkbuf, &payload_type); + // XXX ASSERT HERE !!! + if (rc != HICN_LIB_ERROR_NONE) return -1; + // assert(rc == HICN_LIB_ERROR_NONE); + + if (payload_type != HPT_MANIFEST) return -1; + + rc = hicn_packet_get_payload(pkbuf, &payload, payload_size, false); + // assert(rc == HICN_LIB_ERROR_NONE); + if (rc != HICN_LIB_ERROR_NONE) return -1; + + *int_manifest_header = (interest_manifest_header_t *)payload; + + return 0; +} + +// Manifest is split using splitting strategy, then every +// sub-manifest is sent using the forwarding strategy defined for the prefix +int _forwarder_forward_aggregated_interest( + forwarder_t *forwarder, interest_manifest_header_t *int_manifest_header, + msgbuf_t *msgbuf, off_t msgbuf_id, pkt_cache_entry_t **entries) { + assert(msgbuf_id_is_valid(msgbuf_id) && + msgbuf_get_type(msgbuf) == HICN_PACKET_TYPE_INTEREST); + + int ret = -1; + + fib_entry_t *fib_entry = fib_match_msgbuf(forwarder->fib, msgbuf); + if (!fib_entry) goto END; + + nexthops_t *nexthops = fib_entry_get_nexthops(fib_entry); + if (nexthops_get_curlen(nexthops) == 0) { + ret = 0; + goto END; + } + + /* Backup flags and cur_len*/ + uint_fast32_t flags = nexthops->flags; + size_t cur_len = nexthops_get_curlen(nexthops); + + size_t n_suffixes_per_split = configuration_get_suffixes_per_split( + forwarder_get_configuration(forwarder)); + int_manifest_split_strategy_t disaggregation_strategy = + configuration_get_split_strategy(forwarder_get_configuration(forwarder)); + switch (disaggregation_strategy) { + case INT_MANIFEST_SPLIT_STRATEGY_NONE: + n_suffixes_per_split = int_manifest_header->n_suffixes + 1; + + case INT_MANIFEST_SPLIT_STRATEGY_MAX_N_SUFFIXES: { + // Generate sub-manifests: same as original manifest, + // but different suffix in the header and different bitmap + + int total_len = 0; + // Suffixes in manifest plus the one in the header + int total_suffixes = int_manifest_header->n_suffixes + 1; + + // Save copy of original bitmap to use as a reference + // to generate bitmaps for sub-manifests + hicn_uword original_bitmap[BITMAP_SIZE] = {0}; + memcpy(&original_bitmap, int_manifest_header->request_bitmap, + BITMAP_SIZE * sizeof(hicn_uword)); + + size_t suffix_index = 0; // Position of suffix in initial manifest + interest_manifest_header_t *manifest = NULL; + size_t payload_size; + while (suffix_index < total_suffixes) { + // If more than one sub-manifest, + // clone original interest manifest and update suffix + if (suffix_index > 0) { + msgbuf_t *clone; + off_t clone_id = + msgbuf_pool_clone(forwarder->msgbuf_pool, &clone, msgbuf_id); + msgbuf_pool_acquire(clone); + forwarder_acquired_msgbuf_ids_push(forwarder, clone_id); + + msgbuf_id = clone_id; + msgbuf = clone; + } + + hicn_uword curr_bitmap[BITMAP_SIZE] = {0}; + size_t first_suffix_index_in_submanifest = suffix_index; + suffix_index = interest_manifest_update_bitmap( + original_bitmap, curr_bitmap, suffix_index, total_suffixes, + n_suffixes_per_split); + size_t first_suffix_index_in_next_submanifest = suffix_index; + + // Update manifest bitmap in current msgbuf + + int ret = + _forwarder_get_interest_manifest(msgbuf, &manifest, &payload_size); + _ASSERT(ret == 0); + memcpy(manifest->request_bitmap, curr_bitmap, + BITMAP_SIZE * sizeof(hicn_uword)); + WITH_TRACE({ + bitmap_print(manifest->request_bitmap, BITMAP_SIZE); + printf("\n"); + }); + + /* + * Update PIT entries for suffixes in current sub-manifest. + * + * Note that strategy lookup affects the nexthops, and we need to + *restore the initial state before every lookup + */ + nexthops->flags = flags; + nexthops->cur_elts = cur_len; + nexthops = + strategy_lookup_nexthops(&fib_entry->strategy, nexthops, msgbuf); + + if (nexthops_get_curlen(nexthops) == 0) { + ERROR("Message %p returned an empty next hop set", msgbuf); + goto RESTORE; + } + + for (size_t i = first_suffix_index_in_submanifest; + i < first_suffix_index_in_next_submanifest; i++) { + if (!bitmap_is_set_no_check(manifest->request_bitmap, i)) continue; + + pit_entry_t *pit_entry = &(entries[i]->u.pit_entry); + if (!pit_entry) goto RESTORE; + + pit_entry_set_fib_entry(pit_entry, fib_entry); + nexthops_foreach(nexthops, nexthop, + { pit_entry_egress_add(pit_entry, nexthop); }); + } + + // Serialize manifest before sending it + interest_manifest_serialize(int_manifest_header); + + if (forwarder_forward_to_nexthops(forwarder, msgbuf_id, nexthops) <= + 0) { + ERROR("Message %p returned an empty next hop set", msgbuf); + continue; + } + + total_len += msgbuf_get_len(msgbuf); + } + + ret = total_len; + goto END; + } + + default: + break; + } + +RESTORE: + /* Restore flags & curlen */ + nexthops->flags = flags; + nexthops->cur_elts = cur_len; + +END: + return ret; +} + +static ssize_t forwarder_process_single_interest(forwarder_t *forwarder, + msgbuf_pool_t *msgbuf_pool, + msgbuf_t *msgbuf, + off_t msgbuf_id) { + pkt_cache_verdict_t verdict = PKT_CACHE_VERDICT_ERROR; + off_t data_msgbuf_id = INVALID_MSGBUF_ID; + pkt_cache_entry_t *entry = NULL; + + // Update packet cache + pkt_cache_on_interest(forwarder->pkt_cache, msgbuf_pool, msgbuf_id, &verdict, + &data_msgbuf_id, &entry, msgbuf_get_name(msgbuf), + forwarder->serve_from_cs); + + _forwarder_update_interest_stats(forwarder, verdict, msgbuf, + entry->has_expire_ts, entry->expire_ts); + + int rc = _forwarder_forward_upon_interest( + forwarder, msgbuf_pool, data_msgbuf_id, msgbuf_id, entry, verdict, false); + + // No route when trying to forward interest, remove from PIT + if (rc == -1) pkt_cache_pit_remove_entry(forwarder->pkt_cache, entry); + + return msgbuf_get_len(msgbuf); +} + +static ssize_t forwarder_process_aggregated_interest( + forwarder_t *forwarder, interest_manifest_header_t *int_manifest_header, + msgbuf_pool_t *msgbuf_pool, msgbuf_t *msgbuf, off_t msgbuf_id) { + pkt_cache_verdict_t verdict = PKT_CACHE_VERDICT_ERROR; + off_t data_msgbuf_id = INVALID_MSGBUF_ID; + pkt_cache_entry_t *entry = NULL; + // Save PIT entries to avoid re-doing pkt cache lookup in + // `_forwarder_forward_aggregated_interest()` + pkt_cache_entry_t *entries[BITMAP_SIZE * WORD_WIDTH]; + + int n_suffixes_to_fwd = 0; + + hicn_name_t name_copy = HICN_NAME_EMPTY; + hicn_name_copy(&name_copy, msgbuf_get_name(msgbuf)); + + // Suffixes in interest manifest also contains suffix in main name. We can + // then just iterate the interest manifest and update the suffix in the name + // struct + hicn_name_suffix_t *suffix; + unsigned long pos; + interest_manifest_foreach_suffix(int_manifest_header, suffix, pos) { + // Update name + hicn_name_set_suffix(&name_copy, *suffix); + + // Update packet cache + pkt_cache_on_interest(forwarder->pkt_cache, msgbuf_pool, msgbuf_id, + &verdict, &data_msgbuf_id, &entry, &name_copy, + forwarder->serve_from_cs); + + entries[pos] = entry; + _forwarder_update_interest_stats(forwarder, verdict, msgbuf, + entry->has_expire_ts, entry->expire_ts); + + // Here only data forwarding is performed, interest forwarding is done + // in '_forwarder_forward_aggregated_interest()' + int rc = + _forwarder_forward_upon_interest(forwarder, msgbuf_pool, data_msgbuf_id, + msgbuf_id, entry, verdict, true); + + // No route when trying to forward interest, remove from PIT + if (rc == -1) pkt_cache_pit_remove_entry(forwarder->pkt_cache, entry); + + // Unset in bitmap if no interest forwarding needed, + // otherwise increase count of suffixes to forward + if (rc == -1 || verdict == PKT_CACHE_VERDICT_AGGREGATE_INTEREST || + verdict == PKT_CACHE_VERDICT_FORWARD_DATA) { + bitmap_unset_no_check(int_manifest_header->request_bitmap, pos); + } else { + n_suffixes_to_fwd++; + } + + WITH_DEBUG({ + char buf[MAXSZ_HICN_PREFIX]; + int rc = hicn_name_snprintf(buf, MAXSZ_HICN_NAME, &name_copy); + if (rc < 0 || rc >= MAXSZ_HICN_PREFIX) + snprintf(buf, MAXSZ_HICN_PREFIX, "(error)"); + DEBUG("Next in manifest: %s", buf); + }); + } + + // Return if nothing in the manifest to forward + if (n_suffixes_to_fwd == 0) return msgbuf_get_len(msgbuf); + + return _forwarder_forward_aggregated_interest(forwarder, int_manifest_header, + msgbuf, msgbuf_id, entries); +} + +/** + * @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); + const connection_table_t *table = forwarder_get_connection_table(forwarder); + connection_t *conn = + connection_table_get_by_id(table, msgbuf_get_connection_id(msgbuf)); + + assert(msgbuf_get_type(msgbuf) == HICN_PACKET_TYPE_INTEREST); + + u32 n_suffixes = 0; + interest_manifest_header_t *int_manifest_header = NULL; + size_t payload_size; + int ret = _forwarder_get_interest_manifest(msgbuf, &int_manifest_header, + &payload_size); + if (ret == 0) { + // Deserialize intrest manifest + interest_manifest_deserialize(int_manifest_header); + + if (!interest_manifest_is_valid(int_manifest_header, payload_size)) + return -1; + + n_suffixes = int_manifest_header->n_suffixes; + } + + // Update stats + forwarder->stats.countInterestsReceived++; + conn->stats.interests.rx_pkts++; + conn->stats.interests.rx_bytes += msgbuf_get_len(msgbuf); + + WITH_DEBUG({ + char buf[MAXSZ_HICN_PREFIX]; + int rc = hicn_name_snprintf(buf, MAXSZ_HICN_NAME, msgbuf_get_name(msgbuf)); + if (rc < 0 || rc >= MAXSZ_HICN_PREFIX) + snprintf(buf, MAXSZ_HICN_PREFIX, "(error)"); + DEBUG("INTEREST (%s) msgbuf_id=%lu ingress=%u length=%u", buf, msgbuf_id, + msgbuf_get_connection_id(msgbuf), msgbuf_get_len(msgbuf)); + DEBUG("INTEREST (%s) suffixes=%u msgbuf_id=%lu ingress=%u length=%u", buf, + n_suffixes, msgbuf_id, msgbuf_get_connection_id(msgbuf), + msgbuf_get_len(msgbuf)); + }); + + // Cache suffixes for current prefix to (possibly) avoid double lookups + pkt_cache_save_suffixes_for_prefix( + forwarder->pkt_cache, hicn_name_get_prefix(msgbuf_get_name(msgbuf))); + + if (ret == -1) + return forwarder_process_single_interest(forwarder, msgbuf_pool, msgbuf, + msgbuf_id); + return forwarder_process_aggregated_interest(forwarder, int_manifest_header, + msgbuf_pool, msgbuf, msgbuf_id); +} + +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("Invalid packet cache content"); + break; + default: + break; + } +} + +/** + * @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 buf[MAXSZ_HICN_PREFIX]; + int rc = hicn_name_snprintf(buf, MAXSZ_HICN_NAME, msgbuf_get_name(msgbuf)); + if (rc < 0 || rc >= MAXSZ_HICN_PREFIX) + snprintf(buf, MAXSZ_HICN_PREFIX, "(error)"); + DEBUG("DATA (%s) msgbuf_id=%lu ingress=%u length=%u", buf, msgbuf_id, + msgbuf_get_connection_id(msgbuf), msgbuf_get_len(msgbuf)); + }); + + const connection_table_t *table = forwarder_get_connection_table(forwarder); + connection_t *conn = + connection_table_get_by_id(table, msgbuf_get_connection_id(msgbuf)); + + // Update stats + forwarder->stats.countObjectsReceived++; + conn->stats.data.rx_pkts++; + conn->stats.data.rx_bytes += msgbuf_get_len(msgbuf); + + // Cache suffixes for current prefix to (possibly) avoid double lookups + pkt_cache_save_suffixes_for_prefix( + forwarder->pkt_cache, hicn_name_get_prefix(msgbuf_get_name(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); + + // NOTE : probes are not stored in PIT + if (msgbuf_is_probe(msgbuf)) { + fib_entry_t *entry = fib_match_msgbuf(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()); + } + } + 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_flush_connections(forwarder_t *forwarder) { + // DEBUG("[forwarder_flush_connections]"); + const connection_table_t *table = forwarder_get_connection_table(forwarder); + + unsigned num_pending_conn = (unsigned)vector_len(forwarder->pending_conn); + for (unsigned i = 0; i < num_pending_conn; i++) { + unsigned conn_id = forwarder->pending_conn[i]; + 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... + } + } + vector_reset(forwarder->pending_conn); + // DEBUG("[forwarder_flush_connections] done"); +} + +#if WITH_WLDR +// 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 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 + 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); } +#endif -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, + hicn_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 = hicn_ip_prefix_snprintf(prefix_s, MAXSZ_IP_PREFIX, prefix); + assert(rc < MAXSZ_IP_PREFIX); + if (rc < 0) return false; + + INFO("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"); + 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); + hicn_prefix_t name_prefix = HICN_PREFIX_EMPTY; + hicn_prefix_create_from_ip_address_len(&prefix->address, prefix->len, + &name_prefix); + fib_entry_t *entry = fib_contains(forwarder->fib, &name_prefix); + if (!entry) { + entry = fib_entry_create(&name_prefix, strategy_type, NULL, forwarder); + if (ingress_id != INVALID_FACE_ID) + fib_entry_nexthops_add(entry, ingress_id); + entry = fib_add(forwarder->fib, entry); - return res; + } else { + if (ingress_id != INVALID_FACE_ID) + fib_entry_nexthops_add(entry, ingress_id); + } + + forwarder_on_route_event(forwarder, entry); + + return true; } +bool forwarder_remove_route(forwarder_t *forwarder, hicn_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"); + hicn_prefix_t name_prefix = HICN_PREFIX_EMPTY; + hicn_prefix_create_from_ip_address_len(&prefix->address, prefix->len, + &name_prefix); + 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, + hicn_ip_prefix_t *prefix, + hicn_policy_t *policy) { + assert(forwarder); + assert(prefix); + assert(policy); + + hicn_prefix_t name_prefix = HICN_PREFIX_EMPTY; + hicn_prefix_create_from_ip_address_len(&prefix->address, prefix->len, + &name_prefix); + fib_entry_t *entry = fib_contains(forwarder->fib, &name_prefix); + if (!entry) return false; - return messageProcessor_AddOrUpdatePolicy(forwarder->processor, control); + 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, hicn_ip_prefix_t *prefix) { + assert(forwarder); + assert(prefix); + + hicn_prefix_t name_prefix = HICN_PREFIX_EMPTY; + hicn_prefix_create_from_ip_address_len(&prefix->address, prefix->len, + &name_prefix); + fib_entry_t *entry = fib_contains(forwarder->fib, &name_prefix); + if (!entry) return false; - return messageProcessor_RemovePolicy(forwarder->processor, control); + fib_entry_set_policy(entry, POLICY_EMPTY); + + 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(const forwarder_t *forwarder, + unsigned connection_id) { + fib_entry_t **removed_entries = NULL; + size_t num_removed_entries; + + assert(forwarder); + + fib_remove_connection(forwarder->fib, connection_id, &removed_entries, + &num_removed_entries); + + if (num_removed_entries > 0) { + assert(removed_entries); + + for (int i = 0; i < num_removed_entries; i++) { + fib_entry_t *entry = removed_entries[i]; + forwarder_on_route_event(forwarder, entry); + fib_remove_entry(forwarder->fib, entry); + } + free(removed_entries); + } } -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, + hicn_prefix_t *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)); - processor_SetStrategy(forwarder->processor, prefix, strategy, - related_prefixes_len, related_prefixes); + fib_entry_t *entry = fib_contains(forwarder->fib, name_prefix); + if (!entry) return; + + 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, hicn_prefix_t *prefix, + strategy_type_t strategy_type, + strategy_options_t *strategy_options) { + assert(forwarder); + assert(prefix); + assert(STRATEGY_TYPE_VALID(strategy_type)); + /* strategy_options might be NULL */ + + fib_entry_t *entry = fib_contains(forwarder->fib, 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_prefix(forwarder->fib, 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); +// IMPORTANT: Use this function ONLY for read-only operations since a +// realloc would otherwise modify the returned copy but not the original +// msgbuf ids vector in the forwarder. This constraint cannot be enforced +// by returning a (const off_t *) because the vector_t macros still cast +// to (void **). +off_t *forwarder_get_acquired_msgbuf_ids(const forwarder_t *forwarder) { + return forwarder->acquired_msgbuf_ids; } -PARCClock *forwarder_GetClock(const Forwarder *forwarder) { - return forwarder->clock; +void forwarder_acquired_msgbuf_ids_reset(const forwarder_t *forwarder) { + vector_reset(forwarder->acquired_msgbuf_ids); } -#if !defined(__APPLE__) -hicn_socket_helper_t *forwarder_GetHicnSocketHelper(Forwarder *forwarder) { - return forwarder->hicnSocketHelper; +void forwarder_acquired_msgbuf_ids_push(const forwarder_t *forwarder, + off_t msgbuf_id) { + vector_push(forwarder->acquired_msgbuf_ids, msgbuf_id); } -#endif // ======================================================= -static void _signal_cb(int sig, PARCEventType events, void *user_data) { - Forwarder *forwarder = (Forwarder *)user_data; +fib_t *forwarder_get_fib(const forwarder_t *forwarder) { + return forwarder->fib; +} + +msgbuf_pool_t *forwarder_get_msgbuf_pool(const forwarder_t *forwarder) { + return forwarder->msgbuf_pool; +} + +mapme_t *forwarder_get_mapme(const forwarder_t *forwarder) { + return forwarder->mapme; +} + +#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 */ + +/** + * @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); +} - logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning, - __func__, "signal %d events %d", sig, events); +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); + + hicn_name_t name; + msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); + assert(msgbuf); + + size_t size = msgbuf_get_len(msgbuf); + + const connection_table_t *table = + forwarder_get_connection_table(listener->forwarder); + + /* Connection lookup */ + if (msgbuf_get_connection_id(msgbuf) == CONNECTION_ID_UNDEFINED) { + connection_t *connection = connection_table_get_by_pair(table, pair); + unsigned conn_id = + connection + ? (unsigned)connection_table_get_connection_id(table, connection) + : CONNECTION_ID_UNDEFINED; + + assert((conn_id != CONNECTION_ID_UNDEFINED) || listener); + msgbuf->connection_id = conn_id; + } - switch ((int)sig) { - case SIGTERM: - logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning, - __func__, "Caught an terminate signal; exiting cleanly."); - dispatcher_Stop(forwarder->dispatcher); + forwarder->stats.countReceived++; + + /* Initialize packet buffer stored in msgbuf through libhicn */ + msgbuf_initialize_from_packet(msgbuf); + + /* Detect packet type */ + hicn_packet_analyze(msgbuf_get_pkbuf(msgbuf)); + + msgbuf->recv_ts = now; + +RETRY: + + switch (msgbuf_get_type(msgbuf)) { + case HICN_PACKET_TYPE_INTEREST: + if (!connection_id_is_valid(msgbuf->connection_id)) { + char conn_name[SYMBOLIC_NAME_LEN]; + int rc = connection_table_get_random_name(table, conn_name); + if (rc < 0) { + ERROR("Could not create name for new connection"); + goto DROP; + } + + unsigned connection_id = + listener_create_connection(listener, conn_name, pair); + if (connection_id == CONNECTION_ID_UNDEFINED) { + ERROR("Could not create new connection"); + goto DROP; + } + msgbuf->connection_id = connection_id; + } + msgbuf->path_label = 0; // not used for interest packets + hicn_interest_get_name(msgbuf_get_pkbuf(msgbuf), &name); + msgbuf_set_name(msgbuf, &name); +#ifdef WITH_WLDR + forwarder_apply_wldr(forwarder, msgbuf, connection); +#endif /* WITH_WLDR */ + forwarder_process_interest(forwarder, msgbuf_id); + + pkt_cache_log(forwarder->pkt_cache); break; - case SIGINT: - logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning, - __func__, "Caught an interrupt signal; exiting cleanly."); - dispatcher_Stop(forwarder->dispatcher); + case HICN_PACKET_TYPE_DATA: + /* This include probes */ + if (!connection_id_is_valid(msgbuf->connection_id)) { + ERROR("Invalid connection for data packet"); + goto DROP; + } + msgbuf_init_pathlabel(msgbuf); + hicn_data_get_name(msgbuf_get_pkbuf(msgbuf), &name); + msgbuf_set_name(msgbuf, &name); +#ifdef WITH_WLDR + forwarder_apply_wldr(forwarder, msgbuf, connection); +#endif /* WITH_WLDR */ + forwarder_process_data(forwarder, msgbuf_id); + + pkt_cache_log(forwarder->pkt_cache); break; -#ifndef _WIN32 - case SIGUSR1: - // dump stats + +#ifdef WITH_WLDR + case HICN_PACKET_TYPE_WLDR_NOTIFICATION: + if (!connection_id_is_valid(msgbuf->connection_id)) { + ERROR("Invalid connection for WLDR packet"); + goto DROP; + } + connection_t *connection = + connection_table_get_by_id(table, msgbuf->connection_id); + connection_wldr_handle_notification(connection, msgbuf); break; #endif - default: + case HICN_PACKET_TYPE_MAPME: + INFO("Received MAP-Me packet"); + if (!connection_id_is_valid(msgbuf->connection_id)) { + char conn_name[SYMBOLIC_NAME_LEN]; + int rc = connection_table_get_random_name(table, conn_name); + if (rc < 0) { + ERROR("Could not create name for new connection"); + goto DROP; + } + + unsigned connection_id = + listener_create_connection(listener, conn_name, pair); + if (connection_id == CONNECTION_ID_UNDEFINED) { + ERROR("Could not create new connection"); + goto DROP; + } + INFO("Created connection upon MAP-Me packet"); + msgbuf->connection_id = connection_id; + } + mapme_process(forwarder->mapme, msgbuf); break; - } -} -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 -} + case HICN_PACKET_TYPE_COMMAND: + // Create the connection to send the ack back + if (!connection_id_is_valid(msgbuf->connection_id)) { + char conn_name[SYMBOLIC_NAME_LEN]; + int rc = connection_table_get_random_name(table, conn_name); + if (rc < 0) { + ERROR("Could not create name for new connection"); + goto DROP; + } + + unsigned connection_id = + listener_create_connection(listener, conn_name, pair); + if (connection_id == CONNECTION_ID_UNDEFINED) { + ERROR("Could not create new connection"); + goto DROP; + } + msgbuf->connection_id = connection_id; + } + + msg_header_t *msg = (msg_header_t *)msgbuf_get_packet(msgbuf); + msgbuf->command.type = msg->header.command_id; + if (!command_type_is_valid(msgbuf->command.type)) { + ERROR("Invalid command %d", msgbuf->command.type); + goto DROP; + } + + /* + * We need to retrieve the connection (in case it is useful) before + * proceeding through the removal + */ + connection_t *connection = + connection_table_get_by_id(table, msgbuf_get_connection_id(msgbuf)); + size = command_process_msgbuf(forwarder, msgbuf); + if (msgbuf->command.type == COMMAND_TYPE_CONNECTION_REMOVE) + _forwarder_finalize_connection_if_self(connection, msgbuf); + return size; -#ifdef WITH_MAPME -FIB *forwarder_getFib(Forwarder *forwarder) { - return messageProcessor_getFib(forwarder->processor); -} + default: + /* Commands are not recognized by the packet parser */ + if (msgbuf_is_command(msgbuf)) { + msgbuf_set_type(msgbuf, HICN_PACKET_TYPE_COMMAND); + goto RETRY; + } + goto DROP; + } -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 */ -} + return size; -void forwarder_ProcessMapMe(Forwarder *forwarder, const uint8_t *msgBuffer, - unsigned conn_id) { - mapme_Process(forwarder->mapme, msgBuffer, conn_id); +DROP: + 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 */ +forwarder_stats_t forwarder_get_stats(forwarder_t *forwarder) { + return forwarder->stats; +} diff --git a/hicn-light/src/hicn/core/forwarder.h b/hicn-light/src/hicn/core/forwarder.h index d1815b7d4..b7ce5ff4d 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-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: @@ -18,292 +18,241 @@ * 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); +void forwarder_setup_local_listeners(forwarder_t *forwarder, uint16_t port); -/** - * @function forwarder_GetNextConnectionId - * @abstract Get the next identifier for a new connection - */ -unsigned forwarder_GetNextConnectionId(Forwarder *forwarder); +configuration_t *forwarder_get_configuration(forwarder_t *forwarder); -Messenger *forwarder_GetMessenger(Forwarder *forwarder); - -Dispatcher *forwarder_GetDispatcher(Forwarder *forwarder); +subscription_table_t *forwarder_get_subscriptions(const 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(const 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); +pkt_cache_t *forwarder_get_pkt_cache(const forwarder_t *forwarder); -/** - * 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); +void forwarder_cs_set_store(forwarder_t *forwarder, bool val); + +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_ReceiveCommand(Forwarder *forwarder, command_id command, - struct iovec *message, unsigned ingressId); +void forwarder_cs_set_size(forwarder_t *forwarder, size_t size); -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, + hicn_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, hicn_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, + hicn_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, hicn_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(const 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, + hicn_prefix_t *name_prefix, + strategy_type_t strategy_type, + strategy_options_t *strategy_options); + +void forwarder_set_strategy(forwarder_t *forwarder, hicn_prefix_t *prefix, + strategy_type_t strategy_type, + strategy_options_t *strategy_options); -FibEntryList *forwarder_GetFibEntries(Forwarder *forwarder); +cs_t *forwarder_get_cs(const forwarder_t *forwarder); + +off_t *forwarder_get_acquired_msgbuf_ids(const forwarder_t *forwarder); /** - * Sets the maximum number of content objects in the content store - * - * Implementation dependent - may wipe the cache. + * @note Acquire msgbuf ids vector ONLY for read-only operations. */ -void forwarder_SetContentObjectStoreSize(Forwarder *forwarder, - size_t maximumContentStoreSize); - -void forwarder_SetChacheStoreFlag(Forwarder *forwarder, bool val); +off_t *forwarder_get_acquired_msgbuf_ids(const forwarder_t *forwarder); -bool forwarder_GetChacheStoreFlag(Forwarder *forwarder); +void forwarder_acquired_msgbuf_ids_reset(const forwarder_t *forwarder); -void forwarder_SetChacheServeFlag(Forwarder *forwarder, bool val); +void forwarder_acquired_msgbuf_ids_push(const forwarder_t *forwarder, + off_t msgbuf_id); -bool forwarder_GetChacheServeFlag(Forwarder *forwarder); +/** + * @brief Returns the forwarder's FIB. + * @param[in] forwarder - Pointer to the forwarder. + * @returns Pointer to the hICN FIB. + */ +fib_t *forwarder_get_fib(const forwarder_t *forwarder); -void forwarder_ClearCache(Forwarder *forwarder); +/** + * @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. + */ +msgbuf_pool_t *forwarder_get_msgbuf_pool(const forwarder_t *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 -/** - * @function forwarder_getFib - * @abstract Returns the hICN forwarder's FIB. - * @param [in] forwarder - Pointer to the hICN forwarder. - * @returns Pointer to the hICN FIB. - */ -FIB *forwarder_getFib(Forwarder *forwarder); +void forwarder_on_route_event(const forwarder_t *forwarder, fib_entry_t *entry); + +int forwarder_add_connection(const forwarder_t *forwarder, + const char *symbolic_name, face_type_t type, + address_pair_t *pair, policy_tags_t tags, + int priority, face_state_t admin_state); + +int forwarder_remove_connection(const forwarder_t *forwarder, + unsigned connection_id, bool finalize); /** - * @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); + +forwarder_stats_t forwarder_get_stats(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..d2f547863 --- /dev/null +++ b/hicn-light/src/hicn/core/listener.c @@ -0,0 +1,425 @@ +/* + * 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 "../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 = + (unsigned int)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, + CONNECTION_ID_UNDEFINED, 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); + + /* initialized so that gcc-9 does not complain */ + face_type_t connection_type = FACE_TYPE_UNDEFINED; + 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; + case FACE_TYPE_HICN: + case FACE_TYPE_HICN_LISTENER: + case FACE_TYPE_UDP: + case FACE_TYPE_TCP: + case FACE_TYPE_UNDEFINED: + case FACE_TYPE_N: + return CONNECTION_ID_UNDEFINED; + } + +#ifdef USE_CONNECTED_SOCKETS + /* + * 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. + */ + int fd = listener_get_socket(listener, address_pair_get_local(pair), + address_pair_get_remote(pair), + listener->interface_name); + if (fd < 0) return CONNECTION_ID_UNDEFINED; +#else + int fd = 0; // means listener->fd; +#endif + bool local = address_is_local(address_pair_get_local(pair)); + + connection_table_t *table = + forwarder_get_connection_table(listener->forwarder); + connection_t *connection = + connection_table_allocate(table, pair, connection_name); + unsigned connection_id = + (unsigned int)connection_table_get_connection_id(table, connection); + + 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); + }) + + forwarder_on_connection_event(listener->forwarder, connection, + CONNECTION_EVENT_CREATE); + + 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, + unsigned connection_id) { + 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); + msgbuf_set_connection_id(msgbuf, connection_id); + + // 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, + unsigned connection_id) { + assert(listener); + + size_t total_processed_bytes = 0; + ssize_t num_msg_received = 0; + + forwarder_t *forwarder = listener->forwarder; + msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + forwarder_acquired_msgbuf_ids_reset(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]); + msgbuf_set_connection_id(msgbufs[i], connection_id); + forwarder_acquired_msgbuf_ids_push(forwarder, 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); + + const off_t *acquired_msgbuf_ids = + forwarder_get_acquired_msgbuf_ids(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); + } + + 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, + unsigned connection_id, void *user_data) { + assert(listener); + assert(!user_data); + + /* + * 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, connection_id); + + return listener_read_single(listener, fd, connection_id); +} + +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); +} diff --git a/hicn-light/src/hicn/core/listener.h b/hicn-light/src/hicn/core/listener.h new file mode 100644 index 000000000..76d865c5d --- /dev/null +++ b/hicn-light/src/hicn/core/listener.h @@ -0,0 +1,140 @@ +/* + * 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 <hicn/base/loop.h> + +#define LISTENER_ID_UNDEFINED ~0 + +struct forwarder_s; + +typedef struct { + address_t address; + face_type_t type; +} listener_key_t; + +static inline int listener_key_equals(const listener_key_t *key1, + const listener_key_t *key2) { + return address_equals(&key1->address, &key2->address) && + (key1->type == key2->type); +} + +/** + * @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, + unsigned connection_id); +ssize_t listener_read_batch(listener_t *listener, int fd, + unsigned connection_id); + +/** + * @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, + unsigned connection_id, 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..4a0f74a13 --- /dev/null +++ b/hicn-light/src/hicn/core/listener_table.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. + */ + +/** + * \file listener_table.c + * \brief Implementation of hICN listener table + */ + +#include <hicn/util/log.h> +#include <hicn/util/sstrncpy.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 + +typedef struct { + char name[SYMBOLIC_NAME_LEN]; +} name_key_t; + +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->name_keys = slab_create(name_key_t, SLAB_INIT_SIZE); + table->id_by_key = kh_init_lt_key(); + table->listener_keys = slab_create(listener_key_t, SLAB_INIT_SIZE); + + /* + * 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) { + unsigned listener_id; + kh_foreach_value(table->id_by_key, listener_id, { + listener_t *listener = listener_table_get_by_id(table, listener_id); + const char *name = listener_get_name(listener); + INFO("Removing listener %s [%d]", name, listener->fd); + listener_finalize(listener); + }); + + kh_destroy_lt_name(table->id_by_name); + slab_free(table->name_keys); + kh_destroy_lt_key(table->id_by_key); + slab_free(table->listener_keys); + + pool_free(table->listeners); + free(table); +} + +listener_t *listener_table_allocate(const listener_table_t *table, + const listener_key_t *key, + const char *name) { + listener_t *listener = NULL; + pool_get(table->listeners, listener); + if (!listener) return NULL; + + off_t id = listener - table->listeners; + int rc; + + // Add in name hash table + name_key_t *name_copy = slab_get(name_key_t, table->name_keys); + strcpy_s(name_copy->name, sizeof(name_key_t), name); + + khiter_t k = kh_put_lt_name(table->id_by_name, name_copy->name, &rc); + assert(rc == KH_ADDED || rc == KH_RESET); + kh_value(table->id_by_name, k) = (unsigned int)id; + + // Add in key hash table + listener_key_t *key_copy = slab_get(listener_key_t, table->listener_keys); + memcpy(key_copy, key, sizeof(listener_key_t)); + + k = kh_put_lt_key(table->id_by_key, key_copy, &rc); + assert(rc == KH_ADDED || rc == KH_RESET); + kh_value(table->id_by_key, k) = (unsigned int)id; + + assert(kh_size(table->id_by_name) == kh_size(table->id_by_key)); + return listener; +} + +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); + + // Remove from name hash table + khiter_t k = kh_get_lt_name(table->id_by_name, name); + assert(k != kh_end(table->id_by_name)); + kh_del_lt_name(table->id_by_name, k); + slab_put(table->name_keys, kh_key(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)); + kh_del_lt_key(table->id_by_key, k); + slab_put(table->listener_keys, kh_key(table->id_by_key, k)); + + assert(kh_size(table->id_by_name) == kh_size(table->id_by_key)); + pool_put(table->listeners, listener); +} + +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 = + (unsigned int)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); + }) +} 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..062d1748e --- /dev/null +++ b/hicn-light/src/hicn/core/listener_table.h @@ -0,0 +1,270 @@ +/* + * 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 <hicn/util/khash.h> +#include <hicn/util/hash.h> +#include <hicn/util/slab.h> +#include "address.h" +#include "listener.h" +#include <hicn/util/pool.h> + +/* Hash functions for indices */ +#define key_hash(key) (hash_struct(key)) + +/* Hash table types for indices */ +KHASH_MAP_INIT_STR(lt_name, unsigned); +KHASH_INIT(lt_key, const listener_key_t *, unsigned, 1, key_hash, + listener_key_equals); + +typedef struct { + size_t max_size; + + kh_lt_key_t *id_by_key; + slab_t *listener_keys; + kh_lt_name_t *id_by_name; + slab_t *name_keys; + + 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. + */ +listener_t *listener_table_allocate(const listener_table_t *table, + const listener_key_t *key, + const char *name); + +/** + * @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. + */ +void listener_table_deallocate(const listener_table_t *table, + listener_t *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) \ + do { \ + listener_t *listener; \ + (void)listener; \ + pool_foreach( \ + table->listeners, listener, do { BODY } while (0)); \ + } 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 a22d01ae7..acda2b8cd 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-2023 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -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,697 +116,779 @@ #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_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 */ + + /* + * 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 *forwarder; + 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; - - /* Internal state : set default values */ - memcpy(*mapme, &MapMeDefault, sizeof(MapMe)); +int mapme_on_timeout(void *mapme_arg, int fd, unsigned id, void *data); - (*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; -static MapMeTFIB *mapmeTFIB_Create() { - MapMeTFIB *tfib; - tfib = malloc(sizeof(MapMeTFIB)); - if (!tfib) goto ERR_MALLOC; +#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; + + // 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; } -void mapmeTFIB_Release(MapMeTFIB **tfibPtr) { - MapMeTFIB *tfib = *tfibPtr; - /* TODO; Release all timers */ - parcHashMap_Release(&tfib->nexthops); +void mapme_release_tfib(mapme_tfib_t **tfibPtr) { + mapme_tfib_t *tfib = *tfibPtr; free(tfib); - *tfibPtr = NULL; + tfibPtr = NULL; } /** - * @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(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, tfib, (void (*)(void **))mapmeTFIB_Release); + tfib = mapme_tfib_create(); + fib_entry_set_user_data(entry, tfib, (void (*)(void **))mapme_release_tfib); } -#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) return NULL; - PARCByteArray *array = parcBuffer_Array(buffer); - timer = *((PARCEventTimer **)parcByteArray_Array(array)); - parcUnsigned_Release(&cid); - return timer; -} - -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(MapMeTFIB *tfib, unsigned conn_id) { - // Who releases the timer ? - PARCUnsigned *cid = parcUnsigned_Create(conn_id); - parcHashMap_Remove(tfib->nexthops, cid); - parcUnsigned_Release(&cid); -} - -static PARCIterator *mapmeTFIB_CreateKeyIterator(const MapMeTFIB *tfib) { - return parcHashMap_CreateKeyIterator(tfib->nexthops); -} - -int hicn_prefix_from_name(const Name *name, hicn_prefix_t *prefix) { - NameBitvector *bv = name_GetContentName(name); - ip_prefix_t ip_prefix; - nameBitvector_ToIPAddress(bv, &ip_prefix); - - /* The name length will be equal to ip address' prefix length */ - return hicn_prefix_create_from_ip_prefix(&ip_prefix, prefix); +/** + * @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_get_type_from_heuristic(const mapme_t *mapme, + fib_entry_t *entry) { +#if 0 + if (!entry) return UPDATE; + if (fib_entry_has_local_nexthop(entry)) + /* We are a producer for this entry, send update */ + return UPDATE; +#else /* Always send IU */ + return UPDATE; +#endif } -static Message *mapme_createMessage(const MapMe *mapme, const Name *name, - mapme_params_t *params) { - Ticks now = forwarder_GetTicks(mapme->forwarder); - Logger *logger = logger_Acquire(forwarder_GetLogger(mapme->forwarder)); - - INFO(mapme, "[MAP-Me] CreateMessage type=%d seq=%d", params->type, - params->seq); +/** + * + * Here nexthops is not necessarily FIB nexthops as we might advertise given FIB + * entries on various other connections. + * + * prefix can be specified to send an update for a More Specific Prefix (MSP), + * or left NULL for the default behaviour. Note there will be no support for + * retransmission for MSP. + * + * NOTES: + * - if the face is pending an we receive an IN, maybe we should not cancel the + * timer + * - this function should never be called for Notifications. + */ +int mapme_send_to_nexthops(const mapme_t *mapme, fib_entry_t *entry, + const nexthops_t *nexthops, + const hicn_prefix_t *prefix) { + INFO("mapme send to nexthops"); + const hicn_prefix_t *mapme_prefix; + uint32_t mapme_seq; + + assert(!!prefix ^ !!entry); + + if (mapme->enabled == false) { + WARN("MAP-Me is NOT enabled"); + return -1; + } - size_t size = (params->protocol == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN - : HICN_MAPME_V4_HDRLEN; - uint8_t *icmp_pkt = parcMemory_AllocateAndClear(size); + if (prefix) { + INFO("mapme with given prefix"); + mapme_prefix = prefix; + mapme_seq = 1; + } else { + INFO("mapme wih fib entry prefix"); + mapme_tfib_t *tfib = TFIB(entry); + if (tfib == NULL) { + mapme_create_tfib(mapme, entry); + tfib = TFIB(entry); + } - 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; + mapme_prefix = fib_entry_get_prefix(entry); + mapme_seq = tfib->seq; } - 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; + char prefix_s[MAXSZ_IP_PREFIX]; + int rc = hicn_prefix_snprintf(prefix_s, MAXSZ_IP_PREFIX, mapme_prefix); + assert(rc < MAXSZ_IP_PREFIX); + if (rc < 0) NULL; + + INFO("mapme send to nexthops prefix= %s", prefix_s); + + WITH_INFO({ + char buf[MAXSZ_HICN_PREFIX]; + int rc = hicn_prefix_snprintf(buf, MAXSZ_HICN_PREFIX, mapme_prefix); + if (rc < 0 || rc >= MAXSZ_HICN_PREFIX) + snprintf(buf, MAXSZ_HICN_PREFIX, "(error)"); + INFO("sending IU/IN for name %s on nexthops", buf); + }) + + mapme_params_t params = {.protocol = mapme->protocol, + .type = mapme_get_type_from_heuristic(mapme, entry), + .seq = mapme_seq}; + + uint8_t packet[MTU]; + size_t size = hicn_mapme_create_packet(packet, mapme_prefix, ¶ms); + if (size <= 0) { + ERROR("Could not create MAP-Me packet"); + return -1; } - // hicn_packet_dump(icmp_pkt, MAPME_HDRLEN); + connection_table_t *table = forwarder_get_connection_table(mapme->forwarder); - return message_CreateFromByteArray(NO_INGRESS, icmp_pkt, - MessagePacketType_Interest, now, logger); + nexthops_foreach(nexthops, nexthop, { + const connection_t *conn = connection_table_get_by_id(table, nexthop); + assert(!connection_is_local(conn)); + connection_send_packet(conn, packet, size); + }); -ERR_CREATE: -ERR_NAME: - return NULL; + return 0; } -static Message *mapme_createAckMessage(const MapMe *mapme, - const uint8_t *msgBuffer, - const mapme_params_t *params) { - Ticks now = forwarder_GetTicks(mapme->forwarder); - Logger *logger = logger_Acquire(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"); - return NULL; +#if 0 +/** + * + * 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; } - return message_CreateFromByteArray( - NO_INGRESS, icmp_pkt, MessagePacketType_ContentObject, now, logger); -} - -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); + /* Detect change */ + if (!fib_entry_nexthops_changed(fib_entry)) { + INFO("No change in nexthops"); + return; + } + fib_entry_set_prev_nexthops(fib_entry); - 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); + mapme_send_to_nexthops(mapme, fib_entry, nexthops); } - -/** - * @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) { -#if 0 /* interplay of IU/IN */ - if (TFIB(fibEntry)->lastAckedUpdate == 0) { - return UPDATE; - } else { - Ticks interval = now - TFIB(fibEntry)->lastAckedUpdate; - return (T2NS(interval) > MS2NS(mapme->Tu)) ? 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; +/****************************************************************************** + * MAPME API + ******************************************************************************/ - INFO(mapme, "[MAP-Me] SetFacePending connection=%d prefix=XX retx=%d", - conn_id, num_retx); +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; + } - /* 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; + /* Apply the policy of the fib_entry over all neighbours */ + nexthops_t new_nexthops = NEXTHOPS_EMPTY; + nexthops_t *nexthops = fib_entry_get_mapme_nexthops(entry, &new_nexthops); - /* Safeguard during retransmissions */ - if (!TFIB(fibEntry)) - return true; + /* We set force to true to avoid overriding the FIB cache */ + return mapme_set_adjacencies(mapme, entry, nexthops, NULL); +} +// XXX this will change with the FIB cache +// XXX we are sometimes incrementing tfib seq for nothing +int mapme_set_adjacencies(const mapme_t *mapme, fib_entry_t *entry, + nexthops_t *nexthops, const hicn_prefix_t *prefix) { + INFO("mapme set adjacenies"); /* - * On the producer side, we have to clear the TFIB everytime we change the list - * of adjacencies, otherwise retransmissions will occur to preserve them. + * - entry is provided in case of a producer reannouncement + * - prefix is provided for control plane triggered updates */ - 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) { + assert(!!prefix ^ !!entry); - NumberSet * conns = numberSet_Create(); - - 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); - - for (size_t i = 0; i < numberSet_Length(conns); i++) { - unsigned conn_id = numberSet_GetItem(conns, i); - PARCEventTimer *oldTimer = (PARCEventTimer *)mapmeTFIB_Get(TFIB(fibEntry), conn_id); - if (oldTimer) - parcEventTimer_Stop(oldTimer); - mapmeTFIB_Remove(TFIB(fibEntry), conn_id); - } - - numberSet_Release(&conns); - } + if (mapme->enabled == false) { + WARN("MAP-Me is NOT enabled"); + return -1; } - // 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; - } + if (entry) { + /* Check disabled, we need to be able to send an update for a larger prefix + * that the one being served. + */ + // if (!fib_entry_has_local_nexthop(entry)) return -1; - 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"); + mapme_tfib_t *tfib = TFIB(entry); + if (tfib == NULL) { + mapme_create_tfib(mapme, entry); + tfib = TFIB(entry); } - 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) 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; - } + /* + * We need to prevent pending updates to recreate a link which does not make + * since anymore since we edit the graph here. + */ + nexthops_clear(&tfib->nexthops); - PARCEventTimer *oldTimer = - (PARCEventTimer *)mapmeTFIB_Get(TFIB(fibEntry), conn_id); - if (oldTimer) { - INFO(mapme, "[MAP-Me] - Found old timer, would need to cancel !"); - // parcEventTimer_Stop(oldTimer); + /* We update the sequence number in all cases otherwise this won't allow + * repetition + */ + tfib->seq++; } - INFO(mapme, "[MAP-Me] - Putting new timer in TFIB"); - if (timer) mapmeTFIB_Put(TFIB(fibEntry), conn_id, timer); - return true; - -ERR_MALLOC: -ERR_TIMER: - return false; + INFO("calling send to nh"); + mapme_send_to_nexthops(mapme, entry, nexthops, prefix); + return 0; } -/*------------------------------------------------------------------------------ - * Event handling - *----------------------------------------------------------------------------*/ +int mapme_set_adjacency(const mapme_t *mapme, fib_entry_t *entry, + nexthop_t nexthop, const hicn_prefix_t *prefix) { + nexthops_t nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, nexthop); -/* - * 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 */ - - return true; - } - return false; + return mapme_set_adjacencies(mapme, entry, &nexthops, prefix); } -void -mapme_send_updates(const MapMe * mapme, FibEntry * fibEntry, const NumberSet * nexthops) -{ - if (!TFIB(fibEntry)) /* Create TFIB associated to FIB entry */ - mapme_CreateTFIB(fibEntry); - TFIB(fibEntry)->seq++; - - const Name *name = fibEntry_GetPrefix(fibEntry); - char *name_str = name_ToString(name); - bool clear_tfib = true; - for (size_t j = 0; j < numberSet_Length(nexthops); j++) { - unsigned nexthop_id = numberSet_GetItem(nexthops, j); - INFO(mapme, "[MAP-Me] sending IU/IN for name %s on connection %d", name_str, - nexthop_id); - mapme_setFacePending(mapme, name, fibEntry, nexthop_id, true, true, clear_tfib, 0); - clear_tfib = false; +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; } - free(name_str); -} - -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++; -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; + mapme_send_to_nexthops(mapme, entry, &tfib->nexthops, NULL); + return 0; +} - /* Apply the policy of the fibEntry over all neighbours */ - NumberSet * available_nexthops = fibEntry_GetAvailableNextHops(fibEntry, ~0); +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; + } - /* Advertise prefix on all available next hops (if needed) */ - mapme_send_updates(mapme, fibEntry, available_nexthops); + nexthops_t nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, nexthop); - numberSet_Release(&available_nexthops); + return mapme_send_to_nexthops(mapme, entry, &nexthops, NULL); } +#if 0 /* * 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); + * each concerned fib_entry : connection is involved, or no more involved */ + const fib_t *fib = forwarder_get_fib(mapme->forwarder); + fib_foreach_entry(fib, entry, { mapme_set_all_adjacencies(mapme, entry); }); +} +#endif - /* 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); +/*------------------------------------------------------------------------------ + * Special Interest handling + *----------------------------------------------------------------------------*/ + +#ifdef HICN_MAPME_ALLOW_NONEXISTING_FIB_ENTRY +fib_entry_t *mapme_create_fib_entry(const mapme_t *mapme, + const hicn_prefix_t *prefix, + unsigned ingress_id) { + INFO(" - 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. + * Also in case we have an intermediate node with just a less specific prefix + * (eg. a default route), and thus an announcement with 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 (before adding). + */ + forwarder_t *forwarder = mapme->forwarder; + + fib_t *fib = forwarder_get_fib(forwarder); + configuration_t *config = forwarder_get_configuration(forwarder); + + char prefix_s[MAXSZ_IP_PREFIX]; + int rc = hicn_prefix_snprintf(prefix_s, MAXSZ_IP_PREFIX, prefix); + assert(rc < MAXSZ_IP_PREFIX); + if (rc < 0) NULL; + + INFO("creating FIB entry for prefix %s", prefix_s); + + strategy_type_t strategy_type = configuration_get_strategy(config, prefix_s); + fib_entry_t *entry = fib_entry_create(prefix, strategy_type, NULL, forwarder); + mapme_create_tfib(mapme, entry); + + fib_entry_t *lpm = fib_match_prefix(fib, prefix); + + // Keep this after the LPM lookup + fib_add(fib, entry); + + if (!lpm) { + TFIB(entry)->seq = 0; + if (ingress_id != INVALID_FACE_ID) + fib_entry_nexthops_add(entry, ingress_id); + return entry; } - fibEntryList_Destroy(&fiblist); + /* + * 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 nexthops_t *lpm_nexthops = fib_entry_get_nexthops(lpm); + nexthops_foreach(lpm_nexthops, nh, { fib_entry_nexthops_add(entry, nh); }); + return entry; +} +#endif + +int mapme_on_timeout(void *mapme_arg, int fd, unsigned id, void *data) { + mapme_t *mapme = mapme_arg; + assert(mapme); + assert(id == 0); + 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; - INFO(mapme, "[MAP-Me] Done"); + for (uint8_t pos = 0; pos < CURLEN; pos++) { + mapme_retx_t *retx = &CUR[pos]; + + if (!retx->entry) /* deleted entry */ + continue; + + mapme_tfib_t *tfib = TFIB(retx->entry); + assert(tfib); + + /* 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 + */ + 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); + } + } + + /* 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 -#ifdef WITH_POLICY -void mapme_onPolicyUpdate(const MapMe *mapme, const Connection *conn_selected, FibEntry * fibEntry) -{ - /* Ignore local connections corresponding to applications for now */ - if (connection_IsLocal(conn_selected)) - return; + 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 - unsigned conn_selected_id = connection_GetConnectionId(conn_selected); - INFO(mapme, "[MAP-Me] New connection %d", conn_selected_id); + 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 + */ - const Name *name = fibEntry_GetPrefix(fibEntry); + /* + * 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. + */ - /* Skip entries that have no local connection as next hop */ - if (!mapme_hasLocalNextHops(mapme, fibEntry)) - return; + /* 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; - /* This entry corresponds to a locally served prefix, set - * Special Interest */ - if (!TFIB(fibEntry)) /* Create TFIB associated to FIB entry */ - mapme_CreateTFIB(fibEntry); - TFIB(fibEntry)->seq++; + 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. + */ - char *name_str = name_ToString(name); - INFO(mapme, "[MAP-Me] sending IU/IN for name %s on connection %d", name_str, - conn_selected_id); - free(name_str); + // XXX useless +#if 0 + /* Add ingress face as next hop */ + idle = 0; +#endif + break; - mapme_setFacePending(mapme, name, fibEntry, conn_selected_id, true, true, true, 0); + 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; + } } -#endif /* WITH_POLICY */ -#endif -/*------------------------------------------------------------------------------ - * Special Interest handling - *----------------------------------------------------------------------------*/ +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); -/** - * @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); + 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. + * We always ack, even duplicates. Clone mgsbuf to avoid to overwrite the + * received message */ - Message *ack = mapme_createAckMessage(mapme, msgBuffer, params); - if (!ack) goto ERR_ACK_CREATE; - rv = connection_ReSend(conn_in, ack, NOT_A_NOTIFICATION); - if (!rv) goto ERR_ACK_SEND; - message_Release(&ack); - - /* EPM on FIB */ - /* only the processor has access to the FIB */ - FIB *fib = forwarder_getFib(mapme->forwarder); + 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)) { + /* We accept the packet knowing we will get a retransmit */ + ERROR("Failed to send ACK packet"); + } - FibEntry *fibEntry = fib_Contains(fib, name); - 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; + msgbuf_pool_put(msgbuf_pool, ack); - /* - * 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. - */ -#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(fibEntry); - fib_Add(fib, fibEntry); - if (!lpm) { - TFIB(fibEntry)->seq = seq; - fibEntry_AddNexthop(fibEntry, conn_in_id); - return true; - } + WITH_INFO({ + char buf[MAXSZ_HICN_PREFIX]; + int rc = hicn_prefix_snprintf(buf, MAXSZ_HICN_PREFIX, prefix); + if (rc < 0 || rc >= MAXSZ_HICN_PREFIX) + snprintf(buf, MAXSZ_HICN_PREFIX, "%s", "(error)"); + INFO("Ack'ed interest : connection=%d prefix=%s seq=%d", ingress_id, buf, + params->seq); + }); - /* - * 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)); + /* EPM on FIB */ + const fib_t *fib = forwarder_get_fib(mapme->forwarder); + fib_entry_t *entry = fib_contains(fib, prefix); + if (!entry) { +#ifdef HICN_MAPME_ALLOW_NONEXISTING_FIB_ENTRY + entry = mapme_create_fib_entry(mapme, prefix, ingress_id); + if (!entry) { + 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(fibEntry); + mapme_tfib_t *tfib = TFIB(entry); + if (tfib == NULL) { + mapme_create_tfib(mapme, entry); + tfib = TFIB(entry); } /* @@ -725,108 +899,57 @@ 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 ? - 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)); - 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); - } + /* Initially we were detecting that the update completed when it returned to + * the producer, Because there might be proxies (using local/remote strategy), + * we need instead to verify if there is no non-local faces. + */ - /* 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); + if (fib_entry_has_all_local_nexthops(entry)) { + INFO("Received original interest... Update complete"); + return; + } - /* 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 + * This could might optimized for situations where nothing changes, but + * this is very unlikely if not impossible... */ - - INFO(mapme, "[MAP-Me] - (3/3) next hops ~~> prev hops"); - PARCEventTimer *oldTimer = - (PARCEventTimer *)mapmeTFIB_Get(TFIB(fibEntry), conn_in_id); - if (oldTimer) { - /* This happens if we receive an IU while we are still sending - * one in the other direction - */ - INFO(mapme, "[MAP-Me] - Canceled pending timer"); - parcEventTimer_Stop(oldTimer); - } - mapmeTFIB_Remove(TFIB(fibEntry), conn_in_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; + nexthops_t nexthops_keep = NEXTHOPS_EMPTY; + nexthops_foreach(&entry->nexthops, prevhop, { + const connection_t *conn = connection_table_get_by_id(table, prevhop); + /* Preserve local connections, migrate others to TFIB */ + if (connection_is_local(conn)) { + nexthops_add(&nexthops_keep, prevhop); + } else { + nexthops_add(&tfib->nexthops, prevhop); } + }); - 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; - } + nexthops_remove(&tfib->nexthops, ingress_id); - /* - * The update is completed when the IU could not be sent to any - * other next hop. - */ - if (complete) INFO(mapme, "[MAP-Me] - Update completed !"); + nexthops_clear(&entry->nexthops); + nexthops_add(&entry->nexthops, ingress_id); + nexthops_foreach(&nexthops_keep, nh, + { nexthops_add(&entry->nexthops, nh); }); - numberSet_Release(&nexthops); + event = MAPME_EVENT_NH_SET; - } else if (seq == fibSeq) { + // XXX tell things are complete if we have no IU to send + + } else if (params->seq == tfib->seq) { /* * Multipath, multihoming, multiple producers or duplicate interest * @@ -837,145 +960,77 @@ 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); + 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 { + INFO("Received seq %d < fib_seq %d, sending backwards on face %d", + params->seq, tfib->seq, ingress_id); + nexthops_add(&tfib->nexthops, ingress_id); + } + + event = MAPME_EVENT_PH_ADD; } - return true; + /* Don't trigger events for notification unless we need to send interests + * backwards */ + if ((params->type != UPDATE) && (event != MAPME_EVENT_PH_ADD)) return; -ERR_ACK_SEND: - message_Release(&ack); -ERR_ACK_CREATE: - return false; + mapme_on_event(mapme, event, entry, ingress_id); } -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); - - const 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); - - FIB *fib = forwarder_getFib(mapme->forwarder); - FibEntry *fibEntry = fib_Contains(fib, name); - if (!fibEntry) { +static void mapme_on_data(mapme_t *mapme, msgbuf_t *msgbuf, unsigned ingress_id, + hicn_prefix_t *prefix, mapme_params_t *params) { + WITH_INFO({ + char buf[MAXSZ_HICN_PREFIX]; + int rc = hicn_prefix_snprintf(buf, MAXSZ_HICN_PREFIX, prefix); + if (rc < 0 || rc >= MAXSZ_HICN_PREFIX) + snprintf(buf, MAXSZ_HICN_PREFIX, "(error)"); + INFO("Received ack for name prefix=%s seq=%d on conn id=%d", buf, + params->seq, ingress_id); + }) + + const fib_t *fib = forwarder_get_fib(mapme->forwarder); + fib_entry_t *entry = fib_contains(fib, prefix); + 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"); + if (params->seq < tfib->seq) { + INFO("Ignored ACK with seq %d < %d", params->seq, tfib->seq); 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 ?"); - return; - } - - /* Stop timer and remove entry from TFIB */ - parcEventTimer_Stop(timer); - mapmeTFIB_Remove(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(); } } @@ -990,25 +1045,70 @@ 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 + INFO("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; } } +#if 0 +/* + * 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; + } +} +#endif + +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..9ece8a090 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-2023 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -26,29 +26,34 @@ #include <stdbool.h> #include <stdint.h> +#include <hicn/ctrl/hicn-light.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" + +// Allow processing of MAP-Me requests when no FIB entry is present. +// An alternative would be to perform a LPM +#define HICN_MAPME_ALLOW_NONEXISTING_FIB_ENTRY + +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 +61,68 @@ 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. + * @param [in] prefix - A more specific prefix (special use with no retx), or + * NULL */ -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, const hicn_prefix_t *prefix); /** - * @function mapme_reconsiderFibEntry - * @abstract Process a fib entry for changes that might trigger new updates + * @function mapme_set_adjacencies + * @abstract sends an update to the specified adjacency. Used by control plane + * commands. * @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] nexthop - nexthop on which to send the update. + * @param [in] prefix - A more specific prefix (special use with no retx), or + * NULL */ -void mapme_reconsiderFibEntry(const MapMe *mapme, FibEntry * fibEntry); +int mapme_set_adjacency(const mapme_t *mapme, fib_entry_t *entry, + nexthop_t nexthop, const hicn_prefix_t *prefix); /** - * @function mapme_onConnectionEvent + * @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] 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 + */ +int mapme_update_adjacencies(const mapme_t *mapme, fib_entry_t *entry, + bool inc_iu_seq); + +/** + * @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 +130,27 @@ 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); - -MessagePacketType mapme_LibHicnPktType_To_PktType(hicn_mapme_type_t type); +// nexthops_t * mapme_get_nexthops(const mapme_t *mapme, fib_entry_t *fib_entry, +// const msgbuf_t *interest); + +#ifdef HICN_MAPME_ALLOW_NONEXISTING_FIB_ENTRY +fib_entry_t *mapme_create_fib_entry(const mapme_t *mapme, + const hicn_prefix_t *prefix, + unsigned ingress_id); +#endif /* HICN_MAPME_ALLOW_NONEXISTING_FIB_ENTRY */ + +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 5d0d04ae4..000000000 --- a/hicn-light/src/hicn/core/message.c +++ /dev/null @@ -1,298 +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, 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 deleted file mode 100644 index a8b2a3e54..000000000 --- a/hicn-light/src/hicn/core/messageHandler.h +++ /dev/null @@ -1,770 +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 messageHandler -#define messageHandler - -#include <stdlib.h> -#ifndef _WIN32 -#include <unistd.h> // close -#endif - -#include <hicn/hicn.h> -#include <hicn/core/messagePacketType.h> - -#define H(packet) ((hicn_header_t *)packet) -#define H6(packet) (H(packet)->v6.ip) -#define H6T(packet) (H(packet)->v6.tcp) -#define H4(packet) (H(packet)->v4.ip) -#define H4T(packet) (H(packet)->v4.tcp) - -#define HICN_V6_LEN(packet) (H6(packet).len) -#define HICN_V4_LEN(packet) (H4(packet).len) - -/*** codes and types ***/ -#define IPv6_TYPE 6 -#define IPv4_TYPE 4 -#define ICMP_WLDR_TYPE 42 -#define ICMP_WLDR_CODE 0 -#define ICMP_LB_TYPE 43 - -/*** masks and constants ***/ -#define PATH_LABEL_MASK 0x8000 // 1000 0000 0000 0000 -#define NOT_PATH_LABEL_MASK 0x7fff // 0111 0000 0000 0000 -#define UINT16_T_MASK 0x0000ffff // 1111 1111 1111 1111 - -/*** HICN ALLOWED PORTS ***/ -#define CONTROL_PORT 9695 -#define HTTP_PORT 8080 - -#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> - -#ifdef WITH_MAPME -#include <hicn/core/mapme.h> -#include <hicn/socket/api.h> -#endif /* WITH_MAPME */ - -#define CONNECTION_ID_UNDEFINED -1 - -#define BFD_PORT 3784 - -static inline uint8_t messageHandler_GetIPPacketType(const uint8_t *message) { - return HICN_IP_VERSION(message); -} - -static inline void messageHandler_UpdateTCPCheckSum(uint8_t *message, - uint16_t *old_val, - uint16_t *new_val, - uint8_t size) { - switch (messageHandler_GetIPPacketType(message)) { - case IPv4_TYPE: - for (uint8_t i = 0; i < size; i++) { - uint16_t old_csum = ~(H4T(message).csum); - uint16_t not_old_val = ~(*old_val); - uint32_t sum = (uint32_t)old_csum + not_old_val + *new_val; - - while (sum >> 16) { - sum = (sum >> 16) + (sum & UINT16_T_MASK); - } - - H4T(message).csum = ~sum; - ++old_val; - ++new_val; - } - break; - case IPv6_TYPE: - for (uint8_t i = 0; i < size; i++) { - uint16_t old_csum = ~(H6T(message).csum); - uint16_t not_old_val = ~(*old_val); - uint32_t sum = (uint32_t)old_csum + not_old_val + *new_val; - - while (sum >> 16) { - sum = (sum >> 16) + (sum & UINT16_T_MASK); - } - - H6T(message).csum = ~sum; - ++old_val; - ++new_val; - } - break; - default: - return; - } -} - -static inline void messageHandler_UpdateIPv4CheckSum(uint8_t *message, - uint16_t *old_val, - uint16_t *new_val, - uint8_t size) { - for (uint8_t i = 0; i < size; i++) { - uint16_t old_csum = ~(H4(message).csum); - uint16_t not_old_val = ~(*old_val); - uint32_t sum = (uint32_t)old_csum + not_old_val + *new_val; - - while (sum >> 16) { - sum = (sum >> 16) + (sum & UINT16_T_MASK); - } - - H4(message).csum = ~sum; - ++old_val; - ++new_val; - } -} - -static inline size_t messageHandler_GetEmptyTCPPacketSize(unsigned ipVersion) { - if (ipVersion == IPv4_TYPE) - return IPV4_HDRLEN + TCP_HDRLEN; - else if (ipVersion == IPv6_TYPE) - return IPV6_HDRLEN + TCP_HDRLEN; - else - return 0; -} - -static inline size_t messageHandler_GetICMPPacketSize(unsigned ipVersion) { - if (ipVersion == IPv4_TYPE) - return IPV4_HDRLEN + ICMP_HDRLEN; - else if (ipVersion == IPv6_TYPE) - return IPV6_HDRLEN + ICMP_HDRLEN; - else - return 0; -} - -static inline size_t messageHandler_GetIPHeaderLength(unsigned ipVersion) { - if (ipVersion == IPv4_TYPE) - return IPV4_HDRLEN; - else if (ipVersion == IPv6_TYPE) - return IPV6_HDRLEN; - else - return 0; -} - -static inline bool messageHandler_IsValidHicnPacket(const uint8_t *message) { - uint8_t version = messageHandler_GetIPPacketType(message); - if (version == IPv6_TYPE || version == IPv4_TYPE) { - return true; - } - return false; -} - -static inline uint8_t messageHandler_NextHeaderType(const uint8_t *message) { - switch (messageHandler_GetIPPacketType(message)) { - case IPv6_TYPE: - return (uint8_t)H6(message).nxt; - case IPv4_TYPE: - return (uint8_t)H4(message).protocol; - default: - return 0; - } -} - -/* 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 */ - - return true; -} - -static inline bool messageHandler_IsTCP(const uint8_t *message) { - if (messageHandler_NextHeaderType(message) != IPPROTO_TCP) return false; - return true; -} - -static inline bool messageHandler_IsInterest(const uint8_t *message) { - if (!messageHandler_IsTCP(message)) return false; - - bool flag; - hicn_packet_test_ece((hicn_header_t *)message, - &flag); // ECE flag is set to 0 in interest packets - if (flag == false) return true; - return false; -} - -static inline bool messageHandler_IsData(const uint8_t *message) { - if (!messageHandler_IsTCP(message)) return false; - - bool flag; - hicn_packet_test_ece((hicn_header_t *)message, - &flag); // ECE flag is set to 1 in data packets - if (flag == true) return true; - return false; -} - -static inline bool messageHandler_IsWldrNotification(const uint8_t *message) { - // this function returns true only if the packet is an ICMP packet in Wldr - // form. type must be equal to ICMP_WLDR_TYPE and code equal to ICMP_WLDR_CODE - uint8_t next_header = messageHandler_NextHeaderType(message); - - const uint8_t *icmp_ptr; - if (next_header == IPPROTO_ICMP) { - icmp_ptr = message + IPV4_HDRLEN; - } else if (next_header == IPPROTO_ICMPV6) { - icmp_ptr = message + IPV6_HDRLEN; - } else { - return false; - } - - uint8_t type = ((_icmp_header_t *)icmp_ptr)->type; - uint8_t code = ((_icmp_header_t *)icmp_ptr)->code; - if (type == ICMP_WLDR_TYPE && code == ICMP_WLDR_CODE) { - return true; - } - - return false; -} - -static inline bool messageHandler_IsLoadBalancerProbe(const uint8_t *message) { - uint8_t next_header = messageHandler_NextHeaderType(message); - - const uint8_t *icmp_ptr; - if (next_header == IPPROTO_ICMP) { - icmp_ptr = message + IPV4_HDRLEN; - } else if (next_header == IPPROTO_ICMPV6) { - icmp_ptr = message + IPV6_HDRLEN; - } else { - return false; - } - - uint8_t type = ((_icmp_header_t *)icmp_ptr)->type; - if (type == ICMP_LB_TYPE) { - return true; - } - - return false; -} - -static inline uint16_t messageHandler_GetTotalPacketLength( - const uint8_t *message) { - switch (messageHandler_GetIPPacketType(message)) { - case IPv6_TYPE: - return ntohs((uint16_t)HICN_V6_LEN(message)) + IPV6_HDRLEN; - case IPv4_TYPE: - return ntohs((uint16_t)HICN_V4_LEN(message)); - default: - return 0; - } -} - -static inline uint32_t messageHandler_GetSegment(const uint8_t *message) { - if (!messageHandler_IsTCP(message)) return 0; - - switch (messageHandler_GetIPPacketType(message)) { - case IPv6_TYPE: - return ntohl((uint32_t)H6T(message).seq); - case IPv4_TYPE: - return ntohl((uint32_t)H4T(message).seq); - default: - return 0; - } -} - -static inline uint16_t messageHandler_GetExpectedWldrLabel( - const uint8_t *message) { - const uint8_t *icmp_ptr; - switch (messageHandler_GetIPPacketType(message)) { - case IPv6_TYPE: - icmp_ptr = message + IPV6_HDRLEN; - break; - case IPv4_TYPE: - icmp_ptr = message + IPV4_HDRLEN; - break; - default: - return 0; - } - - return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->expected_lbl); -} - -static inline uint16_t messageHandler_GetWldrLastReceived( - const uint8_t *message) { - const uint8_t *icmp_ptr; - switch (messageHandler_GetIPPacketType(message)) { - case IPv6_TYPE: - icmp_ptr = message + IPV6_HDRLEN; - break; - case IPv4_TYPE: - icmp_ptr = message + IPV4_HDRLEN; - break; - default: - return 0; - } - - return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->received_lbl); -} - -static inline uint16_t messageHandler_GetWldrLabel(const uint8_t *message) { - switch (messageHandler_GetIPPacketType(message)) { - case IPv6_TYPE: - return ntohs((uint16_t)H6T(message).window); - case IPv4_TYPE: - return ntohs((uint16_t)H4T(message).window); - default: - return 0; - } -} - -static inline void messageHandler_SetWldrLabel(uint8_t *message, - uint16_t label) { - uint16_t old_val = messageHandler_GetWldrLabel(message); - - switch (messageHandler_GetIPPacketType(message)) { - case IPv6_TYPE: - H6T(message).window = htons(label); - break; - case IPv4_TYPE: - H4T(message).window = htons(label); - break; - default: - break; - } - - messageHandler_UpdateTCPCheckSum(message, &old_val, &label, 1); -} - -static inline void messageHandler_ResetWldrLabel(uint8_t *message) { - messageHandler_SetWldrLabel(message, 0); -} - -static inline bool messageHandler_HasWldr(const uint8_t *message) { - if (messageHandler_IsTCP(message)) { - uint16_t lbl = messageHandler_GetWldrLabel(message); - if (lbl != 0) { - return true; - } - } - return false; -} - -static inline uint32_t messageHandler_GetPathLabel(const uint8_t *message) { - if (!messageHandler_IsTCP(message)) return 0; - - uint32_t path_label; - int res = hicn_data_get_path_label((hicn_header_t *)message, &path_label); - if (res < 0) return 0; - return path_label; -} - -static inline void messageHandler_SetPathLabel(uint8_t *message, - uint32_t new_path_label) { - if (!messageHandler_IsTCP(message)) return; - - uint32_t old_path_label; - int res = hicn_data_get_path_label((hicn_header_t *)message, &old_path_label); - if (res < 0) return; - - hicn_data_set_path_label((hicn_header_t *)message, new_path_label); - - messageHandler_UpdateTCPCheckSum(message, (uint16_t *)&old_path_label, - (uint16_t *)&new_path_label, 2); -} - -static inline void messageHandler_UpdatePathLabel(uint8_t *message, - uint8_t outFace) { - if (!messageHandler_IsTCP(message)) return; - - uint32_t pl_old_32bit = messageHandler_GetPathLabel(message); - uint8_t pl_old_8bit = (uint8_t)(pl_old_32bit >> 24UL); - uint32_t pl_new_32bit = - (uint32_t)((((pl_old_8bit << 1) | (pl_old_8bit >> 7)) ^ outFace) << 24UL); - - hicn_data_set_path_label((hicn_header_t *)message, pl_new_32bit); - - messageHandler_UpdateTCPCheckSum(message, (uint16_t *)&pl_old_32bit, - (uint16_t *)&pl_new_32bit, 2); -} - -static inline void messageHandler_ResetPathLabel(uint8_t *message) { - if (!messageHandler_IsTCP(message)) return; - - uint32_t pl_old_32bit = messageHandler_GetPathLabel(message); - uint32_t pl_new_32bit = 0; - hicn_data_set_path_label((hicn_header_t *)message, pl_new_32bit); - messageHandler_UpdateTCPCheckSum(message, (uint16_t *)&pl_old_32bit, - (uint16_t *)&pl_new_32bit, 2); -} - -static inline uint16_t messageHandler_GetInterestLifetime( - const uint8_t *message) { - if (!messageHandler_IsTCP(message)) return 0; - - hicn_lifetime_t lifetime; - int res = hicn_interest_get_lifetime((hicn_header_t *)message, &lifetime); - if (res < 0) return 0; - return lifetime; -} - -static inline bool messageHandler_HasInterestLifetime(const uint8_t *message) { - if (!messageHandler_IsTCP(message)) return false; - - if (messageHandler_GetInterestLifetime(message) == 0) return false; - return true; -} - -static inline uint32_t messageHandler_GetContentExpiryTime( - const uint8_t *message) { - if (!messageHandler_IsTCP(message)) return 0; - - uint32_t expirationTime; - int res = - hicn_data_get_expiry_time((hicn_header_t *)message, &expirationTime); - if (res < 0) return 0; - return expirationTime; -} - -static inline bool messageHandler_HasContentExpiryTime(const uint8_t *message) { - if (!messageHandler_IsTCP(message)) return 0; - - uint32_t expirationTime; - int res = - hicn_data_get_expiry_time((hicn_header_t *)message, &expirationTime); - if (res < 0) return false; - - if (expirationTime == HICN_MAX_LIFETIME) return false; - - return true; -} - -static inline void *messageHandler_GetSource(const uint8_t *message) { - switch (messageHandler_GetIPPacketType(message)) { - case IPv6_TYPE: - return &H6(message).saddr; - break; - case IPv4_TYPE: - return &H4(message).saddr; - break; - default: - return NULL; - } -} - -static inline void *messageHandler_GetDestination(const uint8_t *message) { - switch (messageHandler_GetIPPacketType(message)) { - case IPv6_TYPE: - return &H6(message).daddr; - break; - case IPv4_TYPE: - return &H4(message).daddr; - break; - default: - return NULL; - } -} - -static inline void messageHandler_SetSource_IPv6(uint8_t *message, - struct in6_addr *address) { - if (messageHandler_IsTCP(message)) { - uint16_t *old_src = (uint16_t *)messageHandler_GetSource(message); - messageHandler_UpdateTCPCheckSum(message, old_src, (uint16_t *)address, 8); - } - H6(message).saddr.as_in6addr = *address; -} - -static inline void messageHandler_SetDestination_IPv6( - uint8_t *message, struct in6_addr *address) { - if (messageHandler_IsTCP(message)) { - uint16_t *old_dst = (uint16_t *)messageHandler_GetDestination(message); - messageHandler_UpdateTCPCheckSum(message, old_dst, (uint16_t *)address, 8); - } - H6(message).daddr.as_in6addr = *address; -} - -static inline void messageHandler_SetSource_IPv4(uint8_t *message, - uint32_t *address) { - // update tcp checksum - uint16_t *old_src = (uint16_t *)messageHandler_GetSource(message); - if (messageHandler_IsTCP(message)) { - messageHandler_UpdateTCPCheckSum(message, old_src, (uint16_t *)address, 2); - } - // update IPv4 cheksum - // the IPv4 checksum is not part of the psudo header for TCP checksum - // calculation we can update them separetelly - messageHandler_UpdateIPv4CheckSum(message, old_src, (uint16_t *)address, 2); - - H4(message).saddr.as_u32 = *address; -} - -static inline void messageHandler_SetDestination_IPv4(uint8_t *message, - uint32_t *address) { - uint16_t *old_dst = (uint16_t *)messageHandler_GetDestination(message); - if (messageHandler_IsTCP(message)) { - messageHandler_UpdateTCPCheckSum(message, old_dst, (uint16_t *)address, 2); - } - messageHandler_UpdateIPv4CheckSum(message, old_dst, (uint16_t *)address, 2); - H4(message).daddr.as_u32 = *address; -} - -static inline void messageHandler_SetWldrNotification(uint8_t *notification, - uint8_t *original, - uint16_t expected, - uint16_t received) { - hicn_header_t *h = (hicn_header_t *)notification; - switch (messageHandler_GetIPPacketType(original)) { - case IPv6_TYPE: { - *h = (hicn_header_t){.v6 = { - .ip = - { - .version_class_flow = htonl( - (IPV6_DEFAULT_VERSION << 28) | - (IPV6_DEFAULT_TRAFFIC_CLASS << 20) | - (IPV6_DEFAULT_FLOW_LABEL & 0xfffff)), - .len = htons(ICMP_HDRLEN), - .nxt = IPPROTO_ICMPV6, - .hlim = 5, - }, - .wldr = - { - .type = ICMP_WLDR_TYPE, - .code = ICMP_WLDR_CODE, - .expected_lbl = htons(expected), - .received_lbl = htons(received), - }, - }}; - messageHandler_SetSource_IPv6( - notification, - (struct in6_addr *)messageHandler_GetDestination(original)); - messageHandler_SetDestination_IPv6( - notification, (struct in6_addr *)messageHandler_GetSource(original)); - break; - } - case IPv4_TYPE: { - break; - } - default: - break; - } -} - -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); - - hicn_packet_init_header(format, (hicn_header_t *) pkt); - - hicn_packet_set_dst_port((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){ - - hicn_name_t 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); - - uint16_t src_prt; - uint16_t dst_prt; - hicn_packet_get_src_port((const hicn_header_t *) probe, &src_prt); - hicn_packet_get_dst_port((const hicn_header_t *) probe, &dst_prt); - hicn_packet_set_src_port((hicn_header_t *) probe, dst_prt); - hicn_packet_set_dst_port((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); -} - -static inline hicn_name_t * messageHandler_CreateProbeName(const ip_prefix_t *address){ - hicn_name_t * name = parcMemory_AllocateAndClear(sizeof(hicn_name_t)); - 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 bool messageHandler_IsAProbe(const uint8_t *packet){ - uint16_t src_prt; - uint16_t dst_prt; - hicn_packet_get_src_port ((const hicn_header_t *) packet, &src_prt); - hicn_packet_get_dst_port ((const hicn_header_t *) packet, &dst_prt); - - if(dst_prt == BFD_PORT){ - //interest probe - return true; - } - - if(src_prt == BFD_PORT){ - //data (could be a probe) - uint32_t expiry_time; - hicn_data_get_expiry_time ((const hicn_header_t *) packet, &expiry_time); - if(expiry_time == 0){ - //this is a probe - return true; - } - } - - return false; -} - -#endif // Metis_metis_MessageHandler 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/core/msgbuf.c b/hicn-light/src/hicn/core/msgbuf.c new file mode 100644 index 000000000..c58f7a7dc --- /dev/null +++ b/hicn-light/src/hicn/core/msgbuf.c @@ -0,0 +1,55 @@ +/* + * 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. + */ + +/** + * \file msgbuf.c + * \brief Implementation hICN message buffer + */ + +#include "msgbuf.h" +#include "../strategies/probe_generator.h" + +int msgbuf_initialize(msgbuf_t *msgbuf) { + /* + * We define the format and the storage area of the packet buffer we + * manipulate + */ + hicn_packet_buffer_t *pkbuf = msgbuf_get_pkbuf(msgbuf); + hicn_packet_set_buffer(pkbuf, msgbuf->packet, MTU, 0); + hicn_packet_init_header(pkbuf, 0); + return 0; +} + +int msgbuf_initialize_from_packet(msgbuf_t *msgbuf) { + hicn_packet_set_buffer(msgbuf_get_pkbuf(msgbuf), msgbuf->packet, MTU, + msgbuf_get_len(msgbuf)); + return 0; +} + +bool msgbuf_is_command(const msgbuf_t *msgbuf) { + return (*msgbuf->packet == REQUEST_LIGHT); +} + +bool msgbuf_is_probe(const msgbuf_t *msgbuf) { + hicn_name_t name; + hicn_name_suffix_t suffix; + + assert(msgbuf_get_type(msgbuf) == HICN_PACKET_TYPE_DATA); + + const hicn_packet_buffer_t *pkbuf = msgbuf_get_pkbuf(msgbuf); + hicn_data_get_name(pkbuf, &name); + suffix = hicn_name_get_suffix(&name); + return (suffix >= MIN_PROBE_SUFFIX && suffix <= MAX_PROBE_SUFFIX); +} diff --git a/hicn-light/src/hicn/core/msgbuf.h b/hicn-light/src/hicn/core/msgbuf.h new file mode 100644 index 000000000..7a35929f4 --- /dev/null +++ b/hicn-light/src/hicn/core/msgbuf.h @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2021-2023 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file msgbuf.h + * \brief hICN message buffer + */ + +#ifndef HICNLIGHT_MSGBUF +#define HICNLIGHT_MSGBUF + +#include <hicn/name.h> +#include "ticks.h" +#include <hicn/hicn.h> +#include <hicn/ctrl/hicn-light.h> + +#define MTU 1500 +#define INVALID_MSGBUF_ID ~0ul + +#define msgbuf_id_is_valid(msgbuf_id) \ + ((unsigned long)msgbuf_id != INVALID_MSGBUF_ID) + +typedef struct { + hicn_packet_buffer_t pkbuf; + unsigned connection_id; // ingress + Ticks recv_ts; // timestamp + unsigned refs; // refcount + unsigned path_label; // original path label of the received message. used + // as a base for the path label computation when the + // same data packet needs to be forwarded on multiple + // face. + + // XXX Cache storage + union { + /* Interest or data packet */ + struct { + hicn_name_t name; + u32 name_hash; // XXX should be always populate when name is assigned + } id; + /* Command packet */ + struct { + command_type_t type; + } command; + }; + uint8_t packet[MTU]; +} msgbuf_t; + +int msgbuf_initialize(msgbuf_t *msgbuf); +int msgbuf_initialize_from_packet(msgbuf_t *msgbuf); + +#define msgbuf_get_pkbuf(M) (&(M)->pkbuf) + +static inline hicn_packet_type_t msgbuf_get_type(const msgbuf_t *msgbuf) { + return hicn_packet_get_type(msgbuf_get_pkbuf(msgbuf)); +} + +static inline void msgbuf_set_type(msgbuf_t *msgbuf, hicn_packet_type_t type) { + hicn_packet_set_type(msgbuf_get_pkbuf(msgbuf), type); +} + +static inline const hicn_name_t *msgbuf_get_name(const msgbuf_t *msgbuf) { + hicn_packet_type_t type = msgbuf_get_type(msgbuf); + assert(type == HICN_PACKET_TYPE_INTEREST || type == HICN_PACKET_TYPE_DATA); + (void)type; + + return &msgbuf->id.name; +} + +#define msgbuf_get_connection_id(M) ((M)->connection_id) +#define msgbuf_set_connection_id(M, ID) (M)->connection_id = (ID) +#define msgbuf_get_packet(M) ((M)->packet) +#define msgbuf_get_command_type(M) ((M)->command.type) +#if WITH_WLDR +#define msgbuf_has_wldr(M) (messageHandler_HasWldr((M)->packet)) +#endif + +static inline void msgbuf_set_name(msgbuf_t *msgbuf, const hicn_name_t *name) { + msgbuf->id.name = *name; +} + +static inline size_t msgbuf_get_len(const msgbuf_t *msgbuf) { + return hicn_packet_get_len(msgbuf_get_pkbuf(msgbuf)); +} + +static inline void msgbuf_set_len(msgbuf_t *msgbuf, size_t len) { + int rc = hicn_packet_set_len(msgbuf_get_pkbuf(msgbuf), len); + assert(rc == HICN_LIB_ERROR_NONE); // XXX + _unused(rc); +} + +static inline u32 msgbuf_get_name_hash(const msgbuf_t *msgbuf) { + hicn_packet_type_t type = msgbuf_get_type(msgbuf); + assert(type == HICN_PACKET_TYPE_INTEREST || type == HICN_PACKET_TYPE_DATA); + _unused(type); + return msgbuf->id.name_hash; +} + +// Lifetimes/expiry times in milliseconds +static inline u32 msgbuf_get_interest_lifetime(const msgbuf_t *msgbuf) { + u32 lifetime; + int rc = hicn_interest_get_lifetime(msgbuf_get_pkbuf(msgbuf), &lifetime); + if (rc != HICN_LIB_ERROR_NONE) return 0; + return lifetime; +} + +//#define msgbuf_get_lifetime(M) +// (NSEC_TO_TICKS(messageHandler_GetInterestLifetime((M)->packet) * +// 1000000ULL)) +#define msgbuf_get_lifetime msgbuf_get_interest_lifetime + +static inline bool msgbuf_set_interest_lifetime(msgbuf_t *msgbuf, + u32 lifetime) { + int rc = hicn_interest_set_lifetime(msgbuf_get_pkbuf(msgbuf), lifetime); + return (rc == HICN_LIB_ERROR_NONE); +} + +static inline u32 msgbuf_get_data_expiry_time(const msgbuf_t *msgbuf) { + u32 lifetime; + int rc = hicn_data_get_expiry_time(msgbuf_get_pkbuf(msgbuf), &lifetime); + if (rc != HICN_LIB_ERROR_NONE) return 0; + return lifetime; +} + +static inline bool msgbuf_set_data_expiry_time(msgbuf_t *msgbuf, u32 lifetime) { + int rc = hicn_data_set_expiry_time(msgbuf_get_pkbuf(msgbuf), lifetime); + return (rc == HICN_LIB_ERROR_NONE); +} + +/* Path label */ + +static inline void msgbuf_init_pathlabel(msgbuf_t *msgbuf) { + hicn_path_label_t pl; + int rc = hicn_data_get_path_label(msgbuf_get_pkbuf(msgbuf), &pl); + assert(rc == HICN_LIB_ERROR_NONE); + _unused(rc); + msgbuf->path_label = pl; +} + +static inline int msgbuf_get_path_label(const msgbuf_t *msgbuf, + hicn_path_label_t *pl) { + assert(msgbuf_get_type(msgbuf) == HICN_PACKET_TYPE_DATA); + return hicn_data_get_path_label(msgbuf_get_pkbuf(msgbuf), pl); +} + +static inline int msgbuf_set_path_label(msgbuf_t *msgbuf, + hicn_path_label_t pl) { + assert(msgbuf_get_type(msgbuf) == HICN_PACKET_TYPE_DATA); + return hicn_data_set_path_label(msgbuf_get_pkbuf(msgbuf), pl); +} + +static inline int msgbuf_update_pathlabel(msgbuf_t *msgbuf, + hicn_faceid_t outface) { + assert(msgbuf_get_type(msgbuf) == HICN_PACKET_TYPE_DATA); + + hicn_path_label_t pl, newpl; + if (msgbuf_get_path_label(msgbuf, &pl) < 0) return -1; + + update_path_label(pl, outface, &newpl); + + return msgbuf_set_path_label(msgbuf, newpl); +} + +static inline void msgbuf_reset_pathlabel(msgbuf_t *msgbuf) { + msgbuf->path_label = 0; + hicn_data_set_path_label(msgbuf_get_pkbuf(msgbuf), 0); + // ERROR ? +} + +static inline void msgbuf_modify_suffix(msgbuf_t *msgbuf, uint32_t new_suffix) { + hicn_name_t name; + assert(msgbuf_get_type(msgbuf) == HICN_PACKET_TYPE_INTEREST); + hicn_interest_get_name(msgbuf_get_pkbuf(msgbuf), &name); + hicn_name_set_suffix(&name, new_suffix); + hicn_interest_set_name(msgbuf_get_pkbuf(msgbuf), &name); +} + +bool msgbuf_is_command(const msgbuf_t *msgbuf); +bool msgbuf_is_probe(const msgbuf_t *msgbuf); + +/* WLDR */ + +#if 0 +#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 + +#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..892bd59a1 --- /dev/null +++ b/hicn-light/src/hicn/core/msgbuf_pool.c @@ -0,0 +1,123 @@ +/* + * 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. + */ + +/** + * @file msgbuf_pool.c + * @brief Implementation of hICN packet pool. + */ + +#include <hicn/util/pool.h> +#include <hicn/util/log.h> +#include "msgbuf_pool.h" + +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) { + off_t id = pool_get(msgbuf_pool->buffers, *msgbuf); + (*msgbuf)->refs = 0; + return id; +} + +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_get_type(msgbuf) != HICN_PACKET_TYPE_INTEREST && + msgbuf_get_type(msgbuf) != HICN_PACKET_TYPE_DATA) { + TRACE("Msgbuf %d (%p) - put to msgbuf pool", msgbuf_id, msgbuf); + } else { + char buf[MAXSZ_HICN_NAME]; + int rc = + hicn_name_snprintf(buf, MAXSZ_HICN_NAME, msgbuf_get_name(msgbuf)); + if (rc < 0 || rc >= MAXSZ_HICN_NAME) + snprintf(buf, MAXSZ_HICN_NAME, "%s", "(error)"); + const char *msgbuf_type_str = + msgbuf_get_type(msgbuf) == HICN_PACKET_TYPE_INTEREST ? "interest" + : "data"; + TRACE("Msgbuf %d (%p) - %s (%s) put to msgbuf pool", msgbuf_id, msgbuf, + buf, msgbuf_type_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 deleted file mode 100644 index 805e7bfae..000000000 --- a/hicn-light/src/hicn/core/name.c +++ /dev/null @@ -1,263 +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 <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/core/messageHandler.h> -#include <hicn/core/name.h> - -#include <parc/algol/parc_Hash.h> - -#include <parc/assert/parc_Assert.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"); - - uint32_t hash1 = nameBitvector_GetHash32(name->content_name); - return parcHash32_Data_Cumulative((const uint8_t *)&name->segment, 4, 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)); - - 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; - } - } 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; - } - } else { - printf("Error: unknown message type\n"); - parcMemory_Deallocate((void **)&name); - return NULL; - } - - 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); - } else { - parcTrapNotImplemented("Unkown packet type"); - } - - name->segment = 0; - 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)); - } - 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 *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)); - - copy->content_name = nameBitvector_Copy(original->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"); - return name->name_hash; -} - -NameBitvector *name_GetContentName(const Name *name) { - parcAssertNotNull(name, "Parameter must be non-null"); - return 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"); - - /* BEGIN: Workaround for HICN-400 */ - if ((!a->content_name) || (!b->content_name)) - return false; - /* END: Workaround for HICN-400 */ - - 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"); - - if (a == NULL && b == NULL) { - return 0; - } - if (a == NULL) { - return -1; - } - if (b == NULL) { - return +1; - } - - int res = nameBitvector_Compare(a->content_name, b->content_name); - - if (res != 0) { - return res; - } else { - if (a->segment < b->segment) { - return -1; - } else if (a->segment > b->segment) { - return +1; - } else { - return 0; - } - } -} - -char *name_ToString(const Name *name) { - char *output = malloc(128); - - Address *packetAddr = nameBitvector_ToAddress(name_GetContentName(name)); - - sprintf(output, "name: %s seq: %u", addressToString(packetAddr), - name->segment); - - addressDestroy(&packetAddr); - - return output; -} - -void name_setLen(Name *name, uint8_t 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; -} - -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 deleted file mode 100644 index db9438150..000000000 --- a/hicn-light/src/hicn/core/name.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. - */ - -#ifndef name_h -#define name_h - -#include <stdbool.h> -#include <stdlib.h> - -#include <hicn/core/messagePacketType.h> -#include <hicn/core/nameBitvector.h> -#include <hicn/utils/address.h> - -#include <hicn/utils/commands.h> - -struct name; -typedef struct name Name; - -/** - * Creates a name from packet - * - */ -Name *name_CreateFromPacket(const uint8_t *memory, MessagePacketType type); - -/** - * Releases one reference count, and frees memory after last reference - */ -void name_Release(Name **namePtr); - -/** - * 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. - */ -Name *name_Acquire(const Name *original); - -/** - * returns a copy of the name - */ -Name *name_Copy(const Name *original); - -/** - * A hash value for use in hash tables - * - */ -uint32_t name_HashCode(const Name *name); - -/** - * Returns the content name without the segment value - * - */ -NameBitvector *name_GetContentName(const Name *name); - -/** - * Determine if two HicnName instances are equal. - */ -bool name_Equals(const Name *a, const Name *b); - -/** - * Compares two names and returns their ordering - * - */ -int name_Compare(const Name *a, const Name *b); - -/** - * return the name in string format (bitvector + segment number) - * - */ -char *name_ToString(const Name *name); - -/** - * @function message_setNameLen - * @abstract Sets a message name length - * @param [in] message - Interest message - * @param [in] len - Name length - */ -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); - -#ifdef WITH_POLICY -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 deleted file mode 100644 index 6ad623b14..000000000 --- a/hicn-light/src/hicn/core/nameBitvector.c +++ /dev/null @@ -1,362 +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 <stdint.h> -#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> - -#define NAME_LEN 2 - -const uint64_t BV_SIZE = 64; -const uint64_t WIDTH = 128; -const uint64_t ONE = 0x1; - -// address b000:0000:0000:0001:c000:0000:0000:0001 is encodend as follow -// [bits[0] uint64_t ] [bits[1] unit64_t ] -// ^ ^ ^ ^ -// 63 0 127 64 -// [1000 0000 ... 0000 1101] [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)); - - bitvector->bits[0] = 0; - bitvector->bits[1] = 0; - - uint8_t addr_1 = (addr & 0xff000000) >> 24; - uint8_t addr_2 = (addr & 0x00ff0000) >> 16; - uint8_t addr_3 = (addr & 0x0000ff00) >> 8; - uint8_t addr_4 = (addr & 0x000000ff); - - bitvector->bits[0] = (bitvector->bits[0] | addr_4) << 8; - bitvector->bits[0] = (bitvector->bits[0] | addr_3) << 8; - bitvector->bits[0] = (bitvector->bits[0] | addr_2) << 8; - bitvector->bits[0] = (bitvector->bits[0] | addr_1); - bitvector->bits[0] = bitvector->bits[0] << 32; - - 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)); - - bitvector->bits[0] = 0; - bitvector->bits[1] = 0; - - for (int i = 0; i < 8; ++i) { - bitvector->bits[0] = (bitvector->bits[0] << 8) | addr->s6_addr[i]; - } - - for (int i = 8; i < 16; ++i) { - bitvector->bits[1] = (bitvector->bits[1] << 8) | addr->s6_addr[i]; - } - - 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)); - - 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; -} - -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); -} - -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; - return false; -} - -int nameBitvector_Compare(const NameBitvector *a, const NameBitvector *b) { - if (a == NULL && b == NULL) { - return 0; - } - if (a == NULL) { - return -1; - } - if (b == NULL) { - return +1; - } - - if (a->bits[0] < b->bits[0]) { - return -1; - } else if (a->bits[0] > b->bits[0]) { - return +1; - } else if (a->bits[1] < b->bits[1]) { - return -1; - } else if (a->bits[1] > b->bits[1]) { - return +1; - } else if (a->len < b->len) { - return -1; - } else if (a->len > b->len) { - return +1; - } else { - return 0; - } -} - -int nameBitvector_testBit(const NameBitvector *name, uint8_t pos, bool *bit) { - if(pos >= name->len || pos > (WIDTH -1)) - return -1; - - *bit = (name->bits[pos / BV_SIZE] & (ONE << ((BV_SIZE - 1) - (pos % BV_SIZE)))); - - return 0; -} - -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) - uint64_t result = 0; - - if (val & 0xFFFFFFFF00000000) { - val = val >> 32; - result = result | 32; - } - if (val & 0xFFFF0000) { - val = val >> 16; - result = result | 16; - } - if (val & 0xFF00) { - val = val >> 8; - result = result | 8; - } - if (val & 0xF0) { - val = val >> 4; - result = result | 4; - } - if (val & 0xC) { - val = val >> 2; - result = result | 2; - } - if (val & 0x2) { - val = val >> 1; - result = result | 1; - } - return result; -} - -uint32_t nameBitvector_lpm(const NameBitvector *a, - const NameBitvector *b) { - uint32_t limit; - uint32_t prefix_len; - if (a->len < b->len) - limit = a->len; - else - limit = b->len; - - uint64_t diff = a->bits[0] ^ b->bits[0]; - 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 = BV_SIZE; - diff = a->bits[1] ^ b->bits[1]; - 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; - 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))); -} - -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; - prefix->len = IPV4_ADDR_LEN_BITS; - - uint32_t tmp_addr = name->bits[0] >> 32ULL; - uint8_t addr_1 = (tmp_addr & 0xff000000) >> 24; - uint8_t addr_2 = (tmp_addr & 0x00ff0000) >> 16; - uint8_t addr_3 = (tmp_addr & 0x0000ff00) >> 8; - uint8_t addr_4 = (tmp_addr & 0x000000ff); - - addr->s_addr = 0; - addr->s_addr = (addr->s_addr | addr_4) << 8; - addr->s_addr = (addr->s_addr | addr_3) << 8; - addr->s_addr = (addr->s_addr | addr_2) << 8; - addr->s_addr = (addr->s_addr | addr_1); - - } else { - struct in6_addr *addr = (struct in6_addr *)(&prefix->address.v6.buffer); - prefix->family = AF_INET6; - prefix->len = name->len; // IPV6_ADDR_LEN_BITS; - - for (int i = 0; i < 8; i++) { - addr->s6_addr[i] = (uint8_t)((name->bits[0] >> 8 * (7 - i)) & 0xFF); - } - - int x = 0; - for (int i = 8; i < 16; ++i) { - addr->s6_addr[i] = (uint8_t)((name->bits[1] >> 8 * (7 - x)) & 0xFF); - x++; - } - } - return true; -} - -void nameBitvector_setLen(NameBitvector *name, uint8_t len) { name->len = len; } - -Address *nameBitvector_ToAddress(const NameBitvector *name) { - if (name->IPversion == IPv4_TYPE) { - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(1234); - - uint32_t tmp_addr = name->bits[0] >> 32ULL; - uint8_t addr_1 = (tmp_addr & 0xff000000) >> 24; - uint8_t addr_2 = (tmp_addr & 0x00ff0000) >> 16; - 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; - - } else { - struct sockaddr_in6 addr; - addr.sin6_family = AF_INET6; - addr.sin6_port = htons(1234); - addr.sin6_scope_id = 0; - addr.sin6_flowinfo = 0; - - for (int i = 0; i < 8; i++) { - addr.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] = - (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); - - sprintf(output, "prefix: %s len: %u", addressToString(packetAddr), name->len); - - addressDestroy(&packetAddr); - - return output; -} diff --git a/hicn-light/src/hicn/core/nameBitvector.h b/hicn-light/src/hicn/core/nameBitvector.h deleted file mode 100644 index 19944778c..000000000 --- a/hicn-light/src/hicn/core/nameBitvector.h +++ /dev/null @@ -1,58 +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 name_bitvector_h -#define name_bitvector_h - -#include <hicn/hicn.h> -#include <stdint.h> -#include <stdlib.h> - -#include <hicn/utils/address.h> - -struct name_bitvector; -typedef struct name_bitvector NameBitvector; - -NameBitvector *nameBitvector_CreateFromInAddr(uint32_t addr, uint8_t len); - -NameBitvector *nameBitvector_CreateFromIn6Addr(struct in6_addr *addr, - uint8_t len); - -NameBitvector *nameBitvector_Copy(const NameBitvector *original); - -void nameBitvector_Destroy(NameBitvector **bitvectorPtr); - -uint8_t nameBitvector_GetLength(const NameBitvector *name); - -uint32_t nameBitvector_GetHash32(const NameBitvector *name); - -bool nameBitvector_Equals(const NameBitvector *a, const NameBitvector *b); - -int nameBitvector_Compare(const NameBitvector *a, const NameBitvector *b); - -int nameBitvector_testBit(const NameBitvector *name, uint8_t pos, bool *bit); - -uint32_t nameBitvector_lpm(const NameBitvector *a, const NameBitvector *b); - -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); - -char *nameBitvector_ToString(const NameBitvector *name); - -#endif // name_bitvector_h diff --git a/hicn-light/src/hicn/core/nexthops.c b/hicn-light/src/hicn/core/nexthops.c new file mode 100644 index 000000000..1a6096777 --- /dev/null +++ b/hicn-light/src/hicn/core/nexthops.c @@ -0,0 +1,155 @@ +/* + * 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. + */ + +/** + * \file nexthops.c + * \brief Nexthops implementation + */ + +#include <hicn/util/hash.h> + +#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; +} + +int nexthops_disable_all(nexthops_t *nexthops) { + nexthops->flags = ~0; + nexthops->cur_elts = 0; + 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; + 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) { + 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) { + nexthops_foreach(nexthops, n, { + if (n == nexthop) return true; + }); + return false; +} + +off_t nexthops_find(nexthops_t *nexthops, unsigned nexthop) { + nexthops_enumerate(nexthops, i, n, { + if (n == nexthop) return i; + }); + return INVALID_NEXTHOP; +} + +unsigned nexthops_get_one(nexthops_t *nexthops) { + 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) { + 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) { + nexthops_enumerate(nexthops, i, nh, { + (void)nh; + nexthops_reset_priority(nexthops, i); + }); +} + +bool nexthops_equal(nexthops_t *a, nexthops_t *b) { + 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; +} + +/* Adapted from Jenkins hash (commutative) */ +uint32_t nexthops_get_hash(nexthops_t *nexthops) { + uint32_t hash = 0; + + nexthops_foreach(nexthops, nh, { + hash += nh; + hash += hash << 10; + hash ^= hash >> 6; + }); + hash += hash << 3; + hash ^= hash >> 11; + hash += hash << 15; + return hash; +} + +#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..232c74388 --- /dev/null +++ b/hicn-light/src/hicn/core/nexthops.h @@ -0,0 +1,182 @@ +/* + * 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. + */ + +/** + * \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); +int nexthops_disable_all(nexthops_t *nexthops); + +#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 { \ + nexthop_t X; \ + (void)X; \ + unsigned I; \ + (void)I; \ + 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 { \ + 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 */ + +uint32_t nexthops_get_hash(nexthops_t *nexthops); + +#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..937b0480b --- /dev/null +++ b/hicn-light/src/hicn/core/packet_cache.c @@ -0,0 +1,884 @@ +/* + * 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. + */ + +/** + * \file packet_cache.c + * \brief Implementation of hICN packet cache + * + * _get_suffixes : first level lookup to return the suffixes + * + * _remove_suffix : Remove suffix from the two level packet cache structure + * + * __add_suffix : Add a packet cache entry in the second level of the + * two-level data structure _add_suffix : Add a packet cache entry in the both + * the first and second level of the two-level data tructure (helper) + * + * __get_suffix : Lookup in the second level of the packet cache + * + * _get_suffix : Lookup in both the first and second levels of the packet cache + * + * ---- + * + * pkt_cache_save_suffixes_for_prefix : always done at packet reception to keep + * the latest suffixes + * + * pkt_cache_reset_suffixes_for_prefix + * + * ---- + * + * pkt_cache_allocate + * + * pkt_cache_add_to_index + * + * pkt_cache_remove_from_index + * + * pkt_cache_pit_remove_entry + * + * pkt_cache_cs_remove_entry + * + * pkt_cache_add_to_pit + * pkt_cache_add_to_cs + * + * _pkt_cache_add_to_pit + * used by pkt_cache_add_to_pit + * plt_cache_update_pit + * _pkt_cache_add_to_cs + * + * pkt_cache_pit_to_cs + * pkt_cache_cs_to_pit + * + * pkt_cache_update_pit : when an interest expired + * pkt_cache_update_cs + * + * pkt_cache_try_aggregate_in_pit + * + * + * + */ + +#include <hicn/core/forwarder.h> +#include "packet_cache.h" + +const char *_pkt_cache_verdict_str[] = { +#define _(x) [PKT_CACHE_VERDICT_##x] = #x, + foreach_kh_verdict +#undef _ +}; + +/****************************************************************************** + * Low-level operations on the hash table + ******************************************************************************/ + +/** + * Free the two level packet cache structure (helper) + */ +void _prefix_map_free(kh_pkt_cache_prefix_t *prefix_to_suffixes) { + kh_pkt_cache_suffix_t *suffix; + kh_foreach_value(prefix_to_suffixes, suffix, + { kh_destroy_pkt_cache_suffix(suffix); }); + kh_destroy_pkt_cache_prefix(prefix_to_suffixes); +} + +/** + * Perform the first level lookup to return the suffixes (helper) + */ +kh_pkt_cache_suffix_t *_get_suffixes(kh_pkt_cache_prefix_t *prefix_to_suffixes, + const hicn_name_prefix_t *prefix, + bool create, slab_t *prefix_keys) { + khiter_t k = kh_get_pkt_cache_prefix(prefix_to_suffixes, prefix); + + /* Return suffixes if found... */ + if (k != kh_end(prefix_to_suffixes)) { + kh_pkt_cache_suffix_t *suffixes = kh_val(prefix_to_suffixes, k); + return suffixes; + } + + if (!create) return NULL; + + /* ... otherwise populate the first level and return the newly added entry. + */ + kh_pkt_cache_suffix_t *suffixes = kh_init_pkt_cache_suffix(); + + hicn_name_prefix_t *prefix_copy = slab_get(hicn_name_prefix_t, prefix_keys); + memcpy(prefix_copy, prefix, sizeof(hicn_name_prefix_t)); + + int rc; + k = kh_put_pkt_cache_prefix(prefix_to_suffixes, prefix_copy, &rc); + assert(rc == KH_ADDED || rc == KH_RESET); + kh_value(prefix_to_suffixes, k) = suffixes; + return suffixes; +} + +/** + * Remove suffix from the two level packet cache structure (helper) + */ +void _remove_suffix(kh_pkt_cache_prefix_t *prefixes, + const hicn_name_prefix_t *prefix, + const hicn_name_suffix_t suffix, slab_t *prefix_keys) { + kh_pkt_cache_suffix_t *suffixes = + _get_suffixes(prefixes, prefix, false, prefix_keys); + assert(suffixes != NULL); + + khiter_t k = kh_get_pkt_cache_suffix(suffixes, suffix); + assert(k != kh_end(suffixes)); + kh_del_pkt_cache_suffix(suffixes, k); + + // TODO(eloparco): Remove prefix if no associated suffixes? +} + +/** + * Add a packet cache entry in the second level of the two-level data structure + * (helper) + */ +void __add_suffix(kh_pkt_cache_suffix_t *suffixes, hicn_name_suffix_t suffix, + unsigned val) { + // INFO("suffix add suffixes=%p suffix=%d val=%d", suffixes, suffix, val); + int rc; + khiter_t k = kh_put_pkt_cache_suffix(suffixes, suffix, &rc); + assert(rc == KH_ADDED || rc == KH_RESET); + kh_value(suffixes, k) = val; +} + +/** + * Add a packet cache entry in the both the first and second level of the + * two-level data tructure (helper) + */ +void _add_suffix(kh_pkt_cache_prefix_t *prefixes, + const hicn_name_prefix_t *prefix, + const hicn_name_suffix_t suffix, unsigned val, + slab_t *prefix_keys) { + kh_pkt_cache_suffix_t *suffixes = + _get_suffixes(prefixes, prefix, true, prefix_keys); + assert(suffixes != NULL); + + __add_suffix(suffixes, suffix, val); +} + +/** + * Lookup in the second level of the packet cache (helper) + */ +unsigned __get_suffix(kh_pkt_cache_suffix_t *suffixes, + hicn_name_suffix_t suffix) { + khiter_t k = kh_get_pkt_cache_suffix(suffixes, suffix); + + // Not Found + if (k == kh_end(suffixes)) { + return HICN_INVALID_SUFFIX; + } + + unsigned index = kh_val(suffixes, k); + return index; +} + +unsigned _get_suffix(kh_pkt_cache_prefix_t *prefixes, + const hicn_name_prefix_t *prefix, + hicn_name_suffix_t suffix, slab_t *prefix_keys) { + /* create is false as this function is always called by lookup */ + kh_pkt_cache_suffix_t *suffixes = + _get_suffixes(prefixes, prefix, false, prefix_keys); + if (!suffixes) { + return HICN_INVALID_SUFFIX; + } + return __get_suffix(suffixes, suffix); +} + +/** + * Lookup in both the first and second levels of the packet cache (helper) + */ +unsigned _get_suffix_from_name(kh_pkt_cache_prefix_t *prefixes, + const hicn_name_t *name, slab_t *prefix_keys) { + const hicn_name_prefix_t *prefix = hicn_name_get_prefix(name); + const hicn_name_suffix_t suffix = hicn_name_get_suffix(name); + + return _get_suffix(prefixes, prefix, suffix, prefix_keys); +} + +void pkt_cache_save_suffixes_for_prefix(pkt_cache_t *pkt_cache, + const hicn_name_prefix_t *prefix) { + // Cached prefix matches the current one + if (hicn_name_prefix_equals(&pkt_cache->cached_prefix, prefix)) return; + + char buf[MAXSZ_HICN_PREFIX]; + hicn_name_prefix_snprintf(buf, MAXSZ_HICN_PREFIX, &pkt_cache->cached_prefix); + hicn_name_prefix_snprintf(buf, MAXSZ_HICN_PREFIX, prefix); + + // Update cached prefix information + pkt_cache->cached_prefix = *prefix; + pkt_cache->cached_suffixes = + _get_suffixes(pkt_cache->prefix_to_suffixes, prefix, true, + pkt_cache->prefix_keys); // XXX + // +} + +void pkt_cache_reset_suffixes_for_prefix(pkt_cache_t *pkt_cache) { + pkt_cache->cached_suffixes = NULL; +} + +/****************************************************************************** + * Public API + ******************************************************************************/ + +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->prefix_to_suffixes = kh_init_pkt_cache_prefix(); + pkt_cache->prefix_keys = slab_create(hicn_name_prefix_t, SLAB_INIT_SIZE); + pool_init(pkt_cache->entries, DEFAULT_PKT_CACHE_SIZE, 0); + + pkt_cache->cached_prefix = HICN_NAME_PREFIX_EMPTY; + pkt_cache->cached_suffixes = NULL; + + return pkt_cache; +} + +void pkt_cache_free(pkt_cache_t *pkt_cache) { + assert(pkt_cache); + + // Free prefix hash table and pool + _prefix_map_free(pkt_cache->prefix_to_suffixes); + slab_free(pkt_cache->prefix_keys); + pool_free(pkt_cache->entries); + + // Free PIT and CS + pit_free(pkt_cache->pit); + cs_free(pkt_cache->cs); + + free(pkt_cache); +} + +kh_pkt_cache_suffix_t *pkt_cache_get_suffixes(const pkt_cache_t *pkt_cache, + const hicn_name_prefix_t *prefix, + bool create, + slab_t *prefix_keys) { + return _get_suffixes(pkt_cache->prefix_to_suffixes, prefix, create, + prefix_keys); +} + +pkt_cache_entry_t *pkt_cache_allocate(pkt_cache_t *pkt_cache) { + pkt_cache_entry_t *entry = NULL; + pool_get(pkt_cache->entries, entry); + assert(entry); + return entry; +} + +void pkt_cache_add_to_index(const pkt_cache_t *pkt_cache, + const pkt_cache_entry_t *entry) { + off_t id = entry - pkt_cache->entries; + + /* It is important that the name used for the index is the one in the packet + * cache entry, which is common for PIT and CS + */ + const hicn_name_t *name = &entry->name; + + if (pkt_cache->cached_suffixes) { + __add_suffix(pkt_cache->cached_suffixes, hicn_name_get_suffix(name), + (unsigned int)id); + } else { + _add_suffix(pkt_cache->prefix_to_suffixes, hicn_name_get_prefix(name), + hicn_name_get_suffix(name), (unsigned int)id, + pkt_cache->prefix_keys); + } +} + +/** + * Remove a name pointer to the packet cache index (helper) + */ +void pkt_cache_remove_from_index(const pkt_cache_t *pkt_cache, + const hicn_name_t *name) { + _remove_suffix(pkt_cache->prefix_to_suffixes, hicn_name_get_prefix(name), + hicn_name_get_suffix(name), pkt_cache->prefix_keys); + +// TODO +#if 0 + khiter_t k = kh_get_pkt_cache_name(pkt_cache->index_by_name, name); + assert(k != kh_end(pkt_cache->index_by_name)); + kh_del(pkt_cache_name, pkt_cache->index_by_name, k); +#endif +} + +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 hicn_name_t *name, + msgbuf_pool_t *msgbuf_pool, + pkt_cache_lookup_t *lookup_result, + off_t *entry_id, + bool is_serve_from_cs_enabled) { + unsigned index = HICN_INVALID_SUFFIX; + if (pkt_cache->cached_suffixes) { + index = + __get_suffix(pkt_cache->cached_suffixes, hicn_name_get_suffix(name)); + } else { + index = _get_suffix_from_name(pkt_cache->prefix_to_suffixes, name, + pkt_cache->prefix_keys); + } + + if (index == HICN_INVALID_SUFFIX) { + *lookup_result = PKT_CACHE_LU_NONE; + return NULL; + } + + 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); + + // XXX const hicn_name_t *name = msgbuf_get_name(msgbuf); + _remove_suffix(pkt_cache->prefix_to_suffixes, + hicn_name_get_prefix(&entry->name), + hicn_name_get_suffix(&entry->name), pkt_cache->prefix_keys); + + // 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 buf[MAXSZ_HICN_NAME]; + int rc = hicn_name_snprintf(buf, MAXSZ_HICN_NAME, &entry->name); + if (rc < 0 || rc >= MAXSZ_HICN_NAME) + snprintf(buf, MAXSZ_HICN_NAME, "%s", "(error)"); + DEBUG("Packet %s removed from CS", buf); + }) + + msgbuf_pool_release(msgbuf_pool, &msgbuf); +} + +void pkt_cache_pit_remove_entry(pkt_cache_t *pkt_cache, + pkt_cache_entry_t *entry) { + assert(pkt_cache); + assert(entry); + assert(entry->entry_type == PKT_CACHE_PIT_TYPE); + + const hicn_name_t *name = &entry->name; + _remove_suffix(pkt_cache->prefix_to_suffixes, hicn_name_get_prefix(name), + hicn_name_get_suffix(name), pkt_cache->prefix_keys); + + pool_put(pkt_cache->entries, entry); + + WITH_DEBUG({ + char buf[MAXSZ_HICN_NAME]; + int rc = hicn_name_snprintf(buf, MAXSZ_HICN_NAME, name); + if (rc < 0 || rc >= MAXSZ_HICN_NAME) + snprintf(buf, MAXSZ_HICN_NAME, "%s", "(error)"); + DEBUG("Packet %s removed from PIT", buf); + }) +} + +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}}; + Ticks now = ticks_now(); + entry->create_ts = now; + entry->expire_ts = 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 = (int)(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 *entry, + msgbuf_pool_t *msgbuf_pool, msgbuf_t *msgbuf, + off_t msgbuf_id, off_t entry_id) { + assert(pkt_cache); + assert(entry); + assert(entry->entry_type == PKT_CACHE_PIT_TYPE); + + _pkt_cache_add_to_cs(pkt_cache, entry, msgbuf_pool, msgbuf, msgbuf_id, + entry_id); +} + +/** + * entry : newly allocated cache entry + * msgbuf : used for name, ingress connection id and lifetime + */ +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, + const hicn_name_t *name) { + assert(pkt_cache); + + pkt_cache_entry_t *entry = pkt_cache_allocate(pkt_cache); + entry->name = *name; + _pkt_cache_add_to_pit(pkt_cache, entry, msgbuf); + pkt_cache_add_to_index(pkt_cache, entry); + 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); + const hicn_name_t *name = msgbuf_get_name(msgbuf); + entry->name = *name; + 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); + pkt_cache_add_to_index(pkt_cache, entry); + 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, + const hicn_name_t *name) { + 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 the strategy to use for this packet is STRATEGY_TYPE_LOCAL_REMOTE we may + // want to forward the packet even if it should be aggregated. This is useful + // when a local consumer socket and a remote one are asking for the same + // content. If the interest coming from the remote socket is received before + // the one from the local socket, the second interest is aggregated in the PIT + // and no interest is satisfied (IRIS app). + // Forward the interest if: 1) the strategy in the fib_entry stored in the pit + // entry is STRATEGY_TYPE_LOCAL_REMOTE 2) the ingress connection of the + // interest if a local connection 3) the ingress list of pit entry has no + // other local ingress connection if all these conditions are satisfied, send + // the interest. if is_aggregated = false avoid the check (it will be useless) + + if (is_aggregated) { + fib_entry_t *fib_entry = pit_entry_get_fib_entry(pit_entry); + if (fib_entry && + (fib_entry_strategy_type(fib_entry) == STRATEGY_TYPE_LOCAL_REMOTE)) { + // the strategy is STRATEGY_TYPE_LOCAL_REMOTE, check the input face + connection_table_t *table = + forwarder_get_connection_table(fib_entry->forwarder); + if (table) { + connection_t *msg_conn = + connection_table_get_by_id(table, connection_id); + if (msg_conn && connection_is_local(msg_conn)) { + // The face is local, check that no other input face is local. With + // this check only the first local consumer is able to send + // the interest, while the other interests will be aggregated + // (however this is quite inefficient) + nexthops_t *ingressIdSet = pit_entry_get_ingress(pit_entry); + bool in_local_connextion_exists = false; + nexthops_enumerate(ingressIdSet, i, nexthop, { + connection_t *in_conn = connection_table_get_by_id(table, nexthop); + if (in_conn && connection_is_local(in_conn)) { + in_local_connextion_exists = true; + break; + } + }); + if (!in_local_connextion_exists) is_aggregated = false; + } + } + } + } + + if (is_aggregated) pit_entry_ingress_add(pit_entry, connection_id); + + WITH_DEBUG({ + char buf[MAXSZ_HICN_NAME]; + int rc = hicn_name_snprintf(buf, MAXSZ_HICN_NAME, msgbuf_get_name(msgbuf)); + if (rc < 0 || rc >= MAXSZ_HICN_NAME) + snprintf(buf, MAXSZ_HICN_NAME, "%s", "(error)"); + if (is_aggregated) { + DEBUG("Interest %s already existing (expiry %lu): aggregate", buf, + entry->expire_ts); + } else { + DEBUG("Interest %s already existing (expiry %lu): retransmit", buf, + entry->expire_ts); + } + }) + + 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) == HICN_PACKET_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); + *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); + *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("Invalid 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, + const hicn_name_t *name, + 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) == HICN_PACKET_TYPE_INTEREST); + + off_t entry_id; + pkt_cache_lookup_t lookup_result; + pkt_cache_entry_t *entry = + pkt_cache_lookup(pkt_cache, name, 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: + entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name); + *entry_ptr = entry; + + *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, name); + + *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); + + kh_pkt_cache_suffix_t *v_suffixes; + u32 k_suffix; + u32 v_pkt_cache_entry_id; + kh_foreach_value(pkt_cache->prefix_to_suffixes, v_suffixes, { + kh_foreach(v_suffixes, k_suffix, v_pkt_cache_entry_id, { + pkt_cache_entry_t *entry = pkt_cache_at(pkt_cache, v_pkt_cache_entry_id); + if (entry->entry_type == PKT_CACHE_CS_TYPE) { + // Remove from hash table + khiter_t k = kh_get_pkt_cache_suffix(v_suffixes, k_suffix); + assert(k != kh_end(v_suffixes)); + kh_del_pkt_cache_suffix(v_suffixes, k); + + // Remove from pool + pool_put(pkt_cache->entries, entry); + } + }); + }); + + // Reset cached prefix + pkt_cache->cached_prefix = HICN_NAME_PREFIX_EMPTY; + pkt_cache->cached_suffixes = NULL; + + // Re-create CS + cs_clear(pkt_cache->cs); +} + +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_size(pkt_cache_t *pkt_cache) { + return pool_len(pkt_cache->entries); +} + +size_t pkt_cache_get_cs_size(pkt_cache_t *pkt_cache) { + return pkt_cache->cs->num_entries; +} + +size_t pkt_cache_get_pit_size(pkt_cache_t *pkt_cache) { + uint64_t pkt_cache_size = pkt_cache_get_size(pkt_cache); + uint64_t pit_size = pkt_cache_size - pkt_cache_get_cs_size(pkt_cache); + return pit_size; +} + +void pkt_cache_log(pkt_cache_t *pkt_cache) { + DEBUG("Packet cache: total size = %lu, PIT size = %lu, CS size = %u", + pkt_cache_get_size(pkt_cache), pkt_cache_get_pit_size(pkt_cache), + pkt_cache_get_cs_size(pkt_cache)); + + cs_log(pkt_cache->cs); +} + +pkt_cache_stats_t pkt_cache_get_stats(pkt_cache_t *pkt_cache) { + cs_lru_stats_t lru_stats = cs_get_lru_stats(pkt_cache_get_cs(pkt_cache)); + pkt_cache_stats_t stats = { + .n_pit_entries = (uint32_t)pkt_cache_get_pit_size(pkt_cache), + .n_cs_entries = (uint32_t)pkt_cache_get_cs_size(pkt_cache), + .n_lru_evictions = (uint32_t)lru_stats.countLruEvictions, + }; + + return stats; +} 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..1abdc57c2 --- /dev/null +++ b/hicn-light/src/hicn/core/packet_cache.h @@ -0,0 +1,502 @@ +/* + * 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. + */ + +/** + * \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 two-level hash table. + * + * 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. + * + * A prefix hash table <prefix, suffix_hashtable> stores the suffixes associated + * to each prefix, where each value in the map points to a separate hash + * table <suffix, packet_cache_reference> that can be used to retrieved the + * packet cache entry. + * When an interest/data packet is received, the prefix and the associated + * suffixes are saved; if the next packet cache operation involves the same + * prefix, no additional lookups in the prefix hash hashtable are needed. + */ + +#ifndef HICNLIGHT_PACKET_CACHE_H +#define HICNLIGHT_PACKET_CACHE_H + +#include <hicn/util/khash.h> +#include <hicn/util/slab.h> +#include "content_store.h" +#include "pit.h" +#include "msgbuf_pool.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; + +#define foreach_kh_verdict \ + _(FORWARD_INTEREST) \ + _(AGGREGATE_INTEREST) \ + _(RETRANSMIT_INTEREST) \ + _(FORWARD_DATA) \ + _(INTEREST_EXPIRED_FORWARD_INTEREST) \ + _(DATA_EXPIRED_FORWARD_INTEREST) \ + _(STORE_DATA) \ + _(CLEAR_DATA) \ + _(UPDATE_DATA) \ + _(IGNORE_DATA) \ + _(ERROR) + +typedef enum { +#define _(x) PKT_CACHE_VERDICT_##x, + foreach_kh_verdict +#undef _ +} pkt_cache_verdict_t; + +extern const char *_pkt_cache_verdict_str[]; + +#define pkt_cache_verdict_str(x) _pkt_cache_verdict_str[x] + +#define foreach_kh_lookup \ + _(INTEREST_NOT_EXPIRED) \ + _(INTEREST_EXPIRED) \ + _(DATA_NOT_EXPIRED) \ + _(DATA_EXPIRED) \ + _(NONE) + +typedef enum { +#define _(x) PKT_CACHE_LU_##x, + foreach_kh_lookup +#undef _ +} pkt_cache_lookup_t; + +KHASH_MAP_INIT_INT(pkt_cache_suffix, unsigned); +KHASH_INIT(pkt_cache_prefix, const hicn_name_prefix_t *, + kh_pkt_cache_suffix_t *, 1, hicn_name_prefix_get_hash, + hicn_name_prefix_equals); + +typedef struct { + hicn_name_t name; + 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_prefix_t *prefix_to_suffixes; + slab_t *prefix_keys; + + // Cached prefix info to avoid double lookups, + // used for both single interest speculation and interest manifest + hicn_name_prefix_t cached_prefix; + kh_pkt_cache_suffix_t *cached_suffixes; +} 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); + +/** + * @brief Add an entry with the specified name to the packet cache. + * + * @param[in] pkt_cache Pointer to the 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 hicn_name_t to use + * + * NOTE: unlike other pools, PIT and CS entries allocation does not update the + * index as the key is a hicn_name_t * which should point to : + * - the name inside the PIT entry (which is thus not set during allocation), + * - the name inside the msgbuf_t in the CS entry, which is always available + * during the lifetime of the cache entry. + * + * The index is therefore updated in pkt_cache_add_to_pit and + * pkt_cache_add_to_cs functions. + * + * + */ +pkt_cache_entry_t *pkt_cache_allocate(pkt_cache_t *pkt_cache); + +void pkt_cache_add_to_index(const pkt_cache_t *pkt_cache, + const pkt_cache_entry_t *entry); + +void pkt_cache_remove_from_index(const pkt_cache_t *pkt_cache, + const hicn_name_t *name); + +/** + * @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); + +#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 hicn_name_t *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 (PIT entries are left unmodified). + * + * @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); + +pkt_cache_stats_t pkt_cache_get_stats(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 PIT entry to remove + */ +void pkt_cache_pit_remove_entry(pkt_cache_t *pkt_cache, + pkt_cache_entry_t *entry); + +/** + * @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 + * @param[in] name Interest name to use; in case of aggregated interests, it is + * different from the name stored in the msgbuf + * @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, + const hicn_name_t *name); + +/** + * @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 + * @param[in] name Interest name to use; in case of aggregated interests, it is + * different from the name stored in the msgbuf + * @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, + const hicn_name_t *name); + +/** + * @brief Cache prefix info (prefix + associated suffixes) to speed up lookups. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + * @param[in] prefix Name prefix to cache + */ +void pkt_cache_save_suffixes_for_prefix(pkt_cache_t *pkt_cache, + const hicn_name_prefix_t *prefix); + +/** + * @brief Reset cached prefix info to force double lookups. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + */ +void pkt_cache_reset_suffixes_for_prefix(pkt_cache_t *pkt_cache); + +/************ 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, + const hicn_name_t *name, + bool is_serve_from_cs_enabled); + +/********* Low-level operations on the hash table *********/ +#ifdef WITH_TESTS +unsigned __get_suffix(kh_pkt_cache_suffix_t *suffixes, + hicn_name_suffix_t suffix); +unsigned _get_suffix(kh_pkt_cache_prefix_t *prefixes, + const hicn_name_prefix_t *prefix, + hicn_name_suffix_t suffix, slab_t *prefix_keys); +void __add_suffix(kh_pkt_cache_suffix_t *suffixes, hicn_name_suffix_t suffix, + unsigned val); +void _add_suffix(kh_pkt_cache_prefix_t *prefixes, + const hicn_name_prefix_t *prefix, + const hicn_name_suffix_t suffix, unsigned val, slab_t *slab); +void _remove_suffix(kh_pkt_cache_prefix_t *prefixes, + const hicn_name_prefix_t *prefix, hicn_name_suffix_t suffix, + slab_t *slab); +void _prefix_map_free(kh_pkt_cache_prefix_t *prefix_to_suffixes); +kh_pkt_cache_suffix_t *_get_suffixes(kh_pkt_cache_prefix_t *prefix_to_suffixes, + const hicn_name_prefix_t *prefix, + bool create, slab_t *prefix_keys); +#endif + +/************** 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..8706a9244 --- /dev/null +++ b/hicn-light/src/hicn/core/policy_stats.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 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. + */ + +#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, unsigned id, + void* data) { + policy_stats_mgr_t* mgr = mgr_arg; + assert(mgr); + assert(id == 0); + 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_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); + 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); + + 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); + + 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..aee68e515 --- /dev/null +++ b/hicn-light/src/hicn/core/policy_stats.h @@ -0,0 +1,92 @@ + +#ifndef HICNLIGHT_POLICY_STATS_H +#define HICNLIGHT_POLICY_STATS_H + +#ifdef WITH_POLICY_STATS + +#include <hicn/policy.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..46c83ef02 --- /dev/null +++ b/hicn-light/src/hicn/core/strategy.c @@ -0,0 +1,60 @@ +/* + * 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); +} + +int strategy_finalize(strategy_entry_t *entry) { + return strategy_vft[entry->type]->finalize(entry); +} + +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..9f1a7dac7 --- /dev/null +++ b/hicn-light/src/hicn/core/strategy.h @@ -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. + */ + +/** + * \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); + +int strategy_finalize(strategy_entry_t *entry); + +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..0af035c88 --- /dev/null +++ b/hicn-light/src/hicn/core/strategy_vft.c @@ -0,0 +1,39 @@ +/* + * 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; +extern const strategy_ops_t strategy_local_remote; + +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, + [STRATEGY_TYPE_LOCAL_REMOTE] = &strategy_local_remote, +#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..55e61db17 --- /dev/null +++ b/hicn-light/src/hicn/core/strategy_vft.h @@ -0,0 +1,124 @@ +/* + * 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. + */ + +/** + * \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/random.h" +#include "../strategies/replication.h" + +typedef union { + strategy_load_balancer_options_t load_balancer; + 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_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_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..fb954a245 --- /dev/null +++ b/hicn-light/src/hicn/core/subscription.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + */ + +#include "subscription.h" +#include <hicn/util/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))) + +/*----------------------------------------------------------------------------* + * 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_type_str(topic_index)); + return -1; + } + + if (num_duplicates > 0) { + DEBUG("Connection %d had already a subscription for topic %s", + connection_id, object_type_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_TYPE_UNDEFINED + 1; topic_index < NUM_TOPICS; + topic_index++) { + printf("topic %s (%lu subscription/s) from connection/s: [ ", + object_type_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"); + } +} 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 eb69485a5..1a04aad75 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: @@ -11,49 +11,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) - 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 -) - -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 + ${CMAKE_CURRENT_SOURCE_DIR}/base.c + ${CMAKE_CURRENT_SOURCE_DIR}/hicn.c + ${CMAKE_CURRENT_SOURCE_DIR}/tcp.c + ${CMAKE_CURRENT_SOURCE_DIR}/udp.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/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..38d36efbe --- /dev/null +++ b/hicn-light/src/hicn/io/base.c @@ -0,0 +1,131 @@ +/* + * 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. + */ + +/** + * @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_set_len(msgbuf, (size_t)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 *sa = &(address->as_sa); + 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_set_len(msgbuf, (size_t)n); + +#ifdef __APPLE__ + // set __uint8_t sin_len to 0 + uint8_t *ptr = (uint8_t *)sa; + *ptr = 0x0; +#endif /* __APPLE__ */ + + 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); + // INFO("Got n=%d messages", n); + 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_set_len(msgbuf[i], msg->msg_len); + + 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..c5859fbe3 --- /dev/null +++ b/hicn-light/src/hicn/io/hicn.c @@ -0,0 +1,448 @@ +/* + * 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(connection_t *connection) { return false; } + +static bool connection_hicn_send(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 bool 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 bc49f4cee..000000000 --- a/hicn-light/src/hicn/io/hicnListener.c +++ /dev/null @@ -1,669 +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; - - if (strcmp("inet4://0.0.0.0:1234", addressToString(address)) == 0) res = true; - 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->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 00298d1b0..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..a924b6330 --- /dev/null +++ b/hicn-light/src/hicn/io/tcp.c @@ -0,0 +1,532 @@ +/* + * 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. + */ + +/** + * 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" + +// 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(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(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 bool 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..d881b4b01 --- /dev/null +++ b/hicn-light/src/hicn/io/udp.c @@ -0,0 +1,565 @@ +/* + * 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. + */ + +/** + * @file udp.c + * #brief Implementation of the native UDP face leveraging the new packet format + * to avoid encapsulation. + * + */ + +/* 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 <hicn/util/ring.h> + +#include "base.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/msgbuf.h" + +#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 { +#ifdef __linux__ + /* Ring buffer */ + off_t *ring; + + 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); +#ifdef __linux__ + connection_udp_data_t *data = connection->data; + assert(data); + + ring_free(data->ring); +#endif /* __linux__ */ +} + +static bool connection_udp_flush(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) == HICN_PACKET_TYPE_DATA) { + msgbuf_update_pathlabel(msgbuf, connection_get_id(connection)); + + connection->stats.data.tx_pkts++; + connection->stats.data.tx_bytes += msgbuf_get_len(msgbuf); + } else { + connection->stats.interests.tx_pkts++; + connection->stats.interests.tx_bytes += msgbuf_get_len(msgbuf); + } + + 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(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) == HICN_PACKET_TYPE_DATA) { + msgbuf_update_pathlabel(msgbuf, connection_get_id(connection)); + + connection->stats.data.tx_pkts++; + connection->stats.data.tx_bytes += msgbuf_get_len(msgbuf); + } else { + connection->stats.interests.tx_pkts++; + connection->stats.interests.tx_bytes += msgbuf_get_len(msgbuf); + } + + 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 %lu: (%d) %s\n", + writeLength, (long unsigned int)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 bool 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 false; + } +#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 false; +#endif + + return true; +} + +#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 cd3ccc84a..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, 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 21b4f6190..000000000 --- a/hicn-light/src/hicn/io/udpListener.c +++ /dev/null @@ -1,649 +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) { - 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"); - return; - } - - command_id id = *(command + 1); - - if (id >= LAST_COMMAND_VALUE){ - printf("the message received is not a valid command, drop\n"); - 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"); - 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/CMakeLists.txt b/hicn-light/src/hicn/messenger/CMakeLists.txt deleted file mode 100644 index 92bc13b5b..000000000 --- a/hicn-light/src/hicn/messenger/CMakeLists.txt +++ /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. - -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) - -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 -) - -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 -) - -set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file 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 191a72213..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: @@ -11,8 +11,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) - if(${CMAKE_SYSTEM_NAME} STREQUAL "Android") list(APPEND SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/android/system.c 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 b7eeabe3b..000000000 --- a/hicn-light/src/hicn/processor/CMakeLists.txt +++ /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. - -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) - -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 8822134fe..000000000 --- a/hicn-light/src/hicn/processor/fib.c +++ /dev/null @@ -1,548 +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 ++; -} - -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 */ - -} - -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 077e33ff3..000000000 --- a/hicn-light/src/hicn/processor/fibEntry.c +++ /dev/null @@ -1,891 +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; - 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; - void *userData; - void (*userDataRelease)(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->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->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; - 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; -} - -policy_t fibEntry_GetPolicy(const FibEntry *fibEntry) { - return fibEntry->policy; -} - -void fibEntry_SetPolicy(FibEntry *fibEntry, 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); - - 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 += msg_size; - fibEntry->policy.stats.wired.latency = \ - 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 += msg_size; - fibEntry->policy.stats.wifi.latency = \ - 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 += msg_size; - fibEntry->policy.stats.cellular.latency = \ - ALPHA * fibEntry->policy.stats.cellular.latency + \ - (1 - ALPHA) * (double)rtt; - fibEntry->policy_counters.cellular.latency_idle = 0; - } - } - - fibEntry->policy.stats.all.latency = \ - 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 += 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 = 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 = \ - 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 = \ - 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 = 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 = \ - 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 = \ - 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 = 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 = \ - 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 = \ - 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 = 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 = \ - 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 = \ - 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 *userData, - void (*userDataRelease)(void **)) { - parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null"); - 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 9e438b0e6..000000000 --- a/hicn-light/src/hicn/processor/fibEntry.h +++ /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. - */ - -/** - * @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); - -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 */ - -#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 -policy_t fibEntry_GetPolicy(const FibEntry *fibEntry); -void fibEntry_ReconsiderPolicy(FibEntry *fibEntry); -void fibEntry_SetPolicy(FibEntry *fibEntry, 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 *userData, - void (*userDataRelease)(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 bdd9c23e8..000000000 --- a/hicn-light/src/hicn/processor/messageProcessor.c +++ /dev/null @@ -1,908 +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); - } - } - - 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 775693bf0..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: @@ -11,8 +11,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) - if (UNIX AND NOT APPLE) list(APPEND HEADER_FILES socket/api.h @@ -27,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..db377aecd 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 @@ -39,7 +43,7 @@ static hicn_conf_t hicn_default_conf = { struct ip_rule_state_ { char tun_name[IF_NAMESIZE]; - ip_prefix_t prefix; + hicn_ip_prefix_t prefix; uint32_t table_id; uint8_t priority; uint8_t address_family; @@ -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) { @@ -197,7 +193,7 @@ int hicn_socket_cmp(hicn_socket_t *a, hicn_socket_t *b) { return b->fd - a->fd; } -ip_prefix_t *hicn_socket_get_src_ip(hicn_socket_t *socket) { +hicn_ip_prefix_t *hicn_socket_get_src_ip(hicn_socket_t *socket) { if (socket->type != HS_CONNECTION) { return NULL; } @@ -245,7 +241,8 @@ int hicn_set_local_endpoint(hicn_socket_t *socket, const char *local_ip_address, */ /* Copy the local IP address inside the connection */ - rc = ip_prefix_pton(local_ip_address, &socket->connection.tun_ip_address); + rc = + hicn_ip_prefix_pton(local_ip_address, &socket->connection.tun_ip_address); if (rc < 0) { rc = HICN_SOCKET_ERROR_SOCKET_LOCAL_REPR; goto end; @@ -255,14 +252,14 @@ end: return rc; } -int hicn_get_local_address(const ip_prefix_t *remote_address, - ip_prefix_t *local_address) { +int hicn_get_local_address(const hicn_ip_prefix_t *remote_address, + hicn_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)); + rc = hicn_ip_prefix_ntop_short(remote_address, remote_address_str, + sizeof(remote_address_str)); if (rc < 0) { rc = HICN_SOCKET_ERROR_BIND_REMOTE_REPR; goto ERR; @@ -293,7 +290,7 @@ ERR: int hicn_set_remote_endpoint(hicn_socket_t *socket, const char *remote_ip_address) { int af, rc = HICN_SOCKET_ERROR_NONE; - ip_prefix_t addr; + hicn_ip_prefix_t addr; af = get_addr_family(remote_ip_address); if ((af != AF_INET6) && (af != AF_INET)) { @@ -301,7 +298,7 @@ int hicn_set_remote_endpoint(hicn_socket_t *socket, } /* Bind local endpoint if not done yet */ - if (ip_prefix_empty(&socket->connection.tun_ip_address)) { + if (hicn_ip_prefix_empty(&socket->connection.tun_ip_address)) { char local_ip_address[INET_MAX_ADDRSTRLEN + 4]; /* Local interface id */ @@ -331,7 +328,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 = hicn_ip_prefix_ntop_short(&addr, local_ip_address, + sizeof(local_ip_address)); if (rc < 0) { rc = HICN_SOCKET_ERROR_BIND_REMOTE_REPR; goto ERR; @@ -448,8 +446,8 @@ int hicn_listen(hicn_socket_helper_t *hicn, int fd, const char *prefix) { return rc; } - ip_prefix_t ip_prefix; - rc = ip_prefix_pton(prefix, &ip_prefix); + hicn_ip_prefix_t hicn_ip_prefix; + rc = hicn_ip_prefix_pton(prefix, &hicn_ip_prefix); if (rc < 0) { return rc; } @@ -460,16 +458,18 @@ int hicn_listen(hicn_socket_helper_t *hicn, int fd, const char *prefix) { if (punting_table_id == -1) punting_table_id = socket->connection.table_id; - rc = ops.add_prio_rule(&ip_prefix, ip_prefix.family, 0, + rc = ops.add_prio_rule(&hicn_ip_prefix, hicn_ip_prefix.family, 0, socket->connection.table_id); if (rc < 0) { 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; + rules_to_remove[rules_counter].prefix = hicn_ip_prefix; + rules_to_remove[rules_counter].address_family = hicn_ip_prefix.family; rules_to_remove[rules_counter].table_id = socket->connection.table_id; rules_to_remove[rules_counter].priority = 0; ++rules_counter; @@ -533,7 +533,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 +566,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..3caf9ef1e 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 \ @@ -84,7 +83,7 @@ typedef struct hicn_socket_s { union { struct { - ip_prefix_t tun_ip_address; + hicn_ip_prefix_t tun_ip_address; uint32_t interface_id; /* ID of the corresponding table : avoid default values of 0, 32766 and @@ -163,8 +162,8 @@ void hicn_free(hicn_socket_helper_t *hicn); * * @return 0 in case of success, -1 otherwise. */ -int hicn_get_local_address(const ip_prefix_t *remote_address, - ip_prefix_t *local_address); +int hicn_get_local_address(const hicn_ip_prefix_t *remote_address, + hicn_ip_prefix_t *local_address); /* hICN socket */ diff --git a/hicn-light/src/hicn/socket/ops.h b/hicn-light/src/hicn/socket/ops.h index 1bee7c6f6..854b0c461 100644 --- a/hicn-light/src/hicn/socket/ops.h +++ b/hicn-light/src/hicn/socket/ops.h @@ -17,10 +17,10 @@ typedef struct { int (*get_output_ifid)(const char *ip_address, uint8_t address_family, uint32_t *interface_id); int (*get_ip_addr)(uint32_t interface_id, uint8_t address_family, - ip_prefix_t *ip_address); - int (*set_ip_addr)(uint32_t interface_id, ip_prefix_t *ip_address); + hicn_ip_prefix_t *ip_address); + int (*set_ip_addr)(uint32_t interface_id, hicn_ip_prefix_t *ip_address); int (*up_if)(uint32_t interface_id); - int (*add_in_route_table)(const ip_prefix_t *prefix, + int (*add_in_route_table)(const hicn_ip_prefix_t *prefix, const uint32_t interface_id, const uint8_t table_id); int (*add_in_route_table_s)(const char *prefix, const uint32_t interface_id, @@ -30,23 +30,23 @@ typedef struct { const uint8_t table_id, int default_route); int (*del_out_route)(const char *gateway, const uint8_t address_family, const uint8_t table_id); - int (*del_lo_route)(const ip_prefix_t *ip_address); + int (*del_lo_route)(const hicn_ip_prefix_t *ip_address); int (*add_rule)(const char *interface_name, const uint8_t address_family, const uint8_t table_id); int (*del_rule)(const char *interface_name, const uint8_t address_family, const uint8_t table_id); - int (*add_neigh_proxy)(const ip_prefix_t *ip_address, + int (*add_neigh_proxy)(const hicn_ip_prefix_t *ip_address, const uint32_t interface_id); - int (*add_prio_rule)(const ip_prefix_t *ip_address, + int (*add_prio_rule)(const hicn_ip_prefix_t *ip_address, const uint8_t address_family, const uint32_t priority, const uint8_t table_id); - int (*add_lo_prio_rule)(const ip_prefix_t *ip_address, + int (*add_lo_prio_rule)(const hicn_ip_prefix_t *ip_address, const uint8_t address_family, const uint32_t priority); - int (*del_prio_rule)(const ip_prefix_t *ip_address, + int (*del_prio_rule)(const hicn_ip_prefix_t *ip_address, const uint8_t address_family, const uint32_t priority, const uint8_t table_id); - int (*del_lo_prio_rule)(const ip_prefix_t *ip_address, + int (*del_lo_prio_rule)(const hicn_ip_prefix_t *ip_address, const uint8_t address_family, const uint32_t priority); } hicn_socket_ops_t; diff --git a/hicn-light/src/hicn/socket/ops_linux.c b/hicn-light/src/hicn/socket/ops_linux.c index 8bfc438f3..a3675e929 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 */ @@ -60,13 +62,13 @@ int _nl_get_output_ifid(const char *ip_address, uint8_t address_family, * @see getifaddrs */ int _nl_get_ip_addr(uint32_t interface_id, uint8_t address_family, - ip_prefix_t *ip_address); + hicn_ip_prefix_t *ip_address); -int _nl_set_ip_addr(uint32_t interface_id, ip_prefix_t *ip_address); +int _nl_set_ip_addr(uint32_t interface_id, hicn_ip_prefix_t *ip_address); int _nl_up_if(uint32_t interface_id); -int _nl_add_in_route_table(const ip_prefix_t *prefix, +int _nl_add_in_route_table(const hicn_ip_prefix_t *prefix, const uint32_t interface_id, const uint8_t table_id); int _nl_add_in_route_table_s(const char *prefix, const uint32_t interface_id, const uint8_t table_id); @@ -77,25 +79,25 @@ int _nl_add_out_route(const char *gateway, const uint8_t address_family, int _nl_del_out_route(const char *gateway, const uint8_t address_family, const uint8_t table_id); -int _nl_del_lo_route(const ip_prefix_t *ip_address); +int _nl_del_lo_route(const hicn_ip_prefix_t *ip_address); int _nl_add_rule(const char *interface_name, const uint8_t address_family, const uint8_t table_id); int _nl_del_rule(const char *interface_name, const uint8_t address_family, const uint8_t table_id); -int _nl_add_neigh_proxy(const ip_prefix_t *ip_address, +int _nl_add_neigh_proxy(const hicn_ip_prefix_t *ip_address, const uint32_t interface_id); -int _nl_add_prio_rule(const ip_prefix_t *ip_address, +int _nl_add_prio_rule(const hicn_ip_prefix_t *ip_address, const uint8_t address_family, const uint32_t priority, const uint8_t table_id); -int _nl_add_lo_prio_rule(const ip_prefix_t *ip_address, +int _nl_add_lo_prio_rule(const hicn_ip_prefix_t *ip_address, const uint8_t address_family, const uint32_t priority); -int _nl_del_prio_rule(const ip_prefix_t *ip_address, +int _nl_del_prio_rule(const hicn_ip_prefix_t *ip_address, const uint8_t address_family, const uint32_t priority, const uint8_t table_id); -int _nl_del_lo_prio_rule(const ip_prefix_t *ip_address, +int _nl_del_lo_prio_rule(const hicn_ip_prefix_t *ip_address, const uint8_t address_family, const uint32_t priority); #endif /* HICN_NETLINK_H */ @@ -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)}, @@ -530,7 +533,7 @@ ERR: } int _nl_get_ip_addr(uint32_t interface_id, uint8_t address_family, - ip_prefix_t *prefix) { + hicn_ip_prefix_t *prefix) { char buffer[BUFSIZE]; struct nlmsghdr *hdr = (struct nlmsghdr *)buffer; size_t n; @@ -599,7 +602,7 @@ ERR_SOCKET: return HICN_SOCKET_ERROR_UNSPEC; } -int _nl_set_ip_addr(uint32_t interface_id, ip_prefix_t *prefix) { +int _nl_set_ip_addr(uint32_t interface_id, hicn_ip_prefix_t *prefix) { char buffer[BUFSIZE]; struct nlmsghdr *hdr = (struct nlmsghdr *)buffer; size_t n; @@ -619,15 +622,15 @@ int _nl_set_ip_addr(uint32_t interface_id, ip_prefix_t *prefix) { .payload.ifa_index = interface_id}; /* Set attributes = length/type/value */ - struct rtattr ifa_address = {RTA_LENGTH(ip_address_len(prefix->family)), + struct rtattr ifa_address = {RTA_LENGTH(hicn_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 = + hicn_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, hicn_ip_address_len(prefix->family)}, }; msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov)); @@ -965,7 +968,7 @@ ERR_SOCKET: * ip route del 1:2::2 dev lo table local * */ -int _nl_del_lo_route(const ip_prefix_t *prefix) { +int _nl_del_lo_route(const hicn_ip_prefix_t *prefix) { char buffer[BUFSIZE]; struct nlmsghdr *hdr = (struct nlmsghdr *)buffer; size_t n; @@ -991,16 +994,17 @@ int _nl_del_lo_route(const ip_prefix_t *prefix) { /* Set attribute = length/type/value */ uint32_t one = 1; - struct rtattr a_dst = {RTA_LENGTH(ip_address_len(prefix->family)), RTA_DST}; + struct rtattr a_dst = {RTA_LENGTH(hicn_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 void *address = + hicn_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)}, + {(void *)address, hicn_ip_address_len(prefix->family)}, /* Interface id */ {&a_ifid_lo, sizeof(a_ifid_lo)}, {&one, sizeof(one)}}; @@ -1048,7 +1052,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 +1098,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) { @@ -1131,7 +1135,7 @@ ERR_SOCKET: * ip -6 neigh add proxy 1:2::2 dev hicnc-cons-eth0 2>&1 | grep nei * */ -int _nl_add_neigh_proxy(const ip_prefix_t *prefix, +int _nl_add_neigh_proxy(const hicn_ip_prefix_t *prefix, const uint32_t interface_id) { /* Buffer for holding the response, with appropriate casting on the header */ char buffer[BUFSIZE]; @@ -1156,18 +1160,19 @@ 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}; + struct rtattr a_dst = {RTA_LENGTH(hicn_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 = + hicn_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, hicn_ip_address_len(prefix->family)}, }; msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov)); @@ -1205,7 +1210,7 @@ ERR: /* ip -6 route add 0:1::/64 dev hicn-if0 table 100 */ /* ip -6 route add 0:2::/64 dev hicn-if1 table 100 */ -int _nl_add_in_route_table(const ip_prefix_t *prefix, +int _nl_add_in_route_table(const hicn_ip_prefix_t *prefix, const uint32_t interface_id, const uint8_t table_id) { /* Buffer for holding the response, with appropriate casting on the header */ @@ -1237,19 +1242,20 @@ int _nl_add_in_route_table(const ip_prefix_t *prefix, }; /* Message attributes = length/type/value */ - struct rtattr a_dst = {RTA_LENGTH(ip_address_len(prefix->family)), RTA_DST}; + struct rtattr a_dst = {RTA_LENGTH(hicn_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 = + hicn_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, hicn_ip_address_len(prefix->family)}, /* Output interface */ {&a_oif, sizeof(a_oif)}, {(void *)&interface_id, sizeof(uint32_t)}, @@ -1293,9 +1299,9 @@ ERR: int _nl_add_in_route_table_s(const char *prefix, const uint32_t interface_id, const uint8_t table_id) { int rc; - ip_prefix_t ip_address; + hicn_ip_prefix_t ip_address; - rc = ip_prefix_pton(prefix, &ip_address); + rc = hicn_ip_prefix_pton(prefix, &ip_address); if (rc < 0) { return rc; } @@ -1308,7 +1314,7 @@ int _nl_add_in_route_s(const char *prefix, const uint32_t interface_id) { } /* ip -6 rule add from b001::/16 prio 0 table 100 */ -int _nl_add_prio_rule(const ip_prefix_t *prefix, uint8_t address_family, +int _nl_add_prio_rule(const hicn_ip_prefix_t *prefix, uint8_t address_family, const uint32_t priority, const uint8_t table_id) { /* Buffer for holding the response, with appropriate casting on the header */ char buffer[BUFSIZE]; @@ -1343,18 +1349,19 @@ int _nl_add_prio_rule(const ip_prefix_t *prefix, uint8_t address_family, if (prefix) { /* Message attributes = length/type/value */ - struct rtattr a_src = {RTA_LENGTH(ip_address_len(prefix->family)), FRA_SRC}; + struct rtattr a_src = {RTA_LENGTH(hicn_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 = + hicn_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, hicn_ip_address_len(prefix->family)}, /* Priority */ {&a_prio, sizeof(a_prio)}, {(void *)&priority, sizeof(uint32_t)}, @@ -1405,14 +1412,13 @@ ERR: return HICN_SOCKET_ERROR_UNSPEC; } -int _nl_add_lo_prio_rule(const ip_prefix_t *prefix, uint8_t address_family, +int _nl_add_lo_prio_rule(const hicn_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 */ -int _nl_del_prio_rule(const ip_prefix_t *prefix, uint8_t address_family, +int _nl_del_prio_rule(const hicn_ip_prefix_t *prefix, uint8_t address_family, const uint32_t priority, const uint8_t table_id) { /* Buffer for holding the response, with appropriate casting on the header */ char buffer[BUFSIZE]; @@ -1447,19 +1453,20 @@ int _nl_del_prio_rule(const ip_prefix_t *prefix, uint8_t address_family, /* Message attributes = length/type/value */ if (prefix) { - struct rtattr a_src = {RTA_LENGTH(ip_address_len(prefix->family)), FRA_SRC}; + struct rtattr a_src = {RTA_LENGTH(hicn_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 = + hicn_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, hicn_ip_address_len(prefix->family)}, /* Priority */ {&a_prio, sizeof(a_prio)}, {(void *)&priority, sizeof(uint32_t)}, @@ -1512,8 +1519,8 @@ ERR: return HICN_SOCKET_ERROR_UNSPEC; } -int _nl_del_lo_prio_rule(const ip_prefix_t *ip_address, uint8_t address_family, - const uint32_t priority) { +int _nl_del_lo_prio_rule(const hicn_ip_prefix_t *ip_address, + uint8_t address_family, const uint32_t priority) { return _nl_del_prio_rule(ip_address, address_family, priority, RT_TABLE_LOCAL); } @@ -1539,7 +1546,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 +1570,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 +1584,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 400efcde9..754974ee4 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: @@ -11,23 +11,24 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) - 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}/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 + ${CMAKE_CURRENT_SOURCE_DIR}/local_remote.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}/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 + ${CMAKE_CURRENT_SOURCE_DIR}/local_remote.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..9223cc8ac --- /dev/null +++ b/hicn-light/src/hicn/strategies/best_path.c @@ -0,0 +1,353 @@ +/* + * 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 <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); + + /* Backup flags and cur_len: because our code is called from + * strategy_on_data / check_stop_probing / stop_probing + * which does not expect the nexthop flags to be modified. + */ + uint_fast32_t flags = nexthops->flags; + size_t cur_len = nexthops_get_curlen(nexthops); + + nexthops_select(nexthops, offset); + update_remote_node_paths(nexthops, entry->forwarder, options->local_prefixes); + + /* Restore flags & curlen */ + nexthops->flags = flags; + nexthops->cur_elts = cur_len; +} + +// 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; + best_nexthop = state->best_nexthop; + 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; + + 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); + + // TODO explain the purpose of this test + 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 = hicn_name_get_suffix(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 = hicn_name_get_suffix(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; + } + + 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 878a58515..000000000 --- a/hicn-light/src/hicn/strategies/loadBalancer.c +++ /dev/null @@ -1,368 +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; - } - } -#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..0e1a170f7 --- /dev/null +++ b/hicn-light/src/hicn/strategies/load_balancer.c @@ -0,0 +1,148 @@ +/* + * 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 <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) { + 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) { + if (nexthops_get_curlen(nexthops) == 0) return nexthops; + /* Compute the sum of weights of potential next hops */ + double sum = 0; + 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. + */ + nexthops_foreach(timeout_nexthops, timeout_nexthop, { + 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..fb161ab2a --- /dev/null +++ b/hicn-light/src/hicn/strategies/local_prefixes.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021-2023 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "local_prefixes.h" +#include <hicn/core/forwarder.h> +#include <hicn/core/nexthops.h> +#include <hicn/core/mapme.h> + +#define MAX_PREFIXES 10 + +struct local_prefixes_s { + hicn_prefix_t 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(const local_prefixes_t *prefixes, + const hicn_prefix_t *prefix) { + for (unsigned i = 0; i < prefixes->len; i++) { + if (hicn_prefix_equals(&(prefixes->local_prefixes[i]), prefix)) 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]))) { + hicn_prefix_copy(&prefixes->local_prefixes[prefixes->len], + &new_prefixes->local_prefixes[i]); + prefixes->len++; + } + i++; + } +} + +void local_prefixes_add_prefix(local_prefixes_t *prefixes, + const hicn_prefix_t *prefix) { + if (prefixes->len >= MAX_PREFIXES) return; + if (!contain_prefix(prefixes, prefix)) { + hicn_prefix_copy(&(prefixes->local_prefixes[prefixes->len]), prefix); + 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_prefix(fib, &prefixes->local_prefixes[i]); + if (!entry) continue; + // XXX we don't want to force + mapme_set_adjacencies(mapme, entry, (nexthops_t *)nexthops, NULL); + } +} 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..9d7d8ec78 --- /dev/null +++ b/hicn-light/src/hicn/strategies/local_prefixes.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +/** + * 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 + +#include <hicn/name.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 hicn_prefix_t* 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/local_remote.c b/hicn-light/src/hicn/strategies/local_remote.c new file mode 100644 index 000000000..7edf62643 --- /dev/null +++ b/hicn-light/src/hicn/strategies/local_remote.c @@ -0,0 +1,105 @@ +/* + * 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/core/nexthops.h> +#include <hicn/core/forwarder.h> + +#include "local_remote.h" + +static int strategy_local_remote_initialize(strategy_entry_t *entry, + const void *forwarder) { + printf("INIT FWD STRATEGY REMOTE LOCAL\n"); + srand((unsigned int)time(NULL)); + entry->forwarder = forwarder; + return 0; +} + +static int strategy_local_remote_finalize(strategy_entry_t *entry) { + /* Nothing to do */ + return 0; +} + +static int strategy_local_remote_add_nexthop(strategy_entry_t *entry, + nexthops_t *nexthops, + off_t offset) { + /* Nothing to do */ + return 0; +} + +static int strategy_local_remote_remove_nexthop(strategy_entry_t *entry, + nexthops_t *nexthops, + off_t offset) { + /* Nothing to do */ + return 0; +} + +static nexthops_t *strategy_local_remote_lookup_nexthops( + strategy_entry_t *entry, nexthops_t *nexthops, const msgbuf_t *msgbuf) { + if (!entry->forwarder) { + // the forwarder does not exists, drop packet + nexthops_disable_all(nexthops); + return nexthops; + } + + unsigned cid = msgbuf_get_connection_id(msgbuf); + connection_table_t *table = forwarder_get_connection_table(entry->forwarder); + if (!table) { + // the connection table does not exists, drop packet. + nexthops_disable_all(nexthops); + return nexthops; + } + + connection_t *in = connection_table_get_by_id(table, cid); + if (!in) { + // the ingress connection does not exists, drop packet. + nexthops_disable_all(nexthops); + return nexthops; + } + + bool in_is_local = connection_is_local(in); + nexthops_enumerate(nexthops, i, nexthop, { + connection_t *out = connection_table_get_by_id(table, nexthop); + if (out) { + if (connection_is_local(out) != in_is_local) { + // this connection satisfies the requirements, send the intetest here. + nexthops_select(nexthops, i); + return nexthops; + } + } + }); + + // no out connection satisfies the requirements, drop packet. + nexthops_disable_all(nexthops); + return nexthops; +} + +static int strategy_local_remote_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_local_remote_on_timeout( + strategy_entry_t *entry, nexthops_t *nexthops, + const nexthops_t *timeout_nexthops) { + /* Nothing to do */ + return 0; +} + +DECLARE_STRATEGY(local_remote); diff --git a/hicn-light/src/hicn/strategies/local_remote.h b/hicn-light/src/hicn/strategies/local_remote.h new file mode 100644 index 000000000..58ca5abc3 --- /dev/null +++ b/hicn-light/src/hicn/strategies/local_remote.h @@ -0,0 +1,40 @@ +/* + * 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. If the incoming interest arrives from a local face, + * the interest shuold be forwarded only on a remote face. Viceversa, if the + * interest comes from remote it should be sent to a local face. Notice that if + * the condition cannot be satified (e.g. an interest comes from a local face + * and only an other local face can be satified to send the interest) the + * interest is dropped + */ + +#ifndef HICNLIGHT_STRATEGY_LOCAL_REMOTE_H +#define HICNLIGHT_STRATEGY_LOCAL_REMOTE_H + +typedef struct { + void *_; +} strategy_loc_rem_nexthop_state_t; + +typedef struct { + void *_; +} strategy_loc_rem_state_t; + +typedef struct { + void *_; +} strategy_loc_rem_options_t; + +#endif /* HICNLIGHT_STRATEGY_LOCAL_REMOTE_H */ 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/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..fd0bf5471 --- /dev/null +++ b/hicn-light/src/hicn/strategies/probe_generator.c @@ -0,0 +1,113 @@ +/* + * 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 "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); + 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; + msgbuf_modify_suffix(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..065d824a1 --- /dev/null +++ b/hicn-light/src/hicn/strategies/probe_generator.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#ifndef HICNLIGHT_PROBE_GENERATOR +#define HICNLIGHT_PROBE_GENERATOR + +#include <hicn/util/khash.h> +#include <hicn/core/ticks.h> +#include <hicn/core/msgbuf.h> + +#define MIN_PROBE_SUFFIX 0xefffffff +#define MAX_PROBE_SUFFIX 0xffffffff - 1 + +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..aabae73bc --- /dev/null +++ b/hicn-light/src/hicn/strategies/random.c @@ -0,0 +1,77 @@ +/* + * 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) { + if (nexthops_get_curlen(nexthops) == 0) return nexthops; + 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/strategies/loadBalancer.h b/hicn-light/src/hicn/strategies/random.h index 74920768d..bdea5e4dd 100644 --- a/hicn-light/src/hicn/strategies/loadBalancer.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 @@ */ /** - * Forward on the less loaded path + * Forward randomly */ -#ifndef loadBalancer_h -#define loadBalancer_h +#ifndef HICNLIGHT_STRATEGY_RANDOM_H +#define HICNLIGHT_STRATEGY_RANDOM_H -#include <hicn/strategies/strategyImpl.h> +typedef struct { + void *_; +} strategy_random_nexthop_state_t; -StrategyImpl *strategyLoadBalancer_Create(); +typedef struct { + void *_; +} strategy_random_state_t; -#endif // loadBalancer_h +typedef struct { + void *_; +} strategy_random_options_t; + +#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..395b6e333 --- /dev/null +++ b/hicn-light/src/hicn/test/CMakeLists.txt @@ -0,0 +1,40 @@ +# Copyright (c) 2021-2022 Cisco and/or its affiliates. + +include(BuildMacros) + +list(APPEND TESTS_SRC + test-configuration.cc + test-fib.cc + test-loop.cc + test-parser.cc + test-ctrl.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-strategy-local-remote.cc + test-subscription.cc + test-local_prefixes.cc + test-probe_generator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/commands/command_listener.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../ctrl/libhicnctrl/src/commands/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}" + COMPILE_OPTIONS ${COMPILER_OPTIONS} +) + +add_test_internal(hicn_light_tests) diff --git a/hicn-light/src/hicn/strategies/rnd.h b/hicn-light/src/hicn/test/main.cc index 78fb34758..49cc28f66 100644 --- a/hicn-light/src/hicn/strategies/rnd.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 randomly - */ - -#ifndef rnd_h -#define rnd_h - -#include <hicn/strategies/strategyImpl.h> - -StrategyImpl* strategyRnd_Create(); +#include <gtest/gtest.h> -#endif // rnd_h +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} 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..2d3b5329f --- /dev/null +++ b/hicn-light/src/hicn/test/test-configuration.cc @@ -0,0 +1,83 @@ +/* + * 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); + configuration_flush_log(); +} + +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..6723d0ff1 --- /dev/null +++ b/hicn-light/src/hicn/test/test-connection_table.cc @@ -0,0 +1,301 @@ +/* + * 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> +#include <hicn/util/log.h> +#include <hicn/validation.h> +} + +#define CONNECTION_NAME "conn_name" +#define CONNECTION_NAME_2 "conn_name_2" + +class ConnectionTableTest : public ::testing::Test { + protected: + ConnectionTableTest() { + assert(is_symbolic_name(CONNECTION_NAME, SYMBOLIC_NAME_LEN)); + assert(is_symbolic_name(CONNECTION_NAME_2, SYMBOLIC_NAME_LEN)); + + log_conf.log_level = LOG_WARN; + + 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) { + // Set verbose log level + int old_log_level = log_conf.log_level; + log_conf.log_level = LOG_INFO; + + 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")); + + log_conf.log_level = old_log_level; // Restore old log level +} + +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")); +} + +TEST_F(ConnectionTableTest, GenerateConnName) { + char conn_name[SYMBOLIC_NAME_LEN]; + int rc = connection_table_get_random_name(conn_table_, conn_name); + EXPECT_EQ(rc, 0); + + connection_ = connection_table_allocate(conn_table_, &pair_, conn_name); + connection_->type = FACE_TYPE_TCP; + connection_->pair = pair_; + + char conn_name2[SYMBOLIC_NAME_LEN]; + rc = connection_table_get_random_name(conn_table_, conn_name2); + EXPECT_EQ(rc, 0); + EXPECT_NE(strncmp(conn_name, conn_name2, SYMBOLIC_NAME_LEN), 0); +} + +TEST_F(ConnectionTableTest, GenerateConnNameExhaustion) { + char conn_name[SYMBOLIC_NAME_LEN]; + bool unable_to_allocate = false; + + // Force name exhaustion + int n_connections = 1 + USHRT_MAX; + for (int i = 0; i <= n_connections; i++) { + int rc = connection_table_get_random_name(conn_table_, conn_name); + if (rc < 0) { + unable_to_allocate = true; + break; + } + + address_pair_t pair = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(i)); + connection_t *conn = + connection_table_allocate(conn_table_, &pair, conn_name); + memset(conn, 0, sizeof(connection_t)); + conn->type = FACE_TYPE_TCP; + conn->pair = pair; + } + + EXPECT_TRUE(unable_to_allocate); +}
\ No newline at end of file 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..f0d3e7c37 --- /dev/null +++ b/hicn-light/src/hicn/test/test-ctrl.cc @@ -0,0 +1,197 @@ +/* + * 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/ctrl/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(FORWARDER_TYPE_HICNLIGHT); + } + 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. + */ +#if 0 +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_EQ(success, false); +} + +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); +} + +TEST_F(CtrlTest, RouteNameOrID) { + hc_route_t route = { + .face_id = (face_id_t)INVALID_FACE_ID, + .family = AF_INET6, + .remote_addr = IPV6_LOOPBACK, + .len = 64, + .cost = 1, + }; + + // At least one between name (symbolic or ID) and face_id + // should be set to make the route valid + + // Valid name (symbolic) + snprintf(route.name, SYMBOLIC_NAME_LEN, "%s", "test"); + EXPECT_EQ(hc_route_validate(&route), 0); + + // Valid name (ID) + snprintf(route.name, SYMBOLIC_NAME_LEN, "%s", "conn0"); + EXPECT_EQ(hc_route_validate(&route), 0); + + // Valid face_id + route.face_id = 1; + snprintf(route.name, SYMBOLIC_NAME_LEN, "%s", ""); + EXPECT_EQ(hc_route_validate(&route), 0); + + // Invalid name stating with number + // (face_id is only checked if empty name) + route.face_id = 1; + snprintf(route.name, SYMBOLIC_NAME_LEN, "%s", "1test"); + EXPECT_EQ(hc_route_validate(&route), -1); +} +#endif diff --git a/hicn-light/src/hicn/test/test-fib.cc b/hicn-light/src/hicn/test/test-fib.cc new file mode 100644 index 000000000..5068b4fa2 --- /dev/null +++ b/hicn-light/src/hicn/test/test-fib.cc @@ -0,0 +1,338 @@ +/* + * 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 <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 <vector> + +extern "C" { +#define WITH_TESTS +#include <hicn/util/ip_address.h> +#include <hicn/config/configuration.h> +#include <hicn/core/forwarder.h> +#include <hicn/core/fib.h> +} + +/* + * TODO + * - test max_size + */ + +#define DEFAULT_SIZE 10 +#define ARRAY_SIZE(a) ((sizeof(a) / sizeof(*(a)))) + +class FibTest : public ::testing::Test { + protected: + FibTest() { fib = fib_create(NULL); } + virtual ~FibTest() { fib_free(fib); } + + configuration_t *configuration; + forwarder_t *forwarder; + fib_t *fib; +}; + +fib_entry_t *_fib_add_prefix(fib_t *fib, const hicn_prefix_t *prefix, + std::vector<uint32_t> &nexthops) { + fib_entry_t *entry = + fib_entry_create(prefix, STRATEGY_TYPE_UNDEFINED, NULL, NULL); + for (size_t i = 0; i < nexthops.size(); i++) + fib_entry_nexthops_add(entry, nexthops[i]); + fib_add(fib, entry); + return entry; +} + +int compare_str_prefix_to_prefix(char *p1, hicn_prefix_t *p2) { + char prefix_s[MAXSZ_IP_PREFIX]; + hicn_ip_prefix_t ipp; + hicn_prefix_get_ip_prefix(p2, &ipp); + hicn_ip_prefix_snprintf(prefix_s, MAXSZ_IP_PREFIX, + (const hicn_ip_prefix_t *)&ipp); + return strcmp(prefix_s, p1); +} + +#define HICN_PREFIX(P, STR) \ + hicn_prefix_t P; \ + hicn_ip_prefix_t _##P; \ + EXPECT_EQ(hicn_ip_prefix_pton(STR, &_##P), 0); \ + EXPECT_EQ(hicn_prefix_create_from_ip_prefix(&_##P, &P), 0); + +/* TEST: Fib allocation and initialization */ +TEST_F(FibTest, FibAddOne) { + /* Empty fib should be valid */ + + HICN_PREFIX(pfx, "1122:3344:5566:7788:9900:aabb:ccdd:eeff/4"); + + const hicn_prefix_t *empty_prefix_array[] = {}; + bool empty_used_array[] = {}; + EXPECT_TRUE(fib_is_valid(fib)); + EXPECT_TRUE(fib_check_preorder(fib, empty_prefix_array, empty_used_array)); + + const hicn_prefix_t *prefix_array[] = {&pfx}; + bool used_array[] = {true}; + + std::vector<uint32_t> empty_nexthop; + for (unsigned i = 0; i < ARRAY_SIZE(prefix_array); i++) { + if (!used_array[i]) continue; + _fib_add_prefix(fib, prefix_array[i], empty_nexthop); + } + + fib_dump(fib); + + EXPECT_TRUE(fib_is_valid(fib)); + EXPECT_TRUE(fib_check_preorder(fib, prefix_array, used_array)); + + /* Check that free indices and bitmaps are correctly updated */ +} + +TEST_F(FibTest, FibAddTwo) { + HICN_PREFIX(b001, "b001::/64"); + HICN_PREFIX(c001, "c001::/64"); + HICN_PREFIX(inner_8000_1, "8000::/1"); + + const hicn_prefix_t *prefix_array[] = {&b001, &inner_8000_1, &c001}; + bool used_array[] = {true, false, true}; + + std::vector<uint32_t> empty_nexthop; + _fib_add_prefix(fib, &b001, empty_nexthop); + _fib_add_prefix(fib, &c001, empty_nexthop); + + fib_dump(fib); + + EXPECT_TRUE(fib_is_valid(fib)); + EXPECT_TRUE(fib_check_preorder(fib, prefix_array, used_array)); +} + +TEST_F(FibTest, FibAddFive) { + HICN_PREFIX(b002, "b002::/64"); + HICN_PREFIX(b002_abcd_0, "b002::abcd:0:0:0/128"); + HICN_PREFIX(b002_2, "b002::2/128"); + HICN_PREFIX(b002_abcd_1, "b002::abcd:0:0:1/128"); + HICN_PREFIX(b002_3, "b002::3/128"); + HICN_PREFIX(inner_b002_2, "b002::2/127"); + HICN_PREFIX(inner_b002_abcd_0, "b002::abcd:0:0:0/127"); + + const hicn_prefix_t *prefix_array[] = { + &b002_2, &inner_b002_2, &b002_3, &b002, + &b002_abcd_0, &inner_b002_abcd_0, &b002_abcd_1}; + bool used_array[] = {true, false, true, true, true, false, true}; + + std::vector<uint32_t> empty_nexthop; + _fib_add_prefix(fib, &b002, empty_nexthop); + _fib_add_prefix(fib, &b002_abcd_0, empty_nexthop); + _fib_add_prefix(fib, &b002_2, empty_nexthop); + _fib_add_prefix(fib, &b002_abcd_1, empty_nexthop); + _fib_add_prefix(fib, &b002_3, empty_nexthop); + + fib_dump(fib); + + EXPECT_TRUE(fib_is_valid(fib)); + EXPECT_TRUE(fib_check_preorder(fib, prefix_array, used_array)); +} + +TEST_F(FibTest, FibAddRemove) { + HICN_PREFIX(b002_64, "b002::/64"); + HICN_PREFIX(b002_128, "b002::/128"); + + const hicn_prefix_t *prefix_array_1[] = {&b002_128}; + bool used_array_1[] = {true}; + const hicn_prefix_t *prefix_array_2[] = {}; + bool used_array_2[] = {}; + const hicn_prefix_t *prefix_array_3[] = {&b002_64}; + bool used_array_3[] = {true}; + + std::vector<uint32_t> empty_nexthop; + fib_entry_t *entry = _fib_add_prefix(fib, &b002_128, empty_nexthop); + fib_dump(fib); + EXPECT_TRUE(fib_is_valid(fib)); + EXPECT_TRUE(fib_check_preorder(fib, prefix_array_1, used_array_1)); + + fib_remove_entry(fib, entry); + fib_dump(fib); + EXPECT_TRUE(fib_is_valid(fib)); + EXPECT_TRUE(fib_check_preorder(fib, prefix_array_2, used_array_2)); + + entry = _fib_add_prefix(fib, &b002_64, empty_nexthop); + fib_dump(fib); + EXPECT_TRUE(fib_is_valid(fib)); + EXPECT_TRUE(fib_check_preorder(fib, prefix_array_3, used_array_3)); +} + +TEST_F(FibTest, FibAddNested) { + HICN_PREFIX(b002_64, "b002::/64"); + HICN_PREFIX(b002_128, "b002::/128"); + + const hicn_prefix_t *prefix_array_1[] = {&b002_128}; + bool used_array_1[] = {true}; + const hicn_prefix_t *prefix_array_2[] = {&b002_128, &b002_64}; + bool used_array_2[] = {true, true}; + + std::vector<uint32_t> empty_nexthop; + _fib_add_prefix(fib, &b002_128, empty_nexthop); + fib_dump(fib); + EXPECT_TRUE(fib_is_valid(fib)); + EXPECT_TRUE(fib_check_preorder(fib, prefix_array_1, used_array_1)); + + _fib_add_prefix(fib, &b002_64, empty_nexthop); + fib_dump(fib); + EXPECT_TRUE(fib_is_valid(fib)); + EXPECT_TRUE(fib_check_preorder(fib, prefix_array_2, used_array_2)); +} + +TEST_F(FibTest, IRIStest) { + char p_0_s[] = "b001:0:0:3039::/64"; + char p_1_3_s[] = "b001::3039:0:1:2:0/128"; + HICN_PREFIX(p_0, p_0_s); + + HICN_PREFIX(p_1_2, "b001::3039:0:1:0:0/128"); + HICN_PREFIX(p_1_1, "b001::3039:0:1:0:100/128"); + HICN_PREFIX(p_1_3, p_1_3_s); + HICN_PREFIX(p_1_4, "b001::3039:0:1:0:102/128"); + + HICN_PREFIX(p_2_2, "b001::3039:0:2:0:0/128"); + HICN_PREFIX(p_2_1, "b001::3039:0:2:0:100/128"); + HICN_PREFIX(p_2_3, "b001::3039:0:2:2:0/128"); + HICN_PREFIX(p_2_4, "b001::3039:0:2:0:102/128"); + + HICN_PREFIX(to_match1, "b001::3039:0:1:0:101/128"); + HICN_PREFIX(to_match2, "b001:0:0:3039:ffff:ffff::/128"); + HICN_PREFIX(to_match3, "b001:1::/128"); + HICN_PREFIX(to_match4, "b001::3039:0:1:2:0/128"); + + std::vector<uint32_t> nexthop; + nexthop.push_back(2); // add nexthop 2 to the fib entry + /*** add ***/ + _fib_add_prefix(fib, &p_0, nexthop); + EXPECT_TRUE(fib_is_valid(fib)); + + _fib_add_prefix(fib, &p_1_1, nexthop); + EXPECT_TRUE(fib_is_valid(fib)); + + _fib_add_prefix(fib, &p_1_2, nexthop); + EXPECT_TRUE(fib_is_valid(fib)); + + _fib_add_prefix(fib, &p_1_3, nexthop); + EXPECT_TRUE(fib_is_valid(fib)); + + _fib_add_prefix(fib, &p_1_4, nexthop); + fib_dump(fib); + EXPECT_TRUE(fib_is_valid(fib)); + + /*** match ***/ + fib_entry_t *entry = fib_match_prefix(fib, &to_match1); + // the matching prefix should be p0 + EXPECT_TRUE(entry != NULL); + if (entry) { + int ret = compare_str_prefix_to_prefix(p_0_s, &(entry->prefix)); + EXPECT_EQ(ret, 0); + } + + entry = fib_match_prefix(fib, &to_match2); + // the matching prefix should be p0 + EXPECT_TRUE(entry != NULL); + if (entry) { + int ret = compare_str_prefix_to_prefix(p_0_s, &(entry->prefix)); + EXPECT_EQ(ret, 0); + } + + entry = fib_match_prefix(fib, &to_match3); + // we expect no match + EXPECT_FALSE(entry != NULL); + + entry = fib_match_prefix(fib, &to_match4); + // the matching prefix should be p_1_3 + EXPECT_TRUE(entry != NULL); + if (entry) { + int ret = compare_str_prefix_to_prefix(p_1_3_s, &(entry->prefix)); + EXPECT_EQ(ret, 0); + } + + /*** remove ***/ + fib_remove(fib, &p_0, nexthop[0]); + EXPECT_TRUE(fib_is_valid(fib)); + fib_remove(fib, &p_1_1, nexthop[0]); + EXPECT_TRUE(fib_is_valid(fib)); + fib_remove(fib, &p_1_2, nexthop[0]); + EXPECT_TRUE(fib_is_valid(fib)); + fib_remove(fib, &p_1_3, nexthop[0]); + EXPECT_TRUE(fib_is_valid(fib)); + fib_remove(fib, &p_1_4, nexthop[0]); + EXPECT_TRUE(fib_is_valid(fib)); + fib_dump(fib); + + /*** match ***/ + entry = fib_match_prefix(fib, &to_match1); + // we expect no match + EXPECT_FALSE(entry != NULL); + + entry = fib_match_prefix(fib, &to_match2); + // we expect no match + EXPECT_FALSE(entry != NULL); + + entry = fib_match_prefix(fib, &to_match3); + // we expect no match + EXPECT_FALSE(entry != NULL); + + entry = fib_match_prefix(fib, &to_match4); + // we expect no match + EXPECT_FALSE(entry != NULL); + + // add again + _fib_add_prefix(fib, &p_0, nexthop); + EXPECT_TRUE(fib_is_valid(fib)); + _fib_add_prefix(fib, &p_2_1, nexthop); + EXPECT_TRUE(fib_is_valid(fib)); + _fib_add_prefix(fib, &p_2_2, nexthop); + EXPECT_TRUE(fib_is_valid(fib)); + _fib_add_prefix(fib, &p_2_3, nexthop); + EXPECT_TRUE(fib_is_valid(fib)); + _fib_add_prefix(fib, &p_2_4, nexthop); + EXPECT_TRUE(fib_is_valid(fib)); + fib_dump(fib); + + entry = fib_match_prefix(fib, &to_match1); + // the matching prefix should be p0 + EXPECT_TRUE(entry != NULL); + if (entry) { + int ret = compare_str_prefix_to_prefix(p_0_s, &(entry->prefix)); + EXPECT_EQ(ret, 0); + } + + entry = fib_match_prefix(fib, &to_match2); + // the matching prefix should be p0 + EXPECT_TRUE(entry != NULL); + if (entry) { + int ret = compare_str_prefix_to_prefix(p_0_s, &(entry->prefix)); + EXPECT_EQ(ret, 0); + } + + entry = fib_match_prefix(fib, &to_match3); + // we expect no match + EXPECT_FALSE(entry != NULL); + + entry = fib_match_prefix(fib, &to_match4); + // the matching prefix should be p0 + EXPECT_TRUE(entry != NULL); + if (entry) { + int ret = compare_str_prefix_to_prefix(p_0_s, &(entry->prefix)); + EXPECT_EQ(ret, 0); + } +} 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..6bd2a6ab7 --- /dev/null +++ b/hicn-light/src/hicn/test/test-listener_table.cc @@ -0,0 +1,244 @@ +/* + * 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> +#include <hicn/util/log.h> +#include <hicn/validation.h> +} + +#define LISTENER_NAME "listener_name" +#define LISTENER_NAME_2 "listener_name_2" + +class ListenerTableTest : public ::testing::Test { + protected: + ListenerTableTest() { + assert(is_symbolic_name(LISTENER_NAME, SYMBOLIC_NAME_LEN)); + assert(is_symbolic_name(LISTENER_NAME_2, SYMBOLIC_NAME_LEN)); + + 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 + 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..52b1c746e --- /dev/null +++ b/hicn-light/src/hicn/test/test-local_prefixes.cc @@ -0,0 +1,252 @@ +/* + * 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 <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> +} + +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) { + int rc; + local_prefixes_t *lp = create_local_prefixes(); + EXPECT_FALSE(lp == nullptr); + + hicn_ip_address_t result = IP_ADDRESS_EMPTY; + hicn_ip_address_pton(name_str1, &result); + hicn_prefix_t name1; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name1); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str2, &result); + hicn_prefix_t name2; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name2); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str3, &result); + hicn_prefix_t name3; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name3); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str4, &result); + hicn_prefix_t name4; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name4); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str5, &result); + hicn_prefix_t name5; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name5); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str6, &result); + hicn_prefix_t name6; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name6); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str7, &result); + hicn_prefix_t name7; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name7); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str8, &result); + hicn_prefix_t name8; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name8); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str9, &result); + hicn_prefix_t name9; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name9); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str10, &result); + hicn_prefix_t name10; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name10); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str11, &result); + hicn_prefix_t name11; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name11); + EXPECT_EQ(rc, 0); + + 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) { + int rc; + local_prefixes_t *lp = create_local_prefixes(); + EXPECT_FALSE(lp == nullptr); + + hicn_ip_address_t result; + + local_prefixes_t *lp1 = create_local_prefixes(); + EXPECT_FALSE(lp1 == nullptr); + + hicn_ip_address_pton(name_str1, &result); + hicn_prefix_t name1; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name1); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str2, &result); + hicn_prefix_t name2; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name2); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str3, &result); + hicn_prefix_t name3; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name3); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str4, &result); + hicn_prefix_t name4; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name4); + EXPECT_EQ(rc, 0); + + 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); + + hicn_ip_address_pton(name_str5, &result); + hicn_prefix_t name5; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name5); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str6, &result); + hicn_prefix_t name6; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name6); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str7, &result); + hicn_prefix_t name7; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name7); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str8, &result); + hicn_prefix_t name8; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name8); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str9, &result); + hicn_prefix_t name9; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name9); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str10, &result); + hicn_prefix_t name10; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name10); + EXPECT_EQ(rc, 0); + + hicn_ip_address_pton(name_str11, &result); + hicn_prefix_t name11; + rc = hicn_prefix_create_from_ip_address_len(&result, 128, &name11); + EXPECT_EQ(rc, 0); + + 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..71635c929 --- /dev/null +++ b/hicn-light/src/hicn/test/test-loop.cc @@ -0,0 +1,294 @@ +/* + * 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, unsigned id, + void *arg) { + assert(id == 0); + std::cout << "This function should never be called" << std::endl; + EXPECT_TRUE(false); + return -1; + } + + static int onSecondTimerExpiration(void *owner, int fd, unsigned id, + void *arg) { + assert(id == 0); + 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, unsigned id, void *arg) { + assert(id == 0); + // 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, unsigned id, void *arg) { + assert(id == 0); + 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) { // NOSONAR + 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, 0, 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, 0, 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..0a78a7a5d --- /dev/null +++ b/hicn-light/src/hicn/test/test-msgbuf_pool.cc @@ -0,0 +1,191 @@ +/* + * 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 <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/util/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_set_type(msgbuf, HICN_PACKET_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_set_type(msgbuf, HICN_PACKET_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_set_type(msgbuf, HICN_PACKET_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_set_type(msgbuf, HICN_PACKET_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_set_type(msgbuf, HICN_PACKET_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..37f4fe985 --- /dev/null +++ b/hicn-light/src/hicn/test/test-packet_cache.cc @@ -0,0 +1,703 @@ +/* + * 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 <gtest/gtest.h> + +#include <optional> +#include <random> +#include <hicn/test/test-utils.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/packet_cache.h> +} + +static constexpr unsigned CS_SIZE = 100; +static constexpr unsigned CONN_ID = 0; +static constexpr unsigned CONN_ID_2 = 1; +static constexpr unsigned MSGBUF_ID = 0; +static constexpr unsigned MSGBUF_ID_2 = 1; +static constexpr unsigned MSGBUF_ID_3 = 2; +static constexpr unsigned FIVE_SECONDS = 5000; + +static constexpr int N_OPS = 50000; + +class PacketCacheTest : public ::testing::Test { + protected: + PacketCacheTest() { + pkt_cache = pkt_cache_create(CS_SIZE); + int rc = hicn_name_create_from_ip_address(IPV4_ANY, 0, &name); + EXPECT_EQ(rc, 0); + msgbuf_pool = msgbuf_pool_create(); + msgbuf = msgbuf_create(msgbuf_pool, CONN_ID, &name); + } + + virtual ~PacketCacheTest() { + msgbuf_pool_free(msgbuf_pool); + pkt_cache_free(pkt_cache); + } + + msgbuf_t *msgbuf_create(msgbuf_pool_t *msgbuf_pool, unsigned conn_id, + hicn_name_t *name, + std::optional<Ticks> lifetime = FIVE_SECONDS) { + msgbuf_t *msgbuf; + msgbuf_pool_get(msgbuf_pool, &msgbuf); + + msgbuf->connection_id = conn_id; + msgbuf_set_name(msgbuf, name); + + hicn_packet_set_format(msgbuf_get_pkbuf(msgbuf), + HICN_PACKET_FORMAT_IPV6_TCP); + hicn_packet_set_type(msgbuf_get_pkbuf(msgbuf), HICN_PACKET_TYPE_INTEREST); + + hicn_packet_buffer_t *pkbuf = msgbuf_get_pkbuf(msgbuf); + hicn_packet_set_buffer(pkbuf, msgbuf->packet, MTU, 0); + + int rc = hicn_packet_init_header(msgbuf_get_pkbuf(msgbuf), 0); + EXPECT_EQ(rc, 0); + + // Same as 'msgbuf_set_data_expiry_time', + // it would write in the same field + msgbuf_set_interest_lifetime(msgbuf, *lifetime); + + return msgbuf; + } + + hicn_name_t get_name_from_prefix(const char *prefix_str) { + hicn_ip_address_t prefix; + inet_pton(AF_INET6, prefix_str, (struct in6_addr *)&prefix); + + hicn_name_t name; + int rc = hicn_name_create_from_ip_address(prefix, 0, &name); + EXPECT_EQ(rc, 0); + + return name; + } + + pkt_cache_t *pkt_cache; + pkt_cache_entry_t *entry = nullptr; + msgbuf_pool_t *msgbuf_pool; + hicn_name_t name; + msgbuf_t *msgbuf; +}; + +TEST_F(PacketCacheTest, LowLevelOperations) { + kh_pkt_cache_prefix_t *prefix_to_suffixes = kh_init_pkt_cache_prefix(); + const hicn_name_prefix_t *prefix = hicn_name_get_prefix(&name); + _add_suffix(prefix_to_suffixes, prefix, 1, 11, pkt_cache->prefix_keys); + _add_suffix(prefix_to_suffixes, prefix, 2, 22, pkt_cache->prefix_keys); + + unsigned id = + _get_suffix(prefix_to_suffixes, prefix, 1, pkt_cache->prefix_keys); + EXPECT_EQ(id, 11UL); + + id = _get_suffix(prefix_to_suffixes, prefix, 2, pkt_cache->prefix_keys); + EXPECT_EQ(id, 22UL); + + id = _get_suffix(prefix_to_suffixes, prefix, 5, pkt_cache->prefix_keys); + EXPECT_EQ(id, HICN_INVALID_SUFFIX); + + _add_suffix(prefix_to_suffixes, prefix, 5, 55, pkt_cache->prefix_keys); + id = _get_suffix(prefix_to_suffixes, prefix, 5, pkt_cache->prefix_keys); + EXPECT_EQ(id, 55UL); + + _remove_suffix(prefix_to_suffixes, prefix, 2, pkt_cache->prefix_keys); + _add_suffix(prefix_to_suffixes, prefix, 2, 222, pkt_cache->prefix_keys); + id = _get_suffix(prefix_to_suffixes, prefix, 2, pkt_cache->prefix_keys); + EXPECT_EQ(id, 222UL); + + _prefix_map_free(prefix_to_suffixes); +} + +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); + EXPECT_NE(entry, nullptr); + entry->name = name; + ASSERT_EQ(pkt_cache_get_size(pkt_cache), 1u); + pkt_cache_add_to_index(pkt_cache, entry); + + // Get entry by name + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_lookup(pkt_cache, &name, msgbuf_pool, &lookup_result, &entry_id, + true); + EXPECT_NE(lookup_result, PKT_CACHE_LU_NONE); +} + +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); + entry->name = name; + entry->entry_type = PKT_CACHE_PIT_TYPE; + ASSERT_NE(entry, nullptr); + pkt_cache_add_to_index(pkt_cache, entry); + + // 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) { + // Check if entry properly created + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, &name); + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE); + EXPECT_TRUE(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID)); + 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) { + // 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 PIT entry + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, &name); + 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 CS entry + 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_TRUE(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID)); + 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 PIT entry + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, &name); + off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + + hicn_name_t new_name; + int rc = hicn_name_create_from_ip_address(IPV4_LOOPBACK, 0, &new_name); + EXPECT_EQ(rc, 0); + msgbuf_t *new_msgbuf = msgbuf_create(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 CS entry + 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); + + hicn_name_t new_name; + int rc = hicn_name_create_from_ip_address(IPV4_LOOPBACK, 0, &new_name); + EXPECT_EQ(rc, 0); + msgbuf_t *new_msgbuf = msgbuf_create(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 PIT entry + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, &name); + 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); + 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 CS entry + 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 another msgbuf + hicn_name_t new_name; + int rc = hicn_name_create_from_ip_address(IPV4_LOOPBACK, 0, &new_name); + EXPECT_EQ(rc, 0); + msgbuf_t *new_msgbuf = msgbuf_create(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 another msgbuf + hicn_name_t new_name; + int rc = hicn_name_create_from_ip_address(IPV4_LOOPBACK, 0, &new_name); + EXPECT_EQ(rc, 0); + msgbuf_t *new_msgbuf = msgbuf_create(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, &name); + 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, &name); + 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 another msgbuf (using same connection ID) + hicn_name_t new_name; + int rc = hicn_name_create_from_ip_address(IPV4_LOOPBACK, 0, &new_name); + EXPECT_EQ(rc, 0); + msgbuf_t *new_msgbuf = msgbuf_create(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, &name); + 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, &name); + 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_create(msgbuf_pool, CONN_ID, &name, 0); + + // Add to PIT + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, &name); + 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_create(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_create(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) + hicn_name_t name_2; + int rc = hicn_name_create_from_ip_address(IPV4_LOOPBACK, 0, &name_2); + EXPECT_EQ(rc, 0); + msgbuf_t *msgbuf_2 = msgbuf_create(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) + hicn_name_t name_3; + rc = hicn_name_create_from_ip_address(IPV6_LOOPBACK, 0, &name_3); + EXPECT_EQ(rc, 0); + msgbuf_t *msgbuf_3 = + msgbuf_create(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) { + hicn_ip_address_t addr; + char name[30]; + const int NUM_STALES = 10; + int rc; + + // 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); + hicn_name_t name; + rc = hicn_name_create_from_ip_address(addr, 0, &name); + EXPECT_EQ(rc, 0); + msgbuf_t *msgbuf = msgbuf_create(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); + hicn_name_t name; + rc = hicn_name_create_from_ip_address(addr, 0, &name); + EXPECT_EQ(rc, 0); + msgbuf_t *msgbuf = msgbuf_create(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); +} + +TEST_F(PacketCacheTest, PerformanceDoubleLookup) { + hicn_name_t tmp = get_name_from_prefix("b001::0"); + + auto elapsed_time_double = get_execution_time([&]() { + kh_pkt_cache_prefix_t *prefix_to_suffixes = kh_init_pkt_cache_prefix(); + + // Add to hash table + for (int seq = 0; seq < N_OPS; seq++) { + hicn_name_set_suffix(&tmp, seq); + _add_suffix(prefix_to_suffixes, hicn_name_get_prefix(&tmp), + hicn_name_get_suffix(&tmp), hicn_name_get_suffix(&tmp), + pkt_cache->prefix_keys); + } + + // Read from hash table + for (int seq = 0; seq < N_OPS; seq++) { + hicn_name_set_suffix(&tmp, seq); + _get_suffix(prefix_to_suffixes, hicn_name_get_prefix(&tmp), seq, + pkt_cache->prefix_keys); + } + + _prefix_map_free(prefix_to_suffixes); + }); + std::cout << "Double lookup: " << elapsed_time_double << " ms\n"; +} + +TEST_F(PacketCacheTest, PerformanceCachedLookup) { + hicn_name_t tmp = get_name_from_prefix("b001::0"); + + auto elapsed_time_single = get_execution_time([&]() { + kh_pkt_cache_prefix_t *prefix_to_suffixes = kh_init_pkt_cache_prefix(); + kh_pkt_cache_suffix_t *suffixes = + _get_suffixes(prefix_to_suffixes, hicn_name_get_prefix(&tmp), true, + pkt_cache->prefix_keys); + + // Add to hash table + for (int seq = 0; seq < N_OPS; seq++) { + hicn_name_set_suffix(&tmp, seq); + __add_suffix(suffixes, hicn_name_get_suffix(&tmp), + hicn_name_get_suffix(&tmp)); + } + + // Read from hash table + for (int seq = 0; seq < N_OPS; seq++) { + hicn_name_set_suffix(&tmp, seq); + __get_suffix(suffixes, hicn_name_get_suffix(&tmp)); + } + + _prefix_map_free(prefix_to_suffixes); + }); + std::cout << "Cached lookup: " << elapsed_time_single << " ms\n"; +} + +TEST_F(PacketCacheTest, PerformanceCachedLookupRandom) { + hicn_name_t tmp = get_name_from_prefix("b001::0"); + + // Prepare random sequence numbers + std::random_device rd; + std::mt19937 gen(rd()); + uint32_t seqs[N_OPS]; + for (int seq = 0; seq < N_OPS; seq++) seqs[seq] = seq; + std::shuffle(std::begin(seqs), std::end(seqs), gen); + + auto elapsed_time_single_rand = get_execution_time([&]() { + kh_pkt_cache_prefix_t *prefix_to_suffixes = kh_init_pkt_cache_prefix(); + kh_pkt_cache_suffix_t *suffixes = + _get_suffixes(prefix_to_suffixes, hicn_name_get_prefix(&tmp), true, + pkt_cache->prefix_keys); + + // Add to hash table + for (int seq = 0; seq < N_OPS; seq++) { + hicn_name_set_suffix(&tmp, seqs[seq]); + __add_suffix(suffixes, hicn_name_get_suffix(&tmp), + hicn_name_get_suffix(&tmp)); + } + + // Read from hash table + for (int seq = 0; seq < N_OPS; seq++) { + hicn_name_set_suffix(&tmp, seqs[seq]); + __get_suffix(suffixes, hicn_name_get_suffix(&tmp)); + } + + _prefix_map_free(prefix_to_suffixes); + }); + std::cout << "Cached lookup (rand): " << elapsed_time_single_rand << " ms\n"; +} + +TEST_F(PacketCacheTest, Clear) { + hicn_name_t tmp_name1, tmp_name2; + cs_t *cs = pkt_cache_get_cs(pkt_cache); + + // Create name and add to msgbuf pool + hicn_name_copy(&tmp_name1, &name); + hicn_name_set_suffix(&tmp_name1, 1); + msgbuf_t *tmp_msgbuf1 = msgbuf_create(msgbuf_pool, CONN_ID_2, &tmp_name1); + + // Create (another) name and add to msgbuf pool + hicn_name_copy(&tmp_name2, &name); + hicn_name_set_suffix(&tmp_name2, 2); + msgbuf_t *tmp_msgbuf2 = msgbuf_create(msgbuf_pool, CONN_ID_2, &tmp_name2); + + // Add to packet cache (2 entries in the CS, 1 in the PIT) + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + pkt_cache_add_to_pit(pkt_cache, tmp_msgbuf1, &tmp_name1); + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, tmp_msgbuf2, MSGBUF_ID_2); + + // Check stats (before clearing the packet cache) + ASSERT_EQ(pkt_cache_get_size(pkt_cache), 3u); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 2u); + ASSERT_EQ(cs->num_entries, 2); + ASSERT_EQ(cs->stats.lru.countAdds, 2u); + + // Clear packet cache (i.e. remove content packets from packet cache): + // PIT entry should still be there while CS entries are cleared + pkt_cache_cs_clear(pkt_cache); + cs = pkt_cache_get_cs(pkt_cache); + + // Check stats (after clearing the packet cache) + ASSERT_EQ(pkt_cache_get_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + ASSERT_EQ(cs->num_entries, 0); + ASSERT_EQ(cs->stats.lru.countAdds, 0u); +} 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..2e396b97d --- /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/ctrl/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); +} 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-strategy-best-path.cc b/hicn-light/src/hicn/test/test-strategy-best-path.cc new file mode 100644 index 000000000..f909c15f2 --- /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_finalize(&entry); } + + 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-local-remote.cc b/hicn-light/src/hicn/test/test-strategy-local-remote.cc new file mode 100644 index 000000000..6693e29c8 --- /dev/null +++ b/hicn-light/src/hicn/test/test-strategy-local-remote.cc @@ -0,0 +1,233 @@ +/* + * 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> +#include <arpa/inet.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/base/loop.h> +#include <hicn/config/configuration.h> +#include <hicn/core/forwarder.h> +#include <hicn/core/listener.h> +#include <hicn/core/address_pair.h> +#include <hicn/core/address.h> +#include <hicn/core/strategy.h> +#include <hicn/strategies/local_remote.h> +} + +class StrategyLocalRemoteTest : public ::testing::Test { + protected: + StrategyLocalRemoteTest() { + conf_ = configuration_create(); + MAIN_LOOP = loop_create(); + fwd_ = forwarder_create(conf_); + + /* Strategy and strategy entry */ + entry_ = { + .type = STRATEGY_TYPE_LOCAL_REMOTE, + .options = + { + .random = {}, + }, + .state = {.random = {}}, + }; + + strategy_initialize(&entry_, fwd_); + } + + virtual ~StrategyLocalRemoteTest() { + INFO("loop stopped"); + forwarder_free(fwd_); + loop_free(MAIN_LOOP); + MAIN_LOOP = NULL; + strategy_finalize(&entry_); + } + + strategy_entry_t entry_; + nexthops_t available_nexthops_ = NEXTHOPS_EMPTY; + configuration_t* conf_; + forwarder_t* fwd_; + msgbuf_t msgbuf_; +}; + +TEST_F(StrategyLocalRemoteTest, InputLocalOutputLocal) { + address_t prod_addr = ADDRESS4_LOCALHOST(12345); + address_t cons_addr = ADDRESS4_LOCALHOST(12346); + address_t listener_addr = ADDRESS4_LOCALHOST(9596); + + listener_t* listener = listener_create(FACE_TYPE_UDP_LISTENER, &listener_addr, + "lo", "lo_udp4", fwd_); + + address_pair_t pair_conn_prod = { + .local = listener_addr, + .remote = prod_addr, + }; + + address_pair_t pair_conn_cons = { + .local = listener_addr, + .remote = cons_addr, + }; + + unsigned prod_conn_id = + listener_create_connection(listener, "conp", &pair_conn_prod); + unsigned cons_conn_id = + listener_create_connection(listener, "conc", &pair_conn_cons); + + msgbuf_.connection_id = cons_conn_id; + + nexthops_add(&available_nexthops_, prod_conn_id); + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry_, &available_nexthops_, &msgbuf_); + + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)0); +} + +TEST_F(StrategyLocalRemoteTest, InputRemoteOutputRemote) { + address_t prod_addr = ADDRESS4_LOCALHOST(12345); + address_t cons_addr = ADDRESS4_LOCALHOST(12346); + address_t listener_addr = ADDRESS4_LOCALHOST(9596); + + listener_t* listener = listener_create(FACE_TYPE_UDP_LISTENER, &listener_addr, + "lo", "lo_udp4", fwd_); + + address_pair_t pair_conn_prod = { + .local = listener_addr, + .remote = prod_addr, + }; + + address_pair_t pair_conn_cons = { + .local = listener_addr, + .remote = cons_addr, + }; + + connection_t* conn; + unsigned prod_conn_id = + listener_create_connection(listener, "conp", &pair_conn_prod); + unsigned cons_conn_id = + listener_create_connection(listener, "conc", &pair_conn_cons); + + // fake two remote connections + conn = connection_table_get_by_id(forwarder_get_connection_table(fwd_), + prod_conn_id); + ASSERT_TRUE(conn != NULL); + conn->local = false; + + conn = connection_table_get_by_id(forwarder_get_connection_table(fwd_), + cons_conn_id); + ASSERT_TRUE(conn != NULL); + conn->local = false; + + msgbuf_.connection_id = cons_conn_id; + + nexthops_add(&available_nexthops_, prod_conn_id); + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry_, &available_nexthops_, &msgbuf_); + + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)0); +} + +TEST_F(StrategyLocalRemoteTest, InputLocalOutputRemote) { + address_t prod_addr = ADDRESS4_LOCALHOST(12345); + address_t cons_addr = ADDRESS4_LOCALHOST(12346); + address_t listener_addr = ADDRESS4_LOCALHOST(9596); + + listener_t* listener = listener_create(FACE_TYPE_UDP_LISTENER, &listener_addr, + "lo", "lo_udp4", fwd_); + + address_pair_t pair_conn_prod = { + .local = listener_addr, + .remote = prod_addr, + }; + + address_pair_t pair_conn_cons = { + .local = listener_addr, + .remote = cons_addr, + }; + + connection_t* conn; + unsigned prod_conn_id = + listener_create_connection(listener, "conp", &pair_conn_prod); + unsigned cons_conn_id = + listener_create_connection(listener, "conc", &pair_conn_cons); + + conn = connection_table_get_by_id(forwarder_get_connection_table(fwd_), + prod_conn_id); + ASSERT_TRUE(conn != NULL); + conn->local = false; + conn = connection_table_get_by_id(forwarder_get_connection_table(fwd_), + cons_conn_id); + ASSERT_TRUE(conn != NULL); + conn->local = true; + + msgbuf_.connection_id = cons_conn_id; + + nexthops_add(&available_nexthops_, prod_conn_id); + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry_, &available_nexthops_, &msgbuf_); + + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)1); +} + +TEST_F(StrategyLocalRemoteTest, InputRemoteOutputLocal) { + address_t cons_addr = ADDRESS4_LOCALHOST(12345); + address_t prod_addr = ADDRESS4_LOCALHOST(12346); + address_t listener_addr = ADDRESS4_LOCALHOST(9695); + + listener_t* listener = listener_create(FACE_TYPE_UDP_LISTENER, &listener_addr, + "lo", "lo_udp4", fwd_); + + address_pair_t pair_conn_prod = { + .local = listener_addr, + .remote = prod_addr, + }; + + address_pair_t pair_conn_cons = { + .local = listener_addr, + .remote = cons_addr, + }; + + connection_t* conn; + unsigned prod_conn_id = + listener_create_connection(listener, "conp", &pair_conn_prod); + unsigned cons_conn_id = + listener_create_connection(listener, "conc", &pair_conn_cons); + + conn = connection_table_get_by_id(forwarder_get_connection_table(fwd_), + prod_conn_id); + ASSERT_TRUE(conn != NULL); + conn->local = true; + conn = connection_table_get_by_id(forwarder_get_connection_table(fwd_), + cons_conn_id); + ASSERT_TRUE(conn != NULL); + conn->local = false; + + msgbuf_.connection_id = cons_conn_id; + + nexthops_add(&available_nexthops_, prod_conn_id); + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry_, &available_nexthops_, &msgbuf_); + + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)1); +} 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..1c4d824b8 --- /dev/null +++ b/hicn-light/src/hicn/test/test-strategy-replication.cc @@ -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. + */ + +#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_finalize(&entry); } + + 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 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..5fd3ab57d --- /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/util/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_TYPE_STRATEGY); + + object_type = object_from_topic(TOPIC_FACE); + EXPECT_EQ(object_type, OBJECT_TYPE_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); +} diff --git a/hicn-light/src/hicn/test/test-utils.h b/hicn-light/src/hicn/test/test-utils.h new file mode 100644 index 000000000..577629584 --- /dev/null +++ b/hicn-light/src/hicn/test/test-utils.h @@ -0,0 +1,26 @@ +#pragma once + +#include <vector> +#include <thread> +#include <numeric> + +static constexpr int N_RUNS = 100; + +// Utility function for time execution calculation +template <typename F, typename... Args> +double get_execution_time(F func, Args &&...args) { + std::vector<float> execution_times; + + for (int i = 0; i < N_RUNS; i++) { + auto start = std::chrono::high_resolution_clock::now(); + func(std::forward<Args>(args)...); + auto end = std::chrono::high_resolution_clock::now(); + + std::chrono::duration<double, std::milli> ms = end - start; + execution_times.emplace_back(ms.count()); + } + + // Calculate average + return std::reduce(execution_times.begin(), execution_times.end()) / + execution_times.size(); +}
\ 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..c742aa248 --- /dev/null +++ b/hicn-light/src/hicn/test/test_hash.cc @@ -0,0 +1,216 @@ +/* + * 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 <unordered_set> +#include <hicn/test/test-utils.h> + +extern "C" { +#include <hicn/util/hash.h> +#include <hicn/core/address_pair.h> +#include <hicn/core/listener.h> +} + +static constexpr uint32_t init_val = 2166136261UL; +static constexpr int N_HASHES = 50000; + +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) { + std::unordered_set<uint32_t> hashes; + int n_collisions = 0; + 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(uint32_t), init_val); + u32 h = hash(&seg, sizeof(seg)); + + if (hashes.find(h) != hashes.end()) n_collisions++; + hashes.insert(h); + } + EXPECT_EQ(n_collisions, 0); +} + +/*** Compare FNV with Jenkins ***/ + +typedef struct { + uint32_t data[6]; +} small_struct_t; // Same size as 'NameBitvector' + +typedef struct { + uint64_t data[32]; +} big_struct_t; // Same size as 'address_pair_t' + +TEST(HashTest, PerformanceComparisonSmallStruct) { + small_struct_t small_struct; + + // FNV + auto time_fnv = get_execution_time([&]() { + for (int i = 0; i < N_HASHES; i++) { + small_struct.data[0] = i; + cumulative_hash32(&small_struct, sizeof(small_struct_t), init_val); + } + }); + + // Jenkins + auto time_jenkins = get_execution_time([&]() { + for (int i = 0; i < N_HASHES; i++) { + small_struct.data[0] = i; + hash(&small_struct, sizeof(small_struct_t)); + } + }); + + std::cout << "Small struct (size = " << sizeof(small_struct_t) << " bytes)\n"; + std::cout << "FNV: " << time_fnv << "ms\n"; + std::cout << "Jenkins: " << time_jenkins << "ms\n"; +} + +TEST(HashTest, PerformanceComparisonBigStruct) { + big_struct_t big_struct; + + // FNV + auto time_fnv = get_execution_time([&]() { + for (int i = 0; i < N_HASHES; i++) { + big_struct.data[0] = i; + cumulative_hash32(&big_struct, sizeof(big_struct_t), init_val); + } + }); + + // Jenkins + auto time_jenkins = get_execution_time([&]() { + for (int i = 0; i < N_HASHES; i++) { + big_struct.data[0] = i; + hash(&big_struct, sizeof(big_struct_t)); + } + }); + + std::cout << "Big struct (size = " << sizeof(big_struct_t) << " bytes)\n"; + std::cout << "FNV: " << time_fnv << "ms\n"; + std::cout << "Jenkins: " << time_jenkins << "ms\n"; +} + +TEST(HashTest, CollisionsComparison) { + small_struct_t small_struct = {0}; + std::unordered_set<uint32_t> hashes; + int n_collisions_fnv = 0, n_collisions_jenkins = 0; + + // FNV + for (int i = 0; i < 10 * N_HASHES; i++) { + small_struct.data[0] = i; + uint32_t h = + cumulative_hash32(&small_struct, sizeof(small_struct_t), init_val); + + if (hashes.find(h) != hashes.end()) n_collisions_fnv++; + hashes.insert(h); + } + + hashes.clear(); + + // Jenkins + for (int i = 0; i < 10 * N_HASHES; i++) { + small_struct.data[0] = i; + uint32_t h = hash(&small_struct, sizeof(small_struct_t)); + + if (hashes.find(h) != hashes.end()) n_collisions_jenkins++; + hashes.insert(h); + } + + std::cout << "Small struct (size = " << sizeof(small_struct_t) << " bytes)\n"; + std::cout << "FNV: " << n_collisions_fnv << " collision/s\n"; + std::cout << "Jenkins: " << n_collisions_jenkins << " collision/s\n"; +}
\ 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 1ab38deba..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,32 +11,19 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) - +# 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 d8e5329b3..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; - policy_t policy; -} add_policy_command; - -typedef struct { - ip_address_t address; - uint8_t addressType; - uint8_t len; - 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 |