summaryrefslogtreecommitdiffstats
path: root/ctrl/libhicnctrl/src/modules
diff options
context:
space:
mode:
authorLuca Muscariello <muscariello@ieee.org>2022-08-04 16:06:34 +0200
committerLuca Muscariello <muscariello@ieee.org>2022-08-04 16:31:51 +0200
commit6d22a0db96aa7f8e3102ae44d00c09e36a2e9c57 (patch)
tree79546bbf09f6fbf74db7bc89117843f06ce937ea /ctrl/libhicnctrl/src/modules
parent012843b1c0bc0838e69085ed83a79ec8b6f97360 (diff)
feat: Due to the deep modifications related to names and packet format,
this task cover a large part of the codebase and involves several changes: - the library provides a name data structure (hicn_name_t ), which is composed of a name prefix (hicn_name_prefix_t) and a name suffix (hicn_name_suffix_t), and it has been extended to provide all support functions required for name manipulation, including common prefix computation, as required for the Longest Prefix Match (LPM)in the forwarder, in addition to Exact Prefix Match (EPM). - all code has been rewritten to use this data structure instead of having for instance the forwarder define its own name class (used to be Name and NameBitVector) the code has been refactored to minimize name allocations and copies, one remaining aspect is the difference of name storage between PIT and CS entries (respectively in the PIT entry, and in the message buffer), which causes the packet cache index to be updated when a PIT entry is converted into a CS entry. By storing the name in the PIT/CS entry everytime, we might save on this operation). - hicn-light FIB has been rewritten : code has been refactored and should now be shorter and documented; unit tests have been drafted but more would be required to cover all cases and match the algorithms to add/remove nodes, as specified in the doc. all protocol details and hICN header formats are now abstracted by the library for the forwarder (and thus header.h and  protocols/*.h have been removed from public includes, and replaced by packet.h providing protocol agnostic packet level functions, completely replacing the compat.h header that used to provide similar functions. - this works by exposing a opaque buffer to the application (a kind of socket buffer) which is used by the lib to cache the packet format and offsets of the different layers in the buffer and provider efficient operations (the packet format is either defined for packet construction, or guessed at ingress, and this structure is updated accordingly only once). Co-authored-by: Jordan Augé <jordan.auge+fdio@cisco.com> Signed-off-by: Luca Muscariello <muscariello@ieee.org> Change-Id: I31e321897f85f0267fe8ba4720363c180564492f
Diffstat (limited to 'ctrl/libhicnctrl/src/modules')
-rw-r--r--ctrl/libhicnctrl/src/modules/CMakeLists.txt40
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light.c1255
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light.h59
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/base.h60
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/cache.c178
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/connection.c498
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/connection.h27
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/face.c482
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/face.h14
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/listener.c176
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/listener.h21
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/mapme.c139
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/policy.c162
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/punting.c74
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/route.c173
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/route.h42
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/stats.h0
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/strategy.c205
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/strategy.h24
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/subscription.c66
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/subscription.h26
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/wldr.c3
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light_common.h96
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light_ng_api.c3238
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_plugin.c247
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_plugin/base.h36
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_plugin/listener.c184
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_plugin/listener.h (renamed from ctrl/libhicnctrl/src/modules/hicn_light_common.c)22
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_plugin/route.c541
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_plugin/route.h28
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_plugin_api.c1402
31 files changed, 4762 insertions, 4756 deletions
diff --git a/ctrl/libhicnctrl/src/modules/CMakeLists.txt b/ctrl/libhicnctrl/src/modules/CMakeLists.txt
index 8f7916d14..b85ef29dc 100644
--- a/ctrl/libhicnctrl/src/modules/CMakeLists.txt
+++ b/ctrl/libhicnctrl/src/modules/CMakeLists.txt
@@ -14,13 +14,28 @@
##############################################################
# Hicn Light NG Module
##############################################################
-list(APPEND HICNLIGHTNG_MODULE_SOURCE_FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light_common.c
- ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light_ng_api.c
+list(APPEND HICNLIGHT_MODULE_SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/connection.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/face.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/listener.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/route.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/strategy.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/subscription.c
)
-build_module(hicnlightngctrl_module
- SOURCES ${HICNLIGHTNG_MODULE_SOURCE_FILES}
+list(APPEND HICNLIGHT_MODULE_HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/connection.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/face.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/listener.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/route.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/strategy.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/subscription.h
+ )
+
+build_module(hicnlightctrl_module
+ SOURCES ${HICNLIGHT_MODULE_SOURCE_FILES} ${HICNLIGHT_MODULE_HEADER_FILES}
DEPENDS ${DEPENDENCIES}
COMPONENT ${LIBHICNCTRL_COMPONENT}
LINK_LIBRARIES PRIVATE ${HICN_LIBRARIES}
@@ -44,12 +59,21 @@ if(BUILD_HICNPLUGIN AND ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
)
endif()
+
list(APPEND HICN_PLUGIN_SOURCE_FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/hicn_plugin_api.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_plugin.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_plugin/listener.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_plugin/route.c
+ )
+
+ list(APPEND HICN_PLUGIN_HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/base.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/listener.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/route.h
)
build_module(vppctrl_module
- SOURCES ${HICN_PLUGIN_SOURCE_FILES}
+ SOURCES ${HICN_PLUGIN_SOURCE_FILES} ${HICN_PLUGIN_HEADER_FILES}
DEPENDS ${DEPENDENCIES}
LINK_LIBRARIES
PRIVATE ${HICN_LIBRARIES}
@@ -58,6 +82,6 @@ if(BUILD_HICNPLUGIN AND ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
COMPONENT ${LIBHICNCTRL_COMPONENT_MODULES}
INCLUDE_DIRS PRIVATE ${INCLUDE_DIRS}
DEFINITIONS PRIVATE ${COMPILER_DEFINITIONS}
- COMPILE_OPTIONS ${COMPILER_OPTIONS} ${MARCH_COMPILER_OPTIONS}
+ COMPILE_OPTIONS ${COMPILER_OPTIONS} ${MARCH_COMPILER_OPTIONS} "-DHICN_VPP_PLUGIN=1"
)
endif()
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light.c b/ctrl/libhicnctrl/src/modules/hicn_light.c
new file mode 100644
index 000000000..1af6c79e2
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light.c
@@ -0,0 +1,1255 @@
+/*
+ * Copyright (c) 2021-2022 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * 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 modules/hicn_light.c
+ * \brief Implementation of hicn-light module.
+ */
+
+#include <assert.h> // assert
+#include <fcntl.h> // fcntl
+#include <stdbool.h>
+#include <stdio.h> // snprintf
+#include <string.h> // memmove, strcasecmp
+#include <sys/socket.h> // socket
+#include <sys/types.h> // getpid
+#include <unistd.h> // close, fcntl, getpid
+
+#ifdef __linux__
+#include <sys/syscall.h>
+#define gettid() syscall(SYS_gettid)
+#endif /* __linux__ */
+
+#include <strings.h>
+
+#include <hicn/ctrl/hicn-light.h>
+#include <hicn/ctrl/socket.h>
+
+#include "../api_private.h"
+#include "../objects/connection.h" // hc_connection_has_local
+#include "../objects/listener.h" // hc_listener_is_local
+#include "../objects/route.h" // hc_route_has_face
+#include "../request.h"
+#include "../socket_private.h"
+#include "hicn_light.h"
+
+#include "hicn_light/base.h"
+#include "hicn_light/connection.h"
+#include "hicn_light/listener.h"
+#include "hicn_light/face.h"
+#include "hicn_light/route.h"
+#include "hicn_light/strategy.h"
+#include "hicn_light/subscription.h"
+
+#pragma GCC diagnostic ignored "-Warray-bounds"
+
+#define DEFAULT_SOCK_RECV_TIMEOUT_MS 100
+
+#define PORT 9695
+
+#define BOOLSTR(x) ((x) ? "true" : "false")
+
+hc_sock_light_data_t *hc_sock_light_data_create(const char *url) {
+ hc_sock_light_data_t *s = malloc(sizeof(hc_sock_light_data_t));
+ if (!s) goto ERR_MALLOC;
+
+ s->roff = s->woff = 0;
+ s->remaining = 0;
+ s->got_header = false;
+
+ s->url = url ? strdup(url) : NULL;
+
+ s->fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s->fd < 0) goto ERR_SOCKET;
+
+#if 0
+ struct timeval tv = {.tv_sec = 0,
+ .tv_usec = DEFAULT_SOCK_RECV_TIMEOUT_MS * 1000};
+ if (setsockopt(s->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
+ perror("setsockopt");
+ goto ERR_TIMEOUT;
+ }
+#endif
+
+ return s;
+
+#if 0
+ERR_TIMEOUT:
+#endif
+ close(s->fd);
+ERR_SOCKET:
+ if (s->url) free(s->url);
+ free(s);
+ERR_MALLOC:
+ return NULL;
+}
+
+void hc_sock_light_data_free(hc_sock_light_data_t *data) {
+ if (data->url) free(data->url);
+ free(data);
+}
+
+static const struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT;
+
+/******************************************************************************
+ * Control socket
+ ******************************************************************************/
+
+#define AVAILABLE(s) ((s)->woff - (s)->roff)
+
+/**
+ * \brief Parse a connection URL into a sockaddr
+ * \param [in] url - URL
+ * \param [out] sa - Resulting struct sockaddr, expected zero'ed.
+ * \return 0 if parsing succeeded, a negative error value otherwise.
+ */
+static int hicnlight_parse_url(const char *url, struct sockaddr *sa) {
+ /* FIXME URL parsing is currently not implemented */
+ _ASSERT(!url);
+
+#ifdef __linux__
+ srand(time(NULL) ^ getpid() ^ gettid());
+#else
+ srand((unsigned int)(time(NULL) ^ getpid()));
+#endif /* __linux__ */
+
+ /*
+ * A temporary solution is to inspect the sa_family fields of the passed in
+ * sockaddr, which defaults to AF_UNSPEC (0) and thus creates an IPv4/TCP
+ * connection to localhost.
+ */
+ switch (sa->sa_family) {
+ case AF_UNSPEC:
+ case AF_INET: {
+ struct sockaddr_in *sai = (struct sockaddr_in *)sa;
+ sai->sin_family = AF_INET;
+ sai->sin_port = htons(PORT);
+ sai->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ break;
+ }
+ case AF_INET6: {
+ struct sockaddr_in6 *sai6 = (struct sockaddr_in6 *)sa;
+ sai6->sin6_family = AF_INET6;
+ sai6->sin6_port = htons(PORT);
+ sai6->sin6_addr = loopback_addr;
+ break;
+ }
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Return codes:
+ * < 0 : error; invalid buffer data -> flush
+ * otherwise, seq_num of the identified request
+ */
+static int hicnlight_process_header(hc_sock_t *sock) {
+ hc_sock_light_data_t *s = (hc_sock_light_data_t *)sock->data;
+ hc_object_type_t object_type = OBJECT_TYPE_UNDEFINED;
+
+ /* Check we have at least a header's worth of data, and consume it */
+ if (AVAILABLE(s) < sizeof(hc_msg_header_t)) return 0;
+
+ hc_msg_t *msg = (hc_msg_t *)(s->buf + s->roff);
+
+ // INFO("Processing header header %s", command_type_str(msg->hdr.command_id));
+ s->roff += sizeof(hc_msg_header_t);
+ s->got_header = true;
+
+ /* How many elements are we expecting in the reply ? */
+ s->remaining = msg->header.length;
+
+ /* Identify request being parsed */
+ int seq = msg->header.seq_num;
+ hc_request_t *request = NULL;
+ if (hc_sock_map_get(sock->map, seq, &request) < 0) {
+ ERROR("[hc_sock_light_process] Error searching for matching request");
+ return -1;
+ }
+ if (!request) {
+ ERROR("[hc_sock_light_process] No request matching sequence number");
+ return -1;
+ }
+ sock->current_request = request;
+ hc_request_t *current_request = hc_request_get_current(request);
+ hc_data_t *data = hc_request_get_data(current_request);
+ _ASSERT(data);
+
+ switch (msg->header.message_type) {
+ case ACK_LIGHT:
+ _ASSERT(s->remaining == 0);
+
+ s->got_header = false;
+ if (!hc_request_is_subscription(request)) hc_data_set_complete(data);
+ break;
+
+ case NACK_LIGHT:
+ _ASSERT(s->remaining == 0);
+
+ s->got_header = false;
+ hc_data_set_error(data);
+ break;
+
+ case RESPONSE_LIGHT:
+ if (s->remaining == 0) {
+ /* Empty response (i.e. containing 0 elements) */
+ s->got_header = false;
+ hc_data_set_complete(data);
+ return 0;
+ }
+
+ /* Allocate buffer for response */
+ if (hc_data_allocate(data, s->remaining) < 0) {
+ ERROR("[hc_sock_light_process] Cannot allocate result buffer");
+ return -99;
+ }
+ break;
+
+ case NOTIFICATION_LIGHT: {
+ _ASSERT(s->remaining == 1);
+ /*
+ * Assumption: the whole notification data is returned in a single read
+ * and we immediately parse it.
+ */
+ // XXX assert enough buffer for object type + validate returned object
+ object_type = (hc_object_type_t)msg->header.command_id;
+ hc_data_clear(data);
+ hc_data_set_object_type(data, object_type);
+ if (hc_data_allocate(data, s->remaining) < 0) {
+ ERROR("[hc_sock_light_process] Cannot allocate result buffer");
+ return -1;
+ }
+
+ hc_data_push(data, s->buf + s->roff);
+
+ s->roff += AVAILABLE(s);
+
+ hc_request_on_notification(request);
+
+ /*
+ * The buffer is cleared just before the next notification, which means
+ * it will have to be released upon exit. Otherwise we break the code
+ * dumping the notification synchronously (eg. hicnctrl -s).
+ */
+ // hc_data_clear(data);
+
+ s->got_header = false;
+ break;
+ }
+
+ default:
+ ERROR("[hc_sock_light_process] Invalid response received");
+ return -99;
+ }
+
+ return 0;
+}
+
+size_t hc_light_object_size(hc_object_type_t object_type);
+
+static int hicnlight_process_payload(hc_sock_t *sock) {
+ int err = 0;
+ int rc;
+
+ hc_sock_light_data_t *s = (hc_sock_light_data_t *)sock->data;
+ hc_request_t *request = hc_sock_get_request(sock);
+ hc_request_t *current_request = hc_request_get_current(request);
+ hc_data_t *data = hc_request_get_data(current_request);
+
+ hc_object_type_t object_type = hc_data_get_object_type(data);
+ size_t object_size = hc_light_object_size(object_type);
+ if (object_size == 0) return -1;
+
+ /* We only process full elements (size is stored in data) */
+ size_t num_chunks = AVAILABLE(s) / object_size;
+
+ /* Check whether we have enough data to process */
+ if (num_chunks == 0) return 0;
+
+ /* Safeguard: _ASSERT(num_chunks < s->remaining); */
+ if (num_chunks > s->remaining) {
+ WARN(
+ "[hicnlight_process_payload] Unexpected num_chunks > "
+ "s->remaining");
+ num_chunks = s->remaining;
+ }
+
+ for (size_t i = 0; i < num_chunks; i++) {
+ /*
+ * Get storage offset in hc_data_t, which we assume is correctly
+ * provisioned.
+ * XXX
+ */
+ u8 *src = s->buf + s->roff;
+ hc_object_t *dst = (hc_object_t *)hc_data_get_free(data);
+ if (!dst) {
+ ERROR("[hc_sock_light_process] Error in hc_data_get_next");
+ err = -2;
+ break;
+ }
+
+ // XXX we might want to display even incomplete data when printing (eg.
+ // string truncation), and be very strict when processing.
+ rc = hc_sock_parse_object(sock, hc_data_get_object_type(data), src,
+ object_size, dst);
+ s->roff += object_size;
+ if (rc < 0) {
+ ERROR("Error parsing received object");
+ continue;
+ }
+ hc_data_inc_size(data);
+ }
+
+ /*
+ * If we are not expecting any more data, mark the reply as complete
+ */
+ s->remaining -= num_chunks;
+ if (s->remaining == 0) {
+ s->got_header = false;
+ hc_data_set_complete(data);
+ }
+
+ return err;
+}
+
+/*----------------------------------------------------------------------------
+ * Socket operations
+ *----------------------------------------------------------------------------*/
+
+static int hicnlight_get_fd(hc_sock_t *sock) {
+ hc_sock_light_data_t *s = (hc_sock_light_data_t *)sock->data;
+ return s->fd;
+}
+
+static int hicnlight_get_recv_buffer(hc_sock_t *sock, uint8_t **buffer,
+ size_t *size) {
+ hc_sock_light_data_t *s = (hc_sock_light_data_t *)sock->data;
+ *buffer = s->buf + s->woff;
+ *size = RECV_BUFLEN - s->woff;
+
+ return 0;
+}
+
+static int hicnlight_connect(hc_sock_t *sock) {
+ hc_sock_light_data_t *s = (hc_sock_light_data_t *)sock->data;
+ struct sockaddr_storage ss;
+ memset(&ss, 0, sizeof(struct sockaddr_storage));
+
+ if (hicnlight_parse_url(s->url, (struct sockaddr *)&ss) < 0) goto ERR_PARSE;
+
+ size_t size = ss.ss_family == AF_INET ? sizeof(struct sockaddr_in)
+ : sizeof(struct sockaddr_in6);
+ if (connect(s->fd, (struct sockaddr *)&ss, (socklen_t)size) < 0) {
+ perror("connect error");
+ goto ERR_CONNECT;
+ }
+ return 0;
+
+ERR_CONNECT:
+ERR_PARSE:
+ return -1;
+}
+
+static int hicnlight_disconnect(hc_sock_t *sock) {
+ hc_sock_light_data_t *s = (hc_sock_light_data_t *)sock->data;
+
+ /* Remove the connection created to send the command.
+ *
+ * Note this is done as a best effort and we don't expect to receive any
+ * answer from the forwarder (hence the NULL pdata pointer in the request).
+ */
+ hc_object_t object;
+ memset(&object, 0, sizeof(hc_object_t));
+ object.connection.id = 0;
+ int rc =
+ strcpy_s(object.connection.name, sizeof(object.connection.name), "SELF");
+ if (rc == EOK)
+ hc_execute_async(sock, ACTION_DELETE, OBJECT_TYPE_CONNECTION, &object, NULL,
+ NULL);
+
+ close(s->fd);
+
+ return 0;
+}
+
+static ssize_t hicnlight_prepare_generic(hc_sock_t *sock, hc_request_t *request,
+ uint8_t **buffer) {
+ /* Dispatch to subrequest if any */
+ hc_request_t *current_request = hc_request_get_current(request);
+
+ _ASSERT(!hc_request_get_data(current_request));
+
+ hc_action_t action = hc_request_get_action(current_request);
+ hc_object_type_t object_type = hc_request_get_object_type(current_request);
+ hc_object_t *object = hc_request_get_object(current_request);
+
+ hc_sock_light_data_t *s = (hc_sock_light_data_t *)sock->data;
+
+ _ASSERT(hc_request_get_data(current_request) == NULL);
+ hc_data_t *data = hc_data_create(object_type);
+ if (!data) {
+ ERROR("[hicnlight_prepare_generic] Could not create data storage");
+ return -1;
+ }
+ hc_request_set_data(current_request, data);
+
+ /* Serialize request into message */
+ DEBUG("Calling serialize on %s %s", action_str(action),
+ object_type_str(object_type));
+ ssize_t msg_len = hc_sock_serialize_object(sock, action, object_type, object,
+ (uint8_t *)&s->msg);
+ if (msg_len < 0) {
+ ERROR("[hicnlight_prepare_generic] Could not serialize command %s %s",
+ action_str(action), object_type_str(object_type));
+ return INPUT_ERROR;
+ }
+
+ s->msg.header.seq_num = hc_request_get_seq(current_request);
+
+ *buffer = (uint8_t *)&s->msg;
+ return msg_len;
+}
+
+static int hicnlight_send(hc_sock_t *sock, uint8_t *buffer, size_t size) {
+ hc_sock_light_data_t *s = (hc_sock_light_data_t *)sock->data;
+
+ int rc = (int)send(s->fd, buffer, size, 0);
+ if (rc < 0) {
+ perror("[hicnlight_send] Error sending message");
+ return -1;
+ }
+
+ // XXX regular behaviour for others
+ return 0;
+}
+
+// Example : face create udp
+// 1) face to connection (immediate)
+// connection to local listener (immediate) : why not both at the same
+// time listener get
+// listener create / nothing
+// connection create
+// connection get (if needed for populating face_id for instance, aka
+// if we
+// need to return data)
+
+static ssize_t hicnlight_prepare(hc_sock_t *sock, hc_request_t *request,
+ uint8_t **buffer);
+
+static ssize_t hicnlight_prepare_subrequest(
+ hc_sock_t *sock, hc_request_t *request, hc_action_t action,
+ hc_object_type_t object_type, hc_object_t *object, uint8_t **buffer) {
+ WITH_DEBUG({
+ if (object) {
+ char buf[MAXSZ_HC_OBJECT];
+ hc_object_snprintf(buf, sizeof(buf), object_type, object);
+ DEBUG("Creating subrequest %s/%s %s", action_str(action),
+ object_type_str(object_type), buf);
+ }
+ });
+ hc_request_make_subrequest(request, action, object_type, object);
+ return hicnlight_prepare(sock, request, buffer);
+}
+
+/*
+ * XXX shall we update the object in the request for faces ? it is not done
+ * for other objects, but for faces it is needed to further add a route !!!
+ */
+static ssize_t hicnlight_prepare_face_create(hc_sock_t *sock,
+ hc_request_t *request,
+ uint8_t **buffer) {
+ hc_request_t *current_request = hc_request_get_current(request);
+ hc_object_t *object = hc_request_get_object(current_request);
+ hc_data_t *data = hc_request_get_data(current_request);
+ hc_face_t *face = &object->face;
+
+ // XXX those objects are created on stack and expected to be valid across
+ // several calls. A quick fix is to make them static
+ static hc_object_t connection;
+ static hc_object_t listener;
+
+ hc_request_state_t state;
+ const hc_connection_t *conn;
+
+NEXT:
+ state = hc_request_get_state(current_request);
+ DEBUG("hicnlight_prepare_face_create > %s", hc_request_state_str(state));
+
+ switch (state) {
+ case REQUEST_STATE_INIT:
+ _ASSERT(!data);
+
+ switch (face->type) {
+ case FACE_TYPE_HICN:
+ case FACE_TYPE_TCP:
+ case FACE_TYPE_UDP:
+ hc_request_set_state(current_request,
+ REQUEST_STATE_FACE_CREATE_CONNECTION_CREATE);
+ goto NEXT;
+ case FACE_TYPE_HICN_LISTENER:
+ case FACE_TYPE_TCP_LISTENER:
+ case FACE_TYPE_UDP_LISTENER:
+ hc_request_set_state(current_request,
+ REQUEST_STATE_FACE_CREATE_LISTENER_CREATE);
+ goto NEXT;
+ case FACE_TYPE_UNDEFINED:
+ case FACE_TYPE_N:
+ return -99; // Not implemented
+ }
+
+ case REQUEST_STATE_FACE_CREATE_CONNECTION_CREATE:
+ if (hc_face_to_connection(face, &connection.connection, true) < 0) {
+ ERROR("[hc_face_create] Could not convert face to connection.");
+ return -1;
+ }
+ hc_request_set_state(current_request,
+ REQUEST_STATE_FACE_CREATE_CONNECTION_CHECK);
+
+ return hicnlight_prepare_subrequest(sock, request, ACTION_CREATE,
+ OBJECT_TYPE_CONNECTION, &connection,
+ buffer);
+
+ case REQUEST_STATE_FACE_CREATE_CONNECTION_CHECK:
+ /*
+ * If the newly created face_id was not need, we would only
+ * need to return the same data result, which contains a ack/nack,
+ * simply updating the object type.
+ *
+ * With the current API, once the connection is created, our only
+ * solution is to list all connections and compare with the current one
+ * to find the created connection ID, and thus face ID.
+ */
+ /* Has the connection been successfully created ? */
+ if (!data || !hc_data_get_result(data)) return -1;
+
+ hc_request_set_state(current_request,
+ REQUEST_STATE_FACE_CREATE_CONNECTION_GET);
+ goto NEXT;
+
+ case REQUEST_STATE_FACE_CREATE_CONNECTION_GET:
+ hc_request_set_state(current_request,
+ REQUEST_STATE_FACE_CREATE_CONNECTION_VERIFY);
+ return hicnlight_prepare_subrequest(sock, request, ACTION_GET,
+ OBJECT_TYPE_CONNECTION, &connection,
+ buffer);
+
+ case REQUEST_STATE_FACE_CREATE_CONNECTION_VERIFY:
+ if (!data || hc_data_get_size(data) != 1) return -1;
+
+ /* Newly created connection was found */
+ conn = (hc_connection_t *)hc_data_get_buffer(data);
+ DEBUG("created connection id=%d", conn->id);
+ object->face.id = conn->id;
+
+ break;
+
+ case REQUEST_STATE_FACE_CREATE_LISTENER_CREATE:
+ if (hc_face_to_listener(face, &listener.listener) < 0) {
+ ERROR("Could not convert face to listener.");
+ return -1;
+ }
+
+ hc_request_set_state(current_request,
+ REQUEST_STATE_FACE_CREATE_LISTENER_CHECK);
+ return hicnlight_prepare_subrequest(sock, request, ACTION_CREATE,
+ OBJECT_TYPE_LISTENER, &listener,
+ buffer);
+
+ break;
+
+ case REQUEST_STATE_FACE_CREATE_LISTENER_CHECK:
+ /*
+ * No need for face id here, simply return the hc_data_t structure
+ * with the ack/nack, and the proper object type
+ */
+ if (!data) return -1;
+ hc_data_set_object_type(data, OBJECT_TYPE_FACE);
+ break;
+
+#if 0
+ case REQUEST_STATE_COMPLETE:
+ hc_data_set_complete(data);
+ break;
+#endif
+
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static ssize_t hicnlight_prepare_face_list(hc_sock_t *sock,
+ hc_request_t *request,
+ uint8_t **buffer) {
+ hc_request_t *current_request = hc_request_get_current(request);
+ hc_action_t action = hc_request_get_action(current_request);
+ hc_object_type_t object_type = hc_request_get_object_type(current_request);
+ hc_object_t *object = hc_request_get_object(current_request);
+ hc_data_t *data = hc_request_get_data(current_request);
+ hc_face_t face;
+
+ _ASSERT(action == ACTION_LIST);
+ _ASSERT(object_type == OBJECT_TYPE_FACE);
+
+ hc_request_state_t state = hc_request_get_state(current_request);
+ DEBUG("hicnlight_prepare_face_list > %s", hc_request_state_str(state));
+
+ switch (state) {
+ case REQUEST_STATE_INIT:
+ _ASSERT(!data);
+
+ hc_request_set_state(current_request,
+ REQUEST_STATE_FACE_LIST_CONNECTION_LIST);
+ return hicnlight_prepare_subrequest(
+ sock, request, ACTION_LIST, OBJECT_TYPE_CONNECTION, object, buffer);
+
+ case REQUEST_STATE_FACE_LIST_CONNECTION_LIST:
+ _ASSERT(data);
+ /*
+ * 'list connection' succeeded, we just need to allocate hc_data_t,
+ * create faces from connections, and return the data structure as if it
+ * was created by the query
+ */
+ hc_data_t *face_data = hc_data_create(object_type);
+ hc_data_allocate(face_data, hc_data_get_size(data));
+ foreach_connection(c, data) {
+ if (hc_face_from_connection(c, &face) < 0) {
+ ERROR("[hc_face_list] Could not convert connection to face.");
+ return -1;
+ }
+ hc_data_push(face_data, &face);
+ }
+ hc_data_set_complete(face_data);
+
+ hc_request_reset_data(request);
+ hc_request_set_data(request, face_data);
+
+ /* FACE/LIST could be part of FACE/GET */
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t hicnlight_prepare_get(hc_sock_t *sock, hc_request_t *request,
+ uint8_t **buffer) {
+ hc_request_t *current_request = hc_request_get_current(request);
+
+ hc_object_type_t object_type = hc_request_get_object_type(current_request);
+ hc_object_t *object = hc_request_get_object(current_request);
+ hc_data_t *data = hc_request_get_data(current_request);
+ hc_object_t *found;
+
+ hc_request_state_t state = hc_request_get_state(current_request);
+ DEBUG("hicnlight_prepare_get > %s", hc_request_state_str(state));
+
+ switch (state) {
+ case REQUEST_STATE_INIT:
+ _ASSERT(!data);
+ hc_request_set_state(current_request, REQUEST_STATE_GET_LIST);
+ return hicnlight_prepare_subrequest(sock, request, ACTION_LIST,
+ object_type, NULL, buffer);
+ case REQUEST_STATE_GET_LIST:
+ _ASSERT(data);
+
+ found = hc_data_find(data, object);
+ hc_data_t *found_data = hc_data_create(object_type);
+ if (found) {
+ hc_data_allocate(found_data, 1);
+ hc_data_push(found_data, found);
+ }
+ hc_data_set_complete(found_data);
+ hc_request_reset_data(current_request);
+ hc_request_set_data(current_request, found_data);
+ return 0;
+ default:
+ return -1; /* Unexpected */
+ }
+}
+
+// XXX This should process the content of pdata (unless at init), and
+// terminate by sending something
+static ssize_t hicnlight_prepare_face(hc_sock_t *sock, hc_request_t *request,
+ uint8_t **buffer) {
+ hc_request_t *current_request = hc_request_get_current(request);
+ hc_action_t action = hc_request_get_action(current_request);
+ hc_object_type_t object_type = hc_request_get_object_type(request);
+
+ _ASSERT(object_type == OBJECT_TYPE_FACE);
+
+ switch (action) {
+ case ACTION_CREATE:
+ return hicnlight_prepare_face_create(sock, request, buffer);
+ case ACTION_LIST:
+ return hicnlight_prepare_face_list(sock, request, buffer);
+ default:
+ return -99; // Not implemented
+ }
+ return 0;
+}
+
+static ssize_t hicnlight_prepare_connection_create(hc_sock_t *sock,
+ hc_request_t *request,
+ uint8_t **buffer) {
+ hc_request_t *current_request = hc_request_get_current(request);
+
+ hc_action_t action = hc_request_get_action(current_request);
+ hc_object_type_t object_type = hc_request_get_object_type(current_request);
+ hc_object_t *object = hc_request_get_object(current_request);
+
+ _ASSERT(action == ACTION_CREATE);
+ _ASSERT(object_type == OBJECT_TYPE_CONNECTION);
+
+ hc_data_t *data = hc_request_get_data(current_request);
+
+ size_t size;
+ unsigned pos;
+ static hc_object_t listener;
+ const hc_object_t *obj_listener;
+ hc_data_t *listener_data = NULL;
+
+ hc_request_state_t state;
+
+NEXT:
+ state = hc_request_get_state(current_request);
+ DEBUG("hicnlight_prepare_connection_create > %s",
+ hc_request_state_str(state));
+
+ switch (state) {
+ case REQUEST_STATE_INIT:
+ /* Two behaviours depending on the content of local_addr and local_port:
+ * - empty : create connection on all existing listeners, and raise an
+ * error if none
+ * - otherwise, check whether a corresponding listener exists, and
+ * create it if necessary
+ *
+ * We assume connection has been already validated.
+ */
+ if (hc_connection_has_local(&object->connection)) {
+ hc_request_set_state(current_request,
+ REQUEST_STATE_CONNECTION_CREATE_LISTENER_GET);
+ } else {
+ /*
+ * At least part of the local socket specification is missing, match
+ * against existing listeners
+ */
+ hc_request_set_state(current_request,
+ REQUEST_STATE_CONNECTION_CREATE_LISTENER_LIST);
+ }
+ goto NEXT;
+
+ case REQUEST_STATE_CONNECTION_CREATE_LISTENER_LIST:
+
+ hc_request_set_state(current_request,
+ REQUEST_STATE_CONNECTION_CREATE_LISTENER_ITERATE);
+ // XXX We are currently assuming an object is present for rewrite, fix
+ // this
+ return hicnlight_prepare_subrequest(sock, request, ACTION_LIST,
+ OBJECT_TYPE_LISTENER, NULL, buffer);
+
+ case REQUEST_STATE_CONNECTION_CREATE_LISTENER_ITERATE:
+ /*
+ * NOTE: we could create all connections in parallel to speed up
+ * processing
+ */
+ size = hc_data_get_size(data);
+ if (size < 0) return -1;
+ if (size == 0)
+ /* We are done, we cannot create a connection, return a Nack */
+ ; // XXX TODO
+ //
+ /* Save the list of listeners for later iteration */
+ listener_data = data;
+ hc_request_clear_data(current_request); // don't free data
+ data = NULL;
+ hc_request_set_state_count(current_request, 0);
+ hc_request_set_state(current_request, REQUEST_STATE_CONNECTION_CREATE_N);
+ goto NEXT; /* Start iteration */
+
+ case REQUEST_STATE_CONNECTION_CREATE_N:
+ /*
+ * IMPORTANT
+ *
+ * For now we only create a connection with the first non-local
+ * listener.
+ *
+ * Creating N connections in a single commands requires other
+ * changes to the code that we might done later:
+ * - ack/nack is not sufficient, all create function should return the
+ * list of created connections
+ * - this would allow us to avoid a GET at the end of face creation to
+ * retrieve the connection id.
+ * - face create should correspond to N connection create (should work
+ * out of the box provided we don't expect a single connection back).
+ * - route+face creation might then create N faces, and thus we would
+ * have to add N routes.
+ */
+ assert(listener_data);
+
+ // We need to back it up as the subrequest will clear the results
+ pos = hc_request_get_state_count(current_request);
+ size = hc_data_get_size(listener_data);
+ /* We have data if pos > 0, and we did not skipped previous ones */
+ if (data && !hc_data_get_result(data)) {
+ INFO("Failed to create connection for listener %d / %d", pos - 1, size);
+ // XXX we might allow connections that already exist... how to manage
+ // the names
+ return -1;
+ }
+
+ /*
+ * Previous connection was successfully created, let's continue but
+ * first check whether we reached the last one, which would complete the
+ * request.
+ */
+ if (pos >= size) {
+ hc_data_free(listener_data);
+ hc_request_set_state(request, REQUEST_STATE_COMPLETE);
+ goto NEXT;
+ }
+
+ /* Sending count'th connection creation */
+ obj_listener = hc_data_get_object(listener_data, pos);
+
+ // Filter which listener we use
+ // same protocol ? ip ? port ?
+ // avoid local ?
+ if (hc_listener_is_local(&obj_listener->listener)) {
+ /* Skip listener */
+ DEBUG("Skipped local listener");
+ hc_request_set_state_count(current_request, pos + 1);
+ goto NEXT;
+ }
+
+ DEBUG("Creating connection with listener # %d / %d", pos, size);
+ /* We complement missing information from listener */
+ // XXX is_family, etc.
+ object->connection.family = obj_listener->listener.family;
+ object->connection.local_addr = obj_listener->listener.local_addr;
+ object->connection.local_port = obj_listener->listener.local_port;
+ snprintf(object->connection.interface_name, INTERFACE_LEN, "%s",
+ obj_listener->listener.interface_name);
+
+ hc_request_set_state_count(current_request, pos + 1);
+ return hicnlight_prepare_subrequest(
+ sock, request, ACTION_CREATE, OBJECT_TYPE_CONNECTION, object, buffer);
+
+ /* Request listener to further check existence */
+ case REQUEST_STATE_CONNECTION_CREATE_LISTENER_GET:
+ /* Ensure we have a corresponding local listener */
+ if (hc_connection_to_local_listener(&object->connection,
+ &listener.listener) < 0) {
+ ERROR(
+ "[hicnlight_prepare_connection_create] Could not convert face "
+ "to "
+ "local listener.");
+ return -1;
+ }
+ hc_request_set_state(current_request,
+ REQUEST_STATE_CONNECTION_CREATE_LISTENER_VERIFY);
+ return hicnlight_prepare_subrequest(
+ sock, request, ACTION_GET, OBJECT_TYPE_LISTENER, &listener, buffer);
+
+ break;
+
+ /* Check whether listener exists in GET results */
+ case REQUEST_STATE_CONNECTION_CREATE_LISTENER_VERIFY:
+ if (!data) return -1;
+ switch (hc_data_get_size(data)) {
+ case 0:
+ hc_request_set_state(current_request,
+ REQUEST_STATE_CONNECTION_CREATE_LISTENER_CREATE);
+ break;
+ case 1:
+ hc_request_set_state(current_request,
+ REQUEST_STATE_CONNECTION_CREATE);
+ break;
+ default:
+ return -1;
+ }
+ goto NEXT;
+
+ /* Create associated listener */
+ case REQUEST_STATE_CONNECTION_CREATE_LISTENER_CREATE:
+ hc_request_set_state(current_request,
+ REQUEST_STATE_CONNECTION_CREATE_LISTENER_CHECK);
+ return hicnlight_prepare_subrequest(sock, request, ACTION_CREATE,
+ OBJECT_TYPE_LISTENER, &listener,
+ buffer);
+
+ /* Check whether listener creation succeeded */
+ case REQUEST_STATE_CONNECTION_CREATE_LISTENER_CHECK:
+ if (!data || hc_data_get_result(data)) return -1;
+ hc_request_set_state(current_request, REQUEST_STATE_CONNECTION_CREATE);
+ goto NEXT;
+
+ /* Create connection */
+ case REQUEST_STATE_CONNECTION_CREATE:
+ /*
+ * Break recursion by directly calling hicnlight_prepare_generic on
+ * the initial request, that can now be executed since all
+ * prerequisites are validated.
+ */
+ // return hicnlight_prepare_subrequest(
+ // sock, request, ACTION_CREATE, OBJECT_TYPE_CONNECTION, object,
+ // buffer);
+ hc_request_reset_data(current_request);
+ hc_request_set_state(current_request, REQUEST_STATE_COMPLETE);
+ return hicnlight_prepare_generic(sock, request, buffer);
+
+ case REQUEST_STATE_COMPLETE:
+ if (data) {
+ hc_data_set_complete(data);
+ } else {
+ /*
+ * No connection has been created, and we freed the data due to
+ * subrequest
+ */
+ data = hc_data_create(OBJECT_TYPE_CONNECTION);
+ hc_data_set_error(data);
+ }
+ break;
+
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static ssize_t hicnlight_prepare_route_create(hc_sock_t *sock,
+ hc_request_t *request,
+ uint8_t **buffer) {
+ hc_request_t *current_request = hc_request_get_current(request);
+
+ hc_action_t action = hc_request_get_action(current_request);
+ hc_object_type_t object_type = hc_request_get_object_type(current_request);
+ hc_object_t *object = hc_request_get_object(current_request);
+
+ _ASSERT(action == ACTION_CREATE);
+ _ASSERT(object_type == OBJECT_TYPE_ROUTE);
+
+ hc_data_t *data = hc_request_get_data(current_request);
+ const hc_object_t *face_obj;
+
+ hc_request_state_t state;
+
+NEXT:
+ state = hc_request_get_state(current_request);
+ DEBUG("hicnlight_prepare_route_create > %s", hc_request_state_str(state));
+
+ switch (state) {
+ case REQUEST_STATE_INIT:
+ if (hc_route_has_face(&object->route))
+ hc_request_set_state(current_request,
+ REQUEST_STATE_ROUTE_CREATE_FACE_CREATE);
+ else
+ hc_request_set_state(current_request, REQUEST_STATE_ROUTE_CREATE);
+ goto NEXT;
+
+ case REQUEST_STATE_ROUTE_CREATE_FACE_CREATE:
+ hc_request_set_state(current_request,
+ REQUEST_STATE_ROUTE_CREATE_FACE_CHECK);
+ INFO(">>>>>>subrequest create face");
+ return hicnlight_prepare_subrequest(
+ sock, request, ACTION_CREATE, OBJECT_TYPE_FACE,
+ (hc_object_t *)&object->route.face, buffer);
+
+ case REQUEST_STATE_ROUTE_CREATE_FACE_CHECK:
+ if (!data) return -1;
+ int rc = hc_data_get_result(data);
+ if (rc < 0) return -1;
+
+ if (hc_data_get_size(data) != 1) return -1;
+
+ face_obj = hc_data_get_object(data, 0);
+ DEBUG("Created face id=%d", face_obj->face.id);
+ object->route.face_id = face_obj->face.id;
+
+ hc_request_set_state(current_request, REQUEST_STATE_ROUTE_CREATE);
+ goto NEXT;
+
+ /* Create route */
+ case REQUEST_STATE_ROUTE_CREATE:
+ /*
+ * Break recursion by directly calling hicnlight_prepare_generic on the
+ * initial request, that can now be executed since all prerequisites are
+ * validated.
+ */
+ hc_request_set_state(current_request, REQUEST_STATE_COMPLETE);
+ return hicnlight_prepare_generic(sock, request, buffer);
+
+ case REQUEST_STATE_COMPLETE:
+ hc_data_set_complete(data);
+ break;
+
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static int hicnlight_recv(hc_sock_t *sock) {
+ hc_sock_light_data_t *s = (hc_sock_light_data_t *)sock->data;
+ int rc;
+
+ /*
+ * This condition should be ensured to guarantee correct processing of
+ * messages. With TCP, we need at least a header as we will receive part of
+ * the stream. With UDP, we need the be able to receive the full datagram,
+ * otherwise the rest will be lost.
+ *
+ * Let's be sure to always be able to receive at least 1 JUMBO_MTU, which
+ * should be fine for al situations.
+ */
+ _ASSERT(RECV_BUFLEN - s->woff > JUMBO_MTU);
+
+ rc = (int)recv(s->fd, s->buf + s->woff, RECV_BUFLEN - s->woff, 0);
+ if (rc == 0) {
+ /* Connection has been closed */
+ return 0;
+ }
+ if (rc < 0) {
+ /*
+ * Let's not return 0 which currently means the socket has been closed
+ */
+ if (errno == EWOULDBLOCK) {
+ // XXX TODO ?if (hc_request_get_action(request) == ACTION_SUBSCRIBE)
+ // return 0;
+ return -1;
+ }
+ if (errno == EINTR) {
+ WARN("recv has been stopped by signal");
+ return -1;
+ }
+ perror("hc_sock_light_recv");
+ return -1;
+ }
+ DEBUG("Received rc=%ld bytes", rc);
+ s->woff += rc;
+
+ return rc;
+}
+
+/*
+ *
+ * @param [in] data - hc_data_t structure allocated for the request
+ *
+ * This function is the entry point for all requests, and from there we will
+ * decide whether
+ *
+ */
+static ssize_t hicnlight_prepare(hc_sock_t *sock, hc_request_t *request,
+ uint8_t **buffer) {
+ /* Dispatch to subrequest if any */
+ hc_request_t *current_request = hc_request_get_current(request);
+
+ // XXX when do we create data... once for every step
+ hc_action_t action = hc_request_get_action(current_request);
+ hc_object_type_t object_type = hc_request_get_object_type(current_request);
+ hc_object_t *object = hc_request_get_object(current_request);
+
+ static hc_object_t object_subscribe;
+
+ DEBUG("[hicnlight_prepare] %s %s", action_str(action),
+ object_type_str(object_type));
+
+ /*
+ * Here the request is in progress and we just need to iterate through the
+ * FSM, or complete it.
+ */
+ /*
+ * Specific treatment for
+ * CREATE/ROUTE with face
+ * SUBSCRIBE/(*)
+ * GET/(*)
+ * (*)/FACE
+ */
+
+ /*
+ * Special treatment for faces.
+ *
+ * This function will be called multiple times in order to process the
+ * complex request, involving several calls to the API. The process is
+ * responsible for going through the related state machine, and complete the
+ * request when appropriate.
+ */
+ if (object_type == OBJECT_TYPE_FACE)
+ return hicnlight_prepare_face(sock, request, buffer);
+
+ switch (action) {
+ case ACTION_CREATE:
+ switch (object_type) {
+ case OBJECT_TYPE_ROUTE:
+ /* Route might require face creation */
+ return hicnlight_prepare_route_create(sock, request, buffer);
+ case OBJECT_TYPE_CONNECTION:
+ /* Connection could have no corresponging listener, or no local info
+ * provided */
+ return hicnlight_prepare_connection_create(sock, request, buffer);
+ default:
+ break;
+ }
+ break;
+
+ case ACTION_GET:
+ return hicnlight_prepare_get(sock, request, buffer);
+
+ case ACTION_SUBSCRIBE:
+ /* Transform subscription queries */
+ memset(&object_subscribe, 0, sizeof(hc_object_t));
+ object->subscription.topics = topic_from_object_type(object_type);
+
+ hc_request_set(request, ACTION_CREATE, OBJECT_TYPE_SUBSCRIPTION, object);
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * Generic requests should complete after a single call to hicnlight_send,
+ * with *pdata = NULL. If *pdata is not NULL, that means the request has
+ * completed and we can close it.
+ * It is the responsability of each state machine to complete the request
+ * otherwise.
+ */
+#if 1
+ hc_data_t *data = hc_request_get_data(current_request);
+ if (data) {
+ hc_request_set_complete(current_request);
+ return 0;
+ }
+#endif
+
+ return hicnlight_prepare_generic(sock, request, buffer);
+}
+
+/*
+ * This function processes incoming data in the ring buffer. Multiple requests
+ * might be interleaves, including regular requests and notifications.
+ * Responses might arrive fragment over several read events, but our
+ * assumption is that fragments arrive consecutively and are not interleaves
+ * with fragments from other requests... otherwise we would have to way to
+ * reconstruct a message.
+ *
+ * count != 0 when an external process has added data to the ring buffer
+ * without updating indices
+ */
+static int hicnlight_process(hc_sock_t *sock, size_t count) {
+ hc_sock_light_data_t *s = (hc_sock_light_data_t *)sock->data;
+ int rc;
+
+ if (count > 0) s->woff += count;
+
+ /*
+ * We loop consuming messages until there is no more data in the ring
+ * buffer, or that we can find an entire message. Messages are received
+ * sequentially, and we keep track of incomplete requests in s->cur_request.
+ */
+ while (AVAILABLE(s) > 0) {
+ if (!s->got_header) {
+ rc = hicnlight_process_header(sock);
+ } else {
+ rc = hicnlight_process_payload(sock);
+ }
+ if (rc < 0) break;
+ }
+
+ if ((rc == -99) || (s->roff == s->woff)) {
+ /* Flush buffer */
+ s->woff = 0;
+ } else {
+ /* Clean up read data from buffer */
+ memmove(s->buf, s->buf + s->roff, AVAILABLE(s));
+ s->woff -= s->roff;
+ }
+ s->roff = 0;
+
+ return rc;
+}
+
+hc_sock_ops_t hc_sock_light = (hc_sock_ops_t) {
+ .create_data = (void *(*)(const char *))hc_sock_light_data_create,
+ .free_data = (void (*)(void *))hc_sock_light_data_free,
+ .get_fd = hicnlight_get_fd, .get_recv_buffer = hicnlight_get_recv_buffer,
+ .connect = hicnlight_connect, .disconnect = hicnlight_disconnect,
+ .prepare = hicnlight_prepare, .send = hicnlight_send, .recv = hicnlight_recv,
+ .process = hicnlight_process,
+#if 0
+ .object_vft = {
+ [OBJECT_TYPE_LISTENER] = HC_MODULE_OBJECT_OPS(hicnlight, listener),
+ [OBJECT_TYPE_CONNECTION] = HC_MODULE_OBJECT_OPS(hicnlight, connection),
+ [OBJECT_TYPE_FACE] = HC_MODULE_OBJECT_OPS_EMPTY,
+ [OBJECT_TYPE_PUNTING] = HC_MODULE_OBJECT_OPS_EMPTY,
+ [OBJECT_TYPE_CACHE] = HC_MODULE_OBJECT_OPS_EMPTY,
+ [OBJECT_TYPE_MAPME] = HC_MODULE_OBJECT_OPS_EMPTY,
+ [OBJECT_TYPE_WLDR] = HC_MODULE_OBJECT_OPS_EMPTY,
+ [OBJECT_TYPE_POLICY] = HC_MODULE_OBJECT_OPS_EMPTY,
+ [OBJECT_TYPE_ROUTE] = HC_MODULE_OBJECT_OPS(hicnlight, route),
+ [OBJECT_TYPE_STRATEGY] = HC_MODULE_OBJECT_OPS(hicnlight, strategy),
+ [OBJECT_TYPE_SUBSCRIPTION] = HC_MODULE_OBJECT_OPS(hicnlight, subscription),
+}
+#endif
+};
+
+size_t hc_light_object_size(hc_object_type_t object_type) {
+ hc_module_object_ops_t *vft = &hc_sock_light.object_vft[object_type];
+ if (!vft) return 0;
+ return vft->serialized_size;
+}
+
+ssize_t hc_light_command_serialize(hc_action_t action,
+ hc_object_type_t object_type,
+ hc_object_t *object, uint8_t *msg) {
+ hc_module_object_ops_t *vft = &hc_sock_light.object_vft[object_type];
+ if (!vft || !vft->serialize[action]) return 0;
+ return vft->serialize[action](object, msg);
+}
+
+// Public constructor
+
+int hc_sock_initialize_module(hc_sock_t *s) {
+ //
+ /*
+ * We do this because initialization in the static struct fails with
+ * 'initializer element is not constant'
+ */
+#if 1
+ hc_sock_light.object_vft[OBJECT_TYPE_LISTENER] =
+ hicnlight_listener_module_ops;
+ hc_sock_light.object_vft[OBJECT_TYPE_CONNECTION] =
+ hicnlight_connection_module_ops;
+ hc_sock_light.object_vft[OBJECT_TYPE_FACE] = HC_MODULE_OBJECT_OPS_EMPTY;
+ hc_sock_light.object_vft[OBJECT_TYPE_PUNTING] = HC_MODULE_OBJECT_OPS_EMPTY;
+ hc_sock_light.object_vft[OBJECT_TYPE_CACHE] = HC_MODULE_OBJECT_OPS_EMPTY;
+ hc_sock_light.object_vft[OBJECT_TYPE_MAPME] = HC_MODULE_OBJECT_OPS_EMPTY;
+ hc_sock_light.object_vft[OBJECT_TYPE_WLDR] = HC_MODULE_OBJECT_OPS_EMPTY;
+ hc_sock_light.object_vft[OBJECT_TYPE_POLICY] = HC_MODULE_OBJECT_OPS_EMPTY;
+ hc_sock_light.object_vft[OBJECT_TYPE_ROUTE] = hicnlight_route_module_ops;
+ hc_sock_light.object_vft[OBJECT_TYPE_STRATEGY] =
+ hicnlight_strategy_module_ops;
+ hc_sock_light.object_vft[OBJECT_TYPE_SUBSCRIPTION] =
+ hicnlight_subscription_module_ops;
+#endif
+
+ if (s) s->ops = hc_sock_light;
+ return 0;
+}
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light.h b/ctrl/libhicnctrl/src/modules/hicn_light.h
new file mode 100644
index 000000000..0bdcf0b30
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file modules/hicn_light.h
+ * \brief hicn-light module.
+ */
+
+#ifndef HICNCTRL_MODULES_HICN_LIGHT_H
+#define HICNCTRL_MODULES_HICN_LIGHT_H
+
+#include "hicn_light/base.h"
+
+typedef struct {
+ char *url;
+ int fd;
+
+ /* Send buffer */
+ hc_msg_t msg;
+
+ /* Partial receive buffer */
+ u8 buf[RECV_BUFLEN];
+ size_t roff; /**< Read offset */
+ size_t woff; /**< Write offset */
+
+ bool got_header;
+ /*
+ * Because received messages are potentially unbounded in size, we might not
+ * guarantee that we can store a full packet before processing it. We must
+ * implement a very simple state machine remembering the current parsing
+ * status in order to partially process the packet.
+ */
+ size_t remaining;
+ u32 send_id;
+
+ /* Next sequence number to be used for requests */
+ int seq;
+} hc_sock_light_data_t;
+
+extern hc_sock_light_data_t *hc_sock_light_data_create(const char *url);
+extern void hc_sock_light_data_free(hc_sock_light_data_t *data);
+
+ssize_t hc_light_command_serialize(hc_action_t action,
+ hc_object_type_t object_type,
+ hc_object_t *object, uint8_t *msg);
+
+#endif /* HICNCTRL_MODULES_HICN_LIGHT_H */
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/base.h b/ctrl/libhicnctrl/src/modules/hicn_light/base.h
new file mode 100644
index 000000000..fb6a68147
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/base.h
@@ -0,0 +1,60 @@
+#ifndef HICNCTRL_MODULES_HICNLIGHT_BASE_H
+#define HICNCTRL_MODULES_HICNLIGHT_BASE_H
+
+#include <hicn/ctrl/hicn-light.h>
+
+#if 1
+#ifdef __APPLE__
+#define RANDBYTE() (u8)(arc4random() & 0xFF)
+#else
+#define RANDBYTE() (u8)(random() & 0xFF)
+#endif
+#else
+#define RANDBYTE() (u8)(rand() & 0xFF)
+#endif
+
+#define foreach_hc_command \
+ _(connection_add) \
+ _(connection_remove) \
+ _(connection_list) \
+ _(listener_add) \
+ _(listener_remove) \
+ _(listener_list) \
+ _(route_add) \
+ _(route_remove) \
+ _(route_list) \
+ _(cache_set_store) \
+ _(cache_set_serve) \
+ _(cache_clear) \
+ _(cache_list) \
+ _(strategy_set) \
+ _(strategy_add_local_prefix) \
+ _(wldr_set) \
+ _(punting_add) \
+ _(mapme_activator) \
+ _(mapme_timing) \
+ _(subscription_add) \
+ _(subscription_remove)
+
+#if 0
+const char *command_type_str[] = {
+#define _(l, u) [COMMAND_TYPE_##u] = STRINGIZE(u),
+ foreach_command_type
+#undef _
+};
+#endif
+
+typedef union {
+#define _(x) cmd_##x##_t x;
+ foreach_hc_command
+#undef _
+} hc_msg_payload_t;
+
+typedef cmd_header_t hc_msg_header_t;
+
+typedef struct hc_msg_s {
+ hc_msg_header_t header;
+ hc_msg_payload_t payload;
+} hc_msg_t;
+
+#endif /* HICNCTRL_MODULES_HICNLIGHT_BASE_H */
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/cache.c b/ctrl/libhicnctrl/src/modules/hicn_light/cache.c
new file mode 100644
index 000000000..e085142d7
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/cache.c
@@ -0,0 +1,178 @@
+#include "cache.h"
+
+/* CACHE SET STORE */
+
+static int _hcng_cache_set_store_internal(hc_sock_t *socket, hc_cache_t *cache,
+ bool async) {
+#if 0
+ msg_cache_set_store_t msg = {
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_CACHE_SET_STORE,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ .activate = cache->store,
+ }};
+
+ hc_command_params_t params = {
+ .cmd = ACTION_STORE,
+ .cmd_id = COMMAND_TYPE_CACHE_SET_STORE,
+ .size_in = sizeof(cmd_cache_set_store_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
+ NULL, async);
+#endif
+ return 0; // XXX added
+}
+
+static int _hcng_cache_set_store(hc_sock_t *s, hc_cache_t *cache) {
+ return _hcng_cache_set_store_internal(s, cache, false);
+}
+
+static int _hcng_cache_set_store_async(hc_sock_t *s, hc_cache_t *cache) {
+ return _hcng_cache_set_store_internal(s, cache, true);
+}
+
+/* CACHE SET SERVE */
+
+static int _hcng_cache_set_serve_internal(hc_sock_t *socket, hc_cache_t *cache,
+ bool async) {
+#if 0
+ msg_cache_set_serve_t msg = {
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_CACHE_SET_SERVE,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ .activate = cache->serve,
+ }};
+
+ hc_command_params_t params = {
+ .cmd = ACTION_SERVE,
+ .cmd_id = COMMAND_TYPE_CACHE_SET_SERVE,
+ .size_in = sizeof(cmd_cache_set_serve_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
+ NULL, async);
+#endif
+ return 0; /// added
+}
+
+static int _hcng_cache_set_serve(hc_sock_t *s, hc_cache_t *cache) {
+ return _hcng_cache_set_serve_internal(s, cache, false);
+}
+
+static int _hcng_cache_set_serve_async(hc_sock_t *s, hc_cache_t *cache) {
+ return _hcng_cache_set_serve_internal(s, cache, true);
+}
+
+/* CACHE CLEAR */
+
+static int _hcng_cache_clear_internal(hc_sock_t *socket, hc_cache_t *cache,
+ bool async) {
+#if 0
+ msg_cache_clear_t msg = {.header = {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_CACHE_CLEAR,
+ .length = 1,
+ .seq_num = 0,
+ }};
+
+ hc_command_params_t params = {
+ .cmd = ACTION_CLEAR,
+ .cmd_id = COMMAND_TYPE_CACHE_CLEAR,
+ .size_in = sizeof(cmd_cache_clear_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
+ NULL, async);
+#endif
+ return 0; // XXX added
+}
+
+static int _hcng_cache_clear(hc_sock_t *s, hc_cache_t *cache) {
+ return _hcng_cache_clear_internal(s, cache, false);
+}
+
+/* CACHE PARSE */
+
+static int hc_cache_parse(void *in, hc_cache_info_t *cache_info) {
+ cmd_cache_list_reply_t *item = (cmd_cache_list_reply_t *)in;
+ *cache_info = (hc_cache_info_t){.store = item->store_in_cs,
+ .serve = item->serve_from_cs,
+ .cs_size = item->cs_size,
+ .num_stale_entries = item->num_stale_entries};
+
+ return 0;
+}
+
+/* CACHE LIST */
+
+static hc_result_t *_hcng_cache_list_serialize(hc_sock_t *socket,
+ hc_data_t **pdata, bool async) {
+ hc_result_t *res = malloc(sizeof(*res));
+ DEBUG("[hc_cache_list] async=%s", BOOLSTR(async));
+
+ msg_cache_list_t msg = {.header = {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_CACHE_LIST,
+ .length = 0,
+ .seq_num = 0,
+ }};
+
+ hc_command_params_t params = {
+ .cmd = ACTION_LIST,
+ .cmd_id = COMMAND_TYPE_CACHE_LIST,
+ .size_in = sizeof(cmd_cache_list_reply_t),
+ .size_out = sizeof(hc_cache_info_t),
+ .parse = (HC_PARSE)hc_cache_parse,
+ };
+
+ *res = (hc_result_t){
+ .msg =
+ (hc_msg_t){
+ .header = msg.header,
+ .payload.cache_list = msg.payload,
+ },
+ .params = params,
+ .async = async,
+ .success = true,
+ };
+ return res;
+}
+
+static int _hcng_cache_list_internal(hc_sock_t *socket, hc_data_t **pdata,
+ bool async) {
+#if 0
+ hc_result_t *result = _hcng_cache_list_serialize(socket, pdata, async);
+
+ int ret = INPUT_ERROR;
+ if (result->success) {
+ ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
+ sizeof(result->msg), &result->params, pdata,
+ result->async);
+ }
+
+ hc_result_free(result);
+ return ret;
+#endif
+ return 0; // XXX added
+}
+
+static int _hcng_cache_list(hc_sock_t *s, hc_data_t **pdata) {
+ return _hcng_cache_list_internal(s, pdata, false);
+}
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/connection.c b/ctrl/libhicnctrl/src/modules/hicn_light/connection.c
new file mode 100644
index 000000000..c7d06415e
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/connection.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 2022 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * 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 <assert.h>
+#include <stdint.h>
+
+#include <hicn/util/log.h>
+
+#include "base.h"
+#include "connection.h"
+#include "../../object_private.h"
+
+int hc_connection_to_local_listener(const hc_connection_t *connection,
+ hc_listener_t *listener) {
+ int rc;
+
+ face_type_t listener_type;
+ switch (connection->type) {
+ case FACE_TYPE_UDP:
+ listener_type = FACE_TYPE_UDP_LISTENER;
+ break;
+ case FACE_TYPE_TCP:
+ listener_type = FACE_TYPE_TCP_LISTENER;
+ break;
+ default:
+ return -1;
+ }
+
+ *listener = (hc_listener_t){
+ .id = ~0,
+ .type = listener_type,
+ .family = connection->family,
+ .local_addr = connection->local_addr,
+ .local_port = connection->local_port,
+ };
+ rc = snprintf(listener->name, SYMBOLIC_NAME_LEN, "lst%u",
+ RANDBYTE()); // generate name
+ if (rc >= SYMBOLIC_NAME_LEN)
+ WARN(
+ "[hc_connection_to_local_listener] Unexpected truncation of "
+ "symbolic name string");
+ rc = snprintf(listener->interface_name, INTERFACE_LEN, "%s",
+ connection->interface_name);
+ if (rc >= INTERFACE_LEN)
+ WARN(
+ "[hc_connection_to_local_listener] Unexpected truncation of "
+ "interface name string");
+
+ return 0;
+}
+
+/* CONNECTION PARSE */
+
+static int hicnlight_connection_parse(const uint8_t *buffer, size_t size,
+ hc_connection_t *connection) {
+ int rc;
+
+ if (size != sizeof(cmd_connection_list_item_t)) return -1;
+ cmd_connection_list_item_t *item = (cmd_connection_list_item_t *)buffer;
+
+ if (!IS_VALID_ID(item->id)) {
+ ERROR("[hc_connection_parse] Invalid id received");
+ return -1;
+ }
+
+ if (!IS_VALID_NAME(item->name)) {
+ ERROR("[hc_connection_parse] Invalid name received");
+ return -1;
+ }
+ if (!IS_VALID_INTERFACE_NAME(item->interface_name)) {
+ ERROR("[hc_connection_parse] Invalid interface_name received");
+ return -1;
+ }
+
+ if (!IS_VALID_TYPE(item->type)) {
+ ERROR("[hc_connection_parse] Invalid type received");
+ return -1;
+ }
+
+ if (!IS_VALID_FAMILY(item->family)) {
+ ERROR("[hc_connection_parse] Invalid family received");
+ return -1;
+ }
+
+ if (!IS_VALID_ADDRESS(item->local_address)) {
+ ERROR("[hc_connection_parse] Invalid address received");
+ return -1;
+ }
+
+ if (!IS_VALID_PORT(ntohs(item->local_port))) {
+ ERROR("[hc_connection_parse] Invalid port received");
+ return -1;
+ }
+
+ if (!IS_VALID_ADDRESS(item->remote_address)) {
+ ERROR("[hc_connection_parse] Invalid address received");
+ return -1;
+ }
+
+ if (!IS_VALID_PORT(ntohs(item->remote_port))) {
+ ERROR("[hc_connection_parse] Invalid port received");
+ return -1;
+ }
+
+ if (!IS_VALID_FACE_STATE(item->admin_state)) {
+ ERROR("[hc_connection_parse] Invalid admin_state received");
+ return -1;
+ }
+
+ // PRIORITY
+ // TAGS
+
+ if (!IS_VALID_FACE_STATE(item->state)) {
+ ERROR("[hc_connection_parse] Invalid state received");
+ return -1;
+ }
+
+ *connection = (hc_connection_t){
+ .id = item->id,
+ .type = (face_type_t)item->type,
+ .family = (int)item->family,
+ .local_addr = item->local_addr,
+ .local_port = ntohs(item->local_port),
+ .remote_addr = item->remote_addr,
+ .remote_port = ntohs(item->remote_port),
+ .admin_state = (face_state_t)item->admin_state,
+ .priority = item->priority,
+ .tags = item->tags,
+ .state = (face_state_t)item->state,
+ };
+ rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "%s", item->name);
+ if ((rc < 0) || (rc >= SYMBOLIC_NAME_LEN)) return -1;
+
+ rc = snprintf(connection->interface_name, INTERFACE_LEN, "%s",
+ item->interface_name);
+ if ((rc < 0) || (rc >= INTERFACE_LEN)) return -1;
+
+ if (hc_connection_validate(connection, false) < 0) return -1;
+ return 0;
+}
+
+int _hicnlight_connection_parse(const uint8_t *buffer, size_t size,
+ hc_object_t *object) {
+ return hicnlight_connection_parse(buffer, size, &object->connection);
+}
+
+/* CONNECTION CREATE */
+
+int hicnlight_connection_serialize_create(const hc_object_t *object,
+ uint8_t *packet) {
+ int rc;
+ const hc_connection_t *connection = &object->connection;
+
+ msg_connection_add_t *msg = (msg_connection_add_t *)packet;
+ *msg = (msg_connection_add_t){
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_CONNECTION_ADD,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ .remote_ip = connection->remote_addr,
+ .local_ip = connection->local_addr,
+ .remote_port = htons(connection->remote_port),
+ .local_port = htons(connection->local_port),
+ .family = (uint8_t)connection->family,
+ .type = (uint8_t)connection->type,
+ .admin_state = (uint8_t)connection->admin_state,
+ .__pad = 0,
+ .priority = connection->priority,
+ .tags = connection->tags,
+ }};
+
+ rc = snprintf(msg->payload.symbolic, SYMBOLIC_NAME_LEN, "%s",
+ connection->name);
+ if ((rc < 0) || (rc >= SYMBOLIC_NAME_LEN)) return -1;
+
+ return sizeof(msg_connection_add_t);
+}
+
+/* CONNECTION DELETE */
+
+int hicnlight_connection_serialize_delete(const hc_object_t *object,
+ uint8_t *packet) {
+ int rc;
+ const hc_connection_t *connection = &object->connection;
+
+ msg_connection_remove_t *msg = (msg_connection_remove_t *)packet;
+ *msg = (msg_connection_remove_t){
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_CONNECTION_REMOVE,
+ .length = 1,
+ .seq_num = 0,
+ },
+ };
+
+ if (connection->id) {
+ rc = snprintf(msg->payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d",
+ connection->id);
+ // XXX
+ if (rc >= SYMBOLIC_NAME_LEN)
+ WARN(
+ "[_hc_connection_delete] Unexpected truncation of symbolic name "
+ "string");
+ } else if (*connection->name) {
+ rc = snprintf(msg->payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
+ connection->name);
+ // XXX
+ if (rc >= SYMBOLIC_NAME_LEN)
+ WARN(
+ "[_hc_connection_delete] Unexpected truncation of symbolic name "
+ "string");
+#if 0
+ } else {
+ hc_connection_t *connection_found;
+ if (hc_connection_get(socket, connection, &connection_found) < 0)
+ return res;
+ if (!connection_found) return res;
+ rc = snprintf(payload->symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d",
+ connection_found->id);
+ // XXX
+ if (rc >= SYMBOLIC_NAME_LEN)
+ WARN(
+ "[_hc_connection_delete] Unexpected truncation of symbolic name "
+ "string");
+ free(connection_found);
+#endif
+ }
+
+ return sizeof(msg_connection_remove_t);
+}
+
+// XXX How to update a connection XXX
+// Key attributes are mandatory
+// Enum can be undefined
+// family UNSPEC
+// ip address NULL
+// port NULL
+// priority = int ????????? specific negative value == unspec
+// tags = bitmap ????????? 0xFFFFFF special value == unspec
+
+// u32 id; /* Kr. */
+// char name[SYMBOLIC_NAME_LEN]; /* K.w */
+// char interface_name[INTERFACE_LEN]; /* Kr. */
+//
+// netdevice_type_t netdevice_type; undefined
+// face_type_t type;
+// int family;
+// ip_address_t local_addr;
+// u16 local_port;
+// ip_address_t remote_addr;
+// u16 remote_port;
+// face_state_t admin_state;
+// uint32_t priority; /* .rw */
+// policy_tags_t tags; /* .rw */
+// face_state_t state; /* .r. */
+int hicnlight_connection_serialize_update(const hc_object_t *object,
+ uint8_t *packet) {
+ int rc;
+ const hc_connection_t *connection = &object->connection;
+
+ msg_connection_update_t *msg = (msg_connection_update_t *)packet;
+ *msg = (msg_connection_update_t){
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_CONNECTION_UPDATE,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ //.remote_ip = connection->remote_updater,
+ //.local_ip = connection->local_updater,
+ //.remote_port = htons(connection->remote_port),
+ //.local_port = htons(connection->local_port),
+ //.family = connection->family,
+ //.type = connection->type,
+ .admin_state = connection->admin_state,
+ .priority = connection->priority,
+ .tags = connection->tags,
+ }};
+
+ rc = snprintf(msg->payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
+ connection->name);
+ if ((rc < 0) || (rc >= SYMBOLIC_NAME_LEN)) return -1;
+
+ // snprintf(msg.payload.interface_name, INTERFACE_NAME_LEN, "%s",
+ // connection->interface_name);
+
+ return sizeof(msg_connection_update_t);
+}
+
+#if 0
+/* CONNECTION SET ADMIN STATE */
+
+static int _hicnlight_connection_set_admin_state_internal(
+ hc_sock_t *socket, const char *conn_id_or_name, face_state_t state,
+ bool async) {
+ int rc;
+ DEBUG(
+ "[hc_connection_set_admin_state] connection_id/name=%s admin_state=%s "
+ "async=%s",
+ conn_id_or_name, face_state_str(state), BOOLSTR(async));
+
+ struct {
+ cmd_header_t hdr;
+ cmd_connection_set_admin_state_t payload;
+ } msg = {
+ .hdr =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_CONNECTION_SET_ADMIN_STATE,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload =
+ {
+ .admin_state = state,
+ },
+ };
+ rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
+ conn_id_or_name);
+ if (rc >= SYMBOLIC_NAME_LEN)
+ WARN(
+ "[_hc_connection_set_admin_state] Unexpected truncation of symbolic "
+ "name string");
+
+ hc_command_params_t params = {
+ .cmd = ACTION_SET,
+ .cmd_id = COMMAND_TYPE_CONNECTION_SET_ADMIN_STATE,
+ .size_in = sizeof(cmd_connection_set_admin_state_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ return _hicnlight_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
+ NULL, async);
+}
+
+static int _hicnlight_connection_set_admin_state(hc_sock_t *s,
+ const char *conn_id_or_name,
+ face_state_t state) {
+ return _hicnlight_connection_set_admin_state_internal(s, conn_id_or_name, state,
+ false);
+}
+
+static int _hicnlight_connection_set_admin_state_async(hc_sock_t *s,
+ const char *conn_id_or_name,
+ face_state_t state) {
+ return _hicnlight_connection_set_admin_state_internal(s, conn_id_or_name, state,
+ true);
+}
+
+
+static int _hicnlight_connection_set_priority_internal(hc_sock_t *socket,
+ const char *conn_id_or_name,
+ uint32_t priority,
+ bool async) {
+ int rc;
+ DEBUG(
+ "[hc_connection_set_priority] connection_id/name=%s priority=%d "
+ "async=%s",
+ conn_id_or_name, priority, BOOLSTR(async));
+ struct {
+ cmd_header_t hdr;
+ cmd_connection_set_priority_t payload;
+ } msg = {
+ .hdr =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_CONNECTION_SET_PRIORITY,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload =
+ {
+ .priority = priority,
+ },
+ };
+ rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
+ conn_id_or_name);
+ if (rc >= SYMBOLIC_NAME_LEN)
+ WARN(
+ "[_hc_connection_set_priority] Unexpected truncation of symbolic "
+ "name "
+ "string");
+
+ hc_command_params_t params = {
+ .cmd = ACTION_SET,
+ .cmd_id = COMMAND_TYPE_CONNECTION_SET_PRIORITY,
+ .size_in = sizeof(cmd_connection_set_priority_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ return _hicnlight_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
+ NULL, async);
+}
+
+static int _hicnlight_connection_set_priority(hc_sock_t *s,
+ const char *conn_id_or_name,
+ uint32_t priority) {
+ return _hicnlight_connection_set_priority_internal(s, conn_id_or_name, priority,
+ false);
+}
+
+static int _hicnlight_connection_set_priority_async(hc_sock_t *s,
+ const char *conn_id_or_name,
+ uint32_t priority) {
+ return _hicnlight_connection_set_priority_internal(s, conn_id_or_name, priority,
+ true);
+}
+
+
+static int _hicnlight_connection_set_tags_internal(hc_sock_t *s,
+ const char *conn_id_or_name,
+ policy_tags_t tags, bool async) {
+ int rc;
+ DEBUG("[hc_connection_set_tags] connection_id/name=%s tags=%d async=%s",
+ conn_id_or_name, tags, BOOLSTR(async));
+ struct {
+ cmd_header_t hdr;
+ cmd_connection_set_tags_t payload;
+ } msg = {
+ .hdr =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_CONNECTION_SET_TAGS,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload =
+ {
+ .tags = tags,
+ },
+ };
+ rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
+ conn_id_or_name);
+ if (rc >= SYMBOLIC_NAME_LEN)
+ WARN(
+ "[_hc_connection_set_tags] Unexpected truncation of symbolic name "
+ "string");
+
+ hc_command_params_t params = {
+ .cmd = ACTION_SET,
+ .cmd_id = COMMAND_TYPE_CONNECTION_SET_TAGS,
+ .size_in = sizeof(cmd_connection_set_tags_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ return _hicnlight_execute_command(s, (hc_msg_t *)&msg, sizeof(msg), &params, NULL,
+ async);
+}
+
+static int _hicnlight_connection_set_tags(hc_sock_t *s, const char *conn_id_or_name,
+ policy_tags_t tags) {
+ return _hicnlight_connection_set_tags_internal(s, conn_id_or_name, tags, false);
+}
+
+static int _hicnlight_connection_set_tags_async(hc_sock_t *s,
+ const char *conn_id_or_name,
+ policy_tags_t tags) {
+ return _hicnlight_connection_set_tags_internal(s, conn_id_or_name, tags, true);
+}
+#endif
+
+/* CONNECTION LIST */
+
+int hicnlight_connection_serialize_list(const hc_object_t *object,
+ uint8_t *packet) {
+ msg_connection_list_t *msg = (msg_connection_list_t *)packet;
+ *msg = (msg_connection_list_t){.header = {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_CONNECTION_LIST,
+ .length = 0,
+ .seq_num = 0,
+ }};
+ return sizeof(msg_header_t); // Do not use msg_connection_list_t
+}
+
+DECLARE_MODULE_OBJECT_OPS(hicnlight, connection);
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/connection.h b/ctrl/libhicnctrl/src/modules/hicn_light/connection.h
new file mode 100644
index 000000000..77204e6b2
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/connection.h
@@ -0,0 +1,27 @@
+#ifndef HICNCTRL_MODULE_HICNLIGHT_CONNECTION_H
+#define HICNCTRL_MODULE_HICNLIGHT_CONNECTION_H
+
+#include "../../module.h"
+
+int hc_connection_to_local_listener(const hc_connection_t *connection,
+ hc_listener_t *listener);
+
+#if 1
+
+DECLARE_MODULE_OBJECT_OPS_H(hicnlight, connection);
+// extern const hc_module_object_ops_t hicnlight_connection_module_ops;
+
+#else
+
+int _hicnlight_connection_parse(const uint8_t *buffer, size_t size,
+ hc_object_t *object);
+
+int hicnlight_connection_serialize_create(const hc_object_t *object,
+ uint8_t *packet);
+int hicnlight_connection_serialize_delete(const hc_object_t *object,
+ uint8_t *packet);
+int hicnlight_connection_serialize_list(const hc_object_t *object,
+ uint8_t *packet);
+
+#endif
+#endif /* HICNCTRL_MODULE_HICNLIGHT_CONNECTION_H */
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/face.c b/ctrl/libhicnctrl/src/modules/hicn_light/face.c
new file mode 100644
index 000000000..0d9475420
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/face.c
@@ -0,0 +1,482 @@
+#include <hicn/ctrl/objects/listener.h>
+#include <hicn/util/log.h>
+
+#include "base.h"
+#include "face.h"
+
+int hc_face_from_connection(const hc_connection_t *connection,
+ hc_face_t *face) {
+ int rc;
+ switch (connection->type) {
+ case FACE_TYPE_TCP:
+ *face = (hc_face_t){
+ .id = connection->id,
+ .type = FACE_TYPE_TCP,
+ .family = connection->family,
+ .local_addr = connection->local_addr,
+ .local_port = connection->local_port,
+ .remote_addr = connection->remote_addr,
+ .remote_port = connection->remote_port,
+ .admin_state = connection->admin_state,
+ .state = connection->state,
+ .priority = connection->priority,
+ .tags = connection->tags,
+ };
+ break;
+ case FACE_TYPE_UDP:
+ *face = (hc_face_t){
+ .id = connection->id,
+ .type = FACE_TYPE_UDP,
+ .family = connection->family,
+ .local_addr = connection->local_addr,
+ .local_port = connection->local_port,
+ .remote_addr = connection->remote_addr,
+ .remote_port = connection->remote_port,
+ .admin_state = connection->admin_state,
+ .state = connection->state,
+ .priority = connection->priority,
+ .tags = connection->tags,
+ };
+ break;
+ case FACE_TYPE_HICN:
+ *face = (hc_face_t){
+ .id = connection->id,
+ .type = FACE_TYPE_HICN,
+ .family = connection->family,
+ .netdevice.index = NETDEVICE_UNDEFINED_INDEX, // XXX
+ .local_addr = connection->local_addr,
+ .remote_addr = connection->remote_addr,
+ .admin_state = connection->admin_state,
+ .state = connection->state,
+ .priority = connection->priority,
+ .tags = connection->tags,
+ };
+ break;
+ default:
+ return -1;
+ }
+ face->netdevice.name[0] = '\0';
+ face->netdevice.index = 0;
+ rc = snprintf(face->name, SYMBOLIC_NAME_LEN, "%s", connection->name);
+ if (rc >= SYMBOLIC_NAME_LEN)
+ WARN(
+ "[hc_connection_to_face] Unexpected truncation of symbolic name "
+ "string");
+ rc = snprintf(face->netdevice.name, INTERFACE_LEN, "%s",
+ connection->interface_name);
+ if (rc >= INTERFACE_LEN)
+ WARN(
+ "[hc_connection_to_face] Unexpected truncation of interface name "
+ "string");
+ netdevice_update_index(&face->netdevice);
+ return 0;
+}
+
+int hc_face_to_connection(const hc_face_t *face, hc_connection_t *connection,
+ bool generate_name) {
+ int rc;
+
+ switch (face->type) {
+ case FACE_TYPE_HICN:
+ *connection = (hc_connection_t){
+ .type = FACE_TYPE_HICN,
+ .family = face->family,
+ .local_addr = face->local_addr,
+ .local_port = 0,
+ .remote_addr = face->remote_addr,
+ .remote_port = 0,
+ .admin_state = face->admin_state,
+ .state = face->state,
+ .priority = face->priority,
+ .tags = face->tags,
+ };
+ rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "%s",
+ face->netdevice.name);
+ if (rc >= SYMBOLIC_NAME_LEN)
+ WARN(
+ "[hc_face_to_connection] Unexpected truncation of symbolic "
+ "name string");
+ break;
+ case FACE_TYPE_TCP:
+ *connection = (hc_connection_t){
+ .type = FACE_TYPE_TCP,
+ .family = face->family,
+ .local_addr = face->local_addr,
+ .local_port = face->local_port,
+ .remote_addr = face->remote_addr,
+ .remote_port = face->remote_port,
+ .admin_state = face->admin_state,
+ .state = face->state,
+ .priority = face->priority,
+ .tags = face->tags,
+ };
+ if (generate_name) {
+ rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "tcp%u", RANDBYTE());
+ if (rc >= SYMBOLIC_NAME_LEN)
+ WARN(
+ "[hc_face_to_connection] Unexpected truncation of "
+ "symbolic name string");
+ } else {
+ memset(connection->name, 0, SYMBOLIC_NAME_LEN);
+ }
+ break;
+ case FACE_TYPE_UDP:
+ *connection = (hc_connection_t){
+ .type = FACE_TYPE_UDP,
+ .family = face->family,
+ .local_addr = face->local_addr,
+ .local_port = face->local_port,
+ .remote_addr = face->remote_addr,
+ .remote_port = face->remote_port,
+ .admin_state = face->admin_state,
+ .state = face->state,
+ .priority = face->priority,
+ .tags = face->tags,
+ };
+ if (generate_name) {
+ rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "udp%u", RANDBYTE());
+ if (rc >= SYMBOLIC_NAME_LEN)
+ WARN(
+ "[hc_face_to_connection] Unexpected truncation of "
+ "symbolic name string");
+ } else {
+ memset(connection->name, 0, SYMBOLIC_NAME_LEN);
+ }
+ snprintf(connection->interface_name, INTERFACE_LEN, "%s",
+ face->netdevice.name);
+ break;
+ default:
+ return -1;
+ }
+
+ connection->id = face->id;
+ rc = snprintf(connection->interface_name, INTERFACE_LEN, "%s",
+ face->netdevice.name);
+ if (rc >= INTERFACE_LEN)
+ WARN(
+ "hc_face_to_connection] Unexpected truncation of interface name "
+ "string");
+
+ return 0;
+}
+
+int hc_face_to_listener(const hc_face_t *face, hc_listener_t *listener) {
+ switch (face->type) {
+ case FACE_TYPE_HICN_LISTENER:
+ break;
+ case FACE_TYPE_TCP_LISTENER:
+ break;
+ case FACE_TYPE_UDP_LISTENER:
+ break;
+ default:
+ return -1;
+ }
+ return -1; /* XXX Not implemented */
+}
+
+#if 0
+/*----------------------------------------------------------------------------*
+ * Face
+ *
+ * Face support is not directly available in hicn-light, but we can offer such
+ * an interface through a combination of listeners and connections. The code
+ * starts with some conversion functions between faces/listeners/connections.
+ *
+ * We also need to make sure that there always exist a (single) listener when
+ *a connection is created, and in the hICN face case, that there is a single
+ * connection attached to this listener.
+ *
+ *----------------------------------------------------------------------------*/
+
+/* FACE CREATE */
+
+static int _hcng_face_create(hc_sock_t *socket, hc_face_t *face) {
+#if 0
+ hc_listener_t listener;
+ hc_listener_t *listener_found;
+
+ hc_connection_t connection;
+ hc_connection_t *connection_found;
+
+ char face_s[MAXSZ_HC_FACE];
+ int rc = hc_face_snprintf(face_s, MAXSZ_HC_FACE, face);
+ if (rc >= MAXSZ_HC_FACE)
+ WARN("[hc_face_create] Unexpected truncation of face string");
+ DEBUG("[hc_face_create] face=%s", face_s);
+
+ switch (face->face.type) {
+ case FACE_TYPE_HICN:
+ case FACE_TYPE_TCP:
+ case FACE_TYPE_UDP:
+ if (hc_face_to_connection(face, &connection, true) < 0) {
+ ERROR("[hc_face_create] Could not convert face to connection.");
+ return -1;
+ }
+
+ /* Ensure we have a corresponding local listener */
+ if (hc_connection_to_local_listener(&connection, &listener) < 0) {
+ ERROR("[hc_face_create] Could not convert face to local listener.");
+ return -1;
+ }
+
+ if (_hcng_listener_get(socket, &listener, &listener_found) < 0) {
+ ERROR("[hc_face_create] Could not retrieve listener");
+ return -1;
+ }
+
+ if (!listener_found) {
+ /* We need to create the listener if it does not exist */
+ if (hc_listener_create(socket, &listener) < 0) {
+ ERROR("[hc_face_create] Could not create listener.");
+ free(listener_found);
+ return -1;
+ }
+ } else {
+ free(listener_found);
+ }
+
+ /* Create corresponding connection */
+ if (_hcng_connection_create(socket, &connection) < 0) {
+ ERROR("[hc_face_create] Could not create connection.");
+ return -1;
+ }
+
+ /*
+ * Once the connection is created, we need to list all connections
+ * and compare with the current one to find the created face ID.
+ */
+ if (_hcng_connection_get(socket, &connection, &connection_found) < 0) {
+ ERROR("[hc_face_create] Could not retrieve connection");
+ return -1;
+ }
+
+ if (!connection_found) {
+ ERROR("[hc_face_create] Could not find newly created connection.");
+ return -1;
+ }
+
+ face->id = connection_found->id;
+ free(connection_found);
+
+ break;
+
+ case FACE_TYPE_HICN_LISTENER:
+ case FACE_TYPE_TCP_LISTENER:
+ case FACE_TYPE_UDP_LISTENER:
+ if (hc_face_to_listener(face, &listener) < 0) {
+ ERROR("Could not convert face to listener.");
+ return -1;
+ }
+ if (hc_listener_create(socket, &listener) < 0) {
+ ERROR("[hc_face_create] Could not create listener.");
+ return -1;
+ }
+ break;
+ default:
+ ERROR("[hc_face_create] Unknwon face type.");
+
+ return -1;
+ };
+
+#endif
+ return 0;
+}
+
+static int _hcng_face_get(hc_sock_t *socket, hc_face_t *face,
+ hc_face_t **face_found) {
+#if 0
+ hc_listener_t listener;
+ hc_listener_t *listener_found;
+
+ hc_connection_t connection;
+ hc_connection_t *connection_found;
+
+ char face_s[MAXSZ_HC_FACE];
+ int rc = hc_face_snprintf(face_s, MAXSZ_HC_FACE, face);
+ if (rc >= MAXSZ_HC_FACE)
+ WARN("[hc_face_get] Unexpected truncation of face string");
+ DEBUG("[hc_face_get] face=%s", face_s);
+
+ switch (face->face.type) {
+ case FACE_TYPE_HICN:
+ case FACE_TYPE_TCP:
+ case FACE_TYPE_UDP:
+ if (hc_face_to_connection(face, &connection, false) < 0) return -1;
+ if (_hcng_connection_get(socket, &connection, &connection_found) < 0)
+ return -1;
+ if (!connection_found) {
+ *face_found = NULL;
+ return 0;
+ }
+ *face_found = malloc(sizeof(hc_face_t));
+ hc_connection_to_face(connection_found, *face_found);
+ free(connection_found);
+ break;
+
+ case FACE_TYPE_HICN_LISTENER:
+ case FACE_TYPE_TCP_LISTENER:
+ case FACE_TYPE_UDP_LISTENER:
+ if (hc_face_to_listener(face, &listener) < 0) return -1;
+ if (_hcng_listener_get(socket, &listener, &listener_found) < 0) return -1;
+ if (!listener_found) {
+ *face_found = NULL;
+ return 0;
+ }
+ *face_found = malloc(sizeof(hc_face_t));
+ hc_listener_to_face(listener_found, *face_found);
+ free(listener_found);
+ break;
+
+ default:
+ return -1;
+ }
+
+#endif
+ return 0;
+}
+
+/* FACE DELETE */
+
+static int _hcng_face_delete(hc_sock_t *socket, hc_face_t *face,
+ uint8_t delete_listener) {
+#if 0
+ char face_s[MAXSZ_HC_FACE];
+ int rc = hc_face_snprintf(face_s, MAXSZ_HC_FACE, face);
+ if (rc >= MAXSZ_HC_FACE)
+ WARN("[hc_face_delete] Unexpected truncation of face string");
+ DEBUG("[hc_face_delete] face=%s", face_s);
+
+ hc_connection_t connection;
+ if (hc_face_to_connection(face, &connection, false) < 0) {
+ ERROR("[hc_face_delete] Could not convert face to connection.");
+ return -1;
+ }
+
+ if (_hcng_connection_delete(socket, &connection) < 0) {
+ ERROR("[hc_face_delete] Error removing connection");
+ return -1;
+ }
+
+ if (!delete_listener) {
+ return 0;
+ }
+
+ /* If this is the last connection attached to the listener, remove it */
+
+ hc_data_t *connections;
+ hc_listener_t listener = {{0}};
+
+ /*
+ * Ensure we have a corresponding local listener
+ * NOTE: hc_face_to_listener is not appropriate
+ */
+ if (hc_connection_to_local_listener(&connection, &listener) < 0) {
+ ERROR("[hc_face_create] Could not convert face to local listener.");
+ return -1;
+ }
+#if 1
+ /*
+ * The name is generated to prepare listener creation, we need it to be
+ * empty for deletion. The id should not need to be reset though.
+ */
+ listener.id = 0;
+ memset(listener.name, 0, sizeof(listener.name));
+#endif
+ if (_hcng_connection_list(socket, &connections) < 0) {
+ ERROR("[hc_face_delete] Error getting the list of listeners");
+ return -1;
+ }
+
+ bool delete = true;
+ foreach_connection(c, connections) {
+ if ((ip_address_cmp(&c->local_addr, &listener.local_addr, c->family) ==
+ 0) &&
+ (c->local_port == listener.local_port) &&
+ (strcmp(c->interface_name, listener.interface_name) == 0)) {
+ delete = false;
+ }
+ }
+
+ if (delete) {
+ if (_hcng_listener_delete(socket, &listener) < 0) {
+ ERROR("[hc_face_delete] Error removing listener");
+ return -1;
+ }
+ }
+
+ hc_data_free(connections);
+
+#endif
+ return 0;
+}
+
+/* FACE LIST */
+
+static int _hcng_face_list(hc_sock_t *socket, hc_data_t **pdata) {
+#if 0
+ hc_data_t *connection_data;
+ hc_face_t face;
+
+ DEBUG("[hc_face_list]");
+
+ if (_hcng_connection_list(socket, &connection_data) < 0) {
+ ERROR("[hc_face_list] Could not list connections.");
+ return -1;
+ }
+
+ hc_data_t *face_data =
+ hc_data_create(sizeof(hc_connection_t), sizeof(hc_face_t), NULL);
+ foreach_connection(c, connection_data) {
+ if (hc_connection_to_face(c, &face) < 0) {
+ ERROR("[hc_face_list] Could not convert connection to face.");
+ goto ERR;
+ }
+ hc_data_push(face_data, &face);
+ }
+
+ *pdata = face_data;
+ hc_data_free(connection_data);
+ DEBUG("[hc_face_list] done");
+ return 0;
+
+ERR:
+ hc_data_free(connection_data);
+ DEBUG("[hc_face_list] error");
+#endif
+ return -1;
+}
+
+static int hc_connection_parse_to_face(void *in, hc_face_t *face) {
+ hc_connection_t connection;
+
+ if (hcng_connection_parse(in, &connection) < 0) {
+ ERROR("[hc_connection_parse_to_face] Could not parse connection");
+ return -1;
+ }
+
+ if (hc_connection_to_face(&connection, face) < 0) {
+ ERROR(
+ "[hc_connection_parse_to_face] Could not convert connection to "
+ "face.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int _hcng_face_set_admin_state(hc_sock_t *s, const char *conn_id_or_name,
+ face_state_t admin_state) {
+ return hc_connection_set_admin_state(s, conn_id_or_name, admin_state);
+}
+
+static int _hcng_face_set_priority(hc_sock_t *s, const char *conn_id_or_name,
+ uint32_t priority) {
+ return hc_connection_set_priority(s, conn_id_or_name, priority);
+}
+
+static int _hcng_face_set_tags(hc_sock_t *s, const char *conn_id_or_name,
+ policy_tags_t tags) {
+ return hc_connection_set_tags(s, conn_id_or_name, tags);
+}
+
+#endif
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/face.h b/ctrl/libhicnctrl/src/modules/hicn_light/face.h
new file mode 100644
index 000000000..9e1cd48c2
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/face.h
@@ -0,0 +1,14 @@
+#ifndef HICNCTRL_MODULE_HICNLIGHT_FACE
+#define HICNCTRL_MODULE_HICNLIGHT_FACE
+
+#include <hicn/ctrl/objects/connection.h>
+#include <hicn/ctrl/objects/face.h>
+
+int hc_face_from_connection(const hc_connection_t *connection, hc_face_t *face);
+
+int hc_face_to_connection(const hc_face_t *face, hc_connection_t *connection,
+ bool generate_name);
+
+int hc_face_to_listener(const hc_face_t *face, hc_listener_t *listener);
+
+#endif /* HICNCTRL_MODULES_HICNLIGHT_FACE */
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/listener.c b/ctrl/libhicnctrl/src/modules/hicn_light/listener.c
new file mode 100644
index 000000000..68d4b8fcd
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/listener.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2022 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * 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 <assert.h>
+#include <hicn/ctrl/api.h>
+#include <hicn/util/log.h>
+
+#include "base.h"
+#include "../../object_private.h"
+#include "listener.h"
+
+static int hicnlight_listener_parse(const u8 *buffer, size_t size,
+ hc_listener_t *listener) {
+ int rc;
+
+ if (size != sizeof(cmd_listener_list_item_t)) return -1;
+ cmd_listener_list_item_t *item = (cmd_listener_list_item_t *)buffer;
+
+ if (!IS_VALID_ADDRESS(item->local_address)) {
+ ERROR("[hc_listener_parse] Invalid address received");
+ return -1;
+ }
+ if (!IS_VALID_NAME(item->name)) {
+ ERROR("[hc_listener_parse] Invalid name received");
+ return -1;
+ }
+ if (!IS_VALID_INTERFACE_NAME(item->interface_name)) {
+ ERROR("[hc_listener_parse] Invalid interface_name received");
+ return -1;
+ }
+ if (!IS_VALID_ID(item->id)) {
+ ERROR("[hc_listener_parse] Invalid id received");
+ return -1;
+ }
+ if (!IS_VALID_PORT(ntohs(item->local_port))) {
+ ERROR("[hc_listener_parse] Invalid port received");
+ return -1;
+ }
+ if (!IS_VALID_FAMILY(item->family)) {
+ ERROR("[hc_listener_parse] Invalid family received");
+ return -1;
+ }
+ if (!IS_VALID_TYPE(item->type)) {
+ ERROR("[hc_listener_parse] Invalid type received");
+ return -1;
+ }
+ // if (!(IS_VALID_CONNECTION_TYPE(item->type)))
+ // return -1;
+
+ *listener = (hc_listener_t){
+ .id = item->id,
+ .type = (face_type_t)(item->type),
+ .family = (int)(item->family),
+ .local_addr =
+ item->local_addr, // UNION_CAST(item->local_addr, ip_address_t),
+ .local_port = ntohs(item->local_port),
+ };
+
+ rc = snprintf(listener->name, SYMBOLIC_NAME_LEN, "%s", item->name);
+ if ((rc < 0) || (rc >= SYMBOLIC_NAME_LEN)) return -1;
+
+ rc = snprintf(listener->interface_name, INTERFACE_LEN, "%s",
+ item->interface_name);
+ if ((rc < 0) || (rc >= INTERFACE_LEN)) return -1;
+
+ if (hc_listener_validate(listener, false) < 0) return -1;
+ return 0;
+}
+
+int _hicnlight_listener_parse(const uint8_t *buffer, size_t size,
+ hc_object_t *object) {
+ return hicnlight_listener_parse(buffer, size, &object->listener);
+}
+
+/* LISTENER CREATE */
+
+int hicnlight_listener_serialize_create(const hc_object_t *object,
+ uint8_t *packet) {
+ int rc;
+ const hc_listener_t *listener = &object->listener;
+
+ msg_listener_add_t *msg = (msg_listener_add_t *)packet;
+ *msg = (msg_listener_add_t){.header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_LISTENER_ADD,
+ .length = 1,
+ .seq_num = 0,
+ },
+
+ .payload = {
+ .address = listener->local_addr,
+ .port = htons(listener->local_port),
+ .family = (uint8_t)listener->family,
+ .type = (uint8_t)listener->type,
+ }};
+
+ rc = snprintf(msg->payload.symbolic, SYMBOLIC_NAME_LEN, "%s", listener->name);
+ if ((rc < 0) || (rc >= SYMBOLIC_NAME_LEN)) return -1;
+
+ rc = snprintf(msg->payload.interface_name, INTERFACE_LEN, "%s",
+ listener->interface_name);
+ if ((rc < 0) || (rc >= INTERFACE_LEN)) return -1;
+
+ return sizeof(msg_listener_add_t);
+}
+
+/* LISTENER DELETE */
+
+int hicnlight_listener_serialize_delete(const hc_object_t *object,
+ uint8_t *packet) {
+ int rc;
+ const hc_listener_t *listener = &object->listener;
+
+ msg_listener_remove_t *msg = (msg_listener_remove_t *)packet;
+ *msg = (msg_listener_remove_t){.header = {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_LISTENER_REMOVE,
+ .length = 1,
+ .seq_num = 0,
+ }};
+
+ if (listener->id) {
+ rc = snprintf(msg->payload.symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%d",
+ listener->id);
+ } else if (*listener->name) {
+ rc = snprintf(msg->payload.symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%s",
+ listener->name);
+ } else {
+ return -1;
+ }
+
+ // For now we only support delete by name or id
+#if 0
+ hc_listener_t *listener_found;
+ if (hc_listener_get(socket, listener, &listener_found) < 0) return -1;
+ if (!listener_found) return -1;
+ rc = snprintf(payload->symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%d",
+ listener_found->id);
+ free(listener_found);
+ }
+#endif
+
+ if ((rc < 0) || (rc >= SYMBOLIC_NAME_LEN)) return -1;
+
+ return sizeof(msg_listener_remove_t);
+}
+
+/* LISTENER LIST */
+
+int hicnlight_listener_serialize_list(const hc_object_t *object,
+ uint8_t *packet) {
+ msg_listener_list_t *msg = (msg_listener_list_t *)packet;
+ *msg = (msg_listener_list_t){.header = {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_LISTENER_LIST,
+ .length = 0,
+ .seq_num = 0,
+ }};
+
+ return sizeof(msg_header_t); // Do not use msg_listener_list_t
+}
+
+DECLARE_MODULE_OBJECT_OPS(hicnlight, listener);
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/listener.h b/ctrl/libhicnctrl/src/modules/hicn_light/listener.h
new file mode 100644
index 000000000..27ef8434d
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/listener.h
@@ -0,0 +1,21 @@
+#ifndef HICNCTRL_MODULE_HICNLIGHT_LISTENER_H
+#define HICNCTRL_MODULE_HICNLIGHT_LISTENER_H
+
+#include "../../module.h"
+
+#if 1
+DECLARE_MODULE_OBJECT_OPS_H(hicnlight, listener);
+#else
+
+int _hicnlight_listener_parse(const uint8_t *buffer, size_t size,
+ hc_object_t *object);
+
+int hicnlight_listener_serialize_create(const hc_object_t *object,
+ uint8_t *packet);
+int hicnlight_listener_serialize_delete(const hc_object_t *object,
+ uint8_t *packet);
+int hicnlight_listener_serialize_list(const hc_object_t *object,
+ uint8_t *packet);
+#endif
+
+#endif /* HICNCTRL_MODULE_HICNLIGHT_LISTENER_H */
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/mapme.c b/ctrl/libhicnctrl/src/modules/hicn_light/mapme.c
new file mode 100644
index 000000000..de75d82a8
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/mapme.c
@@ -0,0 +1,139 @@
+#include "mapme.h"
+
+static int _hcng_mapme_set(hc_sock_t *socket, int enabled) {
+#if 0
+ msg_mapme_enable_t msg = {.header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_MAPME_ENABLE,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ .activate = enabled,
+ }};
+
+ hc_command_params_t params = {
+ .cmd = ACTION_SET,
+ .cmd_id = COMMAND_TYPE_MAPME_ENABLE,
+ .size_in = sizeof(cmd_mapme_enable_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
+ NULL, false);
+#endif
+ return 0; // XXX added
+}
+
+static int _hcng_mapme_set_discovery(hc_sock_t *socket, int enabled) {
+#if 0
+ msg_mapme_enable_t msg = {
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_MAPME_SET_DISCOVERY,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ .activate = enabled,
+ }};
+
+ hc_command_params_t params = {
+ .cmd = ACTION_SET,
+ .cmd_id = COMMAND_TYPE_MAPME_SET_DISCOVERY,
+ .size_in = sizeof(cmd_mapme_set_discovery_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
+ NULL, false);
+#endif
+ return 0; // XXX added
+}
+
+static int _hcng_mapme_set_timescale(hc_sock_t *socket, uint32_t timescale) {
+#if 0
+ msg_mapme_set_timescale_t msg = {
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_MAPME_SET_TIMESCALE,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ .timePeriod = timescale,
+ }};
+
+ hc_command_params_t params = {
+ .cmd = ACTION_SET,
+ .cmd_id = COMMAND_TYPE_MAPME_SET_TIMESCALE,
+ .size_in = sizeof(cmd_mapme_set_timescale_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
+ NULL, false);
+#endif
+ return 0; // XXX added
+}
+
+static int _hcng_mapme_set_retx(hc_sock_t *socket, uint32_t timescale) {
+#if 0
+ msg_mapme_set_retx_t msg = {.header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_MAPME_SET_RETX,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ .timePeriod = timescale,
+ }};
+
+ hc_command_params_t params = {
+ .cmd = ACTION_SET,
+ .cmd_id = COMMAND_TYPE_MAPME_SET_RETX,
+ .size_in = sizeof(msg_mapme_set_retx_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
+ NULL, false);
+#endif
+ return 0; // XXX added
+}
+
+static int _hcng_mapme_send_update(hc_sock_t *socket, hc_mapme_t *mapme) {
+#if 0
+ if (!IS_VALID_FAMILY(mapme->family)) return -1;
+
+ msg_mapme_send_update_t msg = {
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_MAPME_SEND_UPDATE,
+ .length = 1,
+ .seq_num = 0,
+ },
+ };
+
+ hc_command_params_t params = {
+ .cmd = ACTION_UPDATE,
+ .cmd_id = COMMAND_TYPE_MAPME_SEND_UPDATE,
+ .size_in = sizeof(msg_mapme_send_update_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
+ NULL, false);
+#endif
+ return 0; // XXX added
+}
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/policy.c b/ctrl/libhicnctrl/src/modules/hicn_light/policy.c
new file mode 100644
index 000000000..d48ce014d
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/policy.c
@@ -0,0 +1,162 @@
+#include "policy.h"
+
+/* POLICY CREATE */
+
+static int _hcng_policy_create_internal(hc_sock_t *socket, hc_policy_t *policy,
+ bool async) {
+#if 0
+ if (!IS_VALID_FAMILY(policy->family)) return -1;
+
+ struct {
+ cmd_header_t hdr;
+ cmd_policy_add_t payload;
+ } msg = {.hdr =
+ {
+ .message_type = REQUEST_LIGHT,
+ COMMAND_TYPE_POLICY_ADD,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ .address = policy->remote_addr,
+ .family = policy->family,
+ .len = policy->len,
+ .policy = policy->policy,
+ }};
+
+ hc_command_params_t params = {
+ .cmd = ACTION_CREATE,
+ .cmd_id = COMMAND_TYPE_POLICY_ADD,
+ .size_in = sizeof(cmd_policy_add_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
+ NULL, async);
+#endif
+ return 0; // XXX added
+}
+
+static int _hcng_policy_create(hc_sock_t *s, hc_policy_t *policy) {
+ return _hcng_policy_create_internal(s, policy, false);
+}
+
+static int _hcng_policy_create_async(hc_sock_t *s, hc_policy_t *policy) {
+ return _hcng_policy_create_internal(s, policy, true);
+}
+
+/* POLICY DELETE */
+
+static int _hcng_policy_delete_internal(hc_sock_t *socket, hc_policy_t *policy,
+ bool async) {
+#if 0
+ if (!IS_VALID_FAMILY(policy->family)) return -1;
+
+ struct {
+ cmd_header_t hdr;
+ cmd_policy_remove_t payload;
+ } msg = {.hdr =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_POLICY_REMOVE,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ .address = policy->remote_addr,
+ .family = policy->family,
+ .len = policy->len,
+ }};
+
+ hc_command_params_t params = {
+ .cmd = ACTION_DELETE,
+ .cmd_id = COMMAND_TYPE_POLICY_REMOVE,
+ .size_in = sizeof(cmd_policy_remove_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
+ NULL, async);
+#endif
+ return 0; // XXX added
+}
+
+static int _hcng_policy_delete(hc_sock_t *s, hc_policy_t *policy) {
+ return _hcng_policy_delete_internal(s, policy, false);
+}
+
+static int _hcng_policy_delete_async(hc_sock_t *s, hc_policy_t *policy) {
+ return _hcng_policy_delete_internal(s, policy, true);
+}
+
+/* POLICY PARSE */
+
+static int hc_policy_parse(void *in, hc_policy_t *policy) {
+ hc_policy_t *item = (hc_policy_t *)in;
+
+ if (!IS_VALID_ADDRESS(item->address)) {
+ ERROR("[hc_policy_parse] Invalid address");
+ return -1;
+ }
+ if (!IS_VALID_FAMILY(item->family)) {
+ ERROR("[hc_policy_parse] Invalid family");
+ return -1;
+ }
+ if (!IS_VALID_PREFIX_LEN(item->len)) {
+ ERROR("[hc_policy_parse] Invalid len");
+ return -1;
+ }
+ if (!IS_VALID_POLICY(item->policy)) {
+ ERROR("[hc_policy_parse] Invalid policy");
+ return -1;
+ }
+
+ *policy = (hc_policy_t){
+ .family = item->family,
+ .remote_addr = item->remote_addr,
+ .len = item->len,
+ .policy = item->policy,
+ };
+ return 0;
+}
+
+/* POLICY LIST */
+
+static int _hcng_policy_list_internal(hc_sock_t *socket, hc_data_t **pdata,
+ bool async) {
+#if 0
+ struct {
+ cmd_header_t hdr;
+ } msg = {
+ .hdr =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_POLICY_LIST,
+ .length = 0,
+ .seq_num = 0,
+ },
+ };
+
+ hc_command_params_t params = {
+ .cmd = ACTION_LIST,
+ .cmd_id = COMMAND_TYPE_POLICY_LIST,
+ .size_in = sizeof(hc_policy_t),
+ .size_out = sizeof(hc_policy_t),
+ .parse = (HC_PARSE)hc_policy_parse,
+ };
+
+ return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
+ pdata, async);
+#endif
+ return 0; // XXX added
+}
+
+static int _hcng_policy_list(hc_sock_t *s, hc_data_t **pdata) {
+ return _hcng_policy_list_internal(s, pdata, false);
+}
+
+static int _hcng_policy_list_async(hc_sock_t *s, hc_data_t **pdata) {
+ return _hcng_policy_list_internal(s, pdata, true);
+}
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/punting.c b/ctrl/libhicnctrl/src/modules/hicn_light/punting.c
new file mode 100644
index 000000000..7886ff839
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/punting.c
@@ -0,0 +1,74 @@
+#include "punting.h"
+
+static int _hcng_punting_create_internal(hc_sock_t *socket,
+ hc_punting_t *punting, bool async) {
+#if 0
+ int rc;
+
+ if (hc_punting_validate(punting) < 0) return -1;
+
+ struct {
+ cmd_header_t hdr;
+ cmd_punting_add_t payload;
+ } msg = {.hdr =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_PUNTING_ADD,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ .address = punting->prefix,
+ .family = punting->family,
+ .len = punting->prefix_len,
+ }};
+ rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d",
+ punting->face_id);
+ if (rc >= SYMBOLIC_NAME_LEN)
+ WARN("[_hc_punting_create] Unexpected truncation of symbolic name string");
+
+ hc_command_params_t params = {
+ .cmd = ACTION_CREATE,
+ .cmd_id = COMMAND_TYPE_PUNTING_ADD,
+ .size_in = sizeof(cmd_punting_add_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
+ NULL, async);
+#endif
+ return 0; // XXX added
+}
+
+static int _hcng_punting_create(hc_sock_t *s, hc_punting_t *punting) {
+ return _hcng_punting_create_internal(s, punting, false);
+}
+
+static int _hcng_punting_create_async(hc_sock_t *s, hc_punting_t *punting) {
+ return _hcng_punting_create_internal(s, punting, true);
+}
+
+static int _hcng_punting_get(hc_sock_t *s, hc_punting_t *punting,
+ hc_punting_t **punting_found) {
+ ERROR("hc_punting_get not (yet) implemented.");
+ return -1;
+}
+
+static int _hcng_punting_delete(hc_sock_t *s, hc_punting_t *punting) {
+ ERROR("hc_punting_delete not (yet) implemented.");
+ return -1;
+}
+
+#if 0
+static int hc_punting_parse(void * in, hc_punting_t * punting)
+{
+ ERROR("hc_punting_parse not (yet) implemented.");
+ return -1;
+}
+#endif
+
+static int _hcng_punting_list(hc_sock_t *s, hc_data_t **pdata) {
+ ERROR("hc_punting_list not (yet) implemented.");
+ return -1;
+}
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/route.c b/ctrl/libhicnctrl/src/modules/hicn_light/route.c
new file mode 100644
index 000000000..1adfe4f36
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/route.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2021-2022 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * 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 modules/hicn_light/route.c
+ * \brief Implementation of route object VFT for hicn_light.
+ */
+
+#include <assert.h>
+#include <hicn/ctrl/api.h>
+#include <hicn/util/log.h>
+#include "base.h"
+#include "route.h"
+#include <hicn/ctrl/hicn-light.h>
+
+#include "../../object_private.h"
+
+static int hicnlight_route_parse(const uint8_t *buffer, size_t size,
+ hc_route_t *route) {
+ if (size != sizeof(cmd_route_list_item_t)) return -1;
+ cmd_route_list_item_t *item = (cmd_route_list_item_t *)buffer;
+
+ if (!IS_VALID_NAME(item->face_name)) {
+ ERROR("[hc_connection_parse] Invalid face_name received");
+ return -1;
+ }
+
+ if (!IS_VALID_ID(item->face_id)) {
+ ERROR("[hc_connection_parse] Invalid face_id received");
+ return -1;
+ }
+
+ if (!IS_VALID_FAMILY(item->family)) {
+ ERROR("[hc_listener_parse] Invalid family received");
+ return -1;
+ }
+
+ if (!IS_VALID_ADDRESS(item->remote_addr)) {
+ ERROR("[hc_connection_parse] Invalid address received");
+ return -1;
+ }
+
+ // LEN
+ // COST
+
+ *route = (hc_route_t){
+ .face_name = "", /* This is not reported back */
+ .face_id = item->face_id,
+ .family = (int)(item->family),
+ .remote_addr = item->remote_addr,
+ .len = item->len,
+ .cost = item->cost,
+ };
+
+ if (hc_route_validate(route, false) < 0) return -1;
+ return 0;
+}
+
+int _hicnlight_route_parse(const uint8_t *buffer, size_t size,
+ hc_object_t *object) {
+ return hicnlight_route_parse(buffer, size, &object->route);
+}
+
+/* ROUTE CREATE */
+
+int hicnlight_route_serialize_create(const hc_object_t *object,
+ uint8_t *packet) {
+ const hc_route_t *route = &object->route;
+ int rc;
+
+ msg_route_add_t *msg = (msg_route_add_t *)packet;
+ *msg = (msg_route_add_t){.header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_ROUTE_ADD,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ .address = route->remote_addr,
+ .cost = route->cost,
+ .family = route->family,
+ .len = route->len,
+ }};
+
+ /*
+ * The route commands expects the ID or name as part of the
+ * symbolic_or_connid attribute.
+ */
+ if (route->face_name[0] != '\0') {
+ rc = snprintf(msg->payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
+ route->face_name);
+ } else {
+ rc = snprintf(msg->payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d",
+ route->face_id);
+ }
+
+ if ((rc < 0) || (rc >= SYMBOLIC_NAME_LEN)) return -1;
+
+ return sizeof(msg_route_add_t);
+}
+
+/* ROUTE DELETE */
+
+int hicnlight_route_serialize_delete(const hc_object_t *object,
+ uint8_t *packet) {
+ const hc_route_t *route = &object->route;
+ int rc;
+
+ msg_route_remove_t *msg = (msg_route_remove_t *)packet;
+ memset(msg, 0, sizeof(msg_route_remove_t));
+ *msg = (msg_route_remove_t){.header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_ROUTE_REMOVE,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ .family = (uint8_t)route->family,
+ .len = route->len,
+ }};
+
+ /*
+ * Direct copy as part of the previous assignment does not work correctly...
+ * to be investigated
+ */
+ memcpy(&msg->payload.address, &route->remote_addr, sizeof(hicn_ip_address_t));
+
+ /*
+ * The route commands expects the ID or name as part of the
+ * symbolic_or_connid attribute.
+ */
+ if (route->face_name[0] != '\0') {
+ rc = snprintf(msg->payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
+ route->face_name);
+ } else {
+ rc = snprintf(msg->payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d",
+ route->face_id);
+ }
+
+ if ((rc < 0) || (rc >= SYMBOLIC_NAME_LEN)) return -1;
+
+ return sizeof(msg_route_remove_t);
+}
+
+/* ROUTE LIST */
+
+int hicnlight_route_serialize_list(const hc_object_t *object, uint8_t *packet) {
+ msg_route_list_t *msg = (msg_route_list_t *)packet;
+ *msg = (msg_route_list_t){.header = {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_ROUTE_LIST,
+ .length = 0,
+ .seq_num = 0,
+ }};
+
+ return sizeof(msg_header_t); // Do not use msg_route_list_t
+}
+
+DECLARE_MODULE_OBJECT_OPS(hicnlight, route);
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/route.h b/ctrl/libhicnctrl/src/modules/hicn_light/route.h
new file mode 100644
index 000000000..e86e8b8c3
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/route.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file modules/hicn_light/route.h
+ * \brief route object VFT for hicn_light.
+ */
+
+#ifndef HICNCTRL_MODULE_HICNLIGHT_ROUTE_H
+#define HICNCTRL_MODULE_HICNLIGHT_ROUTE_H
+
+#include "../../module.h"
+
+#if 1
+
+DECLARE_MODULE_OBJECT_OPS_H(hicnlight, route);
+
+#else
+
+int _hicnlight_route_parse(const uint8_t *buffer, size_t size,
+ hc_object_t *object);
+int hicnlight_route_serialize_create(const hc_object_t *object,
+ uint8_t *packet);
+int hicnlight_route_serialize_delete(const hc_object_t *object,
+ uint8_t *packet);
+int hicnlight_route_serialize_list(const hc_object_t *object, uint8_t *packet);
+
+#endif
+
+#endif /* HICNCTRL_MODULE_HICNLIGHT_ROUTE_H */
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/stats.h b/ctrl/libhicnctrl/src/modules/hicn_light/stats.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/stats.h
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/strategy.c b/ctrl/libhicnctrl/src/modules/hicn_light/strategy.c
new file mode 100644
index 000000000..35e241f3e
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/strategy.c
@@ -0,0 +1,205 @@
+#include <assert.h>
+#include "strategy.h"
+
+#include <hicn/ctrl/hicn-light.h>
+
+static int hicnlight_strategy_parse(const u8 *buffer, size_t size,
+ hc_strategy_t *strategy) {
+ return -1;
+}
+
+int _hicnlight_strategy_parse(const uint8_t *buffer, size_t size,
+ hc_object_t *object) {
+ return hicnlight_strategy_parse(buffer, size, &object->strategy);
+}
+
+int hicnlight_strategy_serialize_create(const hc_object_t *object,
+ uint8_t *packet) {
+ return -1;
+}
+
+int hicnlight_strategy_serialize_delete(const hc_object_t *object,
+ uint8_t *packet) {
+ return -1;
+}
+
+int hicnlight_strategy_serialize_list(const hc_object_t *object,
+ uint8_t *packet) {
+ assert(!object);
+ return -1;
+}
+#if 0
+// per prefix
+static hc_result_t *_strategy_set_serialize(hc_sock_t *socket,
+ hc_strategy_t *strategy) {
+ return -1;
+ hc_result_t *res = malloc(sizeof(*res));
+ char strategy_s[MAXSZ_HC_STRATEGY];
+ strncpy(strategy->name, strategy_str(strategy->type),
+ MAXSZ_STRATEGY_NAME - 1);
+
+ int rc = hc_strategy_snprintf(strategy_s, MAXSZ_HC_STRATEGY, strategy);
+ if (rc >= MAXSZ_HC_STRATEGY)
+ WARN("[hicnlight_strategy_create] Unexpected truncation of strategy string");
+ DEBUG("[hicnlight_strategy_create] strategy=%s", strategy_s);
+
+ if (!IS_VALID_FAMILY(strategy->family) ||
+ !IS_VALID_STRATEGY_TYPE(strategy->type)) {
+ res->success = false;
+ return res;
+ }
+
+ msg_strategy_set_t msg = {.header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_STRATEGY_SET,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ .address = strategy->address,
+ .family = strategy->family,
+ .len = strategy->len,
+ .type = strategy->type,
+ }};
+
+ hc_command_params_t params = {
+ .cmd = ACTION_SET,
+ .cmd_id = COMMAND_TYPE_STRATEGY_SET,
+ .size_in = sizeof(cmd_strategy_set_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ *res = (hc_result_t){
+ .msg =
+ (hc_msg_t){
+ .header = msg.header,
+ .payload.strategy_set = msg.payload,
+ },
+ .params = params,
+ .async = false,
+ .success = true,
+ };
+ return res;
+}
+#endif
+
+#if 0
+static hc_result_t *_strategy_add_local_prefix_serialize(
+ hc_sock_t *socket, hc_strategy_t *strategy) {
+ hc_result_t *res = malloc(sizeof(*res));
+ char strategy_s[MAXSZ_HC_STRATEGY];
+ strncpy(strategy->name, strategy_str(strategy->type),
+ MAXSZ_STRATEGY_NAME - 1);
+
+ int rc = hc_strategy_snprintf(strategy_s, MAXSZ_HC_STRATEGY, strategy);
+ if (rc >= MAXSZ_HC_STRATEGY)
+ WARN("[hicnlight_strategy_create] Unexpected truncation of strategy string");
+ DEBUG("[hicnlight_strategy_create] strategy=%s", strategy_s);
+
+ if (!IS_VALID_FAMILY(strategy->family) ||
+ !IS_VALID_STRATEGY_TYPE(strategy->type) ||
+ !IS_VALID_FAMILY(strategy->local_family)) {
+ res->success = false;
+ return res;
+ }
+
+ msg_strategy_add_local_prefix_t msg = {
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_STRATEGY_ADD_LOCAL_PREFIX,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {
+ .type = strategy->type,
+ .address = strategy->address,
+ .family = strategy->family,
+ .len = strategy->len,
+ .local_address = strategy->local_address,
+ .local_family = strategy->local_family,
+ .local_len = strategy->local_len,
+ }};
+
+ hc_command_params_t params = {
+ .cmd = ACTION_SET,
+ .cmd_id = COMMAND_TYPE_STRATEGY_ADD_LOCAL_PREFIX,
+ .size_in = sizeof(cmd_strategy_add_local_prefix_t),
+ .size_out = 0,
+ .parse = NULL,
+ };
+
+ *res = (hc_result_t){
+ .msg =
+ (hc_msg_t){
+ .header = msg.header,
+ .payload.strategy_add_local_prefix = msg.payload,
+ },
+ .params = params,
+ .async = false,
+ .success = true,
+ };
+ return res;
+}
+#endif
+
+#if 0
+static int hicnlight_strategy_set(hc_sock_t *socket, hc_strategy_t *strategy) {
+ hc_result_t *result = _strategy_set_serialize(socket, strategy);
+
+ int ret = INPUT_ERROR;
+ if (result->success) {
+ ret = hicnlight_execute_command(socket, (hc_msg_t *)&result->msg,
+ sizeof(result->msg), &result->params, NULL,
+ result->async);
+ }
+
+ hc_result_free(result);
+ return ret;
+ return -1; // XXX added
+}
+
+static int hicnlight_strategy_add_local_prefix(hc_sock_t *socket,
+ hc_strategy_t *strategy) {
+ hc_result_t *result = _strategy_add_local_prefix_serialize(socket, strategy);
+
+ int ret = INPUT_ERROR;
+ if (result->success) {
+ ret = hicnlight_execute_command(socket, (hc_msg_t *)&result->msg,
+ sizeof(result->msg), &result->params, NULL,
+ result->async);
+ }
+
+ hc_result_free(result);
+ return ret;
+ return -1; // XXX added
+}
+
+/* How to retrieve that from the forwarder ? */
+static const char *strategies[] = {
+ "random",
+ "load_balancer",
+};
+
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array))
+
+static int hicnlight_strategy_list(hc_sock_t *s, hc_data_t **data) {
+ int rc;
+
+ *data = hc_data_create(0, sizeof(hc_strategy_t), NULL);
+
+ for (unsigned i = 0; i < ARRAY_SIZE(strategies); i++) {
+ hc_strategy_t *strategy = (hc_strategy_t *)hc_data_get_next(*data);
+ if (!strategy) return -1;
+ rc = snprintf(strategy->name, MAXSZ_STRATEGY_NAME, "%s", strategies[i]);
+ if (rc >= MAXSZ_STRATEGY_NAME)
+ WARN("[hc_strategy_list] Unexpected truncation of strategy name string");
+ (*data)->size++;
+ }
+ return -1;
+}
+#endif
+
+DECLARE_MODULE_OBJECT_OPS(hicnlight, strategy);
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/strategy.h b/ctrl/libhicnctrl/src/modules/hicn_light/strategy.h
new file mode 100644
index 000000000..6b1933960
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/strategy.h
@@ -0,0 +1,24 @@
+#ifndef HICNCTRL_MODULE_HICNLIGHT_STRATEGY_H
+#define HICNCTRL_MODULE_HICNLIGHT_STRATEGY_H
+
+#include "../../module.h"
+
+#if 1
+
+DECLARE_MODULE_OBJECT_OPS_H(hicnlight, strategy);
+
+int _hicnlight_strategy_parse(const uint8_t *buffer, size_t size,
+ hc_object_t *object);
+
+int hicnlight_strategy_serialize_create(const hc_object_t *object,
+ uint8_t *packet);
+
+int hicnlight_strategy_serialize_delete(const hc_object_t *object,
+ uint8_t *packet);
+
+int hicnlight_strategy_serialize_list(const hc_object_t *object,
+ uint8_t *packet);
+
+#endif
+
+#endif /* HICNCTRL_MODULE_HICNLIGHT_STRATEGY_H */
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/subscription.c b/ctrl/libhicnctrl/src/modules/hicn_light/subscription.c
new file mode 100644
index 000000000..d00055e89
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/subscription.c
@@ -0,0 +1,66 @@
+#include <assert.h>
+#include <hicn/ctrl/api.h>
+#include <hicn/util/log.h>
+
+#include "base.h"
+#include "../../object_private.h"
+#include "subscription.h"
+
+static int hicnlight_subscription_parse(const u8 *buffer, size_t size,
+ hc_subscription_t *subscription) {
+ /* We should never have to parse subscriptions */
+ return -1;
+}
+
+int _hicnlight_subscription_parse(const uint8_t *buffer, size_t size,
+ hc_object_t *object) {
+ return hicnlight_subscription_parse(buffer, size, &object->subscription);
+}
+
+/* SUBSCRIPTION CREATE */
+
+int hicnlight_subscription_serialize_create(const hc_object_t *object,
+ uint8_t *packet) {
+ const hc_subscription_t *subscription = &object->subscription;
+
+ msg_subscription_add_t *msg = (msg_subscription_add_t *)packet;
+ *msg = (msg_subscription_add_t){
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_SUBSCRIPTION_ADD,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {.topics = subscription->topics}};
+
+ return sizeof(msg_subscription_add_t);
+}
+
+/* SUBSCRIPTION DELETE */
+
+int hicnlight_subscription_serialize_delete(const hc_object_t *object,
+ uint8_t *packet) {
+ const hc_subscription_t *subscription = &object->subscription;
+
+ msg_subscription_remove_t *msg = (msg_subscription_remove_t *)packet;
+ *msg = (msg_subscription_remove_t){
+ .header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_SUBSCRIPTION_REMOVE,
+ .length = 1,
+ .seq_num = 0,
+ },
+ .payload = {.topics = subscription->topics}};
+
+ return sizeof(msg_subscription_remove_t);
+}
+
+int hicnlight_subscription_serialize_list(const hc_object_t *object,
+ uint8_t *packet) {
+ assert(!object);
+ return -1;
+}
+
+DECLARE_MODULE_OBJECT_OPS(hicnlight, subscription);
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/subscription.h b/ctrl/libhicnctrl/src/modules/hicn_light/subscription.h
new file mode 100644
index 000000000..a4edf556b
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/subscription.h
@@ -0,0 +1,26 @@
+#ifndef HICNCTRL_MODULE_HICNLIGHT_SUBSCRIPTION_H
+#define HICNCTRL_MODULE_HICNLIGHT_SUBSCRIPTION_H
+
+#include "../../module.h"
+
+#if 1
+
+DECLARE_MODULE_OBJECT_OPS_H(hicnlight, subscription);
+
+#else
+
+int _hicnlight_subscription_parse(const uint8_t *buffer, size_t size,
+ hc_object_t *object);
+
+int hicnlight_subscription_serialize_create(const hc_object_t *object,
+ uint8_t *packet);
+
+int hicnlight_subscription_serialize_delete(const hc_object_t *object,
+ uint8_t *packet);
+
+int hicnlight_subscription_serialize_list(const hc_object_t *object,
+ uint8_t *packet);
+
+#endif
+
+#endif /* HICNCTRL_MODULE_HICNLIGHT_SUBSCRIPTION_H */
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/wldr.c b/ctrl/libhicnctrl/src/modules/hicn_light/wldr.c
new file mode 100644
index 000000000..7d1812ab2
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/wldr.c
@@ -0,0 +1,3 @@
+#include "wldr.h"
+
+static int _hcng_wldr_set(hc_sock_t *s /* XXX */) { return 0; }
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light_common.h b/ctrl/libhicnctrl/src/modules/hicn_light_common.h
deleted file mode 100644
index d24b5bb2d..000000000
--- a/ctrl/libhicnctrl/src/modules/hicn_light_common.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef HICNCTRL_HICN_LIGHT_COMMON
-#define HICNCTRL_HICN_LIGHT_COMMON
-
-#include <assert.h> // assert
-
-#include <hicn/util/khash.h>
-#include "api_private.h"
-
-#define PORT 9695
-
-#define BOOLSTR(x) ((x) ? "true" : "false")
-
-/*
- * Internal state associated to a pending request
- */
-typedef struct {
- int seq;
- hc_data_t *data;
- int (*parse)(const u8 *src, u8 *dst);
-} hc_sock_request_t;
-
-/**
- * Messages to the forwarder might be multiplexed thanks to the seqNum fields in
- * the header_control_message structure. The forwarder simply answers back the
- * original sequence number. We maintain a map of such sequence number to
- * outgoing queries so that replied can be demultiplexed and treated
- * appropriately.
- */
-KHASH_MAP_INIT_INT(sock_map, hc_sock_request_t *);
-
-struct hc_sock_light_s {
- /* This must be the first element of the struct */
- hc_sock_t vft;
-
- char *url;
- int fd;
-
- /* Partial receive buffer */
- u8 buf[RECV_BUFLEN];
- size_t roff; /**< Read offset */
- size_t woff; /**< Write offset */
-
- /*
- * Because received messages are potentially unbounded in size, we might not
- * guarantee that we can store a full packet before processing it. We must
- * implement a very simple state machine remembering the current parsing
- * status in order to partially process the packet.
- */
- size_t remaining;
- u32 send_id;
-
- /* Next sequence number to be used for requests */
- int seq;
-
- /* Request being parsed (NULL if none) */
- hc_sock_request_t *cur_request;
-
- bool async;
- kh_sock_map_t *map;
-};
-
-typedef struct hc_sock_light_s hc_sock_light_t;
-
-#define TO_HC_SOCK_LIGHT(s) (hc_sock_light_t *)(s)
-
-hc_sock_request_t *hc_sock_request_create(int seq, hc_data_t *data,
- HC_PARSE parse);
-
-void hc_sock_light_request_free(hc_sock_request_t *request);
-
-/*
- * list was working with all seq set to 0, but it seems hicnLightControl uses
- * 1, and replies with the same seqno
- */
-#define HICN_CTRL_SEND_SEQ_INIT 1
-#define HICN_CTRL_RECV_SEQ_INIT 1
-
-#define MAX(x, y) ((x > y) ? x : y)
-
-static const struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT;
-
-#endif /* HICNCTRL_HICN_LIGHT_COMMON */
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light_ng_api.c b/ctrl/libhicnctrl/src/modules/hicn_light_ng_api.c
deleted file mode 100644
index 488b2edbf..000000000
--- a/ctrl/libhicnctrl/src/modules/hicn_light_ng_api.c
+++ /dev/null
@@ -1,3238 +0,0 @@
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * \file api.c
- * \brief Implementation of hICN control library API
- */
-
-#include <assert.h> // assert
-#include <fcntl.h> // fcntl
-#include <stdbool.h>
-#include <stdio.h> // snprintf
-#include <string.h> // memmove, strcasecmp
-#include <sys/socket.h> // socket
-#include <sys/types.h> // getpid
-#include <unistd.h> // close, fcntl
-#include <unistd.h> // getpid
-
-#include "api_private.h"
-#ifdef __linux__
-#include <sys/syscall.h>
-#define gettid() syscall(SYS_gettid)
-#endif /* __linux__ */
-#include <hicn/ctrl/hicn-light-ng.h>
-#include <strings.h>
-
-#include "hicn_light_common.h"
-#include <hicn/util/sstrncpy.h>
-
-#pragma GCC diagnostic ignored "-Warray-bounds"
-
-#if 0
-#ifdef __APPLE__
-#define RANDBYTE() (u8)(arc4random() & 0xFF)
-#else
-#define RANDBYTE() (u8)(random() & 0xFF)
-#endif
-#endif
-#define RANDBYTE() (u8)(rand() & 0xFF)
-
-/**
- * \brief Defines the default size for the allocated data arrays holding the
- * results of API calls.
- *
- * This size should not be too small to avoid wasting memoyy, but also not too
- * big to avoid unnecessary realloc's. Later on this size is doubled at each
- * reallocation.
- */
-#define DEFAULT_SIZE_LOG 3
-
-#define connection_state_to_face_state(x) ((face_state_t)(x))
-#define face_state_to_connection_state(x) ((hc_connection_state_t)(x))
-
-/******************************************************************************
- * Message helper types and aliases
- ******************************************************************************/
-
-#define foreach_hc_command \
- _(connection_add) \
- _(connection_remove) \
- _(connection_list) \
- _(listener_add) \
- _(listener_remove) \
- _(listener_list) \
- _(route_add) \
- _(route_remove) \
- _(route_list) \
- _(cache_set_store) \
- _(cache_set_serve) \
- _(cache_clear) \
- _(cache_list) \
- _(strategy_set) \
- _(strategy_add_local_prefix) \
- _(wldr_set) \
- _(punting_add) \
- _(mapme_activator) \
- _(mapme_timing) \
- _(subscription_add) \
- _(subscription_remove) \
- _(stats_get) \
- _(stats_list)
-
-const char *command_type_str[] = {
-#define _(l, u) [COMMAND_TYPE_##u] = STRINGIZE(u),
- foreach_command_type
-#undef _
-};
-
-typedef cmd_header_t hc_msg_header_t;
-
-typedef union {
-#define _(x) cmd_##x##_t x;
- foreach_hc_command
-#undef _
-} hc_msg_payload_t;
-
-typedef struct hc_msg_s {
- hc_msg_header_t hdr;
- hc_msg_payload_t payload;
-} hc_msg_t;
-
-/******************************************************************************
- * Control socket
- ******************************************************************************/
-
-#define AVAILABLE(s) ((s)->woff - (s)->roff)
-#define DEFAULT_SOCK_RECV_TIMEOUT_MS 100
-
-/**
- * \brief Parse a connection URL into a sockaddr
- * \param [in] url - URL
- * \param [out] sa - Resulting struct sockaddr, expected zero'ed.
- * \return 0 if parsing succeeded, a negative error value otherwise.
- */
-static int _hcng_sock_light_parse_url(const char *url, struct sockaddr *sa) {
- /* FIXME URL parsing is currently not implemented */
- assert(!url);
-
-#ifdef __linux__
- srand(time(NULL) ^ getpid() ^ gettid());
-#else
- srand((unsigned int)(time(NULL) ^ getpid()));
-#endif /* __linux__ */
-
- /*
- * A temporary solution is to inspect the sa_family fields of the passed in
- * sockaddr, which defaults to AF_UNSPEC (0) and thus creates an IPv4/TCP
- * connection to localhost.
- */
- switch (sa->sa_family) {
- case AF_UNSPEC:
- case AF_INET: {
- struct sockaddr_in *sai = (struct sockaddr_in *)sa;
- sai->sin_family = AF_INET;
- sai->sin_port = htons(PORT);
- sai->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- break;
- }
- case AF_INET6: {
- struct sockaddr_in6 *sai6 = (struct sockaddr_in6 *)sa;
- sai6->sin6_family = AF_INET6;
- sai6->sin6_port = htons(PORT);
- sai6->sin6_addr = loopback_addr;
- break;
- }
- default:
- return -1;
- }
-
- return 0;
-}
-
-static int _hcng_sock_light_reset(hc_sock_t *socket) {
- hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
- s->roff = s->woff = 0;
- s->remaining = 0;
- return 0;
-}
-
-void _hcng_sock_light_free(hc_sock_t *socket) {
- hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
-
- unsigned k_seq;
- hc_sock_request_t *v_request;
- kh_foreach(s->map, k_seq, v_request,
- { hc_sock_light_request_free(v_request); });
-
- kh_destroy_sock_map(s->map);
- if (s->url) free(s->url);
- close(s->fd);
- free(s);
-}
-
-static void _hcng_sock_increment_woff(hc_sock_t *socket, size_t bytes) {
- hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
- s->woff += bytes;
-}
-
-static int _hcng_sock_light_get_next_seq(hc_sock_t *socket) {
- hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
- return s->seq++;
-}
-
-static int _hcng_sock_light_set_nonblocking(hc_sock_t *socket) {
- hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
- return (fcntl(s->fd, F_SETFL, fcntl(s->fd, F_GETFL) | O_NONBLOCK) < 0);
-}
-
-static int _hcng_sock_light_get_fd(hc_sock_t *socket) {
- hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
- return s->fd;
-}
-
-static int _hcng_sock_light_connect(hc_sock_t *socket) {
- hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
- struct sockaddr_storage ss;
- memset(&ss, 0, sizeof(struct sockaddr_storage));
-
- if (_hcng_sock_light_parse_url(s->url, (struct sockaddr *)&ss) < 0)
- goto ERR_PARSE;
-
- size_t size = ss.ss_family == AF_INET ? sizeof(struct sockaddr_in)
- : sizeof(struct sockaddr_in6);
- if (connect(s->fd, (struct sockaddr *)&ss, (socklen_t)size) < 0) {
- perror("connect error");
- goto ERR_CONNECT;
- }
- return 0;
-
-ERR_CONNECT:
-ERR_PARSE:
- return -1;
-}
-
-static int _hcng_sock_light_send(hc_sock_t *socket, hc_msg_t *msg,
- size_t msglen, uint32_t seq) {
- hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
- int rc;
- msg->hdr.seq_num = seq;
- rc = (int)send(s->fd, msg, msglen, 0);
- if (rc < 0) {
- perror("hc_sock_light_send");
- return -1;
- }
- return 0;
-}
-
-static int _hcng_sock_light_get_available(hc_sock_t *socket, u8 **buffer,
- size_t *size) {
- hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
- *buffer = s->buf + s->woff;
- *size = RECV_BUFLEN - s->woff;
-
- return 0;
-}
-
-static int _hcng_sock_light_recv(hc_sock_t *socket) {
- hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
- int rc;
-
- /*
- * This condition should be ensured to guarantee correct processing of
- * messages. With TCP, we need at least a header as we will receive part of
- * the stream. With UDP, we need the be able to receive the full datagram,
- * otherwise the rest will be lost.
- *
- * Let's be sure to always be able to receive at least 1 JUMBO_MTU, which
- * should be fine for al situations.
- */
- assert(RECV_BUFLEN - s->woff > JUMBO_MTU);
-
- rc = (int)recv(s->fd, s->buf + s->woff, RECV_BUFLEN - s->woff, 0);
- if (rc == 0) {
- /* Connection has been closed */
- return 0;
- }
- if (rc < 0) {
- /*
- * Let's not return 0 which currently means the socket has been closed
- */
- if (errno == EWOULDBLOCK) return -1;
- if (errno == EINTR) {
- WARN("recv has been stopped by signal");
- return -1;
- }
- perror("hc_sock_light_recv");
- return -1;
- }
- s->woff += rc;
- return rc;
-}
-
-static void _hcng_sock_light_mark_complete(hc_sock_light_t *s,
- hc_data_t **pdata) {
- hc_data_t *data = s->cur_request->data;
-
- khiter_t k = kh_get_sock_map(s->map, s->cur_request->seq);
- if (k == kh_end(s->map)) {
- ERROR("[hc_sock_light_mark_complete] Error removing request from map");
- } else {
- kh_del_sock_map(s->map, k);
- }
-
- hc_data_set_complete(data);
- if (pdata) *pdata = data;
-
- /* Free current request */
- hc_sock_light_request_free(s->cur_request);
- s->cur_request = NULL;
-}
-
-static int _hcng_sock_light_process_notification(hc_sock_light_t *s,
- hc_data_t **pdata) {
- /* For now, notifications are not associated to requests */
- assert(!s->cur_request);
-
- /*
- * Assumption: the whole notification data is returned in a single read and we
- * immediately parse it.
- *
- * XXX This is only valid for UDP sockets.
- */
- size_t notification_size = AVAILABLE(s);
-
- *pdata = hc_data_create(0, /* in_element_size, 0 = no parsing */
- notification_size, /* out_element_size */
- NULL); /* complete_cb */
-
- /* Copy the packet payload as the single entry in hc_data_t */
- hc_data_push_many(*pdata, s->buf + s->roff, 1);
-
- return (int)notification_size;
-}
-
-/*
- * Notifications have no sequence number and are not linked to any request
- */
-static hc_sock_request_t *_hcng_sock_light_get_request(hc_sock_light_t *s,
- int seq) {
- hc_sock_request_t *request;
- /* Retrieve request from sock map */
- khiter_t k = kh_get_sock_map(s->map, seq);
- if (k == kh_end(s->map)) {
- ERROR(
- "[_hcng_sock_light_get_request] Error searching for matching request");
- return NULL;
- }
- request = kh_val(s->map, k);
-
- if (!request) {
- ERROR("[_hcng_sock_light_get_request] No request matching sequence number");
- return NULL;
- }
- return request;
-}
-
-/*
- * Return codes:
- * 0 success, or not enough data yet to do something
- * > 0 : notification type
- * -99 invalid buffer data -> flush
- */
-static int _hcng_sock_light_process_header(hc_sock_light_t *s,
- hc_data_t **pdata) {
- int rc;
-
- /* Check we have at least a header's worth of data, and consume it */
- if (AVAILABLE(s) < sizeof(hc_msg_header_t)) return 0;
-
- hc_msg_t *msg = (hc_msg_t *)(s->buf + s->roff);
-
- // INFO("Processing header header %s", command_type_str(msg->hdr.command_id));
- s->roff += sizeof(hc_msg_header_t);
-
- if (msg->hdr.message_type != NOTIFICATION_LIGHT) {
- s->cur_request = _hcng_sock_light_get_request(s, msg->hdr.seq_num);
- if (!s->cur_request) return -99;
- }
-
- /* How many elements are we expecting in the reply ? */
- s->remaining = msg->hdr.length;
- hc_data_t *request_data;
-
- switch (msg->hdr.message_type) {
- case ACK_LIGHT:
- assert(s->remaining == 1); // sic
- assert(!pdata);
- _hcng_sock_light_mark_complete(s, pdata);
- break;
-
- case NACK_LIGHT:
- assert(!pdata);
- assert(s->remaining == 1); // sic
- request_data = s->cur_request->data;
- _hcng_sock_light_mark_complete(s, pdata);
- hc_data_set_error(request_data);
- break;
-
- case RESPONSE_LIGHT:
- assert(pdata);
-
- if (s->remaining == 0) {
- /* Empty response (i.e. containing 0 elements) */
- _hcng_sock_light_mark_complete(s, pdata);
- return 0;
- }
-
- /* Make room in hc_data_t... to avoid multiple calls */
- rc = hc_data_ensure_available(s->cur_request->data, s->remaining);
- if (rc < 0) {
- ERROR("[hc_sock_light_process] Error in hc_data_ensure_available");
- return -99;
- }
- break;
-
- case NOTIFICATION_LIGHT: {
- assert(pdata);
- assert(s->remaining == 0);
-
- /* This returns the notification size */
- size_t notification_size =
- _hcng_sock_light_process_notification(s, pdata);
- s->roff += notification_size;
- return msg->hdr.command_id;
- }
-
- default:
- ERROR("[hc_sock_light_process] Invalid response received");
- return -99;
- }
-
- return 0;
-}
-
-static int _hcng_sock_light_process_payload(hc_sock_light_t *s,
- hc_data_t **pdata) {
- int err = 0;
- int rc;
-
- hc_data_t *data = s->cur_request->data;
-
- /* We only process full elements (size is stored in data) */
- size_t num_chunks = AVAILABLE(s) / data->in_element_size;
-
- /* Check whether we have enough data to process */
- if (num_chunks == 0) return 0;
-
- /* Safeguard: assert(num_chunks < s->remaining); */
- if (num_chunks > s->remaining) {
- WARN(
- "[_hcng_sock_light_process_payload] Unexpected num_chunks > "
- "s->remaining");
- num_chunks = s->remaining;
- }
-
- if (!s->cur_request->parse) {
- /* If we don't need to parse results, then we can directly push
- * all of them into the result data structure */
- hc_data_push_many(data, s->buf + s->roff, num_chunks);
- } else {
- /* Iterate on chunks of data */
- for (int i = 0; i < num_chunks; i++) {
- /* Get storage offset in hc_data_t */
- u8 *dst = hc_data_get_next(data);
- if (!dst) {
- ERROR("[hc_sock_light_process] Error in hc_data_get_next");
- err = -2;
- break;
- }
-
- /* Parse element #i */
- rc = s->cur_request->parse(s->buf + s->roff + i * data->in_element_size,
- dst);
- if (rc < 0) {
- ERROR("[hc_sock_light_process] Error in parse");
- err = -1;
- /* In this case we let the loop complete to collect other results */
- }
- data->size++;
- }
- }
-
- s->roff += num_chunks * data->in_element_size;
-
- /*
- * If we are not expecting any more data, mark the reply as complete
- */
- s->remaining -= num_chunks;
- if (s->remaining == 0) _hcng_sock_light_mark_complete(s, pdata);
-
- return err;
-}
-
-/*
- * Process messages as they are received in the ring buffer. There can be
- * interleaved queries and replies (they are identified by sequence number),
- * and the assumption is that a reply can arrive over mutiple packets (in
- * other terms, it is possible that not all data from the reply is available
- * in the buffer at a given time). However, we assume that a full query is
- * received at once.
- */
-static int _hcng_sock_light_process(hc_sock_t *socket, hc_data_t **data) {
- hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
- int rc = 0;
-
- /*
- * We loop consuming messages until there is no more data in the buffer,
- * or that we can find an entire message. Messages are received
- * sequentially, and we keep track of incomplete requests in s->cur_request.
- */
- while (AVAILABLE(s) > 0) {
- if (!s->cur_request) {
- rc = _hcng_sock_light_process_header(s, data);
- } else {
- rc = _hcng_sock_light_process_payload(s, data);
- }
- if (rc < 0) break;
- }
-
- if ((rc == -99) || (s->roff == s->woff)) {
- /* Flush buffer */
- s->woff = 0;
- } else {
- /* Clean up read data from buffer */
- memmove(s->buf, s->buf + s->roff, AVAILABLE(s));
- s->woff -= s->roff;
- }
- s->roff = 0;
-
- return rc;
-}
-
-static int _hcng_sock_light_callback(hc_sock_t *socket, hc_data_t **pdata) {
- hc_data_t *data = NULL;
- int rc = 0;
-
- for (;;) {
- int n = _hcng_sock_light_recv(socket);
- if (n == 0) goto ERR_EOF;
- if (n < 0) {
- switch (errno) {
- case ECONNRESET:
- case ENODEV:
- /* Forwarder restarted */
- WARN("Forwarder likely restarted: not (yet) implemented");
- goto ERR;
- case EWOULDBLOCK:
- // DEBUG("Would block... stop reading from socket");
- goto END;
- case EINTR:
- WARN("callback has been stopped by signal");
- goto ERR;
- default:
- perror("hc_sock_light_callback");
- goto ERR;
- }
- }
- rc = _hcng_sock_light_process(socket, &data);
- if (rc < 0) goto ERR;
- if (rc > 0) // i.e. rc = notification type
- goto END;
- }
-END:
- if (pdata)
- *pdata = data;
- else
- hc_data_free(data);
- return rc;
-
-ERR:
- hc_data_free(data);
-ERR_EOF:
- return -1;
-}
-
-/******************************************************************************
- * Command-specific structures and functions
- ******************************************************************************/
-
-typedef int (*HC_PARSE)(const u8 *, u8 *);
-
-typedef struct {
- hc_action_t cmd;
- command_type_t cmd_id;
- size_t size_in;
- size_t size_out;
- HC_PARSE parse;
-} hc_command_params_t;
-
-typedef struct hc_result_s {
- hc_msg_t msg;
- hc_command_params_t params;
- bool async;
- bool success;
-} hc_result_t;
-
-int _hcng_sock_prepare_send(hc_sock_t *socket, hc_result_t *result,
- data_callback_t complete_cb,
- void *complete_cb_data) {
- hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
-
- // Prepare data
- hc_data_t *data =
- hc_data_create(result->params.size_in, result->params.size_out, NULL);
- if (!data) {
- ERROR("[_hcng_sock_prepare_send] Could not create data storage");
- goto ERR_DATA;
- }
- hc_data_set_callback(data, complete_cb, complete_cb_data);
-
- // Update the sequence number
- int seq = _hcng_sock_light_get_next_seq(socket);
- result->msg.hdr.seq_num = seq; // Like in _hcng_sock_light_send
-
- // Create state used to process the request
- hc_sock_request_t *request = NULL;
- request = hc_sock_request_create(seq, data, result->params.parse);
- if (!request) {
- ERROR("[_hcng_sock_prepare_send] Could not create request state");
- goto ERR_REQUEST;
- }
-
- int rc;
- khiter_t k = kh_put_sock_map(s->map, seq, &rc);
- if (rc != KH_ADDED && rc != KH_RESET) {
- ERROR("[_hcng_sock_prepare_send] Error adding request state to map");
- goto ERR_MAP;
- }
- kh_value(s->map, k) = request;
-
- return sizeof(result->msg);
-
-ERR_MAP:
- hc_sock_light_request_free(request);
-ERR_REQUEST:
- hc_data_free(data);
-ERR_DATA:
- return -99;
-}
-
-int _hcng_sock_set_recv_timeout_ms(hc_sock_t *socket, long timeout_ms) {
- hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
-
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = (int)(timeout_ms * 1000); // Convert ms into us
- if (setsockopt(s->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
- perror("setsockopt");
- return -1;
- }
-
- return 0;
-}
-
-static int _hcng_execute_command(hc_sock_t *socket, hc_msg_t *msg,
- size_t msg_len, hc_command_params_t *params,
- hc_data_t **pdata, bool async) {
- hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
- int ret;
- if (async) assert(!pdata);
-
- /* Sanity check */
- switch (params->cmd) {
- case ACTION_CREATE:
- assert(params->size_in != 0); /* payload repeated */
- assert(params->size_out == 0);
- assert(params->parse == NULL);
- break;
- case ACTION_DELETE:
- assert(params->size_in != 0); /* payload repeated */
- assert(params->size_out == 0);
- assert(params->parse == NULL);
- break;
- case ACTION_GET:
- case ACTION_LIST:
- assert(params->size_in != 0);
- assert(params->size_out != 0);
- // TODO(eloparco): Parsing should not be necessary after
- // (pending) refatoring
- // assert(params->parse != NULL);
- break;
- case ACTION_SET:
- case ACTION_SERVE:
- case ACTION_STORE:
- case ACTION_UPDATE:
- assert(params->size_in != 0);
- assert(params->size_out == 0);
- assert(params->parse == NULL);
- break;
- case ACTION_CLEAR:
- assert(params->size_in == 0);
- assert(params->size_out == 0);
- assert(params->parse == NULL);
- break;
- default:
- return -1;
- }
-
- // hc_sock_light_reset(s);
-
- /* XXX data will at least store the result (complete) */
- hc_data_t *data = hc_data_create(params->size_in, params->size_out, NULL);
- if (!data) {
- ERROR("[_hcng_execute_command] Could not create data storage");
- goto ERR_DATA;
- }
-
- int seq = _hcng_sock_light_get_next_seq(socket);
-
- /* Create state used to process the request */
- hc_sock_request_t *request = NULL;
- request = hc_sock_request_create(seq, data, params->parse);
- if (!request) {
- ERROR("[_hcng_execute_command] Could not create request state");
- goto ERR_REQUEST;
- }
-
- /* Add state to map */
- int rc;
- khiter_t k = kh_put_sock_map(s->map, seq, &rc);
- if (rc != KH_ADDED && rc != KH_RESET) {
- ERROR("[_hcng_execute_command] Error adding request state to map");
- goto ERR_MAP;
- }
- kh_value(s->map, k) = request;
-
- if (_hcng_sock_light_send(socket, msg, msg_len, seq) < 0) {
- ERROR("[_hcng_execute_command] Error sending message");
- goto ERR_PROCESS;
- }
-
- if (async) return 0;
-
- /*
- * Dangerous zone, we might be doing blocking operations on a non-blocking
- * UDP socket
- */
- int retries = 0;
- while (!data->complete) {
- /*
- * As the socket is non blocking it might happen that we need to read
- * several times before success...
- */
- int n = _hcng_sock_light_recv(socket);
- if (n == 0) goto ERR_EOF;
- if (n < 0) {
- if ((errno == EWOULDBLOCK) && (retries < 10)) { /* Max 500ms */
- DEBUG("read = EWOULDBLOCK... sleeping for 50ms (max 500ms)");
- usleep(50000); /* 50ms */
- retries++;
- continue;
- }
- break;
- }
- int rc = _hcng_sock_light_process(socket, pdata);
- switch (rc) {
- case 0:
- case -1:
- break;
- case -99:
- ERROR("[_hcng_execute_command] Error processing socket results");
- goto ERR;
- default:
- ERROR("[_hcng_execute_command] Unexpected return value");
- goto ERR;
- }
- }
-
-ERR_EOF:
- ret = data->ret;
- if (!data->complete) return -1;
- if (!pdata) hc_data_free(data);
-
- return ret;
-
-ERR_PROCESS:
-ERR_MAP:
- hc_sock_light_request_free(request);
-ERR:
-ERR_REQUEST:
- hc_data_free(data);
-ERR_DATA:
- return -99;
-}
-
-/*----------------------------------------------------------------------------*
- * Listeners
- *----------------------------------------------------------------------------*/
-
-/* LISTENER CREATE */
-
-static hc_result_t *_listener_create_serialize(hc_sock_t *s,
- hc_listener_t *listener,
- bool async) {
- hc_result_t *res = malloc(sizeof(*res));
- char listener_s[MAXSZ_HC_LISTENER];
- int rc = hc_listener_snprintf(listener_s, MAXSZ_HC_LISTENER, listener);
- if (rc >= MAXSZ_HC_LISTENER)
- WARN("[_hcng_listener_create] Unexpected truncation of listener string");
- DEBUG("[_hcng_listener_create] listener=%s async=%s", listener_s,
- BOOLSTR(async));
-
- if (hc_listener_validate(listener) < 0) {
- res->success = false;
- return res;
- }
-
- msg_listener_add_t msg = {.header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_LISTENER_ADD,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .address = listener->local_addr,
- .port = htons(listener->local_port),
- .family = listener->family,
- .type = listener->type,
- }};
-
- rc = snprintf(msg.payload.symbolic, SYMBOLIC_NAME_LEN, "%s", listener->name);
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN(
- "[_hc_listener_create] Unexpected truncation of symbolic name "
- "string");
-
- rc = snprintf(msg.payload.interface_name, INTERFACE_LEN, "%s",
- listener->interface_name);
- if (rc >= INTERFACE_LEN)
- WARN(
- "[_hc_listener_create] Unexpected truncation of interface name "
- "string");
-
- hc_command_params_t params = {
- .cmd = ACTION_CREATE,
- .cmd_id = COMMAND_TYPE_LISTENER_ADD,
- .size_in = sizeof(cmd_listener_add_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- *res = (hc_result_t){
- .msg =
- (hc_msg_t){
- .hdr = msg.header,
- .payload.listener_add = msg.payload,
- },
- .params = params,
- .async = async,
- .success = true,
- };
- return res;
-}
-
-static hc_result_t *_hcng_listener_create_conf(hc_sock_t *s,
- hc_listener_t *listener) {
- return _listener_create_serialize(s, listener, false);
-}
-
-static int _hcng_listener_create_internal(hc_sock_t *socket,
- hc_listener_t *listener, bool async) {
- hc_result_t *result = _listener_create_serialize(socket, listener, async);
-
- int ret = INPUT_ERROR;
- if (result->success) {
- ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
- sizeof(result->msg), &result->params, NULL,
- result->async);
- }
-
- free(result);
- DEBUG("[_hcng_listener_create] done or error");
- return ret;
-}
-
-static int _hcng_listener_create(hc_sock_t *s, hc_listener_t *listener) {
- DEBUG("[_hcng_listener_create]");
- return _hcng_listener_create_internal(s, listener, false);
-}
-
-static int _hcng_listener_create_async(hc_sock_t *s, hc_listener_t *listener) {
- DEBUG("[_hcng_listener_create_async]");
- return _hcng_listener_create_internal(s, listener, true);
-}
-
-/* LISTENER PARSE */
-
-static int hc_listener_parse(void *in, hc_listener_t *listener) {
- int rc;
- cmd_listener_list_item_t *item = (cmd_listener_list_item_t *)in;
-
- if (!IS_VALID_ID(item->id)) {
- ERROR("[hc_listener_parse] Invalid id received");
- return -1;
- }
-
- *listener = (hc_listener_t){
- .id = item->id,
- .type = item->type,
- .family = item->family,
- .local_addr = UNION_CAST(item->address, ip_address_t),
- .local_port = ntohs(item->port),
- };
- rc = snprintf(listener->name, SYMBOLIC_NAME_LEN, "%s", item->name);
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN("[hc_listener_parse] Unexpected truncation of symbolic name string");
- rc = snprintf(listener->interface_name, INTERFACE_LEN, "%s",
- item->interface_name);
- if (rc >= INTERFACE_LEN)
- WARN("[hc_listener_parse] Unexpected truncation of interface name string");
-
- if (hc_listener_validate(listener) < 0) return -1;
- return 0;
-}
-
-/* LISTENER LIST */
-
-static hc_result_t *_hcng_listener_list_serialize(hc_sock_t *socket,
- hc_data_t **pdata,
- bool async) {
- hc_result_t *res = malloc(sizeof(*res));
- DEBUG("[hc_listener_list] async=%s", BOOLSTR(async));
-
- msg_listener_list_t msg = {.header = {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_LISTENER_LIST,
- .length = 0,
- .seq_num = 0,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_LIST,
- .cmd_id = COMMAND_TYPE_LISTENER_LIST,
- .size_in = sizeof(cmd_listener_list_item_t),
- .size_out = sizeof(hc_listener_t),
- .parse = (HC_PARSE)hc_listener_parse,
- };
-
- *res = (hc_result_t){
- .msg =
- (hc_msg_t){
- .hdr = msg.header,
- .payload.listener_list = msg.payload,
- },
- .params = params,
- .async = async,
- .success = true,
- };
- return res;
-}
-
-static hc_result_t *_hcng_listener_list_conf(hc_sock_t *s, hc_data_t **pdata) {
- return _hcng_listener_list_serialize(s, pdata, false);
-}
-
-static int _hcng_listener_list_internal(hc_sock_t *socket, hc_data_t **pdata,
- bool async) {
- hc_result_t *result = _hcng_listener_list_serialize(socket, pdata, async);
-
- int ret = INPUT_ERROR;
- if (result->success) {
- ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
- sizeof(result->msg), &result->params, pdata,
- result->async);
- }
-
- hc_result_free(result);
- DEBUG("[_hcng_listener_list] done or error");
- return ret;
-}
-
-static int _hcng_listener_list(hc_sock_t *s, hc_data_t **pdata) {
- DEBUG("[_hcng_listener_list]");
- return _hcng_listener_list_internal(s, pdata, false);
-}
-
-static int _hcng_listener_list_async(hc_sock_t *s, hc_data_t **pdata) {
- DEBUG("[_hcng_listener_list_as-nc]");
- return _hcng_listener_list_internal(s, pdata, true);
-}
-
-/* LISTENER GET */
-
-static int _hcng_listener_get(hc_sock_t *socket, hc_listener_t *listener,
- hc_listener_t **listener_found) {
- hc_data_t *listeners;
- hc_listener_t *found;
-
- char listener_s[MAXSZ_HC_LISTENER];
- int rc = hc_listener_snprintf(listener_s, MAXSZ_HC_LISTENER, listener);
- if (rc >= MAXSZ_HC_LISTENER)
- WARN("[hc_listener_get] Unexpected truncation of listener string");
- DEBUG("[hc_listener_get] listener=%s", listener_s);
-
- if (_hcng_listener_list(socket, &listeners) < 0) return -1;
-
- /* Test */
- if (hc_listener_find(listeners, listener, &found) < 0) {
- hc_data_free(listeners);
- return -1;
- }
-
- if (found) {
- *listener_found = malloc(sizeof(hc_listener_t));
- if (!*listener_found) return -1;
- **listener_found = *found;
- } else {
- *listener_found = NULL;
- }
-
- hc_data_free(listeners);
-
- return 0;
-}
-
-/* LISTENER DELETE */
-
-static int _hcng_listener_delete_internal(hc_sock_t *socket,
- hc_listener_t *listener, bool async) {
- char listener_s[MAXSZ_HC_LISTENER];
- int rc = hc_listener_snprintf(listener_s, MAXSZ_HC_LISTENER, listener);
- if (rc >= MAXSZ_HC_LISTENER)
- WARN("[_hcng_listener_delete] Unexpected truncation of listener string");
- DEBUG("[_hcng_listener_delete] listener=%s async=%s", listener_s,
- BOOLSTR(async));
-
- msg_listener_remove_t msg = {.header = {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_LISTENER_REMOVE,
- .length = 1,
- .seq_num = 0,
- }};
-
- if (listener->id) {
- rc = snprintf(msg.payload.symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%d",
- listener->id);
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN(
- "[_hc_listener_delete] Unexpected truncation of symbolic name "
- "string");
- } else if (*listener->name) {
- rc = snprintf(msg.payload.symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%s",
- listener->name);
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN(
- "[_hc_listener_delete] Unexpected truncation of symbolic name "
- "string");
- } else {
- hc_listener_t *listener_found;
- if (_hcng_listener_get(socket, listener, &listener_found) < 0) return -1;
- if (!listener_found) return -1;
- rc = snprintf(msg.payload.symbolicOrListenerid, SYMBOLIC_NAME_LEN, "%d",
- listener_found->id);
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN(
- "[_hc_listener_delete] Unexpected truncation of symbolic name "
- "string");
- free(listener_found);
- }
-
- hc_command_params_t params = {
- .cmd = ACTION_DELETE,
- .cmd_id = COMMAND_TYPE_LISTENER_REMOVE,
- .size_in = sizeof(cmd_listener_remove_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, async);
-}
-
-static int _hcng_listener_delete(hc_sock_t *s, hc_listener_t *listener) {
- return _hcng_listener_delete_internal(s, listener, false);
-}
-
-static int _hcng_listener_delete_async(hc_sock_t *s, hc_listener_t *listener) {
- return _hcng_listener_delete_internal(s, listener, true);
-}
-
-/*----------------------------------------------------------------------------*
- * CONNECTION
- *----------------------------------------------------------------------------*/
-
-/* CONNECTION CREATE */
-
-static hc_result_t *_connection_create_serialize(hc_sock_t *socket,
- hc_connection_t *connection,
- bool async) {
- hc_result_t *res = malloc(sizeof(*res));
- char connection_s[MAXSZ_HC_CONNECTION];
- int rc =
- hc_connection_snprintf(connection_s, MAXSZ_HC_CONNECTION, connection);
- if (rc >= MAXSZ_HC_CONNECTION)
- WARN(
- "[_hcng_connection_create] Unexpected truncation of connection "
- "string");
- DEBUG("[_hcng_connection_create] connection=%s async=%s", connection_s,
- BOOLSTR(async));
-
- if (hc_connection_validate(connection) < 0) {
- res->success = false;
- return res;
- }
-
- msg_connection_add_t msg = {.header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_CONNECTION_ADD,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .remote_ip = connection->remote_addr,
- .local_ip = connection->local_addr,
- .remote_port = htons(connection->remote_port),
- .local_port = htons(connection->local_port),
- .family = connection->family,
- .type = connection->type,
- .admin_state = connection->admin_state,
-#ifdef WITH_POLICY
- .priority = connection->priority,
- .tags = connection->tags,
-#endif /* WITH_POLICY */
- }};
- rc =
- snprintf(msg.payload.symbolic, SYMBOLIC_NAME_LEN, "%s", connection->name);
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN(
- "[_hc_connection_create] Unexpected truncation of symbolic name "
- "string");
- // snprintf(msg.payload.interface_name, INTERFACE_NAME_LEN, "%s",
- // connection->interface_name);
-
- hc_command_params_t params = {
- .cmd = ACTION_CREATE,
- .cmd_id = COMMAND_TYPE_CONNECTION_ADD,
- .size_in = sizeof(cmd_connection_add_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- *res = (hc_result_t){
- .msg =
- (hc_msg_t){
- .hdr = msg.header,
- .payload.connection_add = msg.payload,
- },
- .params = params,
- .async = async,
- .success = true,
- };
- return res;
-}
-
-static hc_result_t *_hcng_connection_create_conf(hc_sock_t *s,
- hc_connection_t *connection) {
- return _connection_create_serialize(s, connection, false);
-}
-
-static int _hcng_connection_create_internal(hc_sock_t *socket,
- hc_connection_t *connection,
- bool async) {
- hc_result_t *result = _connection_create_serialize(socket, connection, async);
-
- int ret = INPUT_ERROR;
- if (result->success) {
- ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
- sizeof(result->msg), &result->params, NULL,
- result->async);
- }
-
- hc_result_free(result);
- DEBUG("[_hcng_connection_create] done or error");
- return ret;
-}
-
-static int _hcng_connection_create(hc_sock_t *s, hc_connection_t *connection) {
- DEBUG("[_hcng_connection_create]");
- return _hcng_connection_create_internal(s, connection, false);
-}
-
-static int _hcng_connection_create_async(hc_sock_t *s,
- hc_connection_t *connection) {
- DEBUG("[_hcng_connection_create_async]");
- return _hcng_connection_create_internal(s, connection, true);
-}
-
-/* CONNECTION PARSE */
-
-static int hc_connection_parse(void *in, hc_connection_t *connection) {
- int rc;
- cmd_connection_list_item_t *item = (cmd_connection_list_item_t *)in;
-
- if (!IS_VALID_ID(item->id)) {
- ERROR("[hc_connection_parse] Invalid id received");
- return -1;
- }
-
- *connection = (hc_connection_t){
- .id = item->id,
- .type = item->type,
- .family = item->family,
- .local_addr = item->local_addr,
- .local_port = ntohs(item->local_port),
- .remote_addr = item->remote_addr,
- .remote_port = ntohs(item->remote_port),
- .admin_state = item->admin_state,
-#ifdef WITH_POLICY
- .priority = item->priority,
- .tags = item->tags,
-#endif /* WITH_POLICY */
- .state = item->state,
- };
- rc = snprintf(connection->name, SYMBOLIC_NAME_LEN, "%s", item->name);
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN(
- "[hc_connection_parse] Unexpected truncation of symbolic name "
- "string");
- rc = snprintf(connection->interface_name, INTERFACE_LEN, "%s",
- item->interface_name);
- if (rc >= INTERFACE_LEN)
- WARN(
- "[hc_connection_parse] Unexpected truncation of interface name "
- "string");
-
- if (hc_connection_validate(connection) < 0) return -1;
- return 0;
-}
-
-/* CONNECTION LIST */
-
-static int _hcng_connection_list_internal(hc_sock_t *socket, hc_data_t **pdata,
- bool async) {
- DEBUG("[hc_connection_list] async=%s", BOOLSTR(async));
-
- msg_connection_list_t msg = {.header = {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_CONNECTION_LIST,
- .length = 0,
- .seq_num = 0,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_LIST,
- .cmd_id = COMMAND_TYPE_CONNECTION_LIST,
- .size_in = sizeof(cmd_connection_list_item_t),
- .size_out = sizeof(hc_connection_t),
- .parse = (HC_PARSE)hc_connection_parse,
- };
-
- int ret = _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg),
- &params, pdata, async);
-
- DEBUG("[hc_connection_list] done or error");
- return ret;
-}
-
-static int _hcng_connection_list(hc_sock_t *s, hc_data_t **pdata) {
- DEBUG("[hc_connection_list]");
- return _hcng_connection_list_internal(s, pdata, false);
-}
-
-static int _hcng_connection_list_async(hc_sock_t *s, hc_data_t **pdata) {
- DEBUG("[hc_connection_list_async]");
- return _hcng_connection_list_internal(s, pdata, true);
-}
-
-/* CONNECTION GET */
-
-static int _hcng_connection_get(hc_sock_t *socket, hc_connection_t *connection,
- hc_connection_t **connection_found) {
- hc_data_t *connections;
- hc_connection_t *found;
-
- char connection_s[MAXSZ_HC_CONNECTION];
- int rc =
- hc_connection_snprintf(connection_s, MAXSZ_HC_CONNECTION, connection);
- if (rc >= MAXSZ_HC_CONNECTION)
- WARN("[hc_connection_get] Unexpected truncation of connection string");
- DEBUG("[hc_connection_get] connection=%s", connection_s);
-
- if (_hcng_connection_list(socket, &connections) < 0) return -1;
-
- /* Test */
- if (hc_connection_find(connections, connection, &found) < 0) {
- hc_data_free(connections);
- return -1;
- }
-
- if (found) {
- *connection_found = malloc(sizeof(hc_connection_t));
- if (!*connection_found) return -1;
- **connection_found = *found;
- } else {
- *connection_found = NULL;
- }
-
- hc_data_free(connections);
-
- return 0;
-}
-
-/* CONNECTION DELETE */
-
-static hc_result_t *_hcng_connection_delete_serialize(
- hc_sock_t *socket, hc_connection_t *connection, bool async) {
- hc_result_t *res = malloc(sizeof(*res));
- res->success = false;
-
- char connection_s[MAXSZ_HC_CONNECTION];
- int rc =
- hc_connection_snprintf(connection_s, MAXSZ_HC_CONNECTION, connection);
- if (rc >= MAXSZ_HC_CONNECTION)
- WARN(
- "[_hcng_connection_delete] Unexpected truncation of connection "
- "string");
- DEBUG("[_hcng_connection_delete] connection=%s async=%s", connection_s,
- BOOLSTR(async));
-
- msg_connection_remove_t msg = {
- .header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_CONNECTION_REMOVE,
- .length = 1,
- .seq_num = 0,
- },
- };
-
- if (connection->id) {
- rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d",
- connection->id);
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN(
- "[_hc_connection_delete] Unexpected truncation of symbolic name "
- "string");
- } else if (*connection->name) {
- rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
- connection->name);
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN(
- "[_hc_connection_delete] Unexpected truncation of symbolic name "
- "string");
- } else {
- hc_connection_t *connection_found;
- if (hc_connection_get(socket, connection, &connection_found) < 0)
- return res;
- if (!connection_found) return res;
- rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d",
- connection_found->id);
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN(
- "[_hc_connection_delete] Unexpected truncation of symbolic name "
- "string");
- free(connection_found);
- }
-
- hc_command_params_t params = {
- .cmd = ACTION_DELETE,
- .cmd_id = COMMAND_TYPE_CONNECTION_REMOVE,
- .size_in = sizeof(cmd_connection_remove_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- *res = (hc_result_t){
- .msg =
- (hc_msg_t){
- .hdr = msg.header,
- .payload.connection_remove = msg.payload,
- },
- .params = params,
- .async = async,
- .success = true,
- };
- return res;
-}
-
-static hc_result_t *_hcng_connection_delete_conf(hc_sock_t *s,
- hc_connection_t *connection) {
- return _hcng_connection_delete_serialize(s, connection, false);
-}
-
-static int _hcng_connection_delete_internal(hc_sock_t *socket,
- hc_connection_t *connection,
- bool async) {
- hc_result_t *result =
- _hcng_connection_delete_serialize(socket, connection, async);
-
- int ret = INPUT_ERROR;
- if (result->success) {
- ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
- sizeof(result->msg), &result->params, NULL,
- result->async);
- }
-
- hc_result_free(result);
- return ret;
-}
-
-static int _hcng_connection_delete(hc_sock_t *s, hc_connection_t *connection) {
- return _hcng_connection_delete_internal(s, connection, false);
-}
-
-static int _hcng_connection_delete_async(hc_sock_t *s,
- hc_connection_t *connection) {
- return _hcng_connection_delete_internal(s, connection, true);
-}
-
-/* CONNECTION UPDATE */
-
-static int _hcng_connection_update_by_id(hc_sock_t *s, int hc_connection_id,
- hc_connection_t *connection) {
- // Not implemented
- return -1;
-}
-
-static int _hcng_connection_update(hc_sock_t *s,
- hc_connection_t *connection_current,
- hc_connection_t *connection_updated) {
- // Not implemented
- return -1;
-}
-
-/* CONNECTION SET ADMIN STATE */
-
-static int _hcng_connection_set_admin_state_internal(
- hc_sock_t *socket, const char *conn_id_or_name, face_state_t state,
- bool async) {
- int rc;
- DEBUG(
- "[hc_connection_set_admin_state] connection_id/name=%s admin_state=%s "
- "async=%s",
- conn_id_or_name, face_state_str(state), BOOLSTR(async));
-
- struct {
- cmd_header_t hdr;
- cmd_connection_set_admin_state_t payload;
- } msg = {
- .hdr =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_CONNECTION_SET_ADMIN_STATE,
- .length = 1,
- .seq_num = 0,
- },
- .payload =
- {
- .admin_state = state,
- },
- };
- rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
- conn_id_or_name);
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN(
- "[_hc_connection_set_admin_state] Unexpected truncation of symbolic "
- "name string");
-
- hc_command_params_t params = {
- .cmd = ACTION_SET,
- .cmd_id = COMMAND_TYPE_CONNECTION_SET_ADMIN_STATE,
- .size_in = sizeof(cmd_connection_set_admin_state_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, async);
-}
-
-static int _hcng_connection_set_admin_state(hc_sock_t *s,
- const char *conn_id_or_name,
- face_state_t state) {
- return _hcng_connection_set_admin_state_internal(s, conn_id_or_name, state,
- false);
-}
-
-static int _hcng_connection_set_admin_state_async(hc_sock_t *s,
- const char *conn_id_or_name,
- face_state_t state) {
- return _hcng_connection_set_admin_state_internal(s, conn_id_or_name, state,
- true);
-}
-
-#ifdef WITH_POLICY
-
-static int _hcng_connection_set_priority_internal(hc_sock_t *socket,
- const char *conn_id_or_name,
- uint32_t priority,
- bool async) {
- int rc;
- DEBUG(
- "[hc_connection_set_priority] connection_id/name=%s priority=%d "
- "async=%s",
- conn_id_or_name, priority, BOOLSTR(async));
- struct {
- cmd_header_t hdr;
- cmd_connection_set_priority_t payload;
- } msg = {
- .hdr =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_CONNECTION_SET_PRIORITY,
- .length = 1,
- .seq_num = 0,
- },
- .payload =
- {
- .priority = priority,
- },
- };
- rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
- conn_id_or_name);
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN(
- "[_hc_connection_set_priority] Unexpected truncation of symbolic "
- "name "
- "string");
-
- hc_command_params_t params = {
- .cmd = ACTION_SET,
- .cmd_id = COMMAND_TYPE_CONNECTION_SET_PRIORITY,
- .size_in = sizeof(cmd_connection_set_priority_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, async);
-}
-
-static int _hcng_connection_set_priority(hc_sock_t *s,
- const char *conn_id_or_name,
- uint32_t priority) {
- return _hcng_connection_set_priority_internal(s, conn_id_or_name, priority,
- false);
-}
-
-static int _hcng_connection_set_priority_async(hc_sock_t *s,
- const char *conn_id_or_name,
- uint32_t priority) {
- return _hcng_connection_set_priority_internal(s, conn_id_or_name, priority,
- true);
-}
-
-#endif // WITH_POLICY
-
-static int _hcng_connection_set_tags_internal(hc_sock_t *s,
- const char *conn_id_or_name,
- policy_tags_t tags, bool async) {
- int rc;
- DEBUG("[hc_connection_set_tags] connection_id/name=%s tags=%d async=%s",
- conn_id_or_name, tags, BOOLSTR(async));
- struct {
- cmd_header_t hdr;
- cmd_connection_set_tags_t payload;
- } msg = {
- .hdr =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_CONNECTION_SET_TAGS,
- .length = 1,
- .seq_num = 0,
- },
- .payload =
- {
- .tags = tags,
- },
- };
- rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
- conn_id_or_name);
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN(
- "[_hc_connection_set_tags] Unexpected truncation of symbolic name "
- "string");
-
- hc_command_params_t params = {
- .cmd = ACTION_SET,
- .cmd_id = COMMAND_TYPE_CONNECTION_SET_TAGS,
- .size_in = sizeof(cmd_connection_set_tags_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(s, (hc_msg_t *)&msg, sizeof(msg), &params, NULL,
- async);
-}
-
-static int _hcng_connection_set_tags(hc_sock_t *s, const char *conn_id_or_name,
- policy_tags_t tags) {
- return _hcng_connection_set_tags_internal(s, conn_id_or_name, tags, false);
-}
-
-static int _hcng_connection_set_tags_async(hc_sock_t *s,
- const char *conn_id_or_name,
- policy_tags_t tags) {
- return _hcng_connection_set_tags_internal(s, conn_id_or_name, tags, true);
-}
-
-/*----------------------------------------------------------------------------*
- * Routes
- *----------------------------------------------------------------------------*/
-
-/* ROUTE CREATE */
-
-static hc_result_t *_route_create_serialize(hc_sock_t *socket,
- hc_route_t *route, bool async) {
- hc_result_t *res = malloc(sizeof(*res));
- char route_s[MAXSZ_HC_ROUTE];
- int rc = hc_route_snprintf(route_s, MAXSZ_HC_ROUTE, route);
- if (rc >= MAXSZ_HC_ROUTE)
- WARN("[_hc_route_create] Unexpected truncation of route string");
- if (rc < 0)
- WARN("[_hc_route_create] Error building route string");
- else
- DEBUG("[hc_route_create] route=%s async=%s", route_s, BOOLSTR(async));
-
- if (hc_route_validate(route) < 0) {
- res->success = false;
- return res;
- }
-
- msg_route_add_t msg = {.header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_ROUTE_ADD,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .address = route->remote_addr,
- .cost = route->cost,
- .family = route->family,
- .len = route->len,
- }};
-
- /*
- * The route commands expects the ID or name as part of the
- * symbolic_or_connid attribute.
- */
- if (route->name[0] != '\0') {
- rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
- route->name);
- } else {
- rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d",
- route->face_id);
- }
-
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN("[_hc_route_create] Unexpected truncation of symbolic name string");
-
- hc_command_params_t params = {
- .cmd = ACTION_CREATE,
- .cmd_id = COMMAND_TYPE_ROUTE_ADD,
- .size_in = sizeof(cmd_route_add_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- *res = (hc_result_t){
- .msg =
- (hc_msg_t){
- .hdr = msg.header,
- .payload.route_add = msg.payload,
- },
- .params = params,
- .async = async,
- .success = true,
- };
- return res;
-}
-
-static hc_result_t *_hcng_route_create_conf(hc_sock_t *s, hc_route_t *route) {
- return _route_create_serialize(s, route, false);
-}
-
-static int _hcng_route_create_internal(hc_sock_t *socket, hc_route_t *route,
- bool async) {
- hc_result_t *result = _route_create_serialize(socket, route, async);
-
- int ret = INPUT_ERROR;
- if (result->success) {
- ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
- sizeof(result->msg), &result->params, NULL,
- result->async);
- }
-
- hc_result_free(result);
- return ret;
-}
-
-static int _hcng_route_create(hc_sock_t *s, hc_route_t *route) {
- return _hcng_route_create_internal(s, route, false);
-}
-
-static int _hcng_route_create_async(hc_sock_t *s, hc_route_t *route) {
- return _hcng_route_create_internal(s, route, true);
-}
-
-/* ROUTE DELETE */
-
-static int _hcng_route_delete_internal(hc_sock_t *socket, hc_route_t *route,
- bool async) {
- char route_s[MAXSZ_HC_ROUTE];
- int rc = hc_route_snprintf(route_s, MAXSZ_HC_ROUTE, route);
- if (rc >= MAXSZ_HC_ROUTE)
- WARN("[_hc_route_delete] Unexpected truncation of route string");
- DEBUG("[hc_route_delete] route=%s async=%s", route_s, BOOLSTR(async));
-
- if (!IS_VALID_FAMILY(route->family)) return -1;
-
- struct {
- cmd_header_t hdr;
- cmd_route_remove_t payload;
- } msg = {.hdr =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_ROUTE_REMOVE,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .address = route->remote_addr,
- .family = route->family,
- .len = route->len,
- }};
-
- /*
- * The route commands expects the ID or name as part of the
- * symbolic_or_connid attribute.
- */
- if (route->name[0] != '\0') {
- rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%s",
- route->name);
- } else {
- rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d",
- route->face_id);
- }
-
- hc_command_params_t params = {
- .cmd = ACTION_DELETE,
- .cmd_id = COMMAND_TYPE_ROUTE_REMOVE,
- .size_in = sizeof(cmd_route_remove_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, async);
-}
-
-static int _hcng_route_delete(hc_sock_t *s, hc_route_t *route) {
- return _hcng_route_delete_internal(s, route, false);
-}
-
-static int _hcng_route_delete_async(hc_sock_t *s, hc_route_t *route) {
- return _hcng_route_delete_internal(s, route, true);
-}
-
-/* ROUTE PARSE */
-
-static int hc_route_parse(void *in, hc_route_t *route) {
- cmd_route_list_item_t *item = (cmd_route_list_item_t *)in;
-
- *route = (hc_route_t){
- .name = "", /* This is not reported back */
- .face_id = item->connection_id,
- .family = item->family,
- .remote_addr = item->address,
- .len = item->len,
- .cost = item->cost,
- };
-
- if (hc_route_validate(route) < 0) return -1;
- return 0;
-}
-
-/* ROUTE LIST */
-
-static int _hcng_route_list_internal(hc_sock_t *socket, hc_data_t **pdata,
- bool async) {
- // DEBUG("[hc_route_list] async=%s", BOOLSTR(async));
- msg_route_list_t msg = {.header = {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_ROUTE_LIST,
- .length = 0,
- .seq_num = 0,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_LIST,
- .cmd_id = COMMAND_TYPE_ROUTE_LIST,
- .size_in = sizeof(cmd_route_list_item_t),
- .size_out = sizeof(hc_route_t),
- .parse = (HC_PARSE)hc_route_parse,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- pdata, async);
-}
-
-static int _hcng_route_list(hc_sock_t *s, hc_data_t **pdata) {
- return _hcng_route_list_internal(s, pdata, false);
-}
-
-static int _hcng_route_list_async(hc_sock_t *s) {
- return _hcng_route_list_internal(s, NULL, true);
-}
-
-/*----------------------------------------------------------------------------*
- * Face
- *
- * Face support is not directly available in hicn-light, but we can offer such
- * an interface through a combination of listeners and connections. The code
- * starts with some conversion functions between faces/listeners/connections.
- *
- * We also need to make sure that there always exist a (single) listener when
- *a connection is created, and in the hICN face case, that there is a single
- * connection attached to this listener.
- *
- *----------------------------------------------------------------------------*/
-
-/* FACE CREATE */
-
-static int _hcng_face_create(hc_sock_t *socket, hc_face_t *face) {
- hc_listener_t listener;
- hc_listener_t *listener_found;
-
- hc_connection_t connection;
- hc_connection_t *connection_found;
-
- char face_s[MAXSZ_HC_FACE];
- int rc = hc_face_snprintf(face_s, MAXSZ_HC_FACE, face);
- if (rc >= MAXSZ_HC_FACE)
- WARN("[hc_face_create] Unexpected truncation of face string");
- DEBUG("[hc_face_create] face=%s", face_s);
-
- switch (face->face.type) {
- case FACE_TYPE_HICN:
- case FACE_TYPE_TCP:
- case FACE_TYPE_UDP:
- if (hc_face_to_connection(face, &connection, false) < 0) {
- ERROR("[hc_face_create] Could not convert face to connection.");
- return -1;
- }
-
- /* Ensure we have a corresponding local listener */
- if (hc_connection_to_local_listener(&connection, &listener) < 0) {
- ERROR("[hc_face_create] Could not convert face to local listener.");
- return -1;
- }
-
- if (_hcng_listener_get(socket, &listener, &listener_found) < 0) {
- ERROR("[hc_face_create] Could not retrieve listener");
- return -1;
- }
-
- if (!listener_found) {
- /* We need to create the listener if it does not exist */
- if (hc_listener_create(socket, &listener) < 0) {
- ERROR("[hc_face_create] Could not create listener.");
- free(listener_found);
- return -1;
- }
- } else {
- free(listener_found);
- }
-
- /* Create corresponding connection */
- if (_hcng_connection_create(socket, &connection) < 0) {
- ERROR("[hc_face_create] Could not create connection.");
- return -1;
- }
-
- /*
- * Once the connection is created, we need to list all connections
- * and compare with the current one to find the created face ID.
- */
- if (_hcng_connection_get(socket, &connection, &connection_found) < 0) {
- ERROR("[hc_face_create] Could not retrieve connection");
- return -1;
- }
-
- if (!connection_found) {
- ERROR("[hc_face_create] Could not find newly created connection.");
- return -1;
- }
-
- face->id = connection_found->id;
- free(connection_found);
-
- break;
-
- case FACE_TYPE_HICN_LISTENER:
- case FACE_TYPE_TCP_LISTENER:
- case FACE_TYPE_UDP_LISTENER:
- if (hc_face_to_listener(face, &listener) < 0) {
- ERROR("Could not convert face to listener.");
- return -1;
- }
- if (hc_listener_create(socket, &listener) < 0) {
- ERROR("[hc_face_create] Could not create listener.");
- return -1;
- }
- break;
- default:
- ERROR("[hc_face_create] Unknwon face type.");
-
- return -1;
- };
-
- return 0;
-}
-
-static int _hcng_face_get(hc_sock_t *socket, hc_face_t *face,
- hc_face_t **face_found) {
- hc_listener_t listener;
- hc_listener_t *listener_found;
-
- hc_connection_t connection;
- hc_connection_t *connection_found;
-
- char face_s[MAXSZ_HC_FACE];
- int rc = hc_face_snprintf(face_s, MAXSZ_HC_FACE, face);
- if (rc >= MAXSZ_HC_FACE)
- WARN("[hc_face_get] Unexpected truncation of face string");
- DEBUG("[hc_face_get] face=%s", face_s);
-
- switch (face->face.type) {
- case FACE_TYPE_HICN:
- case FACE_TYPE_TCP:
- case FACE_TYPE_UDP:
- if (hc_face_to_connection(face, &connection, false) < 0) return -1;
- if (_hcng_connection_get(socket, &connection, &connection_found) < 0)
- return -1;
- if (!connection_found) {
- *face_found = NULL;
- return 0;
- }
- *face_found = malloc(sizeof(hc_face_t));
- hc_connection_to_face(connection_found, *face_found);
- free(connection_found);
- break;
-
- case FACE_TYPE_HICN_LISTENER:
- case FACE_TYPE_TCP_LISTENER:
- case FACE_TYPE_UDP_LISTENER:
- if (hc_face_to_listener(face, &listener) < 0) return -1;
- if (_hcng_listener_get(socket, &listener, &listener_found) < 0) return -1;
- if (!listener_found) {
- *face_found = NULL;
- return 0;
- }
- *face_found = malloc(sizeof(hc_face_t));
- hc_listener_to_face(listener_found, *face_found);
- free(listener_found);
- break;
-
- default:
- return -1;
- }
-
- return 0;
-}
-
-/* FACE DELETE */
-
-static int _hcng_face_delete(hc_sock_t *socket, hc_face_t *face,
- uint8_t delete_listener) {
- char face_s[MAXSZ_HC_FACE];
- int rc = hc_face_snprintf(face_s, MAXSZ_HC_FACE, face);
- if (rc >= MAXSZ_HC_FACE)
- WARN("[hc_face_delete] Unexpected truncation of face string");
- DEBUG("[hc_face_delete] face=%s", face_s);
-
- hc_connection_t connection;
- if (hc_face_to_connection(face, &connection, false) < 0) {
- ERROR("[hc_face_delete] Could not convert face to connection.");
- return -1;
- }
-
- if (_hcng_connection_delete(socket, &connection) < 0) {
- ERROR("[hc_face_delete] Error removing connection");
- return -1;
- }
-
- if (!delete_listener) {
- return 0;
- }
-
- /* If this is the last connection attached to the listener, remove it */
-
- hc_data_t *connections;
- hc_listener_t listener = {{0}};
-
- /*
- * Ensure we have a corresponding local listener
- * NOTE: hc_face_to_listener is not appropriate
- */
- if (hc_connection_to_local_listener(&connection, &listener) < 0) {
- ERROR("[hc_face_create] Could not convert face to local listener.");
- return -1;
- }
-#if 1
- /*
- * The name is generated to prepare listener creation, we need it to be
- * empty for deletion. The id should not need to be reset though.
- */
- listener.id = 0;
- memset(listener.name, 0, sizeof(listener.name));
-#endif
- if (_hcng_connection_list(socket, &connections) < 0) {
- ERROR("[hc_face_delete] Error getting the list of listeners");
- return -1;
- }
-
- bool delete = true;
- foreach_connection(c, connections) {
- if ((ip_address_cmp(&c->local_addr, &listener.local_addr, c->family) ==
- 0) &&
- (c->local_port == listener.local_port) &&
- (strcmp(c->interface_name, listener.interface_name) == 0)) {
- delete = false;
- }
- }
-
- if (delete) {
- if (_hcng_listener_delete(socket, &listener) < 0) {
- ERROR("[hc_face_delete] Error removing listener");
- return -1;
- }
- }
-
- hc_data_free(connections);
-
- return 0;
-}
-
-/* FACE LIST */
-
-static int _hcng_face_list(hc_sock_t *socket, hc_data_t **pdata) {
- hc_data_t *connection_data;
- hc_face_t face;
-
- DEBUG("[hc_face_list]");
-
- if (_hcng_connection_list(socket, &connection_data) < 0) {
- ERROR("[hc_face_list] Could not list connections.");
- return -1;
- }
-
- hc_data_t *face_data =
- hc_data_create(sizeof(hc_connection_t), sizeof(hc_face_t), NULL);
- foreach_connection(c, connection_data) {
- if (hc_connection_to_face(c, &face) < 0) {
- ERROR("[hc_face_list] Could not convert connection to face.");
- goto ERR;
- }
- hc_data_push(face_data, &face);
- }
-
- *pdata = face_data;
- hc_data_free(connection_data);
- DEBUG("[hc_face_list] done");
- return 0;
-
-ERR:
- hc_data_free(connection_data);
- DEBUG("[hc_face_list] error");
- return -1;
-}
-
-static int hc_connection_parse_to_face(void *in, hc_face_t *face) {
- hc_connection_t connection;
-
- if (hc_connection_parse(in, &connection) < 0) {
- ERROR("[hc_connection_parse_to_face] Could not parse connection");
- return -1;
- }
-
- if (hc_connection_to_face(&connection, face) < 0) {
- ERROR(
- "[hc_connection_parse_to_face] Could not convert connection to "
- "face.");
- return -1;
- }
-
- return 0;
-}
-
-static int _hcng_face_list_async(hc_sock_t *socket) {
- struct {
- cmd_header_t hdr;
- } msg = {
- .hdr =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_CONNECTION_LIST,
- .length = 0,
- .seq_num = 0,
- },
- };
-
- hc_command_params_t params = {
- .cmd = ACTION_LIST,
- .cmd_id = COMMAND_TYPE_CONNECTION_LIST,
- .size_in = sizeof(cmd_connection_list_item_t),
- .size_out = sizeof(hc_face_t),
- .parse = (HC_PARSE)hc_connection_parse_to_face,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, true);
-}
-
-static int _hcng_face_set_admin_state(hc_sock_t *s, const char *conn_id_or_name,
- face_state_t admin_state) {
- return hc_connection_set_admin_state(s, conn_id_or_name, admin_state);
-}
-
-#ifdef WITH_POLICY
-static int _hcng_face_set_priority(hc_sock_t *s, const char *conn_id_or_name,
- uint32_t priority) {
- return hc_connection_set_priority(s, conn_id_or_name, priority);
-}
-
-static int _hcng_face_set_tags(hc_sock_t *s, const char *conn_id_or_name,
- policy_tags_t tags) {
- return hc_connection_set_tags(s, conn_id_or_name, tags);
-}
-#endif // WITH_POLICY
-
-/*----------------------------------------------------------------------------*
- * Punting
- *----------------------------------------------------------------------------*/
-
-static int _hcng_punting_create_internal(hc_sock_t *socket,
- hc_punting_t *punting, bool async) {
- int rc;
-
- if (hc_punting_validate(punting) < 0) return -1;
-
- struct {
- cmd_header_t hdr;
- cmd_punting_add_t payload;
- } msg = {.hdr =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_PUNTING_ADD,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .address = punting->prefix,
- .family = punting->family,
- .len = punting->prefix_len,
- }};
- rc = snprintf(msg.payload.symbolic_or_connid, SYMBOLIC_NAME_LEN, "%d",
- punting->face_id);
- if (rc >= SYMBOLIC_NAME_LEN)
- WARN("[_hc_punting_create] Unexpected truncation of symbolic name string");
-
- hc_command_params_t params = {
- .cmd = ACTION_CREATE,
- .cmd_id = COMMAND_TYPE_PUNTING_ADD,
- .size_in = sizeof(cmd_punting_add_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, async);
-}
-
-static int _hcng_punting_create(hc_sock_t *s, hc_punting_t *punting) {
- return _hcng_punting_create_internal(s, punting, false);
-}
-
-static int _hcng_punting_create_async(hc_sock_t *s, hc_punting_t *punting) {
- return _hcng_punting_create_internal(s, punting, true);
-}
-
-static int _hcng_punting_get(hc_sock_t *s, hc_punting_t *punting,
- hc_punting_t **punting_found) {
- ERROR("hc_punting_get not (yet) implemented.");
- return -1;
-}
-
-static int _hcng_punting_delete(hc_sock_t *s, hc_punting_t *punting) {
- ERROR("hc_punting_delete not (yet) implemented.");
- return -1;
-}
-
-#if 0
-static int hc_punting_parse(void * in, hc_punting_t * punting)
-{
- ERROR("hc_punting_parse not (yet) implemented.");
- return -1;
-}
-#endif
-
-static int _hcng_punting_list(hc_sock_t *s, hc_data_t **pdata) {
- ERROR("hc_punting_list not (yet) implemented.");
- return -1;
-}
-
-/*----------------------------------------------------------------------------*
- * Cache
- *----------------------------------------------------------------------------*/
-
-/* CACHE SET STORE */
-
-static int _hcng_cache_set_store_internal(hc_sock_t *socket, hc_cache_t *cache,
- bool async) {
- msg_cache_set_store_t msg = {
- .header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_CACHE_SET_STORE,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .activate = cache->store,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_STORE,
- .cmd_id = COMMAND_TYPE_CACHE_SET_STORE,
- .size_in = sizeof(cmd_cache_set_store_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, async);
-}
-
-static int _hcng_cache_set_store(hc_sock_t *s, hc_cache_t *cache) {
- return _hcng_cache_set_store_internal(s, cache, false);
-}
-
-static int _hcng_cache_set_store_async(hc_sock_t *s, hc_cache_t *cache) {
- return _hcng_cache_set_store_internal(s, cache, true);
-}
-
-/* CACHE SET SERVE */
-
-static int _hcng_cache_set_serve_internal(hc_sock_t *socket, hc_cache_t *cache,
- bool async) {
- msg_cache_set_serve_t msg = {
- .header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_CACHE_SET_SERVE,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .activate = cache->serve,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_SERVE,
- .cmd_id = COMMAND_TYPE_CACHE_SET_SERVE,
- .size_in = sizeof(cmd_cache_set_serve_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, async);
-}
-
-static int _hcng_cache_set_serve(hc_sock_t *s, hc_cache_t *cache) {
- return _hcng_cache_set_serve_internal(s, cache, false);
-}
-
-static int _hcng_cache_set_serve_async(hc_sock_t *s, hc_cache_t *cache) {
- return _hcng_cache_set_serve_internal(s, cache, true);
-}
-
-/* CACHE CLEAR */
-
-static int _hcng_cache_clear_internal(hc_sock_t *socket, hc_cache_t *cache,
- bool async) {
- msg_cache_clear_t msg = {.header = {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_CACHE_CLEAR,
- .length = 1,
- .seq_num = 0,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_CLEAR,
- .cmd_id = COMMAND_TYPE_CACHE_CLEAR,
- .size_in = sizeof(cmd_cache_clear_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, async);
-}
-
-static int _hcng_cache_clear(hc_sock_t *s, hc_cache_t *cache) {
- return _hcng_cache_clear_internal(s, cache, false);
-}
-
-/* CACHE PARSE */
-
-static int hc_cache_parse(void *in, hc_cache_info_t *cache_info) {
- cmd_cache_list_reply_t *item = (cmd_cache_list_reply_t *)in;
- *cache_info = (hc_cache_info_t){.store = item->store_in_cs,
- .serve = item->serve_from_cs,
- .cs_size = item->cs_size,
- .num_stale_entries = item->num_stale_entries};
-
- return 0;
-}
-
-/* CACHE LIST */
-
-static hc_result_t *_hcng_cache_list_serialize(hc_sock_t *socket,
- hc_data_t **pdata, bool async) {
- hc_result_t *res = malloc(sizeof(*res));
- DEBUG("[hc_cache_list] async=%s", BOOLSTR(async));
-
- msg_cache_list_t msg = {.header = {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_CACHE_LIST,
- .length = 0,
- .seq_num = 0,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_LIST,
- .cmd_id = COMMAND_TYPE_CACHE_LIST,
- .size_in = sizeof(cmd_cache_list_reply_t),
- .size_out = sizeof(hc_cache_info_t),
- .parse = (HC_PARSE)hc_cache_parse,
- };
-
- *res = (hc_result_t){
- .msg =
- (hc_msg_t){
- .hdr = msg.header,
- .payload.cache_list = msg.payload,
- },
- .params = params,
- .async = async,
- .success = true,
- };
- return res;
-}
-
-static int _hcng_cache_list_internal(hc_sock_t *socket, hc_data_t **pdata,
- bool async) {
- hc_result_t *result = _hcng_cache_list_serialize(socket, pdata, async);
-
- int ret = INPUT_ERROR;
- if (result->success) {
- ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
- sizeof(result->msg), &result->params, pdata,
- result->async);
- }
-
- hc_result_free(result);
- return ret;
-}
-
-static int _hcng_cache_list(hc_sock_t *s, hc_data_t **pdata) {
- return _hcng_cache_list_internal(s, pdata, false);
-}
-
-/*----------------------------------------------------------------------------*
- * Strategy
- *----------------------------------------------------------------------------*/
-
-// per prefix
-static hc_result_t *_strategy_set_serialize(hc_sock_t *socket,
- hc_strategy_t *strategy) {
- hc_result_t *res = malloc(sizeof(*res));
-
- char strategy_s[MAXSZ_HC_STRATEGY];
- int rc = strcpy_s(strategy->name, MAXSZ_STRATEGY_NAME,
- strategy_str(strategy->type));
- if (rc != EOK) goto ERR;
- rc = hc_strategy_snprintf(strategy_s, MAXSZ_HC_STRATEGY, strategy);
- if (rc >= MAXSZ_HC_STRATEGY)
- WARN("[_hcng_strategy_create] Unexpected truncation of strategy string");
- DEBUG("[_hcng_strategy_create] strategy=%s", strategy_s);
-
- if (!IS_VALID_FAMILY(strategy->family) ||
- !IS_VALID_STRATEGY_TYPE(strategy->type)) {
- goto ERR;
- }
-
- msg_strategy_set_t msg = {.header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_STRATEGY_SET,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .address = strategy->address,
- .family = strategy->family,
- .len = strategy->len,
- .type = strategy->type,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_SET,
- .cmd_id = COMMAND_TYPE_STRATEGY_SET,
- .size_in = sizeof(cmd_strategy_set_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- *res = (hc_result_t){
- .msg =
- (hc_msg_t){
- .hdr = msg.header,
- .payload.strategy_set = msg.payload,
- },
- .params = params,
- .async = false,
- .success = true,
- };
- return res;
-
-ERR:
- res->success = false;
- return res;
-}
-
-static hc_result_t *_strategy_add_local_prefix_serialize(
- hc_sock_t *socket, hc_strategy_t *strategy) {
- hc_result_t *res = malloc(sizeof(*res));
-
- char strategy_s[MAXSZ_HC_STRATEGY];
- int rc = strcpy_s(strategy->name, MAXSZ_STRATEGY_NAME,
- strategy_str(strategy->type));
- if (rc != EOK) goto ERR;
- rc = hc_strategy_snprintf(strategy_s, MAXSZ_HC_STRATEGY, strategy);
- if (rc >= MAXSZ_HC_STRATEGY)
- WARN("[_hcng_strategy_create] Unexpected truncation of strategy string");
- DEBUG("[_hcng_strategy_create] strategy=%s", strategy_s);
-
- if (!IS_VALID_FAMILY(strategy->family) ||
- !IS_VALID_STRATEGY_TYPE(strategy->type) ||
- !IS_VALID_FAMILY(strategy->local_family)) {
- goto ERR;
- }
-
- msg_strategy_add_local_prefix_t msg = {
- .header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_STRATEGY_ADD_LOCAL_PREFIX,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .type = strategy->type,
- .address = strategy->address,
- .family = strategy->family,
- .len = strategy->len,
- .local_address = strategy->local_address,
- .local_family = strategy->local_family,
- .local_len = strategy->local_len,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_SET,
- .cmd_id = COMMAND_TYPE_STRATEGY_ADD_LOCAL_PREFIX,
- .size_in = sizeof(cmd_strategy_add_local_prefix_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- *res = (hc_result_t){
- .msg =
- (hc_msg_t){
- .hdr = msg.header,
- .payload.strategy_add_local_prefix = msg.payload,
- },
- .params = params,
- .async = false,
- .success = true,
- };
- return res;
-
-ERR:
- res->success = false;
- return res;
-}
-
-static hc_result_t *_hcng_strategy_set_conf(hc_sock_t *s,
- hc_strategy_t *strategy) {
- return _strategy_set_serialize(s, strategy);
-}
-
-static int _hcng_strategy_set(hc_sock_t *socket, hc_strategy_t *strategy) {
- hc_result_t *result = _strategy_set_serialize(socket, strategy);
-
- int ret = INPUT_ERROR;
- if (result->success) {
- ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
- sizeof(result->msg), &result->params, NULL,
- result->async);
- }
-
- hc_result_free(result);
- return ret;
-}
-
-static hc_result_t *_hcng_strategy_add_local_prefix_conf(
- hc_sock_t *s, hc_strategy_t *strategy) {
- return _strategy_add_local_prefix_serialize(s, strategy);
-}
-
-static int _hcng_strategy_add_local_prefix(hc_sock_t *socket,
- hc_strategy_t *strategy) {
- hc_result_t *result = _strategy_add_local_prefix_serialize(socket, strategy);
-
- int ret = INPUT_ERROR;
- if (result->success) {
- ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
- sizeof(result->msg), &result->params, NULL,
- result->async);
- }
-
- hc_result_free(result);
- return ret;
-}
-
-/* How to retrieve that from the forwarder ? */
-static const char *strategies[] = {
- "random",
- "load_balancer",
-};
-
-#define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array))
-
-static int _hcng_strategy_list(hc_sock_t *s, hc_data_t **data) {
- int rc;
-
- *data = hc_data_create(0, sizeof(hc_strategy_t), NULL);
-
- for (unsigned i = 0; i < ARRAY_SIZE(strategies); i++) {
- hc_strategy_t *strategy = (hc_strategy_t *)hc_data_get_next(*data);
- if (!strategy) return -1;
- rc = snprintf(strategy->name, MAXSZ_STRATEGY_NAME, "%s", strategies[i]);
- if (rc >= MAXSZ_STRATEGY_NAME)
- WARN("[hc_strategy_list] Unexpected truncation of strategy name string");
- (*data)->size++;
- }
-
- return 0;
-}
-
-/*----------------------------------------------------------------------------*
- * WLDR
- *----------------------------------------------------------------------------*/
-
-// per connection
-static int _hcng_wldr_set(hc_sock_t *s /* XXX */) { return 0; }
-
-/*----------------------------------------------------------------------------*
- * MAP-Me
- *----------------------------------------------------------------------------*/
-
-static int _hcng_mapme_set(hc_sock_t *socket, int enabled) {
- msg_mapme_enable_t msg = {.header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_MAPME_ENABLE,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .activate = enabled,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_SET,
- .cmd_id = COMMAND_TYPE_MAPME_ENABLE,
- .size_in = sizeof(cmd_mapme_enable_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, false);
-}
-
-static int _hcng_mapme_set_discovery(hc_sock_t *socket, int enabled) {
- msg_mapme_enable_t msg = {
- .header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_MAPME_SET_DISCOVERY,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .activate = enabled,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_SET,
- .cmd_id = COMMAND_TYPE_MAPME_SET_DISCOVERY,
- .size_in = sizeof(cmd_mapme_set_discovery_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, false);
-}
-
-static int _hcng_mapme_set_timescale(hc_sock_t *socket, uint32_t timescale) {
- msg_mapme_set_timescale_t msg = {
- .header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_MAPME_SET_TIMESCALE,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .timePeriod = timescale,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_SET,
- .cmd_id = COMMAND_TYPE_MAPME_SET_TIMESCALE,
- .size_in = sizeof(cmd_mapme_set_timescale_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, false);
-}
-
-static int _hcng_mapme_set_retx(hc_sock_t *socket, uint32_t timescale) {
- msg_mapme_set_retx_t msg = {.header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_MAPME_SET_RETX,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .timePeriod = timescale,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_SET,
- .cmd_id = COMMAND_TYPE_MAPME_SET_RETX,
- .size_in = sizeof(msg_mapme_set_retx_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, false);
-}
-
-static int _hcng_mapme_send_update(hc_sock_t *socket, hc_mapme_t *mapme) {
- if (!IS_VALID_FAMILY(mapme->family)) return -1;
-
- msg_mapme_send_update_t msg = {
- .header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_MAPME_SEND_UPDATE,
- .length = 1,
- .seq_num = 0,
- },
- };
-
- hc_command_params_t params = {
- .cmd = ACTION_UPDATE,
- .cmd_id = COMMAND_TYPE_MAPME_SEND_UPDATE,
- .size_in = sizeof(msg_mapme_send_update_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, false);
-}
-
-/*----------------------------------------------------------------------------*
- * Policy
- *----------------------------------------------------------------------------*/
-
-#ifdef WITH_POLICY
-
-/* POLICY CREATE */
-
-static int _hcng_policy_create_internal(hc_sock_t *socket, hc_policy_t *policy,
- bool async) {
- if (!IS_VALID_FAMILY(policy->family)) return -1;
-
- struct {
- cmd_header_t hdr;
- cmd_policy_add_t payload;
- } msg = {.hdr =
- {
- .message_type = REQUEST_LIGHT,
- COMMAND_TYPE_POLICY_ADD,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .address = policy->remote_addr,
- .family = policy->family,
- .len = policy->len,
- .policy = policy->policy,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_CREATE,
- .cmd_id = COMMAND_TYPE_POLICY_ADD,
- .size_in = sizeof(cmd_policy_add_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, async);
-}
-
-static int _hcng_policy_create(hc_sock_t *s, hc_policy_t *policy) {
- return _hcng_policy_create_internal(s, policy, false);
-}
-
-static int _hcng_policy_create_async(hc_sock_t *s, hc_policy_t *policy) {
- return _hcng_policy_create_internal(s, policy, true);
-}
-
-/* POLICY DELETE */
-
-static int _hcng_policy_delete_internal(hc_sock_t *socket, hc_policy_t *policy,
- bool async) {
- if (!IS_VALID_FAMILY(policy->family)) return -1;
-
- struct {
- cmd_header_t hdr;
- cmd_policy_remove_t payload;
- } msg = {.hdr =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_POLICY_REMOVE,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {
- .address = policy->remote_addr,
- .family = policy->family,
- .len = policy->len,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_DELETE,
- .cmd_id = COMMAND_TYPE_POLICY_REMOVE,
- .size_in = sizeof(cmd_policy_remove_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- NULL, async);
-}
-
-static int _hcng_policy_delete(hc_sock_t *s, hc_policy_t *policy) {
- return _hcng_policy_delete_internal(s, policy, false);
-}
-
-static int _hcng_policy_delete_async(hc_sock_t *s, hc_policy_t *policy) {
- return _hcng_policy_delete_internal(s, policy, true);
-}
-
-/* POLICY PARSE */
-
-static int hc_policy_parse(void *in, hc_policy_t *policy) {
- cmd_policy_list_item_t *item = (cmd_policy_list_item_t *)in;
-
- if (!IS_VALID_ADDRESS(&item->address, item->family)) {
- ERROR("[hc_policy_parse] Invalid address");
- return -1;
- }
- if (!IS_VALID_FAMILY(item->family)) {
- ERROR("[hc_policy_parse] Invalid family");
- return -1;
- }
- if (!IS_VALID_PREFIX_LEN(item->len)) {
- ERROR("[hc_policy_parse] Invalid len");
- return -1;
- }
- if (!IS_VALID_POLICY(item->policy)) {
- ERROR("[hc_policy_parse] Invalid policy");
- return -1;
- }
-
- *policy = (hc_policy_t){
- .family = item->family,
- .remote_addr = item->address,
- .len = item->len,
- .policy = item->policy,
- };
- return 0;
-}
-
-/* POLICY LIST */
-
-static int _hcng_policy_list_internal(hc_sock_t *socket, hc_data_t **pdata,
- bool async) {
- struct {
- cmd_header_t hdr;
- } msg = {
- .hdr =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_POLICY_LIST,
- .length = 0,
- .seq_num = 0,
- },
- };
-
- hc_command_params_t params = {
- .cmd = ACTION_LIST,
- .cmd_id = COMMAND_TYPE_POLICY_LIST,
- .size_in = sizeof(cmd_policy_list_item_t),
- .size_out = sizeof(hc_policy_t),
- .parse = (HC_PARSE)hc_policy_parse,
- };
-
- return _hcng_execute_command(socket, (hc_msg_t *)&msg, sizeof(msg), &params,
- pdata, async);
-}
-
-static int _hcng_policy_list(hc_sock_t *s, hc_data_t **pdata) {
- return _hcng_policy_list_internal(s, pdata, false);
-}
-
-static int _hcng_policy_list_async(hc_sock_t *s, hc_data_t **pdata) {
- return _hcng_policy_list_internal(s, pdata, true);
-}
-
-#endif /* WITH_POLICY */
-
-/*----------------------------------------------------------------------------*
- * Subscriptioins
- *----------------------------------------------------------------------------*/
-
-/* SUBSCRIPTION CREATE */
-
-static hc_result_t *_subscription_create_serialize(
- hc_sock_t *s, hc_subscription_t *subscription) {
- msg_subscription_add_t msg = {
- .header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_SUBSCRIPTION_ADD,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {.topics = subscription->topics}};
-
- hc_command_params_t params = {
- .cmd = ACTION_CREATE,
- .cmd_id = COMMAND_TYPE_SUBSCRIPTION_ADD,
- .size_in = sizeof(cmd_subscription_add_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- hc_result_t *res = malloc(sizeof(*res));
- *res = (hc_result_t){
- .msg =
- (hc_msg_t){
- .hdr = msg.header,
- .payload.subscription_add = msg.payload,
- },
- .params = params,
- .async = false,
- .success = true,
- };
- return res;
-}
-
-static hc_result_t *_hcng_subscription_create_conf(
- hc_sock_t *s, hc_subscription_t *subscription) {
- return _subscription_create_serialize(s, subscription);
-}
-
-static int _hcng_subscription_create(hc_sock_t *socket,
- hc_subscription_t *subscriiption) {
- hc_result_t *result = _subscription_create_serialize(socket, subscriiption);
-
- int ret = INPUT_ERROR;
- if (result->success) {
- ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
- sizeof(result->msg), &result->params, NULL,
- result->async);
- }
-
- hc_result_free(result);
- return ret;
-}
-
-/* SUBSCRIPTION DELETE */
-
-static hc_result_t *_subscription_delete_serialize(
- hc_sock_t *s, hc_subscription_t *subscription) {
- msg_subscription_remove_t msg = {
- .header =
- {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_SUBSCRIPTION_REMOVE,
- .length = 1,
- .seq_num = 0,
- },
- .payload = {.topics = subscription->topics}};
-
- hc_command_params_t params = {
- .cmd = ACTION_DELETE,
- .cmd_id = COMMAND_TYPE_SUBSCRIPTION_REMOVE,
- .size_in = sizeof(cmd_subscription_remove_t),
- .size_out = 0,
- .parse = NULL,
- };
-
- hc_result_t *res = malloc(sizeof(*res));
- *res = (hc_result_t){
- .msg =
- (hc_msg_t){
- .hdr = msg.header,
- .payload.subscription_remove = msg.payload,
- },
- .params = params,
- .async = false,
- .success = true,
- };
- return res;
-}
-
-static hc_result_t *_hcng_subscription_delete_conf(
- hc_sock_t *s, hc_subscription_t *subscription) {
- return _subscription_delete_serialize(s, subscription);
-}
-
-static int _hcng_subscription_delete(hc_sock_t *socket,
- hc_subscription_t *subscriiption) {
- hc_result_t *result = _subscription_delete_serialize(socket, subscriiption);
-
- int ret = INPUT_ERROR;
- if (result->success) {
- ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
- sizeof(result->msg), &result->params, NULL,
- result->async);
- }
-
- hc_result_free(result);
- return ret;
-}
-
-/*----------------------------------------------------------------------------*
- * Statistics
- *----------------------------------------------------------------------------*/
-
-/* STATS GET */
-
-static hc_result_t *_hcng_stats_get_serialize(hc_sock_t *socket,
- hc_data_t **pdata, bool async) {
- hc_result_t *res = malloc(sizeof(*res));
- DEBUG("[hc_stats_get] async=%s", BOOLSTR(async));
-
- msg_stats_get_t msg = {.header = {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_STATS_GET,
- .length = 0,
- .seq_num = 0,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_GET,
- .cmd_id = COMMAND_TYPE_STATS_GET,
- .size_in = sizeof(hicn_light_stats_t),
- .size_out = sizeof(hicn_light_stats_t),
- };
-
- *res = (hc_result_t){
- .msg =
- (hc_msg_t){
- .hdr = msg.header,
- .payload.stats_get = msg.payload,
- },
- .params = params,
- .async = async,
- .success = true,
- };
- return res;
-}
-
-static int _hcng_stats_get_internal(hc_sock_t *socket, hc_data_t **pdata,
- bool async) {
- hc_result_t *result = _hcng_stats_get_serialize(socket, pdata, async);
-
- int ret = INPUT_ERROR;
- if (result->success) {
- ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
- sizeof(result->msg), &result->params, pdata,
- result->async);
- }
-
- hc_result_free(result);
- DEBUG("[_hcng_stats_get] done or error");
- return ret;
-}
-
-static int _hcng_stats_get(hc_sock_t *s, hc_data_t **pdata) {
- DEBUG("[_hcng_stats_get]");
- return _hcng_stats_get_internal(s, pdata, false);
-}
-
-/* STATS LIST */
-
-static hc_result_t *_hcng_stats_list_serialize(hc_sock_t *socket,
- hc_data_t **pdata, bool async) {
- hc_result_t *res = malloc(sizeof(*res));
- DEBUG("[hc_stats_list] async=%s", BOOLSTR(async));
-
- msg_stats_list_t msg = {.header = {
- .message_type = REQUEST_LIGHT,
- .command_id = COMMAND_TYPE_STATS_LIST,
- .length = 0,
- .seq_num = 0,
- }};
-
- hc_command_params_t params = {
- .cmd = ACTION_LIST,
- .cmd_id = COMMAND_TYPE_STATS_LIST,
- .size_in = sizeof(cmd_stats_list_item_t),
- .size_out = sizeof(cmd_stats_list_item_t),
- };
-
- *res = (hc_result_t){
- .msg =
- (hc_msg_t){
- .hdr = msg.header,
- .payload.stats_list = msg.payload,
- },
- .params = params,
- .async = async,
- .success = true,
- };
- return res;
-}
-
-static int _hcng_stats_list_internal(hc_sock_t *socket, hc_data_t **pdata,
- bool async) {
- hc_result_t *result = _hcng_stats_list_serialize(socket, pdata, async);
-
- int ret = INPUT_ERROR;
- if (result->success) {
- ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
- sizeof(result->msg), &result->params, pdata,
- result->async);
- }
-
- hc_result_free(result);
- DEBUG("[_hcng_stats_list] done or error");
- return ret;
-}
-
-static int _hcng_stats_list(hc_sock_t *s, hc_data_t **pdata) {
- DEBUG("[_hcng_stats_list]");
- return _hcng_stats_list_internal(s, pdata, false);
-}
-
-/* RESULT */
-hc_msg_t *_hcng_result_get_msg(hc_result_t *result) { return &result->msg; }
-int _hcng_result_get_cmd_id(hc_result_t *result) {
- return result->params.cmd_id;
-}
-bool _hcng_result_get_success(hc_result_t *result) { return result->success; }
-
-static hc_sock_t hc_sock_light_ng_interface = (hc_sock_t){
- .hc_sock_get_next_seq = _hcng_sock_light_get_next_seq,
- .hc_sock_set_nonblocking = _hcng_sock_light_set_nonblocking,
- .hc_sock_get_fd = _hcng_sock_light_get_fd,
- .hc_sock_connect = _hcng_sock_light_connect,
- .hc_sock_get_available = _hcng_sock_light_get_available,
- .hc_sock_send = _hcng_sock_light_send,
- .hc_sock_recv = _hcng_sock_light_recv,
- .hc_sock_process = _hcng_sock_light_process,
- .hc_sock_callback = _hcng_sock_light_callback,
- .hc_sock_reset = _hcng_sock_light_reset,
- .hc_sock_free = _hcng_sock_light_free,
- .hc_sock_increment_woff = _hcng_sock_increment_woff,
- .hc_sock_prepare_send = _hcng_sock_prepare_send,
- .hc_sock_set_recv_timeout_ms = _hcng_sock_set_recv_timeout_ms,
- .hc_listener_create = _hcng_listener_create,
- .hc_listener_create_async = _hcng_listener_create_async,
- .hc_listener_get = _hcng_listener_get,
- .hc_listener_delete = _hcng_listener_delete,
- .hc_listener_delete_async = _hcng_listener_delete_async,
- .hc_listener_list = _hcng_listener_list,
- .hc_listener_list_async = _hcng_listener_list_async,
- .hc_connection_create = _hcng_connection_create,
- .hc_connection_create_async = _hcng_connection_create_async,
- .hc_connection_get = _hcng_connection_get,
- .hc_connection_update_by_id = _hcng_connection_update_by_id,
- .hc_connection_update = _hcng_connection_update,
- .hc_connection_delete = _hcng_connection_delete,
- .hc_connection_delete_async = _hcng_connection_delete_async,
- .hc_connection_list = _hcng_connection_list,
- .hc_connection_list_async = _hcng_connection_list_async,
- .hc_connection_set_admin_state = _hcng_connection_set_admin_state,
- .hc_connection_set_admin_state_async =
- _hcng_connection_set_admin_state_async,
-
-#ifdef WITH_POLICY
- .hc_connection_set_priority = _hcng_connection_set_priority,
- .hc_connection_set_priority_async = _hcng_connection_set_priority_async,
- .hc_connection_set_tags = _hcng_connection_set_tags,
- .hc_connection_set_tags_async = _hcng_connection_set_tags_async,
-#endif // WITH_POLICY
-
- .hc_face_create = _hcng_face_create,
- .hc_face_get = _hcng_face_get,
- .hc_face_delete = _hcng_face_delete,
- .hc_face_list = _hcng_face_list,
- .hc_face_list_async = _hcng_face_list_async,
- .hc_face_set_admin_state = _hcng_face_set_admin_state,
-
-#ifdef WITH_POLICY
- .hc_face_set_priority = _hcng_face_set_priority,
- .hc_face_set_tags = _hcng_face_set_tags,
-#endif // WITH_POLICY
- .hc_subscription_create = _hcng_subscription_create,
- .hc_subscription_delete = _hcng_subscription_delete,
-
- .hc_stats_get = _hcng_stats_get,
- .hc_stats_list = _hcng_stats_list,
-
- .hc_route_create = _hcng_route_create,
- .hc_route_create_async = _hcng_route_create_async,
- .hc_route_delete = _hcng_route_delete,
- .hc_route_delete_async = _hcng_route_delete_async,
- .hc_route_list = _hcng_route_list,
- .hc_route_list_async = _hcng_route_list_async,
-
- .hc_punting_create = _hcng_punting_create,
- .hc_punting_create_async = _hcng_punting_create_async,
- .hc_punting_get = _hcng_punting_get,
- .hc_punting_delete = _hcng_punting_delete,
- .hc_punting_list = _hcng_punting_list,
-
- .hc_cache_set_store = _hcng_cache_set_store,
- .hc_cache_set_store_async = _hcng_cache_set_store_async,
- .hc_cache_set_serve = _hcng_cache_set_serve,
- .hc_cache_set_serve_async = _hcng_cache_set_serve_async,
- .hc_cache_clear = _hcng_cache_clear,
- .hc_cache_list = _hcng_cache_list,
-
- .hc_strategy_list = _hcng_strategy_list,
- .hc_strategy_set = _hcng_strategy_set,
- .hc_strategy_add_local_prefix = _hcng_strategy_add_local_prefix,
- .hc_wldr_set = _hcng_wldr_set,
-
- .hc_mapme_set = _hcng_mapme_set,
- .hc_mapme_set_discovery = _hcng_mapme_set_discovery,
- .hc_mapme_set_timescale = _hcng_mapme_set_timescale,
- .hc_mapme_set_retx = _hcng_mapme_set_retx,
- .hc_mapme_send_update = _hcng_mapme_send_update,
-
-#ifdef WITH_POLICY
- .hc_policy_create = _hcng_policy_create,
- .hc_policy_create_async = _hcng_policy_create_async,
- .hc_policy_delete = _hcng_policy_delete,
- .hc_policy_delete_async = _hcng_policy_delete_async,
- .hc_policy_list = _hcng_policy_list,
- .hc_policy_list_async = _hcng_policy_list_async,
-#endif // WITH_POLICY
-
- .hc_listener_create_conf = _hcng_listener_create_conf,
- .hc_listener_list_conf = _hcng_listener_list_conf,
- .hc_connection_create_conf = _hcng_connection_create_conf,
- .hc_connection_delete_conf = _hcng_connection_delete_conf,
- .hc_route_create_conf = _hcng_route_create_conf,
- .hc_strategy_set_conf = _hcng_strategy_set_conf,
- .hc_strategy_add_local_prefix_conf = _hcng_strategy_add_local_prefix_conf,
- .hc_subscription_create_conf = _hcng_subscription_create_conf,
- .hc_subscription_delete_conf = _hcng_subscription_delete_conf,
-
- .hc_result_get_msg = _hcng_result_get_msg,
- .hc_result_get_cmd_id = _hcng_result_get_cmd_id,
- .hc_result_get_success = _hcng_result_get_success,
-};
-
-// Public contructors
-
-hc_sock_t *_hc_sock_create_url(const char *url) {
- hc_sock_light_t *s = malloc(sizeof(hc_sock_light_t));
- if (!s) goto ERR_MALLOC;
-
- s->vft = hc_sock_light_ng_interface;
- s->url = url ? strdup(url) : NULL;
-
- s->fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (s->fd < 0) goto ERR_SOCKET;
-
- if (_hcng_sock_set_recv_timeout_ms((hc_sock_t *)s,
- DEFAULT_SOCK_RECV_TIMEOUT_MS) < 0)
- goto ERR_SOCKET;
-
- if (_hcng_sock_light_reset((hc_sock_t *)s) < 0) goto ERR_RESET;
-
- s->seq = 0;
- s->cur_request = NULL;
-
- s->map = kh_init_sock_map();
- if (!s->map) goto ERR_MAP;
-
- return (hc_sock_t *)(s);
-
- // hc_sock_light_map_free(s->map);
-ERR_MAP:
-ERR_RESET:
- if (s->url) free(s->url);
- close(s->fd);
-ERR_SOCKET:
- free(s);
-ERR_MALLOC:
- return NULL;
-}
diff --git a/ctrl/libhicnctrl/src/modules/hicn_plugin.c b/ctrl/libhicnctrl/src/modules/hicn_plugin.c
new file mode 100644
index 000000000..b3963b46c
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_plugin.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file api.c
+ * \brief Implementation of hICN control library API
+ */
+
+#include <assert.h> // assert
+#include <fcntl.h> // fcntl
+#include <math.h> // log2
+#include <stdbool.h>
+#include <stdio.h> // snprintf
+#include <string.h> // memmove, strcasecmp
+#include <sys/socket.h> // socket
+#include <unistd.h> // close, fcntl
+
+#include <hicn/ctrl/data.h>
+#include <hicn/ctrl/socket.h>
+
+#include <vapi/vapi_safe.h>
+#include <vppinfra/clib.h>
+#include <vpp_plugins/hicn/error.h>
+
+#include "../socket_private.h"
+
+#include "hicn_plugin/base.h" // hc_sock_vpp_data_t
+#include "hicn_plugin/listener.h"
+#include "hicn_plugin/route.h"
+
+/******************************************************************************
+ * Message helper types and aliases
+ ******************************************************************************/
+
+#if 0
+
+#define foreach_hc_command \
+ _(hicn_api_node_params_set) \
+ _(hicn_api_node_params_set_reply) \
+ _(hicn_api_node_params_get_reply) \
+ _(hicn_api_node_stats_get_reply) \
+ _(hicn_api_face_get) \
+ _(hicn_api_faces_details) \
+ _(hicn_api_face_stats_details) \
+ _(hicn_api_face_get_reply) \
+ _(hicn_api_route_get) \
+ _(hicn_api_route_get_reply) \
+ _(hicn_api_routes_details) \
+ _(hicn_api_strategies_get_reply) \
+ _(hicn_api_strategy_get) \
+ _(hicn_api_strategy_get_reply)
+
+
+typedef vapi_type_msg_header2_t hc_msg_header_t;
+
+typedef union {
+#define _(a) vapi_payload_##a a;
+ foreach_hc_command
+#undef _
+} hc_msg_payload_t;
+
+typedef struct __attribute__((__packed__)) {
+ hc_msg_header_t hdr;
+ hc_msg_payload_t payload;
+} hc_hicnp_t;
+
+typedef void (*NTOH)(void *msg);
+
+typedef struct __attribute__((__packed__)) {
+ hc_data_t *data;
+ uint32_t curr_msg;
+} callback_ctx_t;
+
+typedef struct __attribute__((__packed__)) {
+ hc_hicnp_t *msg;
+ vapi_cb_t callback;
+ callback_ctx_t *callback_ctx;
+ NTOH ntoh;
+} hc_msg_s;
+
+/******************************************************************************
+ * Control socket
+ ******************************************************************************/
+
+static void vpp_free(hc_sock_t *socket) {
+ hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket);
+ if (s->url) free(s->url);
+ free(s);
+
+ vapi_disconnect_safe();
+}
+
+static int vpp_get_next_seq(hc_sock_t *socket) {
+ hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket);
+ return vapi_gen_req_context(s->g_vapi_ctx_instance);
+}
+
+static int vpp_set_nonblocking(hc_sock_t *socket) {
+ hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket);
+ return 0;
+}
+
+static int vpp_callback(hc_sock_t *socket, hc_data_t **pdata) {
+ // NOT IMPLEMENTED
+ return -1;
+}
+
+static int vpp_reset(hc_sock_t *socket) {
+ // NOT IMPLEMENTED
+ return -1;
+}
+#endif
+
+/*----------------------------------------------------------------------------*
+ * Listeners
+ *----------------------------------------------------------------------------*/
+
+/******************************************************************************
+ * Module functions
+ ******************************************************************************/
+
+hc_sock_vpp_data_t *hc_sock_vpp_data_create(const char *url) {
+ hc_sock_vpp_data_t *s = malloc(sizeof(hc_sock_vpp_data_t));
+ if (!s) goto ERR_MALLOC;
+
+ s->roff = s->woff = 0;
+ s->url = url ? strdup(url) : NULL;
+
+ return s;
+
+ERR_MALLOC:
+ return NULL;
+}
+
+void hc_sock_vpp_data_free(hc_sock_vpp_data_t *s) {
+ vapi_disconnect_safe();
+
+ if (s->url) free(s->url);
+ free(s);
+}
+
+static int vpp_connect(hc_sock_t *sock) {
+ hc_sock_vpp_data_t *s = (hc_sock_vpp_data_t *)sock->data;
+ vapi_error_e rv =
+ vapi_connect_safe(&s->g_vapi_ctx_instance, hc_sock_is_async(sock));
+ if (rv != VAPI_OK) goto ERR_CONNECT;
+
+ return 0;
+
+ERR_CONNECT:
+ ERROR("[hc_sock_connect] connection failed");
+ return -1;
+}
+
+static ssize_t vpp_prepare(hc_sock_t *sock, hc_request_t *request,
+ uint8_t **buffer) {
+ assert(!buffer);
+
+ // XXX all the beginning is generic and could be shared across multiple
+ // modules
+
+ /* Dispatch to subrequest if any */
+ hc_request_t *current_request = hc_request_get_current(request);
+
+ _ASSERT(!hc_request_get_data(current_request));
+
+ hc_action_t action = hc_request_get_action(current_request);
+ hc_object_type_t object_type = hc_request_get_object_type(current_request);
+ hc_object_t *object = hc_request_get_object(current_request);
+
+ _ASSERT(hc_request_get_data(current_request) == NULL);
+ hc_data_t *data = hc_data_create(object_type);
+ if (!data) {
+ ERROR("[vpp_prepare] Could not create data storage");
+ goto ERR;
+ }
+ hc_request_set_data(current_request, data);
+
+ hc_module_object_ops_t *vft = &sock->ops.object_vft[object_type];
+ if (!vft) goto ERR;
+ hc_execute_t execute = vft->execute[action];
+ if (!execute) goto ERR;
+ int rc = execute(sock, object, data);
+ if (rc < 0) goto ERR;
+
+ /* The result is fully contained in data */
+ (void)rc;
+
+ hc_request_set_complete(request);
+ return 0;
+
+ERR:
+ hc_data_set_error(data);
+ hc_request_set_complete(request);
+ return 0;
+}
+
+static hc_sock_ops_t hc_sock_vpp = (hc_sock_ops_t){
+ .create_data = (void *(*)(const char *))hc_sock_vpp_data_create,
+ .free_data = (void (*)(void *))hc_sock_vpp_data_free,
+ .get_fd = NULL, // not fd based
+ .get_recv_buffer = NULL, // no async support
+ .connect = vpp_connect,
+ .prepare = vpp_prepare,
+ .send = NULL,
+ .recv = NULL,
+ .process = NULL,
+};
+
+ssize_t vpp_command_serialize(hc_action_t action, hc_object_type_t object_type,
+ hc_object_t *object, uint8_t *msg) {
+ return hc_sock_vpp.object_vft[object_type].serialize[action](object, msg);
+}
+
+// Public constructor
+
+int hc_sock_initialize_module(hc_sock_t *s) {
+ s->ops = hc_sock_vpp;
+ // XXX shall we memset the VFT ?
+ /* LISTENER: CREATE, GET, DELETE not implemented, LIST ok */
+ s->ops.object_vft[OBJECT_TYPE_LISTENER] = vpp_listener_module_ops;
+ /* CONNECTION : CREATE, GET, UPDATE, DELETE, LIST, SET_* not
+ implemented */
+ s->ops.object_vft[OBJECT_TYPE_CONNECTION] = HC_MODULE_OBJECT_OPS_EMPTY;
+ s->ops.object_vft[OBJECT_TYPE_FACE] = HC_MODULE_OBJECT_OPS_EMPTY;
+ s->ops.object_vft[OBJECT_TYPE_PUNTING] = HC_MODULE_OBJECT_OPS_EMPTY;
+ s->ops.object_vft[OBJECT_TYPE_CACHE] = HC_MODULE_OBJECT_OPS_EMPTY;
+ s->ops.object_vft[OBJECT_TYPE_MAPME] = HC_MODULE_OBJECT_OPS_EMPTY;
+ s->ops.object_vft[OBJECT_TYPE_WLDR] = HC_MODULE_OBJECT_OPS_EMPTY;
+ s->ops.object_vft[OBJECT_TYPE_POLICY] = HC_MODULE_OBJECT_OPS_EMPTY;
+ s->ops.object_vft[OBJECT_TYPE_ROUTE] = vpp_route_module_ops;
+ s->ops.object_vft[OBJECT_TYPE_STRATEGY] = HC_MODULE_OBJECT_OPS_EMPTY;
+ s->ops.object_vft[OBJECT_TYPE_SUBSCRIPTION] = HC_MODULE_OBJECT_OPS_EMPTY;
+ return 0;
+}
diff --git a/ctrl/libhicnctrl/src/modules/hicn_plugin/base.h b/ctrl/libhicnctrl/src/modules/hicn_plugin/base.h
new file mode 100644
index 000000000..05565e938
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_plugin/base.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file modules/hicn_plugin/base.h
+ * \brief Base structures for hICN plugin module
+ */
+
+#include <vapi/vapi_safe.h>
+#include "../../module.h"
+#include "../../socket_private.h"
+
+typedef struct {
+ vapi_ctx_t g_vapi_ctx_instance;
+ char *url;
+
+ size_t roff; /**< Read offset */
+ size_t woff; /**< Write offset */
+ u32 buffer[RECV_BUFLEN];
+ /* Next sequence number to be used for requests */
+ int seq;
+
+ bool async;
+} hc_sock_vpp_data_t;
diff --git a/ctrl/libhicnctrl/src/modules/hicn_plugin/listener.c b/ctrl/libhicnctrl/src/modules/hicn_plugin/listener.c
new file mode 100644
index 000000000..f0aa4e884
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_plugin/listener.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file modules/hicn_plugin/listener.c
+ * \brief Implementation of listener object VFT for hicn_plugin.
+ */
+
+#include <hicn/util/vector.h>
+
+#include "base.h"
+#include "listener.h"
+
+struct listener_data_s {
+ hc_listener_t listener;
+ hc_data_t *data;
+};
+
+/**
+ * This is a callback used to append in callback_ctx which is a hc_data_t
+ * designed to hold hc_listener_t, a list of listener, each corresponding to an
+ * IP address (v4 then v6) of the interfaces, and thus build a list of hICN
+ * listeners.
+ */
+static vapi_error_e process_ip_info(struct vapi_ctx_s *ctx, void *callback_ctx,
+ vapi_error_e rv, bool is_last,
+ vapi_payload_ip_address_details *reply) {
+ if (reply == NULL || rv != VAPI_OK) return rv;
+ if (reply && is_last) printf("COUCOU\n");
+ if (is_last) return 0;
+
+ struct listener_data_s *ld = (struct listener_data_s *)callback_ctx;
+
+ if (reply->prefix.address.af == ADDRESS_IP4) {
+ memcpy(&(ld->listener.local_addr), reply->prefix.address.un.ip4,
+ IPV4_ADDR_LEN);
+ ld->listener.family = AF_INET;
+ } else {
+ memcpy(&(ld->listener.local_addr), reply->prefix.address.un.ip6,
+ IPV6_ADDR_LEN);
+ ld->listener.family = AF_INET6;
+ }
+ ld->listener.local_port = 0;
+
+ ld->listener.id = reply->sw_if_index;
+ hc_data_t *data = ld->data;
+ hc_listener_t *listener = &ld->listener;
+ hc_data_push(data, listener);
+
+ return rv;
+}
+
+/* LISTENER LIST */
+
+typedef struct {
+ u32 swif;
+ char interface_name[INTERFACE_LEN];
+} hc_vapi_interface_t;
+
+/*
+ * A pointer to hc_data_t is passed in the callback context
+ * Objective is to store a vector of hc_vapi_interface_t inside
+ */
+static vapi_error_e on_listener_list_complete_cb(
+ struct vapi_ctx_s *ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
+ vapi_payload_sw_interface_details *reply) {
+ if (reply == NULL || rv != VAPI_OK) return rv;
+
+ if (is_last) return 0;
+
+ hc_vapi_interface_t **vpp_interfaces_vec =
+ (hc_vapi_interface_t **)callback_ctx;
+
+ hc_vapi_interface_t interface = {.swif = reply->sw_if_index};
+ // XXX bug
+ memcpy(interface.interface_name, reply->interface_name, INTERFACE_LEN);
+
+ vector_push(*vpp_interfaces_vec, interface);
+
+ return rv;
+}
+
+static int _vpp_listener_list(hc_sock_t *sock, hc_data_t *data) {
+ hc_sock_vpp_data_t *s = (hc_sock_vpp_data_t *)sock->data;
+
+ int retval = -1; // VAPI_OK;
+
+ hc_vapi_interface_t *vpp_interfaces_vec = NULL;
+ vector_init(vpp_interfaces_vec, 0, 0);
+
+ vapi_lock();
+
+ vapi_msg_sw_interface_dump *msg =
+ vapi_alloc_sw_interface_dump(s->g_vapi_ctx_instance);
+ if (!msg) {
+ retval = VAPI_ENOMEM;
+ goto ERR_MSG;
+ }
+ msg->payload.sw_if_index = ~0;
+ msg->payload.name_filter_valid = 0;
+
+ /* Retrieve the list of interfaces in vpp_interfaces_vec */
+ int ret =
+ vapi_sw_interface_dump(s->g_vapi_ctx_instance, msg,
+ on_listener_list_complete_cb, &vpp_interfaces_vec);
+
+ if (ret != VAPI_OK) goto ERR_LIST_INTERFACES;
+
+ /* Query the forwarder for each interface */
+ // stored in data->buffer == hc_vapi_interface_t* []
+ // 2 calls for each interface
+ //
+ // This function is called twice for each interface, to get resp. the v4 and
+ // v6 IP addresses associated to it:
+ // ip_address_dump(sw_if_index, is_ipv6)
+ //
+ // Function call :
+ // vapi_msg_XXX *msg = vapi_alloc_XXX(s->g_vapi_ctx_instance);
+ // msg->payload.ATTR = VALUE;
+ // [...]
+ // int ret = vapi_XXX((s->g_vapi_ctx_instance, msg, CALLBACK, USER_DATA);
+ //
+ // CALLBACK = process_ip_info
+ // USER_DATA = data2
+ //
+ // We can assume the callbacks are executed before the function returns, and
+ // that there is no async code.
+ //
+ int rc;
+
+ hc_vapi_interface_t *interface;
+ vapi_msg_ip_address_dump *msg2;
+
+ struct listener_data_s ld;
+ vector_foreach(vpp_interfaces_vec, interface, {
+ memset(&ld, 0, sizeof(struct listener_data_s));
+ ld.listener.type = FACE_TYPE_HICN;
+ rc = snprintf(ld.listener.interface_name, INTERFACE_LEN, "%s",
+ interface->interface_name);
+ if (rc < 0 || rc >= INTERFACE_LEN) goto ERR_FOREACH;
+
+ ld.data = data;
+
+ for (unsigned i = 0; i < 2; i++) {
+ msg2 = vapi_alloc_ip_address_dump(s->g_vapi_ctx_instance);
+ msg2->payload.sw_if_index = interface->swif;
+ msg2->payload.is_ipv6 = i;
+ retval = vapi_ip_address_dump(s->g_vapi_ctx_instance, msg2,
+ process_ip_info, &ld);
+ if (ret != VAPI_OK) goto ERR_GET_IP;
+ }
+ });
+ retval = 0;
+ERR_GET_IP:
+ERR_FOREACH:
+ vector_free(vpp_interfaces_vec);
+ERR_LIST_INTERFACES:
+ERR_MSG:
+ vapi_unlock();
+ return retval;
+}
+
+#define vpp_listener_create NULL
+#define vpp_listener_delete NULL
+
+static int vpp_listener_list(hc_sock_t *sock, hc_object_t *object,
+ hc_data_t *data) {
+ assert(!object || hc_object_is_empty(object));
+ return _vpp_listener_list(sock, data);
+}
+
+DECLARE_VPP_MODULE_OBJECT_OPS(vpp, listener);
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light_common.c b/ctrl/libhicnctrl/src/modules/hicn_plugin/listener.h
index d1fb33993..f75c58db6 100644
--- a/ctrl/libhicnctrl/src/modules/hicn_light_common.c
+++ b/ctrl/libhicnctrl/src/modules/hicn_plugin/listener.h
@@ -13,18 +13,16 @@
* limitations under the License.
*/
-#include "hicn_light_common.h"
+/**
+ * \file modules/hicn_plugin/listener.h
+ * \brief listener object VFT for hicn_plugin.
+ */
+
+#ifndef HICNCTRL_MODULE_VPP_LISTENER_H
+#define HICNCTRL_MODULE_VPP_LISTENER_H
-hc_sock_request_t *hc_sock_request_create(int seq, hc_data_t *data,
- HC_PARSE parse) {
- assert(data);
+#include "../../module.h"
- hc_sock_request_t *request = malloc(sizeof(hc_sock_request_t));
- if (!request) return NULL;
- request->seq = seq;
- request->data = data;
- request->parse = parse;
- return request;
-}
+DECLARE_MODULE_OBJECT_OPS_H(vpp, listener);
-void hc_sock_light_request_free(hc_sock_request_t *request) { free(request); }
+#endif /* HICNCTRL_MODULE_VPP_LISTENER_H */
diff --git a/ctrl/libhicnctrl/src/modules/hicn_plugin/route.c b/ctrl/libhicnctrl/src/modules/hicn_plugin/route.c
new file mode 100644
index 000000000..45aced9cb
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_plugin/route.c
@@ -0,0 +1,541 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file modules/hicn_plugin/route.c
+ * \brief Implementation of route object VFT for hicn_plugin.
+ */
+
+#include "base.h"
+#include "route.h"
+
+static vapi_error_e create_udp_tunnel_cb(
+ vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
+ vapi_payload_hicn_api_udp_tunnel_add_del_reply *reply) {
+ if (reply == NULL || rv != VAPI_OK) return rv;
+
+ if (reply->retval != VAPI_OK) return reply->retval;
+
+ u32 *uei = (u32 *)callback_ctx;
+ *uei = reply->uei;
+
+ return reply->retval;
+}
+
+static vapi_error_e parse_route_create(
+ vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
+ vapi_payload_ip_route_add_del_reply *reply) {
+ if (reply == NULL || rv != VAPI_OK) return rv;
+
+ if (reply->retval != VAPI_OK) return reply->retval;
+
+ return reply->retval;
+}
+
+static vapi_error_e hicn_enable_cb(
+ vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
+ vapi_payload_hicn_api_enable_disable_reply *reply) {
+ if (reply == NULL || rv != VAPI_OK) return rv;
+ face_id_t *faceid = (face_id_t *)callback_ctx;
+
+ if (reply->nfaces) {
+ *faceid = reply->faceids[0];
+ }
+
+ return reply->retval;
+}
+
+static int _vpp_route_create(hc_sock_t *sock, hc_route_t *route) {
+ if (!IS_VALID_FAMILY(route->family)) return -1;
+
+ hc_sock_vpp_data_t *s = (hc_sock_vpp_data_t *)sock->data;
+ int ret = -1;
+ vapi_lock();
+
+ vapi_msg_ip_route_add_del *msg =
+ vapi_alloc_ip_route_add_del(s->g_vapi_ctx_instance, 1);
+
+ msg->payload.is_add = 1;
+ if (route->family == AF_INET) {
+ memcpy(&msg->payload.route.prefix.address.un.ip4[0], &route->remote_addr.v4,
+ 4);
+ msg->payload.route.prefix.address.af = ADDRESS_IP4;
+ msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP4;
+ } else {
+ memcpy(&msg->payload.route.prefix.address.un.ip6[0], &route->remote_addr.v6,
+ 16);
+ msg->payload.route.prefix.address.af = ADDRESS_IP6;
+ msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP6;
+ }
+
+ msg->payload.route.prefix.len = route->len;
+
+ msg->payload.route.paths[0].sw_if_index = ~0;
+ msg->payload.route.paths[0].table_id = 0;
+
+ hc_face_t *face = &(route->face);
+
+ face->netdevice.index = ~0;
+ face->id = INVALID_FACE_ID;
+
+ switch (face->type) {
+ case FACE_TYPE_HICN: {
+ if (hicn_ip_address_is_v4(&(face->remote_addr))) {
+ memcpy(&(msg->payload.route.paths[0].nh.address.ip4),
+ &face->remote_addr.v4, sizeof(ip4_address_t));
+ msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP4;
+ } else {
+ memcpy(&(msg->payload.route.paths[0].nh.address.ip6),
+ &face->remote_addr.v6, sizeof(ip6_address_t));
+ msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP6;
+ }
+
+ msg->payload.route.paths[0].type = FIB_API_PATH_TYPE_NORMAL;
+ msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE;
+
+ break;
+ }
+ case FACE_TYPE_UDP: {
+ vapi_msg_hicn_api_udp_tunnel_add_del *msg2 = NULL;
+ u32 uei = ~0;
+
+ if (hicn_ip_address_is_v4(&(face->remote_addr)) &&
+ hicn_ip_address_is_v4(&(face->local_addr))) {
+ msg2 = vapi_alloc_hicn_api_udp_tunnel_add_del(s->g_vapi_ctx_instance);
+ memcpy(msg2->payload.src_addr.un.ip4, &face->local_addr.v4,
+ sizeof(ip4_address_t));
+ msg2->payload.src_addr.af = ADDRESS_IP4;
+
+ memcpy(msg2->payload.dst_addr.un.ip4, &face->remote_addr.v4,
+ sizeof(ip4_address_t));
+ msg2->payload.dst_addr.af = ADDRESS_IP4;
+
+ } else if (!hicn_ip_address_is_v4(&(route->face.remote_addr)) &&
+ !hicn_ip_address_is_v4(&(route->face.local_addr))) {
+ msg2 = vapi_alloc_hicn_api_udp_tunnel_add_del(s->g_vapi_ctx_instance);
+ memcpy(msg2->payload.src_addr.un.ip6, &face->local_addr.v6,
+ sizeof(ip6_address_t));
+ msg2->payload.src_addr.af = ADDRESS_IP6;
+
+ memcpy(msg2->payload.dst_addr.un.ip6, &face->remote_addr.v6,
+ sizeof(ip6_address_t));
+ msg2->payload.dst_addr.af = ADDRESS_IP6;
+ } else {
+ // NOT IMPLEMENTED
+ ret = -1;
+ goto done;
+ }
+
+ msg2->payload.src_port = face->local_port;
+ msg2->payload.dst_port = face->remote_port;
+ msg2->payload.is_add = 1;
+
+ int ret = vapi_hicn_api_udp_tunnel_add_del(s->g_vapi_ctx_instance, msg2,
+ create_udp_tunnel_cb, &uei);
+
+ if (ret) {
+ ERROR("Error in vapi_hicn_api_udp_tunnel_add_del");
+ vapi_msg_free(s->g_vapi_ctx_instance, msg);
+ goto done;
+ }
+
+ msg->payload.route.paths[0].type = FIB_API_PATH_TYPE_UDP_ENCAP;
+ msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE;
+ msg->payload.route.paths[0].nh.obj_id = uei;
+
+ face->netdevice.index = uei;
+
+ break;
+ }
+ default:
+ ret = -1;
+ goto done;
+ }
+
+ ret = vapi_ip_route_add_del(s->g_vapi_ctx_instance, msg, parse_route_create,
+ NULL);
+
+ if (ret) {
+ ERROR("Error in vapi_ip_route_add_del");
+ goto done;
+ }
+
+ vapi_msg_hicn_api_enable_disable *msg3 =
+ vapi_alloc_hicn_api_enable_disable(s->g_vapi_ctx_instance);
+
+ if (route->family == AF_INET) {
+ memcpy(&msg3->payload.prefix.address.un.ip4[0], &route->remote_addr.v4, 4);
+ msg3->payload.prefix.address.af = ADDRESS_IP4;
+ } else {
+ memcpy(&msg3->payload.prefix.address.un.ip6[0], &route->remote_addr.v6, 16);
+ msg3->payload.prefix.address.af = ADDRESS_IP6;
+ }
+
+ msg3->payload.prefix.len = route->len;
+ msg3->payload.enable_disable = 1;
+
+ ret = vapi_hicn_api_enable_disable(s->g_vapi_ctx_instance, msg3,
+ hicn_enable_cb, &face->id);
+
+ if (ret) {
+ ERROR("Error in vapi_hicn_api_enable_disable");
+ }
+
+done:
+ vapi_unlock();
+ return ret;
+}
+
+static vapi_error_e hicn_disable_cb(
+ vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
+ vapi_payload_hicn_api_enable_disable_reply *reply) {
+ if (reply == NULL || rv != VAPI_OK) return rv;
+
+ return reply->retval;
+}
+
+static vapi_error_e parse_route_delete(
+ vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
+ vapi_payload_ip_route_add_del_reply *reply) {
+ if (reply == NULL || rv != VAPI_OK) return rv;
+
+ return reply->retval;
+}
+
+static int _vpp_route_delete(hc_sock_t *sock, hc_route_t *route) {
+ if (!IS_VALID_FAMILY(route->family)) return -1;
+
+ hc_sock_vpp_data_t *s = (hc_sock_vpp_data_t *)sock->data;
+
+ vapi_lock();
+
+ vapi_msg_hicn_api_enable_disable *msg =
+ vapi_alloc_hicn_api_enable_disable(s->g_vapi_ctx_instance);
+
+ if (route->family == AF_INET) {
+ memcpy(&msg->payload.prefix.address.un.ip4[0], &route->remote_addr.v4, 4);
+ msg->payload.prefix.address.af = ADDRESS_IP4;
+ } else {
+ memcpy(&msg->payload.prefix.address.un.ip6[0], &route->remote_addr.v6, 16);
+ msg->payload.prefix.address.af = ADDRESS_IP6;
+ }
+
+ msg->payload.prefix.len = route->len;
+ msg->payload.enable_disable = 0;
+
+ vapi_error_e ret = vapi_hicn_api_enable_disable(s->g_vapi_ctx_instance, msg,
+ hicn_disable_cb, NULL);
+
+ if (ret) {
+ ERROR("Error in vapi_hicn_api_enable_disable in route delete");
+ goto done;
+ }
+
+ vapi_msg_ip_route_add_del *msg2 =
+ vapi_alloc_ip_route_add_del(s->g_vapi_ctx_instance, 1);
+
+ msg2->payload.is_add = 0;
+ if (route->family == AF_INET) {
+ memcpy(&msg2->payload.route.prefix.address.un.ip4[0],
+ &route->remote_addr.v4, 4);
+ msg2->payload.route.prefix.address.af = ADDRESS_IP4;
+ } else {
+ memcpy(&msg2->payload.route.prefix.address.un.ip6[0],
+ &route->remote_addr.v6, 16);
+ msg2->payload.route.prefix.address.af = ADDRESS_IP6;
+ }
+
+ msg2->payload.route.prefix.len = route->len;
+
+ msg2->payload.route.paths[0].sw_if_index = ~0;
+ msg2->payload.route.paths[0].table_id = 0;
+
+ hc_face_t *face = &(route->face);
+ switch (face->type) {
+ case FACE_TYPE_HICN: {
+ if (hicn_ip_address_is_v4(&(face->remote_addr))) {
+ memcpy(&(msg2->payload.route.paths[0].nh.address.ip4),
+ &face->remote_addr.v4, sizeof(ip4_address_t));
+ msg2->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP4;
+ } else {
+ memcpy(&(msg2->payload.route.paths[0].nh.address.ip6),
+ &face->remote_addr.v6, sizeof(ip6_address_t));
+ msg2->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP6;
+ }
+
+ msg2->payload.route.paths[0].type = FIB_API_PATH_TYPE_NORMAL;
+ msg2->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE;
+
+ break;
+ }
+ case FACE_TYPE_UDP: {
+ msg2->payload.route.paths[0].type = FIB_API_PATH_TYPE_UDP_ENCAP;
+ msg2->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE;
+ msg2->payload.route.paths[0].nh.obj_id = face->netdevice.index;
+ break;
+ }
+ default:
+ return -1;
+ }
+
+ ret = vapi_ip_route_add_del(s->g_vapi_ctx_instance, msg2, parse_route_delete,
+ NULL);
+
+ if (ret) {
+ ERROR("Error in vapi_ip_route_add_del in route delete");
+ goto done;
+ }
+
+done:
+
+ vapi_unlock();
+ return ret;
+}
+
+/* ROUTE LIST */
+
+static vapi_error_e parse_udp_encap_list(
+ vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
+ vapi_payload_udp_encap_details *reply) {
+ if (reply == NULL || rv != VAPI_OK) return rv;
+
+ hc_face_t *face = (hc_face_t *)callback_ctx;
+
+ if (face->netdevice.index == reply->udp_encap.id) {
+ switch (reply->udp_encap.src_ip.af) {
+ case ADDRESS_IP4: {
+ memcpy(&face->local_addr.v4, &(reply->udp_encap.src_ip.un.ip4),
+ sizeof(ip4_address_t));
+ memcpy(&face->remote_addr.v4, &(reply->udp_encap.dst_ip.un.ip4),
+ sizeof(ip4_address_t));
+ break;
+ }
+ case ADDRESS_IP6: {
+ memcpy(&face->local_addr.v6, &(reply->udp_encap.src_ip.un.ip6),
+ sizeof(ip6_address_t));
+ memcpy(&face->remote_addr.v6, &(reply->udp_encap.dst_ip.un.ip6),
+ sizeof(ip6_address_t));
+ break;
+ }
+ default:
+ break;
+ }
+
+ face->local_port = reply->udp_encap.src_port;
+ face->remote_port = reply->udp_encap.dst_port;
+ }
+ return rv;
+}
+
+static int _fill_face_with_info(hc_face_t *face, vapi_type_fib_path *path) {
+ switch (path->type) {
+ case FIB_API_PATH_FLAG_NONE: {
+ face->type = FACE_TYPE_HICN;
+ switch (path->proto) {
+ case FIB_API_PATH_NH_PROTO_IP4:
+ memcpy(&face->remote_addr.v4, &(path->nh.address.ip4),
+ sizeof(ipv4_address_t));
+ break;
+ case FIB_API_PATH_NH_PROTO_IP6:
+ memcpy(&face->remote_addr.v6, &(path->nh.address.ip6),
+ sizeof(ipv6_address_t));
+ break;
+ default:
+ break;
+ }
+ face->netdevice.index = path->sw_if_index;
+ } break;
+ case FIB_API_PATH_TYPE_UDP_ENCAP: {
+ face->type = FACE_TYPE_UDP;
+ face->netdevice.index = clib_net_to_host_u32(path->nh.obj_id);
+ // Let's make the compiler happy
+ (void)parse_udp_encap_list;
+ // vapi_msg_udp_encap_dump *msg;
+ // msg = vapi_alloc_udp_encap_dump(s->g_vapi_ctx_instance);
+ // vapi_udp_encap_dump(s->g_vapi_ctx_instance, msg, parse_udp_encap_list,
+ // face);
+ } break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static vapi_error_e parse_route_list(vapi_ctx_t ctx, void *callback_ctx,
+ vapi_error_e rv, bool is_last,
+ vapi_payload_ip_route_details *reply) {
+ if (reply == NULL || rv != VAPI_OK) return rv;
+
+ // XXX DEBUG XXX
+ if (reply && is_last) printf("COUCOU\n");
+
+ if (is_last) return 0;
+
+ hc_data_t *data = (hc_data_t *)callback_ctx;
+
+ /*
+ * Implementation:
+ * A route has n paths... we iterate for each path and search for a
+ * corresponding face in the hc_data_t result struct... and we fill the face
+ * info with the route path.
+ *
+ * TODO
+ * - comment on paths
+ * - explain the jump to END, this was previously implemented with a
+ * boolean flags skipping all remaining tests in the function...
+ */
+ for (int j = 0; j < reply->route.n_paths; j++) {
+ hc_data_foreach(data, obj, {
+ hc_route_t *route = &obj->route;
+
+ if (hicn_ip_address_is_v4(&(route->remote_addr)) &&
+ memcmp(route->remote_addr.v4.as_u8,
+ reply->route.prefix.address.un.ip4,
+ sizeof(ipv4_address_t)) == 0 &&
+ route->len == reply->route.prefix.len && route->face_id == ~0) {
+ _fill_face_with_info(&(route->face), &reply->route.paths[j]);
+ goto END;
+
+ } else if (memcmp(route->remote_addr.v6.as_u8,
+ reply->route.prefix.address.un.ip6,
+ sizeof(ipv6_address_t)) == 0 &&
+ route->len == reply->route.prefix.len &&
+ route->face_id == ~0) {
+ _fill_face_with_info(&(route->face), &reply->route.paths[j]);
+ goto END;
+ }
+ });
+ }
+
+END:
+ return rv;
+}
+
+/**
+ * Populates the hc_data_t structure passed as the context with...
+ */
+static vapi_error_e parse_hicn_route_list(
+ vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
+ vapi_payload_hicn_api_routes_details *reply) {
+ if (reply == NULL || rv != VAPI_OK) return rv;
+
+ if (reply && is_last) printf("COUCOU\n");
+ if (is_last) return 0;
+
+ hc_data_t *data = (hc_data_t *)callback_ctx;
+
+ for (int i = 0; i < reply->nfaces; i++) {
+ hc_route_t route;
+ memset(&route, 0, sizeof(hc_route_t));
+
+ /*
+ * We set the face_id to ~0 to act as a marker in parse_route_list that
+ * the route is missing face information.
+ */
+ route.face_id = ~0;
+ route.cost = 1;
+ route.len = reply->prefix.len;
+ if (reply->prefix.address.af == ADDRESS_IP6) {
+ memcpy(route.remote_addr.v6.as_u8, reply->prefix.address.un.ip6, 16);
+ route.family = AF_INET6;
+ } else {
+ memcpy(route.remote_addr.v4.as_u8, reply->prefix.address.un.ip4, 4);
+ route.family = AF_INET;
+ }
+
+ hc_data_push(data, &route);
+ }
+
+ return rv;
+}
+
+/*
+ * hicn_api_routes_dump
+ * ip_route_dump
+ *
+ * @returns hc_data_t<hc_route_t>
+ */
+static int _vpp_route_list(hc_sock_t *sock, hc_data_t *data) {
+ int ret;
+ hc_sock_vpp_data_t *s = (hc_sock_vpp_data_t *)sock->data;
+
+ vapi_lock();
+
+ /* Start by retrieving hicn routes (we have no face information at this
+ * stage)... */
+ vapi_msg_hicn_api_routes_dump *msg;
+ msg = vapi_alloc_hicn_api_routes_dump(s->g_vapi_ctx_instance);
+ if (!msg) goto ERR_MSG;
+
+ ret = vapi_hicn_api_routes_dump(s->g_vapi_ctx_instance, msg,
+ parse_hicn_route_list, data);
+ if (ret != VAPI_OK) goto ERR_API;
+
+ /*
+ * ... an complement them using IP (v4 and v6 routes). Similar routes will
+ * be aggregated, based on IP prefix, in parse_*_route_list.
+ */
+ vapi_msg_ip_route_dump *msg2;
+ for (unsigned i = 0; i < 2; i++) {
+ msg2 = vapi_alloc_ip_route_dump(s->g_vapi_ctx_instance);
+ if (!msg2) goto ERR_MSG;
+
+ msg2->payload.table.table_id = 0;
+ msg2->payload.table.is_ip6 = i;
+
+ ret = vapi_ip_route_dump(s->g_vapi_ctx_instance, msg2, parse_route_list,
+ data);
+ if (ret != VAPI_OK) goto ERR_API;
+ }
+
+ goto END;
+
+ERR_MSG:
+ ret = VAPI_ENOMEM;
+ goto END;
+
+ERR_API:
+END:
+ vapi_unlock();
+ return ret;
+}
+
+static int vpp_route_create(hc_sock_t *sock, hc_object_t *object,
+ hc_data_t *data) {
+ int rc = _vpp_route_create(sock, &object->route);
+ if (rc < 0)
+ hc_data_set_complete(data);
+ else
+ hc_data_set_error(data);
+ return rc;
+}
+
+static int vpp_route_delete(hc_sock_t *sock, hc_object_t *object,
+ hc_data_t *data) {
+ int rc = _vpp_route_delete(sock, &object->route);
+ if (rc < 0)
+ hc_data_set_complete(data);
+ else
+ hc_data_set_error(data);
+ return rc;
+}
+
+static int vpp_route_list(hc_sock_t *sock, hc_object_t *object,
+ hc_data_t *data) {
+ assert(!object || hc_object_is_empty(object));
+ return _vpp_route_list(sock, data);
+}
+
+DECLARE_VPP_MODULE_OBJECT_OPS(vpp, route);
diff --git a/ctrl/libhicnctrl/src/modules/hicn_plugin/route.h b/ctrl/libhicnctrl/src/modules/hicn_plugin/route.h
new file mode 100644
index 000000000..652d3e89a
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_plugin/route.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file modules/hicn_plugin/route.h
+ * \brief route object VFT for hicn_plugin.
+ */
+
+#ifndef HICNCTRL_MODULE_VPP_ROUTE_H
+#define HICNCTRL_MODULE_VPP_ROUTE_H
+
+#include "../../module.h"
+
+DECLARE_MODULE_OBJECT_OPS_H(vpp, route);
+
+#endif /* HICNCTRL_MODULE_VPP_ROUTE_H */
diff --git a/ctrl/libhicnctrl/src/modules/hicn_plugin_api.c b/ctrl/libhicnctrl/src/modules/hicn_plugin_api.c
deleted file mode 100644
index 6d1baa786..000000000
--- a/ctrl/libhicnctrl/src/modules/hicn_plugin_api.c
+++ /dev/null
@@ -1,1402 +0,0 @@
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * \file api.c
- * \brief Implementation of hICN control library API
- */
-
-#include <assert.h> // assert
-#include <fcntl.h> // fcntl
-#include <math.h> // log2
-#include <stdbool.h>
-#include <stdio.h> // snprintf
-#include <string.h> // memmove, strcasecmp
-#include <sys/socket.h> // socket
-#include <unistd.h> // close, fcntl
-#include <vapi/vapi_safe.h>
-#include <vppinfra/clib.h>
-#include <vpp_plugins/hicn/error.h>
-
-#include "api_private.h"
-
-/**
- * Messages to the forwarder might be multiplexed thanks to the seqNum fields in
- * the header_control_message structure. The forwarder simply answers back the
- * original sequence number. We maintain a map of such sequence number to
- * outgoing queries so that replied can be demultiplexed and treated
- * appropriately.
- */
-/* TYPEDEF_MAP_H(hc_sock_map, int, hc_sock_request_t *); */
-/* TYPEDEF_MAP(hc_sock_map, int, hc_sock_request_t *, int_cmp, int_snprintf, */
-/* generic_snprintf); */
-
-struct hc_sock_vpp_s {
- /* This must be the first element of the struct */
- hc_sock_t vft;
-
- vapi_ctx_t g_vapi_ctx_instance;
- char *url;
-
- size_t roff; /**< Read offset */
- size_t woff; /**< Write offset */
- u32 buffer[RECV_BUFLEN];
- /* Next sequence number to be used for requests */
- int seq;
-
- bool async;
-};
-
-typedef struct hc_sock_vpp_s hc_sock_vpp_t;
-
-#define TO_HC_SOCK_VPP(s) (hc_sock_vpp_t *)(s)
-
-/******************************************************************************
- * Message helper types and aliases
- ******************************************************************************/
-
-#define foreach_hc_command \
- _(hicn_api_node_params_set) \
- _(hicn_api_node_params_set_reply) \
- _(hicn_api_node_params_get_reply) \
- _(hicn_api_node_stats_get_reply) \
- _(hicn_api_face_get) \
- _(hicn_api_faces_details) \
- _(hicn_api_face_stats_details) \
- _(hicn_api_face_get_reply) \
- _(hicn_api_route_get) \
- _(hicn_api_route_get_reply) \
- _(hicn_api_routes_details) \
- _(hicn_api_strategies_get_reply) \
- _(hicn_api_strategy_get) \
- _(hicn_api_strategy_get_reply)
-
-typedef vapi_type_msg_header2_t hc_msg_header_t;
-
-typedef union {
-#define _(a) vapi_payload_##a a;
- foreach_hc_command
-#undef _
-} hc_msg_payload_t;
-
-typedef struct __attribute__((__packed__)) {
- hc_msg_header_t hdr;
- hc_msg_payload_t payload;
-} hc_hicnp_t;
-
-typedef void (*NTOH)(void *msg);
-
-typedef struct __attribute__((__packed__)) {
- hc_data_t *data;
- uint32_t curr_msg;
-} callback_ctx_t;
-
-typedef struct __attribute__((__packed__)) {
- hc_hicnp_t *hicnp_msg;
- vapi_cb_t callback;
- callback_ctx_t *callback_ctx;
- NTOH ntoh;
-} hc_msg_s;
-
-/******************************************************************************
- * Control socket
- ******************************************************************************/
-
-static void _hc_sock_vpp_free(hc_sock_t *socket) {
- hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket);
- if (s->url) free(s->url);
- free(s);
-
- vapi_disconnect_safe();
-}
-
-static int _hc_sock_vpp_get_next_seq(hc_sock_t *socket) {
- hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket);
- return vapi_gen_req_context(s->g_vapi_ctx_instance);
-}
-
-static int _hc_sock_vpp_set_nonblocking(hc_sock_t *socket) {
- hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket);
- s->async = 1;
- return 0;
-}
-
-static int _hc_sock_vpp_get_fd(hc_sock_t *s) { return 1; }
-
-static int _hc_sock_vpp_connect(hc_sock_t *socket) {
- hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket);
- vapi_error_e rv = vapi_connect_safe(&s->g_vapi_ctx_instance, s->async);
- if (rv != VAPI_OK) goto ERR_CONNECT;
-
- return 0;
-
-ERR_CONNECT:
- ERROR("[hc_sock_connect] connection failed");
- return -1;
-}
-
-static int _hc_sock_vpp_send(hc_sock_t *s, hc_msg_t *msg, size_t msglen,
- uint32_t seq) {
- return -1;
-}
-
-static int _hc_sock_vpp_get_available(hc_sock_t *s, u8 **buffer, size_t *size) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-static int _hc_sock_vpp_recv(hc_sock_t *s) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-static int _hc_sock_vpp_process(hc_sock_t *s, hc_data_t **pdata) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-static int _hc_sock_vpp_callback(hc_sock_t *socket, hc_data_t **pdata) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-static int _hc_sock_vpp_reset(hc_sock_t *socket) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-/******************************************************************************
- * Command-specific structures and functions
- ******************************************************************************/
-
-/*----------------------------------------------------------------------------*
- * Listeners
- *----------------------------------------------------------------------------*/
-
-/* LISTENER CREATE */
-
-static int _hc_listener_create(hc_sock_t *s, hc_listener_t *listener) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-static int _hc_listener_create_async(hc_sock_t *s, hc_listener_t *listener) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-/* LISTENER GET */
-static int _hc_listener_get(hc_sock_t *s, hc_listener_t *listener,
- hc_listener_t **listener_found) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-/* LISTENER DELETE */
-
-static int _hc_listener_delete(hc_sock_t *s, hc_listener_t *listener) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-static int _hc_listener_delete_async(hc_sock_t *s, hc_listener_t *listener) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-static vapi_error_e process_ip_info(struct vapi_ctx_s *ctx, void *callback_ctx,
- vapi_error_e rv, bool is_last,
- vapi_payload_ip_address_details *reply) {
- if (is_last) return 0;
- hc_data_t *data = (hc_data_t *)callback_ctx;
-
- if (data->size == data->current) {
- data->buffer =
- realloc(data->buffer, sizeof(hc_listener_t) * data->size * 2);
-
- if (!data->buffer) return VAPI_ENOMEM;
-
- data->size *= 2;
- }
-
- hc_listener_t *listener =
- (hc_listener_t *)(data->buffer + data->current * sizeof(hc_listener_t));
- memset(listener, 0, sizeof(hc_listener_t));
-
- if (reply->prefix.address.af == ADDRESS_IP4) {
- memcpy(listener->local_addr.v4.as_u8, reply->prefix.address.un.ip4,
- IPV4_ADDR_LEN);
- listener->family = AF_INET;
- } else {
- memcpy(listener->local_addr.v6.as_u8, reply->prefix.address.un.ip6,
- IPV6_ADDR_LEN);
- listener->family = AF_INET6;
- }
-
- listener->id = reply->sw_if_index;
- data->current++;
- return rv;
-}
-
-typedef struct {
- u32 swif;
- char interface_name[INTERFACE_LEN];
-} hc_vapi_interface_t;
-
-static vapi_error_e listener_list_complete_cb(
- struct vapi_ctx_s *ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
- vapi_payload_sw_interface_details *reply) {
- if (reply == NULL || rv != VAPI_OK) return rv;
-
- if (is_last) return 0;
-
- hc_data_t *data = (hc_data_t *)callback_ctx;
-
- if (data->size == data->current) {
- data->buffer =
- realloc(data->buffer, sizeof(hc_vapi_interface_t) * data->size * 2);
-
- if (!data->buffer) return VAPI_ENOMEM;
-
- data->size *= 2;
- }
-
- hc_vapi_interface_t *swif =
- &((hc_vapi_interface_t *)data->buffer)[data->current];
-
- swif[0].swif = reply->sw_if_index;
- memcpy(swif[0].interface_name, reply->interface_name, INTERFACE_LEN);
-
- data->current++;
-
- return rv;
-}
-
-/* LISTENER LIST */
-static int _hc_listener_list(hc_sock_t *socket, hc_data_t **pdata) {
- hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket);
- int retval = VAPI_OK;
- vapi_lock();
- vapi_msg_sw_interface_dump *hicnp_msg;
- hicnp_msg = vapi_alloc_sw_interface_dump(s->g_vapi_ctx_instance);
-
- if (!hicnp_msg) {
- retval = VAPI_ENOMEM;
- goto END;
- }
-
- hicnp_msg->payload.sw_if_index = ~0;
- hicnp_msg->payload.name_filter_valid = 0;
-
- hc_data_t *data = hc_data_create(0, sizeof(hc_vapi_interface_t), NULL);
-
- if (!data) {
- retval = -1;
- goto END;
- }
-
- hc_data_t *data2 = hc_data_create(0, 1, NULL);
-
- if (!data2) {
- retval = -1;
- goto END;
- }
-
- data->buffer = malloc(sizeof(hc_vapi_interface_t));
- data->size = 1;
-
- if (!data->buffer) {
- free(data);
- retval = -1;
- goto FREE_DATA;
- }
-
- int ret = vapi_sw_interface_dump(s->g_vapi_ctx_instance, hicnp_msg,
- listener_list_complete_cb, data);
-
- if (ret != VAPI_OK) {
- free(data->buffer);
- free(data);
- retval = -1;
- goto FREE_DATA_BUFFER;
- }
-
- data2->buffer = malloc(sizeof(hc_listener_t));
- data2->size = 1;
- data2->out_element_size = 1;
-
- if (!data2->buffer) {
- free(data2->buffer);
- retval = -1;
- goto CLEAN;
- }
-
- /* Query the forwarder for each interface */
- for (int i = 0; i < data->current; i++) {
- int index = data2->current;
- vapi_msg_ip_address_dump *msg =
- vapi_alloc_ip_address_dump(s->g_vapi_ctx_instance);
- msg->payload.sw_if_index = ((hc_vapi_interface_t *)data->buffer)[i].swif;
- msg->payload.is_ipv6 = 0;
- retval = vapi_ip_address_dump(s->g_vapi_ctx_instance, msg, process_ip_info,
- data2);
- vapi_msg_ip_address_dump *msg2 =
- vapi_alloc_ip_address_dump(s->g_vapi_ctx_instance);
-
- if (retval) goto CLEAN;
-
- msg2->payload.sw_if_index = ((hc_vapi_interface_t *)data->buffer)[i].swif;
- msg2->payload.is_ipv6 = 1;
- retval = vapi_ip_address_dump(s->g_vapi_ctx_instance, msg2, process_ip_info,
- data2);
- for (size_t j = index; j < data2->current; j++) {
- memcpy(((hc_listener_t *)(data2->buffer))[j].interface_name,
- ((hc_vapi_interface_t *)(data->buffer))[i].interface_name,
- INTERFACE_LEN);
- ((hc_listener_t *)(data2->buffer))[j].type = FACE_TYPE_HICN;
- }
-
- if (retval) goto CLEAN;
- }
-
-CLEAN:
-FREE_DATA_BUFFER:
- free(data->buffer);
-FREE_DATA:
- free(data);
-
- data2->size = data2->current;
- data2->out_element_size = sizeof(hc_listener_t);
- *pdata = data2;
-END:
- vapi_unlock();
- return retval;
-}
-
-static int _hc_listener_list_async(hc_sock_t *s, hc_data_t **pdata) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-/*----------------------------------------------------------------------------*
- * CONNECTION
- *----------------------------------------------------------------------------*/
-
-/* CONNECTION CREATE */
-
-static int _hc_connection_create(hc_sock_t *s, hc_connection_t *connection) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-static int _hc_connection_create_async(hc_sock_t *s,
- hc_connection_t *connection) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-/* CONNECTION GET */
-
-static int _hc_connection_get(hc_sock_t *s, hc_connection_t *connection,
- hc_connection_t **connection_found) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-static int _hc_connection_update_by_id(hc_sock_t *s, int hc_connection_id,
- hc_connection_t *connection) {
- // Not implemented
- return -1;
-}
-
-static int _hc_connection_update(hc_sock_t *s,
- hc_connection_t *connection_current,
- hc_connection_t *connection_updated) {
- // Not implemented
- return -1;
-}
-
-/* CONNECTION DELETE */
-
-static int _hc_connection_delete(hc_sock_t *s, hc_connection_t *connection) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-static int _hc_connection_delete_async(hc_sock_t *s,
- hc_connection_t *connection) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-/* CONNECTION LIST */
-
-static int _hc_connection_list(hc_sock_t *s, hc_data_t **pdata) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-static int _hc_connection_list_async(hc_sock_t *s, hc_data_t **pdata) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-/* CONNECTION SET ADMIN STATE */
-
-static int _hc_connection_set_admin_state(hc_sock_t *s,
- const char *conn_id_or_name,
- face_state_t state) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-static int _hc_connection_set_admin_state_async(hc_sock_t *s,
- const char *conn_id_or_name,
- face_state_t state) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-#ifdef WITH_POLICY
-
-static int _hc_connection_set_priority(hc_sock_t *s,
- const char *conn_id_or_name,
- uint32_t priority) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-static int _hc_connection_set_priority_async(hc_sock_t *s,
- const char *conn_id_or_name,
- uint32_t priority) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-#endif // WITH_POLICY
-
-static int _hc_connection_set_tags(hc_sock_t *s, const char *conn_id_or_name,
- policy_tags_t tags) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-static int _hc_connection_set_tags_async(hc_sock_t *s,
- const char *conn_id_or_name,
- policy_tags_t tags) {
- // NOT IMPLEMENTED
- return -1;
-}
-
-/*----------------------------------------------------------------------------*
- * Routes
- *----------------------------------------------------------------------------*/
-
-static vapi_error_e create_udp_tunnel_cb(
- vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
- vapi_payload_hicn_api_udp_tunnel_add_del_reply *reply) {
- if (reply == NULL || rv != VAPI_OK) return rv;
-
- if (reply->retval != VAPI_OK) return reply->retval;
-
- u32 *uei = (u32 *)callback_ctx;
- *uei = reply->uei;
-
- return reply->retval;
-}
-
-/* ROUTE CREATE */
-static vapi_error_e parse_route_create(
- vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
- vapi_payload_ip_route_add_del_reply *reply) {
- if (reply == NULL || rv != VAPI_OK) return rv;
-
- if (reply->retval != VAPI_OK) return reply->retval;
-
- return reply->retval;
-}
-
-static vapi_error_e hicn_enable_cb(
- vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
- vapi_payload_hicn_api_enable_disable_reply *reply) {
- if (reply == NULL || rv != VAPI_OK) return rv;
- face_id_t *faceid = (face_id_t *)callback_ctx;
-
- if (reply->nfaces) {
- *faceid = reply->faceids[0];
- }
-
- return reply->retval;
-}
-
-static int _hc_route_create_internal(hc_sock_t *socket, hc_route_t *route,
- bool async) {
- if (!IS_VALID_FAMILY(route->family)) return -1;
-
- hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket);
- int ret = -1;
- vapi_lock();
-
- vapi_msg_ip_route_add_del *hicnp_msg =
- vapi_alloc_ip_route_add_del(s->g_vapi_ctx_instance, 1);
-
- hicnp_msg->payload.is_add = 1;
- if (route->family == AF_INET) {
- memcpy(&hicnp_msg->payload.route.prefix.address.un.ip4[0],
- &route->remote_addr.v4, 4);
- hicnp_msg->payload.route.prefix.address.af = ADDRESS_IP4;
- hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP4;
- } else {
- memcpy(&hicnp_msg->payload.route.prefix.address.un.ip6[0],
- &route->remote_addr.v6, 16);
- hicnp_msg->payload.route.prefix.address.af = ADDRESS_IP6;
- hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP6;
- }
-
- hicnp_msg->payload.route.prefix.len = route->len;
-
- hicnp_msg->payload.route.paths[0].sw_if_index = ~0;
- hicnp_msg->payload.route.paths[0].table_id = 0;
-
- hc_face_t *face = &(route->face);
-
- face->face.netdevice.index = ~0;
- face->id = INVALID_FACE_ID;
-
- switch (face->face.type) {
- case FACE_TYPE_HICN: {
- if (ip_address_is_v4((ip_address_t *)(&(face->face.remote_addr)))) {
- memcpy(&(hicnp_msg->payload.route.paths[0].nh.address.ip4),
- &face->face.remote_addr.v4, sizeof(ip4_address_t));
- hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP4;
- } else {
- memcpy(&(hicnp_msg->payload.route.paths[0].nh.address.ip6),
- &face->face.remote_addr.v6, sizeof(ip6_address_t));
- hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP6;
- }
-
- hicnp_msg->payload.route.paths[0].type = FIB_API_PATH_TYPE_NORMAL;
- hicnp_msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE;
-
- break;
- }
- case FACE_TYPE_UDP: {
- vapi_msg_hicn_api_udp_tunnel_add_del *msg = NULL;
- u32 uei = ~0;
-
- if (ip_address_is_v4((ip_address_t *)(&(face->face.remote_addr))) &&
- ip_address_is_v4((ip_address_t *)(&(face->face.local_addr)))) {
- msg = vapi_alloc_hicn_api_udp_tunnel_add_del(s->g_vapi_ctx_instance);
- memcpy(msg->payload.src_addr.un.ip4, &face->face.local_addr.v4,
- sizeof(ip4_address_t));
- msg->payload.src_addr.af = ADDRESS_IP4;
-
- memcpy(msg->payload.dst_addr.un.ip4, &face->face.remote_addr.v4,
- sizeof(ip4_address_t));
- msg->payload.dst_addr.af = ADDRESS_IP4;
-
- } else if (!ip_address_is_v4(
- (ip_address_t *)(&(route->face.face.remote_addr))) &&
- !ip_address_is_v4(
- (ip_address_t *)(&(route->face.face.local_addr)))) {
- msg = vapi_alloc_hicn_api_udp_tunnel_add_del(s->g_vapi_ctx_instance);
- memcpy(msg->payload.src_addr.un.ip6, &face->face.local_addr.v6,
- sizeof(ip6_address_t));
- msg->payload.src_addr.af = ADDRESS_IP6;
-
- memcpy(msg->payload.dst_addr.un.ip6, &face->face.remote_addr.v6,
- sizeof(ip6_address_t));
- msg->payload.dst_addr.af = ADDRESS_IP6;
- } else {
- // NOT IMPLEMENTED
- ret = -1;
- goto done;
- }
-
- msg->payload.src_port = face->face.local_port;
- msg->payload.dst_port = face->face.remote_port;
- msg->payload.is_add = 1;
-
- int ret = vapi_hicn_api_udp_tunnel_add_del(s->g_vapi_ctx_instance, msg,
- create_udp_tunnel_cb, &uei);
-
- if (ret) {
- ERROR("Error in vapi_hicn_api_udp_tunnel_add_del");
- vapi_msg_free(s->g_vapi_ctx_instance, hicnp_msg);
- goto done;
- }
-
- hicnp_msg->payload.route.paths[0].type = FIB_API_PATH_TYPE_UDP_ENCAP;
- hicnp_msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE;
- hicnp_msg->payload.route.paths[0].nh.obj_id = uei;
-
- face->face.netdevice.index = uei;
-
- break;
- }
- default:
- ret = -1;
- goto done;
- }
-
- ret = vapi_ip_route_add_del(s->g_vapi_ctx_instance, hicnp_msg,
- parse_route_create, NULL);
-
- if (ret) {
- ERROR("Error in vapi_ip_route_add_del");
- goto done;
- }
-
- vapi_msg_hicn_api_enable_disable *msg =
- vapi_alloc_hicn_api_enable_disable(s->g_vapi_ctx_instance);
-
- if (route->family == AF_INET) {
- memcpy(&msg->payload.prefix.address.un.ip4[0], &route->remote_addr.v4, 4);
- msg->payload.prefix.address.af = ADDRESS_IP4;
- } else {
- memcpy(&msg->payload.prefix.address.un.ip6[0], &route->remote_addr.v6, 16);
- msg->payload.prefix.address.af = ADDRESS_IP6;
- }
-
- msg->payload.prefix.len = route->len;
- msg->payload.enable_disable = 1;
-
- ret = vapi_hicn_api_enable_disable(s->g_vapi_ctx_instance, msg,
- hicn_enable_cb, &face->id);
-
- if (ret) {
- ERROR("Error in vapi_hicn_api_enable_disable");
- }
-
-done:
- vapi_unlock();
- return ret;
-}
-
-static int _hc_route_create(hc_sock_t *s, hc_route_t *route) {
- return _hc_route_create_internal(s, route, false);
-}
-
-static int _hc_route_create_async(hc_sock_t *s, hc_route_t *route) {
- return _hc_route_create_internal(s, route, true);
-}
-
-/* ROUTE DELETE */
-static vapi_error_e parse_route_delete(
- vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
- vapi_payload_ip_route_add_del_reply *reply) {
- if (reply == NULL || rv != VAPI_OK) return rv;
-
- return reply->retval;
-}
-
-static vapi_error_e hicn_disable_cb(
- vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
- vapi_payload_hicn_api_enable_disable_reply *reply) {
- if (reply == NULL || rv != VAPI_OK) return rv;
-
- return reply->retval;
-}
-
-static int _hc_route_delete_internal(hc_sock_t *socket, hc_route_t *route,
- bool async) {
- if (!IS_VALID_FAMILY(route->family)) return -1;
-
- hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket);
-
- vapi_lock();
-
- vapi_msg_hicn_api_enable_disable *msg =
- vapi_alloc_hicn_api_enable_disable(s->g_vapi_ctx_instance);
-
- if (route->family == AF_INET) {
- memcpy(&msg->payload.prefix.address.un.ip4[0], &route->remote_addr.v4, 4);
- msg->payload.prefix.address.af = ADDRESS_IP4;
- } else {
- memcpy(&msg->payload.prefix.address.un.ip6[0], &route->remote_addr.v6, 16);
- msg->payload.prefix.address.af = ADDRESS_IP6;
- }
-
- msg->payload.prefix.len = route->len;
- msg->payload.enable_disable = 0;
-
- vapi_error_e ret = vapi_hicn_api_enable_disable(s->g_vapi_ctx_instance, msg,
- hicn_disable_cb, NULL);
-
- if (ret) {
- ERROR("Error in vapi_hicn_api_enable_disable in route delete");
- goto done;
- }
-
- vapi_msg_ip_route_add_del *hicnp_msg =
- vapi_alloc_ip_route_add_del(s->g_vapi_ctx_instance, 1);
-
- hicnp_msg->payload.is_add = 0;
- if (route->family == AF_INET) {
- memcpy(&hicnp_msg->payload.route.prefix.address.un.ip4[0],
- &route->remote_addr.v4, 4);
- hicnp_msg->payload.route.prefix.address.af = ADDRESS_IP4;
- } else {
- memcpy(&hicnp_msg->payload.route.prefix.address.un.ip6[0],
- &route->remote_addr.v6, 16);
- hicnp_msg->payload.route.prefix.address.af = ADDRESS_IP6;
- }
-
- hicnp_msg->payload.route.prefix.len = route->len;
-
- hicnp_msg->payload.route.paths[0].sw_if_index = ~0;
- hicnp_msg->payload.route.paths[0].table_id = 0;
-
- hc_face_t *face = &(route->face);
- switch (face->face.type) {
- case FACE_TYPE_HICN: {
- if (ip_address_is_v4((ip_address_t *)(&(face->face.remote_addr)))) {
- memcpy(&(hicnp_msg->payload.route.paths[0].nh.address.ip4),
- &face->face.remote_addr.v4, sizeof(ip4_address_t));
- hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP4;
- } else {
- memcpy(&(hicnp_msg->payload.route.paths[0].nh.address.ip6),
- &face->face.remote_addr.v6, sizeof(ip6_address_t));
- hicnp_msg->payload.route.paths[0].proto = FIB_API_PATH_NH_PROTO_IP6;
- }
-
- hicnp_msg->payload.route.paths[0].type = FIB_API_PATH_TYPE_NORMAL;
- hicnp_msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE;
-
- break;
- }
- case FACE_TYPE_UDP: {
- hicnp_msg->payload.route.paths[0].type = FIB_API_PATH_TYPE_UDP_ENCAP;
- hicnp_msg->payload.route.paths[0].flags = FIB_API_PATH_FLAG_NONE;
- hicnp_msg->payload.route.paths[0].nh.obj_id = face->face.netdevice.index;
- break;
- }
- default:
- return -1;
- }
-
- ret = vapi_ip_route_add_del(s->g_vapi_ctx_instance, hicnp_msg,
- parse_route_delete, NULL);
-
- if (ret) {
- ERROR("Error in vapi_ip_route_add_del in route delete");
- goto done;
- }
-
-done:
-
- vapi_unlock();
- return ret;
-}
-
-static int _hc_route_delete(hc_sock_t *s, hc_route_t *route) {
- return _hc_route_delete_internal(s, route, false);
-}
-
-static int _hc_route_delete_async(hc_sock_t *s, hc_route_t *route) {
- return _hc_route_delete_internal(s, route, true);
-}
-
-static vapi_error_e parse_udp_encap_list(
- vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
- vapi_payload_udp_encap_details *reply) {
- if (reply == NULL || rv != VAPI_OK) return rv;
-
- hc_face_t *face = (hc_face_t *)callback_ctx;
-
- if (face->face.netdevice.index == reply->udp_encap.id) {
- switch (reply->udp_encap.src_ip.af) {
- case ADDRESS_IP4: {
- memcpy(&face->face.local_addr.v4, &(reply->udp_encap.src_ip.un.ip4),
- sizeof(ip4_address_t));
- memcpy(&face->face.remote_addr.v4, &(reply->udp_encap.dst_ip.un.ip4),
- sizeof(ip4_address_t));
- break;
- }
- case ADDRESS_IP6: {
- memcpy(&face->face.local_addr.v6, &(reply->udp_encap.src_ip.un.ip6),
- sizeof(ip6_address_t));
- memcpy(&face->face.remote_addr.v6, &(reply->udp_encap.dst_ip.un.ip6),
- sizeof(ip6_address_t));
- break;
- }
- default:
- break;
- }
-
- face->face.local_port = reply->udp_encap.src_port;
- face->face.remote_port = reply->udp_encap.dst_port;
- }
- return rv;
-}
-
-static int _fill_face_with_info(hc_face_t *face, vapi_type_fib_path *path,
- hc_sock_t *s) {
- switch (path->type) {
- case FIB_API_PATH_FLAG_NONE: {
- face->face.type = FACE_TYPE_HICN;
- switch (path->proto) {
- case FIB_API_PATH_NH_PROTO_IP4:
- memcpy(&face->face.remote_addr.v4, &(path->nh.address.ip4),
- sizeof(ip4_address_t));
- break;
- case FIB_API_PATH_NH_PROTO_IP6:
- memcpy(&face->face.remote_addr.v6, &(path->nh.address.ip6),
- sizeof(ip6_address_t));
- break;
- default:
- break;
- }
- face->face.netdevice.index = path->sw_if_index;
- } break;
- case FIB_API_PATH_TYPE_UDP_ENCAP: {
- face->face.type = FACE_TYPE_UDP;
- face->face.netdevice.index = clib_net_to_host_u32(path->nh.obj_id);
- // Let's make the compiler happy
- (void)parse_udp_encap_list;
- // vapi_msg_udp_encap_dump *msg;
- // msg = vapi_alloc_udp_encap_dump(s->g_vapi_ctx_instance);
- // vapi_udp_encap_dump(s->g_vapi_ctx_instance, msg, parse_udp_encap_list,
- // face);
- } break;
- default:
- return -1;
- }
- return 0;
-}
-
-/* ROUTE LIST */
-typedef struct hicn_route_socket_s {
- hc_data_t *data;
- hc_sock_t *s;
-} hicn_route_socket_t;
-
-static vapi_error_e parse_route_list(vapi_ctx_t ctx, void *callback_ctx,
- vapi_error_e rv, bool is_last,
- vapi_payload_ip_route_details *reply) {
- if (reply == NULL || rv != VAPI_OK) return rv;
-
- hicn_route_socket_t *rs = (hicn_route_socket_t *)callback_ctx;
- hc_data_t *data = rs->data;
-
- u8 found = false;
- for (int j = 0; j < reply->route.n_paths; j++) {
- for (int i = 0; i < data->size && !found; i++) {
- hc_route_t *route = &((hc_route_t *)(data->buffer))[i];
-
- if (ip_address_is_v4((ip_address_t *)&(route->remote_addr)) &&
- memcmp(route->remote_addr.v4.as_u8,
- reply->route.prefix.address.un.ip4,
- sizeof(ip4_address_t)) == 0 &&
- route->len == reply->route.prefix.len && route->face_id == ~0) {
- _fill_face_with_info(&(route->face), &reply->route.paths[j], rs->s);
- found = true;
- } else if (memcmp(route->remote_addr.v6.as_u8,
- reply->route.prefix.address.un.ip6,
- sizeof(ip6_address_t)) == 0 &&
- route->len == reply->route.prefix.len &&
- route->face_id == ~0) {
- _fill_face_with_info(&(route->face), &reply->route.paths[j], rs->s);
- found = true;
- }
- }
- }
-
- return rv;
-}
-
-static vapi_error_e parse_hicn_route_list(
- vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
- vapi_payload_hicn_api_routes_details *reply) {
- if (reply == NULL || rv != VAPI_OK) return rv;
-
- hc_data_t *data = (hc_data_t *)callback_ctx;
-
- int empty_spots = data->size - data->current;
- if (empty_spots < reply->nfaces) {
- int new_size = data->size + (reply->nfaces - empty_spots);
- data->buffer = realloc(data->buffer, sizeof(hc_route_t) * (new_size));
- if (!data->buffer) return VAPI_ENOMEM;
-
- data->size = new_size;
- }
-
- for (int i = 0; i < reply->nfaces; i++) {
- hc_route_t *route = &((hc_route_t *)(data->buffer))[data->current];
- route->face_id = ~0;
- route->cost = 1;
- route->len = reply->prefix.len;
- if (reply->prefix.address.af == ADDRESS_IP6) {
- memcpy(route->remote_addr.v6.as_u8, reply->prefix.address.un.ip6, 16);
- } else {
- memcpy(route->remote_addr.v4.as_u8, reply->prefix.address.un.ip4, 4);
- }
- route->family =
- reply->prefix.address.af == ADDRESS_IP6 ? AF_INET6 : AF_INET;
- data->current++;
- }
-
- return rv;
-}
-
-static int _hc_route_list_internal(hc_sock_t *socket, hc_data_t **pdata,
- bool async) {
- hc_sock_vpp_t *s = TO_HC_SOCK_VPP(socket);
- vapi_lock();
-
- vapi_msg_hicn_api_routes_dump *msg;
- msg = vapi_alloc_hicn_api_routes_dump(s->g_vapi_ctx_instance);
-
- hc_data_t *data = hc_data_create(0, sizeof(hc_route_t), NULL);
- int ret = VAPI_OK;
-
- if (!data) {
- ret = -1;
- goto err;
- }
-
- data->buffer = malloc(sizeof(hc_route_t));
- data->size = 1;
-
- if (!data->buffer) {
- ret = -1;
- goto err_free;
- }
-
- ret = vapi_hicn_api_routes_dump(s->g_vapi_ctx_instance, msg,
- parse_hicn_route_list, data);
-
- if (ret != VAPI_OK) goto err_free;
-
- vapi_msg_ip_route_dump *hicnp_msg;
- hicnp_msg = vapi_alloc_ip_route_dump(s->g_vapi_ctx_instance);
- hicnp_msg->payload.table.table_id = 0;
- hicnp_msg->payload.table.is_ip6 = 1;
-
- hicn_route_socket_t ctx = {
- .data = data,
- .s = socket,
- };
-
- ret = vapi_ip_route_dump(s->g_vapi_ctx_instance, hicnp_msg, parse_route_list,
- &ctx);
-
- hicnp_msg = vapi_alloc_ip_route_dump(s->g_vapi_ctx_instance);
- hicnp_msg->payload.table.table_id = 0;
- hicnp_msg->payload.table.is_ip6 = 0;
-
- ret = vapi_ip_route_dump(s->g_vapi_ctx_instance, hicnp_msg, parse_route_list,
- &ctx);
-
- if (ret != VAPI_OK) goto err_free;
-
- *pdata = data;
-
- vapi_unlock();
- return ret;
-
-err_free:
- free(data);
-err:
- vapi_unlock();
- return ret;
-}
-
-static int _hc_route_list(hc_sock_t *s, hc_data_t **pdata) {
- return _hc_route_list_internal(s, pdata, false);
-}
-
-static int _hc_route_list_async(hc_sock_t *s) {
- return _hc_route_list_internal(s, NULL, true);
-}
-
-/*----------------------------------------------------------------------------*
- * Face
- *
- * Face support is not directly available in hicn-light, but we can offer such
- * an interface through a combination of listeners and connections. The code
- * starts with some conversion functions between faces/listeners/connections.
- *
- * We also need to make sure that there always exist a (single) listener when a
- * connection is created, and in the hICN face case, that there is a single
- * connection attached to this listener.
- *
- *----------------------------------------------------------------------------*/
-
-static int _hc_face_create(hc_sock_t *socket, hc_face_t *face) {
- ERROR("Face creation not implemented.");
- return -1;
-}
-
-static int _hc_face_get(hc_sock_t *socket, hc_face_t *face,
- hc_face_t **face_found) {
- ERROR("Face deletion not implemented.");
- return -1;
-}
-
-static int _hc_face_delete(hc_sock_t *s, hc_face_t *face,
- uint8_t delete_listener) {
- ERROR("Face deletion not implemented.");
- return -1;
-}
-
-/* FACE LIST */
-
-static int _hc_face_list(hc_sock_t *s, hc_data_t **pdata) {
- ERROR("Face list not implemented.");
- return -1;
-}
-
-static int _hc_face_list_async(hc_sock_t *s) { return 0; }
-
-static int _hc_face_set_admin_state(
- hc_sock_t *s, const char *conn_id_or_name, // XXX wrong identifier
- face_state_t admin_state) {
- return 0;
-}
-
-#ifdef WITH_POLICY
-static int _hc_face_set_priority(hc_sock_t *s, const char *conn_id_or_name,
- uint32_t priority) {
- ERROR("Face set priority not implemented.");
- return -1;
-}
-
-static int _hc_face_set_tags(hc_sock_t *s, const char *conn_id_or_name,
- policy_tags_t tags) {
- ERROR("Face set tags not implemented.");
- return -1;
-}
-#endif // WITH_POLICY
-
-/*----------------------------------------------------------------------------*
- * Punting
- *----------------------------------------------------------------------------*/
-
-static int _hc_punting_create_internal(hc_sock_t *s, hc_punting_t *punting,
- bool async) {
- return -1;
-}
-
-static int _hc_punting_create(hc_sock_t *s, hc_punting_t *punting) {
- return _hc_punting_create_internal(s, punting, false);
-}
-
-static int _hc_punting_create_async(hc_sock_t *s, hc_punting_t *punting) {
- return _hc_punting_create_internal(s, punting, true);
-}
-
-static int _hc_punting_get(hc_sock_t *s, hc_punting_t *punting,
- hc_punting_t **punting_found) {
- ERROR("hc_punting_get not (yet) implemented.");
- return -1;
-}
-
-static int _hc_punting_delete(hc_sock_t *s, hc_punting_t *punting) {
- ERROR("hc_punting_delete not (yet) implemented.");
- return -1;
-}
-
-static int _hc_punting_list(hc_sock_t *s, hc_data_t **pdata) {
- ERROR("hc_punting_list not (yet) implemented.");
- return -1;
-}
-
-/*----------------------------------------------------------------------------*
- * Cache
- *----------------------------------------------------------------------------*/
-
-static int _hc_cache_set_store_internal(hc_sock_t *s, hc_cache_t *cache,
- bool async) {
- return 0;
-}
-
-static int _hc_cache_set_store(hc_sock_t *s, hc_cache_t *cache) {
- return _hc_cache_set_store_internal(s, cache, false);
-}
-
-static int _hc_cache_set_store_async(hc_sock_t *s, hc_cache_t *cache) {
- return _hc_cache_set_store_internal(s, cache, true);
-}
-
-static int _hc_cache_set_serve_internal(hc_sock_t *s, hc_cache_t *cache,
- bool async) {
- return 0;
-}
-
-static int _hc_cache_set_serve(hc_sock_t *s, hc_cache_t *cache) {
- return _hc_cache_set_serve_internal(s, cache, false);
-}
-
-static int _hc_cache_set_serve_async(hc_sock_t *s, hc_cache_t *cache) {
- return _hc_cache_set_serve_internal(s, cache, true);
-}
-
-/*----------------------------------------------------------------------------*
- * Strategy
- *----------------------------------------------------------------------------*/
-
-// per prefix
-static int _hc_strategy_set(hc_sock_t *s, hc_strategy_t *strategy) { return 0; }
-
-static int _hc_strategy_add_local_prefix(hc_sock_t *s,
- hc_strategy_t *strategy) {
- return 0;
-}
-
-static int _hc_strategy_list(hc_sock_t *s, hc_data_t **data) { return 0; }
-
-/*----------------------------------------------------------------------------*
- * WLDR
- *----------------------------------------------------------------------------*/
-
-// per connection
-static int _hc_wldr_set(hc_sock_t *s /* XXX */) { return 0; }
-
-/*----------------------------------------------------------------------------*
- * MAP-Me
- *----------------------------------------------------------------------------*/
-
-static int _hc_mapme_set(hc_sock_t *s, int enabled) { return 0; }
-
-static int _hc_mapme_set_discovery(hc_sock_t *s, int enabled) { return 0; }
-
-static int _hc_mapme_set_timescale(hc_sock_t *s, uint32_t timescale) {
- return 0;
-}
-
-static int _hc_mapme_set_retx(hc_sock_t *s, uint32_t timescale) { return 0; }
-
-/*----------------------------------------------------------------------------*
- * Policy
- *----------------------------------------------------------------------------*/
-
-#ifdef WITH_POLICY
-
-/* POLICY CREATE */
-
-static int _hc_policy_create_internal(hc_sock_t *socket, hc_policy_t *policy,
- bool async) {
- return -1;
-}
-
-static int _hc_policy_create(hc_sock_t *s, hc_policy_t *policy) {
- return _hc_policy_create_internal(s, policy, false);
-}
-
-static int _hc_policy_create_async(hc_sock_t *s, hc_policy_t *policy) {
- return _hc_policy_create_internal(s, policy, true);
-}
-
-/* POLICY DELETE */
-
-static int _hc_policy_delete_internal(hc_sock_t *socket, hc_policy_t *policy,
- bool async) {
- return -1;
-}
-
-static int _hc_policy_delete(hc_sock_t *s, hc_policy_t *policy) {
- return _hc_policy_delete_internal(s, policy, false);
-}
-
-static int _hc_policy_delete_async(hc_sock_t *s, hc_policy_t *policy) {
- return _hc_policy_delete_internal(s, policy, true);
-}
-
-/* POLICY LIST */
-
-static int _hc_policy_list_internal(hc_sock_t *socket, hc_data_t **pdata,
- bool async) {
- return -1;
-}
-
-static int _hc_policy_list(hc_sock_t *s, hc_data_t **pdata) {
- return _hc_policy_list_internal(s, pdata, false);
-}
-
-static int _hc_policy_list_async(hc_sock_t *s, hc_data_t **pdata) {
- return _hc_policy_list_internal(s, pdata, true);
-}
-
-#endif /* WITH_POLICY */
-
-/*----------------------------------------------------------------------------*
- * Configuration
- *----------------------------------------------------------------------------*/
-
-typedef struct hc_result_s {
- void *_;
-} hc_result_t;
-
-static hc_result_t *_hc_listener_create_conf(hc_sock_t *s,
- hc_listener_t *listener) {
- ERROR("Not implemented.");
- return NULL;
-}
-static hc_result_t *_hc_connection_create_conf(hc_sock_t *s,
- hc_connection_t *connection) {
- ERROR("Not implemented.");
- return NULL;
-}
-static hc_result_t *_hc_route_create_conf(hc_sock_t *s, hc_route_t *route) {
- ERROR("Not implemented.");
- return NULL;
-}
-static hc_result_t *_hc_strategy_set_conf(hc_sock_t *s,
- hc_strategy_t *strategy) {
- ERROR("Not implemented.");
- return NULL;
-}
-static hc_result_t *_hc_strategy_add_local_prefix_conf(
- hc_sock_t *s, hc_strategy_t *strategy) {
- ERROR("Not implemented.");
- return NULL;
-}
-
-hc_msg_t *_hc_result_get_msg(hc_result_t *result) {
- ERROR("Not implemented.");
- return NULL;
-}
-int _hc_result_get_cmd_id(hc_result_t *result) {
- ERROR("Not implemented.");
- return -1;
-}
-bool _hc_result_get_success(hc_result_t *result) {
- ERROR("Not implemented.");
- return false;
-}
-void _hc_result_free(hc_result_t *result) { free(result); }
-
-static hc_sock_t hc_sock_vpp_interface = (hc_sock_t){
- .hc_sock_get_next_seq = _hc_sock_vpp_get_next_seq,
- .hc_sock_set_nonblocking = _hc_sock_vpp_set_nonblocking,
- .hc_sock_get_fd = _hc_sock_vpp_get_fd,
- .hc_sock_connect = _hc_sock_vpp_connect,
- .hc_sock_get_available = _hc_sock_vpp_get_available,
- .hc_sock_send = _hc_sock_vpp_send,
- .hc_sock_recv = _hc_sock_vpp_recv,
- .hc_sock_process = _hc_sock_vpp_process,
- .hc_sock_callback = _hc_sock_vpp_callback,
- .hc_sock_reset = _hc_sock_vpp_reset,
- .hc_sock_free = _hc_sock_vpp_free,
- .hc_listener_create = _hc_listener_create,
- .hc_listener_create_async = _hc_listener_create_async,
- .hc_listener_get = _hc_listener_get,
- .hc_listener_delete = _hc_listener_delete,
- .hc_listener_delete_async = _hc_listener_delete_async,
- .hc_listener_list = _hc_listener_list,
- .hc_listener_list_async = _hc_listener_list_async,
- .hc_connection_create = _hc_connection_create,
- .hc_connection_create_async = _hc_connection_create_async,
- .hc_connection_get = _hc_connection_get,
- .hc_connection_update_by_id = _hc_connection_update_by_id,
- .hc_connection_update = _hc_connection_update,
- .hc_connection_delete = _hc_connection_delete,
- .hc_connection_delete_async = _hc_connection_delete_async,
- .hc_connection_list = _hc_connection_list,
- .hc_connection_list_async = _hc_connection_list_async,
- .hc_connection_set_admin_state = _hc_connection_set_admin_state,
- .hc_connection_set_admin_state_async = _hc_connection_set_admin_state_async,
-
-#ifdef WITH_POLICY
- .hc_connection_set_priority = _hc_connection_set_priority,
- .hc_connection_set_priority_async = _hc_connection_set_priority_async,
- .hc_connection_set_tags = _hc_connection_set_tags,
- .hc_connection_set_tags_async = _hc_connection_set_tags_async,
-#endif // WITH_POLICY
-
- .hc_face_create = _hc_face_create,
- .hc_face_get = _hc_face_get,
- .hc_face_delete = _hc_face_delete,
- .hc_face_list = _hc_face_list,
- .hc_face_list_async = _hc_face_list_async,
- .hc_face_set_admin_state = _hc_face_set_admin_state,
-
-#ifdef WITH_POLICY
- .hc_face_set_priority = _hc_face_set_priority,
- .hc_face_set_tags = _hc_face_set_tags,
-#endif // WITH_POLICY
-
- .hc_route_create = _hc_route_create,
- .hc_route_create_async = _hc_route_create_async,
- .hc_route_delete = _hc_route_delete,
- .hc_route_delete_async = _hc_route_delete_async,
- .hc_route_list = _hc_route_list,
- .hc_route_list_async = _hc_route_list_async,
-
- .hc_punting_create = _hc_punting_create,
- .hc_punting_create_async = _hc_punting_create_async,
- .hc_punting_get = _hc_punting_get,
- .hc_punting_delete = _hc_punting_delete,
- .hc_punting_list = _hc_punting_list,
-
- .hc_cache_set_store = _hc_cache_set_store,
- .hc_cache_set_store_async = _hc_cache_set_store_async,
- .hc_cache_set_serve = _hc_cache_set_serve,
- .hc_cache_set_serve_async = _hc_cache_set_serve_async,
-
- .hc_strategy_list = _hc_strategy_list,
- .hc_strategy_set = _hc_strategy_set,
- .hc_strategy_add_local_prefix = _hc_strategy_add_local_prefix,
- .hc_wldr_set = _hc_wldr_set,
-
- .hc_mapme_set = _hc_mapme_set,
- .hc_mapme_set_discovery = _hc_mapme_set_discovery,
- .hc_mapme_set_timescale = _hc_mapme_set_timescale,
- .hc_mapme_set_retx = _hc_mapme_set_retx,
-
-#ifdef WITH_POLICY
- .hc_policy_create = _hc_policy_create,
- .hc_policy_create_async = _hc_policy_create_async,
- .hc_policy_delete = _hc_policy_delete,
- .hc_policy_delete_async = _hc_policy_delete_async,
- .hc_policy_list = _hc_policy_list,
- .hc_policy_list_async = _hc_policy_list_async,
-#endif // WITH_POLICY
-
- .hc_listener_create_conf = _hc_listener_create_conf,
- .hc_connection_create_conf = _hc_connection_create_conf,
- .hc_route_create_conf = _hc_route_create_conf,
- .hc_strategy_set_conf = _hc_strategy_set_conf,
- .hc_strategy_add_local_prefix_conf = _hc_strategy_add_local_prefix_conf,
-
- .hc_result_get_msg = _hc_result_get_msg,
- .hc_result_get_cmd_id = _hc_result_get_cmd_id,
- .hc_result_get_success = _hc_result_get_success,
- .hc_result_free = _hc_result_free,
-};
-
-hc_sock_t *_hc_sock_create_url(const char *url) {
- if (url) {
- // NOT IMPLEMENTED
- return NULL;
- }
-
- hc_sock_vpp_t *s = malloc(sizeof(hc_sock_vpp_t));
-
- if (!s) goto ERR_SOCK;
-
- memset(s, 0, sizeof(hc_sock_vpp_t));
-
- s->vft = hc_sock_vpp_interface;
-
- // By default the socket is blocking -- not async
- s->async = 0;
-
- return (hc_sock_t *)(s);
-
-ERR_SOCK:
- return NULL;
-}