aboutsummaryrefslogtreecommitdiffstats
path: root/hicn-light/src/hicn/core
diff options
context:
space:
mode:
Diffstat (limited to 'hicn-light/src/hicn/core')
-rw-r--r--hicn-light/src/hicn/core/CMakeLists.txt54
-rw-r--r--hicn-light/src/hicn/core/address.c43
-rw-r--r--hicn-light/src/hicn/core/address.h88
-rw-r--r--hicn-light/src/hicn/core/address_pair.c33
-rw-r--r--hicn-light/src/hicn/core/address_pair.h48
-rw-r--r--hicn-light/src/hicn/core/connection.c720
-rw-r--r--hicn-light/src/hicn/core/connection.h279
-rw-r--r--hicn-light/src/hicn/core/connectionList.c68
-rw-r--r--hicn-light/src/hicn/core/connectionList.h70
-rw-r--r--hicn-light/src/hicn/core/connectionManager.c196
-rw-r--r--hicn-light/src/hicn/core/connectionManager.h37
-rw-r--r--hicn-light/src/hicn/core/connectionTable.c226
-rw-r--r--hicn-light/src/hicn/core/connectionTable.h99
-rw-r--r--hicn-light/src/hicn/core/connection_table.c89
-rw-r--r--hicn-light/src/hicn/core/connection_table.h126
-rw-r--r--hicn-light/src/hicn/core/connection_vft.c (renamed from hicn-light/src/hicn/core/connectionState.h)30
-rw-r--r--hicn-light/src/hicn/core/connection_vft.h51
-rw-r--r--hicn-light/src/hicn/core/content_store.c198
-rw-r--r--hicn-light/src/hicn/core/content_store.h125
-rw-r--r--hicn-light/src/hicn/core/dispatcher.c474
-rw-r--r--hicn-light/src/hicn/core/dispatcher.h288
-rw-r--r--hicn-light/src/hicn/core/fib.c531
-rw-r--r--hicn-light/src/hicn/core/fib.h60
-rw-r--r--hicn-light/src/hicn/core/fib_entry.c503
-rw-r--r--hicn-light/src/hicn/core/fib_entry.h166
-rw-r--r--hicn-light/src/hicn/core/forwarder.c1370
-rw-r--r--hicn-light/src/hicn/core/forwarder.h225
-rw-r--r--hicn-light/src/hicn/core/listener.c326
-rw-r--r--hicn-light/src/hicn/core/listener.h97
-rw-r--r--hicn-light/src/hicn/core/listener_table.c107
-rw-r--r--hicn-light/src/hicn/core/listener_table.h106
-rw-r--r--hicn-light/src/hicn/core/listener_vft.c31
-rw-r--r--hicn-light/src/hicn/core/listener_vft.h55
-rw-r--r--hicn-light/src/hicn/core/logger.c177
-rw-r--r--hicn-light/src/hicn/core/logger.h170
-rw-r--r--hicn-light/src/hicn/core/mapme.c1573
-rw-r--r--hicn-light/src/hicn/core/mapme.h46
-rw-r--r--hicn-light/src/hicn/core/message.c298
-rw-r--r--hicn-light/src/hicn/core/message.h180
-rw-r--r--hicn-light/src/hicn/core/messageHandler.h219
-rw-r--r--hicn-light/src/hicn/core/messagePacketType.h11
-rw-r--r--hicn-light/src/hicn/core/msgbuf.c21
-rw-r--r--hicn-light/src/hicn/core/msgbuf.h80
-rw-r--r--hicn-light/src/hicn/core/name.c380
-rw-r--r--hicn-light/src/hicn/core/name.h7
-rw-r--r--hicn-light/src/hicn/core/nameBitvector.c534
-rw-r--r--hicn-light/src/hicn/core/nameBitvector.h4
-rw-r--r--hicn-light/src/hicn/core/nexthops.h154
-rw-r--r--hicn-light/src/hicn/core/numberSet.c203
-rw-r--r--hicn-light/src/hicn/core/numberSet.h157
-rw-r--r--hicn-light/src/hicn/core/packet_cache.c20
-rw-r--r--hicn-light/src/hicn/core/packet_cache.h20
-rw-r--r--hicn-light/src/hicn/core/pit.c227
-rw-r--r--hicn-light/src/hicn/core/pit.h92
-rw-r--r--hicn-light/src/hicn/core/prefix_stats.c202
-rw-r--r--hicn-light/src/hicn/core/prefix_stats.h91
-rw-r--r--hicn-light/src/hicn/core/strategy.c39
-rw-r--r--hicn-light/src/hicn/core/strategy.h70
-rw-r--r--hicn-light/src/hicn/core/strategy_vft.h76
-rw-r--r--hicn-light/src/hicn/core/system.h1
-rw-r--r--hicn-light/src/hicn/core/ticks.h33
-rw-r--r--hicn-light/src/hicn/core/wldr.c106
-rw-r--r--hicn-light/src/hicn/core/wldr.h19
63 files changed, 7027 insertions, 5102 deletions
diff --git a/hicn-light/src/hicn/core/CMakeLists.txt b/hicn-light/src/hicn/core/CMakeLists.txt
index 5e2b696d7..b1f952a43 100644
--- a/hicn-light/src/hicn/core/CMakeLists.txt
+++ b/hicn-light/src/hicn/core/CMakeLists.txt
@@ -14,20 +14,27 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
list(APPEND HEADER_FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/connectionManager.h
- ${CMAKE_CURRENT_SOURCE_DIR}/connectionState.h
- ${CMAKE_CURRENT_SOURCE_DIR}/ticks.h
- ${CMAKE_CURRENT_SOURCE_DIR}/connectionList.h
- ${CMAKE_CURRENT_SOURCE_DIR}/connectionTable.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/address.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/address_pair.h
${CMAKE_CURRENT_SOURCE_DIR}/connection.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/connection_vft.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/connection_table.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/content_store.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/fib_entry.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/fib.h
${CMAKE_CURRENT_SOURCE_DIR}/forwarder.h
- ${CMAKE_CURRENT_SOURCE_DIR}/logger.h
- ${CMAKE_CURRENT_SOURCE_DIR}/dispatcher.h
- ${CMAKE_CURRENT_SOURCE_DIR}/message.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/listener.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/listener_table.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/listener_vft.h
${CMAKE_CURRENT_SOURCE_DIR}/messagePacketType.h
- ${CMAKE_CURRENT_SOURCE_DIR}/numberSet.h
- ${CMAKE_CURRENT_SOURCE_DIR}/streamBuffer.h
- ${CMAKE_CURRENT_SOURCE_DIR}/system.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/msgbuf.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/packet_cache.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/pit.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/prefix_stats.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/strategy.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/strategy_vft.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/ticks.h
+# ${CMAKE_CURRENT_SOURCE_DIR}/system.h
${CMAKE_CURRENT_SOURCE_DIR}/mapme.h
${CMAKE_CURRENT_SOURCE_DIR}/wldr.h
${CMAKE_CURRENT_SOURCE_DIR}/messageHandler.h
@@ -36,20 +43,27 @@ list(APPEND HEADER_FILES
)
list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/address.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/address_pair.c
${CMAKE_CURRENT_SOURCE_DIR}/connection.c
- ${CMAKE_CURRENT_SOURCE_DIR}/connectionList.c
- ${CMAKE_CURRENT_SOURCE_DIR}/connectionManager.c
- ${CMAKE_CURRENT_SOURCE_DIR}/connectionTable.c
- ${CMAKE_CURRENT_SOURCE_DIR}/dispatcher.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/connection_table.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/connection_vft.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/content_store.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fib.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fib_entry.c
${CMAKE_CURRENT_SOURCE_DIR}/forwarder.c
- ${CMAKE_CURRENT_SOURCE_DIR}/logger.c
- ${CMAKE_CURRENT_SOURCE_DIR}/message.c
- ${CMAKE_CURRENT_SOURCE_DIR}/numberSet.c
- ${CMAKE_CURRENT_SOURCE_DIR}/streamBuffer.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/listener.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/listener_table.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/listener_vft.c
${CMAKE_CURRENT_SOURCE_DIR}/mapme.c
- ${CMAKE_CURRENT_SOURCE_DIR}/wldr.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/msgbuf.c
${CMAKE_CURRENT_SOURCE_DIR}/nameBitvector.c
${CMAKE_CURRENT_SOURCE_DIR}/name.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/packet_cache.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/pit.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/prefix_stats.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/strategy.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/wldr.c
)
set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
diff --git a/hicn-light/src/hicn/core/address.c b/hicn-light/src/hicn/core/address.c
new file mode 100644
index 000000000..07aa4a8bd
--- /dev/null
+++ b/hicn-light/src/hicn/core/address.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file address.c
+ * \brief Implementation of Address
+ */
+
+#include <hicn/core/address.h>
+
+int
+address_from_ip_port(address_t * address, int family, ip_address_t * addr, uint16_t port)
+{
+ memset(address, 0, sizeof(address_t));
+ switch(family) {
+ case AF_INET:
+ *address = ADDRESS4(addr->v4.as_inaddr.s_addr, port);
+ break;
+ case AF_INET6:
+ *address = ADDRESS6(addr->v6.as_in6addr, port);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+const char * _address_family_str[] = {
+ [AF_INET] = "AF_INET",
+ [AF_INET6] = "AF_INET6",
+};
diff --git a/hicn-light/src/hicn/core/address.h b/hicn-light/src/hicn/core/address.h
new file mode 100644
index 000000000..d13fc99ed
--- /dev/null
+++ b/hicn-light/src/hicn/core/address.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file address.h
+ * \brief Address
+ */
+
+#ifndef HICN_ADDRESS_H
+#define HICN_ADDRESS_H
+
+#include <netinet/in.h>
+
+#include <string.h> // memcmp
+#include <hicn/util/ip_address.h>
+#include <netinet/in.h>
+
+typedef struct sockaddr_storage address_t;
+
+#define address_equals(a, b) (memcmp(a, b, sizeof(address_t)) == 0)
+
+#define address_family(address) ((address)->ss_family)
+
+#define address4(address) ((struct sockaddr_in *)(address))
+#define address6(address) ((struct sockaddr_in6 *)(address))
+#define address_sa(address) ((struct sockaddr *)(address))
+
+#define address4_ip(address) (address4(address)->sin_addr)
+#define address6_ip(address) (address6(address)->sin6_addr)
+#define address6_scope_id(address) (address4_ptr(address)->sin6_scope_id)
+
+#define address_socklen(address) (((address)->ss_family == AF_INET) \
+ ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))
+
+#define address4_is_local(address) \
+ ((htonl((address4_ip(address)).s_addr) & 0xFF000000) == 0x7F000000)
+
+#define address6_is_local(address) (IN6_IS_ADDR_LOOPBACK(address6(address)))
+
+#define address_is_local(address) ((address)->ss_family == AF_INET) \
+ ? address4_is_local(address) : address6_is_local(address)
+
+int address_from_ip_port(address_t * address, int family, ip_address_t * addr, uint16_t port);
+
+#define ADDRESS4(ip, port) (*(address_t*) &((struct sockaddr_in) { \
+ .sin_family = AF_INET, \
+ .sin_port = htons(port), \
+ .sin_addr.s_addr = htonl(ip), \
+}))
+
+#define ADDRESS4_LOCALHOST(port) ADDRESS4(INADDR_LOOPBACK, (port))
+#define ADDRESS4_ANY(port) ADDRESS4(INADDR_ANY, (port))
+
+#define ADDRESS6(ip, port) (*(address_t*) &((struct sockaddr_in6) {\
+ .sin6_family = AF_INET6, \
+ .sin6_port = htons(port), \
+ .sin6_addr = IN6ADDR_ANY_INIT, \
+ .sin6_scope_id = 0, \
+}))
+
+#define ADDRESS6_ANY(port) ADDRESS6(IN6ADDR_ANY_INIT, port)
+
+#define ADDRESS_ANY(family, port) ((family == AF_INET) \
+ ? ADDRESS4_ANY(port) \
+ : ADDRESS6_ANY(port))
+
+extern const char * _address_family_str[];
+
+#define address_family_str(address) (_address_family_str[address_family(address)])
+
+#define address4_empty(address) (address4_ip(address).s_addr == 0)
+#define address6_empty(address) (memcmp(address6_ip(address).s6_addr, &in6addr_any, sizeof(struct in6_addr)) == 0)
+#define address_empty(address) (address_family(address) == AF_INET ? address4_empty(address) : address6_empty(address))
+
+#endif /* HICN_ADDRESS_H */
+
diff --git a/hicn-light/src/hicn/core/address_pair.c b/hicn-light/src/hicn/core/address_pair.c
new file mode 100644
index 000000000..dee06c0a7
--- /dev/null
+++ b/hicn-light/src/hicn/core/address_pair.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file address_pair.c
+ * \brief Implementation of Address pair
+ */
+
+#include "address_pair.h"
+
+int
+address_pair_from_ip_port(address_pair_t * pair, int family,
+ ip_address_t * local_addr, uint16_t local_port,
+ ip_address_t * remote_addr, uint16_t remote_port)
+{
+ if (address_from_ip_port(&pair->local, family, local_addr, local_port) < 0)
+ return -1;
+ if (address_from_ip_port(&pair->remote, family, remote_addr, remote_port) < 0)
+ return -1;
+ return 0;
+}
diff --git a/hicn-light/src/hicn/core/address_pair.h b/hicn-light/src/hicn/core/address_pair.h
new file mode 100644
index 000000000..fae4f255f
--- /dev/null
+++ b/hicn-light/src/hicn/core/address_pair.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file address_pair.h
+ * \brief Address pair
+ */
+
+#ifndef HICN_ADDRESS_PAIR_H
+#define HICN_ADDRESS_PAIR_H
+
+#include <hicn/core/address.h>
+#include <hicn/util/ip_address.h>
+
+typedef struct {
+ address_t local;
+ address_t remote;
+} address_pair_t;
+
+int address_pair_from_ip_port(address_pair_t * pair, int family,
+ ip_address_t * local_addr, uint16_t local_port,
+ ip_address_t * remote_addr, uint16_t remote_port);
+
+#define address_pair_get_local(pair) (&(pair)->local)
+#define address_pair_get_remote(pair) (&(pair)->remote)
+
+#define address_pair_get_local_family(pair) \
+ (address_family(address_pair_local(pair)))
+#define address_pair_get_remote_family(pair) \
+ (address_family(address_pair_remote(pair)))
+#define address_pair_get_family(pair) address_pair_local_family(pair)
+
+#define address_pair_is_valid(pair) \
+ (address_pair_local_family(pair) == address_pair_remote_family(pair))
+
+#endif /* HICN_ADDRESS_PAIR_H */
diff --git a/hicn-light/src/hicn/core/connection.c b/hicn-light/src/hicn/core/connection.c
index c2ac71a5f..582e2f56f 100644
--- a/hicn-light/src/hicn/core/connection.c
+++ b/hicn-light/src/hicn/core/connection.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2020 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -13,347 +13,583 @@
* limitations under the License.
*/
-#include <limits.h>
-#include <hicn/hicn-light/config.h>
-#include <stdio.h>
+/**
+ * @file connection.c
+ * @brief Implementation of hICN connections
+ */
-#include <hicn/core/connection.h>
-#include <hicn/core/connectionState.h>
-#include <hicn/core/messageHandler.h>
-#include <hicn/core/ticks.h>
-#include <hicn/core/wldr.h>
-#include <hicn/io/addressPair.h>
-#include <hicn/io/ioOperations.h>
+#include <assert.h>
-#include <parc/algol/parc_Memory.h>
-#include <parc/assert/parc_Assert.h>
-#ifdef WITH_POLICY
-#include <hicn/policy.h>
-#endif /* WITH_POLICY */
+#include <hicn/core/forwarder.h>
+#include <hicn/util/log.h>
+#include <hicn/core/wldr.h>
-struct connection {
+#include "connection.h"
+#include "connection_vft.h"
- const AddressPair *addressPair;
- IoOperations *ops;
+#define _conn_var(x) _connection_ ## x
- unsigned refCount;
+#if 0
- unsigned counter;
+/* Accessors */
- bool wldrAutoStart; // if true, wldr can be set automatically
- // by default this value is set to true.
- // if wldr is activated using a command (config
- // file/hicnLightControl) this value is set to false so
- // that a base station can not disable wldr at the client
- Wldr *wldr;
+static inline
+unsigned
+connection_get_id(const connection_t * connection)
+{
+ return connection->id;
+}
-#ifdef WITH_POLICY
- policy_tags_t tags;
-#endif /* WITH_POLICY */
+static inline
+char *
+connection_get_name(const connection_t * connection)
+{
+ return connection->name;
+}
-};
+static inline
+face_type_t
+connection_get_type(const connection_t * connection)
+{
+ return connection->type;
+}
-Connection *connection_Create(IoOperations *ops) {
- parcAssertNotNull(ops, "Parameter ops must be non-null");
- Connection *conn = parcMemory_AllocateAndClear(sizeof(Connection));
- parcAssertNotNull(conn, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(Connection));
- conn->addressPair = ioOperations_GetAddressPair(ops);
- conn->ops = ops;
- conn->refCount = 1;
- conn->wldr = NULL;
+static inline
+address_pair_t *
+connection_get_pair(const connection_t * connection)
+{
+ return connection->pair;
+}
- conn->wldrAutoStart = true;
- conn->counter = 0;
+static inline
+bool
+connection_is_up(const connection_t * connection)
+{
+ return connection->up;
+}
- /* By default, a connection will aim at the UP state */
- connection_SetAdminState(conn, CONNECTION_STATE_UP);
+static inline
+bool
+connection_is_local(const connection_t * connection)
+{
+ return connection->local;
+}
-#ifdef WITH_POLICY
- conn->tags = POLICY_TAGS_EMPTY;
-#endif /* WITH_POLICY */
+static inline
+face_state_t
+connection_get_state(const connection_t * connection)
+{
+ return connection->state;
+}
- return conn;
+static inline
+void
+connection_set_state(connection_t * connection, face_state_t state)
+{
+ connection->state = state;
}
-Connection *connection_Acquire(Connection *connection) {
- parcAssertNotNull(connection, "Parameter conn must be non-null");
- connection->refCount++;
- return connection;
+static inline
+face_state_t
+connection_get_admin_state(const connection_t * connection)
+{
+ return connection->admin_state;
}
-void connection_Release(Connection **connectionPtr) {
- parcAssertNotNull(connectionPtr, "Parameter must be non-null double pointer");
- parcAssertNotNull(*connectionPtr,
- "Parameter must dereference to non-null pointer");
- Connection *conn = *connectionPtr;
+static inline
+void
+connection_set_admin_state(connection_t * connection, face_state_t state)
+{
+ connection->admin_state = state;
+}
- parcAssertTrue(
- conn->refCount > 0,
- "Invalid state, connection reference count should be positive, got 0.");
- conn->refCount--;
- if (conn->refCount == 0) {
- // don't destroy addressPair, its part of ops.
- ioOperations_Release(&conn->ops);
- if (conn->wldr != NULL) {
- wldr_Destroy(&(conn->wldr));
- }
- parcMemory_Deallocate((void **)&conn);
- }
- *connectionPtr = NULL;
+static inline
+const char *
+connection_get_interface_name(const connection_t * connection)
+{
+ return connection->interface_name;
}
-bool connection_Send(const Connection *conn, Message *message) {
- parcAssertNotNull(conn, "Parameter conn must be non-null");
- parcAssertNotNull(message, "Parameter message must be non-null");
+#ifdef WITH_POLICY
- if (ioOperations_IsUp(conn->ops)) {
- if (message_GetType(message) == MessagePacketType_ContentObject) {
- uint8_t connectionId = (uint8_t)connection_GetConnectionId(conn);
- message_UpdatePathLabel(message, connectionId);
- }
- if (conn->wldr != NULL) {
- wldr_SetLabel(conn->wldr, message);
- } else {
- message_ResetWldrLabel(message);
- }
- return ioOperations_Send(conn->ops, NULL, message);
- }
- return false;
+static inline
+uint32_t
+connection_get_priority(const connection_t * connection)
+{
+ connection->priority = priority;
}
-bool connection_SendIOVBuffer(const Connection *conn, struct iovec *msg,
- size_t size) {
- parcAssertNotNull(conn, "Parameter conn must be non-null");
- parcAssertNotNull(msg, "Parameter message must be non-null");
-
- return ioOperations_SendIOVBuffer(conn->ops, msg, size);
+static inline
+void
+connection_set_priority(connection_t * connection, uint32_t priority)
+{
+ connection->priority = priority;
}
-bool connection_SendBuffer(const Connection *conn, u8 * buffer, size_t length)
+static inline
+policy_tags_t
+connection_get_tags(const connection_t * connection)
{
- struct iovec iov[1];
- iov[0].iov_base = buffer;
- iov[0].iov_len = length;
- return connection_SendIOVBuffer(conn, iov, 1);
+ return connection->tags;
}
-void connection_Probe(Connection *conn, uint8_t * probe) {
- ioOperations_SendProbe(conn->ops, probe);
+static inline
+void
+connection_set_tags(connection_t * connection, policy_tags_t tags)
+{
+ connection->tags = tags;
}
-void connection_HandleProbe(Connection *conn, uint8_t *probe){
- parcAssertNotNull(conn, "Parameter conn must be non-null");
- parcAssertNotNull(probe, "Parameter pkt must be non-null");
+#endif /* WITH_POLICY */
- if(messageHandler_IsInterest(probe)){
- messageHandler_CreateProbeReply(probe, HF_INET6_TCP);
- ioOperations_SendProbe(conn->ops, probe);
- }
-}
+/* API */
-IoOperations *connection_GetIoOperations(const Connection *conn) {
- return conn->ops;
-}
+#endif
-unsigned connection_GetConnectionId(const Connection *conn) {
- parcAssertNotNull(conn, "Parameter conn must be non-null");
- return ioOperations_GetConnectionId(conn->ops);
-}
+connection_t *
+connection_create_on_listener(const listener_t * listener, const char * name,
+ const address_pair_t * pair, forwarder_t * forwarder)
+{
+ const connection_table_t * table = forwarder_get_connection_table(forwarder);
-const AddressPair *connection_GetAddressPair(const Connection *conn) {
- parcAssertNotNull(conn, "Parameter conn must be non-null");
- return ioOperations_GetAddressPair(conn->ops);
-}
+ connection_t * connection;
+ connection_table_allocate(table, connection, pair, name);
-bool connection_IsUp(const Connection *conn) {
- parcAssertNotNull(conn, "Parameter conn must be non-null");
- if (!conn->ops) return false;
- return ioOperations_IsUp(conn->ops);
+ unsigned connection_id = connection_table_get_connection_id(table, connection);
+
+ const char * interface_name = listener_get_interface_name(listener);
+ // XXX This should not be there !
+ int fd = listener_get_socket(listener, address_pair_get_local(pair),
+ address_pair_get_remote(pair), NULL);
+ bool local = address_is_local(&pair->local);
+
+ if (connection_initialize(connection, listener->type, name, interface_name, fd, pair, local,
+ connection_id, forwarder) < 0) {
+ connection_table_deallocate(table, connection);
+ return NULL;
+ }
+
+ return connection;
}
-bool connection_IsLocal(const Connection *conn) {
- parcAssertNotNull(conn, "Parameter conn must be non-null");
- return ioOperations_IsLocal(conn->ops);
+
+// This is called by configuration
+// XXX different wit create on listener : when listener receives a new
+// connection
+// !
+connection_t *
+connection_create(face_type_t type, const char * name,
+ const address_pair_t * pair, forwarder_t * forwarder)
+{
+ assert(face_type_is_valid(type));
+ assert(pair);
+ assert(forwarder);
+
+ listener_table_t * table = forwarder_get_listener_table(forwarder);
+ listener_t *listener = listener_table_get_by_address(table, type, &pair->local);
+ if (!listener) {
+ // XXX TODO
+ //char *str = addressToString(localAddress);
+ ERROR("Could not find listener to match address N/A");
+ //parcMemory_Deallocate((void **)&str);
+ return NULL;
+ }
+
+ return connection_create_on_listener(listener, name, pair, forwarder);
}
-const void *connection_Class(const Connection *conn) {
- parcAssertNotNull(conn, "Parameter conn must be non-null");
- return ioOperations_Class(conn->ops);
+#if 0
+
+ const char * interface_name = listener->getInterfaceName(listener);
+ int fd = listener->getSocket(listener, pair);
+ bool is_local = address_is_local(&pair->local);
+
+
+ return udpConnection_Create(forwarder, interface_name, fd, pair, is_local, connid);
+
+ // alternatively
+ //
}
+#endif
-bool connection_ReSend(const Connection *conn, Message *message,
- bool notification) {
- parcAssertNotNull(conn, "Parameter conn must be non-null");
- parcAssertNotNull(message, "Parameter message must be non-null");
- bool res = false;
+/**
+ * @brief Initializes a connection
+ *
+ * @param [out] connection - Allocated connection buffer (eg. from pool) to be
+ * initialized.
+ * @param [in] forwarder - forwarder_t to which the connection is associated. This
+ * parameter needs to be non-NULL for connections receiving packets, such
+ * as TCP connections which are very close to UDP listeners, and unlike
+ * bound UDP connections).
+ * @return 0 if no error, -1 otherwise
+ */
+int
+connection_initialize(connection_t * connection, face_type_t type, const char * name,
+ const char * interface_name, int fd, const address_pair_t * pair,
+ bool local, unsigned connection_id, forwarder_t * forwarder)
+{
+ int rc;
+
+ assert(connection);
+ /* Interface name can be NULL eg always for TCP connnections */
+ assert(pair);
+ assert(address_pair_valid(pair));
+
+ *connection = (connection_t) {
+ .id = connection_id,
+ .name = strdup(name),
+ .type = type,
+ .interface_name = strdup(interface_name),
+ .pair = *pair,
+ .fd = fd,
+// .up = true,
+ .local = local,
+ // XXX UDP should start UP, TCP DOWN until remove side answer ?
+ .state = FACE_STATE_UNDEFINED,
+ .admin_state = FACE_STATE_UP,
+#ifdef WITH_POLICY
+ .priority = 0,
+#endif /* WITH_POLICY */
- if (connection_IsUp(conn)) {
- // here the wldr header is alreay set: this message is a retransmission or a
- // notification
+ .forwarder = forwarder,
+ .closed = false,
- // we need to recompiute the path lable since we always store a pointer to
- // the same message if this message will be sent again to someonelse, the
- // new path label must be computed starting from the orignal labelorignal
- // label. Notice that we heve the same problem in case of PIT aggregation.
- // That case is handled insied the MessageProcessor. This is specific to
- // WLDR retransmittions. This is done only for data packets
+ /* WLDR */
+ .wldr = NULL,
+ .wldr_autostart = true,
+ };
- if (message_GetType(message) == MessagePacketType_ContentObject) {
- uint8_t connectionId = (uint8_t)connection_GetConnectionId(conn);
- uint32_t old_path_label = message_GetPathLabel(message);
- message_UpdatePathLabel(message, connectionId);
+ connection->data = malloc(connection_vft[connection->type]->data_size);
+ if (!connection->data)
+ goto ERR_DATA;
- res = ioOperations_Send(conn->ops, NULL, message);
+ assert(connection_has_valid_type(connection));
- message_SetPathLabel(message, old_path_label);
- } else {
- res = ioOperations_Send(conn->ops, NULL, message);
+ rc = connection_vft[connection->type]->initialize(connection);
+ if (rc < 0) {
+ goto ERR_VFT;
}
- }
- if (notification) {
- // the notification is never destroyed
- message_Release(&message);
- }
+ // XXX uncertain as fd is created by the listener !!
+ // XXX check whether it is registered !
+#if 0
+ connection->fd = connection_vft[connection->type]->get_socket(connection, address, NULL, interface_name);
+ if (connection->fd < 0) {
+ ERROR("Error creating connection fd: (%d) %s", errno, strerror(errno));
+ goto ERR_FD;
+ }
+
+ // XXX data should be pre-allocated here
+
+ if (loop_register_fd(MAIN_LOOP, connection->fd, connection,
+ connection_vft[connection->type]->read_callback, NULL) < 0)
+ goto ERR_REGISTER_FD;
+#endif
+
+ // XXX TODO
+ //char *str = pair_ToString(udp->pair);
+ DEBUG("%s connection %p created for address %s (local=%s)",
+ face_type_str(connection->type), connection, "N/A",
+ connection_is_local(connection) ? "true" : "false");
+ //free(str);
+ //
+ return 0;
+
+#if 0
+ERR_REGISTER_FD:
+#ifndef _WIN32
+ close(connection->fd);
+#else
+ closesocket(connection->fd);
+#endif
+ERR_FD:
+#endif
+ERR_VFT:
+ free(connection->data);
+ERR_DATA:
+ free(connection->interface_name);
+ free(connection->name);
+ return -1;
+}
+
+int
+connection_finalize(connection_t * connection)
+{
+ assert(connection);
- return res;
+ if (connection->wldr)
+ wldr_free(connection->wldr);
+
+ connection_vft[connection->type]->finalize(connection);
+
+ free(connection->interface_name);
+ free(connection);
+
+ DEBUG("%s connection %p destroyed", face_type_str(connection->type),
+ connection);
+
+ return 0;
}
-void connection_AllowWldrAutoStart(Connection *conn, bool allow) {
- conn->wldrAutoStart = allow;
+#if 0
+// XXX put in common the validation and processing of commands with UDP and hICN
+// listeners !
+command_type_t
+_isACommand(PARCEventBuffer *input)
+{
+ size_t bytesAvailable = parcEventBuffer_GetLength(input);
+ parcAssertTrue(bytesAvailable >= sizeof(header_control_message),
+ "Called with too short an input: %zu", bytesAvailable);
+
+ uint8_t *msg = parcEventBuffer_Pullup(input, bytesAvailable);
+
+ message_type_t message_type = message_type_from_uchar(msg[0]);
+ //if (!message_type_is_valid(message_type))
+ if (message_type != REQUEST_LIGHT)
+ return COMMAND_TYPE_N;
+
+ return command_type_from_uchar(msg[1]);
}
-void connection_EnableWldr(Connection *conn) {
- if (!connection_IsLocal(conn)) {
- if (conn->wldr == NULL) {
- printf("----------------- enable wldr\n");
- conn->wldr = wldr_Init();
+// XXX new function to process all incoming bytes
+// result : consumed, discard/invalid, wait for more
+// PRE: buffer has at least 8 bytes (to get the length of all packets)
+// This function is only used to make decisions
+/**
+ * \return the number of consumed bytes, or a negative value in case of error
+ */
+// XXX mutualize with listener_process_buffer
+size_t
+connection_process_buffer(connection_t * connection, const uint8_t * buffer, size_t size)
+{
+ size_t expected;
+
+ /* Too small a packet is not useful to decide between a control message and
+ * an hICN packet, the size of a control message is enough to test for both
+ * pakcet types */
+ if (size < sizeof(header_control_message))
+ return 0;
+
+ /* We expect complete packets most of the time, so don't bother with state */
+ message_type_t message_type = message_type_from_uchar(msg[0]);
+ if (message_type == REQUEST_LIGHT) {
+ command_type_t command_type = command_type_from_uchar(msg[1]);
+ if (!command_type_is_valid(command_type))
+ break;
+ expected = sizeof(header_control_message) +
+ command_get_payload_len(command_type);
+ if (size < expected)
+ return 0;
+ forwarder_receive_command(connection->forwarder, command_type, packet,
+ connection->id);
+ return expected;
+ }
+
+ if (!messageHandler_IsValidHicnPacket(packet)) {
+ WARN("Connection #%u: Malformed packet received",
+ connection_get_id(connection));
+ return -1;
}
- }
-}
-void connection_DisableWldr(Connection *conn) {
- if (!connection_IsLocal(conn)) {
- if (conn->wldr != NULL) {
- printf("----------------- disable wldr\n");
- wldr_Destroy(&(conn->wldr));
- conn->wldr = NULL;
+ /* Check that we have a full packet */
+ expected = messageHandler_GetTotalPacketLength(packet),
+ if (size < expected)
+ return 0;
+
+ msgbuf_t msgbuf;
+ MessagePacketType packet_type;
+ if (messageHandler_IsInterest(message->messageHead)) {
+ packet_type = MESSAGE_TYPE_INTEREST;
+ } else if (messageHandler_IsData(message->messageHead)) {
+ packet_type = MESSAGE_TYPE_DATA;
+ } else {
+ ERROR("Dropped packet that is not interest nor data");
+ return -1;
}
- }
-}
-bool connection_HasWldr(const Connection *conn) {
- if (conn->wldr == NULL) {
- return false;
- } else {
- return true;
- }
-}
+ // this is an Hicn packet (here we should distinguish between IPv4 and
+ // IPv6 tryReadMessage may set nextMessageLength
+ msgbuf_from_packet(&msgbuf, packet, expected, packet_type,
+ connection_get_id(connection), ticks_now());
+ forwarder_receive(connection->forwarder, &msgbuf, 1);
-bool connection_WldrAutoStartAllowed(const Connection *conn) {
- return conn->wldrAutoStart;
+ return size;
}
-void connection_DetectLosses(Connection *conn, Message *message) {
- if (conn->wldr != NULL) wldr_DetectLosses(conn->wldr, conn, message);
-}
+int
+connection_read_message(connection_t * connection, msgbuf_t * msgbuf)
+{
+ assert(connection);
+ assert(face_type_is_valid(connection->type));
+ assert(msgbuf);
-void connection_HandleWldrNotification(Connection *conn, Message *message) {
- if (conn->wldr != NULL)
- wldr_HandleWldrNotification(conn->wldr, conn, message);
+ return connection_vft[connection->type]->read_message(connection, msgbuf);
}
-connection_state_t connection_GetState(const Connection *conn)
+uint8_t *
+connection_read_packet(connection_t * connection)
{
- parcAssertNotNull(conn, "Parameter conn must be non-null");
- if (!conn->ops)
- return CONNECTION_STATE_UNDEFINED;
- return ioOperations_GetState(conn->ops);
+ assert(connection);
+ assert(face_type_is_valid(connection->type));
+
+ return connection_vft[connection->type]->read_packet(connection);
}
+#endif
-void connection_SetState(Connection *conn, connection_state_t state)
+int
+connection_send_packet(const connection_t * connection, const uint8_t * packet,
+ size_t size)
{
- parcAssertNotNull(conn, "Parameter conn must be non-null");
- if (!conn->ops)
- return;
- ioOperations_SetState(conn->ops, state);
+ assert(connection);
+ assert(face_type_is_valid(connection->type));
+ assert(packet);
+
+ return connection_vft[connection->type]->send_packet(connection, packet, size);
}
-connection_state_t connection_GetAdminState(const Connection *conn)
+// ALL DEPRECATED CODE HERE TO BE UPDATED
+
+// XXX nexthops null ?? to be removed ???
+bool
+_connection_send(const connection_t * connection, msgbuf_t * msgbuf, bool queue)
{
- parcAssertNotNull(conn, "Parameter conn must be non-null");
- if (!conn->ops)
- return CONNECTION_STATE_UNDEFINED;
- return ioOperations_GetAdminState(conn->ops);
+ return connection_vft[connection->type]->send(connection, msgbuf, queue);
}
-void connection_SetAdminState(Connection *conn, connection_state_t admin_state)
+bool
+connection_send(const connection_t * connection, msgbuf_t * msgbuf, bool queue)
{
- parcAssertNotNull(conn, "Parameter conn must be non-null");
- if (!conn->ops)
- return;
- if ((admin_state != CONNECTION_STATE_UP) && (admin_state != CONNECTION_STATE_DOWN))
- return;
- ioOperations_SetAdminState(conn->ops, admin_state);
+ assert(connection);
+
+ /* NULL message means flush */
+ if (!msgbuf)
+ return _connection_send(connection, NULL, false);
+
+ if (!connection_is_up(connection))
+ return false;
+
+ if (msgbuf_get_type(msgbuf) == MESSAGE_TYPE_DATA) {
+ uint8_t conn_id = (uint8_t)connection_get_id(connection);
+ msgbuf_update_pathlabel(msgbuf, conn_id);
+ }
+
+ if (connection->wldr)
+ wldr_set_label(connection->wldr, msgbuf);
+ else
+ msgbuf_reset_wldr_label(msgbuf);
+
+ return _connection_send(connection, msgbuf, queue);
}
-#ifdef WITH_POLICY
-uint32_t connection_GetPriority(const Connection *conn)
+/*
+ * here the wldr header is alreay set: this message is a retransmission or a
+ * notification
+ *
+ * we need to recompute the path label since we always store a pointer to
+ * the same message if this message will be sent again to someone else, the
+ * new path label must be computed starting from the orignal label. Note
+ * that we heve the same problem in case of PIT aggregation. That case is
+ * handled inside the MessageProcessor. This is specific to WLDR
+ * retransmittions. This is done only for data packets
+ */
+bool
+connection_resend(const connection_t * connection, msgbuf_t * msgbuf, bool
+ notification)
{
- parcAssertNotNull(conn, "Parameter conn must be non-null");
- if (!conn->ops)
- return 0;
- return ioOperations_GetPriority(conn->ops);
+ assert(connection);
+ assert(msgbuf);
+
+ bool ret = false;
+
+ if (!connection_is_up(connection))
+ return ret;
+
+ if (msgbuf_get_type(msgbuf) == MESSAGE_TYPE_DATA) {
+ uint8_t conn_id = (uint8_t)connection_get_id(connection);
+ uint32_t old_path_label = msgbuf_get_pathlabel(msgbuf);
+ msgbuf_update_pathlabel(msgbuf, conn_id);
+ ret = _connection_send(connection, msgbuf, false); /* no queueing */
+ msgbuf_set_pathlabel(msgbuf, old_path_label);
+ } else {
+ ret = _connection_send(connection, msgbuf, false); /* no queueing */
+ }
+
+ return ret;
}
-void connection_SetPriority(Connection *conn, uint32_t priority)
-{
+#if 0
+bool connection_sendv(const connection_t * conn, struct iovec *msg,
+ size_t size) {
parcAssertNotNull(conn, "Parameter conn must be non-null");
- if (!conn->ops)
- return;
- ioOperations_SetPriority(conn->ops, priority);
+ parcAssertNotNull(msg, "Parameter message must be non-null");
+
+ return ioOperations_SendIOVBuffer(conn->ops, msg, size);
}
-#endif /* WITH_POLICY */
-const char * connection_GetInterfaceName(const Connection * conn)
-{
+void connection_probe(connection_t * conn, uint8_t * probe) {
+ ioOperations_SendProbe(conn->ops, probe);
+}
+
+void connection_hangle_probe(connection_t * conn, uint8_t *probe){
parcAssertNotNull(conn, "Parameter conn must be non-null");
- if (!conn->ops)
- return NULL;
- return ioOperations_GetInterfaceName(conn->ops);
+ parcAssertNotNull(probe, "Parameter pkt must be non-null");
+
+ if(messageHandler_IsInterest(probe)){
+ messageHandler_CreateProbeReply(probe, HF_INET6_TCP);
+ ioOperations_SendProbe(conn->ops, probe);
+ }
}
+#endif
-#ifdef WITH_POLICY
-void connection_AddTag(Connection *conn, policy_tag_t tag)
+/* WLDR */
+
+void
+connection_wldr_allow_autostart(connection_t * connection, bool value)
{
- policy_tags_add(&conn->tags, tag);
+ connection->wldr_autostart = value;
}
-void connection_RemoveTag(Connection *conn, policy_tag_t tag)
+bool
+connection_wldr_autostart_is_allowed(connection_t * connection)
{
- policy_tags_remove(&conn->tags, tag);
+ return connection->wldr_autostart;
}
-policy_tags_t connection_GetTags(const Connection *conn)
+void
+connection_wldr_enable(connection_t * connection, bool value)
{
- return conn->tags;
+ if (connection_is_local(connection))
+ return;
+ if (value) {
+ if (connection->wldr)
+ return;
+ connection->wldr = wldr_create();
+ } else {
+ if (!connection->wldr)
+ return;
+ wldr_free(connection->wldr);
+ }
}
-void connection_SetTags(Connection *conn, policy_tags_t tags)
+bool
+connection_has_wldr(const connection_t * connection)
{
- conn->tags = tags;
+ return !!connection->wldr;
}
-void connection_ClearTags(Connection *conn)
+void
+connection_wldr_detect_losses(const connection_t * connection, msgbuf_t * msgbuf)
{
- conn->tags = POLICY_TAGS_EMPTY;
+ if (!connection->wldr)
+ return;
+ wldr_detect_losses(connection->wldr, connection, msgbuf);
}
-int connection_HasTag(const Connection *conn, policy_tag_t tag)
+void
+connection_wldr_handle_notification(const connection_t * connection, msgbuf_t * msgbuf)
{
- return policy_tags_has(conn->tags, tag);
+ if (!connection->wldr)
+ return;
+ wldr_handle_notification(connection->wldr, connection, msgbuf);
}
-
-#endif /* WITH_POLICY */
diff --git a/hicn-light/src/hicn/core/connection.h b/hicn-light/src/hicn/core/connection.h
index b6513ea1a..45d341ab8 100644
--- a/hicn-light/src/hicn/core/connection.h
+++ b/hicn-light/src/hicn/core/connection.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2020 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -15,19 +15,22 @@
/**
* @file connection.h
- * @brief Wrapper for different types of connections
- *
- * A connection wraps a specific set of {@link IoOperations}. Those operations
- * allow for input and output. Connections get stored in the Connection Table.
- *
+ * @brief hICN connections
*/
-#ifndef connection_h
-#define connection_h
-#include <hicn/hicn-light/config.h>
-#include <hicn/core/connectionState.h>
-#include <hicn/io/ioOperations.h>
-#include <hicn/utils/address.h>
+#ifndef HICNLIGHT_CONNECTION_H
+#define HICNLIGHT_CONNECTION_H
+
+#include <hicn/core/address_pair.h>
+#include <hicn/core/listener.h>
+#include <hicn/core/msgbuf.h>
+#include <hicn/face.h>
+
+#ifdef WITH_POLICY
+#include <hicn/policy.h>
+#endif /* WITH_POLICY */
+
+#define CONNECTION_ID_UNDEFINED ~0
#ifdef WITH_MAPME
typedef enum {
@@ -42,157 +45,169 @@ typedef enum {
#endif /* WITH_MAPME */
+struct forwarder_s;
+struct wldr_s;
+
+typedef struct {
+ unsigned id;
+ char * name;
+ char * interface_name;
+ face_type_t type;
+ address_pair_t pair;
+ int fd;
+// bool up;
+ bool local;
+ face_state_t state;
+ face_state_t admin_state;
#ifdef WITH_POLICY
-#include <hicn/policy.h>
+ policy_tags_t tags;
+ uint32_t priority;
#endif /* WITH_POLICY */
+ void * data;
+
+ struct forwarder_s * forwarder; // recv only
+ bool closed;
+
+ /* WLDR */
+
+ bool wldr_autostart;
+ /*
+ * if true, wldr can be set automatically by default this value is set to
+ * true. if wldr is activated using a command (config file/hicnLightControl)
+ * this value is set to false so that a base station can not disable wldr at
+ * the client.
+ */
+ struct wldr_s * wldr;
+
+} connection_t;
+
+#if 1
+#define connection_get_id(C) ((C)->id)
+#define connection_id_is_valid(ID) (ID != CONNECTION_ID_UNDEFINED)
+#define connection_get_name(C) ((C)->name)
+#define connection_get_type(C) ((C)->type)
+#define connection_has_valid_id(C) (connection_id_is_valid(connection_get_id(C))
+#define connection_get_pair(C) (&(C)->pair)
+#define connection_get_local(C) (address_pair_local(connection_get_pair(C)))
+#define connection_get_remote(C) (address_pair_remote(connection_get_pair(C)))
+#define connection_get_local(C) (address_pair_local(connection_get_pair(C)))
+#define connection_get_remote(C) (address_pair_remote(connection_get_pair(C)))
+#define connection_is_up(C) ((C)->state == FACE_STATE_UP)
+#define connection_is_closed(C) ((C)->closed == true)
+#define connection_is_local(C) ((C)->local)
+#define connection_get_state(C) ((C)->state)
+#define connection_set_state(C, STATE) (C)->state = STATE
+#define connection_get_admin_state(C) ((C)->admin_state)
+#define connection_set_admin_state(C, STATE) (C)->admin_state = STATE
+#define connection_get_interface_name(C) ((C)->interface_name)
-struct connection;
-typedef struct connection Connection;
+#ifdef WITH_POLICY
+#define connection_get_priority(C) ((C)->priority)
+#define connection_set_priority(C, PRIORITY) (C)->priority = PRIORITY
+#define connection_get_tags(C) ((C)->tags)
+#define connection_set_tags(C, TAGS) (C)->tags = TAGS
+#define connection_has_tag(C, TAG) policy_tags_has(connection_get_tags(C), TAG)
+#define connection_add_tag(C, TAG) policy_tags_add(connection_get_tags(X), TAG)
+#define connection_remove_tag(C, TAG) \
+do { \
+ policy_tags_t _conn_var(tags); \
+ _conn_var(tags) = connection_get_tags(C); \
+ policy_tags_remove(_conn_var(tags), (TAG)); \
+ connection_set_tags((C), _conn_var(tags)); \
+} while(0)
+#define connection_clear_tags(C) connection_set_tags(C, POLICY_TAGS_EMPTY)
-/**
- * Creates a connection object.
- */
-Connection *connection_Create(IoOperations *ops);
+#endif /* WITH_POLICY */
-/**
- * @function connection_Release
- * @abstract Releases a reference count, destroying on last release
- * @discussion
- * Only frees the memory on the final reference count. The pointer will
- * always be NULL'd.
- */
-void connection_Release(Connection **connectionPtr);
-/**
- * @function connection_Acquire
- * @abstract A reference counted copy.
- * @discussion
- * A shallow copy, they share the same memory.
- */
-Connection *connection_Acquire(Connection *connection);
+#else
-/**
- * @function connection_Send
- * @abstract Sends the message on the connection
- * @return true if message sent, false if connection not up
- */
-bool connection_Send(const Connection *conn, Message *message);
+/* Accessors */
+static inline unsigned connection_get_id(const connection_t * connection);
-/**
- * @function connection_SendIOVBuffer
- * @abstract Sends an IOV buffer
- */
-bool connection_SendIOVBuffer(const Connection *conn, struct iovec *msg,
- size_t size);
+#define connection_id_is_valid(id) (id != CONNECTION_ID_UNDEFINED)
+#define connection_has_valid_id(C) (connection_id_is_valid(connection_get_id(C))
-/**
- * @function connection_SendBuffer
- * @abstract Sends a buffer
- */
-bool connection_SendBuffer(const Connection *conn, u8 * buffer, size_t length);
+static inline char * connection_get_name(const connection_t * connection);
-/**
- * Return the `IoOperations` instance associated with the specified `Connection`
- * instance.
- * @param [in] connection The allocated connection
- * @return a pointer to the IoOperations instance associated by th specified
- * connection.
- */
-IoOperations *connection_GetIoOperations(const Connection *conn);
+static inline face_type_t connection_get_type(const connection_t * connection);
-/**
- * Returns the unique identifier of the connection
- * Calls the underlying IoOperations to fetch the connection id
- * @param [in] connection The allocated connection
- * @return unsigned The unique connection id
- */
-unsigned connection_GetConnectionId(const Connection *conn);
+static inline address_pair_t * connection_get_pair(const connection_t * connection);
-/**
- * Returns the (remote, local) address pair that describes the connection
- * @param [in] connection The allocated connection
- * @return non-null The connection's remote and local address
- * @return null Should never return NULL
- */
-const AddressPair *connection_GetAddressPair(const Connection *conn);
+#define connection_get_local(C) (address_pair_local(connection_get_pair(C)))
+#define connection_get_remote(C) (address_pair_remote(connection_get_pair(C)))
-/**
- * Checks if the connection is in the "up" state
- * @param [in] connection The allocated connection
- * @return true The connection is in the "up" state
- * @return false The connection is not in the "up" state
- */
-bool connection_IsUp(const Connection *conn);
+static inline bool connection_is_up(const connection_t * connection);
-/**
- * Checks if the connection is to a Local/Loopback address
- *
- * A local connection is PF_LOCAL (PF_UNIX) and a loopback connection is
- * 127.0.0.0/8 or ::1 for IPv6.
- *
- * @param [in] connection The allocated connection
- *
- * @retval true The connection is local or loopback
- * @retval false The connection is not local or loopback
- */
-bool connection_IsLocal(const Connection *conn);
+static inline bool connection_is_local(const connection_t * connection);
-/**
- * Returns an opaque pointer representing the class of the Io Operations
- *
- * Returns an opaque pointer that an implementation can use to detect if
- * the connection is based on that class.
- *
- * @param [in] conn The Connection to analyze
- *
- * @return non-null An opaque pointer for each concrete implementation
- */
-const void *connection_Class(const Connection *conn);
+static inline face_state_t connection_get_state(const connection_t * connection);
+
+static inline void connection_set_state(connection_t * connection, face_state_t state);
+
+static inline face_state_t connection_get_admin_state(const connection_t * connection);
-bool connection_ReSend(const Connection *conn, Message *message,
- bool notification);
+static inline void connection_set_admin_state(connection_t * connection, face_state_t state);
-void connection_Probe(Connection *conn, uint8_t *probe);
+static inline const char * connection_get_interface_name(const connection_t * connection);
-void connection_HandleProbe(Connection *conn, uint8_t *message);
+#ifdef WITH_POLICY
-void connection_AllowWldrAutoStart(Connection *conn, bool allow);
+static inline uint32_t connection_get_priority(const connection_t * connection);
-void connection_EnableWldr(Connection *conn);
+static inline void connection_set_priority(connection_t * connection, uint32_t priority);
-void connection_DisableWldr(Connection *conn);
+static inline policy_tags_t connection_get_tags(const connection_t * connection);
-bool connection_HasWldr(const Connection *conn);
+static inline void connection_set_tags(connection_t * connection, policy_tags_t tags);
-bool connection_WldrAutoStartAllowed(const Connection *conn);
+#define connection_has_tag(C, TAG) policy_tags_has(connection_get_tags(C), TAG)
-void connection_DetectLosses(Connection *conn, Message *message);
+#define connection_add_tag(C, TAG) policy_tags_add(connection_get_tags(X), TAG)
-void connection_HandleWldrNotification(Connection *conn, Message *message);
+#define connection_remove_tag(C, TAG) \
+do { \
+ policy_tags_t _conn_var(tags); \
+ _conn_var(tags) = connection_get_tags(C); \
+ policy_tags_remove(_conn_var(tags), (TAG)); \
+ connection_set_tags((C), _conn_var(tags)); \
+} while(0)
-connection_state_t connection_GetState(const Connection *conn);
+#define connection_clear_tags(C) connection_set_tags(C, POLICY_TAGS_EMPTY)
-void connection_SetState(Connection *conn, connection_state_t state);
+#endif /* WITH_POLICY */
-connection_state_t connection_GetAdminState(const Connection *conn);
+#endif
-void connection_SetAdminState(Connection *conn, connection_state_t admin_state);
+connection_t * connection_create(face_type_t type, const char * name,
+ const address_pair_t * pair, struct forwarder_s * forwarder);
-#ifdef WITH_POLICY
-uint32_t connection_GetPriority(const Connection *conn);
+int connection_initialize(connection_t * connection, face_type_t type, const char * name,
+ const char * interface_name, int fd, const address_pair_t * pair,
+ bool local, unsigned connection_id, struct forwarder_s * forwarder);
-void connection_SetPriority(Connection *conn, uint32_t priority);
-#endif /* WITH_POLICY */
+int connection_finalize(connection_t * connection);
-const char * connection_GetInterfaceName(const Connection * conn);
+int connection_send_packet(const connection_t * connection,
+ const uint8_t * packet, size_t size);
-#ifdef WITH_POLICY
-void connection_AddTag(Connection *conn, policy_tag_t tag);
-void connection_RemoveTag(Connection *conn, policy_tag_t tag);
-policy_tags_t connection_GetTags(const Connection *conn);
-void connection_SetTags(Connection *conn, policy_tags_t tags);
-void connection_ClearTags(Connection *conn);
-int connection_HasTag(const Connection *conn, policy_tag_t tag);
-#endif /* WITH_POLICY */
+bool connection_send(const connection_t * connection, msgbuf_t * msgbuf,
+ bool queue);
+
+size_t connection_process_buffer(connection_t * connection, const uint8_t * buffer, size_t size);
+
+/* WLDR */
+
+void connection_wldr_allow_autostart(connection_t * connection, bool value);
+
+bool connection_wldr_autostart_is_allowed(connection_t * connection);
+
+void connection_wldr_enable(connection_t * connection, bool value);
+
+bool connection_has_wldr(const connection_t * connection);
+
+void connection_wldr_detect_losses(const connection_t * connection, msgbuf_t * msgbuf);
+
+void connection_wldr_handle_notification(const connection_t * connection, msgbuf_t * msgbuf);
-#endif // connection_h
+#endif /* HICNLIGHT_CONNECTION_H */
diff --git a/hicn-light/src/hicn/core/connectionList.c b/hicn-light/src/hicn/core/connectionList.c
deleted file mode 100644
index d51a9aad5..000000000
--- a/hicn-light/src/hicn/core/connectionList.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <hicn/hicn-light/config.h>
-#include <stdio.h>
-
-#include <parc/algol/parc_ArrayList.h>
-#include <parc/algol/parc_Memory.h>
-
-#include <parc/assert/parc_Assert.h>
-#include <hicn/core/connectionList.h>
-
-struct connection_list {
- PARCArrayList *listOfConnections;
-};
-
-static void connectionList_ArrayDestroyer(void **voidPtr) {
- Connection **entryPtr = (Connection **)voidPtr;
- connection_Release(entryPtr);
-}
-
-ConnectionList *connectionList_Create() {
- ConnectionList *list = parcMemory_AllocateAndClear(sizeof(ConnectionList));
- parcAssertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(ConnectionList));
- list->listOfConnections = parcArrayList_Create(connectionList_ArrayDestroyer);
- return list;
-}
-
-void connectionList_Destroy(ConnectionList **listPtr) {
- parcAssertNotNull(listPtr, "Parameter must be non-null double pointer");
- parcAssertNotNull(*listPtr, "Parameter must dereference to non-null pointer");
- ConnectionList *list = *listPtr;
- parcArrayList_Destroy(&list->listOfConnections);
- parcMemory_Deallocate((void **)&list);
- *listPtr = NULL;
-}
-
-void connectionList_Append(ConnectionList *list, Connection *entry) {
- parcAssertNotNull(list, "Parameter list must be non-null");
- parcAssertNotNull(entry, "Parameter entry must be non-null");
-
- parcArrayList_Add(list->listOfConnections, connection_Acquire(entry));
-}
-
-size_t connectionList_Length(const ConnectionList *list) {
- parcAssertNotNull(list, "Parameter list must be non-null");
- return parcArrayList_Size(list->listOfConnections);
-}
-
-Connection *connectionList_Get(ConnectionList *list, size_t index) {
- parcAssertNotNull(list, "Parameter list must be non-null");
- Connection *original =
- (Connection *)parcArrayList_Get(list->listOfConnections, index);
- return original;
-}
diff --git a/hicn-light/src/hicn/core/connectionList.h b/hicn-light/src/hicn/core/connectionList.h
deleted file mode 100644
index fbba9f6d8..000000000
--- a/hicn-light/src/hicn/core/connectionList.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @file connectionList.h
- * @brief A typesafe list of Connection objects
- *
- * <#Detailed Description#>
- *
- */
-
-#ifndef connectionList_h
-#define connectionList_h
-
-struct connection_list;
-typedef struct connection_list ConnectionList;
-
-#include <hicn/core/connection.h>
-
-/**
- * Creates a lis of Connection
- *
- * @return non-null An allocated list
- * @return null An error
- */
-ConnectionList *connectionList_Create(void);
-
-/**
- * Destroys the list and all objects inside it
- */
-void connectionList_Destroy(ConnectionList **listPtr);
-
-/**
- * @function connectionList_Append
- * @abstract Adds a connection entry to the list.
- * @discussion
- * Acquires a reference to the passed entry and stores it in the list.
- */
-void connectionList_Append(ConnectionList *list, Connection *entry);
-
-/**
- * Returns the number of items on the list
- * @param [in] list The allocated list to check
- * @return number The number of items on the list
- */
-size_t connectionList_Length(const ConnectionList *list);
-
-/**
- * @function connectionList_Get
- * @abstract Returns the connection entry.
- * @discussion
- * Caller must not destroy the returned value. If you will store the
- * entry in your own data structure, you should acquire your own reference.
- * Will assert if you go beyond the end of the list.
- *
- */
-Connection *connectionList_Get(ConnectionList *list, size_t index);
-#endif // connectionList_h
diff --git a/hicn-light/src/hicn/core/connectionManager.c b/hicn-light/src/hicn/core/connectionManager.c
deleted file mode 100644
index 709f0902a..000000000
--- a/hicn-light/src/hicn/core/connectionManager.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * The Connection Manager sets itself up as a listener to the Messenger so it
- * can take action based on system events.
- *
- * The Connection Manager queues and then processes in a later time slice the
- * messages.
- *
- */
-
-#include <hicn/hicn-light/config.h>
-#include <hicn/core/connectionManager.h>
-#include <hicn/core/forwarder.h>
-#include <hicn/messenger/messenger.h>
-#include <hicn/messenger/messengerRecipient.h>
-#include <hicn/messenger/missiveDeque.h>
-#include <stdio.h>
-
-#include <parc/algol/parc_Memory.h>
-
-#include <parc/assert/parc_Assert.h>
-
-struct connection_manager {
- Forwarder *forwarder;
- Logger *logger;
-
- MessengerRecipient *messengerRecipient;
-
- // we queue missives as they come in to process in our own
- // event timeslice
- MissiveDeque *missiveQueue;
-
- // for deferred queue processing
- PARCEventTimer *timerEvent;
-};
-
-/**
- * Receives missives from the messenger, queues them, and schedules our
- * execution
- *
- * We defer processing of missives to a later time slice
- */
-static void connectionManager_MessengerCallback(MessengerRecipient *recipient,
- Missive *missive);
-
-/**
- * Event callback
- *
- * This is our main run loop to process our queue of messages. It is scheduled
- * in {@link connectionManager_MessengerCallback} when the queue becomes
- * non-empty.
- *
- * When we are called here, we have exclusive use of the system, so we will not
- * create any message loops
- *
- * @param [in] fd unused, required for compliance with function prototype
- * @param [in] which_event unused, required for compliance with function
- * prototype
- * @param [in] connManagerVoidPtr A void* to ConnectionManager
- *
- */
-static void connectionManager_ProcessQueue(int fd, PARCEventType which_event,
- void *connManagerVoidPtr);
-
-static void connectionManager_ProcessClosedMissive(
- ConnectionManager *connManager, const Missive *missive);
-
-// ========================================================
-// Public API
-
-ConnectionManager *connectionManager_Create(Forwarder *forwarder) {
- ConnectionManager *connManager =
- parcMemory_AllocateAndClear(sizeof(ConnectionManager));
- parcAssertNotNull(connManager,
- "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(ConnectionManager));
- connManager->forwarder = forwarder;
- connManager->missiveQueue = missiveDeque_Create();
- connManager->logger = logger_Acquire(forwarder_GetLogger(forwarder));
-
- Messenger *messenger = forwarder_GetMessenger(connManager->forwarder);
-
- // creates the timer, but does not start it
- PARCEventScheduler *base =
- dispatcher_GetEventScheduler(forwarder_GetDispatcher(forwarder));
- connManager->timerEvent = parcEventTimer_Create(
- base, 0, connectionManager_ProcessQueue, connManager);
-
- connManager->messengerRecipient = messengerRecipient_Create(
- connManager, connectionManager_MessengerCallback);
- messenger_Register(messenger, connManager->messengerRecipient);
- return connManager;
-}
-
-void connectionManager_Destroy(ConnectionManager **managerPtr) {
- parcAssertNotNull(managerPtr, "Double pointer must be non-null");
- parcAssertNotNull(*managerPtr, "Double pointer must dereference to non-null");
-
- ConnectionManager *connManager = *managerPtr;
-
- Messenger *messenger = forwarder_GetMessenger(connManager->forwarder);
- parcEventTimer_Destroy(&(connManager->timerEvent));
- messenger_Unregister(messenger, connManager->messengerRecipient);
- messengerRecipient_Destroy(&connManager->messengerRecipient);
- missiveDeque_Release(&connManager->missiveQueue);
- logger_Release(&connManager->logger);
-
- parcMemory_Deallocate((void **)&connManager);
- *managerPtr = NULL;
-}
-
-// ========================================================
-// Internal Functions
-
-static void connectionManager_MessengerCallback(MessengerRecipient *recipient,
- Missive *missive) {
- ConnectionManager *connManager =
- messengerRecipient_GetRecipientContext(recipient);
-
- // we do not release our reference count, we store it until later
- // We are called with our own reference, so we do not need to acquire the
- // missive here.
- missiveDeque_Append(connManager->missiveQueue, missive);
-
- if (missiveDeque_Size(connManager->missiveQueue) == 1) {
- // When it becomes non-empty, schedule {@link
- // connectionManager_ProcessQueue}
- struct timeval immediateTimeout = {0, 0};
- parcEventTimer_Start(connManager->timerEvent, &immediateTimeout);
- }
-}
-
-static void connectionManager_ProcessQueue(int fd, PARCEventType which_event,
- void *connManagerVoidPtr) {
- ConnectionManager *connManager = (ConnectionManager *)connManagerVoidPtr;
-
- Missive *missive;
- while ((missive = missiveDeque_RemoveFirst(connManager->missiveQueue)) !=
- NULL) {
- switch (missive_GetType(missive)) {
- case MissiveType_ConnectionCreate:
- // hook to signal that a new connection was created
- break;
- case MissiveType_ConnectionUp:
- // hook to signal that a new connection is up
- break;
- case MissiveType_ConnectionDown:
- // hook to signal that a connection is down
- break;
- case MissiveType_ConnectionClosed:
- connectionManager_ProcessClosedMissive(connManager, missive);
- break;
- case MissiveType_ConnectionDestroyed:
- // hook to signal that a connection was destroyed
- break;
- default:
- parcTrapUnexpectedState("Missive %p of unknown type: %d",
- (void *)missive, missive_GetType(missive));
- }
- missive_Release(&missive);
- }
-}
-
-static void connectionManager_ProcessClosedMissive(
- ConnectionManager *connManager, const Missive *missive) {
- logger_Log(connManager->logger, LoggerFacility_Core, PARCLogLevel_Debug,
- __func__, "Processing CLOSED message for connid %u",
- missive_GetConnectionId(missive));
-
- ConnectionTable *table = forwarder_GetConnectionTable(connManager->forwarder);
- const Connection *conn =
- connectionTable_FindById(table, missive_GetConnectionId(missive));
-
- if (conn) {
- // this will destroy the connection if its the last reference count
- connectionTable_Remove(table, conn);
-
- // remove from FIB
- forwarder_RemoveConnectionIdFromRoutes(connManager->forwarder,
- missive_GetConnectionId(missive));
- }
-}
diff --git a/hicn-light/src/hicn/core/connectionManager.h b/hicn-light/src/hicn/core/connectionManager.h
deleted file mode 100644
index 34fee8717..000000000
--- a/hicn-light/src/hicn/core/connectionManager.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @file connectionManager.h
- * @brief The connection manager handles connection events, such as going down
- *
- * The connection manager listens to the event notification system. Based on
- * those events, the connection manager will take specific actions. This is
- * expected to be a singleton instantiated by the forwarder.
- *
- */
-
-#ifndef connectionManager_h
-#define connectionManager_h
-
-#include <hicn/core/forwarder.h>
-
-struct connection_manager;
-typedef struct connection_manager ConnectionManager;
-
-ConnectionManager *connectionManager_Create(Forwarder *forwarder);
-
-void connectionManager_Destroy(ConnectionManager **managerPtr);
-#endif // connectionManager_h
diff --git a/hicn-light/src/hicn/core/connectionTable.c b/hicn-light/src/hicn/core/connectionTable.c
deleted file mode 100644
index f8589c12b..000000000
--- a/hicn-light/src/hicn/core/connectionTable.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @header ConnectionTable
- * @abstract Records all the current connections and references to them
- * @discussion
- *
- */
-
-#ifndef _WIN32
-#include <unistd.h>
-#endif
-#include <hicn/hicn-light/config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <parc/assert/parc_Assert.h>
-
-#include <parc/algol/parc_ArrayList.h>
-#include <parc/algol/parc_Hash.h>
-#include <parc/algol/parc_HashCodeTable.h>
-#include <parc/algol/parc_Memory.h>
-#include <parc/algol/parc_TreeRedBlack.h>
-#include <hicn/core/connectionTable.h>
-#include <hicn/io/addressPair.h>
-
-struct connection_table {
- // The main storage table that has a Destroy method.
- // The key is an unsigned int pointer. We use an unsigned int pointer
- // because we want to be able to lookup by the id alone, and not have to
- // have the IoOperations everywhere.
- PARCHashCodeTable *storageTableById;
-
- // The key is a AddressPair
- // It does not have a destroy method for the data or key,
- // as they are derived from the storage table.
- PARCHashCodeTable *indexByAddressPair;
-
- // An iterable stucture organized by connection id. The keys and
- // values are the same pointers as in storageTableById, so there
- // are no destructors in the tree.
- // The only reason to keep this tree is so we have an iterable list
- // of connections, which the hash table does not give us.
- PARCTreeRedBlack *listById;
-};
-
-static bool connectionTable_ConnectionIdEquals(const void *keyA,
- const void *keyB) {
- unsigned idA = *((unsigned *)keyA);
- unsigned idB = *((unsigned *)keyB);
- return (idA == idB);
-}
-
-static int connectionTable_ConnectionIdCompare(const void *keyA,
- const void *keyB) {
- unsigned idA = *((unsigned *)keyA);
- unsigned idB = *((unsigned *)keyB);
- if (idA < idB) {
- return -1;
- }
- if (idA > idB) {
- return +1;
- }
- return 0;
-}
-
-static bool connectionTable_AddressPairEquals(const void *keyA,
- const void *keyB) {
- const AddressPair *pairA = (const AddressPair *)keyA;
- const AddressPair *pairB = (const AddressPair *)keyB;
-
- return addressPair_Equals(pairA, pairB);
-}
-
-static HashCodeType connectionTable_ConnectionIdHashCode(const void *keyA) {
- unsigned idA = *((unsigned *)keyA);
- return parcHash32_Int32(idA);
-}
-
-static HashCodeType connectionTable_AddressPairHashCode(const void *keyA) {
- const AddressPair *pairA = (const AddressPair *)keyA;
- return addressPair_HashCode(pairA);
-}
-
-static void connectionTable_ConnectionIdDestroyer(void **dataPtr) {
- unsigned *idA = (unsigned *)*dataPtr;
- parcMemory_Deallocate((void **)&idA);
- *dataPtr = NULL;
-}
-
-static void connectionTable_ConnectionDestroyer(void **dataPtr) {
- connection_Release((Connection **)dataPtr);
-}
-
-ConnectionTable *connectionTable_Create() {
- size_t initialSize = 16384;
-
- ConnectionTable *conntable =
- parcMemory_AllocateAndClear(sizeof(ConnectionTable));
- parcAssertNotNull(conntable, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(ConnectionTable));
-
- conntable->storageTableById = parcHashCodeTable_Create_Size(
- connectionTable_ConnectionIdEquals, connectionTable_ConnectionIdHashCode,
- connectionTable_ConnectionIdDestroyer,
- connectionTable_ConnectionDestroyer, initialSize);
-
- // no key or data destroyer, this is an index into storageByid.
- conntable->indexByAddressPair = parcHashCodeTable_Create_Size(
- connectionTable_AddressPairEquals, connectionTable_AddressPairHashCode,
- NULL, NULL, initialSize);
-
- conntable->listById =
- parcTreeRedBlack_Create(connectionTable_ConnectionIdCompare,
- NULL, // key free
- NULL, // key copy
- NULL, // value equals
- NULL, // value free
- NULL); // value copy
-
- return conntable;
-}
-
-void connectionTable_Destroy(ConnectionTable **conntablePtr) {
- parcAssertNotNull(conntablePtr, "Parameter must be non-null double pointer");
- parcAssertNotNull(*conntablePtr,
- "Parameter must dereference to non-null pointer");
-
- ConnectionTable *conntable = *conntablePtr;
-
- parcTreeRedBlack_Destroy(&conntable->listById);
- parcHashCodeTable_Destroy(&conntable->indexByAddressPair);
- parcHashCodeTable_Destroy(&conntable->storageTableById);
- parcMemory_Deallocate((void **)&conntable);
- *conntablePtr = NULL;
-}
-
-/**
- * @function connectionTable_Add
- * @abstract Add a connection, takes ownership of memory
- */
-void connectionTable_Add(ConnectionTable *table, Connection *connection) {
- parcAssertNotNull(table, "Parameter table must be non-null");
- parcAssertNotNull(connection, "Parameter connection must be non-null");
-
- unsigned *connectionIdKey = parcMemory_Allocate(sizeof(unsigned));
- parcAssertNotNull(connectionIdKey, "parcMemory_Allocate(%zu) returned NULL",
- sizeof(unsigned));
- *connectionIdKey = connection_GetConnectionId(connection);
-
- if (parcHashCodeTable_Add(table->storageTableById, connectionIdKey,
- connection)) {
- parcHashCodeTable_Add(table->indexByAddressPair,
- (void *)connection_GetAddressPair(connection),
- connection);
- parcTreeRedBlack_Insert(table->listById, connectionIdKey, connection);
- } else {
- parcTrapUnexpectedState(
- "Could not add connection id %u -- is it a duplicate?",
- *connectionIdKey);
- }
-}
-
-/**
- * @function connectionTable_Remove
- * @abstract Removes the connection, calling Destroy on our copy
- */
-void connectionTable_Remove(ConnectionTable *table,
- const Connection *connection) {
- parcAssertNotNull(table, "Parameter table must be non-null");
- parcAssertNotNull(connection, "Parameter connection must be non-null");
-
- unsigned connid = connection_GetConnectionId(connection);
-
- parcTreeRedBlack_Remove(table->listById, &connid);
- parcHashCodeTable_Del(table->indexByAddressPair,
- connection_GetAddressPair(connection));
- parcHashCodeTable_Del(table->storageTableById, &connid);
-}
-
-void connectionTable_RemoveById(ConnectionTable *table, unsigned id) {
- parcAssertNotNull(table, "Parameter table must be non-null");
- const Connection *connection = connectionTable_FindById(table, id);
- if (connection) {
- connectionTable_Remove(table, connection);
- }
-}
-
-const Connection *connectionTable_FindByAddressPair(ConnectionTable *table,
- const AddressPair *pair) {
- parcAssertNotNull(table, "Parameter table must be non-null");
- return (Connection *)parcHashCodeTable_Get(table->indexByAddressPair, pair);
-}
-
-const Connection *connectionTable_FindById(const ConnectionTable *table,
- unsigned id) {
- parcAssertNotNull(table, "Parameter table must be non-null");
- return (Connection *)parcHashCodeTable_Get(table->storageTableById, &id);
-}
-
-ConnectionList *connectionTable_GetEntries(const ConnectionTable *table) {
- parcAssertNotNull(table, "Parameter table must be non-null");
- ConnectionList *list = connectionList_Create();
-
- PARCArrayList *values = parcTreeRedBlack_Values(table->listById);
- for (size_t i = 0; i < parcArrayList_Size(values); i++) {
- Connection *original = parcArrayList_Get(values, i);
- connectionList_Append(list, original);
- }
- parcArrayList_Destroy(&values);
- return list;
-}
diff --git a/hicn-light/src/hicn/core/connectionTable.h b/hicn-light/src/hicn/core/connectionTable.h
deleted file mode 100644
index 548ef8e6e..000000000
--- a/hicn-light/src/hicn/core/connectionTable.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- */
-
-#ifndef connectionTable_h
-#define connectionTable_h
-
-#include <hicn/core/connection.h>
-#include <hicn/core/connectionList.h>
-#include <hicn/io/addressPair.h>
-#include <hicn/io/ioOperations.h>
-
-struct connection_table;
-typedef struct connection_table ConnectionTable;
-
-/**
- * Creates an empty connection table
- */
-ConnectionTable *connectionTable_Create(void);
-
-/**
- * Destroys the connection table
- * This will release the reference to all connections stored in the connection
- * table.
- * @param [in,out] conntablePtr Pointer to the allocated connection table, will
- * be NULL'd
- */
-void connectionTable_Destroy(ConnectionTable **conntablePtr);
-
-/**
- * @function connectionTable_Add
- * @abstract Add a connection, takes ownership of memory
- */
-void connectionTable_Add(ConnectionTable *table, Connection *connection);
-
-/**
- * @function connectionTable_Remove
- * @abstract Removes the connection, calling Destroy on our copy
- */
-void connectionTable_Remove(ConnectionTable *table,
- const Connection *connection);
-
-/**
- * Removes a connection from the connection table
- *
- * Looks up a connection by its connection ID and removes it from the connection
- * table. Removing the connection will call connection_Release() on the
- * connection object.
- *
- * @param [in] table The allocated connection table
- * @param [in] id The connection ID
- */
-void connectionTable_RemoveById(ConnectionTable *table, unsigned id);
-
-/**
- * Lookup a connection by the (local, remote) addres pair
- *
- * @param [in] table The allocated connection table
- * @param [in] pair The address pair to match, based on the inner values of the
- * local and remote addresses
- *
- * @retval non-null The matched conneciton
- * @retval null No match found or error
- */
-const Connection *connectionTable_FindByAddressPair(ConnectionTable *table,
- const AddressPair *pair);
-
-/**
- * @function connectionTable_FindById
- * @abstract Find a connection by its numeric id.
- * @return NULL if not found
- */
-const Connection *connectionTable_FindById(const ConnectionTable *table, unsigned id);
-
-/**
- * @function connectionTable_GetEntries
- * @abstract Returns a list of connections. They are reference counted copies
- * from the table.
- * @discussion
- * An allocated list of connections in the table. Each list entry is a
- * reference counted copy of the connection in the table, thus they are "live"
- * objects.
- */
-ConnectionList *connectionTable_GetEntries(const ConnectionTable *table);
-#endif // connectionTable_h
diff --git a/hicn-light/src/hicn/core/connection_table.c b/hicn-light/src/hicn/core/connection_table.c
new file mode 100644
index 000000000..fd8013b73
--- /dev/null
+++ b/hicn-light/src/hicn/core/connection_table.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file connection_table.c
+ * \brief Implementation of hICN connection table
+ */
+
+#include <hicn/core/connection.h>
+#include <hicn/core/connection_table.h>
+
+/* This is only used for first allocation, as the table is resizeable */
+#define DEFAULT_CONNECTION_TABLE_SIZE 64
+
+connection_table_t *
+connection_table_create(size_t elt_size, size_t max_elts)
+{
+ connection_table_t * table = malloc(sizeof(connection_table_t));
+ if (!table)
+ return NULL;
+
+ table->id_by_pair = kh_init_ct_pair();
+ table->id_by_name = kh_init_ct_name();
+ pool_init(table->connections, DEFAULT_CONNECTION_TABLE_SIZE);
+
+ return table;
+}
+
+void
+connection_table_free(connection_table_t * table)
+{
+ kh_destroy_ct_pair(table->id_by_pair);
+ kh_destroy_ct_name(table->id_by_name);
+ pool_free(table->connections);
+ free(table);
+}
+
+connection_t *
+connection_table_get_by_pair(const connection_table_t * table,
+ const address_pair_t * pair)
+{
+ khiter_t k = kh_get_ct_pair(table->id_by_pair, pair);
+ if (k == kh_end(table->id_by_pair))
+ return NULL;
+ return table->connections + kh_val(table->id_by_pair, k);
+}
+
+unsigned
+connection_table_get_id_by_name(const connection_table_t * table,
+ const char * name)
+{
+ khiter_t k = kh_get_ct_name(table->id_by_name, name);
+ if (k == kh_end(table->id_by_name))
+ return CONNECTION_ID_UNDEFINED;
+ return kh_val(table->id_by_name, k);
+}
+
+connection_t *
+connection_table_get_by_name(const connection_table_t * table,
+ const char * name)
+{
+ unsigned conn_id = connection_table_get_id_by_name(table, name);
+ if (!connection_id_is_valid(conn_id))
+ return NULL;
+ return table->connections + conn_id;
+}
+
+void
+connection_table_remove_by_id(connection_table_t * table, off_t id)
+{
+ /*
+ * Get the connection addresspair & name so as to be able to remove them
+ * from the hash table index
+ */
+ connection_t * connection = connection_table_at(table, id);
+ connection_table_deallocate(table, connection);
+}
diff --git a/hicn-light/src/hicn/core/connection_table.h b/hicn-light/src/hicn/core/connection_table.h
new file mode 100644
index 000000000..c0406ced8
--- /dev/null
+++ b/hicn-light/src/hicn/core/connection_table.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file connection_table.h
+ * \brief hICN connection_table
+ */
+
+/* Iterate on connection table : to remove all connections associated to a
+ * listener based on listen address */
+
+#ifndef HICN_CONNECTION_TABLE_H
+#define HICN_CONNECTION_TABLE_H
+
+//#include <hicn/base/common.h>
+#include <hicn/core/address_pair.h>
+#include <hicn/core/connection.h>
+#include <hicn/base/hash.h>
+#include <hicn/base/khash.h>
+#include <hicn/base/pool.h>
+
+#include <hicn/common.h>
+
+#define address_pair_hash(pair) (hash32(pair, sizeof(address_pair_t)))
+#define address_pair_hash_eq(a, b) (address_pair_hash(b) - address_pair_hash(a))
+
+KHASH_INIT(ct_pair, const address_pair_t *, unsigned, 0, address_pair_hash, address_pair_hash_eq);
+
+KHASH_INIT(ct_name, const char *, unsigned, 0, str_hash, str_hash_eq);
+
+/*
+ * The connection table is composed of :
+ * - a connection pool allowing connection access by id in constant time
+ * - a hash table allowing to perform lookups based on address pairs, to get a connection id.
+ *
+ * For fast lookup by ID, the connection table will point to the beginning of
+ * the pool / vector, holding all connections.
+ * The header will be prepended
+ */
+
+typedef struct {
+ kh_ct_pair_t * id_by_pair;
+ kh_ct_name_t * id_by_name;
+
+ connection_t * connections; // pool
+} connection_table_t;
+
+#define connection_table_allocate(table, conn, pair, name) \
+do { \
+ pool_get(table->connections, conn); \
+ off_t connection_id = conn - table->connections; \
+ int res; \
+ khiter_t k = kh_put_ct_pair(table->id_by_pair, pair, &res); \
+ kh_value(table->id_by_pair, k) = connection_id; \
+ if (name) { \
+ k = kh_put_ct_name(table->id_by_name, name, &res); \
+ kh_value(table->id_by_name, k) = connection_id; \
+ } \
+} while(0)
+
+#define connection_table_deallocate(table, conn) \
+do { \
+ const address_pair_t * pair = connection_get_pair(connection); \
+ khiter_t k = kh_get_ct_pair(table->id_by_pair, pair); \
+ if (k != kh_end(table->id_by_pair)) \
+ kh_del_ct_pair(table->id_by_pair, k); \
+ \
+ const char * name = connection_get_name(connection); \
+ if (name) { \
+ k = kh_get_ct_name(table->id_by_name, name); \
+ if (k != kh_end(table->id_by_name)) \
+ kh_del_ct_name(table->id_by_name, k); \
+ } \
+ \
+ pool_put(table->connections, conn); \
+} while(0) \
+
+#define connection_table_len(table) (pool_elts(table->connections))
+
+#define connection_table_validate_id(table, id) \
+ pool_validate_id((table)->connections, (id))
+
+#define connection_table_at(table, id) ((table)->connections + id)
+
+#define connection_table_get_connection_id(table, conn) \
+ (conn - table->connections)
+
+#define connection_table_foreach(table, conn, BODY) \
+ pool_foreach(table->connections, (conn), BODY)
+
+#define connection_table_enumerate(table, i, conn, BODY) \
+ pool_foreach(table->connections, (i), (conn), BODY)
+
+connection_table_t * connection_table_create();
+void connection_table_free(connection_table_t * table);
+
+#define connection_table_get_by_id(table, id) \
+ connection_table_validate_id((table), (id)) \
+ ? connection_table_at((table), (id)) : NULL;
+
+connection_t * connection_table_get_by_pair(const connection_table_t * table,
+ const address_pair_t * pair);
+
+unsigned connection_table_get_id_by_name(const connection_table_t * table,
+ const char * name);
+
+connection_t * connection_table_get_by_name(const connection_table_t * table,
+ const char * name);
+
+void connection_table_remove_by_id(connection_table_t * table, off_t id);
+
+//unsigned connection_table_add(connection_table_t * table, Connection * connection);
+
+#endif /* HICN_CONNECTION_TABLE_H */
diff --git a/hicn-light/src/hicn/core/connectionState.h b/hicn-light/src/hicn/core/connection_vft.c
index 9daa15c9c..9efdd0107 100644
--- a/hicn-light/src/hicn/core/connectionState.h
+++ b/hicn-light/src/hicn/core/connection_vft.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2020 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -14,24 +14,18 @@
*/
/**
- * @file connection_state.h
- * @brief Represents the state of a connection
- *
+ * @file connection_vft.c
+ * @brief Implementation of connection VFT
*/
-#ifndef connection_state_h
-#define connection_state_h
-
-#define foreach_connection_state \
- _(UNDEFINED) \
- _(DOWN) \
- _(UP) \
- _(N)
+#include "connection_vft.h"
-typedef enum {
-#define _(x) CONNECTION_STATE_ ## x,
-foreach_connection_state
-#undef _
-} connection_state_t;
+extern connection_ops_t connection_hicn;
+extern connection_ops_t connection_tcp;
+extern connection_ops_t connection_udp;
-#endif /* connection_state_h */
+const connection_ops_t * connection_vft[] = {
+ [FACE_TYPE_HICN] = &connection_hicn,
+ [FACE_TYPE_TCP] = &connection_tcp,
+ [FACE_TYPE_UDP] = &connection_udp,
+};
diff --git a/hicn-light/src/hicn/core/connection_vft.h b/hicn-light/src/hicn/core/connection_vft.h
new file mode 100644
index 000000000..589f39536
--- /dev/null
+++ b/hicn-light/src/hicn/core/connection_vft.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file connection_vft.h
+ * @brief Connection VFT
+ */
+
+#ifndef HICNLIGHT_CONNECTION_VFT_H
+#define HICNLIGHT_CONNECTION_VFT_H
+
+#include "connection.h"
+
+typedef struct {
+ int (*initialize)(connection_t * connection);
+ void (*finalize)(connection_t * connection);
+ int (*get_socket)(const listener_t * listener, const address_t * local,
+ const address_t * remote, const char * interface_name);
+ int (*send)(const connection_t * connection, msgbuf_t * msgbuf, bool queue);
+ int (*send_packet)(const connection_t * connection,
+ const uint8_t * packet, size_t size);
+ void (*read_callback)(connection_t * connection, int fd, void * data);
+ size_t data_size;
+} connection_ops_t;
+
+#define DECLARE_CONNECTION(NAME) \
+const connection_ops_t connection_ ## NAME = { \
+ .initialize = connection_ ## NAME ## _initialize, \
+ .finalize = connection_ ## NAME ## _finalize, \
+ .get_socket = listener_ ## NAME ## _get_socket, \
+ .send = connection_ ## NAME ## _send, \
+ .send_packet = connection_ ## NAME ## _send_packet, \
+ .read_callback = connection_ ## NAME ## _read_callback, \
+ .data_size = sizeof(connection_ ## NAME ## _data_t), \
+};
+
+extern const connection_ops_t * connection_vft[];
+
+#endif /* HICNLIGHT_CONNECTION_VFT_H */
diff --git a/hicn-light/src/hicn/core/content_store.c b/hicn-light/src/hicn/core/content_store.c
new file mode 100644
index 000000000..7ed2bd838
--- /dev/null
+++ b/hicn-light/src/hicn/core/content_store.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file content_store.c
+ * \brief Implementation of hICN content_store
+ */
+
+#include <inttypes.h>
+#include <hicn/base/pool.h>
+#include <hicn/util/log.h>
+
+//#include <hicn/content_store/lru.h>
+
+#include "content_store.h"
+
+extern const content_store_ops_t content_store_lru;
+
+const content_store_ops_t * const content_store_vft[] = {
+ [CONTENT_STORE_TYPE_LRU] = &content_store_lru,
+};
+
+// XXX TODO replace by a single packet cache
+// XXX TODO per cs type entry data too !
+// XXX TODO getting rid of logger and the need to acquire
+// XXX TODO separate cs from vft, same with strategy
+
+#define content_store_entry_from_msgbuf(entry, msgbuf) \
+do { \
+ (entry)->hasExpiryTimeTicks = msgbuf_HasContentExpiryTime(msgbuf); \
+ if ((entry)->hasExpiryTimeTicks) \
+ (entry)->expiryTimeTicks = msgbuf_GetContentExpiryTimeTicks(msgbuf); \
+} while(0)
+
+
+content_store_t *
+content_store_create(content_store_type_t type, size_t max_elts)
+{
+ content_store_t * cs = malloc(sizeof(content_store_t));
+ if (!cs)
+ goto ERR_MALLOC;
+ if (!CONTENT_STORE_TYPE_VALID(type))
+ goto ERR_TYPE;
+ cs->type = type;
+
+ // XXX TODO an entry = data + metadata specific to each policy
+ pool_init(cs->entries, max_elts);
+
+ // data
+ // options
+ // stats
+
+
+ // index by name
+ cs->index_by_name = kh_init(cs_name);
+
+ cs->index_by_expiry_time = NULL;
+ if (!cs->index_by_expiry_time) {
+ ERROR("Could not create index (expiry time)");
+ goto ERR_INDEX_EXPIRY;
+ }
+
+
+ // XXX indices specific to each policy => vft
+ // index by expiration time
+ // lru ?
+
+ content_store_vft[type]->initialize(cs);
+
+ERR_INDEX_EXPIRY:
+ // XXX TODO
+ERR_TYPE:
+ERR_MALLOC:
+ return NULL;
+}
+
+void
+content_store_free(content_store_t * cs)
+{
+ content_store_vft[cs->type]->finalize(cs);
+
+ if (cs->index_by_expiry_time)
+ ; //listTimeOrdered_Release(&(store->indexByExpirationTime));
+}
+
+void content_store_clear(content_store_t * cs)
+{
+ // XXX TODO
+}
+
+msgbuf_t *
+content_store_match(content_store_t * cs, msgbuf_t * msgbuf, uint64_t now)
+{
+ assert(cs);
+ assert(msgbuf);
+ assert(msgbuf_get_type(msgbuf) == MESSAGE_TYPE_INTEREST);
+
+ /* Lookup entry by name */
+ khiter_t k = kh_get_cs_name(cs->index_by_name, msgbuf_get_name(msgbuf));
+ if (k == kh_end(cs->index_by_name))
+ return NULL;
+ content_store_entry_t * entry = cs->entries + kh_val(cs->index_by_name, k);
+ assert(entry);
+
+ /* Remove any expired entry */
+ if (content_store_entry_has_expiry_time(entry) &&
+ content_store_entry_expiry_time(entry) < now) {
+ // the entry is expired, we can remove it
+ content_store_remove_entry(cs, entry);
+ goto NOT_FOUND;
+ }
+
+ cs->stats.lru.countHits++;
+
+#if 0 // XXX
+ contentStoreEntry_MoveToHead(entry);
+#endif
+
+ DEBUG("CS %p LRU match %p (hits %" PRIu64 ", misses %" PRIu64 ")",
+ cs, msgbuf, cs->stats.lru.countHits, cs->stats.lru.countMisses);
+ return content_store_entry_message(entry);
+
+NOT_FOUND:
+ cs->stats.lru.countMisses++;
+
+ DEBUG("ContentStoreLRU %p missed msgbuf %p (hits %" PRIu64 ", misses %" PRIu64 ")",
+ cs, msgbuf, cs->stats.lru.countHits, cs->stats.lru.countMisses);
+ return NULL;
+}
+
+void
+content_store_add(content_store_t * cs, msgbuf_t * msgbuf, uint64_t now)
+{
+ assert(cs);
+ assert(msgbuf);
+ assert(msgbuf_get_type(msgbuf) == MESSAGE_TYPE_DATA);
+
+ content_store_entry_t * entry = NULL;
+
+ /* borrow from content_store_lru_add_entry */
+
+ content_store_vft[cs->type]->add_entry(cs, entry);
+}
+
+void
+content_store_remove_entry(content_store_t * cs, content_store_entry_t * entry)
+{
+ assert(cs);
+ assert(entry);
+
+ if (content_store_entry_has_expiry_time(entry))
+ ; // XXX TODO listTimeOrdered_Remove(store->indexByExpirationTime, entryToPurge);
+
+ msgbuf_t * msgbuf = content_store_entry_message(entry);
+ khiter_t k = kh_get_cs_name(cs->index_by_name, msgbuf_get_name(msgbuf));
+ if (k != kh_end(cs->index_by_name))
+ kh_del(cs_name, cs->index_by_name, k);
+
+ // This will take care of LRU entry for instance
+ content_store_vft[cs->type]->remove_entry(cs, entry);
+
+ //store->objectCount--;
+ pool_put(cs->entries, entry);
+
+}
+//
+// XXX TODO what is the difference between purge and remove ?
+bool
+content_store_remove(content_store_t * cs, msgbuf_t * msgbuf)
+{
+ assert(cs);
+ assert(msgbuf);
+ assert(msgbuf_get_type(msgbuf) == MESSAGE_TYPE_DATA);
+
+ /* Lookup entry by name */
+ khiter_t k = kh_get_cs_name(cs->index_by_name, msgbuf_get_name(msgbuf));
+ if (k == kh_end(cs->index_by_name))
+ return false;
+
+ content_store_entry_t * entry = cs->entries + kh_val(cs->index_by_name, k);
+ assert(entry);
+
+ content_store_remove_entry(cs, entry);
+ return true;
+}
+
diff --git a/hicn-light/src/hicn/core/content_store.h b/hicn-light/src/hicn/core/content_store.h
new file mode 100644
index 000000000..1a339f494
--- /dev/null
+++ b/hicn-light/src/hicn/core/content_store.h
@@ -0,0 +1,125 @@
+#ifndef HICNLIGHT_CONTENT_STORE_H
+#define HICNLIGHT_CONTENT_STORE_H
+
+#include <hicn/base/khash.h>
+#include <hicn/base/pool.h>
+#include <hicn/core/msgbuf.h>
+#include <hicn/core/name.h>
+#include <hicn/content_store/lru.h>
+
+typedef struct {
+ msgbuf_t * message;
+ //ListLruEntry *lruEntry;
+ bool hasExpiryTimeTicks;
+ uint64_t expiryTimeTicks; // single value for both ? 0 allowed ?
+} content_store_entry_t;
+
+#define content_store_entry_message(entry) ((entry)->message)
+#define content_store_entry_has_expiry_time(entry) ((entry)->hasExpiryTimeTicks)
+#define content_store_entry_expiry_time(entry) ((entry)->expiryTimeTicks)
+
+typedef enum {
+ CONTENT_STORE_TYPE_UNDEFINED,
+ CONTENT_STORE_TYPE_LRU,
+ CONTENT_STORE_TYPE_N,
+} content_store_type_t;
+
+#define CONTENT_STORE_TYPE_VALID(type) \
+ (type != CONTENT_STORE_TYPE_UNDEFINED) && \
+ (type != CONTENT_STORE_TYPE_N)
+
+typedef struct {
+ /* The maximum allowed expiry time (will never be exceeded). */
+ uint64_t max_expiry_time; // XXX part of lru ?
+} content_store_options_t;
+
+typedef union {
+ content_store_lru_stats_t lru;
+} content_store_stats_t;
+
+// XXX TODO
+#define name_hash(name) (name_HashCode(name))
+#define name_hash_eq(a, b) (name_hash(b) - name_hash(a))
+
+KHASH_INIT(cs_name, const Name *, unsigned, 0, name_hash, name_hash_eq);
+
+typedef struct {
+ content_store_type_t type;
+
+ // XXX TODO api to dynamically set max size
+ content_store_entry_t * entries; // pool
+
+ kh_cs_name_t * index_by_name;
+
+ void * index_by_expiry_time;
+ //ListTimeOrdered *indexByExpirationTime;
+
+
+ void * data; // per cs type data
+ void * options;
+ content_store_stats_t stats;
+} content_store_t;
+
+content_store_t * content_store_create(content_store_type_t type, size_t max_elts);
+
+void content_store_free(content_store_t * cs);
+
+void content_store_clear(content_store_t * cs);
+
+msgbuf_t * content_store_match(content_store_t * cs, msgbuf_t * msgbuf, uint64_t now);
+
+void content_store_add(content_store_t * cs, msgbuf_t * msgbuf, uint64_t now);
+
+void content_store_remove_entry(content_store_t * cs, content_store_entry_t * entry);
+
+bool content_store_remove(content_store_t * cs, msgbuf_t * msgbuf);
+
+#define content_store_size(content_store) (pool_elts(cs->entries))
+
+void content_store_purge_entry(content_store_t * cs, content_store_entry_t * entry);
+
+typedef struct {
+
+ const char * name;
+
+ void (*initialize)(content_store_t * cs);
+
+ void (*finalize)(content_store_t * cs);
+
+ /**
+ * Place a Message representing a ContentObject into the ContentStore. If
+ * necessary to make room, remove expired content or content that has exceeded
+ * the Recommended Cache Time.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ * @param content - a pointer to a `Message` to place in the store.
+ * @param currentTimeTicks - the current time, in hicn-light ticks, since the
+ * UTC epoch.
+ */
+ // XXX Do we always get now before adding ?
+ bool (*add_entry)(content_store_t * cs, content_store_entry_t * entry);
+
+ /**
+ * The function to call to remove content from the ContentStore.
+ * It will Release any references that were created when the content was
+ * placed into the ContentStore.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ * @param content - a pointer to a `Message` to remove from the store.
+ */
+ void (*remove_entry)(content_store_t * cs, content_store_entry_t * entry);
+
+} content_store_ops_t;
+
+extern const content_store_ops_t * const content_store_vft[];
+
+#define DECLARE_CONTENT_STORE(NAME) \
+ const content_store_ops_t content_store_ ## NAME = { \
+ .name = #NAME, \
+ .initialize = content_store_ ## NAME ## _initialize, \
+ .finalize = content_store_ ## NAME ## _finalize, \
+ .add_entry = content_store_ ## NAME ## _add_entry, \
+ .remove_entry = content_store_ ## NAME ## _remove_entry, \
+ }
+
+#endif /* HICNLIGHT_CONTENT_STORE_H */
diff --git a/hicn-light/src/hicn/core/dispatcher.c b/hicn-light/src/hicn/core/dispatcher.c
deleted file mode 100644
index 59951e950..000000000
--- a/hicn-light/src/hicn/core/dispatcher.c
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @header dispatcher.c
- * @abstract Event dispatcher for hicn-light. Uses parcEvent
- * @discussion
- * Wraps the functions we use in parcEvent, along with StreamBuffer and
- * Message. The dispatcher is the event loop, so it manages things like signals,
- * timers, and network events.
- */
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <hicn/hicn-light/config.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include <parc/algol/parc_EventQueue.h>
-#include <parc/algol/parc_EventTimer.h>
-
-#include <parc/assert/parc_Assert.h>
-
-#include <hicn/core/dispatcher.h>
-
-#include <pthread.h>
-
-#ifndef INPORT_ANY
-#define INPORT_ANY 0
-#endif
-
-struct dispatcher {
- PARCEventScheduler *Base;
- Logger *logger;
-};
-
-// ==========================================
-// Public API
-
-PARCEventScheduler *dispatcher_GetEventScheduler(Dispatcher *dispatcher) {
- return dispatcher->Base;
-}
-
-Dispatcher *dispatcher_Create(Logger *logger) {
- Dispatcher *dispatcher = parcMemory_AllocateAndClear(sizeof(Dispatcher));
- parcAssertNotNull(dispatcher,
- "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(Dispatcher));
-
- dispatcher->Base = parcEventScheduler_Create();
- dispatcher->logger = logger_Acquire(logger);
-
- parcAssertNotNull(dispatcher->Base,
- "Got NULL from parcEventScheduler_Create()");
-
- return dispatcher;
-}
-
-void dispatcher_Destroy(Dispatcher **dispatcherPtr) {
- parcAssertNotNull(dispatcherPtr, "Parameter must be non-null double pointer");
- parcAssertNotNull(*dispatcherPtr,
- "Parameter must dereference to non-null pointer");
- Dispatcher *dispatcher = *dispatcherPtr;
-
- logger_Release(&dispatcher->logger);
- parcEventScheduler_Destroy(&(dispatcher->Base));
- parcMemory_Deallocate((void **)&dispatcher);
- *dispatcherPtr = NULL;
-}
-
-void dispatcher_Stop(Dispatcher *dispatcher) {
- struct timeval delay = {0, 1000};
-
- parcEventScheduler_Stop(dispatcher->Base, &delay);
-}
-
-void dispatcher_Run(Dispatcher *dispatcher) {
- parcAssertNotNull(dispatcher, "Parameter must be non-null");
-
- parcEventScheduler_Start(dispatcher->Base, 0);
-}
-
-void dispatcher_RunDuration(Dispatcher *dispatcher, struct timeval *duration) {
- parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
- parcAssertNotNull(duration, "Parameter duration must be non-null");
-
- parcEventScheduler_Stop(dispatcher->Base, duration);
- parcEventScheduler_Start(dispatcher->Base, 0);
-}
-
-void dispatcher_RunCount(Dispatcher *dispatcher, unsigned count) {
- parcAssertNotNull(dispatcher, "Parameter must be non-null");
-
- for (unsigned i = 0; i < count; i++) {
- parcEventScheduler_Start(dispatcher->Base,
- PARCEventSchedulerDispatchType_LoopOnce);
- }
-}
-
-PARCEventSocket *dispatcher_CreateListener(Dispatcher *dispatcher,
- PARCEventSocket_Callback *callback,
- void *user_data, int backlog,
- const struct sockaddr *sa,
- int socklen) {
- PARCEventSocket *listener = parcEventSocket_Create(
- dispatcher->Base, callback, NULL, user_data, sa, socklen);
- if (listener == NULL) {
- perror("Problem creating listener");
- }
- return listener;
-}
-
-void dispatcher_DestroyListener(Dispatcher *dispatcher,
- PARCEventSocket **listenerPtr) {
- parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer");
- parcAssertNotNull(*listenerPtr,
- "Parameter must dereference to non-null pointer");
- parcEventSocket_Destroy(listenerPtr);
-}
-
-PARCEventQueue *dispatcher_CreateStreamBufferFromSocket(Dispatcher *dispatcher,
- SocketType fd) {
- parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
- PARCEventQueue *buffer = parcEventQueue_Create(
- dispatcher->Base, fd,
- PARCEventQueueOption_CloseOnFree | PARCEventQueueOption_DeferCallbacks);
- parcAssertNotNull(buffer,
- "Got null from parcEventBufver_Create for socket %d", fd);
- return buffer;
-}
-
-PARCEventTimer *dispatcher_CreateTimer(Dispatcher *dispatcher, bool isPeriodic,
- PARCEvent_Callback *callback,
- void *userData) {
- parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
- parcAssertNotNull(callback, "Parameter callback must be non-null");
-
- PARCEventType flags = 0;
- if (isPeriodic) {
- flags |= PARCEventType_Persist;
- }
- PARCEventTimer *event =
- parcEventTimer_Create(dispatcher->Base, flags, callback, userData);
- return event;
-}
-
-void dispatcher_StartTimer(Dispatcher *dispatcher, PARCEventTimer *timerEvent,
- struct timeval *delay) {
- parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
- parcAssertNotNull(timerEvent, "Parameter timerEvent must be non-null");
- int failure = parcEventTimer_Start(timerEvent, delay);
- parcAssertFalse(failure < 0, "Error starting timer event %p: (%d) %s",
- (void *)timerEvent, errno, strerror(errno));
-}
-
-void dispatcher_StopTimer(Dispatcher *dispatcher, PARCEventTimer *event) {
- parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
- parcAssertNotNull(event, "Parameter event must be non-null");
-
- int failure = parcEventTimer_Stop(event);
- parcAssertFalse(failure < 0, "Error stopping signal event %p: (%d) %s",
- (void *)event, errno, strerror(errno));
-}
-
-void dispatcher_DestroyTimerEvent(Dispatcher *dispatcher,
- PARCEventTimer **eventPtr) {
- parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
- parcAssertNotNull(eventPtr,
- "Parameter eventPtr must be non-null double pointer");
- parcAssertNotNull(*eventPtr,
- "Paramter eventPtr must dereference to non-null pointer");
-
- parcEventTimer_Destroy(eventPtr);
- eventPtr = NULL;
-}
-
-PARCEvent *dispatcher_CreateNetworkEvent(Dispatcher *dispatcher,
- bool isPersistent,
- PARCEvent_Callback *callback,
- void *userData, int fd) {
- short flags = PARCEventType_Timeout | PARCEventType_Read;
- if (isPersistent) {
- flags |= PARCEventType_Persist;
- }
-
- PARCEvent *event =
- parcEvent_Create(dispatcher->Base, fd, flags, callback, userData);
- parcAssertNotNull(event, "Got null from parcEvent_Create for socket %d", fd);
- return event;
-}
-
-void dispatcher_DestroyNetworkEvent(Dispatcher *dispatcher,
- PARCEvent **eventPtr) {
- parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
- parcAssertNotNull(eventPtr,
- "Parameter eventPtr must be non-null double pointer");
- parcAssertNotNull(*eventPtr,
- "Paramter eventPtr must dereference to non-null pointer");
-
- parcEvent_Destroy(eventPtr);
- eventPtr = NULL;
-}
-
-void dispatcher_StartNetworkEvent(Dispatcher *dispatcher, PARCEvent *event) {
- parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
- parcAssertNotNull(event, "Parameter event must be non-null");
-
- int failure = parcEvent_Start(event);
- parcAssertFalse(failure < 0, "Error starting signal event %p: (%d) %s",
- (void *)event, errno, strerror(errno));
-}
-
-void dispatcher_StopNetworkEvent(Dispatcher *dispatcher, PARCEvent *event) {
- parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
- parcAssertNotNull(event, "Parameter event must be non-null");
-
- int failure = parcEvent_Stop(event);
- parcAssertFalse(failure < 0, "Error stopping signal event %p: (%d) %s",
- (void *)event, errno, strerror(errno));
-}
-
-PARCEventSignal *dispatcher_CreateSignalEvent(
- Dispatcher *dispatcher, PARCEventSignal_Callback *callback, void *userData,
- int signal) {
- parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
- parcAssertNotNull(callback, "Parameter callback must be non-null");
-
- PARCEventSignal *event = parcEventSignal_Create(
- dispatcher->Base, signal, PARCEventType_Signal | PARCEventType_Persist,
- callback, userData);
- parcAssertNotNull(event,
- "Got null event when creating signal catcher for signal %d",
- signal);
-
- return event;
-}
-
-void dispatcher_DestroySignalEvent(Dispatcher *dispatcher,
- PARCEventSignal **eventPtr) {
- parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
- parcAssertNotNull(eventPtr,
- "Parameter eventPtr must be non-null double pointer");
- parcAssertNotNull(*eventPtr,
- "Paramter eventPtr must dereference to non-null pointer");
-
- parcEventSignal_Destroy(eventPtr);
- eventPtr = NULL;
-}
-
-void dispatcher_StartSignalEvent(Dispatcher *dispatcher,
- PARCEventSignal *event) {
- parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
- parcAssertNotNull(event, "Parameter event must be non-null");
-
- int failure = parcEventSignal_Start(event);
- parcAssertFalse(failure < 0, "Error starting signal event %p: (%d) %s",
- (void *)event, errno, strerror(errno));
-}
-
-void dispatcher_StopSignalEvent(Dispatcher *dispatcher,
- PARCEventSignal *event) {
- parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
- parcAssertNotNull(event, "Parameter event must be non-null");
-
- int failure = parcEventSignal_Stop(event);
- parcAssertFalse(failure < 0, "Error stopping signal event %p: (%d) %s",
- (void *)event, errno, strerror(errno));
-}
-
-/**
- * Bind to a local address/port then connect to peer.
- */
-static bool dispatcher_StreamBufferBindAndConnect(Dispatcher *dispatcher,
- PARCEventQueue *buffer,
- struct sockaddr *localSock,
- socklen_t localSockLength,
- struct sockaddr *remoteSock,
- socklen_t remoteSockLength) {
- // we need to bind, then connect. Special operation, so we make our
- // own fd then pass it off to the buffer event
-
-#ifndef _WIN32
- int fd = socket(localSock->sa_family, SOCK_STREAM, 0);
- if (fd < 0) {
- perror("socket");
- return -1;
- }
-
- // Set non-blocking flag
- int flags = fcntl(fd, F_GETFL, NULL);
- if (flags < 0) {
- perror("F_GETFL");
- close(fd);
- return -1;
- }
- int failure = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
- if (failure) {
- perror("F_SETFL");
- close(fd);
- return -1;
- }
-
- failure = bind(fd, localSock, localSockLength);
- if (failure) {
- perror("bind");
- close(fd);
- return false;
- }
-
- parcEventQueue_SetFileDescriptor(buffer, fd);
-
- failure = parcEventQueue_ConnectSocket(buffer, remoteSock, remoteSockLength);
- if (failure && (errno != EINPROGRESS)) {
- perror("connect");
- close(fd);
- return false;
- }
-#else
- SOCKET fd = socket(localSock->sa_family, SOCK_STREAM, 0);
- if (fd == INVALID_SOCKET) {
- perror("socket");
- return -1;
- }
-
- // Set non-blocking flag
- u_long mode = 1;
- int result = ioctlsocket(fd, FIONBIO, &mode);
- if (result == NO_ERROR) {
- perror("ioctlsocket error");
- closesocket(fd);
- WSACleanup();
- return -1;
- }
-
- int failure = bind(fd, localSock, (int)localSockLength);
- if (failure) {
- perror("bind");
- closesocket(fd);
- WSACleanup();
- return false;
- }
-
- parcEventQueue_SetFileDescriptor(buffer, (int)fd);
-
- failure = parcEventQueue_ConnectSocket(buffer, remoteSock, remoteSockLength);
- if (failure && (errno != EINPROGRESS)) {
- perror("connect");
- closesocket(fd);
- WSACleanup();
- return false;
- }
-#endif
-
- return true;
-}
-
-/**
- * Connect to an INET peer
- * @return NULL on error, otherwise a streambuffer
- */
-static PARCEventQueue *dispatcher_StreamBufferConnect_INET(
- Dispatcher *dispatcher, const Address *localAddress,
- const Address *remoteAddress) {
- struct sockaddr_in localSock, remoteSock;
- addressGetInet(localAddress, &localSock);
- addressGetInet(remoteAddress, &remoteSock);
-
- PARCEventQueue *buffer = parcEventQueue_Create(
- dispatcher->Base, -1, PARCEventQueueOption_CloseOnFree);
- parcAssertNotNull(buffer, "got null buffer from parcEventQueue_Create()");
-
- bool success = dispatcher_StreamBufferBindAndConnect(
- dispatcher, buffer, (struct sockaddr *)&localSock, sizeof(localSock),
- (struct sockaddr *)&remoteSock, sizeof(remoteSock));
- if (!success) {
- parcEventQueue_Destroy(&buffer);
- buffer = NULL;
- }
-
- return buffer;
-}
-
-/**
- * Connect to an INET peer
- * @return NULL on error, otherwise a streambuffer
- */
-static PARCEventQueue *
-// static StreamBuffer *
-dispatcher_StreamBufferConnect_INET6(Dispatcher *dispatcher,
- const Address *localAddress,
- const Address *remoteAddress) {
- struct sockaddr_in6 localSock, remoteSock;
- addressGetInet6(localAddress, &localSock);
- addressGetInet6(remoteAddress, &remoteSock);
-
- PARCEventQueue *buffer = parcEventQueue_Create(
- dispatcher->Base, -1, PARCEventQueueOption_CloseOnFree);
- parcAssertNotNull(buffer, "got null buffer from parcEventQueue_Create()");
-
- bool success = dispatcher_StreamBufferBindAndConnect(
- dispatcher, buffer, (struct sockaddr *)&localSock, sizeof(localSock),
- (struct sockaddr *)&remoteSock, sizeof(remoteSock));
- if (!success) {
- parcEventQueue_Destroy(&buffer);
- buffer = NULL;
- }
-
- return buffer;
-}
-
-PARCEventQueue *dispatcher_StreamBufferConnect(Dispatcher *dispatcher,
- const AddressPair *pair) {
- const Address *localAddress = addressPair_GetLocal(pair);
- const Address *remoteAddress = addressPair_GetRemote(pair);
-
- // they must be of the same address family
- if (addressGetType(localAddress) != addressGetType(remoteAddress)) {
- char message[2048];
- char *localAddressString = addressToString(localAddress);
- char *remoteAddressString = addressToString(remoteAddress);
- snprintf(message, 2048,
- "Remote address not same type as local address, expected %d got "
- "%d\nlocal %s remote %s",
- addressGetType(localAddress), addressGetType(remoteAddress),
- localAddressString, remoteAddressString);
-
- parcMemory_Deallocate((void **)&localAddressString);
- parcMemory_Deallocate((void **)&remoteAddressString);
-
- parcAssertTrue(
- addressGetType(localAddress) == addressGetType(remoteAddress), "%s",
- message);
- }
-
- address_type type = addressGetType(localAddress);
-
- PARCEventQueue *result = NULL;
-
- switch (type) {
- case ADDR_INET:
- return dispatcher_StreamBufferConnect_INET(dispatcher, localAddress,
- remoteAddress);
- break;
- case ADDR_INET6:
- return dispatcher_StreamBufferConnect_INET6(dispatcher, localAddress,
- remoteAddress);
- break;
- default:
- parcTrapIllegalValue(type, "local address unsupported address type: %d",
- type);
- }
- return result;
-}
diff --git a/hicn-light/src/hicn/core/dispatcher.h b/hicn-light/src/hicn/core/dispatcher.h
deleted file mode 100644
index e5c2df336..000000000
--- a/hicn-light/src/hicn/core/dispatcher.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @header hicn-light Dispatcher
- * @abstract The dispatcher is the event loop run by Forwarder.
- * @discussion
- * These functions manage listeners, timers, and network events inside
- * the event loop.
- *
- * Curently, it is a thin wrapper around an event so we don't have to
- * expose that implementation detail to other modules.
- *
- */
-
-#ifndef dispatcher_h
-#define dispatcher_h
-
-#ifndef _WIN32
-#include <sys/socket.h>
-#endif
-#include <stdbool.h>
-
-struct dispatcher;
-typedef struct dispatcher Dispatcher;
-
-#include <parc/algol/parc_Event.h>
-#include <parc/algol/parc_EventQueue.h>
-#include <parc/algol/parc_EventScheduler.h>
-#include <parc/algol/parc_EventSignal.h>
-#include <parc/algol/parc_EventSocket.h>
-#include <parc/algol/parc_EventTimer.h>
-#include <parc/algol/parc_Memory.h>
-
-#include <hicn/core/logger.h>
-
-PARCEventScheduler *dispatcher_GetEventScheduler(Dispatcher *dispatcher);
-/**
- * Creates an event dispatcher
- *
- * Event dispatcher based on PARCEvent
- *
- * @return non-null Allocated event dispatcher
- * @return null An error
- */
-Dispatcher *dispatcher_Create(Logger *logger);
-
-/**
- * Destroys event dispatcher
- *
- * Caller is responsible for destroying call events before destroying
- * the event dispatcher.
- */
-void dispatcher_Destroy(Dispatcher **dispatcherPtr);
-
-/**
- * @function dispatcher_Stop
- * @abstract Called from a different thread, tells the dispatcher to stop
- * @discussion
- * Called from a user thread or from an interrupt handler.
- * Does not block. Use <code>dispatcher_WaitForStopped()</code> to
- * block until stopped after calling this.
- */
-void dispatcher_Stop(Dispatcher *dispatcher);
-
-/**
- * @function dispatcher_WaitForStopped
- * @abstract Blocks until dispatcher in stopped state
- * @discussion
- * Used after <code>dispatcher_Stop()</code> to wait for stop.
- */
-void dispatcher_WaitForStopped(Dispatcher *dispatcher);
-
-/**
- * @function dispatcher_Run
- * @abstract Runs the forwarder, blocks.
- */
-void dispatcher_Run(Dispatcher *dispatcher);
-
-/**
- * @function dispatcher_RunDuration
- * @abstract Runs forwarder for at most duration, blocks.
- * @discussion
- * Blocks running the forwarder for a duration. May be called
- * iteratively to keep running. Duration is a minimum, actual
- * runtime may be slightly longer.
- */
-void dispatcher_RunDuration(Dispatcher *dispatcher, struct timeval *duration);
-
-/**
- * @header dispatcher_RunCount
- * @abstract Run the event loop for the given count cycles
- * @discussion
- * Runs the event loop for the given number of cycles, blocking
- * until done. May be called sequentially over and over.
- *
- */
-void dispatcher_RunCount(Dispatcher *dispatcher, unsigned count);
-
-typedef int SocketType;
-
-typedef struct evconnlistener Listener;
-
-/**
- * @typedef ListenerCallback
- * @abstract Callback function typedef for a stream listener
- *
- * @constant listener is the object created by <code>forwarder_NewBind()</code>
- * that received the client connection
- * @constant client_socket is the client socket
- * @constant user_data is the user_data passed to
- * <code>forwarder_NewBind()</code>
- * @constant client_addr is the client address
- * @constant socklen is the length of client_addr
- * @discussion <#Discussion#>
- */
-typedef void(ListenerCallback)(Listener *listener, SocketType client_socket,
- struct sockaddr *client_addr, int socklen,
- void *user_data);
-
-/**
- * @header forwarder_NewBind
- * @abstract Allocate a new stream listener
- * @discussion
- * The server socket will be freed when closed and will be reusable.
- *
- * @param forwarder that owns the event loop
- * @param cb is the callback for a new connection
- * @param user_data is opaque user data passed to the callback
- * @param backlog is the listen() depth, may use -1 for a default value
- * @param sa is the socket address to bind to (INET, INET6, LOCAL)
- * @param socklen is the sizeof the actual sockaddr (e.g. sizeof(sockaddr_un))
- */
-PARCEventSocket *dispatcher_CreateListener(Dispatcher *dispatcher,
- PARCEventSocket_Callback *callback,
- void *user_data, int backlog,
- const struct sockaddr *sa,
- int socklen);
-
-void dispatcher_DestroyListener(Dispatcher *dispatcher,
- PARCEventSocket **listenerPtr);
-
-typedef struct event TimerEvent;
-typedef struct event NetworkEvent;
-typedef struct event SignalEvent;
-
-/**
- * @typedef EventCallback
- * @abstract A network event or a timer callback
- * @constant fd The file descriptor associated with the event, may be -1 for
- * timers
- * @constant which_event is a bitmap of the EventType
- * @constant user_data is the user_data passed to
- * <code>Forwarder_CreateEvent()</code>
- */
-typedef void(EventCallback)(SocketType fd, short which_event, void *user_data);
-
-/**
- * @function dispatcher_CreateTimer
- * @abstract Creates a Event for use as a timer.
- * @discussion
- *
- * When created, the timer is idle and you need to call
- * <code>forwarder_StartTimer()</code>
- *
- * @param isPeriodic means the timer will fire repeatidly, otherwise it is a
- * one-shot and needs to be set again with <code>dispatcher_StartTimer()</code>
- */
-PARCEventTimer *dispatcher_CreateTimer(Dispatcher *dispatcher, bool isPeriodic,
- PARCEvent_Callback *callback,
- void *userData);
-
-/**
- * @function dispatcher_StartTimer
- * @abstract Starts the timer with the given delay.
- * @discussion
- * If the timer is periodic, it will keep firing with the given delay
- */
-void dispatcher_StartTimer(Dispatcher *dispatcher, PARCEventTimer *timerEvent,
- struct timeval *delay);
-
-void dispatcher_StopTimer(Dispatcher *dispatcher, PARCEventTimer *timerEvent);
-
-/**
- * @function dispatcher_DestroyTimerEvent
- * @abstract Cancels the timer and frees the event
- */
-void dispatcher_DestroyTimerEvent(Dispatcher *dispatcher,
- PARCEventTimer **eventPtr);
-
-/**
- * @function dispatcher_CreateNetworkEvent
- * @abstract Creates a network event callback on the socket
- * @discussion
- * May be used on any sort of file descriptor or socket. The event is edge
- * triggered and non-reentrent. This means you need to drain the events off the
- * socket, as the callback will not be called again until a new event arrives.
- *
- * When created, the event is idle and you need to call
- * <code>forwarder_StartNetworkEvent()</code>
- *
- * @param isPersistent means the callback will keep firing with new events,
- * otherwise its a one-shot
- * @param fd is the socket to monitor
- */
-PARCEvent *dispatcher_CreateNetworkEvent(Dispatcher *dispatcher,
- bool isPersistent,
- PARCEvent_Callback *callback,
- void *userData, int fd);
-
-void dispatcher_StartNetworkEvent(Dispatcher *dispatcher, PARCEvent *event);
-void dispatcher_StopNetworkEvent(Dispatcher *dispatcher, PARCEvent *event);
-
-void dispatcher_DestroyNetworkEvent(Dispatcher *dispatcher,
- PARCEvent **eventPtr);
-
-/**
- * @function dispatcher_CreateSignalEvent
- * @abstract Creates a signal trap
- * @discussion
- * May be used on catchable signals. The event is edge triggered and
- * non-reentrent. Signal events are persistent.
- *
- * When created, the signal trap is idle and you need to call
- * <code>forwarder_StartSignalEvent()</code>
- *
- * @param signal is the system signal to monitor (e.g. SIGINT).
- * @return <#return#>
- */
-PARCEventSignal *dispatcher_CreateSignalEvent(
- Dispatcher *dispatcher, PARCEventSignal_Callback *callback, void *userData,
- int signal);
-
-void dispatcher_DestroySignalEvent(Dispatcher *dispatcher,
- PARCEventSignal **eventPtr);
-
-void dispatcher_StartSignalEvent(Dispatcher *dispatcher,
- PARCEventSignal *event);
-void dispatcher_StopSignalEvent(Dispatcher *dispatcher, PARCEventSignal *event);
-
-// =============
-// stream buffers
-
-#include <hicn/core/streamBuffer.h>
-#include <hicn/io/addressPair.h>
-
-/**
- * @function dispatcher_CreateStreamBuffer
- * @abstract Creates a high-function buffer around a stream socket
- */
-PARCEventQueue *dispatcher_CreateStreamBufferFromSocket(Dispatcher *dispatcher,
- SocketType fd);
-
-/**
- * @function dispatcher_StreamBufferConnect
- * @abstract Create a TCP tunnel to a remote peer
- * @discussion
- * For TCP, both address pairs need to be the same address family: both INET
- * or both INET6. The remote address must have the complete socket information
- * (address, port). The local socket could be wildcarded or may specify down to
- * the (address, port) pair.
- *
- * If the local address is IPADDR_ANY and the port is 0, then it is a normal
- * call to "connect" that will use whatever local IP address and whatever local
- * port for the connection. If either the address or port is set, the local
- * socket will first be bound (via bind(2)), and then call connect().
- *
- * It is unlikely that the buffer will be connected by the time the function
- * returns. The eventCallback will fire once the remote system accepts the
- * conneciton.
- *
- * @return NULL on error, otherwise a streambuffer.
- */
-PARCEventQueue *dispatcher_StreamBufferConnect(Dispatcher *dispatcher,
- const AddressPair *pair);
-#endif // dispatcher_h
diff --git a/hicn-light/src/hicn/core/fib.c b/hicn-light/src/hicn/core/fib.c
new file mode 100644
index 000000000..ddd8dd548
--- /dev/null
+++ b/hicn-light/src/hicn/core/fib.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hicn/hicn-light/config.h>
+#include <stdio.h>
+
+#include <hicn/core/fib.h>
+
+typedef struct fib_node_s {
+ struct fib_node_s *left;
+ struct fib_node_s *right;
+ fib_entry_t *entry;
+ bool is_used;
+} fib_node_t;
+
+static
+fib_node_t *
+fib_node_create(fib_node_t * left, fib_node_t * right, fib_entry_t * entry,
+ bool is_used)
+{
+ fib_node_t * node = malloc(sizeof(fib_node_t));
+ if (!node)
+ return NULL;
+
+ *node = (fib_node_t) {
+ .left = left,
+ .right = right,
+ .entry = entry,
+ .is_used = is_used,
+ };
+
+ return node;
+}
+
+static
+void
+fib_node_free(fib_node_t * node)
+{
+ if (!node)
+ return;
+
+ fib_node_free(node->right);
+ fib_node_free(node->left);
+
+ free(node);
+}
+
+/******************************************************************************/
+
+struct fib_s {
+ void * forwarder;
+ fib_node_t * root;
+ unsigned size;
+};
+
+fib_t *
+fib_create(void * forwarder)
+{
+ fib_t * fib = malloc(sizeof(fib_t));
+ if (!fib)
+ return NULL;
+
+ fib->forwarder = forwarder;
+ fib->root = NULL;
+ fib->size = 0;
+
+ return fib;
+}
+
+
+void
+fib_free(fib_t * fib)
+{
+ assert(fib);
+
+ fib_node_free(fib->root);
+
+ free(fib);
+}
+
+size_t
+fib_get_size(const fib_t * fib)
+{
+ return fib->size;
+}
+
+
+#define FIB_SET(CURR, NEW_PREFIX, CURR_PREFIX_LEN) \
+do { \
+ bool bit; \
+ int res = nameBitvector_testBit(NEW_PREFIX, CURR_PREFIX_LEN, &bit); \
+ assert(res >= 0); \
+ (void)res; /* unused */ \
+ CURR = bit ? CURR->right : CURR->left; \
+} while(0)
+
+#define FIB_INSERT(DST, SRC, PREFIX, PREFIX_LEN) \
+do { \
+ bool bit; \
+ int res = nameBitvector_testBit(PREFIX, PREFIX_LEN, &bit); \
+ assert(res >= 0); \
+ (void)res; /* unused */ \
+ if (bit) \
+ DST->right = SRC; \
+ else \
+ DST->left = SRC; \
+} while(0)
+
+void
+fib_add(fib_t * fib, fib_entry_t * entry)
+{
+ assert(fib);
+ assert(entry);
+
+ NameBitvector *new_prefix = name_GetContentName(fib_entry_get_prefix(entry));
+ uint32_t new_prefix_len = nameBitvector_GetLength(new_prefix);
+ fib_node_t * curr = fib->root;
+ fib_node_t * last = NULL;
+
+ NameBitvector *curr_name;
+ uint32_t curr_prefix_len;
+ uint32_t match_len;
+
+ while (curr) {
+ curr_name = name_GetContentName(fib_entry_get_prefix(curr->entry));
+
+ match_len = nameBitvector_lpm(new_prefix, curr_name);
+ curr_prefix_len = nameBitvector_GetLength(curr_name);
+
+ if(curr_prefix_len != match_len || //the new entry does not match the curr
+ curr_prefix_len >= new_prefix_len) //in this case we cannot procede anymore
+ break;
+
+ last = curr;
+ FIB_SET(curr, new_prefix, curr_prefix_len);
+ }
+
+ //this is the root (empty trie) or an empty child
+ if (!curr) {
+ fib_node_t * new_node = fib_node_create(NULL, NULL, entry, true);
+ if (!last) {
+ fib->root = new_node;
+ } else {
+ uint32_t last_prefix_len = nameBitvector_GetLength(
+ name_GetContentName(fib_entry_get_prefix(last->entry)));
+
+ FIB_INSERT(last, new_node, new_prefix, last_prefix_len);
+ }
+ fib->size++;
+ return;
+ }
+
+ //curr is not null
+
+ //the node already exist
+ //if is not in use we turn it on and we set the rigth fib entry
+ if (curr_prefix_len == match_len && new_prefix_len == match_len) {
+ if (!curr->is_used) {
+ curr->is_used = true;
+ curr->entry = entry;
+ fib->size++;
+ return;
+ } else {
+ //this case should never happen beacuse of the way we add
+ //entries in the fib
+ const nexthops_t * nexthops = fib_entry_get_nexthops(entry);
+ unsigned nexthop;
+ nexthops_foreach(nexthops, nexthop, {
+ fib_entry_nexthops_add(curr->entry, nexthop);
+ });
+ }
+ }
+
+ //key is prefix of the curr node (so new_prefix_len < curr_prefix_len)
+ if (new_prefix_len == match_len){
+ fib_node_t * new_node = fib_node_create(NULL, NULL, entry, true);
+ if (!last) {
+ fib->root = new_node;
+ } else {
+ uint32_t last_prefix_len = nameBitvector_GetLength(
+ name_GetContentName(fib_entry_get_prefix(last->entry)));
+ FIB_INSERT(last, new_node, new_prefix, last_prefix_len);
+ }
+ FIB_INSERT(new_node, curr, curr_name, match_len);
+ fib->size++;
+ return;
+ }
+
+ //in the last case we need to add an inner node
+ Name * inner_prefix = name_Copy(fib_entry_get_prefix(entry));
+ nameBitvector_clear(name_GetContentName(inner_prefix), match_len);
+ name_setLen(inner_prefix, match_len);
+
+ //this is an inner node, we don't want an acctive strategy
+ //like low_latency that sends probes in this node
+ fib_entry_t * inner_entry = fib_entry_create(inner_prefix,
+ STRATEGY_TYPE_UNDEFINED, NULL, fib->forwarder);
+
+ fib_node_t * inner_node = fib_node_create(NULL, NULL, inner_entry, false);
+ fib_node_t * new_node = fib_node_create(NULL, NULL, entry, true);
+
+ if (!last) {
+ //we need to place the inner_node at the root
+ fib->root = inner_node;
+ } else {
+ uint32_t last_prefix_len = nameBitvector_GetLength(
+ name_GetContentName(fib_entry_get_prefix(last->entry)));
+ NameBitvector *inner_name = name_GetContentName(inner_prefix);
+ FIB_INSERT(last, inner_node, inner_name, last_prefix_len);
+ }
+
+ bool bit;
+ int res = nameBitvector_testBit(new_prefix, match_len, &bit);
+ assert(res >= 0);
+ (void)res; /* unused */
+ inner_node->left = bit ? curr : new_node;
+ inner_node->right = bit ? new_node : curr;
+ fib->size++;
+}
+
+fib_entry_t *
+fib_contains(const fib_t * fib, const Name * prefix)
+{
+ assert(fib);
+ assert(prefix);
+
+ NameBitvector * key_name = name_GetContentName(prefix);
+ uint32_t key_prefix_len = nameBitvector_GetLength(key_name);
+
+ fib_node_t * curr = fib->root;
+
+ while (curr) {
+ NameBitvector *curr_name =
+ name_GetContentName(fib_entry_get_prefix(curr->entry));
+ uint32_t match_len = nameBitvector_lpm(key_name, curr_name);
+ uint32_t curr_prefix_len = nameBitvector_GetLength(curr_name);
+
+ if (match_len < curr_prefix_len) {
+ //the current node does not match completelly the key, so
+ //the key is not in the trie
+ //this implies curr_prefix_len > key_prefix_len
+ return NULL;
+ }
+
+ if (curr_prefix_len == key_prefix_len) { //== match_len
+ //this is an exact match
+ if (!curr->is_used) {
+ //the key does not exists
+ return NULL;
+ }
+ //we found the key
+ return curr->entry;
+ }
+
+ FIB_SET(curr, key_name, curr_prefix_len);
+ }
+
+ return NULL;
+}
+
+static
+void
+fib_node_remove(fib_t *fib, const Name *prefix)
+{
+ assert(fib);
+ assert(prefix);
+
+ NameBitvector *key_name = name_GetContentName(prefix);
+ uint32_t key_prefix_len = nameBitvector_GetLength(key_name);
+
+ fib_node_t * curr = fib->root;
+ fib_node_t * parent = NULL;
+ fib_node_t * grandpa = NULL;
+
+ uint32_t match_len;
+ uint32_t curr_prefix_len;
+
+ while(curr) {
+ NameBitvector *curr_name =
+ name_GetContentName(fib_entry_get_prefix(curr->entry));
+ match_len = nameBitvector_lpm(key_name, curr_name);
+ curr_prefix_len = nameBitvector_GetLength(curr_name);
+
+ if(match_len < curr_prefix_len ||
+ curr_prefix_len == key_prefix_len){
+ break;
+ }
+
+ grandpa = parent;
+ parent = curr;
+
+ FIB_SET(curr, key_name, curr_prefix_len);
+ }
+
+ if (!curr || !curr->is_used || (curr_prefix_len != key_prefix_len)) {
+ //the node does not exists
+ return;
+ }
+
+ //curr has 2 children, leave it there and mark it as inner
+ if (curr->right && curr->left) {
+ curr->is_used = false;
+ fib->size--;
+ return;
+ }
+
+ //curr has no children
+ if (!curr->right && !curr->left) {
+ if (!parent) {
+ //curr is the root and is the only node in the fib
+ fib->root = NULL;
+ fib->size--;
+ fib_node_free(curr);
+ return;
+ }
+ if (!grandpa) {
+ //parent is the root
+ if(fib->root->left == curr)
+ fib->root->left = NULL;
+ else
+ fib->root->right = NULL;
+ fib->size--;
+ fib_node_free(curr);
+ return;
+ }
+ if(!parent->is_used){
+ //parent is an inner node
+ //remove curr and inner_node (parent), connect the other child
+ //of the parent to the grandpa
+ fib_node_t * tmp = (parent->right == curr) ? parent->left : parent->right;
+
+ if(grandpa->right == parent)
+ grandpa->right = tmp;
+ else
+ grandpa->left = tmp;
+
+ fib->size--;
+ fib_node_free(curr);
+ fib_node_free(parent);
+ return;
+ }
+ //parent is node not an inner_node
+ //just remove curr the node
+ if(parent->right == curr)
+ parent->right = NULL;
+ else
+ parent->left = NULL;
+ fib->size--;
+ fib_node_free(curr);
+ return;
+ }
+
+ //curr has one child
+ if (curr->right || curr->left) {
+ if (!parent) {
+ //curr is the root
+ fib->root = fib->root->right ? fib->root->right : fib->root->left;
+ fib->size--;
+ fib_node_free(curr);
+ return;
+ }
+ //attach the child of curr to parent
+ fib_node_t * tmp = curr->right ? curr->right : curr->left;
+
+ if (parent->right == curr)
+ parent->right = tmp;
+ else
+ parent->left = tmp;
+
+ fib->size--;
+ fib_node_free(curr);
+ return;
+ }
+}
+
+void
+fib_remove(fib_t * fib, const Name * name, unsigned conn_id)
+{
+ assert(fib);
+ assert(name);
+
+ fib_entry_t *entry = fib_contains(fib, name);
+ if (!entry)
+ return;
+
+ fib_entry_nexthops_remove(entry, conn_id);
+#ifndef WITH_MAPME
+ if (fib_entry_nexthops_len(entry) == 0)
+ fib_node_remove(fib, name);
+#endif /* WITH_MAPME */
+}
+
+static
+size_t
+fib_node_remove_connection_id(fib_node_t * node, unsigned conn_id,
+ fib_entry_t ** array, size_t pos)
+{
+ if (!node)
+ return pos;
+ if (node->is_used) {
+ fib_entry_nexthops_remove(node->entry, conn_id);
+#ifndef WITH_MAPME
+ if (fib_entry_nexthops_len(node->entry) == 0)
+ array[pos++] = node->entry;
+#endif /* WITH_MAPME */
+ }
+ pos = fib_node_remove_connection_id(node->right, conn_id, array, pos);
+ pos = fib_node_remove_connection_id(node->left, conn_id, array, pos);
+ return pos;
+}
+
+void
+fib_remove_connection_id(fib_t * fib, unsigned conn_id)
+{
+ assert(fib);
+
+ fib_entry_t ** array = malloc(sizeof(fib_entry_t*) * fib->size);
+
+ size_t pos = 0;
+ pos = fib_node_remove_connection_id(fib->root, conn_id, array, pos);
+
+ for (int i = 0; i < pos; i++)
+ fib_node_remove(fib, fib_entry_get_prefix(array[i]));
+ free(array);
+}
+
+size_t
+fib_length(const fib_t * fib)
+{
+ assert(fib);
+ return fib->size;
+}
+
+fib_entry_t *
+fib_match_message(const fib_t *fib, const msgbuf_t *interest_msgbuf)
+{
+ assert(fib);
+ assert(interest_msgbuf);
+
+ return fib_match_bitvector(fib, name_GetContentName(
+ msgbuf_get_name(interest_msgbuf)));
+}
+
+fib_entry_t *
+fib_match_name(const fib_t * fib, const Name * name)
+{
+ assert(fib);
+ assert(name);
+
+ return fib_match_bitvector(fib, name_GetContentName(name));
+}
+
+
+fib_entry_t *
+fib_match_bitvector(const fib_t * fib, const NameBitvector * name)
+{
+ assert(fib);
+ assert(name);
+
+ uint32_t key_prefix_len = nameBitvector_GetLength(name);
+
+ fib_node_t * curr = fib->root;
+ fib_node_t * candidate = NULL;
+
+ while (curr) {
+ NameBitvector *curr_name =
+ name_GetContentName(fib_entry_get_prefix(curr->entry));
+ uint32_t match_len = nameBitvector_lpm(name, curr_name);
+ uint32_t curr_prefix_len = nameBitvector_GetLength(curr_name);
+
+ if(match_len < curr_prefix_len){
+ //the current node does not match completelly the key, so
+ //return the parent of this node (saved in candidate)
+ break;
+ }
+
+ if (curr->is_used)
+ candidate = curr;
+
+ //if we are here match_len == curr_prefix_len (can't be larger)
+ //so this node is actually a good candidate for a match
+ if (curr_prefix_len == key_prefix_len){
+ //this an exact match, do not continue
+ break;
+ }
+
+ FIB_SET(curr, name, curr_prefix_len);
+ }
+
+ return candidate ? candidate->entry : NULL;
+}
+
+static
+size_t
+fib_node_collect_entries(fib_node_t * node, fib_entry_t ** array, size_t pos)
+{
+ assert(array);
+
+ if (!node)
+ return pos;
+
+ if(node->is_used)
+ array[pos++] = node->entry;
+
+ pos = fib_node_collect_entries(node->right, array, pos);
+ pos = fib_node_collect_entries(node->left, array, pos);
+ return pos;
+}
+
+size_t
+fib_get_entry_array(const fib_t * fib, fib_entry_t *** array_p)
+{
+ size_t pos = 0;
+ *array_p = malloc(sizeof(fib_entry_t*) * fib->size);
+ if (!*array_p)
+ return pos;
+ pos = fib_node_collect_entries(fib->root, *array_p, pos);
+ return pos;
+}
diff --git a/hicn-light/src/hicn/core/fib.h b/hicn-light/src/hicn/core/fib.h
new file mode 100644
index 000000000..f60a42cae
--- /dev/null
+++ b/hicn-light/src/hicn/core/fib.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef fib_h
+#define fib_h
+
+#include <hicn/core/msgbuf.h>
+#include <hicn/core/name.h>
+#include <hicn/core/fib_entry.h>
+
+#define _fib_var(x) _fib_ ## x
+
+typedef struct fib_s fib_t;
+
+fib_t * fib_create(void * forwarder);
+
+void fib_free(fib_t * fib);
+
+size_t fib_get_size(const fib_t * fib);
+
+void fib_add(fib_t *fib, fib_entry_t * node);
+
+fib_entry_t * fib_contains(const fib_t * fib, const Name * prefix);
+
+void fib_remove(fib_t * fib, const Name * prefix, unsigned conn_id);
+
+void fib_remove_connection_id(fib_t *fib, unsigned conn_id);
+
+size_t fib_length(const fib_t *fib);
+
+fib_entry_t * fib_match_message(const fib_t * fib, const msgbuf_t * interest_msgbuf);
+fib_entry_t * fib_match_name(const fib_t * fib, const Name * name);
+fib_entry_t * fib_match_bitvector(const fib_t * fib, const NameBitvector * name);
+
+size_t fib_get_entry_array(const fib_t * fib, fib_entry_t *** array_p);
+
+#define fib_foreach_entry(FIB, ENTRY, BODY) \
+do { \
+ fib_entry_t ** _fib_var(array); \
+ size_t _fib_var(n) = fib_get_entry_array((FIB), &_fib_var(array)); \
+ size_t _fib_var(i); \
+ for (_fib_var(i) = 0; _fib_var(i) < _fib_var(n); _fib_var(i)++) { \
+ ENTRY = _fib_var(array)[_fib_var(i)]; \
+ do { BODY } while(0); \
+ } \
+ free(_fib_var(array)); \
+} while(0)
+
+#endif // fib_h
diff --git a/hicn-light/src/hicn/core/fib_entry.c b/hicn-light/src/hicn/core/fib_entry.c
new file mode 100644
index 000000000..5c6e28d5b
--- /dev/null
+++ b/hicn-light/src/hicn/core/fib_entry.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include <hicn/hicn-light/config.h>
+#include <hicn/core/fib_entry.h>
+//#include <hicn/core/connectionState.h>
+#include <hicn/core/strategy_vft.h>
+#include <hicn/core/nameBitvector.h>
+#include <hicn/utils/commands.h>
+
+#ifdef WITH_MAPME
+#include <hicn/core/ticks.h>
+#endif /* WITH_MAPME */
+
+#ifdef WITH_POLICY
+#include <hicn/core/forwarder.h>
+#include <hicn/policy.h>
+
+#ifdef WITH_MAPME
+#include <hicn/core/mapme.h>
+#endif /* WITH_MAPME */
+
+#endif /* WITH_POLICY */
+
+#ifdef WITH_PREFIX_STATS
+#include <hicn/core/prefix_stats.h>
+#endif /* WITH_PREFIX_STATS */
+
+
+fib_entry_t *
+fib_entry_create(Name *name, strategy_type_t strategy_type,
+ strategy_options_t * strategy_options, const forwarder_t * forwarder)
+{
+
+ assert(name);
+ assert(forwarder);
+
+ fib_entry_t * entry = malloc(sizeof(fib_entry_t));
+ if (!entry)
+ goto ERR_MALLOC;
+
+ entry->name = name_Acquire(name);
+
+ // XXX TODO strategy type might be undefined. We need a default strategy
+ // specified somewhere in the configuration.
+ fib_entry_set_strategy(entry, strategy_type, strategy_options);
+
+#ifdef WITH_MAPME
+ entry->user_data = NULL;
+ entry->user_data_release = NULL;
+#endif /* WITH_MAPME */
+
+ entry->forwarder = forwarder;
+
+#ifdef WITH_POLICY
+ entry->policy = POLICY_NONE;
+#endif /* WITH_POLICY */
+
+#ifdef WITH_PREFIX_STATS
+ entry->prefix_stats = PREFIX_STATS_EMPTY;
+ entry->prefix_counters = PREFIX_COUNTERS_EMPTY;
+#endif /* WITH_PREFIX_STATS */
+
+ return entry;
+
+ERR_MALLOC:
+ return NULL;
+}
+
+void
+fib_entry_free(fib_entry_t * entry)
+{
+ assert(entry);
+
+ name_Release(&entry->name);
+#ifdef WITH_MAPME
+ if (entry->user_data)
+ entry->user_data_release(&entry->user_data);
+#endif /* WITH_MAPME */
+ free(entry);
+}
+
+// XXX TODO DUPLICATE
+void
+fib_entry_set_strategy(fib_entry_t * entry, strategy_type_t strategy_type,
+ strategy_options_t * strategy_options)
+{
+ if (STRATEGY_TYPE_VALID(strategy_type)) {
+ entry->strategy.type = strategy_type;
+ if (strategy_options)
+ entry->strategy.options = *strategy_options;
+ strategy_vft[strategy_type]->initialize(&entry->strategy);
+ }
+}
+
+#ifdef WITH_POLICY
+
+nexthops_t *
+fib_entry_filter_nexthops(fib_entry_t * entry, nexthops_t * nexthops,
+ unsigned ingress_id, bool prefer_local)
+{
+ assert(entry);
+ assert(nexthops);
+
+ /* Filter out ingress, down & administrative down faces */
+ const connection_table_t * table = forwarder_get_connection_table(entry->forwarder);
+ connection_t * conn;
+ unsigned nexthop, i;
+ uint_fast32_t flags;
+
+ policy_t policy = fib_entry_get_policy(entry);
+
+ nexthops_enumerate(nexthops, i, nexthop, {
+ conn = connection_table_at(table, nexthop);
+ nexthops_disable_if(nexthops, i, nexthop == ingress_id);
+ nexthops_disable_if(nexthops, i,
+ (connection_get_admin_state(conn) == FACE_STATE_DOWN));
+ nexthops_disable_if(nexthops, i,
+ (connection_get_state(conn) == FACE_STATE_DOWN));
+ });
+
+ if (prefer_local) {
+ /* Backup flags */
+ flags = nexthops->flags;
+
+ /* Filter local */
+ nexthops_enumerate(nexthops, i, nexthop, {
+ conn = connection_table_at(table, nexthop);
+ nexthops_disable_if(nexthops, i, (!connection_is_local(conn)));
+ });
+
+ /* Local faces have priority */
+ if (nexthops_get_curlen(nexthops) > 0)
+ return nexthops;
+
+ nexthops->flags = flags;
+ }
+
+ /* Filter out local */
+ nexthops_enumerate(nexthops, i, nexthop, {
+ conn = connection_table_at(table, nexthop);
+ nexthops_disable_if(nexthops, i, (connection_is_local(conn)));
+
+ /* Policy filtering : next hops */
+ nexthops_disable_if(nexthops, i,
+ (policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_REQUIRE) &&
+ (!connection_has_tag(conn, POLICY_TAG_WIRED)));
+ nexthops_disable_if(nexthops, i,
+ (policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_PROHIBIT) &&
+ (connection_has_tag(conn, POLICY_TAG_WIRED)));
+ nexthops_disable_if(nexthops, i,
+ (policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_REQUIRE) &&
+ (!connection_has_tag(conn, POLICY_TAG_WIFI)));
+ nexthops_disable_if(nexthops, i,
+ (policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_PROHIBIT) &&
+ (connection_has_tag(conn, POLICY_TAG_WIFI)));
+ nexthops_disable_if(nexthops, i,
+ (policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_REQUIRE) &&
+ (!connection_has_tag(conn, POLICY_TAG_CELLULAR)));
+ nexthops_disable_if(nexthops, i,
+ (policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_PROHIBIT) &&
+ (connection_has_tag(conn, POLICY_TAG_CELLULAR)));
+ nexthops_disable_if(nexthops, i,
+ (policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_REQUIRE) &&
+ (!connection_has_tag(conn, POLICY_TAG_TRUSTED)));
+ nexthops_disable_if(nexthops, i,
+ (policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_PROHIBIT) &&
+ (connection_has_tag(conn, POLICY_TAG_TRUSTED)));
+ });
+
+ if (nexthops_get_curlen(nexthops) == 0)
+ return nexthops;
+
+ /* We have at least one matching next hop, implement heuristic */
+
+ /*
+ * As VPN connections might trigger duplicate uses of one interface, we start
+ * by filtering out interfaces based on trust status.
+ */
+ flags = nexthops->flags;
+
+ if ((policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_REQUIRE) ||
+ (policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_PREFER)) {
+
+ /* Try to filter out NON TRUSTED faces */
+ nexthops_enumerate(nexthops, i, nexthop, {
+ conn = connection_table_at(table, nexthop);
+ nexthops_disable_if(nexthops, i,
+ (!connection_has_tag(conn, POLICY_TAG_TRUSTED)));
+ });
+
+ if ((nexthops_get_curlen(nexthops) == 0) && (policy.tags[POLICY_TAG_TRUSTED].state == POLICY_STATE_REQUIRE)) {
+ return nexthops;
+ }
+
+ } else {
+ /* Try to filter out TRUSTED faces */
+ nexthops_enumerate(nexthops, i, nexthop, {
+ conn = connection_table_at(table, nexthop);
+ nexthops_disable_if(nexthops, i,
+ (connection_has_tag(conn, POLICY_TAG_TRUSTED)));
+ });
+ }
+
+ if (nexthops_get_curlen(nexthops) == 0)
+ nexthops->flags = flags;
+
+ /* Other preferences */
+ if (policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_AVOID) {
+ nexthops_enumerate(nexthops, i, nexthop, {
+ conn = connection_table_at(table, nexthop);
+ nexthops_disable_if(nexthops, i,
+ connection_has_tag(conn, POLICY_TAG_WIRED));
+ });
+ if (nexthops_get_curlen(nexthops) == 0)
+ nexthops->flags = flags;
+ }
+ if (policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_AVOID) {
+ nexthops_enumerate(nexthops, i, nexthop, {
+ conn = connection_table_at(table, nexthop);
+ nexthops_disable_if(nexthops, i,
+ connection_has_tag(conn, POLICY_TAG_WIFI));
+ });
+ if (nexthops_get_curlen(nexthops) == 0)
+ nexthops->flags = flags;
+ }
+ if (policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_AVOID) {
+ nexthops_enumerate(nexthops, i, nexthop, {
+ conn = connection_table_at(table, nexthop);
+ nexthops_disable_if(nexthops, i,
+ connection_has_tag(conn, POLICY_TAG_CELLULAR));
+ });
+ if (nexthops_get_curlen(nexthops) == 0)
+ nexthops->flags = flags;
+ }
+
+ if (policy.tags[POLICY_TAG_WIRED].state == POLICY_STATE_PREFER) {
+ nexthops_enumerate(nexthops, i, nexthop, {
+ conn = connection_table_at(table, nexthop);
+ nexthops_disable_if(nexthops, i,
+ !connection_has_tag(conn, POLICY_TAG_WIRED));
+ });
+ if (nexthops_get_curlen(nexthops) == 0)
+ nexthops->flags = flags;
+ }
+ if (policy.tags[POLICY_TAG_WIFI].state == POLICY_STATE_PREFER) {
+ nexthops_enumerate(nexthops, i, nexthop, {
+ conn = connection_table_at(table, nexthop);
+ nexthops_disable_if(nexthops, i,
+ !connection_has_tag(conn, POLICY_TAG_WIFI));
+ });
+ if (nexthops_get_curlen(nexthops) == 0)
+ nexthops->flags = flags;
+ }
+ if (policy.tags[POLICY_TAG_CELLULAR].state == POLICY_STATE_PREFER) {
+ nexthops_enumerate(nexthops, i, nexthop, {
+ conn = connection_table_at(table, nexthop);
+ nexthops_disable_if(nexthops, i,
+ !connection_has_tag(conn, POLICY_TAG_CELLULAR));
+ });
+ if (nexthops_get_curlen(nexthops) == 0)
+ nexthops->flags = flags;
+ }
+
+ /* Priority */
+ uint32_t max_priority = 0;
+ nexthops_foreach(nexthops, nexthop, {
+ conn = connection_table_at(table, nexthop);
+ uint32_t priority = connection_get_priority(conn);
+ if (priority > max_priority)
+ max_priority = priority;
+ });
+ nexthops_enumerate(nexthops, i, nexthop, {
+ conn = connection_table_at(table, nexthop);
+ nexthops_disable_if(nexthops, i,
+ connection_get_priority(conn) < max_priority);
+ });
+
+ return nexthops;
+}
+
+/*
+ * Update available next hops following policy update.
+ *
+ * The last nexthop parameter is only used if needed, otherwise the pointer to
+ * fib entry is returned to avoid an useless copy
+ */
+nexthops_t *
+fib_entry_get_available_nexthops(fib_entry_t * entry, unsigned ingress_id, nexthops_t * new_nexthops)
+{
+ connection_table_t * table = forwarder_get_connection_table(entry->forwarder);
+
+ /*
+ * Give absolute preference to local faces, with no policy, unless
+ * ingress_id == ~0, which means we are searching faces on which to
+ * advertise our prefix
+ */
+ if (ingress_id == ~0) {
+ assert(new_nexthops);
+ /* We create a nexthop structure based on connections */
+ // XXX This should be done close to where it is needed
+ connection_t * connection;
+ connection_table_foreach(table, connection, {
+ new_nexthops->elts[nexthops_get_len(new_nexthops)] = connection_table_get_connection_id(table, connection);
+ nexthops_inc(new_nexthops);
+ });
+
+ return fib_entry_filter_nexthops(entry, new_nexthops, ingress_id, false);
+ }
+
+ return fib_entry_filter_nexthops(entry, fib_entry_get_nexthops(entry), ingress_id, true);
+}
+
+policy_t
+fib_entry_get_policy(const fib_entry_t * entry)
+{
+ return entry->policy;
+}
+
+void
+fib_entry_set_policy(fib_entry_t * entry, policy_t policy)
+{
+ entry->policy = policy;
+
+#ifdef WITH_MAPME
+ /*
+ * Skip entries that do not correspond to a producer ( / have a locally
+ * served prefix / have no local connection as next hop)
+ */
+ if (!fib_entry_has_local_nexthop(entry))
+ return;
+ mapme_t * mapme = forwarder_get_mapme(entry->forwarder);
+ mapme_send_to_all_nexthops(mapme, entry);
+#endif /* WITH_MAPME */
+}
+
+#endif /* WITH_POLICY */
+
+void
+fib_entry_nexthops_add(fib_entry_t * entry, unsigned nexthop)
+{
+ nexthops_add(fib_entry_get_nexthops(entry), nexthop);
+ // XXX TODO
+ strategy_vft[entry->strategy.type]->add_nexthop(&entry->strategy, nexthop, NULL);
+}
+
+void
+fib_entry_nexthops_remove(fib_entry_t * entry, unsigned nexthop)
+{
+ nexthops_remove(fib_entry_get_nexthops(entry), nexthop);
+ // XXX TODO
+ strategy_vft[entry->strategy.type]->remove_nexthop(&entry->strategy, nexthop, NULL);
+}
+
+const nexthops_t *
+fib_entry_get_nexthops_from_strategy(fib_entry_t * entry,
+ const msgbuf_t * msgbuf, bool is_retransmission)
+{
+ assert(entry);
+ assert(msgbuf);
+
+ const prefix_stats_mgr_t * mgr = forwarder_get_prefix_stats_mgr(entry->forwarder);
+ assert(mgr);
+
+ /* Filtering */
+ nexthops_t * nexthops = fib_entry_get_available_nexthops(entry,
+ msgbuf_get_connection_id(msgbuf), NULL);
+ if (nexthops_get_curlen(nexthops) == 0)
+ return nexthops;
+
+#ifdef WITH_PREFIX_STATS
+ /*
+ * Update statistics about loss rates. We only detect losses upon
+ * retransmissions, and assume for the computation that the candidate set of
+ * output faces is the same as previously (i.e. does not take into account
+ * event such as face up/down, policy update, etc. Otherwise we would need to
+ * know what was the previous choice !
+ */
+ if (is_retransmission)
+ prefix_stats_on_retransmission(mgr, &entry->prefix_counters, nexthops);
+#endif /* WITH_PREFIX_STATS */
+
+ /*
+ * NOTE: We might want to call a forwarding strategy even with no nexthop to
+ * take a fallback decision.
+ */
+ if (nexthops_get_curlen(nexthops) == 0)
+ return nexthops;
+
+#ifdef WITH_POLICY
+ /*
+ * If multipath is disabled, we don't offer much choice to the forwarding
+ * strategy, but still go through it for accounting purposes.
+ */
+ policy_t policy = fib_entry_get_policy(entry);
+ if ((policy.tags[POLICY_TAG_MULTIPATH].state == POLICY_STATE_PROHIBIT) ||
+ (policy.tags[POLICY_TAG_MULTIPATH].state != POLICY_STATE_AVOID)) {
+ nexthops_select_one(nexthops);
+ }
+#endif /* WITH_POLICY */
+
+ return strategy_vft[entry->strategy.type]->lookup_nexthops(&entry->strategy,
+ nexthops, msgbuf);
+}
+
+void
+fib_entry_on_data(fib_entry_t * entry,
+ const nexthops_t * nexthops, const msgbuf_t * msgbuf,
+ Ticks pitEntryCreation, Ticks objReception)
+{
+ assert(entry);
+ assert(nexthops);
+ assert(msgbuf);
+
+#ifdef WITH_PREFIX_STATS
+ const prefix_stats_mgr_t * mgr = forwarder_get_prefix_stats_mgr(entry->forwarder);
+ Ticks rtt = objReception - pitEntryCreation;
+ prefix_stats_on_data(mgr, &entry->prefix_stats, &entry->prefix_counters,
+ nexthops, msgbuf, rtt);
+#endif /* WITH_PREFIX_STATS */
+
+ strategy_vft[entry->strategy.type]->on_data(&entry->strategy, nexthops, msgbuf, pitEntryCreation, objReception);
+}
+
+void
+fib_entry_on_timeout(fib_entry_t * entry, const nexthops_t * nexthops)
+{
+ assert(entry);
+ assert(nexthops);
+
+#ifdef WITH_PREFIX_STATS
+ const prefix_stats_mgr_t * mgr = forwarder_get_prefix_stats_mgr(entry->forwarder);
+ prefix_stats_on_timeout(mgr, &entry->prefix_counters, nexthops);
+#endif /* WITH_PREFIX_STATS */
+
+ strategy_vft[entry->strategy.type]->on_timeout(&entry->strategy, nexthops);
+}
+
+Name *
+fib_entry_get_prefix(const fib_entry_t * entry)
+{
+ assert(entry);
+
+ return entry->name;
+}
+
+
+/*
+ * Return true if we have at least one local connection as next hop
+ */
+bool
+fib_entry_has_local_nexthop(const fib_entry_t * entry)
+{
+ connection_table_t * table = forwarder_get_connection_table(entry->forwarder);
+
+ unsigned nexthop;
+ nexthops_foreach(fib_entry_get_nexthops(entry), nexthop, {
+ const connection_t * conn = connection_table_at(table, nexthop);
+ /* Ignore non-local connections */
+ if (!connection_is_local(conn))
+ continue;
+ return true;
+ });
+ return false;
+}
+
+#ifdef WITH_MAPME
+
+void *
+fib_entry_get_user_data(const fib_entry_t * entry)
+{
+ assert(entry);
+
+ return entry->user_data;
+}
+
+void
+fib_entry_set_user_data(fib_entry_t * entry, const void * user_data,
+ void (*user_data_release)(void **))
+{
+ assert(entry);
+ assert(user_data);
+ assert(user_data_release);
+
+ entry->user_data = (void *)user_data;
+ entry->user_data_release = user_data_release;
+}
+
+#endif /* WITH_MAPME */
diff --git a/hicn-light/src/hicn/core/fib_entry.h b/hicn-light/src/hicn/core/fib_entry.h
new file mode 100644
index 000000000..94d283d0f
--- /dev/null
+++ b/hicn-light/src/hicn/core/fib_entry.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file fib_entry.h
+ * @brief A forwarding entry in the FIB table
+ *
+ * A Forwarding Information Base (FIB) entry (fib_entry_t) is a
+ * set of nexthops for a name. It also indicates the forwarding strategy.
+ *
+ * Each nexthop contains the ConnectionId assocaited with it. This could be
+ * something specific like a MAC address or point-to-point tunnel. Or, it
+ * could be something general like a MAC group address or ip multicast overlay.
+ *
+ * See strategy.h for a description of forwarding strategies.
+ * In short, a strategy is the algorithm used to select one or more nexthops
+ * from the set of available nexthops.
+ *
+ * Each nexthop also contains a void* to a forwarding strategy data container.
+ * This allows a strategy to keep proprietary information about each nexthop.
+ *
+ *
+ */
+
+#ifndef fib_entry_h
+#define fib_entry_h
+
+#include <hicn/core/name.h>
+#include <hicn/core/strategy.h>
+#include <hicn/core/msgbuf.h>
+#include <hicn/core/nexthops.h>
+#include <hicn/core/prefix_stats.h>
+#include <hicn/utils/commands.h> // strategy type
+
+#ifdef WITH_MAPME
+//#include <parc/algol/parc_EventTimer.h>
+//#include <parc/algol/parc_Iterator.h>
+#endif /* WITH_MAPME */
+
+typedef struct {
+ Name *name;
+ unsigned refcount;
+ nexthops_t nexthops;
+ strategy_entry_t strategy;
+
+ const void * forwarder;
+
+#ifdef WITH_POLICY
+ policy_t policy;
+#endif /* WITH_POLICY */
+
+ prefix_counters_t prefix_counters;
+ prefix_stats_t prefix_stats;
+
+#ifdef WITH_MAPME
+ /* In case of no multipath, this stores the previous decision taken by policy. As the list of nexthops is not expected to change, we can simply store the flags */
+ uint_fast32_t prev_nexthops_flags;
+ void *user_data;
+ void (*user_data_release)(void **user_data);
+#endif /* WITH_MAPME */
+} fib_entry_t;
+
+#define _fib_entry_var(x) _fib_entry_##x
+
+#define fib_entry_strategy_type(fib_entry) ((fib_entry)->strategy.type)
+
+#define fib_entry_get_nexthops(fib_entry) (&(fib_entry)->nexthops)
+#define fib_entry_nexthops_len(fib_entry) (nexthops_len(&(fib_entry)->nexthops))
+#define fib_entry_nexthops_curlen(fib_entry) (nexthops_curlen(&(fib_entry)->nexthops))
+#define fib_entry_get_nexthop(fib_entry, i) ((fib_entry)->nexthops.elts[i])
+#define fib_entry_foreach_nexthop(fib_entry, nexthop, BODY) \
+ nexthops_foreach(fib_entry->nexthops, BODY)
+
+#define fib_entry_nexthops_changed(fib_entry) \
+ ((fib_entry)->prev_nexthops_flags == fib_entry_get_nexthops(fib_entry)->flags)
+
+#define fib_entry_set_prev_nexthops(fib_entry) \
+ ((fib_entry)->prev_nexthops_flags = fib_entry_get_nexthops(fib_entry)->flags)
+
+struct forwarder_s;
+fib_entry_t *fib_entry_create(Name *name, strategy_type_t strategy_type,
+ strategy_options_t * strategy_options, const struct forwarder_s * table);
+
+void fib_entry_set_strategy(fib_entry_t *fib_entry,
+ strategy_type_t strategy_type, strategy_options_t * strategy_options);
+
+void fib_entry_nexthops_add(fib_entry_t * fib_entry, unsigned nexthop);
+
+void fib_entry_nexthops_remove(fib_entry_t * fib_entry, unsigned nexthop);
+
+size_t fib_entry_NexthopCount(const fib_entry_t *fib_entry);
+
+/**
+ * @function fib_entry_nexthops_get
+ * @abstract Returns the nexthop set of the FIB entry. You must Acquire if it
+ * will be saved.
+ * @discussion
+ * Returns the next hop set for the FIB entry.
+ */
+const nexthops_t * fib_entry_nexthops_get(const fib_entry_t *fib_entry);
+
+const nexthops_t * fib_entry_nexthops_getFromForwardingStrategy(
+ fib_entry_t *fib_entry, const msgbuf_t *interest_msgbuf, bool is_retransmission);
+
+void fib_entry_on_data(fib_entry_t * fib_entry, const nexthops_t * nexthops,
+ const msgbuf_t * object_msgbuf, Ticks pit_entry_creation,
+ Ticks data_reception);
+
+#ifdef WITH_POLICY
+policy_t fib_entry_get_policy(const fib_entry_t *fib_entry);
+void fib_entry_reconsider_policy(fib_entry_t *fib_entry);
+void fib_entry_set_policy(fib_entry_t *fib_entry, policy_t policy);
+void fib_entry_update_stats(fib_entry_t *fib_entry, uint64_t now);
+#endif /* WITH_POLICY */
+
+nexthops_t * fib_entry_get_available_nexthops(fib_entry_t *fib_entry,
+ unsigned in_connection, nexthops_t * new_nexthops);
+void fib_entry_on_timeout(fib_entry_t *fib_entry, const nexthops_t *egressId);
+const nexthops_t * fib_entry_get_nexthops_from_strategy(fib_entry_t *fib_entry,
+ const msgbuf_t *interest_msgbuf, bool is_retransmission);
+
+/**
+ * @function fib_entry_get_prefix
+ * @abstract Returns a copy of the prefix.
+ * @return A reference counted copy that you must destroy
+ */
+Name *fib_entry_get_prefix(const fib_entry_t *fib_entry);
+
+bool fib_entry_has_local_nexthop(const fib_entry_t * entry);
+
+#ifdef WITH_MAPME
+
+/**
+ * @function fib_entry_get_user_data
+ * @abstract Returns user data associated to the FIB entry.
+ * @param [in] fib_entry - Pointer to the FIB entry.
+ * @return User data as a void pointer
+ */
+void *fib_entry_get_user_data(const fib_entry_t *fib_entry);
+
+/**
+ * @function fib_entry_get_user_data
+ * @abstract Associates user data and release callback to a FIB entry.
+ * @param [in] fib_entry - Pointer to the FIB entry.
+ * @param [in] user_data - Generic pointer to user data
+ * @param [in@ user_data_release - Callback used to release user data upon change
+ * of FIB entry removal.
+ */
+void fib_entry_set_user_data(fib_entry_t *fib_entry, const void *user_data,
+ void (*user_data_release)(void **));
+
+#endif /* WITH_MAPME */
+
+#endif // fib_entry_h
diff --git a/hicn-light/src/hicn/core/forwarder.c b/hicn-light/src/hicn/core/forwarder.c
index f7b0af2c2..f8e99198f 100644
--- a/hicn-light/src/hicn/core/forwarder.c
+++ b/hicn-light/src/hicn/core/forwarder.c
@@ -41,553 +41,1157 @@
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
-#include <parc/algol/parc_ArrayList.h>
-#include <parc/algol/parc_Memory.h>
-#include <parc/algol/parc_Object.h>
-#include <parc/logging/parc_LogReporterTextStdout.h>
-
-#include <hicn/core/connectionManager.h>
-#include <hicn/core/connectionTable.h>
-#include <hicn/core/dispatcher.h>
+#include <hicn/core/connection_table.h>
+#include <hicn/core/listener_table.h>
+#include <hicn/core/pit.h>
+#include <hicn/core/fib.h>
+#include <hicn/core/content_store.h>
#include <hicn/core/forwarder.h>
#include <hicn/core/messagePacketType.h>
#ifdef WITH_MAPME
#include <hicn/core/mapme.h>
#endif /* WITH_MAPME */
#include <hicn/config/configuration.h>
-#include <hicn/config/configurationFile.h>
-#include <hicn/config/configurationListeners.h>
-#include <hicn/processor/messageProcessor.h>
+#include <hicn/config/configuration_file.h>
+
+#ifdef WITH_PREFIX_STATS
+#include <hicn/core/prefix_stats.h>
+#endif /* WITH_PREFIX_STATS */
#include <hicn/core/wldr.h>
+#include <hicn/util/log.h>
-#include <parc/assert/parc_Assert.h>
+#define DEFAULT_PIT_SIZE 65535
-// the router's clock frequency (we now use the monotonic clock)
-#define HZ 1000
+typedef struct {
+ uint32_t countReceived;
+ uint32_t countInterestsReceived;
+ uint32_t countObjectsReceived;
-// these will all be a little off because its all integer division
-#define MSEC_PER_TICK (1000 / HZ)
-#define USEC_PER_TICK (1000000 / HZ)
-#define NSEC_PER_TICK ((1000000000ULL) / HZ)
-#define MSEC_TO_TICKS(msec) \
- ((msec < FC_MSEC_PER_TICK) ? 1 : msec / FC_MSEC_PER_TICK)
-#define NSEC_TO_TICKS(nsec) ((nsec < NSEC_PER_TICK) ? 1 : nsec / NSEC_PER_TICK)
+ uint32_t countInterestsAggregated;
-struct forwarder {
- Dispatcher *dispatcher;
+ uint32_t countDropped;
+ uint32_t countInterestsDropped;
+ uint32_t countDroppedNoRoute;
+ uint32_t countDroppedNoReversePath;
- uint16_t server_port;
+ uint32_t countDroppedConnectionNotFound;
+ uint32_t countObjectsDropped;
+ uint32_t countOtherDropped;
- PARCEventSignal *signal_int;
- PARCEventSignal *signal_term;
-#ifndef _WIN32
- PARCEventSignal *signal_usr1;
-#endif
- PARCEventTimer *keepalive_event;
+ uint32_t countSendFailures;
+ uint32_t countInterestForwarded;
+ uint32_t countObjectsForwarded;
+ uint32_t countInterestsSatisfiedFromStore;
- // will skew the virtual clock forward. In normal operaiton, it is 0.
- Ticks clockOffset;
+ uint32_t countDroppedNoHopLimit;
+ uint32_t countDroppedZeroHopLimitFromRemote;
+ uint32_t countDroppedZeroHopLimitToRemote;
+} forwarder_stats_t;
- unsigned nextConnectionid;
- Messenger *messenger;
- ConnectionManager *connectionManager;
- ConnectionTable *connectionTable;
- ListenerSet *listenerSet;
- Configuration *config;
+struct forwarder_s {
+// uint16_t server_port;
- // we'll eventually want to setup a threadpool of these
- MessageProcessor *processor;
+// XXX TODO signal handling
+#if 0
+ PARCEventSignal *signal_int;
+ PARCEventSignal *signal_term;
+#ifndef _WIN32
+ PARCEventSignal *signal_usr1;
+#endif
+#endif
- Logger *logger;
+ // used by seed48 and nrand48
+ unsigned short seed[3];
- PARCClock *clock;
+ connection_table_t * connection_table;
+ listener_table_t * listener_table;
+ configuration_t *config;
-#if !defined(__APPLE__)
- hicn_socket_helper_t
- *hicnSocketHelper; // state required to manage hicn connections
-#endif
- // used by seed48 and nrand48
- unsigned short seed[3];
+
+ pit_t * pit;
+ content_store_t * content_store;
+ fib_t * fib;
#ifdef WITH_MAPME
- MapMe *mapme;
+ mapme_t * mapme;
#endif /* WITH_MAPME */
+
+ bool store_in_content_store;
+ bool serve_from_content_store;
+
+ forwarder_stats_t stats;
+#ifdef WITH_PREFIX_STATS
+ prefix_stats_mgr_t prefix_stats_mgr;
+#endif /* WITH_PREFIX_STATS */
+
+ /*
+ * The message forwarder has to decide whether to queue incoming packets for
+ * batching, or trigger the transmission on the connection
+ */
+ unsigned pending_conn[MAX_MSG];
+ size_t num_pending_conn;
+
+ msgbuf_t msgbuf; /* Storage for msgbuf, which are currently processed 1 by 1 */
+
};
+#if 0
// signal traps through the event scheduler
static void _signal_cb(int, PARCEventType, void *);
-
-// A no-op keepalive to prevent Libevent from exiting the dispatch loop
-static void _keepalive_cb(int, PARCEventType, void *);
+#endif
/**
* Reseed our pseudo-random number generator.
*/
-static void forwarder_Seed(Forwarder *forwarder) {
+static
+void
+forwarder_seed(forwarder_t * forwarder) {
#ifndef _WIN32
- int fd;
- ssize_t res;
-
- res = -1;
- fd = open("/dev/urandom", O_RDONLY);
- if (fd != -1) {
- res = read(fd, forwarder->seed, sizeof(forwarder->seed));
- close(fd);
- }
- if (res != sizeof(forwarder->seed)) {
+ int fd;
+ ssize_t res;
+
+ res = -1;
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd != -1) {
+ res = read(fd, forwarder->seed, sizeof(forwarder->seed));
+ close(fd);
+ }
+ if (res != sizeof(forwarder->seed)) {
+ forwarder->seed[1] = (unsigned short)getpid(); /* better than no entropy */
+ forwarder->seed[2] = (unsigned short)time(NULL);
+ }
+ /*
+ * The call to seed48 is needed by cygwin, and should be harmless
+ * on other platforms.
+ */
+ seed48(forwarder->seed);
+#else
forwarder->seed[1] = (unsigned short)getpid(); /* better than no entropy */
forwarder->seed[2] = (unsigned short)time(NULL);
- }
- /*
- * The call to seed48 is needed by cygwin, and should be harmless
- * on other platforms.
- */
- seed48(forwarder->seed);
-#else
- forwarder->seed[1] = (unsigned short)getpid(); /* better than no entropy */
- forwarder->seed[2] = (unsigned short)time(NULL);
#endif
}
-Logger *forwarder_GetLogger(const Forwarder *forwarder) {
- return forwarder->logger;
-}
-
-// ============================================================================
-// Setup and destroy section
+int
+init_batch_buffers(batch_buffer_t * bb)
+{
+ /* Setup recvmmsg data structures. */
+ for (unsigned i = 0; i < MAX_MSG; i++) {
+ char *buf = &bb->buffers[i][0];
+ struct iovec *iovec = &bb->iovecs[i];
+ struct mmsghdr *msg = &bb->msghdr[i];
-Forwarder *forwarder_Create(Logger *logger) {
- Forwarder *forwarder = parcMemory_AllocateAndClear(sizeof(Forwarder));
- parcAssertNotNull(forwarder, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(Forwarder));
- memset(forwarder, 0, sizeof(Forwarder));
- forwarder_Seed(forwarder);
+ msg->msg_hdr.msg_iov = iovec;
+ msg->msg_hdr.msg_iovlen = 1;
- forwarder->clock = parcClock_Monotonic();
- forwarder->clockOffset = 0;
+ msg->msg_hdr.msg_name = &bb->addrs[i];
+ msg->msg_hdr.msg_namelen = sizeof(struct sockaddr_storage);
- if (logger) {
- forwarder->logger = logger_Acquire(logger);
- logger_SetClock(forwarder->logger, forwarder->clock);
- } else {
- PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
- forwarder->logger = logger_Create(reporter, forwarder->clock);
- parcLogReporter_Release(&reporter);
+ iovec->iov_base = &buf[0];
+ iovec->iov_len = MTU;
}
+ return 0;
+}
- forwarder->nextConnectionid = 1;
- forwarder->dispatcher = dispatcher_Create(forwarder->logger);
- forwarder->messenger = messenger_Create(forwarder->dispatcher);
- forwarder->connectionManager = connectionManager_Create(forwarder);
- forwarder->connectionTable = connectionTable_Create();
- forwarder->listenerSet = listenerSet_Create();
- forwarder->config = configuration_Create(forwarder);
- forwarder->processor = messageProcessor_Create(forwarder);
-
- forwarder->signal_term = dispatcher_CreateSignalEvent(
- forwarder->dispatcher, _signal_cb, forwarder, SIGTERM);
- dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_term);
-
- forwarder->signal_int = dispatcher_CreateSignalEvent(
- forwarder->dispatcher, _signal_cb, forwarder, SIGINT);
- dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_int);
+forwarder_t *
+forwarder_create()
+{
+ forwarder_t * forwarder = malloc(sizeof(forwarder_t));
+ if (!forwarder)
+ goto ERR_MALLOC;
+
+ forwarder_seed(forwarder);
+
+ forwarder->config = configuration_create(forwarder);
+ if (!forwarder->config)
+ goto ERR_CONFIG;
+
+ forwarder->listener_table = listener_table_create();
+ if (!forwarder->listener_table)
+ goto ERR_LISTENER_TABLE;
+
+ forwarder->connection_table = connection_table_create();
+ if (!forwarder->connection_table)
+ goto ERR_CONNECTION_TABLE;
+
+ forwarder->fib = fib_create(forwarder);
+ if (!forwarder->fib)
+ goto ERR_FIB;
+
+ forwarder->pit = pit_create(DEFAULT_PIT_SIZE);
+ if (!forwarder->pit)
+ goto ERR_PIT;
+
+ size_t objectStoreSize =
+ configuration_content_store_get_size(forwarder_get_configuration(forwarder));
+ forwarder->content_store = content_store_create(CONTENT_STORE_TYPE_LRU,
+ objectStoreSize);
+ if (!forwarder->content_store)
+ goto ERR_CONTENT_STORE;
+
+ // the two flags for the content_store are set to true by default. If the content_store
+ // is active it always work as expected unless the use modifies this
+ // values using controller
+ forwarder->store_in_content_store = true;
+ forwarder->serve_from_content_store = true;
+
+#if 0
+ forwarder->signal_term = dispatcher_CreateSignalEvent(
+ forwarder->dispatcher, _signal_cb, forwarder, SIGTERM);
+ dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_term);
+
+ forwarder->signal_int = dispatcher_CreateSignalEvent(
+ forwarder->dispatcher, _signal_cb, forwarder, SIGINT);
+ dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_int);
#ifndef _WIN32
- forwarder->signal_usr1 = dispatcher_CreateSignalEvent(
- forwarder->dispatcher, _signal_cb, forwarder, SIGPIPE);
- dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_usr1);
+ forwarder->signal_usr1 = dispatcher_CreateSignalEvent(
+ forwarder->dispatcher, _signal_cb, forwarder, SIGPIPE);
+ dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_usr1);
+#endif
#endif
-
-#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && \
- defined(PUNTING)
- forwarder->hicnSocketHelper = hicn_create();
- if (!forwarder->hicnSocketHelper)
- goto ERR_SOCKET;
-#endif /* __APPLE__ */
#ifdef WITH_MAPME
- if (!(mapme_create(&forwarder->mapme, forwarder)))
- goto ERR_MAPME;
+ forwarder->mapme = mapme_create(forwarder);
+ if (!forwarder->mapme)
+ goto ERR_MAPME;
#endif /* WITH_MAPME */
- /* ignore child */
+ /* ignore child */
#ifndef _WIN32
- signal(SIGCHLD, SIG_IGN);
+ signal(SIGCHLD, SIG_IGN);
- /* ignore tty signals */
- signal(SIGTSTP, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
- signal(SIGTTIN, SIG_IGN);
+ /* ignore tty signals */
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
#endif
- // We no longer use this for ticks, but we need to have at least one event
- // schedule to keep Libevent happy.
-
- struct timeval wtnow_timeout;
- timerclear(&wtnow_timeout);
+#ifdef WITH_PREFIX_STATS
+ if (prefix_stats_mgr_initialize(&forwarder->prefix_stats_mgr, forwarder) < 0)
+ goto ERR_MGR;
+#endif /* WITH_PREFIX_STATS */
- wtnow_timeout.tv_sec = 0;
- wtnow_timeout.tv_usec = 50000; // 20 Hz keepalive
-
- PARCEventScheduler *base =
- dispatcher_GetEventScheduler(forwarder->dispatcher);
- forwarder->keepalive_event = parcEventTimer_Create(
- base, PARCEventType_Persist, _keepalive_cb, (void *)forwarder);
- parcEventTimer_Start(forwarder->keepalive_event, &wtnow_timeout);
-
- return forwarder;
+ return forwarder;
+ERR_MGR:
#ifdef WITH_MAPME
ERR_MAPME:
#endif /* WITH_MAPME */
-#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && \
- defined(PUNTING)
- hicn_free(forwarder->hicnSocketHelper);
-ERR_SOCKET:
-#endif
- listenerSet_Destroy(&(forwarder->listenerSet));
- connectionManager_Destroy(&(forwarder->connectionManager));
- connectionTable_Destroy(&(forwarder->connectionTable));
- messageProcessor_Destroy(&(forwarder->processor));
- configuration_Destroy(&(forwarder->config));
- messenger_Destroy(&(forwarder->messenger));
-
- dispatcher_DestroySignalEvent(forwarder->dispatcher,
- &(forwarder->signal_int));
- dispatcher_DestroySignalEvent(forwarder->dispatcher,
- &(forwarder->signal_term));
+
+#if 0
+ dispatcher_DestroySignalEvent(forwarder->dispatcher,
+ &(forwarder->signal_int));
+ dispatcher_DestroySignalEvent(forwarder->dispatcher,
+ &(forwarder->signal_term));
#ifndef _WIN32
- dispatcher_DestroySignalEvent(forwarder->dispatcher,
- &(forwarder->signal_usr1));
+ dispatcher_DestroySignalEvent(forwarder->dispatcher,
+ &(forwarder->signal_usr1));
#endif
- parcClock_Release(&forwarder->clock);
- logger_Release(&forwarder->logger);
-
- // do the dispatcher last
- dispatcher_Destroy(&(forwarder->dispatcher));
+ // do the dispatcher last
+ dispatcher_Destroy(&(forwarder->dispatcher));
+#endif
- parcMemory_Deallocate((void **)&forwarder);
- return NULL;
+ content_store_free(forwarder->content_store);
+ERR_CONTENT_STORE:
+ pit_free(forwarder->pit);
+ERR_PIT:
+ fib_free(forwarder->fib);
+ERR_FIB:
+ connection_table_free(forwarder->connection_table);
+ERR_CONNECTION_TABLE:
+ listener_table_free(forwarder->listener_table);
+ERR_LISTENER_TABLE:
+ configuration_free(forwarder->config);
+ERR_CONFIG:
+ free(forwarder);
+ERR_MALLOC:
+ return NULL;
}
-void forwarder_Destroy(Forwarder **ptr) {
- parcAssertNotNull(ptr, "Parameter must be non-null double pointer");
- parcAssertNotNull(*ptr, "Parameter must dereference to non-null pointer");
- Forwarder *forwarder = *ptr;
-#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && \
- defined(PUNTING)
- hicn_free(forwarder->hicnSocketHelper);
-#endif
- parcEventTimer_Destroy(&(forwarder->keepalive_event));
-
- listenerSet_Destroy(&(forwarder->listenerSet));
- connectionManager_Destroy(&(forwarder->connectionManager));
- connectionTable_Destroy(&(forwarder->connectionTable));
- messageProcessor_Destroy(&(forwarder->processor));
- configuration_Destroy(&(forwarder->config));
+void
+forwarder_free(forwarder_t * forwarder)
+{
+ assert(forwarder);
- // the messenger is used by many of the other pieces, so destroy it last
- messenger_Destroy(&(forwarder->messenger));
+ prefix_stats_mgr_finalize(&forwarder->prefix_stats_mgr);
#ifdef WITH_MAPME
- mapme_free(forwarder->mapme);
+ mapme_free(forwarder->mapme);
#endif /* WITH_MAPME */
- dispatcher_DestroySignalEvent(forwarder->dispatcher,
- &(forwarder->signal_int));
- dispatcher_DestroySignalEvent(forwarder->dispatcher,
- &(forwarder->signal_term));
+#if 0
+ dispatcher_DestroySignalEvent(forwarder->dispatcher,
+ &(forwarder->signal_int));
+ dispatcher_DestroySignalEvent(forwarder->dispatcher,
+ &(forwarder->signal_term));
#ifndef _WIN32
- dispatcher_DestroySignalEvent(forwarder->dispatcher,
- &(forwarder->signal_usr1));
+ dispatcher_DestroySignalEvent(forwarder->dispatcher,
+ &(forwarder->signal_usr1));
#endif
- parcClock_Release(&forwarder->clock);
- logger_Release(&forwarder->logger);
-
- // do the dispatcher last
- dispatcher_Destroy(&(forwarder->dispatcher));
+ // do the dispatcher last
+ dispatcher_Destroy(&(forwarder->dispatcher));
+#endif
- parcMemory_Deallocate((void **)&forwarder);
- *ptr = NULL;
+ content_store_free(forwarder->content_store);
+ pit_free(forwarder->pit);
+ fib_free(forwarder->fib);
+ connection_table_free(forwarder->connection_table);
+ listener_table_free(forwarder->listener_table);
+ configuration_free(forwarder->config);
+ free(forwarder);
}
-void forwarder_SetupAllListeners(Forwarder *forwarder, uint16_t port,
- const char *localPath) {
- parcAssertNotNull(forwarder, "Parameter must be non-null");
+void
+forwarder_setup_all_listeners(forwarder_t * forwarder, uint16_t port,
+ const char * local_path)
+{
+ assert(forwarder);
+ assert(local_path);
- configurationListeners_SetupAll(forwarder->config, port, localPath);
+ listener_setup_all(forwarder, port, local_path);
}
-void forwarder_SetupLocalListeners(Forwarder *forwarder, uint16_t port) {
- parcAssertNotNull(forwarder, "Parameter must be non-null");
- configurationListeners_SetutpLocalIPv4(forwarder->config, port);
+void
+forwarder_setup_local_listeners(forwarder_t * forwarder, uint16_t port)
+{
+ assert(forwarder);
+ listener_setup_local_ipv4(forwarder, port);
}
-void forwarder_SetupFromConfigFile(Forwarder *forwarder, const char *filename) {
- ConfigurationFile *configFile = configurationFile_Create(forwarder, filename);
- if (configFile) {
- configurationFile_Process(configFile);
- configurationFile_Release(&configFile);
- }
-}
+void
+forwarder_read_config(forwarder_t * forwarder, const char * filename)
+{
+ configuration_file_t *cfg = configuration_file_create(forwarder, filename);
+ if (!cfg)
+ return;
-Configuration *forwarder_GetConfiguration(Forwarder *forwarder) {
- parcAssertNotNull(forwarder, "Parameter must be non-null");
- return forwarder->config;
+ configuration_file_process(cfg);
+ configuration_file_free(cfg);
}
-// ============================================================================
+configuration_t *
+forwarder_get_configuration(forwarder_t * forwarder)
+{
+ assert(forwarder);
+ return forwarder->config;
+}
-unsigned forwarder_GetNextConnectionId(Forwarder *forwarder) {
- parcAssertNotNull(forwarder, "Parameter must be non-null");
- return forwarder->nextConnectionid++;
+connection_table_t *
+forwarder_get_connection_table(const forwarder_t * forwarder)
+{
+ assert(forwarder);
+ return forwarder->connection_table;
}
-Messenger *forwarder_GetMessenger(Forwarder *forwarder) {
- parcAssertNotNull(forwarder, "Parameter must be non-null");
- return forwarder->messenger;
+listener_table_t *
+forwarder_get_listener_table(forwarder_t * forwarder)
+{
+ assert(forwarder);
+ return forwarder->listener_table;
}
-Dispatcher *forwarder_GetDispatcher(Forwarder *forwarder) {
- parcAssertNotNull(forwarder, "Parameter must be non-null");
- return forwarder->dispatcher;
+void
+forwarder_content_store_set_store(forwarder_t * forwarder, bool val)
+{
+ assert(forwarder);
+ forwarder->store_in_content_store = val;
}
-#ifdef WITH_POLICY
-ConnectionTable *forwarder_GetConnectionTable(const Forwarder *forwarder) {
-#else
-ConnectionTable *forwarder_GetConnectionTable(Forwarder *forwarder) {
-#endif /* WITH_POLICY */
- parcAssertNotNull(forwarder, "Parameter must be non-null");
- return forwarder->connectionTable;
+bool
+forwarder_content_store_get_store(forwarder_t * forwarder)
+{
+ assert(forwarder);
+ return forwarder->store_in_content_store;
}
-ListenerSet *forwarder_GetListenerSet(Forwarder *forwarder) {
- parcAssertNotNull(forwarder, "Parameter must be non-null");
- return forwarder->listenerSet;
+void
+forwarder_content_store_set_serve(forwarder_t * forwarder, bool val)
+{
+ assert(forwarder);
+ forwarder->serve_from_content_store = val;
}
-void forwarder_SetChacheStoreFlag(Forwarder *forwarder, bool val) {
- parcAssertNotNull(forwarder, "Parameter must be non-null");
- messageProcessor_SetCacheStoreFlag(forwarder->processor, val);
+bool
+forwarder_content_store_get_serve(forwarder_t * forwarder)
+{
+ assert(forwarder);
+ return forwarder->serve_from_content_store;
}
-bool forwarder_GetChacheStoreFlag(Forwarder *forwarder) {
- parcAssertNotNull(forwarder, "Parameter must be non-null");
- return messageProcessor_GetCacheStoreFlag(forwarder->processor);
+void
+forwarder_content_store_set_size(forwarder_t * forwarder, size_t size)
+{
+ assert(forwarder);
+
+ content_store_free(forwarder->content_store);
+
+ // XXX TODO
+#if 0
+ ContentStoreConfig content_storeConfig = {.objectCapacity =
+ maximumContentStoreSize};
+
+ forwarder->content_store =
+ content_storeLRU_Create(&content_storeConfig, forwarder->logger);
+#endif
}
-void forwarder_SetChacheServeFlag(Forwarder *forwarder, bool val) {
- parcAssertNotNull(forwarder, "Parameter must be non-null");
- messageProcessor_SetCacheServeFlag(forwarder->processor, val);
+void
+forwarder_content_store_clear(forwarder_t * forwarder)
+{
+ assert(forwarder);
+
+ content_store_clear(forwarder->content_store);
}
-bool forwarder_GetChacheServeFlag(Forwarder *forwarder) {
- parcAssertNotNull(forwarder, "Parameter must be non-null");
- return messageProcessor_GetCacheServeFlag(forwarder->processor);
+void
+forwarder_receive_command(forwarder_t * forwarder, command_type_t command_type,
+ uint8_t * packet, unsigned connection_id)
+{
+ configuration_receive_command(forwarder->config, command_type, packet, connection_id);
}
-void forwarder_ReceiveCommand(Forwarder *forwarder, command_id command,
- struct iovec *message, unsigned ingressId) {
- configuration_ReceiveCommand(forwarder->config, command, message, ingressId);
+/**
+ * @function forwarder_Drop
+ * @abstract Whenever we "drop" a message, increment countes
+ * @discussion
+ * This is a bookkeeping function. It increments the appropriate counters.
+ *
+ * The default action for a message is to destroy it in
+ * <code>forwarder_Receive()</code>, so this function does not need to do
+ * that.
+ *
+ */
+static
+void
+forwarder_drop(forwarder_t * forwarder, msgbuf_t *message)
+{
+ forwarder->stats.countDropped++;
+
+ switch (msgbuf_get_type(message)) {
+ case MESSAGE_TYPE_INTEREST:
+ forwarder->stats.countInterestsDropped++;
+ break;
+
+ case MESSAGE_TYPE_DATA:
+ forwarder->stats.countObjectsDropped++;
+ break;
+
+ default:
+ forwarder->stats.countOtherDropped++;
+ break;
+ }
+
+ // dont destroy message here, its done at end of receive
}
-void forwarder_Receive(Forwarder *forwarder, Message *message) {
- parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
- parcAssertNotNull(message, "Parameter message must be non-null");
+/*
+ * If the hoplimit is equal to 0, then we may only forward it to local
+ * applications. Otherwise, we may forward it off the system.
+ *
+ */
+static
+void
+forwarder_forward_via_connection(forwarder_t * forwarder, msgbuf_t * msgbuf,
+ unsigned conn_id)
+{
+ connection_table_t * table = forwarder_get_connection_table(forwarder);
+ const connection_t * conn = connection_table_get_by_id(table, conn_id);
+
+ if (!conn) {
+ forwarder->stats.countDroppedConnectionNotFound++;
+ DEBUG("forward msgbuf %p to interface %u not found (count %u)",
+ msgbuf, conn_id, forwarder->stats.countDroppedConnectionNotFound);
+ forwarder_drop(forwarder, msgbuf);
+ return;
+ }
- // this takes ownership of the message, so we're done here
+ /* Always queue the packet... */
+ bool success = connection_send(conn, msgbuf, true);
- // this are the checks needed to implement WLDR. We set wldr only on the STAs
- // and we let the AP to react according to choise of the client.
- // if the STA enables wldr using the set command, the AP enable wldr as well
- // otherwise, if the STA disable it the AP remove wldr
- // WLDR should be enabled only on the STAs using the command line
- // TODO
- // disable WLDR command line on the AP
- const Connection *conn = connectionTable_FindById(
- forwarder->connectionTable, message_GetIngressConnectionId(message));
+ /* ... and mark the connection as pending if this is not yet the case */
+ unsigned i;
+ for (i = 0; i < forwarder->num_pending_conn; i++) {
+ if (forwarder->pending_conn[i] == conn_id)
+ break;
+ }
+ if (i == forwarder->num_pending_conn)
+ forwarder->pending_conn[forwarder->num_pending_conn++] = conn_id;
- if (!conn) {
- return;
- }
+ if (!success) {
+ forwarder->stats.countSendFailures++;
- if (message_HasWldr(message)) {
- if (connection_HasWldr(conn)) {
- // case 1: WLDR is enabled
- connection_DetectLosses((Connection *)conn, message);
- } else if (!connection_HasWldr(conn) &&
- connection_WldrAutoStartAllowed(conn)) {
- // case 2: We are on an AP. We enable WLDR
- connection_EnableWldr((Connection *)conn);
- connection_DetectLosses((Connection *)conn, message);
+ DEBUG("forward msgbuf %p to interface %u send failure (count %u)", msgbuf,
+ conn_id, forwarder->stats.countSendFailures);
+ forwarder_drop(forwarder, msgbuf);
+ return;
}
- // case 3: Ignore WLDR
- } else {
- if (connection_HasWldr(conn) && connection_WldrAutoStartAllowed(conn)) {
- // case 1: STA do not use WLDR, we disable it
- connection_DisableWldr((Connection *)conn);
+
+ switch (msgbuf_get_type(msgbuf)) {
+ case MESSAGE_TYPE_INTEREST:
+ forwarder->stats.countInterestForwarded++;
+ break;
+
+ case MESSAGE_TYPE_DATA:
+ forwarder->stats.countObjectsForwarded++;
+ break;
+
+ default:
+ break;
}
- }
- messageProcessor_Receive(forwarder->processor, message);
+ DEBUG("forward msgbuf %p to interface %u (int %u, obj %u)", msgbuf,
+ conn_id, forwarder->stats.countInterestForwarded,
+ forwarder->stats.countObjectsForwarded);
+
}
-Ticks forwarder_GetTicks(const Forwarder *forwarder) {
- parcAssertNotNull(forwarder, "Parameter must be non-null");
- return parcClock_GetTime(forwarder->clock) + forwarder->clockOffset;
+/**
+ * @function forwarder_forward_to_nexthops
+ * @abstract Try to forward to each nexthop listed in the NumberSet
+ * @discussion
+ * Will not forward to the ingress connection.
+ *
+ * @return The number of nexthops tried
+ */
+static
+unsigned
+forwarder_forward_to_nexthops(forwarder_t * forwarder,
+ msgbuf_t *msgbuf, const nexthops_t * nexthops)
+{
+ unsigned forwardedCopies = 0;
+
+ unsigned ingressId = msgbuf_get_connection_id(msgbuf);
+ uint32_t old_path_label = 0;
+
+ if (msgbuf_get_type(msgbuf) == MESSAGE_TYPE_DATA)
+ old_path_label = msgbuf_get_pathlabel(msgbuf);
+
+ unsigned nexthop;
+ nexthops_foreach(nexthops, nexthop, {
+ if (nexthop == ingressId)
+ continue;
+
+ forwardedCopies++;
+ forwarder_forward_via_connection(forwarder, msgbuf, nexthop);
+
+ // everytime we send out a message we need to restore the original path
+ // label of the message this is important because we keep a single copy
+ // of the message (single pointer) and we modify the path label at each
+ // send.
+ if (msgbuf_get_type(msgbuf) == MESSAGE_TYPE_DATA)
+ msgbuf_set_pathlabel(msgbuf, old_path_label);
+ });
+
+ return forwardedCopies;
}
-Ticks forwarder_NanosToTicks(uint64_t nanos) { return NSEC_TO_TICKS(nanos); }
-uint64_t forwarder_TicksToNanos(Ticks ticks) {
- return (1000000000ULL) * ticks / HZ;
-}
+static
+bool
+forwarder_forward_via_fib(forwarder_t * forwarder, msgbuf_t *msgbuf,
+ pit_verdict_t verdict)
+{
+ assert(forwarder);
+ assert(msgbuf);
+ assert(msgbuf_get_type(msgbuf) == MESSAGE_TYPE_INTEREST);
+
+ fib_entry_t *fib_entry = fib_match_message(forwarder->fib, msgbuf);
+ if (!fib_entry)
+ return false;
+
+ // XXX TODO PROBE HOOK MIGHT BE HANDLED ELSEWHERE
+ if (msgbuf_is_probe(msgbuf)) {
+ connection_table_t * table = forwarder_get_connection_table(forwarder);
+ const nexthops_t * nexthops = fib_entry_get_nexthops(fib_entry);
+
+ unsigned nexthop;
+ nexthops_foreach(nexthops, nexthop, {
+ connection_t * conn = connection_table_at(table, nexthop);
+ if (!conn)
+ continue;
+ if (!connection_is_local(conn))
+ continue;
+ uint8_t * packet = msgbuf_get_packet(msgbuf);
+ unsigned size = msgbuf_get_len(msgbuf);
+ connection_t * reply_connection = connection_table_get_by_id(table,
+ msgbuf_get_connection_id(msgbuf));
+ if (messageHandler_IsInterest(packet)) {
+ messageHandler_CreateProbeReply(packet, HF_INET6_TCP);
+ connection_send_packet(reply_connection, packet, size);
+ }
+ return false;
+ });
+ }
+
+ pit_entry_t * entry = pit_lookup(forwarder->pit, msgbuf);
+ if (!entry)
+ return false;
+
+ pit_entry_set_fib_entry(entry, fib_entry);
-bool forwarder_AddOrUpdateRoute(Forwarder *forwarder,
- add_route_command *control, unsigned ifidx) {
- parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
- parcAssertNotNull(control, "Parameter route must be non-null");
+ const nexthops_t * nexthops = fib_entry_get_nexthops_from_strategy(fib_entry,
+ msgbuf, verdict);
- // we only have one message processor
- bool res =
- messageProcessor_AddOrUpdateRoute(forwarder->processor, control, ifidx);
+ unsigned nexthop;
+ nexthops_foreach(nexthops, nexthop, {
+ pit_entry_egress_add(entry, nexthop);
+ });
+
+ // this requires some additional checks. It may happen that some of the output
+ // faces selected by the forwarding strategy are not usable. So far all the
+ // forwarding strategy return only valid faces (or an empty list)
+
+#if 0
+ // The function GetPitEntry encreases the ref counter in the pit entry
+ // we need to decrease it
+ entry_Release(&entry);
+#endif
+
+ if (forwarder_forward_to_nexthops(forwarder, msgbuf, nexthops) <= 0) {
+ DEBUG("Message %p returned an emtpy next hop set", msgbuf);
+ return false;
+ }
+ return true;
- return res;
}
-bool forwarder_RemoveRoute(Forwarder *forwarder, remove_route_command *control,
- unsigned ifidx) {
- parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
- parcAssertNotNull(control, "Parameter route must be non-null");
+static
+bool
+_satisfy_from_content_store(forwarder_t * forwarder, msgbuf_t *interest_msgbuf)
+{
+ assert(forwarder);
+ assert(msgbuf_get_type(msgbuf) == MESSAGE_TYPE_INTEREST);
+
+ if (msgbuf_get_interest_lifetime(interest_msgbuf) == 0)
+ return false;
+
+ if (!forwarder->serve_from_content_store)
+ return false;
+
+ // See if there's a match in the store.
+ msgbuf_t * data_msgbuf = content_store_match(forwarder->content_store,
+ interest_msgbuf, ticks_now());
+
+ if (!data_msgbuf)
+ return false;
+
+ // Remove it from the PIT. nexthops is allocated, so need to destroy
+ nexthops_t * nexthops = pit_on_data(forwarder->pit, data_msgbuf);
+ assert(nexthops); // Illegal state: got a null nexthops for an interest we just inserted
+
+ // send message in reply, then done
+ forwarder->stats.countInterestsSatisfiedFromStore++;
+
+ DEBUG("Message %p satisfied from content store (satisfied count %u)",
+ interest_msgbuf, forwarder->stats.countInterestsSatisfiedFromStore);
- // we only have one message processor
- return messageProcessor_RemoveRoute(forwarder->processor, control, ifidx);
+ msgbuf_reset_pathlabel(data_msgbuf);
+
+ forwarder_forward_to_nexthops(forwarder, data_msgbuf, nexthops);
+
+ return true;
}
-#ifdef WITH_POLICY
+/**
+ * @function forwarder_receive_interest
+ * @abstract Receive an interest from the network
+ * @discussion
+ * (1) if interest in the PIT, aggregate in PIT
+ * (2) if interest in the ContentStore, reply
+ * (3) if in the FIB, forward
+ * (4) drop
+ *
+ */
+static
+void
+forwarder_receive_interest(forwarder_t * forwarder, msgbuf_t * msgbuf)
+{
+ assert(forwarder);
+ assert(msgbuf);
+ assert(msgbuf_get_type(msgbuf) == MESSAGE_TYPE_INTEREST);
+ forwarder->stats.countInterestsReceived++;
+
+ // (1) Try to aggregate in PIT
+ pit_verdict_t verdict = pit_on_interest(forwarder->pit, msgbuf);
+ switch(verdict) {
+ case PIT_VERDICT_AGGREGATE:
+ forwarder->stats.countInterestsAggregated++;
+ DEBUG("Message %p aggregated in PIT (aggregated count %u)",
+ msgbuf, forwarder->stats.countInterestsAggregated);
+ return;
+
+ case PIT_VERDICT_FORWARD:
+ case PIT_VERDICT_RETRANSMIT:
+ DEBUG("Message %p not aggregated in PIT (aggregated count %u)",
+ msgbuf, forwarder->stats.countInterestsAggregated);
+ break;
+ }
+
+ // At this point, we just created a PIT entry. If we don't forward the
+ // interest, we need to remove the PIT entry.
-bool forwarder_AddOrUpdatePolicy(Forwarder *forwarder,
- add_policy_command *control) {
- parcAssertNotNull(forwarder, "Parameter forwarder must be non-null");
- parcAssertNotNull(control, "Parameter control must be non-null");
+ // (2) Try to satisfy from content store
+ if (_satisfy_from_content_store(forwarder, msgbuf)) {
+ // done
+ // If we found a content object in the CS,
+ // messageProcess_Satisfy_from_content_store already cleared the PIT state
+ return;
+ }
+
+ // (3) Try to forward it
+ if (forwarder_forward_via_fib(forwarder, msgbuf, verdict)) {
+ // done
+ return;
+ }
- return messageProcessor_AddOrUpdatePolicy(forwarder->processor, control);
+ // Remove the PIT entry?
+ forwarder->stats.countDroppedNoRoute++;
+
+ DEBUG("Message %p did not match FIB, no route (count %u)",
+ msgbuf, forwarder->stats.countDroppedNoRoute);
+
+ forwarder_drop(forwarder, msgbuf);
}
-bool forwarder_RemovePolicy(Forwarder *forwarder, remove_policy_command *control) {
- parcAssertNotNull(forwarder, "Parameter forwarder must be non-null");
- parcAssertNotNull(control, "Parameter control must be non-null");
+/**
+ * @function forwarder_receive_data
+ * @abstract Process an in-bound content object
+ * @discussion
+ * (1) If it does not match anything in the PIT, drop it
+ * (2) Add to Content Store
+ * (3) Reverse path forward via PIT entries
+ *
+ * @param <#param1#>
+ */
+static
+void
+forwarder_receive_data(forwarder_t * forwarder,
+ msgbuf_t *msgbuf)
+{
+ forwarder->stats.countObjectsReceived++;
+
+ nexthops_t * ingressSetUnion = pit_on_data(forwarder->pit, msgbuf);
+ if (!ingressSetUnion) {
+ // (1) If it does not match anything in the PIT, drop it
+ forwarder->stats.countDroppedNoReversePath++;
+
+ DEBUG("Message %p did not match PIT, no reverse path (count %u)",
+ msgbuf, forwarder->stats.countDroppedNoReversePath);
+
+ // MOVE PROBE HOOK ELSEWHERE
+ // XXX relationship with forwarding strategy... insert hooks
+ // if the packet is a probe we need to analyze it
+ // NOTE : probes are not stored in PIT
+ if (msgbuf_is_probe(msgbuf)) {
+ fib_entry_t *entry = fib_match_message(forwarder->fib, msgbuf);
+ if (entry && fib_entry_strategy_type(entry) == STRATEGY_TYPE_LOW_LATENCY) {
+ nexthops_t probe_nexthops;
+ nexthops_add(&probe_nexthops, msgbuf_get_connection_id(msgbuf));
+ fib_entry_on_data(entry, &probe_nexthops, msgbuf, 0, ticks_now());
+
+ // XXX TODO CONFIRM WE DON'T EXIT HERE ?
+ }
+ }
+
+ // we store the packets in the content store enven in the case where there
+ // is no match in the PIT table in this way the applications can push the
+ // content in the CS of the forwarder. We allow this only for local faces
+ const connection_table_t * table = forwarder_get_connection_table(forwarder);
+ const connection_t * conn = connection_table_get_by_id(table, msgbuf_get_connection_id(msgbuf));
+
+ if (forwarder->store_in_content_store && connection_is_local(conn)) {
+ content_store_add(forwarder->content_store, msgbuf, ticks_now());
+ DEBUG("Message %p store in CS anyway", msgbuf);
+ }
+
+ forwarder_drop(forwarder, msgbuf);
+ } else {
+ // (2) Add to Content Store. Store may remove expired content, if necessary,
+ // depending on store policy.
+ if (forwarder->store_in_content_store) {
+ content_store_add(forwarder->content_store, msgbuf, ticks_now());
+ }
+ // (3) Reverse path forward via PIT entries
+ forwarder_forward_to_nexthops(forwarder, msgbuf, ingressSetUnion);
- return messageProcessor_RemovePolicy(forwarder->processor, control);
+ }
}
-#endif /* WITH_POLICY */
-void forwarder_RemoveConnectionIdFromRoutes(Forwarder *forwarder,
- unsigned connectionId) {
- parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
- messageProcessor_RemoveConnectionIdFromRoutes(forwarder->processor,
- connectionId);
+/**
+ * A NULL msgbuf is used to indicate the end of a batch
+ */
+void
+forwarder_receive(forwarder_t * forwarder, msgbuf_t * msgbuf)
+{
+ assert(forwarder);
+
+ /* Send batch ? */
+ if (!msgbuf) {
+ const connection_table_t * table = forwarder_get_connection_table(forwarder);
+ for (unsigned i = 0; i < forwarder->num_pending_conn; i++) {
+ const connection_t * conn = connection_table_at(table, forwarder->pending_conn[i]);
+ // flush
+ connection_send(conn, NULL, false);
+ }
+ forwarder->num_pending_conn = 0;
+ }
+
+ // this are the checks needed to implement WLDR. We set wldr only on the STAs
+ // and we let the AP to react according to choise of the client.
+ // if the STA enables wldr using the set command, the AP enable wldr as well
+ // otherwise, if the STA disable it the AP remove wldr
+ // WLDR should be enabled only on the STAs using the command line
+ // TODO
+ // disable WLDR command line on the AP
+ connection_table_t * table = forwarder_get_connection_table(forwarder);
+ connection_t * conn = connection_table_get_by_id(table, msgbuf_get_connection_id(msgbuf));
+ if (!conn)
+ return;
+
+ if (msgbuf_has_wldr(msgbuf)) {
+ if (connection_has_wldr(conn)) {
+ // case 1: WLDR is enabled
+ connection_wldr_detect_losses(conn, msgbuf);
+ } else if (!connection_has_wldr(conn) &&
+ connection_wldr_autostart_is_allowed(conn)) {
+ // case 2: We are on an AP. We enable WLDR
+ connection_wldr_enable(conn, true);
+ connection_wldr_detect_losses(conn, msgbuf);
+ }
+ // case 3: Ignore WLDR
+ } else {
+ if (connection_has_wldr(conn) && connection_wldr_autostart_is_allowed(conn)) {
+ // case 1: STA do not use WLDR, we disable it
+ connection_wldr_enable(conn, false);
+ }
+ }
+
+ forwarder->stats.countReceived++;
+
+ char *nameString = name_ToString(msgbuf_get_name(msgbuf));
+ DEBUG( "Message %p ingress %3u length %5u received name %s", msgbuf,
+ msgbuf_get_connection_id(msgbuf), msgbuf_get_len(msgbuf), nameString);
+ free(nameString);
+
+ switch (msgbuf_get_type(msgbuf)) {
+ case MESSAGE_TYPE_INTEREST:
+ forwarder_receive_interest(forwarder, msgbuf);
+ break;
+
+ case MESSAGE_TYPE_DATA:
+ forwarder_receive_data(forwarder, msgbuf);
+ break;
+
+ default:
+ forwarder_drop(forwarder, msgbuf);
+ break;
+ }
+
}
-void forwarder_SetStrategy(Forwarder *forwarder, Name *prefix,
- strategy_type strategy,
- unsigned related_prefixes_len,
- Name **related_prefixes) {
- parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
- parcAssertNotNull(prefix, "Parameter prefix must be non-null");
+bool
+forwarder_add_or_update_route(forwarder_t * forwarder, ip_prefix_t * prefix,
+ unsigned ingress_id)
+{
+ assert(forwarder);
+ assert(prefix);
+
+ configuration_t *config = forwarder_get_configuration(forwarder);
+
+ char prefix_s[MAXSZ_IP_PREFIX];
+ int rc = ip_prefix_snprintf(prefix_s, MAXSZ_IP_PREFIX, prefix);
+ assert(rc < MAXSZ_IP_PREFIX);
+ if (rc < 0)
+ return false;
+
+ // XXX TODO this should store options too
+ strategy_type_t strategy_type = configuration_get_strategy(config, prefix_s);
+
+ Name * name_prefix = name_CreateFromAddress(prefix->family,
+ prefix->address, prefix->len);
+ // XXX TODO error handling
+ fib_entry_t * entry = fib_contains(forwarder->fib, name_prefix);
+ if (!entry) {
+ entry = fib_entry_create(name_prefix, strategy_type, NULL, forwarder);
+ fib_entry_nexthops_add(entry, ingress_id);
+ fib_add(forwarder->fib, entry);
+ } else {
+ fib_entry_nexthops_add(entry, ingress_id);
+ }
+
+ name_Release(&name_prefix);
- processor_SetStrategy(forwarder->processor, prefix, strategy,
- related_prefixes_len, related_prefixes);
+ return true;
}
-FibEntryList *forwarder_GetFibEntries(Forwarder *forwarder) {
- return messageProcessor_GetFibEntries(forwarder->processor);
+
+bool
+forwarder_remove_route(forwarder_t * forwarder, ip_prefix_t * prefix,
+ unsigned ingress_id)
+{
+ assert(forwarder);
+ assert(prefix);
+
+ Name *name_prefix = name_CreateFromAddress(prefix->family,
+ prefix->address, prefix->len);
+ // XXX TODO error handling
+ fib_remove(forwarder->fib, name_prefix, ingress_id);
+ name_Release(&name_prefix);
+
+ return true;
+}
+
+#ifdef WITH_POLICY
+
+bool
+forwarder_add_or_update_policy(forwarder_t * forwarder, ip_prefix_t * prefix,
+ policy_t * policy)
+{
+ assert(forwarder);
+ assert(prefix);
+ assert(policy);
+
+ Name *name_prefix = name_CreateFromAddress(prefix->family, prefix->address,
+ prefix->len);
+ // XXX TODO error handling
+ fib_entry_t *entry = fib_contains(forwarder->fib, name_prefix);
+ if (!entry)
+ return false;
+ fib_entry_set_policy(entry, *policy);
+
+ name_Release(&name_prefix);
+
+ return true;
}
-void forwarder_SetContentObjectStoreSize(Forwarder *forwarder,
- size_t maximumContentStoreSize) {
- messageProcessor_SetContentObjectStoreSize(forwarder->processor,
- maximumContentStoreSize);
+bool
+forwarder_remove_policy(forwarder_t * forwarder, ip_prefix_t * prefix)
+{
+ assert(forwarder);
+ assert(prefix);
+
+ Name *name_prefix = name_CreateFromAddress(prefix->family, prefix->address,
+ prefix->len);
+ // XXX TODO error handling
+ fib_entry_t * entry = fib_contains(forwarder->fib, name_prefix);
+ name_Release(&name_prefix);
+
+ if (!entry)
+ return false;
+
+ fib_entry_set_policy(entry, POLICY_NONE);
+
+ return true;
}
-void forwarder_ClearCache(Forwarder *forwarder) {
- messageProcessor_ClearCache(forwarder->processor);
+#endif /* WITH_POLICY */
+
+void
+forwarder_remove_connection_id_from_routes(forwarder_t * forwarder,
+ unsigned connection_id)
+{
+ assert(forwarder);
+
+ fib_remove_connection_id(forwarder->fib, connection_id);
}
-PARCClock *forwarder_GetClock(const Forwarder *forwarder) {
- return forwarder->clock;
+void
+forwarder_set_strategy(forwarder_t * forwarder, Name * name_prefix,
+ strategy_type_t strategy_type, strategy_options_t * strategy_options)
+{
+ assert(forwarder);
+ assert(name_prefix);
+ assert(strategy_type_valid(strategy_type));
+ /* strategy_options might be NULL */
+
+ fib_entry_t * entry = fib_contains(forwarder->fib, name_prefix);
+ if (!entry)
+ return;
+
+ fib_entry_set_strategy(entry, strategy_type, strategy_options);
}
-#if !defined(__APPLE__)
-hicn_socket_helper_t *forwarder_GetHicnSocketHelper(Forwarder *forwarder) {
- return forwarder->hicnSocketHelper;
+content_store_t *
+forwarder_get_content_store(const forwarder_t * forwarder)
+{
+ assert(forwarder);
+
+ return forwarder->content_store;
}
-#endif
// =======================================================
+#if 0
static void _signal_cb(int sig, PARCEventType events, void *user_data) {
- Forwarder *forwarder = (Forwarder *)user_data;
-
- logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning,
- __func__, "signal %d events %d", sig, events);
-
- switch ((int)sig) {
- case SIGTERM:
- logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning,
- __func__, "Caught an terminate signal; exiting cleanly.");
- dispatcher_Stop(forwarder->dispatcher);
- break;
-
- case SIGINT:
- logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning,
- __func__, "Caught an interrupt signal; exiting cleanly.");
- dispatcher_Stop(forwarder->dispatcher);
- break;
+ forwarder_t * forwarder = (forwarder_t *)user_data;
+
+ WARN("signal %d events %d", sig, events);
+
+ switch ((int)sig) {
+ case SIGTERM:
+ WARN("Caught an terminate signal; exiting cleanly.");
+ dispatcher_Stop(forwarder->dispatcher);
+ break;
+
+ case SIGINT:
+ WARN("Caught an interrupt signal; exiting cleanly.");
+ dispatcher_Stop(forwarder->dispatcher);
+ break;
#ifndef _WIN32
- case SIGUSR1:
- // dump stats
- break;
+ case SIGUSR1:
+ // dump stats
+ break;
#endif
- default:
- break;
- }
+ default:
+ break;
+ }
}
+#endif
-static void _keepalive_cb(int fd, PARCEventType what, void *user_data) {
- parcAssertTrue(what & PARCEventType_Timeout, "Got unexpected tick_cb: %d",
- what);
- // function is just a keepalive for hicn-light, does not do anything
+fib_t *
+forwarder_get_fib(forwarder_t * forwarder) {
+ return forwarder->fib;
}
#ifdef WITH_MAPME
-FIB *forwarder_getFib(Forwarder *forwarder) {
- return messageProcessor_getFib(forwarder->processor);
+void
+forwarder_on_connection_event(const forwarder_t * forwarder,
+ const connection_t * connection, connection_event_t event)
+{
+ mapme_on_connection_event(forwarder->mapme, connection, event);
}
-void forwarder_onConnectionEvent(Forwarder *forwarder, const Connection *conn, connection_event_t event) {
-//#ifdef WITH_POLICY
-// messageProcessor_onConnectionEvent(forwarder->processor, conn, event);
-//#else
- mapme_onConnectionEvent(forwarder->mapme, conn, event);
-//#endif /* WITH_POLICY */
+mapme_t *
+forwarder_get_mapme(const forwarder_t * forwarder) {
+ return forwarder->mapme;
}
-void forwarder_ProcessMapMe(Forwarder *forwarder, const uint8_t *msgBuffer,
- unsigned conn_id) {
- mapme_Process(forwarder->mapme, msgBuffer, conn_id);
+#endif /* WITH_MAPME */
+
+#ifdef WITH_PREFIX_STATS
+const prefix_stats_mgr_t *
+forwarder_get_prefix_stats_mgr(const forwarder_t * forwarder)
+{
+ return &forwarder->prefix_stats_mgr;
}
+#endif /* WITH_PREFIX_STATS */
+
+static
+void
+process_interest(forwarder_t * forwarder, listener_t * listener,
+ unsigned conn_id, uint8_t * packet, size_t size, const address_pair_t * pair)
+{
+ if (!connection_id_is_valid(conn_id)) {
+ conn_id = listener_create_connection(listener, pair);
+ }
-MapMe *
-forwarder_getMapmeInstance(const Forwarder *forwarder) {
- return forwarder->mapme;
+ assert(messageHandler_GetTotalPacketLength(packet) == size);
+
+ msgbuf_from_packet(&forwarder->msgbuf, packet, size, MESSAGE_TYPE_INTEREST, conn_id, ticks_now());
+ forwarder_receive(listener->forwarder, &forwarder->msgbuf);
}
-#endif /* WITH_MAPME */
+static
+void
+process_data(forwarder_t * forwarder, listener_t * listener,
+ unsigned conn_id, uint8_t * packet, size_t size, const address_pair_t * pair)
+{
+ if (!connection_id_is_valid(conn_id)) {
+ INFO("Ignoring data packet associated to no connection");
+ return;
+ }
+
+ assert(messageHandler_GetTotalPacketLength(packet) == size);
+
+ msgbuf_from_packet(&forwarder->msgbuf, packet, size, MESSAGE_TYPE_DATA, conn_id, ticks_now());
+ forwarder_receive(listener->forwarder, &forwarder->msgbuf);
+
+}
+
+static
+void
+process_wldr_notification(forwarder_t * forwarder, listener_t * listener,
+ unsigned conn_id, uint8_t * packet, size_t size, const address_pair_t * pair)
+{
+ if (!connection_id_is_valid(conn_id)) {
+ INFO("Ignoring WLDR notification not associated to a connection");
+ return;
+ }
+
+ assert(messageHandler_GetTotalPacketLength(packet) == size);
+
+ connection_table_t * table = forwarder_get_connection_table(forwarder);
+ connection_t * connection = connection_table_at(table, conn_id);
+
+ msgbuf_from_packet(&forwarder->msgbuf, packet, size, MESSAGE_TYPE_WLDR_NOTIFICATION, conn_id, ticks_now());
+ connection_wldr_handle_notification(connection, &forwarder->msgbuf);
+
+}
+
+static
+void
+process_mapme(forwarder_t * forwarder, listener_t * listener,
+ unsigned conn_id, uint8_t * packet, size_t size, const address_pair_t * pair)
+{
+ if (!connection_id_is_valid(conn_id))
+ conn_id = listener_create_connection(listener, pair);
+ mapme_process(forwarder->mapme, packet, conn_id);
+}
+
+static
+void
+process_command(const forwarder_t * forwarder, listener_t * listener,
+ unsigned conn_id, uint8_t * packet, size_t size, const address_pair_t * pair)
+{
+ if (!connection_id_is_valid(conn_id))
+ conn_id = listener_create_connection(listener, pair);
+
+ command_type_t command_type= *(packet + 1);
+ if (command_type >= COMMAND_TYPE_N) {
+ ERROR("Invalid command");
+ return;
+ }
+ forwarder_receive_command(listener->forwarder, command_type, packet, conn_id);
+
+}
+
+// = process for listener as we are resolving connection id
+// XXX this would typically be inside the forwarder
+void
+process_packet(forwarder_t * forwarder, listener_t * listener, uint8_t * packet, size_t size, address_pair_t * pair)
+{
+ /* Connection lookup */
+ const connection_table_t * table = forwarder_get_connection_table(listener->forwarder);
+ const connection_t * conn = connection_table_get_by_pair(table, pair);
+ unsigned conn_id = conn ? connection_table_get_connection_id(table, conn): CONNECTION_ID_UNDEFINED;
+
+ assert((conn_id != CONNECTION_ID_UNDEFINED) || listener);
+
+ // Actually hooks should be defined for each packet type to avoid this
+ // spaghetti code
+ if (messageHandler_IsTCP(packet)) {
+ if (messageHandler_IsData(packet)) {
+ process_data(forwarder, listener, conn_id, packet, size, pair);
+ } else if (messageHandler_IsInterest(packet)) {
+ process_interest(forwarder, listener, conn_id, packet, size, pair);
+ } else {
+ INFO("Unknown TCP packet received");
+ forwarder_drop(forwarder, NULL);
+ }
+ } else if (messageHandler_IsWldrNotification(packet)) {
+ process_wldr_notification(forwarder, listener, conn_id, packet, size, pair);
+ } else if (mapme_match_packet(packet)) {
+ process_mapme(forwarder, listener, conn_id, packet, size, pair);
+ } else if (*packet == REQUEST_LIGHT) {
+ process_command(forwarder, listener, conn_id, packet, size, pair);
+ } else {
+ INFO("Unknown packet received");
+ forwarder_drop(forwarder, NULL);
+ }
+}
diff --git a/hicn-light/src/hicn/core/forwarder.h b/hicn-light/src/hicn/core/forwarder.h
index d1815b7d4..5d999a319 100644
--- a/hicn-light/src/hicn/core/forwarder.h
+++ b/hicn-light/src/hicn/core/forwarder.h
@@ -21,44 +21,48 @@
#ifndef forwarder_h
#define forwarder_h
-#ifndef _WIN32
-#include <sys/time.h>
-#endif
-#include <stdlib.h>
+//#ifndef _WIN32
+//#include <sys/time.h>
+//#endif
+//
-#include <hicn/core/connectionTable.h>
-#include <hicn/core/dispatcher.h>
-#include <hicn/messenger/messenger.h>
+#include <stdlib.h>
+#include <sys/socket.h> // struct mmsghdr
-#include <hicn/core/message.h>
+#include <hicn/core/msgbuf.h>
+#include <hicn/core/content_store.h>
+#include <hicn/core/connection.h>
+#include <hicn/core/connection_table.h>
+#include <hicn/core/listener_table.h>
#include <hicn/config/configuration.h>
#ifdef WITH_MAPME
-#include <hicn/processor/fib.h>
+#include <hicn/core/fib.h>
#endif /* WITH_MAPME */
-#include <hicn/core/logger.h>
-#include <hicn/core/ticks.h>
-#include <hicn/io/listenerSet.h>
+#define PORT_NUMBER 9695
+#define PORT_NUMBER_AS_STRING "9695"
-#include <hicn/processor/fibEntryList.h>
+#include <hicn/utils/commands.h>
-#include <parc/algol/parc_Clock.h>
+#define MAX_MSG 64 //16 //32
+#define MTU 1500
-#if !defined(__APPLE__)
-#include <hicn/socket/api.h>
-#endif
-#define PORT_NUMBER 9695
-#define PORT_NUMBER_AS_STRING "9695"
+typedef struct batch_buffer_s {
+ /* sendmmsg / recvmmsg data structures */
+ struct mmsghdr msghdr[MAX_MSG]; // XXX = {0};
+ char buffers[MAX_MSG][MTU];
+ struct iovec iovecs[MAX_MSG]; // XXX = {0};
+ struct sockaddr_storage addrs[MAX_MSG];
+} batch_buffer_t;
-#include <hicn/utils/commands.h>
+int init_batch_buffers(batch_buffer_t * bb);
// ==============================================
-struct forwarder;
-typedef struct forwarder Forwarder;
+typedef struct forwarder_s forwarder_t;
/**
* @function forwarder_Create
@@ -69,13 +73,13 @@ typedef struct forwarder Forwarder;
*
* @param logger may be NULL
*/
-Forwarder *forwarder_Create(Logger *logger);
+forwarder_t * forwarder_create();
/**
* @function forwarder_Destroy
* @abstract Destroys the forwarder, stopping all traffic and freeing all memory
*/
-void forwarder_Destroy(Forwarder **ptr);
+void forwarder_free(forwarder_t * forwarder);
/**
* @function forwarder_SetupAllListeners
@@ -90,14 +94,14 @@ void forwarder_Destroy(Forwarder **ptr);
* @param localPath is the AF_UNIX path to use, if NULL no AF_UNIX listener is
* setup
*/
-void forwarder_SetupAllListeners(Forwarder *forwarder, uint16_t port,
- const char *localPath);
+void forwarder_setup_all_listeners(forwarder_t * forwarder, uint16_t port, const
+ char *local_path);
/**
* @function forwarder_SetupAllListeners
* @abstract Setup one tcp and one udp listener on address 127.0.0.1 and the
* given port
*/
-void forwarder_SetupLocalListeners(Forwarder *forwarder, uint16_t port);
+void forwarder_setup_local_listeners(forwarder_t * forwarder, uint16_t port);
/**
* Configure hicn-light via a configuration file
@@ -106,38 +110,19 @@ void forwarder_SetupLocalListeners(Forwarder *forwarder, uint16_t port);
* You need to have "add listener" lines in the file to receive connections. No
* default listeners are configured.
*
- * @param [in] forwarder An alloated Forwarder
+ * @param [in] forwarder An alloated forwarder_t
* @param [in] filename The path to the configuration file
*/
-void forwarder_SetupFromConfigFile(Forwarder *forwarder, const char *filename);
-
-/**
- * Returns the logger used by this forwarder
- *
- * If you will store the logger, you should acquire a reference to it.
- *
- * @param [in] forwarder An allocated hicn-light forwarder
- *
- * @retval non-null The logger used by hicn-light
- * @retval null An error
- */
-Logger *forwarder_GetLogger(const Forwarder *forwarder);
+void forwarder_read_config(forwarder_t * forwarder, const char * filename);
/**
- * @function forwarder_SetLogLevel
- * @abstract Sets the minimum level to log
- */
-void forwarder_SetLogLevel(Forwarder *forwarder, PARCLogLevel level);
-
-/**
- * @function forwarder_GetNextConnectionId
- * @abstract Get the next identifier for a new connection
+ * @function forwarder_GetConfiguration
+ * @abstract The configuration object
+ * @discussion
+ * The configuration contains all user-issued commands. It does not include
+ * dynamic state.
*/
-unsigned forwarder_GetNextConnectionId(Forwarder *forwarder);
-
-Messenger *forwarder_GetMessenger(Forwarder *forwarder);
-
-Dispatcher *forwarder_GetDispatcher(Forwarder *forwarder);
+configuration_t * forwarder_get_configuration(forwarder_t * forwarder);
/**
* Returns the set of currently active listeners
@@ -147,7 +132,7 @@ Dispatcher *forwarder_GetDispatcher(Forwarder *forwarder);
* @retval non-null The set of active listeners
* @retval null An error
*/
-ListenerSet *forwarder_GetListenerSet(Forwarder *forwarder);
+listener_table_t * forwarder_get_listener_table(forwarder_t *forwarder);
/**
* Returns the forwrder's connection table
@@ -158,119 +143,72 @@ ListenerSet *forwarder_GetListenerSet(Forwarder *forwarder);
* @retval null An error
*
*/
-#ifdef WITH_POLICY
-ConnectionTable *forwarder_GetConnectionTable(const Forwarder *forwarder);
-#else
-ConnectionTable *forwarder_GetConnectionTable(Forwarder *forwarder);
-#endif /* WITH_POLICY */
+connection_table_t * forwarder_get_connection_table(const forwarder_t *forwarder);
-/**
- * Returns a Tick-based clock
- *
- * Runs at approximately 1 msec per tick (see HZ in forwarder.c).
- * Do not Release this clock. If you save a copy of it, create your own
- * reference to it with parcClock_Acquire().
- *
- * @param [in] forwarder An allocated hicn-light forwarder
- *
- * @retval non-null An allocated hicn-light Clock based on the Tick counter
- * @retval null An error
- */
-PARCClock *forwarder_GetClock(const Forwarder *forwarder);
+void forwarder_content_store_set_store(forwarder_t * forwarder, bool val);
-/**
- * Direct call to get the Tick clock
- *
- * Runs at approximately 1 msec per tick (see HZ in forwarder.c)
- *
- * @param [in] forwarder An allocated hicn-light forwarder
- */
-Ticks forwarder_GetTicks(const Forwarder *forwarder);
+bool forwarder_content_store_get_store(forwarder_t * forwarder);
+
+void forwarder_content_store_set_serve(forwarder_t * forwarder, bool val);
+
+bool forwarder_content_store_get_serve(forwarder_t * forwarder);
/**
- * Convert nano seconds to Ticks
+ * Sets the maximum number of content objects in the content store
*
- * Converts nano seconds to Ticks, based on HZ (in forwarder.c)
+ * Implementation dependent - may wipe the cache.
*/
-Ticks forwarder_NanosToTicks(uint64_t nanos);
+void forwarder_content_store_set_size(forwarder_t * forwarder, size_t size);
-uint64_t forwarder_TicksToNanos(Ticks ticks);
+void forwarder_content_store_clear(forwarder_t *forwarder);
-void forwarder_ReceiveCommand(Forwarder *forwarder, command_id command,
- struct iovec *message, unsigned ingressId);
+void forwarder_receive_command(forwarder_t * forwarder, command_type_t command_type,
+ uint8_t * packet, unsigned connection_id);
-void forwarder_Receive(Forwarder *forwarder, Message *mesage);
+void forwarder_receive(forwarder_t * forwarder, msgbuf_t * message);
/**
- * @function forwarder_AddOrUpdateRoute
+ * @function forwarder_add_or_update_route
* @abstract Adds or updates a route on all the message processors
*/
-bool forwarder_AddOrUpdateRoute(Forwarder *forwarder,
- add_route_command *control, unsigned ifidx);
+bool forwarder_add_or_update_route(forwarder_t * forwarder,
+ ip_prefix_t * prefix, unsigned ingress_id);
/**
- * @function forwarder_RemoveRoute
+ * @function forwarder_remove_route
* @abstract Removes a route from all the message processors
*/
-bool forwarder_RemoveRoute(Forwarder *forwarder, remove_route_command *control,
- unsigned ifidx);
+bool forwarder_remove_route(forwarder_t * forwarder, ip_prefix_t * prefix,
+ unsigned ingress_id);
#ifdef WITH_POLICY
/**
- * @function forwarder_AddOrUpdatePolicy
+ * @function forwarder_add_or_update_policy
* @abstract Adds or updates a policy on the message processor
*/
-bool forwarder_AddOrUpdatePolicy(Forwarder *forwarder, add_policy_command *control);
+bool forwarder_add_or_update_policy(forwarder_t * forwarder,
+ ip_prefix_t * prefix, policy_t * policy);
+
/**
* @function forwarder_RemovePolicy
* @abstract Removes a policy from the message processor
*/
-bool forwarder_RemovePolicy(Forwarder *forwarder, remove_policy_command *control);
+bool forwarder_remove_policy(forwarder_t * forwarder, ip_prefix_t * prefix);
+
#endif /* WITH_POLICY */
/**
* Removes a connection id from all routes
*/
-void forwarder_RemoveConnectionIdFromRoutes(Forwarder *forwarder,
- unsigned connectionId);
-
-/**
- * @function forwarder_GetConfiguration
- * @abstract The configuration object
- * @discussion
- * The configuration contains all user-issued commands. It does not include
- * dynamic state.
- */
-Configuration *forwarder_GetConfiguration(Forwarder *forwarder);
-
-FibEntryList *forwarder_GetFibEntries(Forwarder *forwarder);
-
-/**
- * Sets the maximum number of content objects in the content store
- *
- * Implementation dependent - may wipe the cache.
- */
-void forwarder_SetContentObjectStoreSize(Forwarder *forwarder,
- size_t maximumContentStoreSize);
+void forwarder_remove_connection_id_from_routes(forwarder_t * forwarder,
+ unsigned connection_id);
-void forwarder_SetChacheStoreFlag(Forwarder *forwarder, bool val);
+void forwarder_set_strategy(forwarder_t * forwarder, Name * name_prefix,
+ strategy_type_t strategy_type, strategy_options_t * strategy_options);
-bool forwarder_GetChacheStoreFlag(Forwarder *forwarder);
+content_store_t * forwarder_get_content_store(const forwarder_t * forwarder);
-void forwarder_SetChacheServeFlag(Forwarder *forwarder, bool val);
-
-bool forwarder_GetChacheServeFlag(Forwarder *forwarder);
-
-void forwarder_ClearCache(Forwarder *forwarder);
-
-void forwarder_SetStrategy(Forwarder *forwarder, Name *prefix,
- strategy_type strategy, unsigned related_prefixes_len,
- Name **related_prefixes);
-#if !defined(__APPLE__)
-hicn_socket_helper_t *forwarder_GetHicnSocketHelper(Forwarder *forwarder);
-#endif
-#ifdef WITH_MAPME
/**
* @function forwarder_getFib
@@ -278,7 +216,9 @@ hicn_socket_helper_t *forwarder_GetHicnSocketHelper(Forwarder *forwarder);
* @param [in] forwarder - Pointer to the hICN forwarder.
* @returns Pointer to the hICN FIB.
*/
-FIB *forwarder_getFib(Forwarder *forwarder);
+fib_t * forwarder_get_fib(forwarder_t * forwarder);
+
+#ifdef WITH_MAPME
/**
* @function forwarder_onConnectionEvent
@@ -288,7 +228,8 @@ FIB *forwarder_getFib(Forwarder *forwarder);
* @param [in] conn - Pointer to the newly added connection.
* @param [in] event - Connection event
*/
-void forwarder_onConnectionEvent(Forwarder *forwarder, const Connection *conn, connection_event_t event);
+void forwarder_on_connection_event(const forwarder_t * forwarder,
+ const connection_t * connection, connection_event_t event);
/**
* @function forwarder_ProcessMapMe
@@ -298,12 +239,18 @@ void forwarder_onConnectionEvent(Forwarder *forwarder, const Connection *conn, c
* @param [in] msgBuffer - MAP-Me buffer
* @param [in] conn_id - Ingress connection id
*/
-void forwarder_ProcessMapMe(Forwarder *forwarder, const uint8_t *msgBuffer,
- unsigned conn_id);
+void forwarder_process_mapme(const forwarder_t * forwarder, const uint8_t * packet,
+ unsigned conn_id);
-struct mapme;
-struct mapme * forwarder_getMapmeInstance(const Forwarder *forwarder);
+struct mapme_s * forwarder_get_mapme(const forwarder_t * forwarder);
#endif /* WITH_MAPME */
+#ifdef WITH_PREFIX_STATS
+const prefix_stats_mgr_t * forwarder_get_prefix_stats_mgr(const forwarder_t * forwarder);
+#endif /* WITH_PREFIX_STATS */
+
+void process_packet(forwarder_t * forwarder, listener_t * listener,
+ uint8_t * packet, size_t size, address_pair_t * pair);
+
#endif // forwarder_h
diff --git a/hicn-light/src/hicn/core/listener.c b/hicn-light/src/hicn/core/listener.c
new file mode 100644
index 000000000..0ab73b1f4
--- /dev/null
+++ b/hicn-light/src/hicn/core/listener.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file listener.c
+ * @brief Implementation of hICN listeners
+ */
+
+
+
+#include <string.h> // strdup
+
+#include <hicn/core/listener_vft.h>
+#include <hicn/base/loop.h>
+#include <hicn/core/forwarder.h>
+#include <hicn/util/log.h>
+#include "listener.h"
+
+listener_t *
+listener_create(face_type_t type, const address_t * address,
+ const char * interface_name, const char * name, forwarder_t * forwarder)
+{
+ const listener_table_t * table = forwarder_get_listener_table(forwarder);
+
+ listener_t * listener;
+ listener_key_t key = {
+ .type = type,
+ .address = *address,
+ };
+ listener_table_allocate(table, listener, &key, name);
+
+ unsigned listener_id = listener_table_get_listener_id(table, listener);
+
+ listener_initialize(listener, type, name, listener_id, address, interface_name, forwarder);
+ return listener;
+}
+
+int
+listener_initialize(listener_t * listener, face_type_t type, const char * name,
+ unsigned listener_id, const address_t * address,
+ const char * interface_name, forwarder_t * forwarder)
+{
+ int rc;
+
+ assert(listener);
+ assert(forwarder);
+
+ *listener = (listener_t) {
+ .id = listener_id,
+ .name = strdup(name),
+ .type = type,
+ .interface_name = strdup(interface_name),
+ //.interface_index = ,
+ //.family = ,
+ .fd = 0,
+ .address = *address,
+ .forwarder = forwarder,
+ };
+
+ listener->data = malloc(listener_vft[listener->type]->data_size);
+ if (!listener->data)
+ goto ERR_DATA;
+
+ assert(listener_has_valid_type(listener));
+
+ rc = listener_vft[listener->type]->initialize(listener);
+ if (rc < 0)
+ goto ERR_VFT;
+
+ listener->fd = listener_vft[listener->type]->get_socket(listener, address, NULL, interface_name);
+ if (listener->fd < 0) {
+ ERROR("Error creating listener fd: (%d) %s", errno, strerror(errno));
+ goto ERR_FD;
+ }
+ assert(listener->fd > 0);
+
+ // XXX data should be pre-allocated here
+
+ if (loop_register_fd(MAIN_LOOP, listener->fd, listener,
+ (fd_callback_t)listener_vft[listener->type]->read_callback, NULL) < 0)
+ goto ERR_REGISTER_FD;
+
+ // XXX TODO
+ //char *str = addressToString(listener->local_addr);
+ DEBUG("%s UdpListener %p created for address %s",
+ face_type_str(listener->type), listener, "N/A");
+ //free(str);
+
+ return 0;
+
+ERR_REGISTER_FD:
+#ifndef _WIN32
+ close(listener->fd);
+#else
+ closesocket(listener->fd);
+#endif
+ERR_FD:
+ERR_VFT:
+ free(listener->data);
+ERR_DATA:
+ free(listener->interface_name);
+ free(listener->name);
+ return -1;
+}
+
+int
+listener_finalize(listener_t * listener)
+{
+ assert(listener);
+ assert(listener_has_valid_type(listener));
+
+ loop_unregister_fd(MAIN_LOOP, listener->fd);
+
+#ifndef _WIN32
+ close(listener->fd);
+#else
+ closesocket(listener->fd);
+#endif
+
+ listener_vft[listener->type]->finalize(listener);
+
+ free(listener->data);
+ free(listener->interface_name);
+ free(listener->name);
+
+ return 0;
+}
+
+int listener_get_socket(const listener_t * listener, const address_t * local,
+ const address_t * remote, const char * interface_name)
+{
+ assert(listener);
+ assert(listener_has_valid_type(listener));
+ assert(pair);
+
+ return listener_vft[listener->type]->get_socket(listener, local, remote,
+ interface_name);
+}
+
+// XXX CHANGE : we now get the fd directly from the listener
+unsigned listener_create_connection(const listener_t * listener,
+ const address_pair_t * pair)
+{
+ assert(listener);
+ assert(listener_has_valid_type(listener));
+ assert(pair);
+
+ // XXX TODO This code is likely common with connection creation code
+ const char * name = NULL;
+
+ connection_table_t * table = forwarder_get_connection_table(listener->forwarder);
+ connection_t * connection;
+ connection_table_allocate(table, connection, pair, name);
+
+ unsigned connid = connection_table_get_connection_id(table, connection);
+
+ bool local = address_is_local(address_pair_get_local(pair));
+
+ int fd = listener_get_socket(listener, address_pair_get_local(pair),
+ address_pair_get_remote(pair), NULL); // XXX interfacename was not specified
+
+ // XXX here we use the same interface name as the listener
+ int rc = connection_initialize(connection, listener->type, name,
+ listener->interface_name, fd, pair, local, connid, listener->forwarder);
+ if (rc < 0)
+ return ~0; // XXX how to return an error
+
+ // This was already commented:
+ // connection_AllowWldrAutoStart(*conn_ptr);
+
+ return connid;
+}
+
+int
+listener_punt(const listener_t * listener, const char * prefix_s)
+{
+ assert(listener);
+ assert(listener_get_type(listener) == FACE_TYPE_HICN);
+ assert(prefix_s);
+
+ return listener_vft[listener_get_type(listener)]->punt(listener, prefix_s);
+}
+
+ssize_t
+listener_read_callback(forwarder_t * forwarder, listener_t * listener, int fd,
+ address_t * local_addr, uint8_t * packet, size_t size)
+{
+ // XXX TODO mutualize code across all listeners
+ // some do not support batches
+ //
+ // XXX negative in case of error
+ // 0 if we don't consume yet because we don't have enough
+ // needed for TCP !!
+ return size;
+}
+
+void
+listener_batch_read_callback(forwarder_t * forwarder, listener_t * listener,
+ int fd, address_t * local_addr, batch_buffer_t * bb)
+{
+ assert(bb);
+
+ // XXX potential improvement : receive in a loop while we have messages to
+ // read
+
+ // XXX
+ int r = recvmmsg(fd, bb->msghdr, MAX_MSG, 0, NULL);
+ if (r == 0)
+ return;
+
+ if (r < 0) {
+ if (errno == EINTR)
+ return;
+ perror("recv()");
+ return;
+ }
+
+ for (int i = 0; i < r; i++) {
+ struct mmsghdr *msg = &bb->msghdr[i];
+ uint8_t * packet = msg->msg_hdr.msg_iov->iov_base;
+ size_t size = msg->msg_hdr.msg_iovlen;
+
+ /* BEGIN packet processing */
+
+#ifdef __APPLE__
+ // XXX explain
+ msg->msg_hdr.msg_namelen = 0x00;
+#endif
+
+ /* Construct address pair used for connection lookup */
+ address_pair_t pair;
+ pair.local = *local_addr;
+ pair.remote = *(address_t*)msg->msg_hdr.msg_name;
+ // in the case of a connection, we should assert the remote
+
+ process_packet(forwarder, listener, packet, size, &pair);
+ }
+}
+
+
+#if 0
+void
+_listener_callback(evutil_socket_t fd, short what, void * arg)
+{
+ fd_callback_data_t * data = arg;
+ data->callback(data->owner, fd, data->data);
+}
+
+int
+listener_register_fd(listener_t * listener, int fd, fd_callback_t callback, void * data)
+{
+ fd_callback_data_t callback_data = {
+ .fd = fd,
+ .owner = listener,
+ .callback = callback,
+ .data = data,
+ };
+
+ return loop_register_fd(MAIN_LOOP, fd, listener, _listener_callback, callback_data);
+}
+
+int
+listener_unregister_fd(listener_t * listener, int fd)
+{
+ return loop_unregister_fd(MAIN_LOOP, fd);
+}
+#endif
+
+void
+listener_setup_all(const forwarder_t * forwarder, uint16_t port, const char *localPath)
+{
+#if 0
+ InterfaceSet *set = system_Interfaces(forwarder);
+
+ size_t interfaceSetLen = interfaceSetLength(set);
+ for (size_t i = 0; i < interfaceSetLen; i++) {
+ Interface *iface = interfaceSetGetByOrdinalIndex(set, i);
+
+ const AddressList *addresses = interfaceGetAddresses(iface);
+ size_t addressListLen = addressListLength(addresses);
+
+ for (size_t j = 0; j < addressListLen; j++) {
+ const address_t *address = addressListGetItem(addresses, j);
+
+ // Do not start on link address
+ char listenerName[SYMBOLIC_NAME_LEN];
+#ifdef __ANDROID__
+ snprintf(listenerName, SYMBOLIC_NAME_LEN, "local_%zu", i);
+#else
+ snprintf(listenerName, SYMBOLIC_NAME_LEN, "local_%ld", i);
+#endif
+ // XXX TODO if (addressGetType(address) != ADDR_LINK) {
+ _setupTcpListener(forwarder, listenerName, address,
+ (char *)interfaceGetName(iface));
+ // }
+ }
+ }
+
+ interfaceSetDestroy(&set);
+#endif
+}
+
+// XXX TODO
+void
+listener_setup_local_ipv4(const forwarder_t * forwarder, uint16_t port)
+{
+#if 0
+ // XXX memset
+ address_t address = ADDRESS4_LOCALHOST(port);
+
+ _setupUdpListener(forwarder, "lo_udp", &address, "lo");
+ _setupTcpListener(forwarder, "lo_tcp", &address, "lo");
+#endif
+}
diff --git a/hicn-light/src/hicn/core/listener.h b/hicn-light/src/hicn/core/listener.h
new file mode 100644
index 000000000..749e9b177
--- /dev/null
+++ b/hicn-light/src/hicn/core/listener.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file listener.h
+ * @brief hICN listeners
+ */
+
+#ifndef HICNLIGHT_LISTENER_H
+#define HICNLIGHT_LISTENER_H
+
+#include <hicn/core/address_pair.h>
+#include <hicn/face.h>
+
+struct forwarder_s;
+struct batch_buffer_s;
+
+typedef struct {
+ address_t address;
+ face_type_t type;
+} listener_key_t;
+
+/* This structure holds what is in common to all listeners */
+typedef struct {
+ int id;
+ char * name;
+ union {
+ listener_key_t key;
+ struct {
+ address_t address;
+ face_type_t type;
+ };
+ };
+
+ char * interface_name;
+ unsigned interface_index;
+ unsigned family;
+ int fd;
+ void * data; /* Listener specific data */
+ struct forwarder_s * forwarder;
+} listener_t;
+
+#define listener_get_id(L) ((L)->id)
+#define listener_get_name(L) ((L)->name)
+#define listener_get_key(L) (&(L)->key)
+#define listener_get_type(L) ((L)->type)
+#define listener_get_interface_name(L) ((L)->interface_name)
+#define listener_get_interface_index(L) ((L)->interface_index)
+#define listener_get_address(L) (&(L)->address)
+
+#define listener_has_valid_type(L) \
+ (face_type_is_valid((L)->type))
+
+listener_t * listener_create(face_type_t type, const address_t * address,
+ const char * interface_name, const char * symbolic, struct forwarder_s * forwarder);
+
+int listener_initialize(listener_t * listener, face_type_t type, const char * name,
+ unsigned listener_id, const address_t * address,
+ const char * interface_name, struct forwarder_s * forwarder);
+
+int listener_finalize(listener_t * listener);
+
+int listener_punt(const listener_t * listener, const char * prefix_s);
+
+int listener_get_socket(const listener_t * listener, const address_t * local,
+ const address_t * remote, const char * interface_name);
+
+unsigned listener_create_connection(const listener_t * listener,
+ const address_pair_t * pair);
+
+void listener_setup_all(const struct forwarder_s * forwarder, uint16_t port, const char *localPath);
+
+void listener_setup_local_ipv4(const struct forwarder_s * forwarder, uint16_t port);
+
+void listener_process_packet(const listener_t * listener,
+ const uint8_t * packet, size_t size);
+
+ssize_t listener_read_callback(struct forwarder_s * forwarder, listener_t * listener,
+ int fd, address_t * local_addr, uint8_t * packet, size_t size);
+
+void listener_batch_read_callback(struct forwarder_s * forwarder,
+ listener_t * listener, int fd, address_t * local_addr,
+ struct batch_buffer_s * bb);
+
+#endif /* HICNLIGHT_LISTENER_H */
diff --git a/hicn-light/src/hicn/core/listener_table.c b/hicn-light/src/hicn/core/listener_table.c
new file mode 100644
index 000000000..e3cbb310d
--- /dev/null
+++ b/hicn-light/src/hicn/core/listener_table.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file listener_table.c
+ * \brief Implementation of hICN listener table
+ */
+
+#include <hicn/core/listener_table.h>
+#include <hicn/core/listener.h>
+
+/* This is only used for first allocation, as the table is resizeable */
+#define DEFAULT_LISTENER_TABLE_SIZE 64
+
+listener_table_t *
+listener_table_create(size_t elt_size, size_t max_elts)
+{
+ listener_table_t * table = malloc(sizeof(listener_table_t));
+ if (!table)
+ return NULL;
+
+ table->id_by_name = kh_init_lt_name();
+ table->id_by_key = kh_init_lt_key();
+ pool_init(table->listeners, DEFAULT_LISTENER_TABLE_SIZE);
+
+ return table;
+}
+
+void
+listener_table_free(listener_table_t * table)
+{
+ kh_destroy_lt_name(table->id_by_name);
+ kh_destroy_lt_key(table->id_by_key);
+ pool_free(table->listeners);
+ free(table);
+}
+
+listener_t *
+listener_table_get_by_address(listener_table_t * table,
+ face_type_t type, const address_t * address)
+{
+ listener_key_t key;
+ //XXX
+ memset(&key, 0, sizeof(listener_key_t));
+ key = (listener_key_t) {
+ .type = type,
+ .address = *address,
+ };
+ khiter_t k = kh_get_lt_key(table->id_by_key, &key);
+ if (k == kh_end(table->id_by_key))
+ return NULL;
+ return listener_table_at(table, kh_val(table->id_by_key, k));
+}
+
+void
+listener_table_remove_by_id(listener_table_t * table, off_t id)
+{
+ /*
+ * Get the listener address so as to be able to remove it from the
+ * hash table index
+ */
+ listener_t * listener = listener_table_at(table, id);
+ const char * name = listener_get_name(listener);
+ listener_key_t * key = listener_get_key(listener);
+ khiter_t k;
+ k = kh_get_lt_name(table->id_by_name, name);
+ kh_del_lt_name(table->id_by_name, k);
+ k = kh_get_lt_key(table->id_by_key, key);
+ kh_del_lt_key(table->id_by_key, k);
+
+ pool_put(table->listeners, listener);
+}
+
+listener_t *
+listener_table_get_by_name(listener_table_t * table, const char * name)
+{
+ khiter_t k = kh_get_lt_name(table->id_by_name, name);
+ if (k == kh_end(table->id_by_name))
+ return NULL;
+ return listener_table_at(table, kh_val(table->id_by_name, k));
+}
+
+#if 0
+unsigned
+listener_table_add(listener_table_t * table, listener_t * listener)
+{
+ // XXX missing hash and key storage
+ listener_t * lst;
+ pool_get(table->listeners, lst);
+ lst = listener;
+ unsigned listener_id = lst - table,
+ Listener_SetId(listener, listener_id);
+ return listener_id;
+}
+#endif
diff --git a/hicn-light/src/hicn/core/listener_table.h b/hicn-light/src/hicn/core/listener_table.h
new file mode 100644
index 000000000..66959def4
--- /dev/null
+++ b/hicn-light/src/hicn/core/listener_table.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file listener_table.h
+ * \brief hICN listener table
+ */
+
+#ifndef HICN_LISTENER_TABLE_H
+#define HICN_LISTENER_TABLE_H
+
+#include <hicn/core/address.h>
+#include <hicn/base/common.h>
+#include <hicn/base/hash.h>
+#include <hicn/base/khash.h>
+#include <hicn/core/listener.h>
+#include <hicn/base/pool.h>
+
+#define _lt_var(x) _lt_var_##x
+
+#define key_hash(key) (hash(key, sizeof(listener_key_t)))
+#define key_hash_eq(a, b) (key_hash(b) - key_hash(a))
+
+KHASH_INIT(lt_name, const char *, unsigned, 0, str_hash, str_hash_eq);
+KHASH_INIT(lt_key, listener_key_t *, unsigned, 0, key_hash, key_hash_eq);
+
+typedef struct {
+ kh_lt_key_t * id_by_key;
+ kh_lt_name_t * id_by_name;
+ listener_t * listeners; // pool
+} listener_table_t;
+
+#define listener_table_allocate(TABLE, LISTENER, KEY, NAME) \
+do { \
+ pool_get(table->listeners, (LISTENER)); \
+ off_t _lt_var(id) = (LISTENER) - (TABLE)->listeners; \
+ int _lt_var(res); \
+ khiter_t _lt_var(k); \
+ _lt_var(k) = kh_put_lt_name((TABLE)->id_by_name, (NAME), &_lt_var(res)); \
+ kh_value((TABLE)->id_by_name, _lt_var(k)) = _lt_var(id); \
+ \
+ listener->type = (KEY)->type; \
+ listener->address = (KEY)->address; \
+ listener_key_t * _lt_var(key) = listener_get_key(LISTENER); \
+ _lt_var(k) = kh_put_lt_key((TABLE)->id_by_key, _lt_var(key), &_lt_var(res));\
+ kh_value((TABLE)->id_by_key, _lt_var(k)) = _lt_var(id); \
+} while(0)
+
+#define listener_table_deallocate(TABLE, LISTENER) \
+do { \
+ const address_key_t * _lt_var(key) = listener_get_key(LISTENER); \
+ khiter_t _lt_var(k); \
+ _lt_var(k) = kh_get_ct_key((TABLE)->id_by_key, _lt_var(key)); \
+ if (_lt_var(k) != kh_end((TABLE)>id_by_key)) \
+ kh_del_ct_key((TABLE)->id_by_key, _lt_var(k)); \
+ \
+ const char * _lt_var(name) = listener_get_name(LISTENER); \
+ _lt_var(k) = kh_get_ct_name((TABLE)->id_by_name, _lt_var(name)); \
+ if (_lt_var(k) != kh_end((TABLE)->id_by_name)) \
+ kh_del_ct_name((TABLE)->id_by_name, _lt_var(k)); \
+ \
+ pool_put((TABLE)->listeners, LISTENER); \
+} while(0) \
+
+
+#define listener_table_len(table) (pool_elts(table->listeners))
+
+#define listener_table_validate_id(table, id) pool_validate_id(table->listeners, id)
+
+#define listener_table_at(table, id) ((table)->listeners + id)
+
+#define listener_table_get_by_id(table, id) \
+ listener_table_validate_id(table, id) \
+ ? listener_table_at(table, id) : NULL
+
+#define listener_table_get_listener_id(table, listener) (listener - table->listeners)
+
+#define listener_table_foreach(table, listener, BODY) \
+ pool_foreach(table->listeners, listener, do { BODY } while(0) )
+
+listener_table_t * listener_table_create();
+void listener_table_free(listener_table_t * table);
+
+listener_t * listener_table_get_by_address(listener_table_t * table,
+ face_type_t type, const address_t * address);
+
+listener_t * listener_table_get_by_name(listener_table_t * table,
+ const char *name);
+
+void listener_table_remove_by_id(listener_table_t * table, off_t id);
+
+unsigned listener_table_add(listener_table_t * table, listener_t * listener);
+
+#endif /* HICN_LISTENER_TABLE_H */
diff --git a/hicn-light/src/hicn/core/listener_vft.c b/hicn-light/src/hicn/core/listener_vft.c
new file mode 100644
index 000000000..edaa0c264
--- /dev/null
+++ b/hicn-light/src/hicn/core/listener_vft.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file listener_vft.c
+ * @brief Implementation of listener VFT
+ */
+
+#include "listener_vft.h"
+
+extern listener_ops_t listener_hicn;
+extern listener_ops_t listener_tcp;
+extern listener_ops_t listener_udp;
+
+const listener_ops_t * listener_vft[] = {
+ [FACE_TYPE_HICN] = &listener_hicn,
+ [FACE_TYPE_TCP] = &listener_tcp,
+ [FACE_TYPE_UDP] = &listener_udp,
+};
diff --git a/hicn-light/src/hicn/core/listener_vft.h b/hicn-light/src/hicn/core/listener_vft.h
new file mode 100644
index 000000000..2f70dd67d
--- /dev/null
+++ b/hicn-light/src/hicn/core/listener_vft.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file listener_vft.h
+ * @brief Listener VFT
+ */
+
+#ifndef HICNLIGHT_LISTENER_VFT_H
+#define HICNLIGHT_LISTENER_VFT_H
+
+#include <hicn/core/address_pair.h>
+#include <hicn/core/connection.h>
+#include <hicn/core/listener.h>
+#include <hicn/face.h>
+
+typedef struct {
+ int (*initialize)(listener_t * listener);
+ void (*finalize)(listener_t * listener);
+ int (*punt)(const listener_t * listener, const char * prefix_s);
+ int (*get_socket)(const listener_t * listener, const address_t * local,
+ const address_t * remote, const char * interface_name);
+ int (*send)(const connection_t * connection, const address_t * dummy,
+ msgbuf_t * msgbuf, bool queue);
+ int (*send_packet)(const connection_t * connection,
+ const uint8_t * packet, size_t size);
+ void (*read_callback)(listener_t * listener, int fd, void * data);
+ size_t data_size;
+} listener_ops_t;
+
+#define DECLARE_LISTENER(NAME) \
+const listener_ops_t listener_ ## NAME = { \
+ .initialize = listener_ ## NAME ## _initialize, \
+ .finalize = listener_ ## NAME ## _finalize, \
+ .punt = listener_ ## NAME ## _punt, \
+ .get_socket = listener_ ## NAME ## _get_socket, \
+ .read_callback = listener_ ## NAME ## _read_callback, \
+ .data_size = sizeof(listener_ ## NAME ## _data_t), \
+}
+
+extern const listener_ops_t * listener_vft[];
+
+#endif /* HICNLIGHT_LISTENER_VFT_H */
diff --git a/hicn-light/src/hicn/core/logger.c b/hicn-light/src/hicn/core/logger.c
deleted file mode 100644
index 0b9bb264c..000000000
--- a/hicn-light/src/hicn/core/logger.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _WIN32
-#include <unistd.h>
-#endif
-
-#include <errno.h>
-#include <hicn/hicn-light/config.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <parc/assert/parc_Assert.h>
-
-#include <parc/algol/parc_Memory.h>
-#include <parc/algol/parc_Object.h>
-
-#include <parc/logging/parc_Log.h>
-
-#include <hicn/core/forwarder.h>
-#include <hicn/core/logger.h>
-
-struct logger {
- PARCClock *clock;
-
- PARCLogReporter *reporter;
- PARCLog *loggerArray[LoggerFacility_END];
-};
-
-static const struct facility_to_string {
- LoggerFacility facility;
- const char *string;
-} _facilityToString[] = {
- {.facility = LoggerFacility_Config, .string = "Config"},
- {.facility = LoggerFacility_Core, .string = "Core"},
- {.facility = LoggerFacility_IO, .string = "IO"},
- {.facility = LoggerFacility_Message, .string = "Message"},
- {.facility = LoggerFacility_Processor, .string = "Processor"},
- {.facility = LoggerFacility_Strategy, .string = "Strategy"},
- {.facility = 0, .string = NULL}};
-
-const char *logger_FacilityString(LoggerFacility facility) {
- for (int i = 0; _facilityToString[i].string != NULL; i++) {
- if (_facilityToString[i].facility == facility) {
- return _facilityToString[i].string;
- }
- }
- return "Unknown";
-}
-
-static void _allocateLoggers(Logger *logger, PARCLogReporter *reporter) {
- parcTrapUnexpectedStateIf(
- logger->reporter != NULL,
- "Trying to allocate a reporter when the previous one is not null");
- logger->reporter = parcLogReporter_Acquire(reporter);
-
- char hostname[255];
- int gotHostName = gethostname(hostname, 255);
- if (gotHostName < 0) {
- snprintf(hostname, 255, "unknown");
- }
-
- for (int i = 0; i < LoggerFacility_END; i++) {
- logger->loggerArray[i] = parcLog_Create(hostname, logger_FacilityString(i),
- "forwarder", logger->reporter);
- parcLog_SetLevel(logger->loggerArray[i], PARCLogLevel_Error);
- }
-}
-
-static void _releaseLoggers(Logger *logger) {
- for (int i = 0; i < LoggerFacility_END; i++) {
- parcLog_Release(&logger->loggerArray[i]);
- }
- parcLogReporter_Release(&logger->reporter);
-}
-
-static void _destroyer(Logger **loggerPtr) {
- Logger *logger = *loggerPtr;
- _releaseLoggers(logger);
- parcClock_Release(&(*loggerPtr)->clock);
-}
-
-parcObject_ExtendPARCObject(Logger, _destroyer, NULL, NULL, NULL, NULL, NULL,
- NULL);
-
-parcObject_ImplementAcquire(logger, Logger);
-
-parcObject_ImplementRelease(logger, Logger);
-
-Logger *logger_Create(PARCLogReporter *reporter, const PARCClock *clock) {
- parcAssertNotNull(reporter, "Parameter reporter must be non-null");
- parcAssertNotNull(clock, "Parameter clock must be non-null");
-
- Logger *logger = parcObject_CreateAndClearInstance(Logger);
- if (logger) {
- logger->clock = parcClock_Acquire(clock);
- _allocateLoggers(logger, reporter);
- }
-
- return logger;
-}
-
-void logger_SetReporter(Logger *logger, PARCLogReporter *reporter) {
- parcAssertNotNull(logger, "Parameter logger must be non-null");
-
- // save the log level state
- PARCLogLevel savedLevels[LoggerFacility_END];
- for (int i = 0; i < LoggerFacility_END; i++) {
- savedLevels[i] = parcLog_GetLevel(logger->loggerArray[i]);
- }
-
- _releaseLoggers(logger);
-
- _allocateLoggers(logger, reporter);
-
- // restore log level state
- for (int i = 0; i < LoggerFacility_END; i++) {
- parcLog_SetLevel(logger->loggerArray[i], savedLevels[i]);
- }
-}
-
-void logger_SetClock(Logger *logger, PARCClock *clock) {
- parcAssertNotNull(logger, "Parameter logger must be non-null");
- parcClock_Release(&logger->clock);
- logger->clock = parcClock_Acquire(clock);
-}
-
-static void _assertInvariants(const Logger *logger, LoggerFacility facility) {
- parcAssertNotNull(logger, "Parameter logger must be non-null");
- parcTrapOutOfBoundsIf(facility >= LoggerFacility_END, "Invalid facility %d",
- facility);
-}
-
-void logger_SetLogLevel(Logger *logger, LoggerFacility facility,
- PARCLogLevel minimumLevel) {
- _assertInvariants(logger, facility);
- PARCLog *log = logger->loggerArray[facility];
- parcLog_SetLevel(log, minimumLevel);
-}
-
-bool logger_IsLoggable(const Logger *logger, LoggerFacility facility,
- PARCLogLevel level) {
- _assertInvariants(logger, facility);
- PARCLog *log = logger->loggerArray[facility];
- return parcLog_IsLoggable(log, level);
-}
-
-void logger_Log(Logger *logger, LoggerFacility facility, PARCLogLevel level,
- const char *module, const char *format, ...) {
- if (logger_IsLoggable(logger, facility, level)) {
- // this is logged as the messageid
- uint64_t logtime = parcClock_GetTime(logger->clock);
-
- // logger_IsLoggable asserted invariants so we know facility is in bounds
- PARCLog *log = logger->loggerArray[facility];
-
- va_list va;
- va_start(va, format);
-
- parcLog_MessageVaList(log, level, logtime, format, va);
-
- va_end(va);
- }
-}
diff --git a/hicn-light/src/hicn/core/logger.h b/hicn-light/src/hicn/core/logger.h
deleted file mode 100644
index 8ab741f40..000000000
--- a/hicn-light/src/hicn/core/logger.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @file logger.h
- * @brief Logger for the hicn-light forwarder
- *
- * A facility based logger to allow selective logging from different parts of
- * hicn-light
- *
- */
-
-#ifndef logger_h
-#define logger_h
-
-#ifndef _WIN32
-#include <sys/time.h>
-#endif
-#include <parc/algol/parc_Buffer.h>
-#include <parc/algol/parc_Clock.h>
-#include <parc/logging/parc_LogLevel.h>
-#include <parc/logging/parc_LogReporter.h>
-#include <stdarg.h>
-
-struct logger;
-typedef struct logger Logger;
-
-/**
- * CONFIG faciilty concerns anything in the /config directory
- * CORE concerns anything in the /core directory
- * IO concerns anything in the /io directory (listeners, connectors, tcp,
- * ethernet, etc.) PROCESSOR concerns FIB, PIT, CS MESSAGE concerns message
- * events, like parsing
- */
-typedef enum {
- LoggerFacility_Config,
- LoggerFacility_Core,
- LoggerFacility_IO,
- LoggerFacility_Processor,
- LoggerFacility_Message,
- LoggerFacility_Strategy,
- LoggerFacility_END // sentinel value
-} LoggerFacility;
-
-/**
- * Returns a string representation of a facility
- *
- * Do not free the returned value.
- *
- * @param [in] facility The facility to change to a string
- *
- * @retval string A string representation of the facility
- */
-const char *logger_FacilityString(LoggerFacility facility);
-
-/**
- * Returns a string representation of a log level
- *
- * Do not free the returned value.
- *
- * @param [in] level The level to change to a string
- *
- * @retval string A string representation of the level
- */
-const char *logger_LevelString(PARCLogLevel level);
-
-/**
- * Create a logger that uses a given writer and clock
- *
- * <#Paragraphs Of Explanation#>
- *
- * @param [in] writer The output writer
- * @param [in] clock The clock to use for log messages
- *
- * @retval non-null An allocated logger
- * @retval null An error
- */
-Logger *logger_Create(PARCLogReporter *reporter, const PARCClock *clock);
-
-/**
- * Release logger
- */
-void logger_Release(Logger **loggerPtr);
-
-/**
- * Acquire logger
- */
-Logger *logger_Acquire(const Logger *logger);
-
-/**
- * Sets the minimum log level for a facility
- *
- * The default log level is ERROR. For a message to be logged, it must be of
- * equal or higher log level.
- *
- * @param [in] logger An allocated logger
- * @param [in] facility The facility to set the log level for
- * @param [in] The minimum level to log
- *
- */
-void logger_SetLogLevel(Logger *logger, LoggerFacility facility,
- PARCLogLevel minimumLevel);
-
-/**
- * Tests if the log level would be logged
- *
- * If the facility would log the given level, returns true. May be used as a
- * guard around expensive logging functions.
- *
- * @param [in] logger An allocated logger
- * @param [in] facility The facility to test
- * @param [in] The level to test
- *
- * @retval true The given facility would log the given level
- * @retval false A message of the given level would not be logged
- *
- */
-bool logger_IsLoggable(const Logger *logger, LoggerFacility facility,
- PARCLogLevel level);
-
-/**
- * Log a message
- *
- * The message will only be logged if it is loggable (logger_IsLoggable returns
- * true).
- *
- * @param [in] logger An allocated Logger
- * @param [in] facility The facility to log under
- * @param [in] level The log level of the message
- * @param [in] module The specific module logging the message
- * @param [in] format The message with varargs
- *
- */
-void logger_Log(Logger *logger, LoggerFacility facility, PARCLogLevel level,
- const char *module, const char *format, ...);
-
-/**
- * Switch the logger to a new reporter
- *
- * Will close the old reporter and re-setup the internal loggers to use the new
- * reporter. All current log level settings are preserved.
- *
- * @param [in] logger An allocated Logger
- * @param [in] reporter An allocated PARCLogReporter
- */
-void logger_SetReporter(Logger *logger, PARCLogReporter *reporter);
-
-/**
- * Set a new clock to use with the logger
- *
- * The logger will start getting the time (logged as the messageid) from the
- * specified clock
- *
- * @param [in] logger An allocated Logger
- * @param [in] clock An allocated PARCClock
- */
-void logger_SetClock(Logger *logger, PARCClock *clock);
-#endif // logger_h
diff --git a/hicn-light/src/hicn/core/mapme.c b/hicn-light/src/hicn/core/mapme.c
index a22d01ae7..4a254c701 100644
--- a/hicn-light/src/hicn/core/mapme.c
+++ b/hicn-light/src/hicn/core/mapme.c
@@ -16,6 +16,98 @@
/**
* @file mapme.c
* @brief MAP-Me : AnchorLess Producer Mobility Management.
+ *
+ * TODO:
+ * - review notification code with to integration of VPP implementation
+ * - reflect changes back in VPP
+ * - implement heuristic for update/notification selection
+ *
+ * MAP-Me hooks in forwarder
+ *
+ * A) Face table changes
+ *
+ * - face added
+ *
+ * * new local/producer face : this is a new prefix that we need to advertise
+ * on existing connections.
+ *
+ * We go over non-local connections an advertise the prefix through an IU
+ * provided that the connection satisfies the policy associated to the FIB
+ * entry. MAP-Me assumes the prefix already exists in the network, and the
+ * IU shall be discarded if the entry does not exist at the next hop. Three
+ * possibilities:
+ * . a bootstrap mechanism
+ * . we allow subprefixes of a prefix that is not empty by duplicating the
+ * FIB entry
+ * . we allow prefix creation in all circumstances : this is problematic
+ * since we might be creating spurious entries in routers for which we
+ * don't expect entries to be created.
+ *
+ * NOTE: because in general we will not allow for FIB entry creation, we
+ * cannot let the forwarder remove FIB entries with no nexthop (for instance
+ * after the producer leaves a point-of-attachment). This might creates
+ * permanent state in router's tables, but we assume it is the role of the
+ * routing plane to take care of routing entries.
+ *
+ * * new non-local face : a new face is available (eg. thanks to the face
+ * manager, after the node has connection to a new WiFi/LTE access point),
+ * and we thus need to advertise all local/producer prefixes onto this
+ * interface.
+ *
+ * For this, we currently scan the FIB for entries that have at least one
+ * local/producer face in nexthops, advertise the prefix on this new
+ * connection provided that it satisfies the associated policy.
+ *
+ * - face removed
+ *
+ * Currently, we take no action when a face is removed. It might however be a
+ * signal that a producer application is no more running at a given node, and
+ * that we can temporarily disable the forwarding towards that path.
+ *
+ * - face up / down
+ *
+ * - face nexthop added
+ *
+ * - face changed priority/tags
+ *
+ * B) Interest and Data forwarder path
+ *
+ * mapme_on_interest
+ *
+ * mapme_on_data
+ *
+ *
+ * EVENTS
+ * NH_SET
+ * NH_ADD
+ * PH_ADD
+ * PH_DEL
+ *
+ * C) Retransmission management
+ *
+ * Data structure
+ *
+ * mapme_on_timeout
+ *
+ *
+ * This allows us to define a convenient API for implementing MAP-Me:
+ *
+ * mapme_on_face_event XXX rename
+ *
+ * mapme_send_to_nexthops(entry, nexthops)
+ *
+ * mapme_send_to_nexthop(entry, nexthop)
+ * A special case of the previous function when we only need to send to a
+ * single nexthop. This is because we might have some processing to do before
+ * iterating on nexthops (eg clear FIB) XXX TO BE CONFIRMED.
+ *
+ * mapme_maybe_send_to_nexthops(entry, nexthops)
+ * XXX Prev nexthops stored in FIB entry
+ * XXX this is valid for which prefixes ?
+ *
+ * mapme_send_to_all_nexthops
+ *
+ *
*/
#ifdef WITH_MAPME
@@ -25,90 +117,123 @@
#include <stdio.h> // printf
#include <hicn/core/connection.h>
-#include <hicn/core/connectionList.h>
#include <hicn/core/forwarder.h>
-#include <hicn/core/logger.h>
-#include <hicn/core/message.h>
+#include <hicn/core/msgbuf.h>
#include <hicn/core/messagePacketType.h> // packet types
#include <hicn/core/ticks.h>
-#include <hicn/processor/fibEntry.h>
-#include <hicn/processor/pitEntry.h>
-
-#include <parc/algol/parc_HashMap.h>
-#include <parc/algol/parc_Iterator.h>
-#include <parc/algol/parc_Unsigned.h>
-#include <parc/assert/parc_Assert.h>
+#include <hicn/core/fib_entry.h>
+#include <hicn/core/pit.h>
+#include <hicn/base/loop.h>
+#include <hicn/util/log.h>
#define MS2NS(x) x * 1000000
#define T2NS(x) forwarder_TicksToNanos(x)
+//#define MAPME_ALLOW_NONEXISTING_FIB_ENTRY
#define MAPME_DEFAULT_TU 5000 /* ms */
#define MAPME_DEFAULT_RETX 500 /* ms */
-#define MAX_RETX 3
+#define MAPME_DEFAULT_DISCOVERY false
+#define MAPME_DEFAULT_PROTOCOL IPPROTO_IPV6
+#define MAPME_MAX_RETX 3
+#define MTU 1500 // XXX TODO Mutualize this define
-#define NOT_A_NOTIFICATION false
-#define NO_INGRESS 0
+#define DONT_QUEUE false
#define TIMER_NO_REPEAT false
-#define DO_DISCOVERY 1
#define MAPME_INVALID_DICOVERY_SEQ -1
+#define INIT_SEQ 0
-#define LOG_FACILITY LoggerFacility_Core
+#define foreach_mapme_event \
+ _(UNDEFINED) \
+ _(FACE_ADD) \
+ _(FACE_DEL) \
+ _(NH_SET) \
+ _(NH_ADD) \
+ _(PH_ADD) \
+ _(PH_DEL) \
+ _(N)
+
+typedef enum {
+#define _(x) MAPME_EVENT_ ## x,
+ foreach_mapme_event
+#undef _
+} mapme_event_t;
-#define LOG(mapme, log_level, fmt, ...) \
- do { \
- Logger *logger = forwarder_GetLogger(mapme->forwarder); \
- if (logger_IsLoggable(logger, LOG_FACILITY, log_level)) { \
- logger_Log(logger, LOG_FACILITY, log_level, __func__, fmt, \
- ##__VA_ARGS__); \
- } \
- } while (0)
+/*
+ * We need a retransmission pool holding all necessary information for crafting
+ * special interests, thus including both the DPO and the prefix associated to
+ * it.
+ */
+#define NUM_RETX_ENTRIES 100
+#define NUM_RETX_SLOT 2
-#define WARN(mapme, fmt, ...) \
- LOG(mapme, PARCLogLevel_Warning, fmt, ##__VA_ARGS__)
-#define ERR(mapme, fmt, ...) LOG(mapme, PARCLogLevel_Error, fmt, ##__VA_ARGS__)
-#define INFO(mapme, fmt, ...) LOG(mapme, PARCLogLevel_Info, fmt, ##__VA_ARGS__)
-#define DEBUG(mapme, fmt, ...) \
- LOG(mapme, PARCLogLevel_Debug, fmt, ##__VA_ARGS__)
+typedef struct {
+ hicn_prefix_t prefix;
+ fib_entry_t * entry;
+ uint8_t retx_count; // Number of retransmissions since last tfib addition
+} mapme_retx_t;
/**
* MAP-Me state data structure
*/
-struct mapme {
- uint32_t retx; /* ms */
- uint32_t Tu; /* ms */
- bool removeFibEntries;
+struct mapme_s {
+ /* Options XXX mapme_conf_t ! */
+ uint32_t retx; /* retx timeout (in ms) */
+ uint32_t timescale; /* timescale (in ms) */
+ bool discovery; /* discovery flag */
+ int protocol;
- Forwarder *forwarder;
+ /*
+ * Retransmissions
+ * Lite calendar queue with NUM_RETX_SLOT slots
+ */
+ int timer_fd;
+ mapme_retx_t retx_array[NUM_RETX_SLOT][NUM_RETX_ENTRIES];
+ uint8_t retx_len[NUM_RETX_SLOT];
+ uint8_t cur;
+ uint8_t idle;
+
+ forwarder_t * forwarder;
};
-static MapMe MapMeDefault = {.retx = MAPME_DEFAULT_RETX,
- .Tu = MAPME_DEFAULT_TU,
- .removeFibEntries = false};
+#define NEXT_SLOT(CUR) (1-CUR)
+#define CUR mapme->retx_array[mapme->cur]
+#define NXT mapme->retx_array[NEXT_SLOT(mapme->cur)]
+#define CURLEN mapme->retx_len[mapme->cur]
+#define NXTLEN mapme->retx_len[NEXT_SLOT(mapme->cur)]
+
+static mapme_t mapme_default = {
+ .retx = MAPME_DEFAULT_RETX,
+ .timescale = MAPME_DEFAULT_TU,
+ .discovery = MAPME_DEFAULT_DISCOVERY,
+ .protocol = MAPME_DEFAULT_PROTOCOL,
+
+ .timer_fd = -1,
+// .retx_array = {{ 0 }}, // memset
+ .retx_len = { 0 },
+ .cur = 0, /* current slot */
+ .idle = 0,
+};
/******************************************************************************/
-bool mapme_create(MapMe **mapme, Forwarder *forwarder) {
- *mapme = malloc(sizeof(MapMe));
- if (!mapme) goto ERR_MALLOC;
-
- /* Internal state : set default values */
- memcpy(*mapme, &MapMeDefault, sizeof(MapMe));
-
- (*mapme)->forwarder = forwarder;
+mapme_t *
+mapme_create(void * forwarder)
+{
+ mapme_t * mapme = malloc(sizeof(mapme_t));
+ if (!mapme)
+ return NULL;
- /* As there is no face table and no related events, we need to install hooks
- * in various places in the forwarder, where both control commands and
- * signalization are processed.
- */
+ /* Internal state : set default values */
+ memcpy(mapme, &mapme_default, sizeof(mapme_t));
+ memset(mapme->retx_array, 0, NUM_RETX_SLOT * NUM_RETX_ENTRIES);
- return true;
+ mapme->forwarder = forwarder;
-ERR_MALLOC:
- return false;
+ return mapme;
}
-void mapme_free(MapMe *mapme)
+void mapme_free(mapme_t * mapme)
{
free(mapme);
}
@@ -117,191 +242,37 @@ void mapme_free(MapMe *mapme)
* TFIB
******************************************************************************/
-#define INVALID_SEQ 0
-#define INIT_SEQ 0
typedef struct {
- uint32_t seq;
- PARCHashMap *nexthops;
- /* Update/Notification heuristic */
- Ticks lastAckedUpdate;
-} MapMeTFIB;
-
-static MapMeTFIB *mapmeTFIB_Create() {
- MapMeTFIB *tfib;
- tfib = malloc(sizeof(MapMeTFIB));
- if (!tfib) goto ERR_MALLOC;
- tfib->seq = INIT_SEQ;
- tfib->lastAckedUpdate = 0;
- tfib->nexthops = parcHashMap_Create();
- if (!tfib->nexthops) goto ERR_HASHMAP;
-
- return tfib;
-
-ERR_HASHMAP:
- free(tfib);
-ERR_MALLOC:
- return NULL;
-}
-
-void mapmeTFIB_Release(MapMeTFIB **tfibPtr) {
- MapMeTFIB *tfib = *tfibPtr;
- /* TODO; Release all timers */
- parcHashMap_Release(&tfib->nexthops);
- free(tfib);
- *tfibPtr = NULL;
-}
-
-/**
- * @function mapme_CreateTFIB
- * @abstract Associate a new TFIB entry to a FIB entry.
- * @param [in] - Pointer to the FIB entry.
- * @return Boolean indicating the success of the operation.
- */
-static void mapme_CreateTFIB(FibEntry *fibEntry) {
- MapMeTFIB *tfib;
-
- /* Make sure we don't already have an associated TFIB entry */
- tfib = fibEntry_getUserData(fibEntry);
- // assertNull(tfib);
-
- tfib = mapmeTFIB_Create();
- fibEntry_setUserData(fibEntry, tfib, (void (*)(void **))mapmeTFIB_Release);
-}
-
-#define TFIB(fibEntry) ((MapMeTFIB *)fibEntry_getUserData(fibEntry))
-
-static const PARCEventTimer *mapmeTFIB_Get(const MapMeTFIB *tfib,
- unsigned conn_id) {
- const PARCEventTimer *timer;
- const PARCBuffer *buffer;
- PARCUnsigned *cid = parcUnsigned_Create(conn_id);
- buffer = parcHashMap_Get(tfib->nexthops, cid);
- if (!buffer) return NULL;
- PARCByteArray *array = parcBuffer_Array(buffer);
- timer = *((PARCEventTimer **)parcByteArray_Array(array));
- parcUnsigned_Release(&cid);
- return timer;
-}
+ // XXX We need magic number to know whether the TFIB was initialized or not
+ // ... or merge it inside the real data structure.
+ // NOTE: in VPP we reuse the nexthops in opposite order to gain room
+ // XXX need enough space in user_data !!
+ uint32_t seq;
+ nexthops_t nexthops; // XXX useless shadow structure
+ /* Update/Notification heuristic */
+ Ticks last_acked_update;
+} mapme_tfib_t;
+
+#define TFIB(FIB_ENTRY) ((mapme_tfib_t * )fib_entry_get_user_data(FIB_ENTRY))
-static void mapmeTFIB_Put(MapMeTFIB *tfib, unsigned conn_id,
- const PARCEventTimer *timer) {
- /* NOTE: Timers are not objects (the only class not being an object in
- * fact), and as such, we cannot use them as values for the HashMap.
- * Just like for unsigned we needed the PARC wrapper.
- * There is no wrapper for pointers, so we use Arrays, which has an ubly
- * syntax...
- */
- PARCUnsigned *cid = parcUnsigned_Create(conn_id);
- PARCBuffer *buffer =
- parcBuffer_CreateFromArray(&timer, sizeof(PARCEventTimer *));
- parcHashMap_Put(tfib->nexthops, cid, buffer);
- parcUnsigned_Release(&cid);
- parcBuffer_Release(&buffer);
-}
-
-static void mapmeTFIB_Remove(MapMeTFIB *tfib, unsigned conn_id) {
- // Who releases the timer ?
- PARCUnsigned *cid = parcUnsigned_Create(conn_id);
- parcHashMap_Remove(tfib->nexthops, cid);
- parcUnsigned_Release(&cid);
-}
-
-static PARCIterator *mapmeTFIB_CreateKeyIterator(const MapMeTFIB *tfib) {
- return parcHashMap_CreateKeyIterator(tfib->nexthops);
-}
-
-int hicn_prefix_from_name(const Name *name, hicn_prefix_t *prefix) {
- NameBitvector *bv = name_GetContentName(name);
- ip_prefix_t ip_prefix;
- nameBitvector_ToIPAddress(bv, &ip_prefix);
-
- /* The name length will be equal to ip address' prefix length */
- return hicn_prefix_create_from_ip_prefix(&ip_prefix, prefix);
-}
-
-static Message *mapme_createMessage(const MapMe *mapme, const Name *name,
- mapme_params_t *params) {
- Ticks now = forwarder_GetTicks(mapme->forwarder);
- Logger *logger = logger_Acquire(forwarder_GetLogger(mapme->forwarder));
-
- INFO(mapme, "[MAP-Me] CreateMessage type=%d seq=%d", params->type,
- params->seq);
-
- size_t size = (params->protocol == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN
- : HICN_MAPME_V4_HDRLEN;
- uint8_t *icmp_pkt = parcMemory_AllocateAndClear(size);
-
- hicn_prefix_t prefix;
- int rc = hicn_prefix_from_name(name, &prefix);
- if (rc < 0) {
- ERR(mapme, "[MAP-Me] Failed to create lib's name");
- goto ERR_NAME;
- }
-
- INFO(mapme, "[MAP-Me] Creating MAP-Me packet");
- size_t len = hicn_mapme_create_packet(icmp_pkt, &prefix, params);
- if (len == 0) {
- ERR(mapme, "[MAP-Me] Failed to create mapme packet through lib");
- goto ERR_CREATE;
- }
-
- // hicn_packet_dump(icmp_pkt, MAPME_HDRLEN);
-
- return message_CreateFromByteArray(NO_INGRESS, icmp_pkt,
- MessagePacketType_Interest, now, logger);
-
-ERR_CREATE:
-ERR_NAME:
- return NULL;
-}
-
-static Message *mapme_createAckMessage(const MapMe *mapme,
- const uint8_t *msgBuffer,
- const mapme_params_t *params) {
- Ticks now = forwarder_GetTicks(mapme->forwarder);
- Logger *logger = logger_Acquire(forwarder_GetLogger(mapme->forwarder));
-
- size_t size = (params->protocol == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN
- : HICN_MAPME_V4_HDRLEN;
- uint8_t *icmp_pkt = parcMemory_AllocateAndClear(size);
- memcpy(icmp_pkt, msgBuffer, size);
-
- size_t len = hicn_mapme_create_ack(icmp_pkt, params);
- if (len != size) {
- ERR(mapme, "[MAP-Me] Failed to create mapme ack packet through lib");
- return NULL;
- }
-
- return message_CreateFromByteArray(
- NO_INGRESS, icmp_pkt, MessagePacketType_ContentObject, now, logger);
+void
+mapme_tfib_initialize(mapme_tfib_t * tfib)
+{
+ tfib->seq = INIT_SEQ;
+ tfib->last_acked_update = 0;
+ nexthops_set_len(&tfib->nexthops, 0);
}
-struct setFacePendingArgs {
- const MapMe *mapme;
- const Name *name;
- FibEntry *fibEntry;
- unsigned conn_id;
- bool send;
- bool is_producer;
- uint32_t num_retx;
-};
-
-static bool mapme_setFacePending(const MapMe *mapme, const Name *name,
- FibEntry *fibEntry, unsigned conn_id,
- bool send, bool is_producer, bool clear_tfib, uint32_t num_retx);
-
-static void mapme_setFacePendingCallback(int fd, PARCEventType which_event,
- void *data) {
- struct setFacePendingArgs *args = (struct setFacePendingArgs *)data;
-
- parcAssertTrue(which_event & PARCEventType_Timeout,
- "Event incorrect, expecting %X set, got %X",
- PARCEventType_Timeout, which_event);
+int
+hicn_prefix_from_name(const Name *name, hicn_prefix_t *prefix)
+{
+ NameBitvector *bv = name_GetContentName(name);
+ ip_prefix_t ip_prefix;
+ nameBitvector_ToIPAddress(bv, &ip_prefix);
- INFO(args->mapme, "Timeout during retransmission. Re-sending");
- mapme_setFacePending(args->mapme, args->name, args->fibEntry, args->conn_id,
- args->send, args->is_producer, false, args->num_retx);
+ /* The name length will be equal to ip address' prefix length */
+ return hicn_prefix_create_from_ip_prefix(&ip_prefix, prefix);
}
/**
@@ -310,369 +281,204 @@ static void mapme_setFacePendingCallback(int fd, PARCEventType which_event,
* NOTE: IN are currently disabled until the proper placeholder is agreed in the
* interest header.
*/
-static hicn_mapme_type_t mapme_getTypeFromHeuristic(const MapMe *mapme,
- FibEntry *fibEntry) {
+static
+hicn_mapme_type_t
+mapme_get_type_from_heuristic(const mapme_t * mapme, fib_entry_t * entry)
+{
+ if (fib_entry_has_local_nexthop(entry))
+ /* We are a producer for this entry, send update */
+ return UPDATE;
+
#if 0 /* interplay of IU/IN */
- if (TFIB(fibEntry)->lastAckedUpdate == 0) {
+ if (TFIB(fib_entry)->lastAckedUpdate == 0) {
return UPDATE;
} else {
- Ticks interval = now - TFIB(fibEntry)->lastAckedUpdate;
- return (T2NS(interval) > MS2NS(mapme->Tu)) ? UPDATE : NOTIFICATION;
+ Ticks interval = now - TFIB(fib_entry)->lastAckedUpdate;
+ return (T2NS(interval) > MS2NS(mapme->timescale)) ? UPDATE : NOTIFICATION;
}
#else /* Always send IU */
- return UPDATE;
+ return UPDATE;
#endif
}
-static bool mapme_setFacePending(const MapMe *mapme, const Name *name,
- FibEntry *fibEntry, unsigned conn_id,
- bool send, bool is_producer, bool clear_tfib, uint32_t num_retx) {
- int rc;
-
- INFO(mapme, "[MAP-Me] SetFacePending connection=%d prefix=XX retx=%d",
- conn_id, num_retx);
-
- /* NOTE: if the face is pending an we receive an IN, maybe we should not
- * cancel the timer
- */
- Dispatcher *dispatcher = forwarder_GetDispatcher(mapme->forwarder);
- PARCEventTimer *timer;
-
- /* Safeguard during retransmissions */
- if (!TFIB(fibEntry))
- return true;
-
- /*
- * On the producer side, we have to clear the TFIB everytime we change the list
- * of adjacencies, otherwise retransmissions will occur to preserve them.
- */
- if (clear_tfib) {
- /*
- * It is likely we cannot iterator and remove elements from the hashmap at
- * the same time, so we proceed in two steps
- */
- if (parcHashMap_Size(TFIB(fibEntry)->nexthops) > 0) {
-
- NumberSet * conns = numberSet_Create();
-
- PARCIterator *it = parcHashMap_CreateKeyIterator(TFIB(fibEntry)->nexthops);
- while (parcIterator_HasNext(it)) {
- PARCUnsigned *cid = parcIterator_Next(it);
- unsigned conn_id = parcUnsigned_GetUnsigned(cid);
- numberSet_Add(conns, conn_id);
- }
- parcIterator_Release(&it);
-
- for (size_t i = 0; i < numberSet_Length(conns); i++) {
- unsigned conn_id = numberSet_GetItem(conns, i);
- PARCEventTimer *oldTimer = (PARCEventTimer *)mapmeTFIB_Get(TFIB(fibEntry), conn_id);
- if (oldTimer)
- parcEventTimer_Stop(oldTimer);
- mapmeTFIB_Remove(TFIB(fibEntry), conn_id);
- }
-
- numberSet_Release(&conns);
- }
- }
-
- // NOTE
- // - at producer, send always true, we always send something reliably so we
- // set the timer.
- // - in the network, we always forward an IU, and never an IN
- //if (is_producer || send) {
- if (send) {
+
+/**
+ *
+ * Here nexthops is not necessarily FIB nexthops as we might advertise given FIB
+ * entries on various other connections.
+ */
+/* NOTE: if the face is pending an we receive an IN, maybe we should not cancel
+ * the timer
+ */
+// XXX Make sure this function is never called for Notifications
+// XXX overall review notification code and integrate it in VPP
+int
+mapme_send_to_nexthops(const mapme_t * mapme, fib_entry_t * entry,
+ const nexthops_t * nexthops)
+{
+ mapme_tfib_t * tfib = TFIB(entry);
+
+ tfib->seq++;
+
+ const Name *name = fib_entry_get_prefix(entry);
+
+ char *name_str = name_ToString(name);
+ DEBUG("sending IU/IN for name %s on all nexthops", name_str);
+ free(name_str);
+
mapme_params_t params = {
- .protocol = IPPROTO_IPV6,
- .type = is_producer ? mapme_getTypeFromHeuristic(mapme, fibEntry) : UPDATE,
- .seq = TFIB(fibEntry)->seq};
- Message *special_interest = mapme_createMessage(mapme, name, &params);
- if (!special_interest) {
- INFO(mapme, "[MAP-Me] Could not create special interest");
- return false;
+ .protocol = mapme->protocol,
+ .type = mapme_get_type_from_heuristic(mapme, entry),
+ .seq = tfib->seq,
+ };
+
+ hicn_prefix_t prefix;
+ if (hicn_prefix_from_name(name, &prefix) < 0) {
+ ERROR("Failed to create lib's name");
+ return -1;
}
- const ConnectionTable *table =
- forwarder_GetConnectionTable(mapme->forwarder);
- const Connection *conn =
- connectionTable_FindById((ConnectionTable *)table, conn_id);
- if (conn) {
- const Name * name = message_GetName(special_interest);
- char * name_str = name_ToString(name);
- INFO(mapme, "[MAP-Me] Sending MAP-Me packet name=%s seq=%d conn=%d",
- name_str, params.seq, conn_id);
- free(name_str);
- connection_ReSend(conn, special_interest, NOT_A_NOTIFICATION);
- } else {
- INFO(mapme, "[MAP-Me] Stopped retransmissions as face went down");
+ uint8_t packet[MTU];
+ size_t size = hicn_mapme_create_packet(packet, &prefix, &params);
+ if (size <= 0) {
+ ERROR("Could not create MAP-Me packet");
+ return -1;
}
- if (num_retx < MAX_RETX) {
- INFO(mapme, "[MAP-Me] - Scheduling retransmission\n");
- /* Schedule retransmission */
- struct setFacePendingArgs *args =
- malloc(sizeof(struct setFacePendingArgs));
- if (!args) goto ERR_MALLOC;
- args->mapme = mapme;
- args->name = name;
- args->fibEntry = fibEntry;
- args->conn_id = conn_id;
- args->send = send;
- args->is_producer = is_producer;
- args->num_retx = num_retx + 1;
-
- timer = dispatcher_CreateTimer(dispatcher, TIMER_NO_REPEAT,
- mapme_setFacePendingCallback, args);
- struct timeval timeout = {mapme->retx / 1000,
- (mapme->retx % 1000) * 1000};
- rc = parcEventTimer_Start(timer, &timeout);
- if (rc < 0) goto ERR_TIMER;
- } else {
- INFO(mapme, "[MAP-Me] Last retransmission.");
- timer = NULL;
- }
- } else {
- INFO(mapme, "[MAP-Me] - not forwarding as send is False");
- timer = NULL;
- }
-
- PARCEventTimer *oldTimer =
- (PARCEventTimer *)mapmeTFIB_Get(TFIB(fibEntry), conn_id);
- if (oldTimer) {
- INFO(mapme, "[MAP-Me] - Found old timer, would need to cancel !");
- // parcEventTimer_Stop(oldTimer);
- }
- INFO(mapme, "[MAP-Me] - Putting new timer in TFIB");
- if (timer) mapmeTFIB_Put(TFIB(fibEntry), conn_id, timer);
-
- return true;
-
-ERR_MALLOC:
-ERR_TIMER:
- return false;
-}
+ /*
+ * We used to clear TFIB everytime which is wrong.
+ * XXX When to clear TFIB ??
+ *
+ * On the producer side, we have to clear the TFIB everytime we change the list
+ * of adjacencies, otherwise retransmissions will occur to preserve them.
+ */
-/*------------------------------------------------------------------------------
- * Event handling
- *----------------------------------------------------------------------------*/
+ nexthops_clear(&tfib->nexthops);
-/*
- * Return true if we have at least one local connection as next hop
- */
-static bool mapme_hasLocalNextHops(const MapMe *mapme,
- const FibEntry *fibEntry) {
- const NumberSet *nexthops = fibEntry_GetNexthops(fibEntry);
- const ConnectionTable *table = forwarder_GetConnectionTable(mapme->forwarder);
-
- for (size_t j = 0; j < fibEntry_NexthopCount(fibEntry); j++) {
- /* Retrieve Nexthop #j */
- unsigned conn_id = numberSet_GetItem(nexthops, j);
- const Connection *conn =
- connectionTable_FindById((ConnectionTable *)table, conn_id);
-
- /* Ignore non-local connections */
- if (!connection_IsLocal(conn)) continue;
- /* We don't need to test against conn_added since we don't
- * expect it to have any entry in the FIB */
-
- return true;
- }
- return false;
+ connection_table_t * table = forwarder_get_connection_table(mapme->forwarder);
+
+ unsigned nexthop;
+ nexthops_foreach(nexthops, nexthop, {
+ DEBUG("sending packet on connection %d", nexthop);
+ const connection_t * conn = connection_table_get_by_id(table, nexthop);
+ connection_send_packet(conn, packet, size);
+ });
+
+ return 0;
}
-void
-mapme_send_updates(const MapMe * mapme, FibEntry * fibEntry, const NumberSet * nexthops)
+int
+mapme_send_to_nexthop(const mapme_t * mapme, fib_entry_t * entry, unsigned nexthop)
{
- if (!TFIB(fibEntry)) /* Create TFIB associated to FIB entry */
- mapme_CreateTFIB(fibEntry);
- TFIB(fibEntry)->seq++;
-
- const Name *name = fibEntry_GetPrefix(fibEntry);
- char *name_str = name_ToString(name);
- bool clear_tfib = true;
- for (size_t j = 0; j < numberSet_Length(nexthops); j++) {
- unsigned nexthop_id = numberSet_GetItem(nexthops, j);
- INFO(mapme, "[MAP-Me] sending IU/IN for name %s on connection %d", name_str,
- nexthop_id);
- mapme_setFacePending(mapme, name, fibEntry, nexthop_id, true, true, clear_tfib, 0);
- clear_tfib = false;
- }
- free(name_str);
+ nexthops_t nexthops = NEXTHOPS_EMPTY;
+ nexthops_add(&nexthops, nexthop);
+
+ return mapme_send_to_nexthops(mapme, entry, &nexthops);
}
+/**
+ *
+ * Here nexthops is not necessarily FIB nexthops as we might advertise given FIB
+ * entries on various other connections.
+ */
void
-mapme_maybe_send_updates(const MapMe * mapme, FibEntry * fibEntry, const NumberSet * nexthops)
+mapme_maybe_send_to_nexthops(const mapme_t * mapme, fib_entry_t * fib_entry,
+ const nexthops_t * nexthops)
{
- /* Detect change */
- NumberSet * previous_nexthops = fibEntry_GetPreviousNextHops(fibEntry);
- if (numberSet_Equals(nexthops, previous_nexthops)) {
- INFO(mapme, "[MAP-Me] No change in nexthops");
- return;
- }
- fibEntry_SetPreviousNextHops(fibEntry, nexthops);
-
- mapme_send_updates(mapme, fibEntry, nexthops);
+ /* Detect change */
+ if (!fib_entry_nexthops_changed(fib_entry)) {
+ INFO("No change in nexthops");
+ return;
+ }
+ fib_entry_set_prev_nexthops(fib_entry);
+
+ mapme_send_to_nexthops(mapme, fib_entry, nexthops);
}
void
-mapme_reconsiderFibEntry(const MapMe *mapme, FibEntry * fibEntry)
+mapme_send_to_all_nexthops(const mapme_t *mapme, fib_entry_t * entry)
{
- /*
- * Skip entries that do not correspond to a producer ( / have a locally
- * served prefix / have no local connection as next hop)
- */
- if (!mapme_hasLocalNextHops(mapme, fibEntry))
- return;
+ /* Apply the policy of the fib_entry over all neighbours */
+ nexthops_t new_nexthops;
+ nexthops_t * nexthops = fib_entry_get_available_nexthops(entry, ~0, &new_nexthops);
- /* Apply the policy of the fibEntry over all neighbours */
- NumberSet * available_nexthops = fibEntry_GetAvailableNextHops(fibEntry, ~0);
-
- /* Advertise prefix on all available next hops (if needed) */
- mapme_send_updates(mapme, fibEntry, available_nexthops);
-
- numberSet_Release(&available_nexthops);
+ /* Advertise prefix on all available next hops (if needed) */
+ mapme_maybe_send_to_nexthops(mapme, entry, nexthops);
}
/*
* Callback called everytime a new connection is created by the control protocol
*/
void
-mapme_onConnectionEvent(const MapMe *mapme, const Connection *conn_added, connection_event_t event) {
- /* Does the priority change impacts the default route selection; if so,
- * advertise the prefix on this default route. If there are many default
- * routes, either v4 v6, or many connections as next hops on this default
- * route, then send to all.
- */
- if (conn_added) {
- if (connection_IsLocal(conn_added))
- return;
-
- unsigned conn_added_id = connection_GetConnectionId(conn_added);
- switch(event) {
- case CONNECTION_EVENT_CREATE:
- INFO(mapme, "[MAP-Me] Connection %d got created", conn_added_id);
- break;
- case CONNECTION_EVENT_DELETE:
- INFO(mapme, "[MAP-Me] Connection %d got deleted", conn_added_id);
- break;
- case CONNECTION_EVENT_UPDATE:
- INFO(mapme, "[MAP-Me] Connection %d got updated", conn_added_id);
- break;
- case CONNECTION_EVENT_SET_UP:
- INFO(mapme, "[MAP-Me] Connection %d went up", conn_added_id);
- break;
- case CONNECTION_EVENT_SET_DOWN:
- INFO(mapme, "[MAP-Me] Connection %d went down", conn_added_id);
- break;
- case CONNECTION_EVENT_TAGS_CHANGED:
- INFO(mapme, "[MAP-Me] Connection %d changed tags", conn_added_id);
- break;
- case CONNECTION_EVENT_PRIORITY_CHANGED:
- INFO(mapme, "[MAP-Me] Connection %d changed priority to %d",
- conn_added_id, connection_GetPriority(conn_added));
- break;
+mapme_on_connection_event(const mapme_t *mapme, const connection_t * conn_added, connection_event_t event) {
+ /* Does the priority change impacts the default route selection; if so,
+ * advertise the prefix on this default route. If there are many default
+ * routes, either v4 v6, or many connections as next hops on this default
+ * route, then send to all.
+ */
+ if (conn_added) {
+ if (connection_is_local(conn_added))
+ return;
+
+ unsigned conn_added_id = connection_get_id(conn_added);
+ switch(event) {
+ case CONNECTION_EVENT_CREATE:
+ INFO("Connection %d got created", conn_added_id);
+ break;
+ case CONNECTION_EVENT_DELETE:
+ INFO("Connection %d got deleted", conn_added_id);
+ break;
+ case CONNECTION_EVENT_UPDATE:
+ INFO("Connection %d got updated", conn_added_id);
+ break;
+ case CONNECTION_EVENT_SET_UP:
+ INFO("Connection %d went up", conn_added_id);
+ break;
+ case CONNECTION_EVENT_SET_DOWN:
+ INFO("Connection %d went down", conn_added_id);
+ break;
+ case CONNECTION_EVENT_TAGS_CHANGED:
+ INFO("Connection %d changed tags", conn_added_id);
+ break;
+ case CONNECTION_EVENT_PRIORITY_CHANGED:
+ INFO("Connection %d changed priority to %d",
+ conn_added_id, connection_get_priority(conn_added));
+ break;
+ }
}
- }
-
- /* We need to send a MapMe update on the newly selected connections for
- * each concerned fibEntry : connection is involved, or no more involved */
- FibEntryList *fiblist = forwarder_GetFibEntries(mapme->forwarder);
-
- /* Iterate a first time on the FIB to get the locally served prefixes */
- for (size_t i = 0; i < fibEntryList_Length(fiblist); i++) {
- FibEntry *fibEntry = (FibEntry *)fibEntryList_Get(fiblist, i);
- mapme_reconsiderFibEntry(mapme, fibEntry);
- }
-
- fibEntryList_Destroy(&fiblist);
-
- INFO(mapme, "[MAP-Me] Done");
-}
-#if 0
-#ifdef WITH_POLICY
-void mapme_onPolicyUpdate(const MapMe *mapme, const Connection *conn_selected, FibEntry * fibEntry)
-{
- /* Ignore local connections corresponding to applications for now */
- if (connection_IsLocal(conn_selected))
- return;
-
- unsigned conn_selected_id = connection_GetConnectionId(conn_selected);
- INFO(mapme, "[MAP-Me] New connection %d", conn_selected_id);
-
- const Name *name = fibEntry_GetPrefix(fibEntry);
-
- /* Skip entries that have no local connection as next hop */
- if (!mapme_hasLocalNextHops(mapme, fibEntry))
- return;
-
- /* This entry corresponds to a locally served prefix, set
- * Special Interest */
- if (!TFIB(fibEntry)) /* Create TFIB associated to FIB entry */
- mapme_CreateTFIB(fibEntry);
- TFIB(fibEntry)->seq++;
+ /* We need to send a MapMe update on the newly selected connections for
+ * each concerned fib_entry : connection is involved, or no more involved */
+ const fib_t * fib = forwarder_get_fib(mapme->forwarder);
+ fib_entry_t * entry;
+ fib_foreach_entry(fib, entry, {
+ if (!fib_entry_has_local_nexthop(entry))
+ continue;
+ /*
+ * On the producer side, we have to clear the TFIB everytime we change
+ * the list of adjacencies, otherwise retransmissions will occur to
+ * preserve them.
+ */
+ mapme_tfib_t * tfib = TFIB(entry);
+ nexthops_clear(&tfib->nexthops);
- char *name_str = name_ToString(name);
- INFO(mapme, "[MAP-Me] sending IU/IN for name %s on connection %d", name_str,
- conn_selected_id);
- free(name_str);
+ mapme_send_to_all_nexthops(mapme, entry);
+ });
- mapme_setFacePending(mapme, name, fibEntry, conn_selected_id, true, true, true, 0);
+ INFO("Done");
}
-#endif /* WITH_POLICY */
-#endif
/*------------------------------------------------------------------------------
* Special Interest handling
*----------------------------------------------------------------------------*/
-/**
- * @discussion This function is way too long and should be cut out
- */
-static bool mapme_onSpecialInterest(const MapMe *mapme,
- const uint8_t *msgBuffer,
- unsigned conn_in_id, hicn_prefix_t *prefix,
- mapme_params_t *params) {
- const ConnectionTable *table = forwarder_GetConnectionTable(mapme->forwarder);
- /* The cast is needed since connectionTable_FindById miss the
- * const qualifier for the first parameter */
- const Connection *conn_in =
- connectionTable_FindById((ConnectionTable *)table, conn_in_id);
- seq_t fibSeq, seq = params->seq;
- bool send = (params->type == UPDATE);
- bool rv;
-
- Name *name = name_CreateFromPacket(msgBuffer, MessagePacketType_Interest);
- name_setLen(name, prefix->len);
- char *name_str = name_ToString(name);
- INFO(mapme,
- "[MAP-Me] Ack'ed Special Interest on connection %d - prefix=%s type=XX "
- "seq=%d",
- conn_in_id, name_str, seq);
- free(name_str);
-
- /*
- * Immediately send an acknowledgement back on the ingress connection
- * We always ack, even duplicates.
- */
- Message *ack = mapme_createAckMessage(mapme, msgBuffer, params);
- if (!ack) goto ERR_ACK_CREATE;
- rv = connection_ReSend(conn_in, ack, NOT_A_NOTIFICATION);
- if (!rv) goto ERR_ACK_SEND;
- message_Release(&ack);
-
- /* EPM on FIB */
- /* only the processor has access to the FIB */
- FIB *fib = forwarder_getFib(mapme->forwarder);
-
- FibEntry *fibEntry = fib_Contains(fib, name);
- if (!fibEntry) {
- INFO(mapme, "Ignored update with no FIB entry");
- return 0;
-#if 0
- INFO(mapme,
- "[MAP-Me] - Re-creating FIB entry with next hop on connection %d",
- conn_in_id);
+#ifdef MAPME_ALLOW_NONEXISTING_FIB_ENTRY
+int
+mapme_create_fib_entry(const mapme_t * mapme, const Name * name, unsigned ingress_id)
+{
+ INFO(" - Re-creating FIB entry with next hop on connection %d",
+ ingress_id);
/*
* This might happen for a node hosting a producer which has moved.
* Destroying the face has led to removing all corresponding FIB
@@ -686,17 +492,16 @@ static bool mapme_onSpecialInterest(const MapMe *mapme,
* the message should be propagated.
*/
#ifdef WITH_POLICY
- fibEntry = fibEntry_Create(name, fwdStrategy, mapme->forwarder);
+ entry = fib_entry_Create(name, fwdStrategy, mapme->forwarder);
#else
- fibEntry = fibEntry_Create(name, fwdStrategy);
+ entry = fib_entry_Create(name, fwdStrategy);
#endif /* WITH_POLICY */
- FibEntry *lpm = fib_MatchName(fib, name);
- mapme_CreateTFIB(fibEntry);
- fib_Add(fib, fibEntry);
+ fib_entry_t *lpm = fib_MatchName(fib, name);
+ fib_Add(fib, entry);
if (!lpm) {
- TFIB(fibEntry)->seq = seq;
- fibEntry_AddNexthop(fibEntry, conn_in_id);
- return true;
+ TFIB(entry)->seq = seq;
+ fib_entry_AddNexthop(entry, ingress_id);
+ return true;
}
/*
@@ -704,279 +509,387 @@ static bool mapme_onSpecialInterest(const MapMe *mapme,
* the more specific name, and proceed as usual. Worst case we clone the
* default route...
*/
- const NumberSet *lpm_nexthops = fibEntry_GetNexthops(lpm);
+ const NumberSet *lpm_nexthops = fib_entry_nexthops_get(lpm);
for (size_t i = 0; i < numberSet_Length(lpm_nexthops); i++) {
- fibEntry_AddNexthop(fibEntry, numberSet_GetItem(lpm_nexthops, i));
+ fib_entry_AddNexthop(entry, numberSet_GetItem(lpm_nexthops, i));
}
+ return 0;
+}
#endif
- } else if (!TFIB(fibEntry)) {
- /* Create TFIB associated to FIB entry */
- INFO(mapme,
- "[MAP-Me] - Creating TFIB entry with default sequence number");
- mapme_CreateTFIB(fibEntry);
- }
-
- /*
- * In case of multihoming, we might receive a message about our own prefix, we
- * should never take it into account, nor send the IU backwards as a sign of
- * outdated propagation.
- *
- * Detection: we receive a message initially sent by ourselves, ie a message
- * for which the prefix has a local next hop in the FIB.
- */
- if (mapme_hasLocalNextHops(mapme, fibEntry)) {
- INFO(mapme, "[MAP-Me] - Received original interest... Update complete");
- return true;
- }
-
- fibSeq = TFIB(fibEntry)->seq;
- if (seq > fibSeq) {
- INFO(mapme,
- "[MAP-Me] - Higher sequence number than FIB %d, updating seq and "
- "next hops",
- fibSeq);
- /* This has to be done first to allow processing SpecialInterestAck's */
- TFIB(fibEntry)->seq = seq;
-
- /* Reliably forward the IU on all prevHops */
- INFO(mapme, "[MAP-Me] - (1/3) processing prev hops");
- if (params->type == UPDATE) {
- PARCIterator *iterator = mapmeTFIB_CreateKeyIterator(TFIB(fibEntry));
- while (parcIterator_HasNext(iterator)) {
- PARCUnsigned *cid = parcIterator_Next(iterator);
- unsigned conn_id = parcUnsigned_GetUnsigned(cid);
- INFO(mapme, "[MAP-Me] - Re-sending IU to pending connection %d",
- conn_id);
- mapme_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry,
- conn_id, false, false, false, 0);
- }
- parcIterator_Release(&iterator);
- }
- /* nextHops -> prevHops
+void
+mapme_on_timeout(mapme_t * mapme, int fd, void * data)
+{
+ assert(mapme);
+ assert(!data);
+ /* Timeout occurred, we have to retransmit IUs for all pending
+ * prefixes having entries in TFIB
*
- * We add to the list of pendingUpdates the current next hops, and
- * eventually forward them an IU too.
+ * timeouts are slotted
+ * | | | |
*
- * Exception: nextHops -> nextHops
- * Because of retransmission issues, it is possible that a second interest
- * (with same of higher sequence number) is receive from a next-hop
- * interface. In that case, the face remains a next hop.
+ * ^
+ * +- event occurred
+ * new face, wait for the second next
+ * (having two arrays and swapping cur and next)
+ * retx : put in next
*/
- const NumberSet *nexthops_old = fibEntry_GetNexthops(fibEntry);
+ mapme->idle += 1;
- /* We make a copy to be able to send IU _after_ updating next hops */
- NumberSet *nexthops = numberSet_Create();
- numberSet_AddSet(nexthops, nexthops_old);
+ for (uint8_t pos = 0; pos < CURLEN; pos++) {
+ mapme_retx_t * retx = &CUR[pos];
- /* We are considering : * -> nextHops
- *
- * If inFace was a previous hop, we need to cancel the timer and remove
- * the entry. Also, the face should be added to next hops.
- *
- * Optimization : nextHops -> nextHops
- * - no next hop to add
- * - we know that inFace was not a previous hop since it was a next hop and
- * this forms a partition. No need for a search
- */
+ if (!retx->entry) /* deleted entry */
+ continue;
+
+ mapme_tfib_t * tfib = TFIB(retx->entry);
+ assert(tfib);
+
+ /* Re-send interest for all entries */
+ mapme_send_to_all_nexthops(mapme, retx->entry);
- INFO(mapme, "[MAP-Me] - (3/3) next hops ~~> prev hops");
- PARCEventTimer *oldTimer =
- (PARCEventTimer *)mapmeTFIB_Get(TFIB(fibEntry), conn_in_id);
- if (oldTimer) {
- /* This happens if we receive an IU while we are still sending
- * one in the other direction
- */
- INFO(mapme, "[MAP-Me] - Canceled pending timer");
- parcEventTimer_Stop(oldTimer);
+ retx->retx_count++;
+ /* If we exceed the numver of retransmittion it means that all tfib
+ * entries have seens at least HICN_PARAM_RETX_MAX of retransmission
+ */
+ if (retx->retx_count < MAPME_MAX_RETX) {
+ /*
+ * We did some retransmissions, so let's reschedule a check in the
+ * next slot
+ */
+ NXT[NXTLEN++] = CUR[pos];
+ mapme->idle = 0;
+ } else {
+ WARN("Maximum retransmissions exceeded");
+ /* If we exceed the numver of retransmission it means that all TFIB
+ * entries have seens at least HICN_PARAM_RTX_MAX retransmissions.
+ * (Deletion might be slightly late).
+ *
+ * XXX document: when adding an entry in TFIB, we might exceed max
+ * retransmissions for previous entries that started retransmitting
+ * beforehand.
+ */
+ nexthops_clear(&tfib->nexthops);
+ }
}
- mapmeTFIB_Remove(TFIB(fibEntry), conn_in_id);
- /* Remove all next hops */
- for (size_t k = 0; k < numberSet_Length(nexthops); k++) {
- unsigned conn_id = numberSet_GetItem(nexthops, k);
- INFO(mapme, "[MAP-Me] - Replaced next hops by connection %d", conn_id);
- fibEntry_RemoveNexthopByConnectionId(fibEntry, conn_id);
+ /* Reset events in this slot and prepare for next one */
+ CURLEN = 0;
+ mapme->cur = NEXT_SLOT(mapme->cur);
+
+ /* After two empty slots, we disable the timer */
+ if (mapme->idle > 1) {
+ loop_unregister_timer(MAIN_LOOP, mapme->timer_fd);
+ mapme->timer_fd = -1;
}
- fibEntry_AddNexthop(fibEntry, conn_in_id);
-
- INFO(mapme, "[MAP-Me] - (2/3) processing next hops");
- bool complete = true;
- for (size_t k = 0; k < numberSet_Length(nexthops); k++) {
- unsigned conn_id = numberSet_GetItem(nexthops, k);
- INFO(mapme, " - Next hop connection %d", conn_id);
- if (conn_id == conn_in_id) {
- INFO(mapme, " . Ignored this next hop since equal to ingress face");
- continue;
- }
-
- INFO(mapme, "[MAP-Me] - Sending IU on current next hop connection %d",
- conn_id);
- mapme_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry,
- conn_id, send, false, false, 0);
- complete = false;
+}
+
+static
+void
+mapme_on_event(mapme_t * mapme, mapme_event_t event, fib_entry_t * entry,
+ unsigned ingress_id)
+{
+ switch (event) {
+#if 0
+ case HICN_MAPME_EVENT_FACE_ADD:
+ {
+ /*
+ * A face has been added:
+ * - In case of a local app face, we need to advertise a new prefix
+ * - For another local face type, we need to advertise local
+ * prefixes and schedule retransmissions
+ */
+ mapme_retx_t *retx_events = event_data;
+ for (uint8_t i = 0; i < vec_len (retx_events); i++) {
+ hicn_mapme_on_face_added(mapme, retx_events[i].dpo);
+ }
+
+ if (mapme->timer_fd == -1)
+ mapme->timer_fd = loop_register_timer(MAIN_LOOP,
+ mapme->retx, mapme, mapme_on_timeout, NULL);
+ mapme->idle = 0;
+ break;
+ }
+ case HICN_MAPME_EVENT_FACE_DEL:
+ if (mapme->timer_fd == -1)
+ mapme->timer_fd = loop_register_timer(MAIN_LOOP,
+ DEFAULT_TIMEOUT, mapme, mapme_on_timeout, NULL);
+ mapme->idle = 0;
+ break;
+#endif
+
+ case MAPME_EVENT_NH_SET:
+ /*
+ * An hICN FIB entry has been modified. All operations so far
+ * have been procedded in the nodes. Here we need to track
+ * retransmissions upon timeout: we mark the FIB entry as pending in
+ * the second-to-next slot
+ */
+
+ /*
+ * XXX Move this in doc
+ *
+ * The FIB entry has a new next hop, and its TFIB section has:
+ * - eventually previous prev hops for which a IU with a
+ * lower seqno has been sent
+ * - the prev hops that have just been added.
+ *
+ * We don't distinguish any and just send an updated IU to all
+ * of them. The retransmission of the latest IU to all
+ * facilitates the matching of ACKs to a single seqno which is
+ * the one stored in the FIB.
+ *
+ * Since we retransmit to all prev hops, we can remove this
+ * (T)FIB entry for the check at the end of the current slot.
+ */
+
+ /* Mark FIB entry as pending for second-to-next slot */
+ /*
+ * Transmit IU for all TFIB entries with latest seqno (we have
+ * at least one for sure!)
+ */
+ mapme_send_to_all_nexthops(mapme, entry);
+
+ /* Delete entry_id from retransmissions in the current slot (if present) ... */
+ /* ... and schedule it for next slot (if not already) */
+ uint8_t j;
+ for (j = 0; j < CURLEN; j++) {
+ if (CUR[j].entry == entry)
+ CUR[j].entry = NULL; /* sufficient */
+ }
+ for (j = 0; j < NXTLEN; j++) {
+ if (NXT[j].entry == entry)
+ break;
+ }
+ if (j == NXTLEN) /* not found */
+ NXT[NXTLEN++] = (mapme_retx_t) {
+ .entry = entry,
+ .retx_count = 0,
+ };
+
+ if (mapme->timer_fd == -1)
+ mapme->timer_fd = loop_register_timer(MAIN_LOOP,
+ mapme->retx, mapme, mapme_on_timeout, NULL);
+ mapme->idle = 0;
+ break;
+
+ case MAPME_EVENT_NH_ADD:
+ /*
+ * XXX move this in doc
+ *
+ * As per the description of states, this event should add the face
+ * to the list of next hops, and eventually remove it from TFIB.
+ * This corresponds to the multipath case.
+ *
+ * In all cases, we assume the propagation was already done when the first
+ * interest with the same sequence number was received, so we stop here
+ * No change in TFIB = no IU to send
+ *
+ * No change in timers.
+ */
+
+ // XXX useless
+#if 0
+ /* Add ingress face as next hop */
+ idle = 0;
+#endif
+ break;
+
+ case MAPME_EVENT_PH_ADD:
+ /* Back-propagation, interesting even for IN (desync) */
+ mapme_send_to_nexthop(mapme, entry, ingress_id);
+
+ mapme->idle = 0;
+ if (mapme->timer_fd == -1)
+ mapme->timer_fd = loop_register_timer(MAIN_LOOP,
+ mapme->retx, mapme, mapme_on_timeout, NULL);
+ break;
+
+ case MAPME_EVENT_PH_DEL:
+ /* Ack : remove an element from TFIB */
+ break;
+
+ case MAPME_EVENT_FACE_ADD:
+ case MAPME_EVENT_FACE_DEL:
+
+ case MAPME_EVENT_UNDEFINED:
+ case MAPME_EVENT_N:
+ ERROR("Unexpected event");
+ break;
+
}
+}
- /*
- * The update is completed when the IU could not be sent to any
- * other next hop.
- */
- if (complete) INFO(mapme, "[MAP-Me] - Update completed !");
+static
+void
+mapme_on_interest(mapme_t * mapme, uint8_t * packet,
+ unsigned ingress_id, hicn_prefix_t * prefix, mapme_params_t * params)
+{
+ connection_table_t * table = forwarder_get_connection_table(mapme->forwarder);
- numberSet_Release(&nexthops);
+ /* The cast is needed since connectionTable_FindById miss the
+ * const qualifier for the first parameter */
+ const connection_t * conn_in = connection_table_get_by_id(table, ingress_id);
- } else if (seq == fibSeq) {
/*
- * Multipath, multihoming, multiple producers or duplicate interest
- *
- * In all cases, we assume the propagation was already done when the first
- * interest with the same sequence number was received, so we stop here
- *
- * It might happen that the previous AP has still a connection to the
- * producer and that we received back our own IU. In that case, we just
- * need to Ack and ignore it.
+ * Immediately send an acknowledgement back on the ingress connection
+ * We always ack, even duplicates.
*/
-#if 0
- if (mapme_hasLocalNextHops(mapme, fibEntry)) {
- INFO(mapme, "[MAP-Me] - Received original interest... Update complete");
- return true;
+ size_t size = hicn_mapme_create_ack(packet, params);
+ if (connection_send_packet(conn_in, packet, size) < 0) {
+ /* We accept the packet knowing we will get a retransmit */
+ ERROR("Failed to send ACK packet");
}
+
+ Name *name = name_CreateFromPacket(packet, MESSAGE_TYPE_INTEREST);
+ name_setLen(name, prefix->len);
+
+ char *name_str = name_ToString(name);
+ DEBUG("Ack'ed interest : connection=%d prefix=%s seq=%d", ingress_id,
+ name_str, params->seq);
+ free(name_str);
+
+ /* EPM on FIB */
+ const fib_t * fib = forwarder_get_fib(mapme->forwarder);
+ fib_entry_t * entry = fib_contains(fib, name);
+ if (!entry) {
+#ifdef HICN_MAPME_ALLOW_NONEXISTING_FIB_ENTRY
+ if (mapme_create_fib_entry(mapme, name, ingress_id) < 0) {
+ ERROR("Failed to create FIB entry");
+ return;
+ }
+#else
+ INFO("Ignored update with no FIB entry");
+ return;
#endif
+ }
- INFO(mapme, "[MAP-Me] - Adding multipath next hop on connection %d",
- conn_in_id);
- fibEntry_AddNexthop(fibEntry, conn_in_id);
+ mapme_tfib_t * tfib = TFIB(entry);
+ assert(tfib);
- } else { // seq < fibSeq
/*
- * Face is propagating outdated information, we can just
- * consider it as a prevHops. Send the special interest backwards with
- * the new sequence number to reconciliate this outdated part of the
- * arborescence.
+ * In case of multihoming, we might receive a message about our own prefix, we
+ * should never take it into account, nor send the IU backwards as a sign of
+ * outdated propagation.
+ *
+ * Detection: we receive a message initially sent by ourselves, ie a message
+ * for which the prefix has a local next hop in the FIB.
*/
- INFO(
- mapme,
- "[MAP-Me] - Update interest %d -> %d sent backwards on connection %d",
- seq, fibSeq, conn_in_id);
- mapme_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry,
- conn_in_id, send, false, false, 0);
- }
-
- return true;
-
-ERR_ACK_SEND:
- message_Release(&ack);
-ERR_ACK_CREATE:
- return false;
-}
+ // XXX NOT IN VPP ?
+ if (fib_entry_has_local_nexthop(entry)) {
+ INFO("Received original interest... Update complete");
+ return;
+ }
-void mapme_onSpecialInterestAck(const MapMe *mapme, const uint8_t *msgBuffer,
- unsigned conn_in_id, hicn_prefix_t *prefix,
- mapme_params_t *params) {
- INFO(mapme, "[MAP-Me] Receive IU/IN Ack on connection %d", conn_in_id);
-
- const Name * name =
- name_CreateFromPacket(msgBuffer, MessagePacketType_ContentObject);
- name_setLen((Name*) name, prefix->len);
- char * name_str = name_ToString(name);
- INFO(mapme, "[MAP-Me] Received ack for name prefix=%s seq=%d on conn id=%d",
- name_str, params->seq, conn_in_id);
- free(name_str);
-
- FIB *fib = forwarder_getFib(mapme->forwarder);
- FibEntry *fibEntry = fib_Contains(fib, name);
- if (!fibEntry) {
- return;
- }
- parcAssertNotNull(fibEntry,
- "No corresponding FIB entry for name contained in IU Ack");
-
- /* Test if the latest pending update has been ack'ed, otherwise just ignore */
- seq_t seq = params->seq;
- if (seq != INVALID_SEQ) {
- seq_t fibSeq = TFIB(fibEntry)->seq;
-
- if (seq < fibSeq) {
-
- /* If we receive an old ack:
- * - either the connection is still a next hop and we have to ignore
- * the ack until we receive a further update with higher seqno
- * - or the connection is no more to be informed and the ack is
- * sufficient and we can remove future retransmissions
+ mapme_event_t event = MAPME_EVENT_UNDEFINED;
+ if (params->seq > tfib->seq) {
+ DEBUG("seq %d > fib_seq %d, updating seq and next hops", params->seq,
+ tfib->seq);
+ /* This has to be done first to allow processing ack */
+ // XXX this should even be done before sending ack, as in VPP.
+ tfib->seq = params->seq;
+
+ /*
+ * Move nexthops to TFIB... but ingress_id that lands in nexthops
+ *
+ * This could might optimized for situations where nothing changes, but
+ * this is very unlikely if not impossible...
+ * */
+ unsigned prevhop;
+ nexthops_foreach(&entry->nexthops, prevhop, {
+ nexthops_add(&tfib->nexthops, prevhop);
+ });
+ nexthops_remove(&tfib->nexthops, ingress_id);
+ nexthops_add(&tfib->nexthops, ingress_id);
+
+ event = MAPME_EVENT_NH_SET;
+
+ // XXX tell things are complete if we have no IU to send
+
+ } else if (params->seq == tfib->seq) {
+ /*
+ * Multipath, multihoming, multiple producers or duplicate interest
+ *
+ * In all cases, we assume the propagation was already done when the first
+ * interest with the same sequence number was received, so we stop here
+ *
+ * It might happen that the previous AP has still a connection to the
+ * producer and that we received back our own IU. In that case, we just
+ * need to Ack and ignore it.
*/
+ DEBUG("params.seq %d == fib_seq %d, adding nethop %d", params->seq,
+ tfib->seq, ingress_id);
+
+ /* Move ingress to nexthops (and eventually remove it from TFIB) */
+ nexthops_add(&entry->nexthops, ingress_id);
+ nexthops_remove(&tfib->nexthops, ingress_id);
+
+ event = MAPME_EVENT_NH_ADD;
- INFO(mapme,
- "[MAP-Me] - Ignored special interest Ack with seq=%u, expected %u",
- seq, fibSeq);
- return;
+ } else { // params->seq < tfib->seq
+ /*
+ * Face is propagating outdated information, we can just
+ * consider it as a prevHops. Send the special interest backwards with
+ * the new sequence number to reconciliate this outdated part of the
+ * arborescence.
+ */
+ DEBUG("params.seq %d < fib_seq %d, sending backwards on face %d", params->seq, tfib->seq, ingress_id);
+ nexthops_remove(&entry->nexthops, ingress_id);
+ nexthops_add(&tfib->nexthops, ingress_id);
+
+ event = MAPME_EVENT_PH_ADD;
}
- }
-
- /*
- * Ignore the Ack if no TFIB is present, or it has no corresponding entry
- * with the ingress face.
- * Note: previously, we were creating the TFIB entry
- */
- if (!TFIB(fibEntry)) {
- INFO(mapme, "[MAP-Me] - Ignored ACK for prefix with no TFIB entry");
- return;
- }
-
- PARCEventTimer *timer =
- (PARCEventTimer *)mapmeTFIB_Get(TFIB(fibEntry), conn_in_id);
- if (!timer) {
- INFO(mapme,
- "[MAP-Me] - Ignored ACK for prefix not having the Connection in "
- "TFIB entry. Possible duplicate ?");
- return;
- }
-
- /* Stop timer and remove entry from TFIB */
- parcEventTimer_Stop(timer);
- mapmeTFIB_Remove(TFIB(fibEntry), conn_in_id);
-
- INFO(mapme, "[MAP-Me] - Removing TFIB entry for ack on connection %d",
- conn_in_id);
-
- /* We need to update the timestamp only for IU Acks, not for IN Acks */
- if (params->type == UPDATE_ACK) {
- INFO(mapme, "[MAP-Me] - Updating LastAckedUpdate");
- TFIB(fibEntry)->lastAckedUpdate = forwarder_GetTicks(mapme->forwarder);
- }
+
+ /* Don't trigger events for notification unless we need to send interests backwards */
+ if ((params->type != UPDATE) && (event != MAPME_EVENT_PH_ADD))
+ return;
+
+ mapme_on_event(mapme, event, entry, ingress_id);
}
-/*-----------------------------------------------------------------------------
- * Overloaded functions
- *----------------------------------------------------------------------------*/
+static
+void
+mapme_on_data(mapme_t *mapme, const uint8_t * packet,
+ unsigned ingress_id, hicn_prefix_t *prefix,
+ mapme_params_t * params)
+{
+ INFO("Receive IU/IN Ack on connection %d", ingress_id);
-/*
- * @abstract returns where to forward a normal interests(nexthops) defined by
- * mapme, it also set the sequnence number properly if needed
- */
+ const Name * name =
+ name_CreateFromPacket(packet, MESSAGE_TYPE_DATA);
+ name_setLen((Name*) name, prefix->len);
-/******************************************************************************
- * Public functions (exposed in the .h)
- ******************************************************************************/
+ char * name_str = name_ToString(name);
+ DEBUG("Received ack for name prefix=%s seq=%d on conn id=%d",
+ name_str, params->seq, ingress_id);
+ free(name_str);
-/*
- * Returns true iif the message corresponds to a MAP-Me packet
- */
-bool mapme_isMapMe(const uint8_t *packet) {
- hicn_mapme_header_t * mapme = (hicn_mapme_header_t*)packet;
-
- switch(HICN_IP_VERSION(packet)) {
- case 4:
- if (mapme->v4.ip.protocol != IPPROTO_ICMP)
- return false;
- return HICN_IS_MAPME(mapme->v4.icmp_rd.type, mapme->v4.icmp_rd.code);
- case 6:
- if (mapme->v6.ip.nxt != IPPROTO_ICMPV6)
- return false;
- return HICN_IS_MAPME(mapme->v6.icmp_rd.type, mapme->v6.icmp_rd.code);
- default:
- return false;
- }
+ const fib_t * fib = forwarder_get_fib(mapme->forwarder);
+ fib_entry_t * entry = fib_contains(fib, name);
+ if (!entry) {
+ INFO("Ignored ACK with no corresponding FIB entry");
+ return;
+ }
+ mapme_tfib_t * tfib = TFIB(entry);
+
+ /*
+ * As we always retransmit IU with the latest seq, we are not interested in
+ * ACKs with inferior seq
+ */
+ if (params->seq < tfib->seq) {
+ INFO("Ignored ACK with seq %d < %d", params->seq, tfib->seq);
+ return;
+ }
+
+ nexthops_remove(&tfib->nexthops, ingress_id);
+ mapme_on_event(mapme, MAPME_EVENT_PH_DEL, entry, ingress_id);
+
+ /* We need to update the timestamp only for IU Acks, not for IN Acks */
+ if (params->type == UPDATE_ACK) {
+ INFO(" - Updating LastAckedUpdate");
+ tfib->last_acked_update = ticks_now();
+ }
}
/**
@@ -990,25 +903,53 @@ bool mapme_isMapMe(const uint8_t *packet) {
* MAP-Me (eg. ICMP packets) and return higher level messages that can be
* processed by MAP-Me core.
*/
-void mapme_Process(const MapMe *mapme, const uint8_t *msgBuffer,
- unsigned conn_id) {
- hicn_prefix_t prefix;
- mapme_params_t params;
- hicn_mapme_parse_packet(msgBuffer, &prefix, &params);
-
- switch (params.type) {
- case UPDATE:
- case NOTIFICATION:
- mapme_onSpecialInterest(mapme, msgBuffer, conn_id, &prefix, &params);
- break;
- case UPDATE_ACK:
- case NOTIFICATION_ACK:
- mapme_onSpecialInterestAck(mapme, msgBuffer, conn_id, &prefix, &params);
- break;
- default:
- ERR(mapme, "[MAP-Me] Unknown message");
- break;
- }
+void
+mapme_process(mapme_t *mapme, uint8_t *packet, unsigned conn_id)
+{
+ hicn_prefix_t prefix;
+ mapme_params_t params;
+ int rc = hicn_mapme_parse_packet(packet, &prefix, &params);
+ if (rc < 0)
+ return;
+
+ // XXX TYPE STR
+ DEBUG("Received interest type:%d seq:%d len:%d", params.type, params.seq, prefix.len);
+
+ // XXX RENAME TYPES
+ switch (params.type) {
+ case UPDATE:
+ case NOTIFICATION:
+ mapme_on_interest(mapme, packet, conn_id, &prefix, &params);
+ break;
+ case UPDATE_ACK:
+ case NOTIFICATION_ACK:
+ mapme_on_data(mapme, packet, conn_id, &prefix, &params);
+ break;
+ default:
+ ERROR("Unknown message");
+ break;
+ }
}
+/*
+ * Returns true iif the message corresponds to a MAP-Me packet
+ */
+bool mapme_match_packet(const uint8_t *packet) {
+ hicn_mapme_header_t * mapme = (hicn_mapme_header_t*)packet;
+
+ switch(HICN_IP_VERSION(packet)) {
+ case 4:
+ if (mapme->v4.ip.protocol != IPPROTO_ICMP)
+ return false;
+ return HICN_IS_MAPME(mapme->v4.icmp_rd.type, mapme->v4.icmp_rd.code);
+ case 6:
+ if (mapme->v6.ip.nxt != IPPROTO_ICMPV6)
+ return false;
+ return HICN_IS_MAPME(mapme->v6.icmp_rd.type, mapme->v6.icmp_rd.code);
+ default:
+ return false;
+ }
+}
+
+
#endif /* WITH_MAPME */
diff --git a/hicn-light/src/hicn/core/mapme.h b/hicn-light/src/hicn/core/mapme.h
index 72f8d536a..2bf5a413b 100644
--- a/hicn-light/src/hicn/core/mapme.h
+++ b/hicn-light/src/hicn/core/mapme.h
@@ -27,28 +27,27 @@
#include <stdint.h>
#include <hicn/hicn.h>
-#include <hicn/core/forwarder.h>
#include <hicn/core/connection.h>
#include <hicn/utils/commands.h>
+#include <hicn/core/fib_entry.h>
-struct mapme;
-typedef struct mapme MapMe;
+typedef struct mapme_s mapme_t;
/**
* @function mapme_create
* @abstract Initializes MAP-Me state in the forwarder.
* @return bool - Boolean informing about the success of MAP-Me initialization.
*/
-bool mapme_create(MapMe **mapme, Forwarder *Forwarder);
+mapme_t * mapme_create(void *Forwarder);
/**
* @function mapme_free
* @abstract Free MAP-Me state in the forwarder.
*/
-void mapme_free(MapMe *mapme);
+void mapme_free(mapme_t *mapme);
/**
- * @function messageHandler_isMapMe
+ * @function messageHandler_is_mapme
* @abstract Identifies MAP-Me messages
* @discussion This function can be used by the forwarder to dispatch MAP-Me
* message to the appropriate processing function. Ideally this would be
@@ -56,48 +55,50 @@ void mapme_free(MapMe *mapme);
* @param [in] msgBuffer - The buffer to match
* @return A boolean indicating whether message is a MAP-Me control message.
*/
-bool mapme_isMapMe(const uint8_t *msgBuffer);
+bool mapme_match_packet(const uint8_t *msgBuffer);
/**
- * @function mapme_handleMapMeMessage
+ * @function mapme_handlemapme_tMessage
* @abstract Process a MAP-Me message.
* @param [in] mapme - Pointer to the MAP-Me data structure.
* @param [in] message - MAP-Me buffer
* @param [in] conn_id - Ingress connection id
*/
-void mapme_Process(const MapMe *mapme, const uint8_t *msgBuffer,
- unsigned conn_id);
+void mapme_process(mapme_t *mapme, uint8_t * packet, unsigned conn_id);
+
+int mapme_send_to_nexthop(const mapme_t * mapme, fib_entry_t * fib_entry, unsigned nexthop);
/**
* @function mapme_send_updates
* @abstract Trigger (if needed) the update for specified FIB entry and nexthops
* @param [in] mapme - Pointer to the MAP-Me data structure.
- * @param [in] fibEntry - The FIB entry to consider
+ * @param [in] fib_entry - The FIB entry to consider
* @param [in] nexthops - NumberSet holding the next hops on which to send the
* update.
*/
-void mapme_send_updates(const MapMe * mapme, FibEntry * fibEntry, const NumberSet * nexthops);
+int mapme_send_to_nexthops(const mapme_t * mapme, fib_entry_t * entry,
+ const nexthops_t * nexthops);
/**
* @function mapme_send_updates
* @abstract Trigger the update for specified FIB entry and nexthops, only if needed
* @param [in] mapme - Pointer to the MAP-Me data structure.
- * @param [in] fibEntry - The FIB entry to consider
+ * @param [in] fib_entry - The FIB entry to consider
* @param [in] nexthops - NumberSet holding the next hops on which to send the
* update.
*/
-void mapme_maybe_send_updates(const MapMe * mapme, FibEntry * fibEntry, const NumberSet * nexthops);
+void mapme_maybe_send_to_nexthops(const mapme_t * mapme, fib_entry_t * fib_entry, const nexthops_t * nexthops);
/**
- * @function mapme_reconsiderFibEntry
+ * @function mapme_reconsiderfib_entry_t
* @abstract Process a fib entry for changes that might trigger new updates
* @param [in] mapme - Pointer to the MAP-Me data structure.
- * @param [in] fibEntry - The FIB entry to consider
+ * @param [in] fib_entry - The FIB entry to consider
*/
-void mapme_reconsiderFibEntry(const MapMe *mapme, FibEntry * fibEntry);
+void mapme_send_to_all_nexthops(const mapme_t *mapme, fib_entry_t * fib_entry);
/**
- * @function mapme_onConnectionEvent
+ * @function mapme_on_connection_event
* @abstract Callback following the addition of the face though the control
* protocol.
* @discussion This callback triggers the sending of control packets by MAP-Me.
@@ -105,15 +106,16 @@ void mapme_reconsiderFibEntry(const MapMe *mapme, FibEntry * fibEntry);
* @param [in] conn - The newly added connection.
* @param [in] event - Connection event
*/
-void mapme_onConnectionEvent(const MapMe *mapme, const Connection *conn, connection_event_t event);
+void mapme_on_connection_event(const mapme_t *mapme, const connection_t * conn,
+ connection_event_t event);
/**
- * @function mapme_getNextHops
+ * @function mapme_get_nexthops
* @abstract return the nexthops to forward interests defined by mapme, it
* covers also the case where local discovery mechanisms are trriggered.
*/
-NumberSet *mapme_getNextHops(const MapMe *mapme, FibEntry *fibEntry,
- const Message *interest);
+nexthops_t * mapme_get_nexthops(const mapme_t *mapme, fib_entry_t *fib_entry,
+ const msgbuf_t *interest);
hicn_mapme_type_t mapme_PktType_To_LibHicnPktType(MessagePacketType type);
diff --git a/hicn-light/src/hicn/core/message.c b/hicn-light/src/hicn/core/message.c
deleted file mode 100644
index 5d0d04ae4..000000000
--- a/hicn-light/src/hicn/core/message.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <errno.h>
-#include <hicn/hicn-light/config.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <hicn/core/forwarder.h>
-#include <hicn/core/message.h>
-#include <hicn/core/wldr.h>
-
-#include <hicn/core/messageHandler.h>
-
-#include <parc/algol/parc_Hash.h>
-#include <parc/algol/parc_Memory.h>
-#include <hicn/core/messagePacketType.h>
-
-#include <parc/assert/parc_Assert.h>
-
-#include <parc/algol/parc_EventBuffer.h>
-
-struct message {
- Logger *logger;
-
- Ticks receiveTime;
- unsigned ingressConnectionId;
-
- Name *name;
-
- uint8_t *messageHead;
-
- unsigned length;
-
- uint8_t packetType;
-
- unsigned refcount;
-};
-
-Message *message_Acquire(const Message *message) {
- Message *copy = (Message *)message;
- copy->refcount++;
- return copy;
-}
-
-Message *message_CreateFromEventBuffer(PARCEventBuffer *data, size_t dataLength,
- unsigned ingressConnectionId,
- Ticks receiveTime, Logger *logger) {
- // used by applications, we can get only interest or data packets
- Message *message = parcMemory_AllocateAndClear(sizeof(Message));
- parcAssertNotNull(message, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(Message));
-
- message->logger = logger_Acquire(logger);
- message->receiveTime = receiveTime;
- message->ingressConnectionId = ingressConnectionId;
- message->length = (unsigned int)dataLength;
-
- message->messageHead = parcMemory_AllocateAndClear(dataLength);
- parcAssertNotNull(message->messageHead,
- "parcMemory_AllocateAndClear(%zu) returned NULL",
- dataLength);
-
- // copy the data because *data is destroyed in the connection.
- int res = parcEventBuffer_Read(data, message->messageHead, dataLength);
- if (res == -1) {
- return NULL;
- }
-
- if (messageHandler_IsInterest(message->messageHead)) {
- message->packetType = MessagePacketType_Interest;
- } else if (messageHandler_IsData(message->messageHead)) {
- message->packetType = MessagePacketType_ContentObject;
- } else {
- printf("Got a packet that is not a data nor an interest, drop it!\n");
- return NULL;
- }
- message->name =
- name_CreateFromPacket(message->messageHead, message->packetType);
-
- message->refcount = 1;
-
- return message;
-}
-
-Message *message_CreateFromByteArray(unsigned connid, uint8_t *pckt,
- MessagePacketType type, Ticks receiveTime,
- Logger *logger) {
- Message *message = parcMemory_AllocateAndClear(sizeof(Message));
- parcAssertNotNull(message, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(Message));
-
- message->logger = logger_Acquire(logger);
- message->receiveTime = receiveTime;
- message->ingressConnectionId = connid;
- message->messageHead = pckt;
- message->length = messageHandler_GetTotalPacketLength(pckt);
- message->packetType = type;
-
- if (messageHandler_IsWldrNotification(pckt)) {
- message->name = NULL;
- } else {
- message->name =
- name_CreateFromPacket(message->messageHead, message->packetType);
- }
-
- message->refcount = 1;
-
- return message;
-}
-
-void message_Release(Message **messagePtr) {
- parcAssertNotNull(messagePtr, "Parameter must be non-null double pointer");
- parcAssertNotNull(*messagePtr,
- "Parameter must dereference to non-null pointer");
-
- Message *message = *messagePtr;
- parcAssertTrue(
- message->refcount > 0,
- "Invalid state: message_Release called on message with 0 references %p",
- (void *)message);
-
- message->refcount--;
- if (message->refcount == 0) {
- if (logger_IsLoggable(message->logger, LoggerFacility_Message,
- PARCLogLevel_Debug)) {
- logger_Log(message->logger, LoggerFacility_Message, PARCLogLevel_Debug,
- __func__, "Message %p destroyed", (void *)message);
- }
-
- logger_Release(&message->logger);
- if (message->name != NULL) name_Release(&message->name);
- parcMemory_Deallocate((void **)&message->messageHead);
- parcMemory_Deallocate((void **)&message);
- }
- *messagePtr = NULL;
-}
-
-bool message_Write(PARCEventQueue *parcEventQueue, const Message *message) {
- parcAssertNotNull(message, "Message parameter must be non-null");
- parcAssertNotNull(parcEventQueue, "Buffer parameter must be non-null");
-
- return parcEventQueue_Write(parcEventQueue, message->messageHead,
- message_Length(message));
-}
-
-size_t message_Length(const Message *message) {
- parcAssertNotNull(message, "Parameter must be non-null");
- return message->length;
-}
-
-bool message_HasWldr(const Message *message) {
- parcAssertNotNull(message, "Parameter must be non-null");
- return messageHandler_HasWldr(message->messageHead);
-}
-
-bool message_IsWldrNotification(const Message *message) {
- parcAssertNotNull(message, "Parameter must be non-null");
- return messageHandler_IsWldrNotification(message->messageHead);
-}
-
-void message_ResetWldrLabel(Message *message) {
- parcAssertNotNull(message, "Parameter must be non-null");
- messageHandler_ResetWldrLabel(message->messageHead);
-}
-
-unsigned message_GetWldrLabel(const Message *message) {
- parcAssertNotNull(message, "Parameter must be non-null");
- return messageHandler_GetWldrLabel(message->messageHead);
-}
-
-unsigned message_GetWldrExpectedLabel(const Message *message) {
- parcAssertNotNull(message, "Parameter must be non-null");
- return messageHandler_GetExpectedWldrLabel(message->messageHead);
-}
-
-unsigned message_GetWldrLastReceived(const Message *message) {
- parcAssertNotNull(message, "Parameter must be non-null");
- return messageHandler_GetWldrLastReceived(message->messageHead);
-}
-
-void message_SetWldrLabel(Message *message, uint16_t label) {
- parcAssertNotNull(message, "Parameter must be non-null");
- messageHandler_SetWldrLabel(message->messageHead, label);
-}
-
-Message *message_CreateWldrNotification(Message *original, uint16_t expected,
- uint16_t lastReceived) {
- parcAssertNotNull(original, "Parameter original must be non-null");
- Message *message = parcMemory_AllocateAndClear(sizeof(Message));
- parcAssertNotNull(message, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(Message));
- message->receiveTime = original->receiveTime;
- message->ingressConnectionId = original->ingressConnectionId;
- message->refcount = 1;
- message->logger = logger_Acquire(original->logger);
-
- message->length = (unsigned int)messageHandler_GetICMPPacketSize(
- messageHandler_GetIPPacketType(original->messageHead));
- message->messageHead = parcMemory_AllocateAndClear(message->length);
- parcAssertNotNull(message->messageHead,
- "parcMemory_AllocateAndClear returned NULL");
-
- message->packetType = MessagePacketType_WldrNotification;
- message->name = NULL; // nobody will use the name in a notification packet,
- // so we can simply set it to NULL
-
- // set notification stuff.
- messageHandler_SetWldrNotification(
- message->messageHead, original->messageHead, expected, lastReceived);
- return message;
-}
-
-unsigned message_GetIngressConnectionId(const Message *message) {
- parcAssertNotNull(message, "Parameter must be non-null");
- return message->ingressConnectionId;
-}
-
-void message_SetIngressConnectionId(Message *message, unsigned conn) {
- parcAssertNotNull(message, "Parameter must be non-null");
- message->ingressConnectionId = conn;
-}
-
-Ticks message_GetReceiveTime(const Message *message) {
- parcAssertNotNull(message, "Parameter must be non-null");
- return message->receiveTime;
-}
-
-uint32_t message_GetPathLabel(const Message *message) {
- parcAssertNotNull(message, "Parameter must be non-null");
- return messageHandler_GetPathLabel(message->messageHead);
-}
-
-void message_SetPathLabel(Message *message, uint32_t label) {
- parcAssertNotNull(message, "Parameter must be non-null");
- messageHandler_SetPathLabel(message->messageHead, label);
-}
-
-void message_UpdatePathLabel(Message *message, uint8_t outFace) {
- parcAssertNotNull(message, "Parameter must be non-null");
- messageHandler_UpdatePathLabel(message->messageHead, outFace);
-}
-
-void message_ResetPathLabel(Message *message) {
- parcAssertNotNull(message, "Parameter must be non-null");
- messageHandler_ResetPathLabel(message->messageHead);
-}
-
-MessagePacketType message_GetType(const Message *message) {
- parcAssertNotNull(message, "Parameter message must be non-null");
- return message->packetType;
-}
-
-Name *message_GetName(const Message *message) {
- parcAssertNotNull(message, "Parameter message must be non-null");
- return message->name;
-}
-
-bool message_HasInterestLifetime(const Message *message) {
- parcAssertNotNull(message, "Parameter message must be non-null");
- return messageHandler_HasInterestLifetime(message->messageHead);
-}
-
-uint64_t message_GetInterestLifetimeTicks(const Message *message) {
- parcAssertNotNull(message, "Parameter message must be non-null");
- uint64_t lifetime = messageHandler_GetInterestLifetime(message->messageHead);
- return forwarder_NanosToTicks(lifetime * 1000000ULL);
-}
-
-bool message_HasContentExpiryTime(const Message *message) {
- parcAssertNotNull(message, "Parameter message must be non-null");
- return messageHandler_HasContentExpiryTime(message->messageHead);
-}
-
-uint64_t message_GetContentExpiryTimeTicks(const Message *message) {
- parcAssertNotNull(message, "Parameter message must be non-null");
- uint64_t expire = messageHandler_GetContentExpiryTime(message->messageHead);
- if(expire == 0)
- return message->receiveTime;
- return message->receiveTime + forwarder_NanosToTicks(expire * 1000000ULL);
-}
-
-const uint8_t *message_FixedHeader(const Message *message) {
- parcAssertNotNull(message, "Parameter message must be non-null");
- return message->messageHead;
-}
diff --git a/hicn-light/src/hicn/core/message.h b/hicn-light/src/hicn/core/message.h
deleted file mode 100644
index e77dab2b5..000000000
--- a/hicn-light/src/hicn/core/message.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @file message.h
- * @brief Message is the unit of forwarding, i.e. the packets being switched
- *
- */
-#ifndef message_h
-#define message_h
-
-#include <hicn/hicn-light/config.h>
-#include <hicn/core/logger.h>
-#include <hicn/core/messagePacketType.h>
-#include <hicn/core/streamBuffer.h>
-
-#include <hicn/core/name.h>
-
-#include <parc/algol/parc_EventBuffer.h>
-#include <parc/algol/parc_EventQueue.h>
-
-#include <hicn/utils/address.h>
-
-#include <hicn/core/ticks.h>
-
-struct message;
-typedef struct message Message;
-
-/**
- * @function message_CreateFromBuffer
- * @abstract Takes ownership of the input buffer, which comprises one complete
- * message
- */
-
-Message *message_CreateFromEventBuffer(PARCEventBuffer *data, size_t dataLength,
- unsigned ingressConnectionId,
- Ticks receiveTime, Logger *logger);
-
-/**
- * @function message_CreateFromByteArray
- * @abstract create a message from a byte array
- */
-
-Message *message_CreateFromByteArray(unsigned connid, uint8_t *pckt,
- MessagePacketType type, Ticks receiveTime,
- Logger *logger);
-
-/**
- * @function message_Copy
- * @abstract Get a reference counted copy
- */
-
-Message *message_Acquire(const Message *message);
-
-/**
- * Releases the message and frees the memory
- */
-void message_Release(Message **messagePtr);
-
-/**
- * Writes the message to the queue
- */
-
-bool message_Write(PARCEventQueue *parcEventQueue, const Message *message);
-
-/**
- * Returns the total byte length of the message
- */
-size_t message_Length(const Message *message);
-
-bool message_HasWldr(const Message *message);
-
-bool message_IsWldrNotification(const Message *message);
-
-void message_ResetWldrLabel(Message *message);
-
-unsigned message_GetWldrLabel(const Message *message);
-
-unsigned message_GetWldrExpectedLabel(const Message *message);
-
-unsigned message_GetWldrLastReceived(const Message *message);
-
-void message_SetWldrLabel(Message *message, uint16_t label);
-
-Message *message_CreateWldrNotification(Message *original, uint16_t expected,
- uint16_t lastReceived);
-/**
- * Returns the connection id of the packet input
- */
-unsigned message_GetIngressConnectionId(const Message *message);
-
-void message_SetIngressConnectionId(Message *message, unsigned conn);
-
-/**
- * Returns the receive time (in router ticks) of the message
- */
-Ticks message_GetReceiveTime(const Message *message);
-
-/**
- * Returns the PacketType
- */
-MessagePacketType message_GetType(const Message *message);
-
-uint32_t message_GetPathLabel(const Message *message);
-void message_SetPathLabel(Message *message, uint32_t label);
-void message_UpdatePathLabel(Message *message, uint8_t outFace);
-void message_ResetPathLabel(Message *message);
-
-// ===========================================================
-// Accessors used to index and compare messages
-
-/**
- * @function message_GetName
- * @abstract The name in the message
- * @discussion
- * The name of the Interest or Content Object. If the caller will store the
- * name, he should make a reference counted copy.
- * @return The name as stored in the message object.
- */
-
-Name *message_GetName(const Message *message);
-
-/**
- * Determines if the message has an Interest Lifetime parameter
- *
- * @param [in] message An allocated and parsed Message
- *
- * @retval true If an Intrerest Lifetime field exists
- * @retval false If no Interest Lifetime exists
- */
-
-bool message_HasInterestLifetime(const Message *message);
-
-/**
- * Returns the Interest lifetime in hicn-light Ticks
- *
- * the interest expires after now + returned ticks
- *
- * @param [in] message An allocated and parsed Message
- *
- * @retval integer Lifetime in forwarder Ticks
- *
- */
-
-uint64_t message_GetInterestLifetimeTicks(const Message *message);
-
-/**
- * checks if the expiry time is set inside the content object
- */
-bool message_HasContentExpiryTime(const Message *message);
-
-/**
- * returns the moment (in hicn-light ticks) when the content object will expire
- */
-uint64_t message_GetContentExpiryTimeTicks(const Message *message);
-
-/**
- * Returns a pointer to the beginning of the FixedHeader
- *
- * @param [in] message An allocated and parsed Message
- *
- * @return non-null The fixed header memory
- * @return null No fixed header or an error
- */
-
-const uint8_t *message_FixedHeader(const Message *message);
-
-#endif // message_h
diff --git a/hicn-light/src/hicn/core/messageHandler.h b/hicn-light/src/hicn/core/messageHandler.h
index a8b2a3e54..e0eef5e7c 100644
--- a/hicn-light/src/hicn/core/messageHandler.h
+++ b/hicn-light/src/hicn/core/messageHandler.h
@@ -19,11 +19,13 @@
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h> // close
-#endif
+#endif /* _WIN32 */
#include <hicn/hicn.h>
#include <hicn/core/messagePacketType.h>
+//#include <hicn/core/connection_table.h>
+
#define H(packet) ((hicn_header_t *)packet)
#define H6(packet) (H(packet)->v6.ip)
#define H6T(packet) (H(packet)->v6.tcp)
@@ -53,17 +55,12 @@
#define IPV6_DEFAULT_TRAFFIC_CLASS 0
#define IPV6_DEFAULT_FLOW_LABEL 0
-#define expected_lbl wldr_notification_lbl.expected_lbl
-#define received_lbl wldr_notification_lbl.received_lbl
-
-#include <hicn/core/forwarder.h>
+//#include <hicn/core/forwarder.h>
-#ifdef WITH_MAPME
-#include <hicn/core/mapme.h>
-#include <hicn/socket/api.h>
-#endif /* WITH_MAPME */
-
-#define CONNECTION_ID_UNDEFINED -1
+//#ifdef WITH_MAPME
+//#include <hicn/core/mapme.h>
+//#include <hicn/socket/api.h>
+//#endif /* WITH_MAPME */
#define BFD_PORT 3784
@@ -157,6 +154,7 @@ static inline size_t messageHandler_GetIPHeaderLength(unsigned ipVersion) {
return 0;
}
+#if 0
static inline bool messageHandler_IsValidHicnPacket(const uint8_t *message) {
uint8_t version = messageHandler_GetIPPacketType(message);
if (version == IPv6_TYPE || version == IPv4_TYPE) {
@@ -164,6 +162,7 @@ static inline bool messageHandler_IsValidHicnPacket(const uint8_t *message) {
}
return false;
}
+#endif
static inline uint8_t messageHandler_NextHeaderType(const uint8_t *message) {
switch (messageHandler_GetIPPacketType(message)) {
@@ -176,155 +175,6 @@ static inline uint8_t messageHandler_NextHeaderType(const uint8_t *message) {
}
}
-/* Forward declarations */
-static inline void * messageHandler_GetSource(const uint8_t *message);
-static inline void *messageHandler_GetDestination(const uint8_t *message);
-
-static const
-AddressPair *
-_createRecvAddressPairFromPacket(const uint8_t *msgBuffer) {
- Address *packetSrcAddr = NULL; /* This one is in the packet */
- Address *localAddr = NULL; /* This one is to be determined */
-
- if (messageHandler_GetIPPacketType(msgBuffer) == IPv6_TYPE) {
- struct sockaddr_in6 addr_in6;
- addr_in6.sin6_family = AF_INET6;
- addr_in6.sin6_port = htons(1234);
- addr_in6.sin6_flowinfo = 0;
- addr_in6.sin6_scope_id = 0;
- memcpy(&addr_in6.sin6_addr,
- (struct in6_addr *)messageHandler_GetSource(msgBuffer), 16);
- packetSrcAddr = addressCreateFromInet6(&addr_in6);
-
- /* We now determine the local address used to reach the packet src address */
- int sock = (int)socket (AF_INET6, SOCK_DGRAM, 0);
- if (sock < 0)
- goto ERR;
-
- struct sockaddr_in6 remote, local;
- memset(&remote, 0, sizeof(remote));
- remote.sin6_family = AF_INET6;
- remote.sin6_addr = addr_in6.sin6_addr;
- remote.sin6_port = htons(1234);
-
- socklen_t locallen = sizeof(local);
- if (connect(sock, (const struct sockaddr*)&remote, sizeof(remote)) == -1)
- goto ERR;
- if (getsockname(sock, (struct sockaddr*) &local, &locallen) == -1)
- goto ERR;
-
- local.sin6_port = htons(1234);
- localAddr = addressCreateFromInet6(&local);
-
- close(sock);
-
- } else if (messageHandler_GetIPPacketType(msgBuffer) == IPv4_TYPE) {
- struct sockaddr_in addr_in;
- addr_in.sin_family = AF_INET;
- addr_in.sin_port = htons(1234);
- memcpy(&addr_in.sin_addr,
- (struct in_addr *)messageHandler_GetSource(msgBuffer), 4);
- packetSrcAddr = addressCreateFromInet(&addr_in);
-
- /* We now determine the local address used to reach the packet src address */
-
- int sock = (int)socket (AF_INET, SOCK_DGRAM, 0);
- if (sock < 0) {
- perror("Socket error");
- goto ERR;
- }
-
- struct sockaddr_in remote, local;
- memset(&remote, 0, sizeof(remote));
- remote.sin_family = AF_INET;
- remote.sin_addr = addr_in.sin_addr;
- remote.sin_port = htons(1234);
-
- socklen_t locallen = sizeof(local);
- if (connect(sock, (const struct sockaddr*)&remote, sizeof(remote)) == -1)
- goto ERR;
- if (getsockname(sock, (struct sockaddr*) &local, &locallen) == -1)
- goto ERR;
-
- local.sin_port = htons(1234);
- localAddr = addressCreateFromInet(&local);
-
- close(sock);
- }
- /* As this is a receive pair, we swap src and dst */
- return addressPair_Create(localAddr, packetSrcAddr);
-
-ERR:
- perror("Socket error");
- return NULL;
-}
-
-/* Main hook handler */
-
-/**
- * \brief Handle incoming messages
- * \param [in] forwarder - Reference to the Forwarder instance
- * \param [in] packet - Packet buffer
- * \param [in] conn_id - A hint on the connection ID on which the packet
- * was received
- * \return Flag indicating whether the packet matched a hook and was
- * (successfully or not) processed.
- */
-static inline bool messageHandler_handleHooks(Forwarder * forwarder,
- const uint8_t * packet, ListenerOps * listener, int fd, AddressPair * pair)
-{
- bool is_matched = false;
-
- /* BEGIN Match */
-
-#ifdef WITH_MAPME
- bool is_mapme = mapme_isMapMe(packet);
- is_matched |= is_mapme;
-#endif /* WITH_MAPME */
-
- /* ... */
-
- /* END Match */
-
- if (!is_matched)
- return false;
-
- /*
- * Find existing connection or create a new one (we assume all processing
- * requires a valid connection.
- */
-
- if (!pair) {
- /* The hICN listener does not provide any address pair while UDP does */
- const AddressPair * pair = _createRecvAddressPairFromPacket(packet);
- if (!pair)
- return false;
- }
-
- /* Find connection and eventually create it */
- const Connection * conn = connectionTable_FindByAddressPair(
- forwarder_GetConnectionTable(forwarder), pair);
- unsigned conn_id;
- if (conn == NULL) {
- conn_id = listener->createConnection(listener, fd, pair);
- } else {
- conn_id = connection_GetConnectionId(conn);
- }
-
- /* BEGIN Process */
-
-#ifdef WITH_MAPME
- if (mapme_isMapMe(packet))
- forwarder_ProcessMapMe(forwarder, packet, conn_id);
-#endif /* WITH_MAPME */
-
- /* ... */
-
- /* END Process */
-
- return true;
-}
-
static inline bool messageHandler_IsTCP(const uint8_t *message) {
if (messageHandler_NextHeaderType(message) != IPPROTO_TCP) return false;
return true;
@@ -432,7 +282,7 @@ static inline uint16_t messageHandler_GetExpectedWldrLabel(
return 0;
}
- return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->expected_lbl);
+ return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->wldr_notification_lbl.expected_lbl);
}
static inline uint16_t messageHandler_GetWldrLastReceived(
@@ -449,7 +299,7 @@ static inline uint16_t messageHandler_GetWldrLastReceived(
return 0;
}
- return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->received_lbl);
+ return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->wldr_notification_lbl.received_lbl);
}
static inline uint16_t messageHandler_GetWldrLabel(const uint8_t *message) {
@@ -660,25 +510,28 @@ static inline void messageHandler_SetWldrNotification(uint8_t *notification,
hicn_header_t *h = (hicn_header_t *)notification;
switch (messageHandler_GetIPPacketType(original)) {
case IPv6_TYPE: {
- *h = (hicn_header_t){.v6 = {
- .ip =
- {
- .version_class_flow = htonl(
- (IPV6_DEFAULT_VERSION << 28) |
- (IPV6_DEFAULT_TRAFFIC_CLASS << 20) |
- (IPV6_DEFAULT_FLOW_LABEL & 0xfffff)),
- .len = htons(ICMP_HDRLEN),
- .nxt = IPPROTO_ICMPV6,
- .hlim = 5,
- },
- .wldr =
- {
- .type = ICMP_WLDR_TYPE,
- .code = ICMP_WLDR_CODE,
- .expected_lbl = htons(expected),
- .received_lbl = htons(received),
- },
- }};
+ *h = (hicn_header_t){
+ .v6 = {
+ .ip =
+ {
+ .version_class_flow = htonl(
+ (IPV6_DEFAULT_VERSION << 28) |
+ (IPV6_DEFAULT_TRAFFIC_CLASS << 20) |
+ (IPV6_DEFAULT_FLOW_LABEL & 0xfffff)),
+ .len = htons(ICMP_HDRLEN),
+ .nxt = IPPROTO_ICMPV6,
+ .hlim = 5,
+ },
+ .wldr =
+ {
+ .type = ICMP_WLDR_TYPE,
+ .code = ICMP_WLDR_CODE,
+ .wldr_notification_lbl = {
+ .expected_lbl = htons(expected),
+ .received_lbl = htons(received),
+ },
+ },
+ }};
messageHandler_SetSource_IPv6(
notification,
(struct in6_addr *)messageHandler_GetDestination(original));
@@ -699,7 +552,7 @@ static inline uint8_t * messageHandler_CreateProbePacket(hicn_format_t format,
size_t header_length;
hicn_packet_get_header_length_from_format(format, &header_length);
- uint8_t *pkt = parcMemory_AllocateAndClear(header_length);
+ uint8_t *pkt = calloc(header_length, 1);
hicn_packet_init_header(format, (hicn_header_t *) pkt);
@@ -732,7 +585,7 @@ static inline void messageHandler_CreateProbeReply(uint8_t * probe,
}
static inline hicn_name_t * messageHandler_CreateProbeName(const ip_prefix_t *address){
- hicn_name_t * name = parcMemory_AllocateAndClear(sizeof(hicn_name_t));
+ hicn_name_t * name = calloc(sizeof(hicn_name_t), 1);
hicn_name_create_from_ip_prefix(address, 0, name);
return name;
}
diff --git a/hicn-light/src/hicn/core/messagePacketType.h b/hicn-light/src/hicn/core/messagePacketType.h
index dfbb12342..9a559069e 100644
--- a/hicn-light/src/hicn/core/messagePacketType.h
+++ b/hicn-light/src/hicn/core/messagePacketType.h
@@ -23,10 +23,13 @@
#define message_packet_type_h
typedef enum message_type {
- MessagePacketType_Unknown,
- MessagePacketType_Interest,
- MessagePacketType_ContentObject,
- MessagePacketType_WldrNotification
+ MESSAGE_TYPE_UNDEFINED,
+ MESSAGE_TYPE_INTEREST,
+ MESSAGE_TYPE_DATA,
+ MESSAGE_TYPE_WLDR_NOTIFICATION,
+ MESSAGE_TYPE_MAPME,
+ MESSAGE_TYPE_COMMAND,
+ MESSAGE_TYPE_N,
} MessagePacketType;
#endif // message_packet_type_h
diff --git a/hicn-light/src/hicn/core/msgbuf.c b/hicn-light/src/hicn/core/msgbuf.c
new file mode 100644
index 000000000..094ecbafd
--- /dev/null
+++ b/hicn-light/src/hicn/core/msgbuf.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file msgbuf.c
+ * \brief Implementation hICN message buffer
+ */
+
+#include "msgbuf.h"
diff --git a/hicn-light/src/hicn/core/msgbuf.h b/hicn-light/src/hicn/core/msgbuf.h
new file mode 100644
index 000000000..3e96b3bbc
--- /dev/null
+++ b/hicn-light/src/hicn/core/msgbuf.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file msgbuf.h
+ * \brief hICN message buffer
+ */
+
+#ifndef HICN_MSGBUF
+#define HICN_MSGBUF
+
+#include <hicn/core/name.h>
+#include <hicn/core/ticks.h>
+#include <hicn/core/messageHandler.h>
+
+typedef struct {
+ Ticks receiveTime;
+ unsigned connection_id;
+ Name *name;
+ uint8_t *messageHead;
+ unsigned length;
+ uint8_t packetType;
+} msgbuf_t;
+
+#define msgbuf_from_packet(MSGBUF, PACKET, LENGTH, TYPE, CONNID, RECV_TIME) \
+do { \
+ *MSGBUF = (msgbuf_t) { \
+ .receiveTime = (RECV_TIME), \
+ .connection_id = (CONNID), \
+ .messageHead = (PACKET), \
+ .length = (LENGTH), \
+ .packetType = (TYPE), \
+ .name = (TYPE != MESSAGE_TYPE_WLDR_NOTIFICATION \
+ ? name_CreateFromPacket((PACKET), (TYPE)) \
+ : NULL), \
+ }; \
+} while(0)
+
+#define msgbuf_get_name(M) ((M)->name)
+#define msgbuf_get_connection_id(M) ((M)->connection_id)
+#define msgbuf_get_type(M) ((M)->packetType)
+#define msgbuf_has_wldr(M) (messageHandler_HasWldr((M)->messageHead))
+#define msgbuf_get_len(M) ((M)->length)
+#define msgbuf_get_packet(M) ((M)->messageHead)
+
+// XXX TODO EXPLAIN THE CONSTANT
+#define msgbuf_get_interest_lifetime(M) (NSEC_TO_TICKS(messageHandler_GetInterestLifetime((M)->messageHead) * 1000000ULL))
+
+#define msgbuf_is_probe(M) messageHandler_IsAProbe((M)->messageHead)
+
+/* Path label */
+
+#define msgbuf_get_pathlabel(M) (messageHandler_GetPathLabel((M)->messageHead))
+#define msgbuf_set_pathlabel(M, label) (messageHandler_SetPathLabel((M)->messageHead, label))
+#define msgbuf_update_pathlabel(M, outface) (messageHandler_SetPathLabel((M)->messageHead, outface))
+#define msgbuf_reset_pathlabel(M) (messageHandler_ResetPathLabel((M)->messageHead))
+
+/* WLDR */
+
+#define msgbuf_reset_wldr_label(M) (messageHandler_ResetWldrLabel((M)->messageHead))
+#define msgbuf_get_wldr_label(M) (messageHandler_GetWldrLabel((M)->messageHead))
+#define msgbuf_get_wldr_expected_label(M) (messageHandler_GetWldrExpectedLabel((M)->messageHead))
+#define msgbuf_get_wldr_last_received(M) (messageHandler_GetWldrLastReceived((M)->messageHead))
+#define msgbuf_set_wldr_label(M, label) (messageHandler_GetWldrLabel((M)->messageHead, label))
+
+#endif /* HICN_MSGBUF */
+
+
diff --git a/hicn-light/src/hicn/core/name.c b/hicn-light/src/hicn/core/name.c
index 805e7bfae..d50ce4cc2 100644
--- a/hicn-light/src/hicn/core/name.c
+++ b/hicn-light/src/hicn/core/name.c
@@ -13,23 +13,17 @@
* limitations under the License.
*/
+#include <assert.h>
#include <limits.h>
#include <hicn/hicn-light/config.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
-#include <parc/algol/parc_BufferComposer.h>
-#include <parc/algol/parc_Hash.h>
-#include <parc/algol/parc_Memory.h>
-
+#include <hicn/common.h> // cumulative_hash32
#include <hicn/core/messageHandler.h>
#include <hicn/core/name.h>
-#include <parc/algol/parc_Hash.h>
-
-#include <parc/assert/parc_Assert.h>
-
#define IPv6_TYPE 6
#define IPv4_TYPE 4
@@ -37,227 +31,263 @@
// segment
struct name {
- NameBitvector *content_name;
- uint32_t segment;
- uint32_t name_hash;
- // the refcount is shared between all copies
- unsigned *refCountPtr;
+ NameBitvector *content_name;
+ uint32_t segment;
+ uint32_t name_hash;
+ // the refcount is shared between all copies
+ unsigned *refCountPtr;
};
// =====================================================
-static unsigned _getRefCount(const Name *name) { return *name->refCountPtr; }
+static
+unsigned
+_getRefCount(const Name *name)
+{
+ return *name->refCountPtr;
+}
-static void _incrementRefCount(Name *name) {
- parcAssertTrue(*name->refCountPtr > 0,
- "Illegal State: Trying to increment a 0 refcount!");
- (*name->refCountPtr)++;
+static
+void
+_incrementRefCount(Name *name) {
+ assert(*name->refCountPtr > 0);
+ (*name->refCountPtr)++;
}
-static void _decrementRefCount(Name *name) {
- parcAssertTrue(*name->refCountPtr > 0,
- "Illegal State: Trying to decrement a 0 refcount!");
- (*name->refCountPtr)--;
+static
+void
+_decrementRefCount(Name *name) {
+ assert(*name->refCountPtr > 0);
+ (*name->refCountPtr)--;
}
static uint32_t _computeHash(Name *name) {
- parcAssertNotNull(name, "Parameter must be non-null pointer");
+ assert(name);
- uint32_t hash1 = nameBitvector_GetHash32(name->content_name);
- return parcHash32_Data_Cumulative((const uint8_t *)&name->segment, 4, hash1);
+ uint32_t hash1 = nameBitvector_GetHash32(name->content_name);
+ return cumulative_hash32(&name->segment, 4, hash1);
}
// ============================================================================
-Name *name_CreateFromPacket(const uint8_t *packet, MessagePacketType type) {
- Name *name = parcMemory_AllocateAndClear(sizeof(Name));
- parcAssertNotNull(name, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(Name));
-
- if (messageHandler_GetIPPacketType(packet) == IPv6_TYPE) {
- if (type == MessagePacketType_Interest) {
- name->content_name = nameBitvector_CreateFromIn6Addr(
- (struct in6_addr *)messageHandler_GetDestination(packet), 128);
- } else if (type == MessagePacketType_ContentObject) {
- name->content_name = nameBitvector_CreateFromIn6Addr(
- (struct in6_addr *)messageHandler_GetSource(packet), 128);
- } else {
- parcMemory_Deallocate((void **)&name);
- return NULL;
- }
- } else if (messageHandler_GetIPPacketType(packet) == IPv4_TYPE) {
- if (type == MessagePacketType_Interest) {
- name->content_name = nameBitvector_CreateFromInAddr(
- *((uint32_t *)messageHandler_GetDestination(packet)), 32);
- } else if (type == MessagePacketType_ContentObject) {
- name->content_name = nameBitvector_CreateFromInAddr(
- *((uint32_t *)messageHandler_GetSource(packet)), 32);
+Name *
+name_CreateFromPacket(const uint8_t *packet, MessagePacketType type)
+{
+ Name *name = malloc(sizeof(Name));
+ assert(name); // XXX TODO error handling
+
+ if (messageHandler_GetIPPacketType(packet) == IPv6_TYPE) {
+ if (type == MESSAGE_TYPE_INTEREST) {
+ name->content_name = nameBitvector_CreateFromIn6Addr(
+ (struct in6_addr *)messageHandler_GetDestination(packet), 128);
+ } else if (type == MESSAGE_TYPE_DATA) {
+ name->content_name = nameBitvector_CreateFromIn6Addr(
+ (struct in6_addr *)messageHandler_GetSource(packet), 128);
+ } else {
+ free(name);
+ return NULL;
+ }
+ } else if (messageHandler_GetIPPacketType(packet) == IPv4_TYPE) {
+ if (type == MESSAGE_TYPE_INTEREST) {
+ name->content_name = nameBitvector_CreateFromInAddr(
+ *((uint32_t *)messageHandler_GetDestination(packet)), 32);
+ } else if (type == MESSAGE_TYPE_DATA) {
+ name->content_name = nameBitvector_CreateFromInAddr(
+ *((uint32_t *)messageHandler_GetSource(packet)), 32);
+ } else {
+ free(name);
+ return NULL;
+ }
} else {
- parcMemory_Deallocate((void **)&name);
- return NULL;
+ printf("Error: unknown message type\n");
+ free(name);
+ return NULL;
}
- } else {
- printf("Error: unknown message type\n");
- parcMemory_Deallocate((void **)&name);
- return NULL;
- }
-
- name->segment = messageHandler_GetSegment(packet);
- name->name_hash = _computeHash(name);
-
- name->refCountPtr = parcMemory_Allocate(sizeof(unsigned));
- parcAssertNotNull(name->refCountPtr, "parcMemory_Allocate(%zu) returned NULL",
- sizeof(unsigned));
- *name->refCountPtr = 1;
- return name;
+
+ name->segment = messageHandler_GetSegment(packet);
+ name->name_hash = _computeHash(name);
+
+ name->refCountPtr = malloc(sizeof(unsigned));
+ assert(name->refCountPtr); // XXX TODO error handling
+ *name->refCountPtr = 1;
+ return name;
}
-Name *name_CreateFromAddress(address_type addressType, ip_address_t addr,
- uint8_t len) {
- Name *name = parcMemory_AllocateAndClear(sizeof(Name));
- parcAssertNotNull(name, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(Name));
- if (addressType == ADDR_INET) {
- name->content_name = nameBitvector_CreateFromInAddr(addr.v4.as_u32, len);
- } else if (addressType == ADDR_INET6) {
- name->content_name = nameBitvector_CreateFromIn6Addr(&addr.v6.as_in6addr, len);
- } else {
- parcTrapNotImplemented("Unkown packet type");
- }
-
- name->segment = 0;
- name->name_hash = _computeHash(name);
-
- name->refCountPtr = parcMemory_Allocate(sizeof(unsigned));
- parcAssertNotNull(name->refCountPtr, "parcMemory_Allocate(%zu) returned NULL",
- sizeof(unsigned));
- *name->refCountPtr = 1;
-
- return name;
+Name *
+name_CreateFromAddress(int family, ip_address_t addr,
+ uint8_t len)
+{
+ Name *name = malloc(sizeof(Name));
+ assert(name); // XXX TODO error handling
+
+ switch(family) {
+ case AF_INET:
+ name->content_name = nameBitvector_CreateFromInAddr(addr.v4.as_u32, len);
+ break;
+ case AF_INET6:
+ name->content_name = nameBitvector_CreateFromIn6Addr(&addr.v6.as_in6addr, len);
+ break;
+ default:
+ return NULL;
+ }
+
+ name->segment = 0;
+ name->name_hash = _computeHash(name);
+
+ name->refCountPtr = malloc(sizeof(unsigned));
+ assert(name->refCountPtr); // XXX TODO error handling
+ *name->refCountPtr = 1;
+
+ return name;
}
-void name_Release(Name **namePtr) {
- parcAssertNotNull(namePtr, "Parameter must be non-null double pointer");
- parcAssertNotNull(*namePtr, "Parameter must dereference to non-null pointer");
-
- Name *name = *namePtr;
- _decrementRefCount(name);
- if (_getRefCount(name) == 0) {
- parcMemory_Deallocate((void **)&(name->refCountPtr));
- nameBitvector_Destroy(&(name->content_name));
- }
- parcMemory_Deallocate((void **)&name);
- *namePtr = NULL;
+void
+name_Release(Name **namePtr)
+{
+ assert(namePtr);
+ assert(*namePtr);
+
+ Name *name = *namePtr;
+ _decrementRefCount(name);
+ if (_getRefCount(name) == 0) {
+ free(name->refCountPtr);
+ nameBitvector_Destroy(&(name->content_name));
+ }
+ free(name);
+ *namePtr = NULL;
}
-Name *name_Acquire(const Name *original) {
- parcAssertNotNull(original, "Parameter must be non-null");
- Name *copy = parcMemory_AllocateAndClear(sizeof(Name));
- parcAssertNotNull(copy, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(Name));
+Name *
+name_Acquire(const Name *original)
+{
+ assert(original);
+
+ Name *copy = malloc(sizeof(Name));
+ assert(copy); // XXX TODO error handling
- memcpy(copy, original, sizeof(Name));
- _incrementRefCount(copy);
+ memcpy(copy, original, sizeof(Name));
+ _incrementRefCount(copy);
- return copy;
+ return copy;
}
-Name *name_Copy(const Name *original) {
- parcAssertNotNull(original, "Parameter must be non-null");
- Name *copy = parcMemory_AllocateAndClear(sizeof(Name));
- parcAssertNotNull(copy, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(Name));
+Name *
+name_Copy(const Name *original)
+{
+ assert(original);
- copy->content_name = nameBitvector_Copy(original->content_name);
- copy->segment = original->segment;
- copy->name_hash = original->name_hash;
+ Name *copy = malloc(sizeof(Name));
+ assert(copy); // XXX TODO error handling
- copy->refCountPtr = parcMemory_Allocate(sizeof(unsigned));
- parcAssertNotNull(copy->refCountPtr, "parcMemory_Allocate(%zu) returned NULL",
- sizeof(unsigned));
- *copy->refCountPtr = 1;
+ copy->content_name = nameBitvector_Copy(original->content_name);
+ copy->segment = original->segment;
+ copy->name_hash = original->name_hash;
- return copy;
+ copy->refCountPtr = malloc(sizeof(unsigned));
+ assert(copy->refCountPtr); // XXX TODO error handling
+ *copy->refCountPtr = 1;
+
+ return copy;
}
-uint32_t name_HashCode(const Name *name) {
- parcAssertNotNull(name, "Parameter must be non-null");
- return name->name_hash;
+uint32_t
+name_HashCode(const Name *name)
+{
+ assert(name);
+ return name->name_hash;
}
-NameBitvector *name_GetContentName(const Name *name) {
- parcAssertNotNull(name, "Parameter must be non-null");
- return name->content_name;
+NameBitvector *
+name_GetContentName(const Name *name)
+{
+ assert(name);
+ return name->content_name;
}
-bool name_Equals(const Name *a, const Name *b) {
- parcAssertNotNull(a, "Parameter a must be non-null");
- parcAssertNotNull(b, "Parameter b must be non-null");
+bool
+name_Equals(const Name *a, const Name *b)
+{
+ assert(a);
+ assert(b);
+
+ /* BEGIN: Workaround for HICN-400 */
+ if ((!a->content_name) || (!b->content_name))
+ return false;
+ /* END: Workaround for HICN-400 */
+
+ if ((nameBitvector_Equals(a->content_name, b->content_name) &&
+ a->segment == b->segment))
+ return true;
+ return false;
+}
- /* BEGIN: Workaround for HICN-400 */
- if ((!a->content_name) || (!b->content_name))
- return false;
- /* END: Workaround for HICN-400 */
+int
+name_Compare(const Name *a, const Name *b)
+{
+ assert(a);
+ assert(b);
- if ((nameBitvector_Equals(a->content_name, b->content_name) &&
- a->segment == b->segment))
- return true;
- return false;
-}
+ if (a == NULL && b == NULL) {
+ return 0;
+ }
+ if (a == NULL) {
+ return -1;
+ }
+ if (b == NULL) {
+ return +1;
+ }
-int name_Compare(const Name *a, const Name *b) {
- parcAssertNotNull(a, "Parameter a must be non-null");
- parcAssertNotNull(b, "Parameter b must be non-null");
-
- if (a == NULL && b == NULL) {
- return 0;
- }
- if (a == NULL) {
- return -1;
- }
- if (b == NULL) {
- return +1;
- }
-
- int res = nameBitvector_Compare(a->content_name, b->content_name);
-
- if (res != 0) {
- return res;
- } else {
- if (a->segment < b->segment) {
- return -1;
- } else if (a->segment > b->segment) {
- return +1;
+ int res = nameBitvector_Compare(a->content_name, b->content_name);
+
+ if (res != 0) {
+ return res;
} else {
- return 0;
+ if (a->segment < b->segment) {
+ return -1;
+ } else if (a->segment > b->segment) {
+ return +1;
+ } else {
+ return 0;
+ }
}
- }
}
-char *name_ToString(const Name *name) {
- char *output = malloc(128);
-
- Address *packetAddr = nameBitvector_ToAddress(name_GetContentName(name));
+char *
+name_ToString(const Name *name)
+{
+ char *output = malloc(128);
- sprintf(output, "name: %s seq: %u", addressToString(packetAddr),
- name->segment);
+ address_t address;
+ nameBitvector_ToAddress(name_GetContentName(name), &address);
- addressDestroy(&packetAddr);
+ // XXX TODO
+#if 0
+ sprintf(output, "name: %s seq: %u", addressToString(address),
+ name->segment);
+#else
+ snprintf(output, 128, "%s", "Not implemented");
+#endif
- return output;
+ return output;
}
-void name_setLen(Name *name, uint8_t len) {
- nameBitvector_setLen(name->content_name, len);
- name->name_hash = _computeHash(name);
+void
+name_setLen(Name *name, uint8_t len)
+{
+ nameBitvector_setLen(name->content_name, len);
+ name->name_hash = _computeHash(name);
}
#ifdef WITH_POLICY
-uint32_t name_GetSuffix(const Name * name) {
+uint32_t
+name_GetSuffix(const Name * name)
+{
return name->segment;
}
-uint8_t name_GetLen(const Name * name) {
+uint8_t
+name_GetLen(const Name * name)
+{
return nameBitvector_GetLength(name->content_name);
}
#endif /* WITH_POLICY */
diff --git a/hicn-light/src/hicn/core/name.h b/hicn-light/src/hicn/core/name.h
index db9438150..f3b3f2a02 100644
--- a/hicn-light/src/hicn/core/name.h
+++ b/hicn-light/src/hicn/core/name.h
@@ -21,9 +21,9 @@
#include <hicn/core/messagePacketType.h>
#include <hicn/core/nameBitvector.h>
-#include <hicn/utils/address.h>
+//#include <hicn/utils/address.h>
-#include <hicn/utils/commands.h>
+//#include <hicn/utils/commands.h>
struct name;
typedef struct name Name;
@@ -93,8 +93,7 @@ void name_setLen(Name *name, uint8_t len);
* Creates a name from a Address
*
*/
-Name *name_CreateFromAddress(address_type addressType, ip_address_t addr,
- uint8_t len);
+Name *name_CreateFromAddress(int family, ip_address_t addr, uint8_t len);
#ifdef WITH_POLICY
uint32_t name_GetSuffix(const Name * name);
diff --git a/hicn-light/src/hicn/core/nameBitvector.c b/hicn-light/src/hicn/core/nameBitvector.c
index 6ad623b14..d3dc8c0ee 100644
--- a/hicn-light/src/hicn/core/nameBitvector.c
+++ b/hicn-light/src/hicn/core/nameBitvector.c
@@ -17,16 +17,13 @@
#include <stdio.h>
#include <stdlib.h>
-#include <parc/algol/parc_Memory.h>
-#include <parc/assert/parc_Assert.h>
-
#include <hicn/core/messageHandler.h>
#include <hicn/core/nameBitvector.h>
-#include <parc/algol/parc_Hash.h>
-
+#include <hicn/common.h> // hash32
#include <hicn/utils/commands.h>
+#define DEFAULT_PORT 1234
#define NAME_LEN 2
const uint64_t BV_SIZE = 64;
@@ -41,322 +38,335 @@ const uint64_t ONE = 0x1;
// 1 b 1 c //hex
struct name_bitvector {
- uint64_t bits[NAME_LEN];
- uint8_t len;
- uint8_t IPversion;
+ uint64_t bits[NAME_LEN];
+ uint8_t len;
+ uint8_t IPversion;
};
-NameBitvector *nameBitvector_CreateFromInAddr(uint32_t addr, uint8_t len) {
- NameBitvector *bitvector = parcMemory_AllocateAndClear(sizeof(NameBitvector));
- parcAssertNotNull(bitvector, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(NameBitvector));
+NameBitvector *
+nameBitvector_CreateFromInAddr(uint32_t addr, uint8_t len)
+{
+ NameBitvector *bitvector = malloc(sizeof(NameBitvector));
+ assert(bitvector); // XXX TODO error handling
- bitvector->bits[0] = 0;
- bitvector->bits[1] = 0;
+ bitvector->bits[0] = 0;
+ bitvector->bits[1] = 0;
- uint8_t addr_1 = (addr & 0xff000000) >> 24;
- uint8_t addr_2 = (addr & 0x00ff0000) >> 16;
- uint8_t addr_3 = (addr & 0x0000ff00) >> 8;
- uint8_t addr_4 = (addr & 0x000000ff);
+ uint8_t addr_1 = (addr & 0xff000000) >> 24;
+ uint8_t addr_2 = (addr & 0x00ff0000) >> 16;
+ uint8_t addr_3 = (addr & 0x0000ff00) >> 8;
+ uint8_t addr_4 = (addr & 0x000000ff);
- bitvector->bits[0] = (bitvector->bits[0] | addr_4) << 8;
- bitvector->bits[0] = (bitvector->bits[0] | addr_3) << 8;
- bitvector->bits[0] = (bitvector->bits[0] | addr_2) << 8;
- bitvector->bits[0] = (bitvector->bits[0] | addr_1);
- bitvector->bits[0] = bitvector->bits[0] << 32;
+ bitvector->bits[0] = (bitvector->bits[0] | addr_4) << 8;
+ bitvector->bits[0] = (bitvector->bits[0] | addr_3) << 8;
+ bitvector->bits[0] = (bitvector->bits[0] | addr_2) << 8;
+ bitvector->bits[0] = (bitvector->bits[0] | addr_1);
+ bitvector->bits[0] = bitvector->bits[0] << 32;
- bitvector->len = len;
+ bitvector->len = len;
- bitvector->IPversion = IPv4_TYPE;
+ bitvector->IPversion = IPv4_TYPE;
- return bitvector;
+ return bitvector;
}
-NameBitvector *nameBitvector_CreateFromIn6Addr(struct in6_addr *addr,
- uint8_t len) {
- parcAssertNotNull(addr, "addr cannot be null");
+NameBitvector *
+nameBitvector_CreateFromIn6Addr(struct in6_addr *addr, uint8_t len)
+{
+ assert(addr);
- NameBitvector *bitvector = parcMemory_AllocateAndClear(sizeof(NameBitvector));
- parcAssertNotNull(bitvector, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(NameBitvector));
+ NameBitvector *bitvector = malloc(sizeof(NameBitvector));
+ assert(bitvector); // XXX TODO error handling
- bitvector->bits[0] = 0;
- bitvector->bits[1] = 0;
+ bitvector->bits[0] = 0;
+ bitvector->bits[1] = 0;
- for (int i = 0; i < 8; ++i) {
- bitvector->bits[0] = (bitvector->bits[0] << 8) | addr->s6_addr[i];
- }
+ for (int i = 0; i < 8; ++i) {
+ bitvector->bits[0] = (bitvector->bits[0] << 8) | addr->s6_addr[i];
+ }
- for (int i = 8; i < 16; ++i) {
- bitvector->bits[1] = (bitvector->bits[1] << 8) | addr->s6_addr[i];
- }
+ for (int i = 8; i < 16; ++i) {
+ bitvector->bits[1] = (bitvector->bits[1] << 8) | addr->s6_addr[i];
+ }
- bitvector->len = len;
+ bitvector->len = len;
- bitvector->IPversion = IPv6_TYPE;
+ bitvector->IPversion = IPv6_TYPE;
- return bitvector;
+ return bitvector;
}
-NameBitvector *nameBitvector_CreateFromAddress(const Address *prefix,
- uint8_t len) {
- parcAssertNotNull(prefix, "prefix cannot be null");
-
- NameBitvector *bitvector = NULL;
- switch (addressGetType(prefix)) {
- case ADDR_INET: {
- struct sockaddr_in addr;
- addressGetInet(prefix, &addr);
- bitvector = nameBitvector_CreateFromInAddr(addr.sin_addr.s_addr, len);
- break;
+NameBitvector *
+nameBitvector_CreateFromAddress(const address_t * address, uint8_t len)
+{
+ assert(address);
+
+ switch(address_family(address)) {
+ case AF_INET:
+ return nameBitvector_CreateFromInAddr(address4_ip(address).s_addr, len);
+ case AF_INET6:
+ return nameBitvector_CreateFromIn6Addr(&address6_ip(address), len);
+ default:
+ return NULL;
}
- case ADDR_INET6: {
- struct sockaddr_in6 addr;
- addressGetInet6(prefix, &addr);
- bitvector = nameBitvector_CreateFromIn6Addr(&addr.sin6_addr, len);
- break;
- }
- default:
- parcTrapNotImplemented("Unkown packet type");
- break;
- }
-
- return bitvector;
}
-NameBitvector *nameBitvector_Copy(const NameBitvector *original) {
- parcAssertNotNull(original, "original cannot be null");
+NameBitvector *
+nameBitvector_Copy(const NameBitvector *original)
+{
+ assert(original);
- NameBitvector *copy = parcMemory_AllocateAndClear(sizeof(NameBitvector));
- parcAssertNotNull(copy, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(NameBitvector));
+ NameBitvector *copy = malloc(sizeof(NameBitvector));
+ assert(copy); // XXX TODO error handling
- copy->bits[0] = original->bits[0];
- copy->bits[1] = original->bits[1];
- copy->len = original->len;
+ copy->bits[0] = original->bits[0];
+ copy->bits[1] = original->bits[1];
+ copy->len = original->len;
- return copy;
+ return copy;
}
-void nameBitvector_Destroy(NameBitvector **bitvectorPtr) {
- parcAssertNotNull(bitvectorPtr, "Parameter must be non-null double pointer");
- parcAssertNotNull(*bitvectorPtr,
- "Parameter must dereference to non-null pointer");
+void
+nameBitvector_Destroy(NameBitvector **bitvectorPtr)
+{
+ assert(bitvectorPtr);
+ assert(*bitvectorPtr);
- NameBitvector *bv = *bitvectorPtr;
- parcMemory_Deallocate((void **)&(bv));
- *bitvectorPtr = NULL;
+ NameBitvector *bv = *bitvectorPtr;
+ free(bv);
+ *bitvectorPtr = NULL;
}
-uint8_t nameBitvector_GetLength(const NameBitvector *name) { return name->len; }
+uint8_t
+nameBitvector_GetLength(const NameBitvector *name)
+{
+ return name->len;
+}
-uint32_t nameBitvector_GetHash32(const NameBitvector *name) {
- return parcHash32_Data_Cumulative((const uint8_t *)name->bits, 16, 0);
+uint32_t
+nameBitvector_GetHash32(const NameBitvector *name)
+{
+ return hash32(&name->bits, 16);
}
-bool nameBitvector_Equals(const NameBitvector *a, const NameBitvector *b) {
- if (a->bits[0] == b->bits[0] && a->bits[1] == b->bits[1] && a->len == b->len)
- return true;
- return false;
+bool
+nameBitvector_Equals(const NameBitvector *a, const NameBitvector *b)
+{
+ if (a->bits[0] == b->bits[0] && a->bits[1] == b->bits[1] && a->len == b->len)
+ return true;
+ return false;
}
-int nameBitvector_Compare(const NameBitvector *a, const NameBitvector *b) {
- if (a == NULL && b == NULL) {
- return 0;
- }
- if (a == NULL) {
- return -1;
- }
- if (b == NULL) {
- return +1;
- }
-
- if (a->bits[0] < b->bits[0]) {
- return -1;
- } else if (a->bits[0] > b->bits[0]) {
- return +1;
- } else if (a->bits[1] < b->bits[1]) {
- return -1;
- } else if (a->bits[1] > b->bits[1]) {
- return +1;
- } else if (a->len < b->len) {
- return -1;
- } else if (a->len > b->len) {
- return +1;
- } else {
- return 0;
- }
+int
+nameBitvector_Compare(const NameBitvector *a, const NameBitvector *b)
+{
+ if (a == NULL && b == NULL) {
+ return 0;
+ }
+ if (a == NULL) {
+ return -1;
+ }
+ if (b == NULL) {
+ return +1;
+ }
+
+ if (a->bits[0] < b->bits[0]) {
+ return -1;
+ } else if (a->bits[0] > b->bits[0]) {
+ return +1;
+ } else if (a->bits[1] < b->bits[1]) {
+ return -1;
+ } else if (a->bits[1] > b->bits[1]) {
+ return +1;
+ } else if (a->len < b->len) {
+ return -1;
+ } else if (a->len > b->len) {
+ return +1;
+ } else {
+ return 0;
+ }
}
-int nameBitvector_testBit(const NameBitvector *name, uint8_t pos, bool *bit) {
- if(pos >= name->len || pos > (WIDTH -1))
- return -1;
+int
+nameBitvector_testBit(const NameBitvector *name, uint8_t pos, bool *bit)
+{
+ if(pos >= name->len || pos > (WIDTH -1))
+ return -1;
- *bit = (name->bits[pos / BV_SIZE] & (ONE << ((BV_SIZE - 1) - (pos % BV_SIZE))));
+ *bit = (name->bits[pos / BV_SIZE] & (ONE << ((BV_SIZE - 1) - (pos % BV_SIZE))));
- return 0;
+ return 0;
}
-uint64_t _diff_bit_log2(uint64_t val) {
- // base 2 log of an uint64_t. This is the same as get the position of
- // the highest bit set (or most significant bit set, MSB)
- uint64_t result = 0;
-
- if (val & 0xFFFFFFFF00000000) {
- val = val >> 32;
- result = result | 32;
- }
- if (val & 0xFFFF0000) {
- val = val >> 16;
- result = result | 16;
- }
- if (val & 0xFF00) {
- val = val >> 8;
- result = result | 8;
- }
- if (val & 0xF0) {
- val = val >> 4;
- result = result | 4;
- }
- if (val & 0xC) {
- val = val >> 2;
- result = result | 2;
- }
- if (val & 0x2) {
- val = val >> 1;
- result = result | 1;
- }
- return result;
+// TODO XXX use ffs(ll)
+uint64_t
+_diff_bit_log2(uint64_t val)
+{
+ // base 2 log of an uint64_t. This is the same as get the position of
+ // the highest bit set (or most significant bit set, MSB)
+ uint64_t result = 0;
+
+ if (val & 0xFFFFFFFF00000000) {
+ val = val >> 32;
+ result = result | 32;
+ }
+ if (val & 0xFFFF0000) {
+ val = val >> 16;
+ result = result | 16;
+ }
+ if (val & 0xFF00) {
+ val = val >> 8;
+ result = result | 8;
+ }
+ if (val & 0xF0) {
+ val = val >> 4;
+ result = result | 4;
+ }
+ if (val & 0xC) {
+ val = val >> 2;
+ result = result | 2;
+ }
+ if (val & 0x2) {
+ val = val >> 1;
+ result = result | 1;
+ }
+ return result;
}
-uint32_t nameBitvector_lpm(const NameBitvector *a,
- const NameBitvector *b) {
- uint32_t limit;
- uint32_t prefix_len;
- if (a->len < b->len)
- limit = a->len;
- else
- limit = b->len;
-
- uint64_t diff = a->bits[0] ^ b->bits[0];
- if(diff){
- prefix_len = (uint32_t)(BV_SIZE - (_diff_bit_log2(diff) + 1));
- //printf("if 1 diff = %lu plen = %d\n", diff, prefix_len);
- }else{
- prefix_len = BV_SIZE;
- diff = a->bits[1] ^ b->bits[1];
+uint32_t
+nameBitvector_lpm(const NameBitvector *a, const NameBitvector *b)
+{
+ uint32_t limit;
+ uint32_t prefix_len;
+ if (a->len < b->len)
+ limit = a->len;
+ else
+ limit = b->len;
+
+ uint64_t diff = a->bits[0] ^ b->bits[0];
if(diff){
- prefix_len += (BV_SIZE - (_diff_bit_log2(diff) + 1));
- //printf("if 2 diff = %lu plen = %d\n", diff, prefix_len);
+ prefix_len = (uint32_t)(BV_SIZE - (_diff_bit_log2(diff) + 1));
+ //printf("if 1 diff = %lu plen = %d\n", diff, prefix_len);
}else{
- prefix_len += BV_SIZE;
+ prefix_len = BV_SIZE;
+ diff = a->bits[1] ^ b->bits[1];
+ if(diff){
+ prefix_len += (BV_SIZE - (_diff_bit_log2(diff) + 1));
+ //printf("if 2 diff = %lu plen = %d\n", diff, prefix_len);
+ }else{
+ prefix_len += BV_SIZE;
+ }
}
- }
- if(prefix_len < limit)
- return prefix_len;
- return limit;
+ if(prefix_len < limit)
+ return prefix_len;
+ return limit;
}
-void nameBitvector_clear(NameBitvector *a, uint8_t start_from){
- for(uint8_t pos = start_from; pos < WIDTH; pos++)
- a->bits[pos / BV_SIZE] &= ~(ONE << ((BV_SIZE - 1) - (pos % BV_SIZE)));
+void
+nameBitvector_clear(NameBitvector *a, uint8_t start_from)
+{
+ for(uint8_t pos = start_from; pos < WIDTH; pos++)
+ a->bits[pos / BV_SIZE] &= ~(ONE << ((BV_SIZE - 1) - (pos % BV_SIZE)));
}
-int nameBitvector_ToIPAddress(const NameBitvector *name,
- ip_prefix_t *prefix) {
- if (name->IPversion == IPv4_TYPE) {
- struct in_addr *addr = (struct in_addr *)(&prefix->address.v4.buffer);
- prefix->family = AF_INET;
- prefix->len = IPV4_ADDR_LEN_BITS;
-
- uint32_t tmp_addr = name->bits[0] >> 32ULL;
- uint8_t addr_1 = (tmp_addr & 0xff000000) >> 24;
- uint8_t addr_2 = (tmp_addr & 0x00ff0000) >> 16;
- uint8_t addr_3 = (tmp_addr & 0x0000ff00) >> 8;
- uint8_t addr_4 = (tmp_addr & 0x000000ff);
-
- addr->s_addr = 0;
- addr->s_addr = (addr->s_addr | addr_4) << 8;
- addr->s_addr = (addr->s_addr | addr_3) << 8;
- addr->s_addr = (addr->s_addr | addr_2) << 8;
- addr->s_addr = (addr->s_addr | addr_1);
-
- } else {
- struct in6_addr *addr = (struct in6_addr *)(&prefix->address.v6.buffer);
- prefix->family = AF_INET6;
- prefix->len = name->len; // IPV6_ADDR_LEN_BITS;
-
- for (int i = 0; i < 8; i++) {
- addr->s6_addr[i] = (uint8_t)((name->bits[0] >> 8 * (7 - i)) & 0xFF);
- }
-
- int x = 0;
- for (int i = 8; i < 16; ++i) {
- addr->s6_addr[i] = (uint8_t)((name->bits[1] >> 8 * (7 - x)) & 0xFF);
- x++;
+int
+nameBitvector_ToIPAddress(const NameBitvector *name, ip_prefix_t *prefix)
+{
+ if (name->IPversion == IPv4_TYPE) {
+ struct in_addr *addr = (struct in_addr *)(&prefix->address.v4.buffer);
+ prefix->family = AF_INET;
+ prefix->len = IPV4_ADDR_LEN_BITS;
+
+ uint32_t tmp_addr = name->bits[0] >> 32ULL;
+ uint8_t addr_1 = (tmp_addr & 0xff000000) >> 24;
+ uint8_t addr_2 = (tmp_addr & 0x00ff0000) >> 16;
+ uint8_t addr_3 = (tmp_addr & 0x0000ff00) >> 8;
+ uint8_t addr_4 = (tmp_addr & 0x000000ff);
+
+ addr->s_addr = 0;
+ addr->s_addr = (addr->s_addr | addr_4) << 8;
+ addr->s_addr = (addr->s_addr | addr_3) << 8;
+ addr->s_addr = (addr->s_addr | addr_2) << 8;
+ addr->s_addr = (addr->s_addr | addr_1);
+
+ } else {
+ struct in6_addr *addr = (struct in6_addr *)(&prefix->address.v6.buffer);
+ prefix->family = AF_INET6;
+ prefix->len = name->len; // IPV6_ADDR_LEN_BITS;
+
+ for (int i = 0; i < 8; i++) {
+ addr->s6_addr[i] = (uint8_t)((name->bits[0] >> 8 * (7 - i)) & 0xFF);
+ }
+
+ int x = 0;
+ for (int i = 8; i < 16; ++i) {
+ addr->s6_addr[i] = (uint8_t)((name->bits[1] >> 8 * (7 - x)) & 0xFF);
+ x++;
+ }
}
- }
- return true;
+ return true;
}
-void nameBitvector_setLen(NameBitvector *name, uint8_t len) { name->len = len; }
-
-Address *nameBitvector_ToAddress(const NameBitvector *name) {
- if (name->IPversion == IPv4_TYPE) {
- struct sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(1234);
-
- uint32_t tmp_addr = name->bits[0] >> 32ULL;
- uint8_t addr_1 = (tmp_addr & 0xff000000) >> 24;
- uint8_t addr_2 = (tmp_addr & 0x00ff0000) >> 16;
- uint8_t addr_3 = (tmp_addr & 0x0000ff00) >> 8;
- uint8_t addr_4 = (tmp_addr & 0x000000ff);
-
- addr.sin_addr.s_addr = 0;
- addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_4) << 8;
- addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_3) << 8;
- addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_2) << 8;
- addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_1);
-
- Address *packetAddr = addressCreateFromInet(&addr);
-
- return packetAddr;
-
- } else {
- struct sockaddr_in6 addr;
- addr.sin6_family = AF_INET6;
- addr.sin6_port = htons(1234);
- addr.sin6_scope_id = 0;
- addr.sin6_flowinfo = 0;
-
- for (int i = 0; i < 8; i++) {
- addr.sin6_addr.s6_addr[i] =
- (uint8_t)((name->bits[0] >> 8 * (7 - i)) & 0xFF);
- }
+void
+nameBitvector_setLen(NameBitvector *name, uint8_t len)
+{
+ name->len = len;
+}
- int x = 0;
- for (int i = 8; i < 16; ++i) {
- addr.sin6_addr.s6_addr[i] =
- (uint8_t)((name->bits[1] >> 8 * (7 - x)) & 0xFF);
- x++;
+void
+nameBitvector_ToAddress(const NameBitvector *name, address_t * address)
+{
+ if (name->IPversion == IPv4_TYPE) {
+ struct sockaddr_in * sin = address4(address);
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons(DEFAULT_PORT);
+
+ uint32_t tmp_addr = name->bits[0] >> 32ULL;
+ uint8_t addr_1 = (tmp_addr & 0xff000000) >> 24;
+ uint8_t addr_2 = (tmp_addr & 0x00ff0000) >> 16;
+ uint8_t addr_3 = (tmp_addr & 0x0000ff00) >> 8;
+ uint8_t addr_4 = (tmp_addr & 0x000000ff);
+
+ sin->sin_addr.s_addr = 0;
+ sin->sin_addr.s_addr = (sin->sin_addr.s_addr | addr_4) << 8;
+ sin->sin_addr.s_addr = (sin->sin_addr.s_addr | addr_3) << 8;
+ sin->sin_addr.s_addr = (sin->sin_addr.s_addr | addr_2) << 8;
+ sin->sin_addr.s_addr = (sin->sin_addr.s_addr | addr_1);
+ } else {
+ struct sockaddr_in6 * sin6 = address6(address);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = htons(DEFAULT_PORT);
+ sin6->sin6_scope_id = 0;
+ sin6->sin6_flowinfo = 0;
+
+ for (int i = 0; i < 8; i++) {
+ sin6->sin6_addr.s6_addr[i] =
+ (uint8_t)((name->bits[0] >> 8 * (7 - i)) & 0xFF);
+ }
+
+ int x = 0;
+ for (int i = 8; i < 16; ++i) {
+ sin6->sin6_addr.s6_addr[i] =
+ (uint8_t)((name->bits[1] >> 8 * (7 - x)) & 0xFF);
+ x++;
+ }
}
-
- Address *packetAddr = addressCreateFromInet6(&addr);
-
- return packetAddr;
- }
}
-char *nameBitvector_ToString(const NameBitvector *name) {
- char *output = malloc(WIDTH);
-
- Address *packetAddr = nameBitvector_ToAddress(name);
+char *
+nameBitvector_ToString(const NameBitvector *name) {
+ char *output = malloc(WIDTH);
- sprintf(output, "prefix: %s len: %u", addressToString(packetAddr), name->len);
+ address_t address;
+ nameBitvector_ToAddress(name, &address);
- addressDestroy(&packetAddr);
+ // XXX TODO
+#if 0
+ sprintf(output, "prefix: %s len: %u", addressToString(packetAddr), name->len);
+#else
+ snprintf(output, WIDTH, "%s", "ENOIMPL");
+#endif
- return output;
+ return output;
}
diff --git a/hicn-light/src/hicn/core/nameBitvector.h b/hicn-light/src/hicn/core/nameBitvector.h
index 19944778c..256af68a0 100644
--- a/hicn-light/src/hicn/core/nameBitvector.h
+++ b/hicn-light/src/hicn/core/nameBitvector.h
@@ -20,7 +20,7 @@
#include <stdint.h>
#include <stdlib.h>
-#include <hicn/utils/address.h>
+#include <hicn/core/address.h>
struct name_bitvector;
typedef struct name_bitvector NameBitvector;
@@ -51,7 +51,7 @@ void nameBitvector_clear(NameBitvector *a, uint8_t start_from);
int nameBitvector_ToIPAddress(const NameBitvector *name, ip_prefix_t *prefix);
void nameBitvector_setLen(NameBitvector *name, uint8_t len);
-Address *nameBitvector_ToAddress(const NameBitvector *name);
+void nameBitvector_ToAddress(const NameBitvector *name, address_t * address);
char *nameBitvector_ToString(const NameBitvector *name);
diff --git a/hicn-light/src/hicn/core/nexthops.h b/hicn-light/src/hicn/core/nexthops.h
new file mode 100644
index 000000000..b45ae360f
--- /dev/null
+++ b/hicn-light/src/hicn/core/nexthops.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file nexthops.h
+ * \brief Nexthops
+ */
+
+#ifndef HICN_NEXTHOPS_H
+#define HICN_NEXTHOPS_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <hicn/core/strategy.h>
+
+#define _nexthops_var(x) _nexthops_##x
+
+/*
+ * This allows storage within a single integer
+ * 32 or 64 nexthops should be sufficient
+ * Eventually replace this with a resizeable vector
+ */
+#define MAX_NEXTHOPS (sizeof(uint_fast32_t) * 8)
+
+typedef struct {
+ unsigned elts[MAX_NEXTHOPS];
+ strategy_nexthop_state_t state[MAX_NEXTHOPS];
+ size_t num_elts;
+ uint_fast32_t flags;
+ size_t cur_elts;
+} nexthops_t;
+
+#define NEXTHOPS_EMPTY (nexthops_t) { \
+ .elts = { 0 }, \
+ .state = { STRATEGY_NEXTHOP_STATE_EMPTY }, \
+ .num_elts = 0, \
+ .flags = 0, \
+ .cur_elts = 0, \
+}
+
+#define nexthops_state(NH, i) ((NH)->state[(i)])
+
+#define nexthops_get_len(NH) ((NH)->num_elts)
+
+#define nexthops_set_len(NH, LEN) \
+do { \
+ (NH)->num_elts = LEN; \
+ (NH)->cur_elts = LEN; \
+} while(0)
+
+#define nexthops_get_curlen(NH) ((NH)->cur_elts)
+
+#define nexthops_inc(NH) \
+do { \
+ (NH)->num_elts++; \
+ (NH)->cur_elts++; \
+} while(0)
+
+#define nexthops_disable(NH, i) \
+do { \
+ (NH)->flags |= (1 << (i)); \
+ (NH)->cur_elts--; \
+} while(0)
+
+#define nexthops_disable_if(NH, i, condition) \
+do { \
+ if (condition) \
+ nexthops_disable((NH), (i)); \
+} while(0)
+
+#define nexthops_is_disabled(NH, i) ((NH)->flags & (1 << (i)))
+
+#define nexthops_reset(NH) \
+do { \
+ (NH)->flags = 0; \
+ (NH)->cur_elts = (NH)->num_elts; \
+} while(0)
+
+#define nexthops_enumerate(NH, i, X, BODY) \
+do { \
+ for ((i) = 0; (i) < nexthops_get_len(NH); (i)++) { \
+ if (nexthops_is_disabled((NH), (i))) \
+ continue; \
+ X = (NH)->elts[(i)]; \
+ do { BODY } while(0); \
+ } \
+} while(0)
+
+#define nexthops_foreach(NH, X, BODY) \
+do { \
+ unsigned _nexthops_var(i); \
+ nexthops_enumerate((NH), _nexthops_var(i), (X), { BODY });\
+} while(0)
+
+#define nexthops_add(NH, X) \
+do { \
+ unsigned _nexthops_var(n); \
+ bool _nexthops_var(found) = false; \
+ nexthops_foreach((NH), _nexthops_var(n), { \
+ if (_nexthops_var(n) == (X)) { \
+ _nexthops_var(found) = true; \
+ break; \
+ } \
+ }); \
+ if (!_nexthops_var(found)) { \
+ (NH)->elts[(NH)->num_elts++] = (X); \
+ nexthops_reset(NH); \
+ } \
+} while(0)
+
+#define nexthops_remove(NH, X) \
+do { \
+ unsigned _nexthops_var(n); \
+ unsigned _nexthops_var(i); \
+ nexthops_enumerate((NH), _nexthops_var(i), _nexthops_var(n), { \
+ if (_nexthops_var(n) == X) { \
+ (NH)->elts[_nexthops_var(i)] = \
+ (NH)->elts[(NH)->num_elts--]; \
+ nexthops_reset(NH); \
+ } \
+ }); \
+} while(0)
+
+#define nexthops_clear(NH) nexthops_set_len(NH, 0);
+
+static inline
+bool
+nexthops_contains(nexthops_t * nexthops, unsigned nexthop)
+{
+ unsigned n;
+ nexthops_foreach(nexthops, n, {
+ if (n == nexthop)
+ return true;
+ });
+ return false;
+}
+
+#define nexthops_select(nexthops, i) ((nexthops)->flags = 1 << (i))
+#define nexthops_select_one(nexthops) (nexthops_select((nexthops), 0))
+
+#endif /* HICN_NEXTHOPS_H */
diff --git a/hicn-light/src/hicn/core/numberSet.c b/hicn-light/src/hicn/core/numberSet.c
deleted file mode 100644
index 106e13be6..000000000
--- a/hicn-light/src/hicn/core/numberSet.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <parc/algol/parc_ArrayList.h>
-#include <parc/algol/parc_Memory.h>
-#include <hicn/hicn-light/config.h>
-#include <hicn/core/numberSet.h>
-#include <stdio.h>
-
-#include <parc/assert/parc_Assert.h>
-
-struct number_set {
- Number *arrayOfNumbers;
- size_t length;
- size_t limit;
- unsigned refcount;
-};
-
-static void numberSet_Expand(NumberSet *set);
-
-NumberSet *numberSet_Create() {
- NumberSet *set = parcMemory_AllocateAndClear(sizeof(NumberSet));
- parcAssertNotNull(set, "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(NumberSet));
- set->arrayOfNumbers = parcMemory_AllocateAndClear(sizeof(Number) * 16);
- parcAssertNotNull((set->arrayOfNumbers),
- "parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(Number) * 16);
- set->length = 0;
- set->limit = 16;
- set->refcount = 1;
- return set;
-}
-
-NumberSet *numberSet_Acquire(const NumberSet *original) {
- parcAssertNotNull(original, "Parameter original must be non-null");
- NumberSet *copy = (NumberSet *)original;
- copy->refcount++;
- return copy;
-}
-
-void numberSet_Release(NumberSet **setPtr) {
- parcAssertNotNull(setPtr, "Parameter must be non-null double pointer");
- parcAssertNotNull(*setPtr, "Parameter must dereference to non-null pointer");
-
- NumberSet *set = *setPtr;
- parcAssertTrue(
- set->refcount > 0,
- "Invalid state: calling destroy on an object with 0 reference count");
- set->refcount--;
-
- if (set->refcount == 0) {
- parcMemory_Deallocate((void **)&(set->arrayOfNumbers));
- parcMemory_Deallocate((void **)&set);
- *setPtr = NULL;
- }
-}
-
-/**
- * @function numberSet_AddNoChecks
- * @abstract Add a number we know is not already in the set
- * @discussion
- * Used by other functions that already know the number is unique in the set,
- * Does not do the expensive Contains check.
- */
-static void numberSet_AddNoChecks(NumberSet *set, Number number) {
- if (set->length == set->limit) {
- numberSet_Expand(set);
- }
-
- set->arrayOfNumbers[set->length] = number;
- set->length++;
-}
-
-bool numberSet_Add(NumberSet *set, Number number) {
- parcAssertNotNull(set, "Parameter set must be non-null");
- if (numberSet_Contains(set, number)) {
- return false;
- }
-
- numberSet_AddNoChecks(set, number);
- return true;
-}
-
-size_t numberSet_Length(const NumberSet *set) {
- parcAssertNotNull(set, "Parameter set must be non-null");
- return set->length;
-}
-
-Number numberSet_GetItem(const NumberSet *set, size_t ordinalIndex) {
- parcAssertNotNull(set, "Parameter set must be non-null");
- parcAssertTrue(ordinalIndex < set->length,
- "Limit beyond end of set, length %zu got %zu", set->length,
- ordinalIndex);
-
- return set->arrayOfNumbers[ordinalIndex];
-}
-
-bool numberSet_Contains(const NumberSet *set, Number number) {
- parcAssertNotNull(set, "Parameter set must be non-null");
- for (size_t i = 0; i < set->length; i++) {
- if (set->arrayOfNumbers[i] == number) {
- return true;
- }
- }
- return false;
-}
-
-void numberSet_AddSet(NumberSet *destinationSet, const NumberSet *setToAdd) {
- parcAssertNotNull(destinationSet,
- "Parameter destinationSet must be non-null");
- parcAssertNotNull(setToAdd, "Parameter setToAdd must be non-null");
-
- for (size_t i = 0; i < setToAdd->length; i++) {
- numberSet_Add(destinationSet, setToAdd->arrayOfNumbers[i]);
- }
-}
-
-NumberSet *numberSet_Subtract(const NumberSet *minuend,
- const NumberSet *subtrahend) {
- // because the underlying ADT is not sorted, this is pretty ineffient, could
- // be O(n^2).
-
- NumberSet *difference = numberSet_Create();
-
- for (size_t i = 0; i < minuend->length; i++) {
- bool unique = true;
- for (size_t j = 0; j < subtrahend->length && unique; j++) {
- if (minuend->arrayOfNumbers[i] == subtrahend->arrayOfNumbers[j]) {
- unique = false;
- }
- }
-
- if (unique) {
- numberSet_AddNoChecks(difference, minuend->arrayOfNumbers[i]);
- }
- }
- return difference;
-}
-
-bool numberSet_Equals(const NumberSet *a, const NumberSet *b) {
- if (a == NULL && b == NULL) {
- return true;
- }
-
- if (a == NULL || b == NULL) {
- return false;
- }
-
- if (a->length == b->length) {
- for (size_t i = 0; i < a->length; i++) {
- bool found = false;
- for (size_t j = 0; j < b->length && !found; j++) {
- if (a->arrayOfNumbers[i] == b->arrayOfNumbers[j]) {
- found = true;
- }
- }
- if (!found) {
- return false;
- }
- }
- return true;
- }
-
- return false;
-}
-
-void numberSet_Remove(NumberSet *set, Number number) {
- parcAssertNotNull(set, "Parameter set must be non-null");
- for (size_t i = 0; i < set->length; i++) {
- if (set->arrayOfNumbers[i] == number) {
- set->length--;
- if (set->length > 0) {
- // move the last element to the removed element to keep the array
- // packed.
- set->arrayOfNumbers[i] = set->arrayOfNumbers[set->length];
- }
- return;
- }
- }
-}
-
-// =====================================================
-
-static void numberSet_Expand(NumberSet *set) {
- size_t newlimit = set->limit * 2;
- size_t newbytes = newlimit * sizeof(Number);
-
- set->arrayOfNumbers = parcMemory_Reallocate(set->arrayOfNumbers, newbytes);
- set->limit = newlimit;
-}
diff --git a/hicn-light/src/hicn/core/numberSet.h b/hicn-light/src/hicn/core/numberSet.h
deleted file mode 100644
index 91a965d7b..000000000
--- a/hicn-light/src/hicn/core/numberSet.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @brief Stores a set of numbers.
- *
- * Useful for things like the reverse path of a PIT
- * or the forward paths of a FIB. Does not allow duplicates.
- *
- */
-
-#ifndef numberSet_h
-#define numberSet_h
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-struct number_set;
-typedef struct number_set NumberSet;
-
-typedef uint32_t Number;
-
-/**
- * @function numberList_Create
- * @abstract A new list of numbers
- */
-NumberSet *numberSet_Create(void);
-
-/**
- * Obtains a reference counted copy of the original
- * The reference count is increased by one. It must be released with
- * NumberSet_Release().
- * @param [in] original An allocated NumberSet
- * @return non-null The reference counted copy
- */
-NumberSet *numberSet_Acquire(const NumberSet *original);
-
-/**
- * Releases one reference count and destroys the memory after last release
- * The pointer will be NULLed after release regardless if the memory was
- * destroyed.
- * @param [in,out] setPtr A pointer to a NumberSet. Will be NULL'd after
- * release.
- */
-void numberSet_Release(NumberSet **setPtr);
-
-/**
- * @function numberList_Append
- * @abstract Add a number to the end of the list
- * @discussion
- * No check for duplicates is done
- * @return true if added, false if a duplicate
- */
-bool numberSet_Add(NumberSet *set, Number number);
-
-/**
- * @function numberList_Length
- * @abstract The count of numbers in the list
- */
-size_t numberSet_Length(const NumberSet *set);
-
-/**
- * @function numberSet_GetItem
- * @abstract Retrieves an item based on the ordinal index
- * @discussion
- * Will assert if the ordinalIndex is out of bounds.
- */
-Number numberSet_GetItem(const NumberSet *set, size_t ordinalIndex);
-
-/**
- * @function numberSet_Contains
- * @abstract Checks for set membership
- * @return true if the set contains the number, false otherwise
- */
-bool numberSet_Contains(const NumberSet *set, Number number);
-
-/**
- * @function numberSet_AddSet
- * @abstract Adds one set to another set
- * @discussion
- * Adds <code>setToAdd</code> to <code>destinationSet</code>
- * @return true if the set contains the number, false otherwise
- */
-void numberSet_AddSet(NumberSet *destinationSet, const NumberSet *setToAdd);
-
-/**
- * @function numberSet_Subtract
- * @abstract Computes set difference <code>difference = minuend -
- * subtrahend</code>, returns a new number set.
- * @discussion
- * <code>minuend</code> and <code>subtrahend</code> are not modified. A new
- * difference set is created.
- *
- * Returns the elements in <code>minuend</code> that are not in
- * <code>subtrahend</code>.
- *
- * @param minuend The set from which to subtract
- * @param subrahend The set begin removed from minuend
- * @return The set difference. May be empty, but will not be NULL.
- */
-NumberSet *numberSet_Subtract(const NumberSet *minuend,
- const NumberSet *subtrahend);
-
-/**
- * Determine if two NumberSet instances are equal.
- *
- * Two NumberSet instances are equal if, and only if,
- * they are the same size and contain the same elements. Empty sets are
- * equal. NULL equals NULL, but does not equal non-NULL.
- *
- * The following equivalence relations on non-null `NumberSet` instances are
- * maintained:
- *
- * * It is reflexive: for any non-null reference value x, `NumberSet_Equals(x,
- * x)` must return true.
- *
- * * It is symmetric: for any non-null reference values x and y,
- * `numberSet_Equals(x, y)` must return true if and only if
- * `numberSet_Equals(y, x)` returns true.
- *
- * * It is transitive: for any non-null reference values x, y, and z, if
- * `numberSet_Equals(x, y)` returns true and
- * `numberSet_Equals(y, z)` returns true,
- * then `numberSet_Equals(x, z)` must return true.
- *
- * * It is consistent: for any non-null reference values x and y, multiple
- * invocations of `numberSet_Equals(x, y)` consistently return true or
- * consistently return false.
- *
- * * For any non-null reference value x, `numberSet_Equals(x, NULL)` must
- * return false.
- *
- * @param a A pointer to a `NumberSet` instance.
- * @param b A pointer to a `NumberSet` instance.
- * @return true if the two `NumberSet` instances are equal.
- */
-bool numberSet_Equals(const NumberSet *a, const NumberSet *b);
-
-/**
- * @function numberSet_Remove
- * @abstract Removes the number from the set
- */
-void numberSet_Remove(NumberSet *set, Number number);
-#endif // numberSet_h
diff --git a/hicn-light/src/hicn/core/packet_cache.c b/hicn-light/src/hicn/core/packet_cache.c
new file mode 100644
index 000000000..1bd004bcc
--- /dev/null
+++ b/hicn-light/src/hicn/core/packet_cache.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file packet_cache.c
+ * \brief Implementation of hICN packet cache
+ */
+
diff --git a/hicn-light/src/hicn/core/packet_cache.h b/hicn-light/src/hicn/core/packet_cache.h
new file mode 100644
index 000000000..52ccb6f71
--- /dev/null
+++ b/hicn-light/src/hicn/core/packet_cache.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file packet_cache.h
+ * \brief hICN packet cache
+ */
+
diff --git a/hicn-light/src/hicn/core/pit.c b/hicn-light/src/hicn/core/pit.c
new file mode 100644
index 000000000..fa54e2429
--- /dev/null
+++ b/hicn-light/src/hicn/core/pit.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2017-2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * The pending interest table.
+ *
+ * Interest aggregation strategy:
+ * - The first Interest for a name is forwarded
+ * - A second Interest for a name from a different reverse path may be
+ * aggregated
+ * - A second Interest for a name from an existing Interest is forwarded
+ * - The Interest Lifetime is like a subscription time. A reverse path entry is
+ * removed once the lifetime is exceeded.
+ * - Whan an Interest arrives or is aggregated, the Lifetime for that reverse
+ * hop is extended. As a simplification, we only keep a single lifetime not per
+ * reverse hop.
+ *
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <hicn/core/msgbuf.h>
+#include <hicn/base/pool.h>
+#include <hicn/core/ticks.h>
+#include <hicn/util/log.h>
+
+#include "pit.h"
+
+// XXX TODO Should not be defined here
+#define DEFAULT_INTEREST_LIFETIME 4000000000ULL
+
+static Ticks _pit_calculate_lifetime(pit_t * pit,
+ msgbuf_t *interest_msgbuf) {
+ uint64_t interestLifetimeTicks =
+ msgbuf_get_interest_lifetime(interest_msgbuf);
+ if (interestLifetimeTicks == 0) {
+ interestLifetimeTicks = NSEC_TO_TICKS(DEFAULT_INTEREST_LIFETIME);
+ }
+
+ Ticks expiry_time = ticks_now() + interestLifetimeTicks;
+ return expiry_time;
+}
+
+// max_elts default is 65535
+pit_t *
+pit_create(size_t max_elts)
+{
+ pit_t * pit = malloc(sizeof(pit_t));
+ if (!pit)
+ return NULL;
+
+ pool_init(pit->entries, max_elts);
+ pit->index_by_name = kh_init(pit_name);
+
+ DEBUG("PIT %p created", pit);
+
+ return pit;
+}
+
+void
+pit_free(pit_t * pit)
+{
+ assert(pit);
+ // XXX TODO
+
+ DEBUG("PIT %p destroyed", pit);
+}
+
+pit_verdict_t
+pit_on_interest(pit_t * pit, msgbuf_t * interest_msgbuf)
+{
+ assert(pit);
+ assert(interest_msgbuf);
+ assert(msgbuf_get_type(interest_msgbuf) == MESSAGE_TYPE_INTEREST);
+
+ fib_entry_t * fib_entry;
+ Ticks expiry_time;
+
+ /* Lookup entry by name */
+ khiter_t k = kh_get_pit_name(pit->index_by_name, msgbuf_get_name(interest_msgbuf));
+ if (k == kh_end(pit->index_by_name))
+ goto NOT_FOUND;
+ pit_entry_t * entry = pit->entries + kh_val(pit->index_by_name, k);
+ assert(entry);
+
+ // has it expired?
+ if (ticks_now() >= pit_entry_get_expiry_time(entry))
+ goto TIMEOUT;
+
+ /* Extend entry lifetime */
+ expiry_time = _pit_calculate_lifetime(pit, interest_msgbuf);
+ if (expiry_time > pit_entry_get_expiry_time(entry))
+ pit_entry_set_expiry_time(entry, expiry_time);
+
+ unsigned connection_id = msgbuf_get_connection_id(interest_msgbuf);
+
+ // Is the reverse path already in the PIT entry?
+ if (pit_entry_ingress_contains(entry, connection_id)) {
+ // It is already in the PIT entry, so this is a retransmission, so
+ // forward it.
+ DEBUG("Message %p existing entry (expiry %" PRIu64 ") and reverse path, forwarding",
+ interest_msgbuf, pit_entry_get_expiry_time(entry));
+ return PIT_VERDICT_RETRANSMIT;
+ }
+
+ // It is in the PIT but this is the first interest for the reverse path
+ pit_entry_ingress_add(entry, connection_id);
+
+ DEBUG("Message %p existing entry (expiry %" PRIu64 ") and reverse path is new, aggregate",
+ interest_msgbuf, pit_entry_get_expiry_time(entry));
+ return PIT_VERDICT_AGGREGATE;
+
+TIMEOUT:
+ fib_entry = pit_entry_get_fib_entry(entry);
+ if (fib_entry)
+ fib_entry_on_timeout(fib_entry, pit_entry_get_egress(entry));
+
+ // it's an old entry, remove it
+ k = kh_get(pit_name, pit->index_by_name, msgbuf_get_name(interest_msgbuf));
+ if (k != kh_end(pit->index_by_name))
+ kh_del(pit_name, pit->index_by_name, k);
+
+NOT_FOUND:
+ /* Create PIT entry */
+
+ expiry_time = _pit_calculate_lifetime(pit, interest_msgbuf);
+
+ pit_allocate(pit, entry, interest_msgbuf);
+ pit_entry_from_msgbuf(entry, interest_msgbuf, expiry_time, ticks_now());
+
+ DEBUG("Message %p added to PIT (expiry %" PRIu64 ") ingress %u",
+ interest_msgbuf, pit_entry_get_expiry_time(entry),
+ msgbuf_get_connection_id(interest_msgbuf));
+
+ return PIT_VERDICT_FORWARD;
+}
+
+nexthops_t *
+pit_on_data(pit_t * pit, const msgbuf_t * data_msgbuf)
+{
+ assert(pit);
+ assert(data_msgbuf);
+ assert(msgbuf_get_type(data_msgbuf) == MESSAGE_TYPE_DATA);
+
+ nexthops_t * nexthops = NULL;
+
+ /* Lookup entry by name */
+ khiter_t k = kh_get_pit_name(pit->index_by_name, msgbuf_get_name(data_msgbuf));
+ if (k == kh_end(pit->index_by_name))
+ goto NOT_FOUND;
+
+ pit_entry_t * entry = pit->entries + kh_val(pit->index_by_name, k);
+ assert(entry);
+
+ // here we need to check if the PIT entry is expired
+ // if so, remove the PIT entry.
+ Ticks now = ticks_now();
+ if (now >= pit_entry_get_expiry_time(entry))
+ goto TIMEOUT;
+
+ /* PIT entry is not expired, use it */
+ fib_entry_t * fib_entry = pit_entry_get_fib_entry(entry);
+ if (fib_entry)
+ fib_entry_on_data(fib_entry, pit_entry_get_egress(entry),
+ data_msgbuf, pit_entry_get_creation_time(entry), ticks_now());
+
+ // XXX TODO : be sure nexthops are valid b/c pit entry is removed
+ // XXX TODO eventually pass holding structure as parameter
+ nexthops = pit_entry_get_ingress(entry);
+
+TIMEOUT:
+ /* Remove entry from PIT */
+ kh_del(pit_name, pit->index_by_name, k);
+
+NOT_FOUND:
+ return nexthops;
+}
+
+void
+pit_remove(pit_t * pit, const msgbuf_t * interest_msgbuf)
+{
+ assert(pit);
+ assert(interest_msgbuf);
+ assert(msgbuf_get_type(interest_msgbuf) == MESSAGE_TYPE_INTEREST);
+
+ khiter_t k = kh_get(pit_name, pit->index_by_name, msgbuf_get_name(interest_msgbuf));
+ if (k == kh_end(pit->index_by_name))
+ return;
+ //off_t index = kh_val(pit->index_by_name, k);
+ //pit_entry_t * entry = pit_at(pit, index);
+ kh_del(pit_name, pit->index_by_name, k);
+
+ DEBUG("Message %p removed from PIT", interest_msgbuf);
+}
+
+pit_entry_t *
+pit_lookup(const pit_t * pit, const msgbuf_t * interest_msgbuf)
+{
+ assert(pit);
+ assert(interest_msgbuf);
+ assert(msgbuf_get_type(interest_msgbuf) == MESSAGE_TYPE_INTEREST);
+
+ khiter_t k = kh_get(pit_name, pit->index_by_name,
+ msgbuf_get_name(interest_msgbuf));
+ if (k == kh_end(pit->index_by_name))
+ return NULL;
+ off_t index = kh_val(pit->index_by_name, k);
+ pit_entry_t * entry = pit_at(pit, index);
+ assert(entry);
+
+ return entry;
+}
diff --git a/hicn-light/src/hicn/core/pit.h b/hicn-light/src/hicn/core/pit.h
new file mode 100644
index 000000000..1aedcfab9
--- /dev/null
+++ b/hicn-light/src/hicn/core/pit.h
@@ -0,0 +1,92 @@
+#ifndef HICNLIGHT_PIT_H
+#define HICNLIGHT_PIT_H
+
+
+#include <hicn/base/khash.h>
+#include <hicn/core/nexthops.h>
+#include <hicn/core/msgbuf.h>
+#include <hicn/core/fib.h>
+#include <hicn/core/name.h>
+#include <hicn/core/ticks.h>
+
+typedef struct {
+ msgbuf_t * msgbuf;
+ nexthops_t ingressIdSet;
+ nexthops_t egressIdSet;
+
+ fib_entry_t * fib_entry;
+
+ Ticks creation_time;
+ Ticks expiry_time;
+} pit_entry_t;
+
+typedef enum {
+ PIT_VERDICT_FORWARD,
+ PIT_VERDICT_AGGREGATE,
+ PIT_VERDICT_RETRANSMIT,
+} pit_verdict_t;
+
+#define pit_entry_get_ingress(E) (&((E)->ingressIdSet))
+#define pit_entry_get_egress(E) (&((E)->egressIdSet))
+#define pit_entry_get_fib_entry(E) ((E)->fib_entry)
+#define pit_entry_set_fib_entry(E, FIB_ENTRY) ((E)->fib_entry = FIB_ENTRY)
+#define pit_entry_get_creation_time(E) ((E)->creation_time)
+#define pit_entry_get_expiry_time(E) ((E)->expiry_time)
+#define pit_entry_set_expiry_time(E, EXPIRY_TIME) \
+ (entry)->expiry_time = EXPIRY_TIME
+
+#define pit_entry_ingress_add(E, NH) \
+ nexthops_add(pit_entry_get_ingress(E), (NH))
+
+#define pit_entry_ingress_contains(E, NH) \
+ nexthops_contains(pit_entry_get_ingress(E), (NH))
+
+#define pit_entry_egress_add(E, NH) \
+ nexthops_add(pit_entry_get_egress(E), (NH))
+
+#define pit_entry_from_msgbuf(E, MSGBUF, EXPIRY_TIME, CREATION_TIME) \
+do { \
+ E->msgbuf = MSGBUF; \
+ pit_entry_ingress_add(E, msgbuf_get_connection_id(MSGBUF)); \
+ E->fib_entry = NULL; \
+ E->creation_time = CREATION_TIME; \
+ E->expiry_time = EXPIRY_TIME; \
+} while(0)
+
+#define name_hash(name) (name_HashCode(name))
+#define name_hash_eq(a, b) (name_hash(b) - name_hash(a))
+
+KHASH_INIT(pit_name, const Name *, unsigned, 0, name_hash, name_hash_eq);
+
+typedef struct {
+ pit_entry_t * entries; // pool
+ kh_pit_name_t * index_by_name;
+} pit_t;
+
+pit_t * pit_create(size_t max_elts);
+
+void pit_free(pit_t * pit);
+
+#define _pit_var(x) _pit_ ## x
+
+#define pit_allocate(pit, entry, msgbuf) \
+do { \
+ pool_get(pit->entries, entry); \
+ unsigned _pit_var(id) = entry - pit->entries; \
+ int _pit_var(res); \
+ khiter_t _pit_var(k) = kh_put(pit_name, pit->index_by_name, \
+ msgbuf_get_name(msgbuf), &_pit_var(res)); \
+ kh_value(pit->index_by_name, _pit_var(k)) = _pit_var(id); \
+} while(0)
+
+#define pit_at(pit, i) (pit->entries + i)
+
+pit_verdict_t pit_on_interest(pit_t * pit, msgbuf_t * msgbuf);
+
+nexthops_t * pit_on_data(pit_t * pit, const msgbuf_t * msgbuf);
+
+void pit_remove(pit_t * pit, const msgbuf_t * msgbuf);
+
+pit_entry_t * pit_lookup(const pit_t * pit, const msgbuf_t * msgbuf);
+
+#endif /* HICNLIGHT_PIT_H */
diff --git a/hicn-light/src/hicn/core/prefix_stats.c b/hicn-light/src/hicn/core/prefix_stats.c
new file mode 100644
index 000000000..c32665950
--- /dev/null
+++ b/hicn-light/src/hicn/core/prefix_stats.c
@@ -0,0 +1,202 @@
+#ifdef WITH_PREFIX_STATS
+
+// This has to be included first because of _GNU_SOURCE
+#include <hicn/core/forwarder.h>
+
+#include <hicn/core/connection_table.h>
+#include <hicn/base/loop.h>
+#include <hicn/core/ticks.h>
+#include <hicn/policy.h>
+#include <hicn/core/fib.h>
+
+#include "prefix_stats.h"
+
+#define ALPHA 0.9
+#define STATS_INTERVAL 1000 /* ms */
+
+static
+void
+prefix_stats_mgr_tick(prefix_stats_mgr_t * mgr, int fd, void * data)
+{
+
+ assert(mgr);
+ assert(!data);
+
+ uint64_t now = ticks_now();
+
+ /* Loop over FIB entries to compute statistics from counters */
+ const fib_t * fib = forwarder_get_fib(mgr->forwarder);
+ fib_entry_t * entry;
+
+ fib_foreach_entry(fib, entry, {
+ prefix_stats_update(&entry->prefix_stats, &entry->prefix_counters, now);
+ });
+}
+
+int
+prefix_stats_mgr_initialize(prefix_stats_mgr_t * mgr, void * forwarder)
+{
+ mgr->forwarder = forwarder;
+ mgr->timer_fd = loop_register_timer(MAIN_LOOP, STATS_INTERVAL, mgr, prefix_stats_mgr_tick, NULL);
+ if (mgr->timer_fd < 0)
+ return -1;
+
+ return 0;
+}
+
+void
+prefix_stats_mgr_finalize(prefix_stats_mgr_t * mgr)
+{
+ loop_unregister_timer(MAIN_LOOP, mgr->timer_fd);
+}
+
+
+void
+prefix_stats_on_retransmission(const prefix_stats_mgr_t * mgr, prefix_counters_t * counters,
+ const nexthops_t * nexthops)
+{
+ connection_table_t * table = forwarder_get_connection_table(mgr->forwarder);
+ unsigned nexthop;
+ nexthops_foreach(nexthops, nexthop, {
+#ifdef WITH_POLICY
+ const connection_t * conn = connection_table_at(table, nexthop);
+
+ if (connection_has_tag(conn, POLICY_TAG_WIRED))
+ counters->wired.num_losses++;
+ if (connection_has_tag(conn, POLICY_TAG_WIFI))
+ counters->wifi.num_losses++;
+ if (connection_has_tag(conn, POLICY_TAG_CELLULAR))
+ counters->cellular.num_losses++;
+#endif /* WITH_POLICY */
+ counters->all.num_losses++;
+ });
+
+}
+
+#define UPDATE_TAG_STATS(TAG, NAME) \
+do { \
+ if (connection_has_tag(conn, TAG)) { \
+ counters->NAME.num_packets++; \
+ counters->NAME.num_bytes += msg_size; \
+ stats->NAME.latency = ALPHA * stats->NAME.latency + \
+ (1 - ALPHA) * (double)rtt; \
+ counters->NAME.latency_idle = 0; \
+ } \
+} while(0)
+
+/* Update statistic counters upon Data packet reception */
+void
+prefix_stats_on_data(const prefix_stats_mgr_t * mgr, prefix_stats_t * stats,
+ prefix_counters_t * counters, const nexthops_t * nexthops,
+ const msgbuf_t * msgbuf, Ticks rtt)
+{
+#ifdef WITH_POLICY
+ forwarder_t * forwarder = mgr->forwarder;
+ connection_table_t * table = forwarder_get_connection_table(forwarder);
+#endif /* WITH_POLICY */
+
+ size_t msg_size = msgbuf_get_len(msgbuf);
+
+ unsigned nexthop;
+ nexthops_foreach(nexthops, nexthop, {
+#ifdef WITH_POLICY
+ const connection_t * conn = connection_table_at(table, nexthop);
+ if (!conn)
+ continue;
+
+ UPDATE_TAG_STATS(POLICY_TAG_WIRED, wired);
+ UPDATE_TAG_STATS(POLICY_TAG_WIFI, wifi);
+ UPDATE_TAG_STATS(POLICY_TAG_CELLULAR, cellular);
+#endif /* WITH_POLICY */
+ });
+
+ stats->all.latency = ALPHA * stats->all.latency +
+ (1 - ALPHA) * (double)rtt;
+ counters->all.latency_idle = 0;
+ counters->all.num_packets++;
+ counters->all.num_bytes += msg_size;
+}
+
+void
+prefix_stats_on_timeout(const prefix_stats_mgr_t * mgr, prefix_counters_t * counters,
+ const nexthops_t * nexthops)
+{
+#ifdef WITH_POLICY
+ connection_table_t * table = forwarder_get_connection_table(mgr->forwarder);
+
+ unsigned nexthop;
+ nexthops_foreach(nexthops, nexthop, {
+ const connection_t * conn = connection_table_at(table, nexthop);
+ if (!conn)
+ continue;
+ if (connection_has_tag(conn, POLICY_TAG_WIRED))
+ counters->wired.num_losses++;
+ if (connection_has_tag(conn, POLICY_TAG_WIFI))
+ counters->wifi.num_losses++;
+ if (connection_has_tag(conn, POLICY_TAG_CELLULAR))
+ counters->cellular.num_losses++;
+ });
+#endif /* WITH_POLICY */
+
+ counters->all.num_losses++;
+}
+
+#define UPDATE_TYPE(TYPE) \
+do { \
+ /* (a) throughput */ \
+ if (counters->TYPE.num_bytes > 0) { \
+ throughput = counters->TYPE.num_bytes / \
+ (now - counters->last_update) ; \
+ throughput = throughput * 8 / 1024; \
+ if (throughput < 0) \
+ throughput = 0; \
+ } else { \
+ throughput = 0; \
+ } \
+ stats->TYPE.throughput = ALPHA * stats->TYPE.throughput + \
+ (1-ALPHA) * throughput; \
+ \
+ /* (b) loss rate */ \
+ if ((counters->TYPE.num_losses > 0) && \
+ (counters->TYPE.num_packets > 0)) { \
+ loss_rate = counters->TYPE.num_losses / \
+ counters->TYPE.num_packets; \
+ loss_rate *= 100; \
+ } else { \
+ loss_rate = 0; \
+ } \
+ stats->TYPE.loss_rate = ALPHA * stats->TYPE.loss_rate + \
+ (1-ALPHA) * loss_rate; \
+ \
+ /* (c) latency */ \
+ counters->TYPE.latency_idle++; \
+ if (counters->TYPE.latency_idle > 1) \
+ stats->TYPE.latency = 0; \
+ \
+ /* (d) Reset counters */ \
+ counters->TYPE.num_bytes = 0; \
+ counters->TYPE.num_losses = 0; \
+ counters->TYPE.num_packets = 0; \
+} while(0)
+
+void
+prefix_stats_update(prefix_stats_t * stats, prefix_counters_t * counters, uint64_t now)
+{
+ double throughput;
+ double loss_rate;
+
+ if (now == counters->last_update)
+ return;
+
+#ifdef WITH_POLICY
+ UPDATE_TYPE(wired);
+ UPDATE_TYPE(wifi);
+ UPDATE_TYPE(cellular);
+#endif /* WITH_POLICY */
+ UPDATE_TYPE(all);
+
+ counters->last_update = now;
+
+}
+
+#endif /* WITH_PREFIX_STATS */
diff --git a/hicn-light/src/hicn/core/prefix_stats.h b/hicn-light/src/hicn/core/prefix_stats.h
new file mode 100644
index 000000000..257f6b44d
--- /dev/null
+++ b/hicn-light/src/hicn/core/prefix_stats.h
@@ -0,0 +1,91 @@
+
+#ifndef HICNLIGHT_PREFIX_STATS_H
+#define HICNLIGHT_PREFIX_STATS_H
+
+#ifdef WITH_PREFIX_STATS
+
+typedef struct prefix_stats_mgr_s {
+ void * forwarder;
+ int timer_fd;
+} prefix_stats_mgr_t;
+
+
+/* PER-INTERFACE PREFIX STATS */
+
+typedef struct {
+ float throughput;
+ float latency;
+ float loss_rate;
+} interface_stats_t;
+
+/* PREFIX STATS */
+
+typedef struct {
+ interface_stats_t wired;
+ interface_stats_t wifi;
+ interface_stats_t cellular;
+ interface_stats_t all;
+} prefix_stats_t;
+
+typedef struct {
+ uint32_t num_packets;
+ uint32_t num_bytes;
+ uint32_t num_losses;
+ uint32_t latency_idle;
+} interface_counters_t;
+
+typedef struct {
+ interface_counters_t wired;
+ interface_counters_t wifi;
+ interface_counters_t cellular;
+ interface_counters_t all;
+ uint64_t last_update;
+} prefix_counters_t;
+
+#define INTERFACE_STATS_EMPTY (interface_stats_t) { \
+ .throughput = 0, \
+ .latency = 0, \
+ .loss_rate = 0, \
+}
+
+#define PREFIX_STATS_EMPTY (prefix_stats_t) { \
+ .wired = INTERFACE_STATS_EMPTY, \
+ .wifi = INTERFACE_STATS_EMPTY, \
+ .cellular = INTERFACE_STATS_EMPTY, \
+ .all = INTERFACE_STATS_EMPTY, \
+}
+
+#define INTERFACE_COUNTERS_EMPTY (interface_counters_t) { \
+ .num_packets = 0, \
+ .num_bytes = 0, \
+ .num_losses = 0, \
+ .latency_idle = 0, \
+}
+
+#define PREFIX_COUNTERS_EMPTY (prefix_counters_t) { \
+ .wired = INTERFACE_COUNTERS_EMPTY, \
+ .wifi = INTERFACE_COUNTERS_EMPTY, \
+ .cellular = INTERFACE_COUNTERS_EMPTY, \
+ .all = INTERFACE_COUNTERS_EMPTY, \
+ .last_update = 0, \
+}
+
+int prefix_stats_mgr_initialize(prefix_stats_mgr_t * mgr, void * forwarder);
+
+void prefix_stats_mgr_finalize(prefix_stats_mgr_t * mgr);
+
+void prefix_stats_on_retransmission(const prefix_stats_mgr_t * mgr,
+ prefix_counters_t * countrs, const nexthops_t * nexthops);
+
+void prefix_stats_on_data(const prefix_stats_mgr_t * mgr, prefix_stats_t * stats,
+ prefix_counters_t * counters, const nexthops_t * nexthops,
+ const msgbuf_t * msgbuf, Ticks rtt);
+
+void prefix_stats_on_timeout(const prefix_stats_mgr_t * mgr, prefix_counters_t * counters,
+ const nexthops_t * nexthops);
+
+void prefix_stats_update(prefix_stats_t * stats, prefix_counters_t * counters, uint64_t now);
+
+#endif /* WITH_PREFIX_STATS */
+
+#endif /* HICNLIGHT_PREFIX_STATS_H */
diff --git a/hicn-light/src/hicn/core/strategy.c b/hicn-light/src/hicn/core/strategy.c
new file mode 100644
index 000000000..66ab232b5
--- /dev/null
+++ b/hicn-light/src/hicn/core/strategy.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file strategy.c
+ * \brief Implementation of hICN forwarding strategy
+ */
+
+#include <hicn/core/strategy_vft.h>
+
+#include <hicn/strategies/load_balancer.h>
+#include <hicn/strategies/random.h>
+#include <hicn/strategies/low_latency.h>
+
+extern const strategy_ops_t strategy_load_balancer;
+extern const strategy_ops_t strategy_random;
+extern const strategy_ops_t strategy_low_latency;
+
+const strategy_ops_t * const strategy_vft[] = {
+ [STRATEGY_TYPE_LOADBALANCER] = &strategy_load_balancer,
+ [STRATEGY_TYPE_RANDOM] = &strategy_random,
+#if 0
+ [STRATEGY_TYPE_LOW_LATENCY] = &strategy_low_latency,
+#endif
+};
+
+
diff --git a/hicn-light/src/hicn/core/strategy.h b/hicn-light/src/hicn/core/strategy.h
new file mode 100644
index 000000000..3d48c5510
--- /dev/null
+++ b/hicn-light/src/hicn/core/strategy.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file strategy.h
+ * \brief hICN forwarding strategy
+ */
+#ifndef HICN_STRATEGY_H
+#define HICN_STRATEGY_H
+
+#include <hicn/core/name.h>
+#include <hicn/core/msgbuf.h>
+
+#include <hicn/strategies/load_balancer.h>
+#include <hicn/strategies/low_latency.h>
+#include <hicn/strategies/random.h>
+
+typedef enum {
+ STRATEGY_TYPE_UNDEFINED,
+ STRATEGY_TYPE_LOADBALANCER,
+ STRATEGY_TYPE_LOW_LATENCY,
+ STRATEGY_TYPE_RANDOM,
+ STRATEGY_TYPE_N
+} strategy_type_t;
+
+#define STRATEGY_TYPE_VALID(type) \
+ ((type != STRATEGY_TYPE_UNDEFINED) && (type != STRATEGY_TYPE_N))
+
+typedef union {
+ strategy_load_balancer_options_t load_balancer;
+ strategy_low_latency_options_t low_latency;
+ strategy_random_options_t random;
+} strategy_options_t;
+
+typedef union {
+ strategy_load_balancer_nexthop_state_t load_balancer;
+ strategy_low_latency_nexthop_state_t low_latency;
+ strategy_random_nexthop_state_t random;
+} strategy_nexthop_state_t;
+
+#define STRATEGY_NEXTHOP_STATE_EMPTY {{ 0 }}
+
+typedef union {
+ strategy_load_balancer_state_t load_balancer;
+ strategy_low_latency_state_t low_latency;
+ strategy_random_state_t random;
+} strategy_state_t;
+// XXX This has to be merged with nexthops
+// XXX How to avoid errors due to pool id reuse (eg on_data) ?
+
+typedef struct {
+ strategy_type_t type;
+ strategy_options_t options;
+ strategy_state_t state;
+} strategy_entry_t;
+
+
+#endif /* HICN_STRATEGY_H */
diff --git a/hicn-light/src/hicn/core/strategy_vft.h b/hicn-light/src/hicn/core/strategy_vft.h
new file mode 100644
index 000000000..e698c9d94
--- /dev/null
+++ b/hicn-light/src/hicn/core/strategy_vft.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file strategy_vft.h
+ * \brief hICN forwarding strategy VFT
+ */
+#ifndef HICN_STRATEGY_VFT_H
+#define HICN_STRATEGY_VFT_H
+
+#include <hicn/core/strategy.h>
+#include <hicn/core/nexthops.h>
+
+/**
+ * @typedef strategy_ops_t
+ * @abstract Forwarding strategy implementation
+ * @constant receiveObject is called when we receive an object and have a
+ * measured round trip time. This allows a strategy to update its performance
+ * data.
+ * @constant lookupNexthop Find the set of nexthops to use for the Interest.
+ * May be empty, should not be NULL. Must be destroyed.
+ * @constant addNexthop Add a nexthop to the list of available nexthops with a
+ * routing protocol-specific cost.
+ * @constant destroy cleans up the strategy, freeing all memory and state. A
+ * strategy is reference counted, so the final destruction only happens after
+ * the last reference is released.
+ * @discussion <#Discussion#>
+ */
+typedef struct {
+ const char * name;
+
+ void (*initialize)(strategy_entry_t * entry);
+
+ void (*finalize)(strategy_entry_t * entry);
+
+ nexthops_t * (*lookup_nexthops)(strategy_entry_t * entry, nexthops_t * nexthops,
+ const msgbuf_t * msgbuf);
+
+ void (*add_nexthop)(strategy_entry_t * strategy, unsigned nexthop, strategy_nexthop_state_t * state);
+
+ void (*remove_nexthop)(strategy_entry_t * entry, unsigned nexthop, strategy_nexthop_state_t * state);
+
+ void (*on_data)(strategy_entry_t * entry, const nexthops_t * nexthops,
+ const msgbuf_t * msgbuf, Ticks pitEntryCreation, Ticks objReception);
+
+ void (*on_timeout)(strategy_entry_t * entry, const nexthops_t * nexthops);
+
+} strategy_ops_t;
+
+extern const strategy_ops_t * const strategy_vft[];
+
+#define DECLARE_STRATEGY(NAME) \
+const strategy_ops_t strategy_ ## NAME = { \
+ .name = #NAME, \
+ .initialize = strategy_ ## NAME ## _initialize, \
+ .finalize = strategy_ ## NAME ## _finalize, \
+ .add_nexthop = strategy_ ## NAME ## _add_nexthop, \
+ .remove_nexthop = strategy_ ## NAME ## _remove_nexthop, \
+ .lookup_nexthops = strategy_ ## NAME ## _lookup_nexthops, \
+ .on_data = strategy_ ## NAME ## _on_data, \
+ .on_timeout = strategy_ ## NAME ## _on_timeout, \
+}
+
+#endif /* HICN_STRATEGY_VFT_H */
diff --git a/hicn-light/src/hicn/core/system.h b/hicn-light/src/hicn/core/system.h
index be6c3e7cf..b47113f70 100644
--- a/hicn-light/src/hicn/core/system.h
+++ b/hicn-light/src/hicn/core/system.h
@@ -25,7 +25,6 @@
#define system_h
#include <hicn/core/forwarder.h>
-#include <hicn/utils/interfaceSet.h>
/**
* @function system_Interfaces
diff --git a/hicn-light/src/hicn/core/ticks.h b/hicn-light/src/hicn/core/ticks.h
index 8750abde5..bebcd3635 100644
--- a/hicn-light/src/hicn/core/ticks.h
+++ b/hicn-light/src/hicn/core/ticks.h
@@ -25,7 +25,40 @@
#define __STDC_FORMAT_MACROS
#include <stdint.h>
+#include <time.h>
+
+#include <sys/param.h> // HZ
+
typedef uint64_t Ticks;
+// these will all be a little off because its all integer division
+#define NSEC_PER_TICK ((1000000000ULL) / HZ)
+#define NSEC_TO_TICKS(nsec) ((nsec < NSEC_PER_TICK) ? 1 : nsec / NSEC_PER_TICK)
+
+#define TICKS_TO_NSEC(ticks) ((1000000000ULL) * ticks / HZ)
+
+static inline
+Ticks
+ticks_now()
+{
+#if __linux__
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+ return ts.tv_sec * 1000 + ts.tv_nsec / 1e6;
+#elif _WIN32
+ struct timespec ts;
+ _clock_gettime(TIME_UTC, &ts);
+ return ts.tv_sec * 1000 + ts.tv_nsec / 1e6;
+#else
+ clock_serv_t clockService;
+ mach_timespec_t ts;
+ host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &clockService);
+ clock_get_time(clockService, &mts);
+ mach_port_deallocate(mach_task_self(), clockService);
+#endif
+
+ return ts.tv_sec * 1000 + ts.tv_nsec / 1e6;
+}
+
#endif // ticks_h
diff --git a/hicn-light/src/hicn/core/wldr.c b/hicn-light/src/hicn/core/wldr.c
index ad3663d0d..5a6c876b9 100644
--- a/hicn-light/src/hicn/core/wldr.c
+++ b/hicn-light/src/hicn/core/wldr.c
@@ -13,93 +13,100 @@
* limitations under the License.
*/
-#include <parc/assert/parc_Assert.h>
-#include <parc/logging/parc_LogReporterTextStdout.h>
#include <hicn/core/connection.h>
#include <hicn/core/forwarder.h>
#include <hicn/core/wldr.h>
#include <stdint.h>
#include <stdio.h>
-struct wldr_buffer {
- Message *message;
+typedef struct {
+ msgbuf_t *msgbuf;
uint8_t rtx_counter;
-};
-
-typedef struct wldr_buffer WldrBuffer;
+} wldr_buffer_t;
-struct wldr_state {
+struct wldr_s {
uint16_t expected_label;
uint16_t next_label;
- WldrBuffer *buffer[BUFFER_SIZE];
+ wldr_buffer_t * buffer[BUFFER_SIZE];
};
-Wldr *wldr_Init() {
- Wldr *wldr = parcMemory_AllocateAndClear(sizeof(Wldr));
+wldr_t * wldr_create() {
+#if 0
+ wldr_t * wldr = parcMemory_AllocateAndClear(sizeof(Wldr));
parcAssertNotNull(wldr, "parcMemory_AllocateAndClear(%zu) returned NULL",
sizeof(Wldr));
wldr->expected_label = 1;
wldr->next_label = 1;
for (int i = 0; i < BUFFER_SIZE; i++) {
- WldrBuffer *entry = parcMemory_AllocateAndClear(sizeof(WldrBuffer));
+ wldr_buffer_t *entry = parcMemory_AllocateAndClear(sizeof(wldr_buffer_t));
parcAssertNotNull(
entry,
- "WldrBuffer init: parcMemory_AllocateAndClear(%zu) returned NULL",
- sizeof(WldrBuffer));
- entry->message = NULL;
+ "wldr_buffer_t init: parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(wldr_buffer_t));
+ entry->msgbuf = NULL;
entry->rtx_counter = 0;
wldr->buffer[i] = entry;
}
return wldr;
+#else
+ return NULL;
+#endif
}
-void wldr_ResetState(Wldr *wldr) {
+void wldr_resset_state(wldr_t * wldr) {
+#if 0
wldr->expected_label = 1;
wldr->next_label = 1;
for (int i = 0; i < BUFFER_SIZE; i++) {
- wldr->buffer[i]->message = NULL;
+ wldr->buffer[i]->msgbuf = NULL;
wldr->buffer[i]->rtx_counter = 0;
}
+#endif
}
-void wldr_Destroy(Wldr **wldrPtr) {
- Wldr *wldr = *wldrPtr;
+void wldr_free(wldr_t * wldr) {
+#if 0
+ wldr_t * wldr = *wldrPtr;
for (unsigned i = 0; i < BUFFER_SIZE; i++) {
- if (wldr->buffer[i]->message != NULL) {
- message_Release(&(wldr->buffer[i]->message));
+ if (wldr->buffer[i]->msgbuf != NULL) {
+ message_Release(&(wldr->buffer[i]->msgbuf));
parcMemory_Deallocate((void **)&(wldr->buffer[i]));
}
}
parcMemory_Deallocate((void **)&wldr);
*wldrPtr = NULL;
+#endif
}
-static void _wldr_RetransmitPacket(Wldr *wldr, const Connection *conn,
+#if 0
+static void _wldr_RetransmitPacket(wldr_t * wldr, const connection_t * conn,
uint16_t label) {
- if (wldr->buffer[label % BUFFER_SIZE]->message == NULL) {
+ if (wldr->buffer[label % BUFFER_SIZE]->msgbuf == NULL) {
// the required message for retransmission is not in the buffer
return;
}
if (wldr->buffer[label % BUFFER_SIZE]->rtx_counter < MAX_RTX) {
- Message *msg = wldr->buffer[label % BUFFER_SIZE]->message;
+ msgbuf_t *msg = wldr->buffer[label % BUFFER_SIZE]->msgbuf;
message_SetWldrLabel(msg, wldr->next_label);
- if (wldr->buffer[wldr->next_label % BUFFER_SIZE]->message != NULL) {
- message_Release(&(wldr->buffer[wldr->next_label % BUFFER_SIZE]->message));
+ if (wldr->buffer[wldr->next_label % BUFFER_SIZE]->msgbuf != NULL) {
+ msgbuf_Release(&(wldr->buffer[wldr->next_label % BUFFER_SIZE]->msgbuf));
}
- wldr->buffer[wldr->next_label % BUFFER_SIZE]->message = msg;
+ wldr->buffer[wldr->next_label % BUFFER_SIZE]->msgbuf = msg;
wldr->buffer[wldr->next_label % BUFFER_SIZE]->rtx_counter =
wldr->buffer[label % BUFFER_SIZE]->rtx_counter + 1;
- message_Acquire(wldr->buffer[wldr->next_label % BUFFER_SIZE]->message);
+ message_Acquire(wldr->buffer[wldr->next_label % BUFFER_SIZE]->msgbuf);
wldr->next_label++;
connection_ReSend(conn, msg, false);
}
}
+#endif
-static void _wldr_SendWldrNotificaiton(Wldr *wldr, const Connection *conn,
- Message *message, uint16_t expected_lbl,
+#if 0
+static void _wldr_SendWldrNotification(wldr_t * wldr, const connection_t * conn,
+ msgbuf_t *msgbuf, uint16_t expected_lbl,
uint16_t received_lbl) {
// here we need to create a new packet that is used to send the wldr
// notification to the prevoius hop. the destionation address of the
@@ -113,38 +120,42 @@ static void _wldr_SendWldrNotificaiton(Wldr *wldr, const Connection *conn,
// this way the notification packet will be dispaced to the right connection
// at the next hop.
- Message *notification =
- message_CreateWldrNotification(message, expected_lbl, received_lbl);
+ msgbuf_t *notification =
+ message_CreateWldrNotification(msgbuf, expected_lbl, received_lbl);
parcAssertNotNull(notification, "Got null from CreateWldrNotification");
connection_ReSend(conn, notification, true);
}
+#endif
-void wldr_SetLabel(Wldr *wldr, Message *message) {
+void wldr_set_label(wldr_t * wldr, msgbuf_t *msgbuf) {
+#if 0
// in this function we send the packet for the first time
// 1) we set the wldr label
- message_SetWldrLabel(message, wldr->next_label);
+ message_SetWldrLabel(msgbuf, wldr->next_label);
// 2) we store the pointer to packet in the buffer
- if (wldr->buffer[wldr->next_label % BUFFER_SIZE]->message != NULL) {
+ if (wldr->buffer[wldr->next_label % BUFFER_SIZE]->msgbuf != NULL) {
// release an old message if necessary
- message_Release(&(wldr->buffer[wldr->next_label % BUFFER_SIZE]->message));
+ message_Release(&(wldr->buffer[wldr->next_label % BUFFER_SIZE]->msgbuf));
}
// we need to acquire the message to avoid that it gets destroyed
- message_Acquire(message);
+ message_Acquire(msgbuf);
- wldr->buffer[wldr->next_label % BUFFER_SIZE]->message = message;
+ wldr->buffer[wldr->next_label % BUFFER_SIZE]->msgbuf = msgbuf;
wldr->buffer[wldr->next_label % BUFFER_SIZE]->rtx_counter = 0;
wldr->next_label++;
if (wldr->next_label ==
0) // we alwasy skip label 0 beacause it means that wldr is not active
wldr->next_label++;
+#endif
}
-void wldr_DetectLosses(Wldr *wldr, const Connection *conn, Message *message) {
- if (message_HasWldr(message)) {
+void wldr_detect_losses(wldr_t * wldr, const connection_t * conn, msgbuf_t *msgbuf) {
+#if 0
+ if (message_HasWldr(msgbuf)) {
// this is a normal wldr packet
- uint16_t pkt_lbl = (uint16_t)message_GetWldrLabel(message);
+ uint16_t pkt_lbl = (uint16_t)message_GetWldrLabel(msgbuf);
if (pkt_lbl != wldr->expected_label) {
// if the received packet label is 1 and the expected packet label >
// pkt_lbl usually we are in the case where a remote note disconnected for
@@ -153,7 +164,7 @@ void wldr_DetectLosses(Wldr *wldr, const Connection *conn, Message *message) {
// synch the labels
if ((pkt_lbl != 1) || (wldr->expected_label < pkt_lbl)) {
- _wldr_SendWldrNotificaiton(wldr, conn, message, wldr->expected_label,
+ _wldr_SendWldrNotificaiton(wldr, conn, msgbuf, wldr->expected_label,
pkt_lbl);
}
@@ -165,12 +176,14 @@ void wldr_DetectLosses(Wldr *wldr, const Connection *conn, Message *message) {
wldr->expected_label++; // for the next_label we want to skip 0
}
}
+#endif
}
-void wldr_HandleWldrNotification(Wldr *wldr, const Connection *conn,
- Message *message) {
- uint16_t expected_lbl = (uint16_t)message_GetWldrExpectedLabel(message);
- uint16_t received_lbl = (uint16_t)message_GetWldrLastReceived(message);
+void wldr_handle_notification(wldr_t * wldr, const connection_t * conn,
+ msgbuf_t *msgbuf) {
+#if 0
+ uint16_t expected_lbl = (uint16_t)message_GetWldrExpectedLabel(msgbuf);
+ uint16_t received_lbl = (uint16_t)message_GetWldrLastReceived(msgbuf);
if ((wldr->next_label - expected_lbl) > BUFFER_SIZE) {
// the packets are not in the buffer anymore
return;
@@ -179,4 +192,5 @@ void wldr_HandleWldrNotification(Wldr *wldr, const Connection *conn,
_wldr_RetransmitPacket(wldr, conn, expected_lbl);
expected_lbl++;
}
+#endif
}
diff --git a/hicn-light/src/hicn/core/wldr.h b/hicn-light/src/hicn/core/wldr.h
index e21889f63..cb2f0e2cf 100644
--- a/hicn-light/src/hicn/core/wldr.h
+++ b/hicn-light/src/hicn/core/wldr.h
@@ -18,7 +18,7 @@
#include <hicn/hicn-light/config.h>
#include <hicn/core/connection.h>
-#include <hicn/core/message.h>
+#include <hicn/core/msgbuf.h>
#define BUFFER_SIZE 8192
#define MAX_RTX 3
@@ -34,19 +34,18 @@
// ATTENTION!!! in order to detect a notificaiton the
// source and destination ports must be set to 0
-struct wldr_state;
-typedef struct wldr_state Wldr;
+typedef struct wldr_s wldr_t;
-Wldr *wldr_Init();
+wldr_t *wldr_create();
-void wldr_Destroy(Wldr **wldrPtr);
+void wldr_free(wldr_t * wldr);
-void wldr_ResetState(Wldr *wldr);
+void wldr_reset_state(wldr_t * wldr);
-void wldr_SetLabel(Wldr *wldr, Message *message);
+void wldr_set_label(wldr_t * wldr, msgbuf_t * msgbuf);
-void wldr_DetectLosses(Wldr *wldr, const Connection *conn, Message *message);
+void wldr_detect_losses(wldr_t * wldr, const connection_t * conn, msgbuf_t * msgbuf);
-void wldr_HandleWldrNotification(Wldr *wldr, const Connection *conn,
- Message *message);
+void wldr_handle_notification(wldr_t *wldr, const connection_t * conn,
+ msgbuf_t * msgbuf);
#endif // wldr_h