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 | |
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')
27 files changed, 6909 insertions, 5824 deletions
diff --git a/ctrl/libhicnctrl/CMakeLists.txt b/ctrl/libhicnctrl/CMakeLists.txt index 22f81401f..bf5ffd699 100644 --- a/ctrl/libhicnctrl/CMakeLists.txt +++ b/ctrl/libhicnctrl/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,50 +11,65 @@ # See the License for the specific language governing permissions and # limitations under the License. +############################################################## +# Project and cmake version +############################################################## cmake_minimum_required(VERSION 3.10 FATAL_ERROR) - project(libhicnctrl) -if (NOT CMAKE_BUILD_TYPE) - message(STATUS "${PROJECT_NAME}: No build type selected, default to Release") - set(CMAKE_BUILD_TYPE "Release") -endif() +############################################################## +# Cmake modules +############################################################## set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/Modules" - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" ) -include(BuildMacros) - -set(CMAKE_C_STANDARD 11) -set(CMAKE_C_STANDARD_REQUIRED ON) - -set(CMAKE_MACOSX_RPATH ON) - +############################################################## +# Libs and Bins names +############################################################## set(LIBHICNCTRL hicnctrl) - set(LIBHICNCTRL ${LIBHICNCTRL} CACHE INTERNAL "" FORCE) set(LIBHICNCTRL_SHARED ${LIBHICNCTRL}.shared CACHE INTERNAL "" FORCE) set(LIBHICNCTRL_STATIC ${LIBHICNCTRL}.static CACHE INTERNAL "" FORCE) set(HICNCTRL hicnctrl CACHE INTERNAL "" FORCE) -set(LIBHICNCTRL_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/includes CACHE INTERNAL "" FORCE) +set(LIBHICNCTRL_COMPONENT lib${LIBHICNCTRL}) +set(LIBHICNCTRL_COMPONENT_MODULES ${LIBHICNCTRL_COMPONENT}-modules) + + +############################################################## +# Packaging and versioning +############################################################## +include(${CMAKE_CURRENT_SOURCE_DIR}/../../versions.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/packaging.cmake) + +############################################################## +# C Standard +############################################################## +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) + +set(CMAKE_MACOSX_RPATH ON) + + +############################################################## +# Check if building as subproject or as root project +############################################################## if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) - if (BUILD_HICNPLUGIN AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - find_package_wrapper(HicnPlugin REQUIRED) - endif() + include(CommonSetup) - find_package_wrapper(Libhicn REQUIRED) - list(APPEND HICN_LIBRARIES ${LIBHICN_SHARED}) + find_package(Libhicn ${CURRENT_VERSION} REQUIRED NO_MODULE) - set(HICN_INCLUDE_DIRS - ${HICN_INCLUDE_DIRS} - ${HICNPLUGIN_INCLUDE_DIRS} - ${SAFE_VAPI_INCLUDE_DIRS}) + if (DISABLE_SHARED_LIBRARIES) + set(LIBTYPE static) + else() + set(LIBTYPE shared) + endif() + list(APPEND HICN_LIBRARIES hicn::hicn.${LIBTYPE}) else() if (DISABLE_SHARED_LIBRARIES) if (WIN32) @@ -65,36 +80,21 @@ else() list(APPEND DEPENDENCIES ${LIBHICN_STATIC} ) - elseif (BUILD_HICNPLUGIN AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - set( - HICN_INCLUDE_DIRS - ${HICN_INCLUDE_DIRS} - ${HICNPLUGIN_INCLUDE_DIRS} - ${SAFE_VAPI_INCLUDE_DIRS} - ) - - list(APPEND DEPENDENCIES - hicn_plugin - ${SAFE_VAPI_SHARED} - ) else () set(HICN_LIBRARIES ${LIBHICN_SHARED}) list(APPEND DEPENDENCIES ${LIBHICN_SHARED} ) endif () - endif() -set(LIBHICNCTRL_COMPONENT lib${LIBHICNCTRL}) -set (LIBHICNCTRL_COMPONENT_MODULES ${LIBHICNCTRL_COMPONENT}-modules) +############################################################## +# Include directories +############################################################## add_subdirectory(includes) add_subdirectory(src) -include(Packaging) - if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) - include(Packager) - make_packages() + make_packages() endif() diff --git a/ctrl/libhicnctrl/cmake/Modules/Packaging.cmake b/ctrl/libhicnctrl/cmake/packaging.cmake index 2851375be..74905d6c4 100644 --- a/ctrl/libhicnctrl/cmake/Modules/Packaging.cmake +++ b/ctrl/libhicnctrl/cmake/packaging.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Copyright (c) 2021-2022 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: @@ -31,7 +31,7 @@ set(${LIBHICNCTRL_COMPONENT}_DEB_DEPENDENCIES ) set(${LIBHICNCTRL_COMPONENT}-dev_DEB_DEPENDENCIES - "${LIBHICNCTRL_COMPONENT} (>= stable_version)" + "${LIBHICNCTRL_COMPONENT} (= stable_version)" CACHE STRING "Dependencies for deb/rpm package." ) @@ -41,16 +41,16 @@ set(${LIBHICNCTRL_COMPONENT}_RPM_DEPENDENCIES ) set(${LIBHICNCTRL_COMPONENT}-dev_RPM_DEPENDENCIES - "${LIBHICNCTRL_COMPONENT} >= stable_version" + "${LIBHICNCTRL_COMPONENT} = stable_version" CACHE STRING "Dependencies for deb/rpm package." ) set(${LIBHICNCTRL_COMPONENT_MODULES}_DEB_DEPENDENCIES - "hicn-plugin (>= stable_version)" + "hicn-plugin (= stable_version)" CACHE STRING "Dependencies for deb/rpm package." ) set(${LIBHICNCTRL_COMPONENT_MODULES}_RPM_DEPENDENCIES - "hicn-plugin >= stable_version" + "hicn-plugin = stable_version" CACHE STRING "Dependencies for deb/rpm package." ) diff --git a/ctrl/libhicnctrl/examples/create_face.c b/ctrl/libhicnctrl/examples/create_face.c index 5f92f5906..ebd451de1 100644 --- a/ctrl/libhicnctrl/examples/create_face.c +++ b/ctrl/libhicnctrl/examples/create_face.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -22,125 +22,122 @@ */ #include <stdlib.h> -#include <sys/types.h> // getifaddrs -#include <ifaddrs.h> // getifaddrs +#include <sys/types.h> // getifaddrs +#include <ifaddrs.h> // getifaddrs #include <stdio.h> -#include <string.h> /* for strncpy */ -#include <sys/socket.h> // socket -#include <sys/ioctl.h> // ioctl +#include <sys/socket.h> // socket +#include <sys/ioctl.h> // ioctl #include <unistd.h> #include <hicn/ctrl.h> #include <hicn/util/log.h> -int get_local_info(char * if_name, ip_address_t * local_ip) { - struct ifaddrs *addrs; - struct ifreq ifr = { - .ifr_addr.sa_family = AF_INET, - }; - int ret = -1; - - int fd = socket(AF_INET, SOCK_DGRAM, 0); - - getifaddrs(&addrs); - - for (struct ifaddrs * tmp = addrs; tmp; tmp = tmp->ifa_next) { - if (!tmp->ifa_addr || tmp->ifa_addr->sa_family != AF_PACKET) - continue; - if (strcmp(tmp->ifa_name, "lo") == 0) - continue; - snprintf(if_name, IFNAMSIZ, "%s", tmp->ifa_name); - - snprintf(ifr.ifr_name, IFNAMSIZ, "%s", tmp->ifa_name); - if (ioctl(fd, SIOCGIFADDR, &ifr) == -1) { - //perror("ioctl"); - continue; - } - - *local_ip = IP_ADDRESS_EMPTY; - local_ip->v4.as_inaddr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; - if (ip_address_empty(local_ip)) - continue; - - ret = 0; - break; - } - - freeifaddrs(addrs); - close(fd); - return ret; -} +int get_local_info(char *if_name, ip_address_t *local_ip) { + struct ifaddrs *addrs; + struct ifreq ifr = { + .ifr_addr.sa_family = AF_INET, + }; + int ret = -1; -int main() { - char remote_ip_str[INET_ADDRSTRLEN] = "1.1.1.1"; + int fd = socket(AF_INET, SOCK_DGRAM, 0); - ip_address_t local_ip; - ip_address_t remote_ip; - char if_name[IFNAMSIZ]; + getifaddrs(&addrs); - /* Retrieving local info */ + for (struct ifaddrs *tmp = addrs; tmp; tmp = tmp->ifa_next) { + if (!tmp->ifa_addr || tmp->ifa_addr->sa_family != AF_PACKET) continue; + if (strcmp(tmp->ifa_name, "lo") == 0) continue; + snprintf(if_name, IFNAMSIZ, "%s", tmp->ifa_name); - if (get_local_info(if_name, &local_ip) < 0) { - DEBUG("Error getting local information"); - goto ERR_INIT; + snprintf(ifr.ifr_name, IFNAMSIZ, "%s", tmp->ifa_name); + if (ioctl(fd, SIOCGIFADDR, &ifr) == -1) { + // perror("ioctl"); + continue; } - char local_ip_str[MAXSZ_IP_ADDRESS]; - ip_address_snprintf(local_ip_str, MAXSZ_IP_ADDRESS, &local_ip, AF_INET); - DEBUG("Local information :"); - DEBUG(" - Interface name : %s", if_name); - DEBUG(" - IP address : %s", local_ip_str); + *local_ip = IP_ADDRESS_EMPTY; + local_ip->v4.as_inaddr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; + if (ip_address_empty(local_ip)) continue; - if (ip_address_pton (remote_ip_str, &remote_ip) < 0){ - DEBUG("Error parsing remote IP address"); - goto ERR_INIT; - } + ret = 0; + break; + } + + freeifaddrs(addrs); + close(fd); + return ret; +} - /* Filling face information */ - hc_face_t face = { - .face = { - .type = FACE_TYPE_UDP, - .family = AF_INET, - .local_addr = local_ip, - .remote_addr = remote_ip, - .local_port = 6000, - .remote_port = 6000, - .admin_state = FACE_STATE_UNDEFINED, - .state = FACE_STATE_UNDEFINED, +int main() { + char remote_ip_str[INET_ADDRSTRLEN] = "1.1.1.1"; + + ip_address_t local_ip; + ip_address_t remote_ip; + char if_name[IFNAMSIZ]; + + /* Retrieving local info */ + + if (get_local_info(if_name, &local_ip) < 0) { + DEBUG("Error getting local information"); + goto ERR_INIT; + } + + char local_ip_str[MAXSZ_IP_ADDRESS]; + ip_address_snprintf(local_ip_str, MAXSZ_IP_ADDRESS, &local_ip, AF_INET); + DEBUG("Local information :"); + DEBUG(" - Interface name : %s", if_name); + DEBUG(" - IP address : %s", local_ip_str); + + if (ip_address_pton(remote_ip_str, &remote_ip) < 0) { + DEBUG("Error parsing remote IP address"); + goto ERR_INIT; + } + + /* Filling face information */ + hc_face_t face = { + .face = + { + .type = FACE_TYPE_UDP, + .family = AF_INET, + .local_addr = local_ip, + .remote_addr = remote_ip, + .local_port = 6000, + .remote_port = 6000, + .admin_state = FACE_STATE_UNDEFINED, + .state = FACE_STATE_UNDEFINED, #ifdef WITH_POLICY - .priority = 0, - .tags = POLICY_TAGS_EMPTY, + .priority = 0, + .tags = POLICY_TAGS_EMPTY, #endif /* WITH_POLICY */ - }, - }; - if (netdevice_set_name(&face.face.netdevice, if_name) < 0) { - DEBUG("Error setting face netdevice name"); - goto ERR_INIT; - } + }, + }; + if (netdevice_set_name(&face.face.netdevice, if_name) < 0) { + DEBUG("Error setting face netdevice name"); + goto ERR_INIT; + } - /* Connecting to socket and creating face */ + /* Connecting to socket and creating face */ - hc_sock_t * socket = hc_sock_create(); - if (!socket){ - DEBUG("Error creating libhicnctrl socket"); - goto ERR_SOCK; - } + hc_sock_t *socket = hc_sock_create(); + if (!socket) { + DEBUG("Error creating libhicnctrl socket"); + goto ERR_SOCK; + } - if (hc_sock_connect(socket) < 0){ - DEBUG("Error connecting to forwarder"); - goto ERR; - } + if (hc_sock_connect(socket) < 0) { + DEBUG("Error connecting to forwarder"); + goto ERR; + } - if (hc_face_create(socket, &face) < 0){ - DEBUG("Error creating face"); - goto ERR; - } + if (hc_face_create(socket, &face) < 0) { + DEBUG("Error creating face"); + goto ERR; + } - DEBUG("Face created successfully"); + DEBUG("Face created successfully"); ERR: - hc_sock_free(socket); + hc_sock_free(socket); ERR_SOCK: ERR_INIT: - return 0; + return 0; } diff --git a/ctrl/libhicnctrl/examples/update_priority.c b/ctrl/libhicnctrl/examples/update_priority.c index d350f71c9..bbe174c2f 100644 --- a/ctrl/libhicnctrl/examples/update_priority.c +++ b/ctrl/libhicnctrl/examples/update_priority.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -24,37 +24,36 @@ #include <hicn/ctrl.h> #include <hicn/util/log.h> -int main(int argc, char **argv) -{ - if (argc != 3) { - fprintf(stderr, "Usage: %s FACE_ID PRIORITY\n", argv[0]); - exit(EXIT_FAILURE); - } - unsigned face_id = atoi(argv[1]); - unsigned priority = atoi(argv[2]); - char face_id_s[SYMBOLIC_NAME_LEN]; - - hc_sock_t * socket = hc_sock_create(); - if (!socket){ - DEBUG("Error creating libhicnctrl socket"); - goto ERR_SOCK; - } - - if (hc_sock_connect(socket) < 0){ - DEBUG("Error connecting to forwarder"); - goto ERR; - } - - snprintf(face_id_s, SYMBOLIC_NAME_LEN, "%d", face_id); - if (hc_face_set_priority(socket, face_id_s, priority) < 0) { - DEBUG("Error setting face priority"); - goto ERR; - } - - DEBUG("Face priority updated successfully"); +int main(int argc, char **argv) { + if (argc != 3) { + fprintf(stderr, "Usage: %s FACE_ID PRIORITY\n", argv[0]); + exit(EXIT_FAILURE); + } + unsigned face_id = atoi(argv[1]); + unsigned priority = atoi(argv[2]); + char face_id_s[SYMBOLIC_NAME_LEN]; + + hc_sock_t *socket = hc_sock_create(); + if (!socket) { + DEBUG("Error creating libhicnctrl socket"); + goto ERR_SOCK; + } + + if (hc_sock_connect(socket) < 0) { + DEBUG("Error connecting to forwarder"); + goto ERR; + } + + snprintf(face_id_s, SYMBOLIC_NAME_LEN, "%d", face_id); + if (hc_face_set_priority(socket, face_id_s, priority) < 0) { + DEBUG("Error setting face priority"); + goto ERR; + } + + DEBUG("Face priority updated successfully"); ERR: - hc_sock_free(socket); + hc_sock_free(socket); ERR_SOCK: - return 0; + return 0; } diff --git a/ctrl/libhicnctrl/includes/CMakeLists.txt b/ctrl/libhicnctrl/includes/CMakeLists.txt index 50cfa4ad5..1a90690a4 100644 --- a/ctrl/libhicnctrl/includes/CMakeLists.txt +++ b/ctrl/libhicnctrl/includes/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,17 +11,24 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(LIBHICNCTRL_INCLUDE_DIRS - ${CMAKE_CURRENT_SOURCE_DIR} "" +############################################################## +# Public headers directory +############################################################## +set(Libhicnctrl_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" FORCE ) + +############################################################## +# To install header files +############################################################## set(TO_INSTALL_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/ctrl.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/ctrl/api.h - ${CMAKE_CURRENT_SOURCE_DIR}/hicn/ctrl/commands.h - ${CMAKE_CURRENT_SOURCE_DIR}/hicn/ctrl/face.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/ctrl/hicn-light.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/ctrl/hicn-light-ng.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/ctrl/route.h PARENT_SCOPE ) diff --git a/ctrl/libhicnctrl/includes/ctrl.h b/ctrl/libhicnctrl/includes/ctrl.h index e61b7a482..477afd152 100644 --- a/ctrl/libhicnctrl/includes/ctrl.h +++ b/ctrl/libhicnctrl/includes/ctrl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl.h b/ctrl/libhicnctrl/includes/hicn/ctrl.h index e61b7a482..477afd152 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h index b5a968800..8a59cf4d8 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h @@ -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: @@ -67,15 +67,24 @@ #include <stdbool.h> #include <stdint.h> +#include <stddef.h> // object_offset_t #include <hicn/util/ip_address.h> -#include <hicn/ctrl/commands.h> -#include "face.h" +#include <hicn/face.h> +#include <hicn/strategy.h> +/* + * This has to be common between hicn-light and hicn-plugin. We now we keep the + * minimum of the two + */ +#define SYMBOLIC_NAME_LEN 16 #define HICN_DEFAULT_PORT 9695 #define HOTFIXMARGIN 0 +#define INVALID_FACE_ID ~0 +#define INVALID_NETDEVICE_ID ~0 + /** * \brief Defines the default size for the allocated data arrays holding the * results of API calls. @@ -99,26 +108,70 @@ * Message helper types and aliases ******************************************************************************/ -#define foreach_command \ - _(UNDEFINED) \ - _(CREATE) \ - _(UPDATE) \ - _(DELETE) \ - _(LIST) \ - _(SET) \ +/* Action */ + +#define foreach_action \ + _(UNDEFINED) \ + _(CREATE) \ + _(UPDATE) \ + _(DELETE) \ + _(LIST) \ + _(SET) \ + _(SERVE) \ + _(STORE) \ + _(CLEAR) \ _(N) typedef enum { #define _(x) ACTION_##x, - foreach_command + foreach_action #undef _ } hc_action_t; +extern const char *action_str[]; + +#define action_str(x) action_str[x] + +hc_action_t action_from_str(const char *action_str); + +/* Object type */ + +#define foreach_object \ + _(UNDEFINED) \ + _(CONNECTION) \ + _(LISTENER) \ + _(ROUTE) \ + _(FACE) \ + _(STRATEGY) \ + _(PUNTING) \ + _(POLICY) \ + _(CACHE) \ + _(MAPME) \ + _(LOCAL_PREFIX) \ + _(PROBE) \ + _(SUBSCRIPTION) \ + _(N) + +typedef enum { +#define _(x) OBJECT_##x, + foreach_object +#undef _ +} hc_object_type_t; + +extern const char *object_str[]; + +#define object_str(x) object_str[x] + +hc_object_type_t object_from_str(const char *object_str); + +#define IS_VALID_OBJECT_TYPE(x) IS_VALID_ENUM_TYPE(OBJECT, x) +#define IS_VALID_ACTION(x) IS_VALID_ENUM_TYPE(ACTION, x) + /** * \brief hICN control message header */ typedef struct hc_msg_s hc_msg_t; - +typedef struct hc_result_s hc_result_t; /****************************************************************************** * Control Data ******************************************************************************/ @@ -140,7 +193,8 @@ typedef struct hc_data_s { bool complete; /* Callbacks */ - data_callback_t complete_cb; // XXX int (*complete_cb)(struct hc_data_s * data); + data_callback_t + complete_cb; // XXX int (*complete_cb)(struct hc_data_s * data); void *complete_cb_data; int ret; } hc_data_t; @@ -149,7 +203,8 @@ typedef struct hc_data_s { * Create a structure holding the results of an hICN control request. * \result The newly create data structure. */ -hc_data_t *hc_data_create(size_t in_element_size, size_t out_element_size, data_callback_t complete_cb); +hc_data_t *hc_data_create(size_t in_element_size, size_t out_element_size, + data_callback_t complete_cb); /** * Free a structure holding the results of an hICN control request. @@ -214,38 +269,49 @@ int hc_data_reset(hc_data_t *data); * \param [out] found - A pointer to the element, or NULL if not found. * \return Error code */ -#define GENERATE_FIND_HEADER(TYPE) \ -int \ -hc_ ## TYPE ## _find(hc_data_t * data, const hc_ ## TYPE ## _t * element, \ - hc_ ## TYPE ## _t **found) - -#define GENERATE_FIND(TYPE) \ -int \ -hc_ ## TYPE ## _find(hc_data_t * data, const hc_ ## TYPE ## _t * element, \ - hc_ ## TYPE ## _t **found) \ -{ \ - foreach_type(hc_ ## TYPE ## _t, x, data) { \ - if (hc_ ## TYPE ## _cmp(x, element) == 0) { \ - *found = x; \ - return 0; \ - } \ - }; \ - *found = NULL; /* this is optional */ \ - return 0; \ -} +#define GENERATE_FIND_HEADER(TYPE) \ + int hc_##TYPE##_find(hc_data_t *data, const hc_##TYPE##_t *element, \ + hc_##TYPE##_t **found) + +#define GENERATE_FIND(TYPE) \ + int hc_##TYPE##_find(hc_data_t *data, const hc_##TYPE##_t *element, \ + hc_##TYPE##_t **found) { \ + foreach_type(hc_##TYPE##_t, x, data) { \ + if (hc_##TYPE##_cmp(x, element) == 0) { \ + *found = x; \ + return 0; \ + } \ + }; \ + *found = NULL; /* this is optional */ \ + return 0; \ + } /****************************************************************************** * Control socket ******************************************************************************/ -/* This should be at least equal to the maximum packet size */ -#define RECV_BUFLEN 8192 +/* With UDP, the buffer should be able to receieve a full packet, and thus MTU + * (max 9000) is sufficient. Messages will be received fully one by one. + * With TCP, the buffer should be at least able to receive a message header and + * the maximum size of a data element, so any reasonable size will be correct, + * it might just optimize performance. Messages might arrive in chunks that the + * library is able to parse. + */ +#define JUMBO_MTU 9000 +#define RECV_BUFLEN 65535 + +#define foreach_forwarder_type \ + _(UNDEFINED) \ + _(HICNLIGHT) \ + _(HICNLIGHT_NG) \ + _(VPP) \ + _(N) typedef enum { - HICNLIGHT, - VPP, - UNDEFINED -} forwarder_t; +#define _(x) x, + foreach_forwarder_type +#undef _ +} forwarder_type_t; /** * \brief Holds the state of an hICN control socket @@ -257,22 +323,26 @@ typedef struct hc_sock_s hc_sock_t; * \param [in] url - The URL to connect to. * \return an hICN control socket */ -hc_sock_t * -hc_sock_create_url(const char * url); +hc_sock_t *hc_sock_create_url(const char *url); /** * \brief Create an hICN control socket using the provided forwarder. * \return an hICN control socket */ -hc_sock_t * -hc_sock_create_forwarder(forwarder_t forwarder); +hc_sock_t *hc_sock_create_forwarder(forwarder_type_t forwarder); + +/** + * \brief Create an hICN control socket using the provided forwarder and a URL. + * \return an hICN control socket + */ +hc_sock_t *hc_sock_create_forwarder_url(forwarder_type_t forwarder, + const char *url); /** * \brief Create an hICN control socket using the default connection type. * \return an hICN control socket */ -hc_sock_t * -hc_sock_create(void); +hc_sock_t *hc_sock_create(void); /** * \brief Frees an hICN control socket @@ -324,7 +394,7 @@ int hc_sock_get_available(hc_sock_t *s, u8 **buffer, size_t *size); * \param [in] msglen - Length of the message to send * \return Error code */ -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); /** * \brief Helper for reading socket contents @@ -356,6 +426,13 @@ int hc_sock_callback(hc_sock_t *s, hc_data_t **data); */ int hc_sock_reset(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); + /****************************************************************************** * Command-specific structures and functions ******************************************************************************/ @@ -420,50 +497,11 @@ int hc_sock_reset(hc_sock_t *s); VAR < (TYPE *)(data->buffer + data->size * data->out_element_size); \ VAR++) -/** - * New type is defined to reconciliate different enum for add and list. - * Also, values not implemented have been removed for clarity. - */ -#define foreach_connection_type \ - _(UNDEFINED) \ - _(TCP) \ - _(UDP) \ - _(HICN) \ - _(N) - -typedef enum { -#define _(x) CONNECTION_TYPE_##x, - foreach_connection_type -#undef _ -} hc_connection_type_t; - -#define MAXSZ_HC_CONNECTION_TYPE_ 9 -#define MAXSZ_HC_CONNECTION_TYPE MAXSZ_HC_CONNECTION_TYPE_ + NULLTERM + HOTFIXMARGIN - -extern const char *connection_type_str[]; - -hc_connection_type_t connection_type_from_str(const char *str); - -/* Same order as connection_state_t in hicn/core/connectionState.h */ -#define foreach_connection_state \ - _(UNDEFINED) \ - _(DOWN) \ - _(UP) \ - _(N) - -typedef enum { -#define _(x) HC_CONNECTION_STATE_##x, - foreach_connection_state -#undef _ -} hc_connection_state_t; - -#define MAXSZ_HC_CONNECTION_STATE_ 9 -#define MAXSZ_HC_CONNECTION_STATE MAXSZ_HC_CONNECTION_STATE_ + NULLTERM - -extern const char *connection_state_str[]; - typedef int (*HC_PARSE)(const u8 *, u8 *); +#define INPUT_ERROR -2 +#define UNSUPPORTED_CMD_ERROR -3 + /*----------------------------------------------------------------------------* * Listeners *----------------------------------------------------------------------------*/ @@ -473,27 +511,28 @@ typedef struct { char name[SYMBOLIC_NAME_LEN]; /* K.w */ // XXX clarify what used for char interface_name[INTERFACE_LEN]; /* Kr. */ u32 id; - hc_connection_type_t type; /* .rw */ - int family; /* .rw */ - ip_address_t local_addr; /* .rw */ - u16 local_port; /* .rw */ + face_type_t type; /* .rw */ + int family; /* .rw */ + ip_address_t local_addr; /* .rw */ + u16 local_port; /* .rw */ } hc_listener_t; int hc_listener_create(hc_sock_t *s, hc_listener_t *listener); /* listener_found might eventually be allocated, and needs to be freed */ +hc_result_t *hc_listener_create_conf(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); int hc_listener_delete(hc_sock_t *s, hc_listener_t *listener); int hc_listener_list(hc_sock_t *s, hc_data_t **pdata); +hc_result_t *hc_listener_list_conf(hc_sock_t *s); int hc_listener_validate(const hc_listener_t *listener); int hc_listener_cmp(const hc_listener_t *l1, const hc_listener_t *l2); -int hc_listener_parse(void *in, hc_listener_t *listener); #define foreach_listener(VAR, data) foreach_type(hc_listener_t, VAR, data) #define MAXSZ_HC_LISTENER_ \ - INTERFACE_LEN + SPACE + MAXSZ_URL_ + SPACE + MAXSZ_HC_CONNECTION_TYPE_ + INTERFACE_LEN + SPACE + MAXSZ_URL_ + SPACE + MAXSZ_FACE_TYPE_ #define MAXSZ_HC_LISTENER MAXSZ_HC_LISTENER_ + NULLTERM GENERATE_FIND_HEADER(listener); @@ -506,28 +545,30 @@ int hc_listener_snprintf(char *s, size_t size, hc_listener_t *listener); /* * NOTE : - * - interface_name is mainly used to derive listeners from connections, but is - * not itself used to create connections. + * - interface_name is mainly used to derive listeners from connections, + * but is not itself used to create connections. */ typedef struct { u32 id; /* Kr. */ char name[SYMBOLIC_NAME_LEN]; /* K.w */ char interface_name[INTERFACE_LEN]; /* Kr. */ - hc_connection_type_t type; /* .rw */ + face_type_t type; /* .rw */ int family; /* .rw */ ip_address_t local_addr; /* .rw */ u16 local_port; /* .rw */ ip_address_t remote_addr; /* .rw */ u16 remote_port; /* .rw */ - hc_connection_state_t admin_state; /* .rw */ + face_state_t admin_state; /* .rw */ #ifdef WITH_POLICY - uint32_t priority; /* .rw */ - policy_tags_t tags; /* .rw */ -#endif /* WITH_POLICY */ - hc_connection_state_t state; /* .r. */ + uint32_t priority; /* .rw */ + policy_tags_t tags; /* .rw */ +#endif /* WITH_POLICY */ + face_state_t state; /* .r. */ } hc_connection_t; int hc_connection_create(hc_sock_t *s, hc_connection_t *connection); +hc_result_t *hc_connection_create_conf(hc_sock_t *s, + hc_connection_t *connection); /* connection_found will be allocated, and must be freed */ int hc_connection_get(hc_sock_t *s, hc_connection_t *connection, hc_connection_t **connection_found); @@ -536,6 +577,8 @@ int hc_connection_update_by_id(hc_sock_t *s, int hc_connection_id, int hc_connection_update(hc_sock_t *s, hc_connection_t *connection_current, hc_connection_t *connection_updated); int hc_connection_delete(hc_sock_t *s, hc_connection_t *connection); +hc_result_t *hc_connection_delete_conf(hc_sock_t *s, + hc_connection_t *connection); /* int hc_connection_remove_by_id(hc_sock_t * s, char * name); int hc_connection_remove_by_name(hc_sock_t * s, char * name); @@ -544,19 +587,21 @@ int hc_connection_list(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_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(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_tags(hc_sock_t * s, const char * conn_id_or_name, policy_tags_t tags); +int hc_connection_set_priority(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); #endif /* WITH_POLICY */ #define foreach_connection(VAR, data) foreach_type(hc_connection_t, VAR, data) -#define MAXSZ_HC_CONNECTION_ \ - MAXSZ_HC_CONNECTION_STATE_ + INTERFACE_LEN + SPACE + 2 * MAXSZ_URL_ + \ - MAXSZ_HC_CONNECTION_TYPE_ + SPACES(3) +#define MAXSZ_HC_CONNECTION_ \ + MAXSZ_FACE_STATE_ + INTERFACE_LEN + SPACE + 2 * MAXSZ_URL_ + \ + MAXSZ_FACE_TYPE_ + SPACES(3) #define MAXSZ_HC_CONNECTION MAXSZ_HC_CONNECTION_ + NULLTERM GENERATE_FIND_HEADER(connection); @@ -591,14 +636,17 @@ typedef struct { */ 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); //, hc_data_t ** pdata); -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(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_tags(hc_sock_t * s, const char * conn_id_or_name, policy_tags_t tags); +int hc_face_set_priority(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); #endif /* WITH_POLICY */ #define foreach_face(VAR, data) foreach_type(hc_face_t, VAR, data) @@ -609,7 +657,8 @@ int hc_face_set_tags(hc_sock_t * s, const char * conn_id_or_name, policy_tags_t #define MAXSZ_FACE_NAME_ SYMBOLIC_NAME_LEN #define MAXSZ_FACE_NAME MAXSZ_FACE_NAME_ + NULLTERM -#define MAXSZ_HC_FACE_ MAXSZ_FACE_ID_ + MAXSZ_FACE_NAME_ + MAXSZ_FACE_ + 5 + HOTFIXMARGIN +#define MAXSZ_HC_FACE_ \ + MAXSZ_FACE_ID_ + MAXSZ_FACE_NAME_ + MAXSZ_FACE_ + 5 + HOTFIXMARGIN #define MAXSZ_HC_FACE MAXSZ_HC_FACE_ + NULLTERM int hc_face_snprintf(char *s, size_t size, hc_face_t *face); @@ -619,20 +668,20 @@ int hc_face_snprintf(char *s, size_t size, hc_face_t *face); *----------------------------------------------------------------------------*/ typedef struct { - face_id_t face_id; /* Kr. */ - int family; /* Krw */ - ip_address_t remote_addr; /* krw */ - u8 len; /* krw */ - u16 cost; /* .rw */ - hc_face_t face; + face_id_t face_id; /* Kr. use when name == NULL */ + char name[SYMBOLIC_NAME_LEN]; /* Kr. use by default vs face_id */ + int family; /* Krw */ + ip_address_t remote_addr; /* krw */ + u8 len; /* krw */ + u16 cost; /* .rw */ + hc_face_t face; /* TODO remove, used by hicn_plugin_api */ } hc_route_t; -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_delete(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); +hc_result_t *hc_route_create_conf(hc_sock_t *s, hc_route_t *route); +int hc_route_delete(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); #define foreach_route(VAR, data) foreach_type(hc_route_t, VAR, data) @@ -646,6 +695,7 @@ int hc_route_list_async(hc_sock_t * s); #define MAXSZ_HC_ROUTE MAXSZ_HC_ROUTE_ + NULLTERM int hc_route_snprintf(char *s, size_t size, hc_route_t *route); +int hc_route_validate(const hc_route_t *route); /*----------------------------------------------------------------------------* * Punting @@ -653,9 +703,9 @@ int hc_route_snprintf(char *s, size_t size, hc_route_t *route); typedef struct { face_id_t face_id; /* Kr. */ // XXX listener id, could be NULL for all ? - int family; /* Krw */ - ip_address_t prefix; /* krw */ - u8 prefix_len; /* krw */ + int family; /* Krw */ + ip_address_t prefix; /* krw */ + u8 prefix_len; /* krw */ } hc_punting_t; int hc_punting_create(hc_sock_t *s, hc_punting_t *punting); @@ -666,7 +716,6 @@ 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); #define foreach_punting(VAR, data) foreach_type(hc_punting_t, VAR, data) @@ -681,8 +730,23 @@ int hc_punting_snprintf(char *s, size_t size, hc_punting_t *punting); * Cache *----------------------------------------------------------------------------*/ -int hc_cache_set_store(hc_sock_t *s, int enabled); -int hc_cache_set_serve(hc_sock_t *s, int enabled); +typedef struct { + uint8_t serve; // 1 = on, 0 = off + uint8_t store; // 1 = on, 0 = off +} hc_cache_t; + +typedef struct { + bool store; + bool serve; + size_t cs_size; + size_t num_stale_entries; +} hc_cache_info_t; + +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_snprintf(char *s, size_t size, const hc_cache_info_t *cache_info); /*----------------------------------------------------------------------------* * Strategy @@ -691,7 +755,13 @@ int hc_cache_set_serve(hc_sock_t *s, int enabled); #define MAXSZ_STRATEGY_NAME 255 typedef struct { + // The name is not set by the controller + // but populated by the daemon char name[MAXSZ_STRATEGY_NAME]; + strategy_type_t type; + ip_address_t address, local_address; + int family, local_family; + u8 len, local_len; } hc_strategy_t; int hc_strategy_list(hc_sock_t *s, hc_data_t **data); @@ -704,8 +774,11 @@ 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); // per prefix -int hc_strategy_set(hc_sock_t *s /* XXX */); - +int hc_strategy_set(hc_sock_t *s, hc_strategy_t *strategy); +hc_result_t *hc_strategy_set_conf(hc_sock_t *s, hc_strategy_t *strategy); +int hc_strategy_add_local_prefix(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); /*----------------------------------------------------------------------------* * WLDR *----------------------------------------------------------------------------*/ @@ -717,10 +790,45 @@ int hc_wldr_set(hc_sock_t *s /* XXX */); * MAP-Me *----------------------------------------------------------------------------*/ -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); +typedef enum { + MAPME_TARGET_ENABLE, + MAPME_TARGET_DISCOVERY, + MAPME_TARGET_TIMESCALE, + MAPME_TARGET_RETX, +} mapme_target_t; + +static inline mapme_target_t mapme_target_from_str(char *mapme_target_str) { + if (strcasecmp(mapme_target_str, "enable") == 0) + return MAPME_TARGET_ENABLE; + else if (strcasecmp(mapme_target_str, "discovery") == 0) + return MAPME_TARGET_DISCOVERY; + else if (strcasecmp(mapme_target_str, "timescale") == 0) + return MAPME_TARGET_TIMESCALE; + else + return MAPME_TARGET_RETX; +} + +#define MAX_MAPME_ARG_LEN 30 + +typedef struct { + mapme_target_t target; + // Command argument stored as a string + // before being parsed into 'enabled' or 'timescale' + char unparsed_arg[MAX_MAPME_ARG_LEN]; + + uint8_t enabled; // 1 = on, 0 = off + uint32_t timescale; // Milliseconds + + ip_address_t address; + int family; + u8 len; +} hc_mapme_t; + +int hc_mapme_set(hc_sock_t *s, hc_mapme_t *mapme); +int hc_mapme_set_discovery(hc_sock_t *s, hc_mapme_t *mapme); +int hc_mapme_set_timescale(hc_sock_t *s, hc_mapme_t *mapme); +int hc_mapme_set_retx(hc_sock_t *s, hc_mapme_t *mapme); +int hc_mapme_send_update(hc_sock_t *s, hc_mapme_t *mapme); /*----------------------------------------------------------------------------* * Policies @@ -732,11 +840,9 @@ typedef struct { int family; /* Krw */ ip_address_t remote_addr; /* krw */ u8 len; /* krw */ - hicn_policy_t policy; /* .rw */ + hicn_policy_t policy; /* .rw */ } hc_policy_t; -int hc_policy_parse(void *in, hc_policy_t *policy); - int hc_policy_create(hc_sock_t *s, hc_policy_t *policy); int hc_policy_delete(hc_sock_t *s, hc_policy_t *policy); int hc_policy_list(hc_sock_t *s, hc_data_t **pdata); @@ -748,7 +854,114 @@ int hc_policy_list(hc_sock_t *s, hc_data_t **pdata); #define MAXSZ_HC_POLICY MAXSZ_HC_POLICY_ + NULLTERM int hc_policy_snprintf(char *s, size_t size, hc_policy_t *policy); +int hc_policy_validate(const hc_policy_t *policy); #endif /* WITH_POLICY */ +/*----------------------------------------------------------------------------* + * Subscription + *----------------------------------------------------------------------------*/ +// Topics + +#undef PUNTING // TODO(eloparco): Undefined to avoid collisions + // Fix the collision + +// Used only to create 'hc_topic_t' +typedef struct { +#define _(x) char x; + foreach_object +#undef _ +} object_offset_t; + +// Flags for topic subscriptions +typedef enum { +#define _(x) TOPIC_##x = (1 << offsetof(object_offset_t, x)), + foreach_object +#undef _ +} hc_topic_t; + +static inline hc_object_type_t object_from_topic(hc_topic_t topic) { +#define _(x) \ + if (topic == TOPIC_##x) return OBJECT_##x; + foreach_object +#undef _ + return OBJECT_UNDEFINED; +} + +#define NUM_TOPICS OBJECT_N // Because a topic is created for each object +#define ALL_TOPICS ~0 + +// Subscriptions +typedef uint32_t hc_topics_t; +typedef struct { + hc_topics_t topics; +} hc_subscription_t; + +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_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); + +/*----------------------------------------------------------------------------* + * Events + *----------------------------------------------------------------------------*/ +#define foreach_event_type \ + _(UNDEFINED) \ + _(INTERFACE_UPDATE) \ + _(N) +typedef enum { +#define _(x) EVENT_##x, + foreach_event_type +#undef _ +} event_type_t; + +extern const char *event_str[]; +#define event_str(x) event_str[x] + +typedef enum { + FLAG_INTERFACE_TYPE_WIRED = 0x1, + FLAG_INTERFACE_TYPE_WIFI = 0x2, + FLAG_INTERFACE_TYPE_CELLULAR = 0x4, +} flag_interface_type_t; + +typedef struct { + flag_interface_type_t interface_type; +} hc_event_interface_update_t; + +/* Result */ + +hc_msg_t *hc_result_get_msg(hc_sock_t *s, hc_result_t *result); +int hc_result_get_cmd_id(hc_sock_t *s, hc_result_t *result); +bool hc_result_get_success(hc_sock_t *s, hc_result_t *result); +void hc_result_free(hc_result_t *result); + +/* Object */ + +typedef struct { + hc_object_type_t type; + union { + hc_connection_t connection; + hc_listener_t listener; + hc_route_t route; + hc_face_t face; + // hc_data_t *data; + hc_punting_t punting; + hc_strategy_t strategy; +#ifdef WITH_POLICY + hc_policy_t policy; +#endif /* WITH_POLICY */ + hc_subscription_t subscription; + hc_cache_t cache; + hc_mapme_t mapme; + uint8_t as_uint8; + }; +} hc_object_t; + +typedef struct { + hc_action_t action; + hc_object_t object; +} hc_command_t; + #endif /* HICNTRL_API */ diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/face.h b/ctrl/libhicnctrl/includes/hicn/ctrl/face.h deleted file mode 100644 index 49a6a783c..000000000 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/face.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file face.h - * \brief Face abstraction - */ -#ifndef HICN_FACE_H -#define HICN_FACE_H - -#ifndef SPACES -#define SPACES(x) x -#endif -#ifndef SPACE -#define SPACE 1 -#endif -#ifndef NULLTERM -#define NULLTERM 1 -#endif - -#include <hicn/policy.h> - -#include <hicn/util/ip_address.h> - -//typedef unsigned int hash_t; //incompatible with vpp - -/* Netdevice type */ - -#include <net/if.h> // IFNAMSIZ - -#define foreach_netdevice_type \ - _(UNDEFINED) \ - _(LOOPBACK) \ - _(WIRED) \ - _(WIFI) \ - _(CELLULAR) \ - _(VPN) \ - _(N) - -#define MAXSZ_NETDEVICE_TYPE_ 9 -#define MAXSZ_NETDEVICE_TYPE MAXSZ_NETDEVICE_TYPE_ + NULLTERM - -typedef enum { -#define _(x) NETDEVICE_TYPE_ ## x, -foreach_netdevice_type -#undef _ -} netdevice_type_t; - -extern const char * netdevice_type_str[]; - - -/* Netdevice */ - -/** - * \brief Netdevice type - * - * NOTE - * - This struct cannot be made opaque as it is currently part of face_t - * - We recommand using the API as to keep redundant attributes consistent - */ -typedef struct { - u32 index; - char name[IFNAMSIZ]; -} netdevice_t; - -#define NETDEVICE_EMPTY (netdevice_t) { \ - .index = 0, \ - .name = {0}, \ -} - -netdevice_t * netdevice_create_from_index(u32 index); -netdevice_t * netdevice_create_from_name(const char * name); -#define netdevice_initialize_from_index netdevice_set_index -#define netdevice_initialize_from_name netdevice_set_name -void netdevice_free(netdevice_t * netdevice); -int netdevice_get_index(const netdevice_t * netdevice, u32 * index); -int netdevice_set_index(netdevice_t * netdevice, u32 index); -int netdevice_get_name(const netdevice_t * netdevice, const char ** name); -int netdevice_set_name(netdevice_t * netdevice, const char * name); -int netdevice_update_index(netdevice_t * netdevice); -int netdevice_update_name(netdevice_t * netdevice); -int netdevice_cmp(const netdevice_t * nd1, const netdevice_t * nd2); - -#define NETDEVICE_UNDEFINED_INDEX 0 - -/* Face state */ - -#define foreach_face_state \ - _(UNDEFINED) \ - _(DOWN) \ - _(UP) \ - _(N) - - -#define MAXSZ_FACE_STATE_ 9 -#define MAXSZ_FACE_STATE MAXSZ_FACE_STATE_ + 1 - -typedef enum { -#define _(x) FACE_STATE_ ## x, -foreach_face_state -#undef _ -} face_state_t; - -extern const char * face_state_str[]; - - -/* Face type */ - -#define foreach_face_type \ - _(UNDEFINED) \ - _(HICN) \ - _(HICN_LISTENER) \ - _(TCP) \ - _(TCP_LISTENER) \ - _(UDP) \ - _(UDP_LISTENER) \ - _(N) - -#define MAXSZ_FACE_TYPE_ 13 -#define MAXSZ_FACE_TYPE MAXSZ_FACE_TYPE_ + 1 - -typedef enum { -#define _(x) FACE_TYPE_ ## x, -foreach_face_type -#undef _ -} face_type_t; - -extern const char * face_type_str[]; - -#ifdef WITH_POLICY -#define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_URL_ + 2 * MAXSZ_FACE_STATE_ + MAXSZ_POLICY_TAGS_ + 7 -#else -#define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_URL_ + 2 * MAXSZ_FACE_STATE_ + 4 -#endif /* WITH_POLICY */ -#define MAXSZ_FACE MAXSZ_FACE_ + 1 - -/* Face */ - -typedef u32 face_id_t; - -typedef struct { - face_type_t type; - face_state_t admin_state; - face_state_t state; -#ifdef WITH_POLICY - uint32_t priority; - policy_tags_t tags; /**< \see policy_tag_t */ -#endif /* WITH_POLICY */ - - /* - * Depending on the face type, some of the following fields will be unused - */ - netdevice_t netdevice; - int family; /* To access family independently of face type */ - ip_address_t local_addr; - ip_address_t remote_addr; - u16 local_port; - u16 remote_port; -} face_t; - -int face_initialize(face_t * face); -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); -int face_initialize_udp_sa(face_t * face, - const char * interface_name, - const struct sockaddr * local_addr, const struct sockaddr * remote_addr); - -face_t * face_create(); -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_create_udp_sa(const char * interface_name, - const struct sockaddr * local_addr, - const struct sockaddr * remote_addr); - -int face_finalize(face_t * face); - -void face_free(face_t * face); - -typedef int (*face_cmp_t)(const face_t * f1, const face_t * f2); - -int face_cmp(const face_t * f1, const face_t * f2); -unsigned int face_hash(const face_t * face); - -size_t -face_snprintf(char * s, size_t size, const face_t * face); - -policy_tags_t face_get_tags(const face_t * face); -int face_set_tags(face_t * face, policy_tags_t tags); - -#endif /* HICN_FACE_H */ - diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/hicn-light-ng.h b/ctrl/libhicnctrl/includes/hicn/ctrl/hicn-light-ng.h new file mode 100644 index 000000000..7d105a84b --- /dev/null +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/hicn-light-ng.h @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file commands.h + * @brief All hicn-light commands: 14 in total. + * + * Header and payload in binary format. + */ + +#ifndef HICN_CTRL_HICNLIGHTNG_H +#define HICN_CTRL_HICNLIGHTNG_H + +#ifndef _WIN32 +#include <netinet/in.h> +#include <sys/socket.h> +#endif + +#include <stdint.h> +#include <stdlib.h> + +#include <hicn/policy.h> +#include <hicn/strategy.h> +#include <hicn/util/ip_address.h> + +#define SYMBOLIC_NAME_LEN 16 + +typedef struct in6_addr ipv6_addr_t; +typedef uint32_t ipv4_addr_t; + +typedef enum { + MESSAGE_COMMAND_SUBTYPE_UNDEFINED, + REQUEST_LIGHT = 0xc0, // this is a command + RESPONSE_LIGHT, + ACK_LIGHT, + NACK_LIGHT, + NOTIFICATION_LIGHT, + MESSAGE_COMMAND_SUBTYPE_N +} message_command_subtype_t; + +#define message_type_is_valid(message_type) \ + ((message_type != MESSAGE_TYPE_UNDEFINED) && \ + (message_type != MESSAGE_COMMAND_SUBTYPE_N)) + +#define message_type_from_uchar(x) \ + (((x) < REQUEST_LIGHT) || (((x) >= MESSAGE_COMMAND_SUBTYPE_N)) \ + ? MESSAGE_COMMAND_SUBTYPE_N \ + : (message_command_subtype_t)(x)) + +#define foreach_command_type \ + _(listener_add, LISTENER_ADD) \ + _(listener_remove, LISTENER_REMOVE) \ + _(listener_list, LISTENER_LIST) \ + _(connection_add, CONNECTION_ADD) \ + _(connection_remove, CONNECTION_REMOVE) \ + _(connection_list, CONNECTION_LIST) \ + _(connection_set_admin_state, CONNECTION_SET_ADMIN_STATE) \ + _(connection_update, CONNECTION_UPDATE) \ + _(connection_set_priority, CONNECTION_SET_PRIORITY) \ + _(connection_set_tags, CONNECTION_SET_TAGS) \ + _(route_add, ROUTE_ADD) \ + _(route_remove, ROUTE_REMOVE) \ + _(route_list, ROUTE_LIST) \ + _(cache_set_store, CACHE_SET_STORE) \ + _(cache_set_serve, CACHE_SET_SERVE) \ + _(cache_clear, CACHE_CLEAR) \ + _(cache_list, CACHE_LIST) \ + _(strategy_set, STRATEGY_SET) \ + _(strategy_add_local_prefix, STRATEGY_ADD_LOCAL_PREFIX) \ + _(wldr_set, WLDR_SET) \ + _(punting_add, PUNTING_ADD) \ + _(mapme_enable, MAPME_ENABLE) \ + _(mapme_set_discovery, MAPME_SET_DISCOVERY) \ + _(mapme_set_timescale, MAPME_SET_TIMESCALE) \ + _(mapme_set_retx, MAPME_SET_RETX) \ + _(mapme_send_update, MAPME_SEND_UPDATE) \ + _(policy_add, POLICY_ADD) \ + _(policy_remove, POLICY_REMOVE) \ + _(policy_list, POLICY_LIST) \ + _(subscription_add, SUBSCRIPTION_ADD) \ + _(subscription_remove, SUBSCRIPTION_REMOVE) + +typedef enum { + COMMAND_TYPE_UNDEFINED, +#define _(l, u) COMMAND_TYPE_##u, + foreach_command_type +#undef _ + COMMAND_TYPE_N, +} command_type_t; + +extern const char *command_type_str[]; + +#define command_type_str(x) command_type_str[x] + +#define command_type_is_valid(command_type) \ + ((command_type != COMMAND_TYPE_UNDEFINED) && (command_type != COMMAND_TYPE_N)) + +#define command_type_from_uchar(x) \ + (((x) >= COMMAND_TYPE_N) ? COMMAND_TYPE_N : (command_type_t)(x)) + +/* Should be at least 8 bytes */ +typedef struct { + uint8_t message_type; + uint8_t command_id; + uint16_t length; /* Number of structures in the payload */ + uint32_t seq_num; +} cmd_header_t; + +typedef struct { + cmd_header_t header; +} msg_header_t; + +/* Listener */ + +typedef struct { + char symbolic[SYMBOLIC_NAME_LEN]; + char interface_name[SYMBOLIC_NAME_LEN]; + ip_address_t address; + uint16_t port; + uint8_t family; + uint8_t type; +} cmd_listener_add_t; + +typedef struct { + char symbolicOrListenerid[SYMBOLIC_NAME_LEN]; +} cmd_listener_remove_t; + +typedef struct { + void *_; // Otherwise empty structs result in clang build error +} cmd_listener_list_t; + +// Sync this struct with `hc_listener_t` in `api.h` +typedef struct { + char name[SYMBOLIC_NAME_LEN]; + char interface_name[SYMBOLIC_NAME_LEN]; + uint32_t id; + uint8_t type; + uint8_t family; + ip_address_t address; + uint16_t port; +} cmd_listener_list_item_t; + +/* Connection */ + +typedef struct { + char symbolic[SYMBOLIC_NAME_LEN]; + // char interface_name[SYMBOLIC_NAME_LEN]; + ip_address_t remote_ip; + ip_address_t local_ip; + uint16_t remote_port; + uint16_t local_port; + uint8_t family; + uint8_t type; + uint8_t admin_state; +#ifdef WITH_POLICY + uint32_t priority; + policy_tags_t tags; +#endif /* WITH_POLICY */ +} cmd_connection_add_t; + +typedef struct { + char symbolic_or_connid[SYMBOLIC_NAME_LEN]; +} cmd_connection_remove_t; + +typedef struct { + void *_; +} cmd_connection_list_t; + +// Sync this struct with `hc_connection_t` in `api.h` +typedef struct { + uint32_t id; + char name[SYMBOLIC_NAME_LEN]; + char interface_name[SYMBOLIC_NAME_LEN]; + uint8_t type; + uint8_t family; + ip_address_t local_addr; + uint16_t local_port; + ip_address_t remote_addr; + uint16_t remote_port; + uint8_t admin_state; +#ifdef WITH_POLICY + uint32_t priority; + policy_tags_t tags; +#endif /* WITH_POLICY */ + uint8_t state; +} cmd_connection_list_item_t; + +typedef struct { + char symbolic_or_connid[SYMBOLIC_NAME_LEN]; + uint8_t admin_state; + uint8_t pad8[3]; +} cmd_connection_set_admin_state_t; + +typedef struct { + char symbolic_or_connid[SYMBOLIC_NAME_LEN]; + uint8_t admin_state; +#ifdef WITH_POLICY + uint32_t priority; + policy_tags_t tags; +#endif /* WITH_POLICY */ +} cmd_connection_update_t; + +typedef struct { + char symbolic_or_connid[SYMBOLIC_NAME_LEN]; + uint32_t priority; +} cmd_connection_set_priority_t; + +typedef struct { + char symbolic_or_connid[SYMBOLIC_NAME_LEN]; + policy_tags_t tags; +} cmd_connection_set_tags_t; + +/* Route */ + +typedef struct { + char symbolic_or_connid[SYMBOLIC_NAME_LEN]; + ip_address_t address; + uint16_t cost; + uint8_t family; + uint8_t len; +} cmd_route_add_t; + +typedef struct { + char symbolic_or_connid[SYMBOLIC_NAME_LEN]; + ip_address_t address; + uint8_t family; + uint8_t len; +} cmd_route_remove_t; + +typedef struct { + void *_; +} cmd_route_list_t; + +// Sync this struct with `hc_route_t` in `api.h` +typedef struct { + ip_address_t address; + uint32_t connection_id; + uint16_t cost; + uint8_t family; + uint8_t len; +} cmd_route_list_item_t; + +/* Cache */ + +typedef struct { + uint8_t activate; +} cmd_cache_set_store_t; + +typedef struct { + uint8_t activate; +} cmd_cache_set_serve_t; + +typedef struct { + void *_; +} cmd_cache_clear_t; + +typedef struct { + void *_; +} cmd_cache_list_t; + +typedef struct { + uint8_t store_in_cs; + uint8_t serve_from_cs; + uint32_t cs_size; + uint32_t num_stale_entries; +} cmd_cache_list_reply_t; + +typedef struct { + cmd_header_t header; + cmd_cache_list_reply_t payload; +} msg_cache_list_reply_t; + +/* WLDR */ + +typedef struct { + char symbolic_or_connid[SYMBOLIC_NAME_LEN]; + uint8_t activate; +} cmd_wldr_set_t; + +/* Strategy */ + +typedef struct { + ip_address_t address; + uint8_t family; + uint8_t len; + uint8_t type; + uint8_t related_prefixes; + union { + struct { + ip_address_t addresses[MAX_FWD_STRATEGY_RELATED_PREFIXES]; + uint8_t lens[MAX_FWD_STRATEGY_RELATED_PREFIXES]; + uint8_t families[MAX_FWD_STRATEGY_RELATED_PREFIXES]; + } low_latency; + }; +} cmd_strategy_set_t; + +typedef struct { + uint8_t type; + ip_address_t address; + uint8_t family; + uint8_t len; + ip_address_t local_address; + uint8_t local_family; + uint8_t local_len; +} cmd_strategy_add_local_prefix_t; + +/* Punting */ + +typedef struct { + char symbolic_or_connid[SYMBOLIC_NAME_LEN]; + ip_address_t address; + uint8_t family; + uint8_t len; +} cmd_punting_add_t; + +/* MAP-Me */ + +typedef struct { + uint8_t activate; +} cmd_mapme_activator_t; + +typedef cmd_mapme_activator_t cmd_mapme_enable_t; +typedef cmd_mapme_activator_t cmd_mapme_set_discovery_t; + +typedef struct { + uint32_t timePeriod; +} cmd_mapme_timing_t; + +typedef cmd_mapme_timing_t cmd_mapme_set_timescale_t; +typedef cmd_mapme_timing_t cmd_mapme_set_retx_t; + +typedef struct { + void *_; +} cmd_mapme_send_update_t; + +/* Policy */ + +typedef struct { + ip_address_t address; + uint8_t family; + uint8_t len; + hicn_policy_t policy; +} cmd_policy_add_t; + +typedef struct { + ip_address_t address; + uint8_t family; + uint8_t len; +} cmd_policy_remove_t; + +typedef struct { + void *_; +} cmd_policy_list_t; + +typedef struct { + ip_address_t address; + uint8_t family; + uint8_t len; + hicn_policy_t policy; +} cmd_policy_list_item_t; + +/* Subscription */ + +typedef struct { + uint32_t topics; +} cmd_subscription_add_t; + +typedef struct { + uint32_t topics; +} cmd_subscription_remove_t; + +/* Full messages */ + +#define _(l, u) \ + typedef struct { \ + cmd_header_t header; \ + cmd_##l##_t payload; \ + } msg_##l##_t; +foreach_command_type +#undef _ + + typedef struct { + cmd_header_t header; + cmd_listener_list_item_t payload; +} msg_listener_list_reply_t; + +typedef struct { + cmd_header_t header; + cmd_connection_list_item_t payload; +} msg_connection_list_reply_t; + +typedef struct { + cmd_header_t header; + cmd_route_list_item_t payload; +} msg_route_list_reply_t; + +typedef struct { + cmd_header_t header; + cmd_policy_list_item_t payload; +} msg_policy_list_reply_t; + +//===== size of commands ====== +// REMINDER: when a new_command is added, the following switch has to be +// updated. +static inline int command_get_payload_len(command_type_t command_type) { + switch (command_type) { +#define _(l, u) \ + case COMMAND_TYPE_##u: \ + return sizeof(cmd_##l##_t); + foreach_command_type +#undef _ + case COMMAND_TYPE_UNDEFINED : case COMMAND_TYPE_N : return 0; + } +} +#endif /* HICN_CTRL_HICNLIGHTNG_H */ diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h b/ctrl/libhicnctrl/includes/hicn/ctrl/hicn-light.h index 3758f0f41..69ede1985 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/hicn-light.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -20,8 +20,8 @@ * Header and payload in binary format. */ -#ifndef commands_h -#define commands_h +#ifndef HICN_CTRL_HICNLIGHT_H +#define HICN_CTRL_HICNLIGHT_H #ifndef _WIN32 #include <netinet/in.h> @@ -43,7 +43,7 @@ typedef struct in6_addr ipv6_addr_t; typedef uint32_t ipv4_addr_t; typedef enum { - REQUEST_LIGHT = 0xc0, // this is a command + REQUEST_LIGHT = 0xc0, // this is a command RESPONSE_LIGHT, ACK_LIGHT, NACK_LIGHT, @@ -133,7 +133,7 @@ typedef struct { typedef struct { char symbolic[SYMBOLIC_NAME_LEN]; - //char interfaceName[SYMBOLIC_NAME_LEN]; + // char interfaceName[SYMBOLIC_NAME_LEN]; ip_address_t remoteIp; ip_address_t localIp; uint16_t remotePort; @@ -415,7 +415,7 @@ static inline int payloadLengthDaemon(command_id id) { case ADD_POLICY: return sizeof(add_policy_command); case LIST_POLICIES: - return 0; // list policies: payload always 0 + return 0; // list policies: payload always 0 case REMOVE_POLICY: return sizeof(remove_policy_command); case UPDATE_CONNECTION: @@ -431,4 +431,4 @@ static inline int payloadLengthDaemon(command_id id) { return 0; } } -#endif +#endif /* HICN_CTRL_HICNLIGHT_H */ diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/route.h b/ctrl/libhicnctrl/includes/hicn/ctrl/route.h index d7ef6a26f..81f011d4d 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/route.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/route.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: @@ -21,7 +21,7 @@ #define HICN_ROUTE_H #include <hicn/util/ip_address.h> -#include <hicn/ctrl/face.h> +#include <hicn/face.h> typedef u16 route_cost_t; @@ -30,18 +30,23 @@ typedef struct hicn_route_s hicn_route_t; #define MAXSZ_ROUTE_ MAXSZ_PREFIX + 3 + MAXSZ_COST #define MAXSZ_ROUTE MAXSZ_ROUTE_ + NULLTERM -hicn_route_t * hicn_route_create(ip_prefix_t * prefix, face_id_t face_id, route_cost_t cost); -hicn_route_t * hicn_route_dup(const hicn_route_t * route); -void hicn_route_free(hicn_route_t * route); +#define MIN_ROUTE_COST 1 +#define MAX_ROUTE_COST 255 +#define IS_VALID_ROUTE_COST(x) ((x >= MIN_ROUTE_COST) && (x <= MAX_ROUTE_COST)) -int hicn_route_cmp(const hicn_route_t * route1, const hicn_route_t * route2); +hicn_route_t* hicn_route_create(ip_prefix_t* prefix, face_id_t face_id, + route_cost_t cost); +hicn_route_t* hicn_route_dup(const hicn_route_t* route); +void hicn_route_free(hicn_route_t* route); -int hicn_route_get_prefix(const hicn_route_t * route, ip_prefix_t * prefix); -int hicn_route_set_prefix(hicn_route_t * route, const ip_prefix_t prefix); +int hicn_route_cmp(const hicn_route_t* route1, const hicn_route_t* route2); -int hicn_route_get_cost(const hicn_route_t * route, int * cost); -int hicn_route_set_cost(hicn_route_t * route, const int cost); +int hicn_route_get_prefix(const hicn_route_t* route, ip_prefix_t* prefix); +int hicn_route_set_prefix(hicn_route_t* route, const ip_prefix_t prefix); -size_t hicn_route_snprintf(char * s, size_t size, const hicn_route_t * route); +int hicn_route_get_cost(const hicn_route_t* route, int* cost); +int hicn_route_set_cost(hicn_route_t* route, const int cost); + +size_t hicn_route_snprintf(char* s, size_t size, const hicn_route_t* route); #endif 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 */ |