diff options
Diffstat (limited to 'hicn-light/src/hicn/config')
-rw-r--r-- | hicn-light/src/hicn/config/CMakeLists.txt | 99 | ||||
-rw-r--r-- | hicn-light/src/hicn/config/command.c | 61 | ||||
-rw-r--r-- | hicn-light/src/hicn/config/command.h | 163 | ||||
-rw-r--r-- | hicn-light/src/hicn/config/command_connection.c | 113 | ||||
-rw-r--r-- | hicn-light/src/hicn/config/command_face.c | 14 | ||||
-rw-r--r-- | hicn-light/src/hicn/config/command_listener.c | 87 | ||||
-rw-r--r-- | hicn-light/src/hicn/config/command_mapme.c | 0 | ||||
-rw-r--r-- | hicn-light/src/hicn/config/command_policy.c | 53 | ||||
-rw-r--r-- | hicn-light/src/hicn/config/command_punting.c | 36 | ||||
-rw-r--r-- | hicn-light/src/hicn/config/command_route.c | 51 | ||||
-rw-r--r-- | hicn-light/src/hicn/config/command_strategy.c | 12 | ||||
-rw-r--r-- | hicn-light/src/hicn/config/parse.c | 354 | ||||
-rw-r--r-- | hicn-light/src/hicn/config/parse.h | 6 |
13 files changed, 965 insertions, 84 deletions
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 */ |