diff options
author | Jordan Augé <jordan.auge+fdio@cisco.com> | 2020-09-23 17:50:52 +0200 |
---|---|---|
committer | Mauro Sardara <msardara@cisco.com> | 2021-03-19 14:15:14 +0100 |
commit | a070b0de9f9e9cbca150eea4eda74757ca588bed (patch) | |
tree | 9f2a11fa1afcd51b0b14f4b26bebf4deb8289a2f | |
parent | 32dccec98e4c7d7e4ce902e19ba8d1b29b823758 (diff) |
[HICN-645] Control plane (WIP)
Change-Id: I4be6a40b690b62f22f57de6d8c10b01a1be42a6d
Signed-off-by: Jordan Augé <jordan.auge+fdio@cisco.com>
Signed-off-by: Enrico Loparco (eloparco) <eloparco@cisco.com>
Signed-off-by: Mauro Sardara <msardara@cisco.com>
72 files changed, 3564 insertions, 2271 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index c76d89e22..194084de8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,10 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules") set_property(GLOBAL PROPERTY USE_FOLDERS ON) +# Enable gtests (`make test`) +# `make test ARGS="-V"` can be used for verbose output +enable_testing() + ## Enabled components option(BUILD_LIBHICN "Build the hicn core library" ON) option(BUILD_HICNLIGHT "Build the hicn light forwarder" ON) @@ -62,9 +66,9 @@ endif() list(APPEND dir_options BUILD_LIBHICN + BUILD_CTRL BUILD_HICNLIGHT BUILD_HICNPLUGIN - BUILD_CTRL BUILD_LIBTRANSPORT BUILD_UTILS BUILD_APPS @@ -103,4 +107,4 @@ foreach(dir ${subdirs}) endforeach() include(Packager) -make_packages()
\ No newline at end of file +make_packages() diff --git a/ctrl/libhicnctrl/includes/CMakeLists.txt b/ctrl/libhicnctrl/includes/CMakeLists.txt index 36a55caa2..88f8519b7 100644 --- a/ctrl/libhicnctrl/includes/CMakeLists.txt +++ b/ctrl/libhicnctrl/includes/CMakeLists.txt @@ -20,6 +20,7 @@ set(LIBHICNCTRL_INCLUDE_DIRS 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/cli.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/ctrl/commands.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/ctrl/route.h PARENT_SCOPE diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h index c3fb62534..3771b3abd 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h @@ -89,7 +89,9 @@ * Message helper types and aliases ******************************************************************************/ -#define foreach_command \ +/* Action */ + +#define foreach_action \ _(UNDEFINED) \ _(CREATE) \ _(UPDATE) \ @@ -100,10 +102,41 @@ 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) \ + _(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); + /** * \brief hICN control message header */ @@ -729,4 +762,25 @@ int hc_policy_snprintf(char *s, size_t size, hc_policy_t *policy); #endif /* WITH_POLICY */ +/* 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_punting_t punting; + hc_strategy_t strategy; + hc_policy_t policy; + 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/cli.h b/ctrl/libhicnctrl/includes/hicn/ctrl/cli.h new file mode 100644 index 000000000..ce1ee7c74 --- /dev/null +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/cli.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file cli.h + * @brief Command line helpers + */ + +#ifndef HICNCTRL_CLI +#define HICNCTRL_CLI + +#include "api.h" + +#define MAXSZ_OBJECT 255 // XXX + +int hc_object_type_snprintf(char * buf, size_t size, hc_object_type_t type, uint8_t * data); +int hc_object_snprintf(char * buf, size_t size, hc_object_t * object); + +#endif /* HICNCTRL_CLI */ diff --git a/ctrl/libhicnctrl/src/CMakeLists.txt b/ctrl/libhicnctrl/src/CMakeLists.txt index c3d843100..1a64296e8 100644 --- a/ctrl/libhicnctrl/src/CMakeLists.txt +++ b/ctrl/libhicnctrl/src/CMakeLists.txt @@ -16,7 +16,6 @@ list(APPEND COMPILER_DEFINITIONS ) set(HEADER_FILES - api.h commands.h ) @@ -24,6 +23,8 @@ set(UTIL_HEADER_FILES ) set(SOURCE_FILES + hicnctrl.c + cli.c route.c ) diff --git a/ctrl/libhicnctrl/src/api.c b/ctrl/libhicnctrl/src/api.c index 84f34d3c2..080b6541a 100644 --- a/ctrl/libhicnctrl/src/api.c +++ b/ctrl/libhicnctrl/src/api.c @@ -3115,3 +3115,46 @@ hc_policy_snprintf(char * s, size_t size, hc_policy_t * policy) } #endif /* WITH_POLICY */ + +const char * action_str[] = { +#define _(x) [ACTION_ ## x] = #x, + foreach_action +#undef _ +}; + +hc_action_t +action_from_str(const char * action_str) +{ +#define _(x) \ + if (strcasecmp(action_str, # x) == 0) \ + return ACTION_ ## x; \ + else + foreach_action +#undef _ + if (strcasecmp(action_str, "add") == 0) + return ACTION_CREATE; + else + if (strcasecmp(action_str, "remove") == 0) + return ACTION_DELETE; + else + return ACTION_UNDEFINED; +} + +const char * object_str[] = { +#define _(x) [OBJECT_ ## x] = #x, + foreach_object +#undef _ +}; + +hc_object_type_t +object_from_str(const char * object_str) +{ +#define _(x) \ + if (strcasecmp(object_str, # x) == 0) \ + return OBJECT_ ## x; \ + else + foreach_object +#undef _ + return OBJECT_UNDEFINED; +} + diff --git a/ctrl/libhicnctrl/src/cli.c b/ctrl/libhicnctrl/src/cli.c index fc81139d6..17ffa2bd5 100644 --- a/ctrl/libhicnctrl/src/cli.c +++ b/ctrl/libhicnctrl/src/cli.c @@ -1,868 +1,49 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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/ctrl/api.h> +#include <hicn/ctrl/cli.h> -/** - * \file cli.c - * \brief Command line interface - */ -#include <ctype.h> // isalpha isalnum -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> // getopt +typedef int (*hc_object_snprintf_type)(char*, size_t, uint8_t*); -#include <hicn/ctrl.h> -#include <hicn/util/ip_address.h> -#include <hicn/util/token.h> +static const hc_object_snprintf_type map_object_snprintf[] = { + [OBJECT_CONNECTION] = (hc_object_snprintf_type)hc_connection_snprintf, + [OBJECT_LISTENER] = (hc_object_snprintf_type)hc_listener_snprintf, + [OBJECT_ROUTE] = (hc_object_snprintf_type)hc_route_snprintf, + [OBJECT_FACE] = (hc_object_snprintf_type)hc_face_snprintf, + [OBJECT_STRATEGY] = (hc_object_snprintf_type)hc_strategy_snprintf, + [OBJECT_POLICY] = (hc_object_snprintf_type)hc_policy_snprintf, + [OBJECT_PUNTING] = (hc_object_snprintf_type)hc_punting_snprintf, +}; - -#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; - -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 [ [-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) +int +hc_object_type_snprintf(char * buffer, size_t size, hc_object_type_t type, uint8_t * data) { -#define _(x) \ - if (strcasecmp(str, STRINGIZE(x)) == 0) \ - return FACE_TYPE_ ## x; \ - else -foreach_face_type -#undef _ - return FACE_TYPE_UNDEFINED; + return map_object_snprintf[type](buffer, size, data); } - int -parse_options(int argc, char *argv[], hc_command_t * command) +hc_object_snprintf(char * buffer, size_t size, hc_object_t * object) { - command->object = OBJECT_UNDEFINED; - command->action = ACTION_CREATE; - int opt; - int family; - - while ((opt = getopt(argc, argv, "dflcrFLCRSh")) != -1) { - switch (opt) { - 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; - + // XXX assert valid object + return hc_object_type_snprintf(buffer, size, object->type, &object->as_uint8); +#if 0 + switch(object->type) { 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]; - - if (parse_options(argc, argv, &command) < 0) - die(OPTIONS, "Bad arguments"); - - hc_sock_t * s = hc_sock_create(); - 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; - + return hc_connection_snprintf(buffer, size, &object->connection); + case OBJECT_LISTENER: + return hc_listener_snprintf(buffer, size, &object->listener); 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; - + return hc_route_snprintf(buffer, size, &object->route); + case OBJECT_FACE: + return hc_face_snprintf(buffer, size, &object->face); 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; - + return hc_strategy_snprintf(buffer, size, &object->strategy); + case OBJECT_POLICY: + return hc_policy_snprintf(buffer, size, &object->policy); + case OBJECT_PUNTING: + return hc_punting_snprintf(buffer, size, &object->punting); + case OBJECT_UNDEFINED: + case OBJECT_N: default: - die(COMMAND, "Unsupported object"); - break; + return -1; } - -ERR_COMMAND: -ERR_CONNECT: - hc_sock_free(s); -ERR_SOCKET: -ERR_OPTIONS: - return (rc < 0) ? EXIT_FAILURE : EXIT_SUCCESS; +#endif } diff --git a/ctrl/libhicnctrl/src/hicnctrl.c b/ctrl/libhicnctrl/src/hicnctrl.c new file mode 100644 index 000000000..4be9f196c --- /dev/null +++ b/ctrl/libhicnctrl/src/hicnctrl.c @@ -0,0 +1,842 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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) + +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 [ [-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); +} + +/** + * 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) +{ + command->object.type = OBJECT_UNDEFINED; + command->action = ACTION_CREATE; + int opt; + int family; + + while ((opt = getopt(argc, argv, "dflcrFLCRSh")) != -1) { + switch (opt) { + case 'd': + command->action = ACTION_DELETE; + break; + case 'f': + command->object.type = OBJECT_FACE; + break; + case 'l': + command->object.type = OBJECT_LISTENER; + break; + case 'c': + command->object.type = OBJECT_CONNECTION; + break; + case 'r': + command->object.type = OBJECT_ROUTE; + 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->object.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])) { + 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; + } + 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; + } + 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->object.listener.name, SYMBOLIC_NAME_LEN, "%s", argv[optind++]); + command->object.listener.type = connection_type_from_str(argv[optind++]); + if (command->object.listener.type == CONNECTION_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])) { + 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])) { + 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 = connection_type_from_str(argv[optind++]); + if (command->object.listener.type == CONNECTION_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; + } + 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 = connection_type_from_str(argv[optind++]); + if (command->object.connection.type == CONNECTION_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])) { + 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])) { + 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 = connection_type_from_str(argv[optind++]); + if (command->object.connection.type == CONNECTION_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; + } + 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]; + + if (parse_options(argc, argv, &command) < 0) + die(OPTIONS, "Bad arguments"); + + hc_sock_t * s = hc_sock_create(); + 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) < 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; + 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/hicn-light/CMakeLists.txt b/hicn-light/CMakeLists.txt index 42e7d0a01..fa8c6664e 100644 --- a/hicn-light/CMakeLists.txt +++ b/hicn-light/CMakeLists.txt @@ -35,6 +35,8 @@ include( CTest ) include( detectCacheSize ) if(NOT WIN32) + # NOTE: -fPIC -shared is needed to preserve constructors when targetting a + # shared library set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") else () set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4996") @@ -52,28 +54,32 @@ include(WindowsMacros) set(HICN_LIGHT hicn-light CACHE INTERNAL "" FORCE) set(HICN_LIGHT_CONTROL ${HICN_LIGHT}-control CACHE INTERNAL "" FORCE) +set(HICN_LIGHT_SHELL ${HICN_LIGHT}-shell CACHE INTERNAL "" FORCE) set(HICN_LIGHT_DAEMON ${HICN_LIGHT}-daemon CACHE INTERNAL "" FORCE) find_package_wrapper(LibEvent REQUIRED) if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) find_package_wrapper(Libhicn REQUIRED) + find_package_wrapper(Libhicnctrl REQUIRED) else() if (DISABLE_SHARED_LIBRARIES) if (WIN32) - set(HICN_LIBRARIES ${LIBEVENT_STATIC} ${LIBHICN_STATIC}) + set(HICN_LIBRARIES ${LIBEVENT_STATIC} ${LIBHICN_STATIC} ${LIBHICNCTRL_STATIC}) else () - set(HICN_LIBRARIES ${LIBEVENT_STATIC} ${LIBHICN_STATIC} log) + set(HICN_LIBRARIES ${LIBEVENT_STATIC} ${LIBHICN_STATIC} ${LIBHICNCTRL_STATIC} log) endif () list(APPEND DEPENDENCIES ${LIBEVENT_STATIC} ${LIBHICN_STATIC} + ${LIBHICNCTRL_STATIC} ) else () set(HICN_LIBRARIES ${LIBHICN_SHARED}) list(APPEND DEPENDENCIES ${LIBEVENT_SHARED} ${LIBHICN_SHARED} + ${LIBHICNCTRL_SHARED} ) endif () endif() @@ -88,6 +94,7 @@ set(LIBHICN_LIGHT_SHARED ${LIBHICN_LIGHT}.shared) set(HICN_LIGHT_LINK_LIBRARIES ${HICN_LIBRARIES} + ${LIBHICNCTRL_LIBRARIES} ${LIBEVENT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${WINDOWS_LIBRARIES} @@ -97,6 +104,7 @@ set(HICN_LIGHT_LINK_LIBRARIES # Include dirs -- Order does matter! list(APPEND HICN_LIGHT_INCLUDE_DIRS ${HICN_INCLUDE_DIRS} + ${LIBHICNCTRL_INCLUDE_DIRS} ${LIBEVENT_INCLUDE_DIRS} ${WINDOWS_INCLUDE_DIRS} ) diff --git a/hicn-light/src/hicn/CMakeLists.txt b/hicn-light/src/hicn/CMakeLists.txt index 4ecd5e2a0..ff1f2d4fb 100644 --- a/hicn-light/src/hicn/CMakeLists.txt +++ b/hicn-light/src/hicn/CMakeLists.txt @@ -32,7 +32,7 @@ endif() if (NOT DISABLE_EXECUTABLES) - add_subdirectory(command_line) + add_subdirectory(cli) endif() add_subdirectory(base) diff --git a/hicn-light/src/hicn/base/bitmap.h b/hicn-light/src/hicn/base/bitmap.h index 4a78af567..ebc3dddbb 100644 --- a/hicn-light/src/hicn/base/bitmap.h +++ b/hicn-light/src/hicn/base/bitmap.h @@ -43,8 +43,8 @@ typedef uint_fast32_t bitmap_t; * @param[in] max_size Bitmap max_size */ #define bitmap_init(bitmap, init_size, max_size) \ - vector_init(bitmap, next_pow2(init_size / BITMAP_WIDTH(bitmap)), \ - max_size == 0 ? 0 : next_pow2(max_size / BITMAP_WIDTH(bitmap))) + vector_init(bitmap, next_pow2((init_size) / BITMAP_WIDTH(bitmap)), \ + max_size == 0 ? 0 : next_pow2((max_size) / BITMAP_WIDTH(bitmap))) /* * @brief Ensures a bitmap is sufficiently large to hold an element at the @@ -156,7 +156,7 @@ bitmap_set_range(bitmap_t * bitmap, off_t from, off_t to) */ if ((pos_to != BITMAP_WIDTH(bitmap) - 1) && (offset_to != offset_from)) { size_t to_start = MAX(from, offset_to * BITMAP_WIDTH(bitmap)); - for (size_t k = to_start; k < to; k++) { + for (size_t k = to_start; k < (size_t) to; k++) { if (bitmap_set(bitmap, k) < 0) goto END; } diff --git a/hicn-light/src/hicn/base/pool.c b/hicn-light/src/hicn/base/pool.c index 31abb13f1..cb650b9e5 100644 --- a/hicn-light/src/hicn/base/pool.c +++ b/hicn-light/src/hicn/base/pool.c @@ -16,7 +16,7 @@ /** * \file pool.c * \brief Implementation of fixed-size pool allocator. - * + * * NOTE: * - Ideally, we should have a single realloc per resize, that would encompass * both the free indices vector and bitmap, by nesting data structures. Because @@ -81,6 +81,10 @@ ERR_MAX_SIZE: void _pool_free(void ** pool_ptr) { + pool_hdr_t * ph = pool_hdr(*pool_ptr); + vector_free(ph->free_indices); + bitmap_free(ph->free_bitmap); + free(pool_hdr(*pool_ptr)); *pool_ptr = NULL; } diff --git a/hicn-light/src/hicn/base/test/CMakeLists.txt b/hicn-light/src/hicn/base/test/CMakeLists.txt index 351e7bd34..cdf6ed11b 100644 --- a/hicn-light/src/hicn/base/test/CMakeLists.txt +++ b/hicn-light/src/hicn/base/test/CMakeLists.txt @@ -15,9 +15,9 @@ foreach(test ${TESTS}) build_executable(${test} NO_INSTALL SOURCES ${test}.cc - LINK_LIBRARIES ${LIBHICN_LIGHT_SHARED} ${GTEST_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + LINK_LIBRARIES ${LIBHICN_LIGHT_SHARED} ${LIBHICNCTRL_SHARED} ${GTEST_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} INCLUDE_DIRS ${HICN_LIGHT_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS} - DEPENDS gtest ${LIBHICN_LIGHT_SHARED} + DEPENDS gtest ${LIBHICNCTRL_SHARED} ${LIBHICN_LIGHT_SHARED} COMPONENT ${HICN_LIGHT} DEFINITIONS "${COMPILER_DEFINITIONS}" ) diff --git a/hicn-light/src/hicn/base/test/test-bitmap.cc b/hicn-light/src/hicn/base/test/test-bitmap.cc index 1a62edba3..d1b335ace 100644 --- a/hicn-light/src/hicn/base/test/test-bitmap.cc +++ b/hicn-light/src/hicn/base/test/test-bitmap.cc @@ -57,32 +57,32 @@ TEST_F(BitmapTest, BitmapAllocation) * Bitmap should have been allocated with a size rounded to the next power * of 2 */ - EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); /* By default, no element should be set */ EXPECT_FALSE(bitmap_is_set(bitmap, 0)); EXPECT_TRUE(bitmap_is_unset(bitmap, 0)); - EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); EXPECT_FALSE(bitmap_is_set(bitmap, size_not_pow2 - 1)); EXPECT_TRUE(bitmap_is_unset(bitmap, size_not_pow2 - 1)); /* Bitmap should not have been reallocated */ - EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); /* After setting a bit after the end, bitmap should have been reallocated */ bitmap_set(bitmap, sizeof(bitmap[0]) * 8 - 1); - EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); /* After setting a bit after the end, bitmap should have been reallocated */ rc = bitmap_set(bitmap, sizeof(bitmap[0]) * 8); EXPECT_GE(rc, 0); - EXPECT_EQ(bitmap_get_alloc_size(bitmap), 2); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 2UL); rc = bitmap_set(bitmap, sizeof(bitmap[0]) * 8 + 1); EXPECT_GE(rc, 0); - EXPECT_EQ(bitmap_get_alloc_size(bitmap), 2); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 2UL); bitmap_free(bitmap); @@ -90,7 +90,7 @@ TEST_F(BitmapTest, BitmapAllocation) /* Limiting test for allocation size */ bitmap_init(bitmap, size_pow2, 0); - EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); bitmap_free(bitmap); } diff --git a/hicn-light/src/hicn/base/test/test-pool.cc b/hicn-light/src/hicn/base/test/test-pool.cc index 1146ef2b7..f87ff65dd 100644 --- a/hicn-light/src/hicn/base/test/test-pool.cc +++ b/hicn-light/src/hicn/base/test/test-pool.cc @@ -56,7 +56,7 @@ TEST_F(PoolTest, PoolAllocation) /* Check that free indices and bitmaps are correctly initialize */ off_t * fi = pool_get_free_indices(pool); EXPECT_EQ(vector_len(fi), pool_size); - EXPECT_EQ(fi[0], pool_size - 1); + EXPECT_EQ(fi[0], (long) (pool_size - 1)); EXPECT_EQ(fi[pool_size - 1], 0); /* The allocated size of the underlying vector should be the next power of two */ @@ -89,12 +89,12 @@ TEST_F(PoolTest, PoolAllocation) rc = pool_get(pool, elt); EXPECT_GE(rc, 0); - EXPECT_EQ(vector_len(fi), 1); + EXPECT_EQ(vector_len(fi), 1UL); EXPECT_TRUE(bitmap_is_unset(fb, pool_size - 2)); rc = pool_get(pool, elt); EXPECT_GE(rc, 0); - EXPECT_EQ(vector_len(fi), 0); + EXPECT_EQ(vector_len(fi), 0UL); EXPECT_TRUE(bitmap_is_unset(fb, pool_size - 1)); /* @@ -155,6 +155,21 @@ TEST_F(PoolTest, PoolPut) pool_free(pool); } +// TODO: this test fails, there is a problem when N = n*64 +// (i.e. when a bitmap reallocation occurs) +TEST_F(PoolTest, PoolGetForceBitmapRealloc) +{ + const int N = 64; + int *elts[N]; + int *elt = NULL; + pool_init(pool, N, 0); + + for (int i = 0; i < N; i++) + pool_get(pool, elts[i]); + pool_get(pool, elt); + + pool_free(pool); +} int main(int argc, char **argv) { diff --git a/hicn-light/src/hicn/base/test/test-vector.cc b/hicn-light/src/hicn/base/test/test-vector.cc index 59571b053..aaec7a92c 100644 --- a/hicn-light/src/hicn/base/test/test-vector.cc +++ b/hicn-light/src/hicn/base/test/test-vector.cc @@ -49,15 +49,15 @@ TEST_F(VectorTest, VectorAllocate) vector_init(vector, DEFAULT_SIZE, 0); /* Allocated size should be the next power of two */ - EXPECT_EQ(vector_get_alloc_size(vector), 16); + EXPECT_EQ(vector_get_alloc_size(vector), 16UL); /* Setting elements within the allocated size should not trigger a resize */ vector_ensure_pos(vector, 15); - EXPECT_EQ(vector_get_alloc_size(vector), 16); + EXPECT_EQ(vector_get_alloc_size(vector), 16UL); /* Setting elements after should through */ vector_ensure_pos(vector, 16); - EXPECT_EQ(vector_get_alloc_size(vector), 32); + EXPECT_EQ(vector_get_alloc_size(vector), 32UL); /* Check that free indices and bitmaps are correctly updated */ diff --git a/hicn-light/src/hicn/base/vector.h b/hicn-light/src/hicn/base/vector.h index ff12e6ee6..b369086fc 100644 --- a/hicn-light/src/hicn/base/vector.h +++ b/hicn-light/src/hicn/base/vector.h @@ -129,7 +129,7 @@ int _vector_ensure_pos(void ** vector_ptr, size_t elt_size, off_t pos) { vector_hdr_t * vh = vector_hdr(*vector_ptr); - if (pos >= vh->alloc_size) + if (pos >= (off_t) vh->alloc_size) return _vector_resize(vector_ptr, elt_size, pos + 1); return 0; } diff --git a/hicn-light/src/hicn/cli/CMakeLists.txt b/hicn-light/src/hicn/cli/CMakeLists.txt new file mode 100644 index 000000000..3f9906b19 --- /dev/null +++ b/hicn-light/src/hicn/cli/CMakeLists.txt @@ -0,0 +1,56 @@ +# Copyright (c) 2017-2020 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if (NOT DISABLE_EXECUTABLES) + + list(APPEND CONTROLLER_SRC + color.c + hicnc.c + ) + + build_executable(${HICN_LIGHT_CONTROL} + SOURCES ${CONTROLLER_SRC} +#LINK_LIBRARIES -Wl,--whole-archive ${LIBHICN_LIGHT_STATIC} -Wl,--no-whole-archive ${LIBHICNCTRL_STATIC} + LINK_LIBRARIES ${LIBHICN_LIGHT_SHARED} ${LIBHICNCTRL_STATIC} + DEPENDS ${LIBHICN_LIGHT_STATIC} + COMPONENT ${HICN_LIGHT} + DEFINITIONS ${COMPILER_DEFINITIONS} + ) + + list(APPEND SHELL_SRC + color.c + hicns.c + ) + + # XXX here linking to libhicnctrl should be sufficient + build_executable(${HICN_LIGHT_SHELL} + SOURCES ${SHELL_SRC} + LINK_LIBRARIES ${LIBHICN_LIGHT_SHARED} ${LIBHICNCTRL_STATIC} + DEPENDS ${LIBHICN_LIGHT_STATIC} + COMPONENT ${HICN_LIGHT} + DEFINITIONS ${COMPILER_DEFINITIONS} + ) + + list(APPEND DAEMON_SRC + color.c + hicnd.c + ) + + build_executable(${HICN_LIGHT_DAEMON} + SOURCES ${DAEMON_SRC} + LINK_LIBRARIES ${LIBHICN_LIGHT_SHARED} ${LIBHICNCTRL_STATIC} + DEPENDS ${LIBHICN_LIGHT_STATIC} + COMPONENT ${HICN_LIGHT} + DEFINITIONS ${COMPILER_DEFINITIONS} + ) +endif () diff --git a/hicn-light/src/hicn/cli/color.c b/hicn-light/src/hicn/cli/color.c new file mode 100644 index 000000000..2fff2ead6 --- /dev/null +++ b/hicn-light/src/hicn/cli/color.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include "color.h" + +#ifndef _WIN32 + +void +vprintfc(color_t color, const char * fmt, va_list ap) +{ + char * color_s; + switch(color) { +#define _(x, y, z) \ + case COLOR_ ## x: \ + color_s = y; \ + break; + foreach_color +#undef _ + + case COLOR_UNDEFINED: + case COLOR_N: + color_s = ""; + break; + } + printf("%s", color_s); + vprintf(fmt, ap); +} +#else +void +vprintfc(color_t color, const char * fmt, va_list ap) +{ + int color_id; + switch(color) { +#define _(x, y, z) \ + case COLOR_ ## x: \ + color_id = z; \ + break; + foreach_color +#undef _ + + case COLOR_UNDEFINED: + case COLOR_N: + color_id = 0; + break; + } + HANDLE hConsole = NULL; + WORD currentConsoleAttr; + CONSOLE_SCREEN_BUFFER_INFO csbi; + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + if (GetConsoleScreenBufferInfo(hConsole, &csbi)) + currentConsoleAttr = csbi.wAttributes; + if (color_id != 0) + SetConsoleTextAttribute(hConsole, color_id); + fprintf("%s", color); + vfprintf(fmt, ap); + SetConsoleTextAttribute(hConsole, currentConsoleAttr); +} +#endif + +void +printfc(color_t color, const char * fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vprintfc(color, fmt, ap); + va_end(ap); +} diff --git a/hicn-light/src/hicn/cli/color.h b/hicn-light/src/hicn/cli/color.h new file mode 100644 index 000000000..763666f18 --- /dev/null +++ b/hicn-light/src/hicn/cli/color.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HICNLIGHT_COLOR +#define HICNLIGHT_COLOR + +#include <stdarg.h> + +/* + * Format : color_name, escape sequence, windows id + */ +#define foreach_color \ + _(RED, "\033[0;31m", 4) \ + _(WHITE, "\033[0m", 7) + +typedef enum { + COLOR_UNDEFINED, +#define _(x, y, z) COLOR_ ## x, + foreach_color +#undef _ + COLOR_N, +} color_t; + +#define IS_VALID_COLOR(color) \ + ((color != COLOR_UNDEFINED) && (color != COLOR_N)) + +void vprintfc(color_t color, const char * fmt, va_list ap); + +void printfc(color_t color, const char * fmt, ...); + +#endif /* HICNLIGHT_COLOR */ diff --git a/hicn-light/src/hicn/cli/hicnc.c b/hicn-light/src/hicn/cli/hicnc.c new file mode 100644 index 000000000..d6c7c4180 --- /dev/null +++ b/hicn-light/src/hicn/cli/hicnc.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <limits.h> // LONG_MAX, LONG_MIN +#include <hicn/ctrl.h> + +#ifndef _WIN32 +#include <getopt.h> +#endif + +#include "color.h" +#include "../config/parse.h" + +#define PORT 9695 + +static +struct option longFormOptions[] = { + {"help", no_argument, 0, 'h'}, + {"server", required_argument, 0, 'S'}, + {"port", required_argument, 0, 'P'}, + {0, 0, 0, 0}}; + +static void usage(char *prog) { + printf("%s: portable hICN forwarder\n", prog); + printf("\n"); + printf("Usage: %s COMMAND [PARAMETERS]\n", prog); + printf("\n"); + printf(" %s -h This help screen.\n", prog); + printf(" %s help Obtain a list of available commands.\n", prog); + printf("\n"); +} + +int +main(int argc, char * const * argv) +{ + /* Parse commandline */ + char *server_ip = NULL; + uint16_t server_port = 0; + + for(;;) { + // getopt_long stores the option index here. + int optind = 0; + + int c = getopt_long(argc, argv, "hS:P:", longFormOptions, &optind); + if (c == -1) + break; + + switch (c) { + case 'S': + server_ip = optarg; + break; + + case 'P': + { + char *endptr; + long val = strtol(optarg, &endptr, 10); + + errno = 0; /* To distinguish success/failure after call */ + + if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) + || (errno != 0 && val == 0)) { + perror("strtol"); + exit(EXIT_FAILURE); + } + + if (endptr == optarg) { + fprintf(stderr, "No digits were found.\n"); + exit(EXIT_FAILURE); + } + + if (*endptr != '\0') { + fprintf(stderr, "Spurious characters after number: %s.\n", endptr); + exit(EXIT_FAILURE); + } + + if ((val < 1) || (val > 65535)) { + fprintf(stderr, "Invalid port number: %ld.\n", val); + exit(EXIT_FAILURE); + } + + server_port = val; + break; + } + + case 'h': + usage(argv[0]); + exit(EXIT_SUCCESS); + + default: + fprintf(stderr, "Invalid argument.\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + } + + /* Parse */ + char * param = argv[optind]; + for (; optind < argc - 1; optind++) { + char * arg = argv[optind]; + arg[strlen(arg)] = ' '; + } + + if (!param) { + usage(argv[0]); + goto ERR_PARAM; + } + + hc_command_t command; + if (parse(param, &command) < 0) { + fprintf(stderr, "Error parsing command : '%s'\n", param); + goto ERR_PARSE; + } + + + hc_data_t * data; + + hc_sock_t * s; + if (server_ip) { + if (server_port == 0) + server_port = PORT; +#define BUFSIZE 255 + char url[BUFSIZE]; + snprintf(url, BUFSIZE, "tcp://%s:%d/", server_ip, server_port); + s = hc_sock_create_url(url); + } else { + s = hc_sock_create(); + } + if (!s) { + fprintf(stderr, "Could not create socket.\n"); + goto ERR_SOCK; + } + + if (hc_sock_connect(s) < 0) { + fprintf(stderr, "Could not establish connection to forwarder.\n"); + goto ERR_CONNECT; + } + + /* XXX connection list */ + if (hc_connection_list(s, &data) < 0) { + fprintf(stderr, "Error running command"); + goto ERR_CMD; + } + + char buf[MAXSZ_HC_CONNECTION]; // XXX + foreach_connection(c, data) { + /* XXX connection print */ + int rc = hc_connection_snprintf(buf, MAXSZ_HC_CONNECTION, c); + if (rc < 0) { + strncpy(buf, "(Error)", MAXSZ_HC_CONNECTION); + } else if (rc >= MAXSZ_HC_CONNECTION) { + buf[MAXSZ_HC_CONNECTION-1] = '\0'; + buf[MAXSZ_HC_CONNECTION-2] = '.'; + buf[MAXSZ_HC_CONNECTION-3] = '.'; + buf[MAXSZ_HC_CONNECTION-4] = '.'; + } + printf("%s\n", buf); + } + + hc_data_free(data); + exit(EXIT_SUCCESS); + +ERR_CMD: +ERR_CONNECT: + hc_sock_free(s); +ERR_SOCK: +ERR_PARSE: +ERR_PARAM: + exit(EXIT_FAILURE); +} diff --git a/hicn-light/src/hicn/cli/hicnd.c b/hicn-light/src/hicn/cli/hicnd.c new file mode 100644 index 000000000..a989cff25 --- /dev/null +++ b/hicn-light/src/hicn/cli/hicnd.c @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _WIN32 +#include <unistd.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> + +//#include <hicn/hicn-light/config.h> +#include <hicn/util/log.h> + +#include "logo.h" +#include "../base/loop.h" +#include "../core/forwarder.h" + +static +void +usage(const char * prog) +{ + printf("Usage: %s [--port port]" +#ifndef _WIN32 + " [--daemon]" +#endif + " [--capacity objectStoreSize] [--log facility=level]" + "[--log-file filename] [--config file]\n", prog); + printf("\n"); + printf( + "hicn-light run as a daemon is the program to launch the forwarder, " + "either as a console program\n"); + printf( + "or a background daemon (detatched from console). Once running, use the " + "program controller to\n"); + printf("configure hicn-light.\n"); + printf("\n"); + printf( + "The configuration file contains configuration lines as per " + "controller\n"); + printf( + "If logging level or content store capacity is set in the configuraiton " + "file, it overrides the command_line\n"); + printf( + "When a configuration file is specified, no default listeners on 'port' " + "are setup. Only 'add listener' lines\n"); + printf("in the configuration file matter.\n"); + printf("\n"); + printf( + "If no configuration file is specified, daemon will listen on TCP and " + "UDP ports specified by\n"); + printf( + "the --port flag (or default port). It will listen on both IPv4 and " + "IPv6 if available.\n"); + printf("\n"); + printf("Options:\n"); + printf("--port = tcp port for in-bound connections\n"); +#ifndef _WIN32 + printf("--daemon = start as daemon process\n"); +#endif + printf("--objectStoreSize = maximum number of content objects to cache\n"); + printf( + "--log = sets a facility to a given log level. You can have " + "multiple of these.\n"); + printf( + " facilities: all, config, core, io, message, " + "processor\n"); + printf( + " levels: debug, info, notice, warning, error, " + "critical, alert, off\n"); + printf(" example: daemon --log io=debug --log core=off\n"); + printf( + "--log-file = file to write log messages to (required in daemon " + "mode)\n"); + printf("--config = configuration filename\n"); + printf("\n"); +} + +#if 0 +static void _setLogLevelToLevel(int logLevelArray[LoggerFacility_END], + LoggerFacility facility, + const char *levelString) { + PARCLogLevel level = parcLogLevel_FromString(levelString); + + if (level < PARCLogLevel_All) { + // we have a good facility and level + logLevelArray[facility] = level; + } else { + printf("Invalid log level string %s\n", levelString); + usage(""); // XXX + exit(EXIT_FAILURE); + } +} + +/** + * string: "facility=level" + * Set the right thing in the logger + */ +static void _setLogLevel(int logLevelArray[LoggerFacility_END], + const char *string) { + char *tofree = parcMemory_StringDuplicate(string, strlen(string)); + char *p = tofree; + + char *facilityString = strtok(p, "="); + if (facilityString) { + char *levelString = strtok(NULL, "="); + + if (strcasecmp(facilityString, "all") == 0) { + for (LoggerFacility facility = 0; facility < LoggerFacility_END; + facility++) { + _setLogLevelToLevel(logLevelArray, facility, levelString); + } + } else { + LoggerFacility facility; + for (facility = 0; facility < LoggerFacility_END; facility++) { + if (strcasecmp(facilityString, logger_FacilityString(facility)) == 0) { + break; + } + } + + if (facility < LoggerFacility_END) { + _setLogLevelToLevel(logLevelArray, facility, levelString); + } else { + printf("Invalid facility string %s\n", facilityString); + usage(""); // XXX + exit(EXIT_FAILURE); + } + } + } + + parcMemory_Deallocate((void **)&tofree); +} +#endif + +#ifndef _WIN32 +static +int daemonize(void) +{ + /* Check whether we already are a daemon */ + if (getppid() == 1) + return 0; + + int rc = fork(); + if (rc < 0) { + ERROR("Fork error"); + goto ERR_FORK; + } else if (rc > 0) { + /* Parent exits successfully */ + exit(EXIT_SUCCESS); + } + + /* Child daemon detaches */ + DEBUG("child continuing, pid = %u\n", getpid()); + + /* get a new process group independent from old parent */ + setsid(); + + /* close all descriptors */ +#ifdef __ANDROID__ + for (int i = sysconf(_SC_OPEN_MAX); i >= 0; --i) + close(i); +#else + for (int i = getdtablesize(); i >= 0; --i) + close(i); +#endif + + /* + * Reset errno because it might be seg to EBADF from the close calls above + */ + errno = 0; + + /* Redirect stdin and stdout and stderr to /dev/null */ + const char *devnull = "/dev/null"; + int nullfile = open(devnull, O_RDWR); + if (nullfile < 0) { + ERROR("Error opening file '%s': (%d) %s", devnull, errno, strerror(errno)); + goto ERR_DEVNULL; + } + + + rc = dup(nullfile); + if (rc != 1) { + ERROR("Error duping fd 1 got %d file: (%d) %s", rc, errno, strerror(errno)); + goto ERR_DUP1; + } + rc = dup(nullfile); + if (rc != 2) { + ERROR("Error duping fd 2 got %d file: (%d) %s", rc, errno, strerror(errno)); + goto ERR_DUP2; + } + + /* Forwarder will capture signals */ + return 0; + +ERR_DUP2: +ERR_DUP1: +ERR_DEVNULL: +ERR_FORK: + return -1; +} +#endif + +#if 0 +static Logger *_createLogfile(const char *logfile) { +#ifndef _WIN32 + int logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, S_IWUSR | S_IRUSR); +#else + int logfd = + _open(logfile, _O_WRONLY | _O_APPEND | _O_CREAT, _S_IWRITE | _S_IREAD); +#endif + if (logfd < 0) { + fprintf(stderr, "Error opening %s for writing: (%d) %s\n", logfile, errno, + strerror(errno)); + exit(EXIT_FAILURE); + } + +#ifndef _WIN32 + chmod(logfile, S_IRWXU); +#endif + + PARCFileOutputStream *fos = parcFileOutputStream_Create(logfd); + PARCOutputStream *pos = parcFileOutputStream_AsOutputStream(fos); + PARCLogReporter *reporter = parcLogReporterFile_Create(pos); + + Logger *logger = logger_Create(reporter, parcClock_Wallclock()); + + parcOutputStream_Release(&pos); + parcLogReporter_Release(&reporter); + + return logger; +} +#endif + +int +main(int argc, const char * argv[]) +{ + logo(); + +#ifndef _WIN32 + bool daemon = false; +#else + WSADATA wsaData = {0}; + WSAStartup(MAKEWORD(2, 2), &wsaData); +#endif + + uint16_t port = PORT_NUMBER; + uint16_t configurationPort = 2001; + int capacity = -1; + const char *fn_config = NULL; + + char *logfile = NULL; + + if (argc == 2 && strcasecmp(argv[1], "-h") == 0) { + usage(argv[0]); + exit(EXIT_SUCCESS); // XXX redundant + } + +#if 0 + int logLevelArray[LoggerFacility_END]; + for (int i = 0; i < LoggerFacility_END; i++) + logLevelArray[i] = -1; +#endif + + // XXX use getoptlong ???? + for (int i = 0; i < argc; i++) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "--config") == 0) { + fn_config = argv[i + 1]; + i++; + } else if (strcmp(argv[i], "--port") == 0) { + port = atoi(argv[i + 1]); + i++; +#ifndef _WIN32 + } else if (strcmp(argv[i], "--daemon") == 0) { + daemon = true; +#endif + } else if (strcmp(argv[i], "--capacity") == 0 || + strcmp(argv[i], "-c") == 0) { + capacity = atoi(argv[i + 1]); + i++; + } else if (strcmp(argv[i], "--log") == 0) { + // XXX _setLogLevel(logLevelArray, argv[i + 1]); + i++; + } else if (strcmp(argv[i], "--log-file") == 0) { + if (logfile) { + // error cannot repeat + fprintf(stderr, "Cannot specify --log-file more than once\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + logfile = strndup(argv[i + 1], strlen(argv[i + 1])); + i++; + } else { + usage(argv[0]); + exit(EXIT_FAILURE); + } + } + } + + // set restrictive umask, in case we create any files + umask(027); + +#ifndef _WIN32 + if (daemon && (logfile == NULL)) { + fprintf(stderr, "Must specify a logfile when running in daemon mode\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + /* In daemon mode, parent will exit and child will continue */ + if (daemon && daemonize() < 0) { + ERROR("Could not daemonize process"); + exit(EXIT_FAILURE); + } +#endif + +#if 0 // XXX use hicn own logging + Logger *logger = NULL; + if (logfile) { + logger = _createLogfile(logfile); + parcMemory_Deallocate((void **)&logfile); + } else { + PARCLogReporter *stdoutReporter = parcLogReporterTextStdout_Create(); + logger = logger_Create(stdoutReporter, parcClock_Wallclock()); + parcLogReporter_Release(&stdoutReporter); + } + + for (int i = 0; i < LoggerFacility_END; i++) { + if (logLevelArray[i] > -1) { + logger_SetLogLevel(logger, i, logLevelArray[i]); + } + } +#endif + + /* + * The loop should be created before the forwarder instance as it is needed + * for timers + */ + MAIN_LOOP = loop_create(); + + forwarder_t * forwarder = forwarder_create(); + if (!forwarder) { + ERROR("Forwarder initialization failed. Are you running it with sudo privileges?"); + return -1; + } + + configuration_t * configuration = forwarder_get_configuration(forwarder); + if (capacity > -1) { + configuration_cs_set_size(configuration, capacity); + } + + forwarder_setup_local_listeners(forwarder, port); + if (fn_config) { + forwarder_read_config(forwarder, fn_config); + } + + INFO("%s running port %d configuration-port %d", argv[0], port, + configurationPort); + + /* Main loop */ + if (loop_dispatch(MAIN_LOOP) < 0) { + ERROR("Failed to run main loop"); + return EXIT_FAILURE; + } + + INFO("%s exiting port %d", argv[0], port); + + if (loop_undispatch(MAIN_LOOP) < 0) { + ERROR("Failed to terminate main loop"); + return EXIT_FAILURE; + } + + forwarder_free(forwarder); + + loop_free(MAIN_LOOP); + MAIN_LOOP = NULL; + +#ifdef _WIN32 + WSACleanup(); // XXX why is this needed here ? +#endif + + return 0; +} diff --git a/hicn-light/src/hicn/cli/hicns.c b/hicn-light/src/hicn/cli/hicns.c new file mode 100644 index 000000000..03e1bd54c --- /dev/null +++ b/hicn-light/src/hicn/cli/hicns.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <limits.h> // LONG_MAX, LONG_MIN +#include <hicn/ctrl.h> + +#ifndef _WIN32 +#include <getopt.h> +#endif + +#include "logo.h" +#include "../config/parse.h" + +#define PORT 9695 + +static +struct option longFormOptions[] = { + {"help", no_argument, 0, 'h'}, + {"server", required_argument, 0, 'S'}, + {"port", required_argument, 0, 'P'}, + {0, 0, 0, 0}}; + +static +void +usage(char *prog) { + printf("%s: interactive shell for hicn-light\n", prog); + printf("\n"); + printf("Usage: %s", prog); + printf("\n"); + printf(" %s -h This help screen.\n", prog); + printf("\n"); +} + +void +prompt(void) +{ + fputs("hicn> ", stdout); + fflush(stdout); +} + +int +shell(hc_sock_t * s) +{ + char *line = NULL; + size_t len = 0; + hc_data_t * data = NULL; + ssize_t nread; + + prompt(); + while ((nread = getline(&line, &len, stdin)) != -1) { + hc_command_t command; + + char * pos; + if ((pos=strchr(line, '\n')) != NULL) + *pos = '\0'; + + if (strlen(line) == 0) + goto CONTINUE; + + if (strcmp(line, "exit") == 0) + break; + if (strcmp(line, "quit") == 0) + break; + + + if (parse(line, &command) < 0) { + fprintf(stderr, "Unknown command '%s'\n", line); + goto CONTINUE; + } + + /* XXX connection list */ + if (hc_connection_list(s, &data) < 0) { + fprintf(stderr, "Error running command.\n"); + goto CONTINUE; + } + + char buf[MAXSZ_HC_CONNECTION]; // XXX + foreach_connection(c, data) { + /* XXX connection print */ + int rc = hc_connection_snprintf(buf, MAXSZ_HC_CONNECTION, c); + if (rc < 0) { + strncpy(buf, "(Error)", MAXSZ_HC_CONNECTION); + } else if (rc >= MAXSZ_HC_CONNECTION) { + buf[MAXSZ_HC_CONNECTION-1] = '\0'; + buf[MAXSZ_HC_CONNECTION-2] = '.'; + buf[MAXSZ_HC_CONNECTION-3] = '.'; + buf[MAXSZ_HC_CONNECTION-4] = '.'; + } + printf("%s\n", buf); + } + + hc_data_free(data); +CONTINUE: + prompt(); + } + + return 0; +} + +int +main(int argc, char * const * argv) +{ + logo(); + printf("Type 'help' for a list of available commands\n"); + printf("\n"); + printf("\n"); + + /* Parse commandline */ + char *server_ip = NULL; + uint16_t server_port = 0; + + for(;;) { + // getopt_long stores the option index here. + int optind = 0; + + int c = getopt_long(argc, argv, "hS:P:", longFormOptions, &optind); + if (c == -1) + break; + + switch (c) { + case 'S': + server_ip = optarg; + break; + + case 'P': + { + char *endptr; + long val = strtol(optarg, &endptr, 10); + + errno = 0; /* To distinguish success/failure after call */ + + if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) + || (errno != 0 && val == 0)) { + perror("strtol"); + exit(EXIT_FAILURE); + } + + if (endptr == optarg) { + fprintf(stderr, "No digits were found.\n"); + exit(EXIT_FAILURE); + } + + if (*endptr != '\0') { + fprintf(stderr, "Spurious characters after number: %s.\n", endptr); + exit(EXIT_FAILURE); + } + + if ((val < 1) || (val > 65535)) { + fprintf(stderr, "Invalid port number: %ld.\n", val); + exit(EXIT_FAILURE); + } + + server_port = (uint16_t)val; + break; + } + + case 'h': + usage(argv[0]); + exit(EXIT_SUCCESS); + + default: + fprintf(stderr, "Invalid argument.\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + } + + if (optind != argc) { + fprintf(stderr, "Invalid parameters.\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + + hc_sock_t * s; + if (server_ip) { + if (server_port == 0) + server_port = PORT; +#define BUFSIZE 255 + char url[BUFSIZE]; + snprintf(url, BUFSIZE, "tcp://%s:%d/", server_ip, server_port); + s = hc_sock_create_url(url); + } else { + s = hc_sock_create(); + } + if (!s) { + fprintf(stderr, "Could not create socket.\n"); + goto ERR_SOCK; + } + + if (hc_sock_connect(s) < 0) { + fprintf(stderr, "Could not establish connection to forwarder.\n"); + goto ERR_CONNECT; + } + + int rc = shell(s); + + exit((rc < 0) ? EXIT_FAILURE : EXIT_SUCCESS); + +ERR_CONNECT: + hc_sock_free(s); +ERR_SOCK: + exit(EXIT_FAILURE); +} diff --git a/hicn-light/src/hicn/cli/logo.h b/hicn-light/src/hicn/cli/logo.h new file mode 100644 index 000000000..1aff32837 --- /dev/null +++ b/hicn-light/src/hicn/cli/logo.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017-2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HICNLIGHT_LOGO +#define HICNLIGHT_LOGO + +#include "color.h" + +static +void +logo(void) +{ + printfc(COLOR_RED, " ____ ___ _ "); + printfc(COLOR_WHITE, " __ _ __ _ __ __\n"); + printfc(COLOR_RED, " / __// _ \\ (_)___ "); + printfc(COLOR_WHITE, " / / (_)____ ___ ____/ /(_)___ _ / / / /_\n"); + printfc(COLOR_RED, " / _/ / // /_ / // _ \\ "); + printfc(COLOR_WHITE, " / _ \\ / // __// _ \\___/ // // _ `// _ \\/ __/\n"); + printfc(COLOR_RED, "/_/ /____/(_)/_/ \\___/ "); + printfc(COLOR_WHITE, "/_//_//_/ \\__//_//_/ /_//_/ \\_, //_//_/\\__/\n"); + printfc(COLOR_WHITE, + " /___/ " + "\n"); + printf("\n"); +} + +#endif /* HICNLIGHT_LOGO */ diff --git a/hicn-light/src/hicn/command_line/CMakeLists.txt b/hicn-light/src/hicn/command_line/CMakeLists.txt deleted file mode 100644 index 217e00fd3..000000000 --- a/hicn-light/src/hicn/command_line/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -#add_subdirectory(controller) -add_subdirectory(daemon) diff --git a/hicn-light/src/hicn/command_line/controller/CMakeLists.txt b/hicn-light/src/hicn/command_line/controller/CMakeLists.txt deleted file mode 100644 index 26d4c0b63..000000000 --- a/hicn-light/src/hicn/command_line/controller/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -list(APPEND CONTROLLER_SRC -hicnLightControl_main.c -) -if (NOT DISABLE_EXECUTABLES) - build_executable(${HICN_LIGHT_CONTROL} - SOURCES ${CONTROLLER_SRC} - LINK_LIBRARIES ${HICN_LIGHT_LINK_LIBRARIES} - DEPENDS ${LIBHICN_LIGHT_STATIC} - COMPONENT ${HICN_LIGHT} - DEFINITIONS ${COMPILER_DEFINITIONS} - ) -endif () diff --git a/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c b/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c deleted file mode 100644 index cc91e5a70..000000000 --- a/hicn-light/src/hicn/command_line/controller/hicnLightControl_main.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <hicn/hicn-light/config.h> -#include <hicn/utils/utils.h> - -#ifndef _WIN32 -#include <arpa/inet.h> -#include <getopt.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <sys/uio.h> -#include <unistd.h> -#include <arpa/inet.h> -#endif -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> - -#include <parc/assert/parc_Assert.h> -#include <string.h> - -#include <parc/security/parc_IdentityFile.h> -#include <parc/security/parc_Security.h> - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_List.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_SafeMemory.h> - -#include <hicn/core/forwarder.h> - -#include <errno.h> -#include <hicn/config/controlRoot.h> -#include <hicn/config/controlState.h> - -#include <hicn/utils/commands.h> - - - -size_t commandOutputLen = 0; // preserve the number of structs composing - // payload in case on not interactive call. - -// REMINDER: when a new_command is added, the following array has to be updated -// with the sizeof(new_command). It allows to allocate the buffer for receiving -// the payload of the DAEMON RESPONSE after the header has beed read. Each -// command identifier (typedef enum command_id) corresponds to a position in the -// following array. -static int payloadLengthController[LAST_COMMAND_VALUE] = { - sizeof(add_listener_command), - sizeof(add_connection_command), - sizeof(list_connections_command), // needed when get response from FWD - sizeof(add_route_command), - sizeof(list_routes_command), // needed when get response from FWD - sizeof(remove_connection_command), - sizeof(remove_listener_command), - sizeof(remove_route_command), - sizeof(cache_store_command), - sizeof(cache_serve_command), - 0, // cache clear - sizeof(set_strategy_command), - sizeof(set_wldr_command), - sizeof(add_punting_command), - sizeof(list_listeners_command), // needed when get response from FWD - sizeof(mapme_activator_command), - sizeof(mapme_activator_command), - sizeof(mapme_timing_command), - sizeof(mapme_timing_command), - sizeof(mapme_send_update_command), - sizeof(connection_set_admin_state_command), -#ifdef WITH_POLICY - sizeof(add_policy_command), - sizeof(list_policies_command), - sizeof(remove_policy_command), - sizeof(update_connection_command), - sizeof(connection_set_priority_command), - sizeof(connection_set_tags_command), -#endif -}; - -typedef struct controller_main_state { - ControlState *controlState; -} ControlMainState; - -static void _printRed(const char *output) { -#ifndef _WIN32 - printf("\033[0;31m%s", output); -#else - HANDLE hConsole = NULL; - WORD currentConsoleAttr; - CONSOLE_SCREEN_BUFFER_INFO csbi; - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - if (GetConsoleScreenBufferInfo(hConsole, &csbi)) - currentConsoleAttr = csbi.wAttributes; - SetConsoleTextAttribute(hConsole, 4); - printf("%s", output); - SetConsoleTextAttribute(hConsole, currentConsoleAttr); -#endif -} - -static void _printWhite(const char *output) { -#ifndef _WIN32 - printf("\033[0m%s", output); -#else - HANDLE hConsole = NULL; - WORD currentConsoleAttr; - CONSOLE_SCREEN_BUFFER_INFO csbi; - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - if (GetConsoleScreenBufferInfo(hConsole, &csbi)) - currentConsoleAttr = csbi.wAttributes; - SetConsoleTextAttribute(hConsole, 7); - printf("%s", output); - SetConsoleTextAttribute(hConsole, currentConsoleAttr); -#endif -} - -static void _displayForwarderLogo(void) { - _printRed(" ____ ___ _ "); - _printWhite(" __ _ __ _ __ __\n"); - _printRed(" / __// _ \\ (_)___ "); - _printWhite(" / / (_)____ ___ ____/ /(_)___ _ / / / /_\n"); - _printRed(" / _/ / // /_ / // _ \\ "); - _printWhite(" / _ \\ / // __// _ \\___/ // // _ `// _ \\/ __/\n"); - _printRed("/_/ /____/(_)/_/ \\___/ "); - _printWhite("/_//_//_/ \\__//_//_/ /_//_/ \\_, //_//_/\\__/\n"); - _printWhite( - " /___/ " - "\n"); - printf("\n"); -} - -static void _displayUsage(char *programName) { - printf("Usage: %s -h\n", programName); - printf( - "hicn-light is the 1.0 source, which runs on each end system and as a " - "software source\n"); - printf( - "on intermediate systems. controller is the program to configure the " - "source, daemon.\n"); - printf("\n"); - printf("Options:\n"); - printf("-h = This help screen\n"); - printf( - "commands = configuration line to send to hicn-light (use 'help' " - "for list)\n"); - printf("\n"); -} - -static int _parseArgs(int argc, char *argv[], char **server_ip, - uint16_t *server_port, PARCList *commandList){ - static struct option longFormOptions[] = { - {"help", no_argument, 0, 'h'}, - {"server", required_argument, 0, 'S'}, - {"port", required_argument, 0, 'P'}, - {0, 0, 0, 0}}; - - int c; - - while (1) { - // getopt_long stores the option index here. - int optionIndex = 0; - - c = getopt_long(argc, argv, "hS:P:", longFormOptions, &optionIndex); - - // Detect the end of the options. - if (c == -1) { - break; - } - - switch (c) { - case 'S': - { - *server_ip = optarg; - struct sockaddr_in sa; - int result = inet_pton(AF_INET, *server_ip, &(sa.sin_addr)); - //inet_pton() returns 1 on success - if(result != 1){ - return 0; - } - break; - } - case 'P': - { - char * port_str = optarg; - if(utils_IsNumber(port_str)){ - *server_port = (uint16_t) strtol(port_str, NULL, 10); - } else { - return 0; - } - break; - } - case 'h': - default: - return 0; - } - } - - if (optind < argc) { - while (optind < argc) { - parcList_Add(commandList, argv[optind]); - optind++; - } - } - - return 1; -} - -struct iovec *_writeAndReadMessage(ControlState *state, struct iovec *msg) { - parcAssertNotNull(msg, "Parameter msg must be non-null"); - int sockfd = controlState_GetSockfd(state); - - // check if request has a payload - if (((header_control_message *)msg[0].iov_base)->length > - 0) { // command with payload - // write header + payload (compatibility issue: two write needed instead of - // the writev) -#ifndef _WIN32 - if (write(sockfd, msg[0].iov_base, (unsigned int)msg[0].iov_len) < 0 || - write(sockfd, msg[1].iov_base, (unsigned int)msg[1].iov_len) < 0) { -#else - if (send(sockfd, msg[0].iov_base, (int)msg[0].iov_len, 0) == SOCKET_ERROR || - send(sockfd, msg[1].iov_base, (int)msg[1].iov_len, 0) == SOCKET_ERROR) { -#endif - printf("\nError while sending the Message: cannot write on socket \n"); - exit(EXIT_FAILURE); - } - parcMemory_Deallocate(&msg[1].iov_base); - } else { // command without payload, e.g. 'list' - // write header only -#ifndef _WIN32 - if (write(sockfd, msg[0].iov_base, msg[0].iov_len) < 0) { -#else - int result = send(sockfd, msg[0].iov_base, (int)msg[0].iov_len, 0); - if (result == SOCKET_ERROR) { -#endif - printf("\nError while sending the Message: cannot write on socket \n"); - exit(EXIT_FAILURE); - } - } - parcMemory_Deallocate(&msg[0].iov_base); - - // ======= RECEIVE ======= - - header_control_message *headerResponse = - (header_control_message *)parcMemory_AllocateAndClear( - sizeof(header_control_message)); - if (recv(sockfd, (char *)headerResponse, sizeof(header_control_message), 0) < - 0) { - printf("\nError in Receiving the Message \n"); - exit(EXIT_FAILURE); - } - - if (headerResponse->messageType < RESPONSE_LIGHT || - headerResponse->messageType >= LAST_MSG_TYPE_VALUE) { - char *checkFinMsg = parcMemory_Reallocate(headerResponse, 32); -#ifndef _WIN32 - if (recv(sockfd, checkFinMsg, sizeof(checkFinMsg), - MSG_PEEK | MSG_DONTWAIT) == 0) { -#else - if (recv(sockfd, checkFinMsg, sizeof(checkFinMsg), MSG_PEEK) == 0) { -#endif - // if recv returns zero, that means the connection has been closed: - close(sockfd); - printf("\nConnection terminated by the Daemon. Exiting... \n"); - exit(EXIT_SUCCESS); - } else { - printf("\nError: Unrecognized message type received \n"); - exit(EXIT_FAILURE); - } - } - - void *payloadResponse = NULL; - - if ((commandOutputLen = headerResponse->length) > 0) { - payloadResponse = parcMemory_AllocateAndClear( - payloadLengthController[headerResponse->commandID] * - headerResponse->length); - - if (recv(sockfd, payloadResponse, - payloadLengthController[headerResponse->commandID] * - headerResponse->length, - 0) < 0) { - printf("\nError in Receiving the Message \n"); - exit(EXIT_FAILURE); - } - } - - struct iovec *response = - parcMemory_AllocateAndClear(sizeof(struct iovec) * 2); - - response[0].iov_base = headerResponse; - response[0].iov_len = sizeof(header_control_message); - response[1].iov_base = payloadResponse; - response[1].iov_len = payloadLengthController[headerResponse->commandID] * - headerResponse->length; - - return response; -} - -int main(int argc, char *argv[]) { - _displayForwarderLogo(); - -#ifdef _WIN32 - WSADATA wsaData; - WSAStartup(MAKEWORD(2, 2), &wsaData); -#endif - - if (argc == 2 && strcmp("-h", argv[1]) == 0) { - _displayUsage(argv[0]); - exit(EXIT_SUCCESS); - } - - PARCList *commands = - parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList); - - char *server_ip = SRV_CTRL_IP; - uint16_t server_port = SRV_CTRL_PORT; - if (!_parseArgs(argc, argv, &server_ip, - &server_port, commands)) { - _displayUsage(argv[0]); - parcList_Release(&commands); - exit(EXIT_FAILURE); - } - - ControlMainState mainState; - mainState.controlState = - controlState_Create(&mainState, _writeAndReadMessage, true, - server_ip, server_port); - - controlState_RegisterCommand(mainState.controlState, - controlRoot_HelpCreate(mainState.controlState)); - controlState_RegisterCommand(mainState.controlState, - controlRoot_Create(mainState.controlState)); - - if (parcList_Size(commands) > 0) { - controlState_SetInteractiveFlag(mainState.controlState, false); - controlState_DispatchCommand(mainState.controlState, commands); - char **commandOutputMain = - controlState_GetCommandOutput(mainState.controlState); - if (commandOutputMain != NULL && commandOutputLen > 0) { -#if 0 - for (size_t j = 0; j < commandOutputLen; j++) { - printf("Output %zu: %s \n", j, commandOutputMain[j]); - } -#endif - controlState_ReleaseCommandOutput(mainState.controlState, - commandOutputMain, commandOutputLen); - } - // release - - } else { - controlState_Interactive(mainState.controlState); - } - - parcList_Release(&commands); - - controlState_Destroy(&mainState.controlState); -#ifdef _WIN32 - WSACleanup(); -#endif - return EXIT_SUCCESS; -} diff --git a/hicn-light/src/hicn/command_line/daemon/CMakeLists.txt b/hicn-light/src/hicn/command_line/daemon/CMakeLists.txt deleted file mode 100644 index 8606c8f89..000000000 --- a/hicn-light/src/hicn/command_line/daemon/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 2017-2019 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -list(APPEND DAEMON_SRC - hicnLightDaemon_main.c -) -if (NOT DISABLE_EXECUTABLES) - build_executable(${HICN_LIGHT_DAEMON} - SOURCES ${DAEMON_SRC} - LINK_LIBRARIES ${LIBHICN_LIGHT_STATIC} - DEPENDS ${LIBHICN_LIGHT_STATIC} - COMPONENT ${HICN_LIGHT} - DEFINITIONS ${COMPILER_DEFINITIONS} - ) -endif () diff --git a/hicn-light/src/hicn/command_line/daemon/hicnLightDaemon_main.c b/hicn-light/src/hicn/command_line/daemon/hicnLightDaemon_main.c deleted file mode 100644 index c743de743..000000000 --- a/hicn-light/src/hicn/command_line/daemon/hicnLightDaemon_main.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _WIN32 -#include <unistd.h> -#endif -#include <errno.h> -#include <fcntl.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> - -#include <hicn/hicn-light/config.h> -#include <hicn/core/forwarder.h> -#include <hicn/util/log.h> -#include <hicn/base/loop.h> - -static void _printRed(const char *output) { -#ifndef _WIN32 - printf("\033[0;31m%s", output); -#else - HANDLE hConsole = NULL; - WORD currentConsoleAttr; - CONSOLE_SCREEN_BUFFER_INFO csbi; - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - if (GetConsoleScreenBufferInfo(hConsole, &csbi)) - currentConsoleAttr = csbi.wAttributes; - SetConsoleTextAttribute(hConsole, 4); - printf("%s", output); - SetConsoleTextAttribute(hConsole, currentConsoleAttr); -#endif -} - -static void _printWhite(const char *output) { -#ifndef _WIN32 - printf("\033[0m%s", output); -#else - HANDLE hConsole = NULL; - WORD currentConsoleAttr; - CONSOLE_SCREEN_BUFFER_INFO csbi; - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - if (GetConsoleScreenBufferInfo(hConsole, &csbi)) - currentConsoleAttr = csbi.wAttributes; - SetConsoleTextAttribute(hConsole, 7); - printf("%s", output); - SetConsoleTextAttribute(hConsole, currentConsoleAttr); -#endif -} - -static void _displayForwarderLogo(void) { - _printRed(" ____ ___ _ "); - _printWhite(" __ _ __ _ __ __\n"); - _printRed(" / __// _ \\ (_)___ "); - _printWhite(" / / (_)____ ___ ____/ /(_)___ _ / / / /_\n"); - _printRed(" / _/ / // /_ / // _ \\ "); - _printWhite(" / _ \\ / // __// _ \\___/ // // _ `// _ \\/ __/\n"); - _printRed("/_/ /____/(_)/_/ \\___/ "); - _printWhite("/_//_//_/ \\__//_//_/ /_//_/ \\_, //_//_/\\__/\n"); - _printWhite( - " /___/ " - "\n"); - printf("\n"); -} - -static void _usage(int exitCode) { -#ifndef _WIN32 - printf( - "Usage: hicn-light-daemon [--port port] [--capacity objectStoreSize] " - "[--log facility=level] [--log-file filename] [--config file]\n"); -#else - printf( - "Usage: hicn-light-daemon.exe [--port port] [--daemon] [--capacity objectStoreSize] " - "[--log facility=level] [--log-file filename] [--config file]\n"); -#endif - printf("\n"); - printf( - "hicn-light run as a daemon is the program to launch the forwarder, " - "either as a console program\n"); - printf( - "or a background daemon (detatched from console). Once running, use the " - "program controller to\n"); - printf("configure hicn-light.\n"); - printf("\n"); - printf( - "The configuration file contains configuration lines as per " - "controller\n"); - printf( - "If logging level or content store capacity is set in the configuraiton " - "file, it overrides the command_line\n"); - printf( - "When a configuration file is specified, no default listeners on 'port' " - "are setup. Only 'add listener' lines\n"); - printf("in the configuration file matter.\n"); - printf("\n"); - printf( - "If no configuration file is specified, daemon will listen on TCP and " - "UDP ports specified by\n"); - printf( - "the --port flag (or default port). It will listen on both IPv4 and " - "IPv6 if available.\n"); - printf("\n"); - printf("Options:\n"); - printf("--port = tcp port for in-bound connections\n"); -#ifndef _WIN32 - printf("--daemon = start as daemon process\n"); -#endif - printf("--objectStoreSize = maximum number of content objects to cache\n"); - printf( - "--log = sets a facility to a given log level. You can have " - "multiple of these.\n"); - printf( - " facilities: all, config, core, io, message, " - "processor\n"); - printf( - " levels: debug, info, notice, warning, error, " - "critical, alert, off\n"); - printf(" example: daemon --log io=debug --log core=off\n"); - printf( - "--log-file = file to write log messages to (required in daemon " - "mode)\n"); - printf("--config = configuration filename\n"); - printf("\n"); - exit(exitCode); -} - -#if 0 -static void _setLogLevelToLevel(int logLevelArray[LoggerFacility_END], - LoggerFacility facility, - const char *levelString) { - PARCLogLevel level = parcLogLevel_FromString(levelString); - - if (level < PARCLogLevel_All) { - // we have a good facility and level - logLevelArray[facility] = level; - } else { - printf("Invalid log level string %s\n", levelString); - _usage(EXIT_FAILURE); - } -} - -/** - * string: "facility=level" - * Set the right thing in the logger - */ -static void _setLogLevel(int logLevelArray[LoggerFacility_END], - const char *string) { - char *tofree = parcMemory_StringDuplicate(string, strlen(string)); - char *p = tofree; - - char *facilityString = strtok(p, "="); - if (facilityString) { - char *levelString = strtok(NULL, "="); - - if (strcasecmp(facilityString, "all") == 0) { - for (LoggerFacility facility = 0; facility < LoggerFacility_END; - facility++) { - _setLogLevelToLevel(logLevelArray, facility, levelString); - } - } else { - LoggerFacility facility; - for (facility = 0; facility < LoggerFacility_END; facility++) { - if (strcasecmp(facilityString, logger_FacilityString(facility)) == 0) { - break; - } - } - - if (facility < LoggerFacility_END) { - _setLogLevelToLevel(logLevelArray, facility, levelString); - } else { - printf("Invalid facility string %s\n", facilityString); - _usage(EXIT_FAILURE); - } - } - } - - parcMemory_Deallocate((void **)&tofree); -} -#endif - -#ifndef _WIN32 -static void _daemonize(void) { - if (getppid() == 1) { - // already a daemon - return; - } - - int forkReturn = fork(); - assert(forkReturn >= 0); - - if (forkReturn > 0) { - // parent exits - exit(EXIT_SUCCESS); - } - - // Child daemon detaches - printf("child continuing, pid = %u\n", getpid()); - - // get a new process group independent from old parent - setsid(); - - /* close all descriptors */ -#ifdef __ANDROID__ - for (int i = sysconf(_SC_OPEN_MAX); i >= 0; --i) { - close(i); - } -#else - for (int i = getdtablesize(); i >= 0; --i) { - close(i); - } -#endif - // reset errno because it might be seg to EBADF from the close calls above - errno = 0; - - // Redirect stdin and stdout and stderr to /dev/null - const char *devnull = "/dev/null"; - int nullfile = open(devnull, O_RDWR); - assert(nullfile >= 0); - - int ret; - ret = dup(nullfile); - assert(ret == 1); - ret = dup(nullfile); - assert(ret == 2); - (void)ret; /* UNUSED */ - - // forwarder will capture signals -} -#endif - -#if 0 -static Logger *_createLogfile(const char *logfile) { -#ifndef _WIN32 - int logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, S_IWUSR | S_IRUSR); -#else - int logfd = - _open(logfile, _O_WRONLY | _O_APPEND | _O_CREAT, _S_IWRITE | _S_IREAD); -#endif - if (logfd < 0) { - fprintf(stderr, "Error opening %s for writing: (%d) %s\n", logfile, errno, - strerror(errno)); - exit(EXIT_FAILURE); - } - -#ifndef _WIN32 - chmod(logfile, S_IRWXU); -#endif - - PARCFileOutputStream *fos = parcFileOutputStream_Create(logfd); - PARCOutputStream *pos = parcFileOutputStream_AsOutputStream(fos); - PARCLogReporter *reporter = parcLogReporterFile_Create(pos); - - Logger *logger = logger_Create(reporter, parcClock_Wallclock()); - - parcOutputStream_Release(&pos); - parcLogReporter_Release(&reporter); - - return logger; -} -#endif - -int main(int argc, const char *argv[]) { - _displayForwarderLogo(); -#ifndef _WIN32 - bool daemon = false; -#else - WSADATA wsaData = {0}; - WSAStartup(MAKEWORD(2, 2), &wsaData); -#endif - - uint16_t port = PORT_NUMBER; - uint16_t configurationPort = 2001; - int capacity = -1; - const char *configFileName = NULL; - - char *logfile = NULL; - - if (argc == 2 && strcasecmp(argv[1], "-h") == 0) { - _usage(EXIT_SUCCESS); - } - -#if 0 - int logLevelArray[LoggerFacility_END]; - for (int i = 0; i < LoggerFacility_END; i++) { - logLevelArray[i] = -1; - } -#endif - - for (int i = 0; i < argc; i++) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "--config") == 0) { - configFileName = argv[i + 1]; - i++; - } else if (strcmp(argv[i], "--port") == 0) { - port = atoi(argv[i + 1]); - i++; -#ifndef _WIN32 - } else if (strcmp(argv[i], "--daemon") == 0) { - daemon = true; -#endif - } else if (strcmp(argv[i], "--capacity") == 0 || - strcmp(argv[i], "-c") == 0) { - capacity = atoi(argv[i + 1]); - i++; -#if 0 - } else if (strcmp(argv[i], "--log") == 0) { - _setLogLevel(logLevelArray, argv[i + 1]); - i++; - } else if (strcmp(argv[i], "--log-file") == 0) { - if (logfile) { - // error cannot repeat - fprintf(stderr, "Cannot specify --log-file more than once\n"); - _usage(EXIT_FAILURE); - } - - logfile = parcMemory_StringDuplicate(argv[i + 1], strlen(argv[i + 1])); - i++; -#endif - } else { - _usage(EXIT_FAILURE); - } - } - } - - // set restrictive umask, in case we create any files - umask(027); - -#ifndef _WIN32 - if (daemon && (logfile == NULL)) { - fprintf(stderr, "Must specify a logfile when running in daemon mode\n"); - _usage(EXIT_FAILURE); - } - - if (daemon) { - // inside this call, parent will EXIT_SUCCESS and child will continue - _daemonize(); - } -#endif - -#if 0 - Logger *logger = NULL; - if (logfile) { - logger = _createLogfile(logfile); - parcMemory_Deallocate((void **)&logfile); - } else { - PARCLogReporter *stdoutReporter = parcLogReporterTextStdout_Create(); - logger = logger_Create(stdoutReporter, parcClock_Wallclock()); - parcLogReporter_Release(&stdoutReporter); - } - - for (int i = 0; i < LoggerFacility_END; i++) { - if (logLevelArray[i] > -1) { - logger_SetLogLevel(logger, i, logLevelArray[i]); - } - } -#endif - - /* - * The loop should be created before the forwarder instance as it is needed - * for timers - */ - MAIN_LOOP = loop_create(); - - forwarder_t * forwarder = forwarder_create(); - if (!forwarder) { - ERROR("Forwarder initialization failed. Are you running it with sudo privileges?"); - return -1; - } - - configuration_t * configuration = forwarder_get_configuration(forwarder); - if (capacity > -1) { - configuration_cs_set_size(configuration, capacity); - } - - forwarder_setup_local_listeners(forwarder, port); - if (configFileName) { - forwarder_read_config(forwarder, configFileName); - } - - INFO("hicn-light running port %d configuration-port %d", port, - configurationPort); - - /* Main loop */ - if (loop_dispatch(MAIN_LOOP) < 0) { - ERROR("Failed to run main loop"); - return EXIT_FAILURE; - } - - INFO("hicn-light exiting port %d", port); - - if (loop_undispatch(MAIN_LOOP) < 0) { - ERROR("Failed to terminate main loop"); - return EXIT_FAILURE; - } - - forwarder_free(forwarder); - - loop_free(MAIN_LOOP); - MAIN_LOOP = NULL; - -#ifndef _WIN32 - sleep(2); -#else - Sleep(2000); - WSACleanup(); -#endif - - return 0; -} diff --git a/hicn-light/src/hicn/config/CMakeLists.txt b/hicn-light/src/hicn/config/CMakeLists.txt index 9db413867..ebb1d57d3 100644 --- a/hicn-light/src/hicn/config/CMakeLists.txt +++ b/hicn-light/src/hicn/config/CMakeLists.txt @@ -14,93 +14,24 @@ cmake_minimum_required(VERSION 3.5 FATAL_ERROR) list(APPEND HEADER_FILES -# ${CMAKE_CURRENT_SOURCE_DIR}/commandOps.h -# ${CMAKE_CURRENT_SOURCE_DIR}/commandParser.h -${CMAKE_CURRENT_SOURCE_DIR}/configuration.h -# ${CMAKE_CURRENT_SOURCE_DIR}/commandReturn.h -# ${CMAKE_CURRENT_SOURCE_DIR}/symbolicNameTable.h -#${CMAKE_CURRENT_SOURCE_DIR}/controlState.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlRoot.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlAddConnection.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlAdd.h -# ${CMAKE_CURRENT_SOURCE_DIR}/configuration_file.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlAddRoute.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlAddPolicy.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlAddListener.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlListConnections.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlList.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlListListeners.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlListRoutes.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlListPolicies.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlQuit.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlRemove.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveListener.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveConnection.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveRoute.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePolicy.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlSet.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlUnset.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlSetDebug.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlUnsetDebug.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMe.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeEnable.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeDiscovery.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeTimescale.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheServe.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheStore.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheClear.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlCache.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlSetStrategy.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlSetWldr.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlAddPunting.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePunting.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlUpdate.h -# ${CMAKE_CURRENT_SOURCE_DIR}/controlUpdateConnection.h + ${CMAKE_CURRENT_SOURCE_DIR}/configuration.h + ${CMAKE_CURRENT_SOURCE_DIR}/command.h + ${CMAKE_CURRENT_SOURCE_DIR}/parse.h ) list(APPEND SOURCE_FILES -# ${CMAKE_CURRENT_SOURCE_DIR}/commandOps.c -# ${CMAKE_CURRENT_SOURCE_DIR}/commandParser.c - ${CMAKE_CURRENT_SOURCE_DIR}/configuration.c - ${CMAKE_CURRENT_SOURCE_DIR}/configuration_file.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlState.c -# ${CMAKE_CURRENT_SOURCE_DIR}/symbolicNameTable.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlAdd.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlAddConnection.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlAddRoute.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlAddPolicy.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlAddListener.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlList.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlListConnections.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlListListeners.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlListRoutes.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlListPolicies.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlQuit.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlRemove.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveListener.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveConnection.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveRoute.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePolicy.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlRoot.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlSet.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlSetDebug.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlUnset.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlUnsetDebug.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMe.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeEnable.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeDiscovery.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeTimescale.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeRetx.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheServe.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheStore.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheClear.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlCache.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlSetStrategy.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlSetWldr.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlAddPunting.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePunting.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlUpdate.c -# ${CMAKE_CURRENT_SOURCE_DIR}/controlUpdateConnection.c + ${CMAKE_CURRENT_SOURCE_DIR}/configuration.c + ${CMAKE_CURRENT_SOURCE_DIR}/configuration_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_connection.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_face.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_listener.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_mapme.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_policy.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_punting.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_route.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_strategy.c + ${CMAKE_CURRENT_SOURCE_DIR}/command.c + ${CMAKE_CURRENT_SOURCE_DIR}/parse.c ) set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) diff --git a/hicn-light/src/hicn/config/command.c b/hicn-light/src/hicn/config/command.c new file mode 100644 index 000000000..4c89d6680 --- /dev/null +++ b/hicn-light/src/hicn/config/command.c @@ -0,0 +1,61 @@ + +/** + * @file command.c + * @brief Implementation of commands. + */ + +#include <search.h> /* tfind, tdestroy, twalk */ +#include <stdio.h> + +#include "command.h" + +/* Commands are registered in the following tree. */ +static void * commands_root = NULL; /**< Tree ordered by name */ + +static void nothing_to_free() {} + +#ifdef __linux__ +__attribute__((destructor)) +static +void +command_clear() +{ + tdestroy(commands_root, nothing_to_free); +} +#endif /* __linux__ */ + +static +int +_command_compare(const command_parser_t * c1, + const command_parser_t * c2) +{ + if (c1->action != c2->action) + return c2->action - c1->action; + if (c1->object != c2->object) + return c2->object - c1->object; + if (c1->nparams != c2->nparams) + return c2->nparams - c1->nparams; + return 0; +} + +#define command_compare (int (*)(const void *, const void *))(_command_compare) + +void +command_register(const command_parser_t * command) +{ + // Insert the command in the tree if the keys does not exist yet + tsearch(command, &commands_root, command_compare); +} + +const command_parser_t * +command_search(hc_action_t action, hc_object_type_t object, unsigned nparams) +{ + command_parser_t ** command, search; + + search.action = action; + search.object = object; + search.nparams = nparams; + command = tfind(&search, &commands_root, command_compare); + + return command ? *command : NULL; +} diff --git a/hicn-light/src/hicn/config/command.h b/hicn-light/src/hicn/config/command.h new file mode 100644 index 000000000..c0e3e66e8 --- /dev/null +++ b/hicn-light/src/hicn/config/command.h @@ -0,0 +1,163 @@ +#ifndef HICNLIGHT_CONFIG_COMMAND +#define HICNLIGHT_CONFIG_COMMAND + +/** + * @file command.h + * @brief Commands. + */ + +#include <stddef.h> // offsetof +#include <hicn/util/ip_address.h> + +#include <hicn/ctrl/api.h> + +/* Update sscanf accordingly in parse_cmd.c */ +#define MAX_PARAMETERS 10 + +typedef int (*parser_hook_t)(void * arg); + +typedef enum { + TYPENAME_UNDEFINED, + TYPENAME_INT, + TYPENAME_UINT, + TYPENAME_STR, + TYPENAME_SYMBOLIC, + TYPENAME_SYMBOLIC_OR_ID, + TYPENAME_IP_ADDRESS, + TYPENAME_IP_PREFIX, + TYPENAME_ENUM, + TYPENAME_POLICY_STATE, +} parser_typename_t; + +typedef struct { + parser_typename_t name; + union { + struct { + size_t max_size; + } str; + struct { + int min; + int max; + } sint; + struct { + int min; + int max; + } uint; + struct { + int (*from_str)(const char * str); + } enum_; + struct { + policy_tag_t tag; + } policy_state; + }; +} parser_type_t; + +typedef struct { + const char * name; + const char * help; + parser_type_t type; + size_t offset; + /* + * quick hack to let the functions update two or more parameters, like for + * IP_ADDRESS or IP_PREFIX types + */ + size_t offset2; + size_t offset3; +} command_parameter_t; + +typedef struct { + hc_action_t action; + hc_object_type_t object; + unsigned nparams; + command_parameter_t parameters[MAX_PARAMETERS]; + parser_hook_t post_hook; +} command_parser_t; + +#define TYPE_STRN(N) (parser_type_t) { \ + .name = TYPENAME_STR, \ + .str = { \ + .max_size = 0, \ + }, \ +} +#define TYPE_FMT_STRN(N) "%s" + +#define TYPE_INT(MIN, MAX) (parser_type_t) { \ + .name = TYPENAME_INT, \ + .sint = { \ + .min = (MIN), \ + .max = (MAX), \ + }, \ +} +#define TYPE_FMT_INT "%d" + +#define TYPE_UINT(min, max) (parser_type_t) { \ + .name = TYPENAME_INT, \ + .uint = { \ + .min = min, \ + .max = max, \ + }, \ +} +#define TYPE_FMT_UINT "%u" + +#define TYPE_STR TYPE_STRN(0) +#define TYPE_FMT_STR "%s" + +#define TYPE_SYMBOLIC TYPE_STRN(NAME_LEN) +#define TYPE_FMT_SYMBOLIC "%s" + +#define TYPE_SYMBOLIC_OR_ID TYPE_STRN(NAME_LEN) +#define TYPE_FMT_SYMBOLIC_OR_ID "%s" + +#define TYPE_IP_ADDRESS (parser_type_t) { \ + .name = TYPENAME_IP_ADDRESS, \ +} +#define TYPE_FMT_IP_ADDRESS "%s" + +#define TYPE_IP_PREFIX (parser_type_t) { \ + .name = TYPENAME_IP_PREFIX, \ +} +#define TYPE_FMT_IP_PREFIX "%s" + +#define TYPE_ENUM(x) (parser_type_t) { \ + .name = TYPENAME_ENUM, \ + .enum_ = { \ + .from_str = (int(*)(const char *)) x ## _from_str, \ + }, \ +} +/* We need to allocate room for the intermediate string */ +#define TYPE_FMT_ENUM "%ms" + +#define TYPE_POLICY_STATE(TAG) (parser_type_t) { \ + .name = TYPENAME_POLICY_STATE, \ + .policy_state = { \ + .tag = TAG, \ + }, \ +} +/* We need to allocate room for the intermediate string */ +#define TYPE_FMT_POLICY_STATE "%ms" + +/** + * \brief Register a protocol + * \param protocol Pointer to a protocol_t structure describing the protocol to register + * \return None + */ + +void command_register(const command_parser_t * command); + +/** + * \brief Search a registered protocol in the library according to its name + * \param[in] action The action of the command. + * \param[in] object The object of the command. + * \param[in] nparams The number of parameters expected in the command. + * \return A pointer to the corresponding command if any, NULL othewise + */ +const command_parser_t * command_search(hc_action_t action, hc_object_type_t object, + unsigned nparams); + +#define COMMAND_REGISTER(MOD) \ +static void __init_ ## MOD (void) __attribute__ ((constructor)); \ +static void __init_ ## MOD (void) { \ + command_register(&MOD); \ +} + +#endif /* HICNLIGHT_CONFIG_COMMAND */ diff --git a/hicn-light/src/hicn/config/command_connection.c b/hicn-light/src/hicn/config/command_connection.c new file mode 100644 index 000000000..14926f5d5 --- /dev/null +++ b/hicn-light/src/hicn/config/command_connection.c @@ -0,0 +1,113 @@ +#include <math.h> +#include "command.h" + +/* Parameters */ + +static const command_parameter_t type_hicn = { + .name = "type", + .help = "connection type (hICN)", + .type = TYPE_ENUM(connection_type), + .offset = offsetof(hc_connection_t, type), +}; + +static const command_parameter_t type_tcp_udp = { + .name = "type", + .help = "connection type [tcp | udp]", + .type = TYPE_ENUM(connection_type), + .offset = offsetof(hc_connection_t, type), +}; + +static const command_parameter_t symbolic = { + .name = "symbolic", + .help = "symbolic name, e.g. 'conn1' (must be unique, start with alpha)", + .type = TYPE_SYMBOLIC, + .offset = offsetof(hc_connection_t, name), +}; + +static const command_parameter_t local_address = { + .name = "local_addr", + .help = "local IP address on which to bind.", // XXX optional + .type = TYPE_IP_ADDRESS, + .offset = offsetof(hc_connection_t, local_addr), + .offset2 = offsetof(hc_connection_t, family), +}; + +static const command_parameter_t local_port = { + .name = "local_port", + .help = "Local port.", + .type = TYPE_INT(1, pow(2, 16) - 1), + .offset = offsetof(hc_connection_t, local_port), +}; + +static const command_parameter_t remote_address = { + .name = "remote_address", + .help = "The IPv4 or IPv6 or hostname of the remote system.", + .type = TYPE_IP_ADDRESS, + .offset = offsetof(hc_connection_t, remote_addr), + .offset2 = offsetof(hc_connection_t, family), +}; + +static const command_parameter_t remote_port = { + .name = "remote_port", + .help = "Remote port.", + .type = TYPE_INT(1, pow(2, 16) - 1), + .offset = offsetof(hc_connection_t, remote_port), +}; + +static const command_parameter_t interface = { + .name = "interface", + .help = "Interface on which to bind", // optional ? + .type = TYPE_STRN(IFNAMSIZ), + .offset = offsetof(hc_connection_t, interface_name), +}; + +static const command_parameter_t symbolic_or_id = { + .name = "symbolic", + .help = "The connection symbolic name or id", + .type = TYPE_SYMBOLIC_OR_ID, + .offset = offsetof(hc_connection_t, name), +}; + +/* Commands */ + +int +on_connection_create(hc_connection_t * connection) +{ + connection->admin_state = FACE_STATE_UP; + return 0; +} + +static const command_parser_t command_connection_create4 = { + .action = ACTION_CREATE, + .object = OBJECT_CONNECTION, + .nparams = 5, + .parameters = { type_hicn, symbolic, local_address, remote_address, + interface }, + .post_hook = (parser_hook_t)on_connection_create, +}; +COMMAND_REGISTER(command_connection_create4); + +static const command_parser_t command_connection_create6 = { + .action = ACTION_CREATE, + .object = OBJECT_CONNECTION, + .nparams = 7, + .parameters = { type_tcp_udp, symbolic, remote_address, remote_port, + local_address, local_port, interface }, + .post_hook = (parser_hook_t)on_connection_create, +}; +COMMAND_REGISTER(command_connection_create6); + +static const command_parser_t command_connection_list = { + .action = ACTION_LIST, + .object = OBJECT_CONNECTION, + .nparams = 0, +}; +COMMAND_REGISTER(command_connection_list); + +static const command_parser_t command_connection_remove = { + .action = ACTION_DELETE, + .object = OBJECT_CONNECTION, + .nparams = 1, + .parameters = { symbolic_or_id }, +}; +COMMAND_REGISTER(command_connection_remove); diff --git a/hicn-light/src/hicn/config/command_face.c b/hicn-light/src/hicn/config/command_face.c new file mode 100644 index 000000000..d42dc59d9 --- /dev/null +++ b/hicn-light/src/hicn/config/command_face.c @@ -0,0 +1,14 @@ +#include "command.h" + +/* Parameters */ + +/* Commands */ + +// XXX missing add + +static const command_parser_t command_face_list = { + .action = ACTION_LIST, + .object = OBJECT_FACE, + .nparams = 0, +}; +COMMAND_REGISTER(command_face_list); diff --git a/hicn-light/src/hicn/config/command_listener.c b/hicn-light/src/hicn/config/command_listener.c new file mode 100644 index 000000000..9b0d3ce1a --- /dev/null +++ b/hicn-light/src/hicn/config/command_listener.c @@ -0,0 +1,87 @@ +#include <math.h> +#include "command.h" + +/* Parameters */ + +static const command_parameter_t protocol_hicn = { + .name = "protocol", + .help = "Protocol [hicn].", + .type = TYPE_ENUM(connection_type), + .offset = offsetof(hc_listener_t, type), +}; + +static const command_parameter_t protocol_tcp_udp = { + .name = "protocol", + .help = "Protocol [tcp | udp]", + .type = TYPE_ENUM(connection_type), + .offset = offsetof(hc_listener_t, type), +}; + +static const command_parameter_t symbolic = { + .name = "symbolic", + .help = "User defined name for listener, must start with alpha and be alphanum", + .type = TYPE_SYMBOLIC, + .offset = offsetof(hc_listener_t, name), +}; + +static const command_parameter_t local_address = { + .name = "local_addr", + .help = "IPv4 or IPv6 address (or prefix protocol = hicn) assigend to the local interface", + .type = TYPE_IP_ADDRESS, + .offset = offsetof(hc_listener_t, local_addr), + .offset2 = offsetof(hc_listener_t, family), +}; + +static const command_parameter_t local_port = { + .name = "local_port", + .help = "Local port.", + .type = TYPE_INT(1, pow(2, 16) - 1), + .offset = offsetof(hc_listener_t, local_port), +}; + +static const command_parameter_t interface = { + .name = "interface", + .help = "Interface on which to bind", // optional ? + .type = TYPE_STRN(IFNAMSIZ), + .offset = offsetof(hc_listener_t, interface_name), +}; + +static const command_parameter_t symbolic_or_id = { + .name = "symbolic", + .help = "The listener symbolic name or id", + .type = TYPE_SYMBOLIC_OR_ID, + .offset = offsetof(hc_listener_t, name), +}; + +/* Commands */ + +static const command_parser_t command_listener_create4 = { + .action = ACTION_CREATE, + .object = OBJECT_LISTENER, + .nparams = 4, + .parameters = { protocol_hicn, symbolic, local_address, interface }, +}; +COMMAND_REGISTER(command_listener_create4); + +static const command_parser_t command_listener_create6 = { + .action = ACTION_CREATE, + .object = OBJECT_LISTENER, + .nparams = 5, + .parameters = { protocol_tcp_udp, symbolic, local_address, local_port, interface } +}; +COMMAND_REGISTER(command_listener_create6); + +static const command_parser_t command_listener_list = { + .action = ACTION_LIST, + .object = OBJECT_LISTENER, + .nparams = 0, +}; +COMMAND_REGISTER(command_listener_list); + +static const command_parser_t command_listener_remove = { + .action = ACTION_DELETE, + .object = OBJECT_LISTENER, + .nparams = 1, + .parameters = { symbolic_or_id }, +}; +COMMAND_REGISTER(command_listener_remove); diff --git a/hicn-light/src/hicn/config/command_mapme.c b/hicn-light/src/hicn/config/command_mapme.c new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/hicn-light/src/hicn/config/command_mapme.c diff --git a/hicn-light/src/hicn/config/command_policy.c b/hicn-light/src/hicn/config/command_policy.c new file mode 100644 index 000000000..81c0be59d --- /dev/null +++ b/hicn-light/src/hicn/config/command_policy.c @@ -0,0 +1,53 @@ +#include <hicn/policy.h> + +#include "command.h" + +/* Parameters */ + +static const command_parameter_t prefix = { + .name = "prefix", + .help = "The hicn name as IPv4 or IPv6 address (e.g 1234::0/64).", + .type = TYPE_IP_PREFIX, + .offset = offsetof(hc_policy_t, remote_addr), + .offset2 = offsetof(hc_policy_t, len), + .offset3 = offsetof(hc_policy_t, family), +}; + +static const command_parameter_t app_name = { + .name = "app_name", + .help = "The application name associated to this policy", + .type = TYPE_STR, + .offset = offsetof(hc_policy_t, policy.app_name), +}; + + +#define _(x, y) \ +static const command_parameter_t flag_ ## x = { \ + .name = "flag:" #x, \ + .help = "A value among [neutral|require|prefer|avoid|prohibit] with an optional '!' character prefix for disabling changes", \ + .type = TYPE_POLICY_STATE(POLICY_TAG_ ## x), \ + .offset = offsetof(hc_policy_t, policy.tags), \ +}; + foreach_policy_tag +#undef _ + +/* Commands */ + +static const command_parser_t command_policy_create = { + .action = ACTION_CREATE, + .object = OBJECT_POLICY, + .nparams = 2 + POLICY_TAG_N, + .parameters = { prefix, app_name, +#define _(x, y) flag_ ## x, + foreach_policy_tag +#undef _ + }, +}; +COMMAND_REGISTER(command_policy_create); + +static const command_parser_t command_policy_list = { + .action = ACTION_LIST, + .object = OBJECT_POLICY, + .nparams = 0, +}; +COMMAND_REGISTER(command_policy_list); diff --git a/hicn-light/src/hicn/config/command_punting.c b/hicn-light/src/hicn/config/command_punting.c new file mode 100644 index 000000000..ad969e3d2 --- /dev/null +++ b/hicn-light/src/hicn/config/command_punting.c @@ -0,0 +1,36 @@ +#include "command.h" + +/* Parameters */ + +static const command_parameter_t symbolic_or_id = { + .name = "symbolic_or_id", + .help = "The symbolic name for an egress, or the egress punting id (see 'help list puntings')", + .type = TYPE_SYMBOLIC_OR_ID, + .offset = offsetof(hc_punting_t, face_id), +}; + +static const command_parameter_t prefix = { + .name = "prefix", + .help = "Prefix to add as a punting rule. (example 1234::0/64)", + .type = TYPE_IP_PREFIX, + .offset = offsetof(hc_punting_t, prefix), + .offset2 = offsetof(hc_punting_t, prefix_len), + .offset3 = offsetof(hc_punting_t, family), +}; + +/* Commands */ + +static const command_parser_t command_punting_create = { + .action = ACTION_CREATE, + .object = OBJECT_PUNTING, + .nparams = 2, + .parameters = { symbolic_or_id, prefix }, +}; +COMMAND_REGISTER(command_punting_create); + +static const command_parser_t command_punting_list = { + .action = ACTION_LIST, + .object = OBJECT_PUNTING, + .nparams = 0, +}; +COMMAND_REGISTER(command_punting_list); diff --git a/hicn-light/src/hicn/config/command_route.c b/hicn-light/src/hicn/config/command_route.c new file mode 100644 index 000000000..b357cb036 --- /dev/null +++ b/hicn-light/src/hicn/config/command_route.c @@ -0,0 +1,51 @@ +#include "command.h" + +/* Parameters */ + +static const command_parameter_t symbolic_or_id = { + .name = "symbolic_or_id", + .help = "The symbolic name for an egress, or the egress route id (see 'help list routes')", + .type = TYPE_SYMBOLIC_OR_ID, + .offset = offsetof(hc_route_t, face_id), +}; + +static const command_parameter_t prefix = { + .name = "prefix", + .help = "The hicn name as IPv4 or IPv6 address (e.g 1234::0/64).", + .type = TYPE_IP_PREFIX, + .offset = offsetof(hc_route_t, remote_addr), + .offset2 = offsetof(hc_route_t, len), + .offset3 = offsetof(hc_route_t, family), +}; + +static const command_parameter_t cost = { + .name = "cost", + .help = "Positive integer representing cost.", + .type = TYPE_INT(1, 255), + .offset = offsetof(hc_route_t, cost), +}; + +/* Commands */ + +static const command_parser_t command_route_create = { + .action = ACTION_CREATE, + .object = OBJECT_ROUTE, + .nparams = 3, + .parameters = { symbolic_or_id, prefix, cost }, +}; +COMMAND_REGISTER(command_route_create); + +static const command_parser_t command_route_list = { + .action = ACTION_LIST, + .object = OBJECT_ROUTE, + .nparams = 0, +}; +COMMAND_REGISTER(command_route_list); + +static const command_parser_t command_route_remove = { + .action = ACTION_DELETE, + .object = OBJECT_ROUTE, + .nparams = 2, + .parameters = { symbolic_or_id, prefix }, +}; +COMMAND_REGISTER(command_route_remove); diff --git a/hicn-light/src/hicn/config/command_strategy.c b/hicn-light/src/hicn/config/command_strategy.c new file mode 100644 index 000000000..e3a11959c --- /dev/null +++ b/hicn-light/src/hicn/config/command_strategy.c @@ -0,0 +1,12 @@ +#include "command.h" + +/* Parameters */ + +/* Commands */ + +static const command_parser_t command_strategy_list = { + .action = ACTION_LIST, + .object = OBJECT_STRATEGY, + .nparams = 0, +}; +COMMAND_REGISTER(command_strategy_list); diff --git a/hicn-light/src/hicn/config/parse.c b/hicn-light/src/hicn/config/parse.c new file mode 100644 index 000000000..4959b7cde --- /dev/null +++ b/hicn-light/src/hicn/config/parse.c @@ -0,0 +1,354 @@ +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include <hicn/ctrl/cli.h> +#include <hicn/util/log.h> + +#include "parse.h" + +// help add [done] +// help list +// help quit +// help remove +// help set +// help unset +// help cache +// help mapme +// help update +// +// add connection hicn <symbolic> <remote_ip> <local_ip> +// <symbolic> : symbolic name, e.g. 'conn1' (must be unique, start with alpha) +// <remote_ip> : the IPv4 or IPv6 or hostname of the remote system +// <local_ip> : optional local IP address to bind to + +/* + * As there is no portable way to generate a va_list to use with sscanf to + * support a variable number of arguments, and no way to use a variable array + * initialize in a nested struct, we use a fixed maximum number of parameters + * + * NOTE: update sscanf accordingly + */ + +#include "command.h" + +static void * sscanf_params[MAX_PARAMETERS]; + +const char * action_str[] = { +#define _(x) [ACTION_ ## x] = #x, + foreach_action +#undef _ +}; + +#define action_str(x) action_str[x] + +hc_action_t +action_from_str(const char * action_str) +{ +#define _(x) \ + if (strcasecmp(action_str, # x) == 0) \ + return ACTION_ ## x; \ + else + foreach_action +#undef _ + if (strcasecmp(action_str, "add") == 0) + return ACTION_CREATE; + else + if (strcasecmp(action_str, "remove") == 0) + return ACTION_DELETE; + else + return ACTION_UNDEFINED; +} + +const char * object_str[] = { +#define _(x) [OBJECT_ ## x] = #x, + foreach_object +#undef _ +}; + +#define object_str(x) object_str[x] + +hc_object_type_t +object_from_str(const char * object_str) +{ +#define _(x) \ + if (strcasecmp(object_str, # x) == 0) \ + return OBJECT_ ## x; \ + else + foreach_object +#undef _ + return OBJECT_UNDEFINED; +} + +const char * +parser_type_fmt(const parser_type_t * type) +{ + switch(type->name) { + case TYPENAME_INT: + return TYPE_FMT_INT; + case TYPENAME_UINT: + return TYPE_FMT_UINT; + case TYPENAME_STR: + return (type->str.max_size > 0) + ? TYPE_FMT_STRN(type->str.max_size) + : TYPE_FMT_STR; + case TYPENAME_SYMBOLIC: + return TYPE_FMT_SYMBOLIC; + case TYPENAME_SYMBOLIC_OR_ID: + return TYPE_FMT_SYMBOLIC_OR_ID; + case TYPENAME_IP_ADDRESS: + return TYPE_FMT_IP_ADDRESS; + case TYPENAME_IP_PREFIX: + return TYPE_FMT_IP_PREFIX; + case TYPENAME_ENUM: + return TYPE_FMT_ENUM; + case TYPENAME_POLICY_STATE: + return TYPE_FMT_POLICY_STATE; + case TYPENAME_UNDEFINED: + default: + return NULL; + } +} + +int +parser_type_func(const parser_type_t * type, void * src, void *dst, void * dst2, void * dst3) +{ + switch(type->name) { + case TYPENAME_INT: + *(int*)dst = *(int*)src; + break; + case TYPENAME_UINT: + *(unsigned*)dst = *(unsigned*)src; + break; + case TYPENAME_STR: + if (type->str.max_size > 0) { + strncpy(dst, src, type->str.max_size); + } else { + strcpy(dst, src); + } + break; + case TYPENAME_SYMBOLIC: + break; + case TYPENAME_SYMBOLIC_OR_ID: + break; + case TYPENAME_IP_ADDRESS: + *(ip_address_t*)dst = IP_ADDRESS_EMPTY; // XXX + *(int*)dst2 = AF_INET; + break; + case TYPENAME_IP_PREFIX: + *(ip_address_t*)dst = IP_ADDRESS_EMPTY; // XXX + *(int*)dst2 = 128; + *(int*)dst3 = AF_INET; + break; + case TYPENAME_ENUM: + /* Enum index from string */ + assert(type->enum_.from_str); + const char * str = *(const char **)src; + *(int*)dst = type->enum_.from_str(str); + break; + case TYPENAME_POLICY_STATE: + { + assert(IS_VALID_POLICY_TAG(type->policy_state.tag)); + policy_tag_t tag = type->policy_state.tag; + /* Format string is "%ms" */ + const char * str = *(const char **)src; + policy_tag_state_t *pts = ((policy_tag_state_t*)dst); + pts[tag].disabled = (str[0] == '!') ? 1 : 0; + pts[tag].state = policy_state_from_str(str + pts[tag].disabled); + break; + } + case TYPENAME_UNDEFINED: + default: + return -1; + } + return 0; +} + +int +parse_params(const command_parser_t * parser, const char * params_s, + hc_command_t * command) +{ + char fmt[1024]; + int n; + size_t size = 0; + + char * pos = fmt; + + int must_free[MAX_PARAMETERS]; + + unsigned count = 0; + for (unsigned i = 0; i < parser->nparams; i++) { + const command_parameter_t * p = &parser->parameters[i]; + const char * fmt = parser_type_fmt(&p->type); + if (!fmt) { + WARN("Ignored parameter %s with unknown type formatter", p->name); + continue; + } + must_free[count] = (strcmp(fmt, "%ms") == 0), + + n = snprintf(pos, 1024 - size, "%s", fmt); + pos += n; + + *pos = ' '; + pos++; + + size += n + 1; + count++; + } + *pos = '\0'; + + void ** sp = sscanf_params; + /* Update MAX_PARAMETERS accordingly in command.h */ + sscanf(params_s, fmt, &sp[0], &sp[1], &sp[2], &sp[3], &sp[4], &sp[5], + &sp[6], &sp[7], &sp[8], &sp[9]); + + for (unsigned i = 0; i < count; i++) { + const command_parameter_t * p = &parser->parameters[i]; + if (parser_type_func(&p->type, &sp[i], &command->object.as_uint8 + p->offset, + &command->object.as_uint8 + p->offset2, + &command->object.as_uint8 + p->offset3) < 0) { + ERROR("Error during parsing of parameter '%s' value\n", p->name); + goto ERR; + } + if (must_free[i]) + free(sp[i]); + } + return 0; + +ERR: + return -1; +} + +int +parse(const char * cmd, hc_command_t * command) +{ + int nparams = 0; + char * action_s = NULL; + char * object_s = NULL; + char * params_s = NULL; + + errno = 0; + // XXX broken with zero parameters + int n = sscanf(cmd, "%ms %ms%m[^\n]s", &action_s, &object_s, ¶ms_s); + if ((n < 2) || (n > 3)) { + if (errno != 0) + perror("scanf"); + return -1; + } + + command->action = action_from_str(action_s); + command->object.type = object_from_str(object_s); + + if (params_s) { //strlen(params_s) > 0) { + for (char *ptr = params_s; (ptr = strchr(ptr, ' ')) != NULL; ptr++) + nparams++; + } + + /* + * This checks is important even with 0 parameters as it checks whether the + * command exists. + */ + const command_parser_t * parser = command_search(command->action, command->object.type, nparams); + if (!parser) { + ERROR("Could not find parser for command '%s %s'", action_s, object_s); + goto ERR; + } + + if (params_s) { + if (parse_params(parser, params_s, command) < 0) { + ERROR("Could not parse '%s %s' command", action_s, object_s); + goto ERR; + } + } + + if (parser->post_hook) + parser->post_hook(&command->object.as_uint8); + + /* LIST commands with 0 parameters do not expect an output */ + if (params_s) { + char buf[MAXSZ_OBJECT]; + int rc = hc_object_snprintf(buf, MAXSZ_OBJECT, &command->object); + if (rc < 0) + snprintf(buf, MAXSZ_OBJECT, "%s", "[hc_snprintf_error]"); + else if (rc >= MAXSZ_OBJECT) { + buf[MAXSZ_OBJECT-1] = '\0'; + buf[MAXSZ_OBJECT-2] = '.'; + buf[MAXSZ_OBJECT-3] = '.'; + buf[MAXSZ_OBJECT-4] = '.'; + } + + DEBUG("%s %s <%s>", action_s, object_s, buf); + } else { + DEBUG("%s %s <No parameters>", action_s, object_s); + } + + free(action_s); + free(object_s); + free(params_s); + + return 0; + +ERR: + free(action_s); + free(object_s); + free(params_s); + return -1; +} + +#if 0 // tests +/* For the tests, we will need to test all non-compliant inputs */ +const char * cmds[] = { + "add connection hicn conn1 8.8.8.8 127.0.0.1 eth0", + "add connection udp <symbolic> <remote_ip> <port> <local_ip> <port> eth0", + "add listener udp lst1 127.0.0.1 9695 eth0", + //"add face", + "add route 3 b001::/16 1", + //"add punting", + //"add strategy", + "add policy b001::/16 webex require avoid prohibit !prohibit neutral !require prefer", + "list connection", // need pluralize + "list listener", + "list face", + "list route", + "list punting", + "list strategy", + "list policy", + "remove connection 1", + "remove listener 1", + //"remove face", + "remove route 1 b001::/16", + //"remove punting", + //"remove policy", + "set debug", + "unset debug", + "set strategy b001::/16 random", // related prefixes (10 max) ? + "set strategy b001::/16 load_balancer", + "set strategy b001::/16 low_latency", + "set wldr <on|off> <connection_id>", // on-off vs unset + "cache clear", + "cache store on/off", // set/unset + "cache serve on/off", + "mapme enable on/off", + "mapme discovery on/off", + "mapme timescale 500ms", + "mapme retx 500ms", + "update connection conn1 WT", +}; + +#define array_size(x) sizeof(x) / sizeof(typeof(x[0])) +int main() +{ + for (unsigned i = 0; i < array_size(cmds); i++) { + printf("PARSING [%d] %s\n", i, cmds[i]); + if (parse(cmds[i]) < 0) { + ERROR("Could not parse command: %s\n", cmds[i]); + continue; + } + } + exit(EXIT_SUCCESS); + +ERR: + exit(EXIT_FAILURE); +} +#endif diff --git a/hicn-light/src/hicn/config/parse.h b/hicn-light/src/hicn/config/parse.h new file mode 100644 index 000000000..4c3bacd9a --- /dev/null +++ b/hicn-light/src/hicn/config/parse.h @@ -0,0 +1,6 @@ +#ifndef HICNLIGHT_PARSE_CMD +#define HICNLIGHT_PARSE_CMD + +int parse(const char * cmd, hc_command_t * command); + +#endif /* HICNLIGHT_PARSE_CMD */ diff --git a/hicn-light/src/hicn/core/CMakeLists.txt b/hicn-light/src/hicn/core/CMakeLists.txt index f877717aa..32b546400 100644 --- a/hicn-light/src/hicn/core/CMakeLists.txt +++ b/hicn-light/src/hicn/core/CMakeLists.txt @@ -75,3 +75,7 @@ set(TO_INSTALL_HEADER_FILES ${HEADER_FILES} PARENT_SCOPE ) + +if (BUILD_TESTS) + add_subdirectory(test) +endif()
\ No newline at end of file diff --git a/hicn-light/src/hicn/core/address_pair.h b/hicn-light/src/hicn/core/address_pair.h index 4dfdfd9de..09800aa62 100644 --- a/hicn-light/src/hicn/core/address_pair.h +++ b/hicn-light/src/hicn/core/address_pair.h @@ -21,9 +21,10 @@ #ifndef HICNLIGHT_ADDRESS_PAIR_H #define HICNLIGHT_ADDRESS_PAIR_H -#include <hicn/core/address.h> #include <hicn/util/ip_address.h> +#include "address.h" + typedef struct { address_t local; address_t remote; diff --git a/hicn-light/src/hicn/core/connection.h b/hicn-light/src/hicn/core/connection.h index d9ef817d2..186cad5c3 100644 --- a/hicn-light/src/hicn/core/connection.h +++ b/hicn-light/src/hicn/core/connection.h @@ -21,11 +21,12 @@ #ifndef HICNLIGHT_CONNECTION_H #define HICNLIGHT_CONNECTION_H -#include <hicn/core/address_pair.h> -#include <hicn/core/listener.h> -#include <hicn/core/msgbuf.h> #include <hicn/face.h> +#include "address_pair.h" +#include "listener.h" +#include "msgbuf.h" + #ifdef WITH_POLICY #include <hicn/policy.h> #endif /* WITH_POLICY */ diff --git a/hicn-light/src/hicn/core/connection_table.h b/hicn-light/src/hicn/core/connection_table.h index 8a9342f45..d32a5fee8 100644 --- a/hicn-light/src/hicn/core/connection_table.h +++ b/hicn-light/src/hicn/core/connection_table.h @@ -30,11 +30,11 @@ #ifndef HICNLIGHT_CONNECTION_TABLE_H #define HICNLIGHT_CONNECTION_TABLE_H -#include <hicn/core/address_pair.h> -#include <hicn/core/connection.h> -#include <hicn/base/hash.h> -#include <hicn/base/khash.h> -#include <hicn/base/pool.h> +#include "address_pair.h" +#include "connection.h" +#include "../base/hash.h" +#include "../base/khash.h" +#include "../base/pool.h" #define _ct_var(x) _ct_var_##x diff --git a/hicn-light/src/hicn/core/content_store.c b/hicn-light/src/hicn/core/content_store.c index 74b675224..cf1fe3af9 100644 --- a/hicn-light/src/hicn/core/content_store.c +++ b/hicn-light/src/hicn/core/content_store.c @@ -112,11 +112,10 @@ void cs_clear(cs_t * cs) } off_t -cs_match(cs_t * cs, off_t msgbuf_id, uint64_t now) +cs_match(cs_t * cs, msgbuf_pool_t * msgbuf_pool, off_t msgbuf_id, uint64_t now) { assert(cs); - const msgbuf_pool_t * msgbuf_pool = cs_get_msgbuf_pool(cs); const msgbuf_t * msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); assert(msgbuf); @@ -133,7 +132,7 @@ cs_match(cs_t * cs, off_t msgbuf_id, uint64_t now) if (cs_entry_has_expiry_time(entry) && cs_entry_get_expiry_time(entry) < now) { // the entry is expired, we can remove it - cs_remove_entry(cs, entry); + cs_remove_entry(cs, msgbuf_pool, entry); goto NOT_FOUND; } @@ -160,7 +159,7 @@ NOT_FOUND: #define msgbuf_acquire(x) (x) cs_entry_t * -cs_add(cs_t * cs, off_t msgbuf_id, uint64_t now) +cs_add(cs_t * cs, msgbuf_pool_t * msgbuf_pool, off_t msgbuf_id, uint64_t now) { assert(cs); assert(msgbuf_id_is_valid(msgbuf_id)); @@ -235,7 +234,7 @@ ERR_ENTRY: } int -cs_remove_entry(cs_t * cs, cs_entry_t * entry) +cs_remove_entry(cs_t * cs, msgbuf_pool_t * msgbuf_pool, cs_entry_t * entry) { assert(cs); assert(entry); @@ -245,7 +244,6 @@ cs_remove_entry(cs_t * cs, cs_entry_t * entry) off_t msgbuf_id = cs_entry_get_msgbuf_id(entry); - const msgbuf_pool_t * msgbuf_pool = cs_get_msgbuf_pool(cs); const msgbuf_t * msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); khiter_t k = kh_get_cs_name(cs->index_by_name, msgbuf_get_name(msgbuf)); @@ -263,7 +261,7 @@ cs_remove_entry(cs_t * cs, cs_entry_t * entry) // // XXX TODO what is the difference between purge and remove ? bool -cs_remove(cs_t * cs, msgbuf_t * msgbuf) +cs_remove(cs_t * cs, msgbuf_pool_t * msgbuf_pool, msgbuf_t * msgbuf) { assert(cs); assert(msgbuf); @@ -277,7 +275,7 @@ cs_remove(cs_t * cs, msgbuf_t * msgbuf) cs_entry_t * entry = cs->entries + kh_val(cs->index_by_name, k); assert(entry); - cs_remove_entry(cs, entry); + cs_remove_entry(cs, msgbuf_pool, entry); return true; } diff --git a/hicn-light/src/hicn/core/content_store.h b/hicn-light/src/hicn/core/content_store.h index 2973b3955..95b0a1d0a 100644 --- a/hicn-light/src/hicn/core/content_store.h +++ b/hicn-light/src/hicn/core/content_store.h @@ -58,7 +58,6 @@ typedef struct { void * index_by_expiry_time; #endif - const msgbuf_pool_t * msgbuf_pool; void * data; // per cs type data void * options; @@ -96,13 +95,13 @@ void cs_free(cs_t * cs); void cs_clear(cs_t * cs); -off_t cs_match(cs_t * cs, off_t msgbuf_id, uint64_t now); +off_t cs_match(cs_t * cs, msgbuf_pool_t * msgbuf_pool, off_t msgbuf_id, uint64_t now); -cs_entry_t * cs_add(cs_t * cs, off_t msgbuf_id, uint64_t now); +cs_entry_t * cs_add(cs_t * cs, msgbuf_pool_t * msgbuf_pool, off_t msgbuf_id, uint64_t now); -int cs_remove_entry(cs_t * cs, cs_entry_t * entry); +int cs_remove_entry(cs_t * cs, msgbuf_pool_t * msgbuf_pool, cs_entry_t * entry); -bool cs_remove(cs_t * cs, msgbuf_t * msgbuf); +bool cs_remove(cs_t * cs, msgbuf_pool_t * msgbuf_pool, msgbuf_t * msgbuf); #define cs_size(content_store) (pool_len(cs->entries)) @@ -112,13 +111,6 @@ void cs_purge_entry(cs_t * cs, cs_entry_t * entry); #define cs_entry_at(cs, id) (&(cs)->entries[id]) -static inline -const msgbuf_pool_t * -cs_get_msgbuf_pool(const cs_t * cs) -{ - return cs->msgbuf_pool; -} - typedef struct { const char * name; diff --git a/hicn-light/src/hicn/core/fib.h b/hicn-light/src/hicn/core/fib.h index f60a42cae..2b9925b61 100644 --- a/hicn-light/src/hicn/core/fib.h +++ b/hicn-light/src/hicn/core/fib.h @@ -12,12 +12,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef fib_h -#define fib_h -#include <hicn/core/msgbuf.h> -#include <hicn/core/name.h> -#include <hicn/core/fib_entry.h> +#ifndef HICNLIGHT_FIB_H +#define HICNLIGHT_FIB_H + +#include "fib_entry.h" +#include "msgbuf.h" +#include "name.h" #define _fib_var(x) _fib_ ## x @@ -57,4 +58,4 @@ do { free(_fib_var(array)); \ } while(0) -#endif // fib_h +#endif /* HICNLIGHT_FIB_H */ diff --git a/hicn-light/src/hicn/core/fib_entry.h b/hicn-light/src/hicn/core/fib_entry.h index 94d283d0f..5ec0f29de 100644 --- a/hicn-light/src/hicn/core/fib_entry.h +++ b/hicn-light/src/hicn/core/fib_entry.h @@ -37,17 +37,12 @@ #ifndef fib_entry_h #define fib_entry_h -#include <hicn/core/name.h> -#include <hicn/core/strategy.h> -#include <hicn/core/msgbuf.h> -#include <hicn/core/nexthops.h> -#include <hicn/core/prefix_stats.h> -#include <hicn/utils/commands.h> // strategy type - -#ifdef WITH_MAPME -//#include <parc/algol/parc_EventTimer.h> -//#include <parc/algol/parc_Iterator.h> -#endif /* WITH_MAPME */ +#include "name.h" +#include "strategy.h" +#include "msgbuf.h" +#include "nexthops.h" +#include "prefix_stats.h" +//#include "../utils/commands.h" // strategy type typedef struct { Name *name; diff --git a/hicn-light/src/hicn/core/forwarder.c b/hicn-light/src/hicn/core/forwarder.c index 543fc99e4..4a31075f6 100644 --- a/hicn-light/src/hicn/core/forwarder.c +++ b/hicn-light/src/hicn/core/forwarder.c @@ -658,7 +658,7 @@ _satisfy_from_cs(forwarder_t * forwarder, off_t msgbuf_id) assert(forwarder); assert(msgbuf_id_is_valid(msgbuf_id)); - const msgbuf_pool_t * msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + msgbuf_pool_t * msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); const msgbuf_t * msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); assert(msgbuf_get_type(msgbuf) == MSGBUF_TYPE_INTEREST); @@ -670,14 +670,14 @@ _satisfy_from_cs(forwarder_t * forwarder, off_t msgbuf_id) return false; // See if there's a match in the store. - off_t data_msgbuf_id = cs_match(forwarder_get_cs(forwarder), msgbuf_id, + off_t data_msgbuf_id = cs_match(forwarder_get_cs(forwarder), msgbuf_pool, msgbuf_id, ticks_now()); if (msgbuf_id_is_valid(data_msgbuf_id)) return false; // Remove it from the PIT. nexthops is allocated, so need to destroy - nexthops_t * nexthops = pit_on_data(forwarder->pit, data_msgbuf_id); + nexthops_t * nexthops = pit_on_data(forwarder->pit, msgbuf_pool, data_msgbuf_id); assert(nexthops); // Illegal state: got a null nexthops for an interest we just inserted // send message in reply, then done @@ -711,7 +711,7 @@ forwarder_process_interest(forwarder_t * forwarder, off_t msgbuf_id) assert(forwarder); assert(msgbuf_id_is_valid(msgbuf_id)); - const msgbuf_pool_t * msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + msgbuf_pool_t * msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); const msgbuf_t * msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); assert(msgbuf_get_type(msgbuf) == MSGBUF_TYPE_INTEREST); @@ -726,7 +726,7 @@ forwarder_process_interest(forwarder_t * forwarder, off_t msgbuf_id) // (1) Try to aggregate in PIT - pit_verdict_t verdict = pit_on_interest(forwarder->pit, msgbuf_id); + pit_verdict_t verdict = pit_on_interest(forwarder->pit, msgbuf_pool, msgbuf_id); switch(verdict) { case PIT_VERDICT_AGGREGATE: forwarder->stats.countInterestsAggregated++; @@ -781,7 +781,7 @@ static ssize_t forwarder_process_data(forwarder_t * forwarder, off_t msgbuf_id) { - const msgbuf_pool_t * msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + msgbuf_pool_t * msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); const msgbuf_t * msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); char *nameString = name_ToString(msgbuf_get_name(msgbuf)); @@ -792,7 +792,7 @@ forwarder_process_data(forwarder_t * forwarder, off_t msgbuf_id) forwarder->stats.countReceived++; forwarder->stats.countObjectsReceived++; - nexthops_t * ingressSetUnion = pit_on_data(forwarder->pit, msgbuf_id); + nexthops_t * ingressSetUnion = pit_on_data(forwarder->pit, msgbuf_pool, msgbuf_id); if (!ingressSetUnion) { // (1) If it does not match anything in the PIT, drop it forwarder->stats.countDroppedNoReversePath++; @@ -822,7 +822,7 @@ forwarder_process_data(forwarder_t * forwarder, off_t msgbuf_id) const connection_t * conn = connection_table_get_by_id(table, msgbuf_get_connection_id(msgbuf)); if (forwarder->store_in_cs && connection_is_local(conn)) { - cs_add(forwarder->cs, msgbuf_id, ticks_now()); + cs_add(forwarder->cs, msgbuf_pool, msgbuf_id, ticks_now()); DEBUG("Message %p store in CS anyway", msgbuf); } @@ -831,7 +831,7 @@ forwarder_process_data(forwarder_t * forwarder, off_t msgbuf_id) // (2) Add to Content Store. Store may remove expired content, if necessary, // depending on store policy. if (forwarder->store_in_cs) { - cs_add(forwarder->cs, msgbuf_id, ticks_now()); + cs_add(forwarder->cs, msgbuf_pool, msgbuf_id, ticks_now()); } // (3) Reverse path forward via PIT entries return forwarder_forward_to_nexthops(forwarder, msgbuf_id, ingressSetUnion); @@ -1123,7 +1123,7 @@ forwarder_receive(forwarder_t * forwarder, listener_t * listener, assert(msgbuf_id_is_valid(msgbuf_id)); assert(pair); - const msgbuf_pool_t * msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + msgbuf_pool_t * msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); msgbuf_t * msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); assert(msgbuf); diff --git a/hicn-light/src/hicn/core/forwarder.h b/hicn-light/src/hicn/core/forwarder.h index a76e36530..f5ac375da 100644 --- a/hicn-light/src/hicn/core/forwarder.h +++ b/hicn-light/src/hicn/core/forwarder.h @@ -29,23 +29,22 @@ #include <stdlib.h> #include <sys/socket.h> // struct mmsghdr -#include <hicn/core/msgbuf.h> -#include <hicn/core/content_store.h> -#include <hicn/core/connection.h> -#include <hicn/core/connection_table.h> -#include <hicn/core/listener_table.h> -#include <hicn/core/msgbuf_pool.h> - -#include <hicn/config/configuration.h> +#include "connection.h" +#include "connection_table.h" +#include "content_store.h" +#include "listener_table.h" +#include "msgbuf.h" +#include "msgbuf_pool.h" +#include "../config/configuration.h" #ifdef WITH_MAPME -#include <hicn/core/fib.h> +#include "fib.h" #endif /* WITH_MAPME */ #define PORT_NUMBER 9695 #define PORT_NUMBER_AS_STRING "9695" -#include <hicn/utils/commands.h> +//#include <hicn/utils/commands.h> // ============================================== diff --git a/hicn-light/src/hicn/core/listener.c b/hicn-light/src/hicn/core/listener.c index d24fafba0..de078b889 100644 --- a/hicn-light/src/hicn/core/listener.c +++ b/hicn-light/src/hicn/core/listener.c @@ -216,7 +216,7 @@ listener_read_single(listener_t * listener) for (;;) { msgbuf_t * msgbuf = NULL; - off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, msgbuf); + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); if (!msgbuf_id_is_valid(msgbuf_id)) return 0; diff --git a/hicn-light/src/hicn/core/listener.h b/hicn-light/src/hicn/core/listener.h index eb1ec6893..79aefef51 100644 --- a/hicn-light/src/hicn/core/listener.h +++ b/hicn-light/src/hicn/core/listener.h @@ -21,9 +21,9 @@ #ifndef HICNLIGHT_LISTENER_H #define HICNLIGHT_LISTENER_H -#include <hicn/core/address_pair.h> #include <hicn/face.h> +#include "address_pair.h" #include "msgbuf.h" #include "../base/loop.h" diff --git a/hicn-light/src/hicn/core/listener_table.h b/hicn-light/src/hicn/core/listener_table.h index 70cd8bbbf..5824f0551 100644 --- a/hicn-light/src/hicn/core/listener_table.h +++ b/hicn-light/src/hicn/core/listener_table.h @@ -30,12 +30,12 @@ #ifndef HICNLIGHT_LISTENER_TABLE_H #define HICNLIGHT_LISTENER_TABLE_H -#include <hicn/core/address.h> -#include <hicn/base/common.h> -#include <hicn/base/hash.h> -#include <hicn/base/khash.h> -#include <hicn/core/listener.h> -#include <hicn/base/pool.h> +#include "address.h" +#include "listener.h" +#include "../base/common.h" +#include "../base/hash.h" +#include "../base/khash.h" +#include "../base/pool.h" #define _lt_var(x) _lt_var_##x diff --git a/hicn-light/src/hicn/core/messageHandler.h b/hicn-light/src/hicn/core/messageHandler.h index bc7ecf597..1df511a5c 100644 --- a/hicn-light/src/hicn/core/messageHandler.h +++ b/hicn-light/src/hicn/core/messageHandler.h @@ -551,7 +551,7 @@ static inline uint8_t * messageHandler_CreateProbePacket(hicn_format_t format, size_t header_length; hicn_packet_get_header_length_from_format(format, &header_length); - uint8_t *pkt = calloc(header_length, 1); + uint8_t *pkt = (uint8_t *) calloc(header_length, 1); hicn_packet_init_header(format, (hicn_header_t *) pkt); @@ -584,7 +584,7 @@ static inline void messageHandler_CreateProbeReply(uint8_t * probe, } static inline hicn_name_t * messageHandler_CreateProbeName(const ip_prefix_t *address){ - hicn_name_t * name = calloc(sizeof(hicn_name_t), 1); + hicn_name_t * name = (hicn_name_t *) calloc(sizeof(hicn_name_t), 1); hicn_name_create_from_ip_prefix(address, 0, name); return name; } diff --git a/hicn-light/src/hicn/core/msgbuf_pool.c b/hicn-light/src/hicn/core/msgbuf_pool.c index 597123a7a..137d9bb99 100644 --- a/hicn-light/src/hicn/core/msgbuf_pool.c +++ b/hicn-light/src/hicn/core/msgbuf_pool.c @@ -43,11 +43,10 @@ msgbuf_pool_free(msgbuf_pool_t * msgbuf_pool) free(msgbuf_pool); } -int -msgbuf_pool_get(msgbuf_pool_t * msgbuf_pool, msgbuf_t * msgbuf) +off_t +msgbuf_pool_get(msgbuf_pool_t * msgbuf_pool, msgbuf_t ** msgbuf) { - pool_get(msgbuf_pool->buffers, msgbuf); - return 0; + return pool_get(msgbuf_pool->buffers, *msgbuf); } void @@ -60,15 +59,16 @@ int msgbuf_pool_getn(msgbuf_pool_t * msgbuf_pool, msgbuf_t ** msgbuf, size_t n) { for (unsigned i = 0; i < n; i++) { - if (!msgbuf_pool_get(msgbuf_pool, msgbuf[i])) { + // If not able to get the msgbuf + if (msgbuf_pool_get(msgbuf_pool, &msgbuf[i]) < 0) { + // Release all the msgbufs retrieved so far for (unsigned j = 0; j < i; j++) { msgbuf_pool_put(msgbuf_pool, msgbuf[j]); - return 0; } - break; + return -1; } } - return -1; + return 0; } off_t diff --git a/hicn-light/src/hicn/core/msgbuf_pool.h b/hicn-light/src/hicn/core/msgbuf_pool.h index 2ada9fa14..a5c0248bc 100644 --- a/hicn-light/src/hicn/core/msgbuf_pool.h +++ b/hicn-light/src/hicn/core/msgbuf_pool.h @@ -17,7 +17,7 @@ * @file msgbuf_pool.h * @brief hICN msgbuf pool. * - * THe msgbuf pool is used to store packet payloads while the packets are in + * The msgbuf pool is used to store packet payloads while the packets are in * transit, as well as holding them into the packet cache (PIT, CSS), WLDR, * mapme, etc. * @@ -46,20 +46,80 @@ typedef struct { msgbuf_t * buffers; } msgbuf_pool_t; -// 0 for init size means a default value (of 1024) -// 0 for max_size means no limit +/** + * @brief Allocate and initialize a msgbuf pool structure (helper). + * + * @param[in] init_size Number of buffers that can be stored in msgbuf pool. + * @param[in] max_size Maximum size. + * @return msgbuf_pool_t* Pointer to the msgbuf pool created. + * + * @note + * - 0 for init size means a default value (of 1024) + * - 0 for max_size means no limit + */ msgbuf_pool_t * _msgbuf_pool_create(size_t init_size, size_t max_size); +/** + * @brief Allocate and initialize a msgbuf pool data structure. + * + * @return msgbuf_pool_t* Pointer to the msgbuf pool created. + */ #define msgbuf_pool_create() _msgbuf_pool_create(0, 0) +/** + * @brief Free a msgbuf pool data structure. + * + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to free. + */ void msgbuf_pool_free(msgbuf_pool_t * msgbuf_pool); -int msgbuf_pool_get(msgbuf_pool_t * msgbuf_pool, msgbuf_t * msgbuf); +/** + * @brief Get a free msgbuf from the msgbuf pool data structure. + * + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use. + * @param[in, out] msgbuf Empty msgbuf that will be used to return the + * allocated one from the msgbuf pool. + * @return off_t ID of the msgbuf requested. + */ +off_t msgbuf_pool_get(msgbuf_pool_t * msgbuf_pool, msgbuf_t ** msgbuf); +/** + * @brief Release a msgbuf previously obtained, making it available to the msgbuf pool. + * + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use. + * @param[in] msgbuf Pointer to the msgbuf to release. + */ +void msgbuf_pool_put(msgbuf_pool_t * msgbuf_pool, msgbuf_t * msgbuf); + + +/** + * @brief Get multiple free msgbufs from the msgbuf pool data structure. + * + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use. + * @param[in, out] msgbuf Pointer to the first empty msgbuf that will be used to + * allocate the msgbufs. + * @param[in] n Number of msgbufs requested. + * @retval 0 Success. + * @retval -1 Error. + */ int msgbuf_pool_getn(msgbuf_pool_t * msgbuf_pool, msgbuf_t ** msgbuf, size_t n); +/** + * @brief Get the ID corresponding to the msgbuf requested. + * + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use. + * @param[in] msgbuf Pointer to the msgbuf to retrieve the ID for. + * @return off_t ID of the msgbuf requested. + */ off_t msgbuf_pool_get_id(msgbuf_pool_t * msgbuf_pool, msgbuf_t * msgbuf); +/** + * @brief Get the msgbuf corresponding to the ID requested. + * + * @param[in] msgbuf_pool Pointer to the msgbuf pool data structure to use. + * @param[in] id Index of the msgbuf to retrieve. + * @return msgbuf_t* Pointer to the msgbuf corresponding to the ID requested. + */ msgbuf_t * msgbuf_pool_at(const msgbuf_pool_t * msgbuf_pool, off_t id); #endif /* HICNLIGHT_MSGBUF_POOL_H */ diff --git a/hicn-light/src/hicn/core/nameBitvector.h b/hicn-light/src/hicn/core/nameBitvector.h index 256af68a0..d5977f5c0 100644 --- a/hicn-light/src/hicn/core/nameBitvector.h +++ b/hicn-light/src/hicn/core/nameBitvector.h @@ -20,7 +20,7 @@ #include <stdint.h> #include <stdlib.h> -#include <hicn/core/address.h> +#include "address.h" struct name_bitvector; typedef struct name_bitvector NameBitvector; diff --git a/hicn-light/src/hicn/core/nexthops.h b/hicn-light/src/hicn/core/nexthops.h index 8e4878b45..e144fcdc4 100644 --- a/hicn-light/src/hicn/core/nexthops.h +++ b/hicn-light/src/hicn/core/nexthops.h @@ -25,7 +25,7 @@ #include <stdbool.h> #include <stdlib.h> -#include <hicn/core/strategy.h> +#include "strategy.h" #define _nexthops_var(x) _nexthops_##x diff --git a/hicn-light/src/hicn/core/pit.c b/hicn-light/src/hicn/core/pit.c index e80d895ec..36ec8aed1 100644 --- a/hicn-light/src/hicn/core/pit.c +++ b/hicn-light/src/hicn/core/pit.c @@ -96,12 +96,11 @@ pit_free(pit_t * pit) } pit_verdict_t -pit_on_interest(pit_t * pit, off_t msgbuf_id) +pit_on_interest(pit_t * pit, msgbuf_pool_t * msgbuf_pool, off_t msgbuf_id) { assert(pit); assert(msgbuf_id_is_valid(msgbuf_id)); - const msgbuf_pool_t * msgbuf_pool = pit_get_msgbuf_pool(pit); const msgbuf_t * msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); assert(msgbuf_get_type(msgbuf) == MSGBUF_TYPE_INTEREST); @@ -175,12 +174,11 @@ NOT_FOUND: } nexthops_t * -pit_on_data(pit_t * pit, off_t msgbuf_id) +pit_on_data(pit_t * pit, msgbuf_pool_t * msgbuf_pool, off_t msgbuf_id) { assert(pit); assert(msgbuf_id_is_valid(msgbuf_id)); - const msgbuf_pool_t * msgbuf_pool = pit_get_msgbuf_pool(pit); const msgbuf_t * msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); assert(msgbuf_get_type(msgbuf) == MSGBUF_TYPE_DATA); @@ -219,12 +217,11 @@ NOT_FOUND: } void -pit_remove(pit_t * pit, off_t msgbuf_id) +pit_remove(pit_t * pit, msgbuf_pool_t * msgbuf_pool, off_t msgbuf_id) { assert(pit); assert(msgbuf_id_is_valid(msgbuf_id)); - const msgbuf_pool_t * msgbuf_pool = pit_get_msgbuf_pool(pit); const msgbuf_t * msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); assert(msgbuf); diff --git a/hicn-light/src/hicn/core/pit.h b/hicn-light/src/hicn/core/pit.h index 5607827fe..85958f88e 100644 --- a/hicn-light/src/hicn/core/pit.h +++ b/hicn-light/src/hicn/core/pit.h @@ -69,7 +69,6 @@ typedef enum { KHASH_INIT(pit_name, const Name *, unsigned, 0, name_hash, name_hash_eq); typedef struct { - msgbuf_pool_t * msgbuf_pool; size_t max_size; pit_entry_t * entries; // pool kh_pit_name_t * index_by_name; @@ -77,17 +76,17 @@ typedef struct { /** * @brief Allocate a new PIT data structure (extended parameters) - * + * * @param init_size Initial size (0 = default) * @param max_size Maximum size (0 = unbounded) - * + * * @return pit_t* Newly allocated PIT data structure */ pit_t * _pit_create(size_t init_size, size_t max_size); /** * @brief Allocate a new PIT data structure - * + * * @return pit_t* Newly allocated PIT data structure */ #define pit_create() _pit_create(0, 0) @@ -108,14 +107,12 @@ do { #define pit_at(pit, i) (pit->entries + i) -pit_verdict_t pit_on_interest(pit_t * pit, off_t msgbuf_id); +pit_verdict_t pit_on_interest(pit_t * pit, msgbuf_pool_t * msgbuf_pool, off_t msgbuf_id); -nexthops_t * pit_on_data(pit_t * pit, off_t msgbuf_id); +nexthops_t * pit_on_data(pit_t * pit, msgbuf_pool_t * msgbuf_pool, off_t msgbuf_id); -void pit_remove(pit_t * pit, off_t msgbuf_id); +void pit_remove(pit_t * pit, msgbuf_pool_t * msgbuf_pool, off_t msgbuf_id); pit_entry_t * pit_lookup(const pit_t * pit, const msgbuf_t * msgbuf); -#define pit_get_msgbuf_pool(pit) (pit->msgbuf_pool) - #endif /* HICNLIGHT_PIT_H */ diff --git a/hicn-light/src/hicn/core/prefix_stats.h b/hicn-light/src/hicn/core/prefix_stats.h index 4d441203e..deedda793 100644 --- a/hicn-light/src/hicn/core/prefix_stats.h +++ b/hicn-light/src/hicn/core/prefix_stats.h @@ -4,7 +4,7 @@ #ifdef WITH_PREFIX_STATS -#include <hicn/base/loop.h> +#include "../base/loop.h" typedef struct prefix_stats_mgr_s { void * forwarder; diff --git a/hicn-light/src/hicn/core/test/CMakeLists.txt b/hicn-light/src/hicn/core/test/CMakeLists.txt new file mode 100644 index 000000000..1043ce580 --- /dev/null +++ b/hicn-light/src/hicn/core/test/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. + +include(BuildMacros) + +list(APPEND TESTS + test-msgbuf_pool +) + +foreach(test ${TESTS}) + build_executable(${test} + NO_INSTALL + SOURCES ${test}.cc + LINK_LIBRARIES ${LIBHICN_LIGHT_SHARED} ${LIBHICNCTRL_SHARED} ${GTEST_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + INCLUDE_DIRS ${HICN_LIGHT_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS} + DEPENDS gtest ${LIBHICNCTRL_SHARED} ${LIBHICN_LIGHT_SHARED} + COMPONENT ${HICN_LIGHT} + DEFINITIONS "${COMPILER_DEFINITIONS}" + ) + + if(${CMAKE_VERSION} VERSION_GREATER "3.10.0") + gtest_discover_tests(${test}-bin TEST_PREFIX new:) + else() + add_test(NAME ${test}-bin COMMAND ${test}) + endif() +endforeach() diff --git a/hicn-light/src/hicn/core/test/test-msgbuf_pool.cc b/hicn-light/src/hicn/core/test/test-msgbuf_pool.cc new file mode 100644 index 000000000..027f16ac9 --- /dev/null +++ b/hicn-light/src/hicn/core/test/test-msgbuf_pool.cc @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/msgbuf_pool.h> +#include <hicn/base/pool.h> // TODO: remove this line +} + +#define PACKET_POOL_DEFAULT_INIT_SIZE 1024 + +class MsgbufPoolTest : public ::testing::Test { +protected: + MsgbufPoolTest() { + msgbuf_pool = msgbuf_pool_create(); + } + virtual ~MsgbufPoolTest() { + msgbuf_pool_free(msgbuf_pool); + } + + msgbuf_pool_t *msgbuf_pool; +}; + +TEST_F(MsgbufPoolTest, Create) +{ + /* Check msgbuf_pool allocation */ + EXPECT_NE(msgbuf_pool, nullptr); + + /* Check msgbuf_pool size */ + size_t msgbuf_pool_size = pool_hdr(msgbuf_pool->buffers)->alloc_size; + EXPECT_EQ(msgbuf_pool_size, (size_t) PACKET_POOL_DEFAULT_INIT_SIZE); +} + +TEST_F(MsgbufPoolTest, GetMsgbuf) +{ + msgbuf_t *msgbuf = NULL; + + /* Get valid msgbuf from msgbuf_pool */ + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); + EXPECT_NE(msgbuf, nullptr); + EXPECT_NE(msgbuf_id_is_valid((unsigned long) msgbuf_id), 0); + + /* Check if the returned id is correct */ + off_t id = msgbuf_pool_get_id(msgbuf_pool, msgbuf); + EXPECT_EQ(id, msgbuf_id); + + /* Check if the returned msgbuf is correct */ + msgbuf_t *msgbuf_retrieved = msgbuf_pool_at(msgbuf_pool, id); + EXPECT_EQ(msgbuf_retrieved, msgbuf); +} + +TEST_F(MsgbufPoolTest, PutMsgbuf) +{ + /* Check that asking a msgbuf right after releasing another one + returns the same msgbuf */ + + msgbuf_t *msgbuf = NULL; + + off_t id1 = msgbuf_pool_get(msgbuf_pool, &msgbuf); + EXPECT_NE(msgbuf, nullptr); + + msgbuf_pool_put(msgbuf_pool, msgbuf); + + off_t id2 = msgbuf_pool_get(msgbuf_pool, &msgbuf); + EXPECT_NE(msgbuf, nullptr); + + EXPECT_EQ(id2, id1); +} + +TEST_F(MsgbufPoolTest, GetMultipleMsgbufs) +{ + const int NUM_MSG = 3; + msgbuf_t *msgbufs[NUM_MSG]; + + /* Check if successful allocation */ + int ret = msgbuf_pool_getn(msgbuf_pool, msgbufs, NUM_MSG); + EXPECT_EQ(ret, 0); + + /* Check if all msgbufs are valid */ + for (unsigned i = 0; i < NUM_MSG; i++) { + msgbuf_pool_get_id(msgbuf_pool, msgbufs[i]); + EXPECT_NE(msgbufs[i], nullptr) << "Invalid index: " << i; + } +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/hicn-light/src/hicn/utils/commands.h b/hicn-light/src/hicn/utils/commands.h index 358f94d48..ede6177f4 100644 --- a/hicn-light/src/hicn/utils/commands.h +++ b/hicn-light/src/hicn/utils/commands.h @@ -31,11 +31,12 @@ #include <stdint.h> #include <stdlib.h> -#include <hicn/core/strategy.h> // to be moved in libhicn -#include <hicn/util/ip_address.h> #ifdef WITH_POLICY #include <hicn/policy.h> #endif /* WITH_POLICY */ +#include <hicn/util/ip_address.h> + +#include "../core/strategy.h" // to be moved in libhicn #define SYMBOLIC_NAME_LEN 16 diff --git a/lib/includes/hicn/policy.h b/lib/includes/hicn/policy.h index 1fe0dd766..5a9a44467 100644 --- a/lib/includes/hicn/policy.h +++ b/lib/includes/hicn/policy.h @@ -49,6 +49,8 @@ foreach_policy_tag POLICY_TAG_N } policy_tag_t; +#define IS_VALID_POLICY_TAG(x) (x != POLICY_TAG_N) + #define MAXSZ_POLICY_TAG_ 11 #define MAXSZ_POLICY_TAG MAXSZ_POLICY_TAG_ + 1 @@ -134,6 +136,9 @@ foreach_policy_state extern const char * policy_state_str[]; +#define policy_state_str(x) policy_state_str[x] + +policy_state_t policy_state_from_str(const char * str); /* POLICY TAG STATE */ diff --git a/lib/includes/hicn/protocol/ipv6.h b/lib/includes/hicn/protocol/ipv6.h index 5a83abcae..0b5525aba 100644 --- a/lib/includes/hicn/protocol/ipv6.h +++ b/lib/includes/hicn/protocol/ipv6.h @@ -23,21 +23,32 @@ */ #define EXPECTED_IPV6_HDRLEN 40 +// typedef struct +// { +// union +// { +// struct +// { +// u32 version_class_flow; /* version, traffic class and 20 bits of flow-ID */ +// u16 len; /* payload length */ +// u8 nxt; /* next header */ +// u8 hlim; /* hop limit */ +// }; +// u8 vfc; /* 4 bits version, top 4 bits class */ +// }; +// ip6_address_t saddr; /* source address */ +// ip6_address_t daddr; /* destination address */ +// } _ipv6_header_t; + +// TODO: temporary fix typedef struct { - union - { - struct - { - u32 version_class_flow; /* version, traffic class and 20 bits of flow-ID */ - u16 len; /* payload length */ - u8 nxt; /* next header */ - u8 hlim; /* hop limit */ - }; - u8 vfc; /* 4 bits version, top 4 bits class */ - }; - ip6_address_t saddr; /* source address */ - ip6_address_t daddr; /* destination address */ + u32 version_class_flow; /* version, traffic class and 20 bits of flow-ID */ + u16 len; /* payload length */ + u8 nxt; /* next header */ + u8 hlim; /* hop limit */ + ip6_address_t saddr; /* source address */ + ip6_address_t daddr; /* destination address */ } _ipv6_header_t; #define IPV6_HDRLEN sizeof(_ipv6_header_t) diff --git a/lib/src/policy.c b/lib/src/policy.c index 694f0ea5e..8f317bc11 100644 --- a/lib/src/policy.c +++ b/lib/src/policy.c @@ -39,6 +39,18 @@ const char * policy_state_str[] = { #undef _ }; +policy_state_t +policy_state_from_str(const char * str) +{ +#define _(x) \ + if (strcasecmp(str, #x) == 0) \ + return POLICY_STATE_ ## x; \ + else + foreach_policy_state +#undef _ + return POLICY_STATE_N; +} + int policy_tag_state_snprintf(char * s, size_t size, const policy_tag_state_t * tag_state) { diff --git a/scripts/build-extras.sh b/scripts/build-extras.sh index 4112298a8..78a6ac98e 100644 --- a/scripts/build-extras.sh +++ b/scripts/build-extras.sh @@ -15,143 +15,48 @@ set -euxo pipefail SCRIPT_PATH=$( cd "$(dirname "${BASH_SOURCE}")" ; pwd -P ) -APT_PATH=`which apt-get` || true -apt_get=${APT_PATH:-"/usr/local/bin/apt-get"} +source ${SCRIPT_PATH}/functions.sh -PACKAGECLOUD_RELEASE_REPO_DEB="https://packagecloud.io/install/repositories/fdio/release/script.deb.sh" -PACKAGECLOUD_RELEASE_REPO_RPM="https://packagecloud.io/install/repositories/fdio/release/script.rpm.sh" +# Libparc and libmemif are still not available in Ubuntu 20, so +# we remove it from the list for now. +# TODO Remove it as soon as they are available. +DEPS_UBUNTU=(${DEPS_UBUNTU[@]/"libmemif-dev"}) +DEPS_UBUNTU=(${DEPS_UBUNTU[@]/"libmemif"}) +DEPS_UBUNTU=(${DEPS_UBUNTU[@]/"libparc-dev"}) -VPP_GIT_REPO="https://git.fd.io/vpp" -VPP_BRANCH="stable/2001" +DEPS_CENTOS=(${DEPS_CENTOS[@]/"libmemif-devel"}) +DEPS_CENTOS=(${DEPS_CENTOS[@]/"libmemif"}) +DEPS_CENTOS=(${DEPS_CENTOS[@]/"libparc-devel"}) -VPP_VERSION_DEB="20.01-release" -VPP_VERSION_RPM="20.01-release.x86_64" - -BUILD_TOOLS_UBUNTU="build-essential doxygen" -LIBSSL_LIBEVENT_UBUNTU="libevent-dev libssl-dev" -DEPS_UBUNTU="libvppinfra=${VPP_VERSION_DEB} \ - libvppinfra-dev=${VPP_VERSION_DEB} \ - vpp=${VPP_VERSION_DEB} \ - vpp-dev=${VPP_VERSION_DEB} \ - vpp-plugin-core=${VPP_VERSION_DEB}" - -# BUILD_TOOLS_GROUP_CENTOS="'Development Tools'" -DEPS_CENTOS="vpp-devel-${VPP_VERSION_RPM} \ - vpp-lib-${VPP_VERSION_RPM} \ - centos-release-scl \ - devtoolset-7" - -LATEST_EPEL_REPO="http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm" - -install_cmake() { - if ! grep -q "8.8.8.8" /etc/resolv.conf; then - echo "nameserver 8.8.8.8" | sudo tee -a /etc/resolv.conf - fi - - cat /etc/resolv.conf - - CMAKE_INSTALL_SCRIPT_URL="https://cmake.org/files/v3.8/cmake-3.8.0-Linux-x86_64.sh" - CMAKE_INSTALL_SCRIPT="/tmp/install_cmake.sh" - curl ${CMAKE_INSTALL_SCRIPT_URL} > ${CMAKE_INSTALL_SCRIPT} - - sudo mkdir -p /opt/cmake - sudo bash ${CMAKE_INSTALL_SCRIPT} --skip-license --prefix=/opt/cmake - export PATH=/opt/cmake/bin:${PATH} -} - -# Parameters: -# $1 = Distribution id -# $2 = Distribution codename -# -setup_fdio_repo() { - DISTRIB_ID=${1} - - if [ "${DISTRIB_ID}" == "ubuntu" ]; then - curl -s ${PACKAGECLOUD_RELEASE_REPO_DEB} | sudo bash - elif [ "${DISTRIB_ID}" == "centos" ]; then - curl -s ${PACKAGECLOUD_RELEASE_REPO_RPM} | sudo bash - curl ${LATEST_EPEL_REPO} > epel-release-latest-7.noarch.rpm - rpm -ivh epel-release-latest-7.noarch.rpm || true - rm epel-release-latest-7.noarch.rpm - else - echo "Distribution ${DISTRIB_ID} is not supported" - exit -1 - fi -} - -setup() { - # Figure out what system we are running on - if [ -f /etc/os-release ]; then - . /etc/os-release - else - echo "ERROR: System configuration not recognized. Build failed" - exit -1 - fi - - DISTRIB_ID=${ID} - - echo DISTRIBUTION: ${PRETTY_NAME} - echo ARCHITECTURE: $(uname -m) - - ARCH=`uname -m` - if [ "$ARCH" == "x86_64" ] || [ "$ARCH" == "x86" ]; then - install_cmake - fi - setup_fdio_repo ${DISTRIB_ID} - - if [ "${DISTRIB_ID}" == "ubuntu" ]; then - sudo ${apt_get} update || true - fi - - # Install dependencies - if [ ${DISTRIB_ID} == "ubuntu" ]; then - echo ${BUILD_TOOLS_UBUNTU} ${DEPS_UBUNTU} | xargs sudo ${apt_get} install -y --allow-unauthenticated --no-install-recommends - sudo ${apt_get} clean && sudo ${apt_get} update - sudo ${apt_get} install -y --allow-unauthenticated --no-install-recommends libpcre3-dev - elif [ ${DISTRIB_ID} == "centos" ]; then - # echo ${BUILD_TOOLS_GROUP_CENTOS} | xargs sudo yum groupinstall -y --nogpgcheck - echo ${DEPS_CENTOS} | xargs sudo yum install -y --nogpgcheck - sudo yum install devtoolset-7 pcre-devel - - CXX_COMPILER="/opt/rh/devtoolset-7/root/usr/bin/c++" - CC_COMPILER="/opt/rh/devtoolset-7/root/usr/bin/cc" - - ${CXX_COMPILER} --version - ${CC_COMPILER} --version - - export CC=${CC_COMPILER} CXX=${CXX_COMPILER} - fi -} # Parameters: # $1 = Package name # -build_package() { +function build_package() { setup - echo "*******************************************************************" - echo "********************* STARTING PACKAGE BUILD **********************" - echo "*******************************************************************" + echo "**************************************************************************" + echo "********************* STARTING PACKAGE EXTRAS BUILD **********************" + echo "**************************************************************************" mkdir -p build && pushd build - - rm -rf * - cmake -DCMAKE_INSTALL_PREFIX=/usr \ - -DBUILD_LIBHICN=OFF \ - -DBUILD_UTILS=OFF \ - -DBUILD_HICNPLUGIN=OFF \ - -DBUILD_HICNLIGHT=OFF \ - -DBUILD_LIBTRANSPORT=OFF \ - -DBUILD_APPS=OFF \ - -DBUILD_CTRL=OFF \ - -DBUILD_SYSREPOPLUGIN=OFF \ - -DBUILD_EXTRAS=ON \ - ${SCRIPT_PATH}/.. - make package - - find . -type d -iname '_CPack_Packages' -print0 | xargs -0 rm -rf -- || true - find . -iname '*Unspecified*' -print0 | xargs -0 rm -rf -- || true - + rm -rf * + cmake -G Ninja -DCMAKE_INSTALL_PREFIX=/usr \ + -DBUILD_LIBHICN=OFF \ + -DBUILD_UTILS=OFF \ + -DBUILD_HICNPLUGIN=OFF \ + -DBUILD_HICNLIGHT=OFF \ + -DBUILD_LIBTRANSPORT=OFF \ + -DBUILD_APPS=OFF \ + -DBUILD_CTRL=OFF \ + -DBUILD_SYSREPOPLUGIN=OFF \ + -DBUILD_EXTRAS=ON \ + ${SCRIPT_PATH}/.. + ninja + + find . -type f '(' -name '*.deb' -o -name '*.rpm' ')' -exec mv {} . \; + find . -not -name '*.deb' -not -name '*.rpm' -print0 | xargs -0 rm -rf -- || true + rm *Unspecified* || true popd echo "*******************************************************************" diff --git a/scripts/build-packages.sh b/scripts/build-packages.sh index 77c1b94ab..efc1b6717 100644 --- a/scripts/build-packages.sh +++ b/scripts/build-packages.sh @@ -15,193 +15,12 @@ set -euxo pipefail SCRIPT_PATH=$( cd "$(dirname "${BASH_SOURCE}")" ; pwd -P ) -APT_PATH=`which apt-get` || true -apt_get=${APT_PATH:-"/usr/local/bin/apt-get"} - -PACKAGECLOUD_RELEASE_REPO_DEB="https://packagecloud.io/install/repositories/fdio/release/script.deb.sh" -PACKAGECLOUD_RELEASE_REPO_RPM="https://packagecloud.io/install/repositories/fdio/release/script.rpm.sh" - -VPP_GIT_REPO="https://git.fd.io/vpp" -VPP_BRANCH="stable/2001" - -VPP_VERSION_DEB="20.01-release" -VPP_VERSION_RPM="20.01-release.x86_64" - -BUILD_TOOLS_UBUNTU="build-essential doxygen" -LIBSSL_LIBEVENT_UBUNTU="libevent-dev libssl-dev" -DEPS_UBUNTU="libparc-dev \ - libmemif-dev \ - libmemif \ - libasio-dev \ - libconfig-dev \ - libcurl4-openssl-dev \ - vpp=${VPP_VERSION_DEB} \ - vpp-dev=${VPP_VERSION_DEB} \ - libvppinfra=${VPP_VERSION_DEB} \ - libvppinfra-dev=${VPP_VERSION_DEB} \ - vpp-plugin-core=${VPP_VERSION_DEB} \ - python3-ply" - - -DEPS_UBUNTU_NOVERSION="libparc-dev \ - libmemif-dev \ - libmemif \ - libasio-dev \ - libconfig-dev \ - libcurl4-openssl-dev \ - vpp \ - vpp-dev \ - libvppinfra \ - libvppinfra-dev \ - vpp-plugin-core \ - python3-ply \ - python3-setuptools \ - python3-pip" - -DEPS_CMAKE_UBUNTU="curl" - -# BUILD_TOOLS_GROUP_CENTOS="'Development Tools'" -DEPS_CENTOS="vpp-devel-${VPP_VERSION_RPM} \ - vpp-lib-${VPP_VERSION_RPM} \ - libparc-devel \ - libmemif-devel \ - libmemif \ - libcurl-devel \ - asio-devel \ - libconfig-devel \ - centos-release-scl \ - libyang \ - sysrepo \ - devtoolset-7" - -DEPS_CENTOS_NOVERSION="vpp-devel \ - vpp-lib \ - libparc-devel \ - libcurl-devel \ - asio-devel \ - libmemif-devel \ - libmemif \ - centos-release-scl \ - devtoolset-7" - -LATEST_EPEL_REPO="http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm" - -install_cmake() { - if [ "${DISTRIB_ID}" == "ubuntu" ]; then - sudo apt update - echo ${DEPS_CMAKE_UBUNTU} | xargs sudo ${apt_get} install -y --allow-unauthenticated --no-install-recommends - fi - - if ! grep -q "8.8.8.8" /etc/resolv.conf; then - echo "nameserver 8.8.8.8" | sudo tee -a /etc/resolv.conf - fi - - cat /etc/resolv.conf - - CMAKE_INSTALL_SCRIPT_URL="https://cmake.org/files/v3.8/cmake-3.8.0-Linux-x86_64.sh" - CMAKE_INSTALL_SCRIPT="/tmp/install_cmake.sh" - curl ${CMAKE_INSTALL_SCRIPT_URL} > ${CMAKE_INSTALL_SCRIPT} - - sudo mkdir -p /opt/cmake - sudo bash ${CMAKE_INSTALL_SCRIPT} --skip-license --prefix=/opt/cmake - export PATH=/opt/cmake/bin:${PATH} -} - -# Parameters: -# $1 = Distribution id -# $2 = Distribution codename -# -setup_fdio_repo() { - DISTRIB_ID=${1} - - if [ "${DISTRIB_ID}" == "ubuntu" ]; then - rm -r /etc/apt/sources.list.d/* - curl -s ${PACKAGECLOUD_RELEASE_REPO_DEB} | sudo bash - elif [ "${DISTRIB_ID}" == "centos" ]; then - curl -s ${PACKAGECLOUD_RELEASE_REPO_RPM} | sudo bash - curl ${LATEST_EPEL_REPO} > epel-release-latest-7.noarch.rpm - rpm -ivh epel-release-latest-7.noarch.rpm || true - rm epel-release-latest-7.noarch.rpm - else - echo "Distribution ${DISTRIB_ID} is not supported" - exit -1 - fi -} - -setup() { - # Figure out what system we are running on - if [ -f /etc/os-release ]; then - . /etc/os-release - else - echo "ERROR: System configuration not recognized. Build failed" - exit -1 - fi - - DISTRIB_ID=${ID} - - echo DISTRIBUTION: ${PRETTY_NAME} - echo ARCHITECTURE: $(uname -m) - - ARCH=`uname -m` - if [ "$ARCH" == "x86_64" ] || [ "$ARCH" == "x86" ]; then - install_cmake - fi - setup_fdio_repo ${DISTRIB_ID} - - if [ "${DISTRIB_ID}" == "ubuntu" ]; then - sudo ${apt_get} update || true - fi - - # Install dependencies - if [ ${DISTRIB_ID} == "ubuntu" ]; then - echo ${BUILD_TOOLS_UBUNTU} ${DEPS_UBUNTU_NOVERSION} | xargs sudo ${apt_get} install -y --allow-unauthenticated --no-install-recommends - elif [ ${DISTRIB_ID} == "centos" ]; then - # echo ${BUILD_TOOLS_GROUP_CENTOS} | xargs sudo yum groupinstall -y --nogpgcheck - echo ${DEPS_CENTOS} | xargs sudo yum install -y --nogpgcheck - sudo yum install devtoolset-7 - - c++ --version - - CXX_COMPILER="/opt/rh/devtoolset-7/root/usr/bin/c++" - CC_COMPILER="/opt/rh/devtoolset-7/root/usr/bin/cc" - - ${CXX_COMPILER} --version - ${CC_COMPILER} --version - - export CC=${CC_COMPILER} CXX=${CXX_COMPILER} - fi - - # do nothing but check compiler version - c++ --version -} - - -install_collectd_headers() { - if [ -f /etc/os-release ]; then - . /etc/os-release - else - echo "ERROR: System configuration not recognized. Build failed" - exit -1 - fi - - if [ "${DISTRIB_ID}" == "ubuntu" ]; then - sudo apt-get install collectd-dev -y --allow-unauthenticated - - if [ "${VERSION_CODENAME}" == "xenial" ]; then - awk '/config.h/ { print; print "#include \"collectd/liboconfig/oconfig.h\""; next }1' /usr/include/collectd/core/daemon/configfile.h | sudo tee /usr/include/collectd/core/daemon/configfile.h - fi - elif [ "${DISTRIB_ID}" == "centos" ]; then - wget https://storage.googleapis.com/collectd-tarballs/collectd-5.9.2.tar.bz2 - tar -xf collectd-5.9.2.tar.bz2 - cd collectd-5.9.2 && ./configure && make && cd - - export COLLECTD_HOME=${PWD}/collectd-5.9.2/src - fi -} +source ${SCRIPT_PATH}/functions.sh # Parameters: # $1 = Package name # -build_package() { +function build_package() { setup echo "*******************************************************************" @@ -210,29 +29,12 @@ build_package() { # Make the package mkdir -p ${SCRIPT_PATH}/../build && pushd ${SCRIPT_PATH}/../build - - rm -rf * - cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_APPS=ON .. - make VERBOSE=1 -j8 package - - rm -rf libtransport ctrl/libhicnctrl - - install_collectd_headers - - cmake -DCMAKE_INSTALL_PREFIX=/usr \ - -DBUILD_HICNPLUGIN=ON \ - -DBUILD_LIBTRANSPORT=ON \ - -DBUILD_APPS=ON \ - -DBUILD_HICNLIGHT=OFF \ - -DBUILD_SYSREPOPLUGIN=ON \ - -DBUILD_TELEMETRY=ON \ - ${SCRIPT_PATH}/.. - - make VERBOSE=1 -j8 package - - find . -not -name '*.deb' -not -name '*.rpm' -print0 | xargs -0 rm -rf -- || true - rm *Unspecified* || true - + rm -rf * + # First round + cmake -G Ninja -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_APPS=ON .. + ninja -j8 package + find . -not -name '*.deb' -not -name '*.rpm' -print0 | xargs -0 rm -rf -- || true + rm *Unspecified* || true popd echo "*******************************************************************" @@ -264,13 +66,13 @@ build_doxygen() { mkdir -p ${SCRIPT_PATH}/../build-doxygen pushd ${SCRIPT_PATH}/../build-doxygen - cmake -DBUILD_HICNPLUGIN=OFF -DBUILD_HICNLIGHT=OFF -DBUILD_LIBTRANSPORT=OFF -DBUILD_UTILS=OFF -DBUILD_APPS=OFF -DBUILD_CTRL=OFF .. + cmake -DBUILD_HICNPLUGIN=On -DBUILD_HICNLIGHT=OFF -DBUILD_LIBTRANSPORT=OFF -DBUILD_UTILS=OFF -DBUILD_APPS=OFF -DBUILD_CTRL=OFF .. make doc popd } function usage() { - echo "Usage: ${0} [doc|sphinx|doxygen]" + echo "Usage: ${0} [sphinx|doxygen|packages]" exit 1 } diff --git a/scripts/functions.sh b/scripts/functions.sh new file mode 100644 index 000000000..7796935ef --- /dev/null +++ b/scripts/functions.sh @@ -0,0 +1,144 @@ +# Copyright (c) 2020 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#!/bin/bash +set -euxo pipefail + +APT_PATH=`which apt-get` || true +apt_get=${APT_PATH:-"/usr/local/bin/apt-get"} + +# Cmake executable +CMAKE_INSTALL_DIR="/opt/cmake" +export PATH=:${CMAKE_INSTALL_DIR}/bin:${PATH} + +PACKAGECLOUD_RELEASE_REPO_DEB="https://packagecloud.io/install/repositories/fdio/release/script.deb.sh" +PACKAGECLOUD_RELEASE_REPO_RPM="https://packagecloud.io/install/repositories/fdio/release/script.rpm.sh" +PACKAGECLOUD_HICN_REPO_DEB="https://packagecloud.io/install/repositories/fdio/hicn/script.deb.sh" +PACKAGECLOUD_HICN_REPO_RPM="https://packagecloud.io/install/repositories/fdio/hicn/script.rpm.sh" + +VPP_GIT_REPO="https://github.com/FDio/vpp" +VPP_BRANCH="stable/2005" + + # Figure out what system we are running on +if [ -f /etc/os-release ]; then + . /etc/os-release +else + echo "ERROR: System configuration not recognized. Build failed" + exit 1 +fi + +VERSION_REGEX="s/v([0-9]+).([0-9]+)(.*)?-([0-9]+)-(g[0-9a-f]+)/\1.\2-release/g" +VPP_VERSION_DEB=$(git describe --long --match "v*" | sed -E ${VERSION_REGEX}) +VPP_VERSION_RPM="${VPP_VERSION_DEB}.x86_64" + +DEPS_UBUNTU=("build-essential" + "doxygen" + "curl" + "libparc-dev" + "libmemif-dev" + "libmemif" + "libasio-dev" + "libconfig-dev" + "libcurl4-openssl-dev" + "libevent-dev" + "libssl-dev" + "ninja-build" + "python3-ply") + +# BUILD_TOOLS_GROUP_CENTOS="'Development Tools'" +DEPS_CENTOS=("libparc-devel" + "curl" + "libmemif-devel" + "ninja-build" + "libmemif" + "libcurl-devel" + "asio-devel" + "libconfig-devel" + "dnf-plugins-core" + "bzip2" + "rpm-build") + +COLLECTD_SOURCE="https://github.com/collectd/collectd/releases/download/collectd-5.12.0/collectd-5.12.0.tar.bz2" + +function install_collectd_headers() { + curl -OL ${COLLECTD_SOURCE} + tar -xf collectd-5.12.0.tar.bz2 + + pushd collectd-5.12.0 + ./configure && make -j$(nproc) + popd + + export COLLECTD_HOME=${PWD}/collectd-5.12.0/src +} + +function install_cmake() { + [[ $(uname --hardware-platform) = "x86_64" ]] || return 0 + CMAKE_INSTALL_SCRIPT_URL="https://github.com/Kitware/CMake/releases/download/v3.18.4/cmake-3.18.4-Linux-x86_64.sh" + CMAKE_INSTALL_SCRIPT="/tmp/install_cmake.sh" + curl -L ${CMAKE_INSTALL_SCRIPT_URL} > ${CMAKE_INSTALL_SCRIPT} + + sudo mkdir -p ${CMAKE_INSTALL_DIR} + sudo bash ${CMAKE_INSTALL_SCRIPT} --skip-license --prefix=${CMAKE_INSTALL_DIR} +} + +function setup_fdio_repo() { + DISTRIB_ID=${ID} + + if [ "${DISTRIB_ID}" == "ubuntu" ]; then + curl -s ${PACKAGECLOUD_RELEASE_REPO_DEB} | sudo bash + curl -s ${PACKAGECLOUD_HICN_REPO_DEB} | sudo bash + elif [ "${DISTRIB_ID}" == "centos" ]; then + curl -s ${PACKAGECLOUD_RELEASE_REPO_RPM} | sudo bash + curl -s ${PACKAGECLOUD_HICN_REPO_RPM} | sudo bash + else + echo "Distribution ${DISTRIB_ID} is not supported" + exit 1 + fi +} + +# Install dependencies +function install_deps() { + DISTRIB_ID=${ID} + + if [ ${DISTRIB_ID} == "ubuntu" ]; then + echo ${DEPS_UBUNTU[@]} | xargs sudo ${apt_get} install -y --allow-unauthenticated --no-install-recommends + elif [ ${DISTRIB_ID} == "centos" ]; then + yum config-manager --set-enabled powertools + # Temporary workaround until centos fixes the asio-devel package (https://forums.centos.org/viewtopic.php?t=73034) + curl -L http://mirror.centos.org/centos/8/PowerTools/x86_64/os/Packages/asio-devel-1.10.8-7.module_el8.1.0+217+4d875839.x86_64.rpm > /tmp/asio-devel-1.10.8-7.module_el8.1.0+217+4d875839.x86_64.rpm + yum localinstall -y --nogpgcheck /tmp/asio-devel-1.10.8-7.module_el8.1.0+217+4d875839.x86_64.rpm + echo ${DEPS_CENTOS[@]} | xargs sudo yum install -y --nogpgcheck + fi +} + +# Call a function once +function call_once() { + # OP_NAME is the name of the function + OP_NAME=${1} + # If function was already called return + [[ -f /tmp/${OP_NAME} ]] && return 0 + # Otherwise call the function + ${@} + # And mark the function as called if no error occurred + echo ${OP_NAME} > /tmp/${OP_NAME} +} + +function setup() { + echo DISTRIBUTION: ${PRETTY_NAME} + # export variables depending on the platform we are running + + call_once setup_fdio_repo + call_once install_deps + call_once install_cmake + call_once install_collectd_headers +} |