diff options
232 files changed, 14292 insertions, 24130 deletions
diff --git a/.gitreview b/.gitreview index 2579a4aa2..ff42a1007 100644 --- a/.gitreview +++ b/.gitreview @@ -2,3 +2,4 @@ host=gerrit.fd.io port=29418 project=hicn +defaultbranch=hicn-light-ng diff --git a/ctrl/facemgr/includes/hicn/facemgr/cfg.h b/ctrl/facemgr/includes/hicn/facemgr/cfg.h index 84d63fe73..bb436331b 100644 --- a/ctrl/facemgr/includes/hicn/facemgr/cfg.h +++ b/ctrl/facemgr/includes/hicn/facemgr/cfg.h @@ -20,7 +20,7 @@ #ifndef FACEMGR_CFG_H #define FACEMGR_CFG_H -#include <hicn/ctrl/face.h> +#include <hicn/face.h> #include <hicn/facemgr/facelet.h> #include <hicn/util/log.h> diff --git a/ctrl/facemgr/includes/hicn/facemgr/facelet.h b/ctrl/facemgr/includes/hicn/facemgr/facelet.h index cfdc5540e..9ac61ac4e 100644 --- a/ctrl/facemgr/includes/hicn/facemgr/facelet.h +++ b/ctrl/facemgr/includes/hicn/facemgr/facelet.h @@ -28,7 +28,7 @@ #include <stdbool.h> -#include <hicn/ctrl/face.h> +#include <hicn/face.h> #include <hicn/ctrl/route.h> #define MAXSZ_FACELET 1024 diff --git a/ctrl/facemgr/src/api.c b/ctrl/facemgr/src/api.c index f934883de..5d48e993f 100644 --- a/ctrl/facemgr/src/api.c +++ b/ctrl/facemgr/src/api.c @@ -63,7 +63,7 @@ #include "interfaces/android_utility/android_utility.h" #endif /* WITH_ANDROID_UTILITY */ -#include <hicn/ctrl/face.h> +#include <hicn/face.h> #include <hicn/facemgr/facelet.h> #include "common.h" #include "facelet_array.h" @@ -655,7 +655,7 @@ facemgr_facelet_satisfy_rules(facemgr_t * facemgr, facelet_t * facelet) /* Default ignore list */ if ((netdevice_type == NETDEVICE_TYPE_LOOPBACK) || (netdevice_type == NETDEVICE_TYPE_UNDEFINED)) { DEBUG("Ignored interface '%s/%s'...", netdevice.name, - netdevice_type_str[netdevice_type]); + netdevice_type_str(netdevice_type)); return -3; } @@ -666,7 +666,7 @@ facemgr_facelet_satisfy_rules(facemgr_t * facemgr, facelet_t * facelet) return -1; if (ignore) { DEBUG("Ignored interface '%s/%s'...", netdevice.name, - netdevice_type_str[netdevice_type]); + netdevice_type_str(netdevice_type)); return -3; } diff --git a/ctrl/facemgr/src/cfg.c b/ctrl/facemgr/src/cfg.c index df73acd1b..872769d23 100644 --- a/ctrl/facemgr/src/cfg.c +++ b/ctrl/facemgr/src/cfg.c @@ -182,7 +182,7 @@ void facemgr_cfg_rule_dump(facemgr_cfg_rule_t * rule) DEBUG(" <rule>"); DEBUG(" <match interface_name=%s interface_type=%s>", rule->match.interface_name, - netdevice_type_str[rule->match.interface_type]); + netdevice_type_str(rule->match.interface_type)); DEBUG(" <override>"); if (rule->override.is_face_type) { DEBUG(" <face_type>%d</face_type>", rule->override.face_type); diff --git a/ctrl/facemgr/src/facelet.c b/ctrl/facemgr/src/facelet.c index 0cf44d4dc..1958749ae 100644 --- a/ctrl/facemgr/src/facelet.c +++ b/ctrl/facemgr/src/facelet.c @@ -20,7 +20,7 @@ #include <assert.h> #include <stdbool.h> -#include <hicn/ctrl/face.h> +#include <hicn/face.h> #include <hicn/ctrl/route.h> #include <hicn/facemgr/cfg.h> #include <hicn/facemgr/facelet.h> @@ -1072,7 +1072,7 @@ facelet_snprintf(char * s, size_t size, const facelet_t * facelet) /* Netdevice type */ if (facelet_has_netdevice_type(facelet)) { rc = snprintf(cur, s + size - cur, " type=%s", - netdevice_type_str[facelet->netdevice_type]); + netdevice_type_str(facelet->netdevice_type)); if (rc < 0) return rc; cur += rc; @@ -1141,7 +1141,7 @@ facelet_snprintf(char * s, size_t size, const facelet_t * facelet) /* Admin state */ if (facelet_has_admin_state(facelet)) { rc = snprintf(cur, s + size - cur, " admin_state=%s", - face_state_str[facelet->admin_state]); + face_state_str(facelet->admin_state)); if (rc < 0) return rc; cur += rc; @@ -1152,7 +1152,7 @@ facelet_snprintf(char * s, size_t size, const facelet_t * facelet) /* State */ if (facelet_has_state(facelet)) { rc = snprintf(cur, s + size - cur, " state=%s", - face_state_str[facelet->state]); + face_state_str(facelet->state)); if (rc < 0) return rc; cur += rc; @@ -1295,7 +1295,7 @@ int facelet_snprintf_json(char * s, size_t size, const facelet_t * facelet, int if (facelet_has_netdevice_type(facelet)) { rc = snprintf(cur, s + size - cur, "%*s%s: \"%s\",\n", 4 * (indent+1), "", "\"netdevice_type\"", - netdevice_type_str[facelet->netdevice_type]); + netdevice_type_str(facelet->netdevice_type)); if (rc < 0) return rc; cur += rc; @@ -1383,7 +1383,7 @@ int facelet_snprintf_json(char * s, size_t size, const facelet_t * facelet, int if (facelet_has_admin_state(facelet)) { rc = snprintf(cur, s + size - cur, "%*s%s: \"%s\",\n", 4 * (indent+1), "", "\"admin_state\"", - face_state_str[facelet->admin_state]); + face_state_str(facelet->admin_state)); if (rc < 0) return rc; cur += rc; @@ -1395,7 +1395,7 @@ int facelet_snprintf_json(char * s, size_t size, const facelet_t * facelet, int if (facelet_has_state(facelet)) { rc = snprintf(cur, s + size - cur, "%*s%s: \"%s\",\n", 4 * (indent+1), "", "\"state\"", - face_state_str[facelet->state]); + face_state_str(facelet->state)); if (rc < 0) return rc; cur += rc; diff --git a/ctrl/facemgr/src/interfaces/android_utility/android_utility.c b/ctrl/facemgr/src/interfaces/android_utility/android_utility.c index d1fe324fb..55468baf8 100644 --- a/ctrl/facemgr/src/interfaces/android_utility/android_utility.c +++ b/ctrl/facemgr/src/interfaces/android_utility/android_utility.c @@ -20,8 +20,8 @@ #include <assert.h> +#include <hicn/face.h> #include <hicn/facemgr.h> -#include <hicn/ctrl/face.h> #include <hicn/util/log.h> #include "../../common.h" #include "../../interface.h" diff --git a/ctrl/facemgr/src/interfaces/bonjour/bonjour.h b/ctrl/facemgr/src/interfaces/bonjour/bonjour.h index fe053079d..ece6dce5d 100644 --- a/ctrl/facemgr/src/interfaces/bonjour/bonjour.h +++ b/ctrl/facemgr/src/interfaces/bonjour/bonjour.h @@ -25,7 +25,7 @@ * queries... */ -#include <hicn/ctrl/face.h> /* netdevice_t */ +#include <hicn/face.h> /* netdevice_t */ typedef struct { netdevice_t netdevice; diff --git a/ctrl/facemgr/src/interfaces/network_framework/network_framework.c b/ctrl/facemgr/src/interfaces/network_framework/network_framework.c index 2c4bff513..c8963d83a 100644 --- a/ctrl/facemgr/src/interfaces/network_framework/network_framework.c +++ b/ctrl/facemgr/src/interfaces/network_framework/network_framework.c @@ -32,7 +32,7 @@ #include <hicn/util/map.h> #include "../../common.h" -#include <hicn/ctrl/face.h> +#include <hicn/face.h> #include "../../interface.h" #include "network_framework.h" diff --git a/ctrl/libhicnctrl/includes/CMakeLists.txt b/ctrl/libhicnctrl/includes/CMakeLists.txt index 50cfa4ad5..36a55caa2 100644 --- a/ctrl/libhicnctrl/includes/CMakeLists.txt +++ b/ctrl/libhicnctrl/includes/CMakeLists.txt @@ -21,7 +21,6 @@ set(TO_INSTALL_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/ctrl.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/ctrl/api.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/ctrl/commands.h - ${CMAKE_CURRENT_SOURCE_DIR}/hicn/ctrl/face.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/ctrl/route.h PARENT_SCOPE ) diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h index c1eccbd17..c3fb62534 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h @@ -70,7 +70,7 @@ #include <hicn/util/ip_address.h> #include <hicn/ctrl/commands.h> -#include "face.h" +#include <hicn/face.h> #define HICN_DEFAULT_PORT 9695 diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/route.h b/ctrl/libhicnctrl/includes/hicn/ctrl/route.h index d7ef6a26f..b2ca04f37 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/route.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/route.h @@ -21,7 +21,7 @@ #define HICN_ROUTE_H #include <hicn/util/ip_address.h> -#include <hicn/ctrl/face.h> +#include <hicn/face.h> typedef u16 route_cost_t; diff --git a/ctrl/libhicnctrl/src/CMakeLists.txt b/ctrl/libhicnctrl/src/CMakeLists.txt index 00661a2a0..c3d843100 100644 --- a/ctrl/libhicnctrl/src/CMakeLists.txt +++ b/ctrl/libhicnctrl/src/CMakeLists.txt @@ -18,15 +18,12 @@ list(APPEND COMPILER_DEFINITIONS set(HEADER_FILES api.h commands.h - face.h ) set(UTIL_HEADER_FILES - face.h ) set(SOURCE_FILES - face.c route.c ) diff --git a/ctrl/libhicnctrl/src/api.c b/ctrl/libhicnctrl/src/api.c index 8dcb978e0..84f34d3c2 100644 --- a/ctrl/libhicnctrl/src/api.c +++ b/ctrl/libhicnctrl/src/api.c @@ -1640,7 +1640,7 @@ _hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, { int rc; DEBUG("[hc_connection_set_admin_state] connection_id/name=%s admin_state=%s async=%s", - conn_id_or_name, face_state_str[state], BOOLSTR(async)); + conn_id_or_name, face_state_str(state), BOOLSTR(async)); struct { header_control_message hdr; connection_set_admin_state_command payload; @@ -2602,11 +2602,11 @@ hc_face_snprintf(char * s, size_t size, hc_face_t * face) face->id, face->name, face->face.netdevice.index != NETDEVICE_UNDEFINED_INDEX ? face->face.netdevice.name : "*", - face_type_str[face->face.type], + face_type_str(face->face.type), local, remote, - face_state_str[face->face.state], - face_state_str[face->face.admin_state], + face_state_str(face->face.state), + face_state_str(face->face.admin_state), face->face.priority, tags); #else @@ -2614,11 +2614,11 @@ hc_face_snprintf(char * s, size_t size, hc_face_t * face) face->id, face->name, face->face.netdevice.index != NETDEVICE_UNDEFINED_INDEX ? face->face.netdevice.name : "*", - face_type_str[face->face.type], + face_type_str(face->face.type), local, remote, - face_state_str[face->face.state], - face_state_str[face->face.admin_state]); + face_state_str(face->face.state), + face_state_str(face->face.admin_state)); #endif /* WITH_POLICY */ } diff --git a/hicn-light/CMakeLists.txt b/hicn-light/CMakeLists.txt index db56feff7..4a61505ef 100644 --- a/hicn-light/CMakeLists.txt +++ b/hicn-light/CMakeLists.txt @@ -50,27 +50,29 @@ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DLIBRTA_DISABLE_VALIDATION include(IosMacros) include(WindowsMacros) -find_package_wrapper(Libparc REQUIRED) - 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) +find_package_wrapper(LibEvent REQUIRED) + if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) find_package_wrapper(Libhicn REQUIRED) else() if (DISABLE_SHARED_LIBRARIES) if (WIN32) - set(HICN_LIBRARIES ${LIBHICN_STATIC}) + set(HICN_LIBRARIES ${LIBEVENT_STATIC} ${LIBHICN_STATIC}) else () - set(HICN_LIBRARIES ${LIBHICN_STATIC} log) + set(HICN_LIBRARIES ${LIBEVENT_STATIC} ${LIBHICN_STATIC} log) endif () list(APPEND DEPENDENCIES + ${LIBEVENT_STATIC} ${LIBHICN_STATIC} ) else () set(HICN_LIBRARIES ${LIBHICN_SHARED}) list(APPEND DEPENDENCIES + ${LIBEVENT_SHARED} ${LIBHICN_SHARED} ) endif () @@ -86,7 +88,7 @@ set(LIBHICN_LIGHT_STATIC ${LIBHICN_LIGHT}.static) set(HICN_LIGHT_LINK_LIBRARIES ${LIBHICN_LIGHT_STATIC} ${HICN_LIBRARIES} - ${LIBPARC_LIBRARIES} + ${LIBEVENT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${WINDOWS_LIBRARIES} ) @@ -95,7 +97,7 @@ set(HICN_LIGHT_LINK_LIBRARIES # Include dirs -- Order does matter! list(APPEND HICN_LIGHT_INCLUDE_DIRS ${HICN_INCLUDE_DIRS} - ${LIBPARC_INCLUDE_DIRS} + ${LIBEVENT_INCLUDE_DIRS} ${WINDOWS_INCLUDE_DIRS} ) diff --git a/hicn-light/src/hicn/CMakeLists.txt b/hicn-light/src/hicn/CMakeLists.txt index 82de74ac7..29b76da25 100644 --- a/hicn-light/src/hicn/CMakeLists.txt +++ b/hicn-light/src/hicn/CMakeLists.txt @@ -3,6 +3,10 @@ include(BuildMacros) configure_file(config.h.in hicn-light/config.h @ONLY) +if(UNIX AND NOT APPLE) + set(LINUX TRUE) +endif() + if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND ENABLE_PUNTING) list(APPEND COMPILER_DEFINITIONS "-DPUNTING" @@ -10,21 +14,33 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND ENABLE_PUNTING) endif() list(APPEND COMPILER_DEFINITIONS +# "-DWITH_GRO" +# "-DWITH_GSO" +# "-DWITH_ZEROCOPY" "-DWITH_MAPME" - "-DWITH_POLICY" + "-DWITH_POLICY" # XXX Requires WITH_MAPME... enforce + "-DWITH_PREFIX_STATS" + "-DWITH_CLI" +# "-DNDEBUG=1" # disable assertions ) +if (LINUX) +list(APPEND COMPILER_DEFINITIONS + "-D_GNU_SOURCE" # batching support through struct mmsghdr +) +endif() + + if (NOT DISABLE_EXECUTABLES) add_subdirectory(command_line) 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) diff --git a/hicn-light/src/hicn/messenger/CMakeLists.txt b/hicn-light/src/hicn/base/CMakeLists.txt index 92bc13b5b..5b2677ed1 100644 --- a/hicn-light/src/hicn/messenger/CMakeLists.txt +++ b/hicn-light/src/hicn/base/CMakeLists.txt @@ -14,19 +14,25 @@ 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 + ${CMAKE_CURRENT_SOURCE_DIR}/bitmap.h + ${CMAKE_CURRENT_SOURCE_DIR}/common.h + ${CMAKE_CURRENT_SOURCE_DIR}/khash.h + ${CMAKE_CURRENT_SOURCE_DIR}/loop.h + ${CMAKE_CURRENT_SOURCE_DIR}/pool.h + ${CMAKE_CURRENT_SOURCE_DIR}/vector.h ) list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/messenger.c - ${CMAKE_CURRENT_SOURCE_DIR}/messengerRecipient.c - ${CMAKE_CURRENT_SOURCE_DIR}/missive.c - ${CMAKE_CURRENT_SOURCE_DIR}/missiveDeque.c + ${CMAKE_CURRENT_SOURCE_DIR}/loop.c + ${CMAKE_CURRENT_SOURCE_DIR}/pool.c + ${CMAKE_CURRENT_SOURCE_DIR}/vector.c ) set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) + +set(TO_INSTALL_HEADER_FILES + ${TO_INSTALL_HEADER_FILES} + ${HEADER_FILES} + PARENT_SCOPE +) diff --git a/hicn-light/src/hicn/base/bitmap.h b/hicn-light/src/hicn/base/bitmap.h new file mode 100644 index 000000000..df94b8039 --- /dev/null +++ b/hicn-light/src/hicn/base/bitmap.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file bitmap.h + * \brief Bitmap + * + * A bitmap is implemented as a wrapper over a vector made of bit elements + */ + +#ifndef UTIL_BITMAP_H +#define UTIL_BITMAP_H + +#include <string.h> +#include "common.h" + +#define BITMAP_WIDTH(bitmap) (sizeof((bitmap)[0]) * 8) + +#define bitmap_init(bitmap, size) \ + vector_init(bitmap, next_pow2(size / BITMAP_WIDTH(bitmap))) + +#define bitmap_ensure_pos(bitmap, pos) vector_ensure_pos(bitmap, pos / BITMAP_WIDTH(bitmap)) + +#define bitmap_get(bitmap, i) ((bitmap)[(i) / BITMAP_WIDTH(bitmap)] & (1 << ((i) % BITMAP_WIDTH(bitmap)))) + +#define bitmap_is_set(bitmap, i) (bitmap_get((bitmap), (i)) == 1) + +#define bitmap_is_unset(bitmap, i) (bitmap_get((bitmap), (i)) == 0) + +#define bitmap_set(bitmap, i) bitmap[(i) / BITMAP_WIDTH(bitmap)] |= 1 << ((i) % BITMAP_WIDTH(bitmap)) + +#define bitmap_unset(bitmap, i) bitmap[(i) / BITMAP_WIDTH(bitmap)] &= ~ (1 << ((i) % BITMAP_WIDTH(bitmap))) + +#define bitmap_set_to(bitmap, pos) \ +do { \ + size_t offset = (pos / BITMAP_WIDTH(bitmap) + 1); \ + memset(bitmap, 0xFF, pos * sizeof(bitmap[0])); \ + size_t set_bits = offset * BITMAP_WIDTH(bitmap); \ + for (unsigned i = pos; i < set_bits; i++) \ + bitmap_unset(bitmap, i); \ +} while(0); + +#endif /* UTIL_BITMAP_H */ diff --git a/hicn-light/src/hicn/base/common.h b/hicn-light/src/hicn/base/common.h new file mode 100644 index 000000000..996050308 --- /dev/null +++ b/hicn-light/src/hicn/base/common.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file array.h + * \brief Fixed-size pool allocator + */ + +#ifndef UTIL_COMMON_H +#define UTIL_COMMON_H + +#define round_pow2(x, pow2) ((x + pow2 - 1) & ~(pow2 - 1)) + +#define _SIZEOF_ALIGNED(x, size) round_pow2(sizeof(x), size) +#define SIZEOF_ALIGNED(x) _SIZEOF_ALIGNED(x, sizeof(void*)) + +/* Definitions for builtins unavailable on MSVC */ +#if defined(_MSC_VER) && !defined(__clang__) +#include <intrin.h> + +uint32_t __inline __builtin_ctz(uint32_t value) { + uint32_t trailing_zero = 0; + if (_BitScanForward(&trailing_zero, value)) + return trailing_zero; + else + return 32; +} + +uint32_t __inline __builtin_clz(uint32_t value) { + uint32_t leading_zero = 0; + if (_BitScanReverse(&leading_zero, value)) + return 31 - leading_zero; + else + return 32; +} + +uint32_t __inline __builtin_clzll(uint64_t value) { + uint32_t leading_zero = 0; + if (_BitScanReverse64(&leading_zero, value)) + return 63 - leading_zero; + else + return 64; +} + +#define __builtin_clzl __builtin_clzll +#endif + +#define next_pow2(x) (x == 1 ? 1 : 1<<(64-__builtin_clzl(x-1))) + +#endif /* UTIL_COMMON_H */ diff --git a/hicn-light/src/hicn/base/hash.h b/hicn-light/src/hicn/base/hash.h new file mode 100644 index 000000000..0b6a659bd --- /dev/null +++ b/hicn-light/src/hicn/base/hash.h @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * \file hash.h + * \brief Simple non-cryptographic hash implementation. + * + * Two helpers are provided : + * hash(buf, len) : hash a buffer <buf> of length <len> + * hash_struct(buf) : hash a buffer corresponding to an allocated struct + * + * This file consists in excerpts from Jenkins hash (public domain). + * http://www.burtleburtle.net/bob/c/lookup3.c + */ +#ifndef UTIL_HASH_H +#define UTIL_HASH_H + +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) +# define HASH_LITTLE_ENDIAN 1 +# define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 1 +#else +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t)1<<(n)) +#define hashmask(n) (hashsize(n)-1) +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + +static inline +uint32_t hashlittle( const void *key, size_t length, uint32_t initval) +{ + uint32_t a,b,c; /* internal state */ + union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)length) + initval; + + u.ptr = key; + if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : return c; + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; + case 11: c+=((uint32_t)k[10])<<16; + case 10: c+=((uint32_t)k[9])<<8; + case 9 : c+=k[8]; + case 8 : b+=((uint32_t)k[7])<<24; + case 7 : b+=((uint32_t)k[6])<<16; + case 6 : b+=((uint32_t)k[5])<<8; + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3])<<24; + case 3 : a+=((uint32_t)k[2])<<16; + case 2 : a+=((uint32_t)k[1])<<8; + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} + +/* Helpers */ + +#define HASH_INITVAL 1 +//#define hash(buf, len) (hash_t)hashlittle(buf, len, HASH_INITVAL) +#define hash(buf, len) hashlittle(buf, len, HASH_INITVAL) +#define hash_struct(buf) hash(buf, sizeof(buf)) + +#define str_hash(str) (hash(str, strlen(str))) +#define str_hash_eq(a, b) (str_hash(b) - str_hash(a)) + +#endif /* UTIL_JENKINS_HASH_H */ diff --git a/hicn-light/src/hicn/base/khash.h b/hicn-light/src/hicn/base/khash.h new file mode 100644 index 000000000..f75f3474c --- /dev/null +++ b/hicn-light/src/hicn/base/khash.h @@ -0,0 +1,627 @@ +/* The MIT License + + Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +/* + An example: + +#include "khash.h" +KHASH_MAP_INIT_INT(32, char) +int main() { + int ret, is_missing; + khiter_t k; + khash_t(32) *h = kh_init(32); + k = kh_put(32, h, 5, &ret); + kh_value(h, k) = 10; + k = kh_get(32, h, 10); + is_missing = (k == kh_end(h)); + k = kh_get(32, h, 5); + kh_del(32, h, k); + for (k = kh_begin(h); k != kh_end(h); ++k) + if (kh_exist(h, k)) kh_value(h, k) = 1; + kh_destroy(32, h); + return 0; +} +*/ + +/* + 2013-05-02 (0.2.8): + + * Use quadratic probing. When the capacity is power of 2, stepping function + i*(i+1)/2 guarantees to traverse each bucket. It is better than double + hashing on cache performance and is more robust than linear probing. + + In theory, double hashing should be more robust than quadratic probing. + However, my implementation is probably not for large hash tables, because + the second hash function is closely tied to the first hash function, + which reduce the effectiveness of double hashing. + + Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php + + 2011-12-29 (0.2.7): + + * Minor code clean up; no actual effect. + + 2011-09-16 (0.2.6): + + * The capacity is a power of 2. This seems to dramatically improve the + speed for simple keys. Thank Zilong Tan for the suggestion. Reference: + + - http://code.google.com/p/ulib/ + - http://nothings.org/computer/judy/ + + * Allow to optionally use linear probing which usually has better + performance for random input. Double hashing is still the default as it + is more robust to certain non-random input. + + * Added Wang's integer hash function (not used by default). This hash + function is more robust to certain non-random input. + + 2011-02-14 (0.2.5): + + * Allow to declare global functions. + + 2009-09-26 (0.2.4): + + * Improve portability + + 2008-09-19 (0.2.3): + + * Corrected the example + * Improved interfaces + + 2008-09-11 (0.2.2): + + * Improved speed a little in kh_put() + + 2008-09-10 (0.2.1): + + * Added kh_clear() + * Fixed a compiling error + + 2008-09-02 (0.2.0): + + * Changed to token concatenation which increases flexibility. + + 2008-08-31 (0.1.2): + + * Fixed a bug in kh_get(), which has not been tested previously. + + 2008-08-31 (0.1.1): + + * Added destructor +*/ + + +#ifndef __AC_KHASH_H +#define __AC_KHASH_H + +/*! + @header + + Generic hash table library. + */ + +#define AC_VERSION_KHASH_H "0.2.8" + +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +/* compiler specific configuration */ + +#if UINT_MAX == 0xffffffffu +typedef unsigned int khint32_t; +#elif ULONG_MAX == 0xffffffffu +typedef unsigned long khint32_t; +#endif + +#if ULONG_MAX == ULLONG_MAX +typedef unsigned long khint64_t; +#else +typedef unsigned long long khint64_t; +#endif + +#ifndef kh_inline +#ifdef _MSC_VER +#define kh_inline __inline +#else +#define kh_inline inline +#endif +#endif /* kh_inline */ + +#ifndef klib_unused +#if (defined __clang__ && __clang_major__ >= 3) || (defined __GNUC__ && __GNUC__ >= 3) +#define klib_unused __attribute__ ((__unused__)) +#else +#define klib_unused +#endif +#endif /* klib_unused */ + +typedef khint32_t khint_t; +typedef khint_t khiter_t; + +#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2) +#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1) +#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3) +#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1))) +#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1))) +#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1))) +#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1)) + +#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4) + +#ifndef kroundup32 +#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x)) +#endif + +#ifndef kcalloc +#define kcalloc(N,Z) calloc(N,Z) +#endif +#ifndef kmalloc +#define kmalloc(Z) malloc(Z) +#endif +#ifndef krealloc +#define krealloc(P,Z) realloc(P,Z) +#endif +#ifndef kfree +#define kfree(P) free(P) +#endif + +static const double __ac_HASH_UPPER = 0.77; + +#define __KHASH_TYPE(name, khkey_t, khval_t) \ + typedef struct kh_##name##_s { \ + khint_t n_buckets, size, n_occupied, upper_bound; \ + khint32_t *flags; \ + khkey_t *keys; \ + khval_t *vals; \ + } kh_##name##_t; + +#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \ + extern kh_##name##_t *kh_init_##name(void); \ + extern void kh_destroy_##name(kh_##name##_t *h); \ + extern void kh_clear_##name(kh_##name##_t *h); \ + extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \ + extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \ + extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \ + extern void kh_del_##name(kh_##name##_t *h, khint_t x); + +#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ + SCOPE kh_##name##_t *kh_init_##name(void) { \ + return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \ + } \ + SCOPE void kh_destroy_##name(kh_##name##_t *h) \ + { \ + if (h) { \ + kfree((void *)h->keys); kfree(h->flags); \ + kfree((void *)h->vals); \ + kfree(h); \ + } \ + } \ + SCOPE void kh_clear_##name(kh_##name##_t *h) \ + { \ + if (h && h->flags) { \ + memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \ + h->size = h->n_occupied = 0; \ + } \ + } \ + SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \ + { \ + if (h->n_buckets) { \ + khint_t k, i, last, mask, step = 0; \ + mask = h->n_buckets - 1; \ + k = __hash_func(key); i = k & mask; \ + last = i; \ + while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ + i = (i + (++step)) & mask; \ + if (i == last) return h->n_buckets; \ + } \ + return __ac_iseither(h->flags, i)? h->n_buckets : i; \ + } else return 0; \ + } \ + SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \ + { /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \ + khint32_t *new_flags = 0; \ + khint_t j = 1; \ + { \ + kroundup32(new_n_buckets); \ + if (new_n_buckets < 4) new_n_buckets = 4; \ + if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \ + else { /* hash table size to be changed (shrink or expand); rehash */ \ + new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ + if (!new_flags) return -1; \ + memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ + if (h->n_buckets < new_n_buckets) { /* expand */ \ + khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ + if (!new_keys) { kfree(new_flags); return -1; } \ + h->keys = new_keys; \ + if (kh_is_map) { \ + khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \ + if (!new_vals) { kfree(new_flags); return -1; } \ + h->vals = new_vals; \ + } \ + } /* otherwise shrink */ \ + } \ + } \ + if (j) { /* rehashing is needed */ \ + for (j = 0; j != h->n_buckets; ++j) { \ + if (__ac_iseither(h->flags, j) == 0) { \ + khkey_t key = h->keys[j]; \ + khval_t val; \ + khint_t new_mask; \ + new_mask = new_n_buckets - 1; \ + if (kh_is_map) val = h->vals[j]; \ + __ac_set_isdel_true(h->flags, j); \ + while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \ + khint_t k, i, step = 0; \ + k = __hash_func(key); \ + i = k & new_mask; \ + while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \ + __ac_set_isempty_false(new_flags, i); \ + if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \ + { khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \ + if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \ + __ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \ + } else { /* write the element and jump out of the loop */ \ + h->keys[i] = key; \ + if (kh_is_map) h->vals[i] = val; \ + break; \ + } \ + } \ + } \ + } \ + if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \ + h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ + if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \ + } \ + kfree(h->flags); /* free the working space */ \ + h->flags = new_flags; \ + h->n_buckets = new_n_buckets; \ + h->n_occupied = h->size; \ + h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \ + } \ + return 0; \ + } \ + SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \ + { \ + khint_t x; \ + if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \ + if (h->n_buckets > (h->size<<1)) { \ + if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \ + *ret = -1; return h->n_buckets; \ + } \ + } else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \ + *ret = -1; return h->n_buckets; \ + } \ + } /* TODO: to implement automatically shrinking; resize() already support shrinking */ \ + { \ + khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \ + x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \ + if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \ + else { \ + last = i; \ + while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ + if (__ac_isdel(h->flags, i)) site = i; \ + i = (i + (++step)) & mask; \ + if (i == last) { x = site; break; } \ + } \ + if (x == h->n_buckets) { \ + if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \ + else x = i; \ + } \ + } \ + } \ + if (__ac_isempty(h->flags, x)) { /* not present at all */ \ + h->keys[x] = key; \ + __ac_set_isboth_false(h->flags, x); \ + ++h->size; ++h->n_occupied; \ + *ret = 1; \ + } else if (__ac_isdel(h->flags, x)) { /* deleted */ \ + h->keys[x] = key; \ + __ac_set_isboth_false(h->flags, x); \ + ++h->size; \ + *ret = 2; \ + } else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \ + return x; \ + } \ + SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \ + { \ + if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \ + __ac_set_isdel_true(h->flags, x); \ + --h->size; \ + } \ + } + +#define KHASH_DECLARE(name, khkey_t, khval_t) \ + __KHASH_TYPE(name, khkey_t, khval_t) \ + __KHASH_PROTOTYPES(name, khkey_t, khval_t) + +#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ + __KHASH_TYPE(name, khkey_t, khval_t) \ + __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) + +#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ + KHASH_INIT2(name, static kh_inline klib_unused, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) + +/* --- BEGIN OF HASH FUNCTIONS --- */ + +/*! @function + @abstract Integer hash function + @param key The integer [khint32_t] + @return The hash value [khint_t] + */ +#define kh_int_hash_func(key) (khint32_t)(key) +/*! @function + @abstract Integer comparison function + */ +#define kh_int_hash_equal(a, b) ((a) == (b)) +/*! @function + @abstract 64-bit integer hash function + @param key The integer [khint64_t] + @return The hash value [khint_t] + */ +#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11) +/*! @function + @abstract 64-bit integer comparison function + */ +#define kh_int64_hash_equal(a, b) ((a) == (b)) +/*! @function + @abstract const char* hash function + @param s Pointer to a null terminated string + @return The hash value + */ +static kh_inline khint_t __ac_X31_hash_string(const char *s) +{ + khint_t h = (khint_t)*s; + if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s; + return h; +} +/*! @function + @abstract Another interface to const char* hash function + @param key Pointer to a null terminated string [const char*] + @return The hash value [khint_t] + */ +#define kh_str_hash_func(key) __ac_X31_hash_string(key) +/*! @function + @abstract Const char* comparison function + */ +#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0) + +static kh_inline khint_t __ac_Wang_hash(khint_t key) +{ + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + return key; +} +#define kh_int_hash_func2(key) __ac_Wang_hash((khint_t)key) + +/* --- END OF HASH FUNCTIONS --- */ + +/* Other convenient macros... */ + +/*! + @abstract Type of the hash table. + @param name Name of the hash table [symbol] + */ +#define khash_t(name) kh_##name##_t + +/*! @function + @abstract Initiate a hash table. + @param name Name of the hash table [symbol] + @return Pointer to the hash table [khash_t(name)*] + */ +#define kh_init(name) kh_init_##name() + +/*! @function + @abstract Destroy a hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + */ +#define kh_destroy(name, h) kh_destroy_##name(h) + +/*! @function + @abstract Reset a hash table without deallocating memory. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + */ +#define kh_clear(name, h) kh_clear_##name(h) + +/*! @function + @abstract Resize a hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + @param s New size [khint_t] + */ +#define kh_resize(name, h, s) kh_resize_##name(h, s) + +/*! @function + @abstract Insert a key to the hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + @param k Key [type of keys] + @param r Extra return code: -1 if the operation failed; + 0 if the key is present in the hash table; + 1 if the bucket is empty (never used); 2 if the element in + the bucket has been deleted [int*] + @return Iterator to the inserted element [khint_t] + */ +#define kh_put(name, h, k, r) kh_put_##name(h, k, r) + +/*! @function + @abstract Retrieve a key from the hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + @param k Key [type of keys] + @return Iterator to the found element, or kh_end(h) if the element is absent [khint_t] + */ +#define kh_get(name, h, k) kh_get_##name(h, k) + +/*! @function + @abstract Remove a key from the hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + @param k Iterator to the element to be deleted [khint_t] + */ +#define kh_del(name, h, k) kh_del_##name(h, k) + +/*! @function + @abstract Test whether a bucket contains data. + @param h Pointer to the hash table [khash_t(name)*] + @param x Iterator to the bucket [khint_t] + @return 1 if containing data; 0 otherwise [int] + */ +#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x))) + +/*! @function + @abstract Get key given an iterator + @param h Pointer to the hash table [khash_t(name)*] + @param x Iterator to the bucket [khint_t] + @return Key [type of keys] + */ +#define kh_key(h, x) ((h)->keys[x]) + +/*! @function + @abstract Get value given an iterator + @param h Pointer to the hash table [khash_t(name)*] + @param x Iterator to the bucket [khint_t] + @return Value [type of values] + @discussion For hash sets, calling this results in segfault. + */ +#define kh_val(h, x) ((h)->vals[x]) + +/*! @function + @abstract Alias of kh_val() + */ +#define kh_value(h, x) ((h)->vals[x]) + +/*! @function + @abstract Get the start iterator + @param h Pointer to the hash table [khash_t(name)*] + @return The start iterator [khint_t] + */ +#define kh_begin(h) (khint_t)(0) + +/*! @function + @abstract Get the end iterator + @param h Pointer to the hash table [khash_t(name)*] + @return The end iterator [khint_t] + */ +#define kh_end(h) ((h)->n_buckets) + +/*! @function + @abstract Get the number of elements in the hash table + @param h Pointer to the hash table [khash_t(name)*] + @return Number of elements in the hash table [khint_t] + */ +#define kh_size(h) ((h)->size) + +/*! @function + @abstract Get the number of buckets in the hash table + @param h Pointer to the hash table [khash_t(name)*] + @return Number of buckets in the hash table [khint_t] + */ +#define kh_n_buckets(h) ((h)->n_buckets) + +/*! @function + @abstract Iterate over the entries in the hash table + @param h Pointer to the hash table [khash_t(name)*] + @param kvar Variable to which key will be assigned + @param vvar Variable to which value will be assigned + @param code Block of code to execute + */ +#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \ + for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ + if (!kh_exist(h,__i)) continue; \ + (kvar) = kh_key(h,__i); \ + (vvar) = kh_val(h,__i); \ + code; \ + } } + +/*! @function + @abstract Iterate over the values in the hash table + @param h Pointer to the hash table [khash_t(name)*] + @param vvar Variable to which value will be assigned + @param code Block of code to execute + */ +#define kh_foreach_value(h, vvar, code) { khint_t __i; \ + for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ + if (!kh_exist(h,__i)) continue; \ + (vvar) = kh_val(h,__i); \ + code; \ + } } + +/* More convenient interfaces */ + +/*! @function + @abstract Instantiate a hash set containing integer keys + @param name Name of the hash table [symbol] + */ +#define KHASH_SET_INIT_INT(name) \ + KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal) + +/*! @function + @abstract Instantiate a hash map containing integer keys + @param name Name of the hash table [symbol] + @param khval_t Type of values [type] + */ +#define KHASH_MAP_INIT_INT(name, khval_t) \ + KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal) + +/*! @function + @abstract Instantiate a hash set containing 64-bit integer keys + @param name Name of the hash table [symbol] + */ +#define KHASH_SET_INIT_INT64(name) \ + KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal) + +/*! @function + @abstract Instantiate a hash map containing 64-bit integer keys + @param name Name of the hash table [symbol] + @param khval_t Type of values [type] + */ +#define KHASH_MAP_INIT_INT64(name, khval_t) \ + KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal) + +typedef const char *kh_cstr_t; +/*! @function + @abstract Instantiate a hash map containing const char* keys + @param name Name of the hash table [symbol] + */ +#define KHASH_SET_INIT_STR(name) \ + KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal) + +/*! @function + @abstract Instantiate a hash map containing const char* keys + @param name Name of the hash table [symbol] + @param khval_t Type of values [type] + */ +#define KHASH_MAP_INIT_STR(name, khval_t) \ + KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal) + +#endif /* __AC_KHASH_H */ diff --git a/hicn-light/src/hicn/base/loop.c b/hicn-light/src/hicn/base/loop.c new file mode 100644 index 000000000..fecab9c5f --- /dev/null +++ b/hicn-light/src/hicn/base/loop.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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/thread.h> +#include <fcntl.h> // fcntl +#ifdef WITH_THREAD +#include <pthread.h> +#endif /* WITH_THREAD */ +#include <stdlib.h> +#include <sys/timerfd.h> +#include <unistd.h> // fcntl + +#include <hicn/util/log.h> +#include <hicn/util/map.h> + +#include "loop.h" + +loop_t * MAIN_LOOP = NULL; + +/** + * \brief Holds all callback parameters + */ +typedef struct { + void * owner; + fd_callback_t callback; + void * data; +} cb_wrapper_args_t; + +TYPEDEF_MAP_H(event_map, int, struct event *); +TYPEDEF_MAP(event_map, int, struct event *, int_cmp, int_snprintf, generic_snprintf); + +/* Map that associates timer fds with their associated cb_wrapper_args_t */ +TYPEDEF_MAP_H(timer_fd_map, int, cb_wrapper_args_t *); +TYPEDEF_MAP(timer_fd_map, int, cb_wrapper_args_t *, int_cmp, int_snprintf, generic_snprintf); + +struct loop_s { + struct event_base * event_base; + event_map_t * event_map; + timer_fd_map_t * timer_fd_map; +#ifdef WITH_THREAD + pthread_t thread; +#endif /* WITH_THREAD */ +}; + +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) + goto ERR_EVENT; + + loop->event_map = event_map_create(); + if (!loop->event_map) { + ERROR("[loop_create] Failed to create event_map"); + goto ERR_EVENT_MAP; + } + + loop->timer_fd_map = timer_fd_map_create(); + if (!loop->timer_fd_map) { + ERROR("[loop_create] Failed to create timer_fd_map"); + goto ERR_TIMER_FD_MAP; + } + + event_set_log_callback(NULL); + + return loop; + + timer_fd_map_free(loop->timer_fd_map); +ERR_TIMER_FD_MAP: + event_map_free(loop->event_map); +ERR_EVENT_MAP: + event_base_free(loop->event_base); +ERR_EVENT: + free(loop); +ERR_MALLOC: + return NULL; +} + +void +loop_free(loop_t * loop) +{ + /* + * Release all timer cb_wrapper_args_t + * + * We need to stop all timers, this should release associated fd events at + * the same time... for that reason, this code has to be called before + * releasing events + */ + + int * timer_fd_map_array; + int n = timer_fd_map_get_key_array(loop->timer_fd_map, &timer_fd_map_array); + if (n < 0) { + ERROR("[loop_free] Could not get event map array"); + } else { + for (unsigned i = 0; i < n; i++) { + int fd = timer_fd_map_array[i]; + if (loop_unregister_timer(loop, fd) < 0) { + ERROR("[loop_free] Could not unregister timer"); + } + } + free(timer_fd_map_array); + } + timer_fd_map_free(loop->timer_fd_map); + + /* Release all events */ + + int * event_map_array; + n = event_map_get_key_array(loop->event_map, &event_map_array); + if (n < 0) { + ERROR("[loop_free] Could not get event map array"); + } else { + for (unsigned i = 0; i < n; i++) { + int fd = event_map_array[i]; + if (loop_unregister_fd(loop, fd) < 0) { + ERROR("[loop_free] Could not unregister fd"); + } + } + free(event_map_array); + } + event_map_free(loop->event_map); + + event_base_free(loop->event_base); + + free(loop); +} + +int +loop_dispatch(loop_t * loop) +{ +#ifdef WITH_THREAD + if (pthread_create(&loop->thread, NULL, (void * (*)(void *))event_base_dispatch, loop->event_base)) { + fprintf(stderr, "Error creating thread\n"); + return -1; + } +#else + event_base_dispatch(loop->event_base); +#endif /* WITH_THREAD */ + return 0; +} + +int +loop_undispatch(loop_t * loop) +{ +#ifdef WITH_THREAD + DEBUG("Waiting for loop to terminate..."); + if(pthread_join(loop->thread, NULL)) { + fprintf(stderr, "Error joining thread\n"); + return -1; + } + DEBUG("Loop terminated !"); +#endif /* WITH_THREAD */ + return 0; +} + +void +loop_break(loop_t * loop) +{ + event_base_loopbreak(loop->event_base); +} + +void cb_wrapper(evutil_socket_t fd, short what, void * arg) { + cb_wrapper_args_t * cb_wrapper_args = arg; + cb_wrapper_args->callback(cb_wrapper_args->owner, fd, cb_wrapper_args->data); +} + +int +loop_register_fd(loop_t * loop, int fd, void * callback_owner, + fd_callback_t callback, void * callback_data) +{ + /* This will be freed with the event */ + cb_wrapper_args_t * cb_wrapper_args = malloc(sizeof(cb_wrapper_args_t)); + *cb_wrapper_args = (cb_wrapper_args_t) { + .owner = callback_owner, + .callback = callback, + .data = callback_data, + }; + + evutil_make_socket_nonblocking(fd); + struct event * event = event_new(loop->event_base, fd, EV_READ | EV_PERSIST, cb_wrapper, cb_wrapper_args); + if (!event) { + ERROR("[loop_register_fd] event_new"); + goto ERR_EVENT_NEW; + } + + if (event_add(event, NULL) < 0) { + ERROR("[loop_register_fd] event_add"); + goto ERR_EVENT_ADD; + } + + if (event_map_add(loop->event_map, fd, event) < 0) { + ERROR("[loop_register_fd] event_map_add"); + goto ERR_EVENT_MAP; + } + + return 0; + +ERR_EVENT_MAP: +ERR_EVENT_ADD: + event_free(event); +ERR_EVENT_NEW: + return -1; +} + +int +loop_unregister_fd(loop_t * loop, int fd) +{ + struct event * event = NULL; + + if (event_map_remove(loop->event_map, fd, &event) < 0) { + ERROR("[loop_unregister_fd] Error removing event associated to fd"); + return -1; + } + + assert(event); + + cb_wrapper_args_t * cb_wrapper_args = event_get_callback_arg(event); + free(cb_wrapper_args); + + event_del(event); + event_free(event); + + return 0; +} + +int +loop_timer_callback(loop_t * loop, int fd, void * data) +{ + char buf[1024]; /* size is not important */ + cb_wrapper_args_t * cb_wrapper_args = data; + while (read(fd, &buf, sizeof(buf)) > 0) + ; + + int rc = cb_wrapper_args->callback(cb_wrapper_args->owner, fd, + cb_wrapper_args->data); + + return rc; +} + +int +_loop_register_timer(loop_t * loop, unsigned delay_ms, void * owner, + fd_callback_t callback, void * data) +{ + int fd = timerfd_create(CLOCK_MONOTONIC, 0); + if (fd == -1) { + perror("timerfd_create"); + return -1; + } + + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + perror("fcntl"); + return -1; + } + + struct itimerspec ts = { + .it_interval = { + .tv_sec = delay_ms / 1000, + .tv_nsec = (delay_ms % 1000) * 1000000, + }, + .it_value = { + .tv_sec = delay_ms / 1000, + .tv_nsec = (delay_ms % 1000) * 1000000, + } + }; + + if (timerfd_settime(fd, 0, &ts, NULL) == -1) { + perror("timerfd_settime"); + return -1; + } + + /* This should be freed together with the timer release */ + cb_wrapper_args_t * cb_wrapper_args = malloc(sizeof(cb_wrapper_args_t)); + *cb_wrapper_args = (cb_wrapper_args_t) { + .owner = owner, + .callback = callback, + .data = data, + }; + + if (timer_fd_map_add(loop->timer_fd_map, fd, cb_wrapper_args) < 0) { + ERROR("[loop_register_timer] Could not add cb_wrapper to timer map"); + return -1; + } + + if (loop_register_fd(loop, fd, loop, + (fd_callback_t) loop_timer_callback, cb_wrapper_args) < 0) { + ERROR("[loop_register_timer] Error registering fd to event loop"); + return -1; + } + + return fd; +} + +int +loop_unregister_timer(loop_t * loop, int fd) +{ + struct itimerspec ts = { + .it_interval = { + .tv_sec = 0, + .tv_nsec = 0, + }, + .it_value = { /* This value disables the timer */ + .tv_sec = 0, + .tv_nsec = 0, + } + }; + ts.it_value.tv_sec = 0; + + if (timerfd_settime(fd, 0, &ts, NULL) == -1) { + perror("timerfd_settime"); + return -1; + } + + cb_wrapper_args_t * cb_wrapper_args; + if (timer_fd_map_remove(loop->timer_fd_map, fd, &cb_wrapper_args) < 0) { + ERROR("[loop_unregister_timer] Could not remove cb_wrapper from timer map"); + return -1; + } + assert(cb_wrapper_args); + free(cb_wrapper_args); + + if (loop_unregister_fd(loop, fd) < 0) { + ERROR("[loop_unregister_timer] Error unregistering fd from event loop"); + return -1; + } + + return 0; +} diff --git a/hicn-light/src/hicn/base/loop.h b/hicn-light/src/hicn/base/loop.h new file mode 100644 index 000000000..b73d91738 --- /dev/null +++ b/hicn-light/src/hicn/base/loop.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 FACEMGR_LOOP_H +#define FACEMGR_LOOP_H + +/* fd & timer callbacks */ + +typedef int (*fd_callback_t)(void * owner, int fd, void * data); + +typedef struct { + int fd; + void *owner; + fd_callback_t callback; + //int (*callback)(void * owner, int fd, void * data); + void *data; +} fd_callback_data_t; + +/* loop */ + +typedef struct loop_s loop_t; + +/* Global loop to be used in single threaded applications */ +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 + * \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_undispatch(loop_t * loop); + +/** + * \brief Breaks out of the loop + * \param [in] loop - Pointer to the loop instance + */ +void loop_break(loop_t * loop); + +/** + * \brief Registers a new file descriptor to the event loop + * \param [in] fd - File descriptor to register + * \param [in] callback_owner - Pointer to the owner of the callack (first + * parameter of callback function) + * \param [in] callback - Callback function + * \param [in] callback_data - User data to pass alongside callback invocation + * \return 0 in case of success, -1 otherwise + */ +int +loop_register_fd(loop_t * loop, int fd, void * callback_owner, + fd_callback_t callback, void * callback_data); + +/** + * \brief Unregisters a file descriptor from the event loop + * \param [in] fd - File descriptor to unregister + * \return 0 in case of success, -1 otherwise + */ +int +loop_unregister_fd(loop_t * loop, int fd); + +int _loop_register_timer(loop_t * loop, unsigned delay_ms, void * owner, + fd_callback_t callback, void * data); + +#define loop_register_timer(loop, delay_ms, owner, callback, data) \ + _loop_register_timer(loop, delay_ms, owner, (fd_callback_t) callback, data) + +int +loop_unregister_timer(loop_t * loop, int fd); + +#endif /* FACEMGR_LOOP_H */ diff --git a/hicn-light/src/hicn/base/pool.c b/hicn-light/src/hicn/base/pool.c new file mode 100644 index 000000000..abca86422 --- /dev/null +++ b/hicn-light/src/hicn/base/pool.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file pool.c + * \brief Implementation of fixed-size pool allocator + */ + +#include <stdlib.h> // calloc + +#include "common.h" +#include "pool.h" + + +/** + * \brief Initialize the pool data structure + * \param [in,out] pool - Pointer to the pool structure storage + * \param [in] elt_size - Size of elements in vector + * \param [in] max_elts - Maximum size + * + * Note that an empty pool might be equal to NULL + */ +void +_pool_init(void ** pool_ptr, size_t elt_size, size_t max_elts) +{ + pool_hdr_t * ph = calloc(POOL_HDRLEN + elt_size * max_elts, 1); + if (!ph) + abort(); + + /* Free indices */ + off_t * free_indices; + vector_init(free_indices, max_elts); + + uint_fast32_t * fb = ph->free_bitmap; + bitmap_init(fb, max_elts); + bitmap_set_to(fb, max_elts); + + for(unsigned i = 0; i < max_elts; i++) + free_indices[i] = (max_elts - 1) - i; + ph->free_indices = free_indices; + + *pool_ptr = (uint8_t*)ph + POOL_HDRLEN; +} + +void +_pool_free(void ** pool_ptr) +{ + free(pool_hdr(*pool_ptr)); + *pool_ptr = NULL; +} + +void +_pool_resize(void ** pool_ptr, size_t elt_size) +{ + pool_hdr_t * ph = pool_hdr(*pool_ptr); + size_t old_elts = ph->max_elts; + size_t new_elts = old_elts * 2; + + /* Double pool storage */ + ph = realloc(ph, POOL_HDRLEN + new_elts * elt_size); + if (!ph) + abort(); + ph->max_elts = new_elts; + + /* + * After resize, the pool will have old_elts free indices, ranging from + * old_elts to (new_elts - 1) + */ + off_t * free_indices = ph->free_indices; + vector_ensure_pos(free_indices, old_elts); + for (unsigned i = 0; i < old_elts; i++) + free_indices[i] = new_elts - 1 - i; + + /* Reassign pool pointer */ + *pool_ptr = (uint8_t*)ph + POOL_HDRLEN; +} diff --git a/hicn-light/src/hicn/base/pool.h b/hicn-light/src/hicn/base/pool.h new file mode 100644 index 000000000..360dedc5e --- /dev/null +++ b/hicn-light/src/hicn/base/pool.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file array.h + * \brief Fixed-size pool allocator + */ + +#ifndef UTIL_POOL_H +#define UTIL_POOL_H + +#include <stdint.h> + +#include "bitmap.h" +#include "vector.h" + +/** Local variable naming macro. */ +#define _pool_var(v) _pool_##v + + +typedef struct { + size_t elt_size; + size_t max_elts; + uint_fast32_t * free_bitmap; + off_t * free_indices; /* vector of free indices */ +} pool_hdr_t; + +void _pool_init(void ** pool_ptr, size_t elt_size, size_t max_elts); +void _pool_free(void ** pool_ptr); +void _pool_resize(void ** pool_ptr, size_t elt_size); + +#define POOL_HDRLEN SIZEOF_ALIGNED(pool_hdr_t) + +/* This header actually prepends the actual content of the pool */ +#define pool_hdr(pool) ((pool_hdr_t *)((uint8_t*)(pool) - POOL_HDRLEN)) + +// XXX TODO need common naming for cur_len, len, max_len +#define pool_elts(pool) \ + (pool_hdr(pool)->max_elts - vector_len((pool_hdr(pool)->free_indices))) + +#define pool_init(pool, max_elts) \ + _pool_init((void**)&pool, sizeof(pool[0]), max_elts); + +#define pool_free(pool) \ + _pool_free((void**)&pool); + +#define pool_get(pool, elt) \ +do { \ + pool_hdr_t * _pool_var(ph) = pool_hdr(pool); \ + u64 _pool_var(l) = vector_len(_pool_var(ph)->free_indices); \ + if (_pool_var(l) == 0) \ + _pool_resize((void**)&(pool), sizeof((pool)[0])); \ + off_t _pool_var(free_id) = \ + _pool_var(ph)->free_indices[_pool_var(l) - 1]; \ + elt = (pool) + _pool_var(free_id); \ + memset(&elt, 0, sizeof(elt)); \ +} while(0) + +#define pool_put(pool, elt) \ +do { \ + pool_hdr_t * _pool_var(ph) = pool_hdr(pool); \ + u64 _pool_var(l) = vector_len(_pool_var(ph)->free_indices); \ + vector_ensure_pos(_pool_var(ph)->free_indices, _pool_var(l)); \ + _pool_var(ph)->free_indices[_pool_var(l)] = (elt) - (pool); \ + vector_len(_pool_var(ph)->free_indices)++; \ + bitmap_set(_pool_var(ph)->free_bitmap, _pool_var(l)); \ +} while(0) + +#define pool_validate_id(pool, id) \ + bitmap_is_unset((pool_hdr(pool))->free_bitmap, (id)) + +#define pool_enumerate(pool, i, eltp, BODY) \ +do { \ + pool_hdr_t * _pool_var(ph) = pool_hdr(pool); \ + uint_fast32_t * _pool_var(fb) = _pool_var(ph)->free_bitmap; \ + for((i) = 0; (i) < _pool_var(ph)->max_elts; (i)++) { \ + if (bitmap_is_unset(_pool_var(fb), (i))) \ + continue; \ + eltp = (pool) + (i); \ + do { BODY; } while (0); \ + } \ +} while(0) + +#define pool_foreach(pool, eltp, BODY) \ +do { \ + unsigned _pool_var(i); \ + pool_enumerate((pool), _pool_var(i), (eltp), BODY); \ +} while(0) + + + +#endif /* UTIL_POOL_H */ diff --git a/hicn-light/src/hicn/base/vector.c b/hicn-light/src/hicn/base/vector.c new file mode 100644 index 000000000..00ed7c305 --- /dev/null +++ b/hicn-light/src/hicn/base/vector.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file vector.c + * \brief Implementation of resizeable static array + */ + +#include <stddef.h> // size_t +#include <stdlib.h> // calloc + +#include "vector.h" + +void +_vector_init(void ** vector_ptr, size_t elt_size, size_t max_elts) +{ + vector_hdr_t * vh = calloc(VECTOR_HDRLEN + elt_size * max_elts, 1); + *vector_ptr = (uint8_t*)vh - VECTOR_HDRLEN; +} + +void +_vector_free(void ** vector_ptr) +{ + free(vector_hdr(*vector_ptr)); + *vector_ptr = NULL; +} + +void +_vector_resize(void ** vector_ptr, size_t elt_size, off_t pos) +{ + vector_hdr_t * vh = vector_hdr(*vector_ptr); + size_t new_elts = (pos > 0) ? next_pow2(pos) : vh->max_elts * 2; + + /* Double the allocated vector size */ + vh = realloc(vh, VECTOR_HDRLEN + new_elts * elt_size); + if (!vh) + abort(); + vh->max_elts = new_elts; + + /* Reassign vector pointer */ + *vector_ptr = (uint8_t*) + VECTOR_HDRLEN; +} diff --git a/hicn-light/src/hicn/base/vector.h b/hicn-light/src/hicn/base/vector.h new file mode 100644 index 000000000..9b99ba813 --- /dev/null +++ b/hicn-light/src/hicn/base/vector.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file vector.h + * \brief Resizeable static array + */ + +#ifndef UTIL_VECTOR_H +#define UTIL_VECTOR_H + +#include <stddef.h> +#include <stdint.h> +#include <sys/types.h> + +#include "common.h" + +/** Local variable naming macro. */ +#define _vector_var(v) _vector_##v + +typedef struct { + size_t num_elts; + size_t max_elts; +} vector_hdr_t; + +void _vector_init(void ** vector_ptr, size_t elt_size, size_t max_elts); +void _vector_free(void ** vector_ptr); +void _vector_resize(void ** vector_ptr, size_t elt_size, off_t pos); + +/* Make sure elements following the header are aligned */ +#define VECTOR_HDRLEN SIZEOF_ALIGNED(vector_hdr_t) + +/* This header actually prepends the actual content of the vector */ +#define vector_hdr(vector) ((vector_hdr_t *)((uint8_t*)vector - VECTOR_HDRLEN)) + +#define vector_init(vector, max_elts) \ + _vector_init((void**)&vector, sizeof(vector[0]), max_elts) + +#define vector_free(vector) \ + _vector_free(&vector) + +#define vector_len(vector) (vector_hdr(vector)->num_elts) + +#define vector_resize(vector) _vector_resize((void**)&(vector), sizeof((vector)[0]), 0) + +#define vector_ensure_pos(vector, pos) \ +do { \ + if ((pos) >= vector_len(vector)) \ + _vector_resize((void**)&(vector), sizeof((vector)[0]), pos); \ +} while(0) + +#define vector_push(vector, elt) \ +do { \ + vector_ensure_pos(vector_len(vector)); \ + vector[vector_len(vector)++] = elt; \ +} while(0) + +#endif /* UTIL_VECTOR_H */ diff --git a/hicn-light/src/hicn/command_line/CMakeLists.txt b/hicn-light/src/hicn/command_line/CMakeLists.txt index 16c23dc5c..217e00fd3 100644 --- a/hicn-light/src/hicn/command_line/CMakeLists.txt +++ b/hicn-light/src/hicn/command_line/CMakeLists.txt @@ -1,2 +1,2 @@ -add_subdirectory(controller) +#add_subdirectory(controller) add_subdirectory(daemon) diff --git a/hicn-light/src/hicn/command_line/controller/CMakeLists.txt b/hicn-light/src/hicn/command_line/controller/CMakeLists.txt index 949cace28..26d4c0b63 100644 --- a/hicn-light/src/hicn/command_line/controller/CMakeLists.txt +++ b/hicn-light/src/hicn/command_line/controller/CMakeLists.txt @@ -12,7 +12,7 @@ # limitations under the License. list(APPEND CONTROLLER_SRC - hicnLightControl_main.c +hicnLightControl_main.c ) if (NOT DISABLE_EXECUTABLES) build_executable(${HICN_LIGHT_CONTROL} diff --git a/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c b/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c index 8f56dc60a..cc91e5a70 100644 --- a/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c +++ b/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c @@ -41,7 +41,6 @@ #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> diff --git a/hicn-light/src/hicn/command_line/daemon/hicnLightDaemon_main.c b/hicn-light/src/hicn/command_line/daemon/hicnLightDaemon_main.c index 89a80d0b1..f3fbf84dd 100644 --- a/hicn-light/src/hicn/command_line/daemon/hicnLightDaemon_main.c +++ b/hicn-light/src/hicn/command_line/daemon/hicnLightDaemon_main.c @@ -26,136 +26,131 @@ #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> +#include <hicn/util/log.h> +#include <hicn/base/loop.h> static void _printRed(const char *output) { #ifndef _WIN32 - printf("\033[0;31m%s", output); + 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); + 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); + 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); + 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"); + _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"); + 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"); + 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"); + 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"); + 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); + 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); } +#if 0 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); - } + 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); + } } /** @@ -163,251 +158,261 @@ static void _setLogLevelToLevel(int logLevelArray[LoggerFacility_END], * 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; + 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); + } } - } - - if (facility < LoggerFacility_END) { - _setLogLevelToLevel(logLevelArray, facility, levelString); - } else { - printf("Invalid facility string %s\n", facilityString); - _usage(EXIT_FAILURE); - } } - } - parcMemory_Deallocate((void **)&tofree); + parcMemory_Deallocate((void **)&tofree); } +#endif #ifndef _WIN32 static void _daemonize(void) { - if (getppid() == 1) { - // already a daemon - return; - } + if (getppid() == 1) { + // already a daemon + return; + } - int forkReturn = fork(); - parcTrapUnexpectedStateIf(forkReturn < 0, "Fork error") + int forkReturn = fork(); + assert(forkReturn >= 0); - if (forkReturn > 0) { - // parent exits - exit(EXIT_SUCCESS); - } + if (forkReturn > 0) { + // parent exits + exit(EXIT_SUCCESS); + } - // Child daemon detaches - printf("child continuing, pid = %u\n", getpid()); + // Child daemon detaches + printf("child continuing, pid = %u\n", getpid()); - // get a new process group independent from old parent - setsid(); + // get a new process group independent from old parent + setsid(); - /* close all descriptors */ + /* close all descriptors */ #ifdef __ANDROID__ - for (int i = sysconf(_SC_OPEN_MAX); i >= 0; --i) { - close(i); - } + for (int i = sysconf(_SC_OPEN_MAX); i >= 0; --i) { + close(i); + } #else - for (int i = getdtablesize(); i >= 0; --i) { - close(i); - } + 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 + // 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); + assert(nullfile >= 0); + + int ret; + ret = dup(nullfile); + assert(ret == 1); + ret = dup(nullfile); + assert(ret == 2); + (void)ret; /* UNUSED */ + + // forwarder will capture signals } #endif +#if 0 static Logger *_createLogfile(const char *logfile) { #ifndef _WIN32 - int logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, S_IWUSR | S_IRUSR); + 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); + 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); - } + 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); + chmod(logfile, S_IRWXU); #endif - PARCFileOutputStream *fos = parcFileOutputStream_Create(logfd); - PARCOutputStream *pos = parcFileOutputStream_AsOutputStream(fos); - PARCLogReporter *reporter = parcLogReporterFile_Create(pos); + PARCFileOutputStream *fos = parcFileOutputStream_Create(logfd); + PARCOutputStream *pos = parcFileOutputStream_AsOutputStream(fos); + PARCLogReporter *reporter = parcLogReporterFile_Create(pos); - Logger *logger = logger_Create(reporter, parcClock_Wallclock()); + Logger *logger = logger_Create(reporter, parcClock_Wallclock()); - parcOutputStream_Release(&pos); - parcLogReporter_Release(&reporter); + parcOutputStream_Release(&pos); + parcLogReporter_Release(&reporter); - return logger; + return logger; } +#endif int main(int argc, const char *argv[]) { - _displayForwarderLogo(); + _displayForwarderLogo(); #ifndef _WIN32 - bool daemon = false; + bool daemon = false; #else - WSADATA wsaData = {0}; - WSAStartup(MAKEWORD(2, 2), &wsaData); + 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++; + 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); + } + +#if 0 + int logLevelArray[LoggerFacility_END]; + for (int i = 0; i < LoggerFacility_END; i++) { + logLevelArray[i] = -1; + } +#endif + + 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; + } 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); + } else if (strcmp(argv[i], "--capacity") == 0 || + strcmp(argv[i], "-c") == 0) { + capacity = atoi(argv[i + 1]); + i++; +#if 0 + } 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++; +#endif + } else { + _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); + // 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(); - } + 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]); +#if 0 + 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); } - } - // this will update the clock to the tick clock - Forwarder *forwarder = forwarder_Create(logger); + for (int i = 0; i < LoggerFacility_END; i++) { + if (logLevelArray[i] > -1) { + logger_SetLogLevel(logger, i, logLevelArray[i]); + } + } +#endif - if (forwarder == NULL) { - logger_Log(logger, LoggerFacility_Core, PARCLogLevel_Error, "daemon", - "Forwarder initialization failed. Are you running it with sudo " - "privileges?"); - return -1; - } + forwarder_t * forwarder = forwarder_create(); + if (!forwarder) { + ERROR("Forwarder initialization failed. Are you running it with sudo privileges?"); + return -1; + } - Configuration *configuration = forwarder_GetConfiguration(forwarder); + configuration_t * configuration = forwarder_get_configuration(forwarder); + if (capacity > -1) { + configuration_content_store_set_size(configuration, capacity); + } - if (capacity > -1) { - configuration_SetObjectStoreSize(configuration, capacity); - } + forwarder_setup_local_listeners(forwarder, port); + if (configFileName) { + forwarder_read_config(forwarder, configFileName); + } - forwarder_SetupLocalListeners(forwarder, port); - if (configFileName) { - forwarder_SetupFromConfigFile(forwarder, configFileName); - } + INFO("hicn-light running port %d configuration-port %d", port, + configurationPort); - Dispatcher *dispatcher = forwarder_GetDispatcher(forwarder); + /* Main loop */ + MAIN_LOOP = loop_create(); + if (loop_dispatch(MAIN_LOOP) < 0) { + ERROR("Failed to run main loop"); + return EXIT_FAILURE; + } - logger_Log(logger, LoggerFacility_Core, PARCLogLevel_Alert, "daemon", - "hicn-light running port %d configuration-port %d", port, - configurationPort); + INFO("hicn-light exiting port %d", port); - dispatcher_Run(dispatcher); + if (loop_undispatch(MAIN_LOOP) < 0) { + ERROR("Failed to terminate main loop"); + return EXIT_FAILURE; + } - logger_Log(logger, LoggerFacility_Core, PARCLogLevel_Alert, "daemon", - "hicn-light exiting port %d", port); + forwarder_free(forwarder); - forwarder_Destroy(&forwarder); + loop_free(MAIN_LOOP); + MAIN_LOOP = NULL; #ifndef _WIN32 - sleep(2); + sleep(2); #else - Sleep(2000); - WSACleanup(); + Sleep(2000); + WSACleanup(); #endif - logger_Release(&logger); - return 0; + 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..9db413867 100644 --- a/hicn-light/src/hicn/config/CMakeLists.txt +++ b/hicn-light/src/hicn/config/CMakeLists.txt @@ -14,95 +14,93 @@ 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}/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}/configuration_file.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 ) list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/commandOps.c - ${CMAKE_CURRENT_SOURCE_DIR}/commandParser.c +# ${CMAKE_CURRENT_SOURCE_DIR}/commandOps.c +# ${CMAKE_CURRENT_SOURCE_DIR}/commandParser.c ${CMAKE_CURRENT_SOURCE_DIR}/configuration.c - ${CMAKE_CURRENT_SOURCE_DIR}/configurationFile.c - ${CMAKE_CURRENT_SOURCE_DIR}/configurationListeners.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlState.c - ${CMAKE_CURRENT_SOURCE_DIR}/symbolicNameTable.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlAdd.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddConnection.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddRoute.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddPolicy.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddListener.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlList.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlListConnections.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlListListeners.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlListRoutes.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlListPolicies.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlQuit.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemove.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveListener.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveConnection.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveRoute.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePolicy.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlRoot.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlSet.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlSetDebug.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlUnset.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlUnsetDebug.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMe.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeEnable.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeDiscovery.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeTimescale.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeRetx.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheServe.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheStore.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheClear.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlCache.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlSetStrategy.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlSetWldr.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlAddPunting.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePunting.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlUpdate.c - ${CMAKE_CURRENT_SOURCE_DIR}/controlUpdateConnection.c + ${CMAKE_CURRENT_SOURCE_DIR}/configuration_file.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 ) set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) diff --git a/hicn-light/src/hicn/config/configuration.c b/hicn-light/src/hicn/config/configuration.c index 39d327165..a6f78f9c2 100644 --- a/hicn-light/src/hicn/config/configuration.c +++ b/hicn-light/src/hicn/config/configuration.c @@ -26,531 +26,424 @@ #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 <parc/algol/parc_Unsigned.h> -#include <hicn/io/listener.h> //the listener list -#include <hicn/io/listenerSet.h> // needed to print +#include <hicn/core/listener.h> //the listener list +#include <hicn/core/listener_table.h> #include <hicn/utils/commands.h> #include <hicn/utils/utils.h> - -#include <hicn/utils/address.h> +#include <hicn/utils/punting.h> +#include <hicn/util/log.h> +#include <hicn/face.h> #define ETHERTYPE 0x0801 +#define DEFAULT_COST 1 +#define DEFAULT_PORT 1234 + +#define make_ack(msg) msg->header.messageType = ACK_LIGHT +#define make_nack(msg) msg->header.messageType = NACK_LIGHT + +#define msg_malloc_list(msg, N) \ +do { \ + msg = malloc(sizeof((msg)->header) + N * sizeof((msg)->payload)); \ + (msg)->header.messageType = RESPONSE_LIGHT; \ + (msg)->header.length = (uint16_t)(N); \ +} while(0); + +/* + * XXX TODO + * + * Currently the strategy map only stores the strategy type, but it should be + * extended with strategy options. + * + * Or maybe we simply remove this map like in VPP. + * + * prefix_str -> strategy_type + */ +KHASH_INIT(strategy_map, const char *, unsigned, 0, str_hash, str_hash_eq); -struct configuration { - Forwarder *forwarder; - Logger *logger; +struct configuration_s { + forwarder_t * forwarder; - size_t maximumContentObjectStoreSize; + size_t maximumContentObjectStoreSize; - // map from prefix (parcString) to strategy (parcString) - PARCHashMap *strategy_map; + // map from prefix (parcString) to strategy (parcString) + kh_strategy_map_t * strategy_map; - // translates between a symblic name and a connection id - SymbolicNameTable *symbolicNameTable; +#if 0 + // translates between a symblic name and a connection id + // XXX This might be moved as two indices in the listener and connection + // tables to be widely reachable... this has nothing to do with + // configuration. + SymbolicNameTable *symbolic_nameTable; +#endif }; // ======================================================================================== -Connection * -getConnectionBySymbolicOrId(Configuration * config, const char * symbolicOrConnid) +// conn_id = UINT_MAX when symbolic_name is not found +static inline +unsigned +_symbolic_to_conn_id(configuration_t * config, const char * symbolicOrConnid, + bool allow_self, unsigned ingress_id) { - 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"); + unsigned conn_id; + const connection_table_t * table = forwarder_get_connection_table(config->forwarder); + + if (allow_self && strcmp(symbolicOrConnid, "SELF") == 0) { + conn_id = ingress_id; + } else if (utils_IsNumber(symbolicOrConnid)) { + // case for conn_id as input + // XXX type issue ! XXX No check, see man + int id = atoi(symbolicOrConnid); + if (id < 0) + return CONNECTION_ID_UNDEFINED; + conn_id = id; + + if (!connection_table_validate_id(table, conn_id)) { + ERROR("ConnID not found, check list connections"); + conn_id = CONNECTION_ID_UNDEFINED; + } + } else { + // case for symbolic as input: check if symbolic name can be resolved + conn_id = connection_table_get_id_by_name(table, symbolicOrConnid); + if (connection_id_is_valid(conn_id)) { + DEBUG("Resolved symbolic name '%s' to conn_id %u", symbolicOrConnid, conn_id); + } else { + WARN("Symbolic name '%s' could not be resolved", symbolicOrConnid); + } } - } - return conn; + return conn_id; } -// ======================================================================================== +#define symbolic_to_conn_id(config, symbolic) _symbolic_to_conn_id(config, symbolic, false, 0) + +#define symbolic_to_conn_id_self(config, symbolic, ingress_id) \ + _symbolic_to_conn_id(config, symbolic, true, ingress_id) -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; +connection_t * +getConnectionBySymbolicOrId(configuration_t * config, const char * symbolicOrConnid) +{ + connection_table_t * table = forwarder_get_connection_table(config->forwarder); + unsigned conn_id = symbolic_to_conn_id(config, symbolicOrConnid); + if (!connection_id_is_valid(conn_id)) + return NULL; + + /* conn_id is assumed validated here */ + return connection_table_at(table, conn_id); } -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; +// ======================================================================================== + +configuration_t * +configuration_create(forwarder_t * forwarder) +{ + assert(forwarder); + + configuration_t * config = malloc(sizeof(configuration_t)); + if (!config) + return NULL; + + config->forwarder = forwarder; + config->maximumContentObjectStoreSize = 100000; + config->strategy_map = kh_init_strategy_map(); +#if 0 + config->symbolic_nameTable = symbolic_nameTable_Create(); +#endif + + return config; } -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; +void +configuration_free(configuration_t * config) +{ + assert(config); - bool success = false; + kh_destroy_strategy_map(config->strategy_map); +#if 0 + symbolic_nameTable_Destroy(&config->symbolic_nameTable); +#endif + free(config); +} - const char *symbolicOrConnid = control->symbolicOrConnid; +/* Listener */ - 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); +uint8_t * +configuration_on_listener_add(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); - // 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 - } + msg_listener_add_t * msg = (msg_listener_add_t *)packet; + cmd_listener_add_t * control = &msg->payload; - } 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); + forwarder_t * forwarder = configuration_get_forwarder(config); + assert(forwarder); - } 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 - } - } + listener_table_t * table = forwarder_get_listener_table(forwarder); + assert(table); - // generate ACK/NACK - struct iovec *response; + /* Verify that the listener DOES NOT exist */ + listener_t * listener = listener_table_get_by_name(table, control->symbolic); + if (listener) + goto NACK; - if (success) { // ACK - response = utils_CreateAck(header, control, sizeof(add_route_command)); - } else { // NACK - response = utils_CreateNack(header, control, sizeof(add_route_command)); - } + address_t address; + if (address_from_ip_port(&address, control->family, &control->address, + control->port) < 0) { + WARN("Unsupported address type for HICN (ingress id %u): " + "must be either IPV4 or IPV6", ingress_id); + return false; + } - return response; -} + // NOTE: interface_name is expected NULL for hICN listener + face_type_t face_type; + if (!face_type_is_defined(control->listener_type)) + goto NACK; + face_type = (face_type_t)control->listener_type; -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; + listener = listener_create(face_type, &address, control->interface_name, control->symbolic, forwarder); + if (!listener) + goto NACK; - const char *symbolicOrConnid = control->symbolicOrConnid; + make_ack(msg); + return (uint8_t*)msg; - if (utils_IsNumber(symbolicOrConnid)) { - // case for connid as input - unsigned connid = (unsigned)strtold(symbolicOrConnid, NULL); - ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder); +NACK: + make_ack(msg); + return (uint8_t*)msg; +} - // check if interface index present in the fwd table - if (connectionTable_FindById(table, connid)) { - success = forwarder_RemoveRoute(config->forwarder, control, connid); +uint8_t * +configuration_on_listener_remove(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); + + msg_listener_remove_t * msg = (msg_listener_remove_t*)packet; + cmd_listener_remove_t * control = &msg->payload; + + const char *symbolicOrListenerid = control->symbolicOrListenerid; + off_t listener_id; + listener_t * listener; + + listener_table_t * listener_table = forwarder_get_listener_table(config->forwarder); + + // Factor like for connections + if (utils_IsNumber(symbolicOrListenerid)) { + // XXX no check + int id = atoi(symbolicOrListenerid); + if (id < 0) + goto NACK; + listener_id = id; + + listener = listener_table_get_by_id(listener_table, listener_id); + if (!listener) { + ERROR("Listener Id not found, check list listeners"); + goto NACK; + } } else { - logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO, - PARCLogLevel_Error, __func__, - "ConnID not found, check list connections"); - // failure + listener = listener_table_get_by_name(listener_table, symbolicOrListenerid); + listener_id = listener_table_get_listener_id(listener_table, listener); } - } 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 - } - } + connection_table_t * table = forwarder_get_connection_table(config->forwarder); + connection_t * connection; + connection_table_foreach(table, connection, { + const address_pair_t * pair = connection_get_pair(connection); + if (!address_equals(listener_get_address(listener), + address_pair_get_local(pair))) + continue; + + unsigned conn_id = connection_table_get_connection_id(table, connection); + /* Remove connection from the FIB */ + forwarder_remove_connection_id_from_routes(config->forwarder, conn_id); + + /* Remove connection */ + connection_table_remove_by_id(table, conn_id); + +#if 0 + const char *symbolicConnection = + symbolic_nameTable_GetNameByIndex(config->symbolic_nameTable, conn_id); + symbolic_nameTable_Remove(config->symbolic_nameTable, symbolicConnection); +#endif + }); - // generate ACK/NACK - struct iovec *response; + /* Remove listener */ + listener_table_remove_by_id(listener_table, listener_id); - if (success) { // ACK - response = utils_CreateAck(header, control, sizeof(remove_route_command)); - } else { // NACK - response = utils_CreateNack(header, control, sizeof(remove_route_command)); - } + make_ack(msg); + return (uint8_t*)msg; - return response; +NACK: + make_ack(msg); + return (uint8_t*)msg; } -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); +static inline +void +fill_listener_command(configuration_t * config, listener_t * listener, + cmd_listener_list_item_t * cmd) +{ + assert(config); + 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->ss_family) { + case AF_INET: + sin = (struct sockaddr_in *) addr; + cmd->family = AF_INET; + cmd->address.v4.as_inaddr = sin->sin_addr; + cmd->port = sin->sin_port; + break; + case AF_INET6: + sin6 = (struct sockaddr_in6 *) addr; + cmd->family = AF_INET6; + cmd->address.v6.as_in6addr = sin6->sin6_addr; + cmd->port = sin6->sin6_port; + break; + default: + break; } - 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); - } - } + 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); +} - // send response - header_control_message *header = request[0].iov_base; - header->messageType = RESPONSE_LIGHT; - header->length = (unsigned)effective_payloadSize; +uint8_t * +configuration_on_listener_list(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); + + listener_table_t * table = forwarder_get_listener_table(config->forwarder); + size_t n = listener_table_len(table); - struct iovec *response = - parcMemory_AllocateAndClear(sizeof(struct iovec) * 2); + msg_listener_list_reply_t * msg; + msg_malloc_list(msg, n) + if (!msg) + return NULL; - 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; + cmd_listener_list_item_t * payload = &msg->payload; + listener_t * listener; + listener_table_foreach(table, listener, { + fill_listener_command(config, listener, payload); + payload++; + }); - fibEntryList_Destroy(&fibList); - return response; + return (uint8_t*)msg; } -static void configuration_SendResponse(Configuration *config, struct iovec *msg, - unsigned egressId) { - ConnectionTable *connectionTable = - forwarder_GetConnectionTable(config->forwarder); - const Connection *conn = connectionTable_FindById(connectionTable, egressId); +/* Connection */ - if (conn == NULL) { - return; - } - connection_SendIOVBuffer(conn, msg, 2); -} +uint8_t * +configuration_on_connection_add(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); -struct iovec *configuration_ProcessCreateTunnel(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - add_connection_command *control = request[1].iov_base; - - bool success = false; - - Connection *conn; - const char *symbolicName = control->symbolic; - - Address *source = NULL; - Address *destination = NULL; - - if (symbolicNameTable_Exists(config->symbolicNameTable, symbolicName)) { - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error, - __func__, "Connection symbolic name already exists"); - goto ERR; - } - - if (control->ipType == ADDR_INET) { - source = - addressFromInaddr4Port(&control->localIp.v4.as_u32, &control->localPort); - destination = - addressFromInaddr4Port(&control->remoteIp.v4.as_u32, &control->remotePort); - } else if (control->ipType == ADDR_INET6) { - source = - addressFromInaddr6Port(&control->localIp.v6.as_in6addr, &control->localPort); - destination = - addressFromInaddr6Port(&control->remoteIp.v6.as_in6addr, &control->remotePort); - } else { - printf("Invalid IP type.\n"); // will generate a Nack - } - - AddressPair *pair = addressPair_Create(source, destination); - conn = (Connection *)connectionTable_FindByAddressPair( - forwarder_GetConnectionTable(config->forwarder), pair); - - addressPair_Release(&pair); - - if (!conn) { - IoOperations *ops = NULL; - switch (control->connectionType) { - case TCP_CONN: - // logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error, - // __func__, - // "Unsupported tunnel protocol: TCP"); - ops = tcpTunnel_Create(config->forwarder, source, destination); - break; - case UDP_CONN: - ops = udpTunnel_Create(config->forwarder, source, destination); - break; - case GRE_CONN: - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error, - __func__, "Unsupported tunnel protocol: GRE"); - break; -#if !defined(__APPLE__) && !defined(_WIN32) && defined(PUNTING) - case HICN_CONN: - ops = hicnTunnel_Create(config->forwarder, source, destination); - break; -#endif /* __APPLE__ _WIN32*/ - default: - logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error, - __func__, "Unsupported tunnel protocol: %d", - control->connectionType); - break; - } + msg_connection_add_t * msg = (msg_connection_add_t*)packet; + cmd_connection_add_t * control = &msg->payload; - if (ops != NULL) { - Connection *conn = connection_Create(ops); -#ifdef WITH_POLICY - connection_SetTags(conn, control->tags); - connection_SetPriority(conn, control->priority); -#endif /* WITH_POLICY */ + const char *symbolic_name = control->symbolic; - connection_SetAdminState(conn, control->admin_state); + face_type_t face_type; + if (!face_type_is_defined(control->type)) + goto NACK; + face_type = (face_type_t)control->type; - connectionTable_Add(forwarder_GetConnectionTable(config->forwarder), - conn); - symbolicNameTable_Add(config->symbolicNameTable, symbolicName, - connection_GetConnectionId(conn)); + connection_table_t * table = forwarder_get_connection_table(config->forwarder); + if (connection_table_get_by_name(table, symbolic_name)) { + ERROR("Connection symbolic name already exists"); + goto NACK; + } + + address_pair_t pair; + if (address_pair_from_ip_port(&pair, control->family, + &control->local_ip, control->local_port, + &control->remote_ip, control->remote_port) < 0) + goto NACK; + connection_t * connection = connection_table_get_by_pair(table, &pair); #ifdef WITH_MAPME - /* Hook: new connection created through the control protocol */ - forwarder_onConnectionEvent(config->forwarder, conn, CONNECTION_EVENT_CREATE); + connection_event_t event; #endif /* WITH_MAPME */ - success = true; + if (!connection) { + connection = connection_create(face_type, symbolic_name, &pair, config->forwarder); + if (!connection) { + ERROR("Failed to create %s connection", + face_type_str(connection->type)); + goto NACK; + } - } else { - printf("failed, could not create IoOperations"); - } +#ifdef WITH_MAPME + event = CONNECTION_EVENT_CREATE; +#endif /* WITH_MAPME */ - } else { + } 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); + event = CONNECTION_EVENT_UPDATE; #endif /* WITH_MAPME */ - if (source) - addressDestroy(&source); - if (destination) - addressDestroy(&destination); - - success = true; #else - printf("failed, symbolic name or connection already exist\n"); + ERROR("failed, symbolic name or connection already exist\n"); + goto NACK; #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)); -} +#ifdef WITH_POLICY + connection_set_tags(connection, control->tags); + connection_set_priority(connection, control->priority); +#endif /* WITH_POLICY */ -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"); - } - } + connection_set_admin_state(connection, control->admin_state); - // generate ACK/NACK - struct iovec *response; +#ifdef WITH_MAPME + /* Hook: new connection created through the control protocol */ + forwarder_on_connection_event(config->forwarder, connection, event); +#endif /* WITH_MAPME */ - if (success) { // ACK - response = - utils_CreateAck(header, control, sizeof(remove_listener_command)); - } else { // NACK - response = - utils_CreateNack(header, control, sizeof(remove_connection_command)); - } + make_ack(msg); + return (uint8_t*)msg; - return response; +NACK: + make_ack(msg); + return (uint8_t*)msg; } /** * Add an IP-based tunnel. * - * The call cal fail if the symbolic name is a duplicate. It could also fail if + * 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). * @@ -558,952 +451,966 @@ struct iovec *configuration_ProcessRemoveListener(Configuration *config, * @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; +uint8_t * +configuration_on_connection_remove(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); - bool success = false; + msg_connection_remove_t * msg = (msg_connection_remove_t*)packet; + cmd_connection_remove_t * control = &msg->payload; - 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); + unsigned conn_id = symbolic_to_conn_id_self(config, control->symbolicOrConnid, + ingress_id); + if (!connection_id_is_valid(conn_id)) + goto NACK; -#ifdef WITH_MAPME - /* Hook: new connection created through the control protocol */ - forwarder_onConnectionEvent(config->forwarder, NULL, CONNECTION_EVENT_DELETE); -#endif /* WITH_MAPME */ + /* Remove connection from the FIB */ + forwarder_remove_connection_id_from_routes(config->forwarder, conn_id); - 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); + /* Remove connection */ + connection_table_t *table = forwarder_get_connection_table(config->forwarder); + connection_table_remove_by_id(table, conn_id); + +#if 0 + /* Remove connection from symbolic_nameTable */ + const char *symbolicConnection = symbolic_nameTable_GetNameByIndex(config->symbolic_nameTable, conn_id); + symbolic_nameTable_Remove(config->symbolic_nameTable, symbolicConnection); +#endif #ifdef WITH_MAPME - /* Hook: new connection created through the control protocol */ - forwarder_onConnectionEvent(config->forwarder, NULL, CONNECTION_EVENT_DELETE); + /* Hook: new connection created through the control protocol */ + forwarder_on_connection_event(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 - } + make_ack(msg); + return (uint8_t*)msg; - } 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); +NACK: + make_ack(msg); + return (uint8_t*)msg; +} -#ifdef WITH_MAPME - /* Hook: new connection created through the control protocol */ - forwarder_onConnectionEvent(config->forwarder, NULL, CONNECTION_EVENT_DELETE); -#endif /* WITH_MAPME */ +static inline +void +tolower_str(char * str) { + char * p = str; + for (; *p; p++) + *p = tolower(*p); +} - 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 - } - } +static inline +void +fill_connections_command(configuration_t * config, connection_t * connection, + cmd_connection_list_item_t * cmd) +{ + assert(config); + assert(connection); + assert(cmd); + struct sockaddr_in * sin; + struct sockaddr_in6 * sin6; + const address_pair_t * pair = connection_get_pair(connection); +#if 0 + const char *name = symbolic_nameTable_GetNameByIndex(config->symbolic_nameTable, + connection_get_id(connection)); +#endif + + *cmd = (cmd_connection_list_item_t) { + .id = connection_get_id(connection), + .state = connection_get_state(connection), + .admin_state = connection_get_admin_state(connection), + .type = connection_get_type(connection), +#ifdef WITH_POLICY + .priority = connection_get_priority(connection), + .tags = connection_get_tags(connection), +#endif /* WITH_POLICY */ + }; + + snprintf(cmd->name, SYMBOLIC_NAME_LEN, "%s", connection_get_name(connection)); + tolower_str(cmd->name); + + snprintf(cmd->interface_name, SYMBOLIC_NAME_LEN, "%s", + connection_get_interface_name(connection)); + + switch(pair->local.ss_family) { + case AF_INET: + cmd->family = AF_INET; + + sin = (struct sockaddr_in *)(&pair->local); + cmd->local_port = sin->sin_port; + cmd->local_ip.v4.as_inaddr = sin->sin_addr; - // generate ACK/NACK - struct iovec *response; + sin = (struct sockaddr_in *)(&pair->remote); + cmd->remote_port = sin->sin_port; + cmd->remote_ip.v4.as_inaddr = sin->sin_addr; + break; - if (success) { // ACK - response = - utils_CreateAck(header, control, sizeof(remove_connection_command)); - } else { // NACK - response = - utils_CreateNack(header, control, sizeof(remove_connection_command)); - } + case AF_INET6: + cmd->family = AF_INET6; - return response; + sin6 = (struct sockaddr_in6 *)(&pair->local); + cmd->local_port = sin6->sin6_port; + cmd->local_ip.v6.as_in6addr = sin6->sin6_addr; + + sin6 = (struct sockaddr_in6 *)(&pair->remote); + cmd->remote_port = sin6->sin6_port; + cmd->remote_ip.v6.as_in6addr = sin6->sin6_addr; + break; + + default: + break; + } } -void _parc_strlwr(char *string) { - char *p = string; - while ((*p = tolower(*p))) { - p++; - } +uint8_t * +configuration_on_connection_list(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); + + connection_table_t *table = forwarder_get_connection_table(config->forwarder); + size_t n = connection_table_len(table); + + msg_connection_list_reply_t * msg; + msg_malloc_list(msg, n) + if (!msg) + return NULL; + + cmd_connection_list_item_t * payload = &msg->payload; + connection_t * connection; + connection_table_foreach(table, connection, { + fill_connections_command(config, connection, payload); + payload++; + }); + + return (uint8_t*)msg; } -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; +uint8_t * +configuration_on_connection_set_admin_state(configuration_t * config, + uint8_t * packet, unsigned ingress_id) +{ + assert(config); + assert(packet); - // allocate payload, cast from void* to uint8_t* fot bytes granularity - uint8_t *payloadResponse = parcMemory_AllocateAndClear( - sizeof(list_connections_command) * connectionList_Length(connList)); + msg_connection_set_admin_state_t * msg = (msg_connection_set_admin_state_t *)packet; + cmd_connection_set_admin_state_t *control = &msg->payload; - for (size_t i = 0; i < connectionList_Length(connList); i++) { - // Don't release original, it is not stored - Connection *original = connectionList_Get(connList, i); + if ((control->admin_state != FACE_STATE_UP) && + (control->admin_state != FACE_STATE_DOWN)) + goto NACK; - const AddressPair *addressPair = connection_GetAddressPair(original); - Address *localAddress = addressCopy(addressPair_GetLocal(addressPair)); - Address *remoteAddress = addressCopy(addressPair_GetRemote(addressPair)); + connection_t * conn = getConnectionBySymbolicOrId(config, control->symbolicOrConnid); + if (!conn) + goto NACK; - // 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 + connection_set_admin_state(conn, control->admin_state); - listConnectionsCommand->connid = connection_GetConnectionId(original); +#ifdef WITH_MAPME + /* Hook: connection event */ + forwarder_on_connection_event(config->forwarder, conn, + control->admin_state == FACE_STATE_UP + ? CONNECTION_EVENT_SET_UP + : CONNECTION_EVENT_SET_DOWN); +#endif /* WITH_MAPME */ - const char *connectionName = symbolicNameTable_GetNameByIndex(config->symbolicNameTable, connection_GetConnectionId(original)); - snprintf(listConnectionsCommand->connectionName, SYMBOLIC_NAME_LEN, "%s", connectionName); - _parc_strlwr(listConnectionsCommand->connectionName); + make_ack(msg); + return (uint8_t*)msg; - snprintf(listConnectionsCommand->interfaceName, SYMBOLIC_NAME_LEN, "%s", ioOperations_GetInterfaceName(connection_GetIoOperations(original))); +NACK: + make_ack(msg); + return (uint8_t*)msg; +} - 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); +uint8_t * +configuration_on_connection_update(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); #ifdef WITH_POLICY - listConnectionsCommand->connectionData.priority = connection_GetPriority(original); - listConnectionsCommand->connectionData.tags = connection_GetTags(original); -#endif /* WITH_POLICY */ + msg_connection_update_t * msg = (msg_connection_update_t *)packet; + cmd_connection_update_t * control = &msg->payload; + + connection_t * conn = getConnectionBySymbolicOrId(config, control->symbolicOrConnid); + 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); - 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; + make_ack(msg); + return (uint8_t*)msg; + +NACK: +#endif /* WITH_POLICY */ + make_ack(msg); + return (uint8_t*)msg; } -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; - } +uint8_t * +configuration_on_connection_set_priority(configuration_t * config, + uint8_t * packet, unsigned ingress_id) +{ + assert(config); + assert(packet); - 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); - } - } +#ifdef WITH_POLICY + msg_connection_set_priority_t * msg = (msg_connection_set_priority_t *)packet; + cmd_connection_set_priority_t * control = &msg->payload; - // send response - header_control_message *header = request[0].iov_base; - header->messageType = RESPONSE_LIGHT; - header->length = (uint16_t)listenerSet_Length(listenerList); + connection_t * conn = getConnectionBySymbolicOrId(config, control->symbolicOrConnid); + if (!conn) + goto NACK; - struct iovec *response = - parcMemory_AllocateAndClear(sizeof(struct iovec) * 2); + connection_set_priority(conn, control->priority); - 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); +#ifdef WITH_MAPME + /* Hook: connection event */ + forwarder_on_connection_event(config->forwarder, conn, + CONNECTION_EVENT_PRIORITY_CHANGED); +#endif /* WITH_MAPME */ - return response; -} + make_ack(msg); + return (uint8_t*)msg; -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; +NACK: +#endif /* WITH_POLICY */ + make_ack(msg); + return (uint8_t*)msg; } -struct iovec *configuration_ProcessCacheServe(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; - cache_serve_command *control = request[1].iov_base; - - bool success = false; - - switch (control->activate) { - case ACTIVATE_ON: - forwarder_SetChacheServeFlag(config->forwarder, true); - if (forwarder_GetChacheServeFlag(config->forwarder)) { - success = true; - } - break; - - case ACTIVATE_OFF: - forwarder_SetChacheServeFlag(config->forwarder, false); - if (!forwarder_GetChacheServeFlag(config->forwarder)) { - success = true; - } - break; - - default: - break; - } - - struct iovec *response; - if (success) { // ACK - response = utils_CreateAck(header, control, sizeof(cache_store_command)); - } else { // NACK - response = utils_CreateNack(header, control, sizeof(cache_store_command)); - } - - return response; -} +uint8_t * +configuration_on_connection_set_tags(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + 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; -struct iovec *configuration_ProcessCacheClear(Configuration *config, - struct iovec *request) { - header_control_message *header = request[0].iov_base; + connection_t * conn = getConnectionBySymbolicOrId(config, control->symbolicOrConnid); + if (!conn) + goto NACK; - forwarder_ClearCache(config->forwarder); + connection_set_tags(conn, control->tags); - struct iovec *response = utils_CreateAck(header, NULL, 0); - return response; -} +#ifdef WITH_MAPME + /* Hook: connection event */ + forwarder_on_connection_event(config->forwarder, conn, + CONNECTION_EVENT_TAGS_CHANGED); +#endif /* WITH_MAPME */ -size_t configuration_GetObjectStoreSize(Configuration *config) { - return config->maximumContentObjectStoreSize; + make_ack(msg); + return (uint8_t*)msg; + +NACK: +#endif /* WITH_POLICY */ + make_ack(msg); + return (uint8_t*)msg; } -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); + +/* Route */ + +uint8_t * +configuration_on_route_add(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); + + 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(config, + control->symbolicOrConnid, ingress_id); + if (!connection_id_is_valid(conn_id)) + goto NACK; + + ip_prefix_t prefix = { + .family = control->family, + .address = control->address, + .len = control->len + }; + + if (!forwarder_add_or_update_route(config->forwarder, &prefix, conn_id)) + goto NACK; + + make_ack(msg); + return (uint8_t*)msg; + +NACK: + make_ack(msg); + return (uint8_t*)msg; } -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)); - } +uint8_t * +configuration_on_route_remove(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); + + msg_route_remove_t * msg = (msg_route_remove_t *)packet; + cmd_route_remove_t * control = &msg->payload; + + unsigned conn_id = symbolic_to_conn_id(config, control->symbolicOrConnid); + if (!connection_id_is_valid(conn_id)) + goto NACK; + + ip_prefix_t prefix = { + .family = control->family, + .address = control->address, + .len = control->len + }; + + if (!forwarder_remove_route(config->forwarder, &prefix, conn_id)) + goto NACK; - return response; + make_ack(msg); + return (uint8_t*)msg; + +NACK: + make_ack(msg); + return (uint8_t*)msg; } -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; - } +uint8_t * +configuration_on_route_list(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); + + const fib_t * fib = forwarder_get_fib(config->forwarder); + fib_entry_t * entry; + + /* + * Two step approach to precompute the number of entries to allocate + * + * NOTE: we might have routes with no or multiple next hops. + */ + size_t n = 0; + fib_foreach_entry(fib, entry, { + const nexthops_t * nexthops = fib_entry_get_nexthops(entry); + assert(nexthops_get_len(nexthops) == nexthops_get_curlen(nexthops)); + n += nexthops_get_len(nexthops); + }); + + msg_route_list_reply_t * msg; + msg_malloc_list(msg, n); + if (!msg) + return NULL; + + cmd_route_list_item_t * payload = &msg->payload; + fib_foreach_entry(fib, entry, { + const nexthops_t * nexthops = fib_entry_get_nexthops(entry); + assert(nexthops_get_len(nexthops) == nexthops_get_curlen(nexthops)); + size_t num_nexthops = nexthops_get_len(nexthops); + + if (num_nexthops == 0) + continue; + + NameBitvector *prefix = name_GetContentName(fib_entry_get_prefix(entry)); + + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + + address_t address; + nameBitvector_ToAddress(prefix, &address); + switch(address_family(&address)) { + case AF_INET: + payload->family = AF_INET; + payload->address.v4.as_inaddr = address4_ip(&address); + break; + case AF_INET6: + payload->family = AF_INET6; + payload->address.v6.as_in6addr = address6_ip(&address); + break; + default: + break; + } + payload->connection_id = nexthop; + payload->len = nameBitvector_GetLength(prefix); + payload->cost = DEFAULT_COST; + + payload++; + }); + }); + + return (uint8_t*)msg; } -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)); +/* Cache */ - return response; -} +uint8_t * +configuration_on_cache_set_store(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); + + 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; -void configuration_SetObjectStoreSize(Configuration *config, - size_t maximumObjectCount) { - config->maximumContentObjectStoreSize = maximumObjectCount; + forwarder_content_store_set_store(config->forwarder, value); + /* XXX Why do we need to check ? */ + if (forwarder_content_store_get_store(config->forwarder) != value) + goto NACK; - forwarder_SetContentObjectStoreSize(config->forwarder, - config->maximumContentObjectStoreSize); + make_ack(msg); + return (uint8_t*)msg; + +NACK: + make_ack(msg); + return (uint8_t*)msg; } -Forwarder *configuration_GetForwarder(const Configuration *config) { - return config->forwarder; +uint8_t * +configuration_on_cache_set_serve(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); + + 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_content_store_set_serve(config->forwarder, value); + /* XXX Why do we need to check ? */ + if (forwarder_content_store_get_serve(config->forwarder) != value) + goto NACK; + + make_ack(msg); + return (uint8_t*)msg; + +NACK: + make_ack(msg); + return (uint8_t*)msg; } -Logger *configuration_GetLogger(const Configuration *config) { - return config->logger; +uint8_t * +configuration_on_cache_clear(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); + + msg_cache_clear_t * msg = (msg_cache_clear_t *)packet; + + forwarder_content_store_clear(config->forwarder); + + make_ack(msg); + return (uint8_t*)msg; } -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)); +/* Strategy */ + +strategy_type_t +configuration_get_strategy(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); } -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)); +uint8_t * +configuration_on_strategy_set(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); + + msg_strategy_set_t * msg = (msg_strategy_set_t *)packet; + cmd_strategy_set_t * control = &msg->payload; + + char prefix_s[MAXSZ_IP_PREFIX]; + ip_prefix_t prefix = { + .family = control->family, + .address = control->address, + .len = control->len, + }; + int rc = ip_prefix_snprintf(prefix_s, MAXSZ_IP_PREFIX, &prefix); + assert(rc < MAXSZ_IP_PREFIX); + if (rc < 0) + goto NACK; + + strategy_type_t strategy = control->strategy_type; + strategy_type_t existingFwdStrategy = + configuration_get_strategy(config, prefix_s); + + strategy_options_t options; + + if (existingFwdStrategy == STRATEGY_TYPE_UNDEFINED || + strategy != existingFwdStrategy) { + // means such a new strategy is not present in the hash table or has to be + // updated + int res; + khiter_t k = kh_put_strategy_map(config->strategy_map, prefix_s, &res); + kh_value(config->strategy_map, k) = strategy; + + Name *name_prefix = name_CreateFromAddress(control->family, + control->address, control->len); + // XXX TODO error handling + + switch(control->strategy_type) { + case STRATEGY_TYPE_LOW_LATENCY: + options.low_latency.related_prefixes_len = control->related_prefixes; + Name **related_prefixes = options.low_latency.related_prefixes; + + if(control->related_prefixes != 0){ + for(int i = 0; i < control->related_prefixes; i++){ + related_prefixes[i] = name_CreateFromAddress( + control->low_latency.families[i], + control->low_latency.addresses[i], + control->low_latency.lens[i]); + } + // XXX TODO error handling + } + forwarder_set_strategy(config->forwarder, name_prefix, strategy, &options); + + if (control->related_prefixes != 0) { + for(int i = 0; i < control->related_prefixes; i++) + name_Release(&related_prefixes[i]); + } + break; + default: + break; + } + name_Release(&name_prefix); + } + + make_ack(msg); + return (uint8_t*)msg; + +NACK: + make_nack(msg); + return (uint8_t*)msg; } -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; +/* WLDR */ - PARCBufferComposer *composer = parcBufferComposer_Create(); - parcBufferComposer_Format(composer, - "The mapme timescale value received is: %u", - control->timePeriod); +uint8_t * +configuration_on_wldr_set(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - puts(result); - parcMemory_Deallocate((void **)&result); - parcBufferComposer_Release(&composer); + msg_wldr_set_t * msg = (msg_wldr_set_t *)packet; + cmd_wldr_set_t * control = &msg->payload; - return utils_CreateAck(header, control, sizeof(mapme_timing_command)); -} + if ((control->activate != 0) && (control->activate != 1)) + goto NACK; + bool value = (bool)control->activate; -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; + unsigned conn_id = symbolic_to_conn_id(config, control->symbolicOrConnid); + if (!connection_id_is_valid(conn_id)) + goto NACK; - PARCBufferComposer *composer = parcBufferComposer_Create(); - parcBufferComposer_Format( - composer, "The mapme retransmission time value received is: %u", - control->timePeriod); + connection_table_t * table = forwarder_get_connection_table(config->forwarder); + connection_t * conn = connection_table_at(table, conn_id); - PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); - char *result = parcBuffer_ToString(tempBuffer); - parcBuffer_Release(&tempBuffer); - puts(result); - parcMemory_Deallocate((void **)&result); - parcBufferComposer_Release(&composer); + if (value) + connection_wldr_enable(conn, value); - return utils_CreateAck(header, control, sizeof(mapme_timing_command)); + make_ack(msg); + return (uint8_t*)msg; + +NACK: + make_ack(msg); + return (uint8_t*)msg; } -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)); +/* Punting */ + +uint8_t * +configuration_on_punting_add(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ +#if !defined(__APPLE__) && !defined(_WIN32) && defined(PUNTING) + msg_punting_add_t * msg = (msg_punting_add_t *)packet; + cmd_punting_add_t * control = &msg->payload; + + if (ip_address_empty(&control->address)) + goto NACK; + + /* This is for hICN listeners only */ + // XXX add check ! + // comments: + // EncapType: I use the Hicn encap since the punting is available only for + // Hicn listeners LocalAddress: The only listern for which we need punting + // rules is the main one, which has no address + // so I create a fake empty address. This need to be consistent + // with the address set at creation time + address_t fakeaddr; + memset(&fakeaddr, 0, sizeof(address_t)); + fakeaddr = ADDRESS_ANY(control->family, DEFAULT_PORT); + + forwarder_t * forwarder = configuration_get_forwarder(config); + listener_table_t * table = forwarder_get_listener_table(forwarder); + listener_t * listener = listener_table_get_by_address(table, FACE_TYPE_HICN, &fakeaddr); + if (!listener) { + ERROR("the main listener does not exist"); + goto NACK; + } + + + ip_prefix_t prefix = { + .family = control->family, + .address = control->address, + .len = control->len + }; + char prefix_s[MAXSZ_IP_PREFIX]; + int rc = ip_prefix_snprintf(prefix_s, MAXSZ_IP_PREFIX, &prefix); + assert(rc < MAXSZ_IP_PREFIX); + if (rc < 0) + goto NACK; + + if (listener_punt(listener, prefix_s) < 0) { + ERROR("error while adding the punting rule\n"); + goto NACK; } - } -ERR: - return utils_CreateNack(header, control, sizeof(connection_set_admin_state_command)); + make_ack(msg); + return (uint8_t*)msg; + +NACK: +#endif + make_ack(msg); + return (uint8_t*)msg; } +/* MAP-Me */ -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; +uint8_t * +configuration_on_mapme_enable(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); - if ((control->admin_state != CONNECTION_STATE_UP) && (control->admin_state != CONNECTION_STATE_DOWN)) - return utils_CreateNack(header, control, sizeof(connection_set_admin_state_command)); + msg_mapme_enable_t * msg = (msg_mapme_enable_t *)packet; + cmd_mapme_enable_t * control = &msg->payload; - Connection * conn = getConnectionBySymbolicOrId(config, control->symbolicOrConnid); - if (!conn) - return utils_CreateNack(header, control, sizeof(connection_set_admin_state_command)); + if ((control->activate != 0) && (control->activate != 1)) + goto NACK; + bool value = (bool)control->activate; - connection_SetAdminState(conn, control->admin_state); + INFO("MAP-Me SET enable: %s", value ? "on" : "off"); -#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 */ + make_ack(msg); + return (uint8_t*)msg; - return utils_CreateAck(header, control, sizeof(connection_set_admin_state_command)); +NACK: + make_ack(msg); + return (uint8_t*)msg; } -#ifdef WITH_POLICY +uint8_t * +configuration_on_mapme_set_discovery(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); -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; + msg_mapme_set_discovery_t * msg = (msg_mapme_set_discovery_t *)packet; + cmd_mapme_set_discovery_t * control = &msg->payload; - Connection * conn = getConnectionBySymbolicOrId(config, control->symbolicOrConnid); - if (!conn) - return utils_CreateNack(header, control, sizeof(connection_set_priority_command)); + if ((control->activate != 0) && (control->activate != 1)) + goto NACK; + bool value = (bool)control->activate; - connection_SetPriority(conn, control->priority); + INFO("MAP-Me SET discovery: %s", value ? "on" : "off"); -#ifdef WITH_MAPME - /* Hook: connection event */ - forwarder_onConnectionEvent(config->forwarder, conn, - CONNECTION_EVENT_PRIORITY_CHANGED); -#endif /* WITH_MAPME */ + make_ack(msg); + return (uint8_t*)msg; - return utils_CreateAck(header, control, sizeof(connection_set_priority_command)); +NACK: + make_ack(msg); + return (uint8_t*)msg; } -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; +uint8_t * +configuration_on_mapme_set_timescale(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); - Connection * conn = getConnectionBySymbolicOrId(config, control->symbolicOrConnid); - if (!conn) - return utils_CreateNack(header, control, sizeof(connection_set_tags_command)); + msg_mapme_set_timescale_t * msg = (msg_mapme_set_timescale_t *)packet; + cmd_mapme_set_timescale_t * control = &msg->payload; - connection_SetTags(conn, control->tags); + INFO("MAP-Me SET timescale: %u", control->timePeriod); -#ifdef WITH_MAPME - /* Hook: connection event */ - forwarder_onConnectionEvent(config->forwarder, conn, - CONNECTION_EVENT_TAGS_CHANGED); -#endif /* WITH_MAPME */ + make_ack(msg); + return (uint8_t*)msg; +} + +uint8_t * +configuration_on_mapme_set_retx(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); + + msg_mapme_set_retx_t * msg = (msg_mapme_set_retx_t *)packet; + cmd_mapme_set_retx_t * control = &msg->payload; - return utils_CreateAck(header, control, sizeof(connection_set_tags_command)); + INFO("MAP-Me SET retx: %u", control->timePeriod); + + make_ack(msg); + return (uint8_t*)msg; } -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)); - } +uint8_t * +configuration_on_mapme_send_update(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); + + msg_mapme_send_update_t * msg = (msg_mapme_send_update_t *)packet; + cmd_mapme_send_update_t * control = &msg->payload; + + fib_t * fib = forwarder_get_fib(config->forwarder); + if (!fib) + goto NACK; + Name *prefix = name_CreateFromAddress(control->family, control->address, + control->len); + if (!prefix) + goto NACK; + fib_entry_t *entry = fib_contains(fib, prefix); + name_Release(&prefix); + if (!entry) + goto NACK; + + /* The command is accepted iif triggered by (one of) the producer of this prefix */ + const nexthops_t * nexthops = fib_entry_get_nexthops(entry); + + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + if (nexthop != ingress_id) + continue; + mapme_t * mapme = forwarder_get_mapme(config->forwarder); + mapme_send_to_all_nexthops(mapme, entry); + make_ack(msg); + return (uint8_t*)msg; + }); + +NACK: + make_ack(msg); + return (uint8_t*)msg; } -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); +/* Policy */ - addressDestroy(&addressEntry); - } +uint8_t * +configuration_on_policy_add(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); - // send response - header_control_message *header = request[0].iov_base; - header->messageType = RESPONSE_LIGHT; - header->length = (unsigned)payloadSize; +#ifdef WITH_POLICY + msg_policy_add_t * msg = (msg_policy_add_t *)packet; + cmd_policy_add_t * control = &msg->payload; + + ip_prefix_t prefix = { + .family = control->family, + .address = control->address, + .len = control->len + }; - struct iovec *response = - parcMemory_AllocateAndClear(sizeof(struct iovec) * 2); + if (!forwarder_add_or_update_policy(config->forwarder, &prefix, &control->policy)) + goto NACK; - 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; + make_ack(msg); + return (uint8_t*)msg; - fibEntryList_Destroy(&fibList); - return response; +NACK: +#endif /* WITH_POLICY */ + make_ack(msg); + return (uint8_t*)msg; } -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)); -} +uint8_t * +configuration_on_policy_remove(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); -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; +#ifdef WITH_POLICY + msg_policy_remove_t * msg = (msg_policy_remove_t *)packet; + cmd_policy_remove_t * control = &msg->payload; - Connection * conn = getConnectionBySymbolicOrId(config, control->symbolicOrConnid); - if (!conn) - return utils_CreateNack(header, control, sizeof(update_connection_command)); + ip_prefix_t prefix = { + .family = control->family, + .address = control->address, + .len = control->len + }; - connection_SetTags(conn, control->tags); - connection_SetAdminState(conn, control->admin_state); - if (control->priority > 0) - connection_SetPriority(conn, control->priority); + if (!forwarder_remove_policy(config->forwarder, &prefix)) + goto NACK; - return utils_CreateAck(header, control, sizeof(update_connection_command)); -} + make_ack(msg); + return (uint8_t*)msg; + +NACK: #endif /* WITH_POLICY */ + make_ack(msg); + return (uint8_t*)msg; +} -// =========================== -// Main functions that deal with receiving commands, executing them, and sending -// ACK/NACK +uint8_t * +configuration_on_policy_list(configuration_t * config, uint8_t * packet, + unsigned ingress_id) +{ + assert(config); + assert(packet); -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; + const fib_t * fib = forwarder_get_fib(config->forwarder); + assert(fib); + size_t n = fib_get_size(fib); #ifdef WITH_POLICY - case ADD_POLICY: - response = configuration_ProcessPolicyAdd(config, control); - break; + msg_policy_list_reply_t * msg; + msg_malloc_list(msg, n); + if (!msg) + return NULL; + + cmd_policy_list_item_t * payload = &msg->payload; + + fib_entry_t * entry; - case LIST_POLICIES: - response = configuration_ProcessPolicyList(config, control); - break; + fib_foreach_entry(fib, entry, { + NameBitvector *prefix = name_GetContentName(fib_entry_get_prefix(entry)); + address_t address; + nameBitvector_ToAddress(prefix, &address); - case REMOVE_POLICY: - response = configuration_ProcessPolicyRemove(config, control); - break; + switch(address_family(&address)) { + case AF_INET: + payload->family = AF_INET; + payload->address.v4.as_inaddr = address4_ip(&address); + break; - case UPDATE_CONNECTION: - response = configuration_UpdateConnection(config, control); - break; + case AF_INET6: + payload->family = AF_INET6; + payload->address.v6.as_in6addr = address6_ip(&address); + break; - case CONNECTION_SET_PRIORITY: - response = configuration_ConnectionSetPriority(config, control); - break; + default: + break; + } + payload->len = nameBitvector_GetLength(prefix); + payload->policy = fib_entry_get_policy(entry); + + payload++; + }); - case CONNECTION_SET_TAGS: - response = configuration_ConnectionSetTags(config, control); - break; + return (uint8_t*)msg; +#else + return NULL; #endif /* WITH_POLICY */ +} - default: - break; - } +size_t +configuration_content_store_get_size(configuration_t * config) +{ + return config->maximumContentObjectStoreSize; +} + +void +configuration_content_store_set_size(configuration_t * config, size_t size) +{ + config->maximumContentObjectStoreSize = size; - return response; + forwarder_content_store_set_size(config->forwarder, + config->maximumContentObjectStoreSize); } -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 +forwarder_t * +configuration_get_forwarder(const configuration_t * config) { + return config->forwarder; +} + + +// =========================== +// Main functions that deal with receiving commands, executing them, and sending +// ACK/NACK + +uint8_t * +configuration_dispatch_command(configuration_t * config, command_type_t command_type, + uint8_t * packet, unsigned ingress_id) +{ + switch (command_type) { +#define _(l, u) \ + case COMMAND_TYPE_ ## u: \ + return configuration_on_ ## l(config, packet, ingress_id); + foreach_command_type +#undef _ + case COMMAND_TYPE_UNDEFINED: + case COMMAND_TYPE_N: + ERROR("Unexpected command type"); + break; + } + return NULL; +} + +void configuration_receive_command(configuration_t * config, + command_type_t command_type, uint8_t * packet, unsigned ingress_id) +{ + assert(config); + assert(command_type_is_valid(command_type)); + assert(packet); + + bool nack = false; + + uint8_t * reply = configuration_dispatch_command(config, command_type, packet, ingress_id); + if (!reply) { + reply = packet; + msg_header_t * hdr = (msg_header_t *)reply; + make_nack(hdr); + nack = true; + } + + connection_table_t * table = forwarder_get_connection_table(config->forwarder); + const connection_t *connection = connection_table_at(table, ingress_id); + connection_send_packet(connection, reply, false); + + switch (command_type) { + case COMMAND_TYPE_LISTENER_LIST: + case COMMAND_TYPE_CONNECTION_LIST: + case COMMAND_TYPE_ROUTE_LIST: + case COMMAND_TYPE_POLICY_LIST: + if (!nack) + free(reply); + break; + default: + break; + } } diff --git a/hicn-light/src/hicn/config/configuration.h b/hicn-light/src/hicn/config/configuration.h index 5090f1413..86efa5236 100644 --- a/hicn-light/src/hicn/config/configuration.h +++ b/hicn-light/src/hicn/config/configuration.h @@ -26,14 +26,11 @@ #ifndef configuration_h #define configuration_h -#include <hicn/core/logger.h> #include <hicn/utils/commands.h> -struct configuration; -typedef struct configuration Configuration; +typedef struct configuration_s configuration_t; -struct forwarder; -typedef struct forwarder Forwarder; +struct forwarder_s; /** * <#One Line Description#> @@ -49,7 +46,7 @@ typedef struct forwarder Forwarder; * <#example#> * @endcode */ -Configuration *configuration_Create(Forwarder *forwarder); +configuration_t * configuration_create(struct forwarder_s * forwarder); /** * <#One Line Description#> @@ -65,13 +62,13 @@ Configuration *configuration_Create(Forwarder *forwarder); * <#example#> * @endcode */ -void configuration_Destroy(Configuration **configPtr); +void configuration_free(configuration_t * config); -void configuration_SetupAllListeners(Configuration *config, uint16_t port, +void configuration_setup_all_listeners(configuration_t *config, uint16_t port, const char *localPath); -void configuration_ReceiveCommand(Configuration *config, command_id command, - struct iovec *request, unsigned ingressId); +void configuration_receive_command(configuration_t *config, command_type_t command, + uint8_t * packet, unsigned ingress_id); /** * Returns the configured size of the content store @@ -87,7 +84,7 @@ void configuration_ReceiveCommand(Configuration *config, command_id command, * <#example#> * @endcode */ -size_t configuration_GetObjectStoreSize(Configuration *config); +size_t configuration_content_store_get_size(configuration_t *config); /** * Sets the size of the content store (in objects, not bytes) @@ -101,11 +98,9 @@ size_t configuration_GetObjectStoreSize(Configuration *config); * <#example#> * @endcode */ -void configuration_SetObjectStoreSize(Configuration *config, - size_t maximumContentObjectCount); +void configuration_content_store_set_size(configuration_t *config, size_t size); -strategy_type configuration_GetForwardingStrategy(Configuration *config, - const char *prefix); +strategy_type_t configuration_get_strategy(configuration_t *config, const char *prefix); /** * Returns the Forwarder that owns the Configuration @@ -125,28 +120,10 @@ strategy_type configuration_GetForwardingStrategy(Configuration *config, * } * @endcode */ -Forwarder *configuration_GetForwarder(const Configuration *config); +struct forwarder_s * configuration_get_forwarder(const configuration_t *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); - -struct iovec *configuration_DispatchCommand(Configuration *config, - command_id command, - struct iovec *control, - unsigned ingressId); +uint8_t * +configuration_dispatch_command(configuration_t * config, command_type_t command_type, + uint8_t * packet, unsigned ingress_id); #endif // 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 5f9c9ce9d..000000000 --- a/hicn-light/src/hicn/config/configurationFile.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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); - CommandReturn result = - controlState_DispatchCommand(configFile->controlState, args); - - // 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/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..b53bb025f --- /dev/null +++ b/hicn-light/src/hicn/config/configuration_file.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 <hicn/config/configuration.h> +#include <hicn/config/configuration_file.h> +//#include <hicn/config/controlRoot.h> +//#include <hicn/config/controlState.h> +#include <hicn/util/log.h> + +struct configuration_file { + forwarder_t *forwarder; + char *filename; + FILE *fh; + + size_t linesRead; + + // our custom state machine. + // XXX ControlState *control_state; +}; + +#if 0 +/* + * Called by a command to dispatch the correct command + */ +uint8_t * +_write_read(ControlState *state, uint8_t * packet) +{ + assert(state); + assert(packet); + + configuration_file_t *configFile = + (configuration_file_t *)controlState_GetUserdata(state); + + configuration_t * config = forwarder_get_configuration(configFile->forwarder); + command_type_t command_type = + command_type_from_uchar(((cmd_header_t*)packet)->commandID); + + return configuration_dispatch_command(config, command_type, packet, 0); +} + +/** + * 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); + } + return list; +} +#endif + +// ============================================================= + +configuration_file_t * +configuration_file_create(forwarder_t * forwarder, const char * filename) +{ + assert(forwarder); + assert(filename); + + configuration_file_t *cfg = malloc(sizeof(configuration_file_t)); + if (!cfg) + return NULL; + + cfg->linesRead = 0; + cfg->forwarder = forwarder; + cfg->filename = strdup(filename); + assert(cfg->filename); + +#if 0 + // setup the control state for the command parser: last parameter NULL + // because + // write_read still not implemented from configuration file. + cfg->control_state = controlState_Create(cfg, _write_read, false, + SRV_CTRL_IP, SRV_CTRL_PORT); +#endif + + // we do not register Help commands + //controlState_RegisterCommand(cfg->control_state, controlRoot_Create(cfg->control_state)); + + // open the file and make sure we can read it + cfg->fh = fopen(cfg->filename, "r"); + + if (cfg->fh) { + DEBUG("Open config file %s", cfg->filename); + } else { + ERROR("Could not open config file %s: (%d) %s", cfg->filename, errno, strerror(errno)); + + // failure cleanup the object -- this nulls it so final return null be + // NULL + configuration_file_free(cfg); + } + return cfg; +} + +bool +configuration_file_process(configuration_file_t *configFile) +{ + assert(configFile); + + // default to a "true" return value and only set to false if we encounter an + // error. + bool success = true; + +#if 0 +#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); + CommandReturn result = + controlState_DispatchCommand(configFile->control_state, args); + + // we ignore EXIT from the configuration file + if (result == CommandReturn_Failure) { + ERROR("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)) { + ERROR("Error on input file %s line %d: (%d) %s", + configFile->filename, configFile->linesRead, errno, + strerror(errno)); + success = false; + } + +#endif + return success; +} + +void +configuration_file_free(configuration_file_t * cfg) +{ + free(cfg->filename); + if (cfg->fh) + fclose(cfg->fh); + //controlState_Destroy(&cfg->control_state); + free(cfg); +} diff --git a/hicn-light/src/hicn/config/configurationFile.h b/hicn-light/src/hicn/config/configuration_file.h index b748dfc15..eedcbc6bd 100644 --- a/hicn-light/src/hicn/config/configurationFile.h +++ b/hicn-light/src/hicn/config/configuration_file.h @@ -14,7 +14,7 @@ */ /** - * @file configurationFile.h + * @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 @@ -24,24 +24,24 @@ * */ -#ifndef configurationFile_h -#define configurationFile_h +#ifndef configuration_file_h +#define configuration_file_h #include <hicn/core/forwarder.h> struct configuration_file; -typedef struct configuration_file ConfigurationFile; +typedef struct configuration_file configuration_file_t; /** - * Creates a ConfigurationFile to prepare to process the file + * Creates a configuration_file_t 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] hicn-light An allocated forwarder_t * to configure with the file * @param [in] filename The file to use * - * @retval non-null An allocated ConfigurationFile that is readable + * @retval non-null An allocated configuration_file_t that is readable * @retval null An error * * Example: @@ -49,8 +49,8 @@ typedef struct configuration_file ConfigurationFile; * <#example#> * @endcode */ -ConfigurationFile *configurationFile_Create(Forwarder *forwarder, - const char *filename); +configuration_file_t * configuration_file_create(forwarder_t * forwarder, const + char * filename); /** * Reads the configuration file line-by-line and issues commands to @@ -60,7 +60,7 @@ ConfigurationFile *configurationFile_Create(Forwarder *forwarder, * * Will stop on the first error. Lines already processed will not be un-done. * - * @param [in] configFile An allocated ConfigurationFile + * @param [in] configFile An allocated configuration_file_t * * @retval true The entire files was processed without error. * @retval false There was an error in the file. @@ -70,17 +70,17 @@ ConfigurationFile *configurationFile_Create(Forwarder *forwarder, * <#example#> * @endcode */ -bool configurationFile_Process(ConfigurationFile *configFile); +bool configuration_file_process(configuration_file_t *configFile); -// void configurationFile_ProcessForwardingStrategies(Configuration * config, -// ConfigurationFile * configFile); +// void configuration_file_ProcessForwardingStrategies(Configuration * config, +// configuration_file_t * configFile); /** * Closes the underlying file and releases memory * * <#Paragraphs Of Explanation#> * - * @param [in,out] configFilePtr An allocated ConfigurationFile that will be + * @param [in,out] configFilePtr An allocated configuration_file_t that will be * NULL'd as output * * Example: @@ -88,6 +88,6 @@ bool configurationFile_Process(ConfigurationFile *configFile); * <#example#> * @endcode */ -void configurationFile_Release(ConfigurationFile **configFilePtr); +void configuration_file_free(configuration_file_t * configFile); -#endif /* defined(configurationFile_h) */ +#endif /* defined(configuration_file_h) */ diff --git a/hicn-light/src/hicn/config/controlAddConnection.c b/hicn-light/src/hicn/config/controlAddConnection.c index e5af5a251..6160ff188 100644 --- a/hicn-light/src/hicn/config/controlAddConnection.c +++ b/hicn-light/src/hicn/config/controlAddConnection.c @@ -29,6 +29,7 @@ #include <hicn/utils/commands.h> #include <hicn/utils/utils.h> +#include <hicn/face.h> // =================================================== @@ -189,7 +190,7 @@ static CommandReturn _controlAddConnection_Execute(CommandParser *parser, * @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] type The tunneling protocol * @param [in] symbolic The symbolic name for the connection (must be unique) * * @return <#value#> <#explanation#> @@ -218,44 +219,44 @@ static CommandReturn _controlAddConnection_Execute(CommandParser *parser, 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) { + face_type_t type, const char *symbolic) { 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)); + cmd_connection_add_t *cmd = + parcMemory_AllocateAndClear(sizeof(cmd_connection_add_t)); // check and set IP addresses - if (inet_pton(AF_INET, remote_ip, &addConnectionCommand->remoteIp.v4.as_u32) == + if (inet_pton(AF_INET, remote_ip, &cmd->remote_ip.v4.as_u32) == 1 && - inet_pton(AF_INET, local_ip, &addConnectionCommand->localIp.v4.as_u32) == 1) { - addConnectionCommand->ipType = ADDR_INET; + inet_pton(AF_INET, local_ip, &cmd->local_ip.v4.as_u32) == 1) { + cmd->family = AF_INET; } else if (inet_pton(AF_INET6, remote_ip, - &addConnectionCommand->remoteIp.v6.as_in6addr) == 1 && + &cmd->remote_ip.v6.as_in6addr) == 1 && inet_pton(AF_INET6, local_ip, - &addConnectionCommand->localIp.v6.as_in6addr) == 1) { - addConnectionCommand->ipType = ADDR_INET6; + &cmd->local_ip.v6.as_in6addr) == 1) { + cmd->family = AF_INET6; } else { printf("Error: local address %s not same type as remote address %s\n", local_ip, remote_ip); - parcMemory_Deallocate(&addConnectionCommand); + parcMemory_Deallocate(&cmd); 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)); + cmd->type = type; + strcpy(cmd->symbolic, symbolic); + cmd->remote_port = htons((uint16_t)atoi(remote_port)); + cmd->local_port = htons((uint16_t)atoi(local_port)); // send message and receive response struct iovec *response = - utils_SendRequest(state, ADD_CONNECTION, addConnectionCommand, - sizeof(add_connection_command)); + utils_SendRequest(state, COMMAND_TYPE_CONNECTION_ADD, cmd, + sizeof(cmd_connection_add_t)); if (!response) { // get NULL pointer return CommandReturn_Failure; @@ -318,7 +319,7 @@ static CommandReturn _controlAddConnection_HicnExecute(CommandParser *parser, 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); + parser, ops, local_ip, port, remote_ip, port, FACE_TYPE_HICN, symbolic); } #endif @@ -360,7 +361,7 @@ static CommandReturn _controlAddConnection_UdpExecute(CommandParser *parser, char *local_port = parcList_GetAtIndex(args, _indexLocPort); return _controlAddConnection_CreateTunnel(parser, ops, local_ip, local_port, - remote_ip, remote_port, UDP_CONN, + remote_ip, remote_port, FACE_TYPE_UDP, symbolic); } @@ -402,6 +403,6 @@ static CommandReturn _controlAddConnection_TcpExecute(CommandParser *parser, char *local_port = parcList_GetAtIndex(args, _indexLocPort); return _controlAddConnection_CreateTunnel(parser, ops, local_ip, local_port, - remote_ip, remote_port, TCP_CONN, + remote_ip, remote_port, FACE_TYPE_TCP, symbolic); } diff --git a/hicn-light/src/hicn/config/controlAddListener.c b/hicn-light/src/hicn/config/controlAddListener.c index 2f0fd3f67..18766fd49 100644 --- a/hicn-light/src/hicn/config/controlAddListener.c +++ b/hicn-light/src/hicn/config/controlAddListener.c @@ -107,10 +107,10 @@ static CommandReturn _CreateListener(CommandParser *parser, CommandOps *ops, // check and set IP address if (inet_pton(AF_INET, addr, &addListenerCommand->address.v4.as_u32) == 1) { - addListenerCommand->addressType = ADDR_INET; + addListenerCommand->family = AF_INET; } else if (inet_pton(AF_INET6, addr, &addListenerCommand->address.v6.as_in6addr) == 1) { - addListenerCommand->addressType = ADDR_INET6; + addListenerCommand->family = AF_INET6; } else { printf("Error: %s is not a valid network address \n", addr); diff --git a/hicn-light/src/hicn/config/controlAddPolicy.c b/hicn-light/src/hicn/config/controlAddPolicy.c index 29120446b..24b9d5eec 100644 --- a/hicn-light/src/hicn/config/controlAddPolicy.c +++ b/hicn-light/src/hicn/config/controlAddPolicy.c @@ -111,7 +111,7 @@ static CommandReturn _controlAddPolicy_Execute(CommandParser *parser, free(addr); return CommandReturn_Failure; } - addPolicyCommand->addressType = ADDR_INET; + addPolicyCommand->family = AF_INET; } else if (inet_pton(AF_INET6, addr, &addPolicyCommand->address.v6.as_in6addr) == 1) { if (len > 128) { printf("ERROR: exceeded INET6 mask length, max=128\n"); @@ -119,7 +119,7 @@ static CommandReturn _controlAddPolicy_Execute(CommandParser *parser, free(addr); return CommandReturn_Failure; } - addPolicyCommand->addressType = ADDR_INET6; + addPolicyCommand->family = AF_INET6; } else { printf("Error: %s is not a valid network address \n", addr); parcMemory_Deallocate(&addPolicyCommand); diff --git a/hicn-light/src/hicn/config/controlAddPunting.c b/hicn-light/src/hicn/config/controlAddPunting.c index e3fb57c6b..a83350876 100644 --- a/hicn-light/src/hicn/config/controlAddPunting.c +++ b/hicn-light/src/hicn/config/controlAddPunting.c @@ -116,7 +116,7 @@ static CommandReturn _controlAddPunting_Execute(CommandParser *parser, free(addr); return CommandReturn_Failure; } - addPuntingCommand->addressType = ADDR_INET; + addPuntingCommand->family = AF_INET; } else if (inet_pton(AF_INET6, addr, &addPuntingCommand->address.v6.as_in6addr) == 1) { if (len > 128) { printf("ERROR: exceeded INET6 mask length, max=128\n"); @@ -124,7 +124,7 @@ static CommandReturn _controlAddPunting_Execute(CommandParser *parser, free(addr); return CommandReturn_Failure; } - addPuntingCommand->addressType = ADDR_INET6; + addPuntingCommand->family = AF_INET6; } else { printf("Error: %s is not a valid network address \n", addr); parcMemory_Deallocate(&addPuntingCommand); diff --git a/hicn-light/src/hicn/config/controlAddRoute.c b/hicn-light/src/hicn/config/controlAddRoute.c index 8a1adf6d6..f7b83e3a8 100644 --- a/hicn-light/src/hicn/config/controlAddRoute.c +++ b/hicn-light/src/hicn/config/controlAddRoute.c @@ -109,29 +109,29 @@ static CommandReturn _controlAddRoute_Execute(CommandParser *parser, } // allocate command payload - add_route_command *addRouteCommand = - parcMemory_AllocateAndClear(sizeof(add_route_command)); + cmd_route_add_t *cmd = + parcMemory_AllocateAndClear(sizeof(cmd_route_add_t)); // check and set IP address - if (inet_pton(AF_INET, addr, &addRouteCommand->address.v4.as_u32) == 1) { + if (inet_pton(AF_INET, addr, &cmd->address.v4.as_u32) == 1) { if (len > 32) { printf("ERROR: exceeded INET mask length, max=32\n"); - parcMemory_Deallocate(&addRouteCommand); + parcMemory_Deallocate(&cmd); free(addr); return CommandReturn_Failure; } - addRouteCommand->addressType = ADDR_INET; - } else if (inet_pton(AF_INET6, addr, &addRouteCommand->address.v6.as_in6addr) == 1) { + cmd->family = AF_INET; + } else if (inet_pton(AF_INET6, addr, &cmd->address.v6.as_in6addr) == 1) { if (len > 128) { printf("ERROR: exceeded INET6 mask length, max=128\n"); - parcMemory_Deallocate(&addRouteCommand); + parcMemory_Deallocate(&cmd); free(addr); return CommandReturn_Failure; } - addRouteCommand->addressType = ADDR_INET6; + cmd->family = AF_INET6; } else { printf("Error: %s is not a valid network address \n", addr); - parcMemory_Deallocate(&addRouteCommand); + parcMemory_Deallocate(&cmd); free(addr); return CommandReturn_Failure; } @@ -139,13 +139,13 @@ static CommandReturn _controlAddRoute_Execute(CommandParser *parser, free(addr); // Fill remaining payload fields - addRouteCommand->len = len; - addRouteCommand->cost = (uint16_t)cost; - strcpy(addRouteCommand->symbolicOrConnid, symbolicOrConnid); + cmd->len = len; + cmd->cost = (uint16_t)cost; + strcpy(cmd->symbolicOrConnid, symbolicOrConnid); // send message and receive response - struct iovec *response = utils_SendRequest(state, ADD_ROUTE, addRouteCommand, - sizeof(add_route_command)); + struct iovec *response = utils_SendRequest(state, COMMAND_TYPE_ROUTE_ADD, cmd, + sizeof(cmd_route_add_t)); if (!response) { // get NULL pointer return CommandReturn_Failure; diff --git a/hicn-light/src/hicn/config/controlListConnections.c b/hicn-light/src/hicn/config/controlListConnections.c index cbed8a79c..c47431726 100644 --- a/hicn-light/src/hicn/config/controlListConnections.c +++ b/hicn-light/src/hicn/config/controlListConnections.c @@ -38,8 +38,10 @@ static CommandReturn _controlListConnections_HelpExecute(CommandParser *parser, static const char *_commandListConnections = "list connections"; static const char *_commandListConnectionsHelp = "help list connections"; + +// XXX TODO in connection{_state}.h const char *connTypeString[6] = {"GRE", "TCP", "UDP", "MCAST", "L2", "HICN"}; -const char *stateString[3] = {"UP", "DOWN", "UNKNOWN"}; +const char *stateString[3] = {"UNKNOWN", "DOWN", "UP"}; CommandOps *controlListConnections_Create(ControlState *state) { return commandOps_Create(state, _commandListConnections, NULL, @@ -127,12 +129,12 @@ static CommandReturn _controlListConnections_Execute(CommandParser *parser, (i * sizeof(list_connections_command))); sourceString = utils_CommandAddressToString( - listConnectionsCommand->connectionData.ipType, + listConnectionsCommand->connectionData.family, &listConnectionsCommand->connectionData.localIp, &listConnectionsCommand->connectionData.localPort); destinationString = utils_CommandAddressToString( - listConnectionsCommand->connectionData.ipType, + listConnectionsCommand->connectionData.family, &listConnectionsCommand->connectionData.remoteIp, &listConnectionsCommand->connectionData.remotePort); diff --git a/hicn-light/src/hicn/config/controlListListeners.c b/hicn-light/src/hicn/config/controlListListeners.c index 1489470a8..f0ab820f5 100644 --- a/hicn-light/src/hicn/config/controlListListeners.c +++ b/hicn-light/src/hicn/config/controlListListeners.c @@ -106,7 +106,7 @@ static CommandReturn _controlListListeners_Execute(CommandParser *parser, (list_listeners_command *)(receivedPayload + (i * sizeof(list_listeners_command))); - addrString = utils_CommandAddressToString(listListenersCommand->addressType, + addrString = utils_CommandAddressToString(listListenersCommand->family, &listListenersCommand->address, &listListenersCommand->port); diff --git a/hicn-light/src/hicn/config/controlListPolicies.c b/hicn-light/src/hicn/config/controlListPolicies.c index 81be6ddfc..9ea3bae75 100644 --- a/hicn-light/src/hicn/config/controlListPolicies.c +++ b/hicn-light/src/hicn/config/controlListPolicies.c @@ -148,7 +148,7 @@ static CommandReturn _controlListPolicies_Execute(CommandParser *parser, #undef _ addrString = utils_CommandAddressToString( - listPoliciesCommand->addressType, &listPoliciesCommand->address, &port); + listPoliciesCommand->family, &listPoliciesCommand->address, &port); #if 0 PARCBufferComposer *composer = parcBufferComposer_Create(); @@ -191,6 +191,7 @@ static CommandReturn _controlListPolicies_Execute(CommandParser *parser, #endif } +#if 0 printf("\nSTATISTICS\n\n"); // STATISTICS printf("%*s %*s %*s | %*s | %*s | %*s\n", @@ -207,22 +208,23 @@ static CommandReturn _controlListPolicies_Execute(CommandParser *parser, (list_policies_command *)(receivedPayload + (i * sizeof(list_policies_command))); addrString = utils_CommandAddressToString( - listPoliciesCommand->addressType, &listPoliciesCommand->address, &port); + listPoliciesCommand->family, &listPoliciesCommand->address, &port); printf("%*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); + MAXSZ_STR_STAT, listPoliciesCommand->prefix_stats.wired.throughput, + MAXSZ_STR_STAT, listPoliciesCommand->prefix_stats.wired.latency, + MAXSZ_STR_STAT, listPoliciesCommand->prefix_stats.wired.loss_rate, + MAXSZ_STR_STAT, listPoliciesCommand->prefix_stats.wifi.throughput, + MAXSZ_STR_STAT, listPoliciesCommand->prefix_stats.wifi.latency, + MAXSZ_STR_STAT, listPoliciesCommand->prefix_stats.wifi.loss_rate, + MAXSZ_STR_STAT, listPoliciesCommand->prefix_stats.cellular.throughput, + MAXSZ_STR_STAT, listPoliciesCommand->prefix_stats.cellular.latency, + MAXSZ_STR_STAT, listPoliciesCommand->prefix_stats.cellular.loss_rate, + MAXSZ_STR_STAT, listPoliciesCommand->prefix_stats.all.throughput, + MAXSZ_STR_STAT, listPoliciesCommand->prefix_stats.all.latency, + MAXSZ_STR_STAT, listPoliciesCommand->prefix_stats.all.loss_rate); } +#endif controlState_SetCommandOutput(state, commandOutputMain); diff --git a/hicn-light/src/hicn/config/controlListRoutes.c b/hicn-light/src/hicn/config/controlListRoutes.c index 3dc8fa3a3..33a1ac6f5 100644 --- a/hicn-light/src/hicn/config/controlListRoutes.c +++ b/hicn-light/src/hicn/config/controlListRoutes.c @@ -120,7 +120,7 @@ static CommandReturn _controlListRoutes_Execute(CommandParser *parser, (i * sizeof(list_routes_command))); addrString = utils_CommandAddressToString( - listRoutesCommand->addressType, &listRoutesCommand->address, &port); + listRoutesCommand->family, &listRoutesCommand->address, &port); PARCBufferComposer *composer = parcBufferComposer_Create(); diff --git a/hicn-light/src/hicn/config/controlRemoveConnection.c b/hicn-light/src/hicn/config/controlRemoveConnection.c index 7c79f9c2f..cbc1fb8db 100644 --- a/hicn-light/src/hicn/config/controlRemoveConnection.c +++ b/hicn-light/src/hicn/config/controlRemoveConnection.c @@ -25,7 +25,6 @@ #include <parc/algol/parc_Memory.h> #include <parc/algol/parc_Network.h> -#include <hicn/utils/address.h> #include <hicn/config/controlRemoveConnection.h> diff --git a/hicn-light/src/hicn/config/controlRemoveListener.c b/hicn-light/src/hicn/config/controlRemoveListener.c index 545e189c0..2e38a8a2f 100644 --- a/hicn-light/src/hicn/config/controlRemoveListener.c +++ b/hicn-light/src/hicn/config/controlRemoveListener.c @@ -25,7 +25,6 @@ #include <parc/algol/parc_Memory.h> #include <parc/algol/parc_Network.h> -#include <hicn/utils/address.h> #include <hicn/config/controlRemoveListener.h> diff --git a/hicn-light/src/hicn/config/controlRemovePolicy.c b/hicn-light/src/hicn/config/controlRemovePolicy.c index bd2e6e6d8..ff49cb73a 100644 --- a/hicn-light/src/hicn/config/controlRemovePolicy.c +++ b/hicn-light/src/hicn/config/controlRemovePolicy.c @@ -27,8 +27,6 @@ #include <stdio.h> #include <stdlib.h> -#include <hicn/utils/address.h> - #include <hicn/config/controlRemovePolicy.h> #include <hicn/utils/commands.h> @@ -103,7 +101,7 @@ static CommandReturn _controlRemovePolicy_Execute(CommandParser *parser, free(addr); return CommandReturn_Failure; } - removePolicyCommand->addressType = ADDR_INET; + removePolicyCommand->family = AF_INET; } else if (inet_pton(AF_INET6, addr, &removePolicyCommand->address.v6.as_in6addr) == 1) { if (len > 128) { @@ -112,7 +110,7 @@ static CommandReturn _controlRemovePolicy_Execute(CommandParser *parser, free(addr); return CommandReturn_Failure; } - removePolicyCommand->addressType = ADDR_INET6; + removePolicyCommand->family = AF_INET6; } else { printf("Error: %s is not a valid network address \n", addr); parcMemory_Deallocate(&removePolicyCommand); diff --git a/hicn-light/src/hicn/config/controlRemovePunting.c b/hicn-light/src/hicn/config/controlRemovePunting.c index bf00389d6..b5b734820 100644 --- a/hicn-light/src/hicn/config/controlRemovePunting.c +++ b/hicn-light/src/hicn/config/controlRemovePunting.c @@ -25,7 +25,6 @@ #include <parc/algol/parc_Memory.h> #include <parc/algol/parc_Network.h> -#include <hicn/utils/address.h> #include <hicn/config/controlRemovePunting.h> diff --git a/hicn-light/src/hicn/config/controlRemoveRoute.c b/hicn-light/src/hicn/config/controlRemoveRoute.c index 0f46211c1..067fea25f 100644 --- a/hicn-light/src/hicn/config/controlRemoveRoute.c +++ b/hicn-light/src/hicn/config/controlRemoveRoute.c @@ -25,8 +25,6 @@ #include <stdio.h> #include <stdlib.h> -#include <hicn/utils/address.h> - #include <hicn/config/controlRemoveRoute.h> #include <hicn/utils/commands.h> @@ -111,7 +109,7 @@ static CommandReturn _controlRemoveRoute_Execute(CommandParser *parser, free(addr); return CommandReturn_Failure; } - removeRouteCommand->addressType = ADDR_INET; + removeRouteCommand->family = AF_INET; } else if (inet_pton(AF_INET6, addr, &removeRouteCommand->address.v6.as_in6addr) == 1) { if (len > 128) { @@ -120,7 +118,7 @@ static CommandReturn _controlRemoveRoute_Execute(CommandParser *parser, free(addr); return CommandReturn_Failure; } - removeRouteCommand->addressType = ADDR_INET6; + removeRouteCommand->family = AF_INET6; } else { printf("Error: %s is not a valid network address \n", addr); parcMemory_Deallocate(&removeRouteCommand); diff --git a/hicn-light/src/hicn/config/controlSetStrategy.c b/hicn-light/src/hicn/config/controlSetStrategy.c index 10fec964b..3cb5d9df5 100644 --- a/hicn-light/src/hicn/config/controlSetStrategy.c +++ b/hicn-light/src/hicn/config/controlSetStrategy.c @@ -42,7 +42,8 @@ static CommandReturn _controlSetStrategy_HelpExecute(CommandParser *parser, static const char *_commandSetStrategy = "set strategy"; static const char *_commandSetStrategyHelp = "help set strategy"; -static const char *_commandSetStrategyOptions[LAST_STRATEGY_VALUE] = { +static const char *_commandSetStrategyOptions[STRATEGY_TYPE_N] = { + "(undefined)", "loadbalancer", "random", "low_latency", @@ -62,10 +63,10 @@ CommandOps *controlSetStrategy_HelpCreate(ControlState *state) { // ==================================================== -strategy_type _validStrategy(const char *strategy) { - strategy_type validStrategy = LAST_STRATEGY_VALUE; +strategy_type_t _validStrategy(const char *strategy) { + strategy_type_t validStrategy = STRATEGY_TYPE_UNDEFINED; - for (int i = 0; i < LAST_STRATEGY_VALUE; i++) { + for (int i = 0; i < STRATEGY_TYPE_N; i++) { if (strcmp(_commandSetStrategyOptions[i], strategy) == 0) { validStrategy = i; break; @@ -92,7 +93,7 @@ static bool _checkAndSetIp(set_strategy_command * setStrategyCommand, res = inet_pton(AF_INET, addr, &setStrategyCommand->address.v4.as_u32); else res = inet_pton(AF_INET, addr, - &setStrategyCommand->addresses[index].v4.as_u32); + &setStrategyCommand->low_latency.addresses[index].v4.as_u32); if(res == 1) { if (len == UINT32_MAX) { @@ -103,9 +104,9 @@ static bool _checkAndSetIp(set_strategy_command * setStrategyCommand, return false; } if(index == -1) - setStrategyCommand->addressType = ADDR_INET; + setStrategyCommand->family = AF_INET; else - setStrategyCommand->addresses_type[index] = ADDR_INET; + setStrategyCommand->low_latency.families[index] = AF_INET; } else { @@ -114,7 +115,7 @@ static bool _checkAndSetIp(set_strategy_command * setStrategyCommand, &setStrategyCommand->address.v6.as_in6addr); else res = inet_pton(AF_INET6, addr, - &setStrategyCommand->addresses[index].v6.as_in6addr); + &setStrategyCommand->low_latency.addresses[index].v6.as_in6addr); if(res == 1) { if (len == UINT32_MAX) { @@ -126,9 +127,9 @@ static bool _checkAndSetIp(set_strategy_command * setStrategyCommand, } if(index == -1) - setStrategyCommand->addressType = ADDR_INET6; + setStrategyCommand->family = AF_INET6; else - setStrategyCommand->addresses_type[index] = ADDR_INET6; + setStrategyCommand->low_latency.families[index] = AF_INET6; } else { printf("Error: %s is not a valid network address \n", addr); @@ -191,8 +192,8 @@ static CommandReturn _controlSetStrategy_Execute(CommandParser *parser, const char *strategyStr = parcList_GetAtIndex(args, 3); // check valid strategy - strategy_type strategy; - if ((strategy = _validStrategy(strategyStr)) == LAST_STRATEGY_VALUE) { + strategy_type_t strategy; + if ((strategy = _validStrategy(strategyStr)) == STRATEGY_TYPE_UNDEFINED) { printf("Error: invalid strategy \n"); parcMemory_Deallocate(&setStrategyCommand); _controlSetStrategy_HelpExecute(parser, ops, args); @@ -204,7 +205,7 @@ static CommandReturn _controlSetStrategy_Execute(CommandParser *parser, // Fill remaining payload fields setStrategyCommand->len = len; - setStrategyCommand->strategyType = strategy; + setStrategyCommand->strategy_type = strategy; //check additional prefixes if(parcList_Size(args) > 4){ @@ -223,7 +224,7 @@ static CommandReturn _controlSetStrategy_Execute(CommandParser *parser, free(rel_addr); return CommandReturn_Failure; } - setStrategyCommand->lens[addr_index] = rel_len; + setStrategyCommand->low_latency.lens[addr_index] = rel_len; free(rel_addr); index++; addr_index++; diff --git a/hicn-light/src/hicn/config/controlState.c b/hicn-light/src/hicn/config/controlState.c index 2df8805c6..34a0b1327 100644 --- a/hicn-light/src/hicn/config/controlState.c +++ b/hicn-light/src/hicn/config/controlState.c @@ -42,7 +42,7 @@ struct controller_state { bool debugFlag; void *userdata; - struct iovec *(*writeRead)(ControlState *state, struct iovec *msg); + uint8_t *(*writeRead)(ControlState *state, uint8_t *msg); int sockfd; char **commandOutput; bool isInteractive; @@ -75,7 +75,7 @@ int controlState_connectToFwdDeamon(char *server_ip, uint16_t port) { ControlState *controlState_Create( void *userdata, - struct iovec *(*writeRead)(ControlState *state, struct iovec *msg), + uint8_t *(*writeRead)(ControlState *state, uint8_t * msg), bool openControllerConnetion, char *server_ip, uint16_t port) { ControlState *state = parcMemory_AllocateAndClear(sizeof(ControlState)); @@ -128,11 +128,13 @@ void controlState_RegisterCommand(ControlState *state, CommandOps *ops) { 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"); +uint8_t * +controlState_write_read(ControlState *state, uint8_t *packet) +{ + assert(state); + assert(packet); - return state->writeRead(state, msg); + return state->writeRead(state, packet); } static PARCList *_controlState_ParseStringIntoTokens( diff --git a/hicn-light/src/hicn/config/controlState.h b/hicn-light/src/hicn/config/controlState.h index cc38cbe37..5c565f9a4 100644 --- a/hicn-light/src/hicn/config/controlState.h +++ b/hicn-light/src/hicn/config/controlState.h @@ -61,7 +61,7 @@ typedef struct controller_state ControlState; ControlState *controlState_Create( void *userdata, - struct iovec *(*writeRead)(ControlState *state, struct iovec *msg), + uint8_t *(*writeRead)(ControlState *state, uint8_t * msg), bool openControllerConnetion, char * server_ip, uint16_t port); 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/content_store/CMakeLists.txt b/hicn-light/src/hicn/content_store/CMakeLists.txt index 85643cf5e..45cfe2267 100644 --- a/hicn-light/src/hicn/content_store/CMakeLists.txt +++ b/hicn-light/src/hicn/content_store/CMakeLists.txt @@ -14,20 +14,12 @@ 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..30f972ce9 --- /dev/null +++ b/hicn-light/src/hicn/content_store/lru.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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/content_store.h> +#include "lru.h" + +// XXX TODO some part to be moved to parent + +// XXX TODO +#if 0 +static void _content_store_lru_Log(ContentStoreInterface *storeImpl) { + content_store_lru_data_t *store = + (content_store_lru_data_t *)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 +bool +_content_store_lru_remove_least_used(content_store_t * cs) +{ + if (content_store_size(cs) == 0) + return false; + +#if 0 + ListLruEntry *lruEntry = listLRU_PopTail(store->lru); + content_store_entry_t *storeEntry = + (content_store_entry_t *)listLRU_EntryGetData(lruEntry); +#else + content_store_entry_t * entry = NULL; +#endif + + DEBUG("CS %p LRU evict msgbuf %p (#evictions %" PRIu64 ")", + cs, content_store_entry_message(entry), + cs->stats.lru.countLruEvictions); + + content_store_purge_entry(cs, entry); + + return true; +} + +static +void +_evictByStorePolicy(content_store_t * cs, 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. + + content_store_entry_t *entry = + listTimeOrdered_GetOldest(store->indexByExpirationTime); + if (entry && content_store_entry_has_expiry_time(entry) && + (currentTimeInTicks > content_store_entry_get_expiry_time(entry))) { + // Found an expired entry. Remove it, and we're done. + + store->stats.countExpiryEvictions++; + DEBUG("ContentStore %p evict message %p by ExpiryTime (ExpiryTime evictions %" PRIu64 ")", + (void *)store, (void *)contentStoreEntry_GetMessage(entry), + store->stats.countExpiryEvictions); + + _content_store_lru_purge_entry(store, entry); + } else { + store->stats.countLruEvictions++; + _content_store_lru_remove_least_used(store); + } +} +#endif + +void +content_store_lru_initialize(content_store_t * cs) +{ + content_store_lru_data_t * data = cs->data; + + data->lru = NULL; + if (!data->lru) { + ERROR("Could not create LRU index"); + goto ERR_INDEX; + } + +ERR_INDEX: + return; +} + +void +content_store_lru_finalize(content_store_t * cs) +{ + content_store_lru_data_t * data = cs->data; + + if (data->lru != NULL) + ; // XXX TODO listLRU_Destroy(&(store->lru)); +} + +bool +content_store_lru_add_entry(content_store_t * cs, content_store_entry_t * entry) +{ + assert(cs); + assert(entry); + + if (content_store_size(cs) == 0) + return false; +#if 0 + content_store_lru_data_t * data = cs->data; + + content_store_entry_t *dataEntry = parcHashCodeTable_Get(data->storageByName, content); + if(dataEntry) + _content_store_lru_purge_entry(data, dataEntry); + + 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 (now >= expiryTimeTicks) + return false; + + if (data->objectCount >= data->objectCapacity) + // Store is full. Need to make room. + _evictByStorePolicy(data, now); + + // And now add a new entry to the head of the LRU. + content_store_entry_t *entry = contentStoreEntry_Create(content, data->lru); + if (!entry) + return false; + + if (!parcHashCodeTable_Add(data->storageByName, content, entry)) { + // Free what we just created, but did not add. 'entry' has ownership of + // 'copy', and so will call _Release() on it + contentStoreEntry_Release(&entry); + WARN("ContentStoreLRU %p failed to add message %p to hash table", + (void *)data, (void *)content); + return false; + } + + if (content_store_entry_has_expiry_time(entry)) + listTimeOrdered_Add(data->indexByExpirationTime, entry); + + data->objectCount++; + data->stats.countAdds++; + + DEBUG("ContentStoreLRU %p saved message %p (object count %" PRIu64 ")", + data, msgbuf, content_store_size(cs)); +#endif + return true; +} + +/** + * Remove a content_store_entry_t from all tables and indices. + */ +static +void +content_store_lru_remove_entry(content_store_t * cs, content_store_entry_t * entry) +{ + assert(cs); + assert(entry); + // + // XXX REMOVE ENTRY FROM LRU +} + + +DECLARE_CONTENT_STORE(lru); diff --git a/hicn-light/src/hicn/processor/pitStandard.h b/hicn-light/src/hicn/content_store/lru.h index 9d7ce6a23..61341921f 100644 --- a/hicn-light/src/hicn/processor/pitStandard.h +++ b/hicn-light/src/hicn/content_store/lru.h @@ -13,29 +13,22 @@ * limitations under the License. */ -/** - * @file pitStandard.h - * @brief The Pending Interest Table - * - * Implements the standard Pending Interest Table. - * - */ +#ifndef HICNLIGHT_CONTENT_STORE_LRU_H +#define HICNLIGHT_CONTENT_STORE_LRU_H -#ifndef pitStandard_h -#define pitStandard_h +typedef struct { + // This LRU is just for keeping track of insertion and access order. + //ListLru *lru; + void * lru; +} content_store_lru_data_t; -#include <hicn/processor/pit.h> +typedef struct { + uint64_t countExpiryEvictions; + uint64_t countRCTEvictions; + uint64_t countLruEvictions; + uint64_t countAdds; + uint64_t countHits; + uint64_t countMisses; +} content_store_lru_stats_t; -/** - * 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 +#endif /* HICNLIGHT_CONTENT_STORE_LRU_H */ diff --git a/hicn-light/src/hicn/core/CMakeLists.txt b/hicn-light/src/hicn/core/CMakeLists.txt index 5e2b696d7..b1f952a43 100644 --- a/hicn-light/src/hicn/core/CMakeLists.txt +++ b/hicn-light/src/hicn/core/CMakeLists.txt @@ -14,20 +14,27 @@ 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}/listener.h + ${CMAKE_CURRENT_SOURCE_DIR}/listener_table.h + ${CMAKE_CURRENT_SOURCE_DIR}/listener_vft.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}/msgbuf.h + ${CMAKE_CURRENT_SOURCE_DIR}/packet_cache.h + ${CMAKE_CURRENT_SOURCE_DIR}/pit.h + ${CMAKE_CURRENT_SOURCE_DIR}/prefix_stats.h + ${CMAKE_CURRENT_SOURCE_DIR}/strategy.h + ${CMAKE_CURRENT_SOURCE_DIR}/strategy_vft.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 @@ -36,20 +43,27 @@ list(APPEND HEADER_FILES ) list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/address.c + ${CMAKE_CURRENT_SOURCE_DIR}/address_pair.c ${CMAKE_CURRENT_SOURCE_DIR}/connection.c - ${CMAKE_CURRENT_SOURCE_DIR}/connectionList.c - ${CMAKE_CURRENT_SOURCE_DIR}/connectionManager.c - ${CMAKE_CURRENT_SOURCE_DIR}/connectionTable.c - ${CMAKE_CURRENT_SOURCE_DIR}/dispatcher.c + ${CMAKE_CURRENT_SOURCE_DIR}/connection_table.c + ${CMAKE_CURRENT_SOURCE_DIR}/connection_vft.c + ${CMAKE_CURRENT_SOURCE_DIR}/content_store.c + ${CMAKE_CURRENT_SOURCE_DIR}/fib.c + ${CMAKE_CURRENT_SOURCE_DIR}/fib_entry.c ${CMAKE_CURRENT_SOURCE_DIR}/forwarder.c - ${CMAKE_CURRENT_SOURCE_DIR}/logger.c - ${CMAKE_CURRENT_SOURCE_DIR}/message.c - ${CMAKE_CURRENT_SOURCE_DIR}/numberSet.c - ${CMAKE_CURRENT_SOURCE_DIR}/streamBuffer.c + ${CMAKE_CURRENT_SOURCE_DIR}/listener.c + ${CMAKE_CURRENT_SOURCE_DIR}/listener_table.c + ${CMAKE_CURRENT_SOURCE_DIR}/listener_vft.c ${CMAKE_CURRENT_SOURCE_DIR}/mapme.c - ${CMAKE_CURRENT_SOURCE_DIR}/wldr.c + ${CMAKE_CURRENT_SOURCE_DIR}/msgbuf.c ${CMAKE_CURRENT_SOURCE_DIR}/nameBitvector.c ${CMAKE_CURRENT_SOURCE_DIR}/name.c + ${CMAKE_CURRENT_SOURCE_DIR}/packet_cache.c + ${CMAKE_CURRENT_SOURCE_DIR}/pit.c + ${CMAKE_CURRENT_SOURCE_DIR}/prefix_stats.c + ${CMAKE_CURRENT_SOURCE_DIR}/strategy.c + ${CMAKE_CURRENT_SOURCE_DIR}/wldr.c ) set(SOURCE_FILES ${SOURCE_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..07aa4a8bd --- /dev/null +++ b/hicn-light/src/hicn/core/address.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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> + +int +address_from_ip_port(address_t * address, int family, ip_address_t * addr, uint16_t port) +{ + memset(address, 0, sizeof(address_t)); + switch(family) { + case AF_INET: + *address = ADDRESS4(addr->v4.as_inaddr.s_addr, port); + break; + case AF_INET6: + *address = ADDRESS6(addr->v6.as_in6addr, port); + break; + default: + return -1; + } + return 0; +} + +const char * _address_family_str[] = { + [AF_INET] = "AF_INET", + [AF_INET6] = "AF_INET6", +}; diff --git a/hicn-light/src/hicn/core/address.h b/hicn-light/src/hicn/core/address.h new file mode 100644 index 000000000..d13fc99ed --- /dev/null +++ b/hicn-light/src/hicn/core/address.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 HICN_ADDRESS_H +#define HICN_ADDRESS_H + +#include <netinet/in.h> + +#include <string.h> // memcmp +#include <hicn/util/ip_address.h> +#include <netinet/in.h> + +typedef struct sockaddr_storage address_t; + +#define address_equals(a, b) (memcmp(a, b, sizeof(address_t)) == 0) + +#define address_family(address) ((address)->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)->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) + +#define address6_is_local(address) (IN6_IS_ADDR_LOOPBACK(address6(address))) + +#define address_is_local(address) ((address)->ss_family == AF_INET) \ + ? address4_is_local(address) : address6_is_local(address) + +int address_from_ip_port(address_t * address, int family, ip_address_t * addr, uint16_t port); + +#define ADDRESS4(ip, port) (*(address_t*) &((struct sockaddr_in) { \ + .sin_family = AF_INET, \ + .sin_port = htons(port), \ + .sin_addr.s_addr = htonl(ip), \ +})) + +#define ADDRESS4_LOCALHOST(port) ADDRESS4(INADDR_LOOPBACK, (port)) +#define ADDRESS4_ANY(port) ADDRESS4(INADDR_ANY, (port)) + +#define ADDRESS6(ip, port) (*(address_t*) &((struct sockaddr_in6) {\ + .sin6_family = AF_INET6, \ + .sin6_port = htons(port), \ + .sin6_addr = IN6ADDR_ANY_INIT, \ + .sin6_scope_id = 0, \ +})) + +#define ADDRESS6_ANY(port) ADDRESS6(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)) + +#endif /* HICN_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..dee06c0a7 --- /dev/null +++ b/hicn-light/src/hicn/core/address_pair.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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" + +int +address_pair_from_ip_port(address_pair_t * pair, int family, + ip_address_t * local_addr, uint16_t local_port, + ip_address_t * remote_addr, uint16_t remote_port) +{ + 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..fae4f255f --- /dev/null +++ b/hicn-light/src/hicn/core/address_pair.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 HICN_ADDRESS_PAIR_H +#define HICN_ADDRESS_PAIR_H + +#include <hicn/core/address.h> +#include <hicn/util/ip_address.h> + +typedef struct { + address_t local; + address_t remote; +} address_pair_t; + +int address_pair_from_ip_port(address_pair_t * pair, int family, + ip_address_t * local_addr, uint16_t local_port, + ip_address_t * remote_addr, uint16_t remote_port); + +#define address_pair_get_local(pair) (&(pair)->local) +#define address_pair_get_remote(pair) (&(pair)->remote) + +#define address_pair_get_local_family(pair) \ + (address_family(address_pair_local(pair))) +#define address_pair_get_remote_family(pair) \ + (address_family(address_pair_remote(pair))) +#define address_pair_get_family(pair) address_pair_local_family(pair) + +#define address_pair_is_valid(pair) \ + (address_pair_local_family(pair) == address_pair_remote_family(pair)) + +#endif /* HICN_ADDRESS_PAIR_H */ diff --git a/hicn-light/src/hicn/core/connection.c b/hicn-light/src/hicn/core/connection.c index c2ac71a5f..582e2f56f 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) 2017-2020 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.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,583 @@ * limitations under the License. */ -#include <limits.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> +/** + * @file connection.c + * @brief Implementation of hICN connections + */ -#include <hicn/core/connection.h> -#include <hicn/core/connectionState.h> -#include <hicn/core/messageHandler.h> -#include <hicn/core/ticks.h> -#include <hicn/core/wldr.h> -#include <hicn/io/addressPair.h> -#include <hicn/io/ioOperations.h> +#include <assert.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#ifdef WITH_POLICY -#include <hicn/policy.h> -#endif /* WITH_POLICY */ +#include <hicn/core/forwarder.h> +#include <hicn/util/log.h> +#include <hicn/core/wldr.h> -struct connection { +#include "connection.h" +#include "connection_vft.h" - const AddressPair *addressPair; - IoOperations *ops; +#define _conn_var(x) _connection_ ## x - unsigned refCount; +#if 0 - unsigned counter; +/* Accessors */ - 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; +static inline +unsigned +connection_get_id(const connection_t * connection) +{ + return connection->id; +} -#ifdef WITH_POLICY - policy_tags_t tags; -#endif /* WITH_POLICY */ +static inline +char * +connection_get_name(const connection_t * connection) +{ + return connection->name; +} -}; +static inline +face_type_t +connection_get_type(const connection_t * connection) +{ + return connection->type; +} -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; +static inline +address_pair_t * +connection_get_pair(const connection_t * connection) +{ + return connection->pair; +} - conn->wldrAutoStart = true; - conn->counter = 0; +static inline +bool +connection_is_up(const connection_t * connection) +{ + return connection->up; +} - /* By default, a connection will aim at the UP state */ - connection_SetAdminState(conn, CONNECTION_STATE_UP); +static inline +bool +connection_is_local(const connection_t * connection) +{ + return connection->local; +} -#ifdef WITH_POLICY - conn->tags = POLICY_TAGS_EMPTY; -#endif /* WITH_POLICY */ +static inline +face_state_t +connection_get_state(const connection_t * connection) +{ + return connection->state; +} - return conn; +static inline +void +connection_set_state(connection_t * connection, face_state_t state) +{ + connection->state = state; } -Connection *connection_Acquire(Connection *connection) { - parcAssertNotNull(connection, "Parameter conn must be non-null"); - connection->refCount++; - return connection; +static inline +face_state_t +connection_get_admin_state(const connection_t * connection) +{ + return connection->admin_state; } -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; +static inline +void +connection_set_admin_state(connection_t * connection, face_state_t state) +{ + connection->admin_state = state; +} - 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); - } - *connectionPtr = NULL; +static inline +const char * +connection_get_interface_name(const connection_t * connection) +{ + return connection->interface_name; } -bool connection_Send(const Connection *conn, Message *message) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); +#ifdef WITH_POLICY - if (ioOperations_IsUp(conn->ops)) { - if (message_GetType(message) == MessagePacketType_ContentObject) { - uint8_t connectionId = (uint8_t)connection_GetConnectionId(conn); - message_UpdatePathLabel(message, connectionId); - } - if (conn->wldr != NULL) { - wldr_SetLabel(conn->wldr, message); - } else { - message_ResetWldrLabel(message); - } - return ioOperations_Send(conn->ops, NULL, message); - } - return false; +static inline +uint32_t +connection_get_priority(const connection_t * connection) +{ + connection->priority = priority; } -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); +static inline +void +connection_set_priority(connection_t * connection, uint32_t priority) +{ + connection->priority = priority; } -bool connection_SendBuffer(const Connection *conn, u8 * buffer, size_t length) +static inline +policy_tags_t +connection_get_tags(const connection_t * connection) { - struct iovec iov[1]; - iov[0].iov_base = buffer; - iov[0].iov_len = length; - return connection_SendIOVBuffer(conn, iov, 1); + return connection->tags; } -void connection_Probe(Connection *conn, uint8_t * probe) { - ioOperations_SendProbe(conn->ops, probe); +static inline +void +connection_set_tags(connection_t * connection, policy_tags_t tags) +{ + connection->tags = tags; } -void connection_HandleProbe(Connection *conn, uint8_t *probe){ - parcAssertNotNull(conn, "Parameter conn must be non-null"); - parcAssertNotNull(probe, "Parameter pkt must be non-null"); +#endif /* WITH_POLICY */ - if(messageHandler_IsInterest(probe)){ - messageHandler_CreateProbeReply(probe, HF_INET6_TCP); - ioOperations_SendProbe(conn->ops, probe); - } -} +/* API */ -IoOperations *connection_GetIoOperations(const Connection *conn) { - return conn->ops; -} +#endif -unsigned connection_GetConnectionId(const Connection *conn) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - return ioOperations_GetConnectionId(conn->ops); -} +connection_t * +connection_create_on_listener(const listener_t * listener, const char * name, + const address_pair_t * pair, forwarder_t * forwarder) +{ + const connection_table_t * table = forwarder_get_connection_table(forwarder); -const AddressPair *connection_GetAddressPair(const Connection *conn) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - return ioOperations_GetAddressPair(conn->ops); -} + connection_t * connection; + connection_table_allocate(table, connection, pair, name); -bool connection_IsUp(const Connection *conn) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) return false; - return ioOperations_IsUp(conn->ops); + unsigned connection_id = connection_table_get_connection_id(table, connection); + + const char * interface_name = listener_get_interface_name(listener); + // XXX This should not be there ! + int fd = listener_get_socket(listener, address_pair_get_local(pair), + address_pair_get_remote(pair), NULL); + bool local = address_is_local(&pair->local); + + if (connection_initialize(connection, listener->type, name, interface_name, fd, pair, local, + connection_id, forwarder) < 0) { + connection_table_deallocate(table, connection); + return NULL; + } + + return connection; } -bool connection_IsLocal(const Connection *conn) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - return ioOperations_IsLocal(conn->ops); + +// This is called by configuration +// XXX different wit create on listener : when listener receives a new +// connection +// ! +connection_t * +connection_create(face_type_t type, const char * name, + const address_pair_t * pair, forwarder_t * forwarder) +{ + assert(face_type_is_valid(type)); + assert(pair); + assert(forwarder); + + listener_table_t * table = forwarder_get_listener_table(forwarder); + listener_t *listener = listener_table_get_by_address(table, type, &pair->local); + if (!listener) { + // XXX TODO + //char *str = addressToString(localAddress); + ERROR("Could not find listener to match address N/A"); + //parcMemory_Deallocate((void **)&str); + return NULL; + } + + return connection_create_on_listener(listener, name, pair, forwarder); } -const void *connection_Class(const Connection *conn) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - return ioOperations_Class(conn->ops); +#if 0 + + const char * interface_name = listener->getInterfaceName(listener); + int fd = listener->getSocket(listener, pair); + bool is_local = address_is_local(&pair->local); + + + return udpConnection_Create(forwarder, interface_name, fd, pair, is_local, connid); + + // alternatively + // } +#endif -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; +/** + * @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). + * @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, forwarder_t * forwarder) +{ + int rc; + + assert(connection); + /* Interface name can be NULL eg always for TCP connnections */ + assert(pair); + assert(address_pair_valid(pair)); + + *connection = (connection_t) { + .id = connection_id, + .name = strdup(name), + .type = type, + .interface_name = strdup(interface_name), + .pair = *pair, + .fd = fd, +// .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 + .priority = 0, +#endif /* WITH_POLICY */ - if (connection_IsUp(conn)) { - // here the wldr header is alreay set: this message is a retransmission or a - // notification + .forwarder = forwarder, + .closed = false, - // 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 + /* WLDR */ + .wldr = NULL, + .wldr_autostart = true, + }; - 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); + connection->data = malloc(connection_vft[connection->type]->data_size); + if (!connection->data) + goto ERR_DATA; - res = ioOperations_Send(conn->ops, NULL, message); + assert(connection_has_valid_type(connection)); - message_SetPathLabel(message, old_path_label); - } else { - res = ioOperations_Send(conn->ops, NULL, message); + rc = connection_vft[connection->type]->initialize(connection); + if (rc < 0) { + goto ERR_VFT; } - } - if (notification) { - // the notification is never destroyed - message_Release(&message); - } + // XXX uncertain as fd is created by the listener !! + // XXX check whether it is registered ! +#if 0 + connection->fd = connection_vft[connection->type]->get_socket(connection, address, NULL, interface_name); + if (connection->fd < 0) { + ERROR("Error creating connection fd: (%d) %s", errno, strerror(errno)); + goto ERR_FD; + } + + // XXX data should be pre-allocated here + + if (loop_register_fd(MAIN_LOOP, connection->fd, connection, + connection_vft[connection->type]->read_callback, NULL) < 0) + goto ERR_REGISTER_FD; +#endif + + // XXX TODO + //char *str = pair_ToString(udp->pair); + DEBUG("%s connection %p created for address %s (local=%s)", + face_type_str(connection->type), connection, "N/A", + connection_is_local(connection) ? "true" : "false"); + //free(str); + // + return 0; + +#if 0 +ERR_REGISTER_FD: +#ifndef _WIN32 + close(connection->fd); +#else + closesocket(connection->fd); +#endif +ERR_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); - return res; + if (connection->wldr) + wldr_free(connection->wldr); + + connection_vft[connection->type]->finalize(connection); + + free(connection->interface_name); + free(connection); + + DEBUG("%s connection %p destroyed", face_type_str(connection->type), + connection); + + return 0; } -void connection_AllowWldrAutoStart(Connection *conn, bool allow) { - conn->wldrAutoStart = allow; +#if 0 +// XXX put in common the validation and processing of commands with UDP and hICN +// listeners ! +command_type_t +_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); + + message_type_t message_type = message_type_from_uchar(msg[0]); + //if (!message_type_is_valid(message_type)) + if (message_type != REQUEST_LIGHT) + return COMMAND_TYPE_N; + + return command_type_from_uchar(msg[1]); } -void connection_EnableWldr(Connection *conn) { - if (!connection_IsLocal(conn)) { - if (conn->wldr == NULL) { - printf("----------------- enable wldr\n"); - conn->wldr = wldr_Init(); +// XXX new function to process all incoming bytes +// result : consumed, discard/invalid, wait for more +// PRE: buffer has at least 8 bytes (to get the length of all packets) +// This function is only used to make decisions +/** + * \return the number of consumed bytes, or a negative value in case of error + */ +// XXX mutualize with listener_process_buffer +size_t +connection_process_buffer(connection_t * connection, const uint8_t * buffer, size_t size) +{ + size_t expected; + + /* Too small a packet is not useful to decide between a control message and + * an hICN packet, the size of a control message is enough to test for both + * pakcet types */ + if (size < sizeof(header_control_message)) + return 0; + + /* We expect complete packets most of the time, so don't bother with state */ + message_type_t message_type = message_type_from_uchar(msg[0]); + if (message_type == REQUEST_LIGHT) { + command_type_t command_type = command_type_from_uchar(msg[1]); + if (!command_type_is_valid(command_type)) + break; + expected = sizeof(header_control_message) + + command_get_payload_len(command_type); + if (size < expected) + return 0; + forwarder_receive_command(connection->forwarder, command_type, packet, + connection->id); + return expected; + } + + if (!messageHandler_IsValidHicnPacket(packet)) { + WARN("Connection #%u: Malformed packet received", + connection_get_id(connection)); + return -1; } - } -} -void connection_DisableWldr(Connection *conn) { - if (!connection_IsLocal(conn)) { - if (conn->wldr != NULL) { - printf("----------------- disable wldr\n"); - wldr_Destroy(&(conn->wldr)); - conn->wldr = NULL; + /* Check that we have a full packet */ + expected = messageHandler_GetTotalPacketLength(packet), + if (size < expected) + return 0; + + msgbuf_t msgbuf; + MessagePacketType packet_type; + if (messageHandler_IsInterest(message->messageHead)) { + packet_type = MESSAGE_TYPE_INTEREST; + } else if (messageHandler_IsData(message->messageHead)) { + packet_type = MESSAGE_TYPE_DATA; + } else { + ERROR("Dropped packet that is not interest nor data"); + return -1; } - } -} -bool connection_HasWldr(const Connection *conn) { - if (conn->wldr == NULL) { - return false; - } else { - return true; - } -} + // this is an Hicn packet (here we should distinguish between IPv4 and + // IPv6 tryReadMessage may set nextMessageLength + msgbuf_from_packet(&msgbuf, packet, expected, packet_type, + connection_get_id(connection), ticks_now()); + forwarder_receive(connection->forwarder, &msgbuf, 1); -bool connection_WldrAutoStartAllowed(const Connection *conn) { - return conn->wldrAutoStart; + return size; } -void connection_DetectLosses(Connection *conn, Message *message) { - if (conn->wldr != NULL) wldr_DetectLosses(conn->wldr, conn, message); -} +int +connection_read_message(connection_t * connection, msgbuf_t * msgbuf) +{ + assert(connection); + assert(face_type_is_valid(connection->type)); + assert(msgbuf); -void connection_HandleWldrNotification(Connection *conn, Message *message) { - if (conn->wldr != NULL) - wldr_HandleWldrNotification(conn->wldr, conn, message); + return connection_vft[connection->type]->read_message(connection, msgbuf); } -connection_state_t connection_GetState(const Connection *conn) +uint8_t * +connection_read_packet(connection_t * connection) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) - return CONNECTION_STATE_UNDEFINED; - return ioOperations_GetState(conn->ops); + assert(connection); + assert(face_type_is_valid(connection->type)); + + return connection_vft[connection->type]->read_packet(connection); } +#endif -void connection_SetState(Connection *conn, connection_state_t state) +int +connection_send_packet(const connection_t * connection, const uint8_t * packet, + size_t size) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) - return; - ioOperations_SetState(conn->ops, state); + assert(connection); + assert(face_type_is_valid(connection->type)); + assert(packet); + + return connection_vft[connection->type]->send_packet(connection, packet, size); } -connection_state_t connection_GetAdminState(const Connection *conn) +// ALL DEPRECATED CODE HERE TO BE UPDATED + +// XXX nexthops null ?? to be removed ??? +bool +_connection_send(const connection_t * connection, msgbuf_t * msgbuf, bool queue) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) - return CONNECTION_STATE_UNDEFINED; - return ioOperations_GetAdminState(conn->ops); + return connection_vft[connection->type]->send(connection, msgbuf, queue); } -void connection_SetAdminState(Connection *conn, connection_state_t admin_state) +bool +connection_send(const connection_t * connection, msgbuf_t * msgbuf, bool queue) { - 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); + assert(connection); + + /* NULL message means flush */ + if (!msgbuf) + return _connection_send(connection, NULL, false); + + if (!connection_is_up(connection)) + return false; + + if (msgbuf_get_type(msgbuf) == MESSAGE_TYPE_DATA) { + uint8_t conn_id = (uint8_t)connection_get_id(connection); + msgbuf_update_pathlabel(msgbuf, conn_id); + } + + if (connection->wldr) + wldr_set_label(connection->wldr, msgbuf); + else + msgbuf_reset_wldr_label(msgbuf); + + return _connection_send(connection, msgbuf, queue); } -#ifdef WITH_POLICY -uint32_t connection_GetPriority(const Connection *conn) +/* + * here the wldr header is alreay set: this message is a retransmission or a + * notification + * + * we need to recompute the path label since we always store a pointer to + * the same message if this message will be sent again to someone else, the + * new path label must be computed starting from the orignal label. Note + * that we heve the same problem in case of PIT aggregation. That case is + * handled inside the MessageProcessor. This is specific to WLDR + * retransmittions. This is done only for data packets + */ +bool +connection_resend(const connection_t * connection, msgbuf_t * msgbuf, bool + notification) { - parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) - return 0; - return ioOperations_GetPriority(conn->ops); + assert(connection); + assert(msgbuf); + + bool ret = false; + + if (!connection_is_up(connection)) + return ret; + + if (msgbuf_get_type(msgbuf) == MESSAGE_TYPE_DATA) { + uint8_t conn_id = (uint8_t)connection_get_id(connection); + uint32_t old_path_label = msgbuf_get_pathlabel(msgbuf); + msgbuf_update_pathlabel(msgbuf, conn_id); + ret = _connection_send(connection, msgbuf, false); /* no queueing */ + msgbuf_set_pathlabel(msgbuf, old_path_label); + } else { + ret = _connection_send(connection, msgbuf, false); /* no queueing */ + } + + return ret; } -void connection_SetPriority(Connection *conn, uint32_t priority) -{ +#if 0 +bool connection_sendv(const connection_t * conn, struct iovec *msg, + size_t size) { parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) - return; - ioOperations_SetPriority(conn->ops, priority); + parcAssertNotNull(msg, "Parameter message must be non-null"); + + return ioOperations_SendIOVBuffer(conn->ops, msg, size); } -#endif /* WITH_POLICY */ -const char * connection_GetInterfaceName(const Connection * conn) -{ +void connection_probe(connection_t * conn, uint8_t * probe) { + ioOperations_SendProbe(conn->ops, probe); +} + +void connection_hangle_probe(connection_t * conn, uint8_t *probe){ parcAssertNotNull(conn, "Parameter conn must be non-null"); - if (!conn->ops) - return NULL; - return ioOperations_GetInterfaceName(conn->ops); + parcAssertNotNull(probe, "Parameter pkt must be non-null"); + + if(messageHandler_IsInterest(probe)){ + messageHandler_CreateProbeReply(probe, HF_INET6_TCP); + ioOperations_SendProbe(conn->ops, probe); + } } +#endif -#ifdef WITH_POLICY -void connection_AddTag(Connection *conn, policy_tag_t tag) +/* WLDR */ + +void +connection_wldr_allow_autostart(connection_t * connection, bool value) { - policy_tags_add(&conn->tags, tag); + connection->wldr_autostart = value; } -void connection_RemoveTag(Connection *conn, policy_tag_t tag) +bool +connection_wldr_autostart_is_allowed(connection_t * connection) { - policy_tags_remove(&conn->tags, tag); + return connection->wldr_autostart; } -policy_tags_t connection_GetTags(const Connection *conn) +void +connection_wldr_enable(connection_t * connection, bool value) { - return conn->tags; + 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) +bool +connection_has_wldr(const connection_t * connection) { - conn->tags = tags; + return !!connection->wldr; } -void connection_ClearTags(Connection *conn) +void +connection_wldr_detect_losses(const connection_t * connection, msgbuf_t * msgbuf) { - conn->tags = POLICY_TAGS_EMPTY; + if (!connection->wldr) + return; + wldr_detect_losses(connection->wldr, connection, msgbuf); } -int connection_HasTag(const Connection *conn, policy_tag_t tag) +void +connection_wldr_handle_notification(const connection_t * connection, msgbuf_t * msgbuf) { - return policy_tags_has(conn->tags, tag); + 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..45d341ab8 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) 2017-2020 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -15,19 +15,22 @@ /** * @file connection.h - * @brief Wrapper for different types of connections - * - * A connection wraps a specific set of {@link IoOperations}. Those operations - * allow for input and output. Connections get stored in the Connection Table. - * + * @brief hICN connections */ -#ifndef connection_h -#define connection_h -#include <hicn/hicn-light/config.h> -#include <hicn/core/connectionState.h> -#include <hicn/io/ioOperations.h> -#include <hicn/utils/address.h> +#ifndef HICNLIGHT_CONNECTION_H +#define HICNLIGHT_CONNECTION_H + +#include <hicn/core/address_pair.h> +#include <hicn/core/listener.h> +#include <hicn/core/msgbuf.h> +#include <hicn/face.h> + +#ifdef WITH_POLICY +#include <hicn/policy.h> +#endif /* WITH_POLICY */ + +#define CONNECTION_ID_UNDEFINED ~0 #ifdef WITH_MAPME typedef enum { @@ -42,157 +45,169 @@ typedef enum { #endif /* WITH_MAPME */ +struct forwarder_s; +struct wldr_s; + +typedef struct { + unsigned id; + char * name; + char * interface_name; + face_type_t type; + address_pair_t pair; + int fd; +// bool up; + bool local; + face_state_t state; + face_state_t admin_state; #ifdef WITH_POLICY -#include <hicn/policy.h> + policy_tags_t tags; + uint32_t priority; #endif /* WITH_POLICY */ + void * data; + + struct forwarder_s * forwarder; // recv only + bool closed; + + /* WLDR */ + + bool wldr_autostart; + /* + * if true, wldr can be set automatically by default this value is set to + * true. if wldr is activated using a command (config file/hicnLightControl) + * this value is set to false so that a base station can not disable wldr at + * the client. + */ + struct wldr_s * wldr; + +} connection_t; + +#if 1 +#define connection_get_id(C) ((C)->id) +#define connection_id_is_valid(ID) (ID != CONNECTION_ID_UNDEFINED) +#define connection_get_name(C) ((C)->name) +#define connection_get_type(C) ((C)->type) +#define connection_has_valid_id(C) (connection_id_is_valid(connection_get_id(C)) +#define connection_get_pair(C) (&(C)->pair) +#define connection_get_local(C) (address_pair_local(connection_get_pair(C))) +#define connection_get_remote(C) (address_pair_remote(connection_get_pair(C))) +#define connection_get_local(C) (address_pair_local(connection_get_pair(C))) +#define connection_get_remote(C) (address_pair_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) -struct connection; -typedef struct connection Connection; +#ifdef WITH_POLICY +#define connection_get_priority(C) ((C)->priority) +#define connection_set_priority(C, PRIORITY) (C)->priority = PRIORITY +#define connection_get_tags(C) ((C)->tags) +#define connection_set_tags(C, TAGS) (C)->tags = TAGS +#define connection_has_tag(C, TAG) policy_tags_has(connection_get_tags(C), TAG) +#define connection_add_tag(C, TAG) policy_tags_add(connection_get_tags(X), TAG) +#define connection_remove_tag(C, TAG) \ +do { \ + policy_tags_t _conn_var(tags); \ + _conn_var(tags) = connection_get_tags(C); \ + policy_tags_remove(_conn_var(tags), (TAG)); \ + connection_set_tags((C), _conn_var(tags)); \ +} while(0) +#define connection_clear_tags(C) connection_set_tags(C, POLICY_TAGS_EMPTY) -/** - * Creates a connection object. - */ -Connection *connection_Create(IoOperations *ops); +#endif /* WITH_POLICY */ -/** - * @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); -/** - * @function connection_Acquire - * @abstract A reference counted copy. - * @discussion - * A shallow copy, they share the same memory. - */ -Connection *connection_Acquire(Connection *connection); +#else -/** - * @function connection_Send - * @abstract Sends the message on the connection - * @return true if message sent, false if connection not up - */ -bool connection_Send(const Connection *conn, Message *message); +/* Accessors */ +static inline unsigned connection_get_id(const connection_t * connection); -/** - * @function connection_SendIOVBuffer - * @abstract Sends an IOV buffer - */ -bool connection_SendIOVBuffer(const Connection *conn, struct iovec *msg, - size_t size); +#define connection_id_is_valid(id) (id != CONNECTION_ID_UNDEFINED) +#define connection_has_valid_id(C) (connection_id_is_valid(connection_get_id(C)) -/** - * @function connection_SendBuffer - * @abstract Sends a buffer - */ -bool connection_SendBuffer(const Connection *conn, u8 * buffer, size_t length); +static inline char * connection_get_name(const connection_t * connection); -/** - * Return the `IoOperations` instance associated with the specified `Connection` - * instance. - * @param [in] connection The allocated connection - * @return a pointer to the IoOperations instance associated by th specified - * connection. - */ -IoOperations *connection_GetIoOperations(const Connection *conn); +static inline face_type_t connection_get_type(const connection_t * connection); -/** - * Returns the unique identifier of the connection - * Calls the underlying IoOperations to fetch the connection id - * @param [in] connection The allocated connection - * @return unsigned The unique connection id - */ -unsigned connection_GetConnectionId(const Connection *conn); +static inline address_pair_t * connection_get_pair(const connection_t * connection); -/** - * Returns the (remote, local) address pair that describes the connection - * @param [in] connection The allocated connection - * @return non-null The connection's remote and local address - * @return null Should never return NULL - */ -const AddressPair *connection_GetAddressPair(const Connection *conn); +#define connection_get_local(C) (address_pair_local(connection_get_pair(C))) +#define connection_get_remote(C) (address_pair_remote(connection_get_pair(C))) -/** - * Checks if the connection is in the "up" state - * @param [in] connection The allocated connection - * @return true The connection is in the "up" state - * @return false The connection is not in the "up" state - */ -bool connection_IsUp(const Connection *conn); +static inline bool connection_is_up(const connection_t * connection); -/** - * Checks if the connection is to a Local/Loopback address - * - * A local connection is PF_LOCAL (PF_UNIX) and a loopback connection is - * 127.0.0.0/8 or ::1 for IPv6. - * - * @param [in] connection The allocated connection - * - * @retval true The connection is local or loopback - * @retval false The connection is not local or loopback - */ -bool connection_IsLocal(const Connection *conn); +static inline bool connection_is_local(const connection_t * connection); -/** - * Returns an opaque pointer representing the class of the Io Operations - * - * Returns an opaque pointer that an implementation can use to detect if - * the connection is based on that class. - * - * @param [in] conn The Connection to analyze - * - * @return non-null An opaque pointer for each concrete implementation - */ -const void *connection_Class(const Connection *conn); +static inline face_state_t connection_get_state(const connection_t * connection); + +static inline void connection_set_state(connection_t * connection, face_state_t state); + +static inline face_state_t connection_get_admin_state(const connection_t * connection); -bool connection_ReSend(const Connection *conn, Message *message, - bool notification); +static inline void connection_set_admin_state(connection_t * connection, face_state_t state); -void connection_Probe(Connection *conn, uint8_t *probe); +static inline const char * connection_get_interface_name(const connection_t * connection); -void connection_HandleProbe(Connection *conn, uint8_t *message); +#ifdef WITH_POLICY -void connection_AllowWldrAutoStart(Connection *conn, bool allow); +static inline uint32_t connection_get_priority(const connection_t * connection); -void connection_EnableWldr(Connection *conn); +static inline void connection_set_priority(connection_t * connection, uint32_t priority); -void connection_DisableWldr(Connection *conn); +static inline policy_tags_t connection_get_tags(const connection_t * connection); -bool connection_HasWldr(const Connection *conn); +static inline void connection_set_tags(connection_t * connection, policy_tags_t tags); -bool connection_WldrAutoStartAllowed(const Connection *conn); +#define connection_has_tag(C, TAG) policy_tags_has(connection_get_tags(C), TAG) -void connection_DetectLosses(Connection *conn, Message *message); +#define connection_add_tag(C, TAG) policy_tags_add(connection_get_tags(X), TAG) -void connection_HandleWldrNotification(Connection *conn, Message *message); +#define connection_remove_tag(C, TAG) \ +do { \ + policy_tags_t _conn_var(tags); \ + _conn_var(tags) = connection_get_tags(C); \ + policy_tags_remove(_conn_var(tags), (TAG)); \ + connection_set_tags((C), _conn_var(tags)); \ +} while(0) -connection_state_t connection_GetState(const Connection *conn); +#define connection_clear_tags(C) connection_set_tags(C, POLICY_TAGS_EMPTY) -void connection_SetState(Connection *conn, connection_state_t state); +#endif /* WITH_POLICY */ -connection_state_t connection_GetAdminState(const Connection *conn); +#endif -void connection_SetAdminState(Connection *conn, connection_state_t admin_state); +connection_t * connection_create(face_type_t type, const char * name, + const address_pair_t * pair, struct forwarder_s * forwarder); -#ifdef WITH_POLICY -uint32_t connection_GetPriority(const Connection *conn); +int connection_initialize(connection_t * connection, face_type_t type, const char * name, + const char * interface_name, int fd, const address_pair_t * pair, + bool local, unsigned connection_id, struct forwarder_s * forwarder); -void connection_SetPriority(Connection *conn, uint32_t priority); -#endif /* WITH_POLICY */ +int connection_finalize(connection_t * connection); -const char * connection_GetInterfaceName(const Connection * conn); +int connection_send_packet(const connection_t * connection, + const uint8_t * packet, size_t size); -#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 */ +bool connection_send(const connection_t * connection, msgbuf_t * msgbuf, + 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(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, msgbuf_t * msgbuf); + +void connection_wldr_handle_notification(const connection_t * connection, msgbuf_t * msgbuf); -#endif // connection_h +#endif /* HICNLIGHT_CONNECTION_H */ diff --git a/hicn-light/src/hicn/core/connectionList.c b/hicn-light/src/hicn/core/connectionList.c deleted file mode 100644 index d51a9aad5..000000000 --- a/hicn-light/src/hicn/core/connectionList.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_Memory.h> - -#include <parc/assert/parc_Assert.h> -#include <hicn/core/connectionList.h> - -struct connection_list { - PARCArrayList *listOfConnections; -}; - -static void connectionList_ArrayDestroyer(void **voidPtr) { - Connection **entryPtr = (Connection **)voidPtr; - connection_Release(entryPtr); -} - -ConnectionList *connectionList_Create() { - ConnectionList *list = parcMemory_AllocateAndClear(sizeof(ConnectionList)); - parcAssertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ConnectionList)); - list->listOfConnections = parcArrayList_Create(connectionList_ArrayDestroyer); - return list; -} - -void connectionList_Destroy(ConnectionList **listPtr) { - parcAssertNotNull(listPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*listPtr, "Parameter must dereference to non-null pointer"); - ConnectionList *list = *listPtr; - parcArrayList_Destroy(&list->listOfConnections); - parcMemory_Deallocate((void **)&list); - *listPtr = NULL; -} - -void connectionList_Append(ConnectionList *list, Connection *entry) { - parcAssertNotNull(list, "Parameter list must be non-null"); - parcAssertNotNull(entry, "Parameter entry must be non-null"); - - parcArrayList_Add(list->listOfConnections, connection_Acquire(entry)); -} - -size_t connectionList_Length(const ConnectionList *list) { - parcAssertNotNull(list, "Parameter list must be non-null"); - return parcArrayList_Size(list->listOfConnections); -} - -Connection *connectionList_Get(ConnectionList *list, size_t index) { - parcAssertNotNull(list, "Parameter list must be non-null"); - Connection *original = - (Connection *)parcArrayList_Get(list->listOfConnections, index); - return original; -} diff --git a/hicn-light/src/hicn/core/connectionList.h b/hicn-light/src/hicn/core/connectionList.h deleted file mode 100644 index fbba9f6d8..000000000 --- a/hicn-light/src/hicn/core/connectionList.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file connectionList.h - * @brief A typesafe list of Connection objects - * - * <#Detailed Description#> - * - */ - -#ifndef connectionList_h -#define connectionList_h - -struct connection_list; -typedef struct connection_list ConnectionList; - -#include <hicn/core/connection.h> - -/** - * Creates a lis of Connection - * - * @return non-null An allocated list - * @return null An error - */ -ConnectionList *connectionList_Create(void); - -/** - * Destroys the list and all objects inside it - */ -void connectionList_Destroy(ConnectionList **listPtr); - -/** - * @function connectionList_Append - * @abstract Adds a connection entry to the list. - * @discussion - * Acquires a reference to the passed entry and stores it in the list. - */ -void connectionList_Append(ConnectionList *list, Connection *entry); - -/** - * Returns the number of items on the list - * @param [in] list The allocated list to check - * @return number The number of items on the list - */ -size_t connectionList_Length(const ConnectionList *list); - -/** - * @function connectionList_Get - * @abstract Returns the connection entry. - * @discussion - * Caller must not destroy the returned value. If you will store the - * entry in your own data structure, you should acquire your own reference. - * Will assert if you go beyond the end of the list. - * - */ -Connection *connectionList_Get(ConnectionList *list, size_t index); -#endif // connectionList_h diff --git a/hicn-light/src/hicn/core/connectionManager.c b/hicn-light/src/hicn/core/connectionManager.c deleted file mode 100644 index 709f0902a..000000000 --- a/hicn-light/src/hicn/core/connectionManager.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * The Connection Manager sets itself up as a listener to the Messenger so it - * can take action based on system events. - * - * The Connection Manager queues and then processes in a later time slice the - * messages. - * - */ - -#include <hicn/hicn-light/config.h> -#include <hicn/core/connectionManager.h> -#include <hicn/core/forwarder.h> -#include <hicn/messenger/messenger.h> -#include <hicn/messenger/messengerRecipient.h> -#include <hicn/messenger/missiveDeque.h> -#include <stdio.h> - -#include <parc/algol/parc_Memory.h> - -#include <parc/assert/parc_Assert.h> - -struct connection_manager { - Forwarder *forwarder; - Logger *logger; - - MessengerRecipient *messengerRecipient; - - // we queue missives as they come in to process in our own - // event timeslice - MissiveDeque *missiveQueue; - - // for deferred queue processing - PARCEventTimer *timerEvent; -}; - -/** - * Receives missives from the messenger, queues them, and schedules our - * execution - * - * We defer processing of missives to a later time slice - */ -static void connectionManager_MessengerCallback(MessengerRecipient *recipient, - Missive *missive); - -/** - * Event callback - * - * This is our main run loop to process our queue of messages. It is scheduled - * in {@link connectionManager_MessengerCallback} when the queue becomes - * non-empty. - * - * When we are called here, we have exclusive use of the system, so we will not - * create any message loops - * - * @param [in] fd unused, required for compliance with function prototype - * @param [in] which_event unused, required for compliance with function - * prototype - * @param [in] connManagerVoidPtr A void* to ConnectionManager - * - */ -static void connectionManager_ProcessQueue(int fd, PARCEventType which_event, - void *connManagerVoidPtr); - -static void connectionManager_ProcessClosedMissive( - ConnectionManager *connManager, const Missive *missive); - -// ======================================================== -// Public API - -ConnectionManager *connectionManager_Create(Forwarder *forwarder) { - ConnectionManager *connManager = - parcMemory_AllocateAndClear(sizeof(ConnectionManager)); - parcAssertNotNull(connManager, - "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ConnectionManager)); - connManager->forwarder = forwarder; - connManager->missiveQueue = missiveDeque_Create(); - connManager->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - - Messenger *messenger = forwarder_GetMessenger(connManager->forwarder); - - // creates the timer, but does not start it - PARCEventScheduler *base = - dispatcher_GetEventScheduler(forwarder_GetDispatcher(forwarder)); - connManager->timerEvent = parcEventTimer_Create( - base, 0, connectionManager_ProcessQueue, connManager); - - connManager->messengerRecipient = messengerRecipient_Create( - connManager, connectionManager_MessengerCallback); - messenger_Register(messenger, connManager->messengerRecipient); - return connManager; -} - -void connectionManager_Destroy(ConnectionManager **managerPtr) { - parcAssertNotNull(managerPtr, "Double pointer must be non-null"); - parcAssertNotNull(*managerPtr, "Double pointer must dereference to non-null"); - - ConnectionManager *connManager = *managerPtr; - - Messenger *messenger = forwarder_GetMessenger(connManager->forwarder); - parcEventTimer_Destroy(&(connManager->timerEvent)); - messenger_Unregister(messenger, connManager->messengerRecipient); - messengerRecipient_Destroy(&connManager->messengerRecipient); - missiveDeque_Release(&connManager->missiveQueue); - logger_Release(&connManager->logger); - - parcMemory_Deallocate((void **)&connManager); - *managerPtr = NULL; -} - -// ======================================================== -// Internal Functions - -static void connectionManager_MessengerCallback(MessengerRecipient *recipient, - Missive *missive) { - ConnectionManager *connManager = - messengerRecipient_GetRecipientContext(recipient); - - // we do not release our reference count, we store it until later - // We are called with our own reference, so we do not need to acquire the - // missive here. - missiveDeque_Append(connManager->missiveQueue, missive); - - if (missiveDeque_Size(connManager->missiveQueue) == 1) { - // When it becomes non-empty, schedule {@link - // connectionManager_ProcessQueue} - struct timeval immediateTimeout = {0, 0}; - parcEventTimer_Start(connManager->timerEvent, &immediateTimeout); - } -} - -static void connectionManager_ProcessQueue(int fd, PARCEventType which_event, - void *connManagerVoidPtr) { - ConnectionManager *connManager = (ConnectionManager *)connManagerVoidPtr; - - Missive *missive; - while ((missive = missiveDeque_RemoveFirst(connManager->missiveQueue)) != - NULL) { - switch (missive_GetType(missive)) { - case MissiveType_ConnectionCreate: - // hook to signal that a new connection was created - break; - case MissiveType_ConnectionUp: - // hook to signal that a new connection is up - break; - case MissiveType_ConnectionDown: - // hook to signal that a connection is down - break; - case MissiveType_ConnectionClosed: - connectionManager_ProcessClosedMissive(connManager, missive); - break; - case MissiveType_ConnectionDestroyed: - // hook to signal that a connection was destroyed - break; - default: - parcTrapUnexpectedState("Missive %p of unknown type: %d", - (void *)missive, missive_GetType(missive)); - } - missive_Release(&missive); - } -} - -static void connectionManager_ProcessClosedMissive( - ConnectionManager *connManager, const Missive *missive) { - logger_Log(connManager->logger, LoggerFacility_Core, PARCLogLevel_Debug, - __func__, "Processing CLOSED message for connid %u", - missive_GetConnectionId(missive)); - - ConnectionTable *table = forwarder_GetConnectionTable(connManager->forwarder); - const Connection *conn = - connectionTable_FindById(table, missive_GetConnectionId(missive)); - - if (conn) { - // this will destroy the connection if its the last reference count - connectionTable_Remove(table, conn); - - // remove from FIB - forwarder_RemoveConnectionIdFromRoutes(connManager->forwarder, - missive_GetConnectionId(missive)); - } -} diff --git a/hicn-light/src/hicn/core/connectionManager.h b/hicn-light/src/hicn/core/connectionManager.h deleted file mode 100644 index 34fee8717..000000000 --- a/hicn-light/src/hicn/core/connectionManager.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file connectionManager.h - * @brief The connection manager handles connection events, such as going down - * - * The connection manager listens to the event notification system. Based on - * those events, the connection manager will take specific actions. This is - * expected to be a singleton instantiated by the forwarder. - * - */ - -#ifndef connectionManager_h -#define connectionManager_h - -#include <hicn/core/forwarder.h> - -struct connection_manager; -typedef struct connection_manager ConnectionManager; - -ConnectionManager *connectionManager_Create(Forwarder *forwarder); - -void connectionManager_Destroy(ConnectionManager **managerPtr); -#endif // connectionManager_h diff --git a/hicn-light/src/hicn/core/connectionTable.c b/hicn-light/src/hicn/core/connectionTable.c deleted file mode 100644 index f8589c12b..000000000 --- a/hicn-light/src/hicn/core/connectionTable.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @header ConnectionTable - * @abstract Records all the current connections and references to them - * @discussion - * - */ - -#ifndef _WIN32 -#include <unistd.h> -#endif -#include <hicn/hicn-light/config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <parc/assert/parc_Assert.h> - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_HashCodeTable.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_TreeRedBlack.h> -#include <hicn/core/connectionTable.h> -#include <hicn/io/addressPair.h> - -struct connection_table { - // The main storage table that has a Destroy method. - // The key is an unsigned int pointer. We use an unsigned int pointer - // because we want to be able to lookup by the id alone, and not have to - // have the IoOperations everywhere. - PARCHashCodeTable *storageTableById; - - // The key is a AddressPair - // It does not have a destroy method for the data or key, - // as they are derived from the storage table. - PARCHashCodeTable *indexByAddressPair; - - // An iterable stucture organized by connection id. The keys and - // values are the same pointers as in storageTableById, so there - // are no destructors in the tree. - // The only reason to keep this tree is so we have an iterable list - // of connections, which the hash table does not give us. - PARCTreeRedBlack *listById; -}; - -static bool connectionTable_ConnectionIdEquals(const void *keyA, - const void *keyB) { - unsigned idA = *((unsigned *)keyA); - unsigned idB = *((unsigned *)keyB); - return (idA == idB); -} - -static int connectionTable_ConnectionIdCompare(const void *keyA, - const void *keyB) { - unsigned idA = *((unsigned *)keyA); - unsigned idB = *((unsigned *)keyB); - if (idA < idB) { - return -1; - } - if (idA > idB) { - return +1; - } - return 0; -} - -static bool connectionTable_AddressPairEquals(const void *keyA, - const void *keyB) { - const AddressPair *pairA = (const AddressPair *)keyA; - const AddressPair *pairB = (const AddressPair *)keyB; - - return addressPair_Equals(pairA, pairB); -} - -static HashCodeType connectionTable_ConnectionIdHashCode(const void *keyA) { - unsigned idA = *((unsigned *)keyA); - return parcHash32_Int32(idA); -} - -static HashCodeType connectionTable_AddressPairHashCode(const void *keyA) { - const AddressPair *pairA = (const AddressPair *)keyA; - return addressPair_HashCode(pairA); -} - -static void connectionTable_ConnectionIdDestroyer(void **dataPtr) { - unsigned *idA = (unsigned *)*dataPtr; - parcMemory_Deallocate((void **)&idA); - *dataPtr = NULL; -} - -static void connectionTable_ConnectionDestroyer(void **dataPtr) { - connection_Release((Connection **)dataPtr); -} - -ConnectionTable *connectionTable_Create() { - size_t initialSize = 16384; - - ConnectionTable *conntable = - parcMemory_AllocateAndClear(sizeof(ConnectionTable)); - parcAssertNotNull(conntable, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ConnectionTable)); - - conntable->storageTableById = parcHashCodeTable_Create_Size( - connectionTable_ConnectionIdEquals, connectionTable_ConnectionIdHashCode, - connectionTable_ConnectionIdDestroyer, - connectionTable_ConnectionDestroyer, initialSize); - - // no key or data destroyer, this is an index into storageByid. - conntable->indexByAddressPair = parcHashCodeTable_Create_Size( - connectionTable_AddressPairEquals, connectionTable_AddressPairHashCode, - NULL, NULL, initialSize); - - conntable->listById = - parcTreeRedBlack_Create(connectionTable_ConnectionIdCompare, - NULL, // key free - NULL, // key copy - NULL, // value equals - NULL, // value free - NULL); // value copy - - return conntable; -} - -void connectionTable_Destroy(ConnectionTable **conntablePtr) { - parcAssertNotNull(conntablePtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*conntablePtr, - "Parameter must dereference to non-null pointer"); - - ConnectionTable *conntable = *conntablePtr; - - parcTreeRedBlack_Destroy(&conntable->listById); - parcHashCodeTable_Destroy(&conntable->indexByAddressPair); - parcHashCodeTable_Destroy(&conntable->storageTableById); - parcMemory_Deallocate((void **)&conntable); - *conntablePtr = NULL; -} - -/** - * @function connectionTable_Add - * @abstract Add a connection, takes ownership of memory - */ -void connectionTable_Add(ConnectionTable *table, Connection *connection) { - parcAssertNotNull(table, "Parameter table must be non-null"); - parcAssertNotNull(connection, "Parameter connection must be non-null"); - - unsigned *connectionIdKey = parcMemory_Allocate(sizeof(unsigned)); - parcAssertNotNull(connectionIdKey, "parcMemory_Allocate(%zu) returned NULL", - sizeof(unsigned)); - *connectionIdKey = connection_GetConnectionId(connection); - - if (parcHashCodeTable_Add(table->storageTableById, connectionIdKey, - connection)) { - parcHashCodeTable_Add(table->indexByAddressPair, - (void *)connection_GetAddressPair(connection), - connection); - parcTreeRedBlack_Insert(table->listById, connectionIdKey, connection); - } else { - parcTrapUnexpectedState( - "Could not add connection id %u -- is it a duplicate?", - *connectionIdKey); - } -} - -/** - * @function connectionTable_Remove - * @abstract Removes the connection, calling Destroy on our copy - */ -void connectionTable_Remove(ConnectionTable *table, - const Connection *connection) { - parcAssertNotNull(table, "Parameter table must be non-null"); - parcAssertNotNull(connection, "Parameter connection must be non-null"); - - unsigned connid = connection_GetConnectionId(connection); - - parcTreeRedBlack_Remove(table->listById, &connid); - parcHashCodeTable_Del(table->indexByAddressPair, - connection_GetAddressPair(connection)); - parcHashCodeTable_Del(table->storageTableById, &connid); -} - -void connectionTable_RemoveById(ConnectionTable *table, unsigned id) { - parcAssertNotNull(table, "Parameter table must be non-null"); - const Connection *connection = connectionTable_FindById(table, id); - if (connection) { - connectionTable_Remove(table, connection); - } -} - -const Connection *connectionTable_FindByAddressPair(ConnectionTable *table, - const AddressPair *pair) { - parcAssertNotNull(table, "Parameter table must be non-null"); - return (Connection *)parcHashCodeTable_Get(table->indexByAddressPair, pair); -} - -const Connection *connectionTable_FindById(const ConnectionTable *table, - unsigned id) { - parcAssertNotNull(table, "Parameter table must be non-null"); - return (Connection *)parcHashCodeTable_Get(table->storageTableById, &id); -} - -ConnectionList *connectionTable_GetEntries(const ConnectionTable *table) { - parcAssertNotNull(table, "Parameter table must be non-null"); - ConnectionList *list = connectionList_Create(); - - PARCArrayList *values = parcTreeRedBlack_Values(table->listById); - for (size_t i = 0; i < parcArrayList_Size(values); i++) { - Connection *original = parcArrayList_Get(values, i); - connectionList_Append(list, original); - } - parcArrayList_Destroy(&values); - return list; -} diff --git a/hicn-light/src/hicn/core/connectionTable.h b/hicn-light/src/hicn/core/connectionTable.h deleted file mode 100644 index 548ef8e6e..000000000 --- a/hicn-light/src/hicn/core/connectionTable.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - */ - -#ifndef connectionTable_h -#define connectionTable_h - -#include <hicn/core/connection.h> -#include <hicn/core/connectionList.h> -#include <hicn/io/addressPair.h> -#include <hicn/io/ioOperations.h> - -struct connection_table; -typedef struct connection_table ConnectionTable; - -/** - * Creates an empty connection table - */ -ConnectionTable *connectionTable_Create(void); - -/** - * Destroys the connection table - * This will release the reference to all connections stored in the connection - * table. - * @param [in,out] conntablePtr Pointer to the allocated connection table, will - * be NULL'd - */ -void connectionTable_Destroy(ConnectionTable **conntablePtr); - -/** - * @function connectionTable_Add - * @abstract Add a connection, takes ownership of memory - */ -void connectionTable_Add(ConnectionTable *table, Connection *connection); - -/** - * @function connectionTable_Remove - * @abstract Removes the connection, calling Destroy on our copy - */ -void connectionTable_Remove(ConnectionTable *table, - const Connection *connection); - -/** - * Removes a connection from the connection table - * - * Looks up a connection by its connection ID and removes it from the connection - * table. Removing the connection will call connection_Release() on the - * connection object. - * - * @param [in] table The allocated connection table - * @param [in] id The connection ID - */ -void connectionTable_RemoveById(ConnectionTable *table, unsigned id); - -/** - * Lookup a connection by the (local, remote) addres pair - * - * @param [in] table The allocated connection table - * @param [in] pair The address pair to match, based on the inner values of the - * local and remote addresses - * - * @retval non-null The matched conneciton - * @retval null No match found or error - */ -const Connection *connectionTable_FindByAddressPair(ConnectionTable *table, - const AddressPair *pair); - -/** - * @function connectionTable_FindById - * @abstract Find a connection by its numeric id. - * @return NULL if not found - */ -const Connection *connectionTable_FindById(const ConnectionTable *table, unsigned id); - -/** - * @function connectionTable_GetEntries - * @abstract Returns a list of connections. They are reference counted copies - * from the table. - * @discussion - * An allocated list of connections in the table. Each list entry is a - * reference counted copy of the connection in the table, thus they are "live" - * objects. - */ -ConnectionList *connectionTable_GetEntries(const ConnectionTable *table); -#endif // connectionTable_h diff --git a/hicn-light/src/hicn/core/connection_table.c b/hicn-light/src/hicn/core/connection_table.c new file mode 100644 index 000000000..fd8013b73 --- /dev/null +++ b/hicn-light/src/hicn/core/connection_table.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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/core/connection.h> +#include <hicn/core/connection_table.h> + +/* This is only used for first allocation, as the table is resizeable */ +#define DEFAULT_CONNECTION_TABLE_SIZE 64 + +connection_table_t * +connection_table_create(size_t elt_size, size_t max_elts) +{ + connection_table_t * table = malloc(sizeof(connection_table_t)); + if (!table) + return NULL; + + table->id_by_pair = kh_init_ct_pair(); + table->id_by_name = kh_init_ct_name(); + pool_init(table->connections, DEFAULT_CONNECTION_TABLE_SIZE); + + return table; +} + +void +connection_table_free(connection_table_t * table) +{ + kh_destroy_ct_pair(table->id_by_pair); + kh_destroy_ct_name(table->id_by_name); + pool_free(table->connections); + free(table); +} + +connection_t * +connection_table_get_by_pair(const connection_table_t * table, + const address_pair_t * pair) +{ + khiter_t k = kh_get_ct_pair(table->id_by_pair, pair); + if (k == kh_end(table->id_by_pair)) + return NULL; + return table->connections + kh_val(table->id_by_pair, k); +} + +unsigned +connection_table_get_id_by_name(const connection_table_t * table, + const char * name) +{ + khiter_t k = kh_get_ct_name(table->id_by_name, name); + if (k == kh_end(table->id_by_name)) + return CONNECTION_ID_UNDEFINED; + return kh_val(table->id_by_name, k); +} + +connection_t * +connection_table_get_by_name(const connection_table_t * table, + const char * name) +{ + unsigned conn_id = connection_table_get_id_by_name(table, name); + if (!connection_id_is_valid(conn_id)) + return NULL; + return table->connections + conn_id; +} + +void +connection_table_remove_by_id(connection_table_t * table, off_t id) +{ + /* + * Get the connection addresspair & name so as to be able to remove them + * from the hash table index + */ + connection_t * connection = connection_table_at(table, id); + connection_table_deallocate(table, connection); +} 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..c0406ced8 --- /dev/null +++ b/hicn-light/src/hicn/core/connection_table.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + */ + +/* Iterate on connection table : to remove all connections associated to a + * listener based on listen address */ + +#ifndef HICN_CONNECTION_TABLE_H +#define HICN_CONNECTION_TABLE_H + +//#include <hicn/base/common.h> +#include <hicn/core/address_pair.h> +#include <hicn/core/connection.h> +#include <hicn/base/hash.h> +#include <hicn/base/khash.h> +#include <hicn/base/pool.h> + +#include <hicn/common.h> + +#define address_pair_hash(pair) (hash32(pair, sizeof(address_pair_t))) +#define address_pair_hash_eq(a, b) (address_pair_hash(b) - address_pair_hash(a)) + +KHASH_INIT(ct_pair, const address_pair_t *, unsigned, 0, address_pair_hash, address_pair_hash_eq); + +KHASH_INIT(ct_name, const char *, unsigned, 0, str_hash, str_hash_eq); + +/* + * The connection table is composed of : + * - a connection pool allowing connection access by id in constant time + * - a hash table allowing to perform lookups based on address pairs, to get a connection id. + * + * For fast lookup by ID, the connection table will point to the beginning of + * the pool / vector, holding all connections. + * The header will be prepended + */ + +typedef struct { + kh_ct_pair_t * id_by_pair; + kh_ct_name_t * id_by_name; + + connection_t * connections; // pool +} connection_table_t; + +#define connection_table_allocate(table, conn, pair, name) \ +do { \ + pool_get(table->connections, conn); \ + off_t connection_id = conn - table->connections; \ + int res; \ + khiter_t k = kh_put_ct_pair(table->id_by_pair, pair, &res); \ + kh_value(table->id_by_pair, k) = connection_id; \ + if (name) { \ + k = kh_put_ct_name(table->id_by_name, name, &res); \ + kh_value(table->id_by_name, k) = connection_id; \ + } \ +} while(0) + +#define connection_table_deallocate(table, conn) \ +do { \ + const address_pair_t * pair = connection_get_pair(connection); \ + khiter_t k = kh_get_ct_pair(table->id_by_pair, pair); \ + if (k != kh_end(table->id_by_pair)) \ + kh_del_ct_pair(table->id_by_pair, k); \ + \ + const char * name = connection_get_name(connection); \ + if (name) { \ + k = kh_get_ct_name(table->id_by_name, name); \ + if (k != kh_end(table->id_by_name)) \ + kh_del_ct_name(table->id_by_name, k); \ + } \ + \ + pool_put(table->connections, conn); \ +} while(0) \ + +#define connection_table_len(table) (pool_elts(table->connections)) + +#define connection_table_validate_id(table, id) \ + pool_validate_id((table)->connections, (id)) + +#define connection_table_at(table, id) ((table)->connections + id) + +#define connection_table_get_connection_id(table, conn) \ + (conn - table->connections) + +#define connection_table_foreach(table, conn, BODY) \ + pool_foreach(table->connections, (conn), BODY) + +#define connection_table_enumerate(table, i, conn, BODY) \ + pool_foreach(table->connections, (i), (conn), BODY) + +connection_table_t * connection_table_create(); +void connection_table_free(connection_table_t * table); + +#define connection_table_get_by_id(table, id) \ + connection_table_validate_id((table), (id)) \ + ? connection_table_at((table), (id)) : NULL; + +connection_t * connection_table_get_by_pair(const connection_table_t * table, + const address_pair_t * pair); + +unsigned connection_table_get_id_by_name(const connection_table_t * table, + const char * name); + +connection_t * connection_table_get_by_name(const connection_table_t * table, + const char * name); + +void connection_table_remove_by_id(connection_table_t * table, off_t id); + +//unsigned connection_table_add(connection_table_t * table, Connection * connection); + +#endif /* HICN_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..9efdd0107 --- /dev/null +++ b/hicn-light/src/hicn/core/connection_vft.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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" + +extern connection_ops_t connection_hicn; +extern connection_ops_t connection_tcp; +extern connection_ops_t connection_udp; + +const connection_ops_t * connection_vft[] = { + [FACE_TYPE_HICN] = &connection_hicn, + [FACE_TYPE_TCP] = &connection_tcp, + [FACE_TYPE_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..589f39536 --- /dev/null +++ b/hicn-light/src/hicn/core/connection_vft.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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); + int (*send)(const connection_t * connection, msgbuf_t * msgbuf, bool queue); + int (*send_packet)(const connection_t * connection, + const uint8_t * packet, size_t size); + void (*read_callback)(connection_t * connection, int fd, void * data); + size_t data_size; +} connection_ops_t; + +#define DECLARE_CONNECTION(NAME) \ +const connection_ops_t connection_ ## NAME = { \ + .initialize = connection_ ## NAME ## _initialize, \ + .finalize = connection_ ## NAME ## _finalize, \ + .get_socket = listener_ ## NAME ## _get_socket, \ + .send = connection_ ## NAME ## _send, \ + .send_packet = connection_ ## NAME ## _send_packet, \ + .read_callback = connection_ ## NAME ## _read_callback, \ + .data_size = sizeof(connection_ ## NAME ## _data_t), \ +}; + +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..7ed2bd838 --- /dev/null +++ b/hicn-light/src/hicn/core/content_store.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 <inttypes.h> +#include <hicn/base/pool.h> +#include <hicn/util/log.h> + +//#include <hicn/content_store/lru.h> + +#include "content_store.h" + +extern const content_store_ops_t content_store_lru; + +const content_store_ops_t * const content_store_vft[] = { + [CONTENT_STORE_TYPE_LRU] = &content_store_lru, +}; + +// XXX TODO replace by a single packet cache +// XXX TODO per cs type entry data too ! +// XXX TODO getting rid of logger and the need to acquire +// XXX TODO separate cs from vft, same with strategy + +#define content_store_entry_from_msgbuf(entry, msgbuf) \ +do { \ + (entry)->hasExpiryTimeTicks = msgbuf_HasContentExpiryTime(msgbuf); \ + if ((entry)->hasExpiryTimeTicks) \ + (entry)->expiryTimeTicks = msgbuf_GetContentExpiryTimeTicks(msgbuf); \ +} while(0) + + +content_store_t * +content_store_create(content_store_type_t type, size_t max_elts) +{ + content_store_t * cs = malloc(sizeof(content_store_t)); + if (!cs) + goto ERR_MALLOC; + if (!CONTENT_STORE_TYPE_VALID(type)) + goto ERR_TYPE; + cs->type = type; + + // XXX TODO an entry = data + metadata specific to each policy + pool_init(cs->entries, max_elts); + + // data + // options + // stats + + + // index by name + cs->index_by_name = kh_init(cs_name); + + cs->index_by_expiry_time = NULL; + if (!cs->index_by_expiry_time) { + ERROR("Could not create index (expiry time)"); + goto ERR_INDEX_EXPIRY; + } + + + // XXX indices specific to each policy => vft + // index by expiration time + // lru ? + + content_store_vft[type]->initialize(cs); + +ERR_INDEX_EXPIRY: + // XXX TODO +ERR_TYPE: +ERR_MALLOC: + return NULL; +} + +void +content_store_free(content_store_t * cs) +{ + content_store_vft[cs->type]->finalize(cs); + + if (cs->index_by_expiry_time) + ; //listTimeOrdered_Release(&(store->indexByExpirationTime)); +} + +void content_store_clear(content_store_t * cs) +{ + // XXX TODO +} + +msgbuf_t * +content_store_match(content_store_t * cs, msgbuf_t * msgbuf, uint64_t now) +{ + assert(cs); + assert(msgbuf); + assert(msgbuf_get_type(msgbuf) == MESSAGE_TYPE_INTEREST); + + /* Lookup entry by name */ + khiter_t k = kh_get_cs_name(cs->index_by_name, msgbuf_get_name(msgbuf)); + if (k == kh_end(cs->index_by_name)) + return NULL; + content_store_entry_t * entry = cs->entries + kh_val(cs->index_by_name, k); + assert(entry); + + /* Remove any expired entry */ + if (content_store_entry_has_expiry_time(entry) && + content_store_entry_expiry_time(entry) < now) { + // the entry is expired, we can remove it + content_store_remove_entry(cs, entry); + goto NOT_FOUND; + } + + cs->stats.lru.countHits++; + +#if 0 // XXX + contentStoreEntry_MoveToHead(entry); +#endif + + DEBUG("CS %p LRU match %p (hits %" PRIu64 ", misses %" PRIu64 ")", + cs, msgbuf, cs->stats.lru.countHits, cs->stats.lru.countMisses); + return content_store_entry_message(entry); + +NOT_FOUND: + cs->stats.lru.countMisses++; + + DEBUG("ContentStoreLRU %p missed msgbuf %p (hits %" PRIu64 ", misses %" PRIu64 ")", + cs, msgbuf, cs->stats.lru.countHits, cs->stats.lru.countMisses); + return NULL; +} + +void +content_store_add(content_store_t * cs, msgbuf_t * msgbuf, uint64_t now) +{ + assert(cs); + assert(msgbuf); + assert(msgbuf_get_type(msgbuf) == MESSAGE_TYPE_DATA); + + content_store_entry_t * entry = NULL; + + /* borrow from content_store_lru_add_entry */ + + content_store_vft[cs->type]->add_entry(cs, entry); +} + +void +content_store_remove_entry(content_store_t * cs, content_store_entry_t * entry) +{ + assert(cs); + assert(entry); + + if (content_store_entry_has_expiry_time(entry)) + ; // XXX TODO listTimeOrdered_Remove(store->indexByExpirationTime, entryToPurge); + + msgbuf_t * msgbuf = content_store_entry_message(entry); + khiter_t k = kh_get_cs_name(cs->index_by_name, msgbuf_get_name(msgbuf)); + if (k != kh_end(cs->index_by_name)) + kh_del(cs_name, cs->index_by_name, k); + + // This will take care of LRU entry for instance + content_store_vft[cs->type]->remove_entry(cs, entry); + + //store->objectCount--; + pool_put(cs->entries, entry); + +} +// +// XXX TODO what is the difference between purge and remove ? +bool +content_store_remove(content_store_t * cs, msgbuf_t * msgbuf) +{ + assert(cs); + assert(msgbuf); + assert(msgbuf_get_type(msgbuf) == MESSAGE_TYPE_DATA); + + /* Lookup entry by name */ + khiter_t k = kh_get_cs_name(cs->index_by_name, msgbuf_get_name(msgbuf)); + if (k == kh_end(cs->index_by_name)) + return false; + + content_store_entry_t * entry = cs->entries + kh_val(cs->index_by_name, k); + assert(entry); + + content_store_remove_entry(cs, entry); + return true; +} + 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..1a339f494 --- /dev/null +++ b/hicn-light/src/hicn/core/content_store.h @@ -0,0 +1,125 @@ +#ifndef HICNLIGHT_CONTENT_STORE_H +#define HICNLIGHT_CONTENT_STORE_H + +#include <hicn/base/khash.h> +#include <hicn/base/pool.h> +#include <hicn/core/msgbuf.h> +#include <hicn/core/name.h> +#include <hicn/content_store/lru.h> + +typedef struct { + msgbuf_t * message; + //ListLruEntry *lruEntry; + bool hasExpiryTimeTicks; + uint64_t expiryTimeTicks; // single value for both ? 0 allowed ? +} content_store_entry_t; + +#define content_store_entry_message(entry) ((entry)->message) +#define content_store_entry_has_expiry_time(entry) ((entry)->hasExpiryTimeTicks) +#define content_store_entry_expiry_time(entry) ((entry)->expiryTimeTicks) + +typedef enum { + CONTENT_STORE_TYPE_UNDEFINED, + CONTENT_STORE_TYPE_LRU, + CONTENT_STORE_TYPE_N, +} content_store_type_t; + +#define CONTENT_STORE_TYPE_VALID(type) \ + (type != CONTENT_STORE_TYPE_UNDEFINED) && \ + (type != CONTENT_STORE_TYPE_N) + +typedef struct { + /* The maximum allowed expiry time (will never be exceeded). */ + uint64_t max_expiry_time; // XXX part of lru ? +} content_store_options_t; + +typedef union { + content_store_lru_stats_t lru; +} content_store_stats_t; + +// XXX TODO +#define name_hash(name) (name_HashCode(name)) +#define name_hash_eq(a, b) (name_hash(b) - name_hash(a)) + +KHASH_INIT(cs_name, const Name *, unsigned, 0, name_hash, name_hash_eq); + +typedef struct { + content_store_type_t type; + + // XXX TODO api to dynamically set max size + content_store_entry_t * entries; // pool + + kh_cs_name_t * index_by_name; + + void * index_by_expiry_time; + //ListTimeOrdered *indexByExpirationTime; + + + void * data; // per cs type data + void * options; + content_store_stats_t stats; +} content_store_t; + +content_store_t * content_store_create(content_store_type_t type, size_t max_elts); + +void content_store_free(content_store_t * cs); + +void content_store_clear(content_store_t * cs); + +msgbuf_t * content_store_match(content_store_t * cs, msgbuf_t * msgbuf, uint64_t now); + +void content_store_add(content_store_t * cs, msgbuf_t * msgbuf, uint64_t now); + +void content_store_remove_entry(content_store_t * cs, content_store_entry_t * entry); + +bool content_store_remove(content_store_t * cs, msgbuf_t * msgbuf); + +#define content_store_size(content_store) (pool_elts(cs->entries)) + +void content_store_purge_entry(content_store_t * cs, content_store_entry_t * entry); + +typedef struct { + + const char * name; + + void (*initialize)(content_store_t * cs); + + void (*finalize)(content_store_t * cs); + + /** + * 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. + */ + // XXX Do we always get now before adding ? + bool (*add_entry)(content_store_t * cs, content_store_entry_t * entry); + + /** + * 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. + */ + void (*remove_entry)(content_store_t * cs, content_store_entry_t * entry); + +} content_store_ops_t; + +extern const content_store_ops_t * const content_store_vft[]; + +#define DECLARE_CONTENT_STORE(NAME) \ + const content_store_ops_t content_store_ ## NAME = { \ + .name = #NAME, \ + .initialize = content_store_ ## NAME ## _initialize, \ + .finalize = content_store_ ## NAME ## _finalize, \ + .add_entry = content_store_ ## NAME ## _add_entry, \ + .remove_entry = content_store_ ## NAME ## _remove_entry, \ + } + +#endif /* HICNLIGHT_CONTENT_STORE_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..ddd8dd548 --- /dev/null +++ b/hicn-light/src/hicn/core/fib.c @@ -0,0 +1,531 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <hicn/hicn-light/config.h> +#include <stdio.h> + +#include <hicn/core/fib.h> + +typedef struct fib_node_s { + struct fib_node_s *left; + struct fib_node_s *right; + fib_entry_t *entry; + bool is_used; +} fib_node_t; + +static +fib_node_t * +fib_node_create(fib_node_t * left, fib_node_t * right, fib_entry_t * entry, + bool is_used) +{ + fib_node_t * node = malloc(sizeof(fib_node_t)); + if (!node) + return NULL; + + *node = (fib_node_t) { + .left = left, + .right = right, + .entry = entry, + .is_used = is_used, + }; + + return node; +} + +static +void +fib_node_free(fib_node_t * node) +{ + if (!node) + return; + + fib_node_free(node->right); + fib_node_free(node->left); + + 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) +{ + return fib->size; +} + + +#define FIB_SET(CURR, NEW_PREFIX, CURR_PREFIX_LEN) \ +do { \ + bool bit; \ + int res = nameBitvector_testBit(NEW_PREFIX, CURR_PREFIX_LEN, &bit); \ + assert(res >= 0); \ + (void)res; /* unused */ \ + CURR = bit ? CURR->right : CURR->left; \ +} while(0) + +#define FIB_INSERT(DST, SRC, PREFIX, PREFIX_LEN) \ +do { \ + bool bit; \ + int res = nameBitvector_testBit(PREFIX, PREFIX_LEN, &bit); \ + assert(res >= 0); \ + (void)res; /* unused */ \ + if (bit) \ + DST->right = SRC; \ + else \ + DST->left = SRC; \ +} while(0) + +void +fib_add(fib_t * fib, fib_entry_t * entry) +{ + assert(fib); + assert(entry); + + NameBitvector *new_prefix = name_GetContentName(fib_entry_get_prefix(entry)); + uint32_t new_prefix_len = nameBitvector_GetLength(new_prefix); + fib_node_t * curr = fib->root; + fib_node_t * last = NULL; + + NameBitvector *curr_name; + uint32_t curr_prefix_len; + uint32_t match_len; + + while (curr) { + curr_name = name_GetContentName(fib_entry_get_prefix(curr->entry)); + + match_len = nameBitvector_lpm(new_prefix, curr_name); + curr_prefix_len = nameBitvector_GetLength(curr_name); + + if(curr_prefix_len != match_len || //the new entry does not match the curr + curr_prefix_len >= new_prefix_len) //in this case we cannot procede anymore + break; + + last = curr; + FIB_SET(curr, new_prefix, curr_prefix_len); + } + + //this is the root (empty trie) or an empty child + if (!curr) { + fib_node_t * new_node = fib_node_create(NULL, NULL, entry, true); + if (!last) { + fib->root = new_node; + } else { + uint32_t last_prefix_len = nameBitvector_GetLength( + name_GetContentName(fib_entry_get_prefix(last->entry))); + + FIB_INSERT(last, new_node, new_prefix, last_prefix_len); + } + fib->size++; + return; + } + + //curr is not null + + //the node already exist + //if is not in use we turn it on and we set the rigth fib entry + if (curr_prefix_len == match_len && new_prefix_len == match_len) { + if (!curr->is_used) { + curr->is_used = true; + curr->entry = entry; + fib->size++; + return; + } else { + //this case should never happen beacuse of the way we add + //entries in the fib + const nexthops_t * nexthops = fib_entry_get_nexthops(entry); + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + fib_entry_nexthops_add(curr->entry, nexthop); + }); + } + } + + //key is prefix of the curr node (so new_prefix_len < curr_prefix_len) + if (new_prefix_len == match_len){ + fib_node_t * new_node = fib_node_create(NULL, NULL, entry, true); + if (!last) { + fib->root = new_node; + } else { + uint32_t last_prefix_len = nameBitvector_GetLength( + name_GetContentName(fib_entry_get_prefix(last->entry))); + FIB_INSERT(last, new_node, new_prefix, last_prefix_len); + } + FIB_INSERT(new_node, curr, curr_name, match_len); + fib->size++; + return; + } + + //in the last case we need to add an inner node + Name * inner_prefix = name_Copy(fib_entry_get_prefix(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 + fib_entry_t * inner_entry = fib_entry_create(inner_prefix, + STRATEGY_TYPE_UNDEFINED, NULL, fib->forwarder); + + fib_node_t * inner_node = fib_node_create(NULL, NULL, inner_entry, false); + fib_node_t * new_node = fib_node_create(NULL, NULL, entry, true); + + if (!last) { + //we need to place the inner_node at the root + fib->root = inner_node; + } else { + uint32_t last_prefix_len = nameBitvector_GetLength( + name_GetContentName(fib_entry_get_prefix(last->entry))); + NameBitvector *inner_name = name_GetContentName(inner_prefix); + FIB_INSERT(last, inner_node, inner_name, last_prefix_len); + } + + bool bit; + int res = nameBitvector_testBit(new_prefix, match_len, &bit); + assert(res >= 0); + (void)res; /* unused */ + inner_node->left = bit ? curr : new_node; + inner_node->right = bit ? new_node : curr; + fib->size++; +} + +fib_entry_t * +fib_contains(const fib_t * fib, const Name * prefix) +{ + assert(fib); + assert(prefix); + + NameBitvector * key_name = name_GetContentName(prefix); + uint32_t key_prefix_len = nameBitvector_GetLength(key_name); + + fib_node_t * curr = fib->root; + + while (curr) { + NameBitvector *curr_name = + name_GetContentName(fib_entry_get_prefix(curr->entry)); + uint32_t match_len = nameBitvector_lpm(key_name, curr_name); + uint32_t curr_prefix_len = nameBitvector_GetLength(curr_name); + + if (match_len < curr_prefix_len) { + //the current node does not match completelly the key, so + //the key is not in the trie + //this implies curr_prefix_len > key_prefix_len + return NULL; + } + + if (curr_prefix_len == key_prefix_len) { //== match_len + //this is an exact match + if (!curr->is_used) { + //the key does not exists + return NULL; + } + //we found the key + return curr->entry; + } + + FIB_SET(curr, key_name, curr_prefix_len); + } + + return NULL; +} + +static +void +fib_node_remove(fib_t *fib, const Name *prefix) +{ + assert(fib); + assert(prefix); + + NameBitvector *key_name = name_GetContentName(prefix); + uint32_t key_prefix_len = nameBitvector_GetLength(key_name); + + fib_node_t * curr = fib->root; + fib_node_t * parent = NULL; + fib_node_t * grandpa = NULL; + + uint32_t match_len; + uint32_t curr_prefix_len; + + while(curr) { + NameBitvector *curr_name = + name_GetContentName(fib_entry_get_prefix(curr->entry)); + match_len = nameBitvector_lpm(key_name, curr_name); + curr_prefix_len = nameBitvector_GetLength(curr_name); + + if(match_len < curr_prefix_len || + curr_prefix_len == key_prefix_len){ + break; + } + + grandpa = parent; + parent = curr; + + FIB_SET(curr, key_name, curr_prefix_len); + } + + if (!curr || !curr->is_used || (curr_prefix_len != key_prefix_len)) { + //the node does not exists + return; + } + + //curr has 2 children, leave it there and mark it as inner + if (curr->right && curr->left) { + curr->is_used = false; + fib->size--; + return; + } + + //curr has no children + if (!curr->right && !curr->left) { + if (!parent) { + //curr is the root and is the only node in the fib + fib->root = NULL; + fib->size--; + fib_node_free(curr); + return; + } + if (!grandpa) { + //parent is the root + if(fib->root->left == curr) + fib->root->left = NULL; + else + fib->root->right = NULL; + fib->size--; + fib_node_free(curr); + return; + } + if(!parent->is_used){ + //parent is an inner node + //remove curr and inner_node (parent), connect the other child + //of the parent to the grandpa + fib_node_t * tmp = (parent->right == curr) ? parent->left : parent->right; + + if(grandpa->right == parent) + grandpa->right = tmp; + else + grandpa->left = tmp; + + fib->size--; + fib_node_free(curr); + fib_node_free(parent); + return; + } + //parent is node not an inner_node + //just remove curr the node + if(parent->right == curr) + parent->right = NULL; + else + parent->left = NULL; + fib->size--; + fib_node_free(curr); + return; + } + + //curr has one child + if (curr->right || curr->left) { + if (!parent) { + //curr is the root + fib->root = fib->root->right ? fib->root->right : fib->root->left; + fib->size--; + fib_node_free(curr); + return; + } + //attach the child of curr to parent + fib_node_t * tmp = curr->right ? curr->right : curr->left; + + if (parent->right == curr) + parent->right = tmp; + else + parent->left = tmp; + + fib->size--; + fib_node_free(curr); + return; + } +} + +void +fib_remove(fib_t * fib, const Name * name, unsigned conn_id) +{ + assert(fib); + assert(name); + + fib_entry_t *entry = fib_contains(fib, name); + if (!entry) + return; + + fib_entry_nexthops_remove(entry, conn_id); +#ifndef WITH_MAPME + if (fib_entry_nexthops_len(entry) == 0) + fib_node_remove(fib, name); +#endif /* WITH_MAPME */ +} + +static +size_t +fib_node_remove_connection_id(fib_node_t * node, unsigned conn_id, + fib_entry_t ** array, size_t pos) +{ + if (!node) + return pos; + if (node->is_used) { + fib_entry_nexthops_remove(node->entry, conn_id); +#ifndef WITH_MAPME + if (fib_entry_nexthops_len(node->entry) == 0) + array[pos++] = node->entry; +#endif /* WITH_MAPME */ + } + pos = fib_node_remove_connection_id(node->right, conn_id, array, pos); + pos = fib_node_remove_connection_id(node->left, conn_id, array, pos); + return pos; +} + +void +fib_remove_connection_id(fib_t * fib, unsigned conn_id) +{ + assert(fib); + + fib_entry_t ** array = malloc(sizeof(fib_entry_t*) * fib->size); + + size_t pos = 0; + pos = fib_node_remove_connection_id(fib->root, conn_id, array, pos); + + for (int i = 0; i < pos; i++) + fib_node_remove(fib, fib_entry_get_prefix(array[i])); + free(array); +} + +size_t +fib_length(const fib_t * fib) +{ + assert(fib); + return fib->size; +} + +fib_entry_t * +fib_match_message(const fib_t *fib, const msgbuf_t *interest_msgbuf) +{ + assert(fib); + assert(interest_msgbuf); + + return fib_match_bitvector(fib, name_GetContentName( + msgbuf_get_name(interest_msgbuf))); +} + +fib_entry_t * +fib_match_name(const fib_t * fib, const Name * name) +{ + assert(fib); + assert(name); + + return fib_match_bitvector(fib, name_GetContentName(name)); +} + + +fib_entry_t * +fib_match_bitvector(const fib_t * fib, const NameBitvector * name) +{ + assert(fib); + assert(name); + + uint32_t key_prefix_len = nameBitvector_GetLength(name); + + fib_node_t * curr = fib->root; + fib_node_t * candidate = NULL; + + while (curr) { + NameBitvector *curr_name = + name_GetContentName(fib_entry_get_prefix(curr->entry)); + uint32_t match_len = nameBitvector_lpm(name, curr_name); + uint32_t curr_prefix_len = nameBitvector_GetLength(curr_name); + + if(match_len < curr_prefix_len){ + //the current node does not match completelly the key, so + //return the parent of this node (saved in candidate) + break; + } + + if (curr->is_used) + candidate = curr; + + //if we are here match_len == curr_prefix_len (can't be larger) + //so this node is actually a good candidate for a match + if (curr_prefix_len == key_prefix_len){ + //this an exact match, do not continue + break; + } + + FIB_SET(curr, name, curr_prefix_len); + } + + return candidate ? candidate->entry : NULL; +} + +static +size_t +fib_node_collect_entries(fib_node_t * node, fib_entry_t ** array, size_t pos) +{ + assert(array); + + if (!node) + return pos; + + if(node->is_used) + array[pos++] = node->entry; + + pos = fib_node_collect_entries(node->right, array, pos); + pos = fib_node_collect_entries(node->left, array, pos); + return pos; +} + +size_t +fib_get_entry_array(const fib_t * fib, fib_entry_t *** array_p) +{ + size_t pos = 0; + *array_p = malloc(sizeof(fib_entry_t*) * fib->size); + if (!*array_p) + return pos; + pos = fib_node_collect_entries(fib->root, *array_p, pos); + return pos; +} diff --git a/hicn-light/src/hicn/core/fib.h b/hicn-light/src/hicn/core/fib.h new file mode 100644 index 000000000..f60a42cae --- /dev/null +++ b/hicn-light/src/hicn/core/fib.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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/msgbuf.h> +#include <hicn/core/name.h> +#include <hicn/core/fib_entry.h> + +#define _fib_var(x) _fib_ ## x + +typedef struct fib_s fib_t; + +fib_t * fib_create(void * forwarder); + +void fib_free(fib_t * fib); + +size_t fib_get_size(const fib_t * fib); + +void fib_add(fib_t *fib, fib_entry_t * node); + +fib_entry_t * fib_contains(const fib_t * fib, const Name * prefix); + +void fib_remove(fib_t * fib, const Name * prefix, unsigned conn_id); + +void fib_remove_connection_id(fib_t *fib, unsigned conn_id); + +size_t fib_length(const fib_t *fib); + +fib_entry_t * fib_match_message(const fib_t * fib, const msgbuf_t * interest_msgbuf); +fib_entry_t * fib_match_name(const fib_t * fib, const Name * name); +fib_entry_t * fib_match_bitvector(const fib_t * fib, const NameBitvector * name); + +size_t fib_get_entry_array(const fib_t * fib, fib_entry_t *** array_p); + +#define fib_foreach_entry(FIB, ENTRY, BODY) \ +do { \ + fib_entry_t ** _fib_var(array); \ + size_t _fib_var(n) = fib_get_entry_array((FIB), &_fib_var(array)); \ + size_t _fib_var(i); \ + for (_fib_var(i) = 0; _fib_var(i) < _fib_var(n); _fib_var(i)++) { \ + ENTRY = _fib_var(array)[_fib_var(i)]; \ + do { BODY } while(0); \ + } \ + free(_fib_var(array)); \ +} while(0) + +#endif // 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..5c6e28d5b --- /dev/null +++ b/hicn-light/src/hicn/core/fib_entry.c @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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/connectionState.h> +#include <hicn/core/strategy_vft.h> +#include <hicn/core/nameBitvector.h> +#include <hicn/utils/commands.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_PREFIX_STATS +#include <hicn/core/prefix_stats.h> +#endif /* WITH_PREFIX_STATS */ + + +fib_entry_t * +fib_entry_create(Name *name, strategy_type_t strategy_type, + strategy_options_t * strategy_options, const forwarder_t * forwarder) +{ + + assert(name); + assert(forwarder); + + fib_entry_t * entry = malloc(sizeof(fib_entry_t)); + if (!entry) + goto ERR_MALLOC; + + entry->name = name_Acquire(name); + + // XXX TODO strategy type might be undefined. We need a default strategy + // specified somewhere in the configuration. + 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_NONE; +#endif /* WITH_POLICY */ + +#ifdef WITH_PREFIX_STATS + entry->prefix_stats = PREFIX_STATS_EMPTY; + entry->prefix_counters = PREFIX_COUNTERS_EMPTY; +#endif /* WITH_PREFIX_STATS */ + + return entry; + +ERR_MALLOC: + return NULL; +} + +void +fib_entry_free(fib_entry_t * entry) +{ + assert(entry); + + name_Release(&entry->name); +#ifdef WITH_MAPME + if (entry->user_data) + entry->user_data_release(&entry->user_data); +#endif /* WITH_MAPME */ + free(entry); +} + +// XXX TODO DUPLICATE +void +fib_entry_set_strategy(fib_entry_t * entry, strategy_type_t strategy_type, + strategy_options_t * strategy_options) +{ + if (STRATEGY_TYPE_VALID(strategy_type)) { + entry->strategy.type = strategy_type; + if (strategy_options) + entry->strategy.options = *strategy_options; + strategy_vft[strategy_type]->initialize(&entry->strategy); + } +} + +#ifdef WITH_POLICY + +nexthops_t * +fib_entry_filter_nexthops(fib_entry_t * entry, nexthops_t * nexthops, + unsigned ingress_id, bool prefer_local) +{ + assert(entry); + assert(nexthops); + + /* Filter out ingress, down & administrative down faces */ + const connection_table_t * table = forwarder_get_connection_table(entry->forwarder); + connection_t * conn; + unsigned nexthop, i; + uint_fast32_t flags; + + 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)); + }); + + if (prefer_local) { + /* Backup flags */ + flags = nexthops->flags; + + /* 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; + } + + /* Filter out local */ + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, (connection_is_local(conn))); + + /* Policy filtering : next hops */ + nexthops_disable_if(nexthops, i, + (policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_REQUIRE) && + (!connection_has_tag(conn, POLICY_TAG_WIRED))); + nexthops_disable_if(nexthops, i, + (policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_PROHIBIT) && + (connection_has_tag(conn, POLICY_TAG_WIRED))); + nexthops_disable_if(nexthops, i, + (policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_REQUIRE) && + (!connection_has_tag(conn, POLICY_TAG_WIFI))); + nexthops_disable_if(nexthops, i, + (policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_PROHIBIT) && + (connection_has_tag(conn, POLICY_TAG_WIFI))); + nexthops_disable_if(nexthops, i, + (policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_REQUIRE) && + (!connection_has_tag(conn, POLICY_TAG_CELLULAR))); + nexthops_disable_if(nexthops, i, + (policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_PROHIBIT) && + (connection_has_tag(conn, POLICY_TAG_CELLULAR))); + nexthops_disable_if(nexthops, i, + (policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_REQUIRE) && + (!connection_has_tag(conn, POLICY_TAG_TRUSTED))); + nexthops_disable_if(nexthops, i, + (policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_PROHIBIT) && + (connection_has_tag(conn, POLICY_TAG_TRUSTED))); + }); + + if (nexthops_get_curlen(nexthops) == 0) + return nexthops; + + /* We have at least one matching next hop, implement heuristic */ + + /* + * As VPN connections might trigger duplicate uses of one interface, we start + * by filtering out interfaces based on trust status. + */ + flags = nexthops->flags; + + if ((policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_REQUIRE) || + (policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_PREFER)) { + + /* Try to filter out NON TRUSTED faces */ + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + (!connection_has_tag(conn, POLICY_TAG_TRUSTED))); + }); + + if ((nexthops_get_curlen(nexthops) == 0) && (policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_REQUIRE)) { + return nexthops; + } + + } else { + /* Try to filter out TRUSTED faces */ + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + (connection_has_tag(conn, POLICY_TAG_TRUSTED))); + }); + } + + if (nexthops_get_curlen(nexthops) == 0) + nexthops->flags = flags; + + /* Other preferences */ + if (policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_AVOID) { + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + connection_has_tag(conn, POLICY_TAG_WIRED)); + }); + if (nexthops_get_curlen(nexthops) == 0) + nexthops->flags = flags; + } + if (policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_AVOID) { + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + connection_has_tag(conn, POLICY_TAG_WIFI)); + }); + if (nexthops_get_curlen(nexthops) == 0) + nexthops->flags = flags; + } + if (policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_AVOID) { + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + connection_has_tag(conn, POLICY_TAG_CELLULAR)); + }); + if (nexthops_get_curlen(nexthops) == 0) + nexthops->flags = flags; + } + + if (policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_PREFER) { + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + !connection_has_tag(conn, POLICY_TAG_WIRED)); + }); + if (nexthops_get_curlen(nexthops) == 0) + nexthops->flags = flags; + } + if (policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_PREFER) { + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + !connection_has_tag(conn, POLICY_TAG_WIFI)); + }); + if (nexthops_get_curlen(nexthops) == 0) + nexthops->flags = flags; + } + if (policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_PREFER) { + nexthops_enumerate(nexthops, i, nexthop, { + conn = connection_table_at(table, nexthop); + nexthops_disable_if(nexthops, i, + !connection_has_tag(conn, POLICY_TAG_CELLULAR)); + }); + if (nexthops_get_curlen(nexthops) == 0) + nexthops->flags = flags; + } + + /* 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); + }); + + return nexthops; +} + +/* + * Update available next hops following policy update. + * + * The last nexthop parameter is only used if needed, otherwise the pointer to + * fib entry is returned to avoid an useless copy + */ +nexthops_t * +fib_entry_get_available_nexthops(fib_entry_t * entry, unsigned ingress_id, nexthops_t * new_nexthops) +{ + 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, { + new_nexthops->elts[nexthops_get_len(new_nexthops)] = connection_table_get_connection_id(table, connection); + nexthops_inc(new_nexthops); + }); + + return fib_entry_filter_nexthops(entry, new_nexthops, ingress_id, false); + } + + return fib_entry_filter_nexthops(entry, fib_entry_get_nexthops(entry), ingress_id, true); +} + +policy_t +fib_entry_get_policy(const fib_entry_t * entry) +{ + return entry->policy; +} + +void +fib_entry_set_policy(fib_entry_t * entry, policy_t policy) +{ + entry->policy = policy; + +#ifdef WITH_MAPME + /* + * Skip entries that do not correspond to a producer ( / have a locally + * served prefix / have no local connection as next hop) + */ + if (!fib_entry_has_local_nexthop(entry)) + return; + mapme_t * mapme = forwarder_get_mapme(entry->forwarder); + mapme_send_to_all_nexthops(mapme, entry); +#endif /* WITH_MAPME */ +} + +#endif /* WITH_POLICY */ + +void +fib_entry_nexthops_add(fib_entry_t * entry, unsigned nexthop) +{ + nexthops_add(fib_entry_get_nexthops(entry), nexthop); + // XXX TODO + strategy_vft[entry->strategy.type]->add_nexthop(&entry->strategy, nexthop, NULL); +} + +void +fib_entry_nexthops_remove(fib_entry_t * entry, unsigned nexthop) +{ + nexthops_remove(fib_entry_get_nexthops(entry), nexthop); + // XXX TODO + strategy_vft[entry->strategy.type]->remove_nexthop(&entry->strategy, nexthop, NULL); +} + +const nexthops_t * +fib_entry_get_nexthops_from_strategy(fib_entry_t * entry, + const msgbuf_t * msgbuf, bool is_retransmission) +{ + assert(entry); + assert(msgbuf); + + const prefix_stats_mgr_t * mgr = forwarder_get_prefix_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_PREFIX_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) + prefix_stats_on_retransmission(mgr, &entry->prefix_counters, nexthops); +#endif /* WITH_PREFIX_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 + /* + * If multipath is disabled, we don't offer much choice to the forwarding + * strategy, but still go through it for accounting purposes. + */ + 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)) { + nexthops_select_one(nexthops); + } +#endif /* WITH_POLICY */ + + return strategy_vft[entry->strategy.type]->lookup_nexthops(&entry->strategy, + nexthops, msgbuf); +} + +void +fib_entry_on_data(fib_entry_t * entry, + const nexthops_t * nexthops, const msgbuf_t * msgbuf, + Ticks pitEntryCreation, Ticks objReception) +{ + assert(entry); + assert(nexthops); + assert(msgbuf); + +#ifdef WITH_PREFIX_STATS + const prefix_stats_mgr_t * mgr = forwarder_get_prefix_stats_mgr(entry->forwarder); + Ticks rtt = objReception - pitEntryCreation; + prefix_stats_on_data(mgr, &entry->prefix_stats, &entry->prefix_counters, + nexthops, msgbuf, rtt); +#endif /* WITH_PREFIX_STATS */ + + strategy_vft[entry->strategy.type]->on_data(&entry->strategy, nexthops, msgbuf, pitEntryCreation, objReception); +} + +void +fib_entry_on_timeout(fib_entry_t * entry, const nexthops_t * nexthops) +{ + assert(entry); + assert(nexthops); + +#ifdef WITH_PREFIX_STATS + const prefix_stats_mgr_t * mgr = forwarder_get_prefix_stats_mgr(entry->forwarder); + prefix_stats_on_timeout(mgr, &entry->prefix_counters, nexthops); +#endif /* WITH_PREFIX_STATS */ + + strategy_vft[entry->strategy.type]->on_timeout(&entry->strategy, nexthops); +} + +Name * +fib_entry_get_prefix(const fib_entry_t * entry) +{ + assert(entry); + + return entry->name; +} + + +/* + * Return true if we have at least one local connection as next hop + */ +bool +fib_entry_has_local_nexthop(const fib_entry_t * entry) +{ + connection_table_t * table = forwarder_get_connection_table(entry->forwarder); + + unsigned nexthop; + nexthops_foreach(fib_entry_get_nexthops(entry), nexthop, { + const connection_t * conn = connection_table_at(table, nexthop); + /* Ignore non-local connections */ + if (!connection_is_local(conn)) + continue; + return true; + }); + return false; +} + +#ifdef WITH_MAPME + +void * +fib_entry_get_user_data(const fib_entry_t * entry) +{ + assert(entry); + + return entry->user_data; +} + +void +fib_entry_set_user_data(fib_entry_t * entry, const void * user_data, + void (*user_data_release)(void **)) +{ + assert(entry); + assert(user_data); + assert(user_data_release); + + entry->user_data = (void *)user_data; + entry->user_data_release = user_data_release; +} + +#endif /* WITH_MAPME */ diff --git a/hicn-light/src/hicn/core/fib_entry.h b/hicn-light/src/hicn/core/fib_entry.h new file mode 100644 index 000000000..94d283d0f --- /dev/null +++ b/hicn-light/src/hicn/core/fib_entry.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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/core/name.h> +#include <hicn/core/strategy.h> +#include <hicn/core/msgbuf.h> +#include <hicn/core/nexthops.h> +#include <hicn/core/prefix_stats.h> +#include <hicn/utils/commands.h> // strategy type + +#ifdef WITH_MAPME +//#include <parc/algol/parc_EventTimer.h> +//#include <parc/algol/parc_Iterator.h> +#endif /* WITH_MAPME */ + +typedef struct { + Name *name; + unsigned refcount; + nexthops_t nexthops; + strategy_entry_t strategy; + + const void * forwarder; + +#ifdef WITH_POLICY + policy_t policy; +#endif /* WITH_POLICY */ + + prefix_counters_t prefix_counters; + prefix_stats_t prefix_stats; + +#ifdef WITH_MAPME + /* In case of no multipath, this stores the previous decision taken by policy. As the list of nexthops is not expected to change, we can simply store the flags */ + uint_fast32_t prev_nexthops_flags; + void *user_data; + void (*user_data_release)(void **user_data); +#endif /* WITH_MAPME */ +} fib_entry_t; + +#define _fib_entry_var(x) _fib_entry_##x + +#define fib_entry_strategy_type(fib_entry) ((fib_entry)->strategy.type) + +#define fib_entry_get_nexthops(fib_entry) (&(fib_entry)->nexthops) +#define fib_entry_nexthops_len(fib_entry) (nexthops_len(&(fib_entry)->nexthops)) +#define fib_entry_nexthops_curlen(fib_entry) (nexthops_curlen(&(fib_entry)->nexthops)) +#define fib_entry_get_nexthop(fib_entry, i) ((fib_entry)->nexthops.elts[i]) +#define fib_entry_foreach_nexthop(fib_entry, nexthop, BODY) \ + nexthops_foreach(fib_entry->nexthops, BODY) + +#define fib_entry_nexthops_changed(fib_entry) \ + ((fib_entry)->prev_nexthops_flags == fib_entry_get_nexthops(fib_entry)->flags) + +#define fib_entry_set_prev_nexthops(fib_entry) \ + ((fib_entry)->prev_nexthops_flags = fib_entry_get_nexthops(fib_entry)->flags) + +struct forwarder_s; +fib_entry_t *fib_entry_create(Name *name, strategy_type_t strategy_type, + strategy_options_t * strategy_options, const struct forwarder_s * table); + +void fib_entry_set_strategy(fib_entry_t *fib_entry, + strategy_type_t strategy_type, strategy_options_t * strategy_options); + +void fib_entry_nexthops_add(fib_entry_t * fib_entry, unsigned nexthop); + +void fib_entry_nexthops_remove(fib_entry_t * fib_entry, unsigned nexthop); + +size_t fib_entry_NexthopCount(const fib_entry_t *fib_entry); + +/** + * @function fib_entry_nexthops_get + * @abstract Returns the nexthop set of the FIB entry. You must Acquire if it + * will be saved. + * @discussion + * Returns the next hop set for the FIB entry. + */ +const nexthops_t * fib_entry_nexthops_get(const fib_entry_t *fib_entry); + +const nexthops_t * fib_entry_nexthops_getFromForwardingStrategy( + fib_entry_t *fib_entry, const msgbuf_t *interest_msgbuf, bool is_retransmission); + +void fib_entry_on_data(fib_entry_t * fib_entry, const nexthops_t * nexthops, + const msgbuf_t * object_msgbuf, Ticks pit_entry_creation, + Ticks data_reception); + +#ifdef WITH_POLICY +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, policy_t policy); +void fib_entry_update_stats(fib_entry_t *fib_entry, uint64_t now); +#endif /* WITH_POLICY */ + +nexthops_t * fib_entry_get_available_nexthops(fib_entry_t *fib_entry, + unsigned in_connection, nexthops_t * new_nexthops); +void fib_entry_on_timeout(fib_entry_t *fib_entry, const nexthops_t *egressId); +const nexthops_t * fib_entry_get_nexthops_from_strategy(fib_entry_t *fib_entry, + const msgbuf_t *interest_msgbuf, bool is_retransmission); + +/** + * @function fib_entry_get_prefix + * @abstract Returns a copy of the prefix. + * @return A reference counted copy that you must destroy + */ +Name *fib_entry_get_prefix(const fib_entry_t *fib_entry); + +bool fib_entry_has_local_nexthop(const fib_entry_t * entry); + +#ifdef WITH_MAPME + +/** + * @function fib_entry_get_user_data + * @abstract Returns user data associated to the FIB entry. + * @param [in] fib_entry - Pointer to the FIB entry. + * @return User data as a void pointer + */ +void *fib_entry_get_user_data(const fib_entry_t *fib_entry); + +/** + * @function fib_entry_get_user_data + * @abstract Associates user data and release callback to a FIB entry. + * @param [in] fib_entry - Pointer to the FIB entry. + * @param [in] user_data - Generic pointer to user data + * @param [in@ user_data_release - Callback used to release user data upon change + * of FIB entry removal. + */ +void fib_entry_set_user_data(fib_entry_t *fib_entry, const void *user_data, + void (*user_data_release)(void **)); + +#endif /* WITH_MAPME */ + +#endif // fib_entry_h diff --git a/hicn-light/src/hicn/core/forwarder.c b/hicn-light/src/hicn/core/forwarder.c index f7b0af2c2..f8e99198f 100644 --- a/hicn-light/src/hicn/core/forwarder.c +++ b/hicn-light/src/hicn/core/forwarder.c @@ -41,553 +41,1157 @@ #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/connection_table.h> +#include <hicn/core/listener_table.h> +#include <hicn/core/pit.h> +#include <hicn/core/fib.h> +#include <hicn/core/content_store.h> #include <hicn/core/forwarder.h> #include <hicn/core/messagePacketType.h> #ifdef WITH_MAPME #include <hicn/core/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 <hicn/config/configuration_file.h> + +#ifdef WITH_PREFIX_STATS +#include <hicn/core/prefix_stats.h> +#endif /* WITH_PREFIX_STATS */ #include <hicn/core/wldr.h> +#include <hicn/util/log.h> -#include <parc/assert/parc_Assert.h> +#define DEFAULT_PIT_SIZE 65535 -// the router's clock frequency (we now use the monotonic clock) -#define HZ 1000 +typedef struct { + uint32_t countReceived; + uint32_t countInterestsReceived; + uint32_t countObjectsReceived; -// 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) + uint32_t countInterestsAggregated; -struct forwarder { - Dispatcher *dispatcher; + uint32_t countDropped; + uint32_t countInterestsDropped; + uint32_t countDroppedNoRoute; + uint32_t countDroppedNoReversePath; - uint16_t server_port; + uint32_t countDroppedConnectionNotFound; + uint32_t countObjectsDropped; + uint32_t countOtherDropped; - PARCEventSignal *signal_int; - PARCEventSignal *signal_term; -#ifndef _WIN32 - PARCEventSignal *signal_usr1; -#endif - PARCEventTimer *keepalive_event; + uint32_t countSendFailures; + uint32_t countInterestForwarded; + uint32_t countObjectsForwarded; + uint32_t countInterestsSatisfiedFromStore; - // will skew the virtual clock forward. In normal operaiton, it is 0. - Ticks clockOffset; + uint32_t countDroppedNoHopLimit; + uint32_t countDroppedZeroHopLimitFromRemote; + uint32_t countDroppedZeroHopLimitToRemote; +} forwarder_stats_t; - unsigned nextConnectionid; - Messenger *messenger; - ConnectionManager *connectionManager; - ConnectionTable *connectionTable; - ListenerSet *listenerSet; - Configuration *config; +struct forwarder_s { +// uint16_t server_port; - // we'll eventually want to setup a threadpool of these - MessageProcessor *processor; +// XXX TODO signal handling +#if 0 + PARCEventSignal *signal_int; + PARCEventSignal *signal_term; +#ifndef _WIN32 + PARCEventSignal *signal_usr1; +#endif +#endif - Logger *logger; + // used by seed48 and nrand48 + unsigned short seed[3]; - PARCClock *clock; + connection_table_t * connection_table; + listener_table_t * listener_table; + configuration_t *config; -#if !defined(__APPLE__) - hicn_socket_helper_t - *hicnSocketHelper; // state required to manage hicn connections -#endif - // used by seed48 and nrand48 - unsigned short seed[3]; + + pit_t * pit; + content_store_t * content_store; + fib_t * fib; #ifdef WITH_MAPME - MapMe *mapme; + mapme_t * mapme; #endif /* WITH_MAPME */ + + bool store_in_content_store; + bool serve_from_content_store; + + forwarder_stats_t stats; +#ifdef WITH_PREFIX_STATS + prefix_stats_mgr_t prefix_stats_mgr; +#endif /* WITH_PREFIX_STATS */ + + /* + * The message forwarder has to decide whether to queue incoming packets for + * batching, or trigger the transmission on the connection + */ + unsigned pending_conn[MAX_MSG]; + size_t num_pending_conn; + + msgbuf_t msgbuf; /* Storage for msgbuf, which are currently processed 1 by 1 */ + }; +#if 0 // 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 *); +#endif /** * 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; - - res = -1; - fd = open("/dev/urandom", O_RDONLY); - if (fd != -1) { - res = read(fd, forwarder->seed, sizeof(forwarder->seed)); - close(fd); - } - if (res != sizeof(forwarder->seed)) { + int fd; + ssize_t res; + + res = -1; + fd = open("/dev/urandom", O_RDONLY); + if (fd != -1) { + res = read(fd, forwarder->seed, sizeof(forwarder->seed)); + close(fd); + } + if (res != sizeof(forwarder->seed)) { + forwarder->seed[1] = (unsigned short)getpid(); /* better than no entropy */ + forwarder->seed[2] = (unsigned short)time(NULL); + } + /* + * The call to seed48 is needed by cygwin, and should be harmless + * on other platforms. + */ + seed48(forwarder->seed); +#else forwarder->seed[1] = (unsigned short)getpid(); /* better than no entropy */ forwarder->seed[2] = (unsigned short)time(NULL); - } - /* - * The call to seed48 is needed by cygwin, and should be harmless - * on other platforms. - */ - seed48(forwarder->seed); -#else - forwarder->seed[1] = (unsigned short)getpid(); /* better than no entropy */ - forwarder->seed[2] = (unsigned short)time(NULL); #endif } -Logger *forwarder_GetLogger(const Forwarder *forwarder) { - return forwarder->logger; -} - -// ============================================================================ -// Setup and destroy section +int +init_batch_buffers(batch_buffer_t * bb) +{ + /* Setup recvmmsg data structures. */ + for (unsigned i = 0; i < MAX_MSG; i++) { + char *buf = &bb->buffers[i][0]; + struct iovec *iovec = &bb->iovecs[i]; + struct mmsghdr *msg = &bb->msghdr[i]; -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); + msg->msg_hdr.msg_iov = iovec; + msg->msg_hdr.msg_iovlen = 1; - forwarder->clock = parcClock_Monotonic(); - forwarder->clockOffset = 0; + msg->msg_hdr.msg_name = &bb->addrs[i]; + msg->msg_hdr.msg_namelen = sizeof(struct sockaddr_storage); - 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); + iovec->iov_base = &buf[0]; + iovec->iov_len = MTU; } + return 0; +} - 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); +forwarder_t * +forwarder_create() +{ + forwarder_t * forwarder = malloc(sizeof(forwarder_t)); + if (!forwarder) + goto ERR_MALLOC; + + forwarder_seed(forwarder); + + forwarder->config = configuration_create(forwarder); + if (!forwarder->config) + goto ERR_CONFIG; + + forwarder->listener_table = listener_table_create(); + if (!forwarder->listener_table) + goto ERR_LISTENER_TABLE; + + forwarder->connection_table = connection_table_create(); + if (!forwarder->connection_table) + goto ERR_CONNECTION_TABLE; + + forwarder->fib = fib_create(forwarder); + if (!forwarder->fib) + goto ERR_FIB; + + forwarder->pit = pit_create(DEFAULT_PIT_SIZE); + if (!forwarder->pit) + goto ERR_PIT; + + size_t objectStoreSize = + configuration_content_store_get_size(forwarder_get_configuration(forwarder)); + forwarder->content_store = content_store_create(CONTENT_STORE_TYPE_LRU, + objectStoreSize); + if (!forwarder->content_store) + goto ERR_CONTENT_STORE; + + // the two flags for the content_store are set to true by default. If the content_store + // is active it always work as expected unless the use modifies this + // values using controller + forwarder->store_in_content_store = true; + forwarder->serve_from_content_store = true; + +#if 0 + 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); + forwarder->signal_usr1 = dispatcher_CreateSignalEvent( + forwarder->dispatcher, _signal_cb, forwarder, SIGPIPE); + dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_usr1); +#endif #endif - -#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; + forwarder->mapme = mapme_create(forwarder); + if (!forwarder->mapme) + goto ERR_MAPME; #endif /* WITH_MAPME */ - /* ignore child */ + /* ignore child */ #ifndef _WIN32 - signal(SIGCHLD, SIG_IGN); + signal(SIGCHLD, SIG_IGN); - /* ignore tty signals */ - signal(SIGTSTP, SIG_IGN); - signal(SIGTTOU, SIG_IGN); - signal(SIGTTIN, SIG_IGN); + /* ignore tty signals */ + signal(SIGTSTP, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGTTIN, SIG_IGN); #endif - // We no longer use this for ticks, but we need to have at least one event - // schedule to keep Libevent happy. - - struct timeval wtnow_timeout; - timerclear(&wtnow_timeout); +#ifdef WITH_PREFIX_STATS + if (prefix_stats_mgr_initialize(&forwarder->prefix_stats_mgr, forwarder) < 0) + goto ERR_MGR; +#endif /* WITH_PREFIX_STATS */ - wtnow_timeout.tv_sec = 0; - wtnow_timeout.tv_usec = 50000; // 20 Hz keepalive - - 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); - - return forwarder; + 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)); + +#if 0 + dispatcher_DestroySignalEvent(forwarder->dispatcher, + &(forwarder->signal_int)); + dispatcher_DestroySignalEvent(forwarder->dispatcher, + &(forwarder->signal_term)); #ifndef _WIN32 - dispatcher_DestroySignalEvent(forwarder->dispatcher, - &(forwarder->signal_usr1)); + dispatcher_DestroySignalEvent(forwarder->dispatcher, + &(forwarder->signal_usr1)); #endif - parcClock_Release(&forwarder->clock); - logger_Release(&forwarder->logger); - - // do the dispatcher last - dispatcher_Destroy(&(forwarder->dispatcher)); + // do the dispatcher last + dispatcher_Destroy(&(forwarder->dispatcher)); +#endif - parcMemory_Deallocate((void **)&forwarder); - return NULL; + content_store_free(forwarder->content_store); +ERR_CONTENT_STORE: + pit_free(forwarder->pit); +ERR_PIT: + fib_free(forwarder->fib); +ERR_FIB: + connection_table_free(forwarder->connection_table); +ERR_CONNECTION_TABLE: + listener_table_free(forwarder->listener_table); +ERR_LISTENER_TABLE: + configuration_free(forwarder->config); +ERR_CONFIG: + 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)); + prefix_stats_mgr_finalize(&forwarder->prefix_stats_mgr); #ifdef WITH_MAPME - mapme_free(forwarder->mapme); + mapme_free(forwarder->mapme); #endif /* WITH_MAPME */ - dispatcher_DestroySignalEvent(forwarder->dispatcher, - &(forwarder->signal_int)); - dispatcher_DestroySignalEvent(forwarder->dispatcher, - &(forwarder->signal_term)); +#if 0 + dispatcher_DestroySignalEvent(forwarder->dispatcher, + &(forwarder->signal_int)); + dispatcher_DestroySignalEvent(forwarder->dispatcher, + &(forwarder->signal_term)); #ifndef _WIN32 - dispatcher_DestroySignalEvent(forwarder->dispatcher, - &(forwarder->signal_usr1)); + dispatcher_DestroySignalEvent(forwarder->dispatcher, + &(forwarder->signal_usr1)); #endif - parcClock_Release(&forwarder->clock); - logger_Release(&forwarder->logger); - - // do the dispatcher last - dispatcher_Destroy(&(forwarder->dispatcher)); + // do the dispatcher last + dispatcher_Destroy(&(forwarder->dispatcher)); +#endif - parcMemory_Deallocate((void **)&forwarder); - *ptr = NULL; + content_store_free(forwarder->content_store); + pit_free(forwarder->pit); + fib_free(forwarder->fib); + connection_table_free(forwarder->connection_table); + listener_table_free(forwarder->listener_table); + configuration_free(forwarder->config); + free(forwarder); } -void forwarder_SetupAllListeners(Forwarder *forwarder, uint16_t port, - const char *localPath) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); +void +forwarder_setup_all_listeners(forwarder_t * forwarder, uint16_t port, + const char * local_path) +{ + assert(forwarder); + assert(local_path); - configurationListeners_SetupAll(forwarder->config, port, localPath); + listener_setup_all(forwarder, port, local_path); } -void forwarder_SetupLocalListeners(Forwarder *forwarder, uint16_t port) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - configurationListeners_SetutpLocalIPv4(forwarder->config, port); +void +forwarder_setup_local_listeners(forwarder_t * forwarder, uint16_t port) +{ + assert(forwarder); + listener_setup_local_ipv4(forwarder, port); } -void forwarder_SetupFromConfigFile(Forwarder *forwarder, const char *filename) { - ConfigurationFile *configFile = configurationFile_Create(forwarder, filename); - if (configFile) { - configurationFile_Process(configFile); - configurationFile_Release(&configFile); - } -} +void +forwarder_read_config(forwarder_t * forwarder, const char * filename) +{ + configuration_file_t *cfg = configuration_file_create(forwarder, filename); + if (!cfg) + return; -Configuration *forwarder_GetConfiguration(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->config; + configuration_file_process(cfg); + configuration_file_free(cfg); } -// ============================================================================ +configuration_t * +forwarder_get_configuration(forwarder_t * forwarder) +{ + assert(forwarder); + return forwarder->config; +} -unsigned forwarder_GetNextConnectionId(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->nextConnectionid++; +connection_table_t * +forwarder_get_connection_table(const forwarder_t * forwarder) +{ + assert(forwarder); + return forwarder->connection_table; } -Messenger *forwarder_GetMessenger(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->messenger; +listener_table_t * +forwarder_get_listener_table(forwarder_t * forwarder) +{ + assert(forwarder); + return forwarder->listener_table; } -Dispatcher *forwarder_GetDispatcher(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->dispatcher; +void +forwarder_content_store_set_store(forwarder_t * forwarder, bool val) +{ + assert(forwarder); + forwarder->store_in_content_store = 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_content_store_get_store(forwarder_t * forwarder) +{ + assert(forwarder); + return forwarder->store_in_content_store; } -ListenerSet *forwarder_GetListenerSet(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return forwarder->listenerSet; +void +forwarder_content_store_set_serve(forwarder_t * forwarder, bool val) +{ + assert(forwarder); + forwarder->serve_from_content_store = val; } -void forwarder_SetChacheStoreFlag(Forwarder *forwarder, bool val) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - messageProcessor_SetCacheStoreFlag(forwarder->processor, val); +bool +forwarder_content_store_get_serve(forwarder_t * forwarder) +{ + assert(forwarder); + return forwarder->serve_from_content_store; } -bool forwarder_GetChacheStoreFlag(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return messageProcessor_GetCacheStoreFlag(forwarder->processor); +void +forwarder_content_store_set_size(forwarder_t * forwarder, size_t size) +{ + assert(forwarder); + + content_store_free(forwarder->content_store); + + // XXX TODO +#if 0 + ContentStoreConfig content_storeConfig = {.objectCapacity = + maximumContentStoreSize}; + + forwarder->content_store = + content_storeLRU_Create(&content_storeConfig, forwarder->logger); +#endif } -void forwarder_SetChacheServeFlag(Forwarder *forwarder, bool val) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - messageProcessor_SetCacheServeFlag(forwarder->processor, val); +void +forwarder_content_store_clear(forwarder_t * forwarder) +{ + assert(forwarder); + + content_store_clear(forwarder->content_store); } -bool forwarder_GetChacheServeFlag(Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return messageProcessor_GetCacheServeFlag(forwarder->processor); +void +forwarder_receive_command(forwarder_t * forwarder, command_type_t command_type, + uint8_t * packet, unsigned connection_id) +{ + configuration_receive_command(forwarder->config, command_type, packet, connection_id); } -void forwarder_ReceiveCommand(Forwarder *forwarder, command_id command, - struct iovec *message, unsigned ingressId) { - configuration_ReceiveCommand(forwarder->config, command, message, ingressId); +/** + * @function forwarder_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>forwarder_Receive()</code>, so this function does not need to do + * that. + * + */ +static +void +forwarder_drop(forwarder_t * forwarder, msgbuf_t *message) +{ + forwarder->stats.countDropped++; + + switch (msgbuf_get_type(message)) { + case MESSAGE_TYPE_INTEREST: + forwarder->stats.countInterestsDropped++; + break; + + case MESSAGE_TYPE_DATA: + forwarder->stats.countObjectsDropped++; + break; + + default: + forwarder->stats.countOtherDropped++; + break; + } + + // dont destroy message here, its done at end of receive } -void forwarder_Receive(Forwarder *forwarder, Message *message) { - parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); +/* + * 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 +forwarder_forward_via_connection(forwarder_t * forwarder, msgbuf_t * msgbuf, + unsigned conn_id) +{ + connection_table_t * table = forwarder_get_connection_table(forwarder); + const connection_t * conn = connection_table_get_by_id(table, conn_id); + + if (!conn) { + forwarder->stats.countDroppedConnectionNotFound++; + DEBUG("forward msgbuf %p to interface %u not found (count %u)", + msgbuf, conn_id, forwarder->stats.countDroppedConnectionNotFound); + forwarder_drop(forwarder, msgbuf); + return; + } - // this takes ownership of the message, so we're done here + /* Always queue the packet... */ + bool success = connection_send(conn, msgbuf, true); - // 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)); + /* ... and mark the connection as pending if this is not yet the case */ + unsigned i; + for (i = 0; i < forwarder->num_pending_conn; i++) { + if (forwarder->pending_conn[i] == conn_id) + break; + } + if (i == forwarder->num_pending_conn) + forwarder->pending_conn[forwarder->num_pending_conn++] = conn_id; - if (!conn) { - return; - } + if (!success) { + forwarder->stats.countSendFailures++; - if (message_HasWldr(message)) { - if (connection_HasWldr(conn)) { - // case 1: WLDR is enabled - connection_DetectLosses((Connection *)conn, message); - } else if (!connection_HasWldr(conn) && - connection_WldrAutoStartAllowed(conn)) { - // case 2: We are on an AP. We enable WLDR - connection_EnableWldr((Connection *)conn); - connection_DetectLosses((Connection *)conn, message); + DEBUG("forward msgbuf %p to interface %u send failure (count %u)", msgbuf, + conn_id, forwarder->stats.countSendFailures); + forwarder_drop(forwarder, msgbuf); + return; } - // case 3: Ignore WLDR - } else { - if (connection_HasWldr(conn) && connection_WldrAutoStartAllowed(conn)) { - // case 1: STA do not use WLDR, we disable it - connection_DisableWldr((Connection *)conn); + + switch (msgbuf_get_type(msgbuf)) { + case MESSAGE_TYPE_INTEREST: + forwarder->stats.countInterestForwarded++; + break; + + case MESSAGE_TYPE_DATA: + forwarder->stats.countObjectsForwarded++; + break; + + default: + break; } - } - messageProcessor_Receive(forwarder->processor, message); + DEBUG("forward msgbuf %p to interface %u (int %u, obj %u)", msgbuf, + conn_id, forwarder->stats.countInterestForwarded, + forwarder->stats.countObjectsForwarded); + } -Ticks forwarder_GetTicks(const Forwarder *forwarder) { - parcAssertNotNull(forwarder, "Parameter must be non-null"); - return parcClock_GetTime(forwarder->clock) + forwarder->clockOffset; +/** + * @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, + msgbuf_t *msgbuf, const nexthops_t * nexthops) +{ + unsigned forwardedCopies = 0; + + unsigned ingressId = msgbuf_get_connection_id(msgbuf); + uint32_t old_path_label = 0; + + if (msgbuf_get_type(msgbuf) == MESSAGE_TYPE_DATA) + old_path_label = msgbuf_get_pathlabel(msgbuf); + + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + if (nexthop == ingressId) + continue; + + forwardedCopies++; + forwarder_forward_via_connection(forwarder, msgbuf, nexthop); + + // 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. + if (msgbuf_get_type(msgbuf) == MESSAGE_TYPE_DATA) + msgbuf_set_pathlabel(msgbuf, old_path_label); + }); + + return forwardedCopies; } -Ticks forwarder_NanosToTicks(uint64_t nanos) { return NSEC_TO_TICKS(nanos); } -uint64_t forwarder_TicksToNanos(Ticks ticks) { - return (1000000000ULL) * ticks / HZ; -} +static +bool +forwarder_forward_via_fib(forwarder_t * forwarder, msgbuf_t *msgbuf, + pit_verdict_t verdict) +{ + assert(forwarder); + assert(msgbuf); + assert(msgbuf_get_type(msgbuf) == MESSAGE_TYPE_INTEREST); + + fib_entry_t *fib_entry = fib_match_message(forwarder->fib, msgbuf); + if (!fib_entry) + return false; + + // XXX TODO PROBE HOOK MIGHT BE HANDLED ELSEWHERE + if (msgbuf_is_probe(msgbuf)) { + connection_table_t * table = forwarder_get_connection_table(forwarder); + const nexthops_t * nexthops = fib_entry_get_nexthops(fib_entry); + + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + connection_t * conn = connection_table_at(table, nexthop); + if (!conn) + continue; + if (!connection_is_local(conn)) + continue; + uint8_t * packet = msgbuf_get_packet(msgbuf); + unsigned size = msgbuf_get_len(msgbuf); + connection_t * reply_connection = connection_table_get_by_id(table, + msgbuf_get_connection_id(msgbuf)); + if (messageHandler_IsInterest(packet)) { + messageHandler_CreateProbeReply(packet, HF_INET6_TCP); + connection_send_packet(reply_connection, packet, size); + } + return false; + }); + } + + pit_entry_t * entry = pit_lookup(forwarder->pit, msgbuf); + if (!entry) + return false; + + pit_entry_set_fib_entry(entry, fib_entry); -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"); + const nexthops_t * nexthops = fib_entry_get_nexthops_from_strategy(fib_entry, + msgbuf, verdict); - // we only have one message processor - bool res = - messageProcessor_AddOrUpdateRoute(forwarder->processor, control, ifidx); + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + pit_entry_egress_add(entry, nexthop); + }); + + // 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) + +#if 0 + // The function GetPitEntry encreases the ref counter in the pit entry + // we need to decrease it + entry_Release(&entry); +#endif + + if (forwarder_forward_to_nexthops(forwarder, msgbuf, nexthops) <= 0) { + DEBUG("Message %p returned an emtpy next hop set", msgbuf); + return false; + } + return true; - return res; } -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"); +static +bool +_satisfy_from_content_store(forwarder_t * forwarder, msgbuf_t *interest_msgbuf) +{ + assert(forwarder); + assert(msgbuf_get_type(msgbuf) == MESSAGE_TYPE_INTEREST); + + if (msgbuf_get_interest_lifetime(interest_msgbuf) == 0) + return false; + + if (!forwarder->serve_from_content_store) + return false; + + // See if there's a match in the store. + msgbuf_t * data_msgbuf = content_store_match(forwarder->content_store, + interest_msgbuf, ticks_now()); + + if (!data_msgbuf) + return false; + + // Remove it from the PIT. nexthops is allocated, so need to destroy + nexthops_t * nexthops = pit_on_data(forwarder->pit, data_msgbuf); + assert(nexthops); // Illegal state: got a null nexthops for an interest we just inserted + + // send message in reply, then done + forwarder->stats.countInterestsSatisfiedFromStore++; + + DEBUG("Message %p satisfied from content store (satisfied count %u)", + interest_msgbuf, forwarder->stats.countInterestsSatisfiedFromStore); - // we only have one message processor - return messageProcessor_RemoveRoute(forwarder->processor, control, ifidx); + msgbuf_reset_pathlabel(data_msgbuf); + + forwarder_forward_to_nexthops(forwarder, data_msgbuf, nexthops); + + return true; } -#ifdef WITH_POLICY +/** + * @function forwarder_receive_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 +void +forwarder_receive_interest(forwarder_t * forwarder, msgbuf_t * msgbuf) +{ + assert(forwarder); + assert(msgbuf); + assert(msgbuf_get_type(msgbuf) == MESSAGE_TYPE_INTEREST); + forwarder->stats.countInterestsReceived++; + + // (1) Try to aggregate in PIT + pit_verdict_t verdict = pit_on_interest(forwarder->pit, msgbuf); + switch(verdict) { + case PIT_VERDICT_AGGREGATE: + forwarder->stats.countInterestsAggregated++; + DEBUG("Message %p aggregated in PIT (aggregated count %u)", + msgbuf, forwarder->stats.countInterestsAggregated); + return; + + case PIT_VERDICT_FORWARD: + case PIT_VERDICT_RETRANSMIT: + DEBUG("Message %p not aggregated in PIT (aggregated count %u)", + msgbuf, forwarder->stats.countInterestsAggregated); + break; + } + + // At this point, we just created a PIT entry. If we don't forward the + // interest, we need to remove the PIT entry. -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"); + // (2) Try to satisfy from content store + if (_satisfy_from_content_store(forwarder, msgbuf)) { + // done + // If we found a content object in the CS, + // messageProcess_Satisfy_from_content_store already cleared the PIT state + return; + } + + // (3) Try to forward it + if (forwarder_forward_via_fib(forwarder, msgbuf, verdict)) { + // done + return; + } - return messageProcessor_AddOrUpdatePolicy(forwarder->processor, control); + // Remove the PIT entry? + forwarder->stats.countDroppedNoRoute++; + + DEBUG("Message %p did not match FIB, no route (count %u)", + msgbuf, forwarder->stats.countDroppedNoRoute); + + forwarder_drop(forwarder, msgbuf); } -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"); +/** + * @function forwarder_receive_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 +void +forwarder_receive_data(forwarder_t * forwarder, + msgbuf_t *msgbuf) +{ + forwarder->stats.countObjectsReceived++; + + nexthops_t * ingressSetUnion = pit_on_data(forwarder->pit, msgbuf); + if (!ingressSetUnion) { + // (1) If it does not match anything in the PIT, drop it + forwarder->stats.countDroppedNoReversePath++; + + DEBUG("Message %p did not match PIT, no reverse path (count %u)", + msgbuf, forwarder->stats.countDroppedNoReversePath); + + // MOVE PROBE HOOK ELSEWHERE + // XXX relationship with forwarding strategy... insert hooks + // if the packet is a probe we need to analyze it + // NOTE : probes are not stored in PIT + if (msgbuf_is_probe(msgbuf)) { + fib_entry_t *entry = fib_match_message(forwarder->fib, msgbuf); + if (entry && fib_entry_strategy_type(entry) == STRATEGY_TYPE_LOW_LATENCY) { + nexthops_t probe_nexthops; + nexthops_add(&probe_nexthops, msgbuf_get_connection_id(msgbuf)); + fib_entry_on_data(entry, &probe_nexthops, msgbuf, 0, ticks_now()); + + // XXX TODO CONFIRM WE DON'T EXIT HERE ? + } + } + + // 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 + const connection_table_t * table = forwarder_get_connection_table(forwarder); + const connection_t * conn = connection_table_get_by_id(table, msgbuf_get_connection_id(msgbuf)); + + if (forwarder->store_in_content_store && connection_is_local(conn)) { + content_store_add(forwarder->content_store, msgbuf, ticks_now()); + DEBUG("Message %p store in CS anyway", msgbuf); + } + + forwarder_drop(forwarder, msgbuf); + } else { + // (2) Add to Content Store. Store may remove expired content, if necessary, + // depending on store policy. + if (forwarder->store_in_content_store) { + content_store_add(forwarder->content_store, msgbuf, ticks_now()); + } + // (3) Reverse path forward via PIT entries + forwarder_forward_to_nexthops(forwarder, msgbuf, ingressSetUnion); - return messageProcessor_RemovePolicy(forwarder->processor, control); + } } -#endif /* WITH_POLICY */ -void forwarder_RemoveConnectionIdFromRoutes(Forwarder *forwarder, - unsigned connectionId) { - parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null"); - messageProcessor_RemoveConnectionIdFromRoutes(forwarder->processor, - connectionId); +/** + * A NULL msgbuf is used to indicate the end of a batch + */ +void +forwarder_receive(forwarder_t * forwarder, msgbuf_t * msgbuf) +{ + assert(forwarder); + + /* Send batch ? */ + if (!msgbuf) { + const connection_table_t * table = forwarder_get_connection_table(forwarder); + for (unsigned i = 0; i < forwarder->num_pending_conn; i++) { + const connection_t * conn = connection_table_at(table, forwarder->pending_conn[i]); + // flush + connection_send(conn, NULL, false); + } + forwarder->num_pending_conn = 0; + } + + // 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 + connection_table_t * table = forwarder_get_connection_table(forwarder); + connection_t * conn = connection_table_get_by_id(table, msgbuf_get_connection_id(msgbuf)); + if (!conn) + return; + + if (msgbuf_has_wldr(msgbuf)) { + if (connection_has_wldr(conn)) { + // case 1: WLDR is enabled + connection_wldr_detect_losses(conn, msgbuf); + } else if (!connection_has_wldr(conn) && + connection_wldr_autostart_is_allowed(conn)) { + // case 2: We are on an AP. We enable WLDR + connection_wldr_enable(conn, true); + connection_wldr_detect_losses(conn, msgbuf); + } + // case 3: Ignore WLDR + } else { + if (connection_has_wldr(conn) && connection_wldr_autostart_is_allowed(conn)) { + // case 1: STA do not use WLDR, we disable it + connection_wldr_enable(conn, false); + } + } + + forwarder->stats.countReceived++; + + char *nameString = name_ToString(msgbuf_get_name(msgbuf)); + DEBUG( "Message %p ingress %3u length %5u received name %s", msgbuf, + msgbuf_get_connection_id(msgbuf), msgbuf_get_len(msgbuf), nameString); + free(nameString); + + switch (msgbuf_get_type(msgbuf)) { + case MESSAGE_TYPE_INTEREST: + forwarder_receive_interest(forwarder, msgbuf); + break; + + case MESSAGE_TYPE_DATA: + forwarder_receive_data(forwarder, msgbuf); + break; + + default: + forwarder_drop(forwarder, msgbuf); + break; + } + } -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"); +bool +forwarder_add_or_update_route(forwarder_t * forwarder, ip_prefix_t * prefix, + unsigned ingress_id) +{ + assert(forwarder); + assert(prefix); + + configuration_t *config = forwarder_get_configuration(forwarder); + + char prefix_s[MAXSZ_IP_PREFIX]; + int rc = ip_prefix_snprintf(prefix_s, MAXSZ_IP_PREFIX, prefix); + assert(rc < MAXSZ_IP_PREFIX); + if (rc < 0) + return false; + + // XXX TODO this should store options too + strategy_type_t strategy_type = configuration_get_strategy(config, prefix_s); + + Name * name_prefix = name_CreateFromAddress(prefix->family, + prefix->address, prefix->len); + // XXX TODO error handling + fib_entry_t * entry = fib_contains(forwarder->fib, name_prefix); + if (!entry) { + entry = fib_entry_create(name_prefix, strategy_type, NULL, forwarder); + fib_entry_nexthops_add(entry, ingress_id); + fib_add(forwarder->fib, entry); + } else { + fib_entry_nexthops_add(entry, ingress_id); + } + + name_Release(&name_prefix); - processor_SetStrategy(forwarder->processor, prefix, strategy, - related_prefixes_len, related_prefixes); + return true; } -FibEntryList *forwarder_GetFibEntries(Forwarder *forwarder) { - return messageProcessor_GetFibEntries(forwarder->processor); + +bool +forwarder_remove_route(forwarder_t * forwarder, ip_prefix_t * prefix, + unsigned ingress_id) +{ + assert(forwarder); + assert(prefix); + + Name *name_prefix = name_CreateFromAddress(prefix->family, + prefix->address, prefix->len); + // XXX TODO error handling + fib_remove(forwarder->fib, name_prefix, ingress_id); + name_Release(&name_prefix); + + return true; +} + +#ifdef WITH_POLICY + +bool +forwarder_add_or_update_policy(forwarder_t * forwarder, ip_prefix_t * prefix, + policy_t * policy) +{ + assert(forwarder); + assert(prefix); + assert(policy); + + Name *name_prefix = name_CreateFromAddress(prefix->family, prefix->address, + prefix->len); + // XXX TODO error handling + fib_entry_t *entry = fib_contains(forwarder->fib, name_prefix); + if (!entry) + return false; + fib_entry_set_policy(entry, *policy); + + name_Release(&name_prefix); + + return true; } -void forwarder_SetContentObjectStoreSize(Forwarder *forwarder, - size_t maximumContentStoreSize) { - messageProcessor_SetContentObjectStoreSize(forwarder->processor, - maximumContentStoreSize); +bool +forwarder_remove_policy(forwarder_t * forwarder, ip_prefix_t * prefix) +{ + assert(forwarder); + assert(prefix); + + Name *name_prefix = name_CreateFromAddress(prefix->family, prefix->address, + prefix->len); + // XXX TODO error handling + fib_entry_t * entry = fib_contains(forwarder->fib, name_prefix); + name_Release(&name_prefix); + + if (!entry) + return false; + + fib_entry_set_policy(entry, POLICY_NONE); + + return true; } -void forwarder_ClearCache(Forwarder *forwarder) { - messageProcessor_ClearCache(forwarder->processor); +#endif /* WITH_POLICY */ + +void +forwarder_remove_connection_id_from_routes(forwarder_t * forwarder, + unsigned connection_id) +{ + assert(forwarder); + + fib_remove_connection_id(forwarder->fib, connection_id); } -PARCClock *forwarder_GetClock(const Forwarder *forwarder) { - return forwarder->clock; +void +forwarder_set_strategy(forwarder_t * forwarder, Name * name_prefix, + strategy_type_t strategy_type, strategy_options_t * strategy_options) +{ + assert(forwarder); + assert(name_prefix); + assert(strategy_type_valid(strategy_type)); + /* strategy_options might be NULL */ + + fib_entry_t * entry = fib_contains(forwarder->fib, name_prefix); + if (!entry) + return; + + fib_entry_set_strategy(entry, strategy_type, strategy_options); } -#if !defined(__APPLE__) -hicn_socket_helper_t *forwarder_GetHicnSocketHelper(Forwarder *forwarder) { - return forwarder->hicnSocketHelper; +content_store_t * +forwarder_get_content_store(const forwarder_t * forwarder) +{ + assert(forwarder); + + return forwarder->content_store; } -#endif // ======================================================= +#if 0 static void _signal_cb(int sig, PARCEventType events, void *user_data) { - Forwarder *forwarder = (Forwarder *)user_data; - - logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning, - __func__, "signal %d events %d", sig, events); - - switch ((int)sig) { - case SIGTERM: - logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning, - __func__, "Caught an terminate signal; exiting cleanly."); - dispatcher_Stop(forwarder->dispatcher); - break; - - case SIGINT: - logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning, - __func__, "Caught an interrupt signal; exiting cleanly."); - dispatcher_Stop(forwarder->dispatcher); - break; + forwarder_t * forwarder = (forwarder_t *)user_data; + + WARN("signal %d events %d", sig, events); + + switch ((int)sig) { + case SIGTERM: + WARN("Caught an terminate signal; exiting cleanly."); + dispatcher_Stop(forwarder->dispatcher); + break; + + case SIGINT: + WARN("Caught an interrupt signal; exiting cleanly."); + dispatcher_Stop(forwarder->dispatcher); + break; #ifndef _WIN32 - case SIGUSR1: - // dump stats - break; + case SIGUSR1: + // dump stats + break; #endif - default: - break; - } + default: + break; + } } +#endif -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 +fib_t * +forwarder_get_fib(forwarder_t * forwarder) { + return forwarder->fib; } #ifdef WITH_MAPME -FIB *forwarder_getFib(Forwarder *forwarder) { - return messageProcessor_getFib(forwarder->processor); +void +forwarder_on_connection_event(const forwarder_t * forwarder, + const connection_t * connection, connection_event_t event) +{ + mapme_on_connection_event(forwarder->mapme, connection, event); } -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 */ +mapme_t * +forwarder_get_mapme(const forwarder_t * forwarder) { + return forwarder->mapme; } -void forwarder_ProcessMapMe(Forwarder *forwarder, const uint8_t *msgBuffer, - unsigned conn_id) { - mapme_Process(forwarder->mapme, msgBuffer, conn_id); +#endif /* WITH_MAPME */ + +#ifdef WITH_PREFIX_STATS +const prefix_stats_mgr_t * +forwarder_get_prefix_stats_mgr(const forwarder_t * forwarder) +{ + return &forwarder->prefix_stats_mgr; } +#endif /* WITH_PREFIX_STATS */ + +static +void +process_interest(forwarder_t * forwarder, listener_t * listener, + unsigned conn_id, uint8_t * packet, size_t size, const address_pair_t * pair) +{ + if (!connection_id_is_valid(conn_id)) { + conn_id = listener_create_connection(listener, pair); + } -MapMe * -forwarder_getMapmeInstance(const Forwarder *forwarder) { - return forwarder->mapme; + assert(messageHandler_GetTotalPacketLength(packet) == size); + + msgbuf_from_packet(&forwarder->msgbuf, packet, size, MESSAGE_TYPE_INTEREST, conn_id, ticks_now()); + forwarder_receive(listener->forwarder, &forwarder->msgbuf); } -#endif /* WITH_MAPME */ +static +void +process_data(forwarder_t * forwarder, listener_t * listener, + unsigned conn_id, uint8_t * packet, size_t size, const address_pair_t * pair) +{ + if (!connection_id_is_valid(conn_id)) { + INFO("Ignoring data packet associated to no connection"); + return; + } + + assert(messageHandler_GetTotalPacketLength(packet) == size); + + msgbuf_from_packet(&forwarder->msgbuf, packet, size, MESSAGE_TYPE_DATA, conn_id, ticks_now()); + forwarder_receive(listener->forwarder, &forwarder->msgbuf); + +} + +static +void +process_wldr_notification(forwarder_t * forwarder, listener_t * listener, + unsigned conn_id, uint8_t * packet, size_t size, const address_pair_t * pair) +{ + if (!connection_id_is_valid(conn_id)) { + INFO("Ignoring WLDR notification not associated to a connection"); + return; + } + + assert(messageHandler_GetTotalPacketLength(packet) == size); + + connection_table_t * table = forwarder_get_connection_table(forwarder); + connection_t * connection = connection_table_at(table, conn_id); + + msgbuf_from_packet(&forwarder->msgbuf, packet, size, MESSAGE_TYPE_WLDR_NOTIFICATION, conn_id, ticks_now()); + connection_wldr_handle_notification(connection, &forwarder->msgbuf); + +} + +static +void +process_mapme(forwarder_t * forwarder, listener_t * listener, + unsigned conn_id, uint8_t * packet, size_t size, const address_pair_t * pair) +{ + if (!connection_id_is_valid(conn_id)) + conn_id = listener_create_connection(listener, pair); + mapme_process(forwarder->mapme, packet, conn_id); +} + +static +void +process_command(const forwarder_t * forwarder, listener_t * listener, + unsigned conn_id, uint8_t * packet, size_t size, const address_pair_t * pair) +{ + if (!connection_id_is_valid(conn_id)) + conn_id = listener_create_connection(listener, pair); + + command_type_t command_type= *(packet + 1); + if (command_type >= COMMAND_TYPE_N) { + ERROR("Invalid command"); + return; + } + forwarder_receive_command(listener->forwarder, command_type, packet, conn_id); + +} + +// = process for listener as we are resolving connection id +// XXX this would typically be inside the forwarder +void +process_packet(forwarder_t * forwarder, listener_t * listener, uint8_t * packet, size_t size, address_pair_t * pair) +{ + /* Connection lookup */ + const connection_table_t * table = forwarder_get_connection_table(listener->forwarder); + const connection_t * conn = connection_table_get_by_pair(table, pair); + unsigned conn_id = conn ? connection_table_get_connection_id(table, conn): CONNECTION_ID_UNDEFINED; + + assert((conn_id != CONNECTION_ID_UNDEFINED) || listener); + + // Actually hooks should be defined for each packet type to avoid this + // spaghetti code + if (messageHandler_IsTCP(packet)) { + if (messageHandler_IsData(packet)) { + process_data(forwarder, listener, conn_id, packet, size, pair); + } else if (messageHandler_IsInterest(packet)) { + process_interest(forwarder, listener, conn_id, packet, size, pair); + } else { + INFO("Unknown TCP packet received"); + forwarder_drop(forwarder, NULL); + } + } else if (messageHandler_IsWldrNotification(packet)) { + process_wldr_notification(forwarder, listener, conn_id, packet, size, pair); + } else if (mapme_match_packet(packet)) { + process_mapme(forwarder, listener, conn_id, packet, size, pair); + } else if (*packet == REQUEST_LIGHT) { + process_command(forwarder, listener, conn_id, packet, size, pair); + } else { + INFO("Unknown packet received"); + forwarder_drop(forwarder, NULL); + } +} diff --git a/hicn-light/src/hicn/core/forwarder.h b/hicn-light/src/hicn/core/forwarder.h index d1815b7d4..5d999a319 100644 --- a/hicn-light/src/hicn/core/forwarder.h +++ b/hicn-light/src/hicn/core/forwarder.h @@ -21,44 +21,48 @@ #ifndef forwarder_h #define forwarder_h -#ifndef _WIN32 -#include <sys/time.h> -#endif -#include <stdlib.h> +//#ifndef _WIN32 +//#include <sys/time.h> +//#endif +// -#include <hicn/core/connectionTable.h> -#include <hicn/core/dispatcher.h> -#include <hicn/messenger/messenger.h> +#include <stdlib.h> +#include <sys/socket.h> // struct mmsghdr -#include <hicn/core/message.h> +#include <hicn/core/msgbuf.h> +#include <hicn/core/content_store.h> +#include <hicn/core/connection.h> +#include <hicn/core/connection_table.h> +#include <hicn/core/listener_table.h> #include <hicn/config/configuration.h> #ifdef WITH_MAPME -#include <hicn/processor/fib.h> +#include <hicn/core/fib.h> #endif /* WITH_MAPME */ -#include <hicn/core/logger.h> -#include <hicn/core/ticks.h> -#include <hicn/io/listenerSet.h> +#define PORT_NUMBER 9695 +#define PORT_NUMBER_AS_STRING "9695" -#include <hicn/processor/fibEntryList.h> +#include <hicn/utils/commands.h> -#include <parc/algol/parc_Clock.h> +#define MAX_MSG 64 //16 //32 +#define MTU 1500 -#if !defined(__APPLE__) -#include <hicn/socket/api.h> -#endif -#define PORT_NUMBER 9695 -#define PORT_NUMBER_AS_STRING "9695" +typedef struct batch_buffer_s { + /* sendmmsg / recvmmsg data structures */ + struct mmsghdr msghdr[MAX_MSG]; // XXX = {0}; + char buffers[MAX_MSG][MTU]; + struct iovec iovecs[MAX_MSG]; // XXX = {0}; + struct sockaddr_storage addrs[MAX_MSG]; +} batch_buffer_t; -#include <hicn/utils/commands.h> +int init_batch_buffers(batch_buffer_t * bb); // ============================================== -struct forwarder; -typedef struct forwarder Forwarder; +typedef struct forwarder_s forwarder_t; /** * @function forwarder_Create @@ -69,13 +73,13 @@ typedef struct forwarder Forwarder; * * @param logger may be NULL */ -Forwarder *forwarder_Create(Logger *logger); +forwarder_t * forwarder_create(); /** * @function forwarder_Destroy * @abstract Destroys the forwarder, stopping all traffic and freeing all memory */ -void forwarder_Destroy(Forwarder **ptr); +void forwarder_free(forwarder_t * forwarder); /** * @function forwarder_SetupAllListeners @@ -90,14 +94,14 @@ void forwarder_Destroy(Forwarder **ptr); * @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); +void forwarder_setup_all_listeners(forwarder_t * forwarder, uint16_t port, const + char *local_path); /** * @function forwarder_SetupAllListeners * @abstract 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); +void forwarder_setup_local_listeners(forwarder_t * forwarder, uint16_t port); /** * Configure hicn-light via a configuration file @@ -106,38 +110,19 @@ void forwarder_SetupLocalListeners(Forwarder *forwarder, uint16_t port); * 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] forwarder An alloated forwarder_t * @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); +void forwarder_read_config(forwarder_t * forwarder, const char * filename); /** - * @function forwarder_SetLogLevel - * @abstract Sets the minimum level to log - */ -void forwarder_SetLogLevel(Forwarder *forwarder, PARCLogLevel level); - -/** - * @function forwarder_GetNextConnectionId - * @abstract Get the next identifier for a new connection + * @function forwarder_GetConfiguration + * @abstract The configuration object + * @discussion + * The configuration contains all user-issued commands. It does not include + * dynamic state. */ -unsigned forwarder_GetNextConnectionId(Forwarder *forwarder); - -Messenger *forwarder_GetMessenger(Forwarder *forwarder); - -Dispatcher *forwarder_GetDispatcher(Forwarder *forwarder); +configuration_t * forwarder_get_configuration(forwarder_t * forwarder); /** * Returns the set of currently active listeners @@ -147,7 +132,7 @@ Dispatcher *forwarder_GetDispatcher(Forwarder *forwarder); * @retval non-null The set of active listeners * @retval null An error */ -ListenerSet *forwarder_GetListenerSet(Forwarder *forwarder); +listener_table_t * forwarder_get_listener_table(forwarder_t *forwarder); /** * Returns the forwrder's connection table @@ -158,119 +143,72 @@ ListenerSet *forwarder_GetListenerSet(Forwarder *forwarder); * @retval null An error * */ -#ifdef WITH_POLICY -ConnectionTable *forwarder_GetConnectionTable(const Forwarder *forwarder); -#else -ConnectionTable *forwarder_GetConnectionTable(Forwarder *forwarder); -#endif /* WITH_POLICY */ +connection_table_t * forwarder_get_connection_table(const forwarder_t *forwarder); -/** - * Returns a Tick-based clock - * - * Runs at approximately 1 msec per tick (see HZ in forwarder.c). - * Do not Release this clock. If you save a copy of it, create your own - * reference to it with parcClock_Acquire(). - * - * @param [in] forwarder An allocated hicn-light forwarder - * - * @retval non-null An allocated hicn-light Clock based on the Tick counter - * @retval null An error - */ -PARCClock *forwarder_GetClock(const Forwarder *forwarder); +void forwarder_content_store_set_store(forwarder_t * forwarder, bool val); -/** - * Direct call to get the Tick clock - * - * Runs at approximately 1 msec per tick (see HZ in forwarder.c) - * - * @param [in] forwarder An allocated hicn-light forwarder - */ -Ticks forwarder_GetTicks(const Forwarder *forwarder); +bool forwarder_content_store_get_store(forwarder_t * forwarder); + +void forwarder_content_store_set_serve(forwarder_t * forwarder, bool val); + +bool forwarder_content_store_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); +void forwarder_content_store_set_size(forwarder_t * forwarder, size_t size); -uint64_t forwarder_TicksToNanos(Ticks ticks); +void forwarder_content_store_clear(forwarder_t *forwarder); -void forwarder_ReceiveCommand(Forwarder *forwarder, command_id command, - struct iovec *message, unsigned ingressId); +void forwarder_receive_command(forwarder_t * forwarder, command_type_t command_type, + uint8_t * packet, unsigned connection_id); -void forwarder_Receive(Forwarder *forwarder, Message *mesage); +void forwarder_receive(forwarder_t * forwarder, msgbuf_t * message); /** - * @function forwarder_AddOrUpdateRoute + * @function forwarder_add_or_update_route * @abstract Adds or updates a route on all the message processors */ -bool forwarder_AddOrUpdateRoute(Forwarder *forwarder, - add_route_command *control, unsigned ifidx); +bool forwarder_add_or_update_route(forwarder_t * forwarder, + ip_prefix_t * prefix, unsigned ingress_id); /** - * @function forwarder_RemoveRoute + * @function forwarder_remove_route * @abstract Removes a route from all the message processors */ -bool forwarder_RemoveRoute(Forwarder *forwarder, remove_route_command *control, - unsigned ifidx); +bool forwarder_remove_route(forwarder_t * forwarder, ip_prefix_t * prefix, + unsigned ingress_id); #ifdef WITH_POLICY /** - * @function forwarder_AddOrUpdatePolicy + * @function forwarder_add_or_update_policy * @abstract Adds or updates a policy on the message processor */ -bool forwarder_AddOrUpdatePolicy(Forwarder *forwarder, add_policy_command *control); +bool forwarder_add_or_update_policy(forwarder_t * forwarder, + ip_prefix_t * prefix, policy_t * policy); + /** * @function forwarder_RemovePolicy * @abstract Removes a policy from the message processor */ -bool forwarder_RemovePolicy(Forwarder *forwarder, remove_policy_command *control); +bool forwarder_remove_policy(forwarder_t * forwarder, ip_prefix_t * prefix); + #endif /* WITH_POLICY */ /** * Removes a connection id from all routes */ -void forwarder_RemoveConnectionIdFromRoutes(Forwarder *forwarder, - unsigned connectionId); - -/** - * @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); - -FibEntryList *forwarder_GetFibEntries(Forwarder *forwarder); - -/** - * Sets the maximum number of content objects in the content store - * - * Implementation dependent - may wipe the cache. - */ -void forwarder_SetContentObjectStoreSize(Forwarder *forwarder, - size_t maximumContentStoreSize); +void forwarder_remove_connection_id_from_routes(forwarder_t * forwarder, + unsigned connection_id); -void forwarder_SetChacheStoreFlag(Forwarder *forwarder, bool val); +void forwarder_set_strategy(forwarder_t * forwarder, Name * name_prefix, + strategy_type_t strategy_type, strategy_options_t * strategy_options); -bool forwarder_GetChacheStoreFlag(Forwarder *forwarder); +content_store_t * forwarder_get_content_store(const forwarder_t * forwarder); -void forwarder_SetChacheServeFlag(Forwarder *forwarder, bool val); - -bool forwarder_GetChacheServeFlag(Forwarder *forwarder); - -void forwarder_ClearCache(Forwarder *forwarder); - -void forwarder_SetStrategy(Forwarder *forwarder, Name *prefix, - strategy_type strategy, unsigned related_prefixes_len, - Name **related_prefixes); -#if !defined(__APPLE__) -hicn_socket_helper_t *forwarder_GetHicnSocketHelper(Forwarder *forwarder); -#endif -#ifdef WITH_MAPME /** * @function forwarder_getFib @@ -278,7 +216,9 @@ hicn_socket_helper_t *forwarder_GetHicnSocketHelper(Forwarder *forwarder); * @param [in] forwarder - Pointer to the hICN forwarder. * @returns Pointer to the hICN FIB. */ -FIB *forwarder_getFib(Forwarder *forwarder); +fib_t * forwarder_get_fib(forwarder_t * forwarder); + +#ifdef WITH_MAPME /** * @function forwarder_onConnectionEvent @@ -288,7 +228,8 @@ FIB *forwarder_getFib(Forwarder *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 @@ -298,12 +239,18 @@ void forwarder_onConnectionEvent(Forwarder *forwarder, const Connection *conn, c * @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 */ +#ifdef WITH_PREFIX_STATS +const prefix_stats_mgr_t * forwarder_get_prefix_stats_mgr(const forwarder_t * forwarder); +#endif /* WITH_PREFIX_STATS */ + +void process_packet(forwarder_t * forwarder, listener_t * listener, + uint8_t * packet, size_t size, address_pair_t * pair); + #endif // 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..0ab73b1f4 --- /dev/null +++ b/hicn-light/src/hicn/core/listener.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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/core/listener_vft.h> +#include <hicn/base/loop.h> +#include <hicn/core/forwarder.h> +#include <hicn/util/log.h> +#include "listener.h" + +listener_t * +listener_create(face_type_t type, const address_t * address, + const char * interface_name, const char * name, forwarder_t * forwarder) +{ + const listener_table_t * table = forwarder_get_listener_table(forwarder); + + listener_t * listener; + listener_key_t key = { + .type = type, + .address = *address, + }; + listener_table_allocate(table, listener, &key, name); + + unsigned listener_id = listener_table_get_listener_id(table, listener); + + listener_initialize(listener, type, name, listener_id, address, interface_name, forwarder); + 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), + .type = type, + .interface_name = strdup(interface_name), + //.interface_index = , + //.family = , + .fd = 0, + .address = *address, + .forwarder = forwarder, + }; + + listener->data = malloc(listener_vft[listener->type]->data_size); + if (!listener->data) + goto ERR_DATA; + + assert(listener_has_valid_type(listener)); + + rc = listener_vft[listener->type]->initialize(listener); + if (rc < 0) + goto ERR_VFT; + + listener->fd = listener_vft[listener->type]->get_socket(listener, address, NULL, interface_name); + if (listener->fd < 0) { + ERROR("Error creating listener fd: (%d) %s", errno, strerror(errno)); + goto ERR_FD; + } + assert(listener->fd > 0); + + // XXX data should be pre-allocated here + + if (loop_register_fd(MAIN_LOOP, listener->fd, listener, + (fd_callback_t)listener_vft[listener->type]->read_callback, NULL) < 0) + goto ERR_REGISTER_FD; + + // XXX TODO + //char *str = addressToString(listener->local_addr); + DEBUG("%s UdpListener %p created for address %s", + face_type_str(listener->type), listener, "N/A"); + //free(str); + + return 0; + +ERR_REGISTER_FD: +#ifndef _WIN32 + close(listener->fd); +#else + closesocket(listener->fd); +#endif +ERR_FD: +ERR_VFT: + free(listener->data); +ERR_DATA: + free(listener->interface_name); + free(listener->name); + return -1; +} + +int +listener_finalize(listener_t * listener) +{ + assert(listener); + assert(listener_has_valid_type(listener)); + + loop_unregister_fd(MAIN_LOOP, listener->fd); + +#ifndef _WIN32 + close(listener->fd); +#else + closesocket(listener->fd); +#endif + + listener_vft[listener->type]->finalize(listener); + + free(listener->data); + free(listener->interface_name); + free(listener->name); + + 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(pair); + + return listener_vft[listener->type]->get_socket(listener, local, remote, + interface_name); +} + +// XXX CHANGE : we now get the fd directly from the listener +unsigned listener_create_connection(const listener_t * listener, + const address_pair_t * pair) +{ + assert(listener); + assert(listener_has_valid_type(listener)); + assert(pair); + + // XXX TODO This code is likely common with connection creation code + const char * name = NULL; + + connection_table_t * table = forwarder_get_connection_table(listener->forwarder); + connection_t * connection; + connection_table_allocate(table, connection, pair, name); + + unsigned connid = connection_table_get_connection_id(table, connection); + + bool local = address_is_local(address_pair_get_local(pair)); + + int fd = listener_get_socket(listener, address_pair_get_local(pair), + address_pair_get_remote(pair), NULL); // XXX interfacename was not specified + + // XXX here we use the same interface name as the listener + int rc = connection_initialize(connection, listener->type, name, + listener->interface_name, fd, pair, local, connid, listener->forwarder); + if (rc < 0) + return ~0; // XXX how to return an error + + // This was already commented: + // connection_AllowWldrAutoStart(*conn_ptr); + + return connid; +} + +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[listener_get_type(listener)]->punt(listener, prefix_s); +} + +ssize_t +listener_read_callback(forwarder_t * forwarder, listener_t * listener, int fd, + address_t * local_addr, uint8_t * packet, size_t size) +{ + // XXX TODO mutualize code across all listeners + // some do not support batches + // + // XXX negative in case of error + // 0 if we don't consume yet because we don't have enough + // needed for TCP !! + return size; +} + +void +listener_batch_read_callback(forwarder_t * forwarder, listener_t * listener, + int fd, address_t * local_addr, batch_buffer_t * bb) +{ + assert(bb); + + // XXX potential improvement : receive in a loop while we have messages to + // read + + // XXX + int r = recvmmsg(fd, bb->msghdr, MAX_MSG, 0, NULL); + if (r == 0) + return; + + if (r < 0) { + if (errno == EINTR) + return; + perror("recv()"); + return; + } + + for (int i = 0; i < r; i++) { + struct mmsghdr *msg = &bb->msghdr[i]; + uint8_t * packet = msg->msg_hdr.msg_iov->iov_base; + size_t size = msg->msg_hdr.msg_iovlen; + + /* BEGIN packet processing */ + +#ifdef __APPLE__ + // XXX explain + msg->msg_hdr.msg_namelen = 0x00; +#endif + + /* Construct address pair used for connection lookup */ + address_pair_t pair; + pair.local = *local_addr; + pair.remote = *(address_t*)msg->msg_hdr.msg_name; + // in the case of a connection, we should assert the remote + + process_packet(forwarder, listener, packet, size, &pair); + } +} + + +#if 0 +void +_listener_callback(evutil_socket_t fd, short what, void * arg) +{ + fd_callback_data_t * data = arg; + data->callback(data->owner, fd, data->data); +} + +int +listener_register_fd(listener_t * listener, int fd, fd_callback_t callback, void * data) +{ + fd_callback_data_t callback_data = { + .fd = fd, + .owner = listener, + .callback = callback, + .data = data, + }; + + return loop_register_fd(MAIN_LOOP, fd, listener, _listener_callback, callback_data); +} + +int +listener_unregister_fd(listener_t * listener, int fd) +{ + return loop_unregister_fd(MAIN_LOOP, fd); +} +#endif + +void +listener_setup_all(const forwarder_t * forwarder, uint16_t port, const char *localPath) +{ +#if 0 + 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_t *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 + // XXX TODO if (addressGetType(address) != ADDR_LINK) { + _setupTcpListener(forwarder, listenerName, address, + (char *)interfaceGetName(iface)); + // } + } + } + + interfaceSetDestroy(&set); +#endif +} + +// XXX TODO +void +listener_setup_local_ipv4(const forwarder_t * forwarder, uint16_t port) +{ +#if 0 + // XXX memset + address_t address = ADDRESS4_LOCALHOST(port); + + _setupUdpListener(forwarder, "lo_udp", &address, "lo"); + _setupTcpListener(forwarder, "lo_tcp", &address, "lo"); +#endif +} diff --git a/hicn-light/src/hicn/core/listener.h b/hicn-light/src/hicn/core/listener.h new file mode 100644 index 000000000..749e9b177 --- /dev/null +++ b/hicn-light/src/hicn/core/listener.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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/core/address_pair.h> +#include <hicn/face.h> + +struct forwarder_s; +struct batch_buffer_s; + +typedef struct { + address_t address; + face_type_t type; +} listener_key_t; + +/* 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 interface_index; + unsigned family; + int fd; + 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_interface_index(L) ((L)->interface_index) +#define listener_get_address(L) (&(L)->address) + +#define listener_has_valid_type(L) \ + (face_type_is_valid((L)->type)) + +listener_t * listener_create(face_type_t type, const address_t * address, + const char * interface_name, const char * symbolic, struct forwarder_s * forwarder); + +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(const listener_t * listener, + const address_pair_t * pair); + +void listener_setup_all(const struct forwarder_s * forwarder, uint16_t port, const char *localPath); + +void listener_setup_local_ipv4(const 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_callback(struct forwarder_s * forwarder, listener_t * listener, + int fd, address_t * local_addr, uint8_t * packet, size_t size); + +void listener_batch_read_callback(struct forwarder_s * forwarder, + listener_t * listener, int fd, address_t * local_addr, + struct batch_buffer_s * bb); + +#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..e3cbb310d --- /dev/null +++ b/hicn-light/src/hicn/core/listener_table.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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/core/listener_table.h> +#include <hicn/core/listener.h> + +/* This is only used for first allocation, as the table is resizeable */ +#define DEFAULT_LISTENER_TABLE_SIZE 64 + +listener_table_t * +listener_table_create(size_t elt_size, size_t max_elts) +{ + listener_table_t * table = malloc(sizeof(listener_table_t)); + if (!table) + return NULL; + + table->id_by_name = kh_init_lt_name(); + table->id_by_key = kh_init_lt_key(); + pool_init(table->listeners, DEFAULT_LISTENER_TABLE_SIZE); + + return table; +} + +void +listener_table_free(listener_table_t * table) +{ + kh_destroy_lt_name(table->id_by_name); + kh_destroy_lt_key(table->id_by_key); + pool_free(table->listeners); + free(table); +} + +listener_t * +listener_table_get_by_address(listener_table_t * table, + face_type_t type, const address_t * address) +{ + listener_key_t key; + //XXX + memset(&key, 0, sizeof(listener_key_t)); + key = (listener_key_t) { + .type = type, + .address = *address, + }; + 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) +{ + /* + * Get the listener address so as to be able to remove it from the + * hash table index + */ + listener_t * listener = listener_table_at(table, id); + const char * name = listener_get_name(listener); + listener_key_t * key = listener_get_key(listener); + khiter_t k; + k = kh_get_lt_name(table->id_by_name, name); + kh_del_lt_name(table->id_by_name, k); + k = kh_get_lt_key(table->id_by_key, key); + kh_del_lt_key(table->id_by_key, k); + + pool_put(table->listeners, listener); +} + +listener_t * +listener_table_get_by_name(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 NULL; + return listener_table_at(table, kh_val(table->id_by_name, k)); +} + +#if 0 +unsigned +listener_table_add(listener_table_t * table, listener_t * listener) +{ + // XXX missing hash and key storage + listener_t * lst; + pool_get(table->listeners, lst); + lst = listener; + unsigned listener_id = lst - table, + Listener_SetId(listener, listener_id); + return listener_id; +} +#endif 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..66959def4 --- /dev/null +++ b/hicn-light/src/hicn/core/listener_table.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + */ + +#ifndef HICN_LISTENER_TABLE_H +#define HICN_LISTENER_TABLE_H + +#include <hicn/core/address.h> +#include <hicn/base/common.h> +#include <hicn/base/hash.h> +#include <hicn/base/khash.h> +#include <hicn/core/listener.h> +#include <hicn/base/pool.h> + +#define _lt_var(x) _lt_var_##x + +#define key_hash(key) (hash(key, sizeof(listener_key_t))) +#define key_hash_eq(a, b) (key_hash(b) - key_hash(a)) + +KHASH_INIT(lt_name, const char *, unsigned, 0, str_hash, str_hash_eq); +KHASH_INIT(lt_key, listener_key_t *, unsigned, 0, key_hash, key_hash_eq); + +typedef struct { + kh_lt_key_t * id_by_key; + kh_lt_name_t * id_by_name; + listener_t * listeners; // pool +} listener_table_t; + +#define listener_table_allocate(TABLE, LISTENER, KEY, NAME) \ +do { \ + pool_get(table->listeners, (LISTENER)); \ + off_t _lt_var(id) = (LISTENER) - (TABLE)->listeners; \ + int _lt_var(res); \ + khiter_t _lt_var(k); \ + _lt_var(k) = kh_put_lt_name((TABLE)->id_by_name, (NAME), &_lt_var(res)); \ + kh_value((TABLE)->id_by_name, _lt_var(k)) = _lt_var(id); \ + \ + listener->type = (KEY)->type; \ + listener->address = (KEY)->address; \ + listener_key_t * _lt_var(key) = listener_get_key(LISTENER); \ + _lt_var(k) = kh_put_lt_key((TABLE)->id_by_key, _lt_var(key), &_lt_var(res));\ + kh_value((TABLE)->id_by_key, _lt_var(k)) = _lt_var(id); \ +} while(0) + +#define listener_table_deallocate(TABLE, LISTENER) \ +do { \ + const address_key_t * _lt_var(key) = listener_get_key(LISTENER); \ + khiter_t _lt_var(k); \ + _lt_var(k) = kh_get_ct_key((TABLE)->id_by_key, _lt_var(key)); \ + if (_lt_var(k) != kh_end((TABLE)>id_by_key)) \ + kh_del_ct_key((TABLE)->id_by_key, _lt_var(k)); \ + \ + const char * _lt_var(name) = listener_get_name(LISTENER); \ + _lt_var(k) = kh_get_ct_name((TABLE)->id_by_name, _lt_var(name)); \ + if (_lt_var(k) != kh_end((TABLE)->id_by_name)) \ + kh_del_ct_name((TABLE)->id_by_name, _lt_var(k)); \ + \ + pool_put((TABLE)->listeners, LISTENER); \ +} while(0) \ + + +#define listener_table_len(table) (pool_elts(table->listeners)) + +#define listener_table_validate_id(table, id) pool_validate_id(table->listeners, id) + +#define listener_table_at(table, id) ((table)->listeners + id) + +#define listener_table_get_by_id(table, id) \ + listener_table_validate_id(table, id) \ + ? listener_table_at(table, id) : NULL + +#define listener_table_get_listener_id(table, listener) (listener - table->listeners) + +#define listener_table_foreach(table, listener, BODY) \ + pool_foreach(table->listeners, listener, do { BODY } while(0) ) + +listener_table_t * listener_table_create(); +void listener_table_free(listener_table_t * table); + +listener_t * listener_table_get_by_address(listener_table_t * table, + face_type_t type, const address_t * address); + +listener_t * listener_table_get_by_name(listener_table_t * table, + const char *name); + +void listener_table_remove_by_id(listener_table_t * table, off_t id); + +unsigned listener_table_add(listener_table_t * table, listener_t * listener); + +#endif /* HICN_LISTENER_TABLE_H */ diff --git a/hicn-light/src/hicn/core/listener_vft.c b/hicn-light/src/hicn/core/listener_vft.c new file mode 100644 index 000000000..edaa0c264 --- /dev/null +++ b/hicn-light/src/hicn/core/listener_vft.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.c + * @brief Implementation of listener VFT + */ + +#include "listener_vft.h" + +extern listener_ops_t listener_hicn; +extern listener_ops_t listener_tcp; +extern listener_ops_t listener_udp; + +const listener_ops_t * listener_vft[] = { + [FACE_TYPE_HICN] = &listener_hicn, + [FACE_TYPE_TCP] = &listener_tcp, + [FACE_TYPE_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..2f70dd67d --- /dev/null +++ b/hicn-light/src/hicn/core/listener_vft.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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); + void (*read_callback)(listener_t * listener, int fd, void * data); + 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_callback = listener_ ## NAME ## _read_callback, \ + .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..4a254c701 100644 --- a/hicn-light/src/hicn/core/mapme.c +++ b/hicn-light/src/hicn/core/mapme.c @@ -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_send_to_nexthops(entry, nexthops) + * + * mapme_send_to_nexthop(entry, nexthop) + * A special case of the previous function when we only need to send to a + * single nexthop. This is because we might have some processing to do before + * iterating on nexthops (eg clear FIB) XXX TO BE CONFIRMED. + * + * mapme_maybe_send_to_nexthops(entry, nexthops) + * XXX Prev nexthops stored in FIB entry + * XXX this is valid for which prefixes ? + * + * mapme_send_to_all_nexthops + * + * */ #ifdef WITH_MAPME @@ -25,90 +117,123 @@ #include <stdio.h> // printf #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/msgbuf.h> #include <hicn/core/messagePacketType.h> // packet types #include <hicn/core/ticks.h> -#include <hicn/processor/fibEntry.h> -#include <hicn/processor/pitEntry.h> - -#include <parc/algol/parc_HashMap.h> -#include <parc/algol/parc_Iterator.h> -#include <parc/algol/parc_Unsigned.h> -#include <parc/assert/parc_Assert.h> +#include <hicn/core/fib_entry.h> +#include <hicn/core/pit.h> +#include <hicn/base/loop.h> +#include <hicn/util/log.h> #define MS2NS(x) x * 1000000 #define T2NS(x) forwarder_TicksToNanos(x) +//#define MAPME_ALLOW_NONEXISTING_FIB_ENTRY #define MAPME_DEFAULT_TU 5000 /* ms */ #define MAPME_DEFAULT_RETX 500 /* ms */ -#define MAX_RETX 3 +#define MAPME_DEFAULT_DISCOVERY false +#define MAPME_DEFAULT_PROTOCOL IPPROTO_IPV6 +#define MAPME_MAX_RETX 3 +#define MTU 1500 // XXX TODO Mutualize this define -#define NOT_A_NOTIFICATION false -#define NO_INGRESS 0 +#define DONT_QUEUE false #define TIMER_NO_REPEAT false -#define DO_DISCOVERY 1 #define MAPME_INVALID_DICOVERY_SEQ -1 +#define INIT_SEQ 0 -#define LOG_FACILITY LoggerFacility_Core +#define foreach_mapme_event \ + _(UNDEFINED) \ + _(FACE_ADD) \ + _(FACE_DEL) \ + _(NH_SET) \ + _(NH_ADD) \ + _(PH_ADD) \ + _(PH_DEL) \ + _(N) + +typedef enum { +#define _(x) MAPME_EVENT_ ## x, + foreach_mapme_event +#undef _ +} mapme_event_t; -#define LOG(mapme, log_level, fmt, ...) \ - do { \ - Logger *logger = forwarder_GetLogger(mapme->forwarder); \ - if (logger_IsLoggable(logger, LOG_FACILITY, log_level)) { \ - logger_Log(logger, LOG_FACILITY, log_level, __func__, fmt, \ - ##__VA_ARGS__); \ - } \ - } while (0) +/* + * We need a retransmission pool holding all necessary information for crafting + * special interests, thus including both the DPO and the prefix associated to + * it. + */ +#define NUM_RETX_ENTRIES 100 +#define NUM_RETX_SLOT 2 -#define WARN(mapme, fmt, ...) \ - LOG(mapme, PARCLogLevel_Warning, fmt, ##__VA_ARGS__) -#define ERR(mapme, fmt, ...) LOG(mapme, PARCLogLevel_Error, fmt, ##__VA_ARGS__) -#define INFO(mapme, fmt, ...) LOG(mapme, PARCLogLevel_Info, fmt, ##__VA_ARGS__) -#define DEBUG(mapme, fmt, ...) \ - LOG(mapme, PARCLogLevel_Debug, fmt, ##__VA_ARGS__) +typedef struct { + hicn_prefix_t prefix; + fib_entry_t * entry; + uint8_t retx_count; // Number of retransmissions since last tfib addition +} mapme_retx_t; /** * MAP-Me state data structure */ -struct mapme { - uint32_t retx; /* ms */ - uint32_t Tu; /* ms */ - bool removeFibEntries; +struct mapme_s { + /* Options XXX mapme_conf_t ! */ + uint32_t retx; /* retx timeout (in ms) */ + uint32_t timescale; /* timescale (in ms) */ + bool discovery; /* discovery flag */ + int protocol; - Forwarder *forwarder; + /* + * Retransmissions + * Lite calendar queue with NUM_RETX_SLOT slots + */ + int timer_fd; + mapme_retx_t retx_array[NUM_RETX_SLOT][NUM_RETX_ENTRIES]; + uint8_t retx_len[NUM_RETX_SLOT]; + uint8_t cur; + uint8_t idle; + + forwarder_t * forwarder; }; -static MapMe MapMeDefault = {.retx = MAPME_DEFAULT_RETX, - .Tu = MAPME_DEFAULT_TU, - .removeFibEntries = false}; +#define NEXT_SLOT(CUR) (1-CUR) +#define CUR mapme->retx_array[mapme->cur] +#define NXT mapme->retx_array[NEXT_SLOT(mapme->cur)] +#define CURLEN mapme->retx_len[mapme->cur] +#define NXTLEN mapme->retx_len[NEXT_SLOT(mapme->cur)] + +static mapme_t mapme_default = { + .retx = MAPME_DEFAULT_RETX, + .timescale = MAPME_DEFAULT_TU, + .discovery = MAPME_DEFAULT_DISCOVERY, + .protocol = MAPME_DEFAULT_PROTOCOL, + + .timer_fd = -1, +// .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)); - - (*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; -ERR_MALLOC: - return false; + return mapme; } -void mapme_free(MapMe *mapme) +void mapme_free(mapme_t * mapme) { free(mapme); } @@ -117,191 +242,37 @@ void mapme_free(MapMe *mapme) * TFIB ******************************************************************************/ -#define INVALID_SEQ 0 -#define INIT_SEQ 0 typedef struct { - uint32_t seq; - PARCHashMap *nexthops; - /* Update/Notification heuristic */ - Ticks lastAckedUpdate; -} MapMeTFIB; - -static MapMeTFIB *mapmeTFIB_Create() { - MapMeTFIB *tfib; - tfib = malloc(sizeof(MapMeTFIB)); - if (!tfib) goto ERR_MALLOC; - tfib->seq = INIT_SEQ; - tfib->lastAckedUpdate = 0; - tfib->nexthops = parcHashMap_Create(); - if (!tfib->nexthops) goto ERR_HASHMAP; - - 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); - free(tfib); - *tfibPtr = NULL; -} - -/** - * @function mapme_CreateTFIB - * @abstract Associate a new TFIB entry to a FIB entry. - * @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); - - tfib = mapmeTFIB_Create(); - fibEntry_setUserData(fibEntry, tfib, (void (*)(void **))mapmeTFIB_Release); -} - -#define TFIB(fibEntry) ((MapMeTFIB *)fibEntry_getUserData(fibEntry)) - -static const PARCEventTimer *mapmeTFIB_Get(const MapMeTFIB *tfib, - unsigned conn_id) { - const PARCEventTimer *timer; - const PARCBuffer *buffer; - PARCUnsigned *cid = parcUnsigned_Create(conn_id); - buffer = parcHashMap_Get(tfib->nexthops, cid); - if (!buffer) return NULL; - PARCByteArray *array = parcBuffer_Array(buffer); - timer = *((PARCEventTimer **)parcByteArray_Array(array)); - parcUnsigned_Release(&cid); - return timer; -} + // 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; + nexthops_t nexthops; // XXX useless shadow structure + /* Update/Notification heuristic */ + Ticks last_acked_update; +} mapme_tfib_t; + +#define TFIB(FIB_ENTRY) ((mapme_tfib_t * )fib_entry_get_user_data(FIB_ENTRY)) -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); -} - -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); - - size_t size = (params->protocol == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN - : HICN_MAPME_V4_HDRLEN; - uint8_t *icmp_pkt = parcMemory_AllocateAndClear(size); - - 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; - } - - INFO(mapme, "[MAP-Me] Creating MAP-Me packet"); - size_t len = hicn_mapme_create_packet(icmp_pkt, &prefix, params); - if (len == 0) { - ERR(mapme, "[MAP-Me] Failed to create mapme packet through lib"); - goto ERR_CREATE; - } - - // hicn_packet_dump(icmp_pkt, MAPME_HDRLEN); - - return message_CreateFromByteArray(NO_INGRESS, icmp_pkt, - MessagePacketType_Interest, now, logger); - -ERR_CREATE: -ERR_NAME: - return NULL; -} - -static Message *mapme_createAckMessage(const MapMe *mapme, - const uint8_t *msgBuffer, - const mapme_params_t *params) { - Ticks now = forwarder_GetTicks(mapme->forwarder); - Logger *logger = 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; - } - - return message_CreateFromByteArray( - NO_INGRESS, icmp_pkt, MessagePacketType_ContentObject, now, logger); +void +mapme_tfib_initialize(mapme_tfib_t * tfib) +{ + tfib->seq = INIT_SEQ; + tfib->last_acked_update = 0; + nexthops_set_len(&tfib->nexthops, 0); } -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); +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); - 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); + /* The name length will be equal to ip address' prefix length */ + return hicn_prefix_create_from_ip_prefix(&ip_prefix, prefix); } /** @@ -310,369 +281,204 @@ static void mapme_setFacePendingCallback(int fd, PARCEventType which_event, * NOTE: IN are currently disabled until the proper placeholder is agreed in the * interest header. */ -static hicn_mapme_type_t mapme_getTypeFromHeuristic(const MapMe *mapme, - FibEntry *fibEntry) { +static +hicn_mapme_type_t +mapme_get_type_from_heuristic(const mapme_t * mapme, fib_entry_t * entry) +{ + if (fib_entry_has_local_nexthop(entry)) + /* We are a producer for this entry, send update */ + return UPDATE; + #if 0 /* interplay of IU/IN */ - if (TFIB(fibEntry)->lastAckedUpdate == 0) { + if (TFIB(fib_entry)->lastAckedUpdate == 0) { return UPDATE; } else { - Ticks interval = now - TFIB(fibEntry)->lastAckedUpdate; - return (T2NS(interval) > MS2NS(mapme->Tu)) ? UPDATE : NOTIFICATION; + Ticks interval = now - TFIB(fib_entry)->lastAckedUpdate; + return (T2NS(interval) > MS2NS(mapme->timescale)) ? UPDATE : NOTIFICATION; } #else /* Always send IU */ - return UPDATE; + 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; - - INFO(mapme, "[MAP-Me] SetFacePending connection=%d prefix=XX retx=%d", - conn_id, num_retx); - - /* 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; - - /* Safeguard during retransmissions */ - if (!TFIB(fibEntry)) - return true; - - /* - * On the producer side, we have to clear the TFIB everytime we change the list - * of adjacencies, otherwise retransmissions will occur to preserve them. - */ - if (clear_tfib) { - /* - * It is likely we cannot iterator and remove elements from the hashmap at - * the same time, so we proceed in two steps - */ - if (parcHashMap_Size(TFIB(fibEntry)->nexthops) > 0) { - - 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); - } - } - - // 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) { + +/** + * + * Here nexthops is not necessarily FIB nexthops as we might advertise given FIB + * entries on various other connections. + */ +/* NOTE: if the face is pending an we receive an IN, maybe we should not cancel + * the timer + */ +// XXX Make sure this function is never called for Notifications +// XXX overall review notification code and integrate it in VPP +int +mapme_send_to_nexthops(const mapme_t * mapme, fib_entry_t * entry, + const nexthops_t * nexthops) +{ + mapme_tfib_t * tfib = TFIB(entry); + + tfib->seq++; + + const Name *name = fib_entry_get_prefix(entry); + + char *name_str = name_ToString(name); + DEBUG("sending IU/IN for name %s on all nexthops", name_str); + free(name_str); + 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; + .protocol = mapme->protocol, + .type = mapme_get_type_from_heuristic(mapme, entry), + .seq = tfib->seq, + }; + + hicn_prefix_t prefix; + if (hicn_prefix_from_name(name, &prefix) < 0) { + ERROR("Failed to create lib's name"); + 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"); + uint8_t packet[MTU]; + size_t size = hicn_mapme_create_packet(packet, &prefix, ¶ms); + if (size <= 0) { + ERROR("Could not create MAP-Me packet"); + return -1; } - 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; - } - - 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); - } - 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; -} + /* + * We used to clear TFIB everytime which is wrong. + * XXX When to clear TFIB ?? + * + * On the producer side, we have to clear the TFIB everytime we change the list + * of adjacencies, otherwise retransmissions will occur to preserve them. + */ -/*------------------------------------------------------------------------------ - * Event handling - *----------------------------------------------------------------------------*/ + nexthops_clear(&tfib->nexthops); -/* - * 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; + connection_table_t * table = forwarder_get_connection_table(mapme->forwarder); + + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + DEBUG("sending packet on connection %d", nexthop); + const connection_t * conn = connection_table_get_by_id(table, nexthop); + connection_send_packet(conn, packet, size); + }); + + return 0; } -void -mapme_send_updates(const MapMe * mapme, FibEntry * fibEntry, const NumberSet * nexthops) +int +mapme_send_to_nexthop(const mapme_t * mapme, fib_entry_t * entry, unsigned nexthop) { - 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; - } - free(name_str); + nexthops_t nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, nexthop); + + return mapme_send_to_nexthops(mapme, entry, &nexthops); } +/** + * + * Here nexthops is not necessarily FIB nexthops as we might advertise given FIB + * entries on various other connections. + */ void -mapme_maybe_send_updates(const MapMe * mapme, FibEntry * fibEntry, const NumberSet * nexthops) +mapme_maybe_send_to_nexthops(const mapme_t * mapme, fib_entry_t * fib_entry, + const nexthops_t * nexthops) { - /* Detect change */ - NumberSet * previous_nexthops = fibEntry_GetPreviousNextHops(fibEntry); - if (numberSet_Equals(nexthops, previous_nexthops)) { - INFO(mapme, "[MAP-Me] No change in nexthops"); - return; - } - fibEntry_SetPreviousNextHops(fibEntry, nexthops); - - mapme_send_updates(mapme, fibEntry, nexthops); + /* Detect change */ + if (!fib_entry_nexthops_changed(fib_entry)) { + INFO("No change in nexthops"); + return; + } + fib_entry_set_prev_nexthops(fib_entry); + + mapme_send_to_nexthops(mapme, fib_entry, nexthops); } void -mapme_reconsiderFibEntry(const MapMe *mapme, FibEntry * fibEntry) +mapme_send_to_all_nexthops(const mapme_t *mapme, fib_entry_t * entry) { - /* - * 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; + /* Apply the policy of the fib_entry over all neighbours */ + nexthops_t new_nexthops; + nexthops_t * nexthops = fib_entry_get_available_nexthops(entry, ~0, &new_nexthops); - /* Apply the policy of the fibEntry over all neighbours */ - NumberSet * available_nexthops = fibEntry_GetAvailableNextHops(fibEntry, ~0); - - /* Advertise prefix on all available next hops (if needed) */ - mapme_send_updates(mapme, fibEntry, available_nexthops); - - numberSet_Release(&available_nexthops); + /* Advertise prefix on all available next hops (if needed) */ + mapme_maybe_send_to_nexthops(mapme, entry, nexthops); } /* * Callback called everytime a new connection is created by the control protocol */ void -mapme_onConnectionEvent(const MapMe *mapme, const Connection *conn_added, connection_event_t event) { - /* 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; - - unsigned conn_added_id = connection_GetConnectionId(conn_added); - switch(event) { - case CONNECTION_EVENT_CREATE: - INFO(mapme, "[MAP-Me] Connection %d got created", conn_added_id); - break; - case CONNECTION_EVENT_DELETE: - INFO(mapme, "[MAP-Me] Connection %d got deleted", conn_added_id); - break; - case CONNECTION_EVENT_UPDATE: - INFO(mapme, "[MAP-Me] 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; - case CONNECTION_EVENT_SET_DOWN: - INFO(mapme, "[MAP-Me] 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; - case CONNECTION_EVENT_PRIORITY_CHANGED: - INFO(mapme, "[MAP-Me] Connection %d changed priority to %d", - conn_added_id, connection_GetPriority(conn_added)); - break; +mapme_on_connection_event(const mapme_t *mapme, const connection_t * conn_added, connection_event_t event) { + /* 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_is_local(conn_added)) + return; + + unsigned conn_added_id = connection_get_id(conn_added); + switch(event) { + case CONNECTION_EVENT_CREATE: + INFO("Connection %d got created", conn_added_id); + break; + case CONNECTION_EVENT_DELETE: + INFO("Connection %d got deleted", conn_added_id); + break; + case CONNECTION_EVENT_UPDATE: + INFO("Connection %d got updated", conn_added_id); + break; + case CONNECTION_EVENT_SET_UP: + INFO("Connection %d went up", conn_added_id); + break; + case CONNECTION_EVENT_SET_DOWN: + INFO("Connection %d went down", conn_added_id); + break; + case CONNECTION_EVENT_TAGS_CHANGED: + INFO("Connection %d changed tags", conn_added_id); + break; + case CONNECTION_EVENT_PRIORITY_CHANGED: + INFO("Connection %d changed priority to %d", + conn_added_id, connection_get_priority(conn_added)); + break; + } } - } - - /* We need to send a MapMe update on the newly selected connections for - * each concerned fibEntry : connection is involved, or no more involved */ - FibEntryList *fiblist = forwarder_GetFibEntries(mapme->forwarder); - - /* Iterate a first time on the FIB to get the locally served prefixes */ - for (size_t i = 0; i < fibEntryList_Length(fiblist); i++) { - FibEntry *fibEntry = (FibEntry *)fibEntryList_Get(fiblist, i); - mapme_reconsiderFibEntry(mapme, fibEntry); - } - - fibEntryList_Destroy(&fiblist); - - INFO(mapme, "[MAP-Me] Done"); -} -#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; - - unsigned conn_selected_id = connection_GetConnectionId(conn_selected); - INFO(mapme, "[MAP-Me] New connection %d", conn_selected_id); - - const Name *name = fibEntry_GetPrefix(fibEntry); - - /* Skip entries that have no local connection as next hop */ - if (!mapme_hasLocalNextHops(mapme, fibEntry)) - return; - - /* 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++; + /* We need to send a MapMe update on the newly selected connections for + * each concerned fib_entry : connection is involved, or no more involved */ + const fib_t * fib = forwarder_get_fib(mapme->forwarder); + fib_entry_t * entry; + fib_foreach_entry(fib, entry, { + if (!fib_entry_has_local_nexthop(entry)) + continue; + /* + * On the producer side, we have to clear the TFIB everytime we change + * the list of adjacencies, otherwise retransmissions will occur to + * preserve them. + */ + mapme_tfib_t * tfib = TFIB(entry); + nexthops_clear(&tfib->nexthops); - 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); + mapme_send_to_all_nexthops(mapme, entry); + }); - mapme_setFacePending(mapme, name, fibEntry, conn_selected_id, true, true, true, 0); + INFO("Done"); } -#endif /* WITH_POLICY */ -#endif /*------------------------------------------------------------------------------ * Special Interest handling *----------------------------------------------------------------------------*/ -/** - * @discussion This function is way too long and should be cut out - */ -static bool mapme_onSpecialInterest(const MapMe *mapme, - const uint8_t *msgBuffer, - unsigned conn_in_id, hicn_prefix_t *prefix, - mapme_params_t *params) { - const ConnectionTable *table = forwarder_GetConnectionTable(mapme->forwarder); - /* The cast is needed since connectionTable_FindById miss the - * const qualifier for the first parameter */ - const Connection *conn_in = - connectionTable_FindById((ConnectionTable *)table, conn_in_id); - seq_t fibSeq, seq = params->seq; - bool send = (params->type == UPDATE); - bool rv; - - Name *name = name_CreateFromPacket(msgBuffer, MessagePacketType_Interest); - name_setLen(name, prefix->len); - char *name_str = name_ToString(name); - INFO(mapme, - "[MAP-Me] Ack'ed Special Interest on connection %d - prefix=%s type=XX " - "seq=%d", - conn_in_id, name_str, seq); - free(name_str); - - /* - * Immediately send an acknowledgement back on the ingress connection - * We always ack, even duplicates. - */ - 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); - - 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); +#ifdef MAPME_ALLOW_NONEXISTING_FIB_ENTRY +int +mapme_create_fib_entry(const mapme_t * mapme, const Name * name, unsigned ingress_id) +{ + INFO(" - Re-creating FIB entry with next hop on connection %d", + ingress_id); /* * This might happen for a node hosting a producer which has moved. * Destroying the face has led to removing all corresponding FIB @@ -686,17 +492,16 @@ static bool mapme_onSpecialInterest(const MapMe *mapme, * the message should be propagated. */ #ifdef WITH_POLICY - fibEntry = fibEntry_Create(name, fwdStrategy, mapme->forwarder); + entry = fib_entry_Create(name, fwdStrategy, mapme->forwarder); #else - fibEntry = fibEntry_Create(name, fwdStrategy); + entry = fib_entry_Create(name, fwdStrategy); #endif /* WITH_POLICY */ - FibEntry *lpm = fib_MatchName(fib, name); - mapme_CreateTFIB(fibEntry); - fib_Add(fib, fibEntry); + fib_entry_t *lpm = fib_MatchName(fib, name); + fib_Add(fib, entry); if (!lpm) { - TFIB(fibEntry)->seq = seq; - fibEntry_AddNexthop(fibEntry, conn_in_id); - return true; + TFIB(entry)->seq = seq; + fib_entry_AddNexthop(entry, ingress_id); + return true; } /* @@ -704,279 +509,387 @@ static bool mapme_onSpecialInterest(const MapMe *mapme, * the more specific name, and proceed as usual. Worst case we clone the * default route... */ - const NumberSet *lpm_nexthops = fibEntry_GetNexthops(lpm); + const NumberSet *lpm_nexthops = fib_entry_nexthops_get(lpm); for (size_t i = 0; i < numberSet_Length(lpm_nexthops); i++) { - fibEntry_AddNexthop(fibEntry, numberSet_GetItem(lpm_nexthops, i)); + fib_entry_AddNexthop(entry, numberSet_GetItem(lpm_nexthops, i)); } + return 0; +} #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); - } - - /* - * In case of multihoming, we might receive a message about our own prefix, we - * should never take it into account, nor send the IU backwards as a sign of - * outdated propagation. - * - * 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; - } - - 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); - } - /* nextHops -> prevHops +void +mapme_on_timeout(mapme_t * mapme, int fd, void * data) +{ + assert(mapme); + assert(!data); + /* Timeout occurred, we have to retransmit IUs for all pending + * prefixes having entries in TFIB * - * We add to the list of pendingUpdates the current next hops, and - * eventually forward them an IU too. + * timeouts are slotted + * | | | | * - * 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. + * ^ + * +- event occurred + * new face, wait for the second next + * (having two arrays and swapping cur and next) + * retx : put in next */ - const NumberSet *nexthops_old = fibEntry_GetNexthops(fibEntry); + mapme->idle += 1; - /* We make a copy to be able to send IU _after_ updating next hops */ - NumberSet *nexthops = numberSet_Create(); - numberSet_AddSet(nexthops, nexthops_old); + for (uint8_t pos = 0; pos < CURLEN; pos++) { + mapme_retx_t * retx = &CUR[pos]; - /* 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. - * - * 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 - */ + if (!retx->entry) /* deleted entry */ + continue; + + mapme_tfib_t * tfib = TFIB(retx->entry); + assert(tfib); + + /* Re-send interest for all entries */ + mapme_send_to_all_nexthops(mapme, retx->entry); - 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); + 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); + } } - 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); + /* 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_unregister_timer(MAIN_LOOP, mapme->timer_fd); + mapme->timer_fd = -1; } - 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; - } - - 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; +} + +static +void +mapme_on_event(mapme_t * mapme, mapme_event_t event, fib_entry_t * entry, + unsigned ingress_id) +{ + switch (event) { +#if 0 + case HICN_MAPME_EVENT_FACE_ADD: + { + /* + * A face has been added: + * - In case of a local app face, we need to advertise a new prefix + * - For another local face type, we need to advertise local + * prefixes and schedule retransmissions + */ + mapme_retx_t *retx_events = event_data; + for (uint8_t i = 0; i < vec_len (retx_events); i++) { + hicn_mapme_on_face_added(mapme, retx_events[i].dpo); + } + + if (mapme->timer_fd == -1) + mapme->timer_fd = loop_register_timer(MAIN_LOOP, + mapme->retx, mapme, mapme_on_timeout, NULL); + mapme->idle = 0; + break; + } + case HICN_MAPME_EVENT_FACE_DEL: + if (mapme->timer_fd == -1) + mapme->timer_fd = loop_register_timer(MAIN_LOOP, + DEFAULT_TIMEOUT, mapme, mapme_on_timeout, NULL); + mapme->idle = 0; + break; +#endif + + case MAPME_EVENT_NH_SET: + /* + * An hICN FIB entry has been modified. All operations so far + * have been procedded in the nodes. Here we need to track + * retransmissions upon timeout: we mark the FIB entry as pending in + * the second-to-next slot + */ + + /* + * XXX Move this in doc + * + * The FIB entry has a new next hop, and its TFIB section has: + * - eventually previous prev hops for which a IU with a + * lower seqno has been sent + * - the prev hops that have just been added. + * + * We don't distinguish any and just send an updated IU to all + * of them. The retransmission of the latest IU to all + * facilitates the matching of ACKs to a single seqno which is + * the one stored in the FIB. + * + * Since we retransmit to all prev hops, we can remove this + * (T)FIB entry for the check at the end of the current slot. + */ + + /* Mark FIB entry as pending for second-to-next slot */ + /* + * Transmit IU for all TFIB entries with latest seqno (we have + * at least one for sure!) + */ + mapme_send_to_all_nexthops(mapme, entry); + + /* 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 (mapme->timer_fd == -1) + mapme->timer_fd = loop_register_timer(MAIN_LOOP, + mapme->retx, mapme, mapme_on_timeout, NULL); + mapme->idle = 0; + break; + + case MAPME_EVENT_NH_ADD: + /* + * XXX move this in doc + * + * As per the description of states, this event should add the face + * to the list of next hops, and eventually remove it from TFIB. + * This corresponds to the multipath case. + * + * In all cases, we assume the propagation was already done when the first + * interest with the same sequence number was received, so we stop here + * No change in TFIB = no IU to send + * + * No change in timers. + */ + + // XXX useless +#if 0 + /* Add ingress face as next hop */ + idle = 0; +#endif + break; + + case MAPME_EVENT_PH_ADD: + /* Back-propagation, interesting even for IN (desync) */ + mapme_send_to_nexthop(mapme, entry, ingress_id); + + mapme->idle = 0; + if (mapme->timer_fd == -1) + mapme->timer_fd = loop_register_timer(MAIN_LOOP, + mapme->retx, mapme, mapme_on_timeout, NULL); + 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; + } +} - /* - * The update is completed when the IU could not be sent to any - * other next hop. - */ - if (complete) INFO(mapme, "[MAP-Me] - Update completed !"); +static +void +mapme_on_interest(mapme_t * mapme, uint8_t * packet, + unsigned ingress_id, hicn_prefix_t * prefix, mapme_params_t * params) +{ + connection_table_t * table = forwarder_get_connection_table(mapme->forwarder); - numberSet_Release(&nexthops); + /* The cast is needed since connectionTable_FindById miss the + * const qualifier for the first parameter */ + const connection_t * conn_in = connection_table_get_by_id(table, ingress_id); - } else if (seq == fibSeq) { /* - * Multipath, multihoming, multiple producers or duplicate interest - * - * 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 - * - * It might happen that the previous AP has still a connection to the - * producer and that we received back our own IU. In that case, we just - * need to Ack and ignore it. + * Immediately send an acknowledgement back on the ingress connection + * We always ack, even duplicates. */ -#if 0 - if (mapme_hasLocalNextHops(mapme, fibEntry)) { - INFO(mapme, "[MAP-Me] - Received original interest... Update complete"); - return true; + size_t size = hicn_mapme_create_ack(packet, params); + if (connection_send_packet(conn_in, packet, size) < 0) { + /* We accept the packet knowing we will get a retransmit */ + ERROR("Failed to send ACK packet"); } + + Name *name = name_CreateFromPacket(packet, MESSAGE_TYPE_INTEREST); + name_setLen(name, prefix->len); + + char *name_str = name_ToString(name); + DEBUG("Ack'ed interest : connection=%d prefix=%s seq=%d", ingress_id, + name_str, params->seq); + free(name_str); + + /* EPM on FIB */ + const fib_t * fib = forwarder_get_fib(mapme->forwarder); + fib_entry_t * entry = fib_contains(fib, name); + if (!entry) { +#ifdef HICN_MAPME_ALLOW_NONEXISTING_FIB_ENTRY + if (mapme_create_fib_entry(mapme, name, ingress_id) < 0) { + ERROR("Failed to create FIB entry"); + return; + } +#else + INFO("Ignored update with no FIB entry"); + return; #endif + } - INFO(mapme, "[MAP-Me] - Adding multipath next hop on connection %d", - conn_in_id); - fibEntry_AddNexthop(fibEntry, conn_in_id); + mapme_tfib_t * tfib = TFIB(entry); + assert(tfib); - } else { // seq < fibSeq /* - * 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. + * In case of multihoming, we might receive a message about our own prefix, we + * should never take it into account, nor send the IU backwards as a sign of + * outdated propagation. + * + * Detection: we receive a message initially sent by ourselves, ie a message + * for which the prefix has a local next hop in the FIB. */ - INFO( - mapme, - "[MAP-Me] - Update interest %d -> %d sent backwards on connection %d", - seq, fibSeq, conn_in_id); - mapme_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry, - conn_in_id, send, false, false, 0); - } - - return true; - -ERR_ACK_SEND: - message_Release(&ack); -ERR_ACK_CREATE: - return false; -} + // XXX NOT IN VPP ? + if (fib_entry_has_local_nexthop(entry)) { + INFO("Received original interest... Update complete"); + return; + } -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) { - 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 + mapme_event_t event = MAPME_EVENT_UNDEFINED; + if (params->seq > tfib->seq) { + DEBUG("seq %d > fib_seq %d, updating seq and next hops", params->seq, + tfib->seq); + /* 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; + + /* + * Move nexthops to TFIB... but ingress_id that lands in nexthops + * + * This could might optimized for situations where nothing changes, but + * this is very unlikely if not impossible... + * */ + unsigned prevhop; + nexthops_foreach(&entry->nexthops, prevhop, { + nexthops_add(&tfib->nexthops, prevhop); + }); + nexthops_remove(&tfib->nexthops, ingress_id); + nexthops_add(&tfib->nexthops, ingress_id); + + event = MAPME_EVENT_NH_SET; + + // 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 + * + * 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 + * + * It might happen that the previous AP has still a connection to the + * producer and that we received back our own IU. In that case, we just + * need to Ack and ignore it. */ + 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); + + event = MAPME_EVENT_NH_ADD; - INFO(mapme, - "[MAP-Me] - Ignored special interest Ack with seq=%u, expected %u", - seq, fibSeq); - return; + } 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. + */ + DEBUG("params.seq %d < fib_seq %d, sending backwards on face %d", params->seq, tfib->seq, ingress_id); + nexthops_remove(&entry->nexthops, ingress_id); + nexthops_add(&tfib->nexthops, ingress_id); + + event = MAPME_EVENT_PH_ADD; } - } - - /* - * 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 - */ - if (!TFIB(fibEntry)) { - INFO(mapme, "[MAP-Me] - Ignored ACK for prefix with no TFIB entry"); - return; - } - - PARCEventTimer *timer = - (PARCEventTimer *)mapmeTFIB_Get(TFIB(fibEntry), conn_in_id); - if (!timer) { - INFO(mapme, - "[MAP-Me] - Ignored ACK for prefix not having the Connection in " - "TFIB entry. Possible duplicate ?"); - 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); - - /* 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); - } + + /* Don't trigger events for notification unless we need to send interests backwards */ + if ((params->type != UPDATE) && (event != MAPME_EVENT_PH_ADD)) + return; + + mapme_on_event(mapme, event, entry, ingress_id); } -/*----------------------------------------------------------------------------- - * Overloaded functions - *----------------------------------------------------------------------------*/ +static +void +mapme_on_data(mapme_t *mapme, const uint8_t * packet, + unsigned ingress_id, hicn_prefix_t *prefix, + mapme_params_t * params) +{ + INFO("Receive IU/IN Ack on connection %d", ingress_id); -/* - * @abstract returns where to forward a normal interests(nexthops) defined by - * mapme, it also set the sequnence number properly if needed - */ + const Name * name = + name_CreateFromPacket(packet, MESSAGE_TYPE_DATA); + name_setLen((Name*) name, prefix->len); -/****************************************************************************** - * Public functions (exposed in the .h) - ******************************************************************************/ + char * name_str = name_ToString(name); + DEBUG("Received ack for name prefix=%s seq=%d on conn id=%d", + name_str, params->seq, ingress_id); + free(name_str); -/* - * 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; - } + const fib_t * fib = forwarder_get_fib(mapme->forwarder); + fib_entry_t * entry = fib_contains(fib, name); + if (!entry) { + INFO("Ignored ACK with no corresponding FIB entry"); + return; + } + mapme_tfib_t * tfib = TFIB(entry); + + /* + * As we always retransmit IU with the latest seq, we are not interested in + * ACKs with inferior seq + */ + if (params->seq < tfib->seq) { + INFO("Ignored ACK with seq %d < %d", params->seq, tfib->seq); + return; + } + + 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(" - Updating LastAckedUpdate"); + tfib->last_acked_update = ticks_now(); + } } /** @@ -990,25 +903,53 @@ 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) { - hicn_prefix_t prefix; - mapme_params_t params; - hicn_mapme_parse_packet(msgBuffer, &prefix, ¶ms); - - switch (params.type) { - case UPDATE: - case NOTIFICATION: - mapme_onSpecialInterest(mapme, msgBuffer, conn_id, &prefix, ¶ms); - break; - case UPDATE_ACK: - case NOTIFICATION_ACK: - mapme_onSpecialInterestAck(mapme, msgBuffer, conn_id, &prefix, ¶ms); - break; - default: - ERR(mapme, "[MAP-Me] Unknown message"); - break; - } +void +mapme_process(mapme_t *mapme, uint8_t *packet, unsigned conn_id) +{ + hicn_prefix_t prefix; + mapme_params_t params; + int rc = hicn_mapme_parse_packet(packet, &prefix, ¶ms); + if (rc < 0) + return; + + // XXX TYPE STR + DEBUG("Received interest type:%d seq:%d len:%d", params.type, params.seq, prefix.len); + + // XXX RENAME TYPES + switch (params.type) { + case UPDATE: + case NOTIFICATION: + mapme_on_interest(mapme, packet, conn_id, &prefix, ¶ms); + break; + case UPDATE_ACK: + case NOTIFICATION_ACK: + mapme_on_data(mapme, packet, conn_id, &prefix, ¶ms); + break; + default: + ERROR("Unknown message"); + break; + } } +/* + * Returns true iif the message corresponds to a MAP-Me packet + */ +bool mapme_match_packet(const uint8_t *packet) { + hicn_mapme_header_t * mapme = (hicn_mapme_header_t*)packet; + + switch(HICN_IP_VERSION(packet)) { + case 4: + if (mapme->v4.ip.protocol != IPPROTO_ICMP) + return false; + return HICN_IS_MAPME(mapme->v4.icmp_rd.type, mapme->v4.icmp_rd.code); + case 6: + if (mapme->v6.ip.nxt != IPPROTO_ICMPV6) + return false; + return HICN_IS_MAPME(mapme->v6.icmp_rd.type, mapme->v6.icmp_rd.code); + default: + return false; + } +} + + #endif /* WITH_MAPME */ diff --git a/hicn-light/src/hicn/core/mapme.h b/hicn-light/src/hicn/core/mapme.h index 72f8d536a..2bf5a413b 100644 --- a/hicn-light/src/hicn/core/mapme.h +++ b/hicn-light/src/hicn/core/mapme.h @@ -27,28 +27,27 @@ #include <stdint.h> #include <hicn/hicn.h> -#include <hicn/core/forwarder.h> #include <hicn/core/connection.h> #include <hicn/utils/commands.h> +#include <hicn/core/fib_entry.h> -struct mapme; -typedef struct mapme MapMe; +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 +55,50 @@ 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, uint8_t * packet, unsigned conn_id); + +int mapme_send_to_nexthop(const mapme_t * mapme, fib_entry_t * fib_entry, unsigned nexthop); /** * @function mapme_send_updates * @abstract Trigger (if needed) the update for specified FIB entry and nexthops * @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] nexthops - NumberSet holding the next hops on which to send the * update. */ -void mapme_send_updates(const MapMe * mapme, FibEntry * fibEntry, const NumberSet * nexthops); +int mapme_send_to_nexthops(const mapme_t * mapme, fib_entry_t * entry, + const nexthops_t * nexthops); /** * @function mapme_send_updates * @abstract Trigger the update for specified FIB entry and nexthops, only if needed * @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] nexthops - NumberSet holding the next hops on which to send the * update. */ -void mapme_maybe_send_updates(const MapMe * mapme, FibEntry * fibEntry, const NumberSet * nexthops); +void mapme_maybe_send_to_nexthops(const mapme_t * mapme, fib_entry_t * fib_entry, const nexthops_t * nexthops); /** - * @function mapme_reconsiderFibEntry + * @function mapme_reconsiderfib_entry_t * @abstract Process a fib entry for changes that might trigger new updates * @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 */ -void mapme_reconsiderFibEntry(const MapMe *mapme, FibEntry * fibEntry); +void mapme_send_to_all_nexthops(const mapme_t *mapme, fib_entry_t * fib_entry); /** - * @function mapme_onConnectionEvent + * @function mapme_on_connection_event * @abstract Callback following the addition of the face though the control * protocol. * @discussion This callback triggers the sending of control packets by MAP-Me. @@ -105,15 +106,16 @@ 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); +nexthops_t * mapme_get_nexthops(const mapme_t *mapme, fib_entry_t *fib_entry, + const msgbuf_t *interest); hicn_mapme_type_t mapme_PktType_To_LibHicnPktType(MessagePacketType type); 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 index a8b2a3e54..e0eef5e7c 100644 --- a/hicn-light/src/hicn/core/messageHandler.h +++ b/hicn-light/src/hicn/core/messageHandler.h @@ -19,11 +19,13 @@ #include <stdlib.h> #ifndef _WIN32 #include <unistd.h> // close -#endif +#endif /* _WIN32 */ #include <hicn/hicn.h> #include <hicn/core/messagePacketType.h> +//#include <hicn/core/connection_table.h> + #define H(packet) ((hicn_header_t *)packet) #define H6(packet) (H(packet)->v6.ip) #define H6T(packet) (H(packet)->v6.tcp) @@ -53,17 +55,12 @@ #define IPV6_DEFAULT_TRAFFIC_CLASS 0 #define IPV6_DEFAULT_FLOW_LABEL 0 -#define expected_lbl wldr_notification_lbl.expected_lbl -#define received_lbl wldr_notification_lbl.received_lbl - -#include <hicn/core/forwarder.h> +//#include <hicn/core/forwarder.h> -#ifdef WITH_MAPME -#include <hicn/core/mapme.h> -#include <hicn/socket/api.h> -#endif /* WITH_MAPME */ - -#define CONNECTION_ID_UNDEFINED -1 +//#ifdef WITH_MAPME +//#include <hicn/core/mapme.h> +//#include <hicn/socket/api.h> +//#endif /* WITH_MAPME */ #define BFD_PORT 3784 @@ -157,6 +154,7 @@ static inline size_t messageHandler_GetIPHeaderLength(unsigned ipVersion) { return 0; } +#if 0 static inline bool messageHandler_IsValidHicnPacket(const uint8_t *message) { uint8_t version = messageHandler_GetIPPacketType(message); if (version == IPv6_TYPE || version == IPv4_TYPE) { @@ -164,6 +162,7 @@ static inline bool messageHandler_IsValidHicnPacket(const uint8_t *message) { } return false; } +#endif static inline uint8_t messageHandler_NextHeaderType(const uint8_t *message) { switch (messageHandler_GetIPPacketType(message)) { @@ -176,155 +175,6 @@ static inline uint8_t messageHandler_NextHeaderType(const uint8_t *message) { } } -/* Forward declarations */ -static inline void * messageHandler_GetSource(const uint8_t *message); -static inline void *messageHandler_GetDestination(const uint8_t *message); - -static const -AddressPair * -_createRecvAddressPairFromPacket(const uint8_t *msgBuffer) { - Address *packetSrcAddr = NULL; /* This one is in the packet */ - Address *localAddr = NULL; /* This one is to be determined */ - - if (messageHandler_GetIPPacketType(msgBuffer) == IPv6_TYPE) { - struct sockaddr_in6 addr_in6; - addr_in6.sin6_family = AF_INET6; - addr_in6.sin6_port = htons(1234); - addr_in6.sin6_flowinfo = 0; - addr_in6.sin6_scope_id = 0; - memcpy(&addr_in6.sin6_addr, - (struct in6_addr *)messageHandler_GetSource(msgBuffer), 16); - packetSrcAddr = addressCreateFromInet6(&addr_in6); - - /* We now determine the local address used to reach the packet src address */ - int sock = (int)socket (AF_INET6, SOCK_DGRAM, 0); - if (sock < 0) - goto ERR; - - struct sockaddr_in6 remote, local; - memset(&remote, 0, sizeof(remote)); - remote.sin6_family = AF_INET6; - remote.sin6_addr = addr_in6.sin6_addr; - remote.sin6_port = htons(1234); - - socklen_t locallen = sizeof(local); - if (connect(sock, (const struct sockaddr*)&remote, sizeof(remote)) == -1) - goto ERR; - if (getsockname(sock, (struct sockaddr*) &local, &locallen) == -1) - goto ERR; - - local.sin6_port = htons(1234); - localAddr = addressCreateFromInet6(&local); - - close(sock); - - } else if (messageHandler_GetIPPacketType(msgBuffer) == IPv4_TYPE) { - struct sockaddr_in addr_in; - addr_in.sin_family = AF_INET; - addr_in.sin_port = htons(1234); - memcpy(&addr_in.sin_addr, - (struct in_addr *)messageHandler_GetSource(msgBuffer), 4); - packetSrcAddr = addressCreateFromInet(&addr_in); - - /* We now determine the local address used to reach the packet src address */ - - int sock = (int)socket (AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - perror("Socket error"); - goto ERR; - } - - struct sockaddr_in remote, local; - memset(&remote, 0, sizeof(remote)); - remote.sin_family = AF_INET; - remote.sin_addr = addr_in.sin_addr; - remote.sin_port = htons(1234); - - socklen_t locallen = sizeof(local); - if (connect(sock, (const struct sockaddr*)&remote, sizeof(remote)) == -1) - goto ERR; - if (getsockname(sock, (struct sockaddr*) &local, &locallen) == -1) - goto ERR; - - local.sin_port = htons(1234); - localAddr = addressCreateFromInet(&local); - - close(sock); - } - /* As this is a receive pair, we swap src and dst */ - return addressPair_Create(localAddr, packetSrcAddr); - -ERR: - perror("Socket error"); - return NULL; -} - -/* Main hook handler */ - -/** - * \brief Handle incoming messages - * \param [in] forwarder - Reference to the Forwarder instance - * \param [in] packet - Packet buffer - * \param [in] conn_id - A hint on the connection ID on which the packet - * was received - * \return Flag indicating whether the packet matched a hook and was - * (successfully or not) processed. - */ -static inline bool messageHandler_handleHooks(Forwarder * forwarder, - const uint8_t * packet, ListenerOps * listener, int fd, AddressPair * pair) -{ - bool is_matched = false; - - /* BEGIN Match */ - -#ifdef WITH_MAPME - bool is_mapme = mapme_isMapMe(packet); - is_matched |= is_mapme; -#endif /* WITH_MAPME */ - - /* ... */ - - /* END Match */ - - if (!is_matched) - return false; - - /* - * Find existing connection or create a new one (we assume all processing - * requires a valid connection. - */ - - if (!pair) { - /* The hICN listener does not provide any address pair while UDP does */ - const AddressPair * pair = _createRecvAddressPairFromPacket(packet); - if (!pair) - return false; - } - - /* Find connection and eventually create it */ - const Connection * conn = connectionTable_FindByAddressPair( - forwarder_GetConnectionTable(forwarder), pair); - unsigned conn_id; - if (conn == NULL) { - conn_id = listener->createConnection(listener, fd, pair); - } else { - conn_id = connection_GetConnectionId(conn); - } - - /* BEGIN Process */ - -#ifdef WITH_MAPME - if (mapme_isMapMe(packet)) - forwarder_ProcessMapMe(forwarder, packet, conn_id); -#endif /* WITH_MAPME */ - - /* ... */ - - /* END Process */ - - return true; -} - static inline bool messageHandler_IsTCP(const uint8_t *message) { if (messageHandler_NextHeaderType(message) != IPPROTO_TCP) return false; return true; @@ -432,7 +282,7 @@ static inline uint16_t messageHandler_GetExpectedWldrLabel( return 0; } - return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->expected_lbl); + return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->wldr_notification_lbl.expected_lbl); } static inline uint16_t messageHandler_GetWldrLastReceived( @@ -449,7 +299,7 @@ static inline uint16_t messageHandler_GetWldrLastReceived( return 0; } - return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->received_lbl); + return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->wldr_notification_lbl.received_lbl); } static inline uint16_t messageHandler_GetWldrLabel(const uint8_t *message) { @@ -660,25 +510,28 @@ static inline void messageHandler_SetWldrNotification(uint8_t *notification, 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), - }, - }}; + *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, + .wldr_notification_lbl = { + .expected_lbl = htons(expected), + .received_lbl = htons(received), + }, + }, + }}; messageHandler_SetSource_IPv6( notification, (struct in6_addr *)messageHandler_GetDestination(original)); @@ -699,7 +552,7 @@ static inline uint8_t * messageHandler_CreateProbePacket(hicn_format_t format, size_t header_length; hicn_packet_get_header_length_from_format(format, &header_length); - uint8_t *pkt = parcMemory_AllocateAndClear(header_length); + uint8_t *pkt = calloc(header_length, 1); hicn_packet_init_header(format, (hicn_header_t *) pkt); @@ -732,7 +585,7 @@ static inline void messageHandler_CreateProbeReply(uint8_t * probe, } static inline hicn_name_t * messageHandler_CreateProbeName(const ip_prefix_t *address){ - hicn_name_t * name = parcMemory_AllocateAndClear(sizeof(hicn_name_t)); + hicn_name_t * name = calloc(sizeof(hicn_name_t), 1); hicn_name_create_from_ip_prefix(address, 0, name); return name; } diff --git a/hicn-light/src/hicn/core/messagePacketType.h b/hicn-light/src/hicn/core/messagePacketType.h index dfbb12342..9a559069e 100644 --- a/hicn-light/src/hicn/core/messagePacketType.h +++ b/hicn-light/src/hicn/core/messagePacketType.h @@ -23,10 +23,13 @@ #define message_packet_type_h typedef enum message_type { - MessagePacketType_Unknown, - MessagePacketType_Interest, - MessagePacketType_ContentObject, - MessagePacketType_WldrNotification + MESSAGE_TYPE_UNDEFINED, + MESSAGE_TYPE_INTEREST, + MESSAGE_TYPE_DATA, + MESSAGE_TYPE_WLDR_NOTIFICATION, + MESSAGE_TYPE_MAPME, + MESSAGE_TYPE_COMMAND, + MESSAGE_TYPE_N, } MessagePacketType; #endif // message_packet_type_h diff --git a/hicn-light/src/hicn/strategies/rnd.h b/hicn-light/src/hicn/core/msgbuf.c index 78fb34758..094ecbafd 100644 --- a/hicn-light/src/hicn/strategies/rnd.h +++ b/hicn-light/src/hicn/core/msgbuf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2020 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -14,14 +14,8 @@ */ /** - * Forward randomly + * \file msgbuf.c + * \brief Implementation hICN message buffer */ -#ifndef rnd_h -#define rnd_h - -#include <hicn/strategies/strategyImpl.h> - -StrategyImpl* strategyRnd_Create(); - -#endif // rnd_h +#include "msgbuf.h" diff --git a/hicn-light/src/hicn/core/msgbuf.h b/hicn-light/src/hicn/core/msgbuf.h new file mode 100644 index 000000000..3e96b3bbc --- /dev/null +++ b/hicn-light/src/hicn/core/msgbuf.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 HICN_MSGBUF +#define HICN_MSGBUF + +#include <hicn/core/name.h> +#include <hicn/core/ticks.h> +#include <hicn/core/messageHandler.h> + +typedef struct { + Ticks receiveTime; + unsigned connection_id; + Name *name; + uint8_t *messageHead; + unsigned length; + uint8_t packetType; +} msgbuf_t; + +#define msgbuf_from_packet(MSGBUF, PACKET, LENGTH, TYPE, CONNID, RECV_TIME) \ +do { \ + *MSGBUF = (msgbuf_t) { \ + .receiveTime = (RECV_TIME), \ + .connection_id = (CONNID), \ + .messageHead = (PACKET), \ + .length = (LENGTH), \ + .packetType = (TYPE), \ + .name = (TYPE != MESSAGE_TYPE_WLDR_NOTIFICATION \ + ? name_CreateFromPacket((PACKET), (TYPE)) \ + : NULL), \ + }; \ +} while(0) + +#define msgbuf_get_name(M) ((M)->name) +#define msgbuf_get_connection_id(M) ((M)->connection_id) +#define msgbuf_get_type(M) ((M)->packetType) +#define msgbuf_has_wldr(M) (messageHandler_HasWldr((M)->messageHead)) +#define msgbuf_get_len(M) ((M)->length) +#define msgbuf_get_packet(M) ((M)->messageHead) + +// XXX TODO EXPLAIN THE CONSTANT +#define msgbuf_get_interest_lifetime(M) (NSEC_TO_TICKS(messageHandler_GetInterestLifetime((M)->messageHead) * 1000000ULL)) + +#define msgbuf_is_probe(M) messageHandler_IsAProbe((M)->messageHead) + +/* Path label */ + +#define msgbuf_get_pathlabel(M) (messageHandler_GetPathLabel((M)->messageHead)) +#define msgbuf_set_pathlabel(M, label) (messageHandler_SetPathLabel((M)->messageHead, label)) +#define msgbuf_update_pathlabel(M, outface) (messageHandler_SetPathLabel((M)->messageHead, outface)) +#define msgbuf_reset_pathlabel(M) (messageHandler_ResetPathLabel((M)->messageHead)) + +/* WLDR */ + +#define msgbuf_reset_wldr_label(M) (messageHandler_ResetWldrLabel((M)->messageHead)) +#define msgbuf_get_wldr_label(M) (messageHandler_GetWldrLabel((M)->messageHead)) +#define msgbuf_get_wldr_expected_label(M) (messageHandler_GetWldrExpectedLabel((M)->messageHead)) +#define msgbuf_get_wldr_last_received(M) (messageHandler_GetWldrLastReceived((M)->messageHead)) +#define msgbuf_set_wldr_label(M, label) (messageHandler_GetWldrLabel((M)->messageHead, label)) + +#endif /* HICN_MSGBUF */ + + diff --git a/hicn-light/src/hicn/core/name.c b/hicn-light/src/hicn/core/name.c index 805e7bfae..d50ce4cc2 100644 --- a/hicn-light/src/hicn/core/name.c +++ b/hicn-light/src/hicn/core/name.c @@ -13,23 +13,17 @@ * limitations under the License. */ +#include <assert.h> #include <limits.h> #include <hicn/hicn-light/config.h> #include <stdbool.h> #include <stdio.h> #include <string.h> -#include <parc/algol/parc_BufferComposer.h> -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_Memory.h> - +#include <hicn/common.h> // cumulative_hash32 #include <hicn/core/messageHandler.h> #include <hicn/core/name.h> -#include <parc/algol/parc_Hash.h> - -#include <parc/assert/parc_Assert.h> - #define IPv6_TYPE 6 #define IPv4_TYPE 4 @@ -37,227 +31,263 @@ // segment struct name { - NameBitvector *content_name; - uint32_t segment; - uint32_t name_hash; - // the refcount is shared between all copies - unsigned *refCountPtr; + 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 +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 +_incrementRefCount(Name *name) { + assert(*name->refCountPtr > 0); + (*name->refCountPtr)++; } -static void _decrementRefCount(Name *name) { - parcAssertTrue(*name->refCountPtr > 0, - "Illegal State: Trying to decrement a 0 refcount!"); - (*name->refCountPtr)--; +static +void +_decrementRefCount(Name *name) { + assert(*name->refCountPtr > 0); + (*name->refCountPtr)--; } static uint32_t _computeHash(Name *name) { - parcAssertNotNull(name, "Parameter must be non-null pointer"); + assert(name); - uint32_t hash1 = nameBitvector_GetHash32(name->content_name); - return parcHash32_Data_Cumulative((const uint8_t *)&name->segment, 4, hash1); + uint32_t hash1 = nameBitvector_GetHash32(name->content_name); + return cumulative_hash32(&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); +Name * +name_CreateFromPacket(const uint8_t *packet, MessagePacketType type) +{ + Name *name = malloc(sizeof(Name)); + assert(name); // XXX TODO error handling + + if (messageHandler_GetIPPacketType(packet) == IPv6_TYPE) { + if (type == MESSAGE_TYPE_INTEREST) { + name->content_name = nameBitvector_CreateFromIn6Addr( + (struct in6_addr *)messageHandler_GetDestination(packet), 128); + } else if (type == MESSAGE_TYPE_DATA) { + name->content_name = nameBitvector_CreateFromIn6Addr( + (struct in6_addr *)messageHandler_GetSource(packet), 128); + } else { + free(name); + return NULL; + } + } else if (messageHandler_GetIPPacketType(packet) == IPv4_TYPE) { + if (type == MESSAGE_TYPE_INTEREST) { + name->content_name = nameBitvector_CreateFromInAddr( + *((uint32_t *)messageHandler_GetDestination(packet)), 32); + } else if (type == MESSAGE_TYPE_DATA) { + name->content_name = nameBitvector_CreateFromInAddr( + *((uint32_t *)messageHandler_GetSource(packet)), 32); + } else { + free(name); + return NULL; + } } else { - parcMemory_Deallocate((void **)&name); - return NULL; + printf("Error: unknown message type\n"); + free(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->segment = messageHandler_GetSegment(packet); + name->name_hash = _computeHash(name); + + name->refCountPtr = malloc(sizeof(unsigned)); + assert(name->refCountPtr); // XXX TODO error handling + *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; +Name * +name_CreateFromAddress(int family, ip_address_t addr, + uint8_t len) +{ + Name *name = malloc(sizeof(Name)); + assert(name); // XXX TODO error handling + + switch(family) { + case AF_INET: + name->content_name = nameBitvector_CreateFromInAddr(addr.v4.as_u32, len); + break; + case AF_INET6: + name->content_name = nameBitvector_CreateFromIn6Addr(&addr.v6.as_in6addr, len); + break; + default: + return NULL; + } + + name->segment = 0; + name->name_hash = _computeHash(name); + + name->refCountPtr = malloc(sizeof(unsigned)); + assert(name->refCountPtr); // XXX TODO error handling + *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; +void +name_Release(Name **namePtr) +{ + assert(namePtr); + assert(*namePtr); + + Name *name = *namePtr; + _decrementRefCount(name); + if (_getRefCount(name) == 0) { + free(name->refCountPtr); + nameBitvector_Destroy(&(name->content_name)); + } + free(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)); +Name * +name_Acquire(const Name *original) +{ + assert(original); + + Name *copy = malloc(sizeof(Name)); + assert(copy); // XXX TODO error handling - memcpy(copy, original, sizeof(Name)); - _incrementRefCount(copy); + memcpy(copy, original, sizeof(Name)); + _incrementRefCount(copy); - return 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)); +Name * +name_Copy(const Name *original) +{ + assert(original); - copy->content_name = nameBitvector_Copy(original->content_name); - copy->segment = original->segment; - copy->name_hash = original->name_hash; + Name *copy = malloc(sizeof(Name)); + assert(copy); // XXX TODO error handling - copy->refCountPtr = parcMemory_Allocate(sizeof(unsigned)); - parcAssertNotNull(copy->refCountPtr, "parcMemory_Allocate(%zu) returned NULL", - sizeof(unsigned)); - *copy->refCountPtr = 1; + copy->content_name = nameBitvector_Copy(original->content_name); + copy->segment = original->segment; + copy->name_hash = original->name_hash; - return copy; + copy->refCountPtr = malloc(sizeof(unsigned)); + assert(copy->refCountPtr); // XXX TODO error handling + *copy->refCountPtr = 1; + + return copy; } -uint32_t name_HashCode(const Name *name) { - parcAssertNotNull(name, "Parameter must be non-null"); - return name->name_hash; +uint32_t +name_HashCode(const Name *name) +{ + assert(name); + return name->name_hash; } -NameBitvector *name_GetContentName(const Name *name) { - parcAssertNotNull(name, "Parameter must be non-null"); - return name->content_name; +NameBitvector * +name_GetContentName(const Name *name) +{ + assert(name); + 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"); +bool +name_Equals(const Name *a, const Name *b) +{ + assert(a); + assert(b); + + /* 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; +} - /* BEGIN: Workaround for HICN-400 */ - if ((!a->content_name) || (!b->content_name)) - return false; - /* END: Workaround for HICN-400 */ +int +name_Compare(const Name *a, const Name *b) +{ + assert(a); + assert(b); - if ((nameBitvector_Equals(a->content_name, b->content_name) && - a->segment == b->segment)) - return true; - return false; -} + if (a == NULL && b == NULL) { + return 0; + } + if (a == NULL) { + return -1; + } + if (b == NULL) { + return +1; + } -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; + int res = nameBitvector_Compare(a->content_name, b->content_name); + + if (res != 0) { + return res; } else { - return 0; + 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)); +char * +name_ToString(const Name *name) +{ + char *output = malloc(128); - sprintf(output, "name: %s seq: %u", addressToString(packetAddr), - name->segment); + address_t address; + nameBitvector_ToAddress(name_GetContentName(name), &address); - addressDestroy(&packetAddr); + // XXX TODO +#if 0 + sprintf(output, "name: %s seq: %u", addressToString(address), + name->segment); +#else + snprintf(output, 128, "%s", "Not implemented"); +#endif - return output; + return output; } -void name_setLen(Name *name, uint8_t len) { - nameBitvector_setLen(name->content_name, len); - name->name_hash = _computeHash(name); +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) { +uint32_t +name_GetSuffix(const Name * name) +{ return name->segment; } -uint8_t name_GetLen(const Name * name) { +uint8_t +name_GetLen(const Name * name) +{ return nameBitvector_GetLength(name->content_name); } #endif /* WITH_POLICY */ diff --git a/hicn-light/src/hicn/core/name.h b/hicn-light/src/hicn/core/name.h index db9438150..f3b3f2a02 100644 --- a/hicn-light/src/hicn/core/name.h +++ b/hicn-light/src/hicn/core/name.h @@ -21,9 +21,9 @@ #include <hicn/core/messagePacketType.h> #include <hicn/core/nameBitvector.h> -#include <hicn/utils/address.h> +//#include <hicn/utils/address.h> -#include <hicn/utils/commands.h> +//#include <hicn/utils/commands.h> struct name; typedef struct name Name; @@ -93,8 +93,7 @@ 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); +Name *name_CreateFromAddress(int family, ip_address_t addr, uint8_t len); #ifdef WITH_POLICY uint32_t name_GetSuffix(const Name * name); diff --git a/hicn-light/src/hicn/core/nameBitvector.c b/hicn-light/src/hicn/core/nameBitvector.c index 6ad623b14..d3dc8c0ee 100644 --- a/hicn-light/src/hicn/core/nameBitvector.c +++ b/hicn-light/src/hicn/core/nameBitvector.c @@ -17,16 +17,13 @@ #include <stdio.h> #include <stdlib.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> - #include <hicn/core/messageHandler.h> #include <hicn/core/nameBitvector.h> -#include <parc/algol/parc_Hash.h> - +#include <hicn/common.h> // hash32 #include <hicn/utils/commands.h> +#define DEFAULT_PORT 1234 #define NAME_LEN 2 const uint64_t BV_SIZE = 64; @@ -41,322 +38,335 @@ const uint64_t ONE = 0x1; // 1 b 1 c //hex struct name_bitvector { - uint64_t bits[NAME_LEN]; - uint8_t len; - uint8_t IPversion; + 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)); +NameBitvector * +nameBitvector_CreateFromInAddr(uint32_t addr, uint8_t len) +{ + NameBitvector *bitvector = malloc(sizeof(NameBitvector)); + assert(bitvector); // XXX TODO error handling - bitvector->bits[0] = 0; - bitvector->bits[1] = 0; + 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); + 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->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->len = len; - bitvector->IPversion = IPv4_TYPE; + bitvector->IPversion = IPv4_TYPE; - return bitvector; + return bitvector; } -NameBitvector *nameBitvector_CreateFromIn6Addr(struct in6_addr *addr, - uint8_t len) { - parcAssertNotNull(addr, "addr cannot be null"); +NameBitvector * +nameBitvector_CreateFromIn6Addr(struct in6_addr *addr, uint8_t len) +{ + assert(addr); - NameBitvector *bitvector = parcMemory_AllocateAndClear(sizeof(NameBitvector)); - parcAssertNotNull(bitvector, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(NameBitvector)); + NameBitvector *bitvector = malloc(sizeof(NameBitvector)); + assert(bitvector); // XXX TODO error handling - bitvector->bits[0] = 0; - bitvector->bits[1] = 0; + 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 = 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]; - } + for (int i = 8; i < 16; ++i) { + bitvector->bits[1] = (bitvector->bits[1] << 8) | addr->s6_addr[i]; + } - bitvector->len = len; + bitvector->len = len; - bitvector->IPversion = IPv6_TYPE; + bitvector->IPversion = IPv6_TYPE; - return bitvector; + 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; +NameBitvector * +nameBitvector_CreateFromAddress(const address_t * address, uint8_t len) +{ + assert(address); + + switch(address_family(address)) { + case AF_INET: + return nameBitvector_CreateFromInAddr(address4_ip(address).s_addr, len); + case AF_INET6: + return nameBitvector_CreateFromIn6Addr(&address6_ip(address), len); + default: + return NULL; } - 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 * +nameBitvector_Copy(const NameBitvector *original) +{ + assert(original); - NameBitvector *copy = parcMemory_AllocateAndClear(sizeof(NameBitvector)); - parcAssertNotNull(copy, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(NameBitvector)); + NameBitvector *copy = malloc(sizeof(NameBitvector)); + assert(copy); // XXX TODO error handling - copy->bits[0] = original->bits[0]; - copy->bits[1] = original->bits[1]; - copy->len = original->len; + copy->bits[0] = original->bits[0]; + copy->bits[1] = original->bits[1]; + copy->len = original->len; - return copy; + 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"); +void +nameBitvector_Destroy(NameBitvector **bitvectorPtr) +{ + assert(bitvectorPtr); + assert(*bitvectorPtr); - NameBitvector *bv = *bitvectorPtr; - parcMemory_Deallocate((void **)&(bv)); - *bitvectorPtr = NULL; + NameBitvector *bv = *bitvectorPtr; + free(bv); + *bitvectorPtr = NULL; } -uint8_t nameBitvector_GetLength(const NameBitvector *name) { return name->len; } +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); +uint32_t +nameBitvector_GetHash32(const NameBitvector *name) +{ + return hash32(&name->bits, 16); } -bool nameBitvector_Equals(const NameBitvector *a, const NameBitvector *b) { - if (a->bits[0] == b->bits[0] && a->bits[1] == b->bits[1] && a->len == b->len) - return true; - return false; +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_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; +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)))); + *bit = (name->bits[pos / BV_SIZE] & (ONE << ((BV_SIZE - 1) - (pos % BV_SIZE)))); - return 0; + 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; +// TODO XXX use ffs(ll) +uint64_t +_diff_bit_log2(uint64_t val) +{ + // base 2 log of an uint64_t. This is the same as get the position of + // the highest bit set (or most significant bit set, MSB) + 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]; +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 += (BV_SIZE - (_diff_bit_log2(diff) + 1)); - //printf("if 2 diff = %lu plen = %d\n", diff, prefix_len); + 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; + 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; + if(prefix_len < limit) + return prefix_len; + return limit; } -void nameBitvector_clear(NameBitvector *a, uint8_t start_from){ - for(uint8_t pos = start_from; pos < WIDTH; pos++) - a->bits[pos / BV_SIZE] &= ~(ONE << ((BV_SIZE - 1) - (pos % BV_SIZE))); +void +nameBitvector_clear(NameBitvector *a, uint8_t start_from) +{ + for(uint8_t pos = start_from; pos < WIDTH; pos++) + a->bits[pos / BV_SIZE] &= ~(ONE << ((BV_SIZE - 1) - (pos % BV_SIZE))); } -int nameBitvector_ToIPAddress(const NameBitvector *name, - ip_prefix_t *prefix) { - 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++; +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; + 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); - } +void +nameBitvector_setLen(NameBitvector *name, uint8_t len) +{ + name->len = len; +} - 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++; +void +nameBitvector_ToAddress(const NameBitvector *name, address_t * address) +{ + if (name->IPversion == IPv4_TYPE) { + struct sockaddr_in * sin = address4(address); + sin->sin_family = AF_INET; + sin->sin_port = htons(DEFAULT_PORT); + + uint32_t tmp_addr = name->bits[0] >> 32ULL; + uint8_t addr_1 = (tmp_addr & 0xff000000) >> 24; + uint8_t addr_2 = (tmp_addr & 0x00ff0000) >> 16; + uint8_t addr_3 = (tmp_addr & 0x0000ff00) >> 8; + uint8_t addr_4 = (tmp_addr & 0x000000ff); + + sin->sin_addr.s_addr = 0; + sin->sin_addr.s_addr = (sin->sin_addr.s_addr | addr_4) << 8; + sin->sin_addr.s_addr = (sin->sin_addr.s_addr | addr_3) << 8; + sin->sin_addr.s_addr = (sin->sin_addr.s_addr | addr_2) << 8; + sin->sin_addr.s_addr = (sin->sin_addr.s_addr | addr_1); + } else { + struct sockaddr_in6 * sin6 = address6(address); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = htons(DEFAULT_PORT); + sin6->sin6_scope_id = 0; + sin6->sin6_flowinfo = 0; + + for (int i = 0; i < 8; i++) { + sin6->sin6_addr.s6_addr[i] = + (uint8_t)((name->bits[0] >> 8 * (7 - i)) & 0xFF); + } + + int x = 0; + for (int i = 8; i < 16; ++i) { + sin6->sin6_addr.s6_addr[i] = + (uint8_t)((name->bits[1] >> 8 * (7 - x)) & 0xFF); + x++; + } } - - Address *packetAddr = addressCreateFromInet6(&addr); - - return packetAddr; - } } -char *nameBitvector_ToString(const NameBitvector *name) { - char *output = malloc(WIDTH); - - Address *packetAddr = nameBitvector_ToAddress(name); +char * +nameBitvector_ToString(const NameBitvector *name) { + char *output = malloc(WIDTH); - sprintf(output, "prefix: %s len: %u", addressToString(packetAddr), name->len); + address_t address; + nameBitvector_ToAddress(name, &address); - addressDestroy(&packetAddr); + // XXX TODO +#if 0 + sprintf(output, "prefix: %s len: %u", addressToString(packetAddr), name->len); +#else + snprintf(output, WIDTH, "%s", "ENOIMPL"); +#endif - return output; + return output; } diff --git a/hicn-light/src/hicn/core/nameBitvector.h b/hicn-light/src/hicn/core/nameBitvector.h index 19944778c..256af68a0 100644 --- a/hicn-light/src/hicn/core/nameBitvector.h +++ b/hicn-light/src/hicn/core/nameBitvector.h @@ -20,7 +20,7 @@ #include <stdint.h> #include <stdlib.h> -#include <hicn/utils/address.h> +#include <hicn/core/address.h> struct name_bitvector; typedef struct name_bitvector NameBitvector; @@ -51,7 +51,7 @@ void nameBitvector_clear(NameBitvector *a, uint8_t start_from); int nameBitvector_ToIPAddress(const NameBitvector *name, ip_prefix_t *prefix); void nameBitvector_setLen(NameBitvector *name, uint8_t len); -Address *nameBitvector_ToAddress(const NameBitvector *name); +void nameBitvector_ToAddress(const NameBitvector *name, address_t * address); char *nameBitvector_ToString(const NameBitvector *name); diff --git a/hicn-light/src/hicn/core/nexthops.h b/hicn-light/src/hicn/core/nexthops.h new file mode 100644 index 000000000..b45ae360f --- /dev/null +++ b/hicn-light/src/hicn/core/nexthops.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + */ + +#ifndef HICN_NEXTHOPS_H +#define HICN_NEXTHOPS_H + +#include <stdint.h> +#include <stdbool.h> + +#include <hicn/core/strategy.h> + +#define _nexthops_var(x) _nexthops_##x + +/* + * 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 { + unsigned elts[MAX_NEXTHOPS]; + strategy_nexthop_state_t state[MAX_NEXTHOPS]; + size_t num_elts; + 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) + +#define nexthops_disable(NH, i) \ +do { \ + (NH)->flags |= (1 << (i)); \ + (NH)->cur_elts--; \ +} while(0) + +#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))) + +#define nexthops_reset(NH) \ +do { \ + (NH)->flags = 0; \ + (NH)->cur_elts = (NH)->num_elts; \ +} while(0) + +#define nexthops_enumerate(NH, i, X, BODY) \ +do { \ + for ((i) = 0; (i) < nexthops_get_len(NH); (i)++) { \ + if (nexthops_is_disabled((NH), (i))) \ + continue; \ + X = (NH)->elts[(i)]; \ + do { BODY } while(0); \ + } \ +} while(0) + +#define nexthops_foreach(NH, X, BODY) \ +do { \ + unsigned _nexthops_var(i); \ + nexthops_enumerate((NH), _nexthops_var(i), (X), { BODY });\ +} while(0) + +#define nexthops_add(NH, X) \ +do { \ + unsigned _nexthops_var(n); \ + bool _nexthops_var(found) = false; \ + nexthops_foreach((NH), _nexthops_var(n), { \ + if (_nexthops_var(n) == (X)) { \ + _nexthops_var(found) = true; \ + break; \ + } \ + }); \ + if (!_nexthops_var(found)) { \ + (NH)->elts[(NH)->num_elts++] = (X); \ + nexthops_reset(NH); \ + } \ +} while(0) + +#define nexthops_remove(NH, X) \ +do { \ + unsigned _nexthops_var(n); \ + unsigned _nexthops_var(i); \ + nexthops_enumerate((NH), _nexthops_var(i), _nexthops_var(n), { \ + if (_nexthops_var(n) == X) { \ + (NH)->elts[_nexthops_var(i)] = \ + (NH)->elts[(NH)->num_elts--]; \ + nexthops_reset(NH); \ + } \ + }); \ +} while(0) + +#define nexthops_clear(NH) nexthops_set_len(NH, 0); + +static inline +bool +nexthops_contains(nexthops_t * nexthops, unsigned nexthop) +{ + unsigned n; + nexthops_foreach(nexthops, n, { + if (n == nexthop) + return true; + }); + return false; +} + +#define nexthops_select(nexthops, i) ((nexthops)->flags = 1 << (i)) +#define nexthops_select_one(nexthops) (nexthops_select((nexthops), 0)) + +#endif /* HICN_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..1bd004bcc --- /dev/null +++ b/hicn-light/src/hicn/core/packet_cache.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + */ + 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..52ccb6f71 --- /dev/null +++ b/hicn-light/src/hicn/core/packet_cache.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + */ + diff --git a/hicn-light/src/hicn/core/pit.c b/hicn-light/src/hicn/core/pit.c new file mode 100644 index 000000000..fa54e2429 --- /dev/null +++ b/hicn-light/src/hicn/core/pit.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 <assert.h> +#include <stdio.h> +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +#include <hicn/core/msgbuf.h> +#include <hicn/base/pool.h> +#include <hicn/core/ticks.h> +#include <hicn/util/log.h> + +#include "pit.h" + +// XXX TODO Should not be defined here +#define DEFAULT_INTEREST_LIFETIME 4000000000ULL + +static Ticks _pit_calculate_lifetime(pit_t * pit, + msgbuf_t *interest_msgbuf) { + uint64_t interestLifetimeTicks = + msgbuf_get_interest_lifetime(interest_msgbuf); + if (interestLifetimeTicks == 0) { + interestLifetimeTicks = NSEC_TO_TICKS(DEFAULT_INTEREST_LIFETIME); + } + + Ticks expiry_time = ticks_now() + interestLifetimeTicks; + return expiry_time; +} + +// max_elts default is 65535 +pit_t * +pit_create(size_t max_elts) +{ + pit_t * pit = malloc(sizeof(pit_t)); + if (!pit) + return NULL; + + pool_init(pit->entries, max_elts); + pit->index_by_name = kh_init(pit_name); + + DEBUG("PIT %p created", pit); + + return pit; +} + +void +pit_free(pit_t * pit) +{ + assert(pit); + // XXX TODO + + DEBUG("PIT %p destroyed", pit); +} + +pit_verdict_t +pit_on_interest(pit_t * pit, msgbuf_t * interest_msgbuf) +{ + assert(pit); + assert(interest_msgbuf); + assert(msgbuf_get_type(interest_msgbuf) == MESSAGE_TYPE_INTEREST); + + fib_entry_t * fib_entry; + Ticks expiry_time; + + /* Lookup entry by name */ + khiter_t k = kh_get_pit_name(pit->index_by_name, msgbuf_get_name(interest_msgbuf)); + if (k == kh_end(pit->index_by_name)) + goto NOT_FOUND; + pit_entry_t * entry = pit->entries + kh_val(pit->index_by_name, k); + assert(entry); + + // has it expired? + if (ticks_now() >= pit_entry_get_expiry_time(entry)) + goto TIMEOUT; + + /* Extend entry lifetime */ + expiry_time = _pit_calculate_lifetime(pit, interest_msgbuf); + if (expiry_time > pit_entry_get_expiry_time(entry)) + pit_entry_set_expiry_time(entry, expiry_time); + + unsigned connection_id = msgbuf_get_connection_id(interest_msgbuf); + + // Is the reverse path already in the PIT entry? + if (pit_entry_ingress_contains(entry, connection_id)) { + // It is already in the PIT entry, so this is a retransmission, so + // forward it. + DEBUG("Message %p existing entry (expiry %" PRIu64 ") and reverse path, forwarding", + interest_msgbuf, pit_entry_get_expiry_time(entry)); + return PIT_VERDICT_RETRANSMIT; + } + + // It is in the PIT but this is the first interest for the reverse path + pit_entry_ingress_add(entry, connection_id); + + DEBUG("Message %p existing entry (expiry %" PRIu64 ") and reverse path is new, aggregate", + interest_msgbuf, pit_entry_get_expiry_time(entry)); + return PIT_VERDICT_AGGREGATE; + +TIMEOUT: + fib_entry = pit_entry_get_fib_entry(entry); + if (fib_entry) + fib_entry_on_timeout(fib_entry, pit_entry_get_egress(entry)); + + // it's an old entry, remove it + k = kh_get(pit_name, pit->index_by_name, msgbuf_get_name(interest_msgbuf)); + if (k != kh_end(pit->index_by_name)) + kh_del(pit_name, pit->index_by_name, k); + +NOT_FOUND: + /* Create PIT entry */ + + expiry_time = _pit_calculate_lifetime(pit, interest_msgbuf); + + pit_allocate(pit, entry, interest_msgbuf); + pit_entry_from_msgbuf(entry, interest_msgbuf, expiry_time, ticks_now()); + + DEBUG("Message %p added to PIT (expiry %" PRIu64 ") ingress %u", + interest_msgbuf, pit_entry_get_expiry_time(entry), + msgbuf_get_connection_id(interest_msgbuf)); + + return PIT_VERDICT_FORWARD; +} + +nexthops_t * +pit_on_data(pit_t * pit, const msgbuf_t * data_msgbuf) +{ + assert(pit); + assert(data_msgbuf); + assert(msgbuf_get_type(data_msgbuf) == MESSAGE_TYPE_DATA); + + nexthops_t * nexthops = NULL; + + /* Lookup entry by name */ + khiter_t k = kh_get_pit_name(pit->index_by_name, msgbuf_get_name(data_msgbuf)); + if (k == kh_end(pit->index_by_name)) + goto NOT_FOUND; + + pit_entry_t * entry = pit->entries + kh_val(pit->index_by_name, k); + assert(entry); + + // here we need to check if the PIT entry is expired + // if so, remove the PIT entry. + Ticks now = ticks_now(); + if (now >= pit_entry_get_expiry_time(entry)) + goto TIMEOUT; + + /* PIT entry is not expired, use it */ + fib_entry_t * fib_entry = pit_entry_get_fib_entry(entry); + if (fib_entry) + fib_entry_on_data(fib_entry, pit_entry_get_egress(entry), + data_msgbuf, pit_entry_get_creation_time(entry), ticks_now()); + + // 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(entry); + +TIMEOUT: + /* Remove entry from PIT */ + kh_del(pit_name, pit->index_by_name, k); + +NOT_FOUND: + return nexthops; +} + +void +pit_remove(pit_t * pit, const msgbuf_t * interest_msgbuf) +{ + assert(pit); + assert(interest_msgbuf); + assert(msgbuf_get_type(interest_msgbuf) == MESSAGE_TYPE_INTEREST); + + khiter_t k = kh_get(pit_name, pit->index_by_name, msgbuf_get_name(interest_msgbuf)); + if (k == kh_end(pit->index_by_name)) + return; + //off_t index = kh_val(pit->index_by_name, k); + //pit_entry_t * entry = pit_at(pit, index); + kh_del(pit_name, pit->index_by_name, k); + + DEBUG("Message %p removed from PIT", interest_msgbuf); +} + +pit_entry_t * +pit_lookup(const pit_t * pit, const msgbuf_t * interest_msgbuf) +{ + assert(pit); + assert(interest_msgbuf); + assert(msgbuf_get_type(interest_msgbuf) == MESSAGE_TYPE_INTEREST); + + khiter_t k = kh_get(pit_name, pit->index_by_name, + msgbuf_get_name(interest_msgbuf)); + if (k == kh_end(pit->index_by_name)) + return NULL; + off_t index = kh_val(pit->index_by_name, k); + pit_entry_t * entry = pit_at(pit, index); + assert(entry); + + return entry; +} diff --git a/hicn-light/src/hicn/core/pit.h b/hicn-light/src/hicn/core/pit.h new file mode 100644 index 000000000..1aedcfab9 --- /dev/null +++ b/hicn-light/src/hicn/core/pit.h @@ -0,0 +1,92 @@ +#ifndef HICNLIGHT_PIT_H +#define HICNLIGHT_PIT_H + + +#include <hicn/base/khash.h> +#include <hicn/core/nexthops.h> +#include <hicn/core/msgbuf.h> +#include <hicn/core/fib.h> +#include <hicn/core/name.h> +#include <hicn/core/ticks.h> + +typedef struct { + msgbuf_t * msgbuf; + nexthops_t ingressIdSet; + nexthops_t egressIdSet; + + fib_entry_t * fib_entry; + + Ticks creation_time; + Ticks expiry_time; +} pit_entry_t; + +typedef enum { + PIT_VERDICT_FORWARD, + PIT_VERDICT_AGGREGATE, + PIT_VERDICT_RETRANSMIT, +} pit_verdict_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_get_creation_time(E) ((E)->creation_time) +#define pit_entry_get_expiry_time(E) ((E)->expiry_time) +#define pit_entry_set_expiry_time(E, EXPIRY_TIME) \ + (entry)->expiry_time = EXPIRY_TIME + +#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)) + +#define pit_entry_from_msgbuf(E, MSGBUF, EXPIRY_TIME, CREATION_TIME) \ +do { \ + E->msgbuf = MSGBUF; \ + pit_entry_ingress_add(E, msgbuf_get_connection_id(MSGBUF)); \ + E->fib_entry = NULL; \ + E->creation_time = CREATION_TIME; \ + E->expiry_time = EXPIRY_TIME; \ +} while(0) + +#define name_hash(name) (name_HashCode(name)) +#define name_hash_eq(a, b) (name_hash(b) - name_hash(a)) + +KHASH_INIT(pit_name, const Name *, unsigned, 0, name_hash, name_hash_eq); + +typedef struct { + pit_entry_t * entries; // pool + kh_pit_name_t * index_by_name; +} pit_t; + +pit_t * pit_create(size_t max_elts); + +void pit_free(pit_t * pit); + +#define _pit_var(x) _pit_ ## x + +#define pit_allocate(pit, entry, msgbuf) \ +do { \ + pool_get(pit->entries, entry); \ + unsigned _pit_var(id) = entry - pit->entries; \ + int _pit_var(res); \ + khiter_t _pit_var(k) = kh_put(pit_name, pit->index_by_name, \ + msgbuf_get_name(msgbuf), &_pit_var(res)); \ + kh_value(pit->index_by_name, _pit_var(k)) = _pit_var(id); \ +} while(0) + +#define pit_at(pit, i) (pit->entries + i) + +pit_verdict_t pit_on_interest(pit_t * pit, msgbuf_t * msgbuf); + +nexthops_t * pit_on_data(pit_t * pit, const msgbuf_t * msgbuf); + +void pit_remove(pit_t * pit, const msgbuf_t * msgbuf); + +pit_entry_t * pit_lookup(const pit_t * pit, const msgbuf_t * msgbuf); + +#endif /* HICNLIGHT_PIT_H */ diff --git a/hicn-light/src/hicn/core/prefix_stats.c b/hicn-light/src/hicn/core/prefix_stats.c new file mode 100644 index 000000000..c32665950 --- /dev/null +++ b/hicn-light/src/hicn/core/prefix_stats.c @@ -0,0 +1,202 @@ +#ifdef WITH_PREFIX_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/core/ticks.h> +#include <hicn/policy.h> +#include <hicn/core/fib.h> + +#include "prefix_stats.h" + +#define ALPHA 0.9 +#define STATS_INTERVAL 1000 /* ms */ + +static +void +prefix_stats_mgr_tick(prefix_stats_mgr_t * mgr, int fd, void * data) +{ + + assert(mgr); + assert(!data); + + uint64_t now = ticks_now(); + + /* Loop over FIB entries to compute statistics from counters */ + const fib_t * fib = forwarder_get_fib(mgr->forwarder); + fib_entry_t * entry; + + fib_foreach_entry(fib, entry, { + prefix_stats_update(&entry->prefix_stats, &entry->prefix_counters, now); + }); +} + +int +prefix_stats_mgr_initialize(prefix_stats_mgr_t * mgr, void * forwarder) +{ + mgr->forwarder = forwarder; + mgr->timer_fd = loop_register_timer(MAIN_LOOP, STATS_INTERVAL, mgr, prefix_stats_mgr_tick, NULL); + if (mgr->timer_fd < 0) + return -1; + + return 0; +} + +void +prefix_stats_mgr_finalize(prefix_stats_mgr_t * mgr) +{ + loop_unregister_timer(MAIN_LOOP, mgr->timer_fd); +} + + +void +prefix_stats_on_retransmission(const prefix_stats_mgr_t * mgr, prefix_counters_t * counters, + const nexthops_t * nexthops) +{ + connection_table_t * table = forwarder_get_connection_table(mgr->forwarder); + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { +#ifdef WITH_POLICY + const connection_t * conn = connection_table_at(table, nexthop); + + if (connection_has_tag(conn, POLICY_TAG_WIRED)) + counters->wired.num_losses++; + if (connection_has_tag(conn, POLICY_TAG_WIFI)) + counters->wifi.num_losses++; + if (connection_has_tag(conn, POLICY_TAG_CELLULAR)) + counters->cellular.num_losses++; +#endif /* WITH_POLICY */ + counters->all.num_losses++; + }); + +} + +#define UPDATE_TAG_STATS(TAG, NAME) \ +do { \ + if (connection_has_tag(conn, TAG)) { \ + counters->NAME.num_packets++; \ + counters->NAME.num_bytes += msg_size; \ + stats->NAME.latency = ALPHA * stats->NAME.latency + \ + (1 - ALPHA) * (double)rtt; \ + counters->NAME.latency_idle = 0; \ + } \ +} while(0) + +/* Update statistic counters upon Data packet reception */ +void +prefix_stats_on_data(const prefix_stats_mgr_t * mgr, prefix_stats_t * stats, + prefix_counters_t * counters, const nexthops_t * nexthops, + const msgbuf_t * msgbuf, Ticks rtt) +{ +#ifdef WITH_POLICY + forwarder_t * forwarder = mgr->forwarder; + connection_table_t * table = forwarder_get_connection_table(forwarder); +#endif /* WITH_POLICY */ + + size_t msg_size = msgbuf_get_len(msgbuf); + + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { +#ifdef WITH_POLICY + const connection_t * conn = connection_table_at(table, nexthop); + if (!conn) + continue; + + UPDATE_TAG_STATS(POLICY_TAG_WIRED, wired); + UPDATE_TAG_STATS(POLICY_TAG_WIFI, wifi); + UPDATE_TAG_STATS(POLICY_TAG_CELLULAR, cellular); +#endif /* WITH_POLICY */ + }); + + stats->all.latency = ALPHA * stats->all.latency + + (1 - ALPHA) * (double)rtt; + counters->all.latency_idle = 0; + counters->all.num_packets++; + counters->all.num_bytes += msg_size; +} + +void +prefix_stats_on_timeout(const prefix_stats_mgr_t * mgr, prefix_counters_t * counters, + const nexthops_t * nexthops) +{ +#ifdef WITH_POLICY + connection_table_t * table = forwarder_get_connection_table(mgr->forwarder); + + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + const connection_t * conn = connection_table_at(table, nexthop); + if (!conn) + continue; + if (connection_has_tag(conn, POLICY_TAG_WIRED)) + counters->wired.num_losses++; + if (connection_has_tag(conn, POLICY_TAG_WIFI)) + counters->wifi.num_losses++; + if (connection_has_tag(conn, POLICY_TAG_CELLULAR)) + counters->cellular.num_losses++; + }); +#endif /* WITH_POLICY */ + + counters->all.num_losses++; +} + +#define UPDATE_TYPE(TYPE) \ +do { \ + /* (a) throughput */ \ + if (counters->TYPE.num_bytes > 0) { \ + throughput = counters->TYPE.num_bytes / \ + (now - counters->last_update) ; \ + throughput = throughput * 8 / 1024; \ + if (throughput < 0) \ + throughput = 0; \ + } else { \ + throughput = 0; \ + } \ + stats->TYPE.throughput = ALPHA * stats->TYPE.throughput + \ + (1-ALPHA) * throughput; \ + \ + /* (b) loss rate */ \ + if ((counters->TYPE.num_losses > 0) && \ + (counters->TYPE.num_packets > 0)) { \ + loss_rate = counters->TYPE.num_losses / \ + counters->TYPE.num_packets; \ + loss_rate *= 100; \ + } else { \ + loss_rate = 0; \ + } \ + stats->TYPE.loss_rate = ALPHA * stats->TYPE.loss_rate + \ + (1-ALPHA) * loss_rate; \ + \ + /* (c) latency */ \ + counters->TYPE.latency_idle++; \ + if (counters->TYPE.latency_idle > 1) \ + stats->TYPE.latency = 0; \ + \ + /* (d) Reset counters */ \ + counters->TYPE.num_bytes = 0; \ + counters->TYPE.num_losses = 0; \ + counters->TYPE.num_packets = 0; \ +} while(0) + +void +prefix_stats_update(prefix_stats_t * stats, prefix_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_PREFIX_STATS */ diff --git a/hicn-light/src/hicn/core/prefix_stats.h b/hicn-light/src/hicn/core/prefix_stats.h new file mode 100644 index 000000000..257f6b44d --- /dev/null +++ b/hicn-light/src/hicn/core/prefix_stats.h @@ -0,0 +1,91 @@ + +#ifndef HICNLIGHT_PREFIX_STATS_H +#define HICNLIGHT_PREFIX_STATS_H + +#ifdef WITH_PREFIX_STATS + +typedef struct prefix_stats_mgr_s { + void * forwarder; + int timer_fd; +} prefix_stats_mgr_t; + + +/* PER-INTERFACE PREFIX STATS */ + +typedef struct { + float throughput; + float latency; + float loss_rate; +} interface_stats_t; + +/* PREFIX STATS */ + +typedef struct { + interface_stats_t wired; + interface_stats_t wifi; + interface_stats_t cellular; + interface_stats_t all; +} prefix_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; +} prefix_counters_t; + +#define INTERFACE_STATS_EMPTY (interface_stats_t) { \ + .throughput = 0, \ + .latency = 0, \ + .loss_rate = 0, \ +} + +#define PREFIX_STATS_EMPTY (prefix_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 PREFIX_COUNTERS_EMPTY (prefix_counters_t) { \ + .wired = INTERFACE_COUNTERS_EMPTY, \ + .wifi = INTERFACE_COUNTERS_EMPTY, \ + .cellular = INTERFACE_COUNTERS_EMPTY, \ + .all = INTERFACE_COUNTERS_EMPTY, \ + .last_update = 0, \ +} + +int prefix_stats_mgr_initialize(prefix_stats_mgr_t * mgr, void * forwarder); + +void prefix_stats_mgr_finalize(prefix_stats_mgr_t * mgr); + +void prefix_stats_on_retransmission(const prefix_stats_mgr_t * mgr, + prefix_counters_t * countrs, const nexthops_t * nexthops); + +void prefix_stats_on_data(const prefix_stats_mgr_t * mgr, prefix_stats_t * stats, + prefix_counters_t * counters, const nexthops_t * nexthops, + const msgbuf_t * msgbuf, Ticks rtt); + +void prefix_stats_on_timeout(const prefix_stats_mgr_t * mgr, prefix_counters_t * counters, + const nexthops_t * nexthops); + +void prefix_stats_update(prefix_stats_t * stats, prefix_counters_t * counters, uint64_t now); + +#endif /* WITH_PREFIX_STATS */ + +#endif /* HICNLIGHT_PREFIX_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..66ab232b5 --- /dev/null +++ b/hicn-light/src/hicn/core/strategy.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 <hicn/core/strategy_vft.h> + +#include <hicn/strategies/load_balancer.h> +#include <hicn/strategies/random.h> +#include <hicn/strategies/low_latency.h> + +extern const strategy_ops_t strategy_load_balancer; +extern const strategy_ops_t strategy_random; +extern const strategy_ops_t strategy_low_latency; + +const strategy_ops_t * const strategy_vft[] = { + [STRATEGY_TYPE_LOADBALANCER] = &strategy_load_balancer, + [STRATEGY_TYPE_RANDOM] = &strategy_random, +#if 0 + [STRATEGY_TYPE_LOW_LATENCY] = &strategy_low_latency, +#endif +}; + + diff --git a/hicn-light/src/hicn/core/strategy.h b/hicn-light/src/hicn/core/strategy.h new file mode 100644 index 000000000..3d48c5510 --- /dev/null +++ b/hicn-light/src/hicn/core/strategy.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 HICN_STRATEGY_H +#define HICN_STRATEGY_H + +#include <hicn/core/name.h> +#include <hicn/core/msgbuf.h> + +#include <hicn/strategies/load_balancer.h> +#include <hicn/strategies/low_latency.h> +#include <hicn/strategies/random.h> + +typedef enum { + STRATEGY_TYPE_UNDEFINED, + STRATEGY_TYPE_LOADBALANCER, + STRATEGY_TYPE_LOW_LATENCY, + STRATEGY_TYPE_RANDOM, + STRATEGY_TYPE_N +} strategy_type_t; + +#define STRATEGY_TYPE_VALID(type) \ + ((type != STRATEGY_TYPE_UNDEFINED) && (type != STRATEGY_TYPE_N)) + +typedef union { + strategy_load_balancer_options_t load_balancer; + strategy_low_latency_options_t low_latency; + strategy_random_options_t random; +} strategy_options_t; + +typedef union { + strategy_load_balancer_nexthop_state_t load_balancer; + strategy_low_latency_nexthop_state_t low_latency; + strategy_random_nexthop_state_t random; +} strategy_nexthop_state_t; + +#define STRATEGY_NEXTHOP_STATE_EMPTY {{ 0 }} + +typedef union { + strategy_load_balancer_state_t load_balancer; + strategy_low_latency_state_t low_latency; + strategy_random_state_t random; +} 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 struct { + strategy_type_t type; + strategy_options_t options; + strategy_state_t state; +} strategy_entry_t; + + +#endif /* HICN_STRATEGY_H */ 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..e698c9d94 --- /dev/null +++ b/hicn-light/src/hicn/core/strategy_vft.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 HICN_STRATEGY_VFT_H +#define HICN_STRATEGY_VFT_H + +#include <hicn/core/strategy.h> +#include <hicn/core/nexthops.h> + +/** + * @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#> + */ +typedef struct { + const char * name; + + void (*initialize)(strategy_entry_t * entry); + + void (*finalize)(strategy_entry_t * entry); + + nexthops_t * (*lookup_nexthops)(strategy_entry_t * entry, nexthops_t * nexthops, + const msgbuf_t * msgbuf); + + void (*add_nexthop)(strategy_entry_t * strategy, unsigned nexthop, strategy_nexthop_state_t * state); + + void (*remove_nexthop)(strategy_entry_t * entry, unsigned nexthop, strategy_nexthop_state_t * state); + + void (*on_data)(strategy_entry_t * entry, const nexthops_t * nexthops, + const msgbuf_t * msgbuf, Ticks pitEntryCreation, Ticks objReception); + + void (*on_timeout)(strategy_entry_t * entry, const nexthops_t * 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 /* HICN_STRATEGY_VFT_H */ diff --git a/hicn-light/src/hicn/core/system.h b/hicn-light/src/hicn/core/system.h index be6c3e7cf..b47113f70 100644 --- a/hicn-light/src/hicn/core/system.h +++ b/hicn-light/src/hicn/core/system.h @@ -25,7 +25,6 @@ #define system_h #include <hicn/core/forwarder.h> -#include <hicn/utils/interfaceSet.h> /** * @function system_Interfaces diff --git a/hicn-light/src/hicn/core/ticks.h b/hicn-light/src/hicn/core/ticks.h index 8750abde5..bebcd3635 100644 --- a/hicn-light/src/hicn/core/ticks.h +++ b/hicn-light/src/hicn/core/ticks.h @@ -25,7 +25,40 @@ #define __STDC_FORMAT_MACROS #include <stdint.h> +#include <time.h> + +#include <sys/param.h> // HZ + 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, &mts); + 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..5a6c876b9 100644 --- a/hicn-light/src/hicn/core/wldr.c +++ b/hicn-light/src/hicn/core/wldr.c @@ -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,42 @@ 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 * conn, 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 +164,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 +176,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 * conn, + 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 +192,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..cb2f0e2cf 100644 --- a/hicn-light/src/hicn/core/wldr.h +++ b/hicn-light/src/hicn/core/wldr.h @@ -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,18 @@ // 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 * conn, msgbuf_t * msgbuf); -void wldr_HandleWldrNotification(Wldr *wldr, const Connection *conn, - Message *message); +void wldr_handle_notification(wldr_t *wldr, const connection_t * conn, + 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..d7e6977d6 100644 --- a/hicn-light/src/hicn/io/CMakeLists.txt +++ b/hicn-light/src/hicn/io/CMakeLists.txt @@ -14,40 +14,21 @@ 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 + ${CMAKE_CURRENT_SOURCE_DIR}/hicn.c + ${CMAKE_CURRENT_SOURCE_DIR}/tcp.c + ${CMAKE_CURRENT_SOURCE_DIR}/udp.c ) -if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - list(APPEND SOURCE_FILES - io/hicnTunnel.c - io/hicnConnection.c - io/hicnListener.c - ) -endif() +#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} @@ -56,4 +37,4 @@ set(TO_INSTALL_HEADER_FILES ) 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/hicn.c b/hicn-light/src/hicn/io/hicn.c new file mode 100644 index 000000000..a239dc781 --- /dev/null +++ b/hicn-light/src/hicn/io/hicn.c @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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/core/listener.h> +#include <hicn/core/listener_vft.h> +#include <hicn/core/connection.h> +#include <hicn/core/connection_vft.h> +#include <hicn/core/connection_table.h> +#include <hicn/core/forwarder.h> +#include <hicn/core/mapme.h> +#include <hicn/core/messagePacketType.h> +#include <hicn/socket/api.h> +#include <hicn/util/log.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; + +static +void +listener_hicn_read_callback(listener_t * listener, int fd, void * data) +{ + assert(listener); + assert(!data); /* No user data */ + uint8_t packet[MTU_SIZE]; + + int family = address_family(&listener->address); + if ((family != AF_INET) && (family != AF_INET6)) { + /* + * We need to discard the frame. Read 1 byte. This will clear it off + * the stack. + */ + int nread = read(fd, packet, 1); + + if (nread > 0) { + DEBUG("Discarded frame from fd %d", fd); + } else if (nread < 0) { + ERROR("Error trying to discard frame from fd %d: (%d) %s", fd, errno, + strerror(errno)); + } + return; + } + +#if 0 + if (!(what & PARCEventType_Read)) + return; +#endif + + ssize_t n = read(fd, packet, MTU_SIZE); + if (n < 0) { + ERROR("read failed %d: (%d) %s", fd, errno, strerror(errno)); + return; + } + +#if 0 + address_t packet_addr; + if (_createAddressFromPacket(packet, &packet_addr) < 0) + return; + + address_pair_t pair_find = { + .local = packet_addr, + .remote = /* dummy */ hicn->localAddress, + }; + const Connection *conn = _lookupConnection(listener, &pair_find); + if (!conn) { + address_pair_t pair = { + .local = hicn->localAddress, + .remote = packet_addr, + }; + connid = _createNewConnection(listener, fd, &pair); + } else { + connid = connection_GetConnectionId(conn); + } +#endif + + listener_read_callback(listener->forwarder, listener, fd, &listener->address, packet, n); +} + +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(pair); + + /* ... */ + + return -1; + +} + +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 +int +connection_hicn_send(const connection_t * connection, msgbuf_t * msgbuf, + bool queue) +{ + assert(connection); + /* msgbuf can be NULL */ + +// connection_hicn_data_t * data = connection->data; +// assert(data); + + /* ... */ + + return true; +} + +//static +//int +//connection_hicn_sendv(const connection_t * connection, struct iovec * iov, +// size_t size) +//{ +// +// assert(connetion); +// assert(iov); +// +//// connection_hicn_data_t * data = connection->data; +//// assert(data); +// +// /* ... */ +// +// return 0; +//} +// +static +int +connection_hicn_send_packet(const connection_t * connection, const uint8_t * packet, size_t size) +{ + assert(ops); + assert(packet); + + /* ... */ + + return 0; +} + +static +void +connection_hicn_read_callback(connection_t * connection, int fd, void * data) +{ + ERROR("Unexpected read callback for hicn connection"); + return; +} + +DECLARE_CONNECTION(hicn); 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..03911e556 --- /dev/null +++ b/hicn-light/src/hicn/io/tcp.c @@ -0,0 +1,563 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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/core/connection.h> +#include <hicn/core/connection_vft.h> +#include <hicn/core/listener.h> +#include <hicn/core/listener_vft.h> +#include <hicn/core/msgbuf.h> +#include <hicn/core/forwarder.h> + +#include <hicn/core/messageHandler.h> + +#include <hicn/utils/commands.h> +#include <hicn/util/log.h> + +#include <hicn/hicn.h> +// 128 KB output queue +#define OUTPUT_QUEUE_BYTES (128 * 1024) + +#define RECV_BUFLEN 8192 +#define MTU 1500 + +// XXX TODO what is exactly an eventqueue +// XXX TODO can't we write directly to the socket ? + +/****************************************************************************** + * Listener + ******************************************************************************/ + +typedef struct { +} 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; + +} + +static +void +listener_tcp_read_callback(listener_t * listener, int fd, void * data) +{ + ERROR("[listener_tcp_read_callback] Not implemented"); + +} + +DECLARE_LISTENER(tcp); + +/****************************************************************************** + * Connection + ******************************************************************************/ + + +typedef struct { + /* Partial receive buffer */ + u8 buf[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, forwarder_t *forwarder, int fd, + address_pair_t *pair, bool local, unsigned connection_id) +{ + assert(connection); + assert(forwarder); + + *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 */ + + .forwarder = forwarder, + .closed = false, + }; + + // XXX this new connection needs to be registered + //char *str = pair_ToString(udp->pair); + INFO("%s connection %p created for address %s (local=%s)", + face_type_str(connection->type), connection, "N/A", + connection_is_local(connection) ? "true" : "false"); + //free(str); + + 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; + } + + //char *pair_str = address_pair_ToString(pair); + INFO("%s connection %p connect for address pair %s", + face_type_str(connection->type), connection, "N/A"); + //free(pair_str); + + 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 + +/** + * @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 +int +connection_tcp_send(const connection_t * connection, //const address_t * address, + msgbuf_t * msgbuf, bool queue) +{ + assert(connection); + assert(address); + /* msgbuf can be NULL */ + + /* No need to flush */ + if (!msgbuf) + return true; + + if (!connection_is_up(connection)) { + ERROR("Connection #%u tried to send to down connection (up=%d closed=%d)", + connection_get_id(connection), + connection_is_up(connection) ? "true" : "false", + connection_is_closed(connection) ? "true" : "false"); + return false; + } + + // XXX TODO write to fd +#if 0 + PARCEventBuffer *buffer = + parcEventBuffer_GetQueueBufferOutput(connection->events); + size_t buffer_backlog = parcEventBuffer_GetLength(buffer); + parcEventBuffer_Destroy(&buffer); + + if (buffer_backlog >= OUTPUT_QUEUE_BYTES) { + WARN("Connection #%u Writing to buffer backlog %zu bytes DROP MESSAGE", + connection_get_id(connection), buffer_backlog); + return false; + } + + DEBUG("Connection #%u Writing %zu bytes to buffer with backlog %zu bytes", + connection_get_id(connection), msgbuf_len(message), buffer_backlog); + + return (parcEventQueue_Write(connection->events, msgbuf_packet(message), + msgbuf_len(message)) == 0); +#endif + return true; +} + +static +int +connection_tcp_send_packet(const connection_t * connection, + const uint8_t * packet, size_t size) +{ + /* Not implemented for local connections */ + // XXX shall we set the pointer to NULL and add a check ? + + ERROR("[connection_tcp_send_packet] Not implemented"); + + return -1; +} + +// ================================================================= +// the actual I/O functions + +// not needed anymore ? +#if 0 +// XXX this is called iif there is sufficient data to read, otherwise it raises +// an assertion error. This was a problem before I guess +static +int +connection_tcp_read_message(connection_t * connection, msgbuf_t * msgbuf) +{ + assert(connection); + assert(msgbuf); + + connection_tcp_data_t * data = connection->data; + assert(data); + + size_t n = evbuffer_get_length(data->evbuffer); + // XXX this check was wrong + // parcAssertTrue(n >= sizeof(header_control_message), + "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(header_control_message)); + + // 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#> + */ +static +void +connection_tcp_read_callback(connection_t * connection, int fd, void * user_data) +{ + assert(!!(what & PARCEventType_Read)); + assert(connection_void); + + connection_tcp_data_t * data = connection->data; + assert(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, + 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(connection->forwarder, 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 (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; +} + +#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..2baae1e5b --- /dev/null +++ b/hicn-light/src/hicn/io/udp.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file udp.c + * #brief Implementation of the UDP face + * + * Old comment: + * - The Send() function may overflow the output buffer + * + */ + +/* This has to be included early as other modules are including socket.h */ + +#ifndef _WIN32 +#include <arpa/inet.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <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/core/address_pair.h> +#include <hicn/core/connection.h> +#include <hicn/core/connection_vft.h> +#include <hicn/core/listener.h> +#include <hicn/core/listener_vft.h> +#include <hicn/base/loop.h> +#include <hicn/core/msgbuf.h> +#include <hicn/core/forwarder.h> +#include <hicn/core/messageHandler.h> +#include <hicn/core/messagePacketType.h> +#include <hicn/hicn-light/config.h> +#include <hicn/util/log.h> + +// Batching based on recvmmsg is also generic +// the difference is the handling of packet as in tcp we need to go through the +// ring buffer first to do the framing, while in UDP this is already done +// +// each module should have a function to process a packet, then call a callback +// in the forwarder again + +#define BATCH_SOCKET_BUFFER 512 * 1024 /* 256k */ + + +/****************************************************************************** + * Listener + ******************************************************************************/ + +typedef struct { + uint16_t port; // in address ? + + batch_buffer_t bb; +} listener_udp_data_t; + +#ifdef __ANDROID__ +extern int bindSocket(int sock, const char * interface_name); +#endif + +#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; +} + +/* 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_REUSEADDR, &(int){1}, sizeof(int)) < 0) { + perror("setsockopt"); + return -1; + } + +#ifdef WITH_GSO +//● choosing gso_size +//○ ETH_DATA_LEN +//○ IP_MTU_DISCOVER +//● choosing number of segments +//○ fit in network layer +//○ <= UDP_MAX_SEGMENTS +//○ > gso_size +//● checksum offload +//○ csum_and_copy_from_user + 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, + strlen(interface_name) + 1) < 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); + + listener_udp_data_t * data = listener->data; + assert(data); + + init_batch_buffers(&data->bb); + + // XXX Socket creation should be a function per-se and not be called in + // initialize ! + listener->fd = listener_get_socket(listener, &listener->address, NULL, + listener->interface_name); + if (listener->fd < 0) { + ERROR("Error creating UDP socket: (%d) %s", errno, strerror(errno)); + return -1; + } + return 0; +} + +static +void +listener_udp_finalize(listener_t * listener) +{ + assert(listener); + assert(listener_get_type(listener) == FACE_TYPE_UDP); + + 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(remote), 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(remote)) < 0) { + perror("bind"); + goto ERR; + } + +#ifdef __linux__ + if (socket_bind_to_device(fd, interface_name) < 0) { + goto ERR; + } +#endif /* __linux__ */ + + if (remote) { + 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; +} + +static +void +listener_udp_read_callback(listener_t * listener, int fd, void * user_data) +{ + assert(listener); + assert(!user_data); + + listener_udp_data_t * data = listener->data; + assert(data); + + listener_batch_read_callback(listener->forwarder, listener, fd, &listener->address, &data->bb); +} + +DECLARE_LISTENER(udp); + +/****************************************************************************** + * Connection + ******************************************************************************/ + +typedef struct { + batch_buffer_t bb; + int queue_len; +} connection_udp_data_t; + +static +int +connection_udp_initialize(connection_t * connection) +{ + + assert(connection); + assert(connection->type == FACE_TYPE_UDP); + assert(interface_name); + assert(address_pair); + + connection_udp_data_t * data = connection->data; + assert(data); + + init_batch_buffers(&data->bb); + + data->queue_len = 0; + + return 0; +} + +static +void +connection_udp_finalize(connection_t * connection) +{ + ERROR("[connection_udp_finalize] Not implemented"); + +} + +/** + * @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#> + */ +// XXX address not used anywhere +static +int +connection_udp_send(const connection_t * connection, msgbuf_t * msgbuf, bool queue) +{ + assert(connection); + /* msgbuf can be NULL */ + + connection_udp_data_t * data = connection->data; + assert(data); + + /* Flush if required or if queue is full */ + if ((!msgbuf) || (queue && (data->queue_len > MAX_MSG))) { + /* Flush operation */ +#ifdef WITH_ZEROCOPY + int flags = MSG_ZEROCOPY; +#else + int flags = 0; +#endif /* WITH_ZEROCOPY */ + int n = sendmmsg(connection->fd, data->bb.msghdr, data->queue_len, flags); + if (n == -1) { + perror("sendmmsg()"); + data->queue_len = 0; + return false; + } + + if (n < data->queue_len) { + // XXX TODO + printf("Unhandled Error after sending n=%d msgbufs\n", n); + } + + /* XXX check msglen */ + data->queue_len = 0; + return true; + } + + if (queue) { + struct iovec *iovec = &data->bb.iovecs[data->queue_len++]; + iovec->iov_base = msgbuf_get_packet(msgbuf); + iovec->iov_len = msgbuf_get_len(msgbuf); + + } else { + ssize_t writeLength = write(connection->fd, msgbuf_get_packet(msgbuf), + msgbuf_get_len(msgbuf)); + + if (writeLength < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return false; + } else { + // this print is for debugging + printf("Incorrect write length %zd, expected %u: (%d) %s\n", writeLength, + msgbuf_get_len(msgbuf), errno, strerror(errno)); + return false; + } + } + } + + return true; +} + +#if 0 +static +bool +connection_udp_sendv(const connection_t * connection, struct iovec * iov, + size_t size) +{ + + assert(connetion); + assert(iov); + + connection_udp_data_t * data = connection->data; + assert(data); + +#ifndef _WIN32 + // Perform connect before to establish association between this peer and + // the remote peer. This is required to use writev. + // Connection association can be changed at any time. + + if (writev(connection->fd, iov, (int)size) < 0) + return false; +#else + WSABUF *buf = (WSABUF *) malloc(size * sizeof(WSABUF)); + + DWORD bytes_sent = 0; + + for (int i = 0; i < size; i++) { + buf[i].buf = iov[i].iov_base; + buf[i].len = (ULONG)iov[i].iov_len; + } + + int rc = WSASendTo(udp->fd, buf, size, &bytes_sent, 0, + (SOCKADDR *)address_sa(address_pair_remote(&udp->pair)), + address_socklen(address_pair_remote(&udp->pair)), NULL, NULL); + free(dataBuf); + if (rc == SOCKET_ERROR) + return false; +#endif + + return true; +} +#endif + +static +int +connection_udp_send_packet(const connection_t * connection, const uint8_t * packet, size_t size) +{ + assert(ops); + assert(packet); + + if(connection_is_local(connection)) + return -1; + + ssize_t n = sendto(connection->fd, packet, size, 0, + address_sa(address_pair_get_remote(&connection->pair)), + address_socklen(address_pair_get_remote(&connection->pair))); + if (n < 0) + return -1; + return 0; +} + +static +void +connection_udp_read_callback(connection_t * connection, int fd, void * user_data) +{ + assert(connection); + assert(!user_data); + + connection_udp_data_t * data = connection->data; + assert(data); + listener_batch_read_callback(connection->forwarder, NULL, fd, address_pair_get_local(&connection->pair), &data->bb); +} + +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/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/linux/system.c b/hicn-light/src/hicn/platforms/linux/system.c index 3bf23cf57..31a8d79b2 100644 --- a/hicn-light/src/hicn/platforms/linux/system.c +++ b/hicn-light/src/hicn/platforms/linux/system.c @@ -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/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/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/strategies/CMakeLists.txt b/hicn-light/src/hicn/strategies/CMakeLists.txt index 400efcde9..d7a5e7333 100644 --- a/hicn-light/src/hicn/strategies/CMakeLists.txt +++ b/hicn-light/src/hicn/strategies/CMakeLists.txt @@ -14,20 +14,15 @@ 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}/low_latency.h + ${CMAKE_CURRENT_SOURCE_DIR}/random.h ) list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/loadBalancer.c - ${CMAKE_CURRENT_SOURCE_DIR}/lowLatency.c - ${CMAKE_CURRENT_SOURCE_DIR}/nexthopState.c - ${CMAKE_CURRENT_SOURCE_DIR}/nexthopStateLowLatency.c - ${CMAKE_CURRENT_SOURCE_DIR}/rnd.c + ${CMAKE_CURRENT_SOURCE_DIR}/load_balancer.c + ${CMAKE_CURRENT_SOURCE_DIR}/low_latency.c + ${CMAKE_CURRENT_SOURCE_DIR}/random.c ) set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) 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..9f4ba825d --- /dev/null +++ b/hicn-light/src/hicn/strategies/load_balancer.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + +#define NEXTHOP_STATE_INIT { \ + .pi = 0, \ + .avg_pi = 0.0, \ + .weight = 1, \ +} + +/* Shorthand */ +#define nexthop_state_t strategy_load_balancer_nexthop_state_t + +#define update_state(state) \ +do { \ + 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; \ +} while(0) + +#define update_state_inc(state) \ +do { \ + state->pi++; \ + update_state(state); \ +} while(0) + +#define update_state_dec(state) \ +do { \ + if (state->pi > 0) \ + state->pi--; \ + update_state(state); \ +} while(0) + +#if 0 +#define reset_all(nexthops, nexthops_state) \ +do { \ + unsigned _lb_var(nexthop); \ + nexthops_foreach((state), _lb_var(nexthop), { \ + (nexthop) = NEXTHOP_STATE_INIT; \ + }); \ +} while(0) +#else +#define reset_all(state) +#endif + +static +void +strategy_load_balancer_initialize(strategy_entry_t * entry) +{ + // XXXreset_all(entry->state); + // XXX TODO initialize nexthops + // XXX maybe merge with nexthop data structure +} + +static +void +strategy_load_balancer_finalize(strategy_entry_t * entry) +{ + /* Nothing to do */ +} + +static +void +strategy_load_balancer_add_nexthop(strategy_entry_t * entry, unsigned nexthop, + strategy_nexthop_state_t * state) +{ + // Create and reset associated state + // if this is really a new nexthop + // XXX assume nexthop is inserted before + reset_all(state); +} + +static +void +strategy_load_balancer_remove_nexthop(strategy_entry_t * entry, unsigned + nexthop, strategy_nexthop_state_t * state) +{ + reset_all(state); +} + +static +nexthops_t * +strategy_load_balancer_lookup_nexthops(strategy_entry_t * entry, + nexthops_t * nexthops, const msgbuf_t * msgbuf) +{ +// TEMP + nexthop_state_t * state = NULL; + + /* Compute the sum of weights of potential next hops */ + double sum = 0; + unsigned i, nexthop; + nexthops_enumerate(nexthops, i, nexthop, { + (void)nexthop; + sum += nexthops_state(nexthops, i).load_balancer.weight; + }); + + /* Perform weighted random selection */ + double distance = (double)rand() * sum / ((double)RAND_MAX + 1); + + nexthops_enumerate(nexthops, i, nexthop, { + // XXX distance -= nexthop_state(nexthops, i).weight; + if (distance < 0) { + nexthops_select(nexthops, i); + update_state_inc(state); // XXX + break; + } + }); + return nexthops; +} + +static +void +strategy_load_balancer_on_timeout(strategy_entry_t * entry, + const nexthops_t * 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. + */ +// XXX TODO +#if 0 + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + // XXX TODO leverage coexistence between nexthop and state + if (correct_nexthop_id(nexthop)) + update_state_dec(&entry.state.nexthop_state); + }); +#endif +} + +static +void +strategy_load_balancer_on_data(strategy_entry_t * entry, + const nexthops_t * nexthops, const msgbuf_t * msgbuf, + Ticks pitEntryCreation, Ticks objReception) +{ + strategy_load_balancer_on_timeout(entry, nexthops); +} + +DECLARE_STRATEGY(load_balancer); + +#undef nexthop_state_t diff --git a/hicn-light/src/hicn/core/connectionState.h b/hicn-light/src/hicn/strategies/load_balancer.h index 9daa15c9c..f2acc205e 100644 --- a/hicn-light/src/hicn/core/connectionState.h +++ b/hicn-light/src/hicn/strategies/load_balancer.h @@ -14,24 +14,20 @@ */ /** - * @file connection_state.h - * @brief Represents the state of a connection - * + * Forward on the less loaded path */ -#ifndef connection_state_h -#define connection_state_h +#ifndef HICNLIGHT_STRATEGY_LOAD_BALANCER_H +#define HICNLIGHT_STRATEGY_LOAD_BALANCER_H + +typedef struct { + unsigned int pi; + double avg_pi; + double weight; +} strategy_load_balancer_nexthop_state_t; -#define foreach_connection_state \ - _(UNDEFINED) \ - _(DOWN) \ - _(UP) \ - _(N) +typedef struct {} strategy_load_balancer_state_t; -typedef enum { -#define _(x) CONNECTION_STATE_ ## x, -foreach_connection_state -#undef _ -} connection_state_t; +typedef struct {} strategy_load_balancer_options_t; -#endif /* connection_state_h */ +#endif /* HICNLIGHT_STRATEGY_LOAD_BALANCER_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/low_latency.c b/hicn-light/src/hicn/strategies/low_latency.c new file mode 100644 index 000000000..9f7ecb89c --- /dev/null +++ b/hicn-light/src/hicn/strategies/low_latency.c @@ -0,0 +1,783 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if 0 + +#include <hicn/hicn-light/config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <math.h> + +#include <hicn/base/khash.h> + +#include <parc/assert/parc_Assert.h> +#include <parc/algol/parc_HashMap.h> +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_Object.h> +#include <parc/algol/parc_Unsigned.h> + +#include <hicn/core/messageHandler.h> + +#include "low_latency.h" + +#define STABILITY_FACTOR 15 +#define MAX_SWITCH_TRY 10 +#define MAX_LATENCY_DIFF 10 +#define MAX_TOLLERATED_LATENCY_DIFF 15 +#define MAX_ROUNDS_MP_WITHOUT_CHECK 2 +#define MAX_ROUNDS_AVOIDING_MULTIPATH 40 /* about 20 sec */ +#define MAX_ROUNDS_WITH_ERROR 4 +#define PROBE_LIFETIME 500 /* ms */ + +#define MAX_ROUNS_WITHOUT_PROBES 4 + +/* + * If we do not receives probes for 4 rounds it means that we had no responce + * from any producer for 2 sec we can say that this interface is daed + */ +#define MIN_NON_LOSSY_ROUNDS 10 + +/* + * Number of rounds in non lossy mode before switch to no lossy state + * Defaults to 10 % + */ +#define MAX_LOSS_RATE 0.10 + +/* Shorthands */ +#define nexthop_state_t strategy_low_latency_nexthop_state_t +#define state_t strategy_low_latency_state_t + +#define NEXTHOP_STATE_INIT { \ + .in_use = false, \ + .is_allowed = true, \ + .sent_packets = 0, \ + .last_try_to_switch_round = 0, \ + .try_to_switch_counter = 0, \ + .recevied_probes = 0, \ + .rounds_without_probes = 0, \ + .sent_probes = 0, \ + .lost_probes = 0, \ + .non_lossy_rounds = MIN_NON_LOSSY_ROUNDS, \ + .avg_rtt = -1.0, \ + .avg_rtt_in_use = -1.0, \ + .avg_queue = 0.0001, \ + .avg_loss_rate = 0.0, \ +} + +// XXX ???? +#define STATE_INIT { \ +} + +static + void +strategy_low_latency_SendProbesCB(int fd, PARCEventType which_event, void *data) +{ + parcAssertTrue(which_event & PARCEventType_Timeout, + "Event incorrect, expecting %X set, got %X", + PARCEventType_Timeout, which_event); + + StrategyLowLatency *ll = (StrategyLowLatency *) data; + + //delete old pending probes + if(parcHashMap_Size(ll->pending_probes_ticks) != 0){ + Ticks now = forwarder_GetTicks(ll->forwarder); + PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->pending_probes_ticks); + NumberSet *to_remove = numberSet_Create(); + while(parcIterator_HasNext(iterator)) { + PARCUnsigned *parc_seq = (PARCUnsigned *) parcIterator_Next(iterator); + PARCUnsigned *parc_time = (PARCUnsigned *) parcHashMap_Get(ll->pending_probes_ticks, parc_seq); + Ticks sent_time = parcUnsigned_GetUnsigned(parc_time); + if((now - sent_time) > PROBE_LIFETIME){ + //probes to delete + numberSet_Add(to_remove, parcUnsigned_GetUnsigned(parc_seq)); + } + } + parcIterator_Release(&iterator); + + for(int i = 0; i < numberSet_Length(to_remove); i++){ + PARCUnsigned *prob_seq = parcUnsigned_Create(numberSet_GetItem(to_remove,i)); + PARCUnsigned *cid = (PARCUnsigned *) parcHashMap_Get(ll->pending_probes_faces, prob_seq); + StrategyNexthopStateLL *state = + (StrategyNexthopStateLL *) parcHashMap_Get(ll->strategy_state, cid); + strategyNexthopStateLL_LostProbe(state); + parcHashMap_Remove(ll->pending_probes_ticks, prob_seq); + parcHashMap_Remove(ll->pending_probes_faces, prob_seq); + parcUnsigned_Release(&prob_seq); + } + numberSet_Release(&to_remove); + } + + ConnectionTable * ct = forwarder_GetConnectionTable(ll->forwarder); + + PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); + while(parcIterator_HasNext(iterator)){ + PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); + Connection *conn = + (Connection *)connectionTable_FindById(ct, + parcUnsigned_GetUnsigned(cid)); + if(!conn) + continue; + + StrategyNexthopStateLL *state = + (StrategyNexthopStateLL *) parcHashMap_Get(ll->strategy_state, cid); + + //probe only usable paths + if(!strategyNexthopStateLL_IsAllowed(state)) + continue; + + uint32_t seq = rand(); + messageHandler_SetProbeName(ll->probe, HF_INET6_TCP, + ll->name, seq); + connection_Probe(conn, ll->probe); + + PARCUnsigned *parc_seq = parcUnsigned_Create(seq); + Ticks now = forwarder_GetTicks(ll->forwarder); + PARCUnsigned *parc_time = parcUnsigned_Create((unsigned int)now); + parcHashMap_Put(ll->pending_probes_ticks, parc_seq, parc_time); + parcHashMap_Put(ll->pending_probes_faces, parc_seq, cid); + strategyNexthopStateLL_SentProbe(state); + parcUnsigned_Release(&parc_seq); + parcUnsigned_Release(&parc_time); + } + parcIterator_Release(&iterator); + + struct timeval timeout = {0,50000}; + parcEventTimer_Start(ll->sendProbes, &timeout); +} + +static +void +strategy_low_latency_SendMapmeUpdate(StrategyLowLatency *ll, + const NumberSet * nexthops){ + MapMe * mapme = forwarder_getMapmeInstance(ll->forwarder); + FIB * fib = forwarder_getFib((Forwarder*) ll->forwarder); + for(unsigned i = 0; i < ll->related_prefixes_len; i++){ + FibEntry *fibEntry = fib_MatchName(fib, ll->related_prefixes[i]); + if (!fibEntry) + continue; + mapme_maybe_send_to_nexthops(mapme, fibEntry, nexthops); + } +} + +static +void +strategy_low_latency_SelectBestFaces(StrategyLowLatency *ll, bool new_round) +{ + + StrategyNexthopStateLL * old_faces[2]; + old_faces[0] = ll->bestFaces[0]; + old_faces[1] = ll->bestFaces[1]; + + if(new_round){ + ll->round++; + } + + if(parcHashMap_Size(ll->strategy_state) == 0){ + ll->bestFaces[0] = NULL; + ll->bestFaces[1] = NULL; + ll->use2paths = false; + goto NEW_ROUND; + } + + if(ll->use2paths && ll->bestFaces[0] != NULL && ll->bestFaces[1] != NULL){ + //multipath case + + if(!strategyNexthopStateLL_IsLossy(ll->bestFaces[0]) + && !strategyNexthopStateLL_IsLossy(ll->bestFaces[1]) + && strategyNexthopStateLL_IsAllowed(ll->bestFaces[0]) + && strategyNexthopStateLL_IsAllowed(ll->bestFaces[1])){ + + if(ll->rounds_in_multipath < MAX_ROUNDS_MP_WITHOUT_CHECK){ + //we are at the first rounds of the multipath let's wait a bit + //(MAX_ROUNDS_MP_WITHOUT_CHECK) to make the queuing converge + ll->rounds_in_multipath++; + goto NEW_ROUND; + } + + //we need to decide if we want ot keep using two paths or not + ll->rounds_in_multipath++; + double rtt0 = strategyNexthopStateLL_GetRTTLive(ll->bestFaces[0]); + double rtt1 = strategyNexthopStateLL_GetRTTLive(ll->bestFaces[1]); + double diff = fabs(rtt0 - rtt1); + + if(diff < MAX_LATENCY_DIFF){ + //everything is working, keep using the two paths + ll->rounds_with_error = 0; + goto NEW_ROUND; + } + + //check for how many rounds we had problems + if(ll->rounds_with_error < MAX_ROUNDS_WITH_ERROR && + diff < MAX_TOLLERATED_LATENCY_DIFF){ + //we can tollerate few round with errors + ll->rounds_with_error++; + goto NEW_ROUND; + } + + //prevent the usage of multiple paths + ll->rounds_with_error = 0; + ll->avoid_multipath = true; + ll->rounds_avoiding_multipath = 0; + } //else + //at least one of the two path is lossy + //or it is not allowed by the policies. + //search for a better possibility + } + + ll->bestFaces[0] = NULL; + ll->bestFaces[1] = NULL; + + //check if there is at least one non lossy connection + PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); + bool check_losses = true; + bool found_good_face = false; + while(parcIterator_HasNext(iterator) && !found_good_face){ + PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); + const StrategyNexthopStateLL *state = parcHashMap_Get(ll->strategy_state, cid); + if(!strategyNexthopStateLL_IsLossy(state) && + strategyNexthopStateLL_IsAllowed(state)){ + found_good_face = true; + } + } + parcIterator_Release(&iterator); + if(!found_good_face){ + // all the available faces are lossy, so we take into account only + // the latency computed with the probes + check_losses = false; + } + + if(ll->bestFaces[0] == NULL){ + //try to take a random face + PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); + bool face_found = false; + while(parcIterator_HasNext(iterator) && !face_found) { + PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); + StrategyNexthopStateLL *state = (StrategyNexthopStateLL *) + parcHashMap_Get(ll->strategy_state, cid); + + if((check_losses && strategyNexthopStateLL_IsLossy(state)) || + !strategyNexthopStateLL_IsAllowed(state)){ + //skip the face + continue; + } + + ll->bestFaces[0] = state; + face_found = true; + } + parcIterator_Release(&iterator); + } + + if(ll->bestFaces[0] == NULL){ + //no usable face exists + ll->bestFaces[0] = NULL; + ll->bestFaces[1] = NULL; + ll->use2paths = false; + goto NEW_ROUND; + } + + double bestRtt = strategyNexthopStateLL_GetRTTLive(ll->bestFaces[0]); + + if(ll->avoid_multipath) + ll->rounds_avoiding_multipath++; + + if(ll->rounds_avoiding_multipath > MAX_ROUNDS_AVOIDING_MULTIPATH){ + ll->avoid_multipath = false; + ll->rounds_avoiding_multipath = 0; + } + + iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); + while (parcIterator_HasNext(iterator)) { + + PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); + StrategyNexthopStateLL *state = (StrategyNexthopStateLL *) + parcHashMap_Get(ll->strategy_state, cid); + double rtt = strategyNexthopStateLL_GetRTTLive(state); + + if((check_losses && strategyNexthopStateLL_IsLossy(state)) || + !strategyNexthopStateLL_IsAllowed(state)){ + //skip the face + continue; + } + + if(rtt + STABILITY_FACTOR < bestRtt){ + //maybe we found a better face + double rttInUse = strategyNexthopStateLL_GetRTTInUse(state); + unsigned try = strategyNexthopStateLL_GetTryToSwitch(state); + + //we check the rtt in use to check if the new face that we found + //gets congested when we use it to send the traffic + if(rttInUse < bestRtt || try > MAX_SWITCH_TRY){ + //we have a new best face! + strategyNexthopStateLL_ResetTryToSwitch((StrategyNexthopStateLL*) state); + bestRtt = rtt; + if(ll->bestFaces[0] != NULL) + strategyNexthopStateLL_SetUnusedFace(ll->bestFaces[0]); + ll->bestFaces[0] = (StrategyNexthopStateLL*) state; + }else{ + //in this case we should switch but we wait MAX_SWITCH_TRY + //before switch to avoid ossillations between different paths + strategyNexthopStateLL_IncreaseTryToSwitch( + (StrategyNexthopStateLL*) state, ll->round); + } + } + } + + parcIterator_Release(&iterator); + + if(ll->bestFaces[0] == NULL){ + //we found no face so return + ll->bestFaces[0] = NULL; + ll->bestFaces[1] = NULL; + ll->use2paths = false; + goto NEW_ROUND; + } + + if(parcHashMap_Size(ll->strategy_state) == 1 || ll->avoid_multipath){ + //in this case (one face available or avoid multipath) we stop the + //search here. Just reset face 1 if needed + if(ll->bestFaces[1] != NULL){ + strategyNexthopStateLL_SetUnusedFace(ll->bestFaces[1]); + ll->bestFaces[1] = NULL; + } + ll->use2paths = false; + goto NEW_ROUND; + } + + //if we are here we have more than 1 interface, so we search for a second one + //to use in case of multipath + iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); + while (parcIterator_HasNext(iterator)) { + PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); + if(parcUnsigned_GetUnsigned(cid) != + strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])){ + + StrategyNexthopStateLL *state = (StrategyNexthopStateLL *) + parcHashMap_Get(ll->strategy_state, cid); + + if((check_losses && strategyNexthopStateLL_IsLossy(state)) || + !strategyNexthopStateLL_IsAllowed(state)){ + //skip the face + continue; + } + + if(ll->bestFaces[1] == NULL){ + //in case of 2 faces we should pass always here + ll->bestFaces[1] = state; + }else{ + //TODO this must be tested with more then 2 faces + double rtt1 = strategyNexthopStateLL_GetRTTLive(ll->bestFaces[1]); + double rttNewFace = strategyNexthopStateLL_GetRTTLive(state); + if(rttNewFace + STABILITY_FACTOR < rtt1){ + strategyNexthopStateLL_SetUnusedFace(ll->bestFaces[1]); + ll->bestFaces[1] = state; + } + } + } + } + parcIterator_Release(&iterator); + + if(ll->bestFaces[1] != NULL){ + //we are not using the second face yet so we use the normal rtt for comparison + double rtt0 = strategyNexthopStateLL_GetRTTProbe(ll->bestFaces[0]); + double rtt1 = strategyNexthopStateLL_GetRTTProbe(ll->bestFaces[1]); + double diff = fabs(rtt0 - rtt1); + if(diff < MAX_LATENCY_DIFF) { + //let's start to use 2 paths + ll->rounds_with_error = 0; + ll->use2paths = true; + ll->rounds_in_multipath = 0; + }else{ + //we use only one path + strategyNexthopStateLL_SetUnusedFace(ll->bestFaces[1]); + ll->bestFaces[1] = NULL; + ll->use2paths = false; + } + }else{ + ll->use2paths = false; + } + +NEW_ROUND: + { + Logger * log = forwarder_GetLogger(ll->forwarder); + if(log != NULL && + logger_IsLoggable(log, LoggerFacility_Strategy, PARCLogLevel_Info)){ + if(ll->use2paths){ + logger_Log(log, LoggerFacility_Strategy, PARCLogLevel_Info, + __func__, "use 2 paths. rtt face %d = %f queue = %f is_lossy = %d," + "rtt face %d = %f queue = %f is_lossy = %d\n", + strategyNexthopStateLL_GetFaceId(ll->bestFaces[0]), + strategyNexthopStateLL_GetRTTLive(ll->bestFaces[0]), + strategyNexthopStateLL_GetQueuing(ll->bestFaces[0]), + strategyNexthopStateLL_IsLossy(ll->bestFaces[0]), + strategyNexthopStateLL_GetFaceId(ll->bestFaces[1]), + strategyNexthopStateLL_GetRTTLive(ll->bestFaces[1]), + strategyNexthopStateLL_GetQueuing(ll->bestFaces[1]), + strategyNexthopStateLL_IsLossy(ll->bestFaces[1])); + }else{ + if(ll->bestFaces[0] != NULL){ + logger_Log(log, LoggerFacility_Strategy, + PARCLogLevel_Info, __func__, + "use 1 path. rtt face %d = %f is_lossy = %d, " + "(avoid multipath = %d)\n", + strategyNexthopStateLL_GetFaceId(ll->bestFaces[0]), + strategyNexthopStateLL_GetRTTLive(ll->bestFaces[0]), + strategyNexthopStateLL_IsLossy(ll->bestFaces[0]), + ll->avoid_multipath); + }else{ + logger_Log(log, LoggerFacility_Strategy, PARCLogLevel_Info, + __func__, "no face to use!\n"); + } + } + } + } + + //update the round only at the end for all the faces + if(new_round){ + PARCIterator * iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); + while (parcIterator_HasNext(iterator)) { + PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); + strategyNexthopStateLL_StartNewRound((StrategyNexthopStateLL *) + parcHashMap_Get(ll->strategy_state, cid)); + } + parcIterator_Release(&iterator); + } + + //mapme updates + //if ll->bestFaces[0] == NULL we don't have any output faces + //so don't need to send any updates since we are disconnected + if(ll->related_prefixes_len != 0){ + if(ll->bestFaces[0] != NULL){ + NumberSet *out = numberSet_Create(); + if(old_faces[0] == NULL || + (strategyNexthopStateLL_GetFaceId(ll->bestFaces[0]) != + strategyNexthopStateLL_GetFaceId(old_faces[0]))){ + //there is a new face 0 so we need a map me update + //if ll->bestFaces[1] != NULL we need to send the update + //even if it is the same as before + numberSet_Add(out, + strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); + if(ll->bestFaces[1] != NULL){ + numberSet_Add(out, + strategyNexthopStateLL_GetFaceId(ll->bestFaces[1])); + } + strategy_low_latency_SendMapmeUpdate(ll,out); + }else{ + if(ll->bestFaces[1] != NULL){ + if(old_faces[1] == NULL || + (strategyNexthopStateLL_GetFaceId(ll->bestFaces[1]) != + strategyNexthopStateLL_GetFaceId(old_faces[1]))){ + //send a mapme both with face 0 and face 1 + numberSet_Add(out, + strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); + numberSet_Add(out, + strategyNexthopStateLL_GetFaceId(ll->bestFaces[1])); + strategy_low_latency_SendMapmeUpdate(ll,out); + } + }else{ + if(old_faces[1] != NULL){ + //in the previuos round we were using two faces, now only one + //send update with only face 0 + numberSet_Add(out, + strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); + strategy_low_latency_SendMapmeUpdate(ll,out); + } + } + } + numberSet_Release(&out); + } + } +} + +static +void +strategy_low_latency_BestFaceCB(int fd, PARCEventType which_event, void *data) +{ + parcAssertTrue(which_event & PARCEventType_Timeout, + "Event incorrect, expecting %X set, got %X", + PARCEventType_Timeout, which_event); + + StrategyLowLatency * ll = (StrategyLowLatency *) data; + strategy_low_latency_SelectBestFaces(ll, true); + + struct timeval timeout = {0, 500000}; + parcEventTimer_Start(ll->computeBestFace, &timeout); +} + +static +void +_startTimers(strategy_entry_t * entry) +{ + struct timeval timeoutProbes = {0, 10000}; + struct timeval timeoutBF = {1, 0}; + + parcEventTimer_Start(entry->state.sendProbes, &timeoutProbes); + parcEventTimer_Start(entry->state.computeBestFace, &timeoutBF); +} + +static +void +_stopTimers(strategy_entry_t * entry) +{ + parcEventTimer_Stop(entry->state.sendProbes); + parcEventTimer_Stop(entry->state.computeBestFace); +} + +static +void +strategy_low_latency_initialize(strategy_entry_t * entry) +{ + srand((unsigned int)time(NULL)); + + /* XXX TODO Three hashmaps to initialize */ + strategy->strategy_state = parcHashMap_Create(); + strategy->pending_probes_ticks = parcHashMap_Create(); + strategy->pending_probes_faces = parcHashMap_Create(); + + Dispatcher *dispatcher = forwarder_GetDispatcher((Forwarder *)ll->forwarder); + ip_prefix_t address; + nameBitvector_ToIPAddress(name_GetContentName( + fibEntry_GetPrefix(fibEntry)), &address); + + entry->state = { + .probe = messageHandler_CreateProbePacket(HF_INET6_TCP, PROBE_LIFETIME), + .name = messageHandler_CreateProbeName(&address); + .sendProbes = dispatcher_CreateTimer(dispatcher, false, + strategy_low_latency_SendProbesCB, ll); + .round = 0; + .rounds_in_multipath = 0; + .rounds_with_error = 0; + .rounds_avoiding_multipath = 0; + .use2paths = false; + .avoid_multipath = false; + .computeBestFace = dispatcher_CreateTimer(dispatcher, false, + strategy_low_latency_BestFaceCB, ll); + .related_prefixes_len = related_prefixes_len; + // XXX TODO + .related_prefixes = malloc(sizeof(Name *) * related_prefixes_len); + }; + + for(unsigned i = 0; i < entry->state.related_prefixes_len; i++){ + entry->state.related_prefixes[i] = name_Copy(related_prefixes[i]); + } +} + +static +void +strategy_low_latency_finalize(strategy_entry_t * entry) +{ + _stopTimers(entry); + + parcEventTimer_Destroy(&(strategy->sendProbes)); + parcEventTimer_Destroy(&(strategy->computeBestFace)); + + if (parcHashMap_Size(strategy->strategy_state) > 0) { + PARCIterator *it = parcHashMap_CreateKeyIterator(strategy->strategy_state); + while (parcIterator_HasNext(it)) { + PARCUnsigned *cid = parcIterator_Next(it); + StrategyNexthopStateLL *state = + (StrategyNexthopStateLL *)parcHashMap_Get(strategy->strategy_state, cid); + parcObject_Release((void**)&state); + } + parcIterator_Release(&it); + } + + parcHashMap_Release(&(strategy->strategy_state)); + parcHashMap_Release(&(strategy->pending_probes_ticks)); + parcHashMap_Release(&(strategy->pending_probes_faces)); + + parcMemory_Deallocate(&(strategy->probe)); + parcMemory_Deallocate(&(strategy->name)); + + for(unsigned i = 0; i < strategy->related_prefixes_len; i++){ + name_Release(&(strategy->related_prefixes[i])); + } + free(strategy->related_prefixes); + + parcMemory_Deallocate((void **)&strategy); + parcMemory_Deallocate((void **)&impl); + *strategyPtr = NULL; +} + +static +void +strategy_low_latency_add_nexthop(strategy_entry_t * entry, unsigned nexthop, nexthop_state_t * state) +{ + PARCUnsigned *cid = parcUnsigned_Create(connectionId); + + StrategyLowLatency *ll = (StrategyLowLatency *)strategy->context; + + if (!parcHashMap_Contains(ll->strategy_state, cid)) { + StrategyNexthopStateLL *state = strategyNexthopStateLL_Create(connectionId); + parcHashMap_Put(ll->strategy_state, cid, state); + if(ll->bestFaces[0] == NULL){ + ll->bestFaces[0] = state; + } + } + + if(parcHashMap_Size(ll->strategy_state) >= 2){ + _startTimers(strategy); + } + + parcUnsigned_Release(&cid); +} + +static +void +strategy_low_latency_remove_nexthop(strategy_entry_t * entry, unsigned nexthop, nexthop_state_t * state) +{ + bool reset_bestFaces = false; + + if((entry->state.bestFaces[0] != NULL && + strategyNexthopStateLL_GetFaceId(entry->state.bestFaces[0]) == connectionId) || + (entry->state.bestFaces[1] != NULL && + strategyNexthopStateLL_GetFaceId(entry->state.bestFaces[1]) == connectionId)){ + reset_bestFaces = true; + } + + PARCUnsigned *cid = parcUnsigned_Create(connectionId); + + if (parcHashMap_Contains(entry->state.strategy_state, cid)) { + parcHashMap_Remove(entry->state.strategy_state, cid); + } + + if(reset_bestFaces){ + entry->state.bestFaces[0] = NULL; + entry->state.bestFaces[1] = NULL; + strategy_low_latency_SelectBestFaces(ll, false); + } + + if(parcHashMap_Size(entry->state.strategy_state) < 2){ + _stopTimers(strategy); + } + + parcUnsigned_Release(&cid); +} + +static +nexthops_t * +strategy_low_latency_lookup_nexthops(strategy_entry_t * entry, + const msgbuf_t * msgbuf) +{ + //unsigned out_connection; + NumberSet *out = numberSet_Create(); + + StrategyLowLatency *ll = (StrategyLowLatency *)strategy->context; + + //update is_allowed flag of all the next hops + PARCIterator *iterator = parcHashMap_CreateKeyIterator(ll->strategy_state); + while(parcIterator_HasNext(iterator)){ + PARCUnsigned *cid = (PARCUnsigned *) parcIterator_Next(iterator); + StrategyNexthopStateLL *state = + (StrategyNexthopStateLL *) parcHashMap_Get(ll->strategy_state, cid); + if(numberSet_Contains(nexthops, parcUnsigned_GetUnsigned(cid))){ + strategyNexthopStateLL_SetIsAllowed(state,true); + }else{ + strategyNexthopStateLL_SetIsAllowed(state,false); + } + } + parcIterator_Release(&iterator); + + if(ll->bestFaces[0] != NULL && + !strategyNexthopStateLL_IsAllowed(ll->bestFaces[0])){ + //if ll->bestFaces[0] is not allowed we need to find a new face + strategy_low_latency_SelectBestFaces(ll, false); + } + + //at this point ll->bestFaces[0] must be allowed + //single path case + if(ll->bestFaces[0] != NULL && (ll->bestFaces[1] == NULL || !ll->use2paths)){ + strategyNexthopStateLL_SendPacket(ll->bestFaces[0]); + numberSet_Add(out, strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); + + //multipath case + }else if(ll->bestFaces[0] != NULL && ll->bestFaces[1] != NULL && ll->use2paths){ + //it may happen that ll->bestFaces[1] is not allowed, in that case we send on + //ll->bestFaces[0] until the next best face selection + if(!strategyNexthopStateLL_IsAllowed(ll->bestFaces[1])){ + strategyNexthopStateLL_SendPacket(ll->bestFaces[0]); + numberSet_Add(out, strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); + }else{ + double queue0 = strategyNexthopStateLL_GetQueuing(ll->bestFaces[0]); + double queue1 = strategyNexthopStateLL_GetQueuing(ll->bestFaces[1]); + double prob0 = 0.5; + if(queue0 > 1 || queue1 > 1){ + prob0 = 1.0 - (queue0 / (queue0 + queue1)); + } + double coin = ((double) rand() / (RAND_MAX)); + if(coin < prob0){ + strategyNexthopStateLL_SendPacket(ll->bestFaces[0]); + numberSet_Add(out, strategyNexthopStateLL_GetFaceId(ll->bestFaces[0])); + }else{ + strategyNexthopStateLL_SendPacket(ll->bestFaces[1]); + numberSet_Add(out, strategyNexthopStateLL_GetFaceId(ll->bestFaces[1])); + } + } + } + return out; +} + + + +static +void +strategy_low_latency_on_data(strategy_entry_t * entry, + const nexthops_t * nexthops, const msgbuf_t * msgbuf, + Ticks pitEntryCreation, Ticks objReception) +{ + if (!msgbuf_is_probe(msgbuf)) + return; + + uint32_t seq = messageHandler_GetSegment(message_FixedHeader(objectMessage)); + if (!parcHashMap_Contains(ll->pending_probes_ticks, seq)) + return; // unexpected + + /* A single nexthop is expected */ + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, { + const StrategyNexthopStateLL *state = + parcHashMap_Get(ll->strategy_state, nexthop); + if (!state) + // this may happen if we remove a face/route while downloading a file + // we should ignore this timeout + continue; + + Ticks time = parcUnsigned_GetUnsigned( + parcHashMap_Get(ll->pending_probes_ticks, seq)); + Ticks now = forwarder_GetTicks(ll->forwarder); + Ticks RTT = now - time; + if(RTT <= 0) + RTT = 1; + strategyNexthopStateLL_AddRttSample( + (StrategyNexthopStateLL *) state, (unsigned int)RTT); + parcHashMap_Remove(ll->pending_probes_ticks, seq); + } + }; +} + +static +void +strategy_low_latency_on_timeout(strategy_entry_t * entry, const nexthops_t * nexthops) +{ + /* Nothing to do */ +} + +DECLARE_STRATEGY(low_latency); + +#undef nexthop_state_t +#undef state_t + +#endif diff --git a/hicn-light/src/hicn/strategies/low_latency.h b/hicn-light/src/hicn/strategies/low_latency.h new file mode 100644 index 000000000..4745c4c47 --- /dev/null +++ b/hicn-light/src/hicn/strategies/low_latency.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Forward on the path with lowest latency + */ + +#ifndef HICNLIGHT_STRATEGY_LOW_LATENCY_H +#define HICNLIGHT_STRATEGY_LOW_LATENCY_H + +#define MAX_FWD_STRATEGY_RELATED_PREFIXES 10 + +typedef struct { +} strategy_low_latency_nexthop_state_t; + +typedef struct { +} strategy_low_latency_state_t; + +typedef struct { + //Name ** related_prefixes; + Name *related_prefixes[MAX_FWD_STRATEGY_RELATED_PREFIXES]; + unsigned related_prefixes_len; +} strategy_low_latency_options_t; + +#if 0 + +/* + * We have global state in addition to state associated for each next hop : + */ +typedef struct { + bool in_use; + bool is_allowed; // XXX TODO the policy may not allow the use of this face +// unsigned face_id; + unsigned sent_packets; + /* switch metrics */ + unsigned last_try_to_switch_round; + unsigned try_to_switch_counter; + /* probes counters */ + unsigned recevied_probes; + unsigned rounds_without_probes; + unsigned sent_probes; + unsigned lost_probes; + unsigned non_lossy_rounds; + /* Averages */ + double avg_rtt; + double avg_rtt_in_use; + double avg_queue; + double avg_loss_rate; +} strategy_low_latency_nexthop_state_t; + +typedef struct { + // hash map from connectionId to StrategyNexthopStateLL + //PARCHashMap *strategy_state; + // XXX This is now store in each nexthop state + + /* + * Hhash map from sequence number to ticks (sent time) + * + * TODO improvement: the tick and face id could be stored in the probe and + * repeated in the reply to avoid state to be maintained. + * + * Also, in case we have few probes, linear scan might be more effective + */ + PARCHashMap *pending_probes_ticks; + + /* hash map from sequence number to face id */ + PARCHashMap *pending_probes_faces; + + const Forwarder * forwarder; + PARCEventTimer *sendProbes; + PARCEventTimer *computeBestFace; + uint8_t * probe; + hicn_name_t * name; + StrategyNexthopStateLL * bestFaces[2]; + unsigned round; + unsigned rounds_in_multipath; + unsigned rounds_with_error; + unsigned rounds_avoiding_multipath; + bool use2paths; + bool avoid_multipath; +} strategy_low_latency_state_t; + +#endif + + +#endif /* HICNLIGHT_STRATEGY_LOW_LATENCY_H */ diff --git a/hicn-light/src/hicn/strategies/nexthopState.c b/hicn-light/src/hicn/strategies/nexthopState.c deleted file mode 100644 index 40af14832..000000000 --- a/hicn-light/src/hicn/strategies/nexthopState.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <parc/algol/parc_DisplayIndented.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Object.h> - -#include <parc/assert/parc_Assert.h> -#include <hicn/strategies/nexthopState.h> - -#define AVG_PI_THRESHOLD 1e-3 - -struct strategy_nexthop_state { - unsigned int pi; - double avg_pi; - double weight; -}; - -static bool _strategyNexthopState_Destructor( - StrategyNexthopState **instancePtr) { - return true; -} - -parcObject_ImplementAcquire(strategyNexthopState, StrategyNexthopState); - -parcObject_ImplementRelease(strategyNexthopState, StrategyNexthopState); - -parcObject_Override( - StrategyNexthopState, PARCObject, - .destructor = (PARCObjectDestructor *)_strategyNexthopState_Destructor, - .copy = (PARCObjectCopy *)strategyNexthopState_Copy, - .display = (PARCObjectDisplay *)strategyNexthopState_Display, - .toString = (PARCObjectToString *)strategyNexthopState_ToString, - .equals = (PARCObjectEquals *)strategyNexthopState_Equals, - .compare = (PARCObjectCompare *)strategyNexthopState_Compare, - .hashCode = (PARCObjectHashCode *)strategyNexthopState_HashCode, - .display = (PARCObjectDisplay *)strategyNexthopState_Display); - -void strategyNexthopState_AssertValid(const StrategyNexthopState *instance) { - parcAssertTrue(strategyNexthopState_IsValid(instance), - "StrategyNexthopState is not valid."); -} - -StrategyNexthopState *strategyNexthopState_Create() { - StrategyNexthopState *result = - parcObject_CreateInstance(StrategyNexthopState); - if (result != NULL) { - result->pi = 0; - result->avg_pi = 0.0; - result->weight = 1; - } - return result; -} - -void strategyNexthopState_Reset(StrategyNexthopState *x) { - x->pi = 0; - x->avg_pi = 0.0; - x->weight = 1; -} - -int strategyNexthopState_Compare(const StrategyNexthopState *val, - const StrategyNexthopState *other) { - if (val == NULL) { - if (other != NULL) { - return -1; - } - } else if (other == NULL) { - return 1; - } else { - strategyNexthopState_OptionalAssertValid(val); - strategyNexthopState_OptionalAssertValid(other); - - if (val->pi < other->pi) { - return -1; - } else if (val->pi > other->pi) { - return 1; - } - - if (val->avg_pi < other->avg_pi) { - return -1; - } else if (val->avg_pi > other->avg_pi) { - return 1; - } - - if (val->weight < other->weight) { - return -1; - } else if (val->weight > other->weight) { - return 1; - } - } - - return 0; -} - -StrategyNexthopState *strategyNexthopState_Copy( - const StrategyNexthopState *original) { - StrategyNexthopState *result = strategyNexthopState_Create(); - result->pi = original->pi; - result->avg_pi = original->avg_pi; - result->weight = original->weight; - - return result; -} - -void strategyNexthopState_Display(const StrategyNexthopState *instance, - int indentation) { - parcDisplayIndented_PrintLine(indentation, "StrategyNexthopState@%p {", - instance); - parcDisplayIndented_PrintLine(indentation + 1, "%d", instance->pi); - parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->avg_pi); - parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->weight); - parcDisplayIndented_PrintLine(indentation, "}"); -} - -bool strategyNexthopState_Equals(const StrategyNexthopState *x, - const StrategyNexthopState *y) { - bool result = false; - - if (x == y) { - result = true; - } else if (x == NULL || y == NULL) { - result = false; - } else { - strategyNexthopState_OptionalAssertValid(x); - strategyNexthopState_OptionalAssertValid(y); - - if (strategyNexthopState_Compare(x, y) == 0) { - result = true; - } - } - - return result; -} - -PARCHashCode strategyNexthopState_HashCode(const StrategyNexthopState *x) { - PARCHashCode result = 0; - char str[128]; - sprintf(str, "PI:%d: AVG_PI:%f: W:%f", x->pi, x->avg_pi, x->weight); - result = parcHashCode_Hash((uint8_t *)&str, strlen(str)); - return result; -} - -bool strategyNexthopState_IsValid(const StrategyNexthopState *x) { - bool result = false; - - if (x != NULL) { - result = true; - } - - return result; -} - -char *strategyNexthopState_ToString(const StrategyNexthopState *x) { - // this is not implemented - parcTrapNotImplemented("strategyNexthopState_ToString is not implemented"); - return NULL; -} - -unsigned strategyNexthopState_GetPI(const StrategyNexthopState *x) { - strategyNexthopState_OptionalAssertValid(x); - - return x->pi; -} - -double strategyNexthopState_GetAvgPI(const StrategyNexthopState *x) { - strategyNexthopState_OptionalAssertValid(x); - - return x->avg_pi; -} - -double strategyNexthopState_GetWeight(const StrategyNexthopState *x) { - strategyNexthopState_OptionalAssertValid(x); - - return x->weight; -} - -double strategyNexthopState_UpdateState(StrategyNexthopState *x, bool inc, - double alpha) { - if (inc) { - x->pi++; - } else { - if (x->pi > 0) { - x->pi--; - } - } - x->avg_pi = (x->avg_pi * alpha) + (x->pi * (1 - alpha)); -#ifdef WITH_POLICY - if (x->avg_pi < AVG_PI_THRESHOLD) { -#else - if (x->avg_pi == 0.0) { -#endif /* WITH_POLICY */ - x->avg_pi = 0.1; - } - x->weight = 1 / x->avg_pi; - - return x->weight; -} diff --git a/hicn-light/src/hicn/strategies/nexthopState.h b/hicn-light/src/hicn/strategies/nexthopState.h deleted file mode 100644 index 35a9f497b..000000000 --- a/hicn-light/src/hicn/strategies/nexthopState.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef nexthopstate_h -#define nexthopstate_h - -#include <parc/algol/parc_HashCode.h> -#include <parc/algol/parc_Object.h> - -struct strategy_nexthop_state; -typedef struct strategy_nexthop_state StrategyNexthopState; -extern parcObjectDescriptor_Declaration(StrategyNexthopState); - -/** - */ -StrategyNexthopState *strategyNexthopState_Acquire( - const StrategyNexthopState *instance); - -#ifdef PARCLibrary_DISABLE_VALIDATION -#define strategyNexthopState_OptionalAssertValid(_instance_) -#else -#define strategyNexthopState_OptionalAssertValid(_instance_) \ - strategyNexthopState_AssertValid(_instance_) -#endif - -/** - */ -void strategyNexthopState_AssertValid(const StrategyNexthopState *instance); - -/** - */ -StrategyNexthopState *strategyNexthopState_Create(); - -void strategyNexthopState_Reset(StrategyNexthopState *x); -/** - */ -int strategyNexthopState_Compare(const StrategyNexthopState *instance, - const StrategyNexthopState *other); - -/** - */ -StrategyNexthopState *strategyNexthopState_Copy( - const StrategyNexthopState *original); - -/** - */ -void strategyNexthopState_Display(const StrategyNexthopState *instance, - int indentation); - -/** - */ -bool strategyNexthopState_Equals(const StrategyNexthopState *x, - const StrategyNexthopState *y); - -/** - */ -PARCHashCode strategyNexthopState_HashCode( - const StrategyNexthopState *instance); - -/** - */ -bool strategyNexthopState_IsValid(const StrategyNexthopState *instance); - -/** - */ -void strategyNexthopState_Release(StrategyNexthopState **instancePtr); - -/** - */ -char *strategyNexthopState_ToString(const StrategyNexthopState *instance); - -/** - */ -unsigned strategyNexthopState_GetPI(const StrategyNexthopState *x); - -double strategyNexthopState_GetAvgPI(const StrategyNexthopState *x); - -double strategyNexthopState_GetWeight(const StrategyNexthopState *x); - -double strategyNexthopState_UpdateState(StrategyNexthopState *x, bool inc, - double alpha); -#endif diff --git a/hicn-light/src/hicn/strategies/nexthopStateLowLatency.c b/hicn-light/src/hicn/strategies/nexthopStateLowLatency.c index a3953987f..ceed60cf3 100644 --- a/hicn-light/src/hicn/strategies/nexthopStateLowLatency.c +++ b/hicn-light/src/hicn/strategies/nexthopStateLowLatency.c @@ -24,291 +24,6 @@ #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); diff --git a/hicn-light/src/hicn/strategies/random.c b/hicn-light/src/hicn/strategies/random.c new file mode 100644 index 000000000..329bb1153 --- /dev/null +++ b/hicn-light/src/hicn/strategies/random.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +void +strategy_random_initialize(strategy_entry_t * entry) +{ + srand((unsigned int)time(NULL)); +} + +static +void +strategy_random_finalize(strategy_entry_t * entry) +{ + /* Nothing to do */ +} + +static +void +strategy_random_add_nexthop(strategy_entry_t * entry, unsigned nexthop, + strategy_nexthop_state_t * state) +{ + /* Nothing to do */ +} + +static +void +strategy_random_remove_nexthop(strategy_entry_t * entry, unsigned nexthop, + strategy_nexthop_state_t * state) +{ + /* Nothing to do */ +} + +static +nexthops_t * +strategy_random_lookup_nexthops(strategy_entry_t * entry, + nexthops_t * nexthops, + const msgbuf_t * msgbuf) +{ + nexthops_select(nexthops, rand() % nexthops_get_len(nexthops)); + return nexthops; +} + +static +void +strategy_random_on_data(strategy_entry_t * entry, + const nexthops_t * nexthops, const msgbuf_t * msgbuf, + Ticks pitEntryCreation, Ticks objReception) +{ + /* Nothing to do */ +} + +static +void +strategy_random_on_timeout(strategy_entry_t * entry, + const nexthops_t * nexthops) +{ + /* Nothing to do */ +} + + +DECLARE_STRATEGY(random); diff --git a/hicn-light/src/hicn/strategies/loadBalancer.h b/hicn-light/src/hicn/strategies/random.h index 74920768d..edcc893e7 100644 --- a/hicn-light/src/hicn/strategies/loadBalancer.h +++ b/hicn-light/src/hicn/strategies/random.h @@ -14,14 +14,16 @@ */ /** - * 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 {} strategy_random_nexthop_state_t; -StrategyImpl *strategyLoadBalancer_Create(); +typedef struct {} strategy_random_state_t; -#endif // loadBalancer_h +typedef struct {} strategy_random_options_t; + +#endif /* HICNLIGHT_STRATEGY_RANDOM_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/utils/CMakeLists.txt b/hicn-light/src/hicn/utils/CMakeLists.txt index 1ab38deba..99592b31d 100644 --- a/hicn-light/src/hicn/utils/CMakeLists.txt +++ b/hicn-light/src/hicn/utils/CMakeLists.txt @@ -14,21 +14,17 @@ cmake_minimum_required(VERSION 3.5 FATAL_ERROR) 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}/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 ) 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 index d8e5329b3..358f94d48 100644 --- a/hicn-light/src/hicn/utils/commands.h +++ b/hicn-light/src/hicn/utils/commands.h @@ -31,404 +31,347 @@ #include <stdint.h> #include <stdlib.h> +#include <hicn/core/strategy.h> // to be moved in libhicn #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; + MESSAGE_COMMAND_SUBTYPE_UNDEFINED, + REQUEST_LIGHT = 0xc0, // this is a command + RESPONSE_LIGHT, + ACK_LIGHT, + NACK_LIGHT, + MESSAGE_COMMAND_SUBTYPE_N +} message_command_subtype_t; + +#define message_type_is_valid(message_type) \ + ((message_type != MESSAGE_TYPE_UNDEFINED) && (message_type != MESSAGE_COMMAND_SUBTYPE_N)) + +#define message_type_from_uchar(x) \ + (((x) < REQUEST_LIGHT) || (((x) >= MESSAGE_COMMAND_SUBTYPE_N)) ? MESSAGE_COMMAND_SUBTYPE_N : (message_command_subtype_t)(x)) + +#define foreach_command_type \ + _(listener_add, LISTENER_ADD) \ + _(listener_remove, LISTENER_REMOVE) \ + _(listener_list, LISTENER_LIST) \ + _(connection_add, CONNECTION_ADD) \ + _(connection_remove, CONNECTION_REMOVE) \ + _(connection_list, CONNECTION_LIST) \ + _(connection_set_admin_state, CONNECTION_SET_ADMIN_STATE) \ + _(connection_update, CONNECTION_UPDATE) \ + _(connection_set_priority, CONNECTION_SET_PRIORITY) \ + _(connection_set_tags, CONNECTION_SET_TAGS) \ + _(route_add, ROUTE_ADD) \ + _(route_remove, ROUTE_REMOVE) \ + _(route_list, ROUTE_LIST) \ + _(cache_set_store, CACHE_SET_STORE) \ + _(cache_set_serve, CACHE_SET_SERVE) \ + _(cache_clear, CACHE_CLEAR) \ + _(strategy_set, STRATEGY_SET) \ + _(wldr_set, WLDR_SET) \ + _(punting_add, PUNTING_ADD) \ + _(mapme_enable, MAPME_ENABLE) \ + _(mapme_set_discovery, MAPME_SET_DISCOVERY) \ + _(mapme_set_timescale, MAPME_SET_TIMESCALE) \ + _(mapme_set_retx, MAPME_SET_RETX) \ + _(mapme_send_update, MAPME_SEND_UPDATE) \ + _(policy_add, POLICY_ADD) \ + _(policy_remove, POLICY_REMOVE) \ + _(policy_list, POLICY_LIST) \ 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; + COMMAND_TYPE_UNDEFINED, +#define _(l, u) COMMAND_TYPE_ ## u, + foreach_command_type +#undef _ + COMMAND_TYPE_N, +} command_type_t; -typedef enum { - UDP_CONN, - TCP_CONN, - GRE_CONN, // not implemented - HICN_CONN -} connection_type; +#define command_type_is_valid(command_type) \ + ((command_type != COMMAND_TYPE_UNDEFINED) && (command_type != COMMAND_TYPE_N)) -typedef enum { ACTIVATE_ON, ACTIVATE_OFF } activate_type; +#define command_type_from_uchar(x) \ + (((x) >= COMMAND_TYPE_N) ? COMMAND_TYPE_N : (command_type_t)(x)) -//========== HEADER ========== +/* Should be at least 8 bytes */ +typedef struct { + uint8_t messageType; + uint8_t commandID; + uint16_t length; /* Number of structures in the payload */ + uint32_t seqNum; +} cmd_header_t; 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 + cmd_header_t header; +} msg_header_t; -// SIZE=8 +/* Listener */ -//========== [00] ADD LISTENER ========== +typedef struct { + char symbolic[SYMBOLIC_NAME_LEN]; + char interface_name[SYMBOLIC_NAME_LEN]; + ip_address_t address; + uint16_t port; + uint8_t family; + uint8_t listener_type; +} cmd_listener_add_t; -typedef enum { ETHER_MODE, IP_MODE, HICN_MODE } listener_mode; +typedef struct { + char symbolicOrListenerid[SYMBOLIC_NAME_LEN]; +} cmd_listener_remove_t; 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; +} cmd_listener_list_t; -// SIZE=56 +typedef struct { + ip_address_t address; + char name[SYMBOLIC_NAME_LEN]; + char interface_name[SYMBOLIC_NAME_LEN]; + uint32_t id; + uint16_t port; + uint8_t family; + uint8_t type; +} cmd_listener_list_item_t; -//========== [01] ADD CONNECTION ========== +/* 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; + char symbolic[SYMBOLIC_NAME_LEN]; + //char interface_name[SYMBOLIC_NAME_LEN]; + ip_address_t remote_ip; + ip_address_t local_ip; + uint16_t remote_port; + uint16_t local_port; + uint8_t family; + uint8_t type; + uint8_t admin_state; #ifdef WITH_POLICY - uint32_t priority; - policy_tags_t tags; + 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; +} cmd_connection_add_t; 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 ========== + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; +} cmd_connection_remove_t; 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 ========== +} cmd_connection_list_t; typedef struct { - ip_address_t address; - uint32_t connid; - uint16_t cost; - uint8_t addressType; - uint8_t len; -} list_routes_command; - -// SIZE=24 + char symbolic[SYMBOLIC_NAME_LEN]; + //char interface_name[SYMBOLIC_NAME_LEN]; + ip_address_t remote_ip; + ip_address_t local_ip; + uint16_t remote_port; + uint16_t local_port; + uint8_t family; + uint8_t type; + uint8_t admin_state; +#ifdef WITH_POLICY + uint32_t priority; + policy_tags_t tags; +#endif /* WITH_POLICY */ + uint32_t id; + uint8_t state; + char interface_name[SYMBOLIC_NAME_LEN]; + char name[SYMBOLIC_NAME_LEN]; +} cmd_connection_list_item_t; -//========== [05] REMOVE CONNECTION ========== typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; -} remove_connection_command; + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; + uint8_t admin_state; + uint8_t pad8[3]; +} cmd_connection_set_admin_state_t; -//========== [06] REMOVE LISTENER ========== typedef struct { - char symbolicOrListenerid[SYMBOLIC_NAME_LEN]; -} remove_listener_command; - -// SIZE=16 - -//========== [07] REMOVE ROUTE ========== + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; + uint8_t admin_state; + uint32_t priority; + policy_tags_t tags; +} cmd_connection_update_t; 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 ========== + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; + uint32_t priority; +} cmd_connection_set_priority_t; typedef struct { - uint8_t activate; -} cache_store_command; - -// SIZE=1 + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; + policy_tags_t tags; +} cmd_connection_set_tags_t; -//========== [09] CACHE SERVE ========== +/* Route */ typedef struct { - uint8_t activate; -} cache_serve_command; - -// SIZE=1 + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; + ip_address_t address; + uint16_t cost; + uint8_t family; + uint8_t len; +} cmd_route_add_t; -//========== [10] SET STRATEGY ========== +typedef struct { + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; + ip_address_t address; + uint8_t family; + uint8_t len; +} cmd_route_remove_t; -typedef enum { - SET_STRATEGY_LOADBALANCER, - SET_STRATEGY_RANDOM, - SET_STRATEGY_LOW_LATENCY, - LAST_STRATEGY_VALUE -} strategy_type; +typedef struct { +} cmd_route_list_t; 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; + ip_address_t address; + uint32_t connection_id; + uint16_t cost; + uint8_t family; + uint8_t len; +} cmd_route_list_item_t; -// SIZE=208 +/* Cache */ -//========== [11] SET WLDR ========== +typedef struct { + uint8_t activate; +} cmd_cache_set_store_t; typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; - uint8_t activate; -} set_wldr_command; + uint8_t activate; +} cmd_cache_set_serve_t; -// SIZE=17 +typedef struct { +} cmd_cache_clear_t; -//========== [12] ADD PUNTING ========== +/* WLDR */ typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; - ip_address_t address; - uint8_t addressType; - uint8_t len; -} add_punting_command; + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; + uint8_t activate; +} cmd_wldr_set_t; -// SIZE=36 - -//========== [13] LIST LISTENER ========== +/* Strategy */ 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 + ip_address_t address; + uint8_t strategy_type; + uint8_t family; + uint8_t len; + uint8_t related_prefixes; + union { + struct { + ip_address_t addresses[MAX_FWD_STRATEGY_RELATED_PREFIXES]; + uint8_t lens[MAX_FWD_STRATEGY_RELATED_PREFIXES]; + uint8_t families[MAX_FWD_STRATEGY_RELATED_PREFIXES]; + } low_latency; + }; +} cmd_strategy_set_t; + +/* Punting */ -//========== [14] MAPME ========== +typedef struct { + char symbolicOrConnid[SYMBOLIC_NAME_LEN]; + ip_address_t address; + uint8_t family; + uint8_t len; +} cmd_punting_add_t; -// (enable/discovery/timescale/retx) +/* MAP-Me */ typedef struct { - uint8_t activate; -} mapme_activator_command; + uint8_t activate; +} cmd_mapme_activator_t; -// SIZE=1 +typedef cmd_mapme_activator_t cmd_mapme_enable_t; +typedef cmd_mapme_activator_t cmd_mapme_set_discovery_t; typedef struct { - uint32_t timePeriod; -} mapme_timing_command; + uint32_t timePeriod; +} cmd_mapme_timing_t; + +typedef cmd_mapme_timing_t cmd_mapme_set_timescale_t; +typedef cmd_mapme_timing_t cmd_mapme_set_retx_t; typedef struct { - ip_address_t address; - uint8_t addressType; - uint8_t len; -} mapme_send_update_command; + ip_address_t address; + uint8_t family; + uint8_t len; +} cmd_mapme_send_update_t; -// SIZE=1 +/* Policy */ typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; - uint8_t admin_state; - uint8_t pad8[3]; -} connection_set_admin_state_command; - -#ifdef WITH_POLICY + ip_address_t address; + uint8_t family; + uint8_t len; + policy_t policy; +} cmd_policy_add_t; typedef struct { - ip_address_t address; - uint8_t addressType; - uint8_t len; - policy_t policy; -} add_policy_command; + ip_address_t address; + uint8_t family; + uint8_t len; +} cmd_policy_remove_t; typedef struct { - ip_address_t address; - uint8_t addressType; - uint8_t len; - policy_t policy; -} list_policies_command; +} cmd_policy_list_t; typedef struct { - ip_address_t address; - uint8_t addressType; - uint8_t len; -} remove_policy_command; + ip_address_t address; + uint8_t family; + uint8_t len; + policy_t policy; +} cmd_policy_list_item_t; + +/* Full messages */ + +#define _(l, u) \ +typedef struct { \ + cmd_header_t header; \ + cmd_ ## l ## _t payload; \ +} msg_ ## l ## _t; + foreach_command_type +#undef _ typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; - uint8_t admin_state; - uint32_t priority; - policy_tags_t tags; -} update_connection_command; + cmd_header_t header; + cmd_listener_list_item_t payload; +} msg_listener_list_reply_t; typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; - uint32_t priority; -} connection_set_priority_command; + cmd_header_t header; + cmd_connection_list_item_t payload; +} msg_connection_list_reply_t; typedef struct { - char symbolicOrConnid[SYMBOLIC_NAME_LEN]; - policy_tags_t tags; -} connection_set_tags_command; + cmd_header_t header; + cmd_route_list_item_t payload; +} msg_route_list_reply_t; -#endif /* WITH_POLICY */ +typedef struct { + cmd_header_t header; + cmd_policy_list_item_t payload; +} msg_policy_list_reply_t; //===== 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; - } +static inline int command_get_payload_len(command_type_t command_type) { + switch (command_type) { +#define _(l, u) \ + case COMMAND_TYPE_ ## u: \ + return sizeof(cmd_## l ## _t); + foreach_command_type +#undef _ + case COMMAND_TYPE_UNDEFINED: + case COMMAND_TYPE_N: + return 0; + } } #endif diff --git a/hicn-light/src/hicn/utils/interface.c b/hicn-light/src/hicn/utils/interface.c index d8597f3ed..a77b3d066 100644 --- a/hicn-light/src/hicn/utils/interface.c +++ b/hicn-light/src/hicn/utils/interface.c @@ -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..ccaf5f2e8 100644 --- a/hicn-light/src/hicn/utils/interface.h +++ b/hicn-light/src/hicn/utils/interface.h @@ -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/punting.c b/hicn-light/src/hicn/utils/punting.c index 8f33cf763..15e55df60 100644 --- a/hicn-light/src/hicn/utils/punting.c +++ b/hicn-light/src/hicn/utils/punting.c @@ -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..100fd02fd 100644 --- a/hicn-light/src/hicn/utils/punting.h +++ b/hicn-light/src/hicn/utils/punting.h @@ -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/utils.c b/hicn-light/src/hicn/utils/utils.c index 36596f943..42bcb7f87 100644 --- a/hicn-light/src/hicn/utils/utils.c +++ b/hicn-light/src/hicn/utils/utils.c @@ -10,30 +10,27 @@ #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; -} +//// 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 @@ -48,188 +45,137 @@ bool utils_IsNumber(const char *string) { 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; -} +///** +// * 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; +//} +// +//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(int family, ip_address_t *address, in_port_t *port) +//{ +// char *result, *addrStr; +// switch (family) { +// case AF_INET: +// result = utils_BuildStringFromInet(&address->v4.as_u32, port); +// break; +// +// case AF_INET6: +// result = utils_BuildStringFromInet6(&address->v6.as_in6addr, port); +// break; +// +// default: +// addrStr = (char *)parcMemory_Allocate(sizeof(char) * 32); +// snprintf(addrStr, 32, "Error: UNKNOWN family = %d", family); +// result = addrStr; +// break; +// } +// return result; +//} +// +//struct iovec *utils_SendRequest(ControlState *state, command_type_t 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 +//} +//} diff --git a/hicn-light/src/hicn/utils/utils.h b/hicn-light/src/hicn/utils/utils.h index 1fe88e62c..368a93f5a 100644 --- a/hicn-light/src/hicn/utils/utils.h +++ b/hicn-light/src/hicn/utils/utils.h @@ -16,8 +16,7 @@ #ifndef utils_h #define utils_h -#include <hicn/config/controlState.h> -#include <hicn/utils/address.h> +//#include <hicn/config/controlState.h> #include <hicn/utils/commands.h> /** @@ -32,39 +31,20 @@ bool utils_IsNumber(const char *string); 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); +char *utils_CommandAddressToString(int family, 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); +#if 0 +struct iovec * +utils_SendRequest(ControlState *state, command_type_t + command_type, void *payload, size_t payloadLen); #endif +#endif diff --git a/hicn-plugin/src/mapme_ctrl_node.c b/hicn-plugin/src/mapme_ctrl_node.c index ed25a31b0..182fbabd3 100644 --- a/hicn-plugin/src/mapme_ctrl_node.c +++ b/hicn-plugin/src/mapme_ctrl_node.c @@ -130,7 +130,7 @@ hicn_mapme_process_ctrl (vlib_main_t * vm, vlib_buffer_t * b, #endif /* Process the hICN DPO */ - hicn_mapme_tfib_t *tfib = + hicn_mapme_tfib_t * tfib = TFIB (hicn_strategy_dpo_ctx_get (dpo->dpoi_index)); if (tfib == NULL) @@ -158,6 +158,7 @@ hicn_mapme_process_ctrl (vlib_main_t * vm, vlib_buffer_t * b, /* Move next hops to TFIB... but in_face... */ for (u8 pos = 0; pos < tfib->entry_count; pos++) { + // XXX BUG if (dpo_cmp (&tfib->next_hops[pos], in_face) == 0) { tfib->entry_count = 0; @@ -180,10 +181,10 @@ hicn_mapme_process_ctrl (vlib_main_t * vm, vlib_buffer_t * b, HICN_MAPME_EVENT_FACE_NH_SET, 1, sizeof (retx_t)); - *retx = (retx_t) - { - .prefix = prefix,.dpo = *dpo}; - + *retx = (retx_t) { + .prefix = prefix, + .dpo = *dpo + }; } else if (params.seq == fib_seq) { @@ -213,6 +214,7 @@ hicn_mapme_process_ctrl (vlib_main_t * vm, vlib_buffer_t * b, * face is propagating outdated information, we can just consider it as a * prevHops */ + // XXX BUG hicn_mapme_tfib_add (tfib, in_face); retx_t *retx = vlib_process_signal_event_data (vm, diff --git a/hicn-plugin/src/mapme_eventmgr.c b/hicn-plugin/src/mapme_eventmgr.c index 5a9e7967e..f35a9909a 100644 --- a/hicn-plugin/src/mapme_eventmgr.c +++ b/hicn-plugin/src/mapme_eventmgr.c @@ -307,6 +307,7 @@ hicn_mapme_send_updates (vlib_main_t * vm, hicn_prefix_t * prefix, } else { + // XXX BUG are we sure it is always the last ?? hicn_mapme_send_message (vm, prefix, ¶ms, &tfib->next_hops[tfib_last_idx]); } @@ -510,7 +511,7 @@ hicn_mapme_eventmgr_process (vlib_main_t * vm, hicn_mapme_send_updates (vm, &retx->prefix, retx->dpo, true); retx->rtx_count++; - // If we exceed the numver of retransmittion it means that all tfib entries have seens at least HICN_PARAM_RTX_MAX of retransmission + // If we exceed the numver of retransmission it means that all tfib entries have seens at least HICN_PARAM_RTX_MAX of retransmission if (retx->rtx_count < HICN_PARAM_RTX_MAX) { /* diff --git a/hicn-plugin/src/mapme_eventmgr.h b/hicn-plugin/src/mapme_eventmgr.h index 338915d63..b715ae847 100644 --- a/hicn-plugin/src/mapme_eventmgr.h +++ b/hicn-plugin/src/mapme_eventmgr.h @@ -26,7 +26,9 @@ typedef struct u8 rtx_count; // Number of retransmissions since last tfib addition } retx_t; +#if 0 #define HASH32(x) ((u16)x ^ (x << 16)) +#endif /** * @brief This is a process node reacting to face events. diff --git a/lib/includes/CMakeLists.txt b/lib/includes/CMakeLists.txt index 12529bd57..6184f4708 100644 --- a/lib/includes/CMakeLists.txt +++ b/lib/includes/CMakeLists.txt @@ -23,6 +23,7 @@ set(LIBHICN_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/hicn/common.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/compat.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/error.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/face.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/header.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/mapme.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/name.h diff --git a/lib/includes/hicn/base.h b/lib/includes/hicn/base.h index d8a79a9c2..3112d1140 100644 --- a/lib/includes/hicn/base.h +++ b/lib/includes/hicn/base.h @@ -27,7 +27,7 @@ #define HICN_DEFAULT_TTL 254 typedef u32 hicn_faceid_t; -typedef u8 hicn_pathlabel_t; +typedef u32 hicn_pathlabel_t; typedef u32 hicn_lifetime_t; #define HICN_MAX_LIFETIME_SCALED 0xFFFF @@ -95,12 +95,16 @@ HICN_TYPE(int x, int y, int z, int t) #endif #define HICN_TYPE_IPV4_TCP HICN_TYPE(IPPROTO_IP, IPPROTO_TCP, IPPROTO_NONE, IPPROTO_NONE) +#define HICN_TYPE_IPV4_UDP HICN_TYPE(IPPROTO_IP, IPPROTO_UDP, IPPROTO_NONE, IPPROTO_NONE) #define HICN_TYPE_IPV4_ICMP HICN_TYPE(IPPROTO_IP, IPPROTO_ICMP, IPPROTO_NONE, IPPROTO_NONE) #define HICN_TYPE_IPV6_TCP HICN_TYPE(IPPROTO_IPV6, IPPROTO_TCP, IPPROTO_NONE, IPPROTO_NONE) +#define HICN_TYPE_IPV6_UDP HICN_TYPE(IPPROTO_IPV6, IPPROTO_UDP, IPPROTO_NONE, IPPROTO_NONE) #define HICN_TYPE_IPV6_ICMP HICN_TYPE(IPPROTO_IPV6, IPPROTO_ICMPV6, IPPROTO_NONE, IPPROTO_NONE) #define HICN_TYPE_IPV4_TCP_AH HICN_TYPE(IPPROTO_IP, IPPROTO_TCP, IPPROTO_NONE, IPPROTO_NONE) +#define HICN_TYPE_IPV4_UDP_AH HICN_TYPE(IPPROTO_IP, IPPROTO_UDP, IPPROTO_NONE, IPPROTO_NONE) #define HICN_TYPE_IPV4_ICMP_AH HICN_TYPE(IPPROTO_IP, IPPROTO_ICMP, IPPROTO_NONE, IPPROTO_NONE) #define HICN_TYPE_IPV6_TCP_AH HICN_TYPE(IPPROTO_IPV6, IPPROTO_TCP, IPPROTO_AH, IPPROTO_NONE) +#define HICN_TYPE_IPV6_UDP_AH HICN_TYPE(IPPROTO_IPV6, IPPROTO_UDP, IPPROTO_AH, IPPROTO_NONE) #define HICN_TYPE_IPV6_ICMP_AH HICN_TYPE(IPPROTO_IPV6, IPPROTO_ICMPV6, IPPROTO_AH, IPPROTO_NONE) #define HICN_TYPE_NONE HICN_TYPE(IPPROTO_NONE, IPPROTO_NONE, IPPROTO_NONE, IPPROTO_NONE) @@ -127,8 +131,9 @@ typedef enum * NOTE: this computation is not (yet) part of the hICN specification. */ +// XXX TODO deprecate TODO XXX #define HICN_PATH_LABEL_MASK 0xF000 /* 1000 0000 0000 0000 */ -#define HICN_PATH_LABEL_SIZE 8 +#define HICN_PATH_LABEL_SIZE 8 /* XXX in bits ? */ /** * @brief Path label update diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/face.h b/lib/includes/hicn/face.h index 49a6a783c..45a1b97da 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/face.h +++ b/lib/includes/hicn/face.h @@ -34,8 +34,6 @@ #include <hicn/util/ip_address.h> -//typedef unsigned int hash_t; //incompatible with vpp - /* Netdevice type */ #include <net/if.h> // IFNAMSIZ @@ -58,7 +56,8 @@ foreach_netdevice_type #undef _ } netdevice_type_t; -extern const char * netdevice_type_str[]; +extern const char * _netdevice_type_str[]; +#define netdevice_type_str(x) _netdevice_type_str[x] /* Netdevice */ @@ -113,7 +112,9 @@ foreach_face_state #undef _ } face_state_t; -extern const char * face_state_str[]; +extern const char * _face_state_str[]; + +#define face_state_str(x) _face_state_str[x] /* Face type */ @@ -137,7 +138,14 @@ foreach_face_type #undef _ } face_type_t; -extern const char * face_type_str[]; +#define face_type_is_valid(face_type) \ + (((face_type) >= FACE_TYPE_UNDEFINED) && (face_type < FACE_TYPE_N)) +#define face_type_is_defined(face_type) \ + (((face_type) > FACE_TYPE_UNDEFINED) && (face_type < FACE_TYPE_N)) + +extern const char * _face_type_str[]; +#define face_type_str(x) _face_type_str[x] + #ifdef WITH_POLICY #define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_URL_ + 2 * MAXSZ_FACE_STATE_ + MAXSZ_POLICY_TAGS_ + 7 @@ -194,7 +202,6 @@ void face_free(face_t * face); typedef int (*face_cmp_t)(const face_t * f1, const face_t * f2); int face_cmp(const face_t * f1, const face_t * f2); -unsigned int face_hash(const face_t * face); size_t face_snprintf(char * s, size_t size, const face_t * face); diff --git a/lib/includes/hicn/policy.h b/lib/includes/hicn/policy.h index 51bab4241..1fe0dd766 100644 --- a/lib/includes/hicn/policy.h +++ b/lib/includes/hicn/policy.h @@ -147,68 +147,6 @@ typedef struct { int policy_tag_state_snprintf(char * s, size_t size, const policy_tag_state_t * tag_state); - -/* INTERFACE STATS */ - -typedef struct { - float throughput; - float latency; - float loss_rate; -} interface_stats_t; - -#define INTERFACE_STATS_NONE { \ - .throughput = 0, \ - .latency = 0, \ - .loss_rate = 0, \ -} - - -/* POLICY STATS */ - -typedef struct { - interface_stats_t wired; - interface_stats_t wifi; - interface_stats_t cellular; - interface_stats_t all; -} policy_stats_t; - -#define POLICY_STATS_NONE { \ - .wired = INTERFACE_STATS_NONE, \ - .wifi = INTERFACE_STATS_NONE, \ - .cellular = INTERFACE_STATS_NONE, \ - .all = INTERFACE_STATS_NONE, \ -} - -typedef struct { - uint32_t num_packets; - uint32_t num_bytes; - uint32_t num_losses; - uint32_t latency_idle; -} interface_counters_t; - -#define INTERFACE_COUNTERS_NONE { \ - .num_packets = 0, \ - .num_bytes = 0, \ - .num_losses = 0, \ - .latency_idle = 0, \ -} - -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 POLICY_COUNTERS_NONE (policy_counters_t) { \ - .wired = INTERFACE_COUNTERS_NONE, \ - .wifi = INTERFACE_COUNTERS_NONE, \ - .cellular = INTERFACE_COUNTERS_NONE, \ - .all = INTERFACE_COUNTERS_NONE, \ - .last_update = 0, \ -} - /* POLICY */ #define APP_NAME_LEN 128 @@ -216,7 +154,6 @@ typedef struct { typedef struct { char app_name[APP_NAME_LEN]; policy_tag_state_t tags[POLICY_TAG_N]; - policy_stats_t stats; } policy_t; static const policy_t POLICY_NONE = { @@ -226,7 +163,6 @@ static const policy_t POLICY_NONE = { foreach_policy_tag #undef _ }, - .stats = POLICY_STATS_NONE, }; diff --git a/lib/includes/hicn/protocol/tcp.h b/lib/includes/hicn/protocol/tcp.h index ded9a06b2..5cf1a3625 100644 --- a/lib/includes/hicn/protocol/tcp.h +++ b/lib/includes/hicn/protocol/tcp.h @@ -42,11 +42,7 @@ typedef struct union { u32 seq_ack; - struct - { - hicn_pathlabel_t pathlabel; - u8 pad[3]; - }; + hicn_pathlabel_t pathlabel; }; union diff --git a/lib/includes/hicn/util/ip_address.h b/lib/includes/hicn/util/ip_address.h index 4facd9ad0..27880047c 100644 --- a/lib/includes/hicn/util/ip_address.h +++ b/lib/includes/hicn/util/ip_address.h @@ -108,6 +108,7 @@ typedef struct { #define MAXSZ_PREFIX_ MAXSZ_IP_ADDRESS_ + 1 + 3 #define MAXSZ_PREFIX MAXSZ_PREFIX_ + 1 +#define MAXSZ_IP_PREFIX MAXSZ_PREFIX extern const ip_address_t IPV4_LOOPBACK; extern const ip_address_t IPV6_LOOPBACK; @@ -146,6 +147,7 @@ int ip_address_empty(const ip_address_t * ip); int ip_prefix_pton (const char *ip_address_str, ip_prefix_t * ip_prefix); int ip_prefix_ntop_short (const ip_prefix_t * ip_prefix, char *dst, size_t size); int ip_prefix_ntop (const ip_prefix_t * ip_prefix, char *dst, size_t size); +int ip_prefix_snprintf(char * s, size_t size, const ip_prefix_t * prefix); int ip_prefix_len (const ip_prefix_t * prefix); bool ip_prefix_empty (const ip_prefix_t * prefix); int ip_prefix_to_sockaddr(const ip_prefix_t * prefix, struct sockaddr *sa); diff --git a/lib/src/CMakeLists.txt b/lib/src/CMakeLists.txt index 7eecaf775..6eb4c9554 100644 --- a/lib/src/CMakeLists.txt +++ b/lib/src/CMakeLists.txt @@ -17,6 +17,7 @@ list(APPEND LIBHICN_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/common.c ${CMAKE_CURRENT_SOURCE_DIR}/compat.c ${CMAKE_CURRENT_SOURCE_DIR}/error.c + ${CMAKE_CURRENT_SOURCE_DIR}/face.c ${CMAKE_CURRENT_SOURCE_DIR}/mapme.c ${CMAKE_CURRENT_SOURCE_DIR}/name.c ${CMAKE_CURRENT_SOURCE_DIR}/ops.c @@ -30,7 +31,10 @@ list(APPEND LIBHICN_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/util/log.c ) -set (COMPILER_DEFINITIONS "-DWITH_MAPME") +set (COMPILER_DEFINITIONS + "-DWITH_MAPME" + "-DWITH_POLICY" +) include(BuildMacros) include(WindowsMacros) diff --git a/ctrl/libhicnctrl/src/face.c b/lib/src/face.c index e617ff8a4..6d0d9c486 100644 --- a/ctrl/libhicnctrl/src/face.c +++ b/lib/src/face.c @@ -21,17 +21,16 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <hicn/util/token.h> -#include <hicn/ctrl/face.h> -#include "util/hash.h" +#include <hicn/face.h> +#include <hicn/util/token.h> #define member_size(type, member) sizeof(((type *)0)->member) /* Netdevice */ -const char * netdevice_type_str[] = { +const char * _netdevice_type_str[] = { #define _(x) [NETDEVICE_TYPE_ ## x] = STRINGIZE(x), foreach_netdevice_type #undef _ @@ -147,7 +146,7 @@ netdevice_cmp(const netdevice_t * nd1, const netdevice_t * nd2) /* Face state */ -const char * face_state_str[] = { +const char * _face_state_str[] = { #define _(x) [FACE_STATE_ ## x] = STRINGIZE(x), foreach_face_state #undef _ @@ -156,7 +155,7 @@ foreach_face_state /* Face type */ -const char * face_type_str[] = { +const char * _face_type_str[] = { #define _(x) [FACE_TYPE_ ## x] = STRINGIZE(x), foreach_face_type #undef _ @@ -168,7 +167,7 @@ foreach_face_type int face_initialize(face_t * face) { - memset(face, 0, sizeof(face_t)); /* 0'ed for hash */ + memset(face, 0, sizeof(face_t)); return 1; } @@ -250,7 +249,7 @@ face_initialize_udp_sa(face_t * face, const char * interface_name, face_t * face_create() { - face_t * face = calloc(1, sizeof(face_t)); /* 0'ed for hash */ + face_t * face = calloc(1, sizeof(face_t)); return face; } @@ -356,13 +355,6 @@ face_cmp(const face_t * f1, const face_t * f2) return 0; } -unsigned int -face_hash(const face_t * face) -{ - /* Assuming the unused part of the struct is set to zero */ - return hash_struct(face); -} - /* /!\ Please update constants in header file upon changes */ size_t face_snprintf(char * s, size_t size, const face_t * face) @@ -382,7 +374,7 @@ face_snprintf(char * s, size_t size, const face_t * face) face->family); policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->tags); return snprintf(s, size, "%s [%s -> %s] [%s]", - face_type_str[face->type], + face_type_str(face->type), local, remote, tags); @@ -404,7 +396,7 @@ face_snprintf(char * s, size_t size, const face_t * face) policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->tags); return snprintf(s, size, "%s [%s:%d -> %s:%d] [%s]", - face_type_str[face->type], + face_type_str(face->type), local, face->local_port, remote, diff --git a/lib/src/util/ip_address.c b/lib/src/util/ip_address.c index 49916547d..d4b34dc0b 100644 --- a/lib/src/util/ip_address.c +++ b/lib/src/util/ip_address.c @@ -302,10 +302,13 @@ ip_prefix_ntop(const ip_prefix_t * ip_prefix, char *dst, size_t size) } if (!s) return -1; - int rc = snprintf(dst, size, "%s/%d", ip_s, ip_prefix->len); - if (rc >= size) - return (int)size; - return rc; + return snprintf(dst, size, "%s/%d", ip_s, ip_prefix->len); +} + +int +ip_prefix_snprintf(char * s, size_t size, const ip_prefix_t * prefix) +{ + return ip_prefix_ntop(prefix, s, size); } int diff --git a/utils/src/hiperf.cc b/utils/src/hiperf.cc index fee2b34c9..151e4df3d 100644 --- a/utils/src/hiperf.cc +++ b/utils/src/hiperf.cc @@ -718,10 +718,12 @@ class HIperfServer { content_objects_index_(0), mask_((std::uint16_t)(1 << log2_content_object_buffer_size) - 1), last_segment_(0), - ptr_last_segment_(&last_segment_), #ifndef _WIN32 + ptr_last_segment_(&last_segment_), input_(io_service_), rtc_running_(false) +#else + ptr_last_segment_(&last_segment_) #endif { std::string buffer(configuration_.payload_size_, 'X'); |