From a070b0de9f9e9cbca150eea4eda74757ca588bed Mon Sep 17 00:00:00 2001 From: Jordan Augé Date: Wed, 23 Sep 2020 17:50:52 +0200 Subject: [HICN-645] Control plane (WIP) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I4be6a40b690b62f22f57de6d8c10b01a1be42a6d Signed-off-by: Jordan Augé Signed-off-by: Enrico Loparco (eloparco) Signed-off-by: Mauro Sardara --- ctrl/libhicnctrl/includes/CMakeLists.txt | 1 + ctrl/libhicnctrl/includes/hicn/ctrl/api.h | 58 +- ctrl/libhicnctrl/includes/hicn/ctrl/cli.h | 31 ++ ctrl/libhicnctrl/src/CMakeLists.txt | 3 +- ctrl/libhicnctrl/src/api.c | 43 ++ ctrl/libhicnctrl/src/cli.c | 889 ++---------------------------- ctrl/libhicnctrl/src/hicnctrl.c | 842 ++++++++++++++++++++++++++++ 7 files changed, 1010 insertions(+), 857 deletions(-) create mode 100644 ctrl/libhicnctrl/includes/hicn/ctrl/cli.h create mode 100644 ctrl/libhicnctrl/src/hicnctrl.c (limited to 'ctrl') 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 +#include -/** - * \file cli.c - * \brief Command line interface - */ -#include // isalpha isalnum -#include -#include -#include // getopt +typedef int (*hc_object_snprintf_type)(char*, size_t, uint8_t*); -#include -#include -#include +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 // isalpha isalnum +#include +#include +#include // getopt + +#include +#include +#include + + +#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; +} -- cgit 1.2.3-korg