diff options
author | Luca Muscariello <lumuscar@cisco.com> | 2022-03-30 22:29:28 +0200 |
---|---|---|
committer | Mauro Sardara <msardara@cisco.com> | 2022-03-31 19:51:47 +0200 |
commit | c46e5df56b67bb8ea7a068d39324c640084ead2b (patch) | |
tree | eddeb17785938e09bc42eec98ee09b8a28846de6 /ctrl/libhicnctrl/src | |
parent | 18fa668f25d3cc5463417ce7df6637e31578e898 (diff) |
feat: boostrap hicn 22.02
The current patch provides several new features, improvements,
bug fixes and also complete rewrite of entire components.
- lib
The hicn packet parser has been improved with a new packet
format fully based on UDP. The TCP header is still temporarily
supported but the UDP header will replace completely the new hicn
packet format. Improvements have been made to make sure every
packet parsing operation is made via this library. The current
new header can be used as header between the payload and the
UDP header or as trailer in the UDP surplus area to be tested
when UDP options will start to be used.
- hicn-light
The portable packet forwarder has been completely rewritten from
scratch with the twofold objective to improve performance and
code size but also to drop dependencies such as libparc which is
now removed by the current implementation.
- hicn control
the control library is the agent that is used to program the
packet forwarders via their binary API. This component has
benefited from significant improvements in terms of interaction
model which is now event driven and more robust to failures.
- VPP plugin has been updated to support VPP 22.02
- transport
Major improvement have been made to the RTC protocol, to the
support of IO modules and to the security sub system. Signed
manifests are the default data authenticity and integrity framework.
Confidentiality can be enabled by sharing the encryption key to the
prod/cons layer. The library has been tested with group key based
applications such as broadcast/multicast and real-time on-line
meetings with trusted server keys or MLS.
- testing
Unit testing has been introduced using GoogleTest. One third of
the code base is covered by unit testing with priority on
critical features. Functional testing has also been introduce
using Docker, linux bridging and Robot Framework to define
test with Less Code techniques to facilitate the extension
of the coverage.
Co-authored-by: Mauro Sardara <msardara@cisco.com>
Co-authored-by: Jordan Augé <jordan.auge+fdio@cisco.com>
Co-authored-by: Michele Papalini <micpapal@cisco.com>
Co-authored-by: Angelo Mantellini <manangel@cisco.com>
Co-authored-by: Jacques Samain <jsamain@cisco.com>
Co-authored-by: Olivier Roques <oroques+fdio@cisco.com>
Co-authored-by: Enrico Loparco <eloparco@cisco.com>
Co-authored-by: Giulio Grassi <gigrassi@cisco.com>
Change-Id: I75d0ef70f86d921e3ef503c99271216ff583c215
Signed-off-by: Luca Muscariello <muscariello@ieee.org>
Signed-off-by: Mauro Sardara <msardara@cisco.com>
Diffstat (limited to 'ctrl/libhicnctrl/src')
-rw-r--r-- | ctrl/libhicnctrl/src/CMakeLists.txt | 147 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/api.c | 1735 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/api_private.h | 223 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/cli.c | 883 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/face.c | 430 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/hicnctrl.c | 805 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/libhicnctrl-config.cmake.in | 8 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/modules/CMakeLists.txt | 69 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/modules/hicn_light_api.c | 2278 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/modules/hicn_light_common.c | 33 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/modules/hicn_light_common.h | 95 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/modules/hicn_light_ng_api.c | 3111 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/modules/hicn_plugin_api.c | 895 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/route.c | 102 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/util/hash.h | 379 |
15 files changed, 5918 insertions, 5275 deletions
diff --git a/ctrl/libhicnctrl/src/CMakeLists.txt b/ctrl/libhicnctrl/src/CMakeLists.txt index f9934d70e..c8a93c56c 100644 --- a/ctrl/libhicnctrl/src/CMakeLists.txt +++ b/ctrl/libhicnctrl/src/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021-2022 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: @@ -11,80 +11,127 @@ # See the License for the specific language governing permissions and # limitations under the License. -list(APPEND COMPILER_DEFINITIONS - "-DWITH_POLICY" -) - +############################################################## +# Source files +############################################################## set(SOURCE_FILES - face.c - route.c - api.c + route.c + api.c ) set(HEADER_FILES - api_private.h + api_private.h ) + +############################################################## +# Libraries to link +############################################################## set(LIBRARIES - m - dl - ${HICN_LIBRARIES} + m + dl + ${HICN_LIBRARIES} ) + +############################################################## +# Include directories +############################################################## set(INCLUDE_DIRS + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/../includes/ - ${HICN_INCLUDE_DIRS} + PUBLIC + $<BUILD_INTERFACE:${Libhicnctrl_INCLUDE_DIRS}> + $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> ) -# Android requires static libraries + +############################################################## +# Library type +############################################################## if (DISABLE_SHARED_LIBRARIES) - set(LIBRARIES ${LIBRARIES} ${LIBHICN_STATIC}) - set(LINK_TYPE STATIC) + set(LIBRARIES ${LIBRARIES} ${LIBHICN_STATIC}) + set(LINK_TYPE STATIC) else () - set(LINK_TYPE SHARED STATIC) + set(LINK_TYPE SHARED STATIC) endif () + +############################################################## +# Do not use modules if Android +############################################################## if (${CMAKE_SYSTEM_NAME} MATCHES Android) - list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/modules/hicn_light_api.c - ) + list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/modules/hicn_light_common.c + ${CMAKE_CURRENT_SOURCE_DIR}/modules/hicn_light_ng_api.c + ) else() - add_subdirectory(modules) + add_subdirectory(modules) endif() + +############################################################## +# Compiler options +############################################################## +set(COMPILER_OPTIONS + ${DEFAULT_COMPILER_OPTIONS} +) + + +############################################################## +# Build main hicnctrl library +############################################################## build_library(${LIBHICNCTRL} - ${LINK_TYPE} - SOURCES ${SOURCE_FILES} ${HEADER_FILES} - INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES} + ${LINK_TYPE} + SOURCES ${SOURCE_FILES} ${HEADER_FILES} + INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES} + LINK_LIBRARIES ${LIBRARIES} + DEPENDS ${DEPENDENCIES} + COMPONENT ${LIBHICNCTRL_COMPONENT} + INCLUDE_DIRS ${INCLUDE_DIRS} + DEFINITIONS PUBLIC ${COMPILER_DEFINITIONS} + VERSION ${CURRENT_VERSION} + EXPORT_NAME "${LIBHICNCTRL_COMPONENT}" + COMPILE_OPTIONS ${COMPILER_OPTIONS} +) + + +############################################################## +# Cmake config files +############################################################## +create_cmake_config ( + ${LIBHICNCTRL_COMPONENT} + INCLUDE_DIRS ${Libhicnctrl_INCLUDE_DIRS} + VERSION ${CURRENT_VERSION} + COMPONENT ${LIBHICNCTRL_COMPONENT} + NAMESPACE hicn +) + + +############################################################## +# Build executables +############################################################## +if (NOT DISABLE_EXECUTABLES) + if (DISABLE_SHARED_LIBRARIES) + set(LIBRARIES ${LIBRARIES} ${LIBHICNCTRL_STATIC}) + set(DEPENDENCIES ${LIBHICNCTRL_STATIC}) + else () + set(LIBRARIES ${LIBRARIES} ${LIBHICN_SHARED} ${LIBHICNCTRL_SHARED}) + set(DEPENDENCIES ${LIBHICNCTRL_SHARED}) + endif () + + list(APPEND DAEMON_SRC + hicnctrl.c + ) + + build_executable(${HICNCTRL} + SOURCES ${DAEMON_SRC} LINK_LIBRARIES ${LIBRARIES} DEPENDS ${DEPENDENCIES} COMPONENT ${LIBHICNCTRL_COMPONENT} INCLUDE_DIRS ${INCLUDE_DIRS} - HEADER_ROOT_DIR hicn DEFINITIONS ${COMPILER_DEFINITIONS} -) - -if (NOT DISABLE_EXECUTABLES) - if (DISABLE_SHARED_LIBRARIES) - set(LIBRARIES ${LIBRARIES} ${LIBHICNCTRL_STATIC}) - set(DEPENDENCIES ${LIBHICNCTRL_STATIC}) - else () - set(LIBRARIES ${LIBRARIES} ${LIBHICN_SHARED} ${LIBHICNCTRL_SHARED}) - set(DEPENDENCIES ${LIBHICNCTRL_SHARED}) - endif () - - list(APPEND DAEMON_SRC - cli.c - ) - - build_executable(${HICNCTRL} - SOURCES ${DAEMON_SRC} - LINK_LIBRARIES ${LIBRARIES} - DEPENDS ${DEPENDENCIES} - COMPONENT ${LIBHICNCTRL_COMPONENT} - INCLUDE_DIRS ${INCLUDE_DIRS} - DEFINITIONS ${COMPILER_DEFINITIONS} - LINK_FLAGS ${LINK_FLAGS} - ) + LINK_FLAGS ${LINK_FLAGS} + COMPILE_OPTIONS ${COMPILER_OPTIONS} + ) endif () diff --git a/ctrl/libhicnctrl/src/api.c b/ctrl/libhicnctrl/src/api.c index 4bb66c784..4156ceff9 100644 --- a/ctrl/libhicnctrl/src/api.c +++ b/ctrl/libhicnctrl/src/api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -18,22 +18,26 @@ * \brief Implementation of hICN control library API */ +#include <assert.h> +#include <dlfcn.h> // dlopen +#include <hicn/strategy.h> #include <hicn/util/log.h> -#include "api_private.h" +#include <hicn/ctrl/route.h> +#include <math.h> // log2 -#include <math.h> // log2 -#include <dlfcn.h> // dlopen +#include "api_private.h" +#if 0 /* /!\ Please update constants in public header file upon changes */ const char * connection_state_str[] = { -#define _(x) [HC_CONNECTION_STATE_ ## x] = STRINGIZE(x), +#define _(x) [HC_CONNECTION_STATE_##x] = STRINGIZE(x), foreach_connection_state #undef _ }; /* /!\ Please update constants in public header file upon changes */ const char * connection_type_str[] = { -#define _(x) [CONNECTION_TYPE_ ## x] = STRINGIZE(x), +#define _(x) [CONNECTION_TYPE_##x] = STRINGIZE(x), foreach_connection_type #undef _ }; @@ -48,151 +52,72 @@ connection_type_from_str(const char * str) else if (strcasecmp(str, "HICN") == 0) return CONNECTION_TYPE_HICN; else - return CONNECTION_TYPE_UNDEFINED; + return CONNECTION_TYPE_UNDEFINED; } - -/* Conversions to shield lib user from heterogeneity */ - -#define IS_VALID_LIST_CONNECTIONS_TYPE(x) ((x >= CONN_GRE) && (x <= CONN_HICN)) - -const hc_connection_type_t map_from_list_connections_type[] = { - [CONN_GRE] = CONNECTION_TYPE_UNDEFINED, - [CONN_TCP] = CONNECTION_TYPE_TCP, - [CONN_UDP] = CONNECTION_TYPE_UDP, - [CONN_MULTICAST] = CONNECTION_TYPE_UNDEFINED, - [CONN_L2] = CONNECTION_TYPE_UNDEFINED, - [CONN_HICN] = CONNECTION_TYPE_HICN, -}; - -#define IS_VALID_LIST_LISTENERS_TYPE(x) ((x >= ENCAP_TCP) && (x <= ENCAP_HICN)) - -const hc_connection_type_t map_from_encap_type[] = { - [ENCAP_TCP] = CONNECTION_TYPE_TCP, - [ENCAP_UDP] = CONNECTION_TYPE_UDP, - [ENCAP_ETHER] = CONNECTION_TYPE_UNDEFINED, - [ENCAP_LOCAL] = CONNECTION_TYPE_UNDEFINED, - [ENCAP_HICN] = CONNECTION_TYPE_HICN, -}; - -const connection_type map_to_connection_type[] = { - [CONNECTION_TYPE_TCP] = TCP_CONN, - [CONNECTION_TYPE_UDP] = UDP_CONN, - [CONNECTION_TYPE_HICN] = HICN_CONN, -}; - -const listener_mode map_to_listener_mode[] = { - [CONNECTION_TYPE_TCP] = IP_MODE, - [CONNECTION_TYPE_UDP] = IP_MODE, - [CONNECTION_TYPE_HICN] = HICN_MODE, -}; - -#define IS_VALID_LIST_CONNECTIONS_STATE(x) ((x >= IFACE_UP) && (x <= IFACE_UNKNOWN)) - -/* -#define IS_VALID_CONNECTION_STATE(x) IS_VALID_ENUM_TYPE(CONNECTION_STATE, x) - -static const connection_state map_to_connection_state[] = { - [HC_CONNECTION_STATE_UP] = IFACE_UP, - [HC_CONNECTION_STATE_DOWN] = IFACE_DOWN, -}; - -*/ - -const hc_connection_state_t map_from_list_connections_state[] = { - [IFACE_UP] = HC_CONNECTION_STATE_UP, - [IFACE_DOWN] = HC_CONNECTION_STATE_DOWN, - [IFACE_UNKNOWN] = HC_CONNECTION_STATE_UNDEFINED, -}; - - -const int map_from_addr_type[] = { - [ADDR_INET] = AF_INET, - [ADDR_INET6] = AF_INET6, - [ADDR_LINK] = AF_UNSPEC, - [ADDR_IFACE] = AF_UNSPEC, - [ADDR_UNIX] = AF_UNSPEC, -}; - -const address_type map_to_addr_type[] = { - [AF_INET] = ADDR_INET, - [AF_INET6] = ADDR_INET6, -}; +#endif /****************************************************************************** * Control Data ******************************************************************************/ -hc_data_t * -hc_data_create(size_t in_element_size, size_t out_element_size, data_callback_t complete_cb) -{ - hc_data_t * data = malloc(sizeof(hc_data_t)); - if (!data) - goto ERR_MALLOC; - - /* FIXME Could be NULL thanks to realloc provided size is 0 */ - data->max_size_log = DEFAULT_SIZE_LOG; - data->in_element_size = in_element_size; - data->out_element_size = out_element_size; - data->size = 0; - data->complete = false; - data->command_id = 0; // TODO this could also be a busy mark in the socket - /* No callback needed in blocking code for instance */ - data->complete_cb = complete_cb; - - data->buffer = malloc((1 << data->max_size_log) * data->out_element_size); - if (!data->buffer) - goto ERR_BUFFER; - data->ret = 0; - - return data; +hc_data_t *hc_data_create(size_t in_element_size, size_t out_element_size, + data_callback_t complete_cb) { + hc_data_t *data = malloc(sizeof(hc_data_t)); + if (!data) goto ERR_MALLOC; + + /* FIXME Could be NULL thanks to realloc provided size is 0 */ + data->max_size_log = DEFAULT_SIZE_LOG; + data->in_element_size = in_element_size; + data->out_element_size = out_element_size; + data->size = 0; + data->complete = false; + data->command_id = 0; // TODO this could also be a busy mark in the socket + /* No callback needed in blocking code for instance */ + data->complete_cb = complete_cb; + + data->buffer = malloc((1 << data->max_size_log) * data->out_element_size); + if (!data->buffer) goto ERR_BUFFER; + data->ret = 0; + data->current = 0; + + return data; ERR_BUFFER: - hc_data_free(data); + hc_data_free(data); ERR_MALLOC: - return NULL; + return NULL; } -void -hc_data_free(hc_data_t * data) -{ - if (data->buffer) - free(data->buffer); - free(data); +void hc_data_free(hc_data_t *data) { + if (data) free(data->buffer); + free(data); } -int -hc_data_ensure_available(hc_data_t * data, size_t count) -{ - size_t new_size_log = (data->size + count - 1 > 0) - ? log2(data->size + count - 1) + 1 - : 0; - if (new_size_log > data->max_size_log) { - data->max_size_log = new_size_log; - data->buffer = realloc(data->buffer, (1 << new_size_log) * data->out_element_size); - if (!data->buffer) - return -1; - } +int hc_data_ensure_available(hc_data_t *data, size_t count) { + size_t new_size_log = + (data->size + count - 1 > 0) ? log2(data->size + count - 1) + 1 : 0; + if (new_size_log > data->max_size_log) { + data->max_size_log = new_size_log; + data->buffer = + realloc(data->buffer, (1 << new_size_log) * data->out_element_size); + if (!data->buffer) return -1; + } - return 0; + return 0; } -int -hc_data_push_many(hc_data_t * data, const void * elements, size_t count) -{ - if (hc_data_ensure_available(data, count) < 0) - return -1; +int hc_data_push_many(hc_data_t *data, const void *elements, size_t count) { + if (hc_data_ensure_available(data, count) < 0) return -1; - memcpy(data->buffer + data->size * data->out_element_size, elements, - count * data->out_element_size); - data->size += count; + memcpy(data->buffer + data->size * data->out_element_size, elements, + count * data->out_element_size); + data->size += count; - return 0; + return 0; } -int -hc_data_push(hc_data_t * data, const void * element) -{ - return hc_data_push_many(data, element, 1); +int hc_data_push(hc_data_t *data, const void *element) { + return hc_data_push_many(data, element, 1); } /** @@ -200,61 +125,48 @@ hc_data_push(hc_data_t * data, const void * element) * NOTE: This function make sure there is enough room available in the data * structure. */ -u8 * -hc_data_get_next(hc_data_t * data) -{ - if (hc_data_ensure_available(data, 1) < 0) - return NULL; +u8 *hc_data_get_next(hc_data_t *data) { + if (hc_data_ensure_available(data, 1) < 0) return NULL; - return data->buffer + data->size * data->out_element_size; + return data->buffer + data->size * data->out_element_size; } -int -hc_data_set_callback(hc_data_t * data, data_callback_t cb, void * cb_data) -{ - data->complete_cb = cb; - data->complete_cb_data = cb_data; - return 0; +int hc_data_set_callback(hc_data_t *data, data_callback_t cb, void *cb_data) { + data->complete_cb = cb; + data->complete_cb_data = cb_data; + return 0; } -int -hc_data_set_complete(hc_data_t * data) -{ - data->complete = true; - data->ret = 0; - if (data->complete_cb) - return data->complete_cb(data, data->complete_cb_data); - return 0; +int hc_data_set_complete(hc_data_t *data) { + data->complete = true; + data->ret = 0; + if (data->complete_cb) return data->complete_cb(data, data->complete_cb_data); + return 0; } -int -hc_data_set_error(hc_data_t * data) -{ - data->ret = -1; - return 0; +int hc_data_set_error(hc_data_t *data) { + data->ret = -1; + return 0; } -int -hc_data_reset(hc_data_t * data) -{ - data->size = 0; - return 0; +int hc_data_reset(hc_data_t *data) { + data->size = 0; + return 0; } -static hc_sock_t * _open_module(const char *name) -{ +static hc_sock_t *_open_module(const char *name, const char *url) { char complete_name[128]; #ifdef __APPLE__ - sprintf(complete_name, "%s.dylib", name); + snprintf(complete_name, 128, "%s.dylib", name); #elif defined(__linux__) - sprintf(complete_name, "%s.so", name); + snprintf(complete_name, 128, "%s.so", name); #else - #error "System not supported for dynamic lynking" +#error "System not supported for dynamic lynking" #endif void *handle = 0; const char *error = 0; - hc_sock_t *(*creator)(void) = 0; + hc_sock_t *(*creator)(const char *) = 0; hc_sock_t *ret = 0; // open module @@ -263,307 +175,305 @@ static hc_sock_t * _open_module(const char *name) if ((error = dlerror()) != 0) { ERROR("%s", error); } - return 0; } // get factory method - creator = (hc_sock_t * (*)(void)) dlsym(handle, "_hc_sock_create"); + creator = + (hc_sock_t * (*)(const char *)) dlsym(handle, "_hc_sock_create_url"); if (!creator) { if ((error = dlerror()) != 0) { ERROR("%s", error); - return 0; } + return 0; } - ret = (*creator)(); + ret = (*creator)(NULL); ret->handle = handle; return ret; } -hc_sock_t *hc_sock_create_forwarder(forwarder_t forwarder) -{ - switch (forwarder) - { - case HICNLIGHT: - return _open_module("hicnlightctrl_module"); - case VPP: - return _open_module("vppctrl_module"); - default: - return NULL; - } +hc_sock_t *hc_sock_create_forwarder_url(forwarder_type_t forwarder, + const char *url) { + switch (forwarder) { + case HICNLIGHT: + return _open_module("hicnlightctrl_module", url); + case HICNLIGHT_NG: + return _open_module("hicnlightngctrl_module", url); + case VPP: + return _open_module("vppctrl_module", url); + default: + return NULL; + } } #ifdef ANDROID // In android we do not load a module at runtime // but we link the hicnlight implmentation directly // to the main library -extern hc_sock_t *_hc_sock_create(); +extern hc_sock_t *_hc_sock_create_url(const char *url); #endif -hc_sock_t *hc_sock_create(void) -{ +hc_sock_t *hc_sock_create_forwarder(forwarder_type_t forwarder) { #ifdef ANDROID - hc_sock_t *ret = _hc_sock_create(); - ret->handle = NULL; - return ret; + assert(forwarder == HICNLIGHT_NG); + hc_sock_t *ret = _hc_sock_create_url(NULL); + ret->handle = NULL; + return ret; #else - return hc_sock_create_forwarder(HICNLIGHT); + return hc_sock_create_forwarder_url(forwarder, NULL); #endif } -void hc_sock_free(hc_sock_t *s) -{ - void *handle = s->handle; - s->hc_sock_free(s); - - if (handle) { - dlclose(handle); - } +hc_sock_t *hc_sock_create(void) { + return hc_sock_create_forwarder(HICNLIGHT_NG); } -int hc_sock_get_next_seq(hc_sock_t *s) -{ - return s->hc_sock_get_next_seq(s); -} +void hc_sock_free(hc_sock_t *s) { + void *handle = s->handle; + s->hc_sock_free(s); -int hc_sock_set_nonblocking(hc_sock_t *s) -{ - return s->hc_sock_get_next_seq(s); + if (handle) { + dlclose(handle); + } } -int hc_sock_get_fd(hc_sock_t *s) -{ - return s->hc_sock_get_fd(s); +int hc_sock_get_next_seq(hc_sock_t *s) { return s->hc_sock_get_next_seq(s); } + +int hc_sock_set_nonblocking(hc_sock_t *s) { return s->hc_sock_get_next_seq(s); } + +int hc_sock_get_fd(hc_sock_t *s) { return s->hc_sock_get_fd(s); } + +int hc_sock_connect(hc_sock_t *s) { return s->hc_sock_connect(s); } + +int hc_sock_get_available(hc_sock_t *s, u8 **buffer, size_t *size) { + return s->hc_sock_get_available(s, buffer, size); } -int hc_sock_connect(hc_sock_t *s) -{ - return s->hc_sock_connect(s); +int hc_sock_send(hc_sock_t *s, hc_msg_t *msg, size_t msglen, uint32_t seq) { + return s->hc_sock_send(s, msg, msglen, seq); } -int hc_sock_get_available(hc_sock_t *s, u8 **buffer, size_t *size) -{ - return s->hc_sock_get_available(s, buffer, size); +int hc_sock_recv(hc_sock_t *s) { return s->hc_sock_recv(s); } + +int hc_sock_process(hc_sock_t *s, hc_data_t **data) { + return s->hc_sock_process(s, data); } -int hc_sock_send(hc_sock_t *s, hc_msg_t *msg, size_t msglen, int seq) -{ - return s->hc_sock_send(s, msg, msglen, seq); +int hc_sock_callback(hc_sock_t *s, hc_data_t **data) { + return s->hc_sock_callback(s, data); } -int hc_sock_recv(hc_sock_t *s) -{ - return s->hc_sock_recv(s); +int hc_sock_reset(hc_sock_t *s) { return s->hc_sock_reset(s); } + +void hc_sock_increment_woff(hc_sock_t *s, size_t bytes) { + s->hc_sock_increment_woff(s, bytes); } -int hc_sock_process(hc_sock_t *s, hc_data_t **data) -{ - return s->hc_sock_process(s, data); +int hc_sock_prepare_send(hc_sock_t *s, hc_result_t *result, + data_callback_t complete_cb, void *complete_cb_data) { + return s->hc_sock_prepare_send(s, result, complete_cb, complete_cb_data); } -int hc_sock_callback(hc_sock_t *s, hc_data_t **data) -{ - return s->hc_sock_callback(s, data); +int hc_sock_set_recv_timeout_ms(hc_sock_t *s, long timeout_ms) { + return s->hc_sock_set_recv_timeout_ms(s, timeout_ms); } -int hc_sock_reset(hc_sock_t *s) -{ - return s->hc_sock_reset(s); +/*----------------------------------------------------------------------------* + * LISTENER + *----------------------------------------------------------------------------*/ + +int hc_listener_create(hc_sock_t *s, hc_listener_t *listener) { + return s->hc_listener_create(s, listener); } -int hc_listener_create(hc_sock_t *s, hc_listener_t *listener) -{ - return s->hc_listener_create(s, listener); +hc_result_t *hc_listener_create_conf(hc_sock_t *s, hc_listener_t *listener) { + return s->hc_listener_create_conf(s, listener); } int hc_listener_get(hc_sock_t *s, hc_listener_t *listener, - hc_listener_t **listener_found) -{ - return s->hc_listener_get(s, listener, listener_found); + hc_listener_t **listener_found) { + return s->hc_listener_get(s, listener, listener_found); } -int hc_listener_delete(hc_sock_t *s, hc_listener_t *listener) -{ - return s->hc_listener_delete(s, listener); +int hc_listener_delete(hc_sock_t *s, hc_listener_t *listener) { + return s->hc_listener_delete(s, listener); } -int hc_listener_list(hc_sock_t *s, hc_data_t **pdata) -{ - return s->hc_listener_list(s, pdata); +int hc_listener_list(hc_sock_t *s, hc_data_t **pdata) { + return s->hc_listener_list(s, pdata); } GENERATE_FIND(listener); /* LISTENER VALIDATE */ -int -hc_listener_validate(const hc_listener_t * listener) -{ - if (!IS_VALID_FAMILY(listener->family)) - return -1; - - if (!IS_VALID_CONNECTION_TYPE(listener->type)) - return -1; +int hc_listener_validate(const hc_listener_t *listener) { + if (!IS_VALID_NAME(listener->name)) { + ERROR("[hc_listener_validate] Invalid name specified"); + return -1; + } + if (!IS_VALID_INTERFACE_NAME(listener->interface_name)) { + ERROR("[hc_listener_validate] Invalid interface_name specified"); + return -1; + } + if (!IS_VALID_TYPE(listener->type)) { + ERROR("[hc_listener_validate] Invalid type specified"); + return -1; + } + if (!IS_VALID_FAMILY(listener->family)) { + ERROR("[hc_listener_validate] Invalid family specified"); + return -1; + } + if (!IS_VALID_ADDRESS(&listener->local_addr, listener->family)) { + ERROR("[hc_listener_validate] Invalid local_addr specified"); + return -1; + } + if (!IS_VALID_PORT(listener->local_port)) { + ERROR("[hc_listener_validate] Invalid local_port specified"); + return -1; + } - return 0; + return 0; } /* LISTENER CMP */ -int -hc_listener_cmp(const hc_listener_t * l1, const hc_listener_t * l2) -{ - int rc; - - rc = INT_CMP(l1->type, l2->type); - if (rc != 0) - return rc; - - rc = INT_CMP(l1->family, l2->family); - if (rc != 0) - return rc; +int hc_listener_cmp(const hc_listener_t *l1, const hc_listener_t *l2) { + int rc; - rc = strncmp(l1->interface_name, l2->interface_name, INTERFACE_LEN); - if (rc != 0) - return rc; + rc = INT_CMP(l1->type, l2->type); + if (rc != 0) return rc; - rc = ip_address_cmp(&l1->local_addr, &l2->local_addr, l1->family); - if (rc != 0) - return rc; + rc = INT_CMP(l1->family, l2->family); + if (rc != 0) return rc; - rc = INT_CMP(l1->local_port, l2->local_port); - if (rc != 0) - return rc; + rc = strncmp(l1->interface_name, l2->interface_name, INTERFACE_LEN); + if (rc != 0) return rc; - return rc; -} + rc = ip_address_cmp(&l1->local_addr, &l2->local_addr, l1->family); + if (rc != 0) return rc; -/* LISTENER PARSE */ + rc = INT_CMP(l1->local_port, l2->local_port); + if (rc != 0) return rc; -int -hc_listener_parse(void * in, hc_listener_t * listener) -{ - int rc; - - list_listeners_command * cmd = (list_listeners_command *)in; - - if (!IS_VALID_LIST_LISTENERS_TYPE(cmd->encapType)) - return -1; - - hc_connection_type_t type = map_from_encap_type[cmd->encapType]; - if (type == CONNECTION_TYPE_UNDEFINED) - return -1; - - if (!IS_VALID_ADDR_TYPE(cmd->addressType)) - return -1; - - int family = map_from_addr_type[cmd->addressType]; - if (!IS_VALID_FAMILY(family)) - return -1; - - *listener = (hc_listener_t) { - .id = cmd->connid, - .type = type, - .family = family, - .local_addr = UNION_CAST(cmd->address, ip_address_t), - .local_port = ntohs(cmd->port), - }; - rc = snprintf(listener->name, SYMBOLIC_NAME_LEN, "%s", cmd->listenerName); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[hc_listener_parse] Unexpected truncation of symbolic name string"); - rc = snprintf(listener->interface_name, INTERFACE_LEN, "%s", cmd->interfaceName); - if (rc >= INTERFACE_LEN) - WARN("[hc_listener_parse] Unexpected truncation of interface name string"); - return 0; + return rc; } /* LISTENER SNPRINTF */ /* /!\ Please update constants in header file upon changes */ -int -hc_listener_snprintf(char * s, size_t size, hc_listener_t * listener) -{ - char local[MAXSZ_URL]; - int rc; - rc = url_snprintf(local, MAXSZ_URL, - listener->family, &listener->local_addr, listener->local_port); - if (rc >= MAXSZ_URL) - WARN("[hc_listener_snprintf] Unexpected truncation of URL string"); - if (rc < 0) - return rc; +int hc_listener_snprintf(char *s, size_t size, hc_listener_t *listener) { + char local[MAXSZ_URL]; + int rc; + rc = url_snprintf(local, MAXSZ_URL, listener->family, &listener->local_addr, + listener->local_port); + if (rc >= MAXSZ_URL) + WARN("[hc_listener_snprintf] Unexpected truncation of URL string"); + if (rc < 0) return rc; - return snprintf(s, size, "%s %s %s", listener->interface_name, local, - connection_type_str[listener->type]); + return snprintf(s, size, "%s %s %s interface=%s", listener->name, local, + face_type_str(listener->type), listener->interface_name); } -int hc_connection_create(hc_sock_t *s, hc_connection_t *connection) -{ - return s->hc_connection_create(s, connection); +/*----------------------------------------------------------------------------* + * CONNECTION + *----------------------------------------------------------------------------*/ + +int hc_connection_create(hc_sock_t *s, hc_connection_t *connection) { + return s->hc_connection_create(s, connection); +} + +hc_result_t *hc_connection_create_conf(hc_sock_t *s, + hc_connection_t *connection) { + return s->hc_connection_create_conf(s, connection); } int hc_connection_get(hc_sock_t *s, hc_connection_t *connection, - hc_connection_t **connection_found) -{ - return s->hc_connection_get(s, connection, connection_found); + hc_connection_t **connection_found) { + return s->hc_connection_get(s, connection, connection_found); } int hc_connection_update_by_id(hc_sock_t *s, int hc_connection_id, - hc_connection_t *connection) -{ - return s->hc_connection_update_by_id(s, hc_connection_id, connection); + hc_connection_t *connection) { + return s->hc_connection_update_by_id(s, hc_connection_id, connection); } int hc_connection_update(hc_sock_t *s, hc_connection_t *connection_current, - hc_connection_t *connection_updated) -{ - return s->hc_connection_update(s, connection_current, connection_updated); + hc_connection_t *connection_updated) { + return s->hc_connection_update(s, connection_current, connection_updated); } -int hc_connection_delete(hc_sock_t *s, hc_connection_t *connection) -{ - return s->hc_connection_delete(s, connection); +int hc_connection_delete(hc_sock_t *s, hc_connection_t *connection) { + return s->hc_connection_delete(s, connection); } -int hc_connection_list(hc_sock_t *s, hc_data_t **pdata) -{ - return s->hc_connection_list(s, pdata); +hc_result_t *hc_connection_delete_conf(hc_sock_t *s, + hc_connection_t *connection) { + return s->hc_connection_delete_conf(s, connection); } -int hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, face_state_t state) -{ - return s->hc_connection_set_admin_state(s, conn_id_or_name, state); +int hc_connection_list(hc_sock_t *s, hc_data_t **pdata) { + return s->hc_connection_list(s, pdata); +} + +int hc_connection_set_admin_state(hc_sock_t *s, const char *conn_id_or_name, + face_state_t state) { + return s->hc_connection_set_admin_state(s, conn_id_or_name, state); } #ifdef WITH_POLICY -int hc_connection_set_priority(hc_sock_t * s, const char * conn_id_or_name, uint32_t priority) -{ - return s->hc_connection_set_priority(s, conn_id_or_name, priority); +int hc_connection_set_priority(hc_sock_t *s, const char *conn_id_or_name, + uint32_t priority) { + return s->hc_connection_set_priority(s, conn_id_or_name, priority); } -int hc_connection_set_tags(hc_sock_t * s, const char * conn_id_or_name, policy_tags_t tags) -{ - return s->hc_connection_set_tags(s, conn_id_or_name, tags); +int hc_connection_set_tags(hc_sock_t *s, const char *conn_id_or_name, + policy_tags_t tags) { + return s->hc_connection_set_tags(s, conn_id_or_name, tags); } -#endif // WITH_POLICY +#endif // WITH_POLICY GENERATE_FIND(connection); /* CONNECTION VALIDATE */ -int -hc_connection_validate(const hc_connection_t * connection) -{ - if (!IS_VALID_FAMILY(connection->family)) - return -1; - - if (!IS_VALID_CONNECTION_TYPE(connection->type)) - return -1; - - /* TODO assert both local and remote have the right family */ +int hc_connection_validate(const hc_connection_t *connection) { + if (!IS_VALID_NAME(connection->name)) { + ERROR("[hc_connection_validate] Invalid name specified"); + return -1; + } + if (!IS_VALID_INTERFACE_NAME(connection->interface_name)) { + ERROR("[hc_connection_validate] Invalid interface_name specified"); + return -1; + } + if (!IS_VALID_TYPE(connection->type)) { + ERROR("[hc_connection_validate] Invalid type specified"); + return -1; + } + if (!IS_VALID_FAMILY(connection->family)) { + ERROR("[hc_connection_validate] Invalid family specified"); + return -1; + } + if (!IS_VALID_ADDRESS(&connection->local_addr, connection->family)) { + ERROR("[hc_connection_validate] Invalid local_addr specified"); + return -1; + } + if (!IS_VALID_PORT(connection->local_port)) { + ERROR("[hc_connection_validate] Invalid local_port specified"); + return -1; + } + if (!IS_VALID_ADDRESS(&connection->remote_addr, connection->family)) { + ERROR("[hc_connection_validate] Invalid remote_addr specified"); + return -1; + } + if (!IS_VALID_PORT(connection->remote_port)) { + ERROR("[hc_connection_validate] Invalid remote_port specified"); + return -1; + } - return 0; + return 0; } /* CONNECTION CMP */ @@ -573,719 +483,692 @@ hc_connection_validate(const hc_connection_t * connection) * As connections are specific to hicn-light, we can safely use IP and ports for * comparison independently of the face type. */ -int hc_connection_cmp(const hc_connection_t * c1, const hc_connection_t * c2) -{ - int rc; +int hc_connection_cmp(const hc_connection_t *c1, const hc_connection_t *c2) { + int rc; - rc = INT_CMP(c1->type, c2->type); - if (rc != 0) - return rc; + rc = INT_CMP(c1->type, c2->type); + if (rc != 0) return rc; - rc = INT_CMP(c1->family, c2->family); - if (rc != 0) - return rc; + rc = INT_CMP(c1->family, c2->family); + if (rc != 0) return rc; - rc = strncmp(c1->interface_name, c2->interface_name, INTERFACE_LEN); - if (rc != 0) - return rc; + rc = strncmp(c1->interface_name, c2->interface_name, INTERFACE_LEN); + if (rc != 0) return rc; - rc = ip_address_cmp(&c1->local_addr, &c2->local_addr, c1->family); - if (rc != 0) - return rc; + rc = ip_address_cmp(&c1->local_addr, &c2->local_addr, c1->family); + if (rc != 0) return rc; - rc = INT_CMP(c1->local_port, c2->local_port); - if (rc != 0) - return rc; + rc = INT_CMP(c1->local_port, c2->local_port); + if (rc != 0) return rc; - rc = ip_address_cmp(&c1->remote_addr, &c2->remote_addr, c1->family); - if (rc != 0) - return rc; + rc = ip_address_cmp(&c1->remote_addr, &c2->remote_addr, c1->family); + if (rc != 0) return rc; - rc = INT_CMP(c1->remote_port, c2->remote_port); - if (rc != 0) - return rc; + rc = INT_CMP(c1->remote_port, c2->remote_port); + if (rc != 0) return rc; - return rc; -} - -/* CONNECTION PARSE */ - -int -hc_connection_parse(void * in, hc_connection_t * connection) -{ - int rc; - list_connections_command * cmd = (list_connections_command *)in; - - if (!IS_VALID_LIST_CONNECTIONS_TYPE(cmd->connectionData.connectionType)) - return -1; - - hc_connection_type_t type = map_from_list_connections_type[cmd->connectionData.connectionType]; - if (type == CONNECTION_TYPE_UNDEFINED) - return -1; - - if (!IS_VALID_LIST_CONNECTIONS_STATE(cmd->state)) - return -1; - - hc_connection_state_t state = map_from_list_connections_state[cmd->state]; - if (state == HC_CONNECTION_STATE_UNDEFINED) - return -1; - - if (!IS_VALID_ADDR_TYPE(cmd->connectionData.ipType)) - return -1; - - int family = map_from_addr_type[cmd->connectionData.ipType]; - if (!IS_VALID_FAMILY(family)) - return -1; - - *connection = (hc_connection_t) { - .id = cmd->connid, - .type = type, - .family = family, - .local_addr = cmd->connectionData.localIp, - //.local_addr = UNION_CAST(cmd->connectionData.localIp, ip_address_t), - .local_port = ntohs(cmd->connectionData.localPort), - .remote_addr = cmd->connectionData.remoteIp, - //.remote_addr = UNION_CAST(cmd->connectionData.remoteIp, ip_address_t), - .remote_port = ntohs(cmd->connectionData.remotePort), - .admin_state = cmd->connectionData.admin_state, -#ifdef WITH_POLICY - .priority = cmd->connectionData.priority, - .tags = cmd->connectionData.tags, -#endif /* WITH_POLICY */ - .state = state, - }; - rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "%s", cmd->connectionData.symbolic); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[hc_connection_parse] Unexpected truncation of symbolic name string"); - rc = snprintf(connection->interface_name, INTERFACE_LEN, "%s", cmd->interfaceName); - if (rc >= INTERFACE_LEN) - WARN("[hc_connection_parse] Unexpected truncation of interface name string"); - return 0; + return rc; } /* CONNECTION SNPRINTF */ /* /!\ Please update constants in header file upon changes */ -int -hc_connection_snprintf(char * s, size_t size, const hc_connection_t * connection) -{ - char local[MAXSZ_URL]; - char remote[MAXSZ_URL]; - int rc; - - // assert(connection->connection_state) - - rc = url_snprintf(local, MAXSZ_URL, connection->family, - &connection->local_addr, connection->local_port); - if (rc >= MAXSZ_URL) - WARN("[hc_connection_snprintf] Unexpected truncation of URL string"); - if (rc < 0) - return rc; - rc = url_snprintf(remote, MAXSZ_URL, connection->family, - &connection->remote_addr, connection->remote_port); - if (rc >= MAXSZ_URL) - WARN("[hc_connection_snprintf] Unexpected truncation of URL string"); - if (rc < 0) - return rc; - - return snprintf(s, size, "%s %s %s %s %s", - connection_state_str[connection->state], - connection->interface_name, - local, - remote, - connection_type_str[connection->type]); -} - -int hc_face_create(hc_sock_t *s, hc_face_t *face) -{ - return s->hc_face_create(s, face); +int hc_connection_snprintf(char *s, size_t size, + const hc_connection_t *connection) { + char local[MAXSZ_URL]; + char remote[MAXSZ_URL]; + int rc; + + // assert(connection->connection_state) + if (strcmp(connection->name, "SELF") == 0) { + return snprintf(s, size, "%s", connection->name); + } + + rc = url_snprintf(local, MAXSZ_URL, connection->family, + &connection->local_addr, connection->local_port); + if (rc >= MAXSZ_URL) + WARN("[hc_connection_snprintf] Unexpected truncation of URL string"); + if (rc < 0) return rc; + rc = url_snprintf(remote, MAXSZ_URL, connection->family, + &connection->remote_addr, connection->remote_port); + if (rc >= MAXSZ_URL) + WARN("[hc_connection_snprintf] Unexpected truncation of URL string"); + if (rc < 0) return rc; + + return snprintf(s, size, "%s %s %s %s", connection->name, local, remote, + face_type_str(connection->type)); } -int hc_face_get(hc_sock_t *s, hc_face_t *face, hc_face_t **face_found) -{ - return s->hc_face_get(s, face, face_found); +int hc_face_create(hc_sock_t *s, hc_face_t *face) { + return s->hc_face_create(s, face); } -int hc_face_delete(hc_sock_t *s, hc_face_t *face) -{ - return s->hc_face_delete(s, face); +int hc_face_get(hc_sock_t *s, hc_face_t *face, hc_face_t **face_found) { + return s->hc_face_get(s, face, face_found); } -int hc_face_list(hc_sock_t *s, hc_data_t **pdata) -{ - return s->hc_face_list(s, pdata); +int hc_face_delete(hc_sock_t *s, hc_face_t *face, uint8_t delete_listener) { + return s->hc_face_delete(s, face, delete_listener); } -int hc_face_list_async(hc_sock_t *s) -{ - return s->hc_face_list_async(s); +int hc_face_list(hc_sock_t *s, hc_data_t **pdata) { + return s->hc_face_list(s, pdata); } -int hc_face_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, face_state_t state) -{ - return s->hc_face_set_admin_state(s, conn_id_or_name, state); +int hc_face_list_async(hc_sock_t *s) { return s->hc_face_list_async(s); } + +int hc_face_set_admin_state(hc_sock_t *s, const char *conn_id_or_name, + face_state_t state) { + return s->hc_face_set_admin_state(s, conn_id_or_name, state); } #ifdef WITH_POLICY -int hc_face_set_priority(hc_sock_t * s, const char * conn_id_or_name, uint32_t priority) -{ - return s->hc_face_set_priority(s, conn_id_or_name, priority); +int hc_face_set_priority(hc_sock_t *s, const char *conn_id_or_name, + uint32_t priority) { + return s->hc_face_set_priority(s, conn_id_or_name, priority); } -int hc_face_set_tags(hc_sock_t * s, const char * conn_id_or_name, policy_tags_t tags) -{ - return s->hc_face_set_tags(s, conn_id_or_name, tags); +int hc_face_set_tags(hc_sock_t *s, const char *conn_id_or_name, + policy_tags_t tags) { + return s->hc_face_set_tags(s, conn_id_or_name, tags); } #endif /* WITH_POLICY */ /* /!\ Please update constants in header file upon changes */ -int -hc_face_snprintf(char * s, size_t size, hc_face_t * face) -{ - /* URLs are also big enough to contain IP addresses in the hICN case */ - char local[MAXSZ_URL]; - char remote[MAXSZ_URL]; +int hc_face_snprintf(char *s, size_t size, hc_face_t *face) { + /* URLs are also big enough to contain IP addresses in the hICN case */ + char local[MAXSZ_URL]; + char remote[MAXSZ_URL]; #ifdef WITH_POLICY - char tags[MAXSZ_POLICY_TAGS]; + char tags[MAXSZ_POLICY_TAGS]; #endif /* WITH_POLICY */ - int rc; - - switch(face->face.type) { - case FACE_TYPE_HICN: - case FACE_TYPE_HICN_LISTENER: - rc = ip_address_snprintf(local, MAXSZ_URL, - &face->face.local_addr, - face->face.family); - if (rc >= MAXSZ_URL) - WARN("[hc_face_snprintf] Unexpected truncation of URL string"); - if (rc < 0) - return rc; - rc = ip_address_snprintf(remote, MAXSZ_URL, - &face->face.remote_addr, - face->face.family); - if (rc >= MAXSZ_URL) - WARN("[hc_face_snprintf] Unexpected truncation of URL string"); - if (rc < 0) - return rc; - break; - case FACE_TYPE_TCP: - case FACE_TYPE_UDP: - case FACE_TYPE_TCP_LISTENER: - case FACE_TYPE_UDP_LISTENER: - rc = url_snprintf(local, MAXSZ_URL, face->face.family, - &face->face.local_addr, - face->face.local_port); - if (rc >= MAXSZ_URL) - WARN("[hc_face_snprintf] Unexpected truncation of URL string"); - if (rc < 0) - return rc; - rc = url_snprintf(remote, MAXSZ_URL, face->face.family, - &face->face.remote_addr, - face->face.remote_port); - if (rc >= MAXSZ_URL) - WARN("[hc_face_snprintf] Unexpected truncation of URL string"); - if (rc < 0) - return rc; - break; - default: - return -1; - } + int rc; + + switch (face->face.type) { + case FACE_TYPE_HICN: + case FACE_TYPE_HICN_LISTENER: + rc = ip_address_snprintf(local, MAXSZ_URL, &face->face.local_addr, + face->face.family); + if (rc >= MAXSZ_URL) + WARN("[hc_face_snprintf] Unexpected truncation of URL string"); + if (rc < 0) return rc; + rc = ip_address_snprintf(remote, MAXSZ_URL, &face->face.remote_addr, + face->face.family); + if (rc >= MAXSZ_URL) + WARN("[hc_face_snprintf] Unexpected truncation of URL string"); + if (rc < 0) return rc; + break; + case FACE_TYPE_TCP: + case FACE_TYPE_UDP: + case FACE_TYPE_TCP_LISTENER: + case FACE_TYPE_UDP_LISTENER: + rc = url_snprintf(local, MAXSZ_URL, face->face.family, + &face->face.local_addr, face->face.local_port); + if (rc >= MAXSZ_URL) + WARN("[hc_face_snprintf] Unexpected truncation of URL string"); + if (rc < 0) return rc; + rc = url_snprintf(remote, MAXSZ_URL, face->face.family, + &face->face.remote_addr, face->face.remote_port); + if (rc >= MAXSZ_URL) + WARN("[hc_face_snprintf] Unexpected truncation of URL string"); + if (rc < 0) return rc; + break; + default: + return -1; + } // [#ID NAME] TYPE LOCAL_URL REMOTE_URL STATE/ADMIN_STATE (TAGS) #ifdef WITH_POLICY - rc = policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->face.tags); - if (rc >= MAXSZ_POLICY_TAGS) - WARN("[hc_face_snprintf] Unexpected truncation of policy tags string"); - if (rc < 0) - return rc; - - return snprintf(s, size, "[#%d %s] %s %s %s %s %s/%s [%d] (%s)", - face->id, - face->name, - face->face.netdevice.index != NETDEVICE_UNDEFINED_INDEX ? face->face.netdevice.name : "*", - face_type_str[face->face.type], - local, - remote, - face_state_str[face->face.state], - face_state_str[face->face.admin_state], - face->face.priority, - tags); + rc = policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->face.tags); + if (rc >= MAXSZ_POLICY_TAGS) + WARN("[hc_face_snprintf] Unexpected truncation of policy tags string"); + if (rc < 0) return rc; + + return snprintf( + s, size, "[#%d %s] %s %s %s %s %s/%s [%d] (%s)", face->id, face->name, + face->face.netdevice.index != NETDEVICE_UNDEFINED_INDEX + ? face->face.netdevice.name + : "*", + face_type_str(face->face.type), local, remote, + face_state_str(face->face.state), face_state_str(face->face.admin_state), + face->face.priority, tags); #else - return snprintf(s, size, "[#%d %s] %s %s %s %s %s/%s", - face->id, - face->name, - face->face.netdevice.index != NETDEVICE_UNDEFINED_INDEX ? face->face.netdevice.name : "*", - face_type_str[face->face.type], - local, - remote, - face_state_str[face->face.state], - face_state_str[face->face.admin_state]); + return snprintf(s, size, "[#%d %s] %s %s %s %s %s/%s", face->id, face->name, + face->face.netdevice.index != NETDEVICE_UNDEFINED_INDEX + ? face->face.netdevice.name + : "*", + face_type_str(face->face.type), local, remote, + face_state_str(face->face.state), + face_state_str(face->face.admin_state)); #endif /* WITH_POLICY */ } -int -hc_connection_parse_to_face(void * in, hc_face_t * face) -{ - hc_connection_t connection; - - if (hc_connection_parse(in, &connection) < 0) { - ERROR("[hc_connection_parse_to_face] Could not parse connection"); - return -1; - } +/*----------------------------------------------------------------------------* + * ROUTE + *----------------------------------------------------------------------------*/ - if (hc_connection_to_face(&connection, face) < 0) { - ERROR("[hc_connection_parse_to_face] Could not convert connection to face."); - return -1; - } - - return 0; +int hc_route_create(hc_sock_t *s, hc_route_t *route) { + return s->hc_route_create(s, route); } -int hc_route_create(hc_sock_t * s, hc_route_t * route) -{ - return s->hc_route_create(s, route); +hc_result_t *hc_route_create_conf(hc_sock_t *s, hc_route_t *route) { + return s->hc_route_create_conf(s, route); } -int hc_route_delete(hc_sock_t * s, hc_route_t * route) -{ - return s->hc_route_delete(s, route); +int hc_route_delete(hc_sock_t *s, hc_route_t *route) { + return s->hc_route_delete(s, route); } -int hc_route_list(hc_sock_t * s, hc_data_t ** pdata) -{ - return s->hc_route_list(s, pdata); +int hc_route_list(hc_sock_t *s, hc_data_t **pdata) { + return s->hc_route_list(s, pdata); } -int hc_route_list_async(hc_sock_t * s) -{ - return s->hc_route_list_async(s); -} +int hc_route_list_async(hc_sock_t *s) { return s->hc_route_list_async(s); } -/* ROUTE PARSE */ +/* ROUTE SNPRINTF */ -int -hc_route_parse(void * in, hc_route_t * route) -{ - list_routes_command * cmd = (list_routes_command *) in; +/* /!\ Please update constants in header file upon changes */ +int hc_route_snprintf(char *s, size_t size, hc_route_t *route) { + /* interface cost prefix length */ - if (!IS_VALID_ADDR_TYPE(cmd->addressType)) { - ERROR("[hc_route_parse] Invalid address type"); - return -1; - } + char prefix[MAXSZ_IP_ADDRESS]; + int rc; - int family = map_from_addr_type[cmd->addressType]; - if (!IS_VALID_FAMILY(family)) { - ERROR("[hc_route_parse] Invalid address family"); - return -1; - } + rc = ip_address_snprintf(prefix, MAXSZ_IP_ADDRESS, &route->remote_addr, + route->family); + if (rc >= MAXSZ_IP_ADDRESS) + ; + if (rc < 0) return rc; - *route = (hc_route_t) { - .face_id = cmd->connid, - .family = family, - .remote_addr = UNION_CAST(cmd->address, ip_address_t), - .len = cmd->len, - .cost = cmd->cost, - }; - return 0; + return snprintf(s, size, "%s %*d %s %*d conn_id=%d", route->name, MAXSZ_COST, + route->cost, prefix, MAXSZ_LEN, route->len, route->face_id); } -/* ROUTE SNPRINTF */ - -/* /!\ Please update constants in header file upon changes */ -int -hc_route_snprintf(char * s, size_t size, hc_route_t * route) -{ - /* interface cost prefix length */ - - char prefix[MAXSZ_IP_ADDRESS]; - int rc; - - rc = ip_address_snprintf(prefix, MAXSZ_IP_ADDRESS, &route->remote_addr, - route->family); - if (rc >= MAXSZ_IP_ADDRESS) - ; - if (rc < 0) - return rc; +int hc_route_validate(const hc_route_t *route) { + if (!IS_VALID_ID(route->connection_id)) { + ERROR("[hc_route_validate] Invalid connection id"); + return -1; + } + if (!IS_VALID_NAME(route->name) && !IS_VALID_STR_ID(route->name)) { + ERROR("[hc_route_validate] Invalid name specified"); + return -1; + } + if (!IS_VALID_FAMILY(route->family)) { + ERROR("[hc_route_validate] Invalid family specified"); + return -1; + } + if (!IS_VALID_ADDRESS(&route->remote_addr, route->family)) { + ERROR("[hc_route_validate] Invalid remote_addr specified"); + return -1; + } + if (!IS_VALID_ROUTE_COST(route->cost)) { + ERROR("[hc_route_validate] Invalid cost"); + return -1; + } + if (!IS_VALID_PREFIX_LEN(route->len)) { + ERROR("[hc_route_validate] Invalid len"); + return -1; + } - return snprintf(s, size, "%*d %*d %s %*d", MAXSZ_FACE_ID, route->face_id, - MAXSZ_COST, route->cost, prefix, MAXSZ_LEN, route->len); + return 0; } +/*----------------------------------------------------------------------------* + * FACE + *----------------------------------------------------------------------------*/ + /* FACE -> LISTENER */ -int -hc_face_to_listener(const hc_face_t * face, hc_listener_t * listener) -{ - const face_t * f = &face->face; - - switch(f->type) { - case FACE_TYPE_HICN_LISTENER: - break; - case FACE_TYPE_TCP_LISTENER: - break; - case FACE_TYPE_UDP_LISTENER: - break; - default: - return -1; - } - return -1; /* XXX Not implemented */ +int hc_face_to_listener(const hc_face_t *face, hc_listener_t *listener) { + const face_t *f = &face->face; + + switch (f->type) { + case FACE_TYPE_HICN_LISTENER: + break; + case FACE_TYPE_TCP_LISTENER: + break; + case FACE_TYPE_UDP_LISTENER: + break; + default: + return -1; + } + return -1; /* XXX Not implemented */ } /* LISTENER -> FACE */ -int -hc_listener_to_face(const hc_listener_t * listener, hc_face_t * face) -{ - return -1; /* XXX Not implemented */ +int hc_listener_to_face(const hc_listener_t *listener, hc_face_t *face) { + return -1; /* XXX Not implemented */ } /* FACE -> CONNECTION */ -int -hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool generate_name) -{ - int rc; - const face_t * f = &face->face; - - switch(f->type) { - case FACE_TYPE_HICN: - *connection = (hc_connection_t) { - .type = CONNECTION_TYPE_HICN, - .family = f->family, - .local_addr = f->local_addr, - .local_port = 0, - .remote_addr = f->remote_addr, - .remote_port = 0, - .admin_state = face_state_to_connection_state(f->admin_state), - .state = face_state_to_connection_state(f->state), +int hc_face_to_connection(const hc_face_t *face, hc_connection_t *connection, + bool generate_name) { + int rc; + + const face_t *f = &face->face; + switch (f->type) { + case FACE_TYPE_HICN: + *connection = (hc_connection_t){ + .type = FACE_TYPE_HICN, + .family = f->family, + .local_addr = f->local_addr, + .local_port = 0, + .remote_addr = f->remote_addr, + .remote_port = 0, + .admin_state = f->admin_state, + .state = f->state, #ifdef WITH_POLICY - .priority = f->priority, - .tags = f->tags, + .priority = f->priority, + .tags = f->tags, #endif /* WITH_POLICY */ - }; - rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "%s", + }; + rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "%s", f->netdevice.name); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[hc_face_to_connection] Unexpected truncation of symbolic name string"); - break; - case FACE_TYPE_TCP: - *connection = (hc_connection_t) { - .type = CONNECTION_TYPE_TCP, - .family = f->family, - .local_addr = f->local_addr, - .local_port = f->local_port, - .remote_addr = f->remote_addr, - .remote_port = f->remote_port, - .admin_state = face_state_to_connection_state(f->admin_state), - .state = face_state_to_connection_state(f->state), + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[hc_face_to_connection] Unexpected truncation of symbolic " + "name string"); + break; + case FACE_TYPE_TCP: + *connection = (hc_connection_t){ + .type = FACE_TYPE_TCP, + .family = f->family, + .local_addr = f->local_addr, + .local_port = f->local_port, + .remote_addr = f->remote_addr, + .remote_port = f->remote_port, + .admin_state = f->admin_state, + .state = f->state, #ifdef WITH_POLICY - .priority = f->priority, - .tags = f->tags, + .priority = f->priority, + .tags = f->tags, #endif /* WITH_POLICY */ - }; - if (generate_name) { - rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "tcp%u", RANDBYTE()); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[hc_face_to_connection] Unexpected truncation of symbolic name string"); - } else { - memset(connection->name, 0, SYMBOLIC_NAME_LEN); - } - break; - case FACE_TYPE_UDP: - *connection = (hc_connection_t) { - .type = CONNECTION_TYPE_UDP, - .family = AF_INET, - .local_addr = f->local_addr, - .local_port = f->local_port, - .remote_addr = f->remote_addr, - .remote_port = f->remote_port, - .admin_state = face_state_to_connection_state(f->admin_state), - .state = face_state_to_connection_state(f->state), + }; + if (generate_name) { + rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "tcp%u", RANDBYTE()); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[hc_face_to_connection] Unexpected truncation of " + "symbolic name string"); + } else { + memset(connection->name, 0, SYMBOLIC_NAME_LEN); + } + break; + case FACE_TYPE_UDP: + *connection = (hc_connection_t){ + .type = FACE_TYPE_UDP, + .family = f->family, + .local_addr = f->local_addr, + .local_port = f->local_port, + .remote_addr = f->remote_addr, + .remote_port = f->remote_port, + .admin_state = f->admin_state, + .state = f->state, #ifdef WITH_POLICY - .priority = f->priority, - .tags = f->tags, + .priority = f->priority, + .tags = f->tags, #endif /* WITH_POLICY */ - }; - if (generate_name) { - rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "udp%u", RANDBYTE()); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[hc_face_to_connection] Unexpected truncation of symbolic name string"); - } else { - memset(connection->name, 0, SYMBOLIC_NAME_LEN); - } - snprintf(connection->interface_name, INTERFACE_LEN, "%s", - f->netdevice.name); - break; - default: - return -1; - } + }; + if (generate_name) { + rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "udp%u", RANDBYTE()); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[hc_face_to_connection] Unexpected truncation of " + "symbolic name string"); + } else { + memset(connection->name, 0, SYMBOLIC_NAME_LEN); + } + snprintf(connection->interface_name, INTERFACE_LEN, "%s", + f->netdevice.name); + break; + default: + return -1; + } - rc = snprintf(connection->interface_name, INTERFACE_LEN, "%s", - f->netdevice.name); - if (rc >= INTERFACE_LEN) - WARN("hc_face_to_connection] Unexpected truncation of interface name string"); + connection->id = face->id; + rc = snprintf(connection->interface_name, INTERFACE_LEN, "%s", + f->netdevice.name); + if (rc >= INTERFACE_LEN) + WARN( + "hc_face_to_connection] Unexpected truncation of interface name " + "string"); - return 0; + return 0; } /* CONNECTION -> FACE */ -int -hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face) -{ - int rc; - switch (connection->type) { - case CONNECTION_TYPE_TCP: - *face = (hc_face_t) { - .id = connection->id, - .face = { - .type = FACE_TYPE_TCP, - .family = connection->family, - .local_addr = connection->local_addr, - .local_port = connection->local_port, - .remote_addr = connection->remote_addr, - .remote_port = connection->remote_port, - .admin_state = connection_state_to_face_state(connection->admin_state), - .state = connection_state_to_face_state(connection->state), +int hc_connection_to_face(const hc_connection_t *connection, hc_face_t *face) { + int rc; + switch (connection->type) { + case FACE_TYPE_TCP: + *face = (hc_face_t){ + .id = connection->id, + .face = + { + .type = FACE_TYPE_TCP, + .family = connection->family, + .local_addr = connection->local_addr, + .local_port = connection->local_port, + .remote_addr = connection->remote_addr, + .remote_port = connection->remote_port, + .admin_state = connection->admin_state, + .state = connection->state, #ifdef WITH_POLICY - .priority = connection->priority, - .tags = connection->tags, + .priority = connection->priority, + .tags = connection->tags, #endif /* WITH_POLICY */ - }, - }; - break; - case CONNECTION_TYPE_UDP: - *face = (hc_face_t) { - .id = connection->id, - .face = { - .type = FACE_TYPE_UDP, - .family = connection->family, - .local_addr = connection->local_addr, - .local_port = connection->local_port, - .remote_addr = connection->remote_addr, - .remote_port = connection->remote_port, - .admin_state = connection_state_to_face_state(connection->admin_state), - .state = connection_state_to_face_state(connection->state), + }, + }; + break; + case FACE_TYPE_UDP: + *face = (hc_face_t){ + .id = connection->id, + .face = + { + .type = FACE_TYPE_UDP, + .family = connection->family, + .local_addr = connection->local_addr, + .local_port = connection->local_port, + .remote_addr = connection->remote_addr, + .remote_port = connection->remote_port, + .admin_state = connection->admin_state, + .state = connection->state, #ifdef WITH_POLICY - .priority = connection->priority, - .tags = connection->tags, + .priority = connection->priority, + .tags = connection->tags, #endif /* WITH_POLICY */ - }, - }; - break; - case CONNECTION_TYPE_HICN: - *face = (hc_face_t) { - .id = connection->id, - .face = { - .type = FACE_TYPE_HICN, - .family = connection->family, - .netdevice.index = NETDEVICE_UNDEFINED_INDEX, // XXX - .local_addr = connection->local_addr, - .remote_addr = connection->remote_addr, - .admin_state = connection_state_to_face_state(connection->admin_state), - .state = connection_state_to_face_state(connection->state), + }, + }; + break; + case FACE_TYPE_HICN: + *face = (hc_face_t){ + .id = connection->id, + .face = + { + .type = FACE_TYPE_HICN, + .family = connection->family, + .netdevice.index = NETDEVICE_UNDEFINED_INDEX, // XXX + .local_addr = connection->local_addr, + .remote_addr = connection->remote_addr, + .admin_state = connection->admin_state, + .state = connection->state, #ifdef WITH_POLICY - .priority = connection->priority, - .tags = connection->tags, + .priority = connection->priority, + .tags = connection->tags, #endif /* WITH_POLICY */ - }, - }; - break; - default: - return -1; - } - face->face.netdevice.name[0] = '\0'; - face->face.netdevice.index = 0; - rc = snprintf(face->name, SYMBOLIC_NAME_LEN, "%s", connection->name); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[hc_connection_to_face] Unexpected truncation of symbolic name string"); - rc = snprintf(face->face.netdevice.name, INTERFACE_LEN, "%s", connection->interface_name); - if (rc >= INTERFACE_LEN) - WARN("[hc_connection_to_face] Unexpected truncation of interface name string"); - netdevice_update_index(&face->face.netdevice); - return 0; + }, + }; + break; + default: + return -1; + } + face->face.netdevice.name[0] = '\0'; + face->face.netdevice.index = 0; + rc = snprintf(face->name, SYMBOLIC_NAME_LEN, "%s", connection->name); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[hc_connection_to_face] Unexpected truncation of symbolic name " + "string"); + rc = snprintf(face->face.netdevice.name, INTERFACE_LEN, "%s", + connection->interface_name); + if (rc >= INTERFACE_LEN) + WARN( + "[hc_connection_to_face] Unexpected truncation of interface name " + "string"); + netdevice_update_index(&face->face.netdevice); + return 0; } /* CONNECTION -> LISTENER */ -int -hc_connection_to_local_listener(const hc_connection_t * connection, hc_listener_t * listener) -{ - int rc; - *listener = (hc_listener_t) { - .id = ~0, - .type = connection->type, - .family = connection->family, - .local_addr = connection->local_addr, - .local_port = connection->local_port, - }; - rc = snprintf(listener->name, SYMBOLIC_NAME_LEN, "lst%u", RANDBYTE()); // generate name - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[hc_connection_to_local_listener] Unexpected truncation of symbolic name string"); - rc = snprintf(listener->interface_name, INTERFACE_LEN, "%s", connection->interface_name); - if (rc >= INTERFACE_LEN) - WARN("[hc_connection_to_local_listener] Unexpected truncation of interface name string"); +int hc_connection_to_local_listener(const hc_connection_t *connection, + hc_listener_t *listener) { + int rc; + + face_type_t listener_type; + switch (connection->type) { + case FACE_TYPE_UDP: + listener_type = FACE_TYPE_UDP_LISTENER; + break; + case FACE_TYPE_TCP: + listener_type = FACE_TYPE_TCP_LISTENER; + break; + default: + return -1; + } - return 0; + *listener = (hc_listener_t){ + .id = ~0, + .type = listener_type, + .family = connection->family, + .local_addr = connection->local_addr, + .local_port = connection->local_port, + }; + rc = snprintf(listener->name, SYMBOLIC_NAME_LEN, "lst%u", + RANDBYTE()); // generate name + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[hc_connection_to_local_listener] Unexpected truncation of " + "symbolic name string"); + rc = snprintf(listener->interface_name, INTERFACE_LEN, "%s", + connection->interface_name); + if (rc >= INTERFACE_LEN) + WARN( + "[hc_connection_to_local_listener] Unexpected truncation of " + "interface name string"); + + return 0; +} + +/*----------------------------------------------------------------------------* + * Punting + *----------------------------------------------------------------------------*/ + +int hc_punting_create(hc_sock_t *s, hc_punting_t *punting) { + return s->hc_punting_create(s, punting); } -int hc_punting_create(hc_sock_t *s, hc_punting_t *punting) -{ - return s->hc_punting_create(s, punting); +int hc_punting_get(hc_sock_t *s, hc_punting_t *punting, + hc_punting_t **punting_found) { + return s->hc_punting_get(s, punting, punting_found); } -int hc_punting_get(hc_sock_t *s, hc_punting_t *punting, - hc_punting_t **punting_found) -{ - return s->hc_punting_get(s, punting, punting_found); +int hc_punting_delete(hc_sock_t *s, hc_punting_t *punting) { + return s->hc_punting_delete(s, punting); } -int hc_punting_delete(hc_sock_t *s, hc_punting_t *punting) -{ - return s->hc_punting_delete(s, punting); +int hc_punting_list(hc_sock_t *s, hc_data_t **pdata) { + return s->hc_punting_list(s, pdata); } -int hc_punting_list(hc_sock_t *s, hc_data_t **pdata) -{ - return s->hc_punting_list(s, pdata); +int hc_punting_validate(const hc_punting_t *punting) { + if (!IS_VALID_FAMILY(punting->family)) return -1; + + /* + * We might use the zero value to add punting on all faces but this is not + * (yet) implemented + */ + if (punting->face_id == 0) { + ERROR("Punting on all faces is not (yet) implemented."); + return -1; + } + + return 0; } -int hc_punting_validate(const hc_punting_t * punting) -{ - if (!IS_VALID_FAMILY(punting->family)) - return -1; - - /* - * We might use the zero value to add punting on all faces but this is not - * (yet) implemented - */ - if (punting->face_id == 0) { - ERROR("Punting on all faces is not (yet) implemented."); - return -1; - } +int hc_punting_cmp(const hc_punting_t *p1, const hc_punting_t *p2) { + int rc; - return 0; + rc = INT_CMP(p1->face_id, p2->face_id); + if (rc != 0) return rc; + + rc = INT_CMP(p1->family, p2->family); + if (rc != 0) return rc; + + rc = ip_address_cmp(&p1->prefix, &p2->prefix, p1->family); + if (rc != 0) return rc; + + rc = INT_CMP(p1->prefix_len, p2->prefix_len); + if (rc != 0) return rc; + + return rc; } -int hc_punting_cmp(const hc_punting_t * p1, const hc_punting_t * p2) -{ - int rc; +int hc_punting_parse(void *in, hc_punting_t *punting) { + ERROR("hc_punting_parse not (yet) implemented."); + return -1; +} - rc = INT_CMP(p1->face_id, p2->face_id); - if (rc != 0) - return rc; +int hc_punting_snprintf(char *s, size_t size, hc_punting_t *punting) { + ERROR("hc_punting_snprintf not (yet) implemented."); + return -1; +} - rc = INT_CMP(p1->family, p2->family); - if (rc != 0) - return rc; +/*----------------------------------------------------------------------------* + * Cache + *----------------------------------------------------------------------------*/ - rc = ip_address_cmp(&p1->prefix, &p2->prefix, p1->family); - if (rc != 0) - return rc; +int hc_cache_set_store(hc_sock_t *s, hc_cache_t *cache) { + return s->hc_cache_set_store(s, cache); +} - rc = INT_CMP(p1->prefix_len, p2->prefix_len); - if (rc != 0) - return rc; +int hc_cache_set_serve(hc_sock_t *s, hc_cache_t *cache) { + return s->hc_cache_set_serve(s, cache); +} - return rc; +int hc_cache_clear(hc_sock_t *s, hc_cache_t *cache) { + return s->hc_cache_clear(s, cache); } -int hc_punting_parse(void * in, hc_punting_t * punting) -{ - ERROR("hc_punting_parse not (yet) implemented."); - return -1; +int hc_cache_list(hc_sock_t *s, hc_data_t **pdata) { + return s->hc_cache_list(s, pdata); } -int hc_punting_snprintf(char * s, size_t size, hc_punting_t * punting) -{ - ERROR("hc_punting_snprintf not (yet) implemented."); - return -1; +int hc_cache_snprintf(char *s, size_t size, const hc_cache_info_t *cache_info) { + return snprintf( + s, size, "Cache set_store=%s set_serve=%s size=%lu stale_entries=%lu", + cache_info->store ? "true" : "false", + cache_info->serve ? "true" : "false", (unsigned long)cache_info->cs_size, + (unsigned long)cache_info->num_stale_entries); } -int hc_cache_set_store(hc_sock_t *s, int enabled) -{ - return s->hc_cache_set_store(s, enabled); +/*----------------------------------------------------------------------------* + * Strategy + *----------------------------------------------------------------------------*/ + +int hc_strategy_list(hc_sock_t *s, hc_data_t **data) { + return s->hc_strategy_list(s, data); } -int hc_cache_set_serve(hc_sock_t *s, int enabled) -{ - return s->hc_cache_set_serve(s, enabled); +int hc_strategy_set(hc_sock_t *s, hc_strategy_t *strategy) { + return s->hc_strategy_set(s, strategy); } -int hc_strategy_list(hc_sock_t *s, hc_data_t **data) -{ - return s->hc_strategy_list(s, data); +int hc_strategy_add_local_prefix(hc_sock_t *s, hc_strategy_t *strategy) { + return s->hc_strategy_add_local_prefix(s, strategy); } -int hc_strategy_set(hc_sock_t *s /* XXX */) -{ - return s->hc_strategy_set(s); +hc_result_t *hc_strategy_set_conf(hc_sock_t *s, hc_strategy_t *strategy) { + return s->hc_strategy_set_conf(s, strategy); +} + +hc_result_t *hc_strategy_add_local_prefix_conf(hc_sock_t *s, + hc_strategy_t *strategy) { + return s->hc_strategy_add_local_prefix_conf(s, strategy); } /* /!\ Please update constants in header file upon changes */ -int -hc_strategy_snprintf(char * s, size_t size, hc_strategy_t * strategy) -{ - return snprintf(s, size, "%s", strategy->name); +int hc_strategy_snprintf(char *s, size_t size, hc_strategy_t *strategy) { + return snprintf(s, size, "%s", strategy->name); } -int hc_wldr_set(hc_sock_t *s /* XXX */) -{ - return s->hc_wldr_set(s); +/*----------------------------------------------------------------------------* + * WLDR + *----------------------------------------------------------------------------*/ + +int hc_wldr_set(hc_sock_t *s /* XXX */) { return s->hc_wldr_set(s); } + +/*----------------------------------------------------------------------------* + * MAP-Me + *----------------------------------------------------------------------------*/ + +int hc_mapme_set(hc_sock_t *s, hc_mapme_t *mapme) { + return s->hc_mapme_set(s, mapme->enabled); } -int hc_mapme_set(hc_sock_t *s, int enabled) -{ - return s->hc_mapme_set(s, enabled); +int hc_mapme_set_discovery(hc_sock_t *s, hc_mapme_t *mapme) { + return s->hc_mapme_set_discovery(s, mapme->enabled); } -int hc_mapme_set_discovery(hc_sock_t *s, int enabled) -{ - return s->hc_mapme_set_discovery(s, enabled); +int hc_mapme_set_timescale(hc_sock_t *s, hc_mapme_t *mapme) { + return s->hc_mapme_set_timescale(s, mapme->timescale); } -int hc_mapme_set_timescale(hc_sock_t *s, double timescale) -{ - return s->hc_mapme_set_timescale(s, timescale); +int hc_mapme_set_retx(hc_sock_t *s, hc_mapme_t *mapme) { + return s->hc_mapme_set_retx(s, mapme->timescale); } -int hc_mapme_set_retx(hc_sock_t *s, double timescale) -{ - return s->hc_mapme_set_retx(s, timescale); +int hc_mapme_send_update(hc_sock_t *s, hc_mapme_t *mapme) { + return s->hc_mapme_send_update(s, mapme); } +/*----------------------------------------------------------------------------* + * Policy + *----------------------------------------------------------------------------*/ + #ifdef WITH_POLICY -/* POLICY PARSE */ +/* POLICY SNPRINTF */ -int -hc_policy_parse(void * in, hc_policy_t * policy) -{ - list_policies_command * cmd = (list_policies_command *) in; +/* /!\ Please update constants in header file upon changes */ +int hc_policy_snprintf(char *s, size_t size, hc_policy_t *policy) { return 0; } - if (!IS_VALID_ADDR_TYPE(cmd->addressType)) - return -1; +int hc_policy_validate(const hc_policy_t *policy) { + if (!IS_VALID_FAMILY(policy->family)) return -1; - int family = map_from_addr_type[cmd->addressType]; - if (!IS_VALID_FAMILY(family)) - return -1; + return 0; +} - *policy = (hc_policy_t) { - .family = family, - .remote_addr = UNION_CAST(cmd->address, ip_address_t), - .len = cmd->len, - .policy = cmd->policy, - }; - return 0; +#endif /* WITH_POLICY */ + +/*----------------------------------------------------------------------------* + * SUBSCRIPTION + *----------------------------------------------------------------------------*/ +int hc_subscription_create(hc_sock_t *s, hc_subscription_t *subscription) { + return s->hc_subscription_create(s, subscription); } -/* POLICY SNPRINTF */ +int hc_subscription_delete(hc_sock_t *s, hc_subscription_t *subscription) { + return s->hc_subscription_delete(s, subscription); +} -/* /!\ Please update constants in header file upon changes */ -int -hc_policy_snprintf(char * s, size_t size, hc_policy_t * policy) -{ - return 0; +hc_result_t *hc_subscription_create_conf(hc_sock_t *s, + hc_subscription_t *subscription) { + return s->hc_subscription_create_conf(s, subscription); +} + +hc_result_t *hc_subscription_delete_conf(hc_sock_t *s, + hc_subscription_t *subscription) { + return s->hc_subscription_delete_conf(s, subscription); +} + +/*----------------------------------------------------------------------------* + * Result + *----------------------------------------------------------------------------*/ + +hc_msg_t *hc_result_get_msg(hc_sock_t *s, hc_result_t *result) { + return s->hc_result_get_msg(result); +} + +int hc_result_get_cmd_id(hc_sock_t *s, hc_result_t *result) { + return s->hc_result_get_cmd_id(result); +} + +bool hc_result_get_success(hc_sock_t *s, hc_result_t *result) { + return s->hc_result_get_success(result); } -#endif /* WITH_POLICY */
\ No newline at end of file +void hc_result_free(hc_result_t *result) { free(result); } diff --git a/ctrl/libhicnctrl/src/api_private.h b/ctrl/libhicnctrl/src/api_private.h index 3922e1f3c..11cb2e00e 100644 --- a/ctrl/libhicnctrl/src/api_private.h +++ b/ctrl/libhicnctrl/src/api_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -17,10 +17,12 @@ #define HICN_API_PRIVATE_H #include <hicn/ctrl/api.h> -#include <hicn/ctrl/commands.h> #include <hicn/util/token.h> #include <hicn/util/log.h> #include <hicn/util/map.h> +#include <hicn/util/sstrncpy.h> +#include <hicn/validation.h> +#include <ctype.h> #define INT_CMP(x, y) ((x > y) ? 1 : (x < y) ? -1 : 0) #define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array)) @@ -34,57 +36,64 @@ #endif #define RANDBYTE() (u8)(rand() & 0xFF) -hc_connection_type_t -connection_type_from_str(const char * str); - -extern const hc_connection_type_t map_from_list_connections_type[]; -extern const hc_connection_type_t map_from_encap_type[]; -extern const connection_type map_to_connection_type[]; -extern const listener_mode map_to_listener_mode[]; -extern const hc_connection_state_t map_from_list_connections_state[]; -extern const int map_from_addr_type[]; -extern const address_type map_to_addr_type[]; -extern const char * connection_state_str[]; -extern const char * connection_type_str[]; - -typedef enum { - ENCAP_TCP, - ENCAP_UDP, - ENCAP_ETHER, - ENCAP_LOCAL, - ENCAP_HICN -} EncapType; - -#define connection_state_to_face_state(x) ((face_state_t)(x)) -#define face_state_to_connection_state(x) ((hc_connection_state_t)(x)) +/* + * Input validation + */ + +static inline bool IS_VALID_ADDRESS(const ip_address_t *addr, int family) { + char addr_str[INET6_ADDRSTRLEN]; + return !ip_address_empty(addr) && + ip_address_ntop(addr, addr_str, INET6_ADDRSTRLEN, family) >= 0; +} + +static inline bool IS_VALID_PREFIX_LEN(u8 len) { + return len <= MAX_IPV6_PREFIX_LEN; +} + +// https://github.com/shemminger/iproute2/blob/50b668bdbf0ebc270495eb4b352d0c3982159d0a/lib/utils.c#L825 +static inline bool IS_VALID_INTERFACE_NAME(const char *name) { + size_t len = strnlen_s(name, INTERFACE_LEN); + if (len == 0 || len >= IFNAMSIZ) return true; + + while (*name) { + if (*name == '/' || isspace(*name)) return false; + ++name; + } + return true; +} + +static inline bool IS_VALID_NAME(const char *name) { + return is_symbolic_name(name, SYMBOLIC_NAME_LEN); +} + +static inline bool IS_VALID_STR_ID(const char *name) { + return is_number(name, SYMBOLIC_NAME_LEN); +} + +#define IS_VALID_TYPE(x) IS_VALID_ENUM_TYPE(FACE_TYPE, x) #define IS_VALID_ADDR_TYPE(x) ((x >= ADDR_INET) && (x <= ADDR_UNIX)) -#define IS_VALID_CONNECTION_TYPE(x) IS_VALID_ENUM_TYPE(CONNECTION_TYPE, x) +#define IS_VALID_ID(x) (1) +#define IS_VALID_POLICY(x) (1) typedef struct hc_sock_impl_s hc_sock_impl_t; -int hc_data_ensure_available(hc_data_t * data, size_t count); -u8 *hc_data_get_next(hc_data_t * data); -int hc_data_set_error(hc_data_t * data); +int hc_data_ensure_available(hc_data_t *data, size_t count); +u8 *hc_data_get_next(hc_data_t *data); +int hc_data_set_error(hc_data_t *data); -int -hc_connection_parse_to_face(void * in, hc_face_t * face); +int hc_listener_to_face(const hc_listener_t *listener, hc_face_t *face); -int -hc_listener_to_face(const hc_listener_t * listener, hc_face_t * face); +int hc_connection_to_face(const hc_connection_t *connection, hc_face_t *face); -int -hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face); +int hc_face_to_listener(const hc_face_t *face, hc_listener_t *listener); -int -hc_face_to_listener(const hc_face_t * face, hc_listener_t * listener); +int hc_connection_to_local_listener(const hc_connection_t *connection, + hc_listener_t *listener); -int -hc_connection_to_local_listener(const hc_connection_t * connection, hc_listener_t * listener); - -int -hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool generate_name); +int hc_face_to_connection(const hc_face_t *face, hc_connection_t *connection, + bool generate_name); struct hc_sock_s { int (*hc_sock_get_next_seq)(hc_sock_t *s); @@ -92,17 +101,21 @@ struct hc_sock_s { int (*hc_sock_get_fd)(hc_sock_t *s); int (*hc_sock_connect)(hc_sock_t *s); int (*hc_sock_get_available)(hc_sock_t *s, u8 **buffer, size_t *size); - int (*hc_sock_send)(hc_sock_t *s, hc_msg_t *msg, size_t msglen, int seq); + int (*hc_sock_send)(hc_sock_t *s, hc_msg_t *msg, size_t msglen, uint32_t seq); int (*hc_sock_recv)(hc_sock_t *s); int (*hc_sock_process)(hc_sock_t *s, hc_data_t **data); int (*hc_sock_callback)(hc_sock_t *s, hc_data_t **data); int (*hc_sock_reset)(hc_sock_t *s); void (*hc_sock_free)(hc_sock_t *s); - + void (*hc_sock_increment_woff)(hc_sock_t *s, size_t bytes); + int (*hc_sock_prepare_send)(hc_sock_t *s, hc_result_t *result, + data_callback_t complete_cb, + void *complete_cb_data); + int (*hc_sock_set_recv_timeout_ms)(hc_sock_t *s, long timeout_ms); int (*hc_listener_create)(hc_sock_t *s, hc_listener_t *listener); int (*hc_listener_create_async)(hc_sock_t *s, hc_listener_t *listener); int (*hc_listener_get)(hc_sock_t *s, hc_listener_t *listener, - hc_listener_t **listener_found); + hc_listener_t **listener_found); int (*hc_listener_delete)(hc_sock_t *s, hc_listener_t *listener); int (*hc_listener_delete_async)(hc_sock_t *s, hc_listener_t *listener); int (*hc_listener_list)(hc_sock_t *s, hc_data_t **pdata); @@ -114,81 +127,105 @@ struct hc_sock_s { int (*hc_connection_create)(hc_sock_t *s, hc_connection_t *connection); int (*hc_connection_create_async)(hc_sock_t *s, hc_connection_t *connection); int (*hc_connection_get)(hc_sock_t *s, hc_connection_t *connection, - hc_connection_t **connection_found); + hc_connection_t **connection_found); int (*hc_connection_update_by_id)(hc_sock_t *s, int hc_connection_id, - hc_connection_t *connection); + hc_connection_t *connection); int (*hc_connection_update)(hc_sock_t *s, hc_connection_t *connection_current, - hc_connection_t *connection_updated); + hc_connection_t *connection_updated); int (*hc_connection_delete)(hc_sock_t *s, hc_connection_t *connection); int (*hc_connection_delete_async)(hc_sock_t *s, hc_connection_t *connection); int (*hc_connection_list)(hc_sock_t *s, hc_data_t **pdata); int (*hc_connection_list_async)(hc_sock_t *s, hc_data_t **pdata); int (*hc_connection_validate)(const hc_connection_t *connection); - int (*hc_connection_cmp)(const hc_connection_t *c1, const hc_connection_t *c2); + int (*hc_connection_cmp)(const hc_connection_t *c1, + const hc_connection_t *c2); int (*hc_connection_parse)(void *in, hc_connection_t *connection); - int (*hc_connection_set_admin_state)(hc_sock_t * s, const char * conn_id_or_name, face_state_t state); - int (*hc_connection_set_admin_state_async)(hc_sock_t * s, const char * conn_id_or_name, face_state_t state); + int (*hc_connection_set_admin_state)(hc_sock_t *s, + const char *conn_id_or_name, + face_state_t state); + int (*hc_connection_set_admin_state_async)(hc_sock_t *s, + const char *conn_id_or_name, + face_state_t state); #ifdef WITH_POLICY - int (*hc_connection_set_priority)(hc_sock_t * s, const char * conn_id_or_name, uint32_t priority); - int (*hc_connection_set_priority_async)(hc_sock_t * s, const char * conn_id_or_name, uint32_t priority); - int (*hc_connection_set_tags)(hc_sock_t * s, const char * conn_id_or_name, policy_tags_t tags); - int (*hc_connection_set_tags_async)(hc_sock_t * s, const char * conn_id_or_name, policy_tags_t tags); -#endif // WITH_POLICY + int (*hc_connection_set_priority)(hc_sock_t *s, const char *conn_id_or_name, + uint32_t priority); + int (*hc_connection_set_priority_async)(hc_sock_t *s, + const char *conn_id_or_name, + uint32_t priority); + int (*hc_connection_set_tags)(hc_sock_t *s, const char *conn_id_or_name, + policy_tags_t tags); + int (*hc_connection_set_tags_async)(hc_sock_t *s, const char *conn_id_or_name, + policy_tags_t tags); +#endif // WITH_POLICY int (*hc_connection_snprintf)(char *s, size_t size, - const hc_connection_t *connection); + const hc_connection_t *connection); int (*hc_face_create)(hc_sock_t *s, hc_face_t *face); int (*hc_face_get)(hc_sock_t *s, hc_face_t *face, hc_face_t **face_found); - int (*hc_face_delete)(hc_sock_t *s, hc_face_t *face); + int (*hc_face_delete)(hc_sock_t *s, hc_face_t *face, uint8_t delete_listener); int (*hc_face_list)(hc_sock_t *s, hc_data_t **pdata); int (*hc_face_list_async)(hc_sock_t *s); - int (*hc_face_set_admin_state)(hc_sock_t * s, const char * conn_id_or_name, face_state_t state); - int (*hc_face_set_admin_state_async)(hc_sock_t * s, const char * conn_id_or_name, face_state_t state); + int (*hc_face_set_admin_state)(hc_sock_t *s, const char *conn_id_or_name, + face_state_t state); + int (*hc_face_set_admin_state_async)(hc_sock_t *s, + const char *conn_id_or_name, + face_state_t state); #ifdef WITH_POLICY - int (*hc_face_set_priority)(hc_sock_t * s, const char * conn_id_or_name, uint32_t priority); - int (*hc_face_set_priority_async)(hc_sock_t * s, const char * conn_id_or_name, uint32_t priority); - int (*hc_face_set_tags)(hc_sock_t * s, const char * conn_id_or_name, policy_tags_t tags); - int (*hc_face_set_tags_async)(hc_sock_t * s, const char * conn_id_or_name, policy_tags_t tags); -#endif // WITH_POLICY + int (*hc_face_set_priority)(hc_sock_t *s, const char *conn_id_or_name, + uint32_t priority); + int (*hc_face_set_priority_async)(hc_sock_t *s, const char *conn_id_or_name, + uint32_t priority); + int (*hc_face_set_tags)(hc_sock_t *s, const char *conn_id_or_name, + policy_tags_t tags); + int (*hc_face_set_tags_async)(hc_sock_t *s, const char *conn_id_or_name, + policy_tags_t tags); +#endif // WITH_POLICY int (*hc_face_snprintf)(char *s, size_t size, hc_face_t *face); int (*hc_route_parse)(void *in, hc_route_t *route); - int (*hc_route_create)(hc_sock_t * s, hc_route_t * route); - int (*hc_route_create_async)(hc_sock_t * s, hc_route_t * route); - int (*hc_route_delete)(hc_sock_t * s, hc_route_t * route); - int (*hc_route_delete_async)(hc_sock_t * s, hc_route_t * route); - int (*hc_route_list)(hc_sock_t * s, hc_data_t ** pdata); - int (*hc_route_list_async)(hc_sock_t * s); + int (*hc_route_create)(hc_sock_t *s, hc_route_t *route); + int (*hc_route_create_async)(hc_sock_t *s, hc_route_t *route); + int (*hc_route_delete)(hc_sock_t *s, hc_route_t *route); + int (*hc_route_delete_async)(hc_sock_t *s, hc_route_t *route); + int (*hc_route_list)(hc_sock_t *s, hc_data_t **pdata); + int (*hc_route_list_async)(hc_sock_t *s); int (*hc_punting_create)(hc_sock_t *s, hc_punting_t *punting); int (*hc_punting_create_async)(hc_sock_t *s, hc_punting_t *punting); int (*hc_punting_get)(hc_sock_t *s, hc_punting_t *punting, - hc_punting_t **punting_found); + hc_punting_t **punting_found); int (*hc_punting_delete)(hc_sock_t *s, hc_punting_t *punting); int (*hc_punting_list)(hc_sock_t *s, hc_data_t **pdata); int (*hc_punting_validate)(const hc_punting_t *punting); int (*hc_punting_cmp)(const hc_punting_t *c1, const hc_punting_t *c2); int (*hc_punting_parse)(void *in, hc_punting_t *punting); - int (*hc_cache_set_store)(hc_sock_t *s, int enabled); - int (*hc_cache_set_serve)(hc_sock_t *s, int enabled); - int (*hc_cache_set_store_async)(hc_sock_t *s, int enabled); - int (*hc_cache_set_serve_async)(hc_sock_t *s, int enabled); + int (*hc_cache_parse)(void *in, hc_cache_info_t *cache_info); + int (*hc_cache_set_store)(hc_sock_t *s, hc_cache_t *cache); + int (*hc_cache_set_serve)(hc_sock_t *s, hc_cache_t *cache); + int (*hc_cache_clear)(hc_sock_t *s, hc_cache_t *cache); + int (*hc_cache_list)(hc_sock_t *s, hc_data_t **pdata); + int (*hc_cache_set_store_async)(hc_sock_t *s, hc_cache_t *cache); + int (*hc_cache_set_serve_async)(hc_sock_t *s, hc_cache_t *cache); + int (*hc_cache_snprintf)(char *s, size_t size, + const hc_cache_info_t *cache_info); int (*hc_strategy_list)(hc_sock_t *s, hc_data_t **data); int (*hc_strategy_snprintf)(char *s, size_t size, hc_strategy_t *strategy); - int (*hc_strategy_set)(hc_sock_t *s /* XXX */); + int (*hc_strategy_set)(hc_sock_t *s, hc_strategy_t *strategy); + int (*hc_strategy_add_local_prefix)(hc_sock_t *s, hc_strategy_t *strategy); int (*hc_wldr_set)(hc_sock_t *s /* XXX */); int (*hc_mapme_set)(hc_sock_t *s, int enabled); int (*hc_mapme_set_discovery)(hc_sock_t *s, int enabled); - int (*hc_mapme_set_timescale)(hc_sock_t *s, double timescale); - int (*hc_mapme_set_retx)(hc_sock_t *s, double timescale); + int (*hc_mapme_set_timescale)(hc_sock_t *s, uint32_t timescale); + int (*hc_mapme_set_retx)(hc_sock_t *s, uint32_t timescale); + int (*hc_mapme_send_update)(hc_sock_t *s, hc_mapme_t *mapme); #ifdef WITH_POLICY int (*hc_policy_parse)(void *in, hc_policy_t *policy); @@ -199,10 +236,34 @@ struct hc_sock_s { int (*hc_policy_list)(hc_sock_t *s, hc_data_t **pdata); int (*hc_policy_list_async)(hc_sock_t *s, hc_data_t **pdata); int (*hc_policy_snprintf)(char *s, size_t size, hc_policy_t *policy); -#endif // WITH_POLICY +#endif // WITH_POLICY + + int (*hc_subscription_create)(hc_sock_t *s, hc_subscription_t *subscription); + int (*hc_subscription_delete)(hc_sock_t *s, hc_subscription_t *subscription); + + hc_result_t *(*hc_listener_create_conf)(hc_sock_t *s, + hc_listener_t *listener); + hc_result_t *(*hc_listener_list_conf)(hc_sock_t *s, hc_data_t **pdata); + hc_result_t *(*hc_connection_create_conf)(hc_sock_t *s, + hc_connection_t *connection); + hc_result_t *(*hc_connection_delete_conf)(hc_sock_t *s, + hc_connection_t *connection); + hc_result_t *(*hc_route_create_conf)(hc_sock_t *s, hc_route_t *route); + hc_result_t *(*hc_strategy_set_conf)(hc_sock_t *s, hc_strategy_t *strategy); + hc_result_t *(*hc_strategy_add_local_prefix_conf)(hc_sock_t *s, + hc_strategy_t *strategy); + hc_result_t *(*hc_subscription_create_conf)(hc_sock_t *s, + hc_subscription_t *subscription); + hc_result_t *(*hc_subscription_delete_conf)(hc_sock_t *s, + hc_subscription_t *subscription); + + hc_msg_t *(*hc_result_get_msg)(hc_result_t *result); + bool (*hc_result_get_success)(hc_result_t *result); + int (*hc_result_get_cmd_id)(hc_result_t *result); + void (*hc_result_free)(hc_result_t *result); // Reference to module containing the implementation void *handle; }; -#endif // HICN_API_PRIVATE_H
\ No newline at end of file +#endif // HICN_API_PRIVATE_H diff --git a/ctrl/libhicnctrl/src/cli.c b/ctrl/libhicnctrl/src/cli.c deleted file mode 100644 index 064eb77e3..000000000 --- a/ctrl/libhicnctrl/src/cli.c +++ /dev/null @@ -1,883 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 cli.c - * \brief Command line interface - */ -#include <ctype.h> // isalpha isalnum -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> // getopt - -#include <hicn/ctrl.h> -#include <hicn/util/ip_address.h> -#include <hicn/util/token.h> - - -#define die(LABEL, MESSAGE) do { \ - printf(MESSAGE "\n"); \ - rc = -1; \ - goto ERR_ ## LABEL; \ -} while(0) - -#define foreach_object \ - _(UNDEFINED) \ - _(FACE) \ - _(ROUTE) \ - _(STRATEGY) \ - _(LISTENER) \ - _(CONNECTION) \ - _(N) - -typedef enum { -#define _(x) OBJECT_ ## x, -foreach_object -#undef _ -} hc_object_t; - -#define HICNLIGHT_PARAM "hicnlight" -#define VPP_PARAM "vpp" - -void -usage_header() -{ - fprintf(stderr, "Usage:\n"); -} - -void -usage_face_create(const char * prog, bool header, bool verbose) -{ - - if (header) - usage_header(); - fprintf(stderr, "%s -f TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT [INTERFACE_NAME]\n", prog); - if (verbose) - fprintf(stderr, " Create a face on specified address and port.\n"); -} - -void -usage_face_delete(const char * prog, bool header, bool verbose) -{ - if (header) - usage_header(); - fprintf(stderr, "%s -df ID\n", prog); - //fprintf(stderr, "%s -df NAME\n", prog); - fprintf(stderr, "%s -df TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT [INTERFACE_NAME]\n", prog); - if (verbose) - fprintf(stderr, " Delete a face...\n"); -} - -void -usage_face_list(const char * prog, bool header, bool verbose) -{ - if (header) - usage_header(); - fprintf(stderr, "%s -F\n", prog); - if (verbose) - fprintf(stderr, " List all faces.\n"); -} - -void -usage_face(const char * prog, bool header, bool verbose) -{ - usage_face_create(prog, header, verbose); - usage_face_delete(prog, header, verbose); - usage_face_list(prog, header, verbose); -} - -void -usage_route_create(const char * prog, bool header, bool verbose) -{ - if (header) - usage_header(); - fprintf(stderr, "%s -r FACE_ID PREFIX [COST]\n", prog); - //fprintf(stderr, "%s -r [FACE_ID|NAME] PREFIX [COST]\n", prog); - if (verbose) - fprintf(stderr, " Create a route...\n"); -} - -void -usage_route_delete(const char * prog, bool header, bool verbose) -{ - if (header) - usage_header(); - fprintf(stderr, "%s -dr FACE_ID PREFIX\n", prog); - //fprintf(stderr, "%s -dr [FACE_ID|NAME] PREFIX\n", prog); - if (verbose) - fprintf(stderr, " Delete a route...\n"); -} - -void -usage_route_list(const char * prog, bool header, bool verbose) -{ - if (header) - usage_header(); - fprintf(stderr, "%s -R\n", prog); - if (verbose) - fprintf(stderr, " List all routes.\n"); -} - -void -usage_route(const char * prog, bool header, bool verbose) -{ - usage_route_create(prog, header, verbose); - usage_route_delete(prog, header, verbose); - usage_route_list(prog, header, verbose); -} - -void -usage_forwarding_strategy_create(const char * prog, bool header, bool verbose) -{ - if (header) - usage_header(); -} -void -usage_forwarding_strategy_delete(const char * prog, bool header, bool verbose) -{ - if (header) - usage_header(); -} - -void -usage_forwarding_strategy_list(const char * prog, bool header, bool verbose) -{ - if (header) - usage_header(); - fprintf(stderr, "%s -S\n", prog); - if (verbose) - fprintf(stderr, " List all availble forwarding strategies.\n"); -} - -void -usage_forwarding_strategy(const char * prog, bool header, bool verbose) -{ - usage_forwarding_strategy_create(prog, header, verbose); - usage_forwarding_strategy_delete(prog, header, verbose); - usage_forwarding_strategy_list(prog, header, verbose); -} - -void -usage_listener_create(const char * prog, bool header, bool verbose) -{ - if (header) - usage_header(); - fprintf(stderr, "%s -l NAME TYPE LOCAL_ADDRESS LOCAL_PORT [INTERFACE_NAME]\n", prog); - if (verbose) - fprintf(stderr, " Create a listener on specified address and port.\n"); -} - -void -usage_listener_delete(const char * prog, bool header, bool verbose) -{ - if (header) - usage_header(); - fprintf(stderr, "%s -dl ID\n", prog); - fprintf(stderr, "%s -dl NAME\n", prog); - fprintf(stderr, "%s -dl TYPE LOCAL_ADDRESS LOCAL_PORT [INTERFACE_NAME]\n", prog); - if (verbose) - fprintf(stderr, " Delete a listener...\n"); -} - -void -usage_listener_list(const char * prog, bool header, bool verbose) -{ - if (header) - usage_header(); - fprintf(stderr, "%s -L\n", prog); - if (verbose) - fprintf(stderr, " List all listeners.\n"); -} - -void -usage_listener(const char * prog, bool header, bool verbose) -{ - usage_listener_create(prog, header, verbose); - usage_listener_delete(prog, header, verbose); - usage_listener_list(prog, header, verbose); -} -void -usage_connection_create(const char * prog, bool header, bool verbose) -{ - if (header) - usage_header(); - fprintf(stderr, "%s -c NAME TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT [INTERFACE_NAME]\n", prog); - if (verbose) - fprintf(stderr, " Create a connection on specified address and port.\n"); -} - -void -usage_connection_delete(const char * prog, bool header, bool verbose) -{ - if (header) - usage_header(); - fprintf(stderr, "%s -dc ID\n", prog); - fprintf(stderr, "%s -dc NAME\n", prog); - fprintf(stderr, "%s -dc TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT [INTERFACE_NAME]\n", prog); - if (verbose) - fprintf(stderr, " Delete a connection...\n"); -} - -void -usage_connection_list(const char * prog, bool header, bool verbose) -{ - if (header) - usage_header(); - fprintf(stderr, "%s -C\n", prog); - if (verbose) - fprintf(stderr, " List all connections.\n"); -} - -void -usage_connection(const char * prog, bool header, bool verbose) -{ - usage_connection_create(prog, header, verbose); - usage_connection_delete(prog, header, verbose); - usage_connection_list(prog, header, verbose); -} - -void usage(const char * prog) -{ - fprintf(stderr, "Usage: %s [ -z forwarder (hicnlight | vpp) ] [ [-d] [-f|-l|-c|-r] PARAMETERS | [-F|-L|-C|-R] ]\n", prog); - fprintf(stderr, "\n"); - fprintf(stderr, "High-level commands\n"); - fprintf(stderr, "\n"); - usage_face(prog, false, true); - usage_route(prog, false, true); - usage_forwarding_strategy(prog, false, true); - fprintf(stderr, "\n"); - fprintf(stderr, "Low level commands (hicn-light specific)\n"); - fprintf(stderr, "\n"); - usage_listener(prog, false, true); - usage_connection(prog, false, true); -} - -typedef struct { - hc_action_t action; - hc_object_t object; - union { - hc_face_t face; - hc_route_t route; - hc_connection_t connection; - hc_listener_t listener; - }; -} hc_command_t; - -/** - * Return true if string is purely an integer - */ -static inline -bool -is_number(const char *string) { - size_t len = strlen(string); - for (size_t i = 0; i < len; i++) - if (!isdigit(string[i])) - return false; - return true; -} - -/** - * A symbolic name must be at least 1 character and must begin with an alpha. - * The remainder must be an alphanum. - */ -static inline -bool -is_symbolic_name(const char *name) -{ - size_t len = strlen(name); - if (len <= 0) - return false; - if (!isalpha(name[0])) - return false; - for (size_t i = 1; i < len; i++) { - if (!isalnum(name[i])) - return false; - } - return true; -} - -face_type_t -face_type_from_str(const char * str) -{ -#define _(x) \ - if (strcasecmp(str, STRINGIZE(x)) == 0) \ - return FACE_TYPE_ ## x; \ - else -foreach_face_type -#undef _ - return FACE_TYPE_UNDEFINED; -} - - -int -parse_options(int argc, char *argv[], hc_command_t * command, forwarder_t *forwarder) -{ - command->object = OBJECT_UNDEFINED; - command->action = ACTION_CREATE; - int opt; - int family; - - while ((opt = getopt(argc, argv, "dflcrFLCRShz:")) != -1) { - switch (opt) { - case 'z' : - if (strncmp(optarg, VPP_PARAM, strlen(VPP_PARAM)) == 0) { - *forwarder = VPP; - } else if (strncmp(optarg, HICNLIGHT_PARAM, strlen(HICNLIGHT_PARAM))) { - *forwarder = HICNLIGHT; - } else { - usage(argv[0]); - exit(EXIT_FAILURE); - } - break; - case 'd': - command->action = ACTION_DELETE; - break; - case 'f': - command->object = OBJECT_FACE; - break; - case 'l': - command->object = OBJECT_LISTENER; - break; - case 'c': - command->object = OBJECT_CONNECTION; - break; - case 'r': - command->object = OBJECT_ROUTE; - break; - case 'F': - command->action = ACTION_LIST; - command->object = OBJECT_FACE; - break; - case 'L': - command->action = ACTION_LIST; - command->object = OBJECT_LISTENER; - break; - case 'C': - command->action = ACTION_LIST; - command->object = OBJECT_CONNECTION; - break; - case 'R': - command->action = ACTION_LIST; - command->object = OBJECT_ROUTE; - break; - case 'S': - command->action = ACTION_LIST; - command->object = OBJECT_STRATEGY; - break; - default: /* "h" */ - usage(argv[0]); - exit(EXIT_SUCCESS); - } - } - - if (command->object == OBJECT_UNDEFINED) { - fprintf(stderr, "Missing object specification: connection | listener | route\n"); - return -1; - } - - /* Parse and validate parameters for add/delete */ - switch(command->object) { - case OBJECT_FACE: - switch(command->action) { - case ACTION_CREATE: - if ((argc - optind != 5) && (argc - optind != 6)) { - usage_face_create(argv[0], true, false); - goto ERR_PARAM; - } - /* NAME will be autogenerated (and currently not used) */ - //snprintf(command->face.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); - command->face.face.type = face_type_from_str(argv[optind++]); - if (command->face.face.type == FACE_TYPE_UNDEFINED) - goto ERR_PARAM; - command->face.face.family = ip_address_get_family(argv[optind]); - if (!IS_VALID_FAMILY(command->face.face.family)) - goto ERR_PARAM; - if (ip_address_pton(argv[optind++], &command->face.face.local_addr) < 0) - goto ERR_PARAM; - command->face.face.local_port = atoi(argv[optind++]); - family = ip_address_get_family(argv[optind]); - if (!IS_VALID_FAMILY(family) || (command->face.face.family != family)) - goto ERR_PARAM; - if (ip_address_pton(argv[optind++], &command->face.face.remote_addr) < 0) - goto ERR_PARAM; - command->face.face.remote_port = atoi(argv[optind++]); - if (argc != optind) { - //netdevice_set_name(&command->face.face.netdevice, argv[optind++]); - command->face.face.netdevice.index = atoi(argv[optind++]); - } - - break; - case ACTION_DELETE: - if ((argc - optind != 1) && (argc - optind != 5) && (argc - optind != 6)) { - usage_face_delete(argv[0], true, false); - goto ERR_PARAM; - } - - if (argc - optind == 1) { - /* Id or name */ - if (is_number(argv[optind])) { - command->face.id = atoi(argv[optind++]); - snprintf(command->face.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); - //} else if (is_symbolic_name(argv[optind])) { - // snprintf(command->face.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); - } else { - fprintf(stderr, "Invalid argument\n"); - goto ERR_PARAM; - } - } else { - command->face.face.type = face_type_from_str(argv[optind++]); - if (command->face.face.type == FACE_TYPE_UNDEFINED) - goto ERR_PARAM; - command->face.face.family = ip_address_get_family(argv[optind]); - if (!IS_VALID_FAMILY(command->face.face.family)) - goto ERR_PARAM; - if (ip_address_pton(argv[optind++], &command->face.face.local_addr) < 0) - goto ERR_PARAM; - command->face.face.local_port = atoi(argv[optind++]); - family = ip_address_get_family(argv[optind]); - if (!IS_VALID_FAMILY(family) || (command->face.face.family != family)) - goto ERR_PARAM; - if (ip_address_pton(argv[optind++], &command->face.face.remote_addr) < 0) - goto ERR_PARAM; - command->face.face.remote_port = atoi(argv[optind++]); - if (argc != optind) { - command->face.face.netdevice.index = atoi(argv[optind++]); - //netdevice_set_name(&command->face.face.netdevice, argv[optind++]); - } - } - break; - - case ACTION_LIST: - if (argc - optind != 0) { - usage_face_list(argv[0], true, false); - goto ERR_PARAM; - } - break; - - default: - goto ERR_COMMAND; - break; - } - break; - - case OBJECT_ROUTE: - switch(command->action) { - case ACTION_CREATE: - if ((argc - optind != 2) && (argc - optind != 3)) { - usage_route_create(argv[0], true, false); - goto ERR_PARAM; - } - - command->route.face_id = atoi(argv[optind++]); - - { - ip_prefix_t prefix; - ip_prefix_pton(argv[optind++], &prefix); - command->route.family = prefix.family; - command->route.remote_addr = prefix.address; - command->route.len = prefix.len; - } - - if (argc != optind) { - printf("parse cost\n"); - command->route.cost = atoi(argv[optind++]); - } - break; - - case ACTION_DELETE: - if (argc - optind != 2) { - usage_route_delete(argv[0], true, false); - goto ERR_PARAM; - } - - command->route.face_id = atoi(argv[optind++]); - - { - ip_prefix_t prefix; - ip_prefix_pton(argv[optind++], &prefix); - command->route.family = prefix.family; - command->route.remote_addr = prefix.address; - command->route.len = prefix.len; - } - break; - - case ACTION_LIST: - if (argc - optind != 0) { - usage_route_list(argv[0], true, false); - goto ERR_PARAM; - } - break; - - default: - goto ERR_COMMAND; - break; - } - break; - - case OBJECT_STRATEGY: - switch(command->action) { - case ACTION_LIST: - if (argc - optind != 0) { - usage_forwarding_strategy_list(argv[0], true, false); - goto ERR_PARAM; - } - break; - default: - goto ERR_COMMAND; - break; - } - break; - - case OBJECT_LISTENER: - switch(command->action) { - case ACTION_CREATE: - if ((argc - optind != 4) && (argc - optind != 5)) { - usage_listener_create(argv[0], true, false); - goto ERR_PARAM; - } - snprintf(command->listener.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); - command->listener.type = connection_type_from_str(argv[optind++]); - if (command->listener.type == CONNECTION_TYPE_UNDEFINED) - goto ERR_PARAM; - command->listener.family = ip_address_get_family(argv[optind]); - if (!IS_VALID_FAMILY(command->listener.family)) - goto ERR_PARAM; - if (ip_address_pton(argv[optind++], &command->listener.local_addr) < 0) - goto ERR_PARAM; - command->listener.local_port = atoi(argv[optind++]); - if (argc != optind) { - snprintf(command->listener.interface_name, INTERFACE_LEN, "%s", argv[optind++]); - } - break; - - case ACTION_DELETE: - if ((argc - optind != 1) && (argc - optind != 3) && (argc - optind != 4)) { - usage_listener_delete(argv[0], true, false); - goto ERR_PARAM; - } - - if (argc - optind == 1) { - /* Id or name */ - if (is_number(argv[optind])) { - command->listener.id = atoi(argv[optind++]); - snprintf(command->listener.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); - } else if (is_symbolic_name(argv[optind])) { - snprintf(command->listener.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); - } else { - fprintf(stderr, "Invalid argument\n"); - goto ERR_PARAM; - } - } else { - command->listener.type = connection_type_from_str(argv[optind++]); - if (command->listener.type == CONNECTION_TYPE_UNDEFINED) - goto ERR_PARAM; - command->listener.family = ip_address_get_family(argv[optind]); - if (!IS_VALID_FAMILY(command->listener.family)) - goto ERR_PARAM; - if (ip_address_pton(argv[optind++], &command->listener.local_addr) < 0) - goto ERR_PARAM; - command->listener.local_port = atoi(argv[optind++]); - if (argc != optind) { - snprintf(command->listener.interface_name, INTERFACE_LEN, "%s", argv[optind++]); - } - } - break; - - case ACTION_LIST: - if (argc - optind != 0) { - usage_listener_list(argv[0], true, false); - goto ERR_PARAM; - } - break; - - default: - goto ERR_COMMAND; - break; - } - break; - - case OBJECT_CONNECTION: - switch(command->action) { - case ACTION_CREATE: - /* NAME TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT */ - if ((argc - optind != 6) && (argc - optind != 7)) { - usage_connection_create(argv[0], true, false); - goto ERR_PARAM; - } - snprintf(command->connection.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); - command->connection.type = connection_type_from_str(argv[optind++]); - if (command->connection.type == CONNECTION_TYPE_UNDEFINED) - goto ERR_PARAM; - command->connection.family = ip_address_get_family(argv[optind]); - if (!IS_VALID_FAMILY(command->connection.family)) - goto ERR_PARAM; - if (ip_address_pton(argv[optind++], &command->connection.local_addr) < 0) - goto ERR_PARAM; - command->connection.local_port = atoi(argv[optind++]); - family = ip_address_get_family(argv[optind]); - if (!IS_VALID_FAMILY(family) || (command->connection.family != family)) - goto ERR_PARAM; - if (ip_address_pton(argv[optind++], &command->connection.remote_addr) < 0) - goto ERR_PARAM; - command->connection.remote_port = atoi(argv[optind++]); - - break; - - case ACTION_DELETE: - if ((argc - optind != 1) && (argc - optind != 5) && (argc - optind != 6)) { - usage_connection_delete(argv[0], true, false); - goto ERR_PARAM; - } - - if (argc - optind == 1) { - /* Id or name */ - if (is_number(argv[optind])) { - command->connection.id = atoi(argv[optind++]); - snprintf(command->connection.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); - } else if (is_symbolic_name(argv[optind])) { - snprintf(command->connection.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); - } else { - fprintf(stderr, "Invalid argument\n"); - goto ERR_PARAM; - } - } else { - command->connection.type = connection_type_from_str(argv[optind++]); - if (command->connection.type == CONNECTION_TYPE_UNDEFINED) - goto ERR_PARAM; - command->connection.family = ip_address_get_family(argv[optind]); - if (!IS_VALID_FAMILY(command->connection.family)) - goto ERR_PARAM; - if (ip_address_pton(argv[optind++], &command->connection.local_addr) < 0) - goto ERR_PARAM; - command->connection.local_port = atoi(argv[optind++]); - family = ip_address_get_family(argv[optind]); - if (!IS_VALID_FAMILY(family) || (command->connection.family != family)) - goto ERR_PARAM; - if (ip_address_pton(argv[optind++], &command->connection.remote_addr) < 0) - goto ERR_PARAM; - command->connection.remote_port = atoi(argv[optind++]); - } - break; - - case ACTION_LIST: - if (argc - optind != 0) { - usage_connection_list(argv[0], true, false); - goto ERR_PARAM; - } - break; - - default: - goto ERR_COMMAND; - break; - } - break; - - default: - goto ERR_COMMAND; - break; - } - - return 0; - -ERR_PARAM: -ERR_COMMAND: - return -1; -} - -int main(int argc, char *argv[]) -{ - hc_data_t * data; - int rc = 1; - hc_command_t command = {0}; - char buf_listener[MAXSZ_HC_LISTENER]; - char buf_connection[MAXSZ_HC_CONNECTION]; - char buf_route[MAXSZ_HC_ROUTE]; - char buf_strategy[MAXSZ_HC_STRATEGY]; - - forwarder_t forwarder = HICNLIGHT; - - if (parse_options(argc, argv, &command, &forwarder) < 0) - die(OPTIONS, "Bad arguments"); - - hc_sock_t * s = hc_sock_create_forwarder(forwarder); - if (!s) - die(SOCKET, "Error creating socket."); - - if (hc_sock_connect(s) < 0) - die(CONNECT, "Error connecting to the forwarder."); - - switch(command.object) { - case OBJECT_FACE: - switch(command.action) { - case ACTION_CREATE: - if (hc_face_create(s, &command.face) < 0) - die(COMMAND, "Error creating face"); - printf("OK\n"); - break; - - case ACTION_DELETE: - if (hc_face_delete(s, &command.face) < 0) - die(COMMAND, "Error creating face"); - printf("OK\n"); - break; - - case ACTION_LIST: - if (hc_face_list(s, &data) < 0) - die(COMMAND, "Error getting connections."); - - printf("Faces:\n"); - foreach_face(f, data) { - if (hc_face_snprintf(buf_connection, MAXSZ_HC_FACE, f) >= MAXSZ_HC_FACE) - die(COMMAND, "Display error"); - printf("[%s] %s\n", f->name, buf_connection); - } - - hc_data_free(data); - break; - default: - die(COMMAND, "Unsupported command for connection"); - break; - } - break; - - case OBJECT_ROUTE: - switch(command.action) { - case ACTION_CREATE: - if (hc_route_create(s, &command.route) < 0) - die(COMMAND, "Error creating route"); - printf("OK\n"); - break; - - case ACTION_DELETE: - if (hc_route_delete(s, &command.route) < 0) - die(COMMAND, "Error creating route"); - printf("OK\n"); - break; - - case ACTION_LIST: - if (hc_route_list(s, &data) < 0) - die(COMMAND, "Error getting routes."); - - printf("Routes:\n"); - foreach_route(r, data) { - if (hc_route_snprintf(buf_route, MAXSZ_HC_ROUTE, r) >= MAXSZ_HC_ROUTE) - die(COMMAND, "Display error"); - printf("%s\n", buf_route); - } - - hc_data_free(data); - break; - default: - die(COMMAND, "Unsupported command for route"); - break; - } - break; - - case OBJECT_STRATEGY: - switch(command.action) { - case ACTION_LIST: - if (hc_strategy_list(s, &data) < 0) - die(COMMAND, "Error getting routes."); - - printf("Forwarding strategies:\n"); - foreach_strategy(st, data) { - if (hc_strategy_snprintf(buf_strategy, MAXSZ_HC_STRATEGY, st) >= MAXSZ_HC_STRATEGY) - die(COMMAND, "Display error"); - printf("%s\n", buf_strategy); - } - - hc_data_free(data); - break; - default: - die(COMMAND, "Unsupported command for strategy"); - break; - } - break; - - case OBJECT_LISTENER: - switch(command.action) { - case ACTION_CREATE: - if (hc_listener_create(s, &command.listener) < 0) - die(COMMAND, "Error creating listener"); - printf("OK\n"); - break; - case ACTION_DELETE: - if (hc_listener_delete(s, &command.listener) < 0) - die(COMMAND, "Error deleting listener"); - printf("OK\n"); - break; - break; - case ACTION_LIST: - if (hc_listener_list(s, &data) < 0) - die(COMMAND, "Error getting listeners."); - - printf("Listeners:\n"); - foreach_listener(l, data) { - if (hc_listener_snprintf(buf_listener, MAXSZ_HC_LISTENER+17, l) >= MAXSZ_HC_LISTENER) - die(COMMAND, "Display error"); - printf("[%d] %s\n", l->id, buf_listener); - } - - hc_data_free(data); - break; - default: - die(COMMAND, "Unsupported command for listener"); - break; - } - break; - - case OBJECT_CONNECTION: - switch(command.action) { - case ACTION_CREATE: - if (hc_connection_create(s, &command.connection) < 0) - die(COMMAND, "Error creating connection"); - printf("OK\n"); - break; - case ACTION_DELETE: - if (hc_connection_delete(s, &command.connection) < 0) - die(COMMAND, "Error creating connection"); - printf("OK\n"); - break; - case ACTION_LIST: - if (hc_connection_list(s, &data) < 0) - die(COMMAND, "Error getting connections."); - - printf("Connections:\n"); - foreach_connection(c, data) { - if (hc_connection_snprintf(buf_connection, MAXSZ_HC_CONNECTION, c) >= MAXSZ_HC_CONNECTION) - die(COMMAND, "Display error"); - printf("[%s] %s\n", c->name, buf_connection); - } - - hc_data_free(data); - break; - default: - die(COMMAND, "Unsupported command for connection"); - break; - } - break; - - default: - die(COMMAND, "Unsupported object"); - break; - } - -ERR_COMMAND: -ERR_CONNECT: - hc_sock_free(s); -ERR_SOCKET: -ERR_OPTIONS: - return (rc < 0) ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/ctrl/libhicnctrl/src/face.c b/ctrl/libhicnctrl/src/face.c deleted file mode 100644 index e617ff8a4..000000000 --- a/ctrl/libhicnctrl/src/face.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 face.c - * \brief Implementation of face abstraction - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <hicn/util/token.h> - -#include <hicn/ctrl/face.h> -#include "util/hash.h" - -#define member_size(type, member) sizeof(((type *)0)->member) - - -/* Netdevice */ - -const char * netdevice_type_str[] = { -#define _(x) [NETDEVICE_TYPE_ ## x] = STRINGIZE(x), -foreach_netdevice_type -#undef _ -}; - -netdevice_t * -netdevice_create_from_index(u32 index) -{ - netdevice_t * netdevice = malloc(sizeof(netdevice_t)); - if (!netdevice) - goto ERR_MALLOC; - - int rc = netdevice_set_index(netdevice, index); - if (rc < 0) - goto ERR_INIT; - - return netdevice; - -ERR_INIT: - free(netdevice); -ERR_MALLOC: - return NULL; -} - -netdevice_t * -netdevice_create_from_name(const char * name) -{ - netdevice_t * netdevice = malloc(sizeof(netdevice_t)); - if (!netdevice) - goto ERR_MALLOC; - - int rc = netdevice_set_name(netdevice, name); - if (rc < 0) - goto ERR_INIT; - - return netdevice; - -ERR_INIT: - free(netdevice); -ERR_MALLOC: - return NULL; -} - -/** - * \brief Update the index of the netdevice based on the name - */ -int -netdevice_update_index(netdevice_t * netdevice) -{ - netdevice->index = if_nametoindex(netdevice->name); - if (netdevice->index == 0) - return -1; - return 0; -} - -int -netdevice_update_name(netdevice_t * netdevice) -{ - if (!if_indextoname(netdevice->index, netdevice->name)) - return -1; - return 0; -} - -void -netdevice_free(netdevice_t * netdevice) -{ - free(netdevice); -} - -int -netdevice_get_index(const netdevice_t * netdevice, u32 * index) -{ - if (netdevice->index == 0) - return -1; - *index = netdevice->index; - return 0; -} - -int -netdevice_set_index(netdevice_t * netdevice, u32 index) -{ - netdevice->index = index; - return netdevice_update_name(netdevice); -} - -int -netdevice_get_name(const netdevice_t * netdevice, const char ** name) -{ - if (netdevice->name[0] == '\0') - return -1; - *name = netdevice->name; - return 0; -} - -int -netdevice_set_name(netdevice_t * netdevice, const char * name) -{ - memset(netdevice->name, 0, sizeof(netdevice->name)); - int rc = snprintf(netdevice->name, IFNAMSIZ, "%s", name); - if (rc < 0) - return -1; - if (rc >= IFNAMSIZ) - return -2; /* truncated */ - return netdevice_update_index(netdevice); -} - -int -netdevice_cmp(const netdevice_t * nd1, const netdevice_t * nd2) -{ - return (nd1->index - nd2->index); -} - - -/* Face state */ - -const char * face_state_str[] = { -#define _(x) [FACE_STATE_ ## x] = STRINGIZE(x), -foreach_face_state -#undef _ -}; - - -/* Face type */ - -const char * face_type_str[] = { -#define _(x) [FACE_TYPE_ ## x] = STRINGIZE(x), -foreach_face_type -#undef _ -}; - - -/* Face */ - -int -face_initialize(face_t * face) -{ - memset(face, 0, sizeof(face_t)); /* 0'ed for hash */ - return 1; -} - -int -face_initialize_udp(face_t * face, const char * interface_name, const - ip_address_t * local_addr, u16 local_port, - const ip_address_t * remote_addr, u16 remote_port, - int family) -{ - if (!local_addr) - return -1; - - *face = (face_t) { - .type = FACE_TYPE_UDP, - .family = family, - .local_addr = *local_addr, - .local_port = local_port, - .remote_addr = remote_addr ? *remote_addr : IP_ADDRESS_EMPTY, - .remote_port = remote_port, - }; - - snprintf(face->netdevice.name, IFNAMSIZ, "%s", interface_name); - - return 1; -} - -int -face_initialize_udp_sa(face_t * face, const char * interface_name, - const struct sockaddr * local_addr, - const struct sockaddr * remote_addr) -{ - if (!local_addr) - return -1; - - if (remote_addr && (local_addr->sa_family != remote_addr->sa_family)) - return -1; - - switch (local_addr->sa_family) { - case AF_INET: - { - struct sockaddr_in *lsai = (struct sockaddr_in *)local_addr; - struct sockaddr_in *rsai = (struct sockaddr_in *)remote_addr; - *face = (face_t) { - .type = FACE_TYPE_UDP, - .family = AF_INET, - .local_addr.v4.as_inaddr = lsai->sin_addr, - .local_port = lsai ? ntohs(lsai->sin_port) : 0, - .remote_addr = IP_ADDRESS_EMPTY, - .remote_port = rsai ? ntohs(rsai->sin_port) : 0, - }; - if (rsai) - face->remote_addr.v4.as_inaddr = rsai->sin_addr; - } - break; - case AF_INET6: - { - struct sockaddr_in6 *lsai = (struct sockaddr_in6 *)local_addr; - struct sockaddr_in6 *rsai = (struct sockaddr_in6 *)remote_addr; - *face = (face_t) { - .type = FACE_TYPE_UDP, - .family = AF_INET6, - .local_addr.v6.as_in6addr = lsai->sin6_addr, - .local_port = lsai ? ntohs(lsai->sin6_port) : 0, - .remote_addr = IP_ADDRESS_EMPTY, - .remote_port = rsai ? ntohs(rsai->sin6_port) : 0, - }; - if (rsai) - face->remote_addr.v6.as_in6addr = rsai->sin6_addr; - } - break; - default: - return -1; - } - - snprintf(face->netdevice.name, IFNAMSIZ, "%s", interface_name); - - return 1; -} - -face_t * face_create() -{ - face_t * face = calloc(1, sizeof(face_t)); /* 0'ed for hash */ - return face; -} - -face_t * face_create_udp(const char * interface_name, - const ip_address_t * local_addr, u16 local_port, - const ip_address_t * remote_addr, u16 remote_port, int family) -{ - face_t * face = face_create(); - if (face_initialize_udp(face, interface_name, local_addr, local_port, remote_addr, remote_port, family) < 0) - goto ERR_INIT; - return face; - -ERR_INIT: - free(face); - return NULL; -} - -face_t * face_create_udp_sa(const char * interface_name, - const struct sockaddr * local_addr, - const struct sockaddr * remote_addr) -{ - face_t * face = face_create(); - if (face_initialize_udp_sa(face, interface_name, local_addr, remote_addr) < 0) - goto ERR_INIT; - return face; - -ERR_INIT: - free(face); - return NULL; -} - -void face_free(face_t * face) -{ - free(face); -} - -/** - * \brief Compare two faces - * \param [in] f1 - First face - * \param [in] f2 - Second face - * \return whether faces are equal, ie both their types are parameters are - * equal. - * - * NOTE: this function implements a partial order. - */ -int -face_cmp(const face_t * f1, const face_t * f2) -{ - - int ret = f1->type - f2->type; - if (ret != 0) - return ret; - - ret = f1->family - f2->family; - if (ret != 0) - return ret; - - /* - * FIXME As hicn-light API might not return the netdevice, we can discard the - * comparison when one of the two is not set for now... - */ - if ((f1->netdevice.index != 0) && (f2->netdevice.index != 0)) { - ret = netdevice_cmp(&f1->netdevice, &f2->netdevice); - if (ret != 0) - return ret; - } - - switch(f1->type) { - case FACE_TYPE_HICN: - ret = ip_address_cmp(&f1->local_addr, &f2->local_addr, f1->family); - if (ret != 0) - return ret; - - ret = ip_address_cmp(&f1->remote_addr, &f2->remote_addr, f1->family); - if (ret != 0) - return ret; - - break; - - case FACE_TYPE_TCP: - case FACE_TYPE_UDP: - ret = ip_address_cmp(&f1->local_addr, &f2->local_addr, f1->family); - if (ret != 0) - return ret; - - ret = f1->local_port - f2->local_port; - if (ret != 0) - return ret; - - ret = ip_address_cmp(&f1->remote_addr, &f2->remote_addr, f1->family); - if (ret != 0) - return ret; - - ret = f1->remote_port - f2->remote_port; - if (ret != 0) - return ret; - - break; - default: - break; - } - - 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) -{ - switch(face->type) { - case FACE_TYPE_HICN: - { - char local[MAXSZ_IP_ADDRESS]; - char remote[MAXSZ_IP_ADDRESS]; - char tags[MAXSZ_POLICY_TAGS]; - - ip_address_snprintf(local, MAXSZ_IP_ADDRESS, - &face->local_addr, - face->family); - ip_address_snprintf(remote, MAXSZ_IP_ADDRESS, - &face->remote_addr, - face->family); - policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->tags); - return snprintf(s, size, "%s [%s -> %s] [%s]", - face_type_str[face->type], - local, - remote, - tags); - } - case FACE_TYPE_UNDEFINED: - case FACE_TYPE_TCP: - case FACE_TYPE_UDP: - { - char local[MAXSZ_IP_ADDRESS]; - char remote[MAXSZ_IP_ADDRESS]; - char tags[MAXSZ_POLICY_TAGS]; - - ip_address_snprintf(local, MAXSZ_IP_ADDRESS, - &face->local_addr, - face->family); - ip_address_snprintf(remote, MAXSZ_IP_ADDRESS, - &face->remote_addr, - face->family); - policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->tags); - - return snprintf(s, size, "%s [%s:%d -> %s:%d] [%s]", - face_type_str[face->type], - local, - face->local_port, - remote, - face->remote_port, - tags); - } - default: - return -1; - } - -} - -policy_tags_t face_get_tags(const face_t * face) -{ - return face->tags; -} - -int -face_set_tags(face_t * face, policy_tags_t tags) -{ - face->tags = tags; - return 1; -} diff --git a/ctrl/libhicnctrl/src/hicnctrl.c b/ctrl/libhicnctrl/src/hicnctrl.c new file mode 100644 index 000000000..99d67b19f --- /dev/null +++ b/ctrl/libhicnctrl/src/hicnctrl.c @@ -0,0 +1,805 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file cli.c + * \brief Command line interface + */ +#include <ctype.h> // isalpha isalnum +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> // getopt + +#include <hicn/ctrl.h> +#include <hicn/util/ip_address.h> +#include <hicn/util/token.h> +#include <hicn/validation.h> + +#define die(LABEL, MESSAGE) \ + do { \ + printf(MESSAGE "\n"); \ + rc = -1; \ + goto ERR_##LABEL; \ + } while (0) + +const char HICNLIGHT_PARAM[] = "hicnlight"; +const char HICNLIGHT_NG_PARAM[] = "hicnlightng"; +const char VPP_PARAM[] = "vpp"; + +void usage_header() { fprintf(stderr, "Usage:\n"); } + +void usage_face_create(const char *prog, bool header, bool verbose) { + if (header) usage_header(); + fprintf(stderr, + "%s -f TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT " + "[INTERFACE_NAME]\n", + prog); + if (verbose) + fprintf(stderr, " Create a face on specified address and port.\n"); +} + +void usage_face_delete(const char *prog, bool header, bool verbose) { + if (header) usage_header(); + fprintf(stderr, "%s -df ID\n", prog); + // fprintf(stderr, "%s -df NAME\n", prog); + fprintf(stderr, + "%s -df TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT " + "[INTERFACE_NAME]\n", + prog); + if (verbose) fprintf(stderr, " Delete a face...\n"); +} + +void usage_face_list(const char *prog, bool header, bool verbose) { + if (header) usage_header(); + fprintf(stderr, "%s -F\n", prog); + if (verbose) fprintf(stderr, " List all faces.\n"); +} + +void usage_face(const char *prog, bool header, bool verbose) { + usage_face_create(prog, header, verbose); + usage_face_delete(prog, header, verbose); + usage_face_list(prog, header, verbose); +} + +void usage_route_create(const char *prog, bool header, bool verbose) { + if (header) usage_header(); + fprintf(stderr, "%s -r FACE_ID PREFIX [COST]\n", prog); + // fprintf(stderr, "%s -r [FACE_ID|NAME] PREFIX [COST]\n", prog); + if (verbose) fprintf(stderr, " Create a route...\n"); +} + +void usage_route_delete(const char *prog, bool header, bool verbose) { + if (header) usage_header(); + fprintf(stderr, "%s -dr FACE_ID PREFIX\n", prog); + // fprintf(stderr, "%s -dr [FACE_ID|NAME] PREFIX\n", prog); + if (verbose) fprintf(stderr, " Delete a route...\n"); +} + +void usage_route_list(const char *prog, bool header, bool verbose) { + if (header) usage_header(); + fprintf(stderr, "%s -R\n", prog); + if (verbose) fprintf(stderr, " List all routes.\n"); +} + +void usage_route(const char *prog, bool header, bool verbose) { + usage_route_create(prog, header, verbose); + usage_route_delete(prog, header, verbose); + usage_route_list(prog, header, verbose); +} + +void usage_forwarding_strategy_create(const char *prog, bool header, + bool verbose) { + if (header) usage_header(); +} +void usage_forwarding_strategy_delete(const char *prog, bool header, + bool verbose) { + if (header) usage_header(); +} + +void usage_forwarding_strategy_list(const char *prog, bool header, + bool verbose) { + if (header) usage_header(); + fprintf(stderr, "%s -S\n", prog); + if (verbose) + fprintf(stderr, " List all availble forwarding strategies.\n"); +} + +void usage_forwarding_strategy(const char *prog, bool header, bool verbose) { + usage_forwarding_strategy_create(prog, header, verbose); + usage_forwarding_strategy_delete(prog, header, verbose); + usage_forwarding_strategy_list(prog, header, verbose); +} + +void usage_listener_create(const char *prog, bool header, bool verbose) { + if (header) usage_header(); + fprintf(stderr, "%s -l NAME TYPE LOCAL_ADDRESS LOCAL_PORT [INTERFACE_NAME]\n", + prog); + if (verbose) + fprintf(stderr, " Create a listener on specified address and port.\n"); +} + +void usage_listener_delete(const char *prog, bool header, bool verbose) { + if (header) usage_header(); + fprintf(stderr, "%s -dl ID\n", prog); + fprintf(stderr, "%s -dl NAME\n", prog); + fprintf(stderr, "%s -dl TYPE LOCAL_ADDRESS LOCAL_PORT [INTERFACE_NAME]\n", + prog); + if (verbose) fprintf(stderr, " Delete a listener...\n"); +} + +void usage_listener_list(const char *prog, bool header, bool verbose) { + if (header) usage_header(); + fprintf(stderr, "%s -L\n", prog); + if (verbose) fprintf(stderr, " List all listeners.\n"); +} + +void usage_listener(const char *prog, bool header, bool verbose) { + usage_listener_create(prog, header, verbose); + usage_listener_delete(prog, header, verbose); + usage_listener_list(prog, header, verbose); +} +void usage_connection_create(const char *prog, bool header, bool verbose) { + if (header) usage_header(); + fprintf(stderr, + "%s -c NAME TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT " + "[INTERFACE_NAME]\n", + prog); + if (verbose) + fprintf(stderr, " Create a connection on specified address and port.\n"); +} + +void usage_connection_delete(const char *prog, bool header, bool verbose) { + if (header) usage_header(); + fprintf(stderr, "%s -dc ID\n", prog); + fprintf(stderr, "%s -dc NAME\n", prog); + fprintf(stderr, + "%s -dc TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT " + "[INTERFACE_NAME]\n", + prog); + if (verbose) fprintf(stderr, " Delete a connection...\n"); +} + +void usage_connection_list(const char *prog, bool header, bool verbose) { + if (header) usage_header(); + fprintf(stderr, "%s -C\n", prog); + if (verbose) fprintf(stderr, " List all connections.\n"); +} + +void usage_connection(const char *prog, bool header, bool verbose) { + usage_connection_create(prog, header, verbose); + usage_connection_delete(prog, header, verbose); + usage_connection_list(prog, header, verbose); +} + +void usage(const char *prog) { + fprintf(stderr, + "Usage: %s [ -z forwarder (hicnlight | vpp) ] [ [-d] [-f|-l|-c|-r] " + "PARAMETERS | [-F|-L|-C|-R] ]\n", + prog); + fprintf(stderr, "\n"); + fprintf(stderr, "High-level commands\n"); + fprintf(stderr, "\n"); + usage_face(prog, false, true); + usage_route(prog, false, true); + usage_forwarding_strategy(prog, false, true); + fprintf(stderr, "\n"); + fprintf(stderr, "Low level commands (hicn-light specific)\n"); + fprintf(stderr, "\n"); + usage_listener(prog, false, true); + usage_connection(prog, false, true); +} + +#if 0 +typedef struct { + hc_action_t action; + hc_object_t object; + union { + hc_face_t face; + hc_route_t route; + hc_connection_t connection; + hc_listener_t listener; + }; +} hc_command_t; +#endif + +int parse_options(int argc, char *argv[], hc_command_t *command, + forwarder_type_t *forwarder) { + command->object.type = OBJECT_UNDEFINED; + command->action = ACTION_CREATE; + int opt; + int family; + + while ((opt = getopt(argc, argv, "dflcrFLCRShz:")) != -1) { + switch (opt) { + case 'z': + if (strncmp(optarg, VPP_PARAM, strlen(VPP_PARAM)) == 0) { + *forwarder = VPP; + } else if (strncmp(optarg, HICNLIGHT_PARAM, strlen(HICNLIGHT_PARAM))) { + *forwarder = HICNLIGHT; + } else if (strncmp(optarg, HICNLIGHT_NG_PARAM, + strlen(HICNLIGHT_NG_PARAM))) { + *forwarder = HICNLIGHT_NG; + } else { + usage(argv[0]); + exit(EXIT_FAILURE); + } + break; + case 'd': + command->action = ACTION_DELETE; + break; + case 'f': + command->object.type = OBJECT_FACE; + break; + case 'c': + command->object.type = OBJECT_CONNECTION; + break; + case 'F': + command->action = ACTION_LIST; + command->object.type = OBJECT_FACE; + break; + case 'L': + command->action = ACTION_LIST; + command->object.type = OBJECT_LISTENER; + break; + case 'C': + command->action = ACTION_LIST; + command->object.type = OBJECT_CONNECTION; + break; + case 'R': + command->action = ACTION_LIST; + command->object.type = OBJECT_ROUTE; + break; + case 'S': + command->action = ACTION_LIST; + command->object.type = OBJECT_STRATEGY; + break; + default: /* "h" */ + usage(argv[0]); + exit(EXIT_SUCCESS); + } + } + + if (command->object.type == OBJECT_UNDEFINED) { + fprintf(stderr, + "Missing object specification: connection | listener | route\n"); + return -1; + } + + /* Parse and validate parameters for add/delete */ + switch (command->object.type) { + case OBJECT_FACE: + switch (command->action) { + case ACTION_CREATE: + if ((argc - optind != 5) && (argc - optind != 6)) { + usage_face_create(argv[0], true, false); + goto ERR_PARAM; + } + /* NAME will be autogenerated (and currently not used) */ + // snprintf(command->face.name, SYMBOLIC_NAME_LEN, "%s", + // argv[optind++]); + command->object.face.face.type = face_type_from_str(argv[optind++]); + if (command->object.face.face.type == FACE_TYPE_UNDEFINED) + goto ERR_PARAM; + command->object.face.face.family = + ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(command->object.face.face.family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], + &command->object.face.face.local_addr) < 0) + goto ERR_PARAM; + command->object.face.face.local_port = atoi(argv[optind++]); + family = ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(family) || + (command->object.face.face.family != family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], + &command->object.face.face.remote_addr) < 0) + goto ERR_PARAM; + command->object.face.face.remote_port = atoi(argv[optind++]); + if (argc != optind) { + // netdevice_set_name(&command->object.face.face.netdevice, + // argv[optind++]); + command->object.face.face.netdevice.index = atoi(argv[optind++]); + } + + break; + case ACTION_DELETE: + if ((argc - optind != 1) && (argc - optind != 5) && + (argc - optind != 6)) { + usage_face_delete(argv[0], true, false); + goto ERR_PARAM; + } + + if (argc - optind == 1) { + /* Id or name */ + if (is_number(argv[optind], SYMBOLIC_NAME_LEN)) { + command->object.face.id = atoi(argv[optind++]); + snprintf(command->object.face.name, SYMBOLIC_NAME_LEN, "%s", + argv[optind++]); + //} else if (is_symbolic_name(argv[optind])) { + // snprintf(command->object.face.name, SYMBOLIC_NAME_LEN, "%s", + // argv[optind++]); + } else { + fprintf(stderr, "Invalid argument\n"); + goto ERR_PARAM; + } + } else { + command->object.face.face.type = face_type_from_str(argv[optind++]); + if (command->object.face.face.type == FACE_TYPE_UNDEFINED) + goto ERR_PARAM; + command->object.face.face.family = + ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(command->object.face.face.family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], + &command->object.face.face.local_addr) < 0) + goto ERR_PARAM; + command->object.face.face.local_port = atoi(argv[optind++]); + family = ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(family) || + (command->object.face.face.family != family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], + &command->object.face.face.remote_addr) < 0) + goto ERR_PARAM; + command->object.face.face.remote_port = atoi(argv[optind++]); + if (argc != optind) { + command->object.face.face.netdevice.index = atoi(argv[optind++]); + // netdevice_set_name(&command->object.face.face.netdevice, + // argv[optind++]); + } + } + break; + + case ACTION_LIST: + if (argc - optind != 0) { + usage_face_list(argv[0], true, false); + goto ERR_PARAM; + } + break; + + default: + goto ERR_COMMAND; + } + break; + + case OBJECT_ROUTE: + switch (command->action) { + case ACTION_CREATE: + if ((argc - optind != 2) && (argc - optind != 3)) { + usage_route_create(argv[0], true, false); + goto ERR_PARAM; + } + + command->object.route.face_id = atoi(argv[optind++]); + + { + ip_prefix_t prefix; + ip_prefix_pton(argv[optind++], &prefix); + command->object.route.family = prefix.family; + command->object.route.remote_addr = prefix.address; + command->object.route.len = prefix.len; + } + + if (argc != optind) { + printf("parse cost\n"); + command->object.route.cost = atoi(argv[optind++]); + } + break; + + case ACTION_DELETE: + if (argc - optind != 2) { + usage_route_delete(argv[0], true, false); + goto ERR_PARAM; + } + + command->object.route.face_id = atoi(argv[optind++]); + + { + ip_prefix_t prefix; + ip_prefix_pton(argv[optind++], &prefix); + command->object.route.family = prefix.family; + command->object.route.remote_addr = prefix.address; + command->object.route.len = prefix.len; + } + break; + + case ACTION_LIST: + if (argc - optind != 0) { + usage_route_list(argv[0], true, false); + goto ERR_PARAM; + } + break; + + default: + goto ERR_COMMAND; + } + break; + + case OBJECT_STRATEGY: + switch (command->action) { + case ACTION_LIST: + if (argc - optind != 0) { + usage_forwarding_strategy_list(argv[0], true, false); + goto ERR_PARAM; + } + break; + default: + goto ERR_COMMAND; + } + break; + + case OBJECT_LISTENER: + switch (command->action) { + case ACTION_CREATE: + if ((argc - optind != 4) && (argc - optind != 5)) { + usage_listener_create(argv[0], true, false); + goto ERR_PARAM; + } + + snprintf(command->object.listener.name, SYMBOLIC_NAME_LEN, "%s", + argv[optind++]); + command->object.listener.type = face_type_from_str(argv[optind++]); + if (command->object.listener.type == FACE_TYPE_UNDEFINED) + goto ERR_PARAM; + command->object.listener.family = ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(command->object.listener.family)) goto ERR_PARAM; + if (ip_address_pton(argv[optind++], + &command->object.listener.local_addr) < 0) + goto ERR_PARAM; + command->object.listener.local_port = atoi(argv[optind++]); + if (argc != optind) { + snprintf(command->object.listener.interface_name, INTERFACE_LEN, + "%s", argv[optind++]); + } + break; + + case ACTION_DELETE: + if ((argc - optind != 1) && (argc - optind != 3) && + (argc - optind != 4)) { + usage_listener_delete(argv[0], true, false); + goto ERR_PARAM; + } + + if (argc - optind == 1) { + /* Id or name */ + if (is_number(argv[optind], SYMBOLIC_NAME_LEN)) { + command->object.listener.id = atoi(argv[optind++]); + snprintf(command->object.listener.name, SYMBOLIC_NAME_LEN, "%s", + argv[optind++]); + } else if (is_symbolic_name(argv[optind], SYMBOLIC_NAME_LEN)) { + snprintf(command->object.listener.name, SYMBOLIC_NAME_LEN, "%s", + argv[optind++]); + } else { + fprintf(stderr, "Invalid argument\n"); + goto ERR_PARAM; + } + } else { + command->object.listener.type = face_type_from_str(argv[optind++]); + if (command->object.listener.type == FACE_TYPE_UNDEFINED) + goto ERR_PARAM; + command->object.listener.family = + ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(command->object.listener.family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], + &command->object.listener.local_addr) < 0) + goto ERR_PARAM; + command->object.listener.local_port = atoi(argv[optind++]); + if (argc != optind) { + snprintf(command->object.listener.interface_name, INTERFACE_LEN, + "%s", argv[optind++]); + } + } + break; + + case ACTION_LIST: + if (argc - optind != 0) { + usage_listener_list(argv[0], true, false); + goto ERR_PARAM; + } + break; + + default: + goto ERR_COMMAND; + } + break; + + case OBJECT_CONNECTION: + switch (command->action) { + case ACTION_CREATE: + /* NAME TYPE LOCAL_ADDRESS LOCAL_PORT REMOTE_ADDRESS REMOTE_PORT */ + if ((argc - optind != 6) && (argc - optind != 7)) { + usage_connection_create(argv[0], true, false); + goto ERR_PARAM; + } + snprintf(command->object.connection.name, SYMBOLIC_NAME_LEN, "%s", + argv[optind++]); + command->object.connection.type = face_type_from_str(argv[optind++]); + if (command->object.connection.type == FACE_TYPE_UNDEFINED) + goto ERR_PARAM; + command->object.connection.family = + ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(command->object.connection.family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], + &command->object.connection.local_addr) < 0) + goto ERR_PARAM; + command->object.connection.local_port = atoi(argv[optind++]); + family = ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(family) || + (command->object.connection.family != family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], + &command->object.connection.remote_addr) < 0) + goto ERR_PARAM; + command->object.connection.remote_port = atoi(argv[optind++]); + + break; + + case ACTION_DELETE: + if ((argc - optind != 1) && (argc - optind != 5) && + (argc - optind != 6)) { + usage_connection_delete(argv[0], true, false); + goto ERR_PARAM; + } + + if (argc - optind == 1) { + /* Id or name */ + if (is_number(argv[optind], SYMBOLIC_NAME_LEN)) { + command->object.connection.id = atoi(argv[optind++]); + snprintf(command->object.connection.name, SYMBOLIC_NAME_LEN, "%s", + argv[optind++]); + } else if (is_symbolic_name(argv[optind], SYMBOLIC_NAME_LEN)) { + snprintf(command->object.connection.name, SYMBOLIC_NAME_LEN, "%s", + argv[optind++]); + } else { + fprintf(stderr, "Invalid argument\n"); + goto ERR_PARAM; + } + } else { + command->object.connection.type = + face_type_from_str(argv[optind++]); + if (command->object.connection.type == FACE_TYPE_UNDEFINED) + goto ERR_PARAM; + command->object.connection.family = + ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(command->object.connection.family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], + &command->object.connection.local_addr) < 0) + goto ERR_PARAM; + command->object.connection.local_port = atoi(argv[optind++]); + family = ip_address_get_family(argv[optind]); + if (!IS_VALID_FAMILY(family) || + (command->object.connection.family != family)) + goto ERR_PARAM; + if (ip_address_pton(argv[optind++], + &command->object.connection.remote_addr) < 0) + goto ERR_PARAM; + command->object.connection.remote_port = atoi(argv[optind++]); + } + break; + + case ACTION_LIST: + if (argc - optind != 0) { + usage_connection_list(argv[0], true, false); + goto ERR_PARAM; + } + break; + + default: + goto ERR_COMMAND; + } + break; + + default: + goto ERR_COMMAND; + } + + return 0; + +ERR_PARAM: +ERR_COMMAND: + return -1; +} + +int main(int argc, char *argv[]) { + hc_data_t *data; + int rc = 1; + hc_command_t command = {0}; + char buf_listener[MAXSZ_HC_LISTENER]; + char buf_connection[MAXSZ_HC_CONNECTION]; + char buf_route[MAXSZ_HC_ROUTE]; + char buf_strategy[MAXSZ_HC_STRATEGY]; + + forwarder_type_t forwarder = HICNLIGHT; + + if (parse_options(argc, argv, &command, &forwarder) < 0) + die(OPTIONS, "Bad arguments"); + + hc_sock_t *s = hc_sock_create_forwarder(forwarder); + if (!s) die(SOCKET, "Error creating socket."); + + if (hc_sock_connect(s) < 0) + die(CONNECT, "Error connecting to the forwarder."); + + switch (command.object.type) { + case OBJECT_FACE: + switch (command.action) { + case ACTION_CREATE: + if (hc_face_create(s, &command.object.face) < 0) + die(COMMAND, "Error creating face"); + printf("OK\n"); + break; + + case ACTION_DELETE: + if (hc_face_delete(s, &command.object.face, 1) < 0) + die(COMMAND, "Error creating face"); + printf("OK\n"); + break; + + case ACTION_LIST: + if (hc_face_list(s, &data) < 0) + die(COMMAND, "Error getting connections."); + + printf("Faces:\n"); + foreach_face(f, data) { + if (hc_face_snprintf(buf_connection, MAXSZ_HC_FACE, f) >= + MAXSZ_HC_FACE) + die(COMMAND, "Display error"); + printf("[%s] %s\n", f->name, buf_connection); + } + + hc_data_free(data); + break; + default: + die(COMMAND, "Unsupported command for connection"); + break; + } + break; + + case OBJECT_ROUTE: + switch (command.action) { + case ACTION_CREATE: + if (hc_route_create(s, &command.object.route) < 0) + die(COMMAND, "Error creating route"); + printf("OK\n"); + break; + + case ACTION_DELETE: + if (hc_route_delete(s, &command.object.route) < 0) + die(COMMAND, "Error creating route"); + printf("OK\n"); + break; + + case ACTION_LIST: + if (hc_route_list(s, &data) < 0) + die(COMMAND, "Error getting routes."); + + printf("Routes:\n"); + foreach_route(r, data) { + if (hc_route_snprintf(buf_route, MAXSZ_HC_ROUTE, r) >= + MAXSZ_HC_ROUTE) + die(COMMAND, "Display error"); + printf("%s\n", buf_route); + } + + hc_data_free(data); + break; + default: + die(COMMAND, "Unsupported command for route"); + break; + } + break; + + case OBJECT_STRATEGY: + switch (command.action) { + case ACTION_LIST: + if (hc_strategy_list(s, &data) < 0) + die(COMMAND, "Error getting routes."); + + printf("Forwarding strategies:\n"); + foreach_strategy(st, data) { + if (hc_strategy_snprintf(buf_strategy, MAXSZ_HC_STRATEGY, st) >= + MAXSZ_HC_STRATEGY) + die(COMMAND, "Display error"); + printf("%s\n", buf_strategy); + } + + hc_data_free(data); + break; + default: + die(COMMAND, "Unsupported command for strategy"); + break; + } + break; + + case OBJECT_LISTENER: + switch (command.action) { + case ACTION_CREATE: + if (hc_listener_create(s, &command.object.listener) < 0) + die(COMMAND, "Error creating listener"); + printf("OK\n"); + break; + case ACTION_DELETE: + if (hc_listener_delete(s, &command.object.listener) < 0) + die(COMMAND, "Error deleting listener"); + printf("OK\n"); + break; + case ACTION_LIST: + if (hc_listener_list(s, &data) < 0) + die(COMMAND, "Error getting listeners."); + + printf("Listeners:\n"); + foreach_listener(l, data) { + if (hc_listener_snprintf(buf_listener, MAXSZ_HC_LISTENER + 17, l) >= + MAXSZ_HC_LISTENER) + die(COMMAND, "Display error"); + printf("[%d] %s\n", l->id, buf_listener); + } + + hc_data_free(data); + break; + default: + die(COMMAND, "Unsupported command for listener"); + break; + } + break; + + case OBJECT_CONNECTION: + switch (command.action) { + case ACTION_CREATE: + if (hc_connection_create(s, &command.object.connection) < 0) + die(COMMAND, "Error creating connection"); + printf("OK\n"); + break; + case ACTION_DELETE: + if (hc_connection_delete(s, &command.object.connection) < 0) + die(COMMAND, "Error creating connection"); + printf("OK\n"); + break; + case ACTION_LIST: + if (hc_connection_list(s, &data) < 0) + die(COMMAND, "Error getting connections."); + + printf("Connections:\n"); + foreach_connection(c, data) { + if (hc_connection_snprintf(buf_connection, MAXSZ_HC_CONNECTION, + c) >= MAXSZ_HC_CONNECTION) + die(COMMAND, "Display error"); + printf("[%s] %s\n", c->name, buf_connection); + } + + hc_data_free(data); + break; + default: + die(COMMAND, "Unsupported command for connection"); + break; + } + break; + + default: + die(COMMAND, "Unsupported object"); + break; + } + +ERR_COMMAND: +ERR_CONNECT: + hc_sock_free(s); +ERR_SOCKET: +ERR_OPTIONS: + return (rc < 0) ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/ctrl/libhicnctrl/src/libhicnctrl-config.cmake.in b/ctrl/libhicnctrl/src/libhicnctrl-config.cmake.in new file mode 100644 index 000000000..a27d85cde --- /dev/null +++ b/ctrl/libhicnctrl/src/libhicnctrl-config.cmake.in @@ -0,0 +1,8 @@ +@PACKAGE_INIT@ + +set(Libhicnctrl_VERSION_MAJOR "@VERSION_MAJOR@") +set(Libhicnctrl_VERSION_MINOR "@VERSION_MINOR@") +set(Libhicnctrl_VERSION_PATCH "@VERSION_PATCH@") + +set_and_check(Libhicnctrl_INCLUDE_DIRS "@PACKAGE_Libhicnctrl_INCLUDE_DIRS@") +include("${CMAKE_CURRENT_LIST_DIR}/libhicnctrl-targets.cmake") diff --git a/ctrl/libhicnctrl/src/modules/CMakeLists.txt b/ctrl/libhicnctrl/src/modules/CMakeLists.txt index e07ab8c99..8f7916d14 100644 --- a/ctrl/libhicnctrl/src/modules/CMakeLists.txt +++ b/ctrl/libhicnctrl/src/modules/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2021 Cisco and/or its affiliates. +# Copyright (c) 2021-2022 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: @@ -11,38 +11,53 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) - - -list(APPEND HICNLIGHT_MODULE_SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light_api.c +############################################################## +# Hicn Light NG Module +############################################################## +list(APPEND HICNLIGHTNG_MODULE_SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light_common.c + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light_ng_api.c ) -build_module(hicnlightctrl_module - SHARED - SOURCES ${HICNLIGHT_MODULE_SOURCE_FILES} - DEPENDS ${DEPENDENCIES} - COMPONENT ${LIBHICNCTRL_COMPONENT} - INCLUDE_DIRS ${INCLUDE_DIRS} - DEFINITIONS ${COMPILER_DEFINITIONS} - COMPILE_OPTIONS ${COMPILE_FLAGS} +build_module(hicnlightngctrl_module + SOURCES ${HICNLIGHTNG_MODULE_SOURCE_FILES} + DEPENDS ${DEPENDENCIES} + COMPONENT ${LIBHICNCTRL_COMPONENT} + LINK_LIBRARIES PRIVATE ${HICN_LIBRARIES} + INCLUDE_DIRS PRIVATE ${INCLUDE_DIRS} + DEFINITIONS PRIVATE ${COMPILER_DEFINITIONS} + COMPILE_OPTIONS PRIVATE ${COMPILE_FLAGS} + COMPILE_OPTIONS ${COMPILER_OPTIONS} ) + +############################################################## +# VPP Module +############################################################## if(BUILD_HICNPLUGIN AND ${CMAKE_SYSTEM_NAME} MATCHES "Linux") - list(APPEND HICNLIGHT_PLUGIN_SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/hicn_plugin_api.c + if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + find_package(HicnPlugin ${CURRENT_VERSION} REQUIRED) + find_package(Safevapi ${CURRENT_VERSION} REQUIRED) + else() + list(APPEND DEPENDENCIES + ${SAFE_VAPI_SHARED} + ) + endif() + + list(APPEND HICN_PLUGIN_SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_plugin_api.c ) build_module(vppctrl_module - SHARED - SOURCES ${HICNLIGHT_PLUGIN_SOURCE_FILES} - DEPENDS ${DEPENDENCIES} - LINK_LIBRARIES ${HICNPLUGIN_LIBRARIES} ${SAFE_VAPI_LIBRARIES} - COMPONENT ${LIBHICNCTRL_COMPONENT_MODULES} - INCLUDE_DIRS ${INCLUDE_DIRS} - DEFINITIONS ${COMPILER_DEFINITIONS} - COMPILE_OPTIONS ${COMPILE_FLAGS} - LINK_FLAGS "-Wl,-unresolved-symbols=ignore-in-shared-libs" + SOURCES ${HICN_PLUGIN_SOURCE_FILES} + DEPENDS ${DEPENDENCIES} + LINK_LIBRARIES + PRIVATE ${HICN_LIBRARIES} + PRIVATE ${HICNPLUGIN_LIBRARIES} + PRIVATE ${SAFE_VAPI_LIBRARIES} + COMPONENT ${LIBHICNCTRL_COMPONENT_MODULES} + INCLUDE_DIRS PRIVATE ${INCLUDE_DIRS} + DEFINITIONS PRIVATE ${COMPILER_DEFINITIONS} + COMPILE_OPTIONS ${COMPILER_OPTIONS} ${MARCH_COMPILER_OPTIONS} ) - -endif()
\ No newline at end of file +endif() diff --git a/ctrl/libhicnctrl/src/modules/hicn_light_api.c b/ctrl/libhicnctrl/src/modules/hicn_light_api.c deleted file mode 100644 index d1a055777..000000000 --- a/ctrl/libhicnctrl/src/modules/hicn_light_api.c +++ /dev/null @@ -1,2278 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 api.c - * \brief Implementation of hICN control library API - */ - -#include "api_private.h" - -#include <assert.h> // assert -#include <stdbool.h> -#include <stdio.h> // snprintf -#include <string.h> // memmove, strcasecmp -#include <sys/socket.h> // socket -#include <unistd.h> // close, fcntl -#include <fcntl.h> // fcntl -#include <sys/types.h> // getpid -#include <unistd.h> // getpid -#ifdef __linux__ -#include <sys/syscall.h> -#define gettid() syscall(SYS_gettid) -#endif /* __linux__ */ -#include <strings.h> - -#define PORT 9695 - -#define BOOLSTR(x) ((x) ? "true" : "false") - -/* - * Internal state associated to a pending request - */ -typedef struct { - int seq; - hc_data_t * data; - /* Information used to process results */ - int size_in; - int (*parse)(const u8 * src, u8 * dst); -} hc_sock_request_t; - -/** - * Messages to the forwarder might be multiplexed thanks to the seqNum fields in - * the header_control_message structure. The forwarder simply answers back the - * original sequence number. We maintain a map of such sequence number to - * outgoing queries so that replied can be demultiplexed and treated - * appropriately. - */ -TYPEDEF_MAP_H(hc_sock_map, int, hc_sock_request_t *); -TYPEDEF_MAP(hc_sock_map, int, hc_sock_request_t *, int_cmp, int_snprintf, generic_snprintf); - -struct hc_sock_light_s { - /* This must be the first element of the struct */ - hc_sock_t vft; - - char * url; - int fd; - - /* Partial receive buffer */ - u8 buf[RECV_BUFLEN]; - size_t roff; /**< Read offset */ - size_t woff; /**< Write offset */ - - /* - * Because received messages are potentially unbounded in size, we might not - * guarantee that we can store a full packet before processing it. We must - * implement a very simple state machine remembering the current parsing - * status in order to partially process the packet. - */ - size_t remaining; - u32 send_id; - - /* Next sequence number to be used for requests */ - int seq; - - /* Request being parsed (NULL if none) */ - hc_sock_request_t * cur_request; - - bool async; - hc_sock_map_t * map; -}; - -typedef struct hc_sock_light_s hc_sock_light_t; - -#define TO_HC_SOCK_LIGHT(s) (hc_sock_light_t*)(s) - -hc_sock_request_t * -hc_sock_request_create(int seq, hc_data_t * data, HC_PARSE parse) -{ - assert(data); - - hc_sock_request_t * request = malloc(sizeof(hc_sock_request_t)); - if (!request) - return NULL; - request->seq = seq; - request->data = data; - request->parse = parse; - return request; -} - -void -hc_sock_light_request_free(hc_sock_request_t * request) -{ - free(request); -} - -/* - * list was working with all seq set to 0, but it seems hicnLightControl uses - * 1, and replies with the same seqno - */ -#define HICN_CTRL_SEND_SEQ_INIT 1 -#define HICN_CTRL_RECV_SEQ_INIT 1 - -#define MAX(x, y) ((x > y) ? x : y) - -/** - * In practise, we want to preserve enough room to store a full packet of - * average expected size (say a header + N payload elements). - */ -#define AVG_ELEMENTS (1 << DEFAULT_SIZE_LOG) -#define AVG_BUFLEN (sizeof(hc_msg_header_t) + AVG_ELEMENTS * sizeof(hc_msg_payload_t)) - -/* - * We should at least have buffer space allowing to store one processable unit - * of data, either the header of the maximum possible payload - */ -#define MIN_BUFLEN MAX(sizeof(hc_msg_header_t), sizeof(hc_msg_payload_t)) - -static const struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT; - -/****************************************************************************** - * Message helper types and aliases - ******************************************************************************/ - -#define foreach_hc_command \ - _(add_connection) \ - _(remove_connection) \ - _(list_connections) \ - _(add_listener) \ - _(remove_listener) \ - _(list_listeners) \ - _(add_route) \ - _(remove_route) \ - _(list_routes) \ - _(cache_store) \ - _(cache_serve) \ - /*_(cache_clear) */ \ - _(set_strategy) \ - _(set_wldr) \ - _(add_punting) \ - _(mapme_activator) \ - _(mapme_timing) - -typedef header_control_message hc_msg_header_t; - -typedef union { -#define _(x) x ## _command x; - foreach_hc_command -#undef _ -} hc_msg_payload_t; - - -typedef struct hc_msg_s { - hc_msg_header_t hdr; - hc_msg_payload_t payload; -} hc_msg_t; - -/****************************************************************************** - * Control socket - ******************************************************************************/ - -/** - * \brief Parse a connection URL into a sockaddr - * \param [in] url - URL - * \param [out] sa - Resulting struct sockaddr, expected zero'ed. - * \return 0 if parsing succeeded, a negative error value otherwise. - */ -static int -_hc_sock_light_parse_url(const char * url, struct sockaddr * sa) -{ - /* FIXME URL parsing is currently not implemented */ - assert(!url); - -#ifdef __linux__ - srand(time(NULL) ^ getpid() ^ gettid()); -#else - srand((unsigned int )(time(NULL) ^ getpid())); -#endif /* __linux__ */ - - /* - * A temporary solution is to inspect the sa_family fields of the passed in - * sockaddr, which defaults to AF_UNSPEC (0) and thus creates an IPv4/TCP - * connection to localhost. - */ - switch (sa->sa_family) { - case AF_UNSPEC: - case AF_INET: - { - struct sockaddr_in * sai = (struct sockaddr_in *)sa; - sai->sin_family = AF_INET; - sai->sin_port = htons(PORT); - sai->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - break; - } - case AF_INET6: - { - struct sockaddr_in6 * sai6 = (struct sockaddr_in6 *)sa; - sai6->sin6_family = AF_INET6; - sai6->sin6_port = htons(PORT); - sai6->sin6_addr = loopback_addr; - break; - } - default: - return -1; - } - - return 0; -} - -static int -_hc_sock_light_reset(hc_sock_t * socket) -{ - hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); - s->roff = s->woff = 0; - s->remaining = 0; - return 0; -} - -void -_hc_sock_light_free(hc_sock_t * socket) -{ - hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); - hc_sock_request_t ** request_array = NULL; - int n = hc_sock_map_get_value_array(s->map, &request_array); - if (n < 0) { - ERROR("Could not retrieve pending request array for freeing up resources"); - } else { - for (unsigned i = 0; i < n; i++) { - hc_sock_request_t * request = request_array[i]; - if (hc_sock_map_remove(s->map, request->seq, NULL) < 0) - ERROR("[hc_sock_light_process] Error removing request from map"); - hc_sock_light_request_free(request); - } - free(request_array); - } - - hc_sock_map_free(s->map); - if (s->url) - free(s->url); - close(s->fd); - free(s); -} - -static int -_hc_sock_light_get_next_seq(hc_sock_t * socket) -{ - hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); - return s->seq++; -} - -static int -_hc_sock_light_set_nonblocking(hc_sock_t * socket) -{ - hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); - return (fcntl(s->fd, F_SETFL, fcntl(s->fd, F_GETFL) | O_NONBLOCK) < 0); -} - -static int -_hc_sock_light_get_fd(hc_sock_t * socket) -{ - hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); - return s->fd; -} - -static int -_hc_sock_light_connect(hc_sock_t * socket) -{ - hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); - struct sockaddr_storage ss; - memset(&ss, 0, sizeof(struct sockaddr_storage)); - - if (_hc_sock_light_parse_url(s->url, (struct sockaddr *)&ss) < 0) - goto ERR_PARSE; - - size_t size = ss.ss_family == AF_INET - ? sizeof(struct sockaddr_in) - : sizeof(struct sockaddr_in6); - if (connect(s->fd, (struct sockaddr *)&ss, (socklen_t)size) < 0) //sizeof(struct sockaddr)) < 0) - goto ERR_CONNECT; - - return 0; - -ERR_CONNECT: -ERR_PARSE: - return -1; -} - -static int -_hc_sock_light_send(hc_sock_t * socket, hc_msg_t * msg, size_t msglen, int seq) -{ - hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); - int rc; - msg->hdr.seqNum = seq; - rc = (int)send(s->fd, msg, msglen, 0); - if (rc < 0) { - perror("hc_sock_light_send"); - return -1; - } - return 0; -} - -static int -_hc_sock_light_get_available(hc_sock_t * socket, u8 ** buffer, size_t * size) -{ - hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); - *buffer = s->buf + s->woff; - *size = RECV_BUFLEN - s->woff; - - return 0; -} - -static int -_hc_sock_light_recv(hc_sock_t * socket) -{ - hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); - int rc; - - /* - * This condition should be ensured to guarantee correct processing of - * messages - */ - assert(RECV_BUFLEN - s->woff > MIN_BUFLEN); - - rc = (int)recv(s->fd, s->buf + s->woff, RECV_BUFLEN - s->woff, 0); - if (rc == 0) { - /* Connection has been closed */ - return 0; - } - if (rc < 0) { - /* - * Let's not return 0 which currently means the socket has been closed - */ - if (errno == EWOULDBLOCK) - return -1; - perror("hc_sock_light_recv"); - return -1; - } - s->woff += rc; - return rc; -} - -/* - * Returns -99 in case of internal error, -1 in case of API command failure - */ -static int -_hc_sock_light_process(hc_sock_t * socket, hc_data_t ** data) -{ - hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); - int err = 0; - - /* We must have received at least one byte */ - size_t available = s->woff - s->roff; - - while(available > 0) { - - if (!s->cur_request) { // No message being parsed, alternatively (remaining == 0) - hc_msg_t * msg = (hc_msg_t*)(s->buf + s->roff); - - /* We expect a message header */ - if (available < sizeof(hc_msg_header_t)) { - break; - } - - hc_sock_request_t * request = NULL; - if (hc_sock_map_get(s->map, msg->hdr.seqNum, &request) < 0) { - ERROR("[hc_sock_light_process] Error searching for matching request"); - return -99; - } - if (!request) { - ERROR("[hc_sock_light_process] No request matching received sequence number"); - return -99; - } - - s->remaining = msg->hdr.length; - switch(msg->hdr.messageType) { - case ACK_LIGHT: - assert(s->remaining == 1); - assert(!data); - s->cur_request = request; - break; - case NACK_LIGHT: - assert(s->remaining == 1); - assert(!data); - hc_data_set_error(request->data); - s->cur_request = request; - err = -1; - break; - case RESPONSE_LIGHT: - assert(data); - if (s->remaining == 0) { - hc_data_set_complete(request->data); - *data = request->data; - if (hc_sock_map_remove(s->map, request->seq, NULL) < 0) - ERROR("[hc_sock_light_process] Error removing request from map"); - hc_sock_light_request_free(request); - } else { - /* We only remember it if there is still data to parse */ - s->cur_request = request; - } - break; - default: - ERROR("[hc_sock_light_process] Invalid response received"); - return -99; - } - - available -= sizeof(hc_msg_header_t); - s->roff += sizeof(hc_msg_header_t); - } else { - /* We expect the complete payload, or at least a chunk of it */ - size_t num_chunks = available / s->cur_request->data->in_element_size; - if (num_chunks == 0) - break; - if (num_chunks > s->remaining) - num_chunks = s->remaining; - - if (!s->cur_request->parse) { - /* If we don't need to parse results, then we can directly push - * all of them into the result data structure */ - hc_data_push_many(s->cur_request->data, s->buf + s->roff, num_chunks); - } else { - int rc; - rc = hc_data_ensure_available(s->cur_request->data, num_chunks); - if (rc < 0) { - ERROR("[hc_sock_light_process] Error in hc_data_ensure_available"); - return -99; - } - for (int i = 0; i < num_chunks; i++) { - u8 * dst = hc_data_get_next(s->cur_request->data); - if (!dst) { - ERROR("[hc_sock_light_process] Error in hc_data_get_next"); - return -99; - } - - rc = s->cur_request->parse(s->buf + s->roff + i * s->cur_request->data->in_element_size, dst); - if (rc < 0) { - ERROR("[hc_sock_light_process] Error in parse"); - err = -99; /* FIXME we let the loop complete (?) */ - } - s->cur_request->data->size++; - } - } - - s->remaining -= num_chunks; - available -= num_chunks * s->cur_request->data->in_element_size; - s->roff += num_chunks * s->cur_request->data->in_element_size; - if (s->remaining == 0) { - if (hc_sock_map_remove(s->map, s->cur_request->seq, NULL) < 0) { - ERROR("[hc_sock_light_process] Error removing request from map"); - return -99; - } - hc_data_set_complete(s->cur_request->data); - if (data) - *data = s->cur_request->data; - hc_sock_light_request_free(s->cur_request); - s->cur_request = NULL; - } - - } - } - - /* Make sure there is enough remaining space in the buffer */ - if (RECV_BUFLEN - s->woff < AVG_BUFLEN) { - /* - * There should be no overlap provided a sufficiently large BUFLEN, but - * who knows. - */ - memmove(s->buf, s->buf + s->roff, s->woff - s->roff); - s->woff -= s->roff; - s->roff = 0; - } - - return err; -} - -static int -_hc_sock_light_callback(hc_sock_t * socket, hc_data_t ** pdata) -{ - hc_data_t * data; - - for (;;) { - int n = _hc_sock_light_recv(socket); - if (n == 0) - goto ERR_EOF; - if (n < 0) { - switch(errno) { - case ECONNRESET: - case ENODEV: - /* Forwarder restarted */ - WARN("Forwarder likely restarted: not (yet) implemented"); - goto ERR; - case EWOULDBLOCK: - //DEBUG("Would block... stop reading from socket"); - goto END; - default: - perror("hc_sock_light_recv"); - goto ERR; - } - } - if (_hc_sock_light_process(socket, &data) < 0) { - goto ERR; - } - } -END: - if (pdata) - *pdata = data; - else - hc_data_free(data); - return 0; - -ERR: - hc_data_free(data); -ERR_EOF: - return -1; -} - -/****************************************************************************** - * Command-specific structures and functions - ******************************************************************************/ - -typedef int (*HC_PARSE)(const u8 *, u8 *); - -typedef struct { - hc_action_t cmd; - command_id cmd_id; - size_t size_in; - size_t size_out; - HC_PARSE parse; -} hc_command_params_t; - -static int -_hc_execute_command(hc_sock_t * socket, hc_msg_t * msg, size_t msg_len, - hc_command_params_t * params, hc_data_t ** pdata, bool async) -{ - hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); - int ret; - if (async) - assert(!pdata); - - /* Sanity check */ - switch(params->cmd) { - case ACTION_CREATE: - assert(params->size_in != 0); /* payload repeated */ - assert(params->size_out == 0); - assert(params->parse == NULL); - break; - case ACTION_DELETE: - assert(params->size_in != 0); /* payload repeated */ - assert(params->size_out == 0); - assert(params->parse == NULL); - break; - case ACTION_LIST: - assert(params->size_in != 0); - assert(params->size_out != 0); - assert(params->parse != NULL); - break; - case ACTION_SET: - assert(params->size_in != 0); - assert(params->size_out == 0); - assert(params->parse == NULL); - break; - default: - return -1; - } - - //hc_sock_light_reset(s); - - /* XXX data will at least store the result (complete) */ - hc_data_t * data = hc_data_create(params->size_in, params->size_out, NULL); - if (!data) { - ERROR("[_hc_execute_command] Could not create data storage"); - goto ERR_DATA; - } - - int seq = _hc_sock_light_get_next_seq(socket); - - /* Create state used to process the request */ - hc_sock_request_t * request = NULL; - request = hc_sock_request_create(seq, data, params->parse); - if (!request) { - ERROR("[_hc_execute_command] Could not create request state"); - goto ERR_REQUEST; - } - - /* Add state to map */ - if (hc_sock_map_add(s->map, seq, request) < 0) { - ERROR("[_hc_execute_command] Error adding request state to map"); - goto ERR_MAP; - } - - if (_hc_sock_light_send(socket, msg, msg_len, seq) < 0) { - ERROR("[_hc_execute_command] Error sending message"); - goto ERR_PROCESS; - } - - if (async) - return 0; - - while(!data->complete) { - /* - * As the socket is non blocking it might happen that we need to read - * several times before success... shall we alternate between blocking - * and non-blocking mode ? - */ - int n = _hc_sock_light_recv(socket); - if (n == 0) - goto ERR_EOF; - if (n < 0) - continue; //break; - int rc = _hc_sock_light_process(socket, pdata); - switch(rc) { - case 0: - break; - case -1: - ret = rc; - break; - case -99: - ERROR("[_hc_execute_command] Error processing socket results"); - goto ERR; - break; - default: - ERROR("[_hc_execute_command] Unexpected return value"); - goto ERR; - } - } - -ERR_EOF: - ret = data->ret; - if (!data->complete) - return -1; - if (!pdata) - hc_data_free(data); - - return ret; - -ERR_PROCESS: -ERR_MAP: - hc_sock_light_request_free(request); -ERR: -ERR_REQUEST: - hc_data_free(data); -ERR_DATA: - return -99; -} - -/*----------------------------------------------------------------------------* - * Listeners - *----------------------------------------------------------------------------*/ - -/* LISTENER CREATE */ - -static int -_hc_listener_create_internal(hc_sock_t * socket, hc_listener_t * listener, bool async) -{ - char listener_s[MAXSZ_HC_LISTENER]; - int rc = hc_listener_snprintf(listener_s, MAXSZ_HC_LISTENER, listener); - if (rc >= MAXSZ_HC_LISTENER) - WARN("[_hc_listener_create] Unexpected truncation of listener string"); - DEBUG("[_hc_listener_create] listener=%s async=%s", listener_s, - BOOLSTR(async)); - - if (!IS_VALID_FAMILY(listener->family)) - return -1; - - if (!IS_VALID_CONNECTION_TYPE(listener->type)) - return -1; - - struct { - header_control_message hdr; - add_listener_command payload; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = ADD_LISTENER, - .length = 1, - .seqNum = 0, - }, - .payload = { - .address = listener->local_addr, - .port = htons(listener->local_port), - .addressType = (u8)map_to_addr_type[listener->family], - .listenerMode = (u8)map_to_listener_mode[listener->type], - .connectionType = (u8)map_to_connection_type[listener->type], - } - }; - - rc = snprintf(msg.payload.symbolic, SYMBOLIC_NAME_LEN, "%s", listener->name); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[_hc_listener_create] Unexpected truncation of symbolic name string"); - - rc = snprintf(msg.payload.interfaceName, INTERFACE_LEN, "%s", listener->interface_name); - if (rc >= INTERFACE_LEN) - WARN("[_hc_listener_create] Unexpected truncation of interface name string"); - - hc_command_params_t params = { - .cmd = ACTION_CREATE, - .cmd_id = ADD_LISTENER, - .size_in = sizeof(add_listener_command), - .size_out = 0, - .parse = NULL, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); -} - -static int -_hc_listener_create(hc_sock_t * s, hc_listener_t * listener) -{ - return _hc_listener_create_internal(s, listener, false); -} - -static int -_hc_listener_create_async(hc_sock_t * s, hc_listener_t * listener) -{ - return _hc_listener_create_internal(s, listener, true); -} - -/* LISTENER LIST */ - -static int -_hc_listener_list_internal(hc_sock_t * socket, hc_data_t ** pdata, bool async) -{ - DEBUG("[hc_listener_list] async=%s", BOOLSTR(async)); - - struct { - header_control_message hdr; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = LIST_LISTENERS, - .length = 0, - .seqNum = 0, - }, - }; - - hc_command_params_t params = { - .cmd = ACTION_LIST, - .cmd_id = LIST_LISTENERS, - .size_in = sizeof(list_listeners_command), - .size_out = sizeof(hc_listener_t), - .parse = (HC_PARSE)hc_listener_parse, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, pdata, async); -} - -static int -_hc_listener_list(hc_sock_t * s, hc_data_t ** pdata) -{ - return _hc_listener_list_internal(s, pdata, false); -} - -static int -_hc_listener_list_async(hc_sock_t * s, hc_data_t ** pdata) -{ - return _hc_listener_list_internal(s, pdata, true); -} - -/* LISTENER GET */ - -static int -_hc_listener_get(hc_sock_t * socket, hc_listener_t * listener, - hc_listener_t ** listener_found) -{ - hc_data_t * listeners; - hc_listener_t * found; - - char listener_s[MAXSZ_HC_LISTENER]; - int rc = hc_listener_snprintf(listener_s, MAXSZ_HC_LISTENER, listener); - if (rc >= MAXSZ_HC_LISTENER) - WARN("[hc_listener_get] Unexpected truncation of listener string"); - DEBUG("[hc_listener_get] listener=%s", listener_s); - - if (_hc_listener_list(socket, &listeners) < 0) - return -1; - - /* Test */ - if (hc_listener_find(listeners, listener, &found) < 0) { - hc_data_free(listeners); - return -1; - } - - if (found) { - *listener_found = malloc(sizeof(hc_listener_t)); - if (!*listener_found) - return -1; - **listener_found = *found; - } else { - *listener_found = NULL; - } - - hc_data_free(listeners); - - return 0; -} - - -/* LISTENER DELETE */ - -static int -_hc_listener_delete_internal(hc_sock_t * socket, hc_listener_t * listener, bool async) -{ - char listener_s[MAXSZ_HC_LISTENER]; - int rc = hc_listener_snprintf(listener_s, MAXSZ_HC_LISTENER, listener); - if (rc >= MAXSZ_HC_LISTENER) - WARN("[_hc_listener_delete] Unexpected truncation of listener string"); - DEBUG("[_hc_listener_delete] listener=%s async=%s", listener_s, - BOOLSTR(async)); - - struct { - header_control_message hdr; - remove_listener_command payload; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = REMOVE_LISTENER, - .length = 1, - .seqNum = 0, - }, - }; - - if (listener->id) { - rc = snprintf(msg.payload.symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%d", listener->id); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[_hc_listener_delete] Unexpected truncation of symbolic name string"); - } else if (*listener->name) { - rc = snprintf(msg.payload.symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%s", listener->name); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[_hc_listener_delete] Unexpected truncation of symbolic name string"); - } else { - hc_listener_t * listener_found; - if (_hc_listener_get(socket, listener, &listener_found) < 0) - return -1; - if (!listener_found) - return -1; - rc = snprintf(msg.payload.symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%d", listener_found->id); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[_hc_listener_delete] Unexpected truncation of symbolic name string"); - free(listener_found); - } - - hc_command_params_t params = { - .cmd = ACTION_DELETE, - .cmd_id = REMOVE_LISTENER, - .size_in = sizeof(remove_listener_command), - .size_out = 0, - .parse = NULL, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); -} - -static int -_hc_listener_delete(hc_sock_t * s, hc_listener_t * listener) -{ - return _hc_listener_delete_internal(s, listener, false); -} - -static int -_hc_listener_delete_async(hc_sock_t * s, hc_listener_t * listener) -{ - return _hc_listener_delete_internal(s, listener, true); -} - -/*----------------------------------------------------------------------------* - * CONNECTION - *----------------------------------------------------------------------------*/ - -/* CONNECTION CREATE */ - -static int -_hc_connection_create_internal(hc_sock_t * socket, hc_connection_t * connection, bool async) -{ - char connection_s[MAXSZ_HC_CONNECTION]; - int rc = hc_connection_snprintf(connection_s, MAXSZ_HC_CONNECTION, connection); - if (rc >= MAXSZ_HC_CONNECTION) - WARN("[_hc_connection_create] Unexpected truncation of connection string"); - DEBUG("[_hc_connection_create] connection=%s async=%s", connection_s, BOOLSTR(async)); - - if (hc_connection_validate(connection) < 0) - return -1; - - struct { - header_control_message hdr; - add_connection_command payload; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = ADD_CONNECTION, - .length = 1, - .seqNum = 0, - }, - .payload = { - .remoteIp = connection->remote_addr, - .localIp = connection->local_addr, - .remotePort = htons(connection->remote_port), - .localPort = htons(connection->local_port), - .ipType = (u8)map_to_addr_type[connection->family], - .connectionType = (u8)map_to_connection_type[connection->type], - .admin_state = connection->admin_state, -#ifdef WITH_POLICY - .priority = connection->priority, - .tags = connection->tags, -#endif /* WITH_POLICY */ - } - }; - rc = snprintf(msg.payload.symbolic, SYMBOLIC_NAME_LEN, "%s", connection->name); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[_hc_connection_create] Unexpected truncation of symbolic name string"); - //snprintf(msg.payload.interfaceName, INTERFACE_NAME_LEN, "%s", connection->interface_name); - - hc_command_params_t params = { - .cmd = ACTION_CREATE, - .cmd_id = ADD_CONNECTION, - .size_in = sizeof(add_connection_command), - .size_out = 0, - .parse = NULL, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); -} - -static int -_hc_connection_create(hc_sock_t * s, hc_connection_t * connection) -{ - return _hc_connection_create_internal(s, connection, false); -} - -static int -_hc_connection_create_async(hc_sock_t * s, hc_connection_t * connection) -{ - return _hc_connection_create_internal(s, connection, true); -} - -/* CONNECTION LIST */ - -static int -_hc_connection_list_internal(hc_sock_t * socket, hc_data_t ** pdata, bool async) -{ - DEBUG("[hc_connection_list] async=%s", BOOLSTR(async)); - - struct { - header_control_message hdr; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = LIST_CONNECTIONS, - .length = 0, - .seqNum = 0, - }, - }; - - hc_command_params_t params = { - .cmd = ACTION_LIST, - .cmd_id = LIST_CONNECTIONS, - .size_in = sizeof(list_connections_command), - .size_out = sizeof(hc_connection_t), - .parse = (HC_PARSE)hc_connection_parse, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, pdata, async); -} - -static int -_hc_connection_list(hc_sock_t * s, hc_data_t ** pdata) -{ - return _hc_connection_list_internal(s, pdata, false); -} - -static int -_hc_connection_list_async(hc_sock_t * s, hc_data_t ** pdata) -{ - return _hc_connection_list_internal(s, pdata, true); -} - -/* CONNECTION GET */ - -static int -_hc_connection_get(hc_sock_t * socket, hc_connection_t * connection, - hc_connection_t ** connection_found) -{ - hc_data_t * connections; - hc_connection_t * found; - - char connection_s[MAXSZ_HC_CONNECTION]; - int rc = hc_connection_snprintf(connection_s, MAXSZ_HC_CONNECTION, connection); - if (rc >= MAXSZ_HC_CONNECTION) - WARN("[hc_connection_get] Unexpected truncation of connection string"); - DEBUG("[hc_connection_get] connection=%s", connection_s); - - if (_hc_connection_list(socket, &connections) < 0) - return -1; - - /* Test */ - if (hc_connection_find(connections, connection, &found) < 0) { - hc_data_free(connections); - return -1; - } - - if (found) { - *connection_found = malloc(sizeof(hc_connection_t)); - if (!*connection_found) - return -1; - **connection_found = *found; - } else { - *connection_found = NULL; - } - - hc_data_free(connections); - - return 0; -} - - -/* CONNECTION DELETE */ - -static int -_hc_connection_delete_internal(hc_sock_t * socket, hc_connection_t * connection, bool async) -{ - char connection_s[MAXSZ_HC_CONNECTION]; - int rc = hc_connection_snprintf(connection_s, MAXSZ_HC_CONNECTION, connection); - if (rc >= MAXSZ_HC_CONNECTION) - WARN("[_hc_connection_delete] Unexpected truncation of connection string"); - DEBUG("[_hc_connection_delete] connection=%s async=%s", connection_s, BOOLSTR(async)); - - struct { - header_control_message hdr; - remove_connection_command payload; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = REMOVE_CONNECTION, - .length = 1, - .seqNum = 0, - }, - }; - - if (connection->id) { - rc = snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%d", connection->id); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[_hc_connection_delete] Unexpected truncation of symbolic name string"); - } else if (*connection->name) { - rc = snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%s", connection->name); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[_hc_connection_delete] Unexpected truncation of symbolic name string"); - } else { - hc_connection_t * connection_found; - if (_hc_connection_get(socket, connection, &connection_found) < 0) - return -1; - if (!connection_found) - return -1; - rc = snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%d", connection_found->id); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[_hc_connection_delete] Unexpected truncation of symbolic name string"); - free(connection_found); - } - - hc_command_params_t params = { - .cmd = ACTION_DELETE, - .cmd_id = REMOVE_CONNECTION, - .size_in = sizeof(remove_connection_command), - .size_out = 0, - .parse = NULL, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); -} - -static int -_hc_connection_delete(hc_sock_t * s, hc_connection_t * connection) -{ - return _hc_connection_delete_internal(s, connection, false); -} - -static int -_hc_connection_delete_async(hc_sock_t * s, hc_connection_t * connection) -{ - return _hc_connection_delete_internal(s, connection, true); -} - -static int -_hc_connection_update_by_id(hc_sock_t *s, int hc_connection_id, - hc_connection_t *connection) -{ - // Not implemented - return -1; -} - -static int -_hc_connection_update(hc_sock_t *s, hc_connection_t *connection_current, - hc_connection_t *connection_updated) -{ - // Not implemented - return -1; -} - -/* CONNECTION SET ADMIN STATE */ - -static int -_hc_connection_set_admin_state_internal(hc_sock_t * socket, const char * conn_id_or_name, - face_state_t state, bool async) -{ - 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)); - struct { - header_control_message hdr; - connection_set_admin_state_command payload; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = CONNECTION_SET_ADMIN_STATE, - .length = 1, - .seqNum = 0, - }, - .payload = { - .admin_state = state, - }, - }; - rc = snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%s", conn_id_or_name); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[_hc_connection_set_admin_state] Unexpected truncation of symbolic name string"); - - hc_command_params_t params = { - .cmd = ACTION_SET, - .cmd_id = CONNECTION_SET_ADMIN_STATE, - .size_in = sizeof(connection_set_admin_state_command), - .size_out = 0, - .parse = NULL, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); -} - -static int -_hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, - face_state_t state) -{ - return _hc_connection_set_admin_state_internal(s, conn_id_or_name, state, false); -} - -static int -_hc_connection_set_admin_state_async(hc_sock_t * s, const char * conn_id_or_name, - face_state_t state) -{ - return _hc_connection_set_admin_state_internal(s, conn_id_or_name, state, true); -} - -#ifdef WITH_POLICY - -static int -_hc_connection_set_priority_internal(hc_sock_t * socket, const char * conn_id_or_name, - uint32_t priority, bool async) -{ - int rc; - DEBUG("[hc_connection_set_priority] connection_id/name=%s priority=%d async=%s", - conn_id_or_name, priority, BOOLSTR(async)); - struct { - header_control_message hdr; - connection_set_priority_command payload; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = CONNECTION_SET_PRIORITY, - .length = 1, - .seqNum = 0, - }, - .payload = { - .priority = priority, - }, - }; - rc = snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%s", conn_id_or_name); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[_hc_connection_set_priority] Unexpected truncation of symbolic name string"); - - hc_command_params_t params = { - .cmd = ACTION_SET, - .cmd_id = CONNECTION_SET_PRIORITY, - .size_in = sizeof(connection_set_priority_command), - .size_out = 0, - .parse = NULL, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); -} - -static int -_hc_connection_set_priority(hc_sock_t * s, const char * conn_id_or_name, - uint32_t priority) -{ - return _hc_connection_set_priority_internal(s, conn_id_or_name, priority, false); -} - -static int -_hc_connection_set_priority_async(hc_sock_t * s, const char * conn_id_or_name, - uint32_t priority) -{ - return _hc_connection_set_priority_internal(s, conn_id_or_name, priority, true); -} - -#endif // WITH_POLICY - -static int -_hc_connection_set_tags_internal(hc_sock_t * s, const char * conn_id_or_name, - policy_tags_t tags, bool async) -{ - int rc; - DEBUG("[hc_connection_set_tags] connection_id/name=%s tags=%d async=%s", - conn_id_or_name, tags, BOOLSTR(async)); - struct { - header_control_message hdr; - connection_set_tags_command payload; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = CONNECTION_SET_TAGS, - .length = 1, - .seqNum = 0, - }, - .payload = { - .tags = tags, - }, - }; - rc = snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%s", conn_id_or_name); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[_hc_connection_set_tags] Unexpected truncation of symbolic name string"); - - hc_command_params_t params = { - .cmd = ACTION_SET, - .cmd_id = CONNECTION_SET_TAGS, - .size_in = sizeof(connection_set_tags_command), - .size_out = 0, - .parse = NULL, - }; - - return _hc_execute_command(s, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); -} - -static int -_hc_connection_set_tags(hc_sock_t * s, const char * conn_id_or_name, - policy_tags_t tags) -{ - return _hc_connection_set_tags_internal(s, conn_id_or_name, tags, false); -} - -static int -_hc_connection_set_tags_async(hc_sock_t * s, const char * conn_id_or_name, - policy_tags_t tags) -{ - return _hc_connection_set_tags_internal(s, conn_id_or_name, tags, true); -} - -/*----------------------------------------------------------------------------* - * Routes - *----------------------------------------------------------------------------*/ - -/* ROUTE CREATE */ - -static int -_hc_route_create_internal(hc_sock_t * socket, hc_route_t * route, bool async) -{ - char route_s[MAXSZ_HC_ROUTE]; - int rc = hc_route_snprintf(route_s, MAXSZ_HC_ROUTE, route); - if (rc >= MAXSZ_HC_ROUTE) - WARN("[_hc_route_create] Unexpected truncation of route string"); - if (rc < 0) - WARN("[_hc_route_create] Error building route string"); - else - DEBUG("[hc_route_create] route=%s async=%s", route_s, BOOLSTR(async)); - - if (!IS_VALID_FAMILY(route->family)) - return -1; - - struct { - header_control_message hdr; - add_route_command payload; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = ADD_ROUTE, - .length = 1, - .seqNum = 0, - }, - .payload = { - .address = route->remote_addr, - .cost = route->cost, - .addressType = (u8)map_to_addr_type[route->family], - .len = route->len, - } - }; - - /* - * The route commands expects the ID (or name that we don't use) as part of - * the symbolicOrConnid attribute. - */ - rc = snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%d", route->face_id); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[_hc_route_create] Unexpected truncation of symbolic name string"); - - hc_command_params_t params = { - .cmd = ACTION_CREATE, - .cmd_id = ADD_ROUTE, - .size_in = sizeof(add_route_command), - .size_out = 0, - .parse = NULL, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); -} - -static int -_hc_route_create(hc_sock_t * s, hc_route_t * route) -{ - return _hc_route_create_internal(s, route, false); -} - -static int -_hc_route_create_async(hc_sock_t * s, hc_route_t * route) -{ - return _hc_route_create_internal(s, route, true); -} - -/* ROUTE DELETE */ - -static int -_hc_route_delete_internal(hc_sock_t * socket, hc_route_t * route, bool async) -{ - char route_s[MAXSZ_HC_ROUTE]; - int rc = hc_route_snprintf(route_s, MAXSZ_HC_ROUTE, route); - if (rc >= MAXSZ_HC_ROUTE) - WARN("[_hc_route_delete] Unexpected truncation of route string"); - DEBUG("[hc_route_delete] route=%s async=%s", route_s, BOOLSTR(async)); - - if (!IS_VALID_FAMILY(route->family)) - return -1; - - struct { - header_control_message hdr; - remove_route_command payload; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = REMOVE_ROUTE, - .length = 1, - .seqNum = 0, - }, - .payload = { - .address = route->remote_addr, - .addressType = (u8)map_to_addr_type[route->family], - .len = route->len, - } - }; - - /* - * The route commands expects the ID (or name that we don't use) as part of - * the symbolicOrConnid attribute. - */ - snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%d", route->face_id); - - hc_command_params_t params = { - .cmd = ACTION_DELETE, - .cmd_id = REMOVE_ROUTE, - .size_in = sizeof(remove_route_command), - .size_out = 0, - .parse = NULL, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); -} - -static int -_hc_route_delete(hc_sock_t * s, hc_route_t * route) -{ - return _hc_route_delete_internal(s, route, false); -} - -static int -_hc_route_delete_async(hc_sock_t * s, hc_route_t * route) -{ - return _hc_route_delete_internal(s, route, true); -} - -/* ROUTE LIST */ - -static int -_hc_route_list_internal(hc_sock_t * socket, hc_data_t ** pdata, bool async) -{ - //DEBUG("[hc_route_list] async=%s", BOOLSTR(async)); - - struct { - header_control_message hdr; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = LIST_ROUTES, - .length = 0, - .seqNum = 0, - }, - }; - - hc_command_params_t params = { - .cmd = ACTION_LIST, - .cmd_id = LIST_ROUTES, - .size_in = sizeof(list_routes_command), - .size_out = sizeof(hc_route_t), - .parse = (HC_PARSE)hc_route_parse, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, pdata, async); -} - -static int -_hc_route_list(hc_sock_t * s, hc_data_t ** pdata) -{ - return _hc_route_list_internal(s, pdata, false); -} - -static int -_hc_route_list_async(hc_sock_t * s) -{ - return _hc_route_list_internal(s, NULL, true); -} - -/*----------------------------------------------------------------------------* - * Face - * - * Face support is not directly available in hicn-light, but we can offer such - * an interface through a combination of listeners and connections. The code - * starts with some conversion functions between faces/listeners/connections. - * - * We also need to make sure that there always exist a (single) listener when a - * connection is created, and in the hICN face case, that there is a single - * connection attached to this listener. - * - *----------------------------------------------------------------------------*/ - -/* FACE CREATE */ - -static int -_hc_face_create(hc_sock_t * socket, hc_face_t * face) -{ - hc_listener_t listener; - hc_listener_t * listener_found; - - hc_connection_t connection; - hc_connection_t * connection_found; - - char face_s[MAXSZ_HC_FACE]; - int rc = hc_face_snprintf(face_s, MAXSZ_HC_FACE, face); - if (rc >= MAXSZ_HC_FACE) - WARN("[hc_face_create] Unexpected truncation of face string"); - DEBUG("[hc_face_create] face=%s", face_s); - - switch(face->face.type) - { - case FACE_TYPE_HICN: - case FACE_TYPE_TCP: - case FACE_TYPE_UDP: - if (hc_face_to_connection(face, &connection, true) < 0) { - ERROR("[hc_face_create] Could not convert face to connection."); - return -1; - } - - /* Ensure we have a corresponding local listener */ - if (hc_connection_to_local_listener(&connection, &listener) < 0) { - ERROR("[hc_face_create] Could not convert face to local listener."); - return -1; - } - - if (_hc_listener_get(socket, &listener, &listener_found) < 0) { - ERROR("[hc_face_create] Could not retrieve listener"); - return -1; - } - - if (!listener_found) { - /* We need to create the listener if it does not exist */ - if (_hc_listener_create(socket, &listener) < 0) { - ERROR("[hc_face_create] Could not create listener."); - free(listener_found); - return -1; - } - } else { - free(listener_found); - } - - /* Create corresponding connection */ - if (_hc_connection_create(socket, &connection) < 0) { - ERROR("[hc_face_create] Could not create connection."); - return -1; - } - - /* - * Once the connection is created, we need to list all connections - * and compare with the current one to find the created face ID. - */ - if (_hc_connection_get(socket, &connection, &connection_found) < 0) { - ERROR("[hc_face_create] Could not retrieve connection"); - return -1; - } - - if (!connection_found) { - ERROR("[hc_face_create] Could not find newly created connection."); - return -1; - } - - face->id = connection_found->id; - free(connection_found); - - break; - - case FACE_TYPE_HICN_LISTENER: - case FACE_TYPE_TCP_LISTENER: - case FACE_TYPE_UDP_LISTENER: - if (hc_face_to_listener(face, &listener) < 0) { - ERROR("Could not convert face to listener."); - return -1; - } - if (_hc_listener_create(socket, &listener) < 0) { - ERROR("[hc_face_create] Could not create listener."); - return -1; - } - return -1; - break; - default: - ERROR("[hc_face_create] Unknwon face type."); - - return -1; - }; - - return 0; -} - -static int -_hc_face_get(hc_sock_t * socket, hc_face_t * face, hc_face_t ** face_found) -{ - hc_listener_t listener; - hc_listener_t * listener_found; - - hc_connection_t connection; - hc_connection_t * connection_found; - - char face_s[MAXSZ_HC_FACE]; - int rc = hc_face_snprintf(face_s, MAXSZ_HC_FACE, face); - if (rc >= MAXSZ_HC_FACE) - WARN("[hc_face_get] Unexpected truncation of face string"); - DEBUG("[hc_face_get] face=%s", face_s); - - switch(face->face.type) - { - case FACE_TYPE_HICN: - case FACE_TYPE_TCP: - case FACE_TYPE_UDP: - if (hc_face_to_connection(face, &connection, false) < 0) - return -1; - if (_hc_connection_get(socket, &connection, &connection_found) < 0) - return -1; - if (!connection_found) { - *face_found = NULL; - return 0; - } - *face_found = malloc(sizeof(hc_face_t)); - hc_connection_to_face(connection_found, *face_found); - free(connection_found); - break; - - case FACE_TYPE_HICN_LISTENER: - case FACE_TYPE_TCP_LISTENER: - case FACE_TYPE_UDP_LISTENER: - if (hc_face_to_listener(face, &listener) < 0) - return -1; - if (_hc_listener_get(socket, &listener, &listener_found) < 0) - return -1; - if (!listener_found) { - *face_found = NULL; - return 0; - } - *face_found = malloc(sizeof(hc_face_t)); - hc_listener_to_face(listener_found, *face_found); - free(listener_found); - break; - - default: - return -1; - } - - return 0; - -} - -/* FACE DELETE */ - -static int -_hc_face_delete(hc_sock_t * socket, hc_face_t * face) -{ - char face_s[MAXSZ_HC_FACE]; - int rc = hc_face_snprintf(face_s, MAXSZ_HC_FACE, face); - if (rc >= MAXSZ_HC_FACE) - WARN("[hc_face_delete] Unexpected truncation of face string"); - DEBUG("[hc_face_delete] face=%s", face_s); - - hc_connection_t connection; - if (hc_face_to_connection(face, &connection, false) < 0) { - ERROR("[hc_face_delete] Could not convert face to connection."); - return -1; - } - - if (_hc_connection_delete(socket, &connection) < 0) { - ERROR("[hc_face_delete] Error removing connection"); - return -1; - } - - /* If this is the last connection attached to the listener, remove it */ - - hc_data_t * connections; - hc_listener_t listener = {{0}}; - - /* - * Ensure we have a corresponding local listener - * NOTE: hc_face_to_listener is not appropriate - */ - if (hc_connection_to_local_listener(&connection, &listener) < 0) { - ERROR("[hc_face_create] Could not convert face to local listener."); - return -1; - } -#if 1 - /* - * The name is generated to prepare listener creation, we need it to be - * empty for deletion. The id should not need to be reset though. - */ - listener.id = 0; - memset(listener.name, 0, sizeof(listener.name)); -#endif - if (_hc_connection_list(socket, &connections) < 0) { - ERROR("[hc_face_delete] Error getting the list of listeners"); - return -1; - } - - bool delete = true; - foreach_connection(c, connections) { - if ((ip_address_cmp(&c->local_addr, &listener.local_addr, c->family) == 0) && - (c->local_port == listener.local_port) && - (strcmp(c->interface_name, listener.interface_name) == 0)) { - delete = false; - } - } - - if (delete) { - if (_hc_listener_delete(socket, &listener) < 0) { - ERROR("[hc_face_delete] Error removing listener"); - return -1; - } - } - - hc_data_free(connections); - - return 0; - - -} - -/* FACE LIST */ - -static int -_hc_face_list(hc_sock_t * socket, hc_data_t ** pdata) -{ - hc_data_t * connection_data; - hc_face_t face; - - //DEBUG("[hc_face_list]"); - - if (_hc_connection_list(socket, &connection_data) < 0) { - ERROR("[hc_face_list] Could not list connections."); - return -1; - } - - hc_data_t * face_data = hc_data_create(sizeof(hc_connection_t), sizeof(hc_face_t), NULL); - foreach_connection(c, connection_data) { - if (hc_connection_to_face(c, &face) < 0) { - ERROR("[hc_face_list] Could not convert connection to face."); - goto ERR; - } - hc_data_push(face_data, &face); - } - - *pdata = face_data; - hc_data_free(connection_data); - return 0; - -ERR: - hc_data_free(connection_data); - return -1; -} - -static int -_hc_face_list_async(hc_sock_t * socket) -{ - struct { - header_control_message hdr; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = LIST_CONNECTIONS, - .length = 0, - .seqNum = 0, - }, - }; - - hc_command_params_t params = { - .cmd = ACTION_LIST, - .cmd_id = LIST_CONNECTIONS, - .size_in = sizeof(list_connections_command), - .size_out = sizeof(hc_face_t), - .parse = (HC_PARSE)hc_connection_parse_to_face, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, true); -} - -static int -_hc_face_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, - face_state_t admin_state) -{ - return hc_connection_set_admin_state(s, conn_id_or_name, admin_state); -} - -#ifdef WITH_POLICY -static int -_hc_face_set_priority(hc_sock_t * s, const char * conn_id_or_name, - uint32_t priority) -{ - return hc_connection_set_priority(s, conn_id_or_name, priority); -} - -static int -_hc_face_set_tags(hc_sock_t * s, const char * conn_id_or_name, - policy_tags_t tags) -{ - return hc_connection_set_tags(s, conn_id_or_name, tags); -} -#endif // WITH_POLICY - -/*----------------------------------------------------------------------------* - * Punting - *----------------------------------------------------------------------------*/ - -static int -_hc_punting_create_internal(hc_sock_t * socket, hc_punting_t * punting, bool async) -{ - int rc; - - if (hc_punting_validate(punting) < 0) - return -1; - - struct { - header_control_message hdr; - add_punting_command payload; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = ADD_PUNTING, - .length = 1, - .seqNum = 0, - }, - .payload = { - .address = punting->prefix, - .addressType = (u8)map_to_addr_type[punting->family], - .len = punting->prefix_len, - } - }; - rc = snprintf(msg.payload.symbolicOrConnid, SYMBOLIC_NAME_LEN, "%d", punting->face_id); - if (rc >= SYMBOLIC_NAME_LEN) - WARN("[_hc_punting_create] Unexpected truncation of symbolic name string"); - - hc_command_params_t params = { - .cmd = ACTION_CREATE, - .cmd_id = ADD_PUNTING, - .size_in = sizeof(add_punting_command), - .size_out = 0, - .parse = NULL, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); -} - -static int -_hc_punting_create(hc_sock_t * s, hc_punting_t * punting) -{ - return _hc_punting_create_internal(s, punting, false); -} - -static int -_hc_punting_create_async(hc_sock_t * s, hc_punting_t * punting) -{ - return _hc_punting_create_internal(s, punting, true); -} - -static int -_hc_punting_get(hc_sock_t * s, hc_punting_t * punting, hc_punting_t ** punting_found) -{ - ERROR("hc_punting_get not (yet) implemented."); - return -1; -} - -static int -_hc_punting_delete(hc_sock_t * s, hc_punting_t * punting) -{ - ERROR("hc_punting_delete not (yet) implemented."); - return -1; -} - -static int -_hc_punting_list(hc_sock_t * s, hc_data_t ** pdata) -{ - ERROR("hc_punting_list not (yet) implemented."); - return -1; -} - - -/*----------------------------------------------------------------------------* - * Cache - *----------------------------------------------------------------------------*/ - -static int -_hc_cache_set_store_internal(hc_sock_t * socket, int enabled, bool async) -{ - struct { - header_control_message hdr; - cache_store_command payload; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = CACHE_STORE, - .length = 1, - .seqNum = 0, - }, - .payload = { - .activate = enabled, - } - }; - - hc_command_params_t params = { - .cmd = ACTION_SET, - .cmd_id = CACHE_STORE, - .size_in = sizeof(cache_store_command), - .size_out = 0, - .parse = NULL, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); -} - -static int -_hc_cache_set_store(hc_sock_t * s, int enabled) -{ - return _hc_cache_set_store_internal(s, enabled, false); -} - -static int -_hc_cache_set_store_async(hc_sock_t * s, int enabled) -{ - return _hc_cache_set_store_internal(s, enabled, true); -} - -static int -_hc_cache_set_serve_internal(hc_sock_t * socket, int enabled, bool async) -{ - struct { - header_control_message hdr; - cache_serve_command payload; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = CACHE_SERVE, - .length = 1, - .seqNum = 0, - }, - .payload = { - .activate = enabled, - } - }; - - hc_command_params_t params = { - .cmd = ACTION_SET, - .cmd_id = CACHE_SERVE, - .size_in = sizeof(cache_serve_command), - .size_out = 0, - .parse = NULL, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); -} - -static int -_hc_cache_set_serve(hc_sock_t * s, int enabled) -{ - return _hc_cache_set_serve_internal(s, enabled, false); -} - -static int -_hc_cache_set_serve_async(hc_sock_t * s, int enabled) -{ - return _hc_cache_set_serve_internal(s, enabled, true); -} - -/*----------------------------------------------------------------------------* - * Strategy - *----------------------------------------------------------------------------*/ - -// per prefix -static int -_hc_strategy_set(hc_sock_t * s /* XXX */) -{ - return 0; -} - -/* How to retrieve that from the forwarder ? */ -static const char * strategies[] = { - "random", - "load_balancer", -}; - -#define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array)) - -static int -_hc_strategy_list(hc_sock_t * s, hc_data_t ** data) -{ - int rc; - - *data = hc_data_create(0, sizeof(hc_strategy_t), NULL); - - for (unsigned i = 0; i < ARRAY_SIZE(strategies); i++) { - hc_strategy_t * strategy = (hc_strategy_t*)hc_data_get_next(*data); - if (!strategy) - return -1; - rc = snprintf(strategy->name, MAXSZ_HC_STRATEGY, "%s", strategies[i]); - if (rc >= MAXSZ_HC_STRATEGY) - WARN("[hc_strategy_list] Unexpected truncation of strategy name string"); - (*data)->size++; - } - - return 0; -} - -/*----------------------------------------------------------------------------* - * WLDR - *----------------------------------------------------------------------------*/ - -// per connection -static int -_hc_wldr_set(hc_sock_t * s /* XXX */) -{ - return 0; -} - -/*----------------------------------------------------------------------------* - * MAP-Me - *----------------------------------------------------------------------------*/ - -static int -_hc_mapme_set(hc_sock_t * s, int enabled) -{ - return 0; -} - -static int -_hc_mapme_set_discovery(hc_sock_t * s, int enabled) -{ - return 0; -} - -static int -_hc_mapme_set_timescale(hc_sock_t * s, double timescale) -{ - return 0; -} - -static int -_hc_mapme_set_retx(hc_sock_t * s, double timescale) -{ - return 0; -} - -/*----------------------------------------------------------------------------* - * Policy - *----------------------------------------------------------------------------*/ - -#ifdef WITH_POLICY - -/* POLICY CREATE */ - -static int -_hc_policy_create_internal(hc_sock_t * socket, hc_policy_t * policy, bool async) -{ - if (!IS_VALID_FAMILY(policy->family)) - return -1; - - struct { - header_control_message hdr; - add_policy_command payload; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = ADD_POLICY, - .length = 1, - .seqNum = 0, - }, - .payload = { - .address = policy->remote_addr, - .addressType = (u8)map_to_addr_type[policy->family], - .len = policy->len, - .policy = policy->policy, - } - }; - - hc_command_params_t params = { - .cmd = ACTION_CREATE, - .cmd_id = ADD_POLICY, - .size_in = sizeof(add_policy_command), - .size_out = 0, - .parse = NULL, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); -} - -static int -_hc_policy_create(hc_sock_t * s, hc_policy_t * policy) -{ - return _hc_policy_create_internal(s, policy, false); -} - -static int -_hc_policy_create_async(hc_sock_t * s, hc_policy_t * policy) -{ - return _hc_policy_create_internal(s, policy, true); -} - -/* POLICY DELETE */ - -static int -_hc_policy_delete_internal(hc_sock_t * socket, hc_policy_t * policy, bool async) -{ - if (!IS_VALID_FAMILY(policy->family)) - return -1; - - struct { - header_control_message hdr; - remove_policy_command payload; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = REMOVE_POLICY, - .length = 1, - .seqNum = 0, - }, - .payload = { - .address = policy->remote_addr, - .addressType = (u8)map_to_addr_type[policy->family], - .len = policy->len, - } - }; - - hc_command_params_t params = { - .cmd = ACTION_DELETE, - .cmd_id = REMOVE_POLICY, - .size_in = sizeof(remove_policy_command), - .size_out = 0, - .parse = NULL, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, NULL, async); -} - -static int -_hc_policy_delete(hc_sock_t * s, hc_policy_t * policy) -{ - return _hc_policy_delete_internal(s, policy, false); -} - -static int -_hc_policy_delete_async(hc_sock_t * s, hc_policy_t * policy) -{ - return _hc_policy_delete_internal(s, policy, true); -} - -/* POLICY LIST */ - -static int -_hc_policy_list_internal(hc_sock_t * socket, hc_data_t ** pdata, bool async) -{ - struct { - header_control_message hdr; - } msg = { - .hdr = { - .messageType = REQUEST_LIGHT, - .commandID = LIST_POLICIES, - .length = 0, - .seqNum = 0, - }, - }; - - hc_command_params_t params = { - .cmd = ACTION_LIST, - .cmd_id = LIST_POLICIES, - .size_in = sizeof(list_policies_command), - .size_out = sizeof(hc_policy_t), - .parse = (HC_PARSE)hc_policy_parse, - }; - - return _hc_execute_command(socket, (hc_msg_t*)&msg, sizeof(msg), ¶ms, pdata, async); -} - -static int -_hc_policy_list(hc_sock_t * s, hc_data_t ** pdata) -{ - return _hc_policy_list_internal(s, pdata, false); -} - -static int -_hc_policy_list_async(hc_sock_t * s, hc_data_t ** pdata) -{ - return _hc_policy_list_internal(s, pdata, true); -} - -#endif /* WITH_POLICY */ - -static hc_sock_t hc_sock_light_interface = (hc_sock_t) { - .hc_sock_get_next_seq = _hc_sock_light_get_next_seq, - .hc_sock_set_nonblocking = _hc_sock_light_set_nonblocking, - .hc_sock_get_fd = _hc_sock_light_get_fd, - .hc_sock_connect = _hc_sock_light_connect, - .hc_sock_get_available = _hc_sock_light_get_available, - .hc_sock_send = _hc_sock_light_send, - .hc_sock_recv = _hc_sock_light_recv, - .hc_sock_process = _hc_sock_light_process, - .hc_sock_callback = _hc_sock_light_callback, - .hc_sock_reset = _hc_sock_light_reset, - .hc_sock_free = _hc_sock_light_free, - .hc_listener_create = _hc_listener_create, - .hc_listener_create_async = _hc_listener_create_async, - .hc_listener_get = _hc_listener_get, - .hc_listener_delete = _hc_listener_delete, - .hc_listener_delete_async = _hc_listener_delete_async, - .hc_listener_list = _hc_listener_list, - .hc_listener_list_async = _hc_listener_list_async, - .hc_connection_create = _hc_connection_create, - .hc_connection_create_async = _hc_connection_create_async, - .hc_connection_get = _hc_connection_get, - .hc_connection_update_by_id = _hc_connection_update_by_id, - .hc_connection_update = _hc_connection_update, - .hc_connection_delete = _hc_connection_delete, - .hc_connection_delete_async = _hc_connection_delete_async, - .hc_connection_list = _hc_connection_list, - .hc_connection_list_async = _hc_connection_list_async, - .hc_connection_set_admin_state = _hc_connection_set_admin_state, - .hc_connection_set_admin_state_async = _hc_connection_set_admin_state_async, - -#ifdef WITH_POLICY - .hc_connection_set_priority = _hc_connection_set_priority, - .hc_connection_set_priority_async = _hc_connection_set_priority_async, - .hc_connection_set_tags = _hc_connection_set_tags, - .hc_connection_set_tags_async = _hc_connection_set_tags_async, -#endif // WITH_POLICY - - .hc_face_create = _hc_face_create, - .hc_face_get = _hc_face_get, - .hc_face_delete = _hc_face_delete, - .hc_face_list = _hc_face_list, - .hc_face_list_async = _hc_face_list_async, - .hc_face_set_admin_state = _hc_face_set_admin_state, - -#ifdef WITH_POLICY - .hc_face_set_priority = _hc_face_set_priority, - .hc_face_set_tags = _hc_face_set_tags, -#endif // WITH_POLICY - - .hc_route_create = _hc_route_create, - .hc_route_create_async = _hc_route_create_async, - .hc_route_delete = _hc_route_delete, - .hc_route_delete_async = _hc_route_delete_async, - .hc_route_list = _hc_route_list, - .hc_route_list_async = _hc_route_list_async, - - .hc_punting_create = _hc_punting_create, - .hc_punting_create_async = _hc_punting_create_async, - .hc_punting_get = _hc_punting_get, - .hc_punting_delete = _hc_punting_delete, - .hc_punting_list = _hc_punting_list, - - .hc_cache_set_store = _hc_cache_set_store, - .hc_cache_set_store_async = _hc_cache_set_store_async, - .hc_cache_set_serve = _hc_cache_set_serve, - .hc_cache_set_serve_async = _hc_cache_set_serve_async, - - .hc_strategy_list = _hc_strategy_list, - .hc_strategy_set = _hc_strategy_set, - .hc_wldr_set = _hc_wldr_set, - - .hc_mapme_set = _hc_mapme_set, - .hc_mapme_set_discovery = _hc_mapme_set_discovery, - .hc_mapme_set_timescale = _hc_mapme_set_timescale, - .hc_mapme_set_retx = _hc_mapme_set_retx, - -#ifdef WITH_POLICY - .hc_policy_create = _hc_policy_create, - .hc_policy_create_async = _hc_policy_create_async, - .hc_policy_delete = _hc_policy_delete, - .hc_policy_delete_async = _hc_policy_delete_async, - .hc_policy_list = _hc_policy_list, - .hc_policy_list_async = _hc_policy_list_async -#endif // WITH_POLICY -}; - -// Public contructors - -hc_sock_t * -_hc_sock_create_url(const char * url) -{ - hc_sock_light_t * s = malloc(sizeof(hc_sock_light_t)); - if (!s) - goto ERR_MALLOC; - - s->vft = hc_sock_light_interface; - s->url = url ? strdup(url) : NULL; - - s->fd = socket(AF_INET, SOCK_STREAM, 0); - if (s->fd < 0) - goto ERR_SOCKET; - - if (_hc_sock_light_reset((hc_sock_t*)s) < 0) - goto ERR_RESET; - - s->seq = 0; - s->cur_request = NULL; - - s->map = hc_sock_map_create(); - if (!s->map) - goto ERR_MAP; - - return (hc_sock_t*)(s); - - //hc_sock_light_map_free(s->map); -ERR_MAP: -ERR_RESET: - if (s->url) - free(s->url); - close(s->fd); -ERR_SOCKET: - free(s); -ERR_MALLOC: - return NULL; -} - -hc_sock_t * -_hc_sock_create(void) -{ - return _hc_sock_create_url(NULL); -} diff --git a/ctrl/libhicnctrl/src/modules/hicn_light_common.c b/ctrl/libhicnctrl/src/modules/hicn_light_common.c new file mode 100644 index 000000000..bc04404bf --- /dev/null +++ b/ctrl/libhicnctrl/src/modules/hicn_light_common.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hicn_light_common.h" + +TYPEDEF_MAP(hc_sock_map, int, hc_sock_request_t *, int_cmp, int_snprintf, + generic_snprintf); + +hc_sock_request_t *hc_sock_request_create(int seq, hc_data_t *data, + HC_PARSE parse) { + assert(data); + + hc_sock_request_t *request = malloc(sizeof(hc_sock_request_t)); + if (!request) return NULL; + request->seq = seq; + request->data = data; + request->parse = parse; + return request; +} + +void hc_sock_light_request_free(hc_sock_request_t *request) { free(request); } diff --git a/ctrl/libhicnctrl/src/modules/hicn_light_common.h b/ctrl/libhicnctrl/src/modules/hicn_light_common.h new file mode 100644 index 000000000..4749474c8 --- /dev/null +++ b/ctrl/libhicnctrl/src/modules/hicn_light_common.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef HICNCTRL_HICN_LIGHT_COMMON +#define HICNCTRL_HICN_LIGHT_COMMON + +#include <assert.h> // assert + +#include "api_private.h" + +#define PORT 9695 + +#define BOOLSTR(x) ((x) ? "true" : "false") + +/* + * Internal state associated to a pending request + */ +typedef struct { + int seq; + hc_data_t *data; + int (*parse)(const u8 *src, u8 *dst); +} hc_sock_request_t; + +/** + * Messages to the forwarder might be multiplexed thanks to the seqNum fields in + * the header_control_message structure. The forwarder simply answers back the + * original sequence number. We maintain a map of such sequence number to + * outgoing queries so that replied can be demultiplexed and treated + * appropriately. + */ +TYPEDEF_MAP_H(hc_sock_map, int, hc_sock_request_t *); + +struct hc_sock_light_s { + /* This must be the first element of the struct */ + hc_sock_t vft; + + char *url; + int fd; + + /* Partial receive buffer */ + u8 buf[RECV_BUFLEN]; + size_t roff; /**< Read offset */ + size_t woff; /**< Write offset */ + + /* + * Because received messages are potentially unbounded in size, we might not + * guarantee that we can store a full packet before processing it. We must + * implement a very simple state machine remembering the current parsing + * status in order to partially process the packet. + */ + size_t remaining; + u32 send_id; + + /* Next sequence number to be used for requests */ + int seq; + + /* Request being parsed (NULL if none) */ + hc_sock_request_t *cur_request; + + bool async; + hc_sock_map_t *map; +}; + +typedef struct hc_sock_light_s hc_sock_light_t; + +#define TO_HC_SOCK_LIGHT(s) (hc_sock_light_t *)(s) + +hc_sock_request_t *hc_sock_request_create(int seq, hc_data_t *data, + HC_PARSE parse); + +void hc_sock_light_request_free(hc_sock_request_t *request); + +/* + * list was working with all seq set to 0, but it seems hicnLightControl uses + * 1, and replies with the same seqno + */ +#define HICN_CTRL_SEND_SEQ_INIT 1 +#define HICN_CTRL_RECV_SEQ_INIT 1 + +#define MAX(x, y) ((x > y) ? x : y) + +static const struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT; + +#endif /* HICNCTRL_HICN_LIGHT_COMMON */ diff --git a/ctrl/libhicnctrl/src/modules/hicn_light_ng_api.c b/ctrl/libhicnctrl/src/modules/hicn_light_ng_api.c new file mode 100644 index 000000000..a58ee909e --- /dev/null +++ b/ctrl/libhicnctrl/src/modules/hicn_light_ng_api.c @@ -0,0 +1,3111 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file api.c + * \brief Implementation of hICN control library API + */ + +#include <assert.h> // assert +#include <fcntl.h> // fcntl +#include <stdbool.h> +#include <stdio.h> // snprintf +#include <string.h> // memmove, strcasecmp +#include <sys/socket.h> // socket +#include <sys/types.h> // getpid +#include <unistd.h> // close, fcntl +#include <unistd.h> // getpid + +#include "api_private.h" +#ifdef __linux__ +#include <sys/syscall.h> +#define gettid() syscall(SYS_gettid) +#endif /* __linux__ */ +#include <hicn/ctrl/hicn-light-ng.h> +#include <strings.h> + +#include "hicn_light_common.h" +#include <hicn/util/sstrncpy.h> + +#pragma GCC diagnostic ignored "-Warray-bounds" + +#if 0 +#ifdef __APPLE__ +#define RANDBYTE() (u8)(arc4random() & 0xFF) +#else +#define RANDBYTE() (u8)(random() & 0xFF) +#endif +#endif +#define RANDBYTE() (u8)(rand() & 0xFF) + +/** + * \brief Defines the default size for the allocated data arrays holding the + * results of API calls. + * + * This size should not be too small to avoid wasting memoyy, but also not too + * big to avoid unnecessary realloc's. Later on this size is doubled at each + * reallocation. + */ +#define DEFAULT_SIZE_LOG 3 + +#define connection_state_to_face_state(x) ((face_state_t)(x)) +#define face_state_to_connection_state(x) ((hc_connection_state_t)(x)) + +/****************************************************************************** + * Message helper types and aliases + ******************************************************************************/ + +#define foreach_hc_command \ + _(connection_add) \ + _(connection_remove) \ + _(connection_list) \ + _(listener_add) \ + _(listener_remove) \ + _(listener_list) \ + _(route_add) \ + _(route_remove) \ + _(route_list) \ + _(cache_set_store) \ + _(cache_set_serve) \ + _(cache_clear) \ + _(cache_list) \ + _(strategy_set) \ + _(strategy_add_local_prefix) \ + _(wldr_set) \ + _(punting_add) \ + _(mapme_activator) \ + _(mapme_timing) \ + _(subscription_add) \ + _(subscription_remove) + +const char *command_type_str[] = { +#define _(l, u) [COMMAND_TYPE_##u] = STRINGIZE(u), + foreach_command_type +#undef _ +}; + +typedef cmd_header_t hc_msg_header_t; + +typedef union { +#define _(x) cmd_##x##_t x; + foreach_hc_command +#undef _ +} hc_msg_payload_t; + +typedef struct hc_msg_s { + hc_msg_header_t hdr; + hc_msg_payload_t payload; +} hc_msg_t; + +/****************************************************************************** + * Control socket + ******************************************************************************/ + +#define AVAILABLE(s) ((s)->woff - (s)->roff) +#define DEFAULT_SOCK_RECV_TIMEOUT_MS 100 + +/** + * \brief Parse a connection URL into a sockaddr + * \param [in] url - URL + * \param [out] sa - Resulting struct sockaddr, expected zero'ed. + * \return 0 if parsing succeeded, a negative error value otherwise. + */ +static int _hcng_sock_light_parse_url(const char *url, struct sockaddr *sa) { + /* FIXME URL parsing is currently not implemented */ + assert(!url); + +#ifdef __linux__ + srand(time(NULL) ^ getpid() ^ gettid()); +#else + srand((unsigned int)(time(NULL) ^ getpid())); +#endif /* __linux__ */ + + /* + * A temporary solution is to inspect the sa_family fields of the passed in + * sockaddr, which defaults to AF_UNSPEC (0) and thus creates an IPv4/TCP + * connection to localhost. + */ + switch (sa->sa_family) { + case AF_UNSPEC: + case AF_INET: { + struct sockaddr_in *sai = (struct sockaddr_in *)sa; + sai->sin_family = AF_INET; + sai->sin_port = htons(PORT); + sai->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + break; + } + case AF_INET6: { + struct sockaddr_in6 *sai6 = (struct sockaddr_in6 *)sa; + sai6->sin6_family = AF_INET6; + sai6->sin6_port = htons(PORT); + sai6->sin6_addr = loopback_addr; + break; + } + default: + return -1; + } + + return 0; +} + +static int _hcng_sock_light_reset(hc_sock_t *socket) { + hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); + s->roff = s->woff = 0; + s->remaining = 0; + return 0; +} + +void _hcng_sock_light_free(hc_sock_t *socket) { + hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); + hc_sock_request_t **request_array = NULL; + int n = hc_sock_map_get_value_array(s->map, &request_array); + if (n < 0) { + ERROR("Could not retrieve pending request array for freeing up resources"); + } else { + for (unsigned i = 0; i < n; i++) { + hc_sock_request_t *request = request_array[i]; + if (hc_sock_map_remove(s->map, request->seq, NULL) < 0) + ERROR("[hc_sock_light_process] Error removing request from map"); + hc_sock_light_request_free(request); + } + free(request_array); + } + + hc_sock_map_free(s->map); + if (s->url) free(s->url); + close(s->fd); + free(s); +} + +static void _hcng_sock_increment_woff(hc_sock_t *socket, size_t bytes) { + hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); + s->woff += bytes; +} + +static int _hcng_sock_light_get_next_seq(hc_sock_t *socket) { + hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); + return s->seq++; +} + +static int _hcng_sock_light_set_nonblocking(hc_sock_t *socket) { + hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); + return (fcntl(s->fd, F_SETFL, fcntl(s->fd, F_GETFL) | O_NONBLOCK) < 0); +} + +static int _hcng_sock_light_get_fd(hc_sock_t *socket) { + hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); + return s->fd; +} + +static int _hcng_sock_light_connect(hc_sock_t *socket) { + hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); + struct sockaddr_storage ss; + memset(&ss, 0, sizeof(struct sockaddr_storage)); + + if (_hcng_sock_light_parse_url(s->url, (struct sockaddr *)&ss) < 0) + goto ERR_PARSE; + + size_t size = ss.ss_family == AF_INET ? sizeof(struct sockaddr_in) + : sizeof(struct sockaddr_in6); + if (connect(s->fd, (struct sockaddr *)&ss, (socklen_t)size) < 0) { + perror("connect error"); + goto ERR_CONNECT; + } + return 0; + +ERR_CONNECT: +ERR_PARSE: + return -1; +} + +static int _hcng_sock_light_send(hc_sock_t *socket, hc_msg_t *msg, + size_t msglen, uint32_t seq) { + hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); + int rc; + msg->hdr.seq_num = seq; + rc = (int)send(s->fd, msg, msglen, 0); + if (rc < 0) { + perror("hc_sock_light_send"); + return -1; + } + return 0; +} + +static int _hcng_sock_light_get_available(hc_sock_t *socket, u8 **buffer, + size_t *size) { + hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); + *buffer = s->buf + s->woff; + *size = RECV_BUFLEN - s->woff; + + return 0; +} + +static int _hcng_sock_light_recv(hc_sock_t *socket) { + hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); + int rc; + + /* + * This condition should be ensured to guarantee correct processing of + * messages. With TCP, we need at least a header as we will receive part of + * the stream. With UDP, we need the be able to receive the full datagram, + * otherwise the rest will be lost. + * + * Let's be sure to always be able to receive at least 1 JUMBO_MTU, which + * should be fine for al situations. + */ + assert(RECV_BUFLEN - s->woff > JUMBO_MTU); + + rc = (int)recv(s->fd, s->buf + s->woff, RECV_BUFLEN - s->woff, 0); + if (rc == 0) { + /* Connection has been closed */ + return 0; + } + if (rc < 0) { + /* + * Let's not return 0 which currently means the socket has been closed + */ + if (errno == EWOULDBLOCK) return -1; + if (errno == EINTR) { + WARN("recv has been stopped by signal"); + return -1; + } + perror("hc_sock_light_recv"); + return -1; + } + s->woff += rc; + return rc; +} + +static void _hcng_sock_light_mark_complete(hc_sock_light_t *s, + hc_data_t **pdata) { + hc_data_t *data = s->cur_request->data; + + if (hc_sock_map_remove(s->map, s->cur_request->seq, NULL) < 0) { + ERROR("[hc_sock_light_mark_complete] Error removing request from map"); + } + hc_data_set_complete(data); + if (pdata) *pdata = data; + + /* Free current request */ + hc_sock_light_request_free(s->cur_request); + s->cur_request = NULL; +} + +static int _hcng_sock_light_process_notification(hc_sock_light_t *s, + hc_data_t **pdata) { + /* For now, notifications are not associated to requests */ + assert(!s->cur_request); + + /* + * Assumption: the whole notification data is returned in a single read and we + * immediately parse it. + * + * XXX This is only valid for UDP sockets. + */ + size_t notification_size = AVAILABLE(s); + + *pdata = hc_data_create(0, /* in_element_size, 0 = no parsing */ + notification_size, /* out_element_size */ + NULL); /* complete_cb */ + + /* Copy the packet payload as the single entry in hc_data_t */ + hc_data_push_many(*pdata, s->buf + s->roff, 1); + + return notification_size; +} + +/* + * Notifications have no sequence number and are not linked to any request + */ +static hc_sock_request_t *_hcng_sock_light_get_request(hc_sock_light_t *s, + int seq) { + hc_sock_request_t *request; + /* Retrieve request from sock map */ + if (hc_sock_map_get(s->map, seq, &request) < 0) { + ERROR("[hc_sock_light_process] Error searching for matching request"); + return NULL; + } + if (!request) { + ERROR("[hc_sock_light_process] No request matching sequence number"); + return NULL; + } + return request; +} + +/* + * Return codes: + * 0 success, or not enough data yet to do something + * > 0 : notification type + * -99 invalid buffer data -> flush + */ +static int _hcng_sock_light_process_header(hc_sock_light_t *s, + hc_data_t **pdata) { + int rc; + + /* Check we have at least a header's worth of data, and consume it */ + if (AVAILABLE(s) < sizeof(hc_msg_header_t)) return 0; + + hc_msg_t *msg = (hc_msg_t *)(s->buf + s->roff); + + // INFO("Processing header header %s", command_type_str(msg->hdr.command_id)); + s->roff += sizeof(hc_msg_header_t); + + if (msg->hdr.message_type != NOTIFICATION_LIGHT) { + s->cur_request = _hcng_sock_light_get_request(s, msg->hdr.seq_num); + if (!s->cur_request) return -99; + } + + /* How many elements are we expecting in the reply ? */ + s->remaining = msg->hdr.length; + hc_data_t *request_data; + + switch (msg->hdr.message_type) { + case ACK_LIGHT: + assert(s->remaining == 1); // sic + assert(!pdata); + _hcng_sock_light_mark_complete(s, pdata); + break; + + case NACK_LIGHT: + assert(!pdata); + assert(s->remaining == 1); // sic + request_data = s->cur_request->data; + _hcng_sock_light_mark_complete(s, pdata); + hc_data_set_error(request_data); + break; + + case RESPONSE_LIGHT: + assert(pdata); + + if (s->remaining == 0) { + /* Empty response (i.e. containing 0 elements) */ + _hcng_sock_light_mark_complete(s, pdata); + return 0; + } + + /* Make room in hc_data_t... to avoid multiple calls */ + rc = hc_data_ensure_available(s->cur_request->data, s->remaining); + if (rc < 0) { + ERROR("[hc_sock_light_process] Error in hc_data_ensure_available"); + return -99; + } + break; + + case NOTIFICATION_LIGHT: { + assert(pdata); + assert(s->remaining == 0); + + /* This returns the notification size */ + size_t notification_size = + _hcng_sock_light_process_notification(s, pdata); + s->roff += notification_size; + return msg->hdr.command_id; + } + + default: + ERROR("[hc_sock_light_process] Invalid response received"); + return -99; + } + + return 0; +} + +static int _hcng_sock_light_process_payload(hc_sock_light_t *s, + hc_data_t **pdata) { + int err = 0; + int rc; + + hc_data_t *data = s->cur_request->data; + + /* We only process full elements (size is stored in data) */ + size_t num_chunks = AVAILABLE(s) / data->in_element_size; + + /* Check whether we have enough data to process */ + if (num_chunks == 0) return 0; + + /* Safeguard: assert(num_chunks < s->remaining); */ + if (num_chunks > s->remaining) { + WARN( + "[_hcng_sock_light_process_payload] Unexpected num_chunks > " + "s->remaining"); + num_chunks = s->remaining; + } + + if (!s->cur_request->parse) { + /* If we don't need to parse results, then we can directly push + * all of them into the result data structure */ + hc_data_push_many(data, s->buf + s->roff, num_chunks); + } else { + /* Iterate on chunks of data */ + for (int i = 0; i < num_chunks; i++) { + /* Get storage offset in hc_data_t */ + u8 *dst = hc_data_get_next(data); + if (!dst) { + ERROR("[hc_sock_light_process] Error in hc_data_get_next"); + err = -2; + break; + } + + /* Parse element #i */ + rc = s->cur_request->parse(s->buf + s->roff + i * data->in_element_size, + dst); + if (rc < 0) { + ERROR("[hc_sock_light_process] Error in parse"); + err = -1; + /* In this case we let the loop complete to collect other results */ + } + data->size++; + } + } + + s->roff += num_chunks * data->in_element_size; + + /* + * If we are not expecting any more data, mark the reply as complete + */ + s->remaining -= num_chunks; + if (s->remaining == 0) _hcng_sock_light_mark_complete(s, pdata); + + return err; +} + +/* + * Process messages as they are received in the ring buffer. There can be + * interleaved queries and replies (they are identified by sequence number), + * and the assumption is that a reply can arrive over mutiple packets (in + * other terms, it is possible that not all data from the reply is available + * in the buffer at a given time). However, we assume that a full query is + * received at once. + */ +static int _hcng_sock_light_process(hc_sock_t *socket, hc_data_t **data) { + hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); + int rc = 0; + + /* + * We loop consuming messages until there is no more data in the buffer, + * or that we can find an entire message. Messages are received + * sequentially, and we keep track of incomplete requests in s->cur_request. + */ + while (AVAILABLE(s) > 0) { + if (!s->cur_request) { + rc = _hcng_sock_light_process_header(s, data); + } else { + rc = _hcng_sock_light_process_payload(s, data); + } + if (rc < 0) break; + } + + if ((rc == -99) || (s->roff == s->woff)) { + /* Flush buffer */ + s->woff = 0; + } else { + /* Clean up read data from buffer */ + memmove(s->buf, s->buf + s->roff, AVAILABLE(s)); + s->woff -= s->roff; + } + s->roff = 0; + + return rc; +} + +static int _hcng_sock_light_callback(hc_sock_t *socket, hc_data_t **pdata) { + hc_data_t *data = NULL; + int rc = 0; + + for (;;) { + int n = _hcng_sock_light_recv(socket); + if (n == 0) goto ERR_EOF; + if (n < 0) { + switch (errno) { + case ECONNRESET: + case ENODEV: + /* Forwarder restarted */ + WARN("Forwarder likely restarted: not (yet) implemented"); + goto ERR; + case EWOULDBLOCK: + // DEBUG("Would block... stop reading from socket"); + goto END; + case EINTR: + WARN("callback has been stopped by signal"); + goto ERR; + default: + perror("hc_sock_light_callback"); + goto ERR; + } + } + rc = _hcng_sock_light_process(socket, &data); + if (rc < 0) goto ERR; + if (rc > 0) // i.e. rc = notification type + goto END; + } +END: + if (pdata) + *pdata = data; + else + hc_data_free(data); + return rc; + +ERR: + hc_data_free(data); +ERR_EOF: + return -1; +} + +/****************************************************************************** + * Command-specific structures and functions + ******************************************************************************/ + +typedef int (*HC_PARSE)(const u8 *, u8 *); + +typedef struct { + hc_action_t cmd; + command_type_t cmd_id; + size_t size_in; + size_t size_out; + HC_PARSE parse; +} hc_command_params_t; + +typedef struct hc_result_s { + hc_msg_t msg; + hc_command_params_t params; + bool async; + bool success; +} hc_result_t; + +int _hcng_sock_prepare_send(hc_sock_t *socket, hc_result_t *result, + data_callback_t complete_cb, + void *complete_cb_data) { + hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); + + // Prepare data + hc_data_t *data = + hc_data_create(result->params.size_in, result->params.size_out, NULL); + if (!data) { + ERROR("[_hcng_execute_command] Could not create data storage"); + goto ERR_DATA; + } + hc_data_set_callback(data, complete_cb, complete_cb_data); + + // Update the sequence number + int seq = _hcng_sock_light_get_next_seq(socket); + result->msg.hdr.seq_num = seq; // Like in _hcng_sock_light_send + + // Create state used to process the request + hc_sock_request_t *request = NULL; + request = hc_sock_request_create(seq, data, result->params.parse); + if (!request) { + ERROR("[_hcng_execute_command] Could not create request state"); + goto ERR_REQUEST; + } + + // Add state to map + if (hc_sock_map_add(s->map, seq, request) < 0) { + ERROR("[_hcng_execute_command] Error adding request state to map"); + goto ERR_MAP; + } + + return sizeof(result->msg); + +ERR_MAP: + hc_sock_light_request_free(request); +ERR_REQUEST: + hc_data_free(data); +ERR_DATA: + return -99; +} + +int _hcng_sock_set_recv_timeout_ms(hc_sock_t *socket, long timeout_ms) { + hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); + + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = timeout_ms * 1000; // Convert ms into us + if (setsockopt(s->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { + perror("setsockopt"); + return -1; + } + + return 0; +} + +static int _hcng_execute_command(hc_sock_t *socket, hc_msg_t *msg, + size_t msg_len, hc_command_params_t *params, + hc_data_t **pdata, bool async) { + hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); + int ret; + if (async) assert(!pdata); + + /* Sanity check */ + switch (params->cmd) { + case ACTION_CREATE: + assert(params->size_in != 0); /* payload repeated */ + assert(params->size_out == 0); + assert(params->parse == NULL); + break; + case ACTION_DELETE: + assert(params->size_in != 0); /* payload repeated */ + assert(params->size_out == 0); + assert(params->parse == NULL); + break; + case ACTION_LIST: + assert(params->size_in != 0); + assert(params->size_out != 0); + assert(params->parse != NULL); + break; + case ACTION_SET: + case ACTION_SERVE: + case ACTION_STORE: + case ACTION_UPDATE: + assert(params->size_in != 0); + assert(params->size_out == 0); + assert(params->parse == NULL); + break; + case ACTION_CLEAR: + assert(params->size_in == 0); + assert(params->size_out == 0); + assert(params->parse == NULL); + break; + default: + return -1; + } + + // hc_sock_light_reset(s); + + /* XXX data will at least store the result (complete) */ + hc_data_t *data = hc_data_create(params->size_in, params->size_out, NULL); + if (!data) { + ERROR("[_hcng_execute_command] Could not create data storage"); + goto ERR_DATA; + } + + int seq = _hcng_sock_light_get_next_seq(socket); + + /* Create state used to process the request */ + hc_sock_request_t *request = NULL; + request = hc_sock_request_create(seq, data, params->parse); + if (!request) { + ERROR("[_hcng_execute_command] Could not create request state"); + goto ERR_REQUEST; + } + + /* Add state to map */ + if (hc_sock_map_add(s->map, seq, request) < 0) { + ERROR("[_hcng_execute_command] Error adding request state to map"); + goto ERR_MAP; + } + + if (_hcng_sock_light_send(socket, msg, msg_len, seq) < 0) { + ERROR("[_hcng_execute_command] Error sending message"); + goto ERR_PROCESS; + } + + if (async) return 0; + + /* + * Dangerous zone, we might be doing blocking operations on a non-blocking + * UDP socket + */ + int retries = 0; + while (!data->complete) { + /* + * As the socket is non blocking it might happen that we need to read + * several times before success... + */ + int n = _hcng_sock_light_recv(socket); + if (n == 0) goto ERR_EOF; + if (n < 0) { + if ((errno == EWOULDBLOCK) && (retries < 10)) { /* Max 500ms */ + DEBUG("read = EWOULDBLOCK... sleeping for 50ms (max 500ms)"); + usleep(50000); /* 50ms */ + retries++; + continue; + } + break; + } + int rc = _hcng_sock_light_process(socket, pdata); + switch (rc) { + case 0: + case -1: + break; + case -99: + ERROR("[_hcng_execute_command] Error processing socket results"); + goto ERR; + default: + ERROR("[_hcng_execute_command] Unexpected return value"); + goto ERR; + } + } + +ERR_EOF: + ret = data->ret; + if (!data->complete) return -1; + if (!pdata) hc_data_free(data); + + return ret; + +ERR_PROCESS: +ERR_MAP: + hc_sock_light_request_free(request); +ERR: +ERR_REQUEST: + hc_data_free(data); +ERR_DATA: + return -99; +} + +/*----------------------------------------------------------------------------* + * Listeners + *----------------------------------------------------------------------------*/ + +/* LISTENER CREATE */ + +static hc_result_t *_listener_create_serialize(hc_sock_t *s, + hc_listener_t *listener, + bool async) { + hc_result_t *res = malloc(sizeof(*res)); + char listener_s[MAXSZ_HC_LISTENER]; + int rc = hc_listener_snprintf(listener_s, MAXSZ_HC_LISTENER, listener); + if (rc >= MAXSZ_HC_LISTENER) + WARN("[_hcng_listener_create] Unexpected truncation of listener string"); + DEBUG("[_hcng_listener_create] listener=%s async=%s", listener_s, + BOOLSTR(async)); + + if (hc_listener_validate(listener) < 0) { + res->success = false; + return res; + } + + msg_listener_add_t msg = {.header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_LISTENER_ADD, + .length = 1, + .seq_num = 0, + }, + .payload = { + .address = listener->local_addr, + .port = htons(listener->local_port), + .family = listener->family, + .type = listener->type, + }}; + + rc = snprintf(msg.payload.symbolic, SYMBOLIC_NAME_LEN, "%s", listener->name); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[_hc_listener_create] Unexpected truncation of symbolic name " + "string"); + + rc = snprintf(msg.payload.interface_name, INTERFACE_LEN, "%s", + listener->interface_name); + if (rc >= INTERFACE_LEN) + WARN( + "[_hc_listener_create] Unexpected truncation of interface name " + "string"); + + hc_command_params_t params = { + .cmd = ACTION_CREATE, + .cmd_id = COMMAND_TYPE_LISTENER_ADD, + .size_in = sizeof(cmd_listener_add_t), + .size_out = 0, + .parse = NULL, + }; + + *res = (hc_result_t){ + .msg = + (hc_msg_t){ + .hdr = msg.header, + .payload.listener_add = msg.payload, + }, + .params = params, + .async = async, + .success = true, + }; + return res; +} + +static hc_result_t *_hcng_listener_create_conf(hc_sock_t *s, + hc_listener_t *listener) { + return _listener_create_serialize(s, listener, false); +} + +static int _hcng_listener_create_internal(hc_sock_t *socket, + hc_listener_t *listener, bool async) { + hc_result_t *result = _listener_create_serialize(socket, listener, async); + + int ret = INPUT_ERROR; + if (result->success) { + ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg, + sizeof(result->msg), &result->params, NULL, + result->async); + } + + free(result); + DEBUG("[_hcng_listener_create] done or error"); + return ret; +} + +static int _hcng_listener_create(hc_sock_t *s, hc_listener_t *listener) { + DEBUG("[_hcng_listener_create]"); + return _hcng_listener_create_internal(s, listener, false); +} + +static int _hcng_listener_create_async(hc_sock_t *s, hc_listener_t *listener) { + DEBUG("[_hcng_listener_create_async]"); + return _hcng_listener_create_internal(s, listener, true); +} + +/* LISTENER PARSE */ + +static int hc_listener_parse(void *in, hc_listener_t *listener) { + int rc; + cmd_listener_list_item_t *item = (cmd_listener_list_item_t *)in; + + if (!IS_VALID_ID(item->id)) { + ERROR("[hc_listener_parse] Invalid id received"); + return -1; + } + + *listener = (hc_listener_t){ + .id = item->id, + .type = item->type, + .family = item->family, + .local_addr = UNION_CAST(item->address, ip_address_t), + .local_port = ntohs(item->port), + }; + rc = snprintf(listener->name, SYMBOLIC_NAME_LEN, "%s", item->name); + if (rc >= SYMBOLIC_NAME_LEN) + WARN("[hc_listener_parse] Unexpected truncation of symbolic name string"); + rc = snprintf(listener->interface_name, INTERFACE_LEN, "%s", + item->interface_name); + if (rc >= INTERFACE_LEN) + WARN("[hc_listener_parse] Unexpected truncation of interface name string"); + + if (hc_listener_validate(listener) < 0) return -1; + return 0; +} + +/* LISTENER LIST */ + +static hc_result_t *_hcng_listener_list_serialize(hc_sock_t *socket, + hc_data_t **pdata, + bool async) { + hc_result_t *res = malloc(sizeof(*res)); + DEBUG("[hc_listener_list] async=%s", BOOLSTR(async)); + + msg_listener_list_t msg = {.header = { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_LISTENER_LIST, + .length = 0, + .seq_num = 0, + }}; + + hc_command_params_t params = { + .cmd = ACTION_LIST, + .cmd_id = COMMAND_TYPE_LISTENER_LIST, + .size_in = sizeof(cmd_listener_list_item_t), + .size_out = sizeof(hc_listener_t), + .parse = (HC_PARSE)hc_listener_parse, + }; + + *res = (hc_result_t){ + .msg = + (hc_msg_t){ + .hdr = msg.header, + .payload.listener_list = msg.payload, + }, + .params = params, + .async = async, + .success = true, + }; + return res; +} + +static hc_result_t *_hcng_listener_list_conf(hc_sock_t *s, hc_data_t **pdata) { + return _hcng_listener_list_serialize(s, pdata, false); +} + +static int _hcng_listener_list_internal(hc_sock_t *socket, hc_data_t **pdata, + bool async) { + hc_result_t *result = _hcng_listener_list_serialize(socket, pdata, async); + + int ret = INPUT_ERROR; + if (result->success) { + ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg, + sizeof(result->msg), &result->params, pdata, + result->async); + } + + hc_result_free(result); + DEBUG("[_hcng_listener_list] done or error"); + return ret; +} + +static int _hcng_listener_list(hc_sock_t *s, hc_data_t **pdata) { + DEBUG("[_hcng_listener_list]"); + return _hcng_listener_list_internal(s, pdata, false); +} + +static int _hcng_listener_list_async(hc_sock_t *s, hc_data_t **pdata) { + DEBUG("[_hcng_listener_list_as-nc]"); + return _hcng_listener_list_internal(s, pdata, true); +} + +/* LISTENER GET */ + +static int _hcng_listener_get(hc_sock_t *socket, hc_listener_t *listener, + hc_listener_t **listener_found) { + hc_data_t *listeners; + hc_listener_t *found; + + char listener_s[MAXSZ_HC_LISTENER]; + int rc = hc_listener_snprintf(listener_s, MAXSZ_HC_LISTENER, listener); + if (rc >= MAXSZ_HC_LISTENER) + WARN("[hc_listener_get] Unexpected truncation of listener string"); + DEBUG("[hc_listener_get] listener=%s", listener_s); + + if (_hcng_listener_list(socket, &listeners) < 0) return -1; + + /* Test */ + if (hc_listener_find(listeners, listener, &found) < 0) { + hc_data_free(listeners); + return -1; + } + + if (found) { + *listener_found = malloc(sizeof(hc_listener_t)); + if (!*listener_found) return -1; + **listener_found = *found; + } else { + *listener_found = NULL; + } + + hc_data_free(listeners); + + return 0; +} + +/* LISTENER DELETE */ + +static int _hcng_listener_delete_internal(hc_sock_t *socket, + hc_listener_t *listener, bool async) { + char listener_s[MAXSZ_HC_LISTENER]; + int rc = hc_listener_snprintf(listener_s, MAXSZ_HC_LISTENER, listener); + if (rc >= MAXSZ_HC_LISTENER) + WARN("[_hcng_listener_delete] Unexpected truncation of listener string"); + DEBUG("[_hcng_listener_delete] listener=%s async=%s", listener_s, + BOOLSTR(async)); + + msg_listener_remove_t msg = {.header = { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_LISTENER_REMOVE, + .length = 1, + .seq_num = 0, + }}; + + if (listener->id) { + rc = snprintf(msg.payload.symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%d", + listener->id); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[_hc_listener_delete] Unexpected truncation of symbolic name " + "string"); + } else if (*listener->name) { + rc = snprintf(msg.payload.symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%s", + listener->name); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[_hc_listener_delete] Unexpected truncation of symbolic name " + "string"); + } else { + hc_listener_t *listener_found; + if (_hcng_listener_get(socket, listener, &listener_found) < 0) return -1; + if (!listener_found) return -1; + rc = snprintf(msg.payload.symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%d", + listener_found->id); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[_hc_listener_delete] Unexpected truncation of symbolic name " + "string"); + free(listener_found); + } + + hc_command_params_t params = { + .cmd = ACTION_DELETE, + .cmd_id = COMMAND_TYPE_LISTENER_REMOVE, + .size_in = sizeof(cmd_listener_remove_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, async); +} + +static int _hcng_listener_delete(hc_sock_t *s, hc_listener_t *listener) { + return _hcng_listener_delete_internal(s, listener, false); +} + +static int _hcng_listener_delete_async(hc_sock_t *s, hc_listener_t *listener) { + return _hcng_listener_delete_internal(s, listener, true); +} + +/*----------------------------------------------------------------------------* + * CONNECTION + *----------------------------------------------------------------------------*/ + +/* CONNECTION CREATE */ + +static hc_result_t *_connection_create_serialize(hc_sock_t *socket, + hc_connection_t *connection, + bool async) { + hc_result_t *res = malloc(sizeof(*res)); + char connection_s[MAXSZ_HC_CONNECTION]; + int rc = + hc_connection_snprintf(connection_s, MAXSZ_HC_CONNECTION, connection); + if (rc >= MAXSZ_HC_CONNECTION) + WARN( + "[_hcng_connection_create] Unexpected truncation of connection " + "string"); + DEBUG("[_hcng_connection_create] connection=%s async=%s", connection_s, + BOOLSTR(async)); + + if (hc_connection_validate(connection) < 0) { + res->success = false; + return res; + } + + msg_connection_add_t msg = {.header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_CONNECTION_ADD, + .length = 1, + .seq_num = 0, + }, + .payload = { + .remote_ip = connection->remote_addr, + .local_ip = connection->local_addr, + .remote_port = htons(connection->remote_port), + .local_port = htons(connection->local_port), + .family = connection->family, + .type = connection->type, + .admin_state = connection->admin_state, +#ifdef WITH_POLICY + .priority = connection->priority, + .tags = connection->tags, +#endif /* WITH_POLICY */ + }}; + rc = + snprintf(msg.payload.symbolic, SYMBOLIC_NAME_LEN, "%s", connection->name); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[_hc_connection_create] Unexpected truncation of symbolic name " + "string"); + // snprintf(msg.payload.interface_name, INTERFACE_NAME_LEN, "%s", + // connection->interface_name); + + hc_command_params_t params = { + .cmd = ACTION_CREATE, + .cmd_id = COMMAND_TYPE_CONNECTION_ADD, + .size_in = sizeof(cmd_connection_add_t), + .size_out = 0, + .parse = NULL, + }; + + *res = (hc_result_t){ + .msg = + (hc_msg_t){ + .hdr = msg.header, + .payload.connection_add = msg.payload, + }, + .params = params, + .async = async, + .success = true, + }; + return res; +} + +static hc_result_t *_hcng_connection_create_conf(hc_sock_t *s, + hc_connection_t *connection) { + return _connection_create_serialize(s, connection, false); +} + +static int _hcng_connection_create_internal(hc_sock_t *socket, + hc_connection_t *connection, + bool async) { + hc_result_t *result = _connection_create_serialize(socket, connection, async); + + int ret = INPUT_ERROR; + if (result->success) { + ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg, + sizeof(result->msg), &result->params, NULL, + result->async); + } + + hc_result_free(result); + DEBUG("[_hcng_connection_create] done or error"); + return ret; +} + +static int _hcng_connection_create(hc_sock_t *s, hc_connection_t *connection) { + DEBUG("[_hcng_connection_create]"); + return _hcng_connection_create_internal(s, connection, false); +} + +static int _hcng_connection_create_async(hc_sock_t *s, + hc_connection_t *connection) { + DEBUG("[_hcng_connection_create_async]"); + return _hcng_connection_create_internal(s, connection, true); +} + +/* CONNECTION PARSE */ + +static int hc_connection_parse(void *in, hc_connection_t *connection) { + int rc; + cmd_connection_list_item_t *item = (cmd_connection_list_item_t *)in; + + if (!IS_VALID_ID(item->id)) { + ERROR("[hc_connection_parse] Invalid id received"); + return -1; + } + + *connection = (hc_connection_t){ + .id = item->id, + .type = item->type, + .family = item->family, + .local_addr = item->local_addr, + .local_port = ntohs(item->local_port), + .remote_addr = item->remote_addr, + .remote_port = ntohs(item->remote_port), + .admin_state = item->admin_state, +#ifdef WITH_POLICY + .priority = item->priority, + .tags = item->tags, +#endif /* WITH_POLICY */ + .state = item->state, + }; + rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "%s", item->name); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[hc_connection_parse] Unexpected truncation of symbolic name " + "string"); + rc = snprintf(connection->interface_name, INTERFACE_LEN, "%s", + item->interface_name); + if (rc >= INTERFACE_LEN) + WARN( + "[hc_connection_parse] Unexpected truncation of interface name " + "string"); + + if (hc_connection_validate(connection) < 0) return -1; + return 0; +} + +/* CONNECTION LIST */ + +static int _hcng_connection_list_internal(hc_sock_t *socket, hc_data_t **pdata, + bool async) { + DEBUG("[hc_connection_list] async=%s", BOOLSTR(async)); + + msg_connection_list_t msg = {.header = { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_CONNECTION_LIST, + .length = 0, + .seq_num = 0, + }}; + + hc_command_params_t params = { + .cmd = ACTION_LIST, + .cmd_id = COMMAND_TYPE_CONNECTION_LIST, + .size_in = sizeof(cmd_connection_list_item_t), + .size_out = sizeof(hc_connection_t), + .parse = (HC_PARSE)hc_connection_parse, + }; + + int ret = _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), + ¶ms, pdata, async); + + DEBUG("[hc_connection_list] done or error"); + return ret; +} + +static int _hcng_connection_list(hc_sock_t *s, hc_data_t **pdata) { + DEBUG("[hc_connection_list]"); + return _hcng_connection_list_internal(s, pdata, false); +} + +static int _hcng_connection_list_async(hc_sock_t *s, hc_data_t **pdata) { + DEBUG("[hc_connection_list_async]"); + return _hcng_connection_list_internal(s, pdata, true); +} + +/* CONNECTION GET */ + +static int _hcng_connection_get(hc_sock_t *socket, hc_connection_t *connection, + hc_connection_t **connection_found) { + hc_data_t *connections; + hc_connection_t *found; + + char connection_s[MAXSZ_HC_CONNECTION]; + int rc = + hc_connection_snprintf(connection_s, MAXSZ_HC_CONNECTION, connection); + if (rc >= MAXSZ_HC_CONNECTION) + WARN("[hc_connection_get] Unexpected truncation of connection string"); + DEBUG("[hc_connection_get] connection=%s", connection_s); + + if (_hcng_connection_list(socket, &connections) < 0) return -1; + + /* Test */ + if (hc_connection_find(connections, connection, &found) < 0) { + hc_data_free(connections); + return -1; + } + + if (found) { + *connection_found = malloc(sizeof(hc_connection_t)); + if (!*connection_found) return -1; + **connection_found = *found; + } else { + *connection_found = NULL; + } + + hc_data_free(connections); + + return 0; +} + +/* CONNECTION DELETE */ + +static hc_result_t *_hcng_connection_delete_serialize( + hc_sock_t *socket, hc_connection_t *connection, bool async) { + hc_result_t *res = malloc(sizeof(*res)); + res->success = false; + + char connection_s[MAXSZ_HC_CONNECTION]; + int rc = + hc_connection_snprintf(connection_s, MAXSZ_HC_CONNECTION, connection); + if (rc >= MAXSZ_HC_CONNECTION) + WARN( + "[_hcng_connection_delete] Unexpected truncation of connection " + "string"); + DEBUG("[_hcng_connection_delete] connection=%s async=%s", connection_s, + BOOLSTR(async)); + + msg_connection_remove_t msg = { + .header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_CONNECTION_REMOVE, + .length = 1, + .seq_num = 0, + }, + }; + + if (connection->id) { + rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d", + connection->id); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[_hc_connection_delete] Unexpected truncation of symbolic name " + "string"); + } else if (*connection->name) { + rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s", + connection->name); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[_hc_connection_delete] Unexpected truncation of symbolic name " + "string"); + } else { + hc_connection_t *connection_found; + if (hc_connection_get(socket, connection, &connection_found) < 0) + return res; + if (!connection_found) return res; + rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d", + connection_found->id); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[_hc_connection_delete] Unexpected truncation of symbolic name " + "string"); + free(connection_found); + } + + hc_command_params_t params = { + .cmd = ACTION_DELETE, + .cmd_id = COMMAND_TYPE_CONNECTION_REMOVE, + .size_in = sizeof(cmd_connection_remove_t), + .size_out = 0, + .parse = NULL, + }; + + *res = (hc_result_t){ + .msg = + (hc_msg_t){ + .hdr = msg.header, + .payload.connection_remove = msg.payload, + }, + .params = params, + .async = async, + .success = true, + }; + return res; +} + +static hc_result_t *_hcng_connection_delete_conf(hc_sock_t *s, + hc_connection_t *connection) { + return _hcng_connection_delete_serialize(s, connection, false); +} + +static int _hcng_connection_delete_internal(hc_sock_t *socket, + hc_connection_t *connection, + bool async) { + hc_result_t *result = + _hcng_connection_delete_serialize(socket, connection, async); + + int ret = INPUT_ERROR; + if (result->success) { + ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg, + sizeof(result->msg), &result->params, NULL, + result->async); + } + + hc_result_free(result); + return ret; +} + +static int _hcng_connection_delete(hc_sock_t *s, hc_connection_t *connection) { + return _hcng_connection_delete_internal(s, connection, false); +} + +static int _hcng_connection_delete_async(hc_sock_t *s, + hc_connection_t *connection) { + return _hcng_connection_delete_internal(s, connection, true); +} + +/* CONNECTION UPDATE */ + +static int _hcng_connection_update_by_id(hc_sock_t *s, int hc_connection_id, + hc_connection_t *connection) { + // Not implemented + return -1; +} + +static int _hcng_connection_update(hc_sock_t *s, + hc_connection_t *connection_current, + hc_connection_t *connection_updated) { + // Not implemented + return -1; +} + +/* CONNECTION SET ADMIN STATE */ + +static int _hcng_connection_set_admin_state_internal( + hc_sock_t *socket, const char *conn_id_or_name, face_state_t state, + bool async) { + 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)); + + struct { + cmd_header_t hdr; + cmd_connection_set_admin_state_t payload; + } msg = { + .hdr = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_CONNECTION_SET_ADMIN_STATE, + .length = 1, + .seq_num = 0, + }, + .payload = + { + .admin_state = state, + }, + }; + rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s", + conn_id_or_name); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[_hc_connection_set_admin_state] Unexpected truncation of symbolic " + "name string"); + + hc_command_params_t params = { + .cmd = ACTION_SET, + .cmd_id = COMMAND_TYPE_CONNECTION_SET_ADMIN_STATE, + .size_in = sizeof(cmd_connection_set_admin_state_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, async); +} + +static int _hcng_connection_set_admin_state(hc_sock_t *s, + const char *conn_id_or_name, + face_state_t state) { + return _hcng_connection_set_admin_state_internal(s, conn_id_or_name, state, + false); +} + +static int _hcng_connection_set_admin_state_async(hc_sock_t *s, + const char *conn_id_or_name, + face_state_t state) { + return _hcng_connection_set_admin_state_internal(s, conn_id_or_name, state, + true); +} + +#ifdef WITH_POLICY + +static int _hcng_connection_set_priority_internal(hc_sock_t *socket, + const char *conn_id_or_name, + uint32_t priority, + bool async) { + int rc; + DEBUG( + "[hc_connection_set_priority] connection_id/name=%s priority=%d " + "async=%s", + conn_id_or_name, priority, BOOLSTR(async)); + struct { + cmd_header_t hdr; + cmd_connection_set_priority_t payload; + } msg = { + .hdr = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_CONNECTION_SET_PRIORITY, + .length = 1, + .seq_num = 0, + }, + .payload = + { + .priority = priority, + }, + }; + rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s", + conn_id_or_name); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[_hc_connection_set_priority] Unexpected truncation of symbolic " + "name " + "string"); + + hc_command_params_t params = { + .cmd = ACTION_SET, + .cmd_id = COMMAND_TYPE_CONNECTION_SET_PRIORITY, + .size_in = sizeof(cmd_connection_set_priority_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, async); +} + +static int _hcng_connection_set_priority(hc_sock_t *s, + const char *conn_id_or_name, + uint32_t priority) { + return _hcng_connection_set_priority_internal(s, conn_id_or_name, priority, + false); +} + +static int _hcng_connection_set_priority_async(hc_sock_t *s, + const char *conn_id_or_name, + uint32_t priority) { + return _hcng_connection_set_priority_internal(s, conn_id_or_name, priority, + true); +} + +#endif // WITH_POLICY + +static int _hcng_connection_set_tags_internal(hc_sock_t *s, + const char *conn_id_or_name, + policy_tags_t tags, bool async) { + int rc; + DEBUG("[hc_connection_set_tags] connection_id/name=%s tags=%d async=%s", + conn_id_or_name, tags, BOOLSTR(async)); + struct { + cmd_header_t hdr; + cmd_connection_set_tags_t payload; + } msg = { + .hdr = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_CONNECTION_SET_TAGS, + .length = 1, + .seq_num = 0, + }, + .payload = + { + .tags = tags, + }, + }; + rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s", + conn_id_or_name); + if (rc >= SYMBOLIC_NAME_LEN) + WARN( + "[_hc_connection_set_tags] Unexpected truncation of symbolic name " + "string"); + + hc_command_params_t params = { + .cmd = ACTION_SET, + .cmd_id = COMMAND_TYPE_CONNECTION_SET_TAGS, + .size_in = sizeof(cmd_connection_set_tags_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(s, (hc_msg_t *)&msg, sizeof(msg), ¶ms, NULL, + async); +} + +static int _hcng_connection_set_tags(hc_sock_t *s, const char *conn_id_or_name, + policy_tags_t tags) { + return _hcng_connection_set_tags_internal(s, conn_id_or_name, tags, false); +} + +static int _hcng_connection_set_tags_async(hc_sock_t *s, + const char *conn_id_or_name, + policy_tags_t tags) { + return _hcng_connection_set_tags_internal(s, conn_id_or_name, tags, true); +} + +/*----------------------------------------------------------------------------* + * Routes + *----------------------------------------------------------------------------*/ + +/* ROUTE CREATE */ + +static hc_result_t *_route_create_serialize(hc_sock_t *socket, + hc_route_t *route, bool async) { + hc_result_t *res = malloc(sizeof(*res)); + char route_s[MAXSZ_HC_ROUTE]; + int rc = hc_route_snprintf(route_s, MAXSZ_HC_ROUTE, route); + if (rc >= MAXSZ_HC_ROUTE) + WARN("[_hc_route_create] Unexpected truncation of route string"); + if (rc < 0) + WARN("[_hc_route_create] Error building route string"); + else + DEBUG("[hc_route_create] route=%s async=%s", route_s, BOOLSTR(async)); + + if (hc_route_validate(route) < 0) { + res->success = false; + return res; + } + + msg_route_add_t msg = {.header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_ROUTE_ADD, + .length = 1, + .seq_num = 0, + }, + .payload = { + .address = route->remote_addr, + .cost = route->cost, + .family = route->family, + .len = route->len, + }}; + + /* + * The route commands expects the ID or name as part of the + * symbolic_or_connid attribute. + */ + if (route->name[0] != '\0') { + rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s", + route->name); + } else { + rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d", + route->face_id); + } + + if (rc >= SYMBOLIC_NAME_LEN) + WARN("[_hc_route_create] Unexpected truncation of symbolic name string"); + + hc_command_params_t params = { + .cmd = ACTION_CREATE, + .cmd_id = COMMAND_TYPE_ROUTE_ADD, + .size_in = sizeof(cmd_route_add_t), + .size_out = 0, + .parse = NULL, + }; + + *res = (hc_result_t){ + .msg = + (hc_msg_t){ + .hdr = msg.header, + .payload.route_add = msg.payload, + }, + .params = params, + .async = async, + .success = true, + }; + return res; +} + +static hc_result_t *_hcng_route_create_conf(hc_sock_t *s, hc_route_t *route) { + return _route_create_serialize(s, route, false); +} + +static int _hcng_route_create_internal(hc_sock_t *socket, hc_route_t *route, + bool async) { + hc_result_t *result = _route_create_serialize(socket, route, async); + + int ret = INPUT_ERROR; + if (result->success) { + ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg, + sizeof(result->msg), &result->params, NULL, + result->async); + } + + hc_result_free(result); + return ret; +} + +static int _hcng_route_create(hc_sock_t *s, hc_route_t *route) { + return _hcng_route_create_internal(s, route, false); +} + +static int _hcng_route_create_async(hc_sock_t *s, hc_route_t *route) { + return _hcng_route_create_internal(s, route, true); +} + +/* ROUTE DELETE */ + +static int _hcng_route_delete_internal(hc_sock_t *socket, hc_route_t *route, + bool async) { + char route_s[MAXSZ_HC_ROUTE]; + int rc = hc_route_snprintf(route_s, MAXSZ_HC_ROUTE, route); + if (rc >= MAXSZ_HC_ROUTE) + WARN("[_hc_route_delete] Unexpected truncation of route string"); + DEBUG("[hc_route_delete] route=%s async=%s", route_s, BOOLSTR(async)); + + if (!IS_VALID_FAMILY(route->family)) return -1; + + struct { + cmd_header_t hdr; + cmd_route_remove_t payload; + } msg = {.hdr = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_ROUTE_REMOVE, + .length = 1, + .seq_num = 0, + }, + .payload = { + .address = route->remote_addr, + .family = route->family, + .len = route->len, + }}; + + /* + * The route commands expects the ID or name as part of the + * symbolic_or_connid attribute. + */ + if (route->name[0] != '\0') { + rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s", + route->name); + } else { + rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d", + route->face_id); + } + + hc_command_params_t params = { + .cmd = ACTION_DELETE, + .cmd_id = COMMAND_TYPE_ROUTE_REMOVE, + .size_in = sizeof(cmd_route_remove_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, async); +} + +static int _hcng_route_delete(hc_sock_t *s, hc_route_t *route) { + return _hcng_route_delete_internal(s, route, false); +} + +static int _hcng_route_delete_async(hc_sock_t *s, hc_route_t *route) { + return _hcng_route_delete_internal(s, route, true); +} + +/* ROUTE PARSE */ + +static int hc_route_parse(void *in, hc_route_t *route) { + cmd_route_list_item_t *item = (cmd_route_list_item_t *)in; + + *route = (hc_route_t){ + .name = "", /* This is not reported back */ + .face_id = item->connection_id, + .family = item->family, + .remote_addr = item->address, + .len = item->len, + .cost = item->cost, + }; + + if (hc_route_validate(route) < 0) return -1; + return 0; +} + +/* ROUTE LIST */ + +static int _hcng_route_list_internal(hc_sock_t *socket, hc_data_t **pdata, + bool async) { + // DEBUG("[hc_route_list] async=%s", BOOLSTR(async)); + msg_route_list_t msg = {.header = { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_ROUTE_LIST, + .length = 0, + .seq_num = 0, + }}; + + hc_command_params_t params = { + .cmd = ACTION_LIST, + .cmd_id = COMMAND_TYPE_ROUTE_LIST, + .size_in = sizeof(cmd_route_list_item_t), + .size_out = sizeof(hc_route_t), + .parse = (HC_PARSE)hc_route_parse, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + pdata, async); +} + +static int _hcng_route_list(hc_sock_t *s, hc_data_t **pdata) { + return _hcng_route_list_internal(s, pdata, false); +} + +static int _hcng_route_list_async(hc_sock_t *s) { + return _hcng_route_list_internal(s, NULL, true); +} + +/*----------------------------------------------------------------------------* + * Face + * + * Face support is not directly available in hicn-light, but we can offer such + * an interface through a combination of listeners and connections. The code + * starts with some conversion functions between faces/listeners/connections. + * + * We also need to make sure that there always exist a (single) listener when + *a connection is created, and in the hICN face case, that there is a single + * connection attached to this listener. + * + *----------------------------------------------------------------------------*/ + +/* FACE CREATE */ + +static int _hcng_face_create(hc_sock_t *socket, hc_face_t *face) { + hc_listener_t listener; + hc_listener_t *listener_found; + + hc_connection_t connection; + hc_connection_t *connection_found; + + char face_s[MAXSZ_HC_FACE]; + int rc = hc_face_snprintf(face_s, MAXSZ_HC_FACE, face); + if (rc >= MAXSZ_HC_FACE) + WARN("[hc_face_create] Unexpected truncation of face string"); + DEBUG("[hc_face_create] face=%s", face_s); + + switch (face->face.type) { + case FACE_TYPE_HICN: + case FACE_TYPE_TCP: + case FACE_TYPE_UDP: + if (hc_face_to_connection(face, &connection, true) < 0) { + ERROR("[hc_face_create] Could not convert face to connection."); + return -1; + } + + /* Ensure we have a corresponding local listener */ + if (hc_connection_to_local_listener(&connection, &listener) < 0) { + ERROR("[hc_face_create] Could not convert face to local listener."); + return -1; + } + + if (_hcng_listener_get(socket, &listener, &listener_found) < 0) { + ERROR("[hc_face_create] Could not retrieve listener"); + return -1; + } + + if (!listener_found) { + /* We need to create the listener if it does not exist */ + if (hc_listener_create(socket, &listener) < 0) { + ERROR("[hc_face_create] Could not create listener."); + free(listener_found); + return -1; + } + } else { + free(listener_found); + } + + /* Create corresponding connection */ + if (_hcng_connection_create(socket, &connection) < 0) { + ERROR("[hc_face_create] Could not create connection."); + return -1; + } + + /* + * Once the connection is created, we need to list all connections + * and compare with the current one to find the created face ID. + */ + if (_hcng_connection_get(socket, &connection, &connection_found) < 0) { + ERROR("[hc_face_create] Could not retrieve connection"); + return -1; + } + + if (!connection_found) { + ERROR("[hc_face_create] Could not find newly created connection."); + return -1; + } + + face->id = connection_found->id; + free(connection_found); + + break; + + case FACE_TYPE_HICN_LISTENER: + case FACE_TYPE_TCP_LISTENER: + case FACE_TYPE_UDP_LISTENER: + if (hc_face_to_listener(face, &listener) < 0) { + ERROR("Could not convert face to listener."); + return -1; + } + if (hc_listener_create(socket, &listener) < 0) { + ERROR("[hc_face_create] Could not create listener."); + return -1; + } + break; + default: + ERROR("[hc_face_create] Unknwon face type."); + + return -1; + }; + + return 0; +} + +static int _hcng_face_get(hc_sock_t *socket, hc_face_t *face, + hc_face_t **face_found) { + hc_listener_t listener; + hc_listener_t *listener_found; + + hc_connection_t connection; + hc_connection_t *connection_found; + + char face_s[MAXSZ_HC_FACE]; + int rc = hc_face_snprintf(face_s, MAXSZ_HC_FACE, face); + if (rc >= MAXSZ_HC_FACE) + WARN("[hc_face_get] Unexpected truncation of face string"); + DEBUG("[hc_face_get] face=%s", face_s); + + switch (face->face.type) { + case FACE_TYPE_HICN: + case FACE_TYPE_TCP: + case FACE_TYPE_UDP: + if (hc_face_to_connection(face, &connection, false) < 0) return -1; + if (_hcng_connection_get(socket, &connection, &connection_found) < 0) + return -1; + if (!connection_found) { + *face_found = NULL; + return 0; + } + *face_found = malloc(sizeof(hc_face_t)); + hc_connection_to_face(connection_found, *face_found); + free(connection_found); + break; + + case FACE_TYPE_HICN_LISTENER: + case FACE_TYPE_TCP_LISTENER: + case FACE_TYPE_UDP_LISTENER: + if (hc_face_to_listener(face, &listener) < 0) return -1; + if (_hcng_listener_get(socket, &listener, &listener_found) < 0) return -1; + if (!listener_found) { + *face_found = NULL; + return 0; + } + *face_found = malloc(sizeof(hc_face_t)); + hc_listener_to_face(listener_found, *face_found); + free(listener_found); + break; + + default: + return -1; + } + + return 0; +} + +/* FACE DELETE */ + +static int _hcng_face_delete(hc_sock_t *socket, hc_face_t *face, + uint8_t delete_listener) { + char face_s[MAXSZ_HC_FACE]; + int rc = hc_face_snprintf(face_s, MAXSZ_HC_FACE, face); + if (rc >= MAXSZ_HC_FACE) + WARN("[hc_face_delete] Unexpected truncation of face string"); + DEBUG("[hc_face_delete] face=%s", face_s); + + hc_connection_t connection; + if (hc_face_to_connection(face, &connection, false) < 0) { + ERROR("[hc_face_delete] Could not convert face to connection."); + return -1; + } + + if (_hcng_connection_delete(socket, &connection) < 0) { + ERROR("[hc_face_delete] Error removing connection"); + return -1; + } + + if (!delete_listener) { + return 0; + } + + /* If this is the last connection attached to the listener, remove it */ + + hc_data_t *connections; + hc_listener_t listener = {{0}}; + + /* + * Ensure we have a corresponding local listener + * NOTE: hc_face_to_listener is not appropriate + */ + if (hc_connection_to_local_listener(&connection, &listener) < 0) { + ERROR("[hc_face_create] Could not convert face to local listener."); + return -1; + } +#if 1 + /* + * The name is generated to prepare listener creation, we need it to be + * empty for deletion. The id should not need to be reset though. + */ + listener.id = 0; + memset(listener.name, 0, sizeof(listener.name)); +#endif + if (_hcng_connection_list(socket, &connections) < 0) { + ERROR("[hc_face_delete] Error getting the list of listeners"); + return -1; + } + + bool delete = true; + foreach_connection(c, connections) { + if ((ip_address_cmp(&c->local_addr, &listener.local_addr, c->family) == + 0) && + (c->local_port == listener.local_port) && + (strcmp(c->interface_name, listener.interface_name) == 0)) { + delete = false; + } + } + + if (delete) { + if (_hcng_listener_delete(socket, &listener) < 0) { + ERROR("[hc_face_delete] Error removing listener"); + return -1; + } + } + + hc_data_free(connections); + + return 0; +} + +/* FACE LIST */ + +static int _hcng_face_list(hc_sock_t *socket, hc_data_t **pdata) { + hc_data_t *connection_data; + hc_face_t face; + + DEBUG("[hc_face_list]"); + + if (_hcng_connection_list(socket, &connection_data) < 0) { + ERROR("[hc_face_list] Could not list connections."); + return -1; + } + + hc_data_t *face_data = + hc_data_create(sizeof(hc_connection_t), sizeof(hc_face_t), NULL); + foreach_connection(c, connection_data) { + if (hc_connection_to_face(c, &face) < 0) { + ERROR("[hc_face_list] Could not convert connection to face."); + goto ERR; + } + hc_data_push(face_data, &face); + } + + *pdata = face_data; + hc_data_free(connection_data); + DEBUG("[hc_face_list] done"); + return 0; + +ERR: + hc_data_free(connection_data); + DEBUG("[hc_face_list] error"); + return -1; +} + +static int hc_connection_parse_to_face(void *in, hc_face_t *face) { + hc_connection_t connection; + + if (hc_connection_parse(in, &connection) < 0) { + ERROR("[hc_connection_parse_to_face] Could not parse connection"); + return -1; + } + + if (hc_connection_to_face(&connection, face) < 0) { + ERROR( + "[hc_connection_parse_to_face] Could not convert connection to " + "face."); + return -1; + } + + return 0; +} + +static int _hcng_face_list_async(hc_sock_t *socket) { + struct { + cmd_header_t hdr; + } msg = { + .hdr = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_CONNECTION_LIST, + .length = 0, + .seq_num = 0, + }, + }; + + hc_command_params_t params = { + .cmd = ACTION_LIST, + .cmd_id = COMMAND_TYPE_CONNECTION_LIST, + .size_in = sizeof(cmd_connection_list_item_t), + .size_out = sizeof(hc_face_t), + .parse = (HC_PARSE)hc_connection_parse_to_face, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, true); +} + +static int _hcng_face_set_admin_state(hc_sock_t *s, const char *conn_id_or_name, + face_state_t admin_state) { + return hc_connection_set_admin_state(s, conn_id_or_name, admin_state); +} + +#ifdef WITH_POLICY +static int _hcng_face_set_priority(hc_sock_t *s, const char *conn_id_or_name, + uint32_t priority) { + return hc_connection_set_priority(s, conn_id_or_name, priority); +} + +static int _hcng_face_set_tags(hc_sock_t *s, const char *conn_id_or_name, + policy_tags_t tags) { + return hc_connection_set_tags(s, conn_id_or_name, tags); +} +#endif // WITH_POLICY + +/*----------------------------------------------------------------------------* + * Punting + *----------------------------------------------------------------------------*/ + +static int _hcng_punting_create_internal(hc_sock_t *socket, + hc_punting_t *punting, bool async) { + int rc; + + if (hc_punting_validate(punting) < 0) return -1; + + struct { + cmd_header_t hdr; + cmd_punting_add_t payload; + } msg = {.hdr = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_PUNTING_ADD, + .length = 1, + .seq_num = 0, + }, + .payload = { + .address = punting->prefix, + .family = punting->family, + .len = punting->prefix_len, + }}; + rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d", + punting->face_id); + if (rc >= SYMBOLIC_NAME_LEN) + WARN("[_hc_punting_create] Unexpected truncation of symbolic name string"); + + hc_command_params_t params = { + .cmd = ACTION_CREATE, + .cmd_id = COMMAND_TYPE_PUNTING_ADD, + .size_in = sizeof(cmd_punting_add_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, async); +} + +static int _hcng_punting_create(hc_sock_t *s, hc_punting_t *punting) { + return _hcng_punting_create_internal(s, punting, false); +} + +static int _hcng_punting_create_async(hc_sock_t *s, hc_punting_t *punting) { + return _hcng_punting_create_internal(s, punting, true); +} + +static int _hcng_punting_get(hc_sock_t *s, hc_punting_t *punting, + hc_punting_t **punting_found) { + ERROR("hc_punting_get not (yet) implemented."); + return -1; +} + +static int _hcng_punting_delete(hc_sock_t *s, hc_punting_t *punting) { + ERROR("hc_punting_delete not (yet) implemented."); + return -1; +} + +#if 0 +static int hc_punting_parse(void * in, hc_punting_t * punting) +{ + ERROR("hc_punting_parse not (yet) implemented."); + return -1; +} +#endif + +static int _hcng_punting_list(hc_sock_t *s, hc_data_t **pdata) { + ERROR("hc_punting_list not (yet) implemented."); + return -1; +} + +/*----------------------------------------------------------------------------* + * Cache + *----------------------------------------------------------------------------*/ + +/* CACHE SET STORE */ + +static int _hcng_cache_set_store_internal(hc_sock_t *socket, hc_cache_t *cache, + bool async) { + msg_cache_set_store_t msg = { + .header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_CACHE_SET_STORE, + .length = 1, + .seq_num = 0, + }, + .payload = { + .activate = cache->store, + }}; + + hc_command_params_t params = { + .cmd = ACTION_STORE, + .cmd_id = COMMAND_TYPE_CACHE_SET_STORE, + .size_in = sizeof(cmd_cache_set_store_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, async); +} + +static int _hcng_cache_set_store(hc_sock_t *s, hc_cache_t *cache) { + return _hcng_cache_set_store_internal(s, cache, false); +} + +static int _hcng_cache_set_store_async(hc_sock_t *s, hc_cache_t *cache) { + return _hcng_cache_set_store_internal(s, cache, true); +} + +/* CACHE SET SERVE */ + +static int _hcng_cache_set_serve_internal(hc_sock_t *socket, hc_cache_t *cache, + bool async) { + msg_cache_set_serve_t msg = { + .header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_CACHE_SET_SERVE, + .length = 1, + .seq_num = 0, + }, + .payload = { + .activate = cache->serve, + }}; + + hc_command_params_t params = { + .cmd = ACTION_SERVE, + .cmd_id = COMMAND_TYPE_CACHE_SET_SERVE, + .size_in = sizeof(cmd_cache_set_serve_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, async); +} + +static int _hcng_cache_set_serve(hc_sock_t *s, hc_cache_t *cache) { + return _hcng_cache_set_serve_internal(s, cache, false); +} + +static int _hcng_cache_set_serve_async(hc_sock_t *s, hc_cache_t *cache) { + return _hcng_cache_set_serve_internal(s, cache, true); +} + +/* CACHE CLEAR */ + +static int _hcng_cache_clear_internal(hc_sock_t *socket, hc_cache_t *cache, + bool async) { + msg_cache_clear_t msg = {.header = { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_CACHE_CLEAR, + .length = 1, + .seq_num = 0, + }}; + + hc_command_params_t params = { + .cmd = ACTION_CLEAR, + .cmd_id = COMMAND_TYPE_CACHE_CLEAR, + .size_in = sizeof(cmd_cache_clear_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, async); +} + +static int _hcng_cache_clear(hc_sock_t *s, hc_cache_t *cache) { + return _hcng_cache_clear_internal(s, cache, false); +} + +/* CACHE PARSE */ + +static int hc_cache_parse(void *in, hc_cache_info_t *cache_info) { + cmd_cache_list_reply_t *item = (cmd_cache_list_reply_t *)in; + *cache_info = (hc_cache_info_t){.store = item->store_in_cs, + .serve = item->serve_from_cs, + .cs_size = item->cs_size, + .num_stale_entries = item->num_stale_entries}; + + return 0; +} + +/* CACHE LIST */ + +static hc_result_t *_hcng_cache_list_serialize(hc_sock_t *socket, + hc_data_t **pdata, bool async) { + hc_result_t *res = malloc(sizeof(*res)); + DEBUG("[hc_cache_list] async=%s", BOOLSTR(async)); + + msg_cache_list_t msg = {.header = { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_CACHE_LIST, + .length = 0, + .seq_num = 0, + }}; + + hc_command_params_t params = { + .cmd = ACTION_LIST, + .cmd_id = COMMAND_TYPE_CACHE_LIST, + .size_in = sizeof(cmd_cache_list_reply_t), + .size_out = sizeof(hc_cache_info_t), + .parse = (HC_PARSE)hc_cache_parse, + }; + + *res = (hc_result_t){ + .msg = + (hc_msg_t){ + .hdr = msg.header, + .payload.cache_list = msg.payload, + }, + .params = params, + .async = async, + .success = true, + }; + return res; +} + +static int _hcng_cache_list_internal(hc_sock_t *socket, hc_data_t **pdata, + bool async) { + hc_result_t *result = _hcng_cache_list_serialize(socket, pdata, async); + + int ret = INPUT_ERROR; + if (result->success) { + ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg, + sizeof(result->msg), &result->params, pdata, + result->async); + } + + hc_result_free(result); + return ret; +} + +static int _hcng_cache_list(hc_sock_t *s, hc_data_t **pdata) { + return _hcng_cache_list_internal(s, pdata, false); +} + +/*----------------------------------------------------------------------------* + * Strategy + *----------------------------------------------------------------------------*/ + +// per prefix +static hc_result_t *_strategy_set_serialize(hc_sock_t *socket, + hc_strategy_t *strategy) { + hc_result_t *res = malloc(sizeof(*res)); + + char strategy_s[MAXSZ_HC_STRATEGY]; + int rc = strcpy_s(strategy->name, MAXSZ_STRATEGY_NAME, + strategy_str(strategy->type)); + if (rc != EOK) goto ERR; + rc = hc_strategy_snprintf(strategy_s, MAXSZ_HC_STRATEGY, strategy); + if (rc >= MAXSZ_HC_STRATEGY) + WARN("[_hcng_strategy_create] Unexpected truncation of strategy string"); + DEBUG("[_hcng_strategy_create] strategy=%s", strategy_s); + + if (!IS_VALID_FAMILY(strategy->family) || + !IS_VALID_STRATEGY_TYPE(strategy->type)) { + goto ERR; + } + + msg_strategy_set_t msg = {.header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_STRATEGY_SET, + .length = 1, + .seq_num = 0, + }, + .payload = { + .address = strategy->address, + .family = strategy->family, + .len = strategy->len, + .type = strategy->type, + }}; + + hc_command_params_t params = { + .cmd = ACTION_SET, + .cmd_id = COMMAND_TYPE_STRATEGY_SET, + .size_in = sizeof(cmd_strategy_set_t), + .size_out = 0, + .parse = NULL, + }; + + *res = (hc_result_t){ + .msg = + (hc_msg_t){ + .hdr = msg.header, + .payload.strategy_set = msg.payload, + }, + .params = params, + .async = false, + .success = true, + }; + return res; + +ERR: + res->success = false; + return res; +} + +static hc_result_t *_strategy_add_local_prefix_serialize( + hc_sock_t *socket, hc_strategy_t *strategy) { + hc_result_t *res = malloc(sizeof(*res)); + + char strategy_s[MAXSZ_HC_STRATEGY]; + int rc = strcpy_s(strategy->name, MAXSZ_STRATEGY_NAME, + strategy_str(strategy->type)); + if (rc != EOK) goto ERR; + rc = hc_strategy_snprintf(strategy_s, MAXSZ_HC_STRATEGY, strategy); + if (rc >= MAXSZ_HC_STRATEGY) + WARN("[_hcng_strategy_create] Unexpected truncation of strategy string"); + DEBUG("[_hcng_strategy_create] strategy=%s", strategy_s); + + if (!IS_VALID_FAMILY(strategy->family) || + !IS_VALID_STRATEGY_TYPE(strategy->type) || + !IS_VALID_FAMILY(strategy->local_family)) { + goto ERR; + } + + msg_strategy_add_local_prefix_t msg = { + .header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_STRATEGY_ADD_LOCAL_PREFIX, + .length = 1, + .seq_num = 0, + }, + .payload = { + .type = strategy->type, + .address = strategy->address, + .family = strategy->family, + .len = strategy->len, + .local_address = strategy->local_address, + .local_family = strategy->local_family, + .local_len = strategy->local_len, + }}; + + hc_command_params_t params = { + .cmd = ACTION_SET, + .cmd_id = COMMAND_TYPE_STRATEGY_ADD_LOCAL_PREFIX, + .size_in = sizeof(cmd_strategy_add_local_prefix_t), + .size_out = 0, + .parse = NULL, + }; + + *res = (hc_result_t){ + .msg = + (hc_msg_t){ + .hdr = msg.header, + .payload.strategy_add_local_prefix = msg.payload, + }, + .params = params, + .async = false, + .success = true, + }; + return res; + +ERR: + res->success = false; + return res; +} + +static hc_result_t *_hcng_strategy_set_conf(hc_sock_t *s, + hc_strategy_t *strategy) { + return _strategy_set_serialize(s, strategy); +} + +static int _hcng_strategy_set(hc_sock_t *socket, hc_strategy_t *strategy) { + hc_result_t *result = _strategy_set_serialize(socket, strategy); + + int ret = INPUT_ERROR; + if (result->success) { + ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg, + sizeof(result->msg), &result->params, NULL, + result->async); + } + + hc_result_free(result); + return ret; +} + +static hc_result_t *_hcng_strategy_add_local_prefix_conf( + hc_sock_t *s, hc_strategy_t *strategy) { + return _strategy_add_local_prefix_serialize(s, strategy); +} + +static int _hcng_strategy_add_local_prefix(hc_sock_t *socket, + hc_strategy_t *strategy) { + hc_result_t *result = _strategy_add_local_prefix_serialize(socket, strategy); + + int ret = INPUT_ERROR; + if (result->success) { + ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg, + sizeof(result->msg), &result->params, NULL, + result->async); + } + + hc_result_free(result); + return ret; +} + +/* How to retrieve that from the forwarder ? */ +static const char *strategies[] = { + "random", + "load_balancer", +}; + +#define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array)) + +static int _hcng_strategy_list(hc_sock_t *s, hc_data_t **data) { + int rc; + + *data = hc_data_create(0, sizeof(hc_strategy_t), NULL); + + for (unsigned i = 0; i < ARRAY_SIZE(strategies); i++) { + hc_strategy_t *strategy = (hc_strategy_t *)hc_data_get_next(*data); + if (!strategy) return -1; + rc = snprintf(strategy->name, MAXSZ_STRATEGY_NAME, "%s", strategies[i]); + if (rc >= MAXSZ_STRATEGY_NAME) + WARN("[hc_strategy_list] Unexpected truncation of strategy name string"); + (*data)->size++; + } + + return 0; +} + +/*----------------------------------------------------------------------------* + * WLDR + *----------------------------------------------------------------------------*/ + +// per connection +static int _hcng_wldr_set(hc_sock_t *s /* XXX */) { return 0; } + +/*----------------------------------------------------------------------------* + * MAP-Me + *----------------------------------------------------------------------------*/ + +static int _hcng_mapme_set(hc_sock_t *socket, int enabled) { + msg_mapme_enable_t msg = {.header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_MAPME_ENABLE, + .length = 1, + .seq_num = 0, + }, + .payload = { + .activate = enabled, + }}; + + hc_command_params_t params = { + .cmd = ACTION_SET, + .cmd_id = COMMAND_TYPE_MAPME_ENABLE, + .size_in = sizeof(cmd_mapme_enable_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, false); +} + +static int _hcng_mapme_set_discovery(hc_sock_t *socket, int enabled) { + msg_mapme_enable_t msg = { + .header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_MAPME_SET_DISCOVERY, + .length = 1, + .seq_num = 0, + }, + .payload = { + .activate = enabled, + }}; + + hc_command_params_t params = { + .cmd = ACTION_SET, + .cmd_id = COMMAND_TYPE_MAPME_SET_DISCOVERY, + .size_in = sizeof(cmd_mapme_set_discovery_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, false); +} + +static int _hcng_mapme_set_timescale(hc_sock_t *socket, uint32_t timescale) { + msg_mapme_set_timescale_t msg = { + .header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_MAPME_SET_TIMESCALE, + .length = 1, + .seq_num = 0, + }, + .payload = { + .timePeriod = timescale, + }}; + + hc_command_params_t params = { + .cmd = ACTION_SET, + .cmd_id = COMMAND_TYPE_MAPME_SET_TIMESCALE, + .size_in = sizeof(cmd_mapme_set_timescale_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, false); +} + +static int _hcng_mapme_set_retx(hc_sock_t *socket, uint32_t timescale) { + msg_mapme_set_retx_t msg = {.header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_MAPME_SET_RETX, + .length = 1, + .seq_num = 0, + }, + .payload = { + .timePeriod = timescale, + }}; + + hc_command_params_t params = { + .cmd = ACTION_SET, + .cmd_id = COMMAND_TYPE_MAPME_SET_RETX, + .size_in = sizeof(msg_mapme_set_retx_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, false); +} + +static int _hcng_mapme_send_update(hc_sock_t *socket, hc_mapme_t *mapme) { + if (!IS_VALID_FAMILY(mapme->family)) return -1; + + msg_mapme_send_update_t msg = { + .header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_MAPME_SEND_UPDATE, + .length = 1, + .seq_num = 0, + }, + }; + + hc_command_params_t params = { + .cmd = ACTION_UPDATE, + .cmd_id = COMMAND_TYPE_MAPME_SEND_UPDATE, + .size_in = sizeof(msg_mapme_send_update_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, false); +} + +/*----------------------------------------------------------------------------* + * Policy + *----------------------------------------------------------------------------*/ + +#ifdef WITH_POLICY + +/* POLICY CREATE */ + +static int _hcng_policy_create_internal(hc_sock_t *socket, hc_policy_t *policy, + bool async) { + if (!IS_VALID_FAMILY(policy->family)) return -1; + + struct { + cmd_header_t hdr; + cmd_policy_add_t payload; + } msg = {.hdr = + { + .message_type = REQUEST_LIGHT, + COMMAND_TYPE_POLICY_ADD, + .length = 1, + .seq_num = 0, + }, + .payload = { + .address = policy->remote_addr, + .family = policy->family, + .len = policy->len, + .policy = policy->policy, + }}; + + hc_command_params_t params = { + .cmd = ACTION_CREATE, + .cmd_id = COMMAND_TYPE_POLICY_ADD, + .size_in = sizeof(cmd_policy_add_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, async); +} + +static int _hcng_policy_create(hc_sock_t *s, hc_policy_t *policy) { + return _hcng_policy_create_internal(s, policy, false); +} + +static int _hcng_policy_create_async(hc_sock_t *s, hc_policy_t *policy) { + return _hcng_policy_create_internal(s, policy, true); +} + +/* POLICY DELETE */ + +static int _hcng_policy_delete_internal(hc_sock_t *socket, hc_policy_t *policy, + bool async) { + if (!IS_VALID_FAMILY(policy->family)) return -1; + + struct { + cmd_header_t hdr; + cmd_policy_remove_t payload; + } msg = {.hdr = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_POLICY_REMOVE, + .length = 1, + .seq_num = 0, + }, + .payload = { + .address = policy->remote_addr, + .family = policy->family, + .len = policy->len, + }}; + + hc_command_params_t params = { + .cmd = ACTION_DELETE, + .cmd_id = COMMAND_TYPE_POLICY_REMOVE, + .size_in = sizeof(cmd_policy_remove_t), + .size_out = 0, + .parse = NULL, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + NULL, async); +} + +static int _hcng_policy_delete(hc_sock_t *s, hc_policy_t *policy) { + return _hcng_policy_delete_internal(s, policy, false); +} + +static int _hcng_policy_delete_async(hc_sock_t *s, hc_policy_t *policy) { + return _hcng_policy_delete_internal(s, policy, true); +} + +/* POLICY PARSE */ + +static int hc_policy_parse(void *in, hc_policy_t *policy) { + cmd_policy_list_item_t *item = (cmd_policy_list_item_t *)in; + + if (!IS_VALID_ADDRESS(&item->address, item->family)) { + ERROR("[hc_policy_parse] Invalid address"); + return -1; + } + if (!IS_VALID_FAMILY(item->family)) { + ERROR("[hc_policy_parse] Invalid family"); + return -1; + } + if (!IS_VALID_PREFIX_LEN(item->len)) { + ERROR("[hc_policy_parse] Invalid len"); + return -1; + } + if (!IS_VALID_POLICY(item->policy)) { + ERROR("[hc_policy_parse] Invalid policy"); + return -1; + } + + *policy = (hc_policy_t){ + .family = item->family, + .remote_addr = item->address, + .len = item->len, + .policy = item->policy, + }; + return 0; +} + +/* POLICY LIST */ + +static int _hcng_policy_list_internal(hc_sock_t *socket, hc_data_t **pdata, + bool async) { + struct { + cmd_header_t hdr; + } msg = { + .hdr = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_POLICY_LIST, + .length = 0, + .seq_num = 0, + }, + }; + + hc_command_params_t params = { + .cmd = ACTION_LIST, + .cmd_id = COMMAND_TYPE_POLICY_LIST, + .size_in = sizeof(cmd_policy_list_item_t), + .size_out = sizeof(hc_policy_t), + .parse = (HC_PARSE)hc_policy_parse, + }; + + return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), ¶ms, + pdata, async); +} + +static int _hcng_policy_list(hc_sock_t *s, hc_data_t **pdata) { + return _hcng_policy_list_internal(s, pdata, false); +} + +static int _hcng_policy_list_async(hc_sock_t *s, hc_data_t **pdata) { + return _hcng_policy_list_internal(s, pdata, true); +} + +#endif /* WITH_POLICY */ + +/*----------------------------------------------------------------------------* + * Subscriptioins + *----------------------------------------------------------------------------*/ + +/* SUBSCRIPTION CREATE */ + +static hc_result_t *_subscription_create_serialize( + hc_sock_t *s, hc_subscription_t *subscription) { + msg_subscription_add_t msg = { + .header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_SUBSCRIPTION_ADD, + .length = 1, + .seq_num = 0, + }, + .payload = {.topics = subscription->topics}}; + + hc_command_params_t params = { + .cmd = ACTION_CREATE, + .cmd_id = COMMAND_TYPE_SUBSCRIPTION_ADD, + .size_in = sizeof(cmd_subscription_add_t), + .size_out = 0, + .parse = NULL, + }; + + hc_result_t *res = malloc(sizeof(*res)); + *res = (hc_result_t){ + .msg = + (hc_msg_t){ + .hdr = msg.header, + .payload.subscription_add = msg.payload, + }, + .params = params, + .async = false, + .success = true, + }; + return res; +} + +static hc_result_t *_hcng_subscription_create_conf( + hc_sock_t *s, hc_subscription_t *subscription) { + return _subscription_create_serialize(s, subscription); +} + +static int _hcng_subscription_create(hc_sock_t *socket, + hc_subscription_t *subscriiption) { + hc_result_t *result = _subscription_create_serialize(socket, subscriiption); + + int ret = INPUT_ERROR; + if (result->success) { + ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg, + sizeof(result->msg), &result->params, NULL, + result->async); + } + + hc_result_free(result); + return ret; +} + +/* SUBSCRIPTION DELETE */ + +static hc_result_t *_subscription_delete_serialize( + hc_sock_t *s, hc_subscription_t *subscription) { + msg_subscription_remove_t msg = { + .header = + { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_SUBSCRIPTION_REMOVE, + .length = 1, + .seq_num = 0, + }, + .payload = {.topics = subscription->topics}}; + + hc_command_params_t params = { + .cmd = ACTION_DELETE, + .cmd_id = COMMAND_TYPE_SUBSCRIPTION_REMOVE, + .size_in = sizeof(cmd_subscription_remove_t), + .size_out = 0, + .parse = NULL, + }; + + hc_result_t *res = malloc(sizeof(*res)); + *res = (hc_result_t){ + .msg = + (hc_msg_t){ + .hdr = msg.header, + .payload.subscription_remove = msg.payload, + }, + .params = params, + .async = false, + .success = true, + }; + return res; +} + +static hc_result_t *_hcng_subscription_delete_conf( + hc_sock_t *s, hc_subscription_t *subscription) { + return _subscription_delete_serialize(s, subscription); +} + +static int _hcng_subscription_delete(hc_sock_t *socket, + hc_subscription_t *subscriiption) { + hc_result_t *result = _subscription_delete_serialize(socket, subscriiption); + + int ret = INPUT_ERROR; + if (result->success) { + ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg, + sizeof(result->msg), &result->params, NULL, + result->async); + } + + hc_result_free(result); + return ret; +} + +/* RESULT */ +hc_msg_t *_hcng_result_get_msg(hc_result_t *result) { return &result->msg; } +int _hcng_result_get_cmd_id(hc_result_t *result) { + return result->params.cmd_id; +} +bool _hcng_result_get_success(hc_result_t *result) { return result->success; } + +static hc_sock_t hc_sock_light_ng_interface = (hc_sock_t){ + .hc_sock_get_next_seq = _hcng_sock_light_get_next_seq, + .hc_sock_set_nonblocking = _hcng_sock_light_set_nonblocking, + .hc_sock_get_fd = _hcng_sock_light_get_fd, + .hc_sock_connect = _hcng_sock_light_connect, + .hc_sock_get_available = _hcng_sock_light_get_available, + .hc_sock_send = _hcng_sock_light_send, + .hc_sock_recv = _hcng_sock_light_recv, + .hc_sock_process = _hcng_sock_light_process, + .hc_sock_callback = _hcng_sock_light_callback, + .hc_sock_reset = _hcng_sock_light_reset, + .hc_sock_free = _hcng_sock_light_free, + .hc_sock_increment_woff = _hcng_sock_increment_woff, + .hc_sock_prepare_send = _hcng_sock_prepare_send, + .hc_sock_set_recv_timeout_ms = _hcng_sock_set_recv_timeout_ms, + .hc_listener_create = _hcng_listener_create, + .hc_listener_create_async = _hcng_listener_create_async, + .hc_listener_get = _hcng_listener_get, + .hc_listener_delete = _hcng_listener_delete, + .hc_listener_delete_async = _hcng_listener_delete_async, + .hc_listener_list = _hcng_listener_list, + .hc_listener_list_async = _hcng_listener_list_async, + .hc_connection_create = _hcng_connection_create, + .hc_connection_create_async = _hcng_connection_create_async, + .hc_connection_get = _hcng_connection_get, + .hc_connection_update_by_id = _hcng_connection_update_by_id, + .hc_connection_update = _hcng_connection_update, + .hc_connection_delete = _hcng_connection_delete, + .hc_connection_delete_async = _hcng_connection_delete_async, + .hc_connection_list = _hcng_connection_list, + .hc_connection_list_async = _hcng_connection_list_async, + .hc_connection_set_admin_state = _hcng_connection_set_admin_state, + .hc_connection_set_admin_state_async = + _hcng_connection_set_admin_state_async, + +#ifdef WITH_POLICY + .hc_connection_set_priority = _hcng_connection_set_priority, + .hc_connection_set_priority_async = _hcng_connection_set_priority_async, + .hc_connection_set_tags = _hcng_connection_set_tags, + .hc_connection_set_tags_async = _hcng_connection_set_tags_async, +#endif // WITH_POLICY + + .hc_face_create = _hcng_face_create, + .hc_face_get = _hcng_face_get, + .hc_face_delete = _hcng_face_delete, + .hc_face_list = _hcng_face_list, + .hc_face_list_async = _hcng_face_list_async, + .hc_face_set_admin_state = _hcng_face_set_admin_state, + +#ifdef WITH_POLICY + .hc_face_set_priority = _hcng_face_set_priority, + .hc_face_set_tags = _hcng_face_set_tags, +#endif // WITH_POLICY + .hc_subscription_create = _hcng_subscription_create, + .hc_subscription_delete = _hcng_subscription_delete, + + .hc_route_create = _hcng_route_create, + .hc_route_create_async = _hcng_route_create_async, + .hc_route_delete = _hcng_route_delete, + .hc_route_delete_async = _hcng_route_delete_async, + .hc_route_list = _hcng_route_list, + .hc_route_list_async = _hcng_route_list_async, + + .hc_punting_create = _hcng_punting_create, + .hc_punting_create_async = _hcng_punting_create_async, + .hc_punting_get = _hcng_punting_get, + .hc_punting_delete = _hcng_punting_delete, + .hc_punting_list = _hcng_punting_list, + + .hc_cache_set_store = _hcng_cache_set_store, + .hc_cache_set_store_async = _hcng_cache_set_store_async, + .hc_cache_set_serve = _hcng_cache_set_serve, + .hc_cache_set_serve_async = _hcng_cache_set_serve_async, + .hc_cache_clear = _hcng_cache_clear, + .hc_cache_list = _hcng_cache_list, + + .hc_strategy_list = _hcng_strategy_list, + .hc_strategy_set = _hcng_strategy_set, + .hc_strategy_add_local_prefix = _hcng_strategy_add_local_prefix, + .hc_wldr_set = _hcng_wldr_set, + + .hc_mapme_set = _hcng_mapme_set, + .hc_mapme_set_discovery = _hcng_mapme_set_discovery, + .hc_mapme_set_timescale = _hcng_mapme_set_timescale, + .hc_mapme_set_retx = _hcng_mapme_set_retx, + .hc_mapme_send_update = _hcng_mapme_send_update, + +#ifdef WITH_POLICY + .hc_policy_create = _hcng_policy_create, + .hc_policy_create_async = _hcng_policy_create_async, + .hc_policy_delete = _hcng_policy_delete, + .hc_policy_delete_async = _hcng_policy_delete_async, + .hc_policy_list = _hcng_policy_list, + .hc_policy_list_async = _hcng_policy_list_async, +#endif // WITH_POLICY + + .hc_listener_create_conf = _hcng_listener_create_conf, + .hc_listener_list_conf = _hcng_listener_list_conf, + .hc_connection_create_conf = _hcng_connection_create_conf, + .hc_connection_delete_conf = _hcng_connection_delete_conf, + .hc_route_create_conf = _hcng_route_create_conf, + .hc_strategy_set_conf = _hcng_strategy_set_conf, + .hc_strategy_add_local_prefix_conf = _hcng_strategy_add_local_prefix_conf, + .hc_subscription_create_conf = _hcng_subscription_create_conf, + .hc_subscription_delete_conf = _hcng_subscription_delete_conf, + + .hc_result_get_msg = _hcng_result_get_msg, + .hc_result_get_cmd_id = _hcng_result_get_cmd_id, + .hc_result_get_success = _hcng_result_get_success, +}; + +// Public contructors + +hc_sock_t *_hc_sock_create_url(const char *url) { + hc_sock_light_t *s = malloc(sizeof(hc_sock_light_t)); + if (!s) goto ERR_MALLOC; + + s->vft = hc_sock_light_ng_interface; + s->url = url ? strdup(url) : NULL; + + s->fd = socket(AF_INET, SOCK_DGRAM, 0); + if (s->fd < 0) goto ERR_SOCKET; + + if (_hcng_sock_set_recv_timeout_ms((hc_sock_t *)s, + DEFAULT_SOCK_RECV_TIMEOUT_MS) < 0) + goto ERR_SOCKET; + + if (_hcng_sock_light_reset((hc_sock_t *)s) < 0) goto ERR_RESET; + + s->seq = 0; + s->cur_request = NULL; + + s->map = hc_sock_map_create(); + if (!s->map) goto ERR_MAP; + + return (hc_sock_t *)(s); + + // hc_sock_light_map_free(s->map); +ERR_MAP: +ERR_RESET: + if (s->url) free(s->url); + close(s->fd); +ERR_SOCKET: + free(s); +ERR_MALLOC: + return NULL; +} diff --git a/ctrl/libhicnctrl/src/modules/hicn_plugin_api.c b/ctrl/libhicnctrl/src/modules/hicn_plugin_api.c index e59a2e41e..6d1baa786 100644 --- a/ctrl/libhicnctrl/src/modules/hicn_plugin_api.c +++ b/ctrl/libhicnctrl/src/modules/hicn_plugin_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -18,8 +18,6 @@ * \brief Implementation of hICN control library API */ -#include "api_private.h" - #include <assert.h> // assert #include <fcntl.h> // fcntl #include <math.h> // log2 @@ -29,40 +27,10 @@ #include <sys/socket.h> // socket #include <unistd.h> // close, fcntl #include <vapi/vapi_safe.h> -#include <vapi/hicn.api.vapi.h> -#include <vapi/ip.api.vapi.h> -#include <vapi/udp.api.vapi.h> -#include <vapi/interface.api.vapi.h> - - -#if __GNUC__ >= 9 -#pragma GCC diagnostic ignored "-Waddress-of-packed-member" -#endif - -#include <vnet/ip/ip46_address.h> - -#if __GNUC__ >= 9 -#pragma GCC diagnostic pop -#endif - -#define APP_NAME "hicn_plugin" -#define MAX_OUTSTANDING_REQUESTS 4 -#define RESPONSE_QUEUE_SIZE 2 - -DEFINE_VAPI_MSG_IDS_HICN_API_JSON -DEFINE_VAPI_MSG_IDS_INTERFACE_API_JSON -DEFINE_VAPI_MSG_IDS_IP_API_JSON -DEFINE_VAPI_MSG_IDS_UDP_API_JSON +#include <vppinfra/clib.h> +#include <vpp_plugins/hicn/error.h> -typedef struct { - vapi_ctx_t g_vapi_ctx_instance; - bool async; -} vapi_skc_ctx_t; - -vapi_skc_ctx_t vapi_skc = { - .g_vapi_ctx_instance = NULL, - .async = false, -}; +#include "api_private.h" /** * Messages to the forwarder might be multiplexed thanks to the seqNum fields in @@ -81,7 +49,6 @@ struct hc_sock_vpp_s { vapi_ctx_t g_vapi_ctx_instance; char *url; - int fd; size_t roff; /**< Read offset */ size_t woff; /**< Write offset */ @@ -94,43 +61,42 @@ struct hc_sock_vpp_s { typedef struct hc_sock_vpp_s hc_sock_vpp_t; -#define TO_HC_SOCK_VPP(s) (hc_sock_vpp_t*)(s) +#define TO_HC_SOCK_VPP(s) (hc_sock_vpp_t *)(s) /****************************************************************************** * Message helper types and aliases ******************************************************************************/ -#define foreach_hc_command \ - _(hicn_api_node_params_set) \ - _(hicn_api_node_params_set_reply) \ - _(hicn_api_node_params_get_reply) \ - _(hicn_api_node_stats_get_reply) \ - _(hicn_api_face_get) \ - _(hicn_api_faces_details) \ - _(hicn_api_face_stats_details) \ - _(hicn_api_face_get_reply) \ - _(hicn_api_route_get) \ - _(hicn_api_route_get_reply) \ - _(hicn_api_routes_details) \ - _(hicn_api_strategies_get_reply) \ - _(hicn_api_strategy_get) \ +#define foreach_hc_command \ + _(hicn_api_node_params_set) \ + _(hicn_api_node_params_set_reply) \ + _(hicn_api_node_params_get_reply) \ + _(hicn_api_node_stats_get_reply) \ + _(hicn_api_face_get) \ + _(hicn_api_faces_details) \ + _(hicn_api_face_stats_details) \ + _(hicn_api_face_get_reply) \ + _(hicn_api_route_get) \ + _(hicn_api_route_get_reply) \ + _(hicn_api_routes_details) \ + _(hicn_api_strategies_get_reply) \ + _(hicn_api_strategy_get) \ _(hicn_api_strategy_get_reply) - typedef vapi_type_msg_header2_t hc_msg_header_t; typedef union { -#define _(a) vapi_payload_ ## a a; +#define _(a) vapi_payload_##a a; foreach_hc_command #undef _ } hc_msg_payload_t; -typedef struct __attribute__ ((__packed__)) { +typedef struct __attribute__((__packed__)) { hc_msg_header_t hdr; hc_msg_payload_t payload; } hc_hicnp_t; -typedef void (* NTOH)(void *msg); +typedef void (*NTOH)(void *msg); typedef struct __attribute__((__packed__)) { hc_data_t *data; @@ -138,7 +104,7 @@ typedef struct __attribute__((__packed__)) { } callback_ctx_t; typedef struct __attribute__((__packed__)) { - hc_hicnp_t * hicnp_msg; + hc_hicnp_t *hicnp_msg; vapi_cb_t callback; callback_ctx_t *callback_ctx; NTOH ntoh; @@ -151,11 +117,9 @@ typedef struct __attribute__((__packed__)) { static void _hc_sock_vpp_free(hc_sock_t *socket) { hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket); if (s->url) free(s->url); - close(s->fd); free(s); vapi_disconnect_safe(); - vapi_skc.g_vapi_ctx_instance = NULL; } static int _hc_sock_vpp_get_next_seq(hc_sock_t *socket) { @@ -174,8 +138,7 @@ static int _hc_sock_vpp_get_fd(hc_sock_t *s) { return 1; } static int _hc_sock_vpp_connect(hc_sock_t *socket) { hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket); vapi_error_e rv = vapi_connect_safe(&s->g_vapi_ctx_instance, s->async); - if (rv != VAPI_OK) - goto ERR_CONNECT; + if (rv != VAPI_OK) goto ERR_CONNECT; return 0; @@ -184,7 +147,8 @@ ERR_CONNECT: return -1; } -static int _hc_sock_vpp_send(hc_sock_t *s, hc_msg_t *msg, size_t msglen, int seq) { +static int _hc_sock_vpp_send(hc_sock_t *s, hc_msg_t *msg, size_t msglen, + uint32_t seq) { return -1; } @@ -199,16 +163,16 @@ static int _hc_sock_vpp_recv(hc_sock_t *s) { } static int _hc_sock_vpp_process(hc_sock_t *s, hc_data_t **pdata) { - //NOT IMPLEMENTED + // NOT IMPLEMENTED return -1; } -static int _hc_sock_vpp_callback(hc_sock_t * socket, hc_data_t ** pdata) { +static int _hc_sock_vpp_callback(hc_sock_t *socket, hc_data_t **pdata) { // NOT IMPLEMENTED return -1; } -static int _hc_sock_vpp_reset(hc_sock_t * socket) { +static int _hc_sock_vpp_reset(hc_sock_t *socket) { // NOT IMPLEMENTED return -1; } @@ -217,7 +181,6 @@ static int _hc_sock_vpp_reset(hc_sock_t * socket) { * Command-specific structures and functions ******************************************************************************/ - /*----------------------------------------------------------------------------* * Listeners *----------------------------------------------------------------------------*/ @@ -236,7 +199,7 @@ static int _hc_listener_create_async(hc_sock_t *s, hc_listener_t *listener) { /* LISTENER GET */ static int _hc_listener_get(hc_sock_t *s, hc_listener_t *listener, - hc_listener_t **listener_found) { + hc_listener_t **listener_found) { // NOT IMPLEMENTED return -1; } @@ -253,33 +216,32 @@ static int _hc_listener_delete_async(hc_sock_t *s, hc_listener_t *listener) { return -1; } -static vapi_error_e process_ip_info(struct vapi_ctx_s *ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, +static vapi_error_e process_ip_info(struct vapi_ctx_s *ctx, void *callback_ctx, + vapi_error_e rv, bool is_last, vapi_payload_ip_address_details *reply) { - - if (is_last) - return 0; + if (is_last) return 0; hc_data_t *data = (hc_data_t *)callback_ctx; if (data->size == data->current) { - data->buffer = realloc(data->buffer, sizeof(hc_listener_t) * data->size * 2); + data->buffer = + realloc(data->buffer, sizeof(hc_listener_t) * data->size * 2); - if (!data->buffer) - return VAPI_ENOMEM; + if (!data->buffer) return VAPI_ENOMEM; - data->size *=2; + data->size *= 2; } - hc_listener_t * listener = (hc_listener_t *)(data->buffer + data->current * sizeof(hc_listener_t)); + hc_listener_t *listener = + (hc_listener_t *)(data->buffer + data->current * sizeof(hc_listener_t)); + memset(listener, 0, sizeof(hc_listener_t)); - if(reply->prefix.address.af == ADDRESS_IP4) { - memcpy(listener->local_addr.v4.as_u8, reply->prefix.address.un.ip4, IPV4_ADDR_LEN); + if (reply->prefix.address.af == ADDRESS_IP4) { + memcpy(listener->local_addr.v4.as_u8, reply->prefix.address.un.ip4, + IPV4_ADDR_LEN); listener->family = AF_INET; - } - else { - memcpy(listener->local_addr.v6.as_u8, reply->prefix.address.un.ip6, IPV6_ADDR_LEN); + } else { + memcpy(listener->local_addr.v6.as_u8, reply->prefix.address.un.ip6, + IPV6_ADDR_LEN); listener->family = AF_INET6; } @@ -293,31 +255,26 @@ typedef struct { char interface_name[INTERFACE_LEN]; } hc_vapi_interface_t; -static vapi_error_e listener_list_complete_cb ( - struct vapi_ctx_s *ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_sw_interface_details *reply) { +static vapi_error_e listener_list_complete_cb( + struct vapi_ctx_s *ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_sw_interface_details *reply) { + if (reply == NULL || rv != VAPI_OK) return rv; - if (reply == NULL || rv != VAPI_OK) - return rv; - - if (is_last) - return 0; + if (is_last) return 0; hc_data_t *data = (hc_data_t *)callback_ctx; if (data->size == data->current) { - data->buffer = realloc(data->buffer, sizeof(hc_vapi_interface_t) * data->size * 2); + data->buffer = + realloc(data->buffer, sizeof(hc_vapi_interface_t) * data->size * 2); - if (!data->buffer) - return VAPI_ENOMEM; + if (!data->buffer) return VAPI_ENOMEM; - data->size *=2; + data->size *= 2; } - hc_vapi_interface_t *swif = &((hc_vapi_interface_t*)data->buffer)[data->current]; + hc_vapi_interface_t *swif = + &((hc_vapi_interface_t *)data->buffer)[data->current]; swif[0].swif = reply->sw_if_index; memcpy(swif[0].interface_name, reply->interface_name, INTERFACE_LEN); @@ -327,7 +284,6 @@ static vapi_error_e listener_list_complete_cb ( return rv; } - /* LISTENER LIST */ static int _hc_listener_list(hc_sock_t *socket, hc_data_t **pdata) { hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket); @@ -344,14 +300,14 @@ static int _hc_listener_list(hc_sock_t *socket, hc_data_t **pdata) { hicnp_msg->payload.sw_if_index = ~0; hicnp_msg->payload.name_filter_valid = 0; - hc_data_t *data = hc_data_create(0, sizeof(hc_vapi_interface_t),NULL); + hc_data_t *data = hc_data_create(0, sizeof(hc_vapi_interface_t), NULL); if (!data) { retval = -1; goto END; } - hc_data_t *data2 = hc_data_create(0, 1,NULL); + hc_data_t *data2 = hc_data_create(0, 1, NULL); if (!data2) { retval = -1; @@ -362,12 +318,13 @@ static int _hc_listener_list(hc_sock_t *socket, hc_data_t **pdata) { data->size = 1; if (!data->buffer) { - free (data); + free(data); retval = -1; goto FREE_DATA; } - int ret = vapi_sw_interface_dump(s->g_vapi_ctx_instance, hicnp_msg, listener_list_complete_cb, data); + int ret = vapi_sw_interface_dump(s->g_vapi_ctx_instance, hicnp_msg, + listener_list_complete_cb, data); if (ret != VAPI_OK) { free(data->buffer); @@ -381,28 +338,34 @@ static int _hc_listener_list(hc_sock_t *socket, hc_data_t **pdata) { data2->out_element_size = 1; if (!data2->buffer) { - free (data2->buffer); - retval =1 -1; + free(data2->buffer); + retval = -1; goto CLEAN; } /* Query the forwarder for each interface */ - for(int i = 0; i < data->current; i++) { + for (int i = 0; i < data->current; i++) { int index = data2->current; - vapi_msg_ip_address_dump* msg = vapi_alloc_ip_address_dump(s->g_vapi_ctx_instance); + vapi_msg_ip_address_dump *msg = + vapi_alloc_ip_address_dump(s->g_vapi_ctx_instance); msg->payload.sw_if_index = ((hc_vapi_interface_t *)data->buffer)[i].swif; msg->payload.is_ipv6 = 0; - retval = vapi_ip_address_dump(s->g_vapi_ctx_instance, msg, process_ip_info, data2); - vapi_msg_ip_address_dump* msg2 = vapi_alloc_ip_address_dump(s->g_vapi_ctx_instance); + retval = vapi_ip_address_dump(s->g_vapi_ctx_instance, msg, process_ip_info, + data2); + vapi_msg_ip_address_dump *msg2 = + vapi_alloc_ip_address_dump(s->g_vapi_ctx_instance); if (retval) goto CLEAN; msg2->payload.sw_if_index = ((hc_vapi_interface_t *)data->buffer)[i].swif; msg2->payload.is_ipv6 = 1; - retval = vapi_ip_address_dump(s->g_vapi_ctx_instance, msg2, process_ip_info, data2); + retval = vapi_ip_address_dump(s->g_vapi_ctx_instance, msg2, process_ip_info, + data2); for (size_t j = index; j < data2->current; j++) { - memcpy(((hc_listener_t *)(data2->buffer))[j].interface_name, ((hc_vapi_interface_t*)(data->buffer))[i].interface_name, INTERFACE_LEN); - ((hc_listener_t *)(data2->buffer))[j].type = CONNECTION_TYPE_HICN; + memcpy(((hc_listener_t *)(data2->buffer))[j].interface_name, + ((hc_vapi_interface_t *)(data->buffer))[i].interface_name, + INTERFACE_LEN); + ((hc_listener_t *)(data2->buffer))[j].type = FACE_TYPE_HICN; } if (retval) goto CLEAN; @@ -417,7 +380,7 @@ FREE_DATA: data2->size = data2->current; data2->out_element_size = sizeof(hc_listener_t); *pdata = data2; - END: +END: vapi_unlock(); return retval; } @@ -438,7 +401,8 @@ static int _hc_connection_create(hc_sock_t *s, hc_connection_t *connection) { return -1; } -static int _hc_connection_create_async(hc_sock_t *s, hc_connection_t *connection) { +static int _hc_connection_create_async(hc_sock_t *s, + hc_connection_t *connection) { // NOT IMPLEMENTED return -1; } @@ -446,17 +410,20 @@ static int _hc_connection_create_async(hc_sock_t *s, hc_connection_t *connection /* CONNECTION GET */ static int _hc_connection_get(hc_sock_t *s, hc_connection_t *connection, - hc_connection_t **connection_found) { + hc_connection_t **connection_found) { // NOT IMPLEMENTED return -1; } -static int _hc_connection_update_by_id(hc_sock_t *s, int hc_connection_id, hc_connection_t *connection) { +static int _hc_connection_update_by_id(hc_sock_t *s, int hc_connection_id, + hc_connection_t *connection) { // Not implemented return -1; } -static int _hc_connection_update(hc_sock_t *s, hc_connection_t *connection_current, hc_connection_t *connection_updated) { +static int _hc_connection_update(hc_sock_t *s, + hc_connection_t *connection_current, + hc_connection_t *connection_updated) { // Not implemented return -1; } @@ -468,7 +435,8 @@ static int _hc_connection_delete(hc_sock_t *s, hc_connection_t *connection) { return -1; } -static int _hc_connection_delete_async(hc_sock_t *s, hc_connection_t *connection) { +static int _hc_connection_delete_async(hc_sock_t *s, + hc_connection_t *connection) { // NOT IMPLEMENTED return -1; } @@ -487,39 +455,47 @@ static int _hc_connection_list_async(hc_sock_t *s, hc_data_t **pdata) { /* CONNECTION SET ADMIN STATE */ -static int _hc_connection_set_admin_state(hc_sock_t *s, const char *conn_id_or_name, - face_state_t state) { +static int _hc_connection_set_admin_state(hc_sock_t *s, + const char *conn_id_or_name, + face_state_t state) { // NOT IMPLEMENTED return -1; } static int _hc_connection_set_admin_state_async(hc_sock_t *s, - const char *conn_id_or_name, - face_state_t state) { + const char *conn_id_or_name, + face_state_t state) { // NOT IMPLEMENTED return -1; } #ifdef WITH_POLICY -static int _hc_connection_set_priority(hc_sock_t * s, const char * conn_id_or_name, uint32_t priority) { +static int _hc_connection_set_priority(hc_sock_t *s, + const char *conn_id_or_name, + uint32_t priority) { // NOT IMPLEMENTED return -1; } -static int _hc_connection_set_priority_async(hc_sock_t * s, const char * conn_id_or_name, uint32_t priority) { +static int _hc_connection_set_priority_async(hc_sock_t *s, + const char *conn_id_or_name, + uint32_t priority) { // NOT IMPLEMENTED return -1; } -#endif // WITH_POLICY +#endif // WITH_POLICY -static int _hc_connection_set_tags(hc_sock_t * s, const char * conn_id_or_name, policy_tags_t tags) { +static int _hc_connection_set_tags(hc_sock_t *s, const char *conn_id_or_name, + policy_tags_t tags) { // NOT IMPLEMENTED return -1; } -static int _hc_connection_set_tags_async(hc_sock_t * s, const char * conn_id_or_name, policy_tags_t tags) { +static int _hc_connection_set_tags_async(hc_sock_t *s, + const char *conn_id_or_name, + policy_tags_t tags) { // NOT IMPLEMENTED return -1; } @@ -528,66 +504,65 @@ static int _hc_connection_set_tags_async(hc_sock_t * s, const char * conn_id_or_ * Routes *----------------------------------------------------------------------------*/ -static vapi_error_e create_udp_tunnel_cb( vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_hicn_api_udp_tunnel_add_del_reply *reply) { - if (reply == NULL || rv != VAPI_OK) - return rv; +static vapi_error_e create_udp_tunnel_cb( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_hicn_api_udp_tunnel_add_del_reply *reply) { + if (reply == NULL || rv != VAPI_OK) return rv; - if (reply->retval != VAPI_OK) - return reply->retval; + if (reply->retval != VAPI_OK) return reply->retval; - u32 * uei = (u32*) callback_ctx; + u32 *uei = (u32 *)callback_ctx; *uei = reply->uei; return reply->retval; } /* ROUTE CREATE */ -static vapi_error_e parse_route_create( vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_ip_route_add_del_reply *reply) { - if (reply == NULL || rv != VAPI_OK) - return rv; +static vapi_error_e parse_route_create( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_ip_route_add_del_reply *reply) { + if (reply == NULL || rv != VAPI_OK) return rv; - if (reply->retval != VAPI_OK) - return reply->retval; + if (reply->retval != VAPI_OK) return reply->retval; return reply->retval; } -static vapi_error_e hicn_enable_cb( vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_hicn_api_enable_disable_reply *reply) { - if (reply == NULL || rv != VAPI_OK) - return rv; +static vapi_error_e hicn_enable_cb( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_hicn_api_enable_disable_reply *reply) { + if (reply == NULL || rv != VAPI_OK) return rv; + face_id_t *faceid = (face_id_t *)callback_ctx; + + if (reply->nfaces) { + *faceid = reply->faceids[0]; + } return reply->retval; } -static int _hc_route_create_internal(hc_sock_t *socket, hc_route_t *route, bool async) { +static int _hc_route_create_internal(hc_sock_t *socket, hc_route_t *route, + bool async) { if (!IS_VALID_FAMILY(route->family)) return -1; hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket); - int ret; + int ret = -1; vapi_lock(); - vapi_msg_ip_route_add_del *hicnp_msg = vapi_alloc_ip_route_add_del(s->g_vapi_ctx_instance, 1); + vapi_msg_ip_route_add_del *hicnp_msg = + vapi_alloc_ip_route_add_del(s->g_vapi_ctx_instance, 1); hicnp_msg->payload.is_add = 1; if (route->family == AF_INET) { - memcpy(&hicnp_msg->payload.route.prefix.address.un.ip4[0], &route->remote_addr.v4, 4); + memcpy(&hicnp_msg->payload.route.prefix.address.un.ip4[0], + &route->remote_addr.v4, 4); hicnp_msg->payload.route.prefix.address.af = ADDRESS_IP4; - } - else { - memcpy(&hicnp_msg->payload.route.prefix.address.un.ip6[0], &route->remote_addr.v6, 16); + hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP4; + } else { + memcpy(&hicnp_msg->payload.route.prefix.address.un.ip6[0], + &route->remote_addr.v6, 16); hicnp_msg->payload.route.prefix.address.af = ADDRESS_IP6; + hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP6; } hicnp_msg->payload.route.prefix.len = route->len; @@ -596,87 +571,101 @@ static int _hc_route_create_internal(hc_sock_t *socket, hc_route_t *route, bool hicnp_msg->payload.route.paths[0].table_id = 0; hc_face_t *face = &(route->face); - switch (face->face.type) { - case FACE_TYPE_HICN: - { - if (ip46_address_is_ip4((ip46_address_t *)(&(face->face.remote_addr)))) { - memcpy(&(hicnp_msg->payload.route.paths[0].nh.address.ip4), &face->face.remote_addr.v4, sizeof(ip4_address_t)); - hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP4; - } - else{ - memcpy(&(hicnp_msg->payload.route.paths[0].nh.address.ip6), &face->face.remote_addr.v6, sizeof(ip6_address_t)); - hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP6; - } - - hicnp_msg->payload.route.paths[0].type = FIB_API_PATH_FLAG_NONE; - hicnp_msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE; - - break; - } - case FACE_TYPE_UDP: - { - vapi_msg_hicn_api_udp_tunnel_add_del *msg = NULL; - u32 uei = ~0; - - if (ip46_address_is_ip4((ip46_address_t *)(&(face->face.remote_addr))) && - ip46_address_is_ip4((ip46_address_t *)(&(face->face.local_addr)))) { - msg = vapi_alloc_hicn_api_udp_tunnel_add_del(s->g_vapi_ctx_instance); - memcpy(msg->payload.src_addr.un.ip4, &face->face.local_addr.v4, sizeof(ip4_address_t)); - msg->payload.src_addr.af = ADDRESS_IP4; + face->face.netdevice.index = ~0; + face->id = INVALID_FACE_ID; - memcpy(msg->payload.dst_addr.un.ip4, &face->face.remote_addr.v4, sizeof(ip4_address_t)); - msg->payload.dst_addr.af = ADDRESS_IP4; + switch (face->face.type) { + case FACE_TYPE_HICN: { + if (ip_address_is_v4((ip_address_t *)(&(face->face.remote_addr)))) { + memcpy(&(hicnp_msg->payload.route.paths[0].nh.address.ip4), + &face->face.remote_addr.v4, sizeof(ip4_address_t)); + hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP4; + } else { + memcpy(&(hicnp_msg->payload.route.paths[0].nh.address.ip6), + &face->face.remote_addr.v6, sizeof(ip6_address_t)); + hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP6; + } - } else if (!ip46_address_is_ip4((ip46_address_t *)(&(route->face.face.remote_addr))) && - !ip46_address_is_ip4((ip46_address_t *)(&(route->face.face.local_addr)))) { + hicnp_msg->payload.route.paths[0].type = FIB_API_PATH_TYPE_NORMAL; + hicnp_msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE; - msg = vapi_alloc_hicn_api_udp_tunnel_add_del(s->g_vapi_ctx_instance); - memcpy(msg->payload.src_addr.un.ip6, &face->face.local_addr.v6, sizeof(ip6_address_t)); - msg->payload.src_addr.af = ADDRESS_IP4; + break; + } + case FACE_TYPE_UDP: { + vapi_msg_hicn_api_udp_tunnel_add_del *msg = NULL; + u32 uei = ~0; + + if (ip_address_is_v4((ip_address_t *)(&(face->face.remote_addr))) && + ip_address_is_v4((ip_address_t *)(&(face->face.local_addr)))) { + msg = vapi_alloc_hicn_api_udp_tunnel_add_del(s->g_vapi_ctx_instance); + memcpy(msg->payload.src_addr.un.ip4, &face->face.local_addr.v4, + sizeof(ip4_address_t)); + msg->payload.src_addr.af = ADDRESS_IP4; + + memcpy(msg->payload.dst_addr.un.ip4, &face->face.remote_addr.v4, + sizeof(ip4_address_t)); + msg->payload.dst_addr.af = ADDRESS_IP4; + + } else if (!ip_address_is_v4( + (ip_address_t *)(&(route->face.face.remote_addr))) && + !ip_address_is_v4( + (ip_address_t *)(&(route->face.face.local_addr)))) { + msg = vapi_alloc_hicn_api_udp_tunnel_add_del(s->g_vapi_ctx_instance); + memcpy(msg->payload.src_addr.un.ip6, &face->face.local_addr.v6, + sizeof(ip6_address_t)); + msg->payload.src_addr.af = ADDRESS_IP6; + + memcpy(msg->payload.dst_addr.un.ip6, &face->face.remote_addr.v6, + sizeof(ip6_address_t)); + msg->payload.dst_addr.af = ADDRESS_IP6; + } else { + // NOT IMPLEMENTED + ret = -1; + goto done; + } - memcpy(msg->payload.dst_addr.un.ip6, &face->face.remote_addr.v6, sizeof(ip6_address_t)); - msg->payload.dst_addr.af = ADDRESS_IP6; + msg->payload.src_port = face->face.local_port; + msg->payload.dst_port = face->face.remote_port; + msg->payload.is_add = 1; - } else { - //NOT IMPLEMENTED - ret = -1; - goto done; - } + int ret = vapi_hicn_api_udp_tunnel_add_del(s->g_vapi_ctx_instance, msg, + create_udp_tunnel_cb, &uei); - msg->payload.src_port = face->face.local_port; - msg->payload.dst_port = face->face.remote_port; - msg->payload.is_add = 1; + if (ret) { + ERROR("Error in vapi_hicn_api_udp_tunnel_add_del"); + vapi_msg_free(s->g_vapi_ctx_instance, hicnp_msg); + goto done; + } - int ret = vapi_hicn_api_udp_tunnel_add_del(s->g_vapi_ctx_instance, msg, create_udp_tunnel_cb, &uei); + hicnp_msg->payload.route.paths[0].type = FIB_API_PATH_TYPE_UDP_ENCAP; + hicnp_msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE; + hicnp_msg->payload.route.paths[0].nh.obj_id = uei; - if(ret) { - vapi_msg_free(s->g_vapi_ctx_instance, hicnp_msg); - goto done; - } + face->face.netdevice.index = uei; - hicnp_msg->payload.route.paths[0].type = FIB_API_PATH_TYPE_UDP_ENCAP; - hicnp_msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE; - hicnp_msg->payload.route.paths[0].nh.obj_id = uei; - break; - } + break; + } default: ret = -1; goto done; } - ret = vapi_ip_route_add_del(s->g_vapi_ctx_instance, hicnp_msg, parse_route_create, NULL); + ret = vapi_ip_route_add_del(s->g_vapi_ctx_instance, hicnp_msg, + parse_route_create, NULL); - if (ret) + if (ret) { + ERROR("Error in vapi_ip_route_add_del"); goto done; + } - vapi_msg_hicn_api_enable_disable *msg = vapi_alloc_hicn_api_enable_disable(s->g_vapi_ctx_instance); + vapi_msg_hicn_api_enable_disable *msg = + vapi_alloc_hicn_api_enable_disable(s->g_vapi_ctx_instance); if (route->family == AF_INET) { memcpy(&msg->payload.prefix.address.un.ip4[0], &route->remote_addr.v4, 4); msg->payload.prefix.address.af = ADDRESS_IP4; - } - else { + } else { memcpy(&msg->payload.prefix.address.un.ip6[0], &route->remote_addr.v6, 16); msg->payload.prefix.address.af = ADDRESS_IP6; } @@ -684,7 +673,13 @@ static int _hc_route_create_internal(hc_sock_t *socket, hc_route_t *route, bool msg->payload.prefix.len = route->len; msg->payload.enable_disable = 1; - ret = vapi_hicn_api_enable_disable(s->g_vapi_ctx_instance, msg, hicn_enable_cb, NULL); + ret = vapi_hicn_api_enable_disable(s->g_vapi_ctx_instance, msg, + hicn_enable_cb, &face->id); + + if (ret) { + ERROR("Error in vapi_hicn_api_enable_disable"); + } + done: vapi_unlock(); return ret; @@ -699,32 +694,63 @@ static int _hc_route_create_async(hc_sock_t *s, hc_route_t *route) { } /* ROUTE DELETE */ -static vapi_error_e parse_route_delete( vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_ip_route_add_del_reply *reply) { - if (reply == NULL || rv != VAPI_OK) - return rv; +static vapi_error_e parse_route_delete( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_ip_route_add_del_reply *reply) { + if (reply == NULL || rv != VAPI_OK) return rv; + + return reply->retval; +} + +static vapi_error_e hicn_disable_cb( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_hicn_api_enable_disable_reply *reply) { + if (reply == NULL || rv != VAPI_OK) return rv; return reply->retval; } -static int _hc_route_delete_internal(hc_sock_t *socket, hc_route_t *route, bool async) { +static int _hc_route_delete_internal(hc_sock_t *socket, hc_route_t *route, + bool async) { if (!IS_VALID_FAMILY(route->family)) return -1; hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket); vapi_lock(); - vapi_msg_ip_route_add_del *hicnp_msg = vapi_alloc_ip_route_add_del(s->g_vapi_ctx_instance, 1); + + vapi_msg_hicn_api_enable_disable *msg = + vapi_alloc_hicn_api_enable_disable(s->g_vapi_ctx_instance); + + if (route->family == AF_INET) { + memcpy(&msg->payload.prefix.address.un.ip4[0], &route->remote_addr.v4, 4); + msg->payload.prefix.address.af = ADDRESS_IP4; + } else { + memcpy(&msg->payload.prefix.address.un.ip6[0], &route->remote_addr.v6, 16); + msg->payload.prefix.address.af = ADDRESS_IP6; + } + + msg->payload.prefix.len = route->len; + msg->payload.enable_disable = 0; + + vapi_error_e ret = vapi_hicn_api_enable_disable(s->g_vapi_ctx_instance, msg, + hicn_disable_cb, NULL); + + if (ret) { + ERROR("Error in vapi_hicn_api_enable_disable in route delete"); + goto done; + } + + vapi_msg_ip_route_add_del *hicnp_msg = + vapi_alloc_ip_route_add_del(s->g_vapi_ctx_instance, 1); hicnp_msg->payload.is_add = 0; if (route->family == AF_INET) { - memcpy(&hicnp_msg->payload.route.prefix.address.un.ip4[0], &route->remote_addr.v4, 4); + memcpy(&hicnp_msg->payload.route.prefix.address.un.ip4[0], + &route->remote_addr.v4, 4); hicnp_msg->payload.route.prefix.address.af = ADDRESS_IP4; - } - else { - memcpy(&hicnp_msg->payload.route.prefix.address.un.ip6[0], &route->remote_addr.v6, 16); + } else { + memcpy(&hicnp_msg->payload.route.prefix.address.un.ip6[0], + &route->remote_addr.v6, 16); hicnp_msg->payload.route.prefix.address.af = ADDRESS_IP6; } @@ -735,34 +761,41 @@ static int _hc_route_delete_internal(hc_sock_t *socket, hc_route_t *route, bool hc_face_t *face = &(route->face); switch (face->face.type) { - case FACE_TYPE_HICN: - { - if (ip46_address_is_ip4((ip46_address_t *)(&(face->face.remote_addr)))) { - memcpy(&(hicnp_msg->payload.route.paths[0].nh.address.ip4), &face->face.remote_addr.v4, sizeof(ip4_address_t)); - hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP4; - } - else{ - memcpy(&(hicnp_msg->payload.route.paths[0].nh.address.ip6), &face->face.remote_addr.v6, sizeof(ip6_address_t)); - hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP6; - } - - hicnp_msg->payload.route.paths[0].type = FIB_API_PATH_FLAG_NONE; - hicnp_msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE; - - break; - } - case FACE_TYPE_UDP: - { - hicnp_msg->payload.route.paths[0].type = FIB_API_PATH_TYPE_UDP_ENCAP; - hicnp_msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE; - hicnp_msg->payload.route.paths[0].nh.obj_id = face->face.netdevice.index; - break; + case FACE_TYPE_HICN: { + if (ip_address_is_v4((ip_address_t *)(&(face->face.remote_addr)))) { + memcpy(&(hicnp_msg->payload.route.paths[0].nh.address.ip4), + &face->face.remote_addr.v4, sizeof(ip4_address_t)); + hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP4; + } else { + memcpy(&(hicnp_msg->payload.route.paths[0].nh.address.ip6), + &face->face.remote_addr.v6, sizeof(ip6_address_t)); + hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP6; } + + hicnp_msg->payload.route.paths[0].type = FIB_API_PATH_TYPE_NORMAL; + hicnp_msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE; + + break; + } + case FACE_TYPE_UDP: { + hicnp_msg->payload.route.paths[0].type = FIB_API_PATH_TYPE_UDP_ENCAP; + hicnp_msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE; + hicnp_msg->payload.route.paths[0].nh.obj_id = face->face.netdevice.index; + break; + } default: return -1; } - vapi_error_e ret = vapi_ip_route_add_del(s->g_vapi_ctx_instance, hicnp_msg, parse_route_delete, NULL); + ret = vapi_ip_route_add_del(s->g_vapi_ctx_instance, hicnp_msg, + parse_route_delete, NULL); + + if (ret) { + ERROR("Error in vapi_ip_route_add_del in route delete"); + goto done; + } + +done: vapi_unlock(); return ret; @@ -776,33 +809,31 @@ static int _hc_route_delete_async(hc_sock_t *s, hc_route_t *route) { return _hc_route_delete_internal(s, route, true); } -static vapi_error_e parse_udp_encap_list( vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_udp_encap_details *reply) { - if (reply == NULL || rv != VAPI_OK) - return rv; +static vapi_error_e parse_udp_encap_list( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_udp_encap_details *reply) { + if (reply == NULL || rv != VAPI_OK) return rv; - hc_face_t * face = (hc_face_t *)callback_ctx; + hc_face_t *face = (hc_face_t *)callback_ctx; - if (face->face.netdevice.index == reply->udp_encap.id) - { - switch(reply->udp_encap.src_ip.af) { - case ADDRESS_IP4: - { - memcpy(&face->face.local_addr.v4, &(reply->udp_encap.src_ip.un.ip4), sizeof(ip4_address_t)); - memcpy(&face->face.remote_addr.v4, &(reply->udp_encap.dst_ip.un.ip4), sizeof(ip4_address_t)); + if (face->face.netdevice.index == reply->udp_encap.id) { + switch (reply->udp_encap.src_ip.af) { + case ADDRESS_IP4: { + memcpy(&face->face.local_addr.v4, &(reply->udp_encap.src_ip.un.ip4), + sizeof(ip4_address_t)); + memcpy(&face->face.remote_addr.v4, &(reply->udp_encap.dst_ip.un.ip4), + sizeof(ip4_address_t)); break; } - case ADDRESS_IP6: - { - memcpy(&face->face.local_addr.v6, &(reply->udp_encap.src_ip.un.ip6), sizeof(ip6_address_t)); - memcpy(&face->face.remote_addr.v6, &(reply->udp_encap.dst_ip.un.ip6), sizeof(ip6_address_t)); + case ADDRESS_IP6: { + memcpy(&face->face.local_addr.v6, &(reply->udp_encap.src_ip.un.ip6), + sizeof(ip6_address_t)); + memcpy(&face->face.remote_addr.v6, &(reply->udp_encap.dst_ip.un.ip6), + sizeof(ip6_address_t)); break; } default: - break; + break; } face->face.local_port = reply->udp_encap.src_port; @@ -811,35 +842,35 @@ static vapi_error_e parse_udp_encap_list( vapi_ctx_t ctx, return rv; } -static int _fill_face_with_info(hc_face_t * face, vapi_type_fib_path *path, hc_sock_t *s) { - switch(path->type){ - case FIB_API_PATH_FLAG_NONE: - { +static int _fill_face_with_info(hc_face_t *face, vapi_type_fib_path *path, + hc_sock_t *s) { + switch (path->type) { + case FIB_API_PATH_FLAG_NONE: { face->face.type = FACE_TYPE_HICN; - switch(path->proto){ + switch (path->proto) { case FIB_API_PATH_NH_PROTO_IP4: - memcpy(&face->face.remote_addr.v4, &(path->nh.address.ip4), sizeof(ip4_address_t)); - break; + memcpy(&face->face.remote_addr.v4, &(path->nh.address.ip4), + sizeof(ip4_address_t)); + break; case FIB_API_PATH_NH_PROTO_IP6: - memcpy(&face->face.remote_addr.v6, &(path->nh.address.ip6), sizeof(ip6_address_t)); - break; + memcpy(&face->face.remote_addr.v6, &(path->nh.address.ip6), + sizeof(ip6_address_t)); + break; default: - break; + break; } face->face.netdevice.index = path->sw_if_index; - } - break; - case FIB_API_PATH_TYPE_UDP_ENCAP: - { + } break; + case FIB_API_PATH_TYPE_UDP_ENCAP: { face->face.type = FACE_TYPE_UDP; face->face.netdevice.index = clib_net_to_host_u32(path->nh.obj_id); // Let's make the compiler happy (void)parse_udp_encap_list; - //vapi_msg_udp_encap_dump *msg; - //msg = vapi_alloc_udp_encap_dump(s->g_vapi_ctx_instance); - //vapi_udp_encap_dump(s->g_vapi_ctx_instance, msg, parse_udp_encap_list, face); - } - break; + // vapi_msg_udp_encap_dump *msg; + // msg = vapi_alloc_udp_encap_dump(s->g_vapi_ctx_instance); + // vapi_udp_encap_dump(s->g_vapi_ctx_instance, msg, parse_udp_encap_list, + // face); + } break; default: return -1; } @@ -852,32 +883,33 @@ typedef struct hicn_route_socket_s { hc_sock_t *s; } hicn_route_socket_t; -static vapi_error_e parse_route_list( vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_ip_route_details *reply) { - - if (reply == NULL || rv != VAPI_OK) - return rv; +static vapi_error_e parse_route_list(vapi_ctx_t ctx, void *callback_ctx, + vapi_error_e rv, bool is_last, + vapi_payload_ip_route_details *reply) { + if (reply == NULL || rv != VAPI_OK) return rv; hicn_route_socket_t *rs = (hicn_route_socket_t *)callback_ctx; hc_data_t *data = rs->data; u8 found = false; - for (int j = 0; j < reply->route.n_paths; j++){ + for (int j = 0; j < reply->route.n_paths; j++) { for (int i = 0; i < data->size && !found; i++) { - hc_route_t * route = &((hc_route_t*)(data->buffer))[i]; - - if(ip46_address_is_ip4((ip46_address_t *)&(route->remote_addr)) && - memcmp(route->remote_addr.v4.as_u8, reply->route.prefix.address.un.ip4, sizeof(ip4_address_t)) == 0 && - route->len == reply->route.prefix.len && route->face_id == ~0) { - _fill_face_with_info(&(route->face), &reply->route.paths[j], rs->s); - found = true; - } else if (memcmp(route->remote_addr.v6.as_u8, reply->route.prefix.address.un.ip6, sizeof(ip6_address_t)) == 0 && - route->len == reply->route.prefix.len && route->face_id == ~0) { - _fill_face_with_info(&(route->face), &reply->route.paths[j], rs->s); - found = true; + hc_route_t *route = &((hc_route_t *)(data->buffer))[i]; + + if (ip_address_is_v4((ip_address_t *)&(route->remote_addr)) && + memcmp(route->remote_addr.v4.as_u8, + reply->route.prefix.address.un.ip4, + sizeof(ip4_address_t)) == 0 && + route->len == reply->route.prefix.len && route->face_id == ~0) { + _fill_face_with_info(&(route->face), &reply->route.paths[j], rs->s); + found = true; + } else if (memcmp(route->remote_addr.v6.as_u8, + reply->route.prefix.address.un.ip6, + sizeof(ip6_address_t)) == 0 && + route->len == reply->route.prefix.len && + route->face_id == ~0) { + _fill_face_with_info(&(route->face), &reply->route.paths[j], rs->s); + found = true; } } } @@ -885,14 +917,10 @@ static vapi_error_e parse_route_list( vapi_ctx_t ctx, return rv; } -static vapi_error_e parse_hicn_route_list( vapi_ctx_t ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_hicn_api_routes_details *reply) { - - if (reply == NULL || rv != VAPI_OK) - return rv; +static vapi_error_e parse_hicn_route_list( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_hicn_api_routes_details *reply) { + if (reply == NULL || rv != VAPI_OK) return rv; hc_data_t *data = (hc_data_t *)callback_ctx; @@ -900,43 +928,41 @@ static vapi_error_e parse_hicn_route_list( vapi_ctx_t ctx, if (empty_spots < reply->nfaces) { int new_size = data->size + (reply->nfaces - empty_spots); data->buffer = realloc(data->buffer, sizeof(hc_route_t) * (new_size)); - if (!data->buffer) - return VAPI_ENOMEM; + if (!data->buffer) return VAPI_ENOMEM; - data->size =new_size; + data->size = new_size; } for (int i = 0; i < reply->nfaces; i++) { - hc_route_t * route = &((hc_route_t*)(data->buffer))[data->current]; + hc_route_t *route = &((hc_route_t *)(data->buffer))[data->current]; route->face_id = ~0; route->cost = 1; route->len = reply->prefix.len; - if (reply->prefix.address.af == ADDRESS_IP6) - { - memcpy(route->remote_addr.v6.as_u8, reply->prefix.address.un.ip6, 16); - } - else - { - memcpy(route->remote_addr.v4.as_u8, reply->prefix.address.un.ip4, 4); - } - route->family = reply->prefix.address.af == ADDRESS_IP6? AF_INET6 : AF_INET; + if (reply->prefix.address.af == ADDRESS_IP6) { + memcpy(route->remote_addr.v6.as_u8, reply->prefix.address.un.ip6, 16); + } else { + memcpy(route->remote_addr.v4.as_u8, reply->prefix.address.un.ip4, 4); + } + route->family = + reply->prefix.address.af == ADDRESS_IP6 ? AF_INET6 : AF_INET; data->current++; } return rv; } -static int _hc_route_list_internal(hc_sock_t *socket, hc_data_t **pdata, bool async) { +static int _hc_route_list_internal(hc_sock_t *socket, hc_data_t **pdata, + bool async) { hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket); vapi_lock(); vapi_msg_hicn_api_routes_dump *msg; msg = vapi_alloc_hicn_api_routes_dump(s->g_vapi_ctx_instance); - hc_data_t *data = hc_data_create(0, sizeof(hc_route_t),NULL); + hc_data_t *data = hc_data_create(0, sizeof(hc_route_t), NULL); int ret = VAPI_OK; - if (!data){ + if (!data) { ret = -1; goto err; } @@ -949,10 +975,10 @@ static int _hc_route_list_internal(hc_sock_t *socket, hc_data_t **pdata, bool as goto err_free; } - ret = vapi_hicn_api_routes_dump(s->g_vapi_ctx_instance, msg, parse_hicn_route_list, data); + ret = vapi_hicn_api_routes_dump(s->g_vapi_ctx_instance, msg, + parse_hicn_route_list, data); - if (ret != VAPI_OK) - goto err_free; + if (ret != VAPI_OK) goto err_free; vapi_msg_ip_route_dump *hicnp_msg; hicnp_msg = vapi_alloc_ip_route_dump(s->g_vapi_ctx_instance); @@ -960,29 +986,30 @@ static int _hc_route_list_internal(hc_sock_t *socket, hc_data_t **pdata, bool as hicnp_msg->payload.table.is_ip6 = 1; hicn_route_socket_t ctx = { - .data = data, - .s = socket, + .data = data, + .s = socket, }; - ret = vapi_ip_route_dump(s->g_vapi_ctx_instance, hicnp_msg, parse_route_list, &ctx); + ret = vapi_ip_route_dump(s->g_vapi_ctx_instance, hicnp_msg, parse_route_list, + &ctx); hicnp_msg = vapi_alloc_ip_route_dump(s->g_vapi_ctx_instance); hicnp_msg->payload.table.table_id = 0; hicnp_msg->payload.table.is_ip6 = 0; - ret = vapi_ip_route_dump(s->g_vapi_ctx_instance, hicnp_msg, parse_route_list, &ctx); + ret = vapi_ip_route_dump(s->g_vapi_ctx_instance, hicnp_msg, parse_route_list, + &ctx); - if (ret != VAPI_OK) - goto err_free; + if (ret != VAPI_OK) goto err_free; *pdata = data; vapi_unlock(); return ret; - err_free: +err_free: free(data); - err: +err: vapi_unlock(); return ret; } @@ -1008,17 +1035,19 @@ static int _hc_route_list_async(hc_sock_t *s) { * *----------------------------------------------------------------------------*/ -static int _hc_face_create(hc_sock_t *s, hc_face_t *face) { - ERROR("Face creation implemented."); +static int _hc_face_create(hc_sock_t *socket, hc_face_t *face) { + ERROR("Face creation not implemented."); return -1; } -static int _hc_face_get(hc_sock_t * socket, hc_face_t * face, hc_face_t ** face_found) { +static int _hc_face_get(hc_sock_t *socket, hc_face_t *face, + hc_face_t **face_found) { ERROR("Face deletion not implemented."); return -1; } -static int _hc_face_delete(hc_sock_t *s, hc_face_t *face) { +static int _hc_face_delete(hc_sock_t *s, hc_face_t *face, + uint8_t delete_listener) { ERROR("Face deletion not implemented."); return -1; } @@ -1030,9 +1059,7 @@ static int _hc_face_list(hc_sock_t *s, hc_data_t **pdata) { return -1; } -static int _hc_face_list_async(hc_sock_t *s) { - return 0; -} +static int _hc_face_list_async(hc_sock_t *s) { return 0; } static int _hc_face_set_admin_state( hc_sock_t *s, const char *conn_id_or_name, // XXX wrong identifier @@ -1041,22 +1068,25 @@ static int _hc_face_set_admin_state( } #ifdef WITH_POLICY -static int _hc_face_set_priority(hc_sock_t * s, const char * conn_id_or_name, uint32_t priority) { +static int _hc_face_set_priority(hc_sock_t *s, const char *conn_id_or_name, + uint32_t priority) { ERROR("Face set priority not implemented."); return -1; } -static int _hc_face_set_tags(hc_sock_t * s, const char * conn_id_or_name, policy_tags_t tags) { +static int _hc_face_set_tags(hc_sock_t *s, const char *conn_id_or_name, + policy_tags_t tags) { ERROR("Face set tags not implemented."); return -1; } -#endif // WITH_POLICY +#endif // WITH_POLICY /*----------------------------------------------------------------------------* * Punting *----------------------------------------------------------------------------*/ -static int _hc_punting_create_internal(hc_sock_t *s, hc_punting_t *punting, bool async) { +static int _hc_punting_create_internal(hc_sock_t *s, hc_punting_t *punting, + bool async) { return -1; } @@ -1069,7 +1099,7 @@ static int _hc_punting_create_async(hc_sock_t *s, hc_punting_t *punting) { } static int _hc_punting_get(hc_sock_t *s, hc_punting_t *punting, - hc_punting_t **punting_found) { + hc_punting_t **punting_found) { ERROR("hc_punting_get not (yet) implemented."); return -1; } @@ -1088,28 +1118,30 @@ static int _hc_punting_list(hc_sock_t *s, hc_data_t **pdata) { * Cache *----------------------------------------------------------------------------*/ -static int _hc_cache_set_store_internal(hc_sock_t *s, int enabled, bool async) { +static int _hc_cache_set_store_internal(hc_sock_t *s, hc_cache_t *cache, + bool async) { return 0; } -static int _hc_cache_set_store(hc_sock_t *s, int enabled) { - return _hc_cache_set_store_internal(s, enabled, false); +static int _hc_cache_set_store(hc_sock_t *s, hc_cache_t *cache) { + return _hc_cache_set_store_internal(s, cache, false); } -static int _hc_cache_set_store_async(hc_sock_t *s, int enabled) { - return _hc_cache_set_store_internal(s, enabled, true); +static int _hc_cache_set_store_async(hc_sock_t *s, hc_cache_t *cache) { + return _hc_cache_set_store_internal(s, cache, true); } -static int _hc_cache_set_serve_internal(hc_sock_t *s, int enabled, bool async) { +static int _hc_cache_set_serve_internal(hc_sock_t *s, hc_cache_t *cache, + bool async) { return 0; } -static int _hc_cache_set_serve(hc_sock_t *s, int enabled) { - return _hc_cache_set_serve_internal(s, enabled, false); +static int _hc_cache_set_serve(hc_sock_t *s, hc_cache_t *cache) { + return _hc_cache_set_serve_internal(s, cache, false); } -static int _hc_cache_set_serve_async(hc_sock_t *s, int enabled) { - return _hc_cache_set_serve_internal(s, enabled, true); +static int _hc_cache_set_serve_async(hc_sock_t *s, hc_cache_t *cache) { + return _hc_cache_set_serve_internal(s, cache, true); } /*----------------------------------------------------------------------------* @@ -1117,12 +1149,15 @@ static int _hc_cache_set_serve_async(hc_sock_t *s, int enabled) { *----------------------------------------------------------------------------*/ // per prefix -static int _hc_strategy_set(hc_sock_t *s /* XXX */) { return 0; } +static int _hc_strategy_set(hc_sock_t *s, hc_strategy_t *strategy) { return 0; } -static int _hc_strategy_list(hc_sock_t *s, hc_data_t **data) { +static int _hc_strategy_add_local_prefix(hc_sock_t *s, + hc_strategy_t *strategy) { return 0; } +static int _hc_strategy_list(hc_sock_t *s, hc_data_t **data) { return 0; } + /*----------------------------------------------------------------------------* * WLDR *----------------------------------------------------------------------------*/ @@ -1138,9 +1173,11 @@ static int _hc_mapme_set(hc_sock_t *s, int enabled) { return 0; } static int _hc_mapme_set_discovery(hc_sock_t *s, int enabled) { return 0; } -static int _hc_mapme_set_timescale(hc_sock_t *s, double timescale) { return 0; } +static int _hc_mapme_set_timescale(hc_sock_t *s, uint32_t timescale) { + return 0; +} -static int _hc_mapme_set_retx(hc_sock_t *s, double timescale) { return 0; } +static int _hc_mapme_set_retx(hc_sock_t *s, uint32_t timescale) { return 0; } /*----------------------------------------------------------------------------* * Policy @@ -1150,51 +1187,99 @@ static int _hc_mapme_set_retx(hc_sock_t *s, double timescale) { return 0; } /* POLICY CREATE */ -static int _hc_policy_create_internal(hc_sock_t * socket, hc_policy_t * policy, bool async) { +static int _hc_policy_create_internal(hc_sock_t *socket, hc_policy_t *policy, + bool async) { return -1; } -static int -_hc_policy_create(hc_sock_t * s, hc_policy_t * policy) { +static int _hc_policy_create(hc_sock_t *s, hc_policy_t *policy) { return _hc_policy_create_internal(s, policy, false); } -static int _hc_policy_create_async(hc_sock_t * s, hc_policy_t * policy) { +static int _hc_policy_create_async(hc_sock_t *s, hc_policy_t *policy) { return _hc_policy_create_internal(s, policy, true); } /* POLICY DELETE */ -static int _hc_policy_delete_internal(hc_sock_t * socket, hc_policy_t * policy, bool async) { +static int _hc_policy_delete_internal(hc_sock_t *socket, hc_policy_t *policy, + bool async) { return -1; } -static int _hc_policy_delete(hc_sock_t * s, hc_policy_t * policy) { +static int _hc_policy_delete(hc_sock_t *s, hc_policy_t *policy) { return _hc_policy_delete_internal(s, policy, false); } -static int _hc_policy_delete_async(hc_sock_t * s, hc_policy_t * policy) { +static int _hc_policy_delete_async(hc_sock_t *s, hc_policy_t *policy) { return _hc_policy_delete_internal(s, policy, true); } /* POLICY LIST */ -static int -_hc_policy_list_internal(hc_sock_t * socket, hc_data_t ** pdata, bool async) { +static int _hc_policy_list_internal(hc_sock_t *socket, hc_data_t **pdata, + bool async) { return -1; } -static int _hc_policy_list(hc_sock_t * s, hc_data_t ** pdata) { +static int _hc_policy_list(hc_sock_t *s, hc_data_t **pdata) { return _hc_policy_list_internal(s, pdata, false); } -static int _hc_policy_list_async(hc_sock_t * s, hc_data_t ** pdata) { +static int _hc_policy_list_async(hc_sock_t *s, hc_data_t **pdata) { return _hc_policy_list_internal(s, pdata, true); } #endif /* WITH_POLICY */ -static hc_sock_t hc_sock_vpp_interface = (hc_sock_t) { +/*----------------------------------------------------------------------------* + * Configuration + *----------------------------------------------------------------------------*/ + +typedef struct hc_result_s { + void *_; +} hc_result_t; + +static hc_result_t *_hc_listener_create_conf(hc_sock_t *s, + hc_listener_t *listener) { + ERROR("Not implemented."); + return NULL; +} +static hc_result_t *_hc_connection_create_conf(hc_sock_t *s, + hc_connection_t *connection) { + ERROR("Not implemented."); + return NULL; +} +static hc_result_t *_hc_route_create_conf(hc_sock_t *s, hc_route_t *route) { + ERROR("Not implemented."); + return NULL; +} +static hc_result_t *_hc_strategy_set_conf(hc_sock_t *s, + hc_strategy_t *strategy) { + ERROR("Not implemented."); + return NULL; +} +static hc_result_t *_hc_strategy_add_local_prefix_conf( + hc_sock_t *s, hc_strategy_t *strategy) { + ERROR("Not implemented."); + return NULL; +} + +hc_msg_t *_hc_result_get_msg(hc_result_t *result) { + ERROR("Not implemented."); + return NULL; +} +int _hc_result_get_cmd_id(hc_result_t *result) { + ERROR("Not implemented."); + return -1; +} +bool _hc_result_get_success(hc_result_t *result) { + ERROR("Not implemented."); + return false; +} +void _hc_result_free(hc_result_t *result) { free(result); } + +static hc_sock_t hc_sock_vpp_interface = (hc_sock_t){ .hc_sock_get_next_seq = _hc_sock_vpp_get_next_seq, .hc_sock_set_nonblocking = _hc_sock_vpp_set_nonblocking, .hc_sock_get_fd = _hc_sock_vpp_get_fd, @@ -1230,7 +1315,7 @@ static hc_sock_t hc_sock_vpp_interface = (hc_sock_t) { .hc_connection_set_priority_async = _hc_connection_set_priority_async, .hc_connection_set_tags = _hc_connection_set_tags, .hc_connection_set_tags_async = _hc_connection_set_tags_async, -#endif // WITH_POLICY +#endif // WITH_POLICY .hc_face_create = _hc_face_create, .hc_face_get = _hc_face_get, @@ -1242,7 +1327,7 @@ static hc_sock_t hc_sock_vpp_interface = (hc_sock_t) { #ifdef WITH_POLICY .hc_face_set_priority = _hc_face_set_priority, .hc_face_set_tags = _hc_face_set_tags, -#endif // WITH_POLICY +#endif // WITH_POLICY .hc_route_create = _hc_route_create, .hc_route_create_async = _hc_route_create_async, @@ -1264,6 +1349,7 @@ static hc_sock_t hc_sock_vpp_interface = (hc_sock_t) { .hc_strategy_list = _hc_strategy_list, .hc_strategy_set = _hc_strategy_set, + .hc_strategy_add_local_prefix = _hc_strategy_add_local_prefix, .hc_wldr_set = _hc_wldr_set, .hc_mapme_set = _hc_mapme_set, @@ -1277,16 +1363,27 @@ static hc_sock_t hc_sock_vpp_interface = (hc_sock_t) { .hc_policy_delete = _hc_policy_delete, .hc_policy_delete_async = _hc_policy_delete_async, .hc_policy_list = _hc_policy_list, - .hc_policy_list_async = _hc_policy_list_async -#endif // WITH_POLICY + .hc_policy_list_async = _hc_policy_list_async, +#endif // WITH_POLICY + + .hc_listener_create_conf = _hc_listener_create_conf, + .hc_connection_create_conf = _hc_connection_create_conf, + .hc_route_create_conf = _hc_route_create_conf, + .hc_strategy_set_conf = _hc_strategy_set_conf, + .hc_strategy_add_local_prefix_conf = _hc_strategy_add_local_prefix_conf, + + .hc_result_get_msg = _hc_result_get_msg, + .hc_result_get_cmd_id = _hc_result_get_cmd_id, + .hc_result_get_success = _hc_result_get_success, + .hc_result_free = _hc_result_free, }; hc_sock_t *_hc_sock_create_url(const char *url) { - // NOT IMPLEMENTED - return NULL; -} + if (url) { + // NOT IMPLEMENTED + return NULL; + } -hc_sock_t *_hc_sock_create(void) { hc_sock_vpp_t *s = malloc(sizeof(hc_sock_vpp_t)); if (!s) goto ERR_SOCK; @@ -1302,4 +1399,4 @@ hc_sock_t *_hc_sock_create(void) { ERR_SOCK: return NULL; -}
\ No newline at end of file +} diff --git a/ctrl/libhicnctrl/src/route.c b/ctrl/libhicnctrl/src/route.c index 703b4763f..f59dbce7c 100644 --- a/ctrl/libhicnctrl/src/route.c +++ b/ctrl/libhicnctrl/src/route.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -25,84 +25,64 @@ #define DEFAULT_HICN_ROUTE_COST 1 struct hicn_route_s { - ip_prefix_t prefix; - face_id_t face_id; - route_cost_t cost; /* Optional, 0 means no value, defaults to 1 */ + ip_prefix_t prefix; + face_id_t face_id; + route_cost_t cost; /* Optional, 0 means no value, defaults to 1 */ }; -hicn_route_t * -hicn_route_create(ip_prefix_t * prefix, face_id_t face_id, route_cost_t cost) -{ - hicn_route_t * route = malloc(sizeof(hicn_route_t)); - if (!route) - return NULL; - route->prefix = *prefix; - route->face_id = face_id; - route->cost = cost != 0 ? cost : DEFAULT_HICN_ROUTE_COST; +hicn_route_t* hicn_route_create(ip_prefix_t* prefix, face_id_t face_id, + route_cost_t cost) { + hicn_route_t* route = malloc(sizeof(hicn_route_t)); + if (!route) return NULL; + route->prefix = *prefix; + route->face_id = face_id; + route->cost = cost != 0 ? cost : DEFAULT_HICN_ROUTE_COST; - return route; + return route; } -hicn_route_t * -hicn_route_dup(const hicn_route_t * route) -{ - hicn_route_t * new_route = malloc(sizeof(hicn_route_t)); - if (!route) - return NULL; - memcpy(new_route, route, sizeof(hicn_route_t)); - return new_route; +hicn_route_t* hicn_route_dup(const hicn_route_t* route) { + hicn_route_t* new_route = malloc(sizeof(hicn_route_t)); + if (!route) return NULL; + memcpy(new_route, route, sizeof(hicn_route_t)); + return new_route; } -void hicn_route_free(hicn_route_t * route) -{ - free(route); -} +void hicn_route_free(hicn_route_t* route) { free(route); } -int -hicn_route_cmp(const hicn_route_t * route1, const hicn_route_t * route2) -{ - int rc; - rc = ip_prefix_cmp(&route1->prefix, &route2->prefix); - if (rc != 0) - return rc; +int hicn_route_cmp(const hicn_route_t* route1, const hicn_route_t* route2) { + int rc; + rc = ip_prefix_cmp(&route1->prefix, &route2->prefix); + if (rc != 0) return rc; - return (route1->face_id > route2->face_id) ? 1 : - (route1->face_id < route2->face_id) ? -1 : 0; + return (route1->face_id > route2->face_id) ? 1 + : (route1->face_id < route2->face_id) ? -1 + : 0; } -int -hicn_route_get_prefix(const hicn_route_t * route, ip_prefix_t * prefix) -{ - *prefix = route->prefix; - return 0; +int hicn_route_get_prefix(const hicn_route_t* route, ip_prefix_t* prefix) { + *prefix = route->prefix; + return 0; } -int -hicn_route_set_prefix(hicn_route_t * route, const ip_prefix_t prefix) -{ - route->prefix = prefix; - return 0; +int hicn_route_set_prefix(hicn_route_t* route, const ip_prefix_t prefix) { + route->prefix = prefix; + return 0; } -int -hicn_route_get_cost(const hicn_route_t * route, int * cost) -{ - *cost = route->cost; - return 0; +int hicn_route_get_cost(const hicn_route_t* route, int* cost) { + *cost = route->cost; + return 0; } -int -hicn_route_set_cost(hicn_route_t * route, const int cost) -{ - route->cost = cost; - return 0; +int hicn_route_set_cost(hicn_route_t* route, const int cost) { + route->cost = cost; + return 0; } /* /!\ Please update constants in header file upon changes */ -size_t -hicn_route_snprintf(char * s, size_t size, const hicn_route_t * route) -{ - char prefix_s[MAXSZ_PREFIX]; - ip_prefix_ntop(&route->prefix, prefix_s, MAXSZ_PREFIX); - return snprintf(s, size, "%s [%d]", prefix_s, route->cost); +size_t hicn_route_snprintf(char* s, size_t size, const hicn_route_t* route) { + char prefix_s[MAXSZ_IP_PREFIX]; + ip_prefix_ntop(&route->prefix, prefix_s, MAXSZ_IP_PREFIX); + return snprintf(s, size, "%s [%d]", prefix_s, route->cost); } diff --git a/ctrl/libhicnctrl/src/util/hash.h b/ctrl/libhicnctrl/src/util/hash.h index 7c7bb1e3a..f3a1eedcc 100644 --- a/ctrl/libhicnctrl/src/util/hash.h +++ b/ctrl/libhicnctrl/src/util/hash.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -27,67 +27,88 @@ #ifndef UTIL_HASH_H #define UTIL_HASH_H -#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ - __BYTE_ORDER == __LITTLE_ENDIAN) || \ +#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 + 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 + __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 +#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 hashsize(n) ((uint32_t)1 << (n)) +#define hashmask(n) (hashsize(n) - 1) +#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) -#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); \ -} +#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; \ + } -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 */ +#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 */ + 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) - { + while (length > 12) { a += k[0]; b += k[1]; c += k[2]; - mix(a,b,c); + mix(a, b, c); length -= 12; k += 3; } @@ -104,136 +125,214 @@ uint32_t hashlittle( const void *key, size_t length, uint32_t initval) */ #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 */ + 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; + 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; + 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); + 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 */ + 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 */ + } 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) - { + while (length > 12) { a += k[0]; - a += ((uint32_t)k[1])<<8; - a += ((uint32_t)k[2])<<16; - a += ((uint32_t)k[3])<<24; + 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; + 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); + 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 */ + 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; + 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); + final(a, b, c); return c; } @@ -241,7 +340,7 @@ uint32_t hashlittle( const void *key, size_t length, uint32_t initval) #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(buf, len) hashlittle(buf, len, HASH_INITVAL) #define hash_struct(buf) hash(buf, sizeof(buf)) #endif /* UTIL_JENKINS_HASH_H */ |