aboutsummaryrefslogtreecommitdiffstats
path: root/ctrl/libhicnctrl/src/modules/hicn_light
diff options
context:
space:
mode:
Diffstat (limited to 'ctrl/libhicnctrl/src/modules/hicn_light')
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/base.h49
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/cache.c178
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/connection.c503
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/connection.h11
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/face.c165
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/face.h16
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/listener.c181
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/listener.h8
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/mapme.c68
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/mapme.h28
-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.c177
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/route.h28
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/stats.c113
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/stats.h24
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/strategy.c138
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/strategy.h8
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/subscription.c71
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/subscription.h8
-rw-r--r--ctrl/libhicnctrl/src/modules/hicn_light/wldr.c3
21 files changed, 2013 insertions, 0 deletions
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..ea6fc1bc9
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/base.h
@@ -0,0 +1,49 @@
+#ifndef HICNCTRL_MODULES_HICNLIGHT_BASE_H
+#define HICNCTRL_MODULES_HICNLIGHT_BASE_H
+
+#include <hicn/ctrl/hicn-light.h>
+
+#ifdef __APPLE__
+#define RANDBYTE() (u8)(arc4random() & 0xFF)
+#else
+#define RANDBYTE() (u8)(random() & 0xFF)
+#endif
+
+// TODO: is this used?
+#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)
+
+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..d5648d794
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/connection.c
@@ -0,0 +1,503 @@
+/*
+ * 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 local address received");
+ return -1;
+ }
+
+ if (!IS_VALID_PORT(ntohs(item->local_port))) {
+ ERROR("[hc_connection_parse] Invalid local port received");
+ return -1;
+ }
+
+ if (!IS_VALID_ADDRESS(item->remote_address)) {
+ ERROR("[hc_connection_parse] Invalid remote address received");
+ return -1;
+ }
+
+ if (!IS_VALID_PORT(ntohs(item->remote_port))) {
+ ERROR("[hc_connection_parse] Invalid remote 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
+}
+
+int hicnlight_connection_serialize_set(const hc_object_t *object,
+ uint8_t *packet) {
+ return -1;
+}
+
+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..21f3a2fbc
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/connection.h
@@ -0,0 +1,11 @@
+#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);
+
+DECLARE_MODULE_OBJECT_OPS_H(hicnlight, connection);
+
+#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..4dcd96191
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/face.c
@@ -0,0 +1,165 @@
+#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) {
+ return -99; /* XXX Not implemented */
+}
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..6f202b4ce
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/face.h
@@ -0,0 +1,16 @@
+#ifndef HICNCTRL_MODULE_HICNLIGHT_FACE
+#define HICNCTRL_MODULE_HICNLIGHT_FACE
+
+#include <hicn/ctrl/objects/connection.h>
+#include <hicn/ctrl/objects/face.h>
+
+int hc_connection_to_face(const hc_connection_t *connection, hc_face_t *face);
+
+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..46fded2ca
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/listener.c
@@ -0,0 +1,181 @@
+/*
+ * 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
+}
+
+int hicnlight_listener_serialize_set(const hc_object_t *object,
+ uint8_t *packet) {
+ return -1;
+}
+
+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..67eadfbb1
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/listener.h
@@ -0,0 +1,8 @@
+#ifndef HICNCTRL_MODULE_HICNLIGHT_LISTENER_H
+#define HICNCTRL_MODULE_HICNLIGHT_LISTENER_H
+
+#include "../../module.h"
+
+DECLARE_MODULE_OBJECT_OPS_H(hicnlight, listener);
+
+#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..04eb36e24
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/mapme.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2021-2023 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/mapme.c
+ * \brief Implementation of mapme object VFT for hicn_light.
+ */
+
+#include <hicn/ctrl/hicn-light.h>
+#include "mapme.h"
+
+static int hicnlight_mapme_parse(const uint8_t *buffer, size_t size,
+ hc_mapme_t *mapme) {
+ return -1;
+}
+
+int _hicnlight_mapme_parse(const uint8_t *buffer, size_t size,
+ hc_object_t *object) {
+ return hicnlight_mapme_parse(buffer, size, &object->mapme);
+}
+
+int hicnlight_mapme_serialize_create(const hc_object_t *object,
+ uint8_t *packet) {
+ const hc_mapme_t *mapme = &object->mapme;
+
+ msg_mapme_add_t *msg = (msg_mapme_add_t *)packet;
+ *msg = (msg_mapme_add_t){.header =
+ {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_MAPME_ADD,
+ .length = 1,
+ .seq_num = 0,
+ },
+
+ .payload = {.face_id = mapme->face_id,
+ .family = mapme->family,
+ .address = mapme->address,
+ .len = mapme->len}};
+
+ return sizeof(msg_mapme_add_t);
+}
+
+int hicnlight_mapme_serialize_delete(const hc_object_t *object,
+ uint8_t *packet) {
+ return -1;
+}
+
+int hicnlight_mapme_serialize_list(const hc_object_t *object, uint8_t *packet) {
+ return -1;
+}
+
+int hicnlight_mapme_serialize_set(const hc_object_t *object, uint8_t *packet) {
+ return -1;
+}
+
+DECLARE_MODULE_OBJECT_OPS(hicnlight, mapme);
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/mapme.h b/ctrl/libhicnctrl/src/modules/hicn_light/mapme.h
new file mode 100644
index 000000000..58a943b67
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/mapme.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2023 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/mapme.h
+ * \brief mapme object VFT for hicn_light.
+ */
+
+#ifndef HICNCTRL_MODULE_HICNLIGHT_MAPME_H
+#define HICNCTRL_MODULE_HICNLIGHT_MAPME_H
+
+#include "../../module.h"
+
+DECLARE_MODULE_OBJECT_OPS_H(hicnlight, mapme);
+
+#endif /* HICNCTRL_MODULE_HICNLIGHT_MAPME_H */
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..38510704c
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/route.c
@@ -0,0 +1,177 @@
+/*
+ * 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_route_parse] Invalid face_name received");
+ return -1;
+ }
+
+ if (!IS_VALID_ID(item->face_id)) {
+ ERROR("[hc_route_parse] Invalid face_id received");
+ return -1;
+ }
+
+ if (!IS_VALID_FAMILY(item->family)) {
+ ERROR("[hc_route_parse] Invalid family received");
+ return -1;
+ }
+
+ if (!IS_VALID_ADDRESS(item->remote_addr)) {
+ ERROR("[hc_route_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
+}
+
+int hicnlight_route_serialize_set(const hc_object_t *object, uint8_t *packet) {
+ return -1;
+}
+
+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..825253a42
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/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_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"
+
+DECLARE_MODULE_OBJECT_OPS_H(hicnlight, route);
+
+#endif /* HICNCTRL_MODULE_HICNLIGHT_ROUTE_H */
diff --git a/ctrl/libhicnctrl/src/modules/hicn_light/stats.c b/ctrl/libhicnctrl/src/modules/hicn_light/stats.c
new file mode 100644
index 000000000..a60190a13
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/stats.c
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+/**
+ * \file modules/hicn_light/stats.c
+ * \brief Implementation of stats object VFT for hicn_light.
+ */
+
+#include <hicn/util/log.h>
+#include "base.h"
+#include "stats.h"
+
+/* GENERAL STATS */
+
+int hicnlight_stats_parse(const uint8_t *buffer, size_t size,
+ hc_stats_t *stats) {
+ if (size != sizeof(cmd_stats_list_item_t)) return -1;
+
+ cmd_stats_list_item_t *item = (cmd_stats_list_item_t *)buffer;
+ *stats = item->stats;
+ return 0;
+}
+
+int _hicnlight_stats_parse(const uint8_t *buffer, size_t size,
+ hc_object_t *object) {
+ return hicnlight_stats_parse(buffer, size, &object->stats);
+}
+
+int hicnlight_stats_serialize_create(const hc_object_t *object,
+ uint8_t *packet) {
+ return -1;
+}
+
+int hicnlight_stats_serialize_delete(const hc_object_t *object,
+ uint8_t *packet) {
+ return -1;
+}
+
+int hicnlight_stats_serialize_list(const hc_object_t *object, uint8_t *packet) {
+ msg_stats_list_t *msg = (msg_stats_list_t *)packet;
+ *msg = (msg_stats_list_t){.header = {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_STATS_LIST,
+ .length = 0,
+ .seq_num = 0,
+ }};
+
+ return sizeof(msg_header_t); // Do not use msg_stats_list_t
+}
+
+int hicnlight_stats_serialize_set(const hc_object_t *object, uint8_t *packet) {
+ return -1;
+}
+
+DECLARE_MODULE_OBJECT_OPS(hicnlight, stats);
+
+/* PER-FACE STATS */
+
+int hicnlight_face_stats_parse(const uint8_t *buffer, size_t size,
+ hc_face_stats_t *stats) {
+ if (size != sizeof(cmd_face_stats_list_item_t)) return -1;
+
+ cmd_face_stats_list_item_t *item = (cmd_face_stats_list_item_t *)buffer;
+ *stats = item->stats;
+ return 0;
+}
+
+int _hicnlight_face_stats_parse(const uint8_t *buffer, size_t size,
+ hc_object_t *object) {
+ return hicnlight_face_stats_parse(buffer, size, &object->face_stats);
+}
+
+int hicnlight_face_stats_serialize_create(const hc_object_t *object,
+ uint8_t *packet) {
+ return -1;
+}
+
+int hicnlight_face_stats_serialize_delete(const hc_object_t *object,
+ uint8_t *packet) {
+ return -1;
+}
+
+int hicnlight_face_stats_serialize_list(const hc_object_t *object,
+ uint8_t *packet) {
+ msg_face_stats_list_t *msg = (msg_face_stats_list_t *)packet;
+ *msg = (msg_face_stats_list_t){.header = {
+ .message_type = REQUEST_LIGHT,
+ .command_id = COMMAND_TYPE_FACE_STATS_LIST,
+ .length = 0,
+ .seq_num = 0,
+ }};
+
+ return sizeof(msg_header_t); // Do not use msg_stats_list_t
+}
+
+int hicnlight_face_stats_serialize_set(const hc_object_t *object,
+ uint8_t *packet) {
+ return -1;
+}
+
+DECLARE_MODULE_OBJECT_OPS(hicnlight, face_stats);
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..9509be86c
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/stats.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+#ifndef HICNCTRL_MODULE_HICNLIGHT_STATS_H
+#define HICNCTRL_MODULE_HICNLIGHT_STATS_H
+
+#include "../../module.h"
+
+DECLARE_MODULE_OBJECT_OPS_H(hicnlight, stats);
+DECLARE_MODULE_OBJECT_OPS_H(hicnlight, face_stats);
+
+#endif /* HICNCTRL_MODULE_HICNLIGHT_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..16ce2d047
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/strategy.c
@@ -0,0 +1,138 @@
+#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;
+}
+
+int hicnlight_strategy_serialize_set(const hc_object_t *object,
+ uint8_t *packet) {
+ const hc_strategy_t *strategy = &object->strategy;
+
+ msg_strategy_set_t *msg = (msg_strategy_set_t *)packet;
+ *msg = (msg_strategy_set_t){.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,
+ }};
+
+ return sizeof(msg_strategy_set_t);
+}
+
+#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;
+}
+
+/* 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..9fa809751
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/strategy.h
@@ -0,0 +1,8 @@
+#ifndef HICNCTRL_MODULE_HICNLIGHT_STRATEGY_H
+#define HICNCTRL_MODULE_HICNLIGHT_STRATEGY_H
+
+#include "../../module.h"
+
+DECLARE_MODULE_OBJECT_OPS_H(hicnlight, strategy);
+
+#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..e2de09bf5
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/subscription.c
@@ -0,0 +1,71 @@
+#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;
+}
+
+int hicnlight_subscription_serialize_set(const hc_object_t *object,
+ uint8_t *packet) {
+ 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..d67bdd9ba
--- /dev/null
+++ b/ctrl/libhicnctrl/src/modules/hicn_light/subscription.h
@@ -0,0 +1,8 @@
+#ifndef HICNCTRL_MODULE_HICNLIGHT_SUBSCRIPTION_H
+#define HICNCTRL_MODULE_HICNLIGHT_SUBSCRIPTION_H
+
+#include "../../module.h"
+
+DECLARE_MODULE_OBJECT_OPS_H(hicnlight, subscription);
+
+#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; }