aboutsummaryrefslogtreecommitdiffstats
path: root/hicn-light/src/hicn/config
diff options
context:
space:
mode:
Diffstat (limited to 'hicn-light/src/hicn/config')
-rw-r--r--hicn-light/src/hicn/config/CMakeLists.txt99
-rw-r--r--hicn-light/src/hicn/config/command.c61
-rw-r--r--hicn-light/src/hicn/config/command.h163
-rw-r--r--hicn-light/src/hicn/config/command_connection.c113
-rw-r--r--hicn-light/src/hicn/config/command_face.c14
-rw-r--r--hicn-light/src/hicn/config/command_listener.c87
-rw-r--r--hicn-light/src/hicn/config/command_mapme.c0
-rw-r--r--hicn-light/src/hicn/config/command_policy.c53
-rw-r--r--hicn-light/src/hicn/config/command_punting.c36
-rw-r--r--hicn-light/src/hicn/config/command_route.c51
-rw-r--r--hicn-light/src/hicn/config/command_strategy.c12
-rw-r--r--hicn-light/src/hicn/config/parse.c354
-rw-r--r--hicn-light/src/hicn/config/parse.h6
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, &params_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 */