aboutsummaryrefslogtreecommitdiffstats
path: root/hicn-light
diff options
context:
space:
mode:
authorLuca Muscariello <lumuscar@cisco.com>2022-06-09 21:34:09 +0200
committerLuca Muscariello <muscariello@ieee.org>2022-06-30 10:47:50 +0200
commit6b94663b2455e212009a544ae23bb6a8c55407f8 (patch)
tree0af780ce5eeb1009fd24b8af8af08e8368eda3bd /hicn-light
parenta1ac96f497719b897793ac14b287cb8d840651c1 (diff)
refactor(lib, hicn-light, vpp, hiperf): HICN-723
- move infra data structure into the shared lib - new packet cache using double hashing and lookup on prefix suffix - testing updates - authenticated requests using interest manifests Co-authored-by: Mauro Sardara <msardara@cisco.com> Co-authored-by: Jordan Augé <jordan.auge+fdio@cisco.com> Co-authored-by: Michele Papalini <micpapal@cisco.com> Co-authored-by: Olivier Roques <oroques+fdio@cisco.com> Co-authored-by: Enrico Loparco <eloparco@cisco.com> Change-Id: Iaddebfe6aa5279ea8553433b0f519578f6b9ccd9 Signed-off-by: Luca Muscariello <muscariello@ieee.org>
Diffstat (limited to 'hicn-light')
-rw-r--r--hicn-light/CMakeLists.txt1
-rw-r--r--hicn-light/src/hicn/base/CMakeLists.txt10
-rw-r--r--hicn-light/src/hicn/base/bitmap.h191
-rw-r--r--hicn-light/src/hicn/base/common.h62
-rw-r--r--hicn-light/src/hicn/base/hash.h349
-rw-r--r--hicn-light/src/hicn/base/khash.h748
-rw-r--r--hicn-light/src/hicn/base/pool.c158
-rw-r--r--hicn-light/src/hicn/base/pool.h254
-rw-r--r--hicn-light/src/hicn/base/ring.c45
-rw-r--r--hicn-light/src/hicn/base/ring.h201
-rw-r--r--hicn-light/src/hicn/base/vector.c85
-rw-r--r--hicn-light/src/hicn/base/vector.h327
-rw-r--r--hicn-light/src/hicn/cli/hicnc.c65
-rw-r--r--hicn-light/src/hicn/cli/hicnd.c2
-rw-r--r--hicn-light/src/hicn/config/CMakeLists.txt1
-rw-r--r--hicn-light/src/hicn/config/command_stats.c18
-rw-r--r--hicn-light/src/hicn/config/commands.c115
-rw-r--r--hicn-light/src/hicn/config/commands.h3
-rw-r--r--hicn-light/src/hicn/config/configuration.h2
-rw-r--r--hicn-light/src/hicn/core/CMakeLists.txt2
-rw-r--r--hicn-light/src/hicn/core/address_pair.h6
-rw-r--r--hicn-light/src/hicn/core/connection.c12
-rw-r--r--hicn-light/src/hicn/core/connection.h6
-rw-r--r--hicn-light/src/hicn/core/connection_table.c78
-rw-r--r--hicn-light/src/hicn/core/connection_table.h68
-rw-r--r--hicn-light/src/hicn/core/connection_vft.h4
-rw-r--r--hicn-light/src/hicn/core/content_store.c2
-rw-r--r--hicn-light/src/hicn/core/content_store.h4
-rw-r--r--hicn-light/src/hicn/core/fib_entry.c2
-rw-r--r--hicn-light/src/hicn/core/forwarder.c476
-rw-r--r--hicn-light/src/hicn/core/forwarder.h16
-rw-r--r--hicn-light/src/hicn/core/interest_manifest.c64
-rw-r--r--hicn-light/src/hicn/core/interest_manifest.h40
-rw-r--r--hicn-light/src/hicn/core/listener.c14
-rw-r--r--hicn-light/src/hicn/core/listener.h8
-rw-r--r--hicn-light/src/hicn/core/listener_table.c51
-rw-r--r--hicn-light/src/hicn/core/listener_table.h67
-rw-r--r--hicn-light/src/hicn/core/msgbuf_pool.c7
-rw-r--r--hicn-light/src/hicn/core/name.c3
-rw-r--r--hicn-light/src/hicn/core/nameBitvector.c2
-rw-r--r--hicn-light/src/hicn/core/nameBitvector.h8
-rw-r--r--hicn-light/src/hicn/core/packet_cache.c280
-rw-r--r--hicn-light/src/hicn/core/packet_cache.h161
-rw-r--r--hicn-light/src/hicn/core/policy_stats.h1
-rw-r--r--hicn-light/src/hicn/core/subscription.c2
-rw-r--r--hicn-light/src/hicn/io/base.c19
-rw-r--r--hicn-light/src/hicn/io/hicn.c8
-rw-r--r--hicn-light/src/hicn/io/tcp.c8
-rw-r--r--hicn-light/src/hicn/io/udp.c27
-rw-r--r--hicn-light/src/hicn/strategies/probe_generator.c2
-rw-r--r--hicn-light/src/hicn/strategies/probe_generator.h2
-rw-r--r--hicn-light/src/hicn/test/CMakeLists.txt1
-rw-r--r--hicn-light/src/hicn/test/test-bitmap.cc2
-rw-r--r--hicn-light/src/hicn/test/test-connection_table.cc48
-rw-r--r--hicn-light/src/hicn/test/test-hash.cc114
-rw-r--r--hicn-light/src/hicn/test/test-interest_manifest.cc79
-rw-r--r--hicn-light/src/hicn/test/test-khash.cc2
-rw-r--r--hicn-light/src/hicn/test/test-msgbuf_pool.cc2
-rw-r--r--hicn-light/src/hicn/test/test-packet_cache.cc312
-rw-r--r--hicn-light/src/hicn/test/test-pool.cc2
-rw-r--r--hicn-light/src/hicn/test/test-ring.cc2
-rw-r--r--hicn-light/src/hicn/test/test-subscription.cc2
-rw-r--r--hicn-light/src/hicn/test/test-utils.h26
-rw-r--r--hicn-light/src/hicn/test/test-vector.cc190
64 files changed, 1817 insertions, 3052 deletions
diff --git a/hicn-light/CMakeLists.txt b/hicn-light/CMakeLists.txt
index 337e22b7f..241cae7f2 100644
--- a/hicn-light/CMakeLists.txt
+++ b/hicn-light/CMakeLists.txt
@@ -93,6 +93,7 @@ else()
${LIBHICNCTRL_STATIC}
)
else ()
+ message("qui2!!!")
set(HICN_LIBRARIES
${LIBHICN_SHARED}
${LIBHICNCTRL_SHARED}
diff --git a/hicn-light/src/hicn/base/CMakeLists.txt b/hicn-light/src/hicn/base/CMakeLists.txt
index 1180ed05b..2541ed830 100644
--- a/hicn-light/src/hicn/base/CMakeLists.txt
+++ b/hicn-light/src/hicn/base/CMakeLists.txt
@@ -12,21 +12,11 @@
# limitations under the License.
list(APPEND HEADER_FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/bitmap.h
- ${CMAKE_CURRENT_SOURCE_DIR}/common.h
- ${CMAKE_CURRENT_SOURCE_DIR}/hash.h
- ${CMAKE_CURRENT_SOURCE_DIR}/khash.h
${CMAKE_CURRENT_SOURCE_DIR}/loop.h
- ${CMAKE_CURRENT_SOURCE_DIR}/pool.h
- ${CMAKE_CURRENT_SOURCE_DIR}/ring.h
- ${CMAKE_CURRENT_SOURCE_DIR}/vector.h
)
list(APPEND SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/loop.c
- ${CMAKE_CURRENT_SOURCE_DIR}/pool.c
- ${CMAKE_CURRENT_SOURCE_DIR}/ring.c
- ${CMAKE_CURRENT_SOURCE_DIR}/vector.c
)
set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
diff --git a/hicn-light/src/hicn/base/bitmap.h b/hicn-light/src/hicn/base/bitmap.h
deleted file mode 100644
index 060fd5be0..000000000
--- a/hicn-light/src/hicn/base/bitmap.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * \file bitmap.h
- * \brief Bitmap
- *
- * A bitmap is implemented as a wrapper over a vector made of bit elements
- */
-
-#ifndef UTIL_BITMAP_H
-#define UTIL_BITMAP_H
-
-#include <assert.h>
-#include <string.h>
-#include <sys/param.h> // MIN, MAX
-
-#include <hicn/util/log.h>
-
-#include "common.h"
-#include "vector.h"
-
-typedef uint_fast32_t bitmap_t;
-
-#define BITMAP_WIDTH(bitmap) (sizeof((bitmap)[0]) * 8)
-
-/**
- * @brief Allocate and initialize a bitmap
- *
- * @param[in,out] bitmap Bitmap to allocate and initialize
- * @param[in] max_size Bitmap max_size
- */
-#define bitmap_init(bitmap, init_size, max_size) \
- vector_init( \
- bitmap, next_pow2((init_size) / BITMAP_WIDTH(bitmap)), \
- max_size == 0 ? 0 : next_pow2((max_size) / BITMAP_WIDTH(bitmap)))
-
-/*
- * @brief Ensures a bitmap is sufficiently large to hold an element at the
- * given position.
- *
- * @param[in] bitmap The bitmap for which to validate the position.
- * @param[in] pos The position to validate.
- *
- * NOTE:
- * - This function should always be called before writing to a bitmap element
- * to eventually make room for it (the bitmap will eventually be resized).
- */
-static inline int bitmap_ensure_pos(bitmap_t** bitmap, off_t pos) {
- size_t offset = pos / BITMAP_WIDTH(*bitmap);
- return vector_ensure_pos(*bitmap, offset);
-}
-
-/**
- * @brief Returns the allocated size of a bitmap.
- *
- * @see listener_table_get_by_id
- */
-#define bitmap_get_alloc_size(bitmap) vector_get_alloc_size(bitmap)
-
-/**
- * @brief Retrieve the state of the i-th bit in the bitmap.
- *
- * @param[in] bitmap The bitmap to access.
- * @param[in] i The bit position.
- */
-static inline int bitmap_get(const bitmap_t* bitmap, off_t i) {
- size_t offset = i / BITMAP_WIDTH(bitmap);
- assert(offset < bitmap_get_alloc_size(bitmap));
- size_t pos = i % BITMAP_WIDTH(bitmap);
- size_t shift = BITMAP_WIDTH(bitmap) - pos - 1;
- return (bitmap[offset] >> shift) & 1;
-}
-
-/*
- * @brief Returns whether the i-th bit is set (equal to 1) in a bitmap.
- *
- * @param[in] bitmap The bitmap to access.
- * @param[in] i The bit position.
- *
- * @return bool
- */
-#define bitmap_is_set(bitmap, i) (bitmap_get((bitmap), (i)) == 1)
-#define bitmap_is_unset(bitmap, i) (bitmap_get((bitmap), (i)) == 0)
-
-/*
- * @brief Returns whether the i-th bit is unset (equal to 0) in a bitmap.
- *
- * @param[in] bitmap The bitmap to access.
- * @param[in] i The bit position.
- *
- * @return bool
- */
-#define bitmap_set(bitmap, i) _bitmap_set((bitmap_t**)&bitmap, i)
-
-/*
- * @brief Returns whether the i-th bit is unset (equal to 0) in a bitmap
- * (helper).
- *
- * @param[in] bitmap The bitmap to access.
- * @param[in] i The bit position.
- *
- * @return bool
- */
-static inline int _bitmap_set(bitmap_t** bitmap_ptr, off_t i) {
- if (bitmap_ensure_pos(bitmap_ptr, i) < 0) return -1;
-
- bitmap_t* bitmap = *bitmap_ptr;
- size_t offset = i / BITMAP_WIDTH(bitmap);
- size_t pos = i % BITMAP_WIDTH(bitmap);
- size_t shift = BITMAP_WIDTH(bitmap) - pos - 1;
-
- bitmap[offset] |= (bitmap_t)1 << shift;
- return 0;
-}
-
-static inline int bitmap_unset(bitmap_t* bitmap, off_t i) {
- if (bitmap_ensure_pos(&bitmap, i) < 0) return -1;
- size_t offset = i / BITMAP_WIDTH(bitmap);
- size_t pos = i % BITMAP_WIDTH(bitmap);
- size_t shift = BITMAP_WIDTH(bitmap) - pos - 1;
- bitmap[offset] &= ~(1ul << shift);
- return 0;
-}
-
-static inline int bitmap_set_range(bitmap_t* bitmap, off_t from, off_t to) {
- assert(from <= to);
- ssize_t offset_from = from / BITMAP_WIDTH(bitmap);
- ssize_t offset_to = to / BITMAP_WIDTH(bitmap);
- size_t pos_from = from % BITMAP_WIDTH(bitmap);
- size_t pos_to = to % BITMAP_WIDTH(bitmap);
-
- /*
- * First block initialization is needed if <from> is not aligned with the
- * bitmap element size or if to is within the same one.
- */
- if ((pos_from != 0) ||
- ((offset_to == offset_from) && (pos_to != BITMAP_WIDTH(bitmap) - 1))) {
- size_t from_end = MIN(to, (offset_from + 1) * BITMAP_WIDTH(bitmap));
- for (size_t k = from; k < from_end; k++) {
- if (bitmap_set(bitmap, k) < 0) goto END;
- }
- }
-
- /*
- * Second block is needed if <to> is not aligned with the bitmap element
- * size
- */
- if ((pos_to != BITMAP_WIDTH(bitmap) - 1) && (offset_to != offset_from)) {
- size_t to_start = MAX(from, offset_to * BITMAP_WIDTH(bitmap));
- for (size_t k = to_start; k < (size_t)to; k++) {
- if (bitmap_set(bitmap, k) < 0) goto END;
- }
- }
-
- if (pos_from != 0) offset_from += 1;
- if (pos_to != BITMAP_WIDTH(bitmap) - 1) offset_to -= 1;
-
- /*
- * We need to cover both elements at position offset_from and offset_to
- * provided that offset_from is not bigger
- */
- if (offset_to >= offset_from) {
- memset(&bitmap[offset_from], 0xFF,
- (offset_to - offset_from + 1) * sizeof(bitmap[0]));
- }
-
- return 0;
-
-END:
- ERROR("Error setting bitmap range\n");
- return -1;
-}
-
-#define bitmap_set_to(bitmap, to) bitmap_set_range((bitmap), 0, (to))
-
-#define bitmap_free(bitmap) vector_free(bitmap)
-
-#endif /* UTIL_BITMAP_H */
diff --git a/hicn-light/src/hicn/base/common.h b/hicn-light/src/hicn/base/common.h
deleted file mode 100644
index 9f7e3beec..000000000
--- a/hicn-light/src/hicn/base/common.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * \file array.h
- * \brief Fixed-size pool allocator
- */
-
-#ifndef UTIL_COMMON_H
-#define UTIL_COMMON_H
-
-#define round_pow2(x, pow2) ((x + pow2 - 1) & ~(pow2 - 1))
-
-#define _SIZEOF_ALIGNED(x, size) round_pow2(sizeof(x), size)
-#define SIZEOF_ALIGNED(x) _SIZEOF_ALIGNED(x, sizeof(void*))
-
-/* Definitions for builtins unavailable on MSVC */
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <intrin.h>
-
-uint32_t __inline __builtin_ctz(uint32_t value) {
- uint32_t trailing_zero = 0;
- if (_BitScanForward(&trailing_zero, value))
- return trailing_zero;
- else
- return 32;
-}
-
-uint32_t __inline __builtin_clz(uint32_t value) {
- uint32_t leading_zero = 0;
- if (_BitScanReverse(&leading_zero, value))
- return 31 - leading_zero;
- else
- return 32;
-}
-
-uint32_t __inline __builtin_clzl2(uint64_t value) {
- uint32_t leading_zero = 0;
- if (_BitScanReverse64(&leading_zero, value))
- return 63 - leading_zero;
- else
- return 64;
-}
-
-#define __builtin_clzl __builtin_clzll
-#endif
-
-#define next_pow2(x) (x <= 1 ? 1 : 1ul << (64 - __builtin_clzl(x - 1)))
-
-#endif /* UTIL_COMMON_H */
diff --git a/hicn-light/src/hicn/base/hash.h b/hicn-light/src/hicn/base/hash.h
deleted file mode 100644
index 3c54feb29..000000000
--- a/hicn-light/src/hicn/base/hash.h
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * \file hash.h
- * \brief Simple non-cryptographic hash implementation.
- *
- * Two helpers are provided :
- * hash(buf, len) : hash a buffer <buf> of length <len>
- * hash_struct(buf) : hash a buffer corresponding to an allocated struct
- *
- * This file consists in excerpts from Jenkins hash (public domain).
- * http://www.burtleburtle.net/bob/c/lookup3.c
- */
-#ifndef UTIL_HASH_H
-#define UTIL_HASH_H
-
-#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
- __BYTE_ORDER == __LITTLE_ENDIAN) || \
- (defined(i386) || defined(__i386__) || defined(__i486__) || \
- defined(__i586__) || defined(__i686__) || defined(vax) || \
- defined(MIPSEL))
-#define HASH_LITTLE_ENDIAN 1
-#define HASH_BIG_ENDIAN 0
-#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
- __BYTE_ORDER == __BIG_ENDIAN) || \
- (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))
-#define HASH_LITTLE_ENDIAN 0
-#define HASH_BIG_ENDIAN 1
-#else
-#define HASH_LITTLE_ENDIAN 0
-#define HASH_BIG_ENDIAN 0
-#endif
-
-#define hashsize(n) ((uint32_t)1 << (n))
-#define hashmask(n) (hashsize(n) - 1)
-#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
-
-#define mix(a, b, c) \
- { \
- a -= c; \
- a ^= rot(c, 4); \
- c += b; \
- b -= a; \
- b ^= rot(a, 6); \
- a += c; \
- c -= b; \
- c ^= rot(b, 8); \
- b += a; \
- a -= c; \
- a ^= rot(c, 16); \
- c += b; \
- b -= a; \
- b ^= rot(a, 19); \
- a += c; \
- c -= b; \
- c ^= rot(b, 4); \
- b += a; \
- }
-
-#define final(a, b, c) \
- { \
- c ^= b; \
- c -= rot(b, 14); \
- a ^= c; \
- a -= rot(c, 11); \
- b ^= a; \
- b -= rot(a, 25); \
- c ^= b; \
- c -= rot(b, 16); \
- a ^= c; \
- a -= rot(c, 4); \
- b ^= a; \
- b -= rot(a, 14); \
- c ^= b; \
- c -= rot(b, 24); \
- }
-
-static inline uint32_t hashlittle(const void *key, size_t length,
- uint32_t initval) {
- uint32_t a, b, c; /* internal state */
- union {
- const void *ptr;
- size_t i;
- } u; /* needed for Mac Powerbook G4 */
-
- /* Set up the internal state */
- a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
-
- u.ptr = key;
- if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
- const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
-
- /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
- while (length > 12) {
- a += k[0];
- b += k[1];
- c += k[2];
- mix(a, b, c);
- length -= 12;
- k += 3;
- }
-
- /*----------------------------- handle the last (probably partial) block */
- /*
- * "k[2]&0xffffff" actually reads beyond the end of the string, but
- * then masks off the part it's not allowed to read. Because the
- * string is aligned, the masked-off tail is in the same word as the
- * rest of the string. Every machine with memory protection I've seen
- * does it on word boundaries, so is OK with this. But VALGRIND will
- * still catch it and complain. The masking trick does make the hash
- * noticably faster for short strings (like English words).
- */
-#ifndef VALGRIND
-
- switch (length) {
- case 12:
- c += k[2];
- b += k[1];
- a += k[0];
- break;
- case 11:
- c += k[2] & 0xffffff;
- b += k[1];
- a += k[0];
- break;
- case 10:
- c += k[2] & 0xffff;
- b += k[1];
- a += k[0];
- break;
- case 9:
- c += k[2] & 0xff;
- b += k[1];
- a += k[0];
- break;
- case 8:
- b += k[1];
- a += k[0];
- break;
- case 7:
- b += k[1] & 0xffffff;
- a += k[0];
- break;
- case 6:
- b += k[1] & 0xffff;
- a += k[0];
- break;
- case 5:
- b += k[1] & 0xff;
- a += k[0];
- break;
- case 4:
- a += k[0];
- break;
- case 3:
- a += k[0] & 0xffffff;
- break;
- case 2:
- a += k[0] & 0xffff;
- break;
- case 1:
- a += k[0] & 0xff;
- break;
- case 0:
- return c; /* zero length strings require no mixing */
- }
-
-#else /* make valgrind happy */
-
- k8 = (const uint8_t *)k;
- switch (length) {
- case 12:
- c += k[2];
- b += k[1];
- a += k[0];
- break;
- case 11:
- c += ((uint32_t)k8[10]) << 16; /* fall through */
- case 10:
- c += ((uint32_t)k8[9]) << 8; /* fall through */
- case 9:
- c += k8[8]; /* fall through */
- case 8:
- b += k[1];
- a += k[0];
- break;
- case 7:
- b += ((uint32_t)k8[6]) << 16; /* fall through */
- case 6:
- b += ((uint32_t)k8[5]) << 8; /* fall through */
- case 5:
- b += k8[4]; /* fall through */
- case 4:
- a += k[0];
- break;
- case 3:
- a += ((uint32_t)k8[2]) << 16; /* fall through */
- case 2:
- a += ((uint32_t)k8[1]) << 8; /* fall through */
- case 1:
- a += k8[0];
- break;
- case 0:
- return c;
- }
-
-#endif /* !valgrind */
-
- } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
- const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
- const uint8_t *k8;
-
- /*--------------- all but last block: aligned reads and different mixing */
- while (length > 12) {
- a += k[0] + (((uint32_t)k[1]) << 16);
- b += k[2] + (((uint32_t)k[3]) << 16);
- c += k[4] + (((uint32_t)k[5]) << 16);
- mix(a, b, c);
- length -= 12;
- k += 6;
- }
-
- /*----------------------------- handle the last (probably partial) block */
- k8 = (const uint8_t *)k;
- switch (length) {
- case 12:
- c += k[4] + (((uint32_t)k[5]) << 16);
- b += k[2] + (((uint32_t)k[3]) << 16);
- a += k[0] + (((uint32_t)k[1]) << 16);
- break;
- case 11:
- c += ((uint32_t)k8[10]) << 16; /* fall through */
- case 10:
- c += k[4];
- b += k[2] + (((uint32_t)k[3]) << 16);
- a += k[0] + (((uint32_t)k[1]) << 16);
- break;
- case 9:
- c += k8[8]; /* fall through */
- case 8:
- b += k[2] + (((uint32_t)k[3]) << 16);
- a += k[0] + (((uint32_t)k[1]) << 16);
- break;
- case 7:
- b += ((uint32_t)k8[6]) << 16; /* fall through */
- case 6:
- b += k[2];
- a += k[0] + (((uint32_t)k[1]) << 16);
- break;
- case 5:
- b += k8[4]; /* fall through */
- case 4:
- a += k[0] + (((uint32_t)k[1]) << 16);
- break;
- case 3:
- a += ((uint32_t)k8[2]) << 16; /* fall through */
- case 2:
- a += k[0];
- break;
- case 1:
- a += k8[0];
- break;
- case 0:
- return c; /* zero length requires no mixing */
- }
-
- } else { /* need to read the key one byte at a time */
- const uint8_t *k = (const uint8_t *)key;
-
- /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
- while (length > 12) {
- a += k[0];
- a += ((uint32_t)k[1]) << 8;
- a += ((uint32_t)k[2]) << 16;
- a += ((uint32_t)k[3]) << 24;
- b += k[4];
- b += ((uint32_t)k[5]) << 8;
- b += ((uint32_t)k[6]) << 16;
- b += ((uint32_t)k[7]) << 24;
- c += k[8];
- c += ((uint32_t)k[9]) << 8;
- c += ((uint32_t)k[10]) << 16;
- c += ((uint32_t)k[11]) << 24;
- mix(a, b, c);
- length -= 12;
- k += 12;
- }
-
- /*-------------------------------- last block: affect all 32 bits of (c) */
- switch (length) /* all the case statements fall through */
- {
- case 12:
- c += ((uint32_t)k[11]) << 24;
- case 11:
- c += ((uint32_t)k[10]) << 16;
- case 10:
- c += ((uint32_t)k[9]) << 8;
- case 9:
- c += k[8];
- case 8:
- b += ((uint32_t)k[7]) << 24;
- case 7:
- b += ((uint32_t)k[6]) << 16;
- case 6:
- b += ((uint32_t)k[5]) << 8;
- case 5:
- b += k[4];
- case 4:
- a += ((uint32_t)k[3]) << 24;
- case 3:
- a += ((uint32_t)k[2]) << 16;
- case 2:
- a += ((uint32_t)k[1]) << 8;
- case 1:
- a += k[0];
- break;
- case 0:
- return c;
- }
- }
-
- final(a, b, c);
- return c;
-}
-
-/* Helpers */
-
-#define HASH_INITVAL 1
-//#define hash(buf, len) (hash_t)hashlittle(buf, len, HASH_INITVAL)
-#define hash(buf, len) hashlittle(buf, len, HASH_INITVAL)
-#define hash_struct(buf) hash(buf, sizeof(*buf))
-
-#define str_hash(str) (hash(str, strlen(str)))
-#define str_hash_eq(a, b) (str_hash(b) - str_hash(a))
-
-#endif /* UTIL_JENKINS_HASH_H */
diff --git a/hicn-light/src/hicn/base/khash.h b/hicn-light/src/hicn/base/khash.h
deleted file mode 100644
index 4c62b0260..000000000
--- a/hicn-light/src/hicn/base/khash.h
+++ /dev/null
@@ -1,748 +0,0 @@
-/* The MIT License
-
- Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk>
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-*/
-
-/*
- An example:
-
-#include "khash.h"
-KHASH_MAP_INIT_INT(32, char)
-int main() {
- int ret, is_missing;
- khiter_t k;
- khash_t(32) *h = kh_init(32);
- k = kh_put(32, h, 5, &ret);
- kh_value(h, k) = 10;
- k = kh_get(32, h, 10);
- is_missing = (k == kh_end(h));
- k = kh_get(32, h, 5);
- kh_del(32, h, k);
- for (k = kh_begin(h); k != kh_end(h); ++k)
- if (kh_exist(h, k)) kh_value(h, k) = 1;
- kh_destroy(32, h);
- return 0;
-}
-*/
-
-/*
- 2013-05-02 (0.2.8):
-
- * Use quadratic probing. When the capacity is power of 2, stepping
- function i*(i+1)/2 guarantees to traverse each bucket. It is better than
- double hashing on cache performance and is more robust than linear probing.
-
- In theory, double hashing should be more robust than quadratic
- probing. However, my implementation is probably not for large hash tables,
- because the second hash function is closely tied to the first hash function,
- which reduce the effectiveness of double hashing.
-
- Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php
-
- 2011-12-29 (0.2.7):
-
- * Minor code clean up; no actual effect.
-
- 2011-09-16 (0.2.6):
-
- * The capacity is a power of 2. This seems to dramatically improve the
- speed for simple keys. Thank Zilong Tan for the suggestion. Reference:
-
- - http://code.google.com/p/ulib/
- - http://nothings.org/computer/judy/
-
- * Allow to optionally use linear probing which usually has better
- performance for random input. Double hashing is still the default as
- it is more robust to certain non-random input.
-
- * Added Wang's integer hash function (not used by default). This hash
- function is more robust to certain non-random input.
-
- 2011-02-14 (0.2.5):
-
- * Allow to declare global functions.
-
- 2009-09-26 (0.2.4):
-
- * Improve portability
-
- 2008-09-19 (0.2.3):
-
- * Corrected the example
- * Improved interfaces
-
- 2008-09-11 (0.2.2):
-
- * Improved speed a little in kh_put()
-
- 2008-09-10 (0.2.1):
-
- * Added kh_clear()
- * Fixed a compiling error
-
- 2008-09-02 (0.2.0):
-
- * Changed to token concatenation which increases flexibility.
-
- 2008-08-31 (0.1.2):
-
- * Fixed a bug in kh_get(), which has not been tested previously.
-
- 2008-08-31 (0.1.1):
-
- * Added destructor
-*/
-
-#ifndef __AC_KHASH_H
-#define __AC_KHASH_H
-
-/*!
- @header
-
- Generic hash table library.
- */
-
-#define AC_VERSION_KHASH_H "0.2.8"
-
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-
-/* compiler specific configuration */
-
-#if UINT_MAX == 0xffffffffu
-typedef unsigned int khint32_t;
-#elif ULONG_MAX == 0xffffffffu
-typedef unsigned long khint32_t;
-#endif
-
-#if ULONG_MAX == ULLONG_MAX
-typedef unsigned long khint64_t;
-#else
-typedef unsigned long long khint64_t;
-#endif
-
-#ifndef kh_inline
-#ifdef _MSC_VER
-#define kh_inline __inline
-#else
-#define kh_inline inline
-#endif
-#endif /* kh_inline */
-
-#ifndef klib_unused
-#if (defined __clang__ && __clang_major__ >= 3) || \
- (defined __GNUC__ && __GNUC__ >= 3)
-#define klib_unused __attribute__((__unused__))
-#else
-#define klib_unused
-#endif
-#endif /* klib_unused */
-
-typedef khint32_t khint_t;
-typedef khint_t khiter_t;
-
-#define __ac_isempty(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 2)
-#define __ac_isdel(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 1)
-#define __ac_iseither(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 3)
-#define __ac_set_isdel_false(flag, i) \
- (flag[i >> 4] &= ~(1ul << ((i & 0xfU) << 1)))
-#define __ac_set_isempty_false(flag, i) \
- (flag[i >> 4] &= ~(2ul << ((i & 0xfU) << 1)))
-#define __ac_set_isboth_false(flag, i) \
- (flag[i >> 4] &= ~(3ul << ((i & 0xfU) << 1)))
-#define __ac_set_isdel_true(flag, i) (flag[i >> 4] |= 1ul << ((i & 0xfU) << 1))
-
-#define __ac_fsize(m) ((m) < 16 ? 1 : (m) >> 4)
-
-#ifndef kroundup32
-#define kroundup32(x) \
- (--(x), (x) |= (x) >> 1, (x) |= (x) >> 2, (x) |= (x) >> 4, (x) |= (x) >> 8, \
- (x) |= (x) >> 16, ++(x))
-#endif
-
-#ifndef kcalloc
-#define kcalloc(N, Z) calloc(N, Z)
-#endif
-#ifndef kmalloc
-#define kmalloc(Z) malloc(Z)
-#endif
-#ifndef krealloc
-#define krealloc(P, Z) realloc(P, Z)
-#endif
-#ifndef kfree
-#define kfree(P) free(P)
-#endif
-
-static const double __ac_HASH_UPPER = 0.77;
-
-#define __KHASH_TYPE(name, khkey_t, khval_t) \
- typedef struct kh_##name##_s { \
- khint_t n_buckets, size, n_occupied, upper_bound; \
- khint32_t *flags; \
- khkey_t *keys; \
- khval_t *vals; \
- } kh_##name##_t;
-
-#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
- extern kh_##name##_t *kh_init_##name(void); \
- extern void kh_destroy_##name(kh_##name##_t *h); \
- extern void kh_clear_##name(kh_##name##_t *h); \
- extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
- extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
- extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
- extern void kh_del_##name(kh_##name##_t *h, khint_t x);
-
-#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, \
- __hash_equal) \
- SCOPE kh_##name##_t *kh_init_##name(void) { \
- return (kh_##name##_t *)kcalloc(1, sizeof(kh_##name##_t)); \
- } \
- SCOPE void kh_destroy_##name(kh_##name##_t *h) { \
- if (h) { \
- kfree((void *)h->keys); \
- kfree(h->flags); \
- kfree((void *)h->vals); \
- kfree(h); \
- } \
- } \
- SCOPE void kh_clear_##name(kh_##name##_t *h) { \
- if (h && h->flags) { \
- memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
- h->size = h->n_occupied = 0; \
- } \
- } \
- SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) { \
- if (h->n_buckets) { \
- khint_t k, i, last, mask, step = 0; \
- mask = h->n_buckets - 1; \
- k = __hash_func(key); \
- i = k & mask; \
- last = i; \
- while (!__ac_isempty(h->flags, i) && \
- (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
- i = (i + (++step)) & mask; \
- if (i == last) return h->n_buckets; \
- } \
- return __ac_iseither(h->flags, i) ? h->n_buckets : i; \
- } else \
- return 0; \
- } \
- SCOPE int kh_resize_##name( \
- kh_##name##_t *h, \
- khint_t new_n_buckets) { /* This function uses 0.25*n_buckets bytes of \
- working space instead of \
- [sizeof(key_t+val_t)+.25]*n_buckets. */ \
- khint32_t *new_flags = 0; \
- khint_t j = 1; \
- { \
- kroundup32(new_n_buckets); \
- if (new_n_buckets < 4) new_n_buckets = 4; \
- if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) \
- j = 0; /* requested size is too small */ \
- else { /* hash table size to be changed (shrink or expand); rehash */ \
- new_flags = (khint32_t *)kmalloc(__ac_fsize(new_n_buckets) * \
- sizeof(khint32_t)); \
- if (!new_flags) return -1; \
- memset(new_flags, 0xaa, \
- __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
- if (h->n_buckets < new_n_buckets) { /* expand */ \
- khkey_t *new_keys = (khkey_t *)krealloc( \
- (void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
- if (!new_keys) { \
- kfree(new_flags); \
- return -1; \
- } \
- h->keys = new_keys; \
- if (kh_is_map) { \
- khval_t *new_vals = (khval_t *)krealloc( \
- (void *)h->vals, new_n_buckets * sizeof(khval_t)); \
- if (!new_vals) { \
- kfree(new_flags); \
- return -1; \
- } \
- h->vals = new_vals; \
- } \
- } /* otherwise shrink */ \
- } \
- } \
- if (j) { /* rehashing is needed */ \
- for (j = 0; j != h->n_buckets; ++j) { \
- if (__ac_iseither(h->flags, j) == 0) { \
- khkey_t key = h->keys[j]; \
- khval_t val; \
- khint_t new_mask; \
- new_mask = new_n_buckets - 1; \
- if (kh_is_map) val = h->vals[j]; \
- __ac_set_isdel_true(h->flags, j); \
- while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
- khint_t k, i, step = 0; \
- k = __hash_func(key); \
- i = k & new_mask; \
- while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
- __ac_set_isempty_false(new_flags, i); \
- if (i < h->n_buckets && \
- __ac_iseither(h->flags, i) == \
- 0) { /* kick out the existing element */ \
- { \
- khkey_t tmp = h->keys[i]; \
- h->keys[i] = key; \
- key = tmp; \
- } \
- if (kh_is_map) { \
- khval_t tmp = h->vals[i]; \
- h->vals[i] = val; \
- val = tmp; \
- } \
- __ac_set_isdel_true( \
- h->flags, i); /* mark it as deleted in the old hash table */ \
- } else { /* write the element and jump out of the loop */ \
- h->keys[i] = key; \
- if (kh_is_map) h->vals[i] = val; \
- break; \
- } \
- } \
- } \
- } \
- if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
- h->keys = (khkey_t *)krealloc((void *)h->keys, \
- new_n_buckets * sizeof(khkey_t)); \
- if (kh_is_map) \
- h->vals = (khval_t *)krealloc((void *)h->vals, \
- new_n_buckets * sizeof(khval_t)); \
- } \
- kfree(h->flags); /* free the working space */ \
- h->flags = new_flags; \
- h->n_buckets = new_n_buckets; \
- h->n_occupied = h->size; \
- h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
- } \
- return 0; \
- } \
- SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) { \
- khint_t x; \
- if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
- if (h->n_buckets > (h->size << 1)) { \
- if (kh_resize_##name(h, h->n_buckets - 1) < \
- 0) { /* clear "deleted" elements */ \
- *ret = -1; \
- return h->n_buckets; \
- } \
- } else if (kh_resize_##name(h, h->n_buckets + 1) < \
- 0) { /* expand the hash table */ \
- *ret = -1; \
- return h->n_buckets; \
- } \
- } /* TODO: to implement automatically shrinking; resize() already support \
- shrinking */ \
- { \
- khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
- x = site = h->n_buckets; \
- k = __hash_func(key); \
- i = k & mask; \
- if (__ac_isempty(h->flags, i)) \
- x = i; /* for speed up */ \
- else { \
- last = i; \
- while (!__ac_isempty(h->flags, i) && \
- (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
- if (__ac_isdel(h->flags, i)) site = i; \
- i = (i + (++step)) & mask; \
- if (i == last) { \
- x = site; \
- break; \
- } \
- } \
- if (x == h->n_buckets) { \
- if (__ac_isempty(h->flags, i) && site != h->n_buckets) \
- x = site; \
- else \
- x = i; \
- } \
- } \
- } \
- if (__ac_isempty(h->flags, x)) { /* not present at all */ \
- h->keys[x] = key; \
- __ac_set_isboth_false(h->flags, x); \
- ++h->size; \
- ++h->n_occupied; \
- *ret = 1; \
- } else if (__ac_isdel(h->flags, x)) { /* deleted */ \
- h->keys[x] = key; \
- __ac_set_isboth_false(h->flags, x); \
- ++h->size; \
- *ret = 2; \
- } else \
- *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
- return x; \
- } \
- SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) { \
- if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
- __ac_set_isdel_true(h->flags, x); \
- --h->size; \
- } \
- }
-
-#define KHASH_DECLARE(name, khkey_t, khval_t) \
- __KHASH_TYPE(name, khkey_t, khval_t) \
- __KHASH_PROTOTYPES(name, khkey_t, khval_t)
-
-#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, \
- __hash_equal) \
- __KHASH_TYPE(name, khkey_t, khval_t) \
- __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, \
- __hash_equal)
-
-#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, \
- __hash_equal) \
- KHASH_INIT2(name, static kh_inline klib_unused, khkey_t, khval_t, kh_is_map, \
- __hash_func, __hash_equal)
-
-/* --- BEGIN OF HASH FUNCTIONS --- */
-
-/*! @function
- @abstract Integer hash function
- @param key The integer [khint32_t]
- @return The hash value [khint_t]
- */
-#define kh_int_hash_func(key) (khint32_t)(key)
-/*! @function
- @abstract Integer comparison function
- */
-#define kh_int_hash_equal(a, b) ((a) == (b))
-/*! @function
- @abstract 64-bit integer hash function
- @param key The integer [khint64_t]
- @return The hash value [khint_t]
- */
-#define kh_int64_hash_func(key) (khint32_t)((key) >> 33 ^ (key) ^ (key) << 11)
-/*! @function
- @abstract 64-bit integer comparison function
- */
-#define kh_int64_hash_equal(a, b) ((a) == (b))
-/*! @function
- @abstract const char* hash function
- @param s Pointer to a null terminated string
- @return The hash value
- */
-static kh_inline khint_t __ac_X31_hash_string(const char *s) {
- khint_t h = (khint_t)*s;
- if (h)
- for (++s; *s; ++s) h = (h << 5) - h + (khint_t)*s;
- return h;
-}
-/*! @function
- @abstract Another interface to const char* hash function
- @param key Pointer to a null terminated string [const char*]
- @return The hash value [khint_t]
- */
-#define kh_str_hash_func(key) __ac_X31_hash_string(key)
-/*! @function
- @abstract Const char* comparison function
- */
-#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)
-
-static kh_inline khint_t __ac_Wang_hash(khint_t key) {
- key += ~(key << 15);
- key ^= (key >> 10);
- key += (key << 3);
- key ^= (key >> 6);
- key += ~(key << 11);
- key ^= (key >> 16);
- return key;
-}
-#define kh_int_hash_func2(key) __ac_Wang_hash((khint_t)key)
-
-/* --- END OF HASH FUNCTIONS --- */
-
-/* Other convenient macros... */
-
-/*!
- @abstract Type of the hash table.
- @param name Name of the hash table [symbol]
- */
-#define khash_t(name) kh_##name##_t
-
-/*! @function
- @abstract Initiate a hash table.
- @param name Name of the hash table [symbol]
- @return Pointer to the hash table [khash_t(name)*]
- */
-#define kh_init(name) kh_init_##name()
-
-/*! @function
- @abstract Destroy a hash table.
- @param name Name of the hash table [symbol]
- @param h Pointer to the hash table [khash_t(name)*]
- */
-#define kh_destroy(name, h) kh_destroy_##name(h)
-
-/*! @function
- @abstract Reset a hash table without deallocating memory.
- @param name Name of the hash table [symbol]
- @param h Pointer to the hash table [khash_t(name)*]
- */
-#define kh_clear(name, h) kh_clear_##name(h)
-
-/*! @function
- @abstract Resize a hash table.
- @param name Name of the hash table [symbol]
- @param h Pointer to the hash table [khash_t(name)*]
- @param s New size [khint_t]
- */
-#define kh_resize(name, h, s) kh_resize_##name(h, s)
-
-/*! @function
- @abstract Insert a key to the hash table.
- @param name Name of the hash table [symbol]
- @param h Pointer to the hash table [khash_t(name)*]
- @param k Key [type of keys]
- @param r Extra return code: -1 if the operation failed;
- 0 if the key is present in the hash table;
- 1 if the bucket is empty (never used); 2 if the element in
- the bucket has been deleted [int*]
- @return Iterator to the inserted element [khint_t]
- */
-#define kh_put(name, h, k, r) kh_put_##name(h, k, r)
-
-/*! @function
- @abstract Retrieve a key from the hash table.
- @param name Name of the hash table [symbol]
- @param h Pointer to the hash table [khash_t(name)*]
- @param k Key [type of keys]
- @return Iterator to the found element, or kh_end(h) if the element is
- absent [khint_t]
- */
-#define kh_get(name, h, k) kh_get_##name(h, k)
-
-/*! @function
- @abstract Remove a key from the hash table.
- @param name Name of the hash table [symbol]
- @param h Pointer to the hash table [khash_t(name)*]
- @param k Iterator to the element to be deleted [khint_t]
- */
-#define kh_del(name, h, k) kh_del_##name(h, k)
-
-/*! @function
- @abstract Test whether a bucket contains data.
- @param h Pointer to the hash table [khash_t(name)*]
- @param x Iterator to the bucket [khint_t]
- @return 1 if containing data; 0 otherwise [int]
- */
-#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
-
-/*! @function
- @abstract Get key given an iterator
- @param h Pointer to the hash table [khash_t(name)*]
- @param x Iterator to the bucket [khint_t]
- @return Key [type of keys]
- */
-#define kh_key(h, x) ((h)->keys[x])
-
-/*! @function
- @abstract Get value given an iterator
- @param h Pointer to the hash table [khash_t(name)*]
- @param x Iterator to the bucket [khint_t]
- @return Value [type of values]
- @discussion For hash sets, calling this results in segfault.
- */
-#define kh_val(h, x) ((h)->vals[x])
-
-/*! @function
- @abstract Alias of kh_val()
- */
-#define kh_value(h, x) ((h)->vals[x])
-
-/*! @function
- @abstract Get the start iterator
- @param h Pointer to the hash table [khash_t(name)*]
- @return The start iterator [khint_t]
- */
-#define kh_begin(h) (khint_t)(0)
-
-/*! @function
- @abstract Get the end iterator
- @param h Pointer to the hash table [khash_t(name)*]
- @return The end iterator [khint_t]
- */
-#define kh_end(h) ((h)->n_buckets)
-
-/*! @function
- @abstract Get the number of elements in the hash table
- @param h Pointer to the hash table [khash_t(name)*]
- @return Number of elements in the hash table [khint_t]
- */
-#define kh_size(h) ((h)->size)
-
-/*! @function
- @abstract Get the number of buckets in the hash table
- @param h Pointer to the hash table [khash_t(name)*]
- @return Number of buckets in the hash table [khint_t]
- */
-#define kh_n_buckets(h) ((h)->n_buckets)
-
-/*! @function
- @abstract Iterate over the entries in the hash table
- @param h Pointer to the hash table [khash_t(name)*]
- @param kvar Variable to which key will be assigned
- @param vvar Variable to which value will be assigned
- @param code Block of code to execute
- */
-#define kh_foreach(h, kvar, vvar, code) \
- { \
- khint_t __i; \
- for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
- if (!kh_exist(h, __i)) continue; \
- (kvar) = kh_key(h, __i); \
- (vvar) = kh_val(h, __i); \
- code; \
- } \
- }
-
-/*! @function
- @abstract Iterate over the values in the hash table
- @param h Pointer to the hash table [khash_t(name)*]
- @param vvar Variable to which value will be assigned
- @param code Block of code to execute
- */
-#define kh_foreach_value(h, vvar, code) \
- { \
- khint_t __i; \
- for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
- if (!kh_exist(h, __i)) continue; \
- (vvar) = kh_val(h, __i); \
- code; \
- } \
- }
-
-/* More convenient interfaces */
-
-/*! @function
- @abstract Instantiate a hash set containing integer keys
- @param name Name of the hash table [symbol]
- */
-#define KHASH_SET_INIT_INT(name) \
- KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
-
-/*! @function
- @abstract Instantiate a hash map containing integer keys
- @param name Name of the hash table [symbol]
- @param khval_t Type of values [type]
- */
-#define KHASH_MAP_INIT_INT(name, khval_t) \
- KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
-
-/*! @function
- @abstract Instantiate a hash set containing 64-bit integer keys
- @param name Name of the hash table [symbol]
- */
-#define KHASH_SET_INIT_INT64(name) \
- KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
-
-/*! @function
- @abstract Instantiate a hash map containing 64-bit integer keys
- @param name Name of the hash table [symbol]
- @param khval_t Type of values [type]
- */
-#define KHASH_MAP_INIT_INT64(name, khval_t) \
- KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, \
- kh_int64_hash_equal)
-
-typedef const char *kh_cstr_t;
-/*! @function
- @abstract Instantiate a hash map containing const char* keys
- @param name Name of the hash table [symbol]
- */
-#define KHASH_SET_INIT_STR(name) \
- KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
-
-/*! @function
- @abstract Instantiate a hash map containing const char* keys
- @param name Name of the hash table [symbol]
- @param khval_t Type of values [type]
- */
-#define KHASH_MAP_INIT_STR(name, khval_t) \
- KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
-
-/******************************************************************************
- * Custom
- *high-level interface
- ******************************************************************************/
-
-#define _kh_var(x) _kh_var_##x
-
-/**
- * @brief Return the value corresponding to a key in the hashtable.
- * @return The value associated with the key or null if not found
- */
-#define kh_get_val(kname, hashtable, key, default_val) \
- ({ \
- khiter_t _kh_var(k) = kh_get(kname, hashtable, key); \
- (_kh_var(k) != kh_end(hashtable) ? kh_val(hashtable, _kh_var(k)) \
- : default_val); \
- })
-
-/**
- * @brief Add key/value pair in the hashtable.
- * @return 0 if an existing value (corresponding to the provided key)
- * has been replaced; 1 if a new key/value pair has been added
- * (the key was not already present in the hash table);
- * 2 if a new key/value pair has been added in correspondence
- * of a key previously deleted key
- */
-#define kh_put_val(kname, hashtable, key, val) \
- ({ \
- int _kh_var(ret); \
- khiter_t _kh_var(k) = kh_put(kname, hashtable, key, &_kh_var(ret)); \
- kh_value(hashtable, _kh_var(k)) = val; \
- _kh_var(ret); \
- })
-
-/**
- * @brief Remove a key/value pair from the hashtable.
- * @return void
- */
-#define kh_remove_val(kname, hashtable, key) \
- ({ \
- khiter_t _kh_var(k) = kh_get(kname, hashtable, key); \
- if (_kh_var(k) != kh_end(hashtable)) { \
- free((void *)kh_key(hashtable, _kh_var(k))); \
- kh_del(kname, hashtable, _kh_var(k)); \
- } \
- })
-
-/**
- * @brief Free the hashtable.
- * @return void
- */
-#define kh_free(kname, hashtable) \
- ({ \
- const void *_kh_var(key); \
- unsigned _kh_var(val); \
- (void)_kh_var(val); \
- \
- kh_foreach(hashtable, _kh_var(key), _kh_var(val), \
- { free((void *)_kh_var(key)); }) kh_destroy(kname, hashtable); \
- })
-
-#endif /* __AC_KHASH_H */
diff --git a/hicn-light/src/hicn/base/pool.c b/hicn-light/src/hicn/base/pool.c
deleted file mode 100644
index e5fb7d6ac..000000000
--- a/hicn-light/src/hicn/base/pool.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * \file pool.c
- * \brief Implementation of fixed-size pool allocator.
- *
- * NOTE:
- * - Ideally, we should have a single realloc per resize, that would encompass
- * both the free indices vector and bitmap, by nesting data structures. Because
- * of the added complexity, and by lack of evidence of the need for this, we
- * currently rely on a simpler implementation.
- */
-
-#include <assert.h>
-#include <stdlib.h> // calloc
-
-#include "common.h"
-#include "pool.h"
-
-#include <stdio.h> // XXX
-
-void _pool_init(void** pool_ptr, size_t elt_size, size_t init_size,
- size_t max_size) {
- assert(pool_ptr);
- assert(elt_size);
-
- init_size = next_pow2(init_size);
-
- if (max_size && init_size > max_size) goto ERR_MAX_SIZE;
-
- /* The initial pool size is rounded to the next power of two */
- size_t alloc_size = next_pow2(init_size);
-
- pool_hdr_t* ph = calloc(POOL_HDRLEN + alloc_size * elt_size, 1);
- if (!ph) goto ERR_MALLOC;
-
- ph->elt_size = elt_size;
- ph->alloc_size = alloc_size;
- ph->max_size = max_size;
-
- /* Free indices */
- off_t* free_indices;
- vector_init(free_indices, init_size, max_size);
- for (unsigned i = 0; i < init_size; i++)
- free_indices[i] = (init_size - 1) - i;
- vector_len(free_indices) = init_size;
- ph->free_indices = free_indices;
-
- /* Free bitmap */
- bitmap_t* fb = ph->free_bitmap;
- bitmap_init(fb, init_size, max_size);
- bitmap_set_to(fb, init_size);
- ph->free_bitmap = fb;
-
- *pool_ptr = (uint8_t*)ph + POOL_HDRLEN;
-
- return;
-
-ERR_MALLOC:
-ERR_MAX_SIZE:
- *pool_ptr = NULL;
- return;
-}
-
-void _pool_free(void** pool_ptr) {
- pool_hdr_t* ph = pool_hdr(*pool_ptr);
- vector_free(ph->free_indices);
- bitmap_free(ph->free_bitmap);
-
- free(pool_hdr(*pool_ptr));
- *pool_ptr = NULL;
-}
-
-bool _pool_validate_id(void** pool_ptr, off_t id) {
- pool_hdr_t* ph = pool_hdr(*pool_ptr);
- size_t pool_size = pool_get_alloc_size(*pool_ptr);
- if (id >= pool_size || !bitmap_is_unset(ph->free_bitmap, id)) return false;
-
- return true;
-}
-
-void _pool_resize(void** pool_ptr, size_t elt_size) {
- pool_hdr_t* ph = pool_hdr(*pool_ptr);
- size_t old_size = ph->alloc_size;
- size_t new_size = old_size * 2;
-
- TRACE("pool_resize to %lu", new_size);
-
- if (ph->max_size && new_size > ph->max_size) goto ERR_MAX_SIZE;
-
- /* Double pool storage */
- ph = realloc(ph, POOL_HDRLEN + new_size * elt_size);
- if (!ph) goto ERR_REALLOC;
- ph->elt_size = elt_size;
- ph->alloc_size = new_size;
-
- /*
- * After resize, the pool will have new free indices, ranging from
- * old_size to (new_size - 1)
- */
- vector_ensure_pos(ph->free_indices, old_size);
- for (unsigned i = 0; i < old_size; i++)
- ph->free_indices[i] = new_size - 1 - i;
- vector_len(ph->free_indices) = old_size;
-
- /* We also need to update the bitmap */
- bitmap_ensure_pos(&(ph->free_bitmap), new_size - 1);
- bitmap_set_range(ph->free_bitmap, old_size, new_size - 1);
-
- /* Reassign pool pointer */
- *pool_ptr = (uint8_t*)ph + POOL_HDRLEN;
-
- return;
-
-ERR_REALLOC:
-ERR_MAX_SIZE:
- *pool_ptr = NULL;
- return;
-}
-
-off_t _pool_get(void** pool_ptr, void** elt, size_t elt_size) {
- pool_hdr_t* ph = pool_hdr(*pool_ptr);
- uint64_t l = vector_len(ph->free_indices);
- if (l == 0) {
- _pool_resize(pool_ptr, elt_size);
- ph = pool_hdr(*pool_ptr);
- l = vector_len(ph->free_indices);
- }
- off_t free_id = ph->free_indices[l - 1];
- vector_len(ph->free_indices)--;
- bitmap_unset(ph->free_bitmap, free_id);
- *elt = *pool_ptr + free_id * elt_size;
- memset(*elt, 0, elt_size);
- return free_id;
-}
-
-void _pool_put(void** pool_ptr, void** elt, size_t elt_size) {
- pool_hdr_t* ph = pool_hdr(*pool_ptr);
- uint64_t l = vector_len(ph->free_indices);
- vector_ensure_pos(ph->free_indices, l);
- off_t freed_id = (*elt - *pool_ptr) / elt_size;
- ph->free_indices[l] = freed_id;
- vector_len(ph->free_indices)++;
- bitmap_set(ph->free_bitmap, freed_id);
-}
diff --git a/hicn-light/src/hicn/base/pool.h b/hicn-light/src/hicn/base/pool.h
deleted file mode 100644
index b6573195c..000000000
--- a/hicn-light/src/hicn/base/pool.h
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * \file pool.h
- * \brief Fixed-size pool allocator.
- *
- * This memory pool allocates a single block of memory that is used to
- * efficiently allocate/deallocate fixed-size blocks for high churn data
- * structures.
- *
- * Internally this data structure leverages a vector for managing elements (and
- * it thus resizeable if needed), as well as a list of free indices (in the
- * form of another vector) and a bitmap marking free indices also (for fast
- * iteration).
- *
- * The internal API manipulates a pointer to the vector that that is can be
- * seamlessly resized, and a more convenient user interface is provided through
- * macros.
- *
- * The vector of free indices is managed as a stack where elements indices are
- * retrieved from and put back to the end of the vector. In the bitmap,
- * available elements are set to 1, and unset to 0 when in use.
- *
- * The pool is not currently resized down when releasing elements.
- *
- * It is freely inspired (and simplified) from the VPP infra infrastructure
- * library.
- */
-
-#ifndef UTIL_POOL_H
-#define UTIL_POOL_H
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#include "bitmap.h"
-#include "vector.h"
-
-/* Pool header */
-
-typedef struct {
- size_t elt_size;
- size_t alloc_size;
- size_t max_size;
- bitmap_t *free_bitmap; /* bitmap of free indices */
- off_t *free_indices; /* vector of free indices */
-} pool_hdr_t;
-
-#define POOL_HDRLEN SIZEOF_ALIGNED(pool_hdr_t)
-
-/* This header actually prepends the actual content of the pool. */
-#define pool_hdr(pool) ((pool_hdr_t *)((uint8_t *)(pool)-POOL_HDRLEN))
-
-/******************************************************************************/
-/* Helpers */
-
-/** Local variable naming macro. */
-#define _pool_var(v) _pool_##v
-
-/**
- * @brief Allocate and initialize a pool data structure (helper).
- *
- * @param[in,out] pool_ptr Pointer to the pool data structure.
- * @param[in] elt_size Size of elements in vector.
- * @param[in] max_size Maximum size.
- *
- * NOTE: that an empty pool might be equal to NULL.
- */
-void _pool_init(void **pool_ptr, size_t elt_size, size_t init_size,
- size_t max_size);
-
-/**
- * @brief Free a pool data structure (helper).
- *
- * @param[in] pool_ptr Pointer to the pool data structure.
- */
-void _pool_free(void **pool_ptr);
-
-/**
- * @brief Resize a pool data structure (helper).
- *
- * @param pool_ptr Pointer to the pool data structure.
- *
- * This function should only be called internally, as the resize is implicitly
- * done (if allowed by the maximum size) when the user tries to get a new slot.
- */
-void _pool_resize(void **pool_ptr, size_t elt_size);
-
-/**
- * @brief Get a free element from the pool data structure (helper).
- *
- * @param[in] pool Pointer to the pool data structure to use.
- * @param[in,out] elt Pointer to an empty element that will be used to return
- * the allocated one from the pool.
- *
- * NOTES:
- * - The memory chunk is cleared upon attribution
- */
-off_t _pool_get(void **pool, void **elt, size_t elt_size);
-
-/**
- * @brief Put an element back into the pool data structure (helper).
- *
- * @param[in] pool_ptr Pointer to the pool data structure to use.
- * @param[in] elt Pointer to the pool element to put back.
- */
-void _pool_put(void **pool, void **elt, size_t elt_size);
-
-/**
- * @brief Validate a pool element by index (helper).
- *
- * @param[in] pool The pool data structure to use.
- * @param[in] id The index of the element to validate.
- *
- * @return bool A flag indicating whether the index is valid or not.
- */
-bool _pool_validate_id(void **pool_ptr, off_t id);
-/******************************************************************************/
-/* Public API */
-
-/**
- * @brief Allocate and initialize a pool data structure.
- *
- * @param[in,out] pool Pointer to the pool data structure.
- * @param[in] elt_size Size of elements in pool.
- * @param[in] max_size Maximum size.
- *
- * NOTE: that an empty pool might be equal to NULL.
- */
-#define pool_init(pool, init_size, max_size) \
- _pool_init((void **)&pool, sizeof(pool[0]), init_size, max_size);
-
-/**
- * @brief Free a pool data structure.
- *
- * @param[in] pool The pool data structure to free.
- */
-#define pool_free(pool) _pool_free((void **)&pool);
-
-/**
- * @brief Get a free element from the pool data structure.
- *
- * @param[in] pool The pool data structure to use.
- * @param[in,out] elt An empty element that will be used to return the
- * allocated one from the pool.
- *
- * NOTES:
- * - The memory chunk is cleared upon attribution
- */
-#define pool_get(pool, elt) \
- _pool_get((void **)&pool, (void **)&elt, sizeof(*elt))
-
-/**
- * @brief Put an element back into the pool data structure.
- *
- * @param[in] pool The pool data structure to use.
- * @param[in] elt The pool element to put back.
- */
-#define pool_put(pool, elt) \
- _pool_put((void **)&pool, (void **)&elt, sizeof(*elt))
-
-/**
- * @brief Validate a pool element by index.
- *
- * @param[in] pool The pool data structure to use.
- * @param[in] id The index of the element to validate.
- *
- * @return bool A flag indicating whether the index is valid or not.
- */
-#define pool_validate_id(pool, id) _pool_validate_id((void **)&pool, (id))
-
-#define pool_get_free_indices_size(pool) \
- vector_len(pool_hdr(pool)->free_indices)
-
-/**
- * @brief Returns the current length of the pool.
- *
- * @param[in] pool The pool data structure for which to return the length.
- *
- * @return size_t The current length of the pool.
- *
- * NOTE:
- * - The pool length corresponds to the number of allocated elements, not the
- * size of the pool.
- */
-#define pool_len(pool) \
- (pool_hdr(pool)->alloc_size - pool_get_free_indices_size(pool))
-
-/**
- * @brief Enumerate elements from a pool.
- *
- * @param[in] pool The pool data structure to enumerate.
- * @param[in, out] i An integer that will be used for enumeration.
- * @param[in, out] eltp A pointer to the element type that will be used for
- * enumeration.
- * @param[in] BODY Block to execute during enumeration.
- *
- * Enumeration will iteratively execute BODY with (i, eltp) corresponding
- * respectively to the index and element found in the pool.
- *
- * NOTE: i stars at 0.
- */
-#define pool_enumerate(pool, i, eltp, BODY) \
- do { \
- pool_hdr_t *_pool_var(ph) = pool_hdr(pool); \
- bitmap_t *_pool_var(fb) = _pool_var(ph)->free_bitmap; \
- for ((i) = 0; (i) < _pool_var(ph)->alloc_size; (i)++) { \
- if (bitmap_is_set(_pool_var(fb), (i))) continue; \
- eltp = (pool) + (i); \
- do { \
- BODY; \
- } while (0); \
- } \
- } while (0)
-
-/**
- * @brief Iterate over elements in a pool.
- *
- * @param[in] pool The pool data structure to iterate over.
- * @param[in,out] eltp A pointer to the element type that will be used for
- * iteration.
- * @param[in] BODY Block to execute during iteration.
- *
- * Iteration will execute BODY with eltp corresponding successively to all
- * elements found in the pool. It is implemented using the more generic
- * enumeration function.
- */
-#define pool_foreach(pool, eltp, BODY) \
- do { \
- unsigned _pool_var(i); \
- pool_enumerate((pool), _pool_var(i), (eltp), BODY); \
- } while (0)
-
-#define pool_get_alloc_size(pool) pool_hdr(pool)->alloc_size
-
-#ifdef WITH_TESTS
-#define pool_get_free_indices(pool) pool_hdr(pool)->free_indices
-#define pool_get_free_bitmap(pool) pool_hdr(pool)->free_bitmap
-#endif /* WITH_TESTS */
-
-#endif /* UTIL_POOL_H */
diff --git a/hicn-light/src/hicn/base/ring.c b/hicn-light/src/hicn/base/ring.c
deleted file mode 100644
index 29727886a..000000000
--- a/hicn-light/src/hicn/base/ring.c
+++ /dev/null
@@ -1,45 +0,0 @@
-
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * \file ring.c
- * \brief Implementation of ring buffer.
- */
-
-#include <stdlib.h>
-
-#include "ring.h"
-
-void _ring_init(void** ring_ptr, size_t elt_size, size_t max_size) {
- assert(ring_ptr);
- assert(elt_size > 0);
- // we use a static array, not a vector (for now)
- assert(max_size != 0);
-
- ring_hdr_t* rh = malloc(RING_HDRLEN + max_size * elt_size);
-
- rh->roff = 0;
- rh->woff = 0;
- rh->size = 0;
- rh->max_size = max_size;
-
- *ring_ptr = (uint8_t*)rh + RING_HDRLEN;
-}
-
-void _ring_free(void** ring_ptr) {
- free(ring_hdr(*ring_ptr));
- *ring_ptr = NULL;
-}
diff --git a/hicn-light/src/hicn/base/ring.h b/hicn-light/src/hicn/base/ring.h
deleted file mode 100644
index 492a8fdac..000000000
--- a/hicn-light/src/hicn/base/ring.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * \file ring.h
- * \brief Fixed-size pool allocator.
- */
-
-#ifndef UTIL_RING_H
-#define UTIL_RING_H
-
-#include <assert.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/param.h> // MIN
-#include <sys/types.h>
-
-#include <stdio.h> // XXX debug
-
-#include "common.h"
-
-/******************************************************************************/
-/* Ring header */
-
-typedef struct {
- size_t roff;
- size_t woff;
- size_t size;
- size_t max_size;
-} ring_hdr_t;
-
-/* Make sure elements following the header are aligned */
-#define RING_HDRLEN SIZEOF_ALIGNED(ring_hdr_t)
-
-/* This header actually prepends the actual content of the vector */
-#define ring_hdr(ring) ((ring_hdr_t *)((uint8_t *)ring - RING_HDRLEN))
-
-/******************************************************************************/
-/* Helpers */
-
-/** Local variable naming macro. */
-#define _ring_var(v) _ring_##v
-
-/**
- * @brief Allocate and initialize a ring data structure (helper function).
- *
- * @param[in,out] ring_ptr Ring buffer to allocate and initialize.
- * @param[in] elt_size Size of a ring element.
- * @param[in] max_size Maximum vector size (O = unlimited).
- */
-void _ring_init(void **ring_ptr, size_t elt_size, size_t max_size);
-
-/**
- * @brief Free a ring data structure.
- *
- * @param ring_ptr[in] Pointer to the ring data structure to free.
- */
-void _ring_free(void **ring_ptr);
-
-static inline int _ring_add(void **ring_ptr, size_t elt_size, void *eltp) {
- assert(*ring_ptr);
- ring_hdr_t *rh = ring_hdr(*ring_ptr);
-
- /* We always write ! */
- memcpy((uint8_t *)*ring_ptr + rh->woff * elt_size, eltp, elt_size);
- rh->woff++;
- if (rh->woff == rh->max_size) rh->woff = 0;
- if (rh->size < rh->max_size) {
- rh->size++;
- } else {
- /* One packet was dropped */
- rh->roff++;
- if (rh->roff == rh->max_size) rh->roff = 0;
- }
- return 0;
-}
-
-static inline unsigned _ring_get_fullness(void **ring_ptr) {
- assert(*ring_ptr);
- ring_hdr_t *rh = ring_hdr(*ring_ptr);
- return rh->size * 100 / rh->max_size;
-}
-
-static inline unsigned _ring_is_full(void **ring_ptr) {
- assert(*ring_ptr);
- ring_hdr_t *rh = ring_hdr(*ring_ptr);
- return rh->size == rh->max_size;
-}
-
-static inline size_t _ring_get_size(void **ring_ptr) {
- assert(*ring_ptr);
- ring_hdr_t *rh = ring_hdr(*ring_ptr);
- return rh->size;
-}
-
-static inline int _ring_advance(void **ring_ptr, unsigned n) {
- assert(*ring_ptr);
- ring_hdr_t *rh = ring_hdr(*ring_ptr);
- assert(n <= rh->size);
-
- rh->roff += n;
- rh->size -= n;
- while (rh->roff >= rh->max_size) rh->roff -= rh->max_size;
- return 0;
-}
-
-static inline int _ring_get(void **ring_ptr, size_t elt_size, unsigned i,
- void *eltp) {
- assert(*ring_ptr);
- ring_hdr_t *rh = ring_hdr(*ring_ptr);
- assert(i <= rh->size);
- size_t pos = rh->roff + i;
- if (pos >= rh->max_size) pos -= rh->max_size;
- memcpy(eltp, (uint8_t *)*ring_ptr + pos * elt_size, elt_size);
- return 0;
-}
-
-/******************************************************************************/
-/* Public API */
-
-/**
- * @brief Allocate and initialize a ring data structure.
- *
- * @param[in,out] ring Ring to allocate and initialize.
- * @param[in] max_size Maximum ring size (nonzero).
- *
- * NOTE:
- * - Allocated memory is set to 0 (used by bitmap)
- */
-
-#define ring_init(RING, MAX_SIZE) \
- _ring_init((void **)&(RING), sizeof((RING)[0]), (MAX_SIZE))
-
-#define ring_free(RING) _ring_free((void **)&(RING))
-
-#define ring_get_fullness(RING) _ring_get_fullness((void **)&(RING))
-
-#define ring_is_full(RING) _ring_is_full((void **)&(RING))
-
-#define ring_get_size(RING) _ring_get_size((void **)&(RING))
-
-#define ring_add(RING, ELT) _ring_add((void **)&(RING), sizeof(RING[0]), ELT)
-
-#define ring_add_value(RING, VALUE) \
- do { \
- typeof(VALUE) _ring_var(v) = VALUE; \
- _ring_add((void **)&(RING), sizeof(RING[0]), &_ring_var(v)); \
- } while (0)
-
-#define ring_advance(RING, N) _ring_advance((void **)&(RING), (N))
-
-#define ring_get(RING, I, ELTP) \
- _ring_get((void **)&RING, sizeof(RING[0]), (I), (ELTP))
-
-/**
- * @brief Helper function used by ring_foreach().
- */
-#define ring_enumerate_n(RING, I, ELTP, COUNT, BODY) \
- ({ \
- for ((I) = 0; (I) < MIN(ring_get_size(RING), (COUNT)); (I)++) { \
- ring_get((RING), (I), (ELTP)); \
- { BODY; } \
- } \
- })
-
-#define ring_enumerate(ring, i, eltp, BODY) \
- ring_enumerate_n((ring), (i), (eltp), 1, (BODY))
-
-/**
- * @brief Iterate over elements in a ring.
- *
- * @param[in] pool The ring data structure to iterate over
- * @param[in, out] eltp A pointer to the element that will be used for
- * iteration
- * @param[in] BODY Block to execute during iteration
- *
- * @note Iteration will execute BODY with eltp corresponding successively to all
- * elements found in the ring. It is implemented using the more generic
- * enumeration function.
- */
-#define ring_foreach_n(ring, eltp, count, BODY) \
- ({ \
- unsigned _ring_var(i); \
- ring_enumerate_n((ring), _ring_var(i), (eltp), (count), BODY); \
- })
-
-#define ring_foreach(ring, eltp, BODY) ring_foreach_n((ring), (eltp), 1, (BODY))
-
-#endif /* UTIL_RING_H */
diff --git a/hicn-light/src/hicn/base/vector.c b/hicn-light/src/hicn/base/vector.c
deleted file mode 100644
index 36d808932..000000000
--- a/hicn-light/src/hicn/base/vector.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * \file vector.c
- * \brief Implementation of resizeable static array
- */
-
-#include <assert.h>
-#include <stddef.h> // size_t
-#include <stdlib.h> // calloc
-#include <stdio.h>
-
-#include "vector.h"
-
-#define DEFAULT_VECTOR_SIZE 64
-
-void _vector_init(void** vector_ptr, size_t elt_size, size_t init_size,
- size_t max_size) {
- assert(vector_ptr);
- assert(max_size == 0 || init_size < max_size);
-
- if (init_size == 0) init_size = DEFAULT_VECTOR_SIZE;
-
- *vector_ptr = NULL;
- _vector_resize(vector_ptr, elt_size, init_size);
-
- vector_hdr_t* vh = vector_hdr(*vector_ptr);
- vh->cur_size = 0;
- vh->max_size = max_size;
-}
-
-void _vector_free(void** vector_ptr) {
- free(vector_hdr(*vector_ptr));
- *vector_ptr = NULL;
-}
-
-int _vector_resize(void** vector_ptr, size_t elt_size, off_t pos) {
- vector_hdr_t* vh;
-
- size_t old_size;
-
- if (*vector_ptr) {
- vh = vector_hdr(*vector_ptr);
- old_size = vh->alloc_size;
- } else {
- vh = NULL;
- old_size = 0;
- }
-
- /* Round the allocated size to the next power of 2 of the requested position
- */
- size_t new_size = next_pow2(pos);
-
- /* Don't grow the vector back */
- if (new_size < old_size) return 0;
-
- /* Don't exceed maximum size (for init, check is done beforehand) */
- if (vh && vh->max_size && new_size > vh->max_size) return -1;
-
- vh = realloc(vh, VECTOR_HDRLEN + new_size * elt_size);
- if (!vh) return -1;
- vh->alloc_size = new_size;
-
- /* Zero out the newly allocated memory (except headers) */
- memset((uint8_t*)vh + VECTOR_HDRLEN + old_size * elt_size, 0,
- (new_size - old_size) * elt_size);
-
- /* Reassign vector pointer */
- *vector_ptr = (uint8_t*)vh + VECTOR_HDRLEN;
-
- return 0;
-}
diff --git a/hicn-light/src/hicn/base/vector.h b/hicn-light/src/hicn/base/vector.h
deleted file mode 100644
index 0b7a74aeb..000000000
--- a/hicn-light/src/hicn/base/vector.h
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * \file vector.h
- * \brief Resizeable static array
- *
- * A vector is a resizeable area of contiguous memory that contains elements of
- * fixed size. It is mostly useful to serve as the basis for more advanced data
- * structures such as memory pools.
- *
- * The internal API manipulates a pointer to the vector so that it can be
- * seamlessly resized, and a more convenient user interface is provided through
- * macros.
- *
- * A vector starts at index 0, and is typed according to the elements it
- * contains. For that matter, the data structure header precedes the returned
- * pointer which corresponds to the storage area.
- *
- * A vector is by default used as a stack where an end marker is maintained and
- * new elements are pushed right after this end marker (an indication of
- * the size of the vector) after ensuring the vector is sufficiently large.
- *
- * A user should not store any pointer to vector elements as this might change
- * during reallocations, but should use indices instead.
- *
- * NOTE: a maximum size is currently not implemented.
- *
- * It is freely inspired (and simplified) from the VPP infra infrastructure
- * library.
- */
-
-#ifndef UTIL_VECTOR_H
-#define UTIL_VECTOR_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include "common.h"
-
-/******************************************************************************/
-/* Vector header */
-
-typedef struct {
- size_t cur_size; /** Vector current size (corresponding to the highest used
- element). */
- size_t alloc_size; /** The currently allocated size. */
- size_t max_size; /** The maximum allowed size (0 = no limit) */
-} vector_hdr_t;
-
-/* Make sure elements following the header are aligned */
-#define VECTOR_HDRLEN SIZEOF_ALIGNED(vector_hdr_t)
-
-/* This header actually prepends the actual content of the vector */
-#define vector_hdr(vector) ((vector_hdr_t *)((uint8_t *)vector - VECTOR_HDRLEN))
-
-/******************************************************************************/
-/* Helpers */
-
-/** Local variable naming macro. */
-#define _vector_var(v) _vector_##v
-
-/**
- * @brief Allocate and initialize a vector data structure (helper function).
- *
- * @param[in,out] vector_ptr Vector to allocate and initialize.
- * @param[in] elt_size Size of a vector element.
- * @param[in] init_size Initial vector size.
- * @param[in] max_size Maximum vector size (O = unlimited).
- */
-void _vector_init(void **vector_ptr, size_t elt_size, size_t init_size,
- size_t max_size);
-
-/**
- * @brief Free a vector data structure.
- *
- * @param vector_ptr[in] Pointer to the vector data structure to free.
- */
-void _vector_free(void **vector_ptr);
-
-/**
- * @brief Resize a vector data structure.
- *
- * @param[in] vector_ptr A pointer to the vector data structure to resize.
- * @param[in] elt_size The size of a vector element.
- * @param[in] pos The position at which the vector should be able to hold an
- * element.
- *
- * @return int Flag indicating whether the vector has been correctly resized.
- *
- * NOTE:
- * - The resize operation does not specify the final size of the vector but
- * instead ensure that it is large enough to hold an element at the specified
- * position. This allows the caller not to care about doing successive calls to
- * this API while the vector is growing in size.
- */
-int _vector_resize(void **vector_ptr, size_t elt_size, off_t pos);
-
-/**
- * @brief Ensures a vector is sufficiently large to hold an element at the
- * given position.
- *
- * @param[in] vector_ptr A pointer to the vector data structure to resize.
- * @param[in] elt_size The size of a vector element.
- * @param[in] pos The position to validate.
- *
- * @return int Flag indicating whether the vector is available.
- *
- * NOTE:
- * - This function should always be called before writing to a vector element
- * to eventually make room for it (the vector will eventually be resized).
- * - This function can fail if the vector is full and for any reason it cannot
- * be resized.
- */
-static inline int _vector_ensure_pos(void **vector_ptr, size_t elt_size,
- off_t pos) {
- vector_hdr_t *vh = vector_hdr(*vector_ptr);
- if (pos >= (off_t)vh->alloc_size)
- return _vector_resize(vector_ptr, elt_size, pos + 1);
- return 0;
-}
-
-/**
- * @brief Push an element at the end of a vector.
- *
- * @param[in] vector_ptr A pointer to the vector data structure to resize.
- * @param[in] elt_size The size of a vector element.
- * @param[in] elt The element to insert.
- *
- * NOTE:
- * - This function ensures there is sufficient room for inserting the element,
- * and evenutually resizes the vector to make room for it (if allowed by
- * maximum size).
- */
-static inline int _vector_push(void **vector_ptr, size_t elt_size, void *elt) {
- vector_hdr_t *vh = vector_hdr(*vector_ptr);
- if (_vector_ensure_pos(vector_ptr, elt_size, vh->cur_size) < 0) return -1;
-
- /* Always get header after a potential resize */
- vh = vector_hdr(*vector_ptr);
- memcpy((uint8_t *)*vector_ptr + vh->cur_size * elt_size, elt, elt_size);
- vh = vector_hdr(*vector_ptr);
- vh->cur_size++;
- return 0;
-}
-
-/**
- * @brief Remove all the occurrencies of an element from the vector.
- * The order of the elements is NOT maintained.
- *
- * @param[in, out] vector The vector data structure to resize
- * @param[in] elt_size The size of a vector element
- * @param[in] elt The element to remove
- * @return int Number of elemets (equal to 'elt') removed from the vector
- */
-static inline int _vector_remove_unordered(void *vector, size_t elt_size,
- void *elt) {
- size_t num_removed = 0;
- vector_hdr_t *vh = vector_hdr(vector);
- for (size_t i = 0; i < vector_hdr(vector)->cur_size; i++) {
- if (memcmp((uint8_t *)vector + i * elt_size, elt, elt_size) == 0) {
- vh->cur_size--;
- memcpy((uint8_t *)vector + i * elt_size,
- (uint8_t *)vector + vh->cur_size * elt_size, elt_size);
- num_removed++;
- }
- }
- return num_removed;
-}
-
-/******************************************************************************/
-/* Public API */
-
-/**
- * @brief Allocate and initialize a vector data structure.
- *
- * @param[in,out] vector Vector to allocate and initialize.
- * @param[in] init_size Initial vector size.
- * @param[in] max_size Maximum vector size (nonzero).
- *
- * NOTE:
- * - Allocated memory is set to 0 (used by bitmap)
- */
-
-#define vector_init(vector, init_size, max_size) \
- _vector_init((void **)&vector, sizeof(vector[0]), init_size, max_size)
-
-/**
- * @brief Free a vector data structure.
- *
- * @param[in] vector The vector data structure to free.
- */
-#define vector_free(vector) _vector_free((void **)&vector)
-
-/**
- * @brief Resize a vector data structure.
- *
- * @param[in] vector The vector data structure to resize.
- * @param[in] pos The position at which the vector should be able to hold an
- * element.
- *
- * @return int Flag indicating whether the vector has been correctly resized.
- *
- * NOTE:
- * - The resize operation does not specify the final size of the vector but
- * instead ensure that it is large enough to hold an element at the specified
- * position. This allows the caller not to care about doing successive calls to
- * this API while the vector is growing in size.
- * - If the new size is smaller than the current size, the content of the
- * vector will be truncated.
- * - Newly allocated memory is set to 0 (used by bitmap)
- */
-#define vector_resize(vector) \
- _vector_resize((void **)&(vector), sizeof((vector)[0]), 0)
-
-/**
- * @brief Ensures a vector is sufficiently large to hold an element at the
- * given position.
- *
- * @param[in] vector The vector for which to validate the position.
- * @param[in] pos The position to validate.
- *
- * NOTE:
- * - This function should always be called before writing to a vector element
- * to eventually make room for it (the vector will eventually be resized).
- */
-#define vector_ensure_pos(vector, pos) \
- _vector_ensure_pos((void **)&(vector), sizeof((vector)[0]), pos);
-
-/**
- * @brief Push an element at the end of a vector.
- *
- * @param[in] vector The vector in which to insert the element.
- * @param[in] elt The element to insert.
- *
- * NOTE:
- * - This function ensures there is sufficient room for inserting the element,
- * and evenutually resizes the vector to make room for it (if allowed by
- * maximum size).
- */
-#define vector_push(vector, elt) \
- ({ \
- typeof(elt) x = elt; \
- _vector_push((void **)&(vector), sizeof((vector)[0]), (void *)(&x)); \
- })
-
-/**
- * @brief Remove all the occurrencies of an element from the vector.
- * The order of the elements is NOT maintained.
- *
- * @param[in, out] vector The vector data structure to resize
- * @param[in] elt The element to remove
- * @return int Number of elemets (equal to 'elt') removed from the vector
- */
-#define vector_remove_unordered(vector, elt) \
- ({ \
- typeof(elt) x = elt; \
- _vector_remove_unordered((void *)(vector), sizeof((vector)[0]), \
- (void *)(&x)); \
- })
-
-/**
- * @brief Returns the length of a vector.
- *
- * @param[in] vector The vector from which to get the size.
- *
- * @see vector_ensure_pos
- *
- * NOTE:
- * - The size of the vector corresponds to the highest accessed index (for
- * example as specified in the resize operation) and not the currently
- * allocated size which will typically be bigger to amortize allocations.
- * - A user should always call vector_ensure_pos to ensure the vector is
- * sufficiently large to hold an element at the specified position.
- */
-#define vector_len(vector) vector_hdr(vector)->cur_size
-
-/**
- * @brief Returns the allocated size of a vector.
- */
-#define vector_get_alloc_size(vector) vector_hdr(vector)->alloc_size
-
-/**
- * @brief Iterate over elements in a vector.
- *
- * @param[in] pool The vector data structure to iterate over
- * @param[in, out] eltp A pointer to the element that will be used for
- * iteration
- * @param[in] BODY Block to execute during iteration
- *
- * @note Iteration will execute BODY with eltp corresponding successively to all
- * elements found in the vector. It is implemented using the more generic
- * enumeration function.
- */
-#define vector_foreach(vector, eltp, BODY) \
- ({ \
- unsigned _vector_var(i); \
- vector_enumerate((vector), _vector_var(i), (eltp), BODY); \
- })
-
-/**
- * @brief Helper function used by vector_foreach().
- */
-#define vector_enumerate(vector, i, eltp, BODY) \
- ({ \
- for ((i) = 0; (i) < vector_len(vector); (i)++) { \
- eltp = (vector) + (i); \
- { BODY; } \
- } \
- })
-
-#endif /* UTIL_VECTOR_H */
diff --git a/hicn-light/src/hicn/cli/hicnc.c b/hicn-light/src/hicn/cli/hicnc.c
index d14093b6b..3074016c5 100644
--- a/hicn-light/src/hicn/cli/hicnc.c
+++ b/hicn-light/src/hicn/cli/hicnc.c
@@ -25,6 +25,7 @@
#include "../config/parse.h"
#include <hicn/util/log.h>
#include <hicn/util/sstrncpy.h>
+#include <hicn/ctrl/hicn-light-ng.h>
#define PORT 9695
@@ -359,6 +360,70 @@ int main(int argc, char *const *argv) {
rc = hc_subscription_delete(s, &command.object.subscription);
break;
+ case OBJECT_STATS:
+ switch (command.action) {
+ case ACTION_GET:
+ rc = hc_stats_get(s, &data);
+ if (rc < 0) break;
+
+ hc_stats_snprintf(buf, MAX_LEN, (hicn_light_stats_t *)data->buffer);
+ INFO("\n%s", buf);
+ break;
+
+ case ACTION_LIST:
+ rc = hc_stats_list(s, &data);
+ if (rc < 0) break;
+
+ cmd_stats_list_item_t *conn_stats =
+ (cmd_stats_list_item_t *)data->buffer;
+ cmd_stats_list_item_t *end =
+ (cmd_stats_list_item_t *)(data->buffer +
+ data->size * data->out_element_size);
+ while (conn_stats < end) {
+ INFO("Connection #%d:", conn_stats->id);
+ INFO("\tinterests received: %d pkts (%d bytes)",
+ conn_stats->stats.interests.rx_pkts,
+ conn_stats->stats.interests.rx_bytes);
+ INFO("\tinterests transmitted: %d pkts (%d bytes)",
+ conn_stats->stats.interests.tx_pkts,
+ conn_stats->stats.interests.tx_bytes);
+ INFO("\tdata received: %d pkts (%d bytes)",
+ conn_stats->stats.data.rx_pkts,
+ conn_stats->stats.data.rx_bytes);
+ INFO("\tdata transmitted: %d pkts (%d bytes)",
+ conn_stats->stats.data.tx_pkts,
+ conn_stats->stats.data.tx_bytes);
+
+ conn_stats++;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+#ifdef TEST_FACE_CREATION
+ case OBJECT_FACE:
+ switch (command.action) {
+ case ACTION_CREATE: {
+ hc_face_t face = {0};
+ face.face.type = FACE_TYPE_UDP;
+ face.face.family = AF_INET;
+ face.face.local_addr = IPV4_LOOPBACK;
+ face.face.remote_addr = IPV4_LOOPBACK;
+ face.face.local_port = 9696;
+ face.face.remote_port = 9696;
+
+ rc = hc_face_create(s, &face);
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+#endif
+
default:
break;
}
diff --git a/hicn-light/src/hicn/cli/hicnd.c b/hicn-light/src/hicn/cli/hicnd.c
index e73517e4c..fa1b1c024 100644
--- a/hicn-light/src/hicn/cli/hicnd.c
+++ b/hicn-light/src/hicn/cli/hicnd.c
@@ -26,9 +26,9 @@
#include <sys/stat.h>
#include <hicn/util/log.h>
+#include <hicn/base/loop.h>
#include "logo.h"
-#include "../base/loop.h"
#include "../core/forwarder.h"
#include "../config/configuration.h" // XXX needed ?
#include "../config/configuration_file.h"
diff --git a/hicn-light/src/hicn/config/CMakeLists.txt b/hicn-light/src/hicn/config/CMakeLists.txt
index 00ee24077..90d0a2229 100644
--- a/hicn-light/src/hicn/config/CMakeLists.txt
+++ b/hicn-light/src/hicn/config/CMakeLists.txt
@@ -29,6 +29,7 @@ list(APPEND SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/command_policy.c
${CMAKE_CURRENT_SOURCE_DIR}/command_punting.c
${CMAKE_CURRENT_SOURCE_DIR}/command_route.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/command_stats.c
${CMAKE_CURRENT_SOURCE_DIR}/command_strategy.c
${CMAKE_CURRENT_SOURCE_DIR}/command_subscription.c
${CMAKE_CURRENT_SOURCE_DIR}/command.c
diff --git a/hicn-light/src/hicn/config/command_stats.c b/hicn-light/src/hicn/config/command_stats.c
new file mode 100644
index 000000000..70f74fd8c
--- /dev/null
+++ b/hicn-light/src/hicn/config/command_stats.c
@@ -0,0 +1,18 @@
+#include <math.h>
+#include "command.h"
+
+/* Commands */
+
+static const command_parser_t command_stats_get = {
+ .action = ACTION_GET,
+ .object = OBJECT_STATS,
+ .nparams = 0,
+};
+COMMAND_REGISTER(command_stats_get);
+
+static const command_parser_t command_stats_list = {
+ .action = ACTION_LIST,
+ .object = OBJECT_STATS,
+ .nparams = 0,
+};
+COMMAND_REGISTER(command_stats_list); \ No newline at end of file
diff --git a/hicn-light/src/hicn/config/commands.c b/hicn-light/src/hicn/config/commands.c
index e99e0b8f5..be00575d7 100644
--- a/hicn-light/src/hicn/config/commands.c
+++ b/hicn-light/src/hicn/config/commands.c
@@ -90,7 +90,8 @@ static inline unsigned _symbolic_to_conn_id(forwarder_t *forwarder,
}
} else {
// case for symbolic as input: check if symbolic name can be resolved
- conn_id = connection_table_get_id_by_name(table, symbolic_or_connid);
+ conn_id = (unsigned int)connection_table_get_id_by_name(table,
+ symbolic_or_connid);
if (connection_id_is_valid(conn_id)) {
DEBUG("Resolved symbolic name '%s' to conn_id %u", symbolic_or_connid,
conn_id);
@@ -151,6 +152,7 @@ uint8_t *configuration_on_listener_add(forwarder_t *forwarder, uint8_t *packet,
}
address_t address;
+ memset(&address, 0, sizeof(address_t));
if (address_from_ip_port(&address, control->family, &control->address,
control->port) < 0) {
WARN(
@@ -206,7 +208,8 @@ unsigned symbolic_to_listener_id(forwarder_t *forwarder,
}
} else {
// case for symbolic as input: check if symbolic name can be resolved
- listener_id = listener_table_get_id_by_name(table, symbolic_or_listener_id);
+ listener_id = (unsigned int)listener_table_get_id_by_name(
+ table, symbolic_or_listener_id);
if (listener_id_is_valid(listener_id)) {
DEBUG("Resolved symbolic name '%s' to conn_id %u",
symbolic_or_listener_id, listener_id);
@@ -262,7 +265,8 @@ uint8_t *configuration_on_listener_remove(forwarder_t *forwarder,
address_pair_get_local(pair)))
continue;
- unsigned conn_id = connection_table_get_connection_id(table, connection);
+ unsigned conn_id =
+ (unsigned int)connection_table_get_connection_id(table, connection);
/* Remove connection from the FIB */
forwarder_remove_connection_id_from_routes(forwarder, conn_id);
@@ -335,8 +339,9 @@ uint8_t *configuration_on_listener_list(forwarder_t *forwarder, uint8_t *packet,
uint8_t command_id = msg_received->header.command_id;
uint32_t seq_num = msg_received->header.seq_num;
- msg_listener_list_reply_t *msg;
- msg_malloc_list(msg, command_id, n, seq_num) if (!msg) goto NACK;
+ msg_listener_list_reply_t *msg = NULL;
+ msg_malloc_list(msg, command_id, n, seq_num);
+ if (!msg) goto NACK;
cmd_listener_list_item_t *payload = &msg->payload;
listener_t *listener;
@@ -376,14 +381,23 @@ uint8_t *configuration_on_connection_add(forwarder_t *forwarder,
goto NACK;
}
- const char *symbolic_name = control->symbolic;
-
if (!face_type_is_defined(control->type)) goto NACK;
connection_table_t *table = forwarder_get_connection_table(forwarder);
- if (connection_table_get_by_name(table, symbolic_name)) {
- ERROR("Connection symbolic name already exists");
- goto NACK;
+ char *symbolic_name = control->symbolic;
+
+ // Generate connection name if not specified
+ if (symbolic_name[0] == '\0') {
+ int rc = connection_table_get_random_name(table, symbolic_name);
+ if (rc < 0) {
+ ERROR("Unable to generate new connection name");
+ goto NACK;
+ }
+ } else {
+ if (connection_table_get_by_name(table, symbolic_name)) {
+ ERROR("Connection symbolic name already exists");
+ goto NACK;
+ }
}
address_pair_t pair;
@@ -561,6 +575,14 @@ static inline void fill_connections_command(forwarder_t *forwarder,
}
}
+static inline void fill_connection_stats_command(connection_t *connection,
+ cmd_stats_list_item_t *cmd) {
+ assert(connection && cmd);
+
+ cmd->id = connection->id;
+ cmd->stats = connection->stats;
+}
+
uint8_t *configuration_on_connection_list(forwarder_t *forwarder,
uint8_t *packet, unsigned ingress_id,
size_t *reply_size) {
@@ -576,8 +598,9 @@ uint8_t *configuration_on_connection_list(forwarder_t *forwarder,
uint8_t command_id = msg_received->header.command_id;
uint32_t seq_num = msg_received->header.seq_num;
- msg_connection_list_reply_t *msg;
- msg_malloc_list(msg, command_id, n, seq_num) if (!msg) goto NACK;
+ msg_connection_list_reply_t *msg = NULL;
+ msg_malloc_list(msg, command_id, n, seq_num);
+ if (!msg) goto NACK;
cmd_connection_list_item_t *payload = &msg->payload;
connection_t *connection;
@@ -807,7 +830,7 @@ uint8_t *configuration_on_route_list(forwarder_t *forwarder, uint8_t *packet,
n += nexthops_get_len(nexthops);
});
- msg_route_list_reply_t *msg;
+ msg_route_list_reply_t *msg = NULL;
msg_malloc_list(msg, command_id, n, seq_num);
if (!msg) goto NACK;
@@ -938,8 +961,9 @@ uint8_t *configuration_on_cache_list(forwarder_t *forwarder, uint8_t *packet,
.payload = {
.store_in_cs = forwarder_cs_get_store(forwarder),
.serve_from_cs = forwarder_cs_get_serve(forwarder),
- .cs_size = forwarder_cs_get_size(forwarder),
- .num_stale_entries = forwarder_cs_get_num_stale_entries(forwarder)}};
+ .cs_size = (unsigned int)forwarder_cs_get_size(forwarder),
+ .num_stale_entries =
+ (unsigned int)forwarder_cs_get_num_stale_entries(forwarder)}};
*reply_size = sizeof(*msg);
return (uint8_t *)msg;
@@ -1068,6 +1092,65 @@ NACK:
return (uint8_t *)msg;
}
+/* Statistics */
+
+uint8_t *configuration_on_stats_get(forwarder_t *forwarder, uint8_t *packet,
+ unsigned ingress_id, size_t *reply_size) {
+ assert(forwarder && packet);
+ INFO("CMD: stats get (ingress=%d)", ingress_id);
+
+ msg_stats_get_t *msg_received = (msg_stats_get_t *)packet;
+ uint32_t seq_num = msg_received->header.seq_num;
+
+ msg_stats_get_reply_t *msg = malloc(sizeof(*msg));
+ *msg = (msg_stats_get_reply_t){
+ .header = {.message_type = RESPONSE_LIGHT,
+ .length = 1,
+ .seq_num = seq_num},
+ .payload = {.forwarder = forwarder_get_stats(forwarder),
+ .pkt_cache =
+ pkt_cache_get_stats(forwarder_get_pkt_cache(forwarder))}
+
+ };
+
+ *reply_size = sizeof(*msg);
+ return (uint8_t *)msg;
+}
+
+uint8_t *configuration_on_stats_list(forwarder_t *forwarder, uint8_t *packet,
+ unsigned ingress_id, size_t *reply_size) {
+ assert(forwarder && packet);
+ INFO("CMD: stats list (ingress=%d)", ingress_id);
+
+ connection_table_t *table = forwarder_get_connection_table(forwarder);
+ // -1 since current connection (i.e. the one used to send
+ // the command) is not considered
+ size_t n = connection_table_len(table) - 1;
+ msg_stats_list_t *msg_received = (msg_stats_list_t *)packet;
+ uint8_t command_id = msg_received->header.command_id;
+ uint32_t seq_num = msg_received->header.seq_num;
+
+ msg_stats_list_reply_t *msg = NULL;
+ msg_malloc_list(msg, command_id, n, seq_num);
+ if (!msg) goto NACK;
+
+ cmd_stats_list_item_t *payload = &msg->payload;
+ connection_t *connection;
+ connection_table_foreach(table, connection, {
+ if (connection->id == ingress_id) continue;
+ fill_connection_stats_command(connection, payload);
+ payload++;
+ });
+
+ *reply_size = sizeof(msg->header) + n * sizeof(msg->payload);
+ return (uint8_t *)msg;
+
+NACK:
+ *reply_size = sizeof(msg_header_t);
+ make_nack(msg);
+ return (uint8_t *)msg;
+}
+
/* WLDR */
uint8_t *configuration_on_wldr_set(forwarder_t *forwarder, uint8_t *packet,
@@ -1365,7 +1448,7 @@ uint8_t *configuration_on_policy_list(forwarder_t *forwarder, uint8_t *packet,
uint8_t command_id = msg_received->header.command_id;
uint32_t seq_num = msg_received->header.seq_num;
- msg_policy_list_reply_t *msg;
+ msg_policy_list_reply_t *msg = NULL;
msg_malloc_list(msg, command_id, n, seq_num);
if (!msg) goto NACK;
diff --git a/hicn-light/src/hicn/config/commands.h b/hicn-light/src/hicn/config/commands.h
index cedf4de01..3852a76ac 100644
--- a/hicn-light/src/hicn/config/commands.h
+++ b/hicn-light/src/hicn/config/commands.h
@@ -149,4 +149,7 @@ uint8_t *configuration_on_policy_remove(forwarder_t *forwarder, uint8_t *packet,
uint8_t *configuration_on_policy_list(forwarder_t *forwarder, uint8_t *packet,
unsigned ingress_id, size_t *reply_size);
+uint8_t *configuration_on_stats_list(forwarder_t *forwarder, uint8_t *packet,
+ unsigned ingress_id, size_t *reply_size);
+
#endif // HICNLIGHT_COMMANDS_H
diff --git a/hicn-light/src/hicn/config/configuration.h b/hicn-light/src/hicn/config/configuration.h
index 9861b6c9f..93b4cf7c3 100644
--- a/hicn-light/src/hicn/config/configuration.h
+++ b/hicn-light/src/hicn/config/configuration.h
@@ -26,7 +26,7 @@
#ifndef HICNLIGHT_CONFIGURATION_H
#define HICNLIGHT_CONFIGURATION_H
-#include "../base/khash.h"
+#include <hicn/util/khash.h>
#include "../core/msgbuf.h"
#include "../core/strategy.h"
#include <hicn/ctrl/api.h>
diff --git a/hicn-light/src/hicn/core/CMakeLists.txt b/hicn-light/src/hicn/core/CMakeLists.txt
index 57ffb780f..9516a6a72 100644
--- a/hicn-light/src/hicn/core/CMakeLists.txt
+++ b/hicn-light/src/hicn/core/CMakeLists.txt
@@ -21,6 +21,7 @@ list(APPEND HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/fib_entry.h
${CMAKE_CURRENT_SOURCE_DIR}/fib.h
${CMAKE_CURRENT_SOURCE_DIR}/forwarder.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/interest_manifest.h
${CMAKE_CURRENT_SOURCE_DIR}/listener.h
${CMAKE_CURRENT_SOURCE_DIR}/listener_table.h
${CMAKE_CURRENT_SOURCE_DIR}/listener_vft.h
@@ -52,6 +53,7 @@ list(APPEND SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/fib.c
${CMAKE_CURRENT_SOURCE_DIR}/fib_entry.c
${CMAKE_CURRENT_SOURCE_DIR}/forwarder.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/interest_manifest.c
${CMAKE_CURRENT_SOURCE_DIR}/listener.c
${CMAKE_CURRENT_SOURCE_DIR}/listener_table.c
${CMAKE_CURRENT_SOURCE_DIR}/listener_vft.c
diff --git a/hicn-light/src/hicn/core/address_pair.h b/hicn-light/src/hicn/core/address_pair.h
index 72b92d6b5..2fd207d34 100644
--- a/hicn-light/src/hicn/core/address_pair.h
+++ b/hicn-light/src/hicn/core/address_pair.h
@@ -43,6 +43,12 @@ 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);
+static inline int address_pair_equals(const address_pair_t* pair1,
+ const address_pair_t* pair2) {
+ return address_equals(&pair1->local, &pair2->local) &&
+ address_equals(&pair1->remote, &pair2->remote);
+}
+
#define address_pair_get_local(pair) (&(pair)->local)
#define address_pair_get_remote(pair) (&(pair)->remote)
diff --git a/hicn-light/src/hicn/core/connection.c b/hicn-light/src/hicn/core/connection.c
index c8cc1d0b9..2108d30af 100644
--- a/hicn-light/src/hicn/core/connection.c
+++ b/hicn-light/src/hicn/core/connection.c
@@ -28,8 +28,6 @@
#include "connection.h"
#include "connection_vft.h"
-#define _conn_var(x) _connection_##x
-
// This is called by configuration
connection_t *connection_create(face_type_t type, const char *name,
const address_pair_t *pair,
@@ -212,18 +210,16 @@ int connection_send_packet(const connection_t *connection,
connection, packet, size);
}
-bool _connection_send(const connection_t *connection, msgbuf_t *msgbuf,
- bool queue) {
+bool _connection_send(connection_t *connection, msgbuf_t *msgbuf, bool queue) {
return connection_vft[get_protocol(connection->type)]->send(connection,
msgbuf, queue);
}
-bool connection_flush(const connection_t *connection) {
+bool connection_flush(connection_t *connection) {
return connection_vft[get_protocol(connection->type)]->flush(connection);
}
-bool connection_send(const connection_t *connection, off_t msgbuf_id,
- bool queue) {
+bool connection_send(connection_t *connection, off_t msgbuf_id, bool queue) {
assert(connection);
assert(msgbuf_id_is_valid(msgbuf_id));
@@ -254,7 +250,7 @@ bool connection_send(const connection_t *connection, off_t msgbuf_id,
* 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 connection_resend(connection_t *connection, msgbuf_t *msgbuf,
bool notification) {
assert(connection);
assert(msgbuf);
diff --git a/hicn-light/src/hicn/core/connection.h b/hicn-light/src/hicn/core/connection.h
index 05dc1d6e2..ac75428dd 100644
--- a/hicn-light/src/hicn/core/connection.h
+++ b/hicn-light/src/hicn/core/connection.h
@@ -84,6 +84,7 @@ typedef struct {
*/
struct wldr_s* wldr;
+ connection_stats_t stats;
} connection_t;
#if 1
@@ -209,10 +210,9 @@ int connection_finalize(connection_t* connection);
int connection_send_packet(const connection_t* connection,
const uint8_t* packet, size_t size);
-bool connection_flush(const connection_t* connection);
+bool connection_flush(connection_t* connection);
-bool connection_send(const connection_t* connection, off_t msgbuf_id,
- bool queue);
+bool connection_send(connection_t* connection, off_t msgbuf_id, bool queue);
size_t connection_process_buffer(connection_t* connection,
const uint8_t* buffer, size_t size);
diff --git a/hicn-light/src/hicn/core/connection_table.c b/hicn-light/src/hicn/core/connection_table.c
index 09236ae8e..c723073a1 100644
--- a/hicn-light/src/hicn/core/connection_table.c
+++ b/hicn-light/src/hicn/core/connection_table.c
@@ -74,6 +74,54 @@ void connection_table_free(connection_table_t *table) {
free(table);
}
+connection_t *connection_table_allocate(const connection_table_t *table,
+ const address_pair_t *pair,
+ const char *name) {
+ connection_t *conn = NULL;
+ pool_get(table->connections, conn);
+ if (!conn) return NULL;
+
+ off_t id = conn - table->connections;
+ int rc;
+
+ // Add in name hash table
+ khiter_t k = kh_put_ct_name(table->id_by_name, strdup(name), &rc);
+ assert(rc == KH_ADDED || rc == KH_RESET);
+ kh_value(table->id_by_name, k) = (unsigned int)id;
+
+ // Add in pair hash table
+ address_pair_t *pair_copy = (address_pair_t *)malloc(sizeof(address_pair_t));
+ memcpy(pair_copy, pair, sizeof(address_pair_t));
+
+ k = kh_put_ct_pair(table->id_by_pair, pair_copy, &rc);
+ assert(rc == KH_ADDED || rc == KH_RESET);
+ kh_value(table->id_by_pair, k) = (unsigned int)id;
+
+ assert(kh_size(table->id_by_name) == kh_size(table->id_by_pair));
+ return conn;
+}
+
+void connection_table_deallocate(const connection_table_t *table,
+ const connection_t *conn) {
+ const char *name = connection_get_name(conn);
+ const address_pair_t *pair = connection_get_pair(conn);
+
+ // Remove from name hash table
+ khiter_t k = kh_get_ct_name(table->id_by_name, name);
+ assert(k != kh_end(table->id_by_name));
+ free((char *)kh_key(table->id_by_name, k));
+ kh_del_ct_name(table->id_by_name, k);
+
+ // Remove from pair hash table
+ k = kh_get_ct_pair(table->id_by_pair, pair);
+ assert(k != kh_end(table->id_by_pair));
+ free((address_pair_t *)kh_key(table->id_by_pair, k));
+ kh_del_ct_pair(table->id_by_pair, k);
+
+ assert(kh_size(table->id_by_name) == kh_size(table->id_by_pair));
+ pool_put(table->connections, conn);
+}
+
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);
@@ -90,7 +138,7 @@ off_t connection_table_get_id_by_name(const connection_table_t *table,
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);
+ unsigned conn_id = (unsigned int)connection_table_get_id_by_name(table, name);
if (!connection_id_is_valid(conn_id)) return NULL;
return connection_table_at(table, conn_id);
}
@@ -141,22 +189,24 @@ connection_t *_connection_table_get_by_id(connection_table_t *table, off_t id) {
return connection_table_get_by_id(table, id);
}
-#define RANDBYTE() (u8)(rand() & 0xFF)
-
-char *connection_table_get_random_name(const connection_table_t *table) {
- char *connection_name = malloc(SYMBOLIC_NAME_LEN * sizeof(char));
- u8 rand_num;
+static inline u16 RAND16() { return rand() & 0xFFFF; }
- /* Generate a random connection name */
- while (1) {
- rand_num = RANDBYTE();
- int rc = snprintf(connection_name, SYMBOLIC_NAME_LEN, "conn%u", rand_num);
- _ASSERT(rc < SYMBOLIC_NAME_LEN);
+int connection_table_get_random_name(const connection_table_t *table,
+ char *name) {
+ int i, n_attempts = 2 * USHRT_MAX;
+ for (i = 0; i < n_attempts; i++) {
+ int rc = snprintf(name, SYMBOLIC_NAME_LEN, "conn%u", RAND16());
+ if (rc >= SYMBOLIC_NAME_LEN) continue;
- // Return if connection name does not already exist
- khiter_t k = kh_get_ct_name(table->id_by_name, connection_name);
+ // Check if generated connection name is a duplicate
+ khiter_t k = kh_get_ct_name(table->id_by_name, name);
if (k == kh_end(table->id_by_name)) break;
}
- return connection_name;
+ if (i == n_attempts) {
+ ERROR("Unable to generate new unique connection name");
+ return -1;
+ }
+
+ return 0;
} \ No newline at end of file
diff --git a/hicn-light/src/hicn/core/connection_table.h b/hicn-light/src/hicn/core/connection_table.h
index 4c03aa642..7d4bad761 100644
--- a/hicn-light/src/hicn/core/connection_table.h
+++ b/hicn-light/src/hicn/core/connection_table.h
@@ -30,22 +30,18 @@
#ifndef HICNLIGHT_CONNECTION_TABLE_H
#define HICNLIGHT_CONNECTION_TABLE_H
+#include <hicn/util/khash.h>
+#include <hicn/util/hash.h>
#include "address_pair.h"
#include "connection.h"
-#include "../base/hash.h"
-#include "../base/khash.h"
-#include "../base/pool.h"
-
-#define _ct_var(x) _ct_var_##x
+#include <hicn/util/pool.h>
/* Hash functions for indices. */
#define address_pair_hash(pair) (hash_struct(pair))
-#define address_pair_hash_eq(a, b) \
- (address_pair_hash(b) == address_pair_hash(a))
/* Hash table types for indices. */
KHASH_INIT(ct_pair, const address_pair_t *, unsigned, 1, address_pair_hash,
- address_pair_hash_eq);
+ address_pair_equals);
KHASH_MAP_INIT_STR(ct_name, unsigned);
typedef struct {
@@ -72,34 +68,9 @@ typedef struct {
* - You should always check that the returned connection is not NULL, which
* would signal that the pool is exhausted and could not be extended.
*/
-static inline connection_t *connection_table_allocate(
- const connection_table_t *table, const address_pair_t *pair,
- const char *name) {
- connection_t *conn;
- pool_get(table->connections, conn);
-
- if (conn) {
- off_t id = conn - table->connections;
- int res;
- khiter_t k;
-
- // Add in name hash table
- k = kh_put_ct_name(table->id_by_name, strdup(name), &res);
- kh_value(table->id_by_name, k) = id;
-
- // Add in pair hash table
- address_pair_t *pair_copy =
- (address_pair_t *)malloc(sizeof(address_pair_t));
- memcpy(pair_copy, pair, sizeof(address_pair_t));
-
- k = kh_put_ct_pair(table->id_by_pair, pair_copy, &res);
- assert(res != -1);
- kh_value(table->id_by_pair, k) = id;
- }
-
- return conn;
-}
-
+connection_t *connection_table_allocate(const connection_table_t *table,
+ const address_pair_t *pair,
+ const char *name);
/**
* @brief Deallocate a connection and return it to the connection table pool.
*
@@ -110,26 +81,8 @@ static inline connection_t *connection_table_allocate(
* - Upon returning a connection to the pool, all indices pointing to that
* connection are also cleared.
*/
-static inline void connection_table_deallocate(const connection_table_t *table,
- const connection_t *conn) {
- const char *name = connection_get_name(conn);
- const address_pair_t *pair = connection_get_pair(conn);
- khiter_t k;
-
- // Remove from name hash table
- k = kh_get_ct_name(table->id_by_name, name);
- assert(k != kh_end(table->id_by_name));
- free((char *)kh_key(table->id_by_name, k));
- kh_del_ct_name(table->id_by_name, k);
-
- // Remove from pair hash table
- k = kh_get_ct_pair(table->id_by_pair, pair);
- assert(k != kh_end(table->id_by_pair));
- free((address_pair_t *)kh_key(table->id_by_pair, k));
- kh_del_ct_pair(table->id_by_pair, k);
-
- pool_put(table->connections, conn);
-}
+void connection_table_deallocate(const connection_table_t *table,
+ const connection_t *conn);
/**
* @brief Returns the length of the connection table, the number of active
@@ -292,6 +245,7 @@ void connection_table_print_by_pair(const connection_table_t *table);
void connection_table_print_by_name(const connection_table_t *table);
-char *connection_table_get_random_name(const connection_table_t *table);
+int connection_table_get_random_name(const connection_table_t *table,
+ char *name);
#endif /* HICNLIGHT_CONNECTION_TABLE_H */
diff --git a/hicn-light/src/hicn/core/connection_vft.h b/hicn-light/src/hicn/core/connection_vft.h
index e6290cdd4..1a6ecbb78 100644
--- a/hicn-light/src/hicn/core/connection_vft.h
+++ b/hicn-light/src/hicn/core/connection_vft.h
@@ -28,8 +28,8 @@ typedef struct {
void (*finalize)(connection_t* connection);
int (*get_socket)(const listener_t* listener, const address_t* local,
const address_t* remote, const char* interface_name);
- bool (*flush)(const connection_t* connection);
- bool (*send)(const connection_t* connection, msgbuf_t* msgbuf, bool queue);
+ bool (*flush)(connection_t* connection);
+ bool (*send)(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);
diff --git a/hicn-light/src/hicn/core/content_store.c b/hicn-light/src/hicn/core/content_store.c
index edbdc5ac1..360e6d333 100644
--- a/hicn-light/src/hicn/core/content_store.c
+++ b/hicn-light/src/hicn/core/content_store.c
@@ -84,3 +84,5 @@ void cs_log(cs_t *cs) {
cs->stats.lru.countUpdates, cs->stats.lru.countLruDeletions,
cs->stats.lru.countLruEvictions);
}
+
+cs_lru_stats_t cs_get_lru_stats(cs_t *cs) { return cs->stats.lru; }
diff --git a/hicn-light/src/hicn/core/content_store.h b/hicn-light/src/hicn/core/content_store.h
index d47d603be..ceaf05e6b 100644
--- a/hicn-light/src/hicn/core/content_store.h
+++ b/hicn-light/src/hicn/core/content_store.h
@@ -1,7 +1,7 @@
#ifndef HICNLIGHT_CS_H
#define HICNLIGHT_CS_H
-#include "../base/pool.h"
+#include <hicn/util/pool.h>
#include "../content_store/lru.h"
#include "msgbuf_pool.h"
@@ -103,4 +103,6 @@ void cs_miss(cs_t *cs);
*/
void cs_log(cs_t *cs);
+cs_lru_stats_t cs_get_lru_stats(cs_t *cs);
+
#endif /* HICNLIGHT_CS_H */
diff --git a/hicn-light/src/hicn/core/fib_entry.c b/hicn-light/src/hicn/core/fib_entry.c
index 616f12961..80d337884 100644
--- a/hicn-light/src/hicn/core/fib_entry.c
+++ b/hicn-light/src/hicn/core/fib_entry.c
@@ -378,7 +378,7 @@ nexthops_t *fib_entry_get_available_nexthops(fib_entry_t *entry,
connection_table_foreach(table, connection, {
if (connection_is_local(connection)) continue;
new_nexthops->elts[nexthops_get_len(new_nexthops)] =
- connection_table_get_connection_id(table, connection);
+ (unsigned int)connection_table_get_connection_id(table, connection);
nexthops_inc(new_nexthops);
});
diff --git a/hicn-light/src/hicn/core/forwarder.c b/hicn-light/src/hicn/core/forwarder.c
index 37502f3ac..74be6431a 100644
--- a/hicn-light/src/hicn/core/forwarder.c
+++ b/hicn-light/src/hicn/core/forwarder.c
@@ -69,45 +69,9 @@
#endif /* WITH_POLICY_STATS */
#include <hicn/core/wldr.h>
+#include <hicn/core/interest_manifest.h>
#include <hicn/util/log.h>
-typedef struct {
- // Packets processed
- uint32_t countReceived; // Interest and data only
- uint32_t countInterestsReceived;
- uint32_t countObjectsReceived;
-
- // Packets Dropped
- uint32_t countDropped;
- uint32_t countInterestsDropped;
- uint32_t countObjectsDropped;
- uint32_t countOtherDropped;
-
- // Forwarding
- uint32_t countInterestForwarded;
- uint32_t countObjectsForwarded;
-
- // Errors while forwarding
- uint32_t countDroppedConnectionNotFound;
- uint32_t countSendFailures;
- uint32_t countDroppedNoRoute;
-
- // Interest processing
- uint32_t countInterestsAggregated;
- uint32_t countInterestsRetransmitted;
- uint32_t countInterestsSatisfiedFromStore;
- uint32_t countInterestsExpired;
- uint32_t countDataExpired;
-
- // Data processing
- uint32_t countDroppedNoReversePath;
-
- // TODO(eloparco): Currently not used
- // uint32_t countDroppedNoHopLimit;
- // uint32_t countDroppedZeroHopLimitFromRemote;
- // uint32_t countDroppedZeroHopLimitToRemote;
-} forwarder_stats_t;
-
struct forwarder_s {
// uint16_t server_port;
@@ -138,13 +102,12 @@ struct forwarder_s {
* 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 */
+ unsigned *pending_conn;
subscription_table_t *subscriptions;
+
+ // Used to store the msgbufs that need to be released
+ off_t *acquired_msgbuf_ids;
};
/**
@@ -223,8 +186,12 @@ forwarder_t *forwarder_create(configuration_t *configuration) {
#endif /* WITH_POLICY_STATS */
memset(&forwarder->stats, 0, sizeof(forwarder_stats_t));
+ vector_init(forwarder->pending_conn, MAX_MSG, 0);
+ vector_init(forwarder->acquired_msgbuf_ids, MAX_MSG, 0);
- forwarder->num_pending_conn = 0;
+ char *n_suffixes_per_split_str = getenv("N_SUFFIXES_PER_SPIT");
+ if (n_suffixes_per_split_str)
+ N_SUFFIXES_PER_SPIT = atoi(n_suffixes_per_split_str);
return forwarder;
@@ -267,6 +234,8 @@ void forwarder_free(forwarder_t *forwarder) {
listener_table_free(forwarder->listener_table);
subscription_table_free(forwarder->subscriptions);
configuration_free(forwarder->config);
+ vector_free(forwarder->pending_conn);
+ vector_free(forwarder->acquired_msgbuf_ids);
free(forwarder);
}
@@ -295,6 +264,11 @@ listener_table_t *forwarder_get_listener_table(forwarder_t *forwarder) {
return forwarder->listener_table;
}
+pkt_cache_t *forwarder_get_pkt_cache(const forwarder_t *forwarder) {
+ assert(forwarder);
+ return forwarder->pkt_cache;
+}
+
void forwarder_cs_set_store(forwarder_t *forwarder, bool val) {
assert(forwarder);
forwarder->store_in_cs = val;
@@ -393,7 +367,7 @@ static ssize_t forwarder_forward_via_connection(forwarder_t *forwarder,
const msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder);
msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id);
- const connection_t *conn = connection_table_get_by_id(table, conn_id);
+ connection_t *conn = connection_table_get_by_id(table, conn_id);
if (!conn) {
forwarder->stats.countDroppedConnectionNotFound++;
@@ -429,12 +403,8 @@ static ssize_t forwarder_forward_via_connection(forwarder_t *forwarder,
#endif
/* ... 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) // Not found
- forwarder->pending_conn[forwarder->num_pending_conn++] = conn_id;
+ if (!vector_contains(forwarder->pending_conn, conn_id))
+ vector_push(forwarder->pending_conn, conn_id);
if (!success) {
forwarder->stats.countSendFailures++;
@@ -457,7 +427,8 @@ static ssize_t forwarder_forward_via_connection(forwarder_t *forwarder,
break;
}
- TRACE("forward msgbuf %p to interface %u", msgbuf, conn_id);
+ TRACE("forward msgbuf %p (size=%u) to interface %u", msgbuf,
+ msgbuf_get_len(msgbuf), conn_id);
return msgbuf_get_len(msgbuf);
}
@@ -496,8 +467,7 @@ static unsigned forwarder_forward_to_nexthops(forwarder_t *forwarder,
static bool forwarder_forward_via_fib(forwarder_t *forwarder, off_t msgbuf_id,
pkt_cache_verdict_t verdict,
pkt_cache_entry_t *entry) {
- assert(forwarder);
- assert(msgbuf_id_is_valid(msgbuf_id));
+ assert(forwarder && entry && msgbuf_id_is_valid(msgbuf_id));
const msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder);
msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id);
@@ -515,15 +485,8 @@ static bool forwarder_forward_via_fib(forwarder_t *forwarder, off_t msgbuf_id,
return false;
}
- // if this is the first time that we sent this interest the pit entry would be
- // NULL. in that case we add the interest to the pit
- if (entry == NULL) {
- entry = pkt_cache_add_to_pit(forwarder->pkt_cache, msgbuf);
- }
pit_entry_t *pit_entry = &entry->u.pit_entry;
- if (!pit_entry) {
- return false;
- }
+ if (!pit_entry) return false;
pit_entry_set_fib_entry(pit_entry, fib_entry);
@@ -547,21 +510,19 @@ static bool forwarder_forward_via_fib(forwarder_t *forwarder, off_t msgbuf_id,
#endif /* ! BYPASS_FIB */
-ssize_t _forwarder_forward_upon_interest(forwarder_t *forwarder,
- msgbuf_pool_t *msgbuf_pool,
- off_t data_msgbuf_id,
- off_t interest_msgbuf_id,
- pkt_cache_entry_t *entry,
- pkt_cache_verdict_t verdict) {
+int _forwarder_forward_upon_interest(
+ forwarder_t *forwarder, msgbuf_pool_t *msgbuf_pool, off_t data_msgbuf_id,
+ off_t interest_msgbuf_id, pkt_cache_entry_t *entry,
+ pkt_cache_verdict_t verdict, bool is_aggregated) {
msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, interest_msgbuf_id);
+ // - Aggregation can be perfomed, do not forward
if (verdict == PKT_CACHE_VERDICT_AGGREGATE_INTEREST) {
- // the packet shuold not be forwarder
forwarder_drop(forwarder, interest_msgbuf_id);
return msgbuf_get_len(msgbuf);
}
- // - Forward reply if a data packet matching the interest was found
+ // - Data packet matching the interest was found, forward reply
if (verdict == PKT_CACHE_VERDICT_FORWARD_DATA) {
assert(forwarder->serve_from_cs == true);
@@ -569,19 +530,26 @@ ssize_t _forwarder_forward_upon_interest(forwarder_t *forwarder,
msgbuf_t *data_msgbuf = msgbuf_pool_at(msgbuf_pool, data_msgbuf_id);
msgbuf_reset_pathlabel(data_msgbuf);
-
forwarder_forward_via_connection(forwarder, data_msgbuf_id,
msgbuf_get_connection_id(interest_msgbuf));
+ return msgbuf_get_len(msgbuf);
+ }
+
+ // - For aggregated interest, the interest forwarding is done in
+ // `_forwarder_forward_aggregated_interest()`
+ if (is_aggregated) return msgbuf_get_len(msgbuf);
- // - Try to forward the interest
- } else if (!forwarder_forward_via_fib(forwarder, interest_msgbuf_id, verdict,
- entry)) {
+ // - Try to forward the interest
+ int rc =
+ forwarder_forward_via_fib(forwarder, interest_msgbuf_id, verdict, entry);
+ if (!rc) {
+ // - Not able to forward, drop the packet
forwarder->stats.countDroppedNoRoute++;
INFO("Message %lu did not match FIB, no route (count %u)",
interest_msgbuf_id, forwarder->stats.countDroppedNoRoute);
- // - Drop the packet (no forwarding)
forwarder_drop(forwarder, interest_msgbuf_id);
+ return -1;
}
return msgbuf_get_len(msgbuf);
@@ -590,19 +558,12 @@ ssize_t _forwarder_forward_upon_interest(forwarder_t *forwarder,
static void _forwarder_update_interest_stats(forwarder_t *forwarder,
pkt_cache_verdict_t verdict,
msgbuf_t *msgbuf,
- pkt_cache_entry_t *entry) {
- long expiration = -1;
- if (entry == NULL)
- expiration = ticks_now() + msgbuf_get_interest_lifetime(msgbuf);
- else if (entry->has_expire_ts)
- expiration = entry->expire_ts;
-
+ bool has_expire_ts,
+ uint64_t expire_ts) {
+ long expiration = has_expire_ts ? expire_ts : -1;
switch (verdict) {
case PKT_CACHE_VERDICT_FORWARD_INTEREST:
- DEBUG(
- "Message will be added to PIT (expiration=%ld), "
- "if nexthops are available",
- expiration);
+ DEBUG("Message added to PIT (expiration=%ld)", expiration);
break;
case PKT_CACHE_VERDICT_AGGREGATE_INTEREST:
@@ -632,7 +593,7 @@ static void _forwarder_update_interest_stats(forwarder_t *forwarder,
break;
case PKT_CACHE_VERDICT_ERROR:
- ERROR("Inivalid packet cache content");
+ ERROR("Invalid packet cache content");
break;
default:
@@ -640,6 +601,234 @@ static void _forwarder_update_interest_stats(forwarder_t *forwarder,
}
}
+static interest_manifest_header_t *_forwarder_get_interest_manifest(
+ msgbuf_t *msgbuf) {
+ uint8_t *packet = msgbuf_get_packet(msgbuf);
+ hicn_header_t *header = (hicn_header_t *)packet;
+ hicn_type_t type = hicn_header_to_type(header);
+
+ hicn_payload_type_t payload_type;
+ int rc = hicn_ops_vft[type.l1]->get_payload_type(type, &header->protocol,
+ &payload_type);
+ _ASSERT(rc == HICN_LIB_ERROR_NONE);
+ if (payload_type != HPT_MANIFEST) return NULL;
+
+ size_t header_length, payload_length;
+ rc = hicn_ops_vft[type.l1]->get_header_length(type, &header->protocol,
+ &header_length);
+ assert(rc == HICN_LIB_ERROR_NONE);
+
+ rc = hicn_ops_vft[type.l1]->get_payload_length(type, &header->protocol,
+ &payload_length);
+ assert(rc == HICN_LIB_ERROR_NONE);
+
+ u8 *payload = (u8 *)header + header_length;
+ interest_manifest_header_t *int_manifest_header =
+ (interest_manifest_header_t *)payload;
+ if (!interest_manifest_is_valid(int_manifest_header, payload_length))
+ return NULL;
+
+ return int_manifest_header;
+}
+
+// Manifest is split using splitting strategy, then every
+// sub-manifest is sent using the forwarding strategy defined for the prefix
+int _forwarder_forward_aggregated_interest(
+ forwarder_t *forwarder, interest_manifest_header_t *int_manifest_header,
+ int n_suffixes_to_fwd, msgbuf_t *msgbuf, off_t msgbuf_id,
+ pkt_cache_entry_t **entries) {
+ assert(msgbuf_id_is_valid(msgbuf_id) &&
+ msgbuf_get_type(msgbuf) == MSGBUF_TYPE_INTEREST);
+
+ fib_entry_t *fib_entry = fib_match_message(forwarder->fib, msgbuf);
+ if (!fib_entry) return -1;
+
+ int n_suffixes_per_split = N_SUFFIXES_PER_SPIT;
+ switch (disaggregation_strategy) {
+ case INT_MANIFEST_SPLIT_NONE:
+ n_suffixes_per_split = int_manifest_header->n_suffixes + 1;
+
+ case INT_MANIFEST_SPLIT_MAX_N_SUFFIXES: {
+ // Generate sub-manifests: same as original manifest,
+ // but different suffix in the header and different bitmap
+
+ int total_len = 0;
+ // Suffixes in manifest plus the one in the header
+ int total_suffixes = int_manifest_header->n_suffixes + 1;
+
+ // Save copy of original bitmap to use as a reference
+ // to generate bitmaps for sub-manifests
+ u32 original_bitmap[BITMAP_SIZE] = {0};
+ memcpy(&original_bitmap, int_manifest_header->request_bitmap,
+ BITMAP_SIZE * sizeof(u32));
+
+ int suffix_index = 0; // Position of suffix in initial manifest
+ while (suffix_index < total_suffixes) {
+ // If more than one sub-manifest,
+ // clone original interest manifest and update suffix
+ if (suffix_index > 0) {
+ msgbuf_t *clone;
+ off_t clone_id =
+ msgbuf_pool_clone(forwarder->msgbuf_pool, &clone, msgbuf_id);
+ msgbuf_pool_acquire(clone);
+ forwarder_acquired_msgbuf_ids_push(forwarder, clone_id);
+
+ msgbuf_id = clone_id;
+ msgbuf = clone;
+ }
+
+ u32 curr_bitmap[BITMAP_SIZE] = {0};
+ int first_suffix_index_in_submanifest = suffix_index;
+ suffix_index = interest_manifest_update_bitmap(
+ original_bitmap, curr_bitmap, suffix_index, total_suffixes,
+ n_suffixes_per_split);
+ int first_suffix_index_in_next_submanifest = suffix_index;
+
+ // Update manifest bitmap in current msgbuf
+ interest_manifest_header_t *manifest =
+ _forwarder_get_interest_manifest(msgbuf);
+ assert(manifest != NULL);
+ memcpy(manifest->request_bitmap, curr_bitmap,
+ BITMAP_SIZE * sizeof(u32));
+ WITH_TRACE({
+ bitmap_print(manifest->request_bitmap, BITMAP_SIZE);
+ printf("\n");
+ });
+
+ // Update PIT entries for suffixes in current sub-manifest
+ nexthops_t *nexthops =
+ fib_entry_get_nexthops_from_strategy(fib_entry, msgbuf, false);
+ if (nexthops_get_curlen(nexthops) == 0) return -1;
+
+ for (int i = first_suffix_index_in_submanifest;
+ i < first_suffix_index_in_next_submanifest; i++) {
+ if (!is_bit_set(manifest->request_bitmap, i)) continue;
+
+ pit_entry_t *pit_entry = &(entries[i]->u.pit_entry);
+ if (!pit_entry) return -1;
+
+ pit_entry_set_fib_entry(pit_entry, fib_entry);
+ unsigned nexthop;
+ nexthops_foreach(nexthops, nexthop,
+ { pit_entry_egress_add(pit_entry, nexthop); });
+ }
+
+ if (forwarder_forward_to_nexthops(forwarder, msgbuf_id, nexthops) <=
+ 0) {
+ ERROR("Message %p returned an empty next hop set", msgbuf);
+ continue;
+ }
+
+ total_len += msgbuf_get_len(msgbuf);
+ }
+
+ return total_len;
+ }
+
+ default:
+ return -1;
+ }
+}
+
+static ssize_t forwarder_process_single_interest(forwarder_t *forwarder,
+ msgbuf_pool_t *msgbuf_pool,
+ msgbuf_t *msgbuf,
+ off_t msgbuf_id) {
+ pkt_cache_verdict_t verdict = PKT_CACHE_VERDICT_ERROR;
+ off_t data_msgbuf_id = INVALID_MSGBUF_ID;
+ pkt_cache_entry_t *entry = NULL;
+
+ // Update packet cache
+ pkt_cache_on_interest(forwarder->pkt_cache, msgbuf_pool, msgbuf_id, &verdict,
+ &data_msgbuf_id, &entry, msgbuf_get_name(msgbuf),
+ forwarder->serve_from_cs);
+ _forwarder_update_interest_stats(forwarder, verdict, msgbuf,
+ entry->has_expire_ts, entry->expire_ts);
+
+ int rc = _forwarder_forward_upon_interest(
+ forwarder, msgbuf_pool, data_msgbuf_id, msgbuf_id, entry, verdict, false);
+
+ // No route when trying to forward interest, remove from PIT
+ if (rc == -1)
+ pkt_cache_pit_remove_entry(forwarder->pkt_cache, entry,
+ msgbuf_get_name(msgbuf));
+
+ return msgbuf_get_len(msgbuf);
+}
+
+static ssize_t forwarder_process_aggregated_interest(
+ forwarder_t *forwarder, interest_manifest_header_t *int_manifest_header,
+ msgbuf_pool_t *msgbuf_pool, msgbuf_t *msgbuf, off_t msgbuf_id) {
+ pkt_cache_verdict_t verdict = PKT_CACHE_VERDICT_ERROR;
+ off_t data_msgbuf_id = INVALID_MSGBUF_ID;
+ pkt_cache_entry_t *entry = NULL;
+ // Save PIT entries to avoid re-doing pkt cache lookup in
+ // `_forwarder_forward_aggregated_interest()`
+ pkt_cache_entry_t *entries[BITMAP_SIZE * WORD_WIDTH];
+
+ int pos = 0; // Position of current suffix in manifest
+ int n_suffixes_to_fwd = 0;
+ u32 *suffix = (u32 *)(int_manifest_header + 1);
+ u32 seq = name_GetSegment(msgbuf_get_name(msgbuf));
+
+ Name name_copy = EMPTY_NAME;
+ name_Copy(msgbuf_get_name(msgbuf), &name_copy);
+
+ // The fist loop iteration handles the suffix in the header,
+ // the following ones handle the suffiexes in the manifest
+ while (true) {
+ if (!is_bit_set(int_manifest_header->request_bitmap, pos)) goto NEXT_SUFFIX;
+
+ // Update packet cache
+ pkt_cache_on_interest(forwarder->pkt_cache, msgbuf_pool, msgbuf_id,
+ &verdict, &data_msgbuf_id, &entry, &name_copy,
+ forwarder->serve_from_cs);
+ entries[pos] = entry;
+ _forwarder_update_interest_stats(forwarder, verdict, msgbuf,
+ entry->has_expire_ts, entry->expire_ts);
+
+ // Here only data forwarding is performed, interest forwarding is done
+ // in '_forwarder_forward_aggregated_interest()'
+ int rc =
+ _forwarder_forward_upon_interest(forwarder, msgbuf_pool, data_msgbuf_id,
+ msgbuf_id, entry, verdict, true);
+
+ // No route when trying to forward interest, remove from PIT
+ if (rc == -1)
+ pkt_cache_pit_remove_entry(forwarder->pkt_cache, entry, &name_copy);
+
+ // Unset in bitmap if no interest forwarding needed,
+ // otherwise increase count of suffixes to forward
+ if (rc == -1 || verdict == PKT_CACHE_VERDICT_AGGREGATE_INTEREST ||
+ verdict == PKT_CACHE_VERDICT_FORWARD_DATA) {
+ unset_bit(int_manifest_header->request_bitmap, pos);
+ } else {
+ n_suffixes_to_fwd++;
+ }
+
+ NEXT_SUFFIX:
+ if (pos++ >= int_manifest_header->n_suffixes) break;
+
+ // Use next segment in manifest
+ seq = *suffix;
+ suffix++;
+ name_SetSegment(&name_copy, seq);
+
+ WITH_DEBUG({
+ char *nameString = name_ToString(&name_copy);
+ DEBUG("Next in manifest: %s", nameString);
+ free(nameString);
+ });
+ }
+
+ // Return if nothing in the manifest to forward
+ if (n_suffixes_to_fwd == 0) return msgbuf_get_len(msgbuf);
+
+ return _forwarder_forward_aggregated_interest(forwarder, int_manifest_header,
+ n_suffixes_to_fwd, msgbuf,
+ msgbuf_id, entries);
+}
+
/**
* @function forwarder_process_interest
* @abstract Receive an interest from the network
@@ -657,29 +846,39 @@ static ssize_t forwarder_process_interest(forwarder_t *forwarder,
msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder);
msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id);
+ const connection_table_t *table = forwarder_get_connection_table(forwarder);
+ connection_t *conn =
+ connection_table_get_by_id(table, msgbuf_get_connection_id(msgbuf));
assert(msgbuf_get_type(msgbuf) == MSGBUF_TYPE_INTEREST);
- forwarder->stats.countReceived++;
+ u32 n_suffixes = 0;
+ interest_manifest_header_t *int_manifest_header =
+ _forwarder_get_interest_manifest(msgbuf);
+ if (int_manifest_header) n_suffixes = int_manifest_header->n_suffixes;
+
+ // Update stats
forwarder->stats.countInterestsReceived++;
+ conn->stats.interests.rx_pkts++;
+ conn->stats.interests.rx_bytes += msgbuf_get_len(msgbuf);
WITH_DEBUG({
char *nameString = name_ToString(msgbuf_get_name(msgbuf));
- DEBUG("INTEREST (%s) msgbuf_id=%lu ingress=%u length=%u", nameString,
- msgbuf_id, msgbuf_get_connection_id(msgbuf), msgbuf_get_len(msgbuf));
+ DEBUG("INTEREST (%s) suffixes=%u msgbuf_id=%lu ingress=%u length=%u",
+ nameString, n_suffixes, msgbuf_id, msgbuf_get_connection_id(msgbuf),
+ msgbuf_get_len(msgbuf));
free(nameString);
- })
-
- pkt_cache_verdict_t verdict = PKT_CACHE_VERDICT_ERROR;
- off_t data_msgbuf_id = INVALID_MSGBUF_ID;
- pkt_cache_entry_t *entry = NULL;
- pkt_cache_on_interest(forwarder->pkt_cache, msgbuf_pool, msgbuf_id, &verdict,
- &data_msgbuf_id, &entry, forwarder->serve_from_cs);
+ });
- _forwarder_update_interest_stats(forwarder, verdict, msgbuf, entry);
+ // Cache suffixes for current prefix to (possibly) avoid double lookups
+ pkt_cache_save_suffixes_for_prefix(
+ forwarder->pkt_cache, name_GetContentName(msgbuf_get_name(msgbuf)));
- return _forwarder_forward_upon_interest(
- forwarder, msgbuf_pool, data_msgbuf_id, msgbuf_id, entry, verdict);
+ if (!int_manifest_header)
+ return forwarder_process_single_interest(forwarder, msgbuf_pool, msgbuf,
+ msgbuf_id);
+ return forwarder_process_aggregated_interest(forwarder, int_manifest_header,
+ msgbuf_pool, msgbuf, msgbuf_id);
}
static void _forwarder_log_on_data(forwarder_t *forwarder,
@@ -700,7 +899,7 @@ static void _forwarder_log_on_data(forwarder_t *forwarder,
DEBUG("Message not stored in CS");
break;
case PKT_CACHE_VERDICT_ERROR:
- ERROR("Inivalid packet cache content");
+ ERROR("Invalid packet cache content");
break;
default:
break;
@@ -726,24 +925,31 @@ static ssize_t forwarder_process_data(forwarder_t *forwarder, off_t msgbuf_id) {
DEBUG("DATA (%s) msgbuf_id=%lu ingress=%u length=%u", nameString, msgbuf_id,
msgbuf_get_connection_id(msgbuf), msgbuf_get_len(msgbuf));
free(nameString);
- )}
-
- forwarder->stats.countReceived++;
- forwarder->stats.countObjectsReceived++;
+ });
const connection_table_t *table = forwarder_get_connection_table(forwarder);
- const connection_t *conn =
+ connection_t *conn =
connection_table_get_by_id(table, msgbuf_get_connection_id(msgbuf));
+ // Update stats
+ forwarder->stats.countObjectsReceived++;
+ conn->stats.data.rx_pkts++;
+ conn->stats.data.rx_bytes += msgbuf_get_len(msgbuf);
+
+ // Cache suffixes for current prefix to (possibly) avoid double lookups
+ pkt_cache_save_suffixes_for_prefix(
+ forwarder->pkt_cache, name_GetContentName(msgbuf_get_name(msgbuf)));
+
pkt_cache_verdict_t verdict = PKT_CACHE_VERDICT_ERROR;
bool wrong_egress;
- nexthops_t *ingressSetUnion =
- pkt_cache_on_data(forwarder->pkt_cache, msgbuf_pool, msgbuf_id,
- forwarder->store_in_cs, connection_is_local(conn), &wrong_egress, &verdict);
+ nexthops_t *ingressSetUnion = pkt_cache_on_data(
+ forwarder->pkt_cache, msgbuf_pool, msgbuf_id, forwarder->store_in_cs,
+ connection_is_local(conn), &wrong_egress, &verdict);
_forwarder_log_on_data(forwarder, verdict);
- if (wrong_egress) { // Interest sent via a connection but received from another
+ if (wrong_egress) { // Interest sent via a connection but received from
+ // another
WARN("Data coming from unexpected connection, discarded");
} else if (!ingressSetUnion) { // No match in the PIT
forwarder->stats.countDroppedNoReversePath++;
@@ -776,15 +982,15 @@ void forwarder_flush_connections(forwarder_t *forwarder) {
// DEBUG("[forwarder_flush_connections]");
const connection_table_t *table = forwarder_get_connection_table(forwarder);
- for (unsigned i = 0; i < forwarder->num_pending_conn; i++) {
+ for (unsigned i = 0; i < vector_len(forwarder->pending_conn); i++) {
unsigned conn_id = forwarder->pending_conn[i];
- const connection_t *conn = connection_table_at(table, conn_id);
+ connection_t *conn = connection_table_at(table, conn_id);
if (!connection_flush(conn)) {
WARN("Could not flush connection queue");
// XXX keep track of non flushed connections...
}
}
- forwarder->num_pending_conn = 0;
+ vector_reset(forwarder->pending_conn);
// DEBUG("[forwarder_flush_connections] done");
}
@@ -957,6 +1163,23 @@ cs_t *forwarder_get_cs(const forwarder_t *forwarder) {
return pkt_cache_get_cs(forwarder->pkt_cache);
}
+// IMPORTANT: Use this function ONLY for read-only operations since a realloc
+// would otherwise modify the returned copy but not the original msgbuf ids
+// vector in the forwarder. This constraint cannot be enforced by returning a
+// (const off_t *) because the vector_t macros still cast to (void **).
+off_t *forwarder_get_acquired_msgbuf_ids(const forwarder_t *forwarder) {
+ return forwarder->acquired_msgbuf_ids;
+}
+
+void forwarder_acquired_msgbuf_ids_reset(const forwarder_t *forwarder) {
+ vector_reset(forwarder->acquired_msgbuf_ids);
+}
+
+void forwarder_acquired_msgbuf_ids_push(const forwarder_t *forwarder,
+ off_t msgbuf_id) {
+ vector_push(forwarder->acquired_msgbuf_ids, msgbuf_id);
+}
+
// =======================================================
fib_t *forwarder_get_fib(forwarder_t *forwarder) { return forwarder->fib; }
@@ -1052,14 +1275,15 @@ ssize_t forwarder_receive(forwarder_t *forwarder, listener_t *listener,
const connection_table_t *table =
forwarder_get_connection_table(listener->forwarder);
connection_t *connection = connection_table_get_by_pair(table, pair);
- unsigned conn_id = connection
- ? connection_table_get_connection_id(table, connection)
- : CONNECTION_ID_UNDEFINED;
+ unsigned conn_id = connection ? (unsigned)connection_table_get_connection_id(
+ table, connection)
+ : CONNECTION_ID_UNDEFINED;
assert((conn_id != CONNECTION_ID_UNDEFINED) || listener);
msgbuf_type_t type = get_type_from_packet(msgbuf_get_packet(msgbuf));
+ forwarder->stats.countReceived++;
msgbuf->type = type;
msgbuf->connection_id = conn_id;
msgbuf->recv_ts = now;
@@ -1067,12 +1291,14 @@ ssize_t forwarder_receive(forwarder_t *forwarder, listener_t *listener,
switch (type) {
case MSGBUF_TYPE_INTEREST:
if (!connection_id_is_valid(msgbuf->connection_id)) {
- char *conn_name = connection_table_get_random_name(table);
+ char conn_name[SYMBOLIC_NAME_LEN];
+ int rc = connection_table_get_random_name(table, conn_name);
+ if (rc < 0) return 0;
+
unsigned connection_id =
listener_create_connection(listener, conn_name, pair);
msgbuf->connection_id = connection_id;
connection = connection_table_get_by_id(table, connection_id);
- free(conn_name);
}
msgbuf->path_label = 0; // not used for interest packets
name_create_from_interest(packet, msgbuf_get_name(msgbuf));
@@ -1102,10 +1328,12 @@ ssize_t forwarder_receive(forwarder_t *forwarder, listener_t *listener,
case MSGBUF_TYPE_MAPME:
// XXX what about acks ?
if (!connection_id_is_valid(msgbuf->connection_id)) {
- char *conn_name = connection_table_get_random_name(table);
+ char conn_name[SYMBOLIC_NAME_LEN];
+ int rc = connection_table_get_random_name(table, conn_name);
+ if (rc < 0) return 0;
+
msgbuf->connection_id =
listener_create_connection(listener, conn_name, pair);
- free(conn_name);
}
mapme_process(forwarder->mapme, msgbuf);
return size;
@@ -1113,12 +1341,14 @@ ssize_t forwarder_receive(forwarder_t *forwarder, listener_t *listener,
case MSGBUF_TYPE_COMMAND:
// Create the connection to send the ack back
if (!connection_id_is_valid(msgbuf->connection_id)) {
- char *conn_name = connection_table_get_random_name(table);
+ char conn_name[SYMBOLIC_NAME_LEN];
+ int rc = connection_table_get_random_name(table, conn_name);
+ if (rc < 0) return 0;
+
unsigned connection_id =
listener_create_connection(listener, conn_name, pair);
msgbuf->connection_id = connection_id;
connection = connection_table_get_by_id(table, connection_id);
- free(conn_name);
}
msg_header_t *msg = (msg_header_t *)packet;
@@ -1163,3 +1393,7 @@ void forwarder_log(forwarder_t *forwarder) {
forwarder->stats.countInterestsExpired, forwarder->stats.countDataExpired,
forwarder->stats.countDroppedNoReversePath);
}
+
+forwarder_stats_t forwarder_get_stats(forwarder_t *forwarder) {
+ return forwarder->stats;
+} \ No newline at end of file
diff --git a/hicn-light/src/hicn/core/forwarder.h b/hicn-light/src/hicn/core/forwarder.h
index 76c12368a..2f940cf15 100644
--- a/hicn-light/src/hicn/core/forwarder.h
+++ b/hicn-light/src/hicn/core/forwarder.h
@@ -98,6 +98,8 @@ listener_table_t *forwarder_get_listener_table(forwarder_t *forwarder);
connection_table_t *forwarder_get_connection_table(
const forwarder_t *forwarder);
+pkt_cache_t *forwarder_get_pkt_cache(const forwarder_t *forwarder);
+
void forwarder_cs_set_store(forwarder_t *forwarder, bool val);
bool forwarder_cs_get_store(forwarder_t *forwarder);
@@ -159,6 +161,18 @@ void forwarder_set_strategy(forwarder_t *forwarder, Name *name_prefix,
cs_t *forwarder_get_cs(const forwarder_t *forwarder);
+off_t *forwarder_get_acquired_msgbuf_ids(const forwarder_t *forwarder);
+
+/**
+ * @note Acquire msgbuf ids vector ONLY for read-only operations.
+ */
+off_t *forwarder_get_acquired_msgbuf_ids(const forwarder_t *forwarder);
+
+void forwarder_acquired_msgbuf_ids_reset(const forwarder_t *forwarder);
+
+void forwarder_acquired_msgbuf_ids_push(const forwarder_t *forwarder,
+ off_t msgbuf_id);
+
/**
* @brief Returns the forwarder's FIB.
* @param[in] forwarder - Pointer to the forwarder.
@@ -226,4 +240,6 @@ ssize_t forwarder_receive(forwarder_t *forwarder, listener_t *listener,
*/
void forwarder_log(forwarder_t *forwarder);
+forwarder_stats_t forwarder_get_stats(forwarder_t *forwarder);
+
#endif // HICNLIGHT_FORWARDER_H
diff --git a/hicn-light/src/hicn/core/interest_manifest.c b/hicn-light/src/hicn/core/interest_manifest.c
new file mode 100644
index 000000000..1be8a3fb5
--- /dev/null
+++ b/hicn-light/src/hicn/core/interest_manifest.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2022 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "interest_manifest.h"
+
+int_manifest_split_strategy_t disaggregation_strategy =
+ INT_MANIFEST_SPLIT_MAX_N_SUFFIXES;
+unsigned N_SUFFIXES_PER_SPIT = 256;
+
+bool interest_manifest_is_valid(interest_manifest_header_t *int_manifest_header,
+ size_t payload_length) {
+ if (int_manifest_header->n_suffixes == 0 ||
+ int_manifest_header->n_suffixes > MAX_SUFFIXES_IN_MANIFEST) {
+ ERROR("Manifest with invalid number of suffixes (%d)",
+ int_manifest_header->n_suffixes);
+ return false;
+ }
+
+ uint32_t empty_bitmap[BITMAP_SIZE] = {0};
+ if (memcmp(empty_bitmap, int_manifest_header->request_bitmap,
+ sizeof(empty_bitmap)) == 0) {
+ ERROR("Manifest with empty bitmap");
+ return false;
+ }
+
+ if (payload_length - sizeof(interest_manifest_header_t) !=
+ int_manifest_header->n_suffixes * sizeof(u32)) {
+ ERROR("Size of suffixes in intereset manifest (%d) is not equal to %d",
+ payload_length - sizeof(interest_manifest_header_t),
+ int_manifest_header->n_suffixes * sizeof(u32));
+ return false;
+ }
+
+ return true;
+}
+
+int interest_manifest_update_bitmap(const u32 *initial_bitmap,
+ u32 *bitmap_to_update, int start, int n,
+ int max_suffixes) {
+ int i = start, n_ones = 0;
+ while (i < n) {
+ if (is_bit_set(initial_bitmap, i)) {
+ set_bit(bitmap_to_update, i);
+ n_ones++;
+ }
+ i++;
+
+ if (n_ones == max_suffixes) break;
+ }
+
+ return i;
+}
diff --git a/hicn-light/src/hicn/core/interest_manifest.h b/hicn-light/src/hicn/core/interest_manifest.h
new file mode 100644
index 000000000..fcb2b9897
--- /dev/null
+++ b/hicn-light/src/hicn/core/interest_manifest.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HICNLIGHT_INTEREST_MANIFEST_H
+#define HICNLIGHT_INTEREST_MANIFEST_H
+
+#include <string.h>
+#include <stdbool.h>
+
+#include <hicn/util/log.h>
+#include <hicn/base.h>
+
+typedef enum {
+ INT_MANIFEST_SPLIT_NONE,
+ INT_MANIFEST_SPLIT_MAX_N_SUFFIXES
+} int_manifest_split_strategy_t;
+
+extern int_manifest_split_strategy_t disaggregation_strategy;
+extern unsigned N_SUFFIXES_PER_SPIT;
+
+bool interest_manifest_is_valid(interest_manifest_header_t *int_manifest_header,
+ size_t payload_length);
+
+int interest_manifest_update_bitmap(const u32 *initial_bitmap,
+ u32 *bitmap_to_update, int start, int n,
+ int max_suffixes);
+
+#endif /* HICNLIGHT_INTEREST_MANIFEST_H */
diff --git a/hicn-light/src/hicn/core/listener.c b/hicn-light/src/hicn/core/listener.c
index ecdfc38f4..188f0c317 100644
--- a/hicn-light/src/hicn/core/listener.c
+++ b/hicn-light/src/hicn/core/listener.c
@@ -24,7 +24,6 @@
#include "forwarder.h"
#include "listener_vft.h"
-#include "../base/loop.h"
#include "../io/base.h"
listener_key_t listener_key_factory(address_t address, face_type_t type) {
@@ -44,7 +43,8 @@ listener_t *listener_create(face_type_t type, const address_t *address,
listener_key_t key = listener_key_factory(*address, type);
listener_t *listener = listener_table_allocate(table, &key, name);
- unsigned listener_id = listener_table_get_listener_id(table, listener);
+ unsigned listener_id =
+ (unsigned int)listener_table_get_listener_id(table, listener);
int ret = listener_initialize(listener, type, name, listener_id, address,
interface_name, forwarder);
@@ -194,7 +194,7 @@ unsigned listener_create_connection(listener_t *listener,
connection_t *connection =
connection_table_allocate(table, pair, connection_name);
unsigned connection_id =
- connection_table_get_connection_id(table, connection);
+ (unsigned int)connection_table_get_connection_id(table, connection);
/*
* We create a connected connection with its own fd, instead of returning
@@ -337,11 +337,10 @@ ssize_t listener_read_batch(listener_t *listener, int fd) {
size_t total_processed_bytes = 0;
ssize_t num_msg_received = 0;
- off_t *acquired_msgbuf_ids;
- vector_init(acquired_msgbuf_ids, MAX_MSG, 0);
forwarder_t *forwarder = listener->forwarder;
msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder);
+ forwarder_acquired_msgbuf_ids_reset(forwarder);
/* Receive messages in the loop as long as we manage to fill the buffers */
do {
@@ -381,7 +380,7 @@ ssize_t listener_read_batch(listener_t *listener, int fd) {
}
msgbuf_pool_acquire(msgbufs[i]);
- vector_push(acquired_msgbuf_ids, msgbuf_ids[i]);
+ forwarder_acquired_msgbuf_ids_push(forwarder, msgbuf_ids[i]);
}
if (num_msg_received < 0) break;
@@ -403,11 +402,12 @@ ssize_t listener_read_batch(listener_t *listener, int fd) {
*/
forwarder_flush_connections(forwarder);
+ const off_t *acquired_msgbuf_ids =
+ forwarder_get_acquired_msgbuf_ids(forwarder);
for (int i = 0; i < vector_len(acquired_msgbuf_ids); i++) {
msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, acquired_msgbuf_ids[i]);
msgbuf_pool_release(msgbuf_pool, &msgbuf);
}
- vector_free(acquired_msgbuf_ids);
return total_processed_bytes;
}
diff --git a/hicn-light/src/hicn/core/listener.h b/hicn-light/src/hicn/core/listener.h
index 346c874c0..5d0384329 100644
--- a/hicn-light/src/hicn/core/listener.h
+++ b/hicn-light/src/hicn/core/listener.h
@@ -25,7 +25,7 @@
#include "address_pair.h"
#include "msgbuf.h"
-#include "../base/loop.h"
+#include <hicn/base/loop.h>
#define LISTENER_ID_UNDEFINED ~0
@@ -36,6 +36,12 @@ typedef struct {
face_type_t type;
} listener_key_t;
+static inline int listener_key_equals(const listener_key_t *key1,
+ const listener_key_t *key2) {
+ return address_equals(&key1->address, &key2->address) &&
+ (key1->type == key2->type);
+}
+
/**
* @brief Create a listener key starting from an address and a face type.
*
diff --git a/hicn-light/src/hicn/core/listener_table.c b/hicn-light/src/hicn/core/listener_table.c
index 32b8e9d45..220b738bb 100644
--- a/hicn-light/src/hicn/core/listener_table.c
+++ b/hicn-light/src/hicn/core/listener_table.c
@@ -72,6 +72,54 @@ void listener_table_free(listener_table_t *table) {
free(table);
}
+listener_t *listener_table_allocate(const listener_table_t *table,
+ const listener_key_t *key,
+ const char *name) {
+ listener_t *listener = NULL;
+ pool_get(table->listeners, listener);
+ if (!listener) return NULL;
+
+ off_t id = listener - table->listeners;
+ int rc;
+
+ // Add in name hash table
+ khiter_t k = kh_put_lt_name(table->id_by_name, strdup(name), &rc);
+ assert(rc == KH_ADDED || rc == KH_RESET);
+ kh_value(table->id_by_name, k) = (unsigned int)id;
+
+ // Add in key hash table
+ listener_key_t *key_copy = (listener_key_t *)malloc(sizeof(listener_key_t));
+ memcpy(key_copy, key, sizeof(listener_key_t));
+
+ k = kh_put_lt_key(table->id_by_key, key_copy, &rc);
+ assert(rc == KH_ADDED || rc == KH_RESET);
+ kh_value(table->id_by_key, k) = (unsigned int)id;
+
+ assert(kh_size(table->id_by_name) == kh_size(table->id_by_key));
+ return listener;
+}
+
+void listener_table_deallocate(const listener_table_t *table,
+ listener_t *listener) {
+ const char *name = listener_get_name(listener);
+ listener_key_t *key = listener_get_key(listener);
+
+ // Remove from name hash table
+ khiter_t k = kh_get_lt_name(table->id_by_name, name);
+ assert(k != kh_end(table->id_by_name));
+ free((char *)kh_key(table->id_by_name, k));
+ kh_del_lt_name(table->id_by_name, k);
+
+ // Remove from key hash table
+ k = kh_get_lt_key(table->id_by_key, key);
+ assert(k != kh_end(table->id_by_key));
+ free((listener_key_t *)kh_key(table->id_by_key, k));
+ kh_del_lt_key(table->id_by_key, k);
+
+ assert(kh_size(table->id_by_name) == kh_size(table->id_by_key));
+ pool_put(table->listeners, listener);
+}
+
listener_t *listener_table_get_by_address(listener_table_t *table,
face_type_t type,
const address_t *address) {
@@ -104,7 +152,8 @@ off_t listener_table_get_id_by_name(const listener_table_t *table,
listener_t *listener_table_get_by_name(listener_table_t *table,
const char *name) {
- unsigned listener_id = listener_table_get_id_by_name(table, name);
+ unsigned listener_id =
+ (unsigned int)listener_table_get_id_by_name(table, name);
if (!listener_id_is_valid(listener_id)) return NULL;
return listener_table_at(table, listener_id);
}
diff --git a/hicn-light/src/hicn/core/listener_table.h b/hicn-light/src/hicn/core/listener_table.h
index 5fed638e8..7e2e99d7f 100644
--- a/hicn-light/src/hicn/core/listener_table.h
+++ b/hicn-light/src/hicn/core/listener_table.h
@@ -30,22 +30,19 @@
#ifndef HICNLIGHT_LISTENER_TABLE_H
#define HICNLIGHT_LISTENER_TABLE_H
+#include <hicn/util/khash.h>
+#include <hicn/util/hash.h>
#include "address.h"
#include "listener.h"
-#include "../base/common.h"
-#include "../base/hash.h"
-#include "../base/khash.h"
-#include "../base/pool.h"
-
-#define _lt_var(x) _lt_var_##x
+#include <hicn/util/pool.h>
/* Hash functions for indices */
#define key_hash(key) (hash_struct(key))
-#define key_hash_eq(a, b) (key_hash(b) == key_hash(a))
/* Hash table types for indices */
KHASH_MAP_INIT_STR(lt_name, unsigned);
-KHASH_INIT(lt_key, const listener_key_t *, unsigned, 1, key_hash, key_hash_eq);
+KHASH_INIT(lt_key, const listener_key_t *, unsigned, 1, key_hash,
+ listener_key_equals);
typedef struct {
size_t max_size;
@@ -70,34 +67,9 @@ typedef struct {
* - You should always check that the returned listener is not NULL, which
* would signal that the pool is exhausted and could not be extended.
*/
-
-static inline listener_t *listener_table_allocate(const listener_table_t *table,
- const listener_key_t *key,
- const char *name) {
- listener_t *listener;
- pool_get(table->listeners, listener);
-
- if (listener) {
- off_t id = listener - table->listeners;
- int res;
- khiter_t k;
-
- // Add in name hash table
- k = kh_put_lt_name(table->id_by_name, strdup(name), &res);
- assert(res > 0);
- kh_value(table->id_by_name, k) = id;
-
- // Add in key hash table
- listener_key_t *key_copy = (listener_key_t *)malloc(sizeof(listener_key_t));
- memcpy(key_copy, key, sizeof(listener_key_t));
-
- k = kh_put_lt_key(table->id_by_key, key_copy, &res);
- assert(res > 0);
- kh_value(table->id_by_key, k) = id;
- }
-
- return listener;
-}
+listener_t *listener_table_allocate(const listener_table_t *table,
+ const listener_key_t *key,
+ const char *name);
/**
* @brief Deallocate a listener and return it to the listener table pool.
@@ -109,27 +81,8 @@ static inline listener_t *listener_table_allocate(const listener_table_t *table,
* - Upon returning a listener to the pool, all indices pointing to that
* listener are also cleared.
*/
-
-static inline void listener_table_deallocate(const listener_table_t *table,
- listener_t *listener) {
- const char *name = listener_get_name(listener);
- listener_key_t *key = listener_get_key(listener);
- khiter_t k;
-
- // Remove from name hash table
- k = kh_get_lt_name(table->id_by_name, name);
- assert(k != kh_end(table->id_by_name));
- free((char *)kh_key(table->id_by_name, k));
- kh_del_lt_name(table->id_by_name, k);
-
- // Remove from key hash table
- k = kh_get_lt_key(table->id_by_key, key);
- assert(k != kh_end(table->id_by_key));
- free((listener_key_t *)kh_key(table->id_by_key, k));
- kh_del_lt_key(table->id_by_key, k);
-
- pool_put(table->listeners, listener);
-}
+void listener_table_deallocate(const listener_table_t *table,
+ listener_t *listener);
/**
* @brief Returns the length of the listener table, the number of active
diff --git a/hicn-light/src/hicn/core/msgbuf_pool.c b/hicn-light/src/hicn/core/msgbuf_pool.c
index fb5d0a07c..a2092aaf6 100644
--- a/hicn-light/src/hicn/core/msgbuf_pool.c
+++ b/hicn-light/src/hicn/core/msgbuf_pool.c
@@ -18,9 +18,8 @@
* @brief Implementation of hICN packet pool.
*/
-#include "../base/pool.h"
+#include <hicn/util/pool.h>
#include "msgbuf_pool.h"
-#include "../core/name.h" // name_Release
msgbuf_pool_t *_msgbuf_pool_create(size_t init_size, size_t max_size) {
msgbuf_pool_t *msgbuf_pool = malloc(sizeof(msgbuf_pool_t));
@@ -38,7 +37,9 @@ void msgbuf_pool_free(msgbuf_pool_t *msgbuf_pool) {
}
off_t msgbuf_pool_get(msgbuf_pool_t *msgbuf_pool, msgbuf_t **msgbuf) {
- return pool_get(msgbuf_pool->buffers, *msgbuf);
+ off_t id = pool_get(msgbuf_pool->buffers, *msgbuf);
+ (*msgbuf)->refs = 0;
+ return id;
}
void msgbuf_pool_put(msgbuf_pool_t *msgbuf_pool, msgbuf_t *msgbuf) {
diff --git a/hicn-light/src/hicn/core/name.c b/hicn-light/src/hicn/core/name.c
index 8886cc929..d30cebefc 100644
--- a/hicn-light/src/hicn/core/name.c
+++ b/hicn-light/src/hicn/core/name.c
@@ -20,11 +20,10 @@
#include <stdio.h>
#include <string.h>
-#include <hicn/common.h> // cumulative_hash32
#include <hicn/core/messageHandler.h>
#include <hicn/core/name.h>
#include <hicn/util/log.h>
-#include <hicn/base/hash.h>
+#include <hicn/util/hash.h>
#define IPv6_TYPE 6
#define IPv4_TYPE 4
diff --git a/hicn-light/src/hicn/core/nameBitvector.c b/hicn-light/src/hicn/core/nameBitvector.c
index 1314671db..aa431879c 100644
--- a/hicn-light/src/hicn/core/nameBitvector.c
+++ b/hicn-light/src/hicn/core/nameBitvector.c
@@ -20,7 +20,7 @@
#include <hicn/core/messageHandler.h>
#include <hicn/core/nameBitvector.h>
-#include <hicn/base/hash.h>
+#include <hicn/util/hash.h>
#include <hicn/ctrl/hicn-light-ng.h>
#define DEFAULT_PORT 1234
diff --git a/hicn-light/src/hicn/core/nameBitvector.h b/hicn-light/src/hicn/core/nameBitvector.h
index e3cc108ac..549b26679 100644
--- a/hicn-light/src/hicn/core/nameBitvector.h
+++ b/hicn-light/src/hicn/core/nameBitvector.h
@@ -23,11 +23,13 @@
#include "address.h"
#define NAME_LEN 2
-typedef struct {
+typedef struct __attribute__((__packed__)) {
uint64_t bits[NAME_LEN];
- uint8_t len;
- uint8_t IPversion;
+ uint32_t len;
+ uint32_t IPversion;
} NameBitvector;
+static_assert(sizeof(NameBitvector) == 24,
+ "Name prefix should be stored on 24 bytes");
#define EMPTY_NAME_BITVECTOR \
(NameBitvector) { .bits[0] = 0, .bits[1] = 0, .len = 0, .IPversion = 0, }
diff --git a/hicn-light/src/hicn/core/packet_cache.c b/hicn-light/src/hicn/core/packet_cache.c
index 203ad4a63..8bd188c8b 100644
--- a/hicn-light/src/hicn/core/packet_cache.c
+++ b/hicn-light/src/hicn/core/packet_cache.c
@@ -20,6 +20,111 @@
#include "packet_cache.h"
+/******************************************************************************
+ * Low-level operations on the hash table
+ ******************************************************************************/
+
+void _prefix_map_free(kh_pkt_cache_prefix_t *prefix_to_suffixes) {
+ const NameBitvector *key;
+ kh_pkt_cache_suffix_t *value;
+ kh_foreach(prefix_to_suffixes, key, value, {
+ free((NameBitvector *)key);
+ kh_destroy_pkt_cache_suffix(value);
+ });
+ kh_destroy_pkt_cache_prefix(prefix_to_suffixes);
+}
+
+kh_pkt_cache_suffix_t *_get_suffixes(kh_pkt_cache_prefix_t *prefix_to_suffixes,
+ const NameBitvector *prefix) {
+ khiter_t k = kh_get_pkt_cache_prefix(prefix_to_suffixes, prefix);
+
+ // Return suffixes found
+ if (k != kh_end(prefix_to_suffixes)) {
+ kh_pkt_cache_suffix_t *suffixes = kh_val(prefix_to_suffixes, k);
+ return suffixes;
+ }
+
+ kh_pkt_cache_suffix_t *suffixes = kh_init_pkt_cache_suffix();
+ NameBitvector *nb_copy = (NameBitvector *)malloc(sizeof(NameBitvector));
+ *nb_copy = *prefix;
+
+ int rc;
+ k = kh_put_pkt_cache_prefix(prefix_to_suffixes, nb_copy, &rc);
+ assert(rc == KH_ADDED || rc == KH_RESET);
+ kh_value(prefix_to_suffixes, k) = suffixes;
+ return suffixes;
+}
+
+void _remove_suffix(kh_pkt_cache_prefix_t *prefixes,
+ const NameBitvector *prefix, uint32_t suffix) {
+ kh_pkt_cache_suffix_t *suffixes = _get_suffixes(prefixes, prefix);
+ assert(suffixes != NULL);
+
+ khiter_t k = kh_get_pkt_cache_suffix(suffixes, suffix);
+ assert(k != kh_end(suffixes));
+ kh_del_pkt_cache_suffix(suffixes, k);
+
+ // TODO(eloparco): Remove prefix if no associated suffixes?
+}
+
+void __add_suffix(kh_pkt_cache_suffix_t *suffixes, uint32_t suffix,
+ unsigned val) {
+ int rc;
+ khiter_t k = kh_put_pkt_cache_suffix(suffixes, suffix, &rc);
+ assert(rc == KH_ADDED || rc == KH_RESET);
+ kh_value(suffixes, k) = val;
+}
+
+void _add_suffix(kh_pkt_cache_prefix_t *prefixes, const NameBitvector *prefix,
+ uint32_t suffix, unsigned val) {
+ kh_pkt_cache_suffix_t *suffixes = _get_suffixes(prefixes, prefix);
+ assert(suffixes != NULL);
+
+ __add_suffix(suffixes, suffix, val);
+}
+
+unsigned __get_suffix(kh_pkt_cache_suffix_t *suffixes, uint32_t suffix,
+ int *rc) {
+ *rc = KH_FOUND;
+ khiter_t k = kh_get_pkt_cache_suffix(suffixes, suffix);
+
+ // Not Found
+ if (k == kh_end(suffixes)) {
+ *rc = KH_NOT_FOUND;
+ return -1;
+ }
+
+ unsigned index = kh_val(suffixes, k);
+ return index;
+}
+
+void pkt_cache_save_suffixes_for_prefix(pkt_cache_t *pkt_cache,
+ const NameBitvector *prefix) {
+ // Cached prefix matches the current one
+ if (nameBitvector_Compare(&pkt_cache->cached_prefix, prefix) == 0) return;
+
+ // Update cached prefix information
+ pkt_cache->cached_prefix = *prefix;
+ pkt_cache->cached_suffixes =
+ _get_suffixes(pkt_cache->prefix_to_suffixes, prefix);
+}
+
+void pkt_cache_reset_suffixes_for_prefix(pkt_cache_t *pkt_cache) {
+ pkt_cache->cached_suffixes = NULL;
+}
+
+unsigned _get_suffix(kh_pkt_cache_prefix_t *prefixes,
+ const NameBitvector *prefix, uint32_t suffix, int *rc) {
+ kh_pkt_cache_suffix_t *suffixes = _get_suffixes(prefixes, prefix);
+ assert(suffixes != NULL);
+
+ return __get_suffix(suffixes, suffix, rc);
+}
+
+/******************************************************************************
+ * Public API
+ ******************************************************************************/
+
pkt_cache_t *pkt_cache_create(size_t cs_size) {
pkt_cache_t *pkt_cache = (pkt_cache_t *)malloc(sizeof(pkt_cache_t));
@@ -28,23 +133,20 @@ pkt_cache_t *pkt_cache_create(size_t cs_size) {
pkt_cache->cs = cs_create(cs_size);
if (!pkt_cache->cs) return NULL;
- pkt_cache->index_by_name = kh_init(pkt_cache_name);
+ pkt_cache->prefix_to_suffixes = kh_init_pkt_cache_prefix();
pool_init(pkt_cache->entries, DEFAULT_PKT_CACHE_SIZE, 0);
+ pkt_cache->cached_prefix = EMPTY_NAME_BITVECTOR;
+ pkt_cache->cached_suffixes = NULL;
+
return pkt_cache;
}
void pkt_cache_free(pkt_cache_t *pkt_cache) {
assert(pkt_cache);
- // Free hashmap
- const Name *k_name;
- unsigned v;
- (void)v;
- kh_foreach(pkt_cache->index_by_name, k_name, v, { free((Name *)k_name); });
- kh_destroy(pkt_cache_name, pkt_cache->index_by_name);
-
- // Free pool
+ // Free prefix hash table and pool
+ _prefix_map_free(pkt_cache->prefix_to_suffixes);
pool_free(pkt_cache->entries);
// Free PIT and CS
@@ -54,6 +156,30 @@ void pkt_cache_free(pkt_cache_t *pkt_cache) {
free(pkt_cache);
}
+kh_pkt_cache_suffix_t *pkt_cache_get_suffixes(const pkt_cache_t *pkt_cache,
+ const NameBitvector *prefix) {
+ return _get_suffixes(pkt_cache->prefix_to_suffixes, prefix);
+}
+
+pkt_cache_entry_t *pkt_cache_allocate(pkt_cache_t *pkt_cache,
+ const Name *name) {
+ pkt_cache_entry_t *entry = NULL;
+ pool_get(pkt_cache->entries, entry);
+ if (!entry) return NULL;
+
+ off_t id = entry - pkt_cache->entries;
+
+ if (pkt_cache->cached_suffixes) {
+ __add_suffix(pkt_cache->cached_suffixes, name_GetSegment(name),
+ (unsigned int)id);
+ } else {
+ _add_suffix(pkt_cache->prefix_to_suffixes, name_GetContentName(name),
+ name_GetSegment(name), (unsigned int)id);
+ }
+
+ return entry;
+}
+
pit_t *pkt_cache_get_pit(pkt_cache_t *pkt_cache) { return pkt_cache->pit; }
cs_t *pkt_cache_get_cs(pkt_cache_t *pkt_cache) { return pkt_cache->cs; }
@@ -63,14 +189,22 @@ pkt_cache_entry_t *pkt_cache_lookup(pkt_cache_t *pkt_cache, const Name *name,
pkt_cache_lookup_t *lookup_result,
off_t *entry_id,
bool is_serve_from_cs_enabled) {
- Name name_key = name_key_factory(name);
- khiter_t k = kh_get_pkt_cache_name(pkt_cache->index_by_name, &name_key);
- if (k == kh_end(pkt_cache->index_by_name)) {
+ int rc;
+
+ unsigned index = -1;
+ if (pkt_cache->cached_suffixes) {
+ index =
+ __get_suffix(pkt_cache->cached_suffixes, name_GetSegment(name), &rc);
+ } else {
+ index = _get_suffix(pkt_cache->prefix_to_suffixes,
+ name_GetContentName(name), name_GetSegment(name), &rc);
+ }
+
+ if (rc == KH_NOT_FOUND) {
*lookup_result = PKT_CACHE_LU_NONE;
return NULL;
}
- off_t index = kh_val(pkt_cache->index_by_name, k);
pkt_cache_entry_t *entry = pkt_cache_at(pkt_cache, index);
assert(entry);
bool expired = false;
@@ -103,11 +237,9 @@ void pkt_cache_cs_remove_entry(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry,
off_t msgbuf_id = entry->u.cs_entry.msgbuf_id;
msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id);
- Name name_key = name_key_factory(msgbuf_get_name(msgbuf));
- khiter_t k = kh_get_pkt_cache_name(pkt_cache->index_by_name, &name_key);
- assert(k != kh_end(pkt_cache->index_by_name));
- free((Name *)kh_key(pkt_cache->index_by_name, k));
- kh_del(pkt_cache_name, pkt_cache->index_by_name, k);
+ const Name *name = msgbuf_get_name(msgbuf);
+ _remove_suffix(pkt_cache->prefix_to_suffixes, name_GetContentName(name),
+ name_GetSegment(name));
// Do not update the LRU cache for evicted entries
if (!is_evicted) cs_vft[pkt_cache->cs->type]->remove_entry(pkt_cache, entry);
@@ -130,12 +262,8 @@ void pkt_cache_pit_remove_entry(pkt_cache_t *pkt_cache,
assert(entry);
assert(entry->entry_type == PKT_CACHE_PIT_TYPE);
- Name name_key = name_key_factory(name);
- khiter_t k = kh_get_pkt_cache_name(pkt_cache->index_by_name, &name_key);
- assert(k != kh_end(pkt_cache->index_by_name));
- free((Name *)kh_key(pkt_cache->index_by_name, k));
- kh_del(pkt_cache_name, pkt_cache->index_by_name, k);
-
+ _remove_suffix(pkt_cache->prefix_to_suffixes, name_GetContentName(name),
+ name_GetSegment(name));
pool_put(pkt_cache->entries, entry);
WITH_DEBUG({
@@ -158,7 +286,7 @@ void _pkt_cache_add_to_cs(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry,
pkt_cache->cs->num_entries++;
- int tail_id = pkt_cache->cs->lru.tail;
+ int tail_id = (int)(pkt_cache->cs->lru.tail);
int result = cs_vft[pkt_cache->cs->type]->add_entry(pkt_cache, entry_id);
if (result == LRU_EVICTION) {
// Remove tail (already removed from LRU cache)
@@ -237,11 +365,11 @@ void pkt_cache_update_cs(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool,
}
pkt_cache_entry_t *pkt_cache_add_to_pit(pkt_cache_t *pkt_cache,
- const msgbuf_t *msgbuf) {
+ const msgbuf_t *msgbuf,
+ const Name *name) {
assert(pkt_cache);
- pkt_cache_entry_t *entry =
- pkt_cache_allocate(pkt_cache, msgbuf_get_name(msgbuf));
+ pkt_cache_entry_t *entry = pkt_cache_allocate(pkt_cache, name);
_pkt_cache_add_to_pit(pkt_cache, entry, msgbuf);
return entry;
}
@@ -276,7 +404,7 @@ void pkt_cache_update_pit(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry,
bool pkt_cache_try_aggregate_in_pit(pkt_cache_t *pkt_cache,
pkt_cache_entry_t *entry,
- const msgbuf_t *msgbuf) {
+ const msgbuf_t *msgbuf, const Name *name) {
assert(pkt_cache);
assert(entry);
assert(entry->entry_type == PKT_CACHE_PIT_TYPE);
@@ -294,7 +422,7 @@ bool pkt_cache_try_aggregate_in_pit(pkt_cache_t *pkt_cache,
if (is_aggregated) pit_entry_ingress_add(pit_entry, connection_id);
WITH_DEBUG({
- char *name_str = name_ToString(msgbuf_get_name(msgbuf));
+ char *name_str = name_ToString(name);
if (is_aggregated) {
DEBUG("Interest %s already existing (expiry %lu): aggregate", name_str,
entry->expire_ts);
@@ -407,7 +535,7 @@ nexthops_t *pkt_cache_on_data(pkt_cache_t *pkt_cache,
return NULL;
default:
- ERROR("Inivalid packet cache content");
+ ERROR("Invalid packet cache content");
return NULL;
}
}
@@ -415,7 +543,7 @@ nexthops_t *pkt_cache_on_data(pkt_cache_t *pkt_cache,
void pkt_cache_on_interest(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool,
off_t msgbuf_id, pkt_cache_verdict_t *verdict,
off_t *data_msgbuf_id, pkt_cache_entry_t **entry_ptr,
- bool is_serve_from_cs_enabled) {
+ const Name *name, bool is_serve_from_cs_enabled) {
assert(pkt_cache);
assert(msgbuf_id_is_valid(msgbuf_id));
@@ -425,8 +553,8 @@ void pkt_cache_on_interest(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool,
off_t entry_id;
pkt_cache_lookup_t lookup_result;
pkt_cache_entry_t *entry =
- pkt_cache_lookup(pkt_cache, msgbuf_get_name(msgbuf), msgbuf_pool,
- &lookup_result, &entry_id, is_serve_from_cs_enabled);
+ pkt_cache_lookup(pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id,
+ is_serve_from_cs_enabled);
*entry_ptr = entry;
cs_entry_t *cs_entry = NULL;
@@ -434,6 +562,9 @@ void pkt_cache_on_interest(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool,
bool is_aggregated;
switch (lookup_result) {
case PKT_CACHE_LU_NONE:
+ entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name);
+ *entry_ptr = entry;
+
*verdict = PKT_CACHE_VERDICT_FORWARD_INTEREST;
break;
@@ -448,7 +579,8 @@ void pkt_cache_on_interest(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool,
break;
case PKT_CACHE_LU_INTEREST_NOT_EXPIRED:
- is_aggregated = pkt_cache_try_aggregate_in_pit(pkt_cache, entry, msgbuf);
+ is_aggregated =
+ pkt_cache_try_aggregate_in_pit(pkt_cache, entry, msgbuf, name);
*verdict = is_aggregated ? PKT_CACHE_VERDICT_AGGREGATE_INTEREST
: PKT_CACHE_VERDICT_RETRANSMIT_INTEREST;
@@ -477,36 +609,30 @@ void pkt_cache_on_interest(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool,
void pkt_cache_cs_clear(pkt_cache_t *pkt_cache) {
assert(pkt_cache);
- const Name *k_name;
- unsigned v_pool_pos;
- kh_foreach(pkt_cache->index_by_name, k_name, v_pool_pos,
- {
- khiter_t k =
- kh_get_pkt_cache_name(pkt_cache->index_by_name, k_name);
- assert(k != kh_end(pkt_cache->index_by_name));
-
- pkt_cache_entry_t *entry = pkt_cache_at(pkt_cache, v_pool_pos);
- if (entry->entry_type == PKT_CACHE_CS_TYPE) {
- // Remove from hashmap
- free((Name *)kh_key(pkt_cache->index_by_name, k));
- kh_del(pkt_cache_name, pkt_cache->index_by_name, k);
-
- // Remove from pool
- pool_put(pkt_cache->entries, entry);
- }
- })
-
- // Re-create CS
- cs_clear(pkt_cache->cs);
-}
+ kh_pkt_cache_suffix_t *v_suffixes;
+ u32 k_suffix;
+ u32 v_pkt_cache_entry_id;
+ kh_foreach_value(pkt_cache->prefix_to_suffixes, v_suffixes, {
+ kh_foreach(v_suffixes, k_suffix, v_pkt_cache_entry_id, {
+ pkt_cache_entry_t *entry = pkt_cache_at(pkt_cache, v_pkt_cache_entry_id);
+ if (entry->entry_type == PKT_CACHE_CS_TYPE) {
+ // Remove from hash table
+ khiter_t k = kh_get_pkt_cache_suffix(v_suffixes, k_suffix);
+ assert(k != kh_end(v_suffixes));
+ kh_del_pkt_cache_suffix(v_suffixes, k);
+
+ // Remove from pool
+ pool_put(pkt_cache->entries, entry);
+ }
+ });
+ });
-size_t pkt_cache_get_size(pkt_cache_t *pkt_cache) {
- uint64_t hashmap_size = kh_size(pkt_cache->index_by_name);
- return hashmap_size;
-}
+ // Reset cached prefix
+ pkt_cache->cached_prefix = EMPTY_NAME_BITVECTOR;
+ pkt_cache->cached_suffixes = NULL;
-size_t pkt_cache_get_cs_size(pkt_cache_t *pkt_cache) {
- return pkt_cache->cs->num_entries;
+ // Re-create CS
+ cs_clear(pkt_cache->cs);
}
size_t pkt_cache_get_num_cs_stale_entries(pkt_cache_t *pkt_cache) {
@@ -531,17 +657,35 @@ int pkt_cache_set_cs_size(pkt_cache_t *pkt_cache, size_t size) {
return 0;
}
+size_t pkt_cache_get_size(pkt_cache_t *pkt_cache) {
+ return pool_len(pkt_cache->entries);
+}
+
+size_t pkt_cache_get_cs_size(pkt_cache_t *pkt_cache) {
+ return pkt_cache->cs->num_entries;
+}
+
size_t pkt_cache_get_pit_size(pkt_cache_t *pkt_cache) {
- uint64_t hashmap_size = kh_size(pkt_cache->index_by_name);
- uint64_t pit_size = hashmap_size - pkt_cache->cs->num_entries;
+ uint64_t pkt_cache_size = pkt_cache_get_size(pkt_cache);
+ uint64_t pit_size = pkt_cache_size - pkt_cache_get_cs_size(pkt_cache);
return pit_size;
}
void pkt_cache_log(pkt_cache_t *pkt_cache) {
- uint64_t hashmap_size = kh_size(pkt_cache->index_by_name);
- uint64_t pit_size = hashmap_size - pkt_cache->cs->num_entries;
DEBUG("Packet cache: total size = %lu, PIT size = %lu, CS size = %u",
- hashmap_size, pit_size, pkt_cache->cs->num_entries);
+ pkt_cache_get_size(pkt_cache), pkt_cache_get_pit_size(pkt_cache),
+ pkt_cache_get_cs_size(pkt_cache));
cs_log(pkt_cache->cs);
}
+
+pkt_cache_stats_t pkt_cache_get_stats(pkt_cache_t *pkt_cache) {
+ cs_lru_stats_t lru_stats = cs_get_lru_stats(pkt_cache_get_cs(pkt_cache));
+ pkt_cache_stats_t stats = {
+ .n_pit_entries = (uint32_t)pkt_cache_get_pit_size(pkt_cache),
+ .n_cs_entries = (uint32_t)pkt_cache_get_cs_size(pkt_cache),
+ .n_lru_evictions = (uint32_t)lru_stats.countLruEvictions,
+ };
+
+ return stats;
+}
diff --git a/hicn-light/src/hicn/core/packet_cache.h b/hicn-light/src/hicn/core/packet_cache.h
index ccfc83b97..47926fcdc 100644
--- a/hicn-light/src/hicn/core/packet_cache.h
+++ b/hicn-light/src/hicn/core/packet_cache.h
@@ -19,7 +19,7 @@
*
* The packet cache is a data structure that merges together the PIT and the CS,
* to which it holds a reference.
- * It contains PIT and CS entries, indexed in a hashtable by hICN packet names.
+ * It contains PIT and CS entries, indexed in a two-level hash table.
*
* Each entry has shared fields, e.g. entry type (PIT or CS) and timestamps,
* which are used by both PIT and CS entries. In addition, a C union holds
@@ -27,41 +27,64 @@
*
* Having a single entry that can hold PIT or CS entries allows to reduce
* the number of lookups.
+ *
+ * A prefix hash table <prefix, suffix_hashtable> stores the suffixes associated
+ * to each prefix, where each value in the map points to a separate hash
+ * table <suffix, packet_cache_reference> that can be used to retrieved the
+ * packet cache entry.
+ * When an interest/data packet is received, the prefix and the associated
+ * suffixes are saved; if the next packet cache operation involves the same
+ * prefix, no additional lookups in the prefix hash hashtable are needed.
*/
#ifndef HICNLIGHT_PACKET_CACHE_H
#define HICNLIGHT_PACKET_CACHE_H
+#include <hicn/util/khash.h>
#include "content_store.h"
#include "pit.h"
#include "msgbuf_pool.h"
-#include "../base/khash.h"
#include "../content_store/lru.h"
#define DEFAULT_PKT_CACHE_SIZE 2048
typedef enum { PKT_CACHE_PIT_TYPE, PKT_CACHE_CS_TYPE } pkt_cache_entry_type_t;
-/**
- * @brief Return a Name that can be used as key for hash table lookups.
- * The returned Name is a copy of the input one but it is "memsetted"
- * to ensure successful hash calculation.
- */
-static inline Name name_key_factory(const Name *name) {
- NameBitvector *content_name = name_GetContentName(name);
+#define foreach_kh_verdict \
+ _(FORWARD_INTEREST) \
+ _(AGGREGATE_INTEREST) \
+ _(RETRANSMIT_INTEREST) \
+ _(FORWARD_DATA) \
+ _(INTEREST_EXPIRED_FORWARD_INTEREST) \
+ _(DATA_EXPIRED_FORWARD_INTEREST) \
+ _(STORE_DATA) \
+ _(CLEAR_DATA) \
+ _(UPDATE_DATA) \
+ _(IGNORE_DATA) \
+ _(ERROR)
- Name name_key;
- memset(&name_key, 0, sizeof(Name));
+typedef enum {
+#define _(x) PKT_CACHE_VERDICT_##x,
+ foreach_kh_verdict
+#undef _
+} pkt_cache_verdict_t;
- name_key.content_name = *content_name;
- name_key.segment = name_GetSegment(name);
- name_key.name_hash = name_HashCode(name);
+#define foreach_kh_lookup \
+ _(INTEREST_NOT_EXPIRED) \
+ _(INTEREST_EXPIRED) \
+ _(DATA_NOT_EXPIRED) \
+ _(DATA_EXPIRED) \
+ _(NONE)
- return name_key;
-}
+typedef enum {
+#define _(x) PKT_CACHE_LU_##x,
+ foreach_kh_lookup
+#undef _
+} pkt_cache_lookup_t;
-KHASH_INIT(pkt_cache_name, const Name *, unsigned, 1, name_HashCode,
- name_Equals);
+KHASH_MAP_INIT_INT(pkt_cache_suffix, unsigned);
+KHASH_INIT(pkt_cache_prefix, const NameBitvector *, kh_pkt_cache_suffix_t *, 1,
+ nameBitvector_GetHash32, nameBitvector_Equals);
typedef struct {
pkt_cache_entry_type_t entry_type;
@@ -82,7 +105,12 @@ typedef struct {
pit_t *pit;
cs_t *cs;
pkt_cache_entry_t *entries;
- kh_pkt_cache_name_t *index_by_name;
+ kh_pkt_cache_prefix_t *prefix_to_suffixes;
+
+ // Cached prefix info to avoid double lookups,
+ // used for both single interest speculation and interest manifest
+ NameBitvector cached_prefix;
+ kh_pkt_cache_suffix_t *cached_suffixes;
} pkt_cache_t;
/**
@@ -92,7 +120,6 @@ typedef struct {
*/
pkt_cache_t *pkt_cache_create(size_t cs_size);
-#define _pc_var(x) _pkt_cache_##x
/**
* @brief Add an entry with the specified name to the packet cache.
*
@@ -101,29 +128,7 @@ pkt_cache_t *pkt_cache_create(size_t cs_size);
* allocated one from the msgbuf pool.
* * @param[in] name Name to use
*/
-static inline pkt_cache_entry_t *pkt_cache_allocate(
- const pkt_cache_t *pkt_cache, const Name *name) {
- pkt_cache_entry_t *entry = NULL;
- pool_get(pkt_cache->entries, entry);
- assert(entry);
-
- off_t id = entry - pkt_cache->entries;
- int res;
-
- // Generate the key (starting from the name) to use in the name hash table
- NameBitvector *nb = name_GetContentName(name);
- Name *name_copy = (Name *)calloc(1, sizeof(Name));
- name_copy->content_name = *nb;
- name_copy->segment = name_GetSegment(name);
- name_copy->name_hash = name_HashCode(name);
-
- // Add in name hash table
- khiter_t k = kh_put_pkt_cache_name(pkt_cache->index_by_name, name_copy, &res);
- assert(res != -1);
- kh_value(pkt_cache->index_by_name, k) = id;
-
- return entry;
-}
+pkt_cache_entry_t *pkt_cache_allocate(pkt_cache_t *pkt_cache, const Name *name);
/**
* @brief Free a packet cache data structure.
@@ -189,28 +194,6 @@ size_t pkt_cache_get_cs_size(pkt_cache_t *pkt_cache);
*/
size_t pkt_cache_get_pit_size(pkt_cache_t *pkt_cache);
-typedef enum {
- PKT_CACHE_LU_INTEREST_NOT_EXPIRED,
- PKT_CACHE_LU_INTEREST_EXPIRED,
- PKT_CACHE_LU_DATA_NOT_EXPIRED,
- PKT_CACHE_LU_DATA_EXPIRED,
- PKT_CACHE_LU_NONE
-} pkt_cache_lookup_t;
-
-typedef enum {
- PKT_CACHE_VERDICT_FORWARD_INTEREST,
- PKT_CACHE_VERDICT_AGGREGATE_INTEREST,
- PKT_CACHE_VERDICT_RETRANSMIT_INTEREST,
- PKT_CACHE_VERDICT_FORWARD_DATA,
- PKT_CACHE_VERDICT_INTEREST_EXPIRED_FORWARD_INTEREST,
- PKT_CACHE_VERDICT_DATA_EXPIRED_FORWARD_INTEREST,
- PKT_CACHE_VERDICT_STORE_DATA,
- PKT_CACHE_VERDICT_CLEAR_DATA,
- PKT_CACHE_VERDICT_UPDATE_DATA,
- PKT_CACHE_VERDICT_IGNORE_DATA,
- PKT_CACHE_VERDICT_ERROR
-} pkt_cache_verdict_t;
-
#define pkt_cache_entry_get_create_ts(E) ((E)->create_ts)
#define pkt_cache_entry_get_expire_ts(E) ((E)->expire_ts)
#define pkt_cache_entry_set_expire_ts(E, EXPIRY_TIME) \
@@ -241,7 +224,7 @@ pkt_cache_entry_t *pkt_cache_lookup(pkt_cache_t *pkt_cache, const Name *name,
bool is_serve_from_cs_enabled);
/**
- * @brief Clear the content of the CS.
+ * @brief Clear the content of the CS (PIT entries are left unmodified).
*
* @param pkt_cache Pointer to the packet cache data structure to use
*/
@@ -254,6 +237,8 @@ void pkt_cache_cs_clear(pkt_cache_t *pkt_cache);
*/
void pkt_cache_log(pkt_cache_t *pkt_cache);
+pkt_cache_stats_t pkt_cache_get_stats(pkt_cache_t *pkt_cache);
+
// TODO(eloparco): To implement
void pkt_cache_print(const pkt_cache_t *pkt_cache);
@@ -320,10 +305,13 @@ void pkt_cache_cs_to_pit(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry,
* @param[in] pkt_cache Pointer to the packet cache data structure to use
* @param[in] msgbuf Pointer to the msgbuf associated with the PIT entry to
* insert
+ * @param[in] name Interest name to use; in case of aggregated interests, it is
+ * different from the name stored in the msgbuf
* @return pkt_cache_entry_t* Pointer to the packet cache (PIT) entry created
*/
pkt_cache_entry_t *pkt_cache_add_to_pit(pkt_cache_t *pkt_cache,
- const msgbuf_t *msgbuf);
+ const msgbuf_t *msgbuf,
+ const Name *name);
/**
* @brief Add CS entry to the packet cache.
@@ -374,6 +362,8 @@ void pkt_cache_update_cs(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool,
* @param[in, out] entry Pointer to the PIT entry to update
* @param[in] msgbuf Pointer to the msgbuf associated with the PIT entry to
* update
+ * @param[in] name Interest name to use; in case of aggregated interests, it is
+ * different from the name stored in the msgbuf
* @return true If aggregation (interest sent from a connection not stored in
* the PIT entry)
* @return false If retransmission (interest sent from a connection already
@@ -381,7 +371,23 @@ void pkt_cache_update_cs(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool,
*/
bool pkt_cache_try_aggregate_in_pit(pkt_cache_t *pkt_cache,
pkt_cache_entry_t *entry,
- const msgbuf_t *msgbuf);
+ const msgbuf_t *msgbuf, const Name *name);
+
+/**
+ * @brief Cache prefix info (prefix + associated suffixes) to speed up lookups.
+ *
+ * @param[in] pkt_cache Pointer to the packet cache data structure to use
+ * @param[in] prefix Name prefix to cache
+ */
+void pkt_cache_save_suffixes_for_prefix(pkt_cache_t *pkt_cache,
+ const NameBitvector *prefix);
+
+/**
+ * @brief Reset cached prefix info to force double lookups.
+ *
+ * @param[in] pkt_cache Pointer to the packet cache data structure to use
+ */
+void pkt_cache_reset_suffixes_for_prefix(pkt_cache_t *pkt_cache);
/************ Handle data/interest packets received *******/
@@ -413,7 +419,24 @@ nexthops_t *pkt_cache_on_data(pkt_cache_t *pkt_cache,
void pkt_cache_on_interest(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool,
off_t msgbuf_id, pkt_cache_verdict_t *verdict,
off_t *data_msgbuf_id, pkt_cache_entry_t **entry_ptr,
- bool is_serve_from_cs_enabled);
+ const Name *name, bool is_serve_from_cs_enabled);
+
+/********* Low-level operations on the hash table *********/
+#ifdef WITH_TESTS
+unsigned __get_suffix(kh_pkt_cache_suffix_t *suffixes, uint32_t suffix,
+ int *rc);
+unsigned _get_suffix(kh_pkt_cache_prefix_t *prefixes,
+ const NameBitvector *prefix, uint32_t suffix, int *rc);
+void __add_suffix(kh_pkt_cache_suffix_t *suffixes, uint32_t suffix,
+ unsigned val);
+void _add_suffix(kh_pkt_cache_prefix_t *prefixes, const NameBitvector *prefix,
+ uint32_t suffix, unsigned val);
+void _remove_suffix(kh_pkt_cache_prefix_t *prefixes,
+ const NameBitvector *prefix, uint32_t suffix);
+void _prefix_map_free(kh_pkt_cache_prefix_t *prefix_to_suffixes);
+kh_pkt_cache_suffix_t *_get_suffixes(kh_pkt_cache_prefix_t *prefix_to_suffixes,
+ const NameBitvector *prefix);
+#endif
/************** Content Store *****************************/
diff --git a/hicn-light/src/hicn/core/policy_stats.h b/hicn-light/src/hicn/core/policy_stats.h
index fa12b51cb..aee68e515 100644
--- a/hicn-light/src/hicn/core/policy_stats.h
+++ b/hicn-light/src/hicn/core/policy_stats.h
@@ -5,7 +5,6 @@
#ifdef WITH_POLICY_STATS
#include <hicn/policy.h>
-#include "../base/loop.h"
typedef struct policy_stats_mgr_s {
void* forwarder;
diff --git a/hicn-light/src/hicn/core/subscription.c b/hicn-light/src/hicn/core/subscription.c
index 0c4949f26..ad4006531 100644
--- a/hicn-light/src/hicn/core/subscription.c
+++ b/hicn-light/src/hicn/core/subscription.c
@@ -3,7 +3,7 @@
*/
#include "subscription.h"
-#include <hicn/base/vector.h>
+#include <hicn/util/vector.h>
#include <hicn/util/log.h>
/*----------------------------------------------------------------------------*
diff --git a/hicn-light/src/hicn/io/base.c b/hicn-light/src/hicn/io/base.c
index 71d10021e..cd7362956 100644
--- a/hicn-light/src/hicn/io/base.c
+++ b/hicn-light/src/hicn/io/base.c
@@ -42,7 +42,7 @@ ssize_t io_read_single_fd(int fd, msgbuf_t *msgbuf, address_t *address) {
return -1;
}
- msgbuf->length = n;
+ msgbuf->length = (unsigned int)n;
*address = ADDRESS_ANY(AF_UNSPEC, 0); // XXX placeholder, see hicn.c
}
@@ -55,7 +55,7 @@ ssize_t io_read_single_socket(int fd, msgbuf_t *msgbuf, address_t *address) {
uint8_t *packet = msgbuf_get_packet(msgbuf);
ssize_t n = recvfrom(fd, packet, MTU, 0, (struct sockaddr *)sa, &sa_len);
- msgbuf->length = n;
+ msgbuf->length = (unsigned int)n;
return n;
}
@@ -114,21 +114,6 @@ ssize_t io_read_batch_socket(int fd, msgbuf_t **msgbuf, address_t **address,
struct mmsghdr *msg = &msghdr[i];
msgbuf[i]->length = msg->msg_len;
- /*
- * As is, the address we put in the array has uninitialized
- * memory in it:
- * *address[i] = *(address_t*)msg->msg_hdr.msg_name;
- *
- * This can be confirmed by testing with the following
- * memset which removes the valgrind errors:
- * memset(address[i], 0, sizeof(address_t));
- *
- * The solution is to copy only the part which we know is
- * initialized (we have compatible types, since the destination, an
- * address_t, is effectively a struct sockaddr_storage). We might
- * eventually provide a helper for this to avoid similar mistakes.
- */
- //*address[i] = *(address_t*)msg->msg_hdr.msg_name;
memcpy(address[i], msg->msg_hdr.msg_name, msg->msg_hdr.msg_namelen);
}
break;
diff --git a/hicn-light/src/hicn/io/hicn.c b/hicn-light/src/hicn/io/hicn.c
index 8b4ad2e00..d019a49c1 100644
--- a/hicn-light/src/hicn/io/hicn.c
+++ b/hicn-light/src/hicn/io/hicn.c
@@ -401,12 +401,10 @@ static void connection_hicn_finalize(connection_t *connection) {
return;
}
-static bool connection_hicn_flush(const connection_t *connection) {
- return false;
-}
+static bool connection_hicn_flush(connection_t *connection) { return false; }
-static bool connection_hicn_send(const connection_t *connection,
- msgbuf_t *msgbuf, bool queue) {
+static bool connection_hicn_send(connection_t *connection, msgbuf_t *msgbuf,
+ bool queue) {
assert(connection);
/* msgbuf can be NULL */
diff --git a/hicn-light/src/hicn/io/tcp.c b/hicn-light/src/hicn/io/tcp.c
index 69ad32d16..50591c3fc 100644
--- a/hicn-light/src/hicn/io/tcp.c
+++ b/hicn-light/src/hicn/io/tcp.c
@@ -287,9 +287,7 @@ connection_tcp_sendv(connnection_t * connection, struct iovec * iov,
}
#endif
-static bool connection_tcp_flush(const connection_t *connection) {
- return true;
-}
+static bool connection_tcp_flush(connection_t *connection) { return true; }
/**
* @function streamConnection_Send
@@ -303,8 +301,8 @@ static bool connection_tcp_flush(const connection_t *connection) {
*/
// XXX address not used anywhere
// XXX too much repeated code with sendv here
-static bool connection_tcp_send(const connection_t *connection,
- msgbuf_t *msgbuf, bool queue) {
+static bool connection_tcp_send(connection_t *connection, msgbuf_t *msgbuf,
+ bool queue) {
assert(connection);
assert(msgbuf);
diff --git a/hicn-light/src/hicn/io/udp.c b/hicn-light/src/hicn/io/udp.c
index 3301e2178..149d53aea 100644
--- a/hicn-light/src/hicn/io/udp.c
+++ b/hicn-light/src/hicn/io/udp.c
@@ -49,10 +49,9 @@
#include <hicn/util/log.h>
#include <hicn/util/sstrncpy.h>
+#include <hicn/util/ring.h>
#include "base.h"
-#include "../base/loop.h"
-#include "../base/ring.h"
#include "../core/address_pair.h"
#include "../core/connection.h"
#include "../core/connection_vft.h"
@@ -344,7 +343,7 @@ static void connection_udp_finalize(connection_t *connection) {
ring_free(data->ring);
}
-static bool connection_udp_flush(const connection_t *connection) {
+static bool connection_udp_flush(connection_t *connection) {
#ifdef __linux__
int retry = 0;
off_t msgbuf_id = 0;
@@ -375,9 +374,16 @@ SEND:
msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id);
// update path label
- if (msgbuf_get_type(msgbuf) == MSGBUF_TYPE_DATA)
+ if (msgbuf_get_type(msgbuf) == MSGBUF_TYPE_DATA) {
msgbuf_update_pathlabel(msgbuf, connection_get_id(connection));
+ connection->stats.data.tx_pkts++;
+ connection->stats.data.tx_bytes += msgbuf_get_len(msgbuf);
+ } else {
+ connection->stats.interests.tx_pkts++;
+ connection->stats.interests.tx_bytes += msgbuf_get_len(msgbuf);
+ }
+
data->iovecs[i].iov_base = msgbuf_get_packet(msgbuf);
data->iovecs[i].iov_len = msgbuf_get_len(msgbuf);
cpt++;
@@ -430,8 +436,8 @@ SENDMMSG:
* @param dummy is ignored. A udp connection has only one peer.
* @return <#return#>
*/
-static bool connection_udp_send(const connection_t *connection,
- msgbuf_t *msgbuf, bool queue) {
+static bool connection_udp_send(connection_t *connection, msgbuf_t *msgbuf,
+ bool queue) {
assert(connection);
assert(msgbuf);
@@ -454,9 +460,16 @@ static bool connection_udp_send(const connection_t *connection,
#endif /* __linux__ */
/* Send one */
// update the path label befor send the packet
- if (msgbuf_get_type(msgbuf) == MSGBUF_TYPE_DATA)
+ if (msgbuf_get_type(msgbuf) == MSGBUF_TYPE_DATA) {
msgbuf_update_pathlabel(msgbuf, connection_get_id(connection));
+ connection->stats.data.tx_pkts++;
+ connection->stats.data.tx_bytes += msgbuf_get_len(msgbuf);
+ } else {
+ connection->stats.interests.tx_pkts++;
+ connection->stats.interests.tx_bytes += msgbuf_get_len(msgbuf);
+ }
+
ssize_t writeLength = write(connection->fd, msgbuf_get_packet(msgbuf),
msgbuf_get_len(msgbuf));
diff --git a/hicn-light/src/hicn/strategies/probe_generator.c b/hicn-light/src/hicn/strategies/probe_generator.c
index 439de0a12..bc141e518 100644
--- a/hicn-light/src/hicn/strategies/probe_generator.c
+++ b/hicn-light/src/hicn/strategies/probe_generator.c
@@ -78,7 +78,7 @@ int generate_probe(probe_generator_t *pg, const msgbuf_t *msgbuf,
const forwarder_t *forwarder, nexthop_t nexthop) {
msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder);
connection_table_t *table = forwarder_get_connection_table(forwarder);
- const connection_t *conn = connection_table_get_by_id(table, nexthop);
+ connection_t *conn = connection_table_get_by_id(table, nexthop);
if (!conn) return -1;
msgbuf_t *probe;
diff --git a/hicn-light/src/hicn/strategies/probe_generator.h b/hicn-light/src/hicn/strategies/probe_generator.h
index 26d6a3a22..7a9f3a58a 100644
--- a/hicn-light/src/hicn/strategies/probe_generator.h
+++ b/hicn-light/src/hicn/strategies/probe_generator.h
@@ -16,7 +16,7 @@
#ifndef HICNLIGHT_PROBE_GENERATOR
#define HICNLIGHT_PROBE_GENERATOR
-#include "../base/khash.h"
+#include <hicn/util/khash.h>
#include <hicn/core/ticks.h>
#include <hicn/core/msgbuf.h>
diff --git a/hicn-light/src/hicn/test/CMakeLists.txt b/hicn-light/src/hicn/test/CMakeLists.txt
index 0ded4253d..65e216c1e 100644
--- a/hicn-light/src/hicn/test/CMakeLists.txt
+++ b/hicn-light/src/hicn/test/CMakeLists.txt
@@ -13,6 +13,7 @@ list(APPEND TESTS_SRC
test-ctrl.cc
test-ring.cc
test-vector.cc
+ test-interest_manifest.cc
test-msgbuf_pool.cc
test-nexthops.cc
test-connection_table.cc
diff --git a/hicn-light/src/hicn/test/test-bitmap.cc b/hicn-light/src/hicn/test/test-bitmap.cc
index f9cd4024f..1fd21a1bb 100644
--- a/hicn-light/src/hicn/test/test-bitmap.cc
+++ b/hicn-light/src/hicn/test/test-bitmap.cc
@@ -25,7 +25,7 @@
extern "C" {
#define WITH_TESTS
-#include <hicn/base/bitmap.h>
+#include <hicn/util/bitmap.h>
}
#define DEFAULT_SIZE 10
diff --git a/hicn-light/src/hicn/test/test-connection_table.cc b/hicn-light/src/hicn/test/test-connection_table.cc
index 6bbf478e2..d17de7c2c 100644
--- a/hicn-light/src/hicn/test/test-connection_table.cc
+++ b/hicn-light/src/hicn/test/test-connection_table.cc
@@ -35,7 +35,7 @@ extern "C" {
class ConnectionTableTest : public ::testing::Test {
protected:
ConnectionTableTest() {
- log_conf.log_level = LOG_INFO;
+ log_conf.log_level = LOG_WARN;
conn_table_ = connection_table_create();
pair_ =
@@ -164,6 +164,10 @@ TEST_F(ConnectionTableTest, RemoveConnection) {
}
TEST_F(ConnectionTableTest, PrintTable) {
+ // Set verbose log level
+ int old_log_level = log_conf.log_level;
+ log_conf.log_level = LOG_INFO;
+
connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME);
connection_->type = FACE_TYPE_TCP;
@@ -184,6 +188,8 @@ TEST_F(ConnectionTableTest, PrintTable) {
EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:2"));
EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:3"));
EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:4"));
+
+ log_conf.log_level = old_log_level; // Restore old log level
}
TEST_F(ConnectionTableTest, AddMultipleConnections) {
@@ -248,3 +254,43 @@ TEST_F(ConnectionTableTest, Iterate) {
EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:3"));
EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:4"));
}
+
+TEST_F(ConnectionTableTest, GenerateConnName) {
+ char conn_name[SYMBOLIC_NAME_LEN];
+ int rc = connection_table_get_random_name(conn_table_, conn_name);
+ EXPECT_EQ(rc, 0);
+
+ connection_ = connection_table_allocate(conn_table_, &pair_, conn_name);
+ connection_->type = FACE_TYPE_TCP;
+ connection_->pair = pair_;
+
+ char conn_name2[SYMBOLIC_NAME_LEN];
+ rc = connection_table_get_random_name(conn_table_, conn_name2);
+ EXPECT_EQ(rc, 0);
+ EXPECT_NE(strncmp(conn_name, conn_name2, SYMBOLIC_NAME_LEN), 0);
+}
+
+TEST_F(ConnectionTableTest, GenerateConnNameExhaustion) {
+ char conn_name[SYMBOLIC_NAME_LEN];
+ bool unable_to_allocate = false;
+
+ // Force name exhaustion
+ int i, n_connections = 1 + USHRT_MAX;
+ for (int i = 0; i <= n_connections; i++) {
+ int rc = connection_table_get_random_name(conn_table_, conn_name);
+ if (rc < 0) {
+ unable_to_allocate = true;
+ break;
+ }
+
+ address_pair_t pair =
+ address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(i));
+ connection_t *conn =
+ connection_table_allocate(conn_table_, &pair, conn_name);
+ memset(conn, 0, sizeof(connection_t));
+ conn->type = FACE_TYPE_TCP;
+ conn->pair = pair;
+ }
+
+ EXPECT_TRUE(unable_to_allocate);
+} \ No newline at end of file
diff --git a/hicn-light/src/hicn/test/test-hash.cc b/hicn-light/src/hicn/test/test-hash.cc
index 2b72e194a..3b03a08a6 100644
--- a/hicn-light/src/hicn/test/test-hash.cc
+++ b/hicn-light/src/hicn/test/test-hash.cc
@@ -22,14 +22,18 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
-// #include <hicn/transport/utils/hash.h>
+#include <unordered_set>
+#include <hicn/test/test-utils.h>
extern "C" {
-#include <hicn/base/hash.h>
+#include <hicn/util/hash.h>
#include <hicn/core/address_pair.h>
#include <hicn/core/listener.h>
}
+static constexpr uint32_t init_val = 2166136261UL;
+static constexpr int N_HASHES = 50000;
+
TEST(HashTest, MultipleHashesForSameAddrPair) {
address_pair_t pair =
address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(2));
@@ -108,16 +112,106 @@ TEST(HashTest, SameListenerKeys) {
}
TEST(HashTest, Collisions) {
- uint32_t init_val = 2166136261UL;
- (void)init_val;
-
- std::map<u32, uint32_t> hashes;
+ std::unordered_set<uint32_t> hashes;
+ int n_collisions = 0;
for (int i = 0; i < 50000; i++) {
uint32_t seg = i;
- // u32 h = utils::hash::fnv32_buf (&seg, sizeof (seg));
- // u32 h = cumulative_hash32 (&seg, sizeof (seg), init_val);
+ // u32 h = utils::hash::fnv32_buf(&seg, sizeof(seg));
+ // u32 h = cumulative_hash32(&seg, sizeof(uint32_t), init_val);
u32 h = hash(&seg, sizeof(seg));
- EXPECT_FALSE(hashes.find(h) != hashes.end()) << seg << " - " << hashes[h];
- hashes[h] = seg;
+
+ if (hashes.find(h) != hashes.end()) n_collisions++;
+ hashes.insert(h);
}
+ EXPECT_EQ(n_collisions, 0);
+}
+
+/*** Compare FNV with Jenkins ***/
+
+typedef struct {
+ uint32_t data[6];
+} small_struct_t; // Same size as 'NameBitvector'
+
+typedef struct {
+ uint64_t data[32];
+} big_struct_t; // Same size as 'address_pair_t'
+
+TEST(HashTest, PerformanceComparisonSmallStruct) {
+ small_struct_t small_struct;
+
+ // FNV
+ auto time_fnv = get_execution_time([&]() {
+ for (int i = 0; i < N_HASHES; i++) {
+ small_struct.data[0] = i;
+ cumulative_hash32(&small_struct, sizeof(small_struct_t), init_val);
+ }
+ });
+
+ // Jenkins
+ auto time_jenkins = get_execution_time([&]() {
+ for (int i = 0; i < N_HASHES; i++) {
+ small_struct.data[0] = i;
+ hash(&small_struct, sizeof(small_struct_t));
+ }
+ });
+
+ std::cout << "Small struct (size = " << sizeof(small_struct_t) << " bytes)\n";
+ std::cout << "FNV: " << time_fnv << "ms\n";
+ std::cout << "Jenkins: " << time_jenkins << "ms\n";
+}
+
+TEST(HashTest, PerformanceComparisonBigStruct) {
+ big_struct_t big_struct;
+
+ // FNV
+ auto time_fnv = get_execution_time([&]() {
+ for (int i = 0; i < N_HASHES; i++) {
+ big_struct.data[0] = i;
+ cumulative_hash32(&big_struct, sizeof(big_struct_t), init_val);
+ }
+ });
+
+ // Jenkins
+ auto time_jenkins = get_execution_time([&]() {
+ for (int i = 0; i < N_HASHES; i++) {
+ big_struct.data[0] = i;
+ hash(&big_struct, sizeof(big_struct_t));
+ }
+ });
+
+ std::cout << "Big struct (size = " << sizeof(big_struct_t) << " bytes)\n";
+ std::cout << "FNV: " << time_fnv << "ms\n";
+ std::cout << "Jenkins: " << time_jenkins << "ms\n";
+}
+
+TEST(HashTest, CollisionsComparison) {
+ small_struct_t small_struct = {0};
+ std::unordered_set<uint32_t> hashes;
+ int n_collisions_fnv = 0, n_collisions_jenkins = 0, n_collisions_murmur = 0,
+ n_collisions_xxhash = 0;
+
+ // FNV
+ for (int i = 0; i < 10 * N_HASHES; i++) {
+ small_struct.data[0] = i;
+ uint32_t h =
+ cumulative_hash32(&small_struct, sizeof(small_struct_t), init_val);
+
+ if (hashes.find(h) != hashes.end()) n_collisions_fnv++;
+ hashes.insert(h);
+ }
+
+ hashes.clear();
+
+ // Jenkins
+ for (int i = 0; i < 10 * N_HASHES; i++) {
+ small_struct.data[0] = i;
+ uint32_t h = hash(&small_struct, sizeof(small_struct_t));
+
+ if (hashes.find(h) != hashes.end()) n_collisions_jenkins++;
+ hashes.insert(h);
+ }
+
+ std::cout << "Small struct (size = " << sizeof(small_struct_t) << " bytes)\n";
+ std::cout << "FNV: " << n_collisions_fnv << " collision/s\n";
+ std::cout << "Jenkins: " << n_collisions_jenkins << " collision/s\n";
} \ No newline at end of file
diff --git a/hicn-light/src/hicn/test/test-interest_manifest.cc b/hicn-light/src/hicn/test/test-interest_manifest.cc
new file mode 100644
index 000000000..6408a3f2a
--- /dev/null
+++ b/hicn-light/src/hicn/test/test-interest_manifest.cc
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+extern "C" {
+#include <hicn/core/interest_manifest.h>
+}
+
+static constexpr size_t WORD_SIZE = 32;
+
+class InterestManifestTest : public ::testing::Test {
+ protected:
+ InterestManifestTest() {}
+ virtual ~InterestManifestTest() {}
+};
+
+TEST_F(InterestManifestTest, OneWordBitmapUpdate) {
+ u32 initial_bitmap[1];
+ u32 curr_bitmap[1] = {0};
+ initial_bitmap[0] = 0x00000b07; // 000000000000000000000101100000111
+
+ // Consume first 4 'one' bits (i.e. suffixes), reaching position 9
+ int pos = 0, max_suffixes = 4;
+ pos = interest_manifest_update_bitmap(initial_bitmap, curr_bitmap, pos,
+ WORD_SIZE, max_suffixes);
+ EXPECT_EQ(pos, 9);
+ EXPECT_EQ(curr_bitmap[0], 0x00000107);
+
+ // Consume the remaining 2 'one' bits, reaching end of bitmap
+ u32 curr_bitmap2[1] = {0};
+ pos = interest_manifest_update_bitmap(initial_bitmap, curr_bitmap2, pos,
+ WORD_SIZE, max_suffixes);
+ EXPECT_EQ(pos, WORD_SIZE);
+ EXPECT_EQ(curr_bitmap2[0], 0x00000a00);
+
+ // Consume all suffixes at once
+ u32 curr_bitmap3[1] = {0};
+ max_suffixes = 16;
+ pos = interest_manifest_update_bitmap(initial_bitmap, curr_bitmap3, 0,
+ WORD_SIZE, max_suffixes);
+ EXPECT_EQ(pos, WORD_SIZE);
+ EXPECT_EQ(curr_bitmap3[0], initial_bitmap[0]);
+}
+
+TEST_F(InterestManifestTest, TwoWordBitmapUpdate) {
+ u32 initial_bitmap[2];
+ initial_bitmap[0] = 0x00000b07;
+ initial_bitmap[1] = 0x00000b07;
+ // -> 100000000000000000000101100000111000000000000000000000101100000111
+
+ int expected_pos[] = {34, 64};
+ u32 expected_bitmap[][2] = {{0x00000b07, 0x00000003}, {0x0, 0x00000b04}};
+
+ // Loop to consume all suffixes
+ int pos = 0, max_suffixes = 8, i = 0, len = WORD_SIZE * 2;
+ while (pos != len) {
+ u32 curr_bitmap[2] = {0};
+ pos = interest_manifest_update_bitmap(initial_bitmap, curr_bitmap, pos, len,
+ max_suffixes);
+
+ EXPECT_EQ(pos, expected_pos[i]);
+ EXPECT_EQ(curr_bitmap[0], expected_bitmap[i][0]);
+ EXPECT_EQ(curr_bitmap[1], expected_bitmap[i][1]);
+ i++;
+ }
+} \ No newline at end of file
diff --git a/hicn-light/src/hicn/test/test-khash.cc b/hicn-light/src/hicn/test/test-khash.cc
index 4fcb48c31..f437f8858 100644
--- a/hicn-light/src/hicn/test/test-khash.cc
+++ b/hicn-light/src/hicn/test/test-khash.cc
@@ -24,7 +24,7 @@
#include <netinet/in.h>
extern "C" {
-#include <hicn/base/khash.h>
+#include <hicn/util/khash.h>
}
KHASH_MAP_INIT_INT(int, unsigned char)
diff --git a/hicn-light/src/hicn/test/test-msgbuf_pool.cc b/hicn-light/src/hicn/test/test-msgbuf_pool.cc
index 5537aa216..e9c8e6424 100644
--- a/hicn-light/src/hicn/test/test-msgbuf_pool.cc
+++ b/hicn-light/src/hicn/test/test-msgbuf_pool.cc
@@ -26,7 +26,7 @@
extern "C" {
#define WITH_TESTS
#include <hicn/core/msgbuf_pool.h>
-#include <hicn/base/pool.h>
+#include <hicn/util/pool.h>
}
class MsgbufPoolTest : public ::testing::Test {
diff --git a/hicn-light/src/hicn/test/test-packet_cache.cc b/hicn-light/src/hicn/test/test-packet_cache.cc
index bb24daeb8..0b4b214f0 100644
--- a/hicn-light/src/hicn/test/test-packet_cache.cc
+++ b/hicn-light/src/hicn/test/test-packet_cache.cc
@@ -15,23 +15,26 @@
#include <gtest/gtest.h>
-#include <thread>
#include <optional>
+#include <random>
+#include <hicn/test/test-utils.h>
extern "C" {
#define WITH_TESTS
#include <hicn/core/packet_cache.h>
}
-const unsigned CS_SIZE = 100;
-const unsigned CONN_ID = 0;
-const unsigned CONN_ID_2 = 1;
-const unsigned MSGBUF_ID = 0;
-const unsigned MSGBUF_ID_2 = 1;
-const unsigned MSGBUF_ID_3 = 2;
-const unsigned FIVE_SECONDS = 5000;
-const unsigned IPV4_LEN = 32;
-const unsigned IPV6_LEN = 128;
+static constexpr unsigned CS_SIZE = 100;
+static constexpr unsigned CONN_ID = 0;
+static constexpr unsigned CONN_ID_2 = 1;
+static constexpr unsigned MSGBUF_ID = 0;
+static constexpr unsigned MSGBUF_ID_2 = 1;
+static constexpr unsigned MSGBUF_ID_3 = 2;
+static constexpr unsigned FIVE_SECONDS = 5000;
+static constexpr unsigned IPV4_LEN = 32;
+static constexpr unsigned IPV6_LEN = 128;
+
+static constexpr int N_OPS = 50000;
class PacketCacheTest : public ::testing::Test {
protected:
@@ -40,33 +43,78 @@ class PacketCacheTest : public ::testing::Test {
name = (Name *)malloc(sizeof(Name));
name_CreateFromAddress(name, AF_INET, IPV4_ANY, IPV4_LEN);
msgbuf_pool = msgbuf_pool_create();
+ msgbuf = msgbuf_create(msgbuf_pool, CONN_ID, name);
}
+
virtual ~PacketCacheTest() {
- pkt_cache_free(pkt_cache);
+ free(name);
msgbuf_pool_free(msgbuf_pool);
+ pkt_cache_free(pkt_cache);
+ }
+
+ msgbuf_t *msgbuf_create(msgbuf_pool_t *msgbuf_pool, unsigned conn_id,
+ Name *name,
+ std::optional<Ticks> lifetime = FIVE_SECONDS) {
+ msgbuf_t *msgbuf;
+ msgbuf_pool_get(msgbuf_pool, &msgbuf);
+
+ msgbuf->connection_id = conn_id;
+ name_Copy(name, msgbuf_get_name(msgbuf));
+ hicn_packet_init_header(HF_INET6_TCP,
+ (hicn_header_t *)msgbuf_get_packet(msgbuf));
+ msgbuf_set_interest_lifetime(msgbuf, *lifetime);
+
+ return msgbuf;
+ }
+
+ Name get_name_from_prefix(const char *prefix_str) {
+ ip_address_t prefix;
+ inet_pton(AF_INET6, prefix_str, (struct in6_addr *)&prefix);
+
+ Name name;
+ name_CreateFromAddress(&name, AF_INET6, prefix, IPV6_LEN);
+
+ return name;
}
pkt_cache_t *pkt_cache;
pkt_cache_entry_t *entry = nullptr;
msgbuf_pool_t *msgbuf_pool;
Name *name;
-};
-
-msgbuf_t *msgbuf_factory(msgbuf_pool_t *msgbuf_pool, unsigned conn_id,
- Name *name,
- std::optional<Ticks> lifetime = FIVE_SECONDS) {
msgbuf_t *msgbuf;
- msgbuf_pool_get(msgbuf_pool, &msgbuf);
-
- msgbuf->connection_id = conn_id;
- name_Copy(name, msgbuf_get_name(msgbuf));
- hicn_packet_init_header(HF_INET6_TCP,
- (hicn_header_t *)msgbuf_get_packet(msgbuf));
- // Same as 'msgbuf_set_data_expiry_time',
- // it would write in the same field
- msgbuf_set_interest_lifetime(msgbuf, *lifetime);
+};
- return msgbuf;
+TEST_F(PacketCacheTest, LowLevelOperations) {
+ int rc;
+ kh_pkt_cache_prefix_t *prefix_to_suffixes = kh_init_pkt_cache_prefix();
+ NameBitvector *prefix = name_GetContentName(name);
+ _add_suffix(prefix_to_suffixes, prefix, 1, 11);
+ _add_suffix(prefix_to_suffixes, prefix, 2, 22);
+
+ unsigned id = _get_suffix(prefix_to_suffixes, prefix, 1, &rc);
+ EXPECT_EQ(rc, KH_FOUND);
+ EXPECT_EQ(id, 11);
+
+ id = _get_suffix(prefix_to_suffixes, prefix, 2, &rc);
+ EXPECT_EQ(rc, KH_FOUND);
+ EXPECT_EQ(id, 22);
+
+ id = _get_suffix(prefix_to_suffixes, prefix, 5, &rc);
+ EXPECT_EQ(rc, KH_NOT_FOUND);
+ EXPECT_EQ(id, -1);
+
+ _add_suffix(prefix_to_suffixes, prefix, 5, 55);
+ id = _get_suffix(prefix_to_suffixes, prefix, 5, &rc);
+ EXPECT_EQ(rc, KH_FOUND);
+ EXPECT_EQ(id, 55);
+
+ _remove_suffix(prefix_to_suffixes, prefix, 2);
+ _add_suffix(prefix_to_suffixes, prefix, 2, 222);
+ id = _get_suffix(prefix_to_suffixes, prefix, 2, &rc);
+ EXPECT_EQ(rc, KH_FOUND);
+ EXPECT_EQ(id, 222);
+
+ _prefix_map_free(prefix_to_suffixes);
}
TEST_F(PacketCacheTest, CreatePacketCache) {
@@ -89,10 +137,12 @@ TEST_F(PacketCacheTest, AddPacketCacheEntry) {
EXPECT_NE(entry, nullptr);
ASSERT_EQ(pkt_cache_get_size(pkt_cache), 1u);
- // // Get entry by name
- Name name_key = name_key_factory(name);
- khiter_t k = kh_get_pkt_cache_name(pkt_cache->index_by_name, &name_key);
- EXPECT_NE(k, kh_end(pkt_cache->index_by_name));
+ // Get entry by name
+ pkt_cache_lookup_t lookup_result;
+ off_t entry_id;
+ pkt_cache_entry_t *entry = pkt_cache_lookup(pkt_cache, name, msgbuf_pool,
+ &lookup_result, &entry_id, true);
+ EXPECT_NE(lookup_result, PKT_CACHE_LU_NONE);
}
TEST_F(PacketCacheTest, GetCS) {
@@ -141,14 +191,11 @@ TEST_F(PacketCacheTest, AddEntryAndLookup) {
}
TEST_F(PacketCacheTest, AddToPIT) {
- // Prepare msgbuf
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name);
-
// Check if entry properly created
- pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf);
+ pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name);
ASSERT_NE(entry, nullptr);
EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE);
- EXPECT_EQ(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID), true);
+ EXPECT_TRUE(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID));
ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u);
ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u);
@@ -162,9 +209,6 @@ TEST_F(PacketCacheTest, AddToPIT) {
}
TEST_F(PacketCacheTest, AddToCS) {
- // Prepare msgbuf
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name);
-
// Check if entry properly created
pkt_cache_entry_t *entry =
pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID);
@@ -191,9 +235,8 @@ TEST_F(PacketCacheTest, AddToCS) {
}
TEST_F(PacketCacheTest, PitToCS) {
- // Prepare msgbuf and PIT entry
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name);
- pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf);
+ // Prepare PIT entry
+ pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name);
off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry);
ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u);
ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u);
@@ -224,8 +267,7 @@ TEST_F(PacketCacheTest, PitToCS) {
}
TEST_F(PacketCacheTest, CsToPIT) {
- // Prepare msgbuf and CS entry
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name);
+ // Prepare CS entry
pkt_cache_entry_t *entry =
pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID);
off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry);
@@ -237,7 +279,7 @@ TEST_F(PacketCacheTest, CsToPIT) {
entry_id);
ASSERT_NE(entry, nullptr);
EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE);
- EXPECT_EQ(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID), true);
+ EXPECT_TRUE(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID));
ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u);
ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u);
@@ -250,14 +292,13 @@ TEST_F(PacketCacheTest, CsToPIT) {
}
TEST_F(PacketCacheTest, UpdateInPIT) {
- // Prepare msgbuf and PIT entry
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name);
- pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf);
+ // Prepare PIT entry
+ pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name);
off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry);
Name new_name;
name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN);
- msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name);
+ msgbuf_t *new_msgbuf = msgbuf_create(msgbuf_pool, CONN_ID_2, &new_name);
// Check if entry properly updated
pkt_cache_update_pit(pkt_cache, entry, new_msgbuf);
@@ -276,15 +317,14 @@ TEST_F(PacketCacheTest, UpdateInPIT) {
}
TEST_F(PacketCacheTest, UpdateInCS) {
- // Prepare msgbuf and CS entry
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name);
+ // Prepare CS entry
pkt_cache_entry_t *entry =
pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID);
off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry);
Name new_name;
name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN);
- msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name);
+ msgbuf_t *new_msgbuf = msgbuf_create(msgbuf_pool, CONN_ID_2, &new_name);
// Check if entry properly updated
pkt_cache_update_cs(pkt_cache, msgbuf_pool, entry, new_msgbuf, MSGBUF_ID_2);
@@ -304,9 +344,8 @@ TEST_F(PacketCacheTest, UpdateInCS) {
}
TEST_F(PacketCacheTest, RemoveFromPIT) {
- // Prepare msgbuf and PIT entry
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name);
- pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf);
+ // Prepare PIT entry
+ pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name);
ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u);
ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u);
@@ -324,8 +363,7 @@ TEST_F(PacketCacheTest, RemoveFromPIT) {
}
TEST_F(PacketCacheTest, RemoveFromCS) {
- // Prepare msgbuf and CS entry
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name);
+ // Prepare CS entry
pkt_cache_entry_t *entry =
pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID);
ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u);
@@ -351,11 +389,10 @@ TEST_F(PacketCacheTest, RemoveFromCS) {
}
TEST_F(PacketCacheTest, AddTwoEntriesToCS) {
- // Prepare msgbufs
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name);
+ // Prepare another msgbuf
Name new_name;
name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN);
- msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name);
+ msgbuf_t *new_msgbuf = msgbuf_create(msgbuf_pool, CONN_ID_2, &new_name);
pkt_cache_entry_t *entry_1 =
pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID);
@@ -374,18 +411,17 @@ TEST_F(PacketCacheTest, AddTwoEntriesToCS) {
}
TEST_F(PacketCacheTest, AggregateInPIT) {
- // Prepare msgbufs
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name);
+ // Prepare another msgbuf
Name new_name;
name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN);
- msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name);
+ msgbuf_t *new_msgbuf = msgbuf_create(msgbuf_pool, CONN_ID_2, &new_name);
// Check if entry properly created (use sleep to get an updated ts)
- pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf);
+ pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name);
Ticks old_lifetime = entry->expire_ts;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
bool is_aggregated =
- pkt_cache_try_aggregate_in_pit(pkt_cache, entry, new_msgbuf);
+ pkt_cache_try_aggregate_in_pit(pkt_cache, entry, new_msgbuf, name);
Ticks new_lifetime = entry->expire_ts;
ASSERT_NE(entry, nullptr);
@@ -403,18 +439,17 @@ TEST_F(PacketCacheTest, AggregateInPIT) {
}
TEST_F(PacketCacheTest, RetransmissionInPIT) {
- // Prepare msgbufs (using same connection ID)
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name);
+ // Prepare another msgbuf (using same connection ID)
Name new_name;
name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN);
- msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, &new_name);
+ msgbuf_t *new_msgbuf = msgbuf_create(msgbuf_pool, CONN_ID, &new_name);
// Check if entry properly created (use sleep to get an updated ts)
- pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf);
+ pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name);
Ticks old_lifetime = entry->expire_ts;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
bool is_aggregated =
- pkt_cache_try_aggregate_in_pit(pkt_cache, entry, new_msgbuf);
+ pkt_cache_try_aggregate_in_pit(pkt_cache, entry, new_msgbuf, name);
Ticks new_lifetime = entry->expire_ts;
ASSERT_NE(entry, nullptr);
@@ -433,10 +468,10 @@ TEST_F(PacketCacheTest, RetransmissionInPIT) {
TEST_F(PacketCacheTest, LookupExpiredInterest) {
// Prepare msgbuf with 0 as interest lifetime
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name, 0);
+ msgbuf_t *msgbuf = msgbuf_create(msgbuf_pool, CONN_ID, name, 0);
// Add to PIT
- pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf);
+ pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name);
ASSERT_NE(entry, nullptr);
// Wait to make the interest expire
@@ -451,7 +486,7 @@ TEST_F(PacketCacheTest, LookupExpiredInterest) {
TEST_F(PacketCacheTest, LookupExpiredData) {
// Prepare msgbuf with 0 as data expiry time
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name, 0);
+ msgbuf_t *msgbuf = msgbuf_create(msgbuf_pool, CONN_ID, name, 0);
// Add to CS
pkt_cache_entry_t *entry =
@@ -470,20 +505,20 @@ TEST_F(PacketCacheTest, LookupExpiredData) {
TEST_F(PacketCacheTest, GetStaleEntries) {
// Add to CS a msgbuf with immediate expiration (i.e. stale)
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name, 0);
+ msgbuf_t *msgbuf = msgbuf_create(msgbuf_pool, CONN_ID, name, 0);
pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID);
// Add to CS another msgbuf with immediate expiration (i.e. stale)
Name name_2;
name_CreateFromAddress(&name_2, AF_INET, IPV4_LOOPBACK, IPV4_LEN);
- msgbuf_t *msgbuf_2 = msgbuf_factory(msgbuf_pool, CONN_ID, &name_2, 0);
+ msgbuf_t *msgbuf_2 = msgbuf_create(msgbuf_pool, CONN_ID, &name_2, 0);
pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf_2, MSGBUF_ID_2);
// Add to CS a msgbuf with 5-seconds expiration (i.e. not stale)
Name name_3;
name_CreateFromAddress(&name_3, AF_INET6, IPV6_LOOPBACK, IPV6_LEN);
msgbuf_t *msgbuf_3 =
- msgbuf_factory(msgbuf_pool, CONN_ID, &name_3, FIVE_SECONDS);
+ msgbuf_create(msgbuf_pool, CONN_ID, &name_3, FIVE_SECONDS);
pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf_3, MSGBUF_ID_3);
size_t num_stale_entries = pkt_cache_get_num_cs_stale_entries(pkt_cache);
@@ -502,7 +537,7 @@ TEST_F(PacketCacheTest, GetMultipleStaleEntries) {
inet_pton(AF_INET6, name, (struct in6_addr *)&addr);
Name name;
name_CreateFromAddress(&name, AF_INET6, addr, IPV6_LEN);
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, i, &name, 0);
+ msgbuf_t *msgbuf = msgbuf_create(msgbuf_pool, i, &name, 0);
pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, i);
}
@@ -514,7 +549,7 @@ TEST_F(PacketCacheTest, GetMultipleStaleEntries) {
inet_pton(AF_INET6, name, (struct in6_addr *)&addr);
Name name;
name_CreateFromAddress(&name, AF_INET6, addr, IPV6_LEN);
- msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, i, &name, FIVE_SECONDS);
+ msgbuf_t *msgbuf = msgbuf_create(msgbuf_pool, i, &name, FIVE_SECONDS);
pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, i);
}
@@ -522,3 +557,126 @@ TEST_F(PacketCacheTest, GetMultipleStaleEntries) {
size_t num_stale_entries = pkt_cache_get_num_cs_stale_entries(pkt_cache);
EXPECT_EQ(num_stale_entries, (size_t)NUM_STALES);
}
+
+TEST_F(PacketCacheTest, PerformanceDoubleLookup) {
+ Name tmp = get_name_from_prefix("b001::0");
+
+ auto elapsed_time_double = get_execution_time([&]() {
+ kh_pkt_cache_prefix_t *prefix_to_suffixes = kh_init_pkt_cache_prefix();
+
+ // Add to hash table
+ for (int seq = 0; seq < N_OPS; seq++) {
+ name_SetSegment(&tmp, seq);
+ _add_suffix(prefix_to_suffixes, name_GetContentName(&tmp),
+ name_GetSegment(&tmp), name_GetSegment(&tmp));
+ }
+
+ // Read from hash table
+ int rc;
+ for (int seq = 0; seq < N_OPS; seq++) {
+ name_SetSegment(&tmp, seq);
+ _get_suffix(prefix_to_suffixes, name_GetContentName(&tmp), seq, &rc);
+ }
+
+ _prefix_map_free(prefix_to_suffixes);
+ });
+ std::cout << "Double lookup: " << elapsed_time_double << " ms\n";
+}
+
+TEST_F(PacketCacheTest, PerformanceCachedLookup) {
+ Name tmp = get_name_from_prefix("b001::0");
+
+ auto elapsed_time_single = get_execution_time([&]() {
+ kh_pkt_cache_prefix_t *prefix_to_suffixes = kh_init_pkt_cache_prefix();
+ kh_pkt_cache_suffix_t *suffixes =
+ _get_suffixes(prefix_to_suffixes, name_GetContentName(&tmp));
+
+ // Add to hash table
+ for (int seq = 0; seq < N_OPS; seq++) {
+ name_SetSegment(&tmp, seq);
+ __add_suffix(suffixes, name_GetSegment(&tmp), name_GetSegment(&tmp));
+ }
+
+ // Read from hash table
+ int rc;
+ for (int seq = 0; seq < N_OPS; seq++) {
+ name_SetSegment(&tmp, seq);
+ __get_suffix(suffixes, name_GetSegment(&tmp), &rc);
+ }
+
+ _prefix_map_free(prefix_to_suffixes);
+ });
+ std::cout << "Cached lookup: " << elapsed_time_single << " ms\n";
+}
+
+TEST_F(PacketCacheTest, PerformanceCachedLookupRandom) {
+ Name tmp = get_name_from_prefix("b001::0");
+
+ // Prepare random sequence numbers
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ uint32_t seqs[N_OPS];
+ for (int seq = 0; seq < N_OPS; seq++) seqs[seq] = seq;
+ std::shuffle(std::begin(seqs), std::end(seqs), gen);
+
+ auto elapsed_time_single_rand = get_execution_time([&]() {
+ kh_pkt_cache_prefix_t *prefix_to_suffixes = kh_init_pkt_cache_prefix();
+ kh_pkt_cache_suffix_t *suffixes =
+ _get_suffixes(prefix_to_suffixes, name_GetContentName(&tmp));
+
+ // Add to hash table
+ for (int seq = 0; seq < N_OPS; seq++) {
+ name_SetSegment(&tmp, seqs[seq]);
+ __add_suffix(suffixes, name_GetSegment(&tmp), name_GetSegment(&tmp));
+ }
+
+ // Read from hash table
+ int rc;
+ for (int seq = 0; seq < N_OPS; seq++) {
+ name_SetSegment(&tmp, seqs[seq]);
+ __get_suffix(suffixes, name_GetSegment(&tmp), &rc);
+ }
+
+ _prefix_map_free(prefix_to_suffixes);
+ });
+ std::cout << "Cached lookup (rand): " << elapsed_time_single_rand << " ms\n";
+}
+
+TEST_F(PacketCacheTest, Clear) {
+ Name tmp_name1, tmp_name2;
+ cs_t *cs = pkt_cache_get_cs(pkt_cache);
+
+ // Create name and add to msgbuf pool
+ name_Copy(name, &tmp_name1);
+ name_SetSegment(&tmp_name1, 1);
+ msgbuf_t *tmp_msgbuf1 = msgbuf_create(msgbuf_pool, CONN_ID_2, &tmp_name1);
+
+ // Create (another) name and add to msgbuf pool
+ name_Copy(name, &tmp_name2);
+ name_SetSegment(&tmp_name2, 2);
+ msgbuf_t *tmp_msgbuf2 = msgbuf_create(msgbuf_pool, CONN_ID_2, &tmp_name2);
+
+ // Add to packet cache (2 entries in the CS, 1 in the PIT)
+ pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID);
+ pkt_cache_add_to_pit(pkt_cache, tmp_msgbuf1, &tmp_name1);
+ pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, tmp_msgbuf2, MSGBUF_ID_2);
+
+ // Check stats (before clearing the packet cache)
+ ASSERT_EQ(pkt_cache_get_size(pkt_cache), 3u);
+ ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u);
+ ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 2u);
+ ASSERT_EQ(cs->num_entries, 2u);
+ ASSERT_EQ(cs->stats.lru.countAdds, 2u);
+
+ // Clear packet cache (i.e. remove content packets from packet cache):
+ // PIT entry should still be there while CS entries are cleared
+ pkt_cache_cs_clear(pkt_cache);
+ cs = pkt_cache_get_cs(pkt_cache);
+
+ // Check stats (after clearing the packet cache)
+ ASSERT_EQ(pkt_cache_get_size(pkt_cache), 1u);
+ ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u);
+ ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u);
+ ASSERT_EQ(cs->num_entries, 0u);
+ ASSERT_EQ(cs->stats.lru.countAdds, 0u);
+} \ No newline at end of file
diff --git a/hicn-light/src/hicn/test/test-pool.cc b/hicn-light/src/hicn/test/test-pool.cc
index c631415ca..8cd891d6a 100644
--- a/hicn-light/src/hicn/test/test-pool.cc
+++ b/hicn-light/src/hicn/test/test-pool.cc
@@ -25,7 +25,7 @@
extern "C" {
#define WITH_TESTS
-#include <hicn/base/pool.h>
+#include <hicn/util/pool.h>
}
/*
diff --git a/hicn-light/src/hicn/test/test-ring.cc b/hicn-light/src/hicn/test/test-ring.cc
index 51f1f5327..ab96d76c0 100644
--- a/hicn-light/src/hicn/test/test-ring.cc
+++ b/hicn-light/src/hicn/test/test-ring.cc
@@ -25,7 +25,7 @@
extern "C" {
#define WITH_TESTS
-#include <hicn/base/ring.h>
+#include <hicn/util/ring.h>
}
#define DEFAULT_SIZE 10UL
diff --git a/hicn-light/src/hicn/test/test-subscription.cc b/hicn-light/src/hicn/test/test-subscription.cc
index 18ef60c0d..f89254e67 100644
--- a/hicn-light/src/hicn/test/test-subscription.cc
+++ b/hicn-light/src/hicn/test/test-subscription.cc
@@ -6,7 +6,7 @@
extern "C" {
#include <hicn/core/subscription.h>
-#include <hicn/base/vector.h>
+#include <hicn/util/vector.h>
}
static inline unsigned CONN_ID = 1;
diff --git a/hicn-light/src/hicn/test/test-utils.h b/hicn-light/src/hicn/test/test-utils.h
new file mode 100644
index 000000000..577629584
--- /dev/null
+++ b/hicn-light/src/hicn/test/test-utils.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <vector>
+#include <thread>
+#include <numeric>
+
+static constexpr int N_RUNS = 100;
+
+// Utility function for time execution calculation
+template <typename F, typename... Args>
+double get_execution_time(F func, Args &&...args) {
+ std::vector<float> execution_times;
+
+ for (int i = 0; i < N_RUNS; i++) {
+ auto start = std::chrono::high_resolution_clock::now();
+ func(std::forward<Args>(args)...);
+ auto end = std::chrono::high_resolution_clock::now();
+
+ std::chrono::duration<double, std::milli> ms = end - start;
+ execution_times.emplace_back(ms.count());
+ }
+
+ // Calculate average
+ return std::reduce(execution_times.begin(), execution_times.end()) /
+ execution_times.size();
+} \ No newline at end of file
diff --git a/hicn-light/src/hicn/test/test-vector.cc b/hicn-light/src/hicn/test/test-vector.cc
index fb30a8228..dda71fd0c 100644
--- a/hicn-light/src/hicn/test/test-vector.cc
+++ b/hicn-light/src/hicn/test/test-vector.cc
@@ -15,26 +15,12 @@
#include <gtest/gtest.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include <netinet/in.h>
-
extern "C" {
-#define WITH_TESTS
-#include <hicn/base/vector.h>
+#include <hicn/util/vector.h>
}
-/*
- * TODO
- * - test max_size
- */
-
-#define DEFAULT_SIZE 10
-const size_t N_ELEMENTS = 5;
+static constexpr size_t DEFAULT_SIZE = 10;
+static constexpr size_t N_ELEMENTS = 5;
class VectorTest : public ::testing::Test {
protected:
@@ -44,58 +30,62 @@ class VectorTest : public ::testing::Test {
int *vector = NULL;
};
-/* TEST: Vector allocation and initialization */
-TEST_F(VectorTest, VectorAllocate) {
- /* Allocated size should be the next power of two */
+TEST_F(VectorTest, VectorAllocateAndResize) {
+ // Allocated size should be the next power of two
EXPECT_EQ(vector_get_alloc_size(vector), 16UL);
- /* Setting elements within the allocated size should not trigger a resize */
+ // Setting elements within the allocated size should not trigger a resize
vector_ensure_pos(vector, 15);
EXPECT_EQ(vector_get_alloc_size(vector), 16UL);
- /* Setting elements after should through */
+ // Setting elements after should through
vector_ensure_pos(vector, 16);
EXPECT_EQ(vector_get_alloc_size(vector), 32UL);
-
- /* Check that free indices and bitmaps are correctly updated */
}
TEST_F(VectorTest, VectorSize) {
- vector_push(vector, 109);
- int size = vector_len(vector);
- EXPECT_EQ(size, 1);
- vector_push(vector, 109);
- size = vector_len(vector);
- EXPECT_EQ(size, 2);
- vector_push(vector, 109);
- size = vector_len(vector);
- EXPECT_EQ(size, 3);
+ EXPECT_EQ(vector_len(vector), 0);
+
+ // Check size after pushing one element
+ vector_push(vector, 1);
+ EXPECT_EQ(vector_len(vector), 1);
+
+ // Check size after pushing additional elements
+ vector_push(vector, 2);
+ vector_push(vector, 3);
+ EXPECT_EQ(vector_len(vector), 3);
+
+ // Try adding multiple elements
+ const int n_elements_to_add = 5;
+ size_t expected_new_len = vector_len(vector) + n_elements_to_add;
+ for (int i = 0; i < n_elements_to_add; i++) vector_push(vector, i);
+ EXPECT_EQ(vector_len(vector), expected_new_len);
}
TEST_F(VectorTest, VectorCheckValue) {
+ // Add elements
vector_push(vector, 109);
vector_push(vector, 200);
- EXPECT_EQ(vector[0], 109);
- EXPECT_EQ(vector[1], 200);
-}
-
-TEST_F(VectorTest, VectorEnsurePos) {
- printf(" %p\n", vector);
- vector_ensure_pos(vector, 1025);
- for (int i = 0; i < 1025; i++) {
- // printf("i %d\n", i);
- // printf (" %p\n", vector);
- vector_push(vector, i);
- }
- int size = vector_len(vector);
- EXPECT_EQ(size, 1025);
+ EXPECT_EQ(vector_at(vector, 0), 109);
+ EXPECT_EQ(vector_at(vector, 1), 200);
+
+ // Update element
+ vector_set(vector, 1, 400);
+ EXPECT_EQ(vector_at(vector, 1), 400);
+
+ // Add at last available position
+ size_t prev_size = vector_len(vector);
+ vector_set(vector, vector_len(vector) - 1, 123);
+ EXPECT_EQ(vector_at(vector, vector_len(vector) - 1), 123);
+ EXPECT_EQ(prev_size, vector_len(vector)) << "Size should not have changed";
}
TEST_F(VectorTest, RemoveElement) {
// Populate vector
for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(vector, i);
EXPECT_EQ(vector_len(vector), N_ELEMENTS);
- for (size_t i = 0; i < vector_len(vector); i++) EXPECT_EQ(vector[i], (int)i);
+ for (size_t i = 0; i < vector_len(vector); i++)
+ EXPECT_EQ(vector_at(vector, i), (int)i);
// Remove element
int value_to_remove = 3;
@@ -104,15 +94,30 @@ TEST_F(VectorTest, RemoveElement) {
EXPECT_EQ(vector_len(vector), N_ELEMENTS - 1);
EXPECT_EQ(num_removed, 1);
for (size_t i = 0; i < vector_len(vector); i++)
- EXPECT_NE(vector[i], value_to_remove);
+ EXPECT_NE(vector_at(vector, i), value_to_remove);
+}
+
+TEST_F(VectorTest, RemoveNonExistingElement) {
+ // Push some initial values
+ vector_push(vector, 1);
+ vector_push(vector, 2);
+ vector_push(vector, 3);
+ EXPECT_EQ(vector_len(vector), 3);
+
+ // Remove non-existing element
+ int num_removed = vector_remove_unordered(vector, 5);
+ EXPECT_EQ(num_removed, 0);
+ size_t prev_size = vector_len(vector);
+ EXPECT_EQ(prev_size, vector_len(vector)) << "Size should not have changed";
}
TEST_F(VectorTest, RemoveDuplicatedElement) {
// Populate vector
for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(vector, i);
EXPECT_EQ(vector_len(vector), N_ELEMENTS);
- for (size_t i = 0; i < vector_len(vector); i++) EXPECT_EQ(vector[i], (int)i);
- vector[0] = 3; // Duplicate element
+ for (size_t i = 0; i < vector_len(vector); i++)
+ EXPECT_EQ(vector_at(vector, i), (int)i);
+ vector_set(vector, 0, 3); // Duplicate element
// Remove (duplicated) elements
int value_to_remove = 3;
@@ -121,7 +126,7 @@ TEST_F(VectorTest, RemoveDuplicatedElement) {
EXPECT_EQ(vector_len(vector), N_ELEMENTS - 2);
EXPECT_EQ(num_removed, 2);
for (size_t i = 0; i < vector_len(vector); i++)
- EXPECT_NE(vector[i], value_to_remove);
+ EXPECT_NE(vector_at(vector, i), value_to_remove);
}
TEST_F(VectorTest, Iterate) {
@@ -139,10 +144,89 @@ TEST_F(VectorTest, MultipleResize) {
for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(small_vector, i);
- for (size_t i = 0; i < N_ELEMENTS; i++) EXPECT_EQ(small_vector[i], (int)i);
+ for (size_t i = 0; i < N_ELEMENTS; i++)
+ EXPECT_EQ(vector_at(small_vector, i), (int)i);
EXPECT_EQ(vector_len(small_vector), 5UL);
EXPECT_EQ(vector_get_alloc_size(small_vector), 8UL);
vector_free(small_vector);
+}
+
+TEST_F(VectorTest, MaxSize) {
+ const int max_size = 4;
+
+ // Fill the vector until max size is reached
+ int *small_vector;
+ vector_init(small_vector, 2, max_size);
+ for (int i = 0; i < max_size; i++) vector_push(small_vector, i);
+
+ // Try expanding or appending elements should fail
+ int rc = vector_ensure_pos(small_vector, max_size);
+ EXPECT_EQ(rc, -1);
+ rc = vector_push(small_vector, 123);
+ EXPECT_EQ(rc, -1);
+
+ vector_free(small_vector);
+}
+
+TEST_F(VectorTest, Contains) {
+ // No elements
+ EXPECT_EQ(vector_contains(vector, 1), false);
+
+ // Push one element
+ vector_push(vector, 1);
+ EXPECT_EQ(vector_contains(vector, 1), true);
+
+ // Update element
+ vector_set(vector, 0, 2);
+ EXPECT_EQ(vector_contains(vector, 1), false);
+ EXPECT_EQ(vector_contains(vector, 2), true);
+}
+
+TEST_F(VectorTest, Remove) {
+ // Remove element at invalid position
+ int rc = vector_remove_at(vector, 2);
+ EXPECT_EQ(rc, -1); // Failure
+
+ // Push two elements and remove the second one
+ vector_push(vector, 1);
+ vector_push(vector, 2);
+ rc = vector_remove_at(vector, 1);
+ EXPECT_EQ(rc, 0); // Success
+ EXPECT_EQ(vector_len(vector), 1);
+
+ // Push another element: it should replace the previous one
+ vector_push(vector, 3);
+ EXPECT_EQ(vector_len(vector), 2);
+ EXPECT_EQ(vector_at(vector, 1), 3);
+}
+
+TEST_F(VectorTest, RemoveInTheMiddle) {
+ for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(vector, i);
+
+ // Remove element in central position
+ int rc = vector_remove_at(vector, 2);
+ EXPECT_EQ(rc, 0); // Success
+ EXPECT_EQ(vector_contains(vector, 2), false);
+ EXPECT_EQ(vector_len(vector), N_ELEMENTS - 1);
+
+ // Check if elements have been shifted (preserving the order)
+ int expected[] = {0, 1, 3, 4};
+ for (int i = 0; i < vector_len(vector); i++)
+ EXPECT_EQ(vector_at(vector, i), expected[i]);
+}
+
+TEST_F(VectorTest, Reset) {
+ vector_push(vector, 1);
+ vector_push(vector, 2);
+ EXPECT_EQ(vector_len(vector), 2);
+
+ vector_reset(vector);
+ EXPECT_EQ(vector_len(vector), 0);
+
+ vector_push(vector, 5);
+ EXPECT_EQ(vector_len(vector), 1);
+ EXPECT_EQ(vector_contains(vector, 5), true);
+ EXPECT_EQ(vector_at(vector, 0), 5);
} \ No newline at end of file