summaryrefslogtreecommitdiffstats
path: root/ctrl/libhicnctrl/src/modules
diff options
context:
space:
mode:
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;
-}