diff options
Diffstat (limited to 'hicn-light/src/hicn/core')
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, ¶ms); - 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, ¶ms); + 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, ¶ms); - - switch (params.type) { - case UPDATE: - case NOTIFICATION: - mapme_onSpecialInterest(mapme, msgBuffer, conn_id, &prefix, ¶ms); - break; - case UPDATE_ACK: - case NOTIFICATION_ACK: - mapme_onSpecialInterestAck(mapme, msgBuffer, conn_id, &prefix, ¶ms); - 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, ¶ms); + 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, ¶ms); + break; + case UPDATE_ACK: + case NOTIFICATION_ACK: + mapme_on_data(mapme, packet, conn_id, &prefix, ¶ms); + 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 |