refactor(lib, hicn-light, vpp, hiperf): HICN-723 17/36417/6
authorLuca Muscariello <lumuscar@cisco.com>
Thu, 9 Jun 2022 19:34:09 +0000 (21:34 +0200)
committerLuca Muscariello <muscariello@ieee.org>
Thu, 30 Jun 2022 08:47:50 +0000 (10:47 +0200)
 - 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>
337 files changed:
.cz.toml
.gitignore
CMakeLists.txt
Dockerfile.dev
Makefile
apps/hiperf/CMakeLists.txt
apps/hiperf/src/client.cc
apps/hiperf/src/client.h
apps/hiperf/src/common.h
apps/hiperf/src/forwarder_config.h [deleted file]
apps/hiperf/src/forwarder_interface.cc [deleted file]
apps/hiperf/src/forwarder_interface.h [deleted file]
apps/hiperf/src/main.cc
apps/hiperf/src/server.cc
apps/hiperf/src/server.h
apps/http-proxy/includes/hicn/http-proxy/forwarder_interface.h
apps/http-proxy/includes/hicn/http-proxy/http_session.h
apps/http-proxy/src/icn_receiver.cc
apps/ping/src/ping_client.cc
apps/ping/src/ping_server.cc
ctrl/CMakeLists.txt
ctrl/facemgr/includes/hicn/facemgr/cfg.h
ctrl/facemgr/src/cfg.c
ctrl/facemgr/src/interfaces/network_framework/network_framework.c
ctrl/facemgr/src/loop_dispatcher.c
ctrl/libhicnctrl/includes/hicn/ctrl/api.h
ctrl/libhicnctrl/includes/hicn/ctrl/hicn-light-ng.h
ctrl/libhicnctrl/src/CMakeLists.txt
ctrl/libhicnctrl/src/api.c
ctrl/libhicnctrl/src/api_private.h
ctrl/libhicnctrl/src/modules/hicn_light_common.c
ctrl/libhicnctrl/src/modules/hicn_light_common.h
ctrl/libhicnctrl/src/modules/hicn_light_ng_api.c
docs/source/telemetry.md
docs/source/transport.md
hicn-light/CMakeLists.txt
hicn-light/src/hicn/base/CMakeLists.txt
hicn-light/src/hicn/base/bitmap.h [deleted file]
hicn-light/src/hicn/base/common.h [deleted file]
hicn-light/src/hicn/base/hash.h [deleted file]
hicn-light/src/hicn/base/khash.h [deleted file]
hicn-light/src/hicn/base/pool.c [deleted file]
hicn-light/src/hicn/base/ring.h [deleted file]
hicn-light/src/hicn/cli/hicnc.c
hicn-light/src/hicn/cli/hicnd.c
hicn-light/src/hicn/config/CMakeLists.txt
hicn-light/src/hicn/config/command_stats.c [new file with mode: 0644]
hicn-light/src/hicn/config/commands.c
hicn-light/src/hicn/config/commands.h
hicn-light/src/hicn/config/configuration.h
hicn-light/src/hicn/core/CMakeLists.txt
hicn-light/src/hicn/core/address_pair.h
hicn-light/src/hicn/core/connection.c
hicn-light/src/hicn/core/connection.h
hicn-light/src/hicn/core/connection_table.c
hicn-light/src/hicn/core/connection_table.h
hicn-light/src/hicn/core/connection_vft.h
hicn-light/src/hicn/core/content_store.c
hicn-light/src/hicn/core/content_store.h
hicn-light/src/hicn/core/fib_entry.c
hicn-light/src/hicn/core/forwarder.c
hicn-light/src/hicn/core/forwarder.h
hicn-light/src/hicn/core/interest_manifest.c [new file with mode: 0644]
hicn-light/src/hicn/core/interest_manifest.h [new file with mode: 0644]
hicn-light/src/hicn/core/listener.c
hicn-light/src/hicn/core/listener.h
hicn-light/src/hicn/core/listener_table.c
hicn-light/src/hicn/core/listener_table.h
hicn-light/src/hicn/core/msgbuf_pool.c
hicn-light/src/hicn/core/name.c
hicn-light/src/hicn/core/nameBitvector.c
hicn-light/src/hicn/core/nameBitvector.h
hicn-light/src/hicn/core/packet_cache.c
hicn-light/src/hicn/core/packet_cache.h
hicn-light/src/hicn/core/policy_stats.h
hicn-light/src/hicn/core/subscription.c
hicn-light/src/hicn/io/base.c
hicn-light/src/hicn/io/hicn.c
hicn-light/src/hicn/io/tcp.c
hicn-light/src/hicn/io/udp.c
hicn-light/src/hicn/strategies/probe_generator.c
hicn-light/src/hicn/strategies/probe_generator.h
hicn-light/src/hicn/test/CMakeLists.txt
hicn-light/src/hicn/test/test-bitmap.cc
hicn-light/src/hicn/test/test-connection_table.cc
hicn-light/src/hicn/test/test-hash.cc
hicn-light/src/hicn/test/test-interest_manifest.cc [new file with mode: 0644]
hicn-light/src/hicn/test/test-khash.cc
hicn-light/src/hicn/test/test-msgbuf_pool.cc
hicn-light/src/hicn/test/test-packet_cache.cc
hicn-light/src/hicn/test/test-pool.cc
hicn-light/src/hicn/test/test-ring.cc
hicn-light/src/hicn/test/test-subscription.cc
hicn-light/src/hicn/test/test-utils.h [new file with mode: 0644]
hicn-light/src/hicn/test/test-vector.cc
hicn-plugin/includes/vpp_plugins/hicn/error.h
hicn-plugin/src/CMakeLists.txt
hicn-plugin/src/cli.c
hicn-plugin/src/data_fwd_node.c
hicn-plugin/src/data_input_node.c
hicn-plugin/src/data_pcslookup_node.c
hicn-plugin/src/faces/app/face_prod_node.c
hicn-plugin/src/faces/face.c
hicn-plugin/src/faces/face.h
hicn-plugin/src/faces/face_flags.h [new file with mode: 0644]
hicn-plugin/src/faces/face_node.c
hicn-plugin/src/faces/iface_node.c
hicn-plugin/src/hicn.c
hicn-plugin/src/hicn.h
hicn-plugin/src/hicn_buffer_flags.h [new file with mode: 0644]
hicn-plugin/src/interest_hitcs_node.c
hicn-plugin/src/interest_hitpit.h
hicn-plugin/src/interest_hitpit_node.c
hicn-plugin/src/interest_pcslookup_node.c
hicn-plugin/src/parser.h
hicn-plugin/src/pg.c
hicn-plugin/src/pg.h
hicn-plugin/src/pg_node.c [new file with mode: 0644]
hicn-plugin/src/route.c
hicn-plugin/src/strategy_node.c
lib/includes/CMakeLists.txt
lib/includes/hicn/base.h
lib/includes/hicn/common.h
lib/includes/hicn/compat.h
lib/includes/hicn/header.h
lib/includes/hicn/ops.h
lib/includes/hicn/util/array.h
lib/includes/hicn/util/bitmap.h [new file with mode: 0644]
lib/includes/hicn/util/hash.h [new file with mode: 0644]
lib/includes/hicn/util/khash.h [new file with mode: 0644]
lib/includes/hicn/util/pool.h [moved from hicn-light/src/hicn/base/pool.h with 63% similarity]
lib/includes/hicn/util/ring.h [new file with mode: 0644]
lib/includes/hicn/util/vector.h [moved from hicn-light/src/hicn/base/vector.h with 51% similarity]
lib/src/CMakeLists.txt
lib/src/common.c
lib/src/ops.c
lib/src/protocol/ah.c
lib/src/protocol/icmp.c
lib/src/protocol/ipv4.c
lib/src/protocol/ipv6.c
lib/src/protocol/new.c
lib/src/protocol/tcp.c
lib/src/protocol/udp.c
lib/src/util/log.c
lib/src/util/pool.c [new file with mode: 0644]
lib/src/util/ring.c [moved from hicn-light/src/hicn/base/ring.c with 71% similarity]
lib/src/util/vector.c [moved from hicn-light/src/hicn/base/vector.c with 51% similarity]
libtransport/includes/hicn/transport/core/asio_wrapper.h
libtransport/includes/hicn/transport/core/connector.h
libtransport/includes/hicn/transport/core/content_object.h
libtransport/includes/hicn/transport/core/interest.h
libtransport/includes/hicn/transport/core/io_module.h
libtransport/includes/hicn/transport/core/name.h
libtransport/includes/hicn/transport/core/prefix.h
libtransport/includes/hicn/transport/interfaces/CMakeLists.txt
libtransport/includes/hicn/transport/interfaces/global_conf_interface.h
libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h [deleted file]
libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h [deleted file]
libtransport/includes/hicn/transport/interfaces/portal.h
libtransport/includes/hicn/transport/interfaces/socket_consumer.h
libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h
libtransport/includes/hicn/transport/interfaces/socket_options_keys.h
libtransport/includes/hicn/transport/interfaces/socket_producer.h
libtransport/includes/hicn/transport/interfaces/statistics.h
libtransport/includes/hicn/transport/portability/CMakeLists.txt
libtransport/includes/hicn/transport/portability/cache.h [new file with mode: 0644]
libtransport/includes/hicn/transport/portability/endianess.h [new file with mode: 0644]
libtransport/includes/hicn/transport/portability/portability.h
libtransport/includes/hicn/transport/utils/chrono_typedefs.h
libtransport/includes/hicn/transport/utils/color.h [new file with mode: 0644]
libtransport/includes/hicn/transport/utils/event_thread.h
libtransport/includes/hicn/transport/utils/linux.h
libtransport/includes/hicn/transport/utils/thread_pool.h
libtransport/src/auth/signer.cc
libtransport/src/auth/verifier.cc
libtransport/src/core/CMakeLists.txt
libtransport/src/core/constructor.cc [new file with mode: 0644]
libtransport/src/core/content_object.cc
libtransport/src/core/facade.h
libtransport/src/core/global_id_counter.h [moved from libtransport/src/io_modules/forwarder/global_id_counter.h with 100% similarity]
libtransport/src/core/global_module_manager.h [new file with mode: 0644]
libtransport/src/core/global_workers.h
libtransport/src/core/interest.cc
libtransport/src/core/io_module.cc
libtransport/src/core/local_connector.cc [deleted file]
libtransport/src/core/local_connector.h
libtransport/src/core/manifest.cc [deleted file]
libtransport/src/core/manifest.h
libtransport/src/core/manifest_format.h
libtransport/src/core/manifest_format_fixed.cc
libtransport/src/core/manifest_format_fixed.h
libtransport/src/core/manifest_inline.h [deleted file]
libtransport/src/core/name.cc
libtransport/src/core/pending_interest.h
libtransport/src/core/portal.cc
libtransport/src/core/portal.h
libtransport/src/core/prefix.cc
libtransport/src/core/udp_connector.cc
libtransport/src/core/udp_connector.h
libtransport/src/core/udp_listener.cc
libtransport/src/core/udp_listener.h
libtransport/src/implementation/CMakeLists.txt
libtransport/src/implementation/p2psecure_socket_consumer.cc [deleted file]
libtransport/src/implementation/p2psecure_socket_consumer.h [deleted file]
libtransport/src/implementation/p2psecure_socket_producer.cc [deleted file]
libtransport/src/implementation/p2psecure_socket_producer.h [deleted file]
libtransport/src/implementation/socket.cc
libtransport/src/implementation/socket.h
libtransport/src/implementation/socket_consumer.h
libtransport/src/implementation/socket_producer.h
libtransport/src/implementation/tls_rtc_socket_producer.cc [deleted file]
libtransport/src/implementation/tls_rtc_socket_producer.h [deleted file]
libtransport/src/implementation/tls_socket_consumer.cc [deleted file]
libtransport/src/implementation/tls_socket_consumer.h [deleted file]
libtransport/src/implementation/tls_socket_producer.cc [deleted file]
libtransport/src/implementation/tls_socket_producer.h [deleted file]
libtransport/src/interfaces/CMakeLists.txt
libtransport/src/interfaces/global_configuration.cc
libtransport/src/interfaces/p2psecure_socket_consumer.cc [deleted file]
libtransport/src/interfaces/p2psecure_socket_producer.cc [deleted file]
libtransport/src/interfaces/portal.cc
libtransport/src/interfaces/socket_consumer.cc
libtransport/src/interfaces/socket_producer.cc
libtransport/src/interfaces/tls_rtc_socket_producer.cc [deleted file]
libtransport/src/interfaces/tls_rtc_socket_producer.h [deleted file]
libtransport/src/interfaces/tls_socket_consumer.cc [deleted file]
libtransport/src/interfaces/tls_socket_consumer.h [deleted file]
libtransport/src/interfaces/tls_socket_producer.cc [deleted file]
libtransport/src/interfaces/tls_socket_producer.h [deleted file]
libtransport/src/io_modules/CMakeLists.txt
libtransport/src/io_modules/forwarder/CMakeLists.txt
libtransport/src/io_modules/forwarder/forwarder.cc
libtransport/src/io_modules/forwarder/forwarder.h
libtransport/src/io_modules/forwarder/forwarder_module.cc
libtransport/src/io_modules/forwarder/forwarder_module.h
libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.cc
libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.h
libtransport/src/io_modules/loopback/loopback_module.cc
libtransport/src/io_modules/loopback/loopback_module.h
libtransport/src/io_modules/memif/vpp_forwarder_module.cc
libtransport/src/io_modules/memif/vpp_forwarder_module.h
libtransport/src/protocols/byte_stream_reassembly.cc
libtransport/src/protocols/byte_stream_reassembly.h
libtransport/src/protocols/cbr.cc
libtransport/src/protocols/datagram_reassembly.cc
libtransport/src/protocols/datagram_reassembly.h
libtransport/src/protocols/fec/rely.cc
libtransport/src/protocols/fec/rely.h
libtransport/src/protocols/fec/rs.cc
libtransport/src/protocols/fec/rs.h
libtransport/src/protocols/fec_base.h
libtransport/src/protocols/manifest_incremental_indexer_bytestream.cc
libtransport/src/protocols/manifest_incremental_indexer_bytestream.h
libtransport/src/protocols/prod_protocol_bytestream.cc
libtransport/src/protocols/prod_protocol_rtc.cc
libtransport/src/protocols/prod_protocol_rtc.h
libtransport/src/protocols/production_protocol.cc
libtransport/src/protocols/production_protocol.h
libtransport/src/protocols/raaqm.cc
libtransport/src/protocols/raaqm.h
libtransport/src/protocols/raaqm_data_path.cc
libtransport/src/protocols/raaqm_data_path.h
libtransport/src/protocols/rate_estimation.cc
libtransport/src/protocols/rate_estimation.h
libtransport/src/protocols/reassembly.h
libtransport/src/protocols/rtc/probe_handler.cc
libtransport/src/protocols/rtc/rtc.cc
libtransport/src/protocols/rtc/rtc.h
libtransport/src/protocols/rtc/rtc_consts.h
libtransport/src/protocols/rtc/rtc_data_path.cc
libtransport/src/protocols/rtc/rtc_data_path.h
libtransport/src/protocols/rtc/rtc_forwarding_strategy.cc
libtransport/src/protocols/rtc/rtc_forwarding_strategy.h
libtransport/src/protocols/rtc/rtc_ldr.cc
libtransport/src/protocols/rtc/rtc_ldr.h
libtransport/src/protocols/rtc/rtc_packet.h
libtransport/src/protocols/rtc/rtc_reassembly.cc
libtransport/src/protocols/rtc/rtc_recovery_strategy.cc
libtransport/src/protocols/rtc/rtc_recovery_strategy.h
libtransport/src/protocols/rtc/rtc_rs_delay.cc
libtransport/src/protocols/rtc/rtc_rs_delay.h
libtransport/src/protocols/rtc/rtc_rs_fec_only.cc
libtransport/src/protocols/rtc/rtc_rs_fec_only.h
libtransport/src/protocols/rtc/rtc_rs_low_rate.cc
libtransport/src/protocols/rtc/rtc_rs_low_rate.h
libtransport/src/protocols/rtc/rtc_rs_recovery_off.cc
libtransport/src/protocols/rtc/rtc_rs_recovery_off.h
libtransport/src/protocols/rtc/rtc_rs_rtx_only.cc
libtransport/src/protocols/rtc/rtc_rs_rtx_only.h
libtransport/src/protocols/rtc/rtc_state.cc
libtransport/src/protocols/rtc/rtc_state.h
libtransport/src/protocols/rtc/rtc_verifier.cc
libtransport/src/protocols/rtc/rtc_verifier.h
libtransport/src/protocols/transport_protocol.cc
libtransport/src/protocols/transport_protocol.h
libtransport/src/test/CMakeLists.txt
libtransport/src/test/test_core_manifest.cc
libtransport/src/test/test_interest.cc
libtransport/src/test/test_memif_connector.cc
libtransport/src/test/test_packet_allocator.cc
libtransport/src/test/test_prefix.cc [new file with mode: 0644]
libtransport/src/test/test_quadloop.cc [new file with mode: 0644]
libtransport/src/utils/epoll_event_reactor.h
libtransport/src/utils/fd_deadline_timer.h
libtransport/src/utils/suffix_strategy.h
telemetry/.clang-format [new file with mode: 0644]
telemetry/CMakeLists.txt
telemetry/cmake/packaging.cmake [moved from telemetry/vpp-collectd/cmake/packaging.cmake with 84% similarity]
telemetry/collectd.conf [new file with mode: 0644]
telemetry/data_model.h [new file with mode: 0644]
telemetry/hicn-light-collectd/CMakeLists.txt [new file with mode: 0644]
telemetry/hicn-light-collectd/hicn_light.c [new file with mode: 0644]
telemetry/kafka-collectd/CMakeLists.txt [new file with mode: 0644]
telemetry/kafka-collectd/format_influxdb.c [new file with mode: 0644]
telemetry/kafka-collectd/format_influxdb.h [new file with mode: 0644]
telemetry/kafka-collectd/write_kafka_line_protocol.c [new file with mode: 0644]
telemetry/third-party/CMakeLists.txt [new file with mode: 0644]
telemetry/vpp-collectd/CMakeLists.txt
telemetry/vpp-collectd/common/README.md [deleted file]
telemetry/vpp-collectd/common/common.h [deleted file]
telemetry/vpp-collectd/common/meta_data.h [deleted file]
telemetry/vpp-collectd/common/plugin.h [deleted file]
telemetry/vpp-collectd/vpp-hicn/CMakeLists.txt
telemetry/vpp-collectd/vpp-hicn/vpp_hicn.c
telemetry/vpp-collectd/vpp/CMakeLists.txt
telemetry/vpp-collectd/vpp/vpp.c
tests/.env
tests/2-nodes-hicn-light.yml
tests/2-nodes-vpp-bridge.yml
tests/2-nodes-vpp-memif-replication.yml
tests/2-nodes-vpp-memif.yml
tests/Makefile
tests/config.sh
tests/forwarder.robot [deleted file]
tests/hiperf-local.sh [new file with mode: 0644]
tests/test_forwarder.sh [deleted file]
versions.cmake

index 1f9d82d..a131c41 100644 (file)
--- a/.cz.toml
+++ b/.cz.toml
@@ -1,5 +1,5 @@
 [tool]
 [tool.commitizen]
 name = "cz_conventional_commits"
-version = "3.11.3"
+version = "3.13.0"
 tag_format = "v$version"
index 9099d8d..cbdd348 100644 (file)
@@ -16,3 +16,4 @@ tests/**/*.xml
 tests/**/*.html
 tests/**/*.log
 *.tar
+**/env
\ No newline at end of file
index 27afca2..41ecda0 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+
+##############################################################
+# Compiler preferences
+##############################################################
+set(CMAKE_C_COMPILER_NAMES
+  clang-13
+  clang-12
+  clang-11
+  clang-10
+  clang-9
+  gcc-10
+  gcc-9
+  cc
+)
+
+set(CMAKE_CXX_COMPILER_NAMES
+  clang++-13
+  clang++-12
+  clang++-11
+  clang++-10
+  clang++-9
+  g++-10
+  g++-9
+  c++
+)
+
 ##############################################################
 # Project and cmake version
 ##############################################################
index cfb75f1..9c96193 100644 (file)
@@ -1,17 +1,16 @@
-FROM dockerhub.cisco.com/icn-docker/hicn-base-devel-focal:x86_64
+FROM ubuntu:focal
+ENV DEBIAN_FRONTEND=noninteractive
 WORKDIR /hicn-build
 
-# Get versions from versions.cmake
-ARG VERSION_PATH=/tmp/versions.cmake
-COPY versions.cmake ${VERSION_PATH}
-ARG INSTALL_VPP_SCRIPT=/tmp/install-vpp.sh
-COPY scripts/install-vpp.sh ${INSTALL_VPP_SCRIPT}
+COPY Makefile versions.cmake ./
+COPY scripts scripts/
 
-RUN VERSION_PATH=${VERSION_PATH} bash -x ${INSTALL_VPP_SCRIPT}
-RUN apt update && apt-get install -y          \
-  libssl-dev                                  \
-  iproute2                                    \
-  iperf3                                      \
-  iputils-ping                                \
-  tcpdump                                     \
-  gdb --no-install-recommends
+RUN apt update && apt-get install -y \
+  make \
+  sudo \
+  curl \
+  git
+
+RUN make deps debug-tools
+
+ENV DEBIAN_FRONTEND=
index 3d74f9b..1fb9632 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -47,15 +47,18 @@ endif
 DEB_DEPENDS  = cmake ninja-build unzip python3-ply libasio-dev
 DEB_DEPENDS += libconfig-dev libconfig++-dev libevent-dev
 DEB_DEPENDS += build-essential vpp-dev libvppinfra-dev
-DEB_DEPENDS += vpp-plugin-core libcurl4-openssl-dev
+DEB_DEPENDS += vpp-plugin-core libcurl4-openssl-dev libssl-dev
 DEB_DEPENDS += doxygen
 
-MACOS_DEPENDS = asio libconfig ninja
+DEBUG_DEPENDS = iproute2 iperf3 iputils-ping tcpdump gdb
+
+MACOS_DEPENDS = asio libconfig ninja openssl@1.1
 
 .PHONY = help
 help:
        @echo "Targets"
        @echo " dep                 - install software dependencies"
+       @echo " debug-tools         - install debug dependencies"
        @echo " build               - build debug binaries. Optional argument: INSTALL_DIR"
        @echo " build-release       - build release binaries"
        @echo " build-coverage      - build with coverage metainformation"
@@ -97,6 +100,10 @@ endif
 .PHONY = deps
 deps: dep
 
+.PHONY = debug-tools
+debug-tools:
+       @sudo -E apt-get $(APT_ARGS) -y install $(DEBUG_DEPENDS) --no-install-recommends
+
 define build_folder
        $(eval LOWER_BUILDTYPE=$(shell echo $(2) | tr A-Z a-z))
        $(eval BUILD_FOLDER=$(or $(BUILD_PATH), build-$(LOWER_BUILDTYPE)-$(OS_ID)))
index 6986c90..8a0c46e 100644 (file)
@@ -19,7 +19,6 @@ if (NOT DISABLE_EXECUTABLES)
     ${CMAKE_CURRENT_SOURCE_DIR}/src/client.cc
     ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cc
     ${CMAKE_CURRENT_SOURCE_DIR}/src/server.cc
-    ${CMAKE_CURRENT_SOURCE_DIR}/src/forwarder_interface.cc
   )
 
 
index ba36cd2..0e1f596 100644 (file)
@@ -14,8 +14,7 @@
  */
 
 #include <client.h>
-#include <forwarder_config.h>
-#include <forwarder_interface.h>
+#include <hicn/transport/portability/endianess.h>
 
 #include <libconfig.h++>
 
@@ -31,1098 +30,831 @@ class Callback;
  * Hiperf client class: configure and setup an hicn consumer following the
  * ClientConfiguration.
  */
-class HIperfClient::Impl : ForwarderInterface::ICallback {
+class HIperfClient::Impl {
   friend class Callback;
   friend class RTCCallback;
 
-  static const constexpr uint16_t log2_header_counter = 4;
-
-  struct nack_packet_t {
-    uint64_t timestamp;
-    uint32_t prod_rate;
-    uint32_t prod_seg;
-
-    inline uint64_t getTimestamp() const { return _ntohll(&timestamp); }
-    inline void setTimestamp(uint64_t time) { timestamp = _htonll(&time); }
-
-    inline uint32_t getProductionRate() const { return ntohl(prod_rate); }
-    inline void setProductionRate(uint32_t rate) { prod_rate = htonl(rate); }
-
-    inline uint32_t getProductionSegement() const { return ntohl(prod_seg); }
-    inline void setProductionSegement(uint32_t seg) { prod_seg = htonl(seg); }
-  };
-
- public:
-  Impl(const hiperf::ClientConfiguration &conf)
-      : configuration_(conf),
-        total_duration_milliseconds_(0),
-        old_bytes_value_(0),
-        old_interest_tx_value_(0),
-        old_fec_interest_tx_value_(0),
-        old_fec_data_rx_value_(0),
-        old_lost_data_value_(0),
-        old_bytes_recovered_value_(0),
-        old_definitely_lost_data_value_(0),
-        old_retx_value_(0),
-        old_sent_int_value_(0),
-        old_received_nacks_value_(0),
-        old_fec_pkt_(0),
-        avg_data_delay_(0),
-        delay_sample_(0),
-        received_bytes_(0),
-        received_data_pkt_(0),
-        auth_alerts_(0),
-        data_delays_(""),
-        signals_(io_service_),
-        rtc_callback_(*this),
-        callback_(*this),
-        socket_(io_service_),
-        // switch_threshold_(~0),
-        fwd_connected_(false),
-        use_bestpath_(false),
-        rtt_threshold_(~0),
-        loss_threshold_(~0),
-        prefix_name_(""),
-        prefix_len_(0),
-        // done_(false),
-        header_counter_mask_((1 << log2_header_counter) - 1),
-        header_counter_(0),
-        print_headers_(configuration_.print_headers_),
-        first_(true),
-        forwarder_interface_(io_service_) {
-    setForwarderConnection(conf.forwarder_type_);
+  static inline constexpr uint16_t klog2_header_counter() { return 4; }
+  static inline constexpr uint16_t kheader_counter_mask() {
+    return (1 << klog2_header_counter()) - 1;
   }
 
-  virtual ~Impl() {}
-
-  void checkReceivedRtcContent(ConsumerSocket &c,
-                               const ContentObject &contentObject) {}
-
-  void processLeavingInterest(ConsumerSocket &c, const Interest &interest) {}
-
-  void addFace(const std::string &local_address, uint16_t local_port,
-               const std::string &remote_address, uint16_t remote_port,
-               std::string interface);
-
-  void handleTimerExpiration(ConsumerSocket &c,
-                             const TransportStatistics &stats) {
-    const char separator = ' ';
-    const int width = 18;
-
-    utils::SteadyTime::TimePoint t2 = utils::SteadyTime::Clock::now();
-    auto exact_duration = utils::SteadyTime::getDurationMs(t_stats_, t2);
-
-    std::stringstream interval_ms;
-    interval_ms << total_duration_milliseconds_ << "-"
-                << total_duration_milliseconds_ + exact_duration.count();
-
-    std::stringstream bytes_transferred;
-    bytes_transferred << std::fixed << std::setprecision(3)
-                      << (stats.getBytesRecv() - old_bytes_value_) / 1000000.0
-                      << std::setfill(separator);
-
-    std::stringstream bandwidth;
-    bandwidth << ((stats.getBytesRecv() - old_bytes_value_) * 8) /
-                     (exact_duration.count()) / 1000.0
-              << std::setfill(separator);
-
-    std::stringstream window;
-    window << stats.getAverageWindowSize() << std::setfill(separator);
+  class ConsumerContext
+      : public Base<ConsumerContext, ClientConfiguration, Impl>,
+        private ConsumerSocket::ReadCallback {
+    static inline const std::size_t kmtu = HIPERF_MTU;
 
-    std::stringstream avg_rtt;
-    avg_rtt << stats.getAverageRtt() << std::setfill(separator);
-
-    if (configuration_.rtc_) {
-      std::stringstream lost_data;
-      lost_data << stats.getLostData() - old_lost_data_value_
-                << std::setfill(separator);
-
-      std::stringstream bytes_recovered_data;
-      bytes_recovered_data << stats.getBytesRecoveredData() -
-                                  old_bytes_recovered_value_
-                           << std::setfill(separator);
-
-      std::stringstream definitely_lost_data;
-      definitely_lost_data << stats.getDefinitelyLostData() -
-                                  old_definitely_lost_data_value_
-                           << std::setfill(separator);
-
-      std::stringstream data_delay;
-      data_delay << std::fixed << std::setprecision(3) << avg_data_delay_
-                 << std::setfill(separator);
-
-      std::stringstream received_data_pkt;
-      received_data_pkt << received_data_pkt_ << std::setfill(separator);
-
-      std::stringstream goodput;
-      goodput << std::fixed << std::setprecision(3)
-              << (received_bytes_ * 8.0) / (exact_duration.count()) / 1000.0
-              << std::setfill(separator);
-
-      std::stringstream loss_rate;
-      loss_rate << std::fixed << std::setprecision(2)
-                << stats.getLossRatio() * 100.0 << std::setfill(separator);
-
-      std::stringstream retx_sent;
-      retx_sent << stats.getRetxCount() - old_retx_value_
-                << std::setfill(separator);
-
-      std::stringstream interest_sent;
-      interest_sent << stats.getInterestTx() - old_sent_int_value_
-                    << std::setfill(separator);
+   public:
+    using ConfType = ClientConfiguration;
+    using ParentType = typename HIperfClient::Impl;
+    static inline auto getContextType() -> std::string {
+      return "ConsumerContext";
+    }
+
+    ConsumerContext(Impl &client, int consumer_identifier)
+        : Base(client, client.io_service_, consumer_identifier),
+          receive_buffer_(
+              utils::MemBuf::create(client.config_.receive_buffer_size_)),
+          socket_(client.io_service_),
+          payload_size_max_(PayloadSize(client.config_.packet_format_)
+                                .getPayloadSizeMax(RTC_HEADER_SIZE)),
+          nb_iterations_(client.config_.nb_iterations_) {}
+
+    ConsumerContext(ConsumerContext &&other) noexcept
+        : Base(std::move(other)),
+          receive_buffer_(std::move(other.receive_buffer_)),
+          socket_(std::move(other.socket_)),
+          payload_size_max_(other.payload_size_max_),
+          remote_(std::move(other.remote_)),
+          nb_iterations_(other.nb_iterations_),
+          saved_stats_(std::move(other.saved_stats_)),
+          header_counter_(other.header_counter_),
+          first_(other.first_),
+          consumer_socket_(std::move(other.consumer_socket_)),
+          producer_socket_(std::move(other.producer_socket_)) {}
+
+    ~ConsumerContext() override = default;
+
+    /***************************************************************
+     * ConsumerSocket::ReadCallback implementation
+     ***************************************************************/
 
-      std::stringstream nacks;
-      nacks << stats.getReceivedNacks() - old_received_nacks_value_
-            << std::setfill(separator);
+    bool isBufferMovable() noexcept override { return false; }
 
-      std::stringstream fec_pkt;
-      fec_pkt << stats.getReceivedFEC() - old_fec_pkt_
-              << std::setfill(separator);
+    void getReadBuffer(uint8_t **application_buffer,
+                       size_t *max_length) override {
+      *application_buffer = receive_buffer_->writableData();
 
-      std::stringstream queuing_delay;
-      queuing_delay << std::fixed << std::setprecision(3)
-                    << stats.getQueuingDelay() << std::setfill(separator);
+      if (configuration_.rtc_) {
+        *max_length = kmtu;
+      } else {
+        *max_length = configuration_.receive_buffer_size_;
+      }
+    }
 
-      std::stringstream residual_losses;
-      double rl_perc = stats.getResidualLossRate() * 100;
-      residual_losses << std::fixed << std::setprecision(2) << rl_perc
-                      << std::setfill(separator);
+    void readBufferAvailable(
+        std::unique_ptr<utils::MemBuf> &&buffer) noexcept override {
+      // Nothing to do here
+      auto ret = std::move(buffer);
+    }
 
-      std::stringstream quality_score;
-      quality_score << std::fixed << (int)stats.getQualityScore()
-                    << std::setfill(separator);
+    void readDataAvailable(std::size_t length) noexcept override {
+      if (configuration_.rtc_) {
+        saved_stats_.received_bytes_ += length;
+        saved_stats_.received_data_pkt_++;
 
-      std::stringstream alerts;
-      alerts << stats.getAlerts() << std::setfill(separator);
+        // collecting delay stats. Just for performance testing
+        auto senderTimeStamp =
+            *reinterpret_cast<uint64_t *>(receive_buffer_->writableData());
 
-      std::stringstream auth_alerts;
-      auth_alerts << auth_alerts_ << std::setfill(separator);
+        auto now = utils::SystemTime::nowMs().count();
+        auto new_delay = double(now - senderTimeStamp);
 
-      if (fwd_connected_ && use_bestpath_ &&
-          ((stats.getAverageRtt() > rtt_threshold_) ||
-           ((stats.getResidualLossRate() * 100) > loss_threshold_))) {
-        forwarder_interface_.setStrategy(prefix_name_, prefix_len_, "bestpath");
-      }
+        if (senderTimeStamp > now)
+          new_delay = -1 * double(senderTimeStamp - now);
 
-      if ((header_counter_ == 0 && print_headers_) || first_) {
-        std::cout << std::right << std::setw(width) << "Interval[ms]";
-        std::cout << std::right << std::setw(width) << "RecvData[pkt]";
-        std::cout << std::right << std::setw(width) << "Bandwidth[Mbps]";
-        std::cout << std::right << std::setw(width) << "Goodput[Mbps]";
-        std::cout << std::right << std::setw(width) << "LossRate[%]";
-        std::cout << std::right << std::setw(width) << "Retr[pkt]";
-        std::cout << std::right << std::setw(width) << "InterestSent";
-        std::cout << std::right << std::setw(width) << "ReceivedNacks";
-        std::cout << std::right << std::setw(width) << "SyncWnd[pkt]";
-        std::cout << std::right << std::setw(width) << "MinRtt[ms]";
-        std::cout << std::right << std::setw(width) << "QueuingDelay[ms]";
-        std::cout << std::right << std::setw(width) << "LostData[pkt]";
-        std::cout << std::right << std::setw(width) << "RecoveredData";
-        std::cout << std::right << std::setw(width) << "DefinitelyLost";
-        std::cout << std::right << std::setw(width) << "State";
-        std::cout << std::right << std::setw(width) << "DataDelay[ms]";
-        std::cout << std::right << std::setw(width) << "FecPkt";
-        std::cout << std::right << std::setw(width) << "Congestion";
-        std::cout << std::right << std::setw(width) << "ResidualLosses";
-        std::cout << std::right << std::setw(width) << "QualityScore";
-        std::cout << std::right << std::setw(width) << "Alerts";
-        std::cout << std::right << std::setw(width) << "AuthAlerts"
-                  << std::endl;
-
-        first_ = false;
-      }
+        saved_stats_.delay_sample_++;
+        saved_stats_.avg_data_delay_ =
+            saved_stats_.avg_data_delay_ +
+            (double(new_delay) - saved_stats_.avg_data_delay_) /
+                saved_stats_.delay_sample_;
 
-      std::cout << std::right << std::setw(width) << interval_ms.str();
-      std::cout << std::right << std::setw(width) << received_data_pkt.str();
-      std::cout << std::right << std::setw(width) << bandwidth.str();
-      std::cout << std::right << std::setw(width) << goodput.str();
-      std::cout << std::right << std::setw(width) << loss_rate.str();
-      std::cout << std::right << std::setw(width) << retx_sent.str();
-      std::cout << std::right << std::setw(width) << interest_sent.str();
-      std::cout << std::right << std::setw(width) << nacks.str();
-      std::cout << std::right << std::setw(width) << window.str();
-      std::cout << std::right << std::setw(width) << avg_rtt.str();
-      std::cout << std::right << std::setw(width) << queuing_delay.str();
-      std::cout << std::right << std::setw(width) << lost_data.str();
-      std::cout << std::right << std::setw(width) << bytes_recovered_data.str();
-      std::cout << std::right << std::setw(width) << definitely_lost_data.str();
-      std::cout << std::right << std::setw(width) << stats.getCCStatus();
-      std::cout << std::right << std::setw(width) << data_delay.str();
-      std::cout << std::right << std::setw(width) << fec_pkt.str();
-      std::cout << std::right << std::setw(width) << stats.isCongested();
-      std::cout << std::right << std::setw(width) << residual_losses.str();
-      std::cout << std::right << std::setw(width) << quality_score.str();
-      std::cout << std::right << std::setw(width) << alerts.str();
-      std::cout << std::right << std::setw(width) << auth_alerts.str();
-      std::cout << std::endl;
-
-      if (configuration_.test_mode_) {
-        if (data_delays_.size() > 0) data_delays_.pop_back();
-
-        auto now = utils::SteadyTime::nowMs();
-        std::cout << std::fixed << std::setprecision(0) << now.count()
-                  << " DATA-DELAYS:[" << data_delays_ << "]" << std::endl;
-      }
+        if (configuration_.test_mode_) {
+          saved_stats_.data_delays_ += std::to_string(int(new_delay));
+          saved_stats_.data_delays_ += ",";
+        }
 
-      // statistics not yet available in the transport
-      // std::cout << std::right << std::setw(width) << interest_fec_tx.str();
-      // std::cout << std::right << std::setw(width) << bytes_fec_recv.str();
-    } else {
-      if ((header_counter_ == 0 && print_headers_) || first_) {
-        std::cout << std::right << std::setw(width) << "Interval[ms]";
-        std::cout << std::right << std::setw(width) << "Transfer[MB]";
-        std::cout << std::right << std::setw(width) << "Bandwidth[Mbps]";
-        std::cout << std::right << std::setw(width) << "Retr[pkt]";
-        std::cout << std::right << std::setw(width) << "Cwnd[Int]";
-        std::cout << std::right << std::setw(width) << "AvgRtt[ms]"
-                  << std::endl;
-
-        first_ = false;
+        if (configuration_.relay_ && configuration_.parallel_flows_ == 1) {
+          producer_socket_->produceDatagram(
+              configuration_.relay_name_.makeName(),
+              receive_buffer_->writableData(),
+              length < payload_size_max_ ? length : payload_size_max_);
+        }
+        if (configuration_.output_stream_mode_ &&
+            configuration_.parallel_flows_ == 1) {
+          const uint8_t *start = receive_buffer_->writableData();
+          start += sizeof(uint64_t);
+          std::size_t pkt_len = length - sizeof(uint64_t);
+          socket_.send_to(asio::buffer(start, pkt_len), remote_);
+        }
       }
-
-      std::cout << std::right << std::setw(width) << interval_ms.str();
-      std::cout << std::right << std::setw(width) << bytes_transferred.str();
-      std::cout << std::right << std::setw(width) << bandwidth.str();
-      std::cout << std::right << std::setw(width) << stats.getRetxCount();
-      std::cout << std::right << std::setw(width) << window.str();
-      std::cout << std::right << std::setw(width) << avg_rtt.str() << std::endl;
-    }
-
-    total_duration_milliseconds_ += (uint32_t)exact_duration.count();
-    old_bytes_value_ = stats.getBytesRecv();
-    old_lost_data_value_ = stats.getLostData();
-    old_bytes_recovered_value_ = stats.getBytesRecoveredData();
-    old_definitely_lost_data_value_ = stats.getDefinitelyLostData();
-    old_fec_interest_tx_value_ = stats.getInterestFecTxCount();
-    old_fec_data_rx_value_ = stats.getBytesFecRecv();
-    old_retx_value_ = stats.getRetxCount();
-    old_sent_int_value_ = stats.getInterestTx();
-    old_received_nacks_value_ = stats.getReceivedNacks();
-    old_fec_pkt_ = stats.getReceivedFEC();
-    delay_sample_ = 0;
-    avg_data_delay_ = 0;
-    received_bytes_ = 0;
-    received_data_pkt_ = 0;
-    data_delays_ = "";
-
-    t_stats_ = utils::SteadyTime::Clock::now();
-
-    header_counter_ = (header_counter_ + 1) & header_counter_mask_;
-
-    if (--configuration_.nb_iterations_ == 0) {
-      // We reached the maximum nb of runs. Stop now.
-      io_service_.stop();
-    }
-  }
-
-  bool setForwarderConnection(forwarder_type_t forwarder_type) {
-    using namespace libconfig;
-    Config cfg;
-
-    const char *conf_file = getenv("FORWARDER_CONFIG");
-    if (!conf_file) return false;
-
-    if ((forwarder_type != HICNLIGHT) && (forwarder_type != HICNLIGHT_NG))
-      return false;
-
-    try {
-      cfg.readFile(conf_file);
-    } catch (const FileIOException &fioex) {
-      std::cerr << "I/O error while reading file." << std::endl;
-      return false;
-    } catch (const ParseException &pex) {
-      std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
-                << " - " << pex.getError() << std::endl;
-      return false;
     }
 
-    Setting &config = cfg.getRoot();
-
-    /* conf file example
-     *
-     * use_bestpath = "ON | OFF"
-     * rtt_threshold = 200 //ms
-     * loss_threshold = 20 //%
-     * name = "b001::/16"
-     */
-
-    if (config.exists("use_bestpath")) {
-      std::string val;
-      config.lookupValue("use_bestpath", val);
-      if (val.compare("ON") == 0) use_bestpath_ = true;
+    size_t maxBufferSize() const override {
+      return configuration_.rtc_ ? kmtu : configuration_.receive_buffer_size_;
     }
 
-    if (config.exists("rtt_threshold")) {
-      unsigned val;
-      config.lookupValue("rtt_threshold", val);
-      rtt_threshold_ = val;
+    void readError(const std::error_code &ec) noexcept override {
+      getOutputStream() << "Error " << ec.message()
+                        << " while reading from socket" << std::endl;
+      parent_.io_service_.stop();
     }
 
-    if (config.exists("loss_threshold")) {
-      unsigned val;
-      config.lookupValue("loss_threshold", val);
-      loss_threshold_ = val;
-    }
+    void readSuccess(std::size_t total_size) noexcept override {
+      if (configuration_.rtc_) {
+        getOutputStream() << "Data successfully read" << std::endl;
+      } else {
+        auto t2 = utils::SteadyTime::now();
+        auto dt =
+            utils::SteadyTime::getDurationUs(saved_stats_.t_download_, t2);
+        auto usec = dt.count();
 
-    if (config.exists("name")) {
-      std::string route;
-      config.lookupValue("name", route);
+        getOutputStream() << "Content retrieved. Size: " << total_size
+                          << " [Bytes]" << std::endl;
 
-      std::string delimiter = "/";
-      size_t pos = 0;
+        getOutputStream() << "Elapsed Time: " << usec / 1000000.0
+                          << " seconds -- "
+                          << double(total_size * 8) * 1.0 / double(usec) * 1.0
+                          << " [Mbps]" << std::endl;
 
-      if ((pos = route.find(delimiter)) != std::string::npos) {
-        prefix_name_ = route.substr(0, pos);
-        route.erase(0, pos + delimiter.length());
-        prefix_len_ = std::stoul(route.substr(0));
+        parent_.io_service_.stop();
       }
     }
 
-    forwarder_interface_.initForwarderInterface(this, forwarder_type);
-
-    return true;
-  }
+    /***************************************************************
+     * End of ConsumerSocket::ReadCallback implementation
+     ***************************************************************/
 
-  void onHicnServiceReady() override {
-    std::cout << "Successfully connected to local forwarder!" << std::endl;
-    fwd_connected_ = true;
-  }
+   private:
+    struct SavedStatistics {
+      utils::SteadyTime::TimePoint t_stats_{};
+      utils::SteadyTime::TimePoint t_download_{};
+      uint32_t total_duration_milliseconds_{0};
+      uint64_t old_bytes_value_{0};
+      uint64_t old_interest_tx_value_{0};
+      uint64_t old_fec_interest_tx_value_{0};
+      uint64_t old_fec_data_rx_value_{0};
+      uint64_t old_lost_data_value_{0};
+      uint64_t old_bytes_recovered_value_{0};
+      uint64_t old_definitely_lost_data_value_{0};
+      uint64_t old_retx_value_{0};
+      uint64_t old_sent_int_value_{0};
+      uint64_t old_received_nacks_value_{0};
+      uint32_t old_fec_pkt_{0};
+      // IMPORTANT: to be used only for performance testing, when consumer and
+      // producer are synchronized. Used for rtc only at the moment
+      double avg_data_delay_{0};
+      uint32_t delay_sample_{0};
+      uint32_t received_bytes_{0};
+      uint32_t received_data_pkt_{0};
+      uint32_t auth_alerts_{0};
+      std::string data_delays_{""};
+    };
+
+    /***************************************************************
+     * Transport callbacks
+     ***************************************************************/
+
+    void checkReceivedRtcContent(
+        [[maybe_unused]] const ConsumerSocket &c,
+        [[maybe_unused]] const ContentObject &content_object) const {
+      // Nothing to do here
+    }
+
+    void processLeavingInterest(const ConsumerSocket & /*c*/,
+                                const Interest & /*interest*/) const {
+      // Nothing to do here
+    }
+
+    transport::auth::VerificationPolicy onAuthFailed(
+        transport::auth::Suffix /*suffix*/,
+        transport::auth::VerificationPolicy /*policy*/) {
+      saved_stats_.auth_alerts_++;
+      return transport::auth::VerificationPolicy::ACCEPT;
+    }
+
+    void handleTimerExpiration([[maybe_unused]] const ConsumerSocket &c,
+                               const TransportStatistics &stats) {
+      const char separator = ' ';
+      const int width = 18;
+
+      utils::SteadyTime::TimePoint t2 = utils::SteadyTime::Clock::now();
+      auto exact_duration =
+          utils::SteadyTime::getDurationMs(saved_stats_.t_stats_, t2);
+
+      std::stringstream interval_ms;
+      interval_ms << saved_stats_.total_duration_milliseconds_ << "-"
+                  << saved_stats_.total_duration_milliseconds_ +
+                         exact_duration.count();
+
+      std::stringstream bytes_transferred;
+      bytes_transferred << std::fixed << std::setprecision(3)
+                        << double(stats.getBytesRecv() -
+                                  saved_stats_.old_bytes_value_) /
+                               1000000.0
+                        << std::setfill(separator);
+
+      std::stringstream bandwidth;
+      bandwidth << (double(stats.getBytesRecv() -
+                           saved_stats_.old_bytes_value_) *
+                    8) /
+                       (exact_duration.count()) / 1000.0
+                << std::setfill(separator);
 
-  void onRouteConfigured(
-      std::vector<ForwarderInterface::RouteInfoPtr> &route_info) override {
-    std::cout << "Routes successfully configured!" << std::endl;
-  }
+      std::stringstream window;
+      window << stats.getAverageWindowSize() << std::setfill(separator);
 
-#ifdef FORWARDER_INTERFACE
-  bool parseConfig(const char *conf_file) {
-    using namespace libconfig;
-    Config cfg;
-
-    try {
-      cfg.readFile(conf_file);
-    } catch (const FileIOException &fioex) {
-      std::cerr << "I/O error while reading file." << std::endl;
-      return false;
-    } catch (const ParseException &pex) {
-      std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
-                << " - " << pex.getError() << std::endl;
-      return false;
-    }
+      std::stringstream avg_rtt;
+      avg_rtt << std::setprecision(3) << std::fixed << stats.getAverageRtt()
+              << std::setfill(separator);
 
-    Setting &config = cfg.getRoot();
+      if (configuration_.rtc_) {
+        std::stringstream lost_data;
+        lost_data << stats.getLostData() - saved_stats_.old_lost_data_value_
+                  << std::setfill(separator);
+
+        std::stringstream bytes_recovered_data;
+        bytes_recovered_data << stats.getBytesRecoveredData() -
+                                    saved_stats_.old_bytes_recovered_value_
+                             << std::setfill(separator);
+
+        std::stringstream definitely_lost_data;
+        definitely_lost_data << stats.getDefinitelyLostData() -
+                                    saved_stats_.old_definitely_lost_data_value_
+                             << std::setfill(separator);
+
+        std::stringstream data_delay;
+        data_delay << std::fixed << std::setprecision(3)
+                   << saved_stats_.avg_data_delay_ << std::setfill(separator);
+
+        std::stringstream received_data_pkt;
+        received_data_pkt << saved_stats_.received_data_pkt_
+                          << std::setfill(separator);
+
+        std::stringstream goodput;
+        goodput << std::fixed << std::setprecision(3)
+                << (saved_stats_.received_bytes_ * 8.0) /
+                       (exact_duration.count()) / 1000.0
+                << std::setfill(separator);
 
-    if (config.exists("switch_threshold")) {
-      unsigned threshold;
-      config.lookupValue("switch_threshold", threshold);
-      switch_threshold_ = threshold;
-    }
+        std::stringstream loss_rate;
+        loss_rate << std::fixed << std::setprecision(2)
+                  << stats.getLossRatio() * 100.0 << std::setfill(separator);
 
-    // listeners
-    if (config.exists("listeners")) {
-      // get path where looking for modules
-      const Setting &listeners = config.lookup("listeners");
-      auto count = listeners.getLength();
-
-      for (int i = 0; i < count; i++) {
-        const Setting &listener = listeners[i];
-        ListenerConfig list;
-        unsigned port;
-        std::string interface;
-
-        list.name = listener.getName();
-        listener.lookupValue("local_address", list.address);
-        listener.lookupValue("local_port", port);
-        listener.lookupValue("interface", list.interface);
-        list.port = (uint16_t)(port);
-
-        std::cout << "Adding listener " << list.name << ", ( " << list.address
-                  << ":" << list.port << ")" << std::endl;
-        config_.addListener(std::move(list));
-      }
-    }
+        std::stringstream retx_sent;
+        retx_sent << stats.getRetxCount() - saved_stats_.old_retx_value_
+                  << std::setfill(separator);
 
-    // connectors
-    if (config.exists("connectors")) {
-      // get path where looking for modules
-      const Setting &connectors = config.lookup("connectors");
-      auto count = connectors.getLength();
+        std::stringstream interest_sent;
+        interest_sent << stats.getInterestTx() -
+                             saved_stats_.old_sent_int_value_
+                      << std::setfill(separator);
 
-      for (int i = 0; i < count; i++) {
-        const Setting &connector = connectors[i];
-        ConnectorConfig conn;
+        std::stringstream nacks;
+        nacks << stats.getReceivedNacks() -
+                     saved_stats_.old_received_nacks_value_
+              << std::setfill(separator);
 
-        conn.name = connector.getName();
-        unsigned port = 0;
+        std::stringstream fec_pkt;
+        fec_pkt << stats.getReceivedFEC() - saved_stats_.old_fec_pkt_
+                << std::setfill(separator);
 
-        if (!connector.lookupValue("local_address", conn.local_address)) {
-          conn.local_address = "";
-        }
+        std::stringstream queuing_delay;
+        queuing_delay << std::fixed << std::setprecision(3)
+                      << stats.getQueuingDelay() << std::setfill(separator);
 
-        if (!connector.lookupValue("local_port", port)) {
-          port = 0;
-        }
+        std::stringstream residual_losses;
+        double rl_perc = stats.getResidualLossRate() * 100;
+        residual_losses << std::fixed << std::setprecision(2) << rl_perc
+                        << std::setfill(separator);
 
-        conn.local_port = (uint16_t)(port);
+        std::stringstream quality_score;
+        quality_score << std::fixed << (int)stats.getQualityScore()
+                      << std::setfill(separator);
 
-        if (!connector.lookupValue("remote_address", conn.remote_address)) {
-          std::cerr
-              << "Error in configuration file: remote_address is a mandatory "
-                 "field of Connectors."
-              << std::endl;
-          return false;
+        std::stringstream alerts;
+        alerts << stats.getAlerts() << std::setfill(separator);
+
+        std::stringstream auth_alerts;
+        auth_alerts << saved_stats_.auth_alerts_ << std::setfill(separator);
+
+        if ((header_counter_ == 0 && configuration_.print_headers_) || first_) {
+          getOutputStream() << std::right << std::setw(width) << "Interval[ms]";
+          getOutputStream()
+              << std::right << std::setw(width) << "RecvData[pkt]";
+          getOutputStream()
+              << std::right << std::setw(width) << "Bandwidth[Mbps]";
+          getOutputStream()
+              << std::right << std::setw(width) << "Goodput[Mbps]";
+          getOutputStream() << std::right << std::setw(width) << "LossRate[%]";
+          getOutputStream() << std::right << std::setw(width) << "Retr[pkt]";
+          getOutputStream() << std::right << std::setw(width) << "InterestSent";
+          getOutputStream()
+              << std::right << std::setw(width) << "ReceivedNacks";
+          getOutputStream() << std::right << std::setw(width) << "SyncWnd[pkt]";
+          getOutputStream() << std::right << std::setw(width) << "MinRtt[ms]";
+          getOutputStream()
+              << std::right << std::setw(width) << "QueuingDelay[ms]";
+          getOutputStream()
+              << std::right << std::setw(width) << "LostData[pkt]";
+          getOutputStream()
+              << std::right << std::setw(width) << "RecoveredData";
+          getOutputStream()
+              << std::right << std::setw(width) << "DefinitelyLost";
+          getOutputStream() << std::right << std::setw(width) << "State";
+          getOutputStream()
+              << std::right << std::setw(width) << "DataDelay[ms]";
+          getOutputStream() << std::right << std::setw(width) << "FecPkt";
+          getOutputStream() << std::right << std::setw(width) << "Congestion";
+          getOutputStream()
+              << std::right << std::setw(width) << "ResidualLosses";
+          getOutputStream() << std::right << std::setw(width) << "QualityScore";
+          getOutputStream() << std::right << std::setw(width) << "Alerts";
+          getOutputStream()
+              << std::right << std::setw(width) << "AuthAlerts" << std::endl;
+
+          first_ = false;
         }
 
-        if (!connector.lookupValue("remote_port", port)) {
-          std::cerr << "Error in configuration file: remote_port is a "
-                       "mandatory field of Connectors."
-                    << std::endl;
-          return false;
+        getOutputStream() << std::right << std::setw(width)
+                          << interval_ms.str();
+        getOutputStream() << std::right << std::setw(width)
+                          << received_data_pkt.str();
+        getOutputStream() << std::right << std::setw(width) << bandwidth.str();
+        getOutputStream() << std::right << std::setw(width) << goodput.str();
+        getOutputStream() << std::right << std::setw(width) << loss_rate.str();
+        getOutputStream() << std::right << std::setw(width) << retx_sent.str();
+        getOutputStream() << std::right << std::setw(width)
+                          << interest_sent.str();
+        getOutputStream() << std::right << std::setw(width) << nacks.str();
+        getOutputStream() << std::right << std::setw(width) << window.str();
+        getOutputStream() << std::right << std::setw(width) << avg_rtt.str();
+        getOutputStream() << std::right << std::setw(width)
+                          << queuing_delay.str();
+        getOutputStream() << std::right << std::setw(width) << lost_data.str();
+        getOutputStream() << std::right << std::setw(width)
+                          << bytes_recovered_data.str();
+        getOutputStream() << std::right << std::setw(width)
+                          << definitely_lost_data.str();
+        getOutputStream() << std::right << std::setw(width)
+                          << stats.getCCStatus();
+        getOutputStream() << std::right << std::setw(width) << data_delay.str();
+        getOutputStream() << std::right << std::setw(width) << fec_pkt.str();
+        getOutputStream() << std::right << std::setw(width)
+                          << stats.isCongested();
+        getOutputStream() << std::right << std::setw(width)
+                          << residual_losses.str();
+        getOutputStream() << std::right << std::setw(width)
+                          << quality_score.str();
+        getOutputStream() << std::right << std::setw(width) << alerts.str();
+        getOutputStream() << std::right << std::setw(width) << auth_alerts.str()
+                          << std::endl;
+
+        if (configuration_.test_mode_) {
+          if (saved_stats_.data_delays_.size() > 0)
+            saved_stats_.data_delays_.pop_back();
+
+          auto now = utils::SteadyTime::nowMs();
+          getOutputStream() << std::fixed << std::setprecision(0) << now.count()
+                            << " DATA-DELAYS:[" << saved_stats_.data_delays_
+                            << "]" << std::endl;
         }
-
-        if (!connector.lookupValue("interface", conn.interface)) {
-          std::cerr << "Error in configuration file: interface is a "
-                       "mandatory field of Connectors."
-                    << std::endl;
-          return false;
+      } else {
+        if ((header_counter_ == 0 && configuration_.print_headers_) || first_) {
+          getOutputStream() << std::right << std::setw(width) << "Interval[ms]";
+          getOutputStream() << std::right << std::setw(width) << "Transfer[MB]";
+          getOutputStream()
+              << std::right << std::setw(width) << "Bandwidth[Mbps]";
+          getOutputStream() << std::right << std::setw(width) << "Retr[pkt]";
+          getOutputStream() << std::right << std::setw(width) << "Cwnd[Int]";
+          getOutputStream()
+              << std::right << std::setw(width) << "AvgRtt[ms]" << std::endl;
+
+          first_ = false;
         }
 
-        conn.remote_port = (uint16_t)(port);
-
-        std::cout << "Adding connector " << conn.name << ", ("
-                  << conn.local_address << ":" << conn.local_port << " "
-                  << conn.remote_address << ":" << conn.remote_port << ")"
-                  << std::endl;
-        config_.addConnector(conn.name, std::move(conn));
+        getOutputStream() << std::right << std::setw(width)
+                          << interval_ms.str();
+        getOutputStream() << std::right << std::setw(width)
+                          << bytes_transferred.str();
+        getOutputStream() << std::right << std::setw(width) << bandwidth.str();
+        getOutputStream() << std::right << std::setw(width)
+                          << stats.getRetxCount();
+        getOutputStream() << std::right << std::setw(width) << window.str();
+        getOutputStream() << std::right << std::setw(width) << avg_rtt.str()
+                          << std::endl;
       }
-    }
 
-    // Routes
-    if (config.exists("routes")) {
-      const Setting &routes = config.lookup("routes");
-      auto count = routes.getLength();
-
-      for (int i = 0; i < count; i++) {
-        const Setting &route = routes[i];
-        RouteConfig r;
-        unsigned weight;
-
-        r.name = route.getName();
-        route.lookupValue("prefix", r.prefix);
-        route.lookupValue("weight", weight);
-        route.lookupValue("main_connector", r.main_connector);
-        route.lookupValue("backup_connector", r.backup_connector);
-        r.weight = (uint16_t)(weight);
-
-        std::cout << "Adding route " << r.name << " " << r.prefix << " ("
-                  << r.main_connector << " " << r.backup_connector << " "
-                  << r.weight << ")" << std::endl;
-        config_.addRoute(std::move(r));
+      saved_stats_.total_duration_milliseconds_ +=
+          (uint32_t)exact_duration.count();
+      saved_stats_.old_bytes_value_ = stats.getBytesRecv();
+      saved_stats_.old_lost_data_value_ = stats.getLostData();
+      saved_stats_.old_bytes_recovered_value_ = stats.getBytesRecoveredData();
+      saved_stats_.old_definitely_lost_data_value_ =
+          stats.getDefinitelyLostData();
+      saved_stats_.old_fec_interest_tx_value_ = stats.getInterestFecTxCount();
+      saved_stats_.old_fec_data_rx_value_ = stats.getBytesFecRecv();
+      saved_stats_.old_retx_value_ = stats.getRetxCount();
+      saved_stats_.old_sent_int_value_ = stats.getInterestTx();
+      saved_stats_.old_received_nacks_value_ = stats.getReceivedNacks();
+      saved_stats_.old_fec_pkt_ = stats.getReceivedFEC();
+      saved_stats_.delay_sample_ = 0;
+      saved_stats_.avg_data_delay_ = 0;
+      saved_stats_.received_bytes_ = 0;
+      saved_stats_.received_data_pkt_ = 0;
+      saved_stats_.data_delays_ = "";
+      saved_stats_.t_stats_ = utils::SteadyTime::Clock::now();
+
+      header_counter_ = (header_counter_ + 1) & kheader_counter_mask();
+
+      if (--nb_iterations_ == 0) {
+        // We reached the maximum nb of runs. Stop now.
+        parent_.io_service_.stop();
       }
     }
 
-    std::cout << "Ok" << std::endl;
+    /***************************************************************
+     * Setup functions
+     ***************************************************************/
 
-    return true;
-  }
+    int setupRTCSocket() {
+      int ret = ERROR_SUCCESS;
 
-  bool splitRoute(std::string route, std::string &prefix,
-                  uint8_t &prefix_length) {
-    std::string delimiter = "/";
-
-    size_t pos = 0;
-    if ((pos = route.find(delimiter)) != std::string::npos) {
-      prefix = route.substr(0, pos);
-      route.erase(0, pos + delimiter.length());
-    } else {
-      return false;
-    }
+      configuration_.transport_protocol_ = RTC;
 
-    prefix_length = std::stoul(route.substr(0));
-    return true;
-  }
+      if (configuration_.relay_ && configuration_.parallel_flows_ == 1) {
+        int production_protocol = ProductionProtocolAlgorithms::RTC_PROD;
+        producer_socket_ =
+            std::make_unique<ProducerSocket>(production_protocol);
+        producer_socket_->registerPrefix(configuration_.relay_name_);
+        producer_socket_->connect();
+        producer_socket_->start();
+      }
 
-  void onHicnServiceReady() override {
-    std::cout << "Successfully connected to local forwarder!" << std::endl;
+      if (configuration_.output_stream_mode_ &&
+          configuration_.parallel_flows_ == 1) {
+        remote_ = asio::ip::udp::endpoint(
+            asio::ip::address::from_string("127.0.0.1"), configuration_.port_);
+        socket_.open(asio::ip::udp::v4());
+      }
 
-    std::cout << "Setting up listeners" << std::endl;
-    const char *config = getenv("FORWARDER_CONFIG");
+      consumer_socket_ =
+          std::make_unique<ConsumerSocket>(configuration_.transport_protocol_);
 
-    if (config) {
-      if (!parseConfig(config)) {
-        return;
+      RtcTransportRecoveryStrategies recovery_strategy =
+          RtcTransportRecoveryStrategies::RTX_ONLY;
+      switch (configuration_.recovery_strategy_) {
+        case 1:
+          recovery_strategy = RtcTransportRecoveryStrategies::RECOVERY_OFF;
+          break;
+        case 2:
+          recovery_strategy = RtcTransportRecoveryStrategies::RTX_ONLY;
+          break;
+        case 3:
+          recovery_strategy = RtcTransportRecoveryStrategies::FEC_ONLY;
+          break;
+        case 4:
+          recovery_strategy = RtcTransportRecoveryStrategies::DELAY_BASED;
+          break;
+        case 5:
+          recovery_strategy = RtcTransportRecoveryStrategies::LOW_RATE;
+          break;
+        case 6:
+          recovery_strategy =
+              RtcTransportRecoveryStrategies::LOW_RATE_AND_BESTPATH;
+          break;
+        case 7:
+          recovery_strategy =
+              RtcTransportRecoveryStrategies::LOW_RATE_AND_REPLICATION;
+          break;
+        case 8:
+          recovery_strategy =
+              RtcTransportRecoveryStrategies::LOW_RATE_AND_ALL_FWD_STRATEGIES;
+          break;
+        case 9:
+          recovery_strategy =
+              RtcTransportRecoveryStrategies::FEC_ONLY_LOW_RES_LOSSES;
+          break;
+        case 10:
+          recovery_strategy =
+              RtcTransportRecoveryStrategies::DELAY_AND_BESTPATH;
+          break;
+        case 11:
+          recovery_strategy =
+              RtcTransportRecoveryStrategies::DELAY_AND_REPLICATION;
+          break;
+        default:
+          break;
       }
 
-      // Create faces and route using first face in the list.
-      auto &routes = config_.getRoutes();
-      auto &connectors = config_.getConnectors();
+      ret = consumer_socket_->setSocketOption(
+          RtcTransportOptions::RECOVERY_STRATEGY,
+          static_cast<uint32_t>(recovery_strategy));
 
-      if (routes.size() == 0 || connectors.size() == 0) {
-        std::cerr << "Nothing to configure" << std::endl;
-        return;
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
       }
 
-      for (auto &route : routes) {
-        auto the_connector_it = connectors.find(route.main_connector);
-        if (the_connector_it == connectors.end()) {
-          std::cerr << "No valid main connector found for route " << route.name
-                    << std::endl;
-          continue;
-        }
-
-        auto &the_connector = the_connector_it->second;
-        auto route_info = std::make_shared<ForwarderInterface::RouteInfo>();
-        route_info->family = AF_INET;
-        route_info->local_addr = the_connector.local_address;
-        route_info->local_port = the_connector.local_port;
-        route_info->remote_addr = the_connector.remote_address;
-        route_info->remote_port = the_connector.remote_port;
-        route_info->interface = the_connector.interface;
-        route_info->name = the_connector.name;
-
-        std::string prefix;
-        uint8_t prefix_length;
-        auto ret = splitRoute(route.prefix, prefix, prefix_length);
-
-        if (!ret) {
-          std::cerr << "Error parsing route" << std::endl;
-          return;
-        }
+      ret = consumer_socket_->setSocketOption(
+          RtcTransportOptions::AGGREGATED_DATA,
+          configuration_.aggregated_data_);
 
-        route_info->route_addr = prefix;
-        route_info->route_len = prefix_length;
-
-        main_routes_.emplace_back(route_info);
-
-        if (!route.backup_connector.empty()) {
-          // Add also the backup route
-          auto the_backup_connector_it =
-              connectors.find(route.backup_connector);
-          if (the_backup_connector_it == connectors.end()) {
-            std::cerr << "No valid backup connector found for route "
-                      << route.name << std::endl;
-            continue;
-          }
-
-          auto &the_backup_connector = the_backup_connector_it->second;
-          auto backup_route_info =
-              std::make_shared<ForwarderInterface::RouteInfo>();
-          backup_route_info->family = AF_INET;
-          backup_route_info->local_addr = the_backup_connector.local_address;
-          backup_route_info->local_port = the_backup_connector.local_port;
-          backup_route_info->remote_addr = the_backup_connector.remote_address;
-          backup_route_info->remote_port = the_backup_connector.remote_port;
-          backup_route_info->interface = the_backup_connector.interface;
-          backup_route_info->name = the_backup_connector.name;
-
-          std::string prefix;
-          uint8_t prefix_length;
-          auto ret = splitRoute(route.prefix, prefix, prefix_length);
-
-          if (!ret) {
-            std::cerr << "Error parsing route" << std::endl;
-            return;
-          }
-
-          backup_route_info->route_addr = prefix;
-          backup_route_info->route_len = prefix_length;
-
-          backup_routes_.emplace_back(backup_route_info);
-        }
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
       }
 
-      // Create main routes
-      std::cout << "Creating main routes" << std::endl;
-      forwarder_interface_.createFaceAndRoutes(main_routes_);
-    }
-  }
+      ret = consumer_socket_->setSocketOption(
+          RtcTransportOptions::CONTENT_SHARING_MODE,
+          configuration_.content_sharing_mode_);
 
-  void onRouteConfigured(
-      std::vector<ForwarderInterface::RouteInfoPtr> &route_info) override {
-    std::cout << "Routes successfully configured!" << std::endl;
-  }
-#endif
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
 
-  transport::auth::VerificationPolicy onAuthFailed(
-      transport::auth::Suffix suffix,
-      transport::auth::VerificationPolicy policy) {
-    auth_alerts_++;
-    return transport::auth::VerificationPolicy::ACCEPT;
-  }
+      ret = consumer_socket_->setSocketOption(
+          ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT,
+          (ConsumerContentObjectCallback)std::bind(
+              &Impl::ConsumerContext::checkReceivedRtcContent, this,
+              std::placeholders::_1, std::placeholders::_2));
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
 
-  int setup() {
-    int ret;
+      std::shared_ptr<TransportStatistics> transport_stats;
+      ret = consumer_socket_->getSocketOption(
+          OtherOptions::STATISTICS, (TransportStatistics **)&transport_stats);
+      transport_stats->setAlpha(0.0);
 
-    if (configuration_.rtc_) {
-      configuration_.transport_protocol_ = RTC;
-    } else if (configuration_.window < 0) {
-      configuration_.transport_protocol_ = RAAQM;
-    } else {
-      configuration_.transport_protocol_ = CBR;
-    }
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
 
-    if (configuration_.relay_ && configuration_.rtc_) {
-      int production_protocol = ProductionProtocolAlgorithms::RTC_PROD;
-      producer_socket_ = std::make_unique<ProducerSocket>(production_protocol);
-      producer_socket_->registerPrefix(configuration_.relay_name_);
-      producer_socket_->connect();
-      producer_socket_->start();
+      return ERROR_SUCCESS;
     }
 
-    if (configuration_.output_stream_mode_ && configuration_.rtc_) {
-      remote_ = asio::ip::udp::endpoint(
-          asio::ip::address::from_string("127.0.0.1"), configuration_.port_);
-      socket_.open(asio::ip::udp::v4());
-    }
+    int setupRAAQMSocket() {
+      int ret = ERROR_SUCCESS;
+
+      configuration_.transport_protocol_ = RAAQM;
 
-    if (configuration_.secure_) {
-      consumer_socket_ = std::make_unique<P2PSecureConsumerSocket>(
-          RAAQM, configuration_.transport_protocol_);
-      if (configuration_.producer_prefix_.getPrefixLength() == 0) {
-        std::cerr << "ERROR -- Missing producer prefix on which perform the "
-                     "handshake."
-                  << std::endl;
-      } else {
-        P2PSecureConsumerSocket &secure_consumer_socket =
-            *(static_cast<P2PSecureConsumerSocket *>(consumer_socket_.get()));
-        secure_consumer_socket.registerPrefix(configuration_.producer_prefix_);
-      }
-    } else {
       consumer_socket_ =
           std::make_unique<ConsumerSocket>(configuration_.transport_protocol_);
-    }
 
-    consumer_socket_->setSocketOption(
-        GeneralTransportOptions::INTEREST_LIFETIME,
-        configuration_.interest_lifetime_);
-
-    consumer_socket_->setSocketOption(
-        GeneralTransportOptions::UNVERIFIED_INTERVAL,
-        configuration_.unverified_interval_);
-
-    consumer_socket_->setSocketOption(GeneralTransportOptions::UNVERIFIED_RATIO,
-                                      configuration_.unverified_ratio_);
-
-    if (consumer_socket_->setSocketOption(
-            GeneralTransportOptions::PACKET_FORMAT,
-            configuration_.packet_format_) == SOCKET_OPTION_NOT_SET) {
-      std::cerr << "ERROR -- Impossible to set the packet format." << std::endl;
-      return ERROR_SETUP;
-    }
-
-#if defined(DEBUG) && defined(__linux__)
-    std::shared_ptr<transport::BasePortal> portal;
-    consumer_socket_->getSocketOption(GeneralTransportOptions::PORTAL, portal);
-    signals_ =
-        std::make_unique<asio::signal_set>(portal->getIoService(), SIGUSR1);
-    signals_->async_wait([this](const std::error_code &, const int &) {
-      std::cout << "Signal SIGUSR1!" << std::endl;
-      mtrace();
-    });
-
-    ret = consumer_socket_->setSocketOption(
-        ConsumerCallbacksOptions::FWD_STRATEGY_CHANGE,
-        [this](notification::Strategy strategy) {
-          std::cout << "Forwarder strategy callback" << std::endl;
-        });
-    if (ret == SOCKET_OPTION_NOT_SET) return ERROR_SETUP;
-
-    ret = consumer_socket_->setSocketOption(
-        ConsumerCallbacksOptions::REC_STRATEGY_CHANGE,
-        [this](notification::Strategy strategy) {
-          std::cout << "Recovery strategy callback" << std::endl;
-        });
-    if (ret == SOCKET_OPTION_NOT_SET) return ERROR_SETUP;
-#endif
-
-    if (consumer_socket_->setSocketOption(CURRENT_WINDOW_SIZE,
-                                          configuration_.window) ==
-        SOCKET_OPTION_NOT_SET) {
-      std::cerr << "ERROR -- Impossible to set the size of the window."
-                << std::endl;
-      return ERROR_SETUP;
-    }
-
-    if (configuration_.transport_protocol_ == RAAQM &&
-        configuration_.beta != -1.f) {
-      if (consumer_socket_->setSocketOption(RaaqmTransportOptions::BETA_VALUE,
-                                            configuration_.beta) ==
-          SOCKET_OPTION_NOT_SET) {
-        return ERROR_SETUP;
+      if (configuration_.beta_ != -1.f) {
+        ret = consumer_socket_->setSocketOption(
+            RaaqmTransportOptions::BETA_VALUE, configuration_.beta_);
+        if (ret == SOCKET_OPTION_NOT_SET) {
+          return ERROR_SETUP;
+        }
       }
-    }
 
-    if (configuration_.transport_protocol_ == RAAQM &&
-        configuration_.drop_factor != -1.f) {
-      if (consumer_socket_->setSocketOption(RaaqmTransportOptions::DROP_FACTOR,
-                                            configuration_.drop_factor) ==
-          SOCKET_OPTION_NOT_SET) {
-        return ERROR_SETUP;
+      if (configuration_.drop_factor_ != -1.f) {
+        ret = consumer_socket_->setSocketOption(
+            RaaqmTransportOptions::DROP_FACTOR, configuration_.drop_factor_);
+        if (ret == SOCKET_OPTION_NOT_SET) {
+          return ERROR_SETUP;
+        }
       }
-    }
-
-    std::shared_ptr<Verifier> verifier = std::make_shared<VoidVerifier>();
 
-    if (!configuration_.producer_certificate.empty()) {
-      verifier = std::make_shared<AsymmetricVerifier>(
-          configuration_.producer_certificate);
+      return ERROR_SUCCESS;
     }
 
-    if (!configuration_.passphrase.empty()) {
-      verifier = std::make_shared<SymmetricVerifier>(configuration_.passphrase);
-    }
+    int setupCBRSocket() {
+      configuration_.transport_protocol_ = CBR;
 
-    verifier->setVerificationFailedCallback(
-        std::bind(&HIperfClient::Impl::onAuthFailed, this,
-                  std::placeholders::_1, std::placeholders::_2));
+      consumer_socket_ =
+          std::make_unique<ConsumerSocket>(configuration_.transport_protocol_);
 
-    if (consumer_socket_->setSocketOption(GeneralTransportOptions::VERIFIER,
-                                          verifier) == SOCKET_OPTION_NOT_SET) {
-      return ERROR_SETUP;
+      return ERROR_SUCCESS;
     }
 
-    ret = consumer_socket_->setSocketOption(
-        ConsumerCallbacksOptions::INTEREST_OUTPUT,
-        (ConsumerInterestCallback)std::bind(&Impl::processLeavingInterest, this,
-                                            std::placeholders::_1,
-                                            std::placeholders::_2));
+   public:
+    int setup() {
+      int ret;
+      std::shared_ptr<Verifier> verifier = std::make_shared<VoidVerifier>();
+
+      if (configuration_.rtc_) {
+        ret = setupRTCSocket();
+      } else if (configuration_.window_ < 0) {
+        ret = setupRAAQMSocket();
+      } else {
+        ret = setupCBRSocket();
+      }
 
-    if (ret == SOCKET_OPTION_NOT_SET) {
-      return ERROR_SETUP;
-    }
+      if (ret != ERROR_SUCCESS) {
+        return ret;
+      }
 
-    if (!configuration_.rtc_) {
       ret = consumer_socket_->setSocketOption(
-          ConsumerCallbacksOptions::READ_CALLBACK, &callback_);
-    } else {
-      ret = consumer_socket_->setSocketOption(
-          ConsumerCallbacksOptions::READ_CALLBACK, &rtc_callback_);
-    }
-
-    if (ret == SOCKET_OPTION_NOT_SET) {
-      return ERROR_SETUP;
-    }
-
-    if (configuration_.rtc_) {
-      if (configuration_.recovery_strategy_ == 1) {  // unreliable
-        ret = consumer_socket_->setSocketOption(
-            RtcTransportOptions::RECOVERY_STRATEGY,
-            (uint32_t)RtcTransportRecoveryStrategies::RECOVERY_OFF);
-      } else if (configuration_.recovery_strategy_ == 2) {  // rtx only
-        ret = consumer_socket_->setSocketOption(
-            RtcTransportOptions::RECOVERY_STRATEGY,
-            (uint32_t)RtcTransportRecoveryStrategies::RTX_ONLY);
-      } else if (configuration_.recovery_strategy_ == 3) {  // fec only
-        ret = consumer_socket_->setSocketOption(
-            RtcTransportOptions::RECOVERY_STRATEGY,
-            (uint32_t)RtcTransportRecoveryStrategies::FEC_ONLY);
-      } else if (configuration_.recovery_strategy_ == 4) {  // delay based
-        ret = consumer_socket_->setSocketOption(
-            RtcTransportOptions::RECOVERY_STRATEGY,
-            (uint32_t)RtcTransportRecoveryStrategies::DELAY_BASED);
-      } else if (configuration_.recovery_strategy_ == 5) {  // low rate flow
-        ret = consumer_socket_->setSocketOption(
-            RtcTransportOptions::RECOVERY_STRATEGY,
-            (uint32_t)RtcTransportRecoveryStrategies::LOW_RATE);
-      } else if (configuration_.recovery_strategy_ ==
-                 6) {  // low rate + bestpath
-        ret = consumer_socket_->setSocketOption(
-            RtcTransportOptions::RECOVERY_STRATEGY,
-            (uint32_t)RtcTransportRecoveryStrategies::LOW_RATE_AND_BESTPATH);
-      } else if (configuration_.recovery_strategy_ ==
-                 7) {  // low rate + replication
-        ret = consumer_socket_->setSocketOption(
-            RtcTransportOptions::RECOVERY_STRATEGY,
-            (uint32_t)RtcTransportRecoveryStrategies::LOW_RATE_AND_REPLICATION);
-      } else if (configuration_.recovery_strategy_ ==
-                 8) {  // low rate + bestpath or replication
-        ret = consumer_socket_->setSocketOption(
-            RtcTransportOptions::RECOVERY_STRATEGY,
-            (uint32_t)RtcTransportRecoveryStrategies::
-                LOW_RATE_AND_ALL_FWD_STRATEGIES);
-      } else {
-        // default
-        ret = consumer_socket_->setSocketOption(
-            RtcTransportOptions::RECOVERY_STRATEGY,
-            (uint32_t)RtcTransportRecoveryStrategies::RTX_ONLY);
+          GeneralTransportOptions::INTEREST_LIFETIME,
+          configuration_.interest_lifetime_);
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
       }
 
+      ret = consumer_socket_->setSocketOption(
+          GeneralTransportOptions::MANIFEST_FACTOR_RELEVANT,
+          configuration_.manifest_factor_relevant_);
       if (ret == SOCKET_OPTION_NOT_SET) {
         return ERROR_SETUP;
       }
-    }
 
-    if (configuration_.rtc_) {
       ret = consumer_socket_->setSocketOption(
-          RtcTransportOptions::AGGREGATED_DATA,
-          configuration_.aggregated_data_);
+          GeneralTransportOptions::MANIFEST_FACTOR_ALERT,
+          configuration_.manifest_factor_alert_);
 
       if (ret == SOCKET_OPTION_NOT_SET) {
         return ERROR_SETUP;
       }
-    }
 
-    if (configuration_.rtc_) {
       ret = consumer_socket_->setSocketOption(
-          ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT,
-          (ConsumerContentObjectCallback)std::bind(
-              &Impl::checkReceivedRtcContent, this, std::placeholders::_1,
-              std::placeholders::_2));
+          GeneralTransportOptions::PACKET_FORMAT,
+          configuration_.packet_format_);
       if (ret == SOCKET_OPTION_NOT_SET) {
+        getOutputStream() << "ERROR -- Impossible to set the packet format."
+                          << std::endl;
         return ERROR_SETUP;
       }
-    }
-
-    if (configuration_.rtc_) {
-      std::shared_ptr<TransportStatistics> transport_stats;
-      consumer_socket_->getSocketOption(
-          OtherOptions::STATISTICS, (TransportStatistics **)&transport_stats);
-      transport_stats->setAlpha(0.0);
-    }
-
-    ret = consumer_socket_->setSocketOption(
-        ConsumerCallbacksOptions::STATS_SUMMARY,
-        (ConsumerTimerCallback)std::bind(&Impl::handleTimerExpiration, this,
-                                         std::placeholders::_1,
-                                         std::placeholders::_2));
-
-    if (ret == SOCKET_OPTION_NOT_SET) {
-      return ERROR_SETUP;
-    }
-
-    if (consumer_socket_->setSocketOption(
-            GeneralTransportOptions::STATS_INTERVAL,
-            configuration_.report_interval_milliseconds_) ==
-        SOCKET_OPTION_NOT_SET) {
-      return ERROR_SETUP;
-    }
-
-    consumer_socket_->connect();
 
-    return ERROR_SUCCESS;
-  }
+      ret = consumer_socket_->setSocketOption(
+          ConsumerCallbacksOptions::FWD_STRATEGY_CHANGE,
+          (StrategyCallback)[](
+              [[maybe_unused]] notification::Strategy strategy){
+              // nothing to do
+          });
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
 
-  int run() {
-    std::cout << "Starting download of " << configuration_.name << std::endl;
+      ret = consumer_socket_->setSocketOption(
+          ConsumerCallbacksOptions::REC_STRATEGY_CHANGE,
+          (StrategyCallback)[](
+              [[maybe_unused]] notification::Strategy strategy){
+              // nothing to do
+          });
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
 
-    signals_.add(SIGINT);
-    signals_.async_wait(
-        [this](const std::error_code &, const int &) { io_service_.stop(); });
+      ret = consumer_socket_->setSocketOption(CURRENT_WINDOW_SIZE,
+                                              configuration_.window_);
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        getOutputStream()
+            << "ERROR -- Impossible to set the size of the window."
+            << std::endl;
+        return ERROR_SETUP;
+      }
 
-    t_download_ = t_stats_ = utils::SteadyTime::now();
-    consumer_socket_->consume(configuration_.name);
+      if (!configuration_.producer_certificate_.empty()) {
+        verifier = std::make_shared<AsymmetricVerifier>(
+            configuration_.producer_certificate_);
+      }
 
-    io_service_.run();
-    consumer_socket_->stop();
+      if (!configuration_.passphrase_.empty()) {
+        verifier =
+            std::make_shared<SymmetricVerifier>(configuration_.passphrase_);
+      }
 
-    return ERROR_SUCCESS;
-  }
+      verifier->setVerificationFailedCallback(
+          std::bind(&HIperfClient::Impl::ConsumerContext::onAuthFailed, this,
+                    std::placeholders::_1, std::placeholders::_2));
 
- private:
-  class RTCCallback : public ConsumerSocket::ReadCallback {
-    static constexpr std::size_t mtu = HIPERF_MTU;
+      ret = consumer_socket_->setSocketOption(GeneralTransportOptions::VERIFIER,
+                                              verifier);
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
 
-   public:
-    RTCCallback(Impl &hiperf_client) : client_(hiperf_client) {
-      client_.configuration_.receive_buffer = utils::MemBuf::create(mtu);
-      Packet::Format format =
-          PayloadSize::getFormatFromName(client_.configuration_.name, false);
-      payload_size_max_ =
-          PayloadSize(format).getPayloadSizeMax(RTC_HEADER_SIZE);
-    }
+      // Signer for aggregatd interests
+      std::shared_ptr<Signer> signer = std::make_shared<VoidSigner>();
+      if (!configuration_.aggr_interest_passphrase_.empty()) {
+        signer = std::make_shared<SymmetricSigner>(
+            CryptoSuite::HMAC_SHA256, configuration_.aggr_interest_passphrase_);
+      }
+      ret = consumer_socket_->setSocketOption(GeneralTransportOptions::SIGNER,
+                                              signer);
+      if (ret == SOCKET_OPTION_NOT_SET) return ERROR_SETUP;
 
-    bool isBufferMovable() noexcept override { return false; }
+      if (configuration_.aggregated_interests_) {
+        ret = consumer_socket_->setSocketOption(
+            RtcTransportOptions::AGGREGATED_INTERESTS, true);
 
-    void getReadBuffer(uint8_t **application_buffer,
-                       size_t *max_length) override {
-      *application_buffer =
-          client_.configuration_.receive_buffer->writableData();
-      *max_length = mtu;
-    }
+        if (ret == SOCKET_OPTION_NOT_SET) return ERROR_SETUP;
+      }
 
-    void readDataAvailable(std::size_t length) noexcept override {
-      client_.received_bytes_ += length;
-      client_.received_data_pkt_++;
+      ret = consumer_socket_->setSocketOption(
+          ConsumerCallbacksOptions::INTEREST_OUTPUT,
+          (ConsumerInterestCallback)std::bind(
+              &ConsumerContext::processLeavingInterest, this,
+              std::placeholders::_1, std::placeholders::_2));
 
-      // collecting delay stats. Just for performance testing
-      uint64_t *senderTimeStamp =
-          (uint64_t *)client_.configuration_.receive_buffer->writableData();
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
 
-      auto now = utils::SystemTime::nowMs().count();
-      double new_delay = (double)(now - *senderTimeStamp);
+      ret = consumer_socket_->setSocketOption(
+          ConsumerCallbacksOptions::READ_CALLBACK, this);
 
-      if (*senderTimeStamp > now)
-        new_delay = -1 * (double)(*senderTimeStamp - now);
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
 
-      client_.delay_sample_++;
-      client_.avg_data_delay_ =
-          client_.avg_data_delay_ +
-          (new_delay - client_.avg_data_delay_) / client_.delay_sample_;
+      ret = consumer_socket_->setSocketOption(
+          ConsumerCallbacksOptions::STATS_SUMMARY,
+          (ConsumerTimerCallback)std::bind(
+              &Impl::ConsumerContext::handleTimerExpiration, this,
+              std::placeholders::_1, std::placeholders::_2));
 
-      if (client_.configuration_.test_mode_) {
-        client_.data_delays_ += std::to_string(int(new_delay));
-        client_.data_delays_ += ",";
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
       }
 
-      if (client_.configuration_.relay_) {
-        client_.producer_socket_->produceDatagram(
-            client_.configuration_.relay_name_.getName(),
-            client_.configuration_.receive_buffer->writableData(),
-            length < payload_size_max_ ? length : payload_size_max_);
-      }
-      if (client_.configuration_.output_stream_mode_) {
-        uint8_t *start =
-            (uint8_t *)client_.configuration_.receive_buffer->writableData();
-        start += sizeof(uint64_t);
-        std::size_t pkt_len = length - sizeof(uint64_t);
-        client_.socket_.send_to(asio::buffer(start, pkt_len), client_.remote_);
+      if (consumer_socket_->setSocketOption(
+              GeneralTransportOptions::STATS_INTERVAL,
+              configuration_.report_interval_milliseconds_) ==
+          SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
       }
-    }
 
-    size_t maxBufferSize() const override { return mtu; }
+      consumer_socket_->connect();
 
-    void readError(const std::error_code &ec) noexcept override {
-      std::cerr << "Error while reading from RTC socket" << std::endl;
-      client_.io_service_.stop();
+      return ERROR_SUCCESS;
     }
 
-    void readSuccess(std::size_t total_size) noexcept override {
-      std::cout << "Data successfully read" << std::endl;
+    /***************************************************************
+     * Run functions
+     ***************************************************************/
+
+    int run() {
+      getOutputStream() << "Starting download of " << flow_name_ << std::endl;
+
+      saved_stats_.t_download_ = saved_stats_.t_stats_ =
+          utils::SteadyTime::now();
+      consumer_socket_->consume(flow_name_);
+
+      return ERROR_SUCCESS;
     }
 
-   private:
-    Impl &client_;
+    // Members initialized by the constructor
+    std::shared_ptr<utils::MemBuf> receive_buffer_;
+    asio::ip::udp::socket socket_;
     std::size_t payload_size_max_;
+    asio::ip::udp::endpoint remote_;
+    std::uint32_t nb_iterations_;
+
+    // Members initialized by in-class initializer
+    SavedStatistics saved_stats_{};
+    uint16_t header_counter_{0};
+    bool first_{true};
+    std::unique_ptr<ConsumerSocket> consumer_socket_;
+    std::unique_ptr<ProducerSocket> producer_socket_;
   };
 
-  class Callback : public ConsumerSocket::ReadCallback {
-   public:
-    Callback(Impl &hiperf_client) : client_(hiperf_client) {
-      client_.configuration_.receive_buffer =
-          utils::MemBuf::create(client_.configuration_.receive_buffer_size_);
-    }
+ public:
+  explicit Impl(const hiperf::ClientConfiguration &conf)
+      : config_(conf), signals_(io_service_) {}
 
-    bool isBufferMovable() noexcept override { return false; }
+  virtual ~Impl() = default;
 
-    void getReadBuffer(uint8_t **application_buffer,
-                       size_t *max_length) override {
-      *application_buffer =
-          client_.configuration_.receive_buffer->writableData();
-      *max_length = client_.configuration_.receive_buffer_size_;
+  int setup() {
+    int ret = ensureFlows(config_.name_, config_.parallel_flows_);
+    if (ret != ERROR_SUCCESS) {
+      return ret;
     }
 
-    void readDataAvailable(std::size_t length) noexcept override {}
-
-    void readBufferAvailable(
-        std::unique_ptr<utils::MemBuf> &&buffer) noexcept override {}
+    consumer_contexts_.reserve(config_.parallel_flows_);
+    for (uint32_t i = 0; i < config_.parallel_flows_; i++) {
+      auto &ctx = consumer_contexts_.emplace_back(*this, i);
+      ret = ctx.setup();
 
-    size_t maxBufferSize() const override {
-      return client_.configuration_.receive_buffer_size_;
-    }
-
-    void readError(const std::error_code &ec) noexcept override {
-      std::cerr << "Error " << ec.message() << " while reading from socket"
-                << std::endl;
-      client_.io_service_.stop();
+      if (ret) {
+        break;
+      }
     }
 
-    void readSuccess(std::size_t total_size) noexcept override {
-      auto t2 = utils::SteadyTime::now();
-      auto dt = utils::SteadyTime::getDurationUs(client_.t_download_, t2);
-      long usec = (long)dt.count();
-
-      std::cout << "Content retrieved. Size: " << total_size << " [Bytes]"
-                << std::endl;
+    return ret;
+  }
 
-      std::cerr << "Elapsed Time: " << usec / 1000000.0 << " seconds -- "
-                << (total_size * 8) * 1.0 / usec * 1.0 << " [Mbps]"
-                << std::endl;
+  int run() {
+    signals_.add(SIGINT);
+    signals_.async_wait(
+        [this](const std::error_code &, const int &) { io_service_.stop(); });
 
-      client_.io_service_.stop();
+    for (auto &consumer_context : consumer_contexts_) {
+      consumer_context.run();
     }
 
-   private:
-    Impl &client_;
-  };
+    io_service_.run();
 
-  hiperf::ClientConfiguration configuration_;
-  utils::SteadyTime::TimePoint t_stats_;
-  utils::SteadyTime::TimePoint t_download_;
-  uint32_t total_duration_milliseconds_;
-  uint64_t old_bytes_value_;
-  uint64_t old_interest_tx_value_;
-  uint64_t old_fec_interest_tx_value_;
-  uint64_t old_fec_data_rx_value_;
-  uint64_t old_lost_data_value_;
-  uint64_t old_bytes_recovered_value_;
-  uint64_t old_definitely_lost_data_value_;
-  uint32_t old_retx_value_;
-  uint32_t old_sent_int_value_;
-  uint32_t old_received_nacks_value_;
-  uint32_t old_fec_pkt_;
-
-  // IMPORTANT: to be used only for performance testing, when consumer and
-  // producer are synchronized. Used for rtc only at the moment
-  double avg_data_delay_;
-  uint32_t delay_sample_;
-
-  uint32_t received_bytes_;
-  uint32_t received_data_pkt_;
-  uint32_t auth_alerts_;
-
-  std::string data_delays_;
+    return ERROR_SUCCESS;
+  }
 
+  ClientConfiguration &getConfig() { return config_; }
+
+ private:
   asio::io_service io_service_;
+  hiperf::ClientConfiguration config_;
   asio::signal_set signals_;
-  RTCCallback rtc_callback_;
-  Callback callback_;
-  std::unique_ptr<ConsumerSocket> consumer_socket_;
-  std::unique_ptr<ProducerSocket> producer_socket_;
-  asio::ip::udp::socket socket_;
-  asio::ip::udp::endpoint remote_;
-
-  ForwarderConfiguration config_;
-  // uint16_t switch_threshold_; /* ms */
-  bool fwd_connected_;
-  bool use_bestpath_;
-  uint32_t rtt_threshold_;   /* ms */
-  uint32_t loss_threshold_;  /* ms */
-  std::string prefix_name_;  // bestpath route
-  uint32_t prefix_len_;
-  // bool done_;
-
-  std::vector<ForwarderInterface::RouteInfoPtr> main_routes_;
-  std::vector<ForwarderInterface::RouteInfoPtr> backup_routes_;
-  uint16_t header_counter_mask_;
-  uint16_t header_counter_;
-
-  bool print_headers_;
-  bool first_;
-
-  ForwarderInterface forwarder_interface_;
+  std::vector<ConsumerContext> consumer_contexts_;
 };
 
-HIperfClient::HIperfClient(const ClientConfiguration &conf) {
-  impl_ = new Impl(conf);
-}
-
-HIperfClient::HIperfClient(HIperfClient &&other) {
-  impl_ = other.impl_;
-  other.impl_ = nullptr;
-}
-
-HIperfClient &HIperfClient::operator=(HIperfClient &&other) {
-  if (this != &other) {
-    impl_ = other.impl_;
-    other.impl_ = nullptr;
-  }
-
-  return *this;
-}
+HIperfClient::HIperfClient(const ClientConfiguration &conf)
+    : impl_(std::make_unique<Impl>(conf)) {}
 
-HIperfClient::~HIperfClient() { delete impl_; }
+HIperfClient::~HIperfClient() = default;
 
-int HIperfClient::setup() { return impl_->setup(); }
+int HIperfClient::setup() const { return impl_->setup(); }
 
-void HIperfClient::run() { impl_->run(); }
+void HIperfClient::run() const { impl_->run(); }
 
 }  // namespace hiperf
index bc80c87..c4c6bc2 100644 (file)
 
 namespace hiperf {
 
-class HIperfClient : ::utils::NonCopyable {
+class HIperfClient : private ::utils::NonCopyable {
  public:
-  HIperfClient(const ClientConfiguration &conf);
-  HIperfClient(HIperfClient &&other);
-  HIperfClient &operator=(HIperfClient &&other);
+  explicit HIperfClient(const ClientConfiguration &conf);
 
   ~HIperfClient();
-  int setup();
-  void run();
+  int setup() const;
+  void run() const;
 
  private:
   class Impl;
-  Impl *impl_;
+  std::unique_ptr<Impl> impl_;
 };
 
 }  // namespace hiperf
\ No newline at end of file
index 3a90f37..5143afe 100644 (file)
 
 #pragma once
 
-#include <forwarder_interface.h>
 #include <hicn/transport/auth/signer.h>
 #include <hicn/transport/config.h>
 #include <hicn/transport/core/content_object.h>
 #include <hicn/transport/core/interest.h>
 #include <hicn/transport/interfaces/global_conf_interface.h>
-#include <hicn/transport/interfaces/p2psecure_socket_consumer.h>
-#include <hicn/transport/interfaces/p2psecure_socket_producer.h>
 #include <hicn/transport/interfaces/socket_consumer.h>
 #include <hicn/transport/interfaces/socket_producer.h>
 #include <hicn/transport/utils/chrono_typedefs.h>
+#include <hicn/transport/utils/color.h>
 #include <hicn/transport/utils/literals.h>
 
 #ifndef _WIN32
@@ -36,6 +34,7 @@
 #include <cmath>
 #include <fstream>
 #include <iomanip>
+#include <iostream>
 #include <sstream>
 #include <string>
 #include <unordered_set>
@@ -53,27 +52,112 @@ using namespace transport::interface;
 using namespace transport::auth;
 using namespace transport::core;
 
-static inline uint64_t _ntohll(const uint64_t *input) {
-  uint64_t return_val;
-  uint8_t *tmp = (uint8_t *)&return_val;
+namespace hiperf {
 
-  tmp[0] = *input >> 56;
-  tmp[1] = *input >> 48;
-  tmp[2] = *input >> 40;
-  tmp[3] = *input >> 32;
-  tmp[4] = *input >> 24;
-  tmp[5] = *input >> 16;
-  tmp[6] = *input >> 8;
-  tmp[7] = *input >> 0;
+/**
+ * Logger
+ */
+static std::ostream &Logger() { return std::cout; }
 
-  return return_val;
-}
+template <typename D, typename ConfType, typename ParentType>
+class Base : protected std::stringbuf, protected std::ostream {
+ protected:
+  static inline const char separator[] = "|   ";
 
-static inline uint64_t _htonll(const uint64_t *input) {
-  return (_ntohll(input));
-}
+  Base(ParentType &parent, asio::io_service &io_service, int identifier)
+      : std::stringbuf(),
+        std::ostream(this),
+        parent_(parent),
+        configuration_(parent_.getConfig()),
+        io_service_(io_service),
+        identifier_(identifier),
+        name_id_(D::getContextType() + std::to_string(identifier_)),
+        flow_name_(configuration_.name_.makeNameWithIndex(identifier_)) {
+    std::stringstream begin;
+    std::stringstream end;
+    if (configuration_.colored_) {
+      begin << color_mod_ << bold_mod_;
+      end << end_mod_;
+    } else {
+      begin << "";
+      end << "";
+    }
 
-namespace hiperf {
+    begin << "|" << name_id_ << separator;
+    begin_ = begin.str();
+    end_ = end.str();
+  }
+
+  Base(Base &&other)
+      : parent_(other.parent_),
+        configuration_(other.configuration_),
+        io_service_(other.io_service_),
+        identifier_(other.identifier_),
+        name_id_(std::move(other.name_id_)),
+        flow_name_(other.flow_name_) {}
+
+  /***************************************************************
+   * std::stringbuf sync override
+   ***************************************************************/
+
+  int sync() override {
+    auto string = str();
+    asio::post(io_service_,
+               [this, string]() { Logger() << begin_ << string << end_; });
+    str("");
+
+    return 0;
+  }
+
+  std::ostream &getOutputStream() { return *this; }
+
+  // Members initialized by the constructor
+  ParentType &parent_;
+  ConfType &configuration_;
+  asio::io_service &io_service_;
+  int identifier_;
+  std::string name_id_;
+  transport::core::Name flow_name_;
+  std::string begin_;
+  std::string end_;
+
+  // Members initialized by the in-class initializer
+  utils::ColorModifier color_mod_;
+  utils::ColorModifier bold_mod_{utils::ColorModifier::Code::BOLD};
+  utils::ColorModifier end_mod_{utils::ColorModifier::Code::RESET};
+};
+
+static inline int ensureFlows(const Prefix &prefix, std::size_t flows) {
+  int ret = ERROR_SUCCESS;
+
+  // Make sure the provided prefix length not allows to accomodate the
+  // provided number of flows.
+  uint16_t max_ip_addr_len_bits;
+  uint16_t log2_n_flow;
+  u64 max_n_flow;
+  if (prefix.getAddressFamily() == AF_INET) {
+    max_ip_addr_len_bits = IPV4_ADDR_LEN_BITS;
+  } else if (prefix.getAddressFamily() == AF_INET6) {
+    max_ip_addr_len_bits = IPV6_ADDR_LEN_BITS;
+  } else {
+    Logger() << "Error: unknown address family." << std::endl;
+    ret = ERROR_SETUP;
+    goto end;
+  }
+
+  log2_n_flow = max_ip_addr_len_bits - prefix.getPrefixLength();
+  max_n_flow = log2_n_flow < 64 ? (1 << log2_n_flow) : ~0ULL;
+
+  if (flows > max_n_flow) {
+    Logger() << "Error: the provided prefix length does not allow to "
+                "accomodate the provided number of flows ("
+             << flows << " > " << max_n_flow << ")." << std::endl;
+    ret = ERROR_SETUP;
+  }
+
+end:
+  return ret;
+}
 
 /**
  * Class to retrieve the maximum payload size given the MTU and packet headers.
@@ -90,8 +174,9 @@ class PayloadSize {
            transport_size - fec_size;
   }
 
-  static Packet::Format getFormatFromName(Name name, bool ah = false) {
-    switch (name.getAddressFamily()) {
+  static Packet::Format getFormatFromPrefix(const Prefix &prefix,
+                                            bool ah = false) {
+    switch (prefix.getAddressFamily()) {
       case AF_INET:
         return ah ? HF_INET_TCP_AH : HF_INET_TCP;
       case AF_INET6:
@@ -158,124 +243,69 @@ struct packet_t {
   uint32_t size;
 };
 
+struct Configuration {
+  Prefix name_{"b001::abcd/64"};
+  std::string passphrase_;
+  std::string aggr_interest_passphrase_;
+  bool rtc_{false};
+  uint16_t port_{0};
+  bool aggregated_data_{false};
+  Packet::Format packet_format_{default_values::packet_format};
+  uint32_t parallel_flows_{1};
+  bool colored_{true};
+};
+
 /**
  * Container for command line configuration for hiperf client.
  */
-struct ClientConfiguration {
-  ClientConfiguration()
-      : name("b001::abcd", 0),
-        beta(-1.f),
-        drop_factor(-1.f),
-        window(-1),
-        producer_certificate(""),
-        passphrase(""),
-        receive_buffer(nullptr),
-        receive_buffer_size_(128 * 1024),
-        download_size(0),
-        report_interval_milliseconds_(1000),
-        transport_protocol_(CBR),
-        rtc_(false),
-        test_mode_(false),
-        relay_(false),
-        secure_(false),
-        producer_prefix_(),
-        interest_lifetime_(500),
-        unverified_interval_(10000),
-        unverified_ratio_(0.2),
-        relay_name_("c001::abcd/64"),
-        output_stream_mode_(false),
-        port_(0),
-        recovery_strategy_(4),
-        aggregated_data_(false),
-        packet_format_(default_values::packet_format),
-        print_headers_(true),
-        nb_iterations_(std::numeric_limits<decltype(nb_iterations_)>::max()) {}
-
-  Name name;
-  double beta;
-  double drop_factor;
-  double window;
-  std::string producer_certificate;
-  std::string passphrase;
-  std::shared_ptr<utils::MemBuf> receive_buffer;
-  std::size_t receive_buffer_size_;
-  std::size_t download_size;
-  std::uint32_t report_interval_milliseconds_;
-  TransportProtocolAlgorithms transport_protocol_;
-  bool rtc_;
-  bool test_mode_;
-  bool relay_;
-  bool secure_;
+struct ClientConfiguration : public Configuration {
+  double beta_{-1.f};
+  double drop_factor_{-1.f};
+  double window_{-1.f};
+  std::string producer_certificate_;
+  std::string passphrase_;
+  std::size_t receive_buffer_size_{128 * 1024};
+  std::uint32_t report_interval_milliseconds_{1000};
+  TransportProtocolAlgorithms transport_protocol_{CBR};
+  bool test_mode_{false};
+  bool relay_{false};
   Prefix producer_prefix_;
-  uint32_t interest_lifetime_;
-  uint32_t unverified_interval_;
-  double unverified_ratio_;
-  Prefix relay_name_;
-  bool output_stream_mode_;
-  uint16_t port_;
-  uint32_t recovery_strategy_;
-  bool aggregated_data_;
-  Packet::Format packet_format_;
-  bool print_headers_;
-  std::uint32_t nb_iterations_;
-  forwarder_type_t forwarder_type_;
+  uint32_t interest_lifetime_{500};
+  uint32_t manifest_factor_relevant_{100};
+  uint32_t manifest_factor_alert_{20};
+  Prefix relay_name_{"c001::abcd/64"};
+  bool output_stream_mode_{false};
+  uint32_t recovery_strategy_{4};
+  bool print_headers_{true};
+  std::uint32_t nb_iterations_{
+      std::numeric_limits<decltype(nb_iterations_)>::max()};
+  bool content_sharing_mode_{false};
+  bool aggregated_interests_{false};
 };
 
 /**
  * Container for command line configuration for hiperf server.
  */
-struct ServerConfiguration {
-  ServerConfiguration()
-      : name("b001::abcd/64"),
-        virtual_producer(true),
-        manifest(0),
-        live_production(false),
-        content_lifetime(600000000_U32),
-        download_size(20 * 1024 * 1024),
-        hash_algorithm_(CryptoHashType::SHA256),
-        keystore_name(""),
-        passphrase(""),
-        keystore_password("cisco"),
-        multiphase_produce_(false),
-        rtc_(false),
-        interactive_(false),
-        trace_based_(false),
-        trace_index_(0),
-        trace_file_(nullptr),
-        production_rate_(std::string("2048kbps")),
-        payload_size_(1384),
-        secure_(false),
-        input_stream_mode_(false),
-        port_(0),
-        aggregated_data_(false),
-        fec_type_(""),
-        packet_format_(default_values::packet_format) {}
-
-  Prefix name;
-  bool virtual_producer;
-  std::uint32_t manifest;
-  bool live_production;
-  std::uint32_t content_lifetime;
-  std::uint32_t download_size;
-  CryptoHashType hash_algorithm_;
-  std::string keystore_name;
-  std::string passphrase;
-  std::string keystore_password;
-  bool multiphase_produce_;
-  bool rtc_;
-  bool interactive_;
-  bool trace_based_;
-  std::uint32_t trace_index_;
-  char *trace_file_;
-  Rate production_rate_;
-  std::size_t payload_size_;
-  bool secure_;
-  bool input_stream_mode_;
-  uint16_t port_;
+struct ServerConfiguration : public Configuration {
+  bool virtual_producer_{true};
+  std::uint32_t manifest_max_capacity_{0};
+  bool live_production_{false};
+  std::uint32_t content_lifetime_{
+      transport::interface::default_values::content_object_expiry_time};
+  std::uint32_t download_size_{20 * 1024 * 1024};
+  CryptoHashType hash_algorithm_{CryptoHashType::SHA256};
+  std::string keystore_name_;
+  std::string keystore_password_{"cisco"};
+  bool multiphase_produce_{false};
+  bool interactive_{false};
+  bool trace_based_{false};
+  std::uint32_t trace_index_{0};
+  char *trace_file_{nullptr};
+  Rate production_rate_{"2048kbps"};
+  std::size_t payload_size_{1384};
+  bool input_stream_mode_{false};
   std::vector<struct packet_t> trace_;
-  bool aggregated_data_;
   std::string fec_type_;
-  Packet::Format packet_format_;
 };
 
 }  // namespace hiperf
diff --git a/apps/hiperf/src/forwarder_config.h b/apps/hiperf/src/forwarder_config.h
deleted file mode 100644 (file)
index aaac148..0000000
+++ /dev/null
@@ -1,97 +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.
- */
-
-#pragma once
-
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-namespace hiperf {
-
-struct ListenerConfig {
-  std::string address;
-  std::uint16_t port;
-  std::string interface;
-  std::string name;
-};
-
-struct ConnectorConfig {
-  std::string local_address;
-  std::uint16_t local_port;
-  std::string remote_address;
-  std::uint16_t remote_port;
-  std::string interface;
-  std::string name;
-};
-
-struct RouteConfig {
-  std::string prefix;
-  uint16_t weight;
-  std::string main_connector;
-  std::string backup_connector;
-  std::string name;
-};
-
-class ForwarderConfiguration {
- public:
-  ForwarderConfiguration() : n_threads_(1) {}
-
-  bool empty() {
-    return listeners_.empty() && connectors_.empty() && routes_.empty();
-  }
-
-  ForwarderConfiguration &setThreadNumber(std::size_t threads) {
-    n_threads_ = threads;
-    return *this;
-  }
-
-  std::size_t getThreadNumber() { return n_threads_; }
-
-  template <typename... Args>
-  ForwarderConfiguration &addListener(Args &&...args) {
-    listeners_.emplace_back(std::forward<Args>(args)...);
-    return *this;
-  }
-
-  template <typename... Args>
-  ForwarderConfiguration &addConnector(const std::string &name,
-                                       Args &&...args) {
-    connectors_.emplace(name, std::forward<Args>(args)...);
-    return *this;
-  }
-
-  template <typename... Args>
-  ForwarderConfiguration &addRoute(Args &&...args) {
-    routes_.emplace_back(std::forward<Args>(args)...);
-    return *this;
-  }
-
-  std::vector<ListenerConfig> &getListeners() { return listeners_; }
-
-  std::unordered_map<std::string, ConnectorConfig> &getConnectors() {
-    return connectors_;
-  }
-
-  std::vector<RouteConfig> &getRoutes() { return routes_; }
-
- private:
-  std::vector<ListenerConfig> listeners_;
-  std::unordered_map<std::string, ConnectorConfig> connectors_;
-  std::vector<RouteConfig> routes_;
-  std::size_t n_threads_;
-};
-
-}  // namespace hiperf
\ No newline at end of file
diff --git a/apps/hiperf/src/forwarder_interface.cc b/apps/hiperf/src/forwarder_interface.cc
deleted file mode 100644 (file)
index e87a595..0000000
+++ /dev/null
@@ -1,696 +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.
- */
-
-#include <arpa/inet.h>
-#include <forwarder_interface.h>
-#include <hicn/transport/utils/log.h>
-
-#include <chrono>
-#include <iostream>
-#include <thread>
-#include <unordered_set>
-
-extern "C" {
-#include <hicn/error.h>
-#include <hicn/util/ip_address.h>
-#include <hicn/util/sstrncpy.h>
-}
-
-// XXX the main listener should be retrieve in this class at initialization, aka
-// when hICN becomes avialable
-//
-// XXX the main listener port will be retrieved in the forwarder
-// interface... everything else will be delayed until we have this
-// information
-
-namespace hiperf {
-
-ForwarderInterface::ForwarderInterface(asio::io_service &io_service)
-    : external_ioservice_(io_service), timer_(io_service) {}
-
-ForwarderInterface::ForwarderInterface(asio::io_service &io_service,
-                                       ICallback *callback,
-                                       forwarder_type_t fwd_type)
-    : external_ioservice_(io_service), timer_(io_service) {
-  initForwarderInterface(callback, fwd_type);
-}
-
-ForwarderInterface::~ForwarderInterface() {
-  if (thread_ && thread_->joinable()) {
-    internal_ioservice_.dispatch([this]() {
-      if (sock_) {
-        hc_sock_free(sock_);
-        sock_ = nullptr;
-      }
-
-      work_.reset();
-    });
-
-    thread_->join();
-  }
-}
-
-void ForwarderInterface::initForwarderInterface(ICallback *callback,
-                                                forwarder_type_t fwd_type) {
-  forwarder_interface_callback_ = callback;
-  work_ = std::make_unique<asio::io_service::work>(internal_ioservice_);
-  sock_ = nullptr;
-  thread_ = std::make_unique<std::thread>([this]() {
-    std::cout << "Starting Forwarder Interface thread" << std::endl;
-    internal_ioservice_.run();
-    std::cout << "Stopping Forwarder Interface thread" << std::endl;
-  });
-  check_routes_timer_ = nullptr;
-  pending_add_route_counter_ = 0;
-  hicn_listen_port_ = 9695;
-  /* We start in disabled state even when a forwarder is always available */
-  state_ = State::Disabled;
-  fwd_type_ = fwd_type;
-  num_reattempts = 0;
-  std::cout << "Forwarder interface created... connecting to forwarder...\n";
-  internal_ioservice_.post([this]() { onHicnServiceAvailable(true); });
-}
-
-void ForwarderInterface::onHicnServiceAvailable(bool flag) {
-  if (flag) {
-    switch (state_) {
-      case State::Disabled:
-      case State::Requested:
-        state_ = State::Available;
-      case State::Available:
-        connectToForwarder();
-        /* Synchronous */
-        if (state_ != State::Connected) {
-          std::cout << "ConnectToForwarder failed" << std::endl;
-          goto REATTEMPT;
-        }
-        state_ = State::Ready;
-
-        std::cout << "Connected to forwarder... cancelling reconnection timer"
-                  << std::endl;
-
-        timer_.cancel();
-        num_reattempts = 0;
-
-        std::cout << "Forwarder interface is ready... communicate to controller"
-                  << std::endl;
-
-        forwarder_interface_callback_->onHicnServiceReady();
-      case State::Connected:
-      case State::Ready:
-        break;
-    }
-  } else {
-    if (sock_) {
-      hc_sock_free(sock_);
-      sock_ = nullptr;
-    }
-    state_ = State::Disabled;  // XXX to be checked upon callback to prevent the
-                               // state from going forward (used to manage
-                               // concurrency)
-  }
-  return;
-
-REATTEMPT:
-  /* Schedule reattempt */
-  std::cout << "Failed to connect, scheduling reattempt" << std::endl;
-  num_reattempts++;
-
-  timer_.expires_from_now(
-      std::chrono::milliseconds(ForwarderInterface::REATTEMPT_DELAY_MS));
-  // timer_.async_wait(std::bind(&ForwarderInterface::onHicnServiceAvailable,
-  // this, flag, std::placeholders::_1));
-  timer_.async_wait([this, flag](const std::error_code &ec) {
-    if (ec) return;
-    onHicnServiceAvailable(flag);
-  });
-}
-
-int ForwarderInterface::connectToForwarder() {
-  sock_ = hc_sock_create_forwarder(fwd_type_);
-  if (!sock_) {
-    std::cout << "Could not create socket" << std::endl;
-    goto ERR_SOCK;
-  }
-
-  if (hc_sock_connect(sock_) < 0) {
-    std::cout << "Could not connect to forwarder" << std::endl;
-    goto ERR;
-  }
-
-  std::cout << "Forwarder interface connected" << std::endl;
-  state_ = State::Connected;
-  return 0;
-
-ERR:
-  hc_sock_free(sock_);
-  sock_ = nullptr;
-ERR_SOCK:
-  return -1;
-}
-
-int ForwarderInterface::checkListener() {
-  if (!sock_) return -1;
-
-  hc_data_t *data;
-  if (hc_listener_list(sock_, &data) < 0) return -1;
-
-  int ret = -1;
-  foreach_listener(l, data) {
-    std::string interface = std::string(l->interface_name);
-    if (interface.compare("lo") != 0) {
-      hicn_listen_port_ = l->local_port;
-      state_ = State::Ready;
-      ret = 0;
-      std::cout << "Got listener port" << std::endl;
-      break;
-    }
-  }
-
-  hc_data_free(data);
-  return ret;
-}
-
-void ForwarderInterface::close() {
-  std::cout << "ForwarderInterface::close" << std::endl;
-
-  state_ = State::Disabled;
-  /* Cancelling eventual reattempts */
-  timer_.cancel();
-
-  if (sock_) {
-    hc_sock_free(sock_);
-    sock_ = nullptr;
-  }
-
-  internal_ioservice_.post([this]() { work_.reset(); });
-
-  if (thread_->joinable()) {
-    thread_->join();
-  }
-}
-
-#if 0
-void ForwarderInterface::enableCheckRoutesTimer() {
-  if (check_routes_timer_ != nullptr) return;
-
-  check_routes_timer_ =
-      std::make_unique<asio::steady_timer>(internal_ioservice_);
-  checkRoutesLoop();
-}
-
-void ForwarderInterface::removeConnectedUserNow(ProtocolPtr protocol) {
-  internalRemoveConnectedUser(protocol);
-}
-
-void ForwarderInterface::scheduleRemoveConnectedUser(ProtocolPtr protocol) {
-  internal_ioservice_.post(
-      [this, protocol]() { internalRemoveConnectedUser(protocol); });
-}
-#endif
-
-void ForwarderInterface::createFaceAndRoute(const RouteInfoPtr &route_info) {
-  std::vector<RouteInfoPtr> routes;
-  routes.push_back(std::move(route_info));
-  createFaceAndRoutes(routes);
-}
-
-void ForwarderInterface::createFaceAndRoutes(
-    const std::vector<RouteInfoPtr> &routes_info) {
-  pending_add_route_counter_++;
-  auto timer = new asio::steady_timer(internal_ioservice_);
-  internal_ioservice_.post([this, routes_info, timer]() {
-    internalCreateFaceAndRoutes(routes_info, ForwarderInterface::MAX_REATTEMPT,
-                                timer);
-  });
-}
-
-void ForwarderInterface::deleteFaceAndRoute(const RouteInfoPtr &route_info) {
-  std::vector<RouteInfoPtr> routes;
-  routes.push_back(std::move(route_info));
-  deleteFaceAndRoutes(routes);
-}
-
-void ForwarderInterface::deleteFaceAndRoutes(
-    const std::vector<RouteInfoPtr> &routes_info) {
-  internal_ioservice_.post([this, routes_info]() {
-    for (auto &route : routes_info) {
-      internalDeleteFaceAndRoute(route);
-    }
-  });
-}
-
-void ForwarderInterface::setStrategy(std::string prefix, uint32_t prefix_len,
-                                     std::string strategy) {
-  if (!sock_) return;
-
-  ip_address_t ip_prefix;
-  if (ip_address_pton(prefix.c_str(), &ip_prefix) < 0) {
-    return;
-  }
-
-  strategy_type_t strategy_type = strategy_type_from_str(strategy.c_str());
-  if (strategy_type == STRATEGY_TYPE_UNDEFINED) return;
-
-  hc_strategy_t strategy_conf;
-  strategy_conf.address = ip_prefix;
-  strategy_conf.len = prefix_len;
-  strategy_conf.family = AF_INET6;
-  strategy_conf.type = strategy_type;
-
-  hc_strategy_set(sock_, &strategy_conf);
-}
-
-void ForwarderInterface::internalDeleteFaceAndRoute(
-    const RouteInfoPtr &route_info) {
-  if (!sock_) return;
-
-  hc_data_t *data;
-  if (hc_route_list(sock_, &data) < 0) return;
-
-  std::vector<hc_route_t *> routes_to_remove;
-  foreach_route(r, data) {
-    char remote_addr[INET6_ADDRSTRLEN];
-    int ret = ip_address_ntop(&r->remote_addr, remote_addr, r->len, r->family);
-    if (ret < 0) continue;
-
-    std::string route_addr(remote_addr);
-    if (route_addr.compare(route_info->route_addr) == 0 &&
-        r->len == route_info->route_len) {
-      // route found
-      routes_to_remove.push_back(r);
-    }
-  }
-
-  if (routes_to_remove.size() == 0) {
-    // nothing to do here
-    hc_data_free(data);
-    return;
-  }
-
-  std::unordered_set<uint32_t> connids_to_remove;
-  for (unsigned i = 0; i < routes_to_remove.size(); i++) {
-    connids_to_remove.insert(routes_to_remove[i]->face_id);
-    if (hc_route_delete(sock_, routes_to_remove[i]) < 0) {
-      std::cout << "Error removing route from forwarder." << std::endl;
-    }
-  }
-
-  // remove connection
-  if (hc_connection_list(sock_, &data) < 0) {
-    hc_data_free(data);
-    return;
-  }
-
-  // collects pointerst to the connections using the conn IDs
-  std::vector<hc_connection_t *> conns_to_remove;
-  foreach_connection(c, data) {
-    if (connids_to_remove.find(c->id) != connids_to_remove.end()) {
-      // conn found
-      conns_to_remove.push_back(c);
-    }
-  }
-
-  if (conns_to_remove.size() == 0) {
-    // nothing else to do here
-    hc_data_free(data);
-    return;
-  }
-
-  for (unsigned i = 0; i < conns_to_remove.size(); i++) {
-    if (hc_connection_delete(sock_, conns_to_remove[i]) < 0) {
-      std::cout << "Error removing connection from forwarder." << std::endl;
-    }
-  }
-
-  hc_data_free(data);
-}
-
-void ForwarderInterface::internalCreateFaceAndRoutes(
-    const std::vector<RouteInfoPtr> &route_info, uint8_t max_try,
-    asio::steady_timer *timer) {
-  uint32_t face_id;
-
-  std::vector<RouteInfoPtr> failed;
-  for (auto &route : route_info) {
-    int ret = tryToCreateFace(route.get(), &face_id);
-    if (ret >= 0) {
-      auto ret = tryToCreateRoute(route.get(), face_id);
-      if (ret < 0) {
-        failed.push_back(route);
-        std::cerr << "Error creating route and face" << std::endl;
-        continue;
-      }
-    }
-  }
-
-  if (failed.size() > 0) {
-    if (max_try == 0) {
-      /* All attempts failed */
-      goto RESULT;
-    }
-    max_try--;
-    timer->expires_from_now(std::chrono::milliseconds(500));
-    timer->async_wait(
-        [this, failed, max_try, timer](const std::error_code &ec) {
-          if (ec) return;
-          internalCreateFaceAndRoutes(failed, max_try, timer);
-        });
-    return;
-  }
-
-#if 0
-  // route_status_[protocol] = std::move(route_info);
-  for (size_t i = 0; i < route_info.size(); i++) {
-    route_status_.insert(
-        std::pair<ClientId, RouteInfoPtr>(protocol, std::move(route_info[i])));
-  }
-#endif
-
-RESULT:
-  std::cout << "Face / Route create ok, now calling back protocol" << std::endl;
-  pending_add_route_counter_--;
-  external_ioservice_.post([this, r = std::move(route_info)]() mutable {
-    forwarder_interface_callback_->onRouteConfigured(r);
-  });
-  delete timer;
-}
-
-int ForwarderInterface::tryToCreateFace(RouteInfo *route_info,
-                                        uint32_t *face_id) {
-  bool found = false;
-
-  // check connection with the forwarder
-  if (!sock_) {
-    std::cout << "[ForwarderInterface::tryToCreateFace] socket error"
-              << std::endl;
-    goto ERR_SOCK;
-  }
-
-  // get listeners list
-  hc_data_t *data;
-  if (hc_listener_list(sock_, &data) < 0) {
-    std::cout << "[ForwarderInterface::tryToCreateFace] cannot list listeners";
-    goto ERR_LIST;
-  }
-
-  char _local_address[128];
-  foreach_listener(l, data) {
-    std::cout << "Processing " << l->interface_name << std::endl;
-    std::string interface = std::string(l->interface_name);
-    int ret = ip_address_ntop(&l->local_addr, _local_address, 128, AF_INET);
-    if (ret < 0) {
-      std::cerr << "Error in ip_address_ntop" << std::endl;
-      goto ERR;
-    }
-
-    std::string local_address = std::string(_local_address);
-    uint16_t local_port = l->local_port;
-
-    if (interface.compare(route_info->interface) == 0 &&
-        local_address.compare(route_info->local_addr) == 0 &&
-        local_port == route_info->local_port) {
-      found = true;
-      break;
-    }
-  }
-
-  std::cout << route_info->remote_addr << std::endl;
-
-  ip_address_t local_address, remote_address;
-  ip_address_pton(route_info->local_addr.c_str(), &local_address);
-  ip_address_pton(route_info->remote_addr.c_str(), &remote_address);
-
-  if (!found) {
-    // Create listener
-    hc_listener_t listener;
-    memset(&listener, 0, sizeof(hc_listener_t));
-
-    std::string name = "l_" + route_info->name;
-    listener.local_addr = local_address;
-    listener.type = FACE_TYPE_UDP;
-    listener.family = AF_INET;
-    listener.local_port = route_info->local_port;
-    int ret = strcpy_s(listener.name, SYMBOLIC_NAME_LEN - 1, name.c_str());
-    if (ret < EOK) goto ERR;
-    ret = strcpy_s(listener.interface_name, INTERFACE_LEN - 1,
-                   route_info->interface.c_str());
-    if (ret < EOK) goto ERR;
-
-    std::cout << "------------> " << route_info->interface << std::endl;
-
-    ret = hc_listener_create(sock_, &listener);
-
-    if (ret < 0) {
-      std::cerr << "Error creating listener." << std::endl;
-      return -1;
-    } else {
-      std::cout << "Listener " << listener.id << " created." << std::endl;
-    }
-  }
-
-  // Create face
-  hc_face_t face;
-  memset(&face, 0, sizeof(hc_face_t));
-
-  // crate face with the local interest
-  face.face.type = FACE_TYPE_UDP;
-  face.face.family = route_info->family;
-  face.face.local_addr = local_address;
-  face.face.remote_addr = remote_address;
-  face.face.local_port = route_info->local_port;
-  face.face.remote_port = route_info->remote_port;
-
-  if (netdevice_set_name(&face.face.netdevice, route_info->interface.c_str()) <
-      0) {
-    std::cout << "[ForwarderInterface::tryToCreateFaceAndRoute] "
-                 "netdevice_set_name "
-                 "("
-              << face.face.netdevice.name << ", "
-              << route_info->interface << ") error" << std::endl;
-    goto ERR;
-  }
-
-  // create face
-  if (hc_face_create(sock_, &face) < 0) {
-    std::cout << "[ForwarderInterface::tryToCreateFace] error creating face";
-    goto ERR;
-  }
-
-  std::cout << "Face created successfully" << std::endl;
-
-  // assing face to the return value
-  *face_id = face.id;
-
-  hc_data_free(data);
-  return 0;
-
-ERR:
-  hc_data_free(data);
-ERR_LIST:
-ERR_SOCK:
-  return -1;
-}
-
-int ForwarderInterface::tryToCreateRoute(RouteInfo *route_info,
-                                         uint32_t face_id) {
-  std::cout << "Trying to create route" << std::endl;
-
-  // check connection with the forwarder
-  if (!sock_) {
-    std::cout << "[ForwarderInterface::tryToCreateRoute] socket error";
-    return -1;
-  }
-
-  ip_address_t route_ip;
-  hc_route_t route;
-
-  if (ip_address_pton(route_info->route_addr.c_str(), &route_ip) < 0) {
-    std::cout << "[ForwarderInterface::tryToCreateRoute] ip_address_pton error";
-    return -1;
-  }
-
-  route.face_id = face_id;
-  route.family = AF_INET6;
-  route.remote_addr = route_ip;
-  route.len = route_info->route_len;
-  route.cost = 1;
-
-  if (hc_route_create(sock_, &route) < 0) {
-    std::cout << "[ForwarderInterface::tryToCreateRoute] error creating route";
-    return -1;
-  }
-
-  std::cout << "[ForwarderInterface::tryToCreateRoute] OK" << std::endl;
-  return 0;
-}
-
-#if 0  // not used
-void ForwarderInterface::checkRoutesLoop() {
-  check_routes_timer_->expires_from_now(std::chrono::milliseconds(1000));
-  check_routes_timer_->async_wait([this](const std::error_code &ec) {
-    if (ec) return;
-    if (pending_add_route_counter_ == 0) checkRoutes();
-  });
-}
-
-void ForwarderInterface::checkRoutes() {
-  std::cout << "someone called the checkRoutes function" << std::endl;
-  if (!sock_) return;
-
-  hc_data_t *data;
-  if (hc_route_list(sock_, &data) < 0) {
-    return;
-  }
-
-  std::unordered_set<std::string> routes_set;
-  foreach_route(r, data) {
-    char remote_addr[INET6_ADDRSTRLEN];
-    int ret = ip_address_ntop(&r->remote_addr, remote_addr, r->len, r->family);
-    if (ret < 0) continue;
-    std::string route(std::string(remote_addr) + "/" + std::to_string(r->len));
-    routes_set.insert(route);
-  }
-
-  for (auto it = route_status_.begin(); it != route_status_.end(); it++) {
-    std::string route(it->second->route_addr + "/" +
-                      std::to_string(it->second->route_len));
-    if (routes_set.find(route) == routes_set.end()) {
-      // the route is missing
-      createFaceAndRoute(it->second, it->first);
-      break;
-    }
-  }
-
-  hc_data_free(data);
-}
-#endif
-
-#if 0
-      using ListenerRetrievedCallback =
-          std::function<void(std::error_code, uint32_t)>;
-
-      ListenerRetrievedCallback listener_retrieved_callback_;
-
-#ifdef __ANDROID__
-            hicn_listen_port_(9695),
-#else
-            hicn_listen_port_(0),
-#endif
-            timer_(forward_engine_.getIoService()),
-
-      void initConfigurationProtocol(void)
-      {
-        // We need the configuration, which is different for every protocol...
-        // so we move this step down towards the protocol implementation itself.
-        if (!permanent_hicn) {
-          doInitConfigurationProtocol();
-        } else {
-          // XXX This should be moved somewhere else
-          getMainListener(
-              [this](const std::error_code &ec, uint32_t hicn_listen_port) {
-                if (!ec)
-                {
-                  hicn_listen_port_ = hicn_listen_port;
-                  doInitConfigurationProtocol();
-                }
-              });
-          }
-      }
-
-      template <typename Callback>
-      void getMainListener(Callback &&callback)
-      {
-        listener_retrieved_callback_ = std::forward<Callback &&>(callback);
-        tryToConnectToForwarder();
-      }
-    private:
-      void doGetMainListener(const std::error_code &ec)
-      {
-        if (!ec)
-        {
-          // ec == 0 --> timer expired
-          int ret = forwarder_interface_.getMainListenerPort();
-          if (ret <= 0)
-          {
-            // Since without the main listener of the forwarder the proxy cannot
-            // work, we can stop the program here until we get the listener port.
-            std::cout <<
-                "Could not retrieve main listener port from the forwarder. "
-                "Retrying.";
-
-            timer_.expires_from_now(std::chrono::milliseconds(RETRY_INTERVAL));
-            timer_.async_wait(std::bind(&Protocol::doGetMainListener, this,
-                                        std::placeholders::_1));
-          }
-          else
-          {
-            timer_.cancel();
-            retx_count_ = 0;
-            hicn_listen_port_ = uint16_t(ret);
-            listener_retrieved_callback_(
-                make_error_code(configuration_error::success), hicn_listen_port_);
-          }
-        }
-        else
-        {
-          std::cout <<  "Timer for retrieving main hicn listener canceled." << std::endl;
-        }
-      }
-
-      void tryToConnectToForwarder()
-      {
-        doTryToConnectToForwarder(std::make_error_code(std::errc(0)));
-      }
-
-      void doTryToConnectToForwarder(const std::error_code &ec)
-      {
-        if (!ec)
-        {
-          // ec == 0 --> timer expired
-          int ret = forwarder_interface_.connect();
-          if (ret < 0)
-          {
-            // We were not able to connect to the local forwarder. Do not give up
-            // and retry.
-            std::cout <<  "Could not connect to local forwarder. Retrying." << std::endl;
-
-            timer_.expires_from_now(std::chrono::milliseconds(RETRY_INTERVAL));
-            timer_.async_wait(std::bind(&Protocol::doTryToConnectToForwarder, this,
-                                        std::placeholders::_1));
-          }
-          else
-          {
-            timer_.cancel();
-            retx_count_ = 0;
-            doGetMainListener(std::make_error_code(std::errc(0)));
-          }
-        }
-        else
-        {
-          std::cout <<  "Timer for re-trying forwarder connection canceled." << std::endl;
-        }
-      }
-
-
-    template <typename ProtocolImplementation>
-    constexpr uint32_t Protocol<ProtocolImplementation>::RETRY_INTERVAL;
-
-#endif
-
-constexpr uint32_t ForwarderInterface::REATTEMPT_DELAY_MS;
-constexpr uint32_t ForwarderInterface::MAX_REATTEMPT;
-
-}  // namespace hiperf
diff --git a/apps/hiperf/src/forwarder_interface.h b/apps/hiperf/src/forwarder_interface.h
deleted file mode 100644 (file)
index e589892..0000000
+++ /dev/null
@@ -1,143 +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.
- */
-
-#pragma once
-
-#include <hicn/transport/utils/noncopyable.h>
-
-extern "C" {
-#ifndef WITH_POLICY
-#define WITH_POLICY
-#endif
-#include <hicn/ctrl/api.h>
-#include <hicn/util/ip_address.h>
-}
-
-#ifndef ASIO_STANDALONE
-#define ASIO_STANDALONE
-#endif
-#include <asio.hpp>
-#include <functional>
-#include <thread>
-#include <unordered_map>
-
-namespace hiperf {
-
-class ForwarderInterface : ::utils::NonCopyable {
-  static const uint32_t REATTEMPT_DELAY_MS = 500;
-  static const uint32_t MAX_REATTEMPT = 10;
-
- public:
-  struct RouteInfo {
-    int family;
-    std::string local_addr;
-    uint16_t local_port;
-    std::string remote_addr;
-    uint16_t remote_port;
-    std::string route_addr;
-    uint8_t route_len;
-    std::string interface;
-    std::string name;
-  };
-
-  using RouteInfoPtr = std::shared_ptr<RouteInfo>;
-
-  class ICallback {
-   public:
-    virtual void onHicnServiceReady() = 0;
-    virtual void onRouteConfigured(std::vector<RouteInfoPtr> &route_info) = 0;
-  };
-
-  enum class State {
-    Disabled,  /* Stack is stopped */
-    Requested, /* Stack is starting */
-    Available, /* Forwarder is running */
-    Connected, /* Control socket connected */
-    Ready,     /* Listener present */
-  };
-
- public:
-  explicit ForwarderInterface(asio::io_service &io_service);
-  explicit ForwarderInterface(asio::io_service &io_service, ICallback *callback,
-                              forwarder_type_t fwd_type);
-
-  ~ForwarderInterface();
-
-  void initForwarderInterface(ICallback *callback, forwarder_type_t fwd_type);
-
-  State getState();
-
-  void setState(State state);
-
-  void onHicnServiceAvailable(bool flag);
-
-  void enableCheckRoutesTimer();
-
-  void createFaceAndRoutes(const std::vector<RouteInfoPtr> &routes_info);
-
-  void createFaceAndRoute(const RouteInfoPtr &route_info);
-
-  void deleteFaceAndRoutes(const std::vector<RouteInfoPtr> &routes_info);
-
-  void deleteFaceAndRoute(const RouteInfoPtr &route_info);
-
-  void setStrategy(std::string prefix, uint32_t prefix_len,
-                   std::string strategy);
-
-  void close();
-
-  uint16_t getHicnListenerPort() { return hicn_listen_port_; }
-
- private:
-  ForwarderInterface &operator=(const ForwarderInterface &other) = delete;
-
-  int connectToForwarder();
-
-  int checkListener();
-
-  void internalCreateFaceAndRoutes(const std::vector<RouteInfoPtr> &route_info,
-                                   uint8_t max_try, asio::steady_timer *timer);
-
-  void internalDeleteFaceAndRoute(const RouteInfoPtr &routes_info);
-
-  int tryToCreateFace(RouteInfo *RouteInfo, uint32_t *face_id);
-  int tryToCreateRoute(RouteInfo *RouteInfo, uint32_t face_id);
-
-  void checkRoutesLoop();
-
-  void checkRoutes();
-
-  asio::io_service &external_ioservice_;
-  asio::io_service internal_ioservice_;
-  ICallback *forwarder_interface_callback_;
-  std::unique_ptr<asio::io_service::work> work_;
-  hc_sock_t *sock_;
-  std::unique_ptr<std::thread> thread_;
-  //  SetRouteCallback set_route_callback_;
-  // std::unordered_multimap<ProtocolPtr, RouteInfoPtr> route_status_;
-  std::unique_ptr<asio::steady_timer> check_routes_timer_;
-  uint32_t pending_add_route_counter_;
-  uint16_t hicn_listen_port_;
-
-  State state_;
-
-  forwarder_type_t fwd_type_;
-
-  /* Reattempt timer */
-  asio::steady_timer timer_;
-  unsigned num_reattempts;
-};
-
-}  // namespace hiperf
index 9c0f0a1..85cadd6 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 #include <client.h>
-#include <forwarder_interface.h>
 #include <server.h>
 
 namespace hiperf {
@@ -44,6 +43,11 @@ void usage() {
   std::cerr << "-X\t<param>\t\t\t\t"
             << "Set FEC params. Options are Rely_K#_N# or RS_K#_N#"
             << std::endl;
+  std::cerr
+      << "-J\t<passphrase>\t\t\t"
+      << "Set the passphrase used to sign/verify aggregated interests. "
+         "If set on the client, aggregated interests are enable automatically."
+      << std::endl;
 #endif
   std::cerr << std::endl;
   std::cerr << "SERVER SPECIFIC:" << std::endl;
@@ -51,11 +55,17 @@ void usage() {
                "Sends an application data unit in bytes that is published once "
                "before exit"
             << std::endl;
+  std::cerr << "-E\t<expiry_time>\t\t\t"
+               "Expiration time for data packets generated by the producer "
+               "socket"
+            << std::endl;
   std::cerr << "-s\t<packet_size>\t\t\tData packet payload size." << std::endl;
   std::cerr << "-r\t\t\t\t\t"
             << "Produce real content of <content_size> bytes" << std::endl;
-  std::cerr << "-m\t<manifest_capacity>\t\t"
-            << "Produce transport manifest" << std::endl;
+  std::cerr << "-m\t<manifest_max_capacity>\t\t"
+            << "The maximum number of entries a manifest can contain. Set it "
+               "to 0 to disable manifests. Default is 30, max is 255."
+            << std::endl;
   std::cerr << "-l\t\t\t\t\t"
             << "Start producing content upon the reception of the "
                "first interest"
@@ -92,11 +102,6 @@ void usage() {
          "the packet to generate. To be used with the -R option. -B and -I "
          "will be ignored."
       << std::endl;
-  std::cerr << "-E\t\t\t\t\t"
-            << "Enable encrypted communication. Requires the path to a p12 "
-               "file containing the "
-               "crypto material used for the TLS handshake"
-            << std::endl;
   std::cerr << "-G\t<port>\t\t\t\t"
             << "Input stream from localhost at the specified port" << std::endl;
 #endif
@@ -110,12 +115,27 @@ void usage() {
             << std::endl;
   std::cerr << "-L\t<interest lifetime>\t\t"
             << "Set interest lifetime." << std::endl;
-  std::cerr << "-u\t<delay>\t\t\t\t"
-            << "Set max lifetime of unverified packets." << std::endl;
+  std::cerr << "-U\t<factor>\t\t\t"
+            << "Update the relevance threshold: if an unverified packet has "
+               "been received before the last U * manifest_max_capacity_ "
+               "packets received (verified or not), it will be flushed out. "
+               "Should be > 1, default is 100."
+            << std::endl;
+  std::cerr << "-u\t<factor>\t\t\t"
+            << "Update the alert threshold: if the "
+               "number of unverified packet is > u * manifest_max_capacity_, "
+               "an alert is raised. Should be set such that U > u >= 1, "
+               "default is 20. If u >= U, no alert will ever be raised."
+            << std::endl;
   std::cerr << "-M\t<input_buffer_size>\t\t"
             << "Size of consumer input buffer. If 0, reassembly of packets "
                "will be disabled."
             << std::endl;
+  std::cerr << "-N\t\t\t\t\t"
+            << "Enable aggregated interests; the number of suffixes (including "
+               "the one in the header) can be set through the env variable "
+               "`MAX_AGGREGATED_INTERESTS`."
+            << std::endl;
   std::cerr << "-W\t<window_size>\t\t\t"
             << "Use a fixed congestion window "
                "for retrieving the data."
@@ -137,7 +157,10 @@ void usage() {
                "used with the -R (default: false)"
             << std::endl;
   std::cerr << "-P\t\t\t\t\t"
-            << "Prefix of the producer where to do the handshake" << std::endl;
+            << "Number of parallel streams. For hiperf client, this is the "
+               "number of consumer to create, while for hiperf server this is "
+               "the number of producers to create."
+            << std::endl;
   std::cerr << "-j\t<relay_name>\t\t\t"
             << "Publish received content under the name relay_name."
                "This is an RTC specific option, to be "
@@ -145,13 +168,25 @@ void usage() {
             << std::endl;
   std::cerr << "-g\t<port>\t\t\t\t"
             << "Output stream to localhost at the specified port" << std::endl;
+  std::cerr << "-o\t\t\t\t\t"
+            << "Content sharing mode: if set the socket work in content sharing"
+            << "mode. It works only in RTC mode" << std::endl;
   std::cerr << "-e\t<strategy>\t\t\t"
-            << "Enhance the network with a reliability strategy. Options 1:"
-            << " unreliable, 2: rtx only, 3: fec only, "
-            << "4: delay based, 5: low rate, 6: low rate and best path "
-            << "7: low rate and replication, 8: low rate and best"
-            << " path/replication"
-            << "(default: 2 = rtx only) " << std::endl;
+            << "Enhance the network with a reliability strategy. Options"
+            << std::endl;
+  std::cerr << "\t\t\t\t\t\t1: unreliable " << std::endl;
+  std::cerr << "\t\t\t\t\t\t2: rtx only " << std::endl;
+  std::cerr << "\t\t\t\t\t\t3: fec only " << std::endl;
+  std::cerr << "\t\t\t\t\t\t4: delay based " << std::endl;
+  std::cerr << "\t\t\t\t\t\t5: low rate " << std::endl;
+  std::cerr << "\t\t\t\t\t\t6: low rate and best path " << std::endl;
+  std::cerr << "\t\t\t\t\t\t7: low rate and replication" << std::endl;
+  std::cerr << "\t\t\t\t\t\t8: low rate and best path/replication "
+            << std::endl;
+  std::cerr << "\t\t\t\t\t\t9: only fec low residual losses " << std::endl;
+  std::cerr << "\t\t\t\t\t\t10: delay and best path " << std::endl;
+  std::cerr << "\t\t\t\t\t\t11: delay and replication " << std::endl;
+  std::cerr << "\t\t\t\t\t\t(default: 2 = rtx only) " << std::endl;
   std::cerr << "-H\t\t\t\t\t"
             << "Disable periodic print headers in stats report." << std::endl;
   std::cerr << "-n\t<nb_iterations>\t\t\t"
@@ -170,6 +205,8 @@ int main(int argc, char *argv[]) {
   WSAStartup(MAKEWORD(2, 2), &wsaData);
 #endif
 
+  transport::interface::global_config::GlobalConfigInterface global_conf;
+
   // -1 server, 0 undefined, 1 client
   int role = 0;
   int options = 0;
@@ -188,9 +225,10 @@ int main(int argc, char *argv[]) {
   int opt;
 #ifndef _WIN32
   // Please keep in alphabetical order.
-  while ((opt = getopt(argc, argv,
-                       "A:B:CDE:F:G:HIK:L:M:P:RST:U:W:X:ab:c:d:e:f:g:hi:j:k:lm:"
-                       "n:p:rs:tu:vwxy:z:")) != -1) {
+  while (
+      (opt = getopt(argc, argv,
+                    "A:B:CDE:F:G:HIJ:K:L:M:NP:RST:U:W:X:ab:c:d:e:f:g:hi:j:k:lm:"
+                    "n:op:qrs:tu:vwxy:z:")) != -1) {
     switch (opt) {
       // Common
       case 'D': {
@@ -225,10 +263,14 @@ int main(int argc, char *argv[]) {
 #else
   // Please keep in alphabetical order.
   while ((opt = getopt(argc, argv,
-                       "A:B:CE:F:HK:L:M:P:RSU:W:X:ab:c:d:e:f:hi:j:k:lm:n:p:rs:"
+                       "A:B:CE:F:HK:L:M:P:RSU:W:X:ab:c:d:e:f:hi:j:k:lm:n:op:rs:"
                        "tu:vwxy:z:")) != -1) {
     switch (opt) {
 #endif
+      case 'E': {
+        server_configuration.content_lifetime_ = std::stoul(optarg);
+        break;
+      }
       case 'f': {
         log_file = optarg;
         break;
@@ -243,14 +285,18 @@ int main(int argc, char *argv[]) {
         server_configuration.aggregated_data_ = true;
         break;
       }
+      case 'o': {
+        client_configuration.content_sharing_mode_ = true;
+        break;
+      }
       case 'w': {
         client_configuration.packet_format_ = Packet::Format::HF_INET6_UDP;
         server_configuration.packet_format_ = Packet::Format::HF_INET6_UDP;
         break;
       }
       case 'k': {
-        server_configuration.passphrase = std::string(optarg);
-        client_configuration.passphrase = std::string(optarg);
+        server_configuration.passphrase_ = std::string(optarg);
+        client_configuration.passphrase_ = std::string(optarg);
         break;
       }
       case 'z': {
@@ -271,20 +317,31 @@ int main(int argc, char *argv[]) {
         role += 1;
         break;
       }
-
+      case 'q': {
+        client_configuration.colored_ = server_configuration.colored_ = false;
+        break;
+      }
+      case 'J': {
+        client_configuration.aggr_interest_passphrase_ = optarg;
+        server_configuration.aggr_interest_passphrase_ = optarg;
+        // Consumer signature is only used with aggregated interests,
+        // hence enabling it also forces usage of aggregated interests
+        client_configuration.aggregated_interests_ = true;
+        break;
+      }
       // Client specifc
       case 'b': {
-        client_configuration.beta = std::stod(optarg);
+        client_configuration.beta_ = std::stod(optarg);
         options = 1;
         break;
       }
       case 'd': {
-        client_configuration.drop_factor = std::stod(optarg);
+        client_configuration.drop_factor_ = std::stod(optarg);
         options = 1;
         break;
       }
       case 'W': {
-        client_configuration.window = std::stod(optarg);
+        client_configuration.window_ = std::stod(optarg);
         options = 1;
         break;
       }
@@ -293,13 +350,17 @@ int main(int argc, char *argv[]) {
         options = 1;
         break;
       }
+      case 'N': {
+        client_configuration.aggregated_interests_ = true;
+        break;
+      }
       case 'P': {
-        client_configuration.producer_prefix_ = Prefix(optarg);
-        client_configuration.secure_ = true;
+        client_configuration.parallel_flows_ =
+            server_configuration.parallel_flows_ = std::stoull(optarg);
         break;
       }
       case 'c': {
-        client_configuration.producer_certificate = std::string(optarg);
+        client_configuration.producer_certificate_ = std::string(optarg);
         options = 1;
         break;
       }
@@ -318,13 +379,13 @@ int main(int argc, char *argv[]) {
         options = 1;
         break;
       }
-      case 'u': {
-        client_configuration.unverified_interval_ = std::stoul(optarg);
+      case 'U': {
+        client_configuration.manifest_factor_relevant_ = std::stoul(optarg);
         options = 1;
         break;
       }
-      case 'U': {
-        client_configuration.unverified_ratio_ = std::stod(optarg);
+      case 'u': {
+        client_configuration.manifest_factor_alert_ = std::stoul(optarg);
         options = 1;
         break;
       }
@@ -346,7 +407,7 @@ int main(int argc, char *argv[]) {
       }
       // Server specific
       case 'A': {
-        server_configuration.download_size = std::stoul(optarg);
+        server_configuration.download_size_ = std::stoul(optarg);
         options = -1;
         break;
       }
@@ -356,22 +417,22 @@ int main(int argc, char *argv[]) {
         break;
       }
       case 'r': {
-        server_configuration.virtual_producer = false;
+        server_configuration.virtual_producer_ = false;
         options = -1;
         break;
       }
       case 'm': {
-        server_configuration.manifest = std::stoul(optarg);
+        server_configuration.manifest_max_capacity_ = std::stoul(optarg);
         options = -1;
         break;
       }
       case 'l': {
-        server_configuration.live_production = true;
+        server_configuration.live_production_ = true;
         options = -1;
         break;
       }
       case 'K': {
-        server_configuration.keystore_name = std::string(optarg);
+        server_configuration.keystore_name_ = std::string(optarg);
         options = -1;
         break;
       }
@@ -393,7 +454,7 @@ int main(int argc, char *argv[]) {
         break;
       }
       case 'p': {
-        server_configuration.keystore_password = std::string(optarg);
+        server_configuration.keystore_password_ = std::string(optarg);
         options = -1;
         break;
       }
@@ -409,11 +470,6 @@ int main(int argc, char *argv[]) {
         options = -1;
         break;
       }
-      case 'E': {
-        server_configuration.keystore_name = std::string(optarg);
-        server_configuration.secure_ = true;
-        break;
-      }
       case 'e': {
         client_configuration.recovery_strategy_ = std::stoul(optarg);
         options = 1;
@@ -457,9 +513,9 @@ int main(int argc, char *argv[]) {
     return EXIT_FAILURE;
   } else {
     if (role > 0) {
-      client_configuration.name = Name(argv[optind]);
+      client_configuration.name_ = Prefix(argv[optind]);
     } else {
-      server_configuration.name = Prefix(argv[optind]);
+      server_configuration.name_ = Prefix(argv[optind]);
     }
   }
 
@@ -490,16 +546,9 @@ int main(int argc, char *argv[]) {
   config.set();
 
   // Parse config file
-  transport::interface::global_config::parseConfigurationFile(conf_file);
+  global_conf.parseConfigurationFile(conf_file);
 
   if (role > 0) {
-    // set forwarder type
-    client_configuration.forwarder_type_ = UNDEFINED;
-    if (config.name.compare("hicnlightng_module") == 0)
-      client_configuration.forwarder_type_ = HICNLIGHT;
-    else if (config.name.compare("hicnlightng_module") == 0)
-      client_configuration.forwarder_type_ = HICNLIGHT_NG;
-
     HIperfClient c(client_configuration);
     if (c.setup() != ERROR_SETUP) {
       c.run();
index 7101e7a..afaf542 100644 (file)
@@ -21,156 +21,79 @@ namespace hiperf {
  * Hiperf server class: configure and setup an hicn producer following the
  * ServerConfiguration.
  */
-class HIperfServer::Impl : public ProducerSocket::Callback {
-  const std::size_t log2_content_object_buffer_size = 8;
-
- public:
-  Impl(const hiperf::ServerConfiguration &conf)
-      : configuration_(conf),
-        signals_(io_service_),
-        rtc_timer_(io_service_),
-        unsatisfied_interests_(),
-        content_objects_((std::uint16_t)(1 << log2_content_object_buffer_size)),
-        content_objects_index_(0),
-        mask_((std::uint16_t)(1 << log2_content_object_buffer_size) - 1),
-        last_segment_(0),
-#ifndef _WIN32
-        input_(io_service_),
-        rtc_running_(false),
-#endif
-        flow_name_(configuration_.name.getName()),
-        socket_(io_service_),
-        recv_buffer_(nullptr, 0) {
-    std::string buffer(configuration_.payload_size_, 'X');
-    std::cout << "Producing contents under name " << conf.name.getName()
-              << std::endl;
-#ifndef _WIN32
-    if (configuration_.interactive_) {
-      input_.assign(::dup(STDIN_FILENO));
-    }
-#endif
-
-    for (int i = 0; i < (1 << log2_content_object_buffer_size); i++) {
-      content_objects_[i] = ContentObject::Ptr(new ContentObject(
-          configuration_.name.getName(), configuration_.packet_format_, 0,
-          (const uint8_t *)buffer.data(), buffer.size()));
-      content_objects_[i]->setLifetime(
-          default_values::content_object_expiry_time);
-    }
+class HIperfServer::Impl {
+  static inline constexpr std::size_t klog2_content_object_buffer_size() {
+    return 8;
   }
-
-  virtual ~Impl() {}
-
-  void virtualProcessInterest(ProducerSocket &p, const Interest &interest) {
-    content_objects_[content_objects_index_ & mask_]->setName(
-        interest.getName());
-    producer_socket_->produce(
-        *content_objects_[content_objects_index_++ & mask_]);
+  static inline constexpr std::size_t kcontent_object_buffer_size() {
+    return (1 << klog2_content_object_buffer_size());
   }
-
-  void processInterest(ProducerSocket &p, const Interest &interest) {
-    p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS,
-                      (ProducerInterestCallback)VOID_HANDLER);
-    p.setSocketOption(GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME,
-                      5000000_U32);
-
-    produceContent(p, interest.getName(), interest.getName().getSuffix());
-    std::cout << "Received interest " << interest.getName().getSuffix()
-              << std::endl;
+  static inline constexpr std::size_t kmask() {
+    return (kcontent_object_buffer_size() - 1);
   }
 
-  void asyncProcessInterest(ProducerSocket &p, const Interest &interest) {
-    p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS,
-                      (ProducerInterestCallback)bind(&Impl::cacheMiss, this,
-                                                     std::placeholders::_1,
-                                                     std::placeholders::_2));
-    p.setSocketOption(GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME,
-                      5000000_U32);
-    uint32_t suffix = interest.getName().getSuffix();
-
-    if (suffix == 0) {
-      last_segment_ = 0;
-      unsatisfied_interests_.clear();
-    }
-
-    // The suffix will either come from the received interest or will be set to
-    // the smallest suffix of a previous interest not satisfied
-    if (!unsatisfied_interests_.empty()) {
-      auto it = std::lower_bound(unsatisfied_interests_.begin(),
-                                 unsatisfied_interests_.end(), last_segment_);
-      if (it != unsatisfied_interests_.end()) {
-        suffix = *it;
+  /**
+   * @brief As we can (potentially) setup many producer sockets, we need to keep
+   * a separate context for each one of them. The context contains parameters
+   * and variable that are specific to a single producer socket.
+   */
+  class ProducerContext
+      : public Base<ProducerContext, ServerConfiguration, Impl>,
+        public ProducerSocket::Callback {
+   public:
+    using ConfType = ServerConfiguration;
+    using ParentType = typename HIperfServer::Impl;
+    static inline const auto getContextType() { return "ProducerContext"; }
+
+    ProducerContext(HIperfServer::Impl &server, int producer_identifier)
+        : Base(server, server.io_service_, producer_identifier) {
+      // Allocate buffer to copy as content objects payload
+      std::string buffer(configuration_.payload_size_, 'X');
+
+      // Allocate array of content objects. They are share_ptr so that the
+      // transport will only capture a reference to them instead of performing
+      // an hard copy.
+      for (std::size_t i = 0; i < kcontent_object_buffer_size(); i++) {
+        const auto &element =
+            content_objects_.emplace_back(std::make_shared<ContentObject>(
+                configuration_.name_.makeName(), configuration_.packet_format_,
+                0, (const uint8_t *)buffer.data(), buffer.size()));
+        element->setLifetime(default_values::content_object_expiry_time);
       }
-      unsatisfied_interests_.erase(unsatisfied_interests_.begin(), it);
     }
 
-    std::cout << "Received interest " << interest.getName().getSuffix()
-              << ", starting production at " << suffix << std::endl;
-    std::cout << unsatisfied_interests_.size() << " interests still unsatisfied"
-              << std::endl;
-    produceContentAsync(p, interest.getName(), suffix);
-  }
+    // To make vector happy (move or copy constructor is needed when vector
+    // resizes)
+    ProducerContext(ProducerContext &&other) noexcept
+        : Base(std::move(other)),
+          content_objects_(std::move(other.content_objects_)),
+          unsatisfied_interests_(std::move(other.unsatisfied_interests_)),
+          last_segment_(other.last_segment_),
+          producer_socket_(std::move(other.producer_socket_)),
+          content_objects_index_(other.content_objects_index_),
+          payload_size_max_(other.payload_size_max_) {}
 
-  void produceContent(ProducerSocket &p, const Name &content_name,
-                      uint32_t suffix) {
-    auto b = utils::MemBuf::create(configuration_.download_size);
-    std::memset(b->writableData(), '?', configuration_.download_size);
-    b->append(configuration_.download_size);
-    uint32_t total;
-
-    utils::SteadyTime::TimePoint t0 = utils::SteadyTime::Clock::now();
-    total = p.produceStream(content_name, std::move(b),
-                            !configuration_.multiphase_produce_, suffix);
-    utils::SteadyTime::TimePoint t1 = utils::SteadyTime::Clock::now();
-
-    std::cout << "Written " << total
-              << " data packets in output buffer (Segmentation time: "
-              << utils::SteadyTime::getDurationUs(t0, t1).count() << " us)"
-              << std::endl;
-  }
+    virtual ~ProducerContext() = default;
 
-  void produceContentAsync(ProducerSocket &p, Name content_name,
-                           uint32_t suffix) {
-    produce_thread_.add([this, suffix, content_name]() {
-      auto b = utils::MemBuf::create(configuration_.download_size);
-      std::memset(b->writableData(), '?', configuration_.download_size);
-      b->append(configuration_.download_size);
-
-      last_segment_ = suffix + producer_socket_->produceStream(
-                                   content_name, std::move(b),
-                                   !configuration_.multiphase_produce_, suffix);
-    });
-  }
+    /**
+     * @brief Produce datagram
+     */
+    void produceDatagram(const uint8_t *buffer, std::size_t buffer_size) const {
+      assert(producer_socket_);
 
-  void cacheMiss(ProducerSocket &p, const Interest &interest) {
-    unsatisfied_interests_.push_back(interest.getName().getSuffix());
-  }
+      auto size = std::min(buffer_size, payload_size_max_);
 
-  void onContentProduced(ProducerSocket &p, const std::error_code &err,
-                         uint64_t bytes_written) {
-    p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS,
-                      (ProducerInterestCallback)bind(
-                          &Impl::asyncProcessInterest, this,
-                          std::placeholders::_1, std::placeholders::_2));
-  }
+      producer_socket_->produceDatagram(flow_name_, buffer, size);
+    }
 
-  void produceError(const std::error_code &err) noexcept override {
-    std::cerr << "Error from producer transport: " << err.message()
-              << std::endl;
-    producer_socket_->stop();
-    io_service_.stop();
-  }
+    /**
+     * @brief Create and setup the producer socket
+     */
+    int setup() {
+      int ret;
+      int production_protocol;
+      std::shared_ptr<Signer> signer = std::make_shared<VoidSigner>();
 
-  int setup() {
-    int ret;
-    int production_protocol;
-    std::shared_ptr<Signer> signer = std::make_shared<VoidSigner>();
-
-    if (configuration_.secure_) {
-      producer_socket_ = std::make_unique<P2PSecureProducerSocket>(
-          configuration_.rtc_, configuration_.keystore_name,
-          configuration_.keystore_password);
-    } else {
       if (!configuration_.rtc_) {
         production_protocol = ProductionProtocolAlgorithms::BYTE_STREAM;
       } else {
@@ -178,255 +101,466 @@ class HIperfServer::Impl : public ProducerSocket::Callback {
       }
 
       producer_socket_ = std::make_unique<ProducerSocket>(production_protocol);
-    }
-
-    if (producer_socket_->setSocketOption(
-            ProducerCallbacksOptions::PRODUCER_CALLBACK, this) ==
-        SOCKET_OPTION_NOT_SET) {
-      std::cerr << "Failed to set producer callback." << std::endl;
-      return ERROR_SETUP;
-    }
-
-    if (producer_socket_->setSocketOption(
-            GeneralTransportOptions::MAKE_MANIFEST, configuration_.manifest) ==
-        SOCKET_OPTION_NOT_SET) {
-      return ERROR_SETUP;
-    }
 
-    if (producer_socket_->setSocketOption(
-            GeneralTransportOptions::HASH_ALGORITHM,
-            configuration_.hash_algorithm_) == SOCKET_OPTION_NOT_SET) {
-      return ERROR_SETUP;
-    }
-
-    if (producer_socket_->setSocketOption(PACKET_FORMAT,
-                                          configuration_.packet_format_) ==
-        SOCKET_OPTION_NOT_SET) {
-      std::cerr << "ERROR -- Impossible to set the packet format." << std::endl;
-      return ERROR_SETUP;
-    }
+      if (producer_socket_->setSocketOption(
+              ProducerCallbacksOptions::PRODUCER_CALLBACK, this) ==
+          SOCKET_OPTION_NOT_SET) {
+        getOutputStream() << "Failed to set producer callback." << std::endl;
+        return ERROR_SETUP;
+      }
 
-    if (!configuration_.passphrase.empty()) {
-      signer = std::make_shared<SymmetricSigner>(CryptoSuite::HMAC_SHA256,
-                                                 configuration_.passphrase);
-    }
+      if (producer_socket_->setSocketOption(
+              GeneralTransportOptions::HASH_ALGORITHM,
+              configuration_.hash_algorithm_) == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
 
-    if (!configuration_.keystore_name.empty()) {
-      signer = std::make_shared<AsymmetricSigner>(
-          configuration_.keystore_name, configuration_.keystore_password);
-    }
+      if (producer_socket_->setSocketOption(
+              GeneralTransportOptions::MANIFEST_MAX_CAPACITY,
+              configuration_.manifest_max_capacity_) == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
 
-    producer_socket_->setSocketOption(GeneralTransportOptions::SIGNER, signer);
+      if (producer_socket_->setSocketOption(PACKET_FORMAT,
+                                            configuration_.packet_format_) ==
+          SOCKET_OPTION_NOT_SET) {
+        getOutputStream() << "ERROR -- Impossible to set the packet format."
+                          << std::endl;
+        return ERROR_SETUP;
+      }
 
-    // Compute maximum payload size
-    Packet::Format format = PayloadSize::getFormatFromName(
-        configuration_.name.getName(), !configuration_.manifest);
-    payload_size_max_ = PayloadSize(format).getPayloadSizeMax(
-        configuration_.rtc_ ? RTC_HEADER_SIZE : 0,
-        configuration_.fec_type_.empty() ? 0 : FEC_HEADER_MAX_SIZE,
-        !configuration_.manifest ? signer->getSignatureFieldSize() : 0);
+      if (!configuration_.passphrase_.empty()) {
+        signer = std::make_shared<SymmetricSigner>(CryptoSuite::HMAC_SHA256,
+                                                   configuration_.passphrase_);
+      }
 
-    if (configuration_.payload_size_ > payload_size_max_) {
-      std::cerr << "WARNING: Payload has size " << configuration_.payload_size_
-                << ", maximum is " << payload_size_max_
-                << ". Payload will be truncated to fit." << std::endl;
-    }
+      if (!configuration_.keystore_name_.empty()) {
+        signer = std::make_shared<AsymmetricSigner>(
+            configuration_.keystore_name_, configuration_.keystore_password_);
+      }
 
-    if (configuration_.rtc_) {
-      ret = producer_socket_->setSocketOption(
-          RtcTransportOptions::AGGREGATED_DATA,
-          configuration_.aggregated_data_);
+      producer_socket_->setSocketOption(GeneralTransportOptions::SIGNER,
+                                        signer);
+
+      // Compute maximum payload size
+      Packet::Format format = PayloadSize::getFormatFromPrefix(
+          configuration_.name_, !configuration_.manifest_max_capacity_);
+      payload_size_max_ = PayloadSize(format).getPayloadSizeMax(
+          configuration_.rtc_ ? RTC_HEADER_SIZE : 0,
+          configuration_.fec_type_.empty() ? 0 : FEC_HEADER_MAX_SIZE,
+          !configuration_.manifest_max_capacity_
+              ? signer->getSignatureFieldSize()
+              : 0);
+
+      if (configuration_.payload_size_ > payload_size_max_) {
+        getOutputStream() << "WARNING: Payload has size "
+                          << configuration_.payload_size_ << ", maximum is "
+                          << payload_size_max_
+                          << ". Payload will be truncated to fit." << std::endl;
+      }
 
-      if (ret == SOCKET_OPTION_NOT_SET) {
-        return ERROR_SETUP;
+      // Verifier for aggregated interests
+      std::shared_ptr<Verifier> verifier = std::make_shared<VoidVerifier>();
+      if (!configuration_.aggr_interest_passphrase_.empty()) {
+        verifier = std::make_unique<SymmetricVerifier>(
+            configuration_.aggr_interest_passphrase_);
       }
-    }
+      ret = producer_socket_->setSocketOption(GeneralTransportOptions::VERIFIER,
+                                              verifier);
+      if (ret == SOCKET_OPTION_NOT_SET) return ERROR_SETUP;
 
-    if (configuration_.rtc_) {
-      ret = producer_socket_->setSocketOption(GeneralTransportOptions::FEC_TYPE,
-                                              configuration_.fec_type_);
+      if (configuration_.rtc_) {
+        ret = producer_socket_->setSocketOption(
+            RtcTransportOptions::AGGREGATED_DATA,
+            configuration_.aggregated_data_);
 
-      if (ret == SOCKET_OPTION_NOT_SET) {
-        return ERROR_SETUP;
-      }
-    }
+        if (ret == SOCKET_OPTION_NOT_SET) {
+          return ERROR_SETUP;
+        }
 
-    producer_socket_->registerPrefix(configuration_.name);
-    producer_socket_->connect();
-    producer_socket_->start();
+        ret = producer_socket_->setSocketOption(
+            GeneralTransportOptions::FEC_TYPE, configuration_.fec_type_);
 
-    if (configuration_.rtc_) {
-      std::cout << "Running RTC producer: the prefix length will be ignored."
-                   " Use /128 by default in RTC mode"
-                << std::endl;
-      return ERROR_SUCCESS;
-    }
+        if (ret == SOCKET_OPTION_NOT_SET) {
+          return ERROR_SETUP;
+        }
+      }
 
-    if (!configuration_.virtual_producer) {
       if (producer_socket_->setSocketOption(
               GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME,
-              configuration_.content_lifetime) == SOCKET_OPTION_NOT_SET) {
+              configuration_.content_lifetime_) == SOCKET_OPTION_NOT_SET) {
         return ERROR_SETUP;
       }
 
-      if (producer_socket_->setSocketOption(
-              GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 200000U) ==
-          SOCKET_OPTION_NOT_SET) {
-        return ERROR_SETUP;
-      }
+      producer_socket_->registerPrefix(Prefix(flow_name_, 128));
+      producer_socket_->connect();
+      producer_socket_->start();
 
-      if (producer_socket_->setSocketOption(
-              GeneralTransportOptions::MAX_SEGMENT_SIZE,
-              static_cast<uint32_t>(configuration_.payload_size_)) ==
-          SOCKET_OPTION_NOT_SET) {
-        return ERROR_SETUP;
+      if (configuration_.rtc_) {
+        return ERROR_SUCCESS;
       }
 
-      if (!configuration_.live_production) {
-        produceContent(*producer_socket_, configuration_.name.getName(), 0);
+      if (!configuration_.virtual_producer_) {
+        if (producer_socket_->setSocketOption(
+                GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 200000U) ==
+            SOCKET_OPTION_NOT_SET) {
+          return ERROR_SETUP;
+        }
+
+        if (producer_socket_->setSocketOption(
+                GeneralTransportOptions::MAX_SEGMENT_SIZE,
+                static_cast<uint32_t>(configuration_.payload_size_)) ==
+            SOCKET_OPTION_NOT_SET) {
+          return ERROR_SETUP;
+        }
+
+        if (!configuration_.live_production_) {
+          produceContent(*producer_socket_, configuration_.name_.makeName(), 0);
+        } else {
+          ret = producer_socket_->setSocketOption(
+              ProducerCallbacksOptions::CACHE_MISS,
+              (ProducerInterestCallback)bind(
+                  &ProducerContext::asyncProcessInterest, this,
+                  std::placeholders::_1, std::placeholders::_2));
+
+          if (ret == SOCKET_OPTION_NOT_SET) {
+            return ERROR_SETUP;
+          }
+        }
       } else {
+        ret = producer_socket_->setSocketOption(
+            GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 0U);
+
+        if (ret == SOCKET_OPTION_NOT_SET) {
+          return ERROR_SETUP;
+        }
+
         ret = producer_socket_->setSocketOption(
             ProducerCallbacksOptions::CACHE_MISS,
-            (ProducerInterestCallback)bind(&Impl::asyncProcessInterest, this,
-                                           std::placeholders::_1,
-                                           std::placeholders::_2));
+            (ProducerInterestCallback)bind(
+                &ProducerContext::virtualProcessInterest, this,
+                std::placeholders::_1, std::placeholders::_2));
 
         if (ret == SOCKET_OPTION_NOT_SET) {
           return ERROR_SETUP;
         }
       }
-    } else {
-      ret = producer_socket_->setSocketOption(
-          GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 0U);
 
+      ret = producer_socket_->setSocketOption(
+          ProducerCallbacksOptions::CONTENT_PRODUCED,
+          (ProducerContentCallback)bind(
+              &ProducerContext::onContentProduced, this, std::placeholders::_1,
+              std::placeholders::_2, std::placeholders::_3));
       if (ret == SOCKET_OPTION_NOT_SET) {
         return ERROR_SETUP;
       }
 
-      ret = producer_socket_->setSocketOption(
-          ProducerCallbacksOptions::CACHE_MISS,
-          (ProducerInterestCallback)bind(&Impl::virtualProcessInterest, this,
-                                         std::placeholders::_1,
-                                         std::placeholders::_2));
+      return ERROR_SUCCESS;
+    }
 
-      if (ret == SOCKET_OPTION_NOT_SET) {
-        return ERROR_SETUP;
+    int run() {
+      getOutputStream() << "started to serve consumers with name " << flow_name_
+                        << std::endl;
+      return ERROR_SUCCESS;
+    }
+
+    void stop() {
+      getOutputStream() << "stopped to serve consumers" << std::endl;
+      producer_socket_->stop();
+    }
+
+   private:
+    /**
+     * @brief Produce an existing content object. Set the name as the
+     * interest.
+     */
+    void virtualProcessInterest(ProducerSocket &p, const Interest &interest) {
+      content_objects_[content_objects_index_ & kmask()]->setName(
+          interest.getName());
+      p.produce(*content_objects_[content_objects_index_++ & kmask()]);
+    }
+
+    /**
+     * @brief Create and produce a buffer of configuration_.download_size_
+     * length.
+     */
+    void produceContent(ProducerSocket &p, const Name &content_name,
+                        uint32_t suffix) const {
+      uint32_t total;
+
+      auto b = utils::MemBuf::create(configuration_.download_size_);
+      std::memset(b->writableData(), '?', configuration_.download_size_);
+      b->append(configuration_.download_size_);
+
+      utils::SteadyTime::TimePoint t0 = utils::SteadyTime::Clock::now();
+      total = p.produceStream(content_name, std::move(b),
+                              !configuration_.multiphase_produce_, suffix);
+      utils::SteadyTime::TimePoint t1 = utils::SteadyTime::Clock::now();
+
+      Logger() << "Written " << total
+               << " data packets in output buffer (Segmentation time: "
+               << utils::SteadyTime::getDurationUs(t0, t1).count() << " us)"
+               << std::endl;
+    }
+
+    /**
+     * @brief Synchronously produce content upon reception of one interest
+     */
+    void processInterest(ProducerSocket &p, const Interest &interest) const {
+      p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS,
+                        (ProducerInterestCallback)VOID_HANDLER);
+      p.setSocketOption(GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME,
+                        configuration_.content_lifetime_);
+
+      produceContent(p, interest.getName(), interest.getName().getSuffix());
+      Logger() << "Received interest " << interest.getName().getSuffix()
+               << std::endl;
+    }
+
+    /**
+     * @brief Async create and produce a buffer of
+     * configuration_.download_size_ length.
+     */
+    void produceContentAsync(ProducerSocket &p, Name content_name,
+                             uint32_t suffix) {
+      parent_.produce_thread_.add([this, suffix, content_name, &p]() {
+        auto b = utils::MemBuf::create(configuration_.download_size_);
+        std::memset(b->writableData(), '?', configuration_.download_size_);
+        b->append(configuration_.download_size_);
+
+        last_segment_ =
+            suffix + p.produceStream(content_name, std::move(b),
+                                     !configuration_.multiphase_produce_,
+                                     suffix);
+      });
+    }
+
+    /**
+     * @brief Asynchronously produce content upon reception of one interest
+     */
+    void asyncProcessInterest(ProducerSocket &p, const Interest &interest) {
+      p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS,
+                        (ProducerInterestCallback)bind(
+                            &ProducerContext::cacheMiss, this,
+                            std::placeholders::_1, std::placeholders::_2));
+      p.setSocketOption(GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME,
+                        configuration_.content_lifetime_);
+      uint32_t suffix = interest.getName().getSuffix();
+
+      if (suffix == 0) {
+        last_segment_ = 0;
+        unsatisfied_interests_.clear();
+      }
+
+      // The suffix will either come from the received interest or will be set
+      // to the smallest suffix of a previous interest not satisfied
+      if (!unsatisfied_interests_.empty()) {
+        auto it = std::lower_bound(unsatisfied_interests_.begin(),
+                                   unsatisfied_interests_.end(), last_segment_);
+        if (it != unsatisfied_interests_.end()) {
+          suffix = *it;
+        }
+        unsatisfied_interests_.erase(unsatisfied_interests_.begin(), it);
       }
+
+      getOutputStream() << " Received interest "
+                        << interest.getName().getSuffix()
+                        << ", starting production at " << suffix << end_mod_
+                        << std::endl;
+      getOutputStream() << unsatisfied_interests_.size()
+                        << " interests still unsatisfied" << end_mod_
+                        << std::endl;
+      produceContentAsync(p, interest.getName(), suffix);
     }
 
-    ret = producer_socket_->setSocketOption(
-        ProducerCallbacksOptions::CONTENT_PRODUCED,
-        (ProducerContentCallback)bind(
-            &Impl::onContentProduced, this, std::placeholders::_1,
-            std::placeholders::_2, std::placeholders::_3));
+    /**
+     * @brief Register cache miss events
+     */
+    void cacheMiss([[maybe_unused]] const ProducerSocket &p,
+                   const Interest &interest) {
+      unsatisfied_interests_.push_back(interest.getName().getSuffix());
+    }
 
-    return ERROR_SUCCESS;
+    /**
+     * @brief When content is produced, set cache miss callback so that we can
+     * register any cache miss happening after the production.
+     */
+    void onContentProduced(ProducerSocket &p,
+                           [[maybe_unused]] const std::error_code &err,
+                           [[maybe_unused]] uint64_t bytes_written) {
+      p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS,
+                        (ProducerInterestCallback)bind(
+                            &ProducerContext::asyncProcessInterest, this,
+                            std::placeholders::_1, std::placeholders::_2));
+    }
+
+    /**
+     * @brief Internal producer error. When this callback is triggered
+     * something important happened. Here we stop the program.
+     */
+    void produceError(const std::error_code &err) noexcept override {
+      getOutputStream() << "Error from producer transport: " << err.message()
+                        << std::endl;
+      parent_.stop();
+    }
+
+    // Members initialized in constructor
+    std::vector<ContentObject::Ptr> content_objects_;
+
+    // Members initialized by in-class initializer
+    std::vector<uint32_t> unsatisfied_interests_;
+    std::uint32_t last_segment_{0};
+    std::unique_ptr<ProducerSocket> producer_socket_{nullptr};
+    std::uint16_t content_objects_index_{0};
+    std::size_t payload_size_max_{0};
+  };
+
+ public:
+  explicit Impl(const hiperf::ServerConfiguration &conf) : config_(conf) {
+#ifndef _WIN32
+    if (config_.interactive_) {
+      input_.assign(::dup(STDIN_FILENO));
+    }
+#endif
+
+    std::memset(rtc_payload_.data(), 'X', rtc_payload_.size());
+  }
+
+  ~Impl() = default;
+
+  int setup() {
+    int ret = ensureFlows(config_.name_, config_.parallel_flows_);
+    if (ret != ERROR_SUCCESS) {
+      return ret;
+    }
+
+    producer_contexts_.reserve(config_.parallel_flows_);
+    for (uint32_t i = 0; i < config_.parallel_flows_; i++) {
+      auto &ctx = producer_contexts_.emplace_back(*this, i);
+      ret = ctx.setup();
+
+      if (ret) {
+        break;
+      }
+    }
+
+    return ret;
   }
 
   void receiveStream() {
     socket_.async_receive_from(
-        asio::buffer(recv_buffer_.first, recv_buffer_.second), remote_,
-        [this](const std::error_code &ec, std::size_t length) {
+        asio::buffer(recv_buffer_.writableData(), recv_buffer_.capacity()),
+        remote_, [this](const std::error_code &ec, std::size_t length) {
           if (ec) return;
-          sendRTCContentFromStream(recv_buffer_.first, length);
+          sendRTCContentFromStream(recv_buffer_.writableData(), length);
           receiveStream();
         });
   }
 
-  void sendRTCContentFromStream(uint8_t *buff, std::size_t len) {
-    auto payload =
-        content_objects_[content_objects_index_++ & mask_]->getPayload();
+  void sendRTCContentFromStream(const uint8_t *buff, std::size_t len) {
     // this is used to compute the data packet delay
     // Used only for performance evaluation
     // It requires clock synchronization between producer and consumer
-    uint64_t now = utils::SystemTime::nowMs().count();
+    auto now = utils::SystemTime::nowMs().count();
 
-    uint8_t *start = (uint8_t *)payload->writableData();
+    auto start = rtc_payload_.data();
     std::memcpy(start, &now, sizeof(uint64_t));
     std::memcpy(start + sizeof(uint64_t), buff, len);
-    producer_socket_->produceDatagram(flow_name_, start,
-                                      len + sizeof(uint64_t));
+
+    for (const auto &producer_context : producer_contexts_) {
+      producer_context.produceDatagram(start, len + sizeof(uint64_t));
+    }
   }
 
   void sendRTCContentObjectCallback(const std::error_code &ec) {
     if (ec) return;
     rtc_timer_.expires_from_now(
-        configuration_.production_rate_.getMicrosecondsForPacket(
-            configuration_.payload_size_));
+        config_.production_rate_.getMicrosecondsForPacket(
+            config_.payload_size_));
     rtc_timer_.async_wait(std::bind(&Impl::sendRTCContentObjectCallback, this,
                                     std::placeholders::_1));
-    auto payload =
-        content_objects_[content_objects_index_++ & mask_]->getPayload();
+
+    auto start = rtc_payload_.data();
 
     // this is used to compute the data packet delay
     // Used only for performance evaluation
     // It requires clock synchronization between producer and consumer
-    uint64_t now = utils::SystemTime::nowMs().count();
-
-    std::memcpy(payload->writableData(), &now, sizeof(uint64_t));
+    auto now = utils::SystemTime::nowMs().count();
+    std::memcpy(start, &now, sizeof(uint64_t));
 
-    producer_socket_->produceDatagram(flow_name_, payload->data(),
-                                      payload->length() < payload_size_max_
-                                          ? payload->length()
-                                          : payload_size_max_);
+    for (const auto &producer_context : producer_contexts_) {
+      producer_context.produceDatagram(start, config_.payload_size_);
+    }
   }
 
   void sendRTCContentObjectCallbackWithTrace(const std::error_code &ec) {
     if (ec) return;
 
-    auto payload =
-        content_objects_[content_objects_index_++ & mask_]->getPayload();
-
-    uint32_t packet_len =
-        configuration_.trace_[configuration_.trace_index_].size;
+    std::size_t packet_len = config_.trace_[config_.trace_index_].size;
 
     // this is used to compute the data packet delay
     // used only for performance evaluation
     // it requires clock synchronization between producer and consumer
-    uint64_t now = utils::SystemTime::nowMs().count();
-    std::memcpy(payload->writableData(), &now, sizeof(uint64_t));
+    auto now = utils::SystemTime::nowMs().count();
+    auto start = rtc_payload_.data();
+    std::memcpy(start, &now, sizeof(uint64_t));
 
-    if (packet_len > payload->length()) packet_len = payload->length();
-    if (packet_len > payload_size_max_) packet_len = payload_size_max_;
+    if (packet_len > config_.payload_size_) {
+      packet_len = config_.payload_size_;
+    }
 
-    producer_socket_->produceDatagram(flow_name_, payload->data(), packet_len);
+    for (const auto &producer_context : producer_contexts_) {
+      producer_context.produceDatagram(start, packet_len);
+    }
 
-    uint32_t next_index = configuration_.trace_index_ + 1;
+    uint32_t next_index = config_.trace_index_ + 1;
     uint64_t schedule_next;
-    if (next_index < configuration_.trace_.size()) {
-      schedule_next =
-          configuration_.trace_[next_index].timestamp -
-          configuration_.trace_[configuration_.trace_index_].timestamp;
+    if (next_index < config_.trace_.size()) {
+      schedule_next = config_.trace_[next_index].timestamp -
+                      config_.trace_[config_.trace_index_].timestamp;
     } else {
       // here we need to loop, schedule in a random time
       schedule_next = 1000;
     }
 
-    configuration_.trace_index_ =
-        (configuration_.trace_index_ + 1) % configuration_.trace_.size();
+    config_.trace_index_ = (config_.trace_index_ + 1) % config_.trace_.size();
     rtc_timer_.expires_from_now(std::chrono::microseconds(schedule_next));
     rtc_timer_.async_wait(
         std::bind(&Impl::sendRTCContentObjectCallbackWithTrace, this,
                   std::placeholders::_1));
   }
 
+  int parseTraceFile() {
+    std::ifstream trace(config_.trace_file_);
+    if (trace.fail()) {
+      return -1;
+    }
+    std::string line;
+    while (std::getline(trace, line)) {
+      std::istringstream iss(line);
+      hiperf::packet_t packet;
+      iss >> packet.timestamp >> packet.size;
+      config_.trace_.push_back(packet);
+    }
+    return 0;
+  }
+
 #ifndef _WIN32
   void handleInput(const std::error_code &error, std::size_t length) {
     if (error) {
-      producer_socket_->stop();
-      io_service_.stop();
+      stop();
     }
 
     if (rtc_running_) {
-      std::cout << "stop real time content production" << std::endl;
+      Logger() << "stop real time content production" << std::endl;
       rtc_running_ = false;
       rtc_timer_.cancel();
     } else {
-      std::cout << "start real time content production" << std::endl;
+      Logger() << "start real time content production" << std::endl;
       rtc_running_ = true;
       rtc_timer_.expires_from_now(
-          configuration_.production_rate_.getMicrosecondsForPacket(
-              configuration_.payload_size_));
+          config_.production_rate_.getMicrosecondsForPacket(
+              config_.payload_size_));
       rtc_timer_.async_wait(std::bind(&Impl::sendRTCContentObjectCallback, this,
                                       std::placeholders::_1));
     }
@@ -439,46 +573,33 @@ class HIperfServer::Impl : public ProducerSocket::Callback {
   }
 #endif
 
-  int parseTraceFile() {
-    std::ifstream trace(configuration_.trace_file_);
-    if (trace.fail()) {
-      return -1;
-    }
-    std::string line;
-    while (std::getline(trace, line)) {
-      std::istringstream iss(line);
-      hiperf::packet_t packet;
-      iss >> packet.timestamp >> packet.size;
-      configuration_.trace_.push_back(packet);
+  void stop() {
+    for (auto &producer_context : producer_contexts_) {
+      producer_context.stop();
     }
-    return 0;
+
+    io_service_.stop();
   }
 
   int run() {
-    std::cerr << "Starting to serve consumers" << std::endl;
-
     signals_.add(SIGINT);
-    signals_.async_wait([this](const std::error_code &, const int &) {
-      std::cout << "STOPPING!!" << std::endl;
-      producer_socket_->stop();
-      io_service_.stop();
-    });
+    signals_.async_wait(
+        [this](const std::error_code &, const int &) { stop(); });
 
-    if (configuration_.rtc_) {
-#ifndef _WIN32
-      if (configuration_.interactive_) {
+    if (config_.rtc_) {
+      if (config_.interactive_) {
         asio::async_read_until(
             input_, input_buffer_, '\n',
             std::bind(&Impl::handleInput, this, std::placeholders::_1,
                       std::placeholders::_2));
-      } else if (configuration_.trace_based_) {
-        std::cout << "trace-based mode enabled" << std::endl;
-        if (configuration_.trace_file_ == nullptr) {
-          std::cout << "cannot find the trace file" << std::endl;
+      } else if (config_.trace_based_) {
+        Logger() << "trace-based mode enabled" << std::endl;
+        if (config_.trace_file_ == nullptr) {
+          Logger() << "cannot find the trace file" << std::endl;
           return ERROR_SETUP;
         }
         if (parseTraceFile() < 0) {
-          std::cout << "cannot parse the trace file" << std::endl;
+          Logger() << "cannot parse the trace file" << std::endl;
           return ERROR_SETUP;
         }
         rtc_running_ = true;
@@ -486,31 +607,26 @@ class HIperfServer::Impl : public ProducerSocket::Callback {
         rtc_timer_.async_wait(
             std::bind(&Impl::sendRTCContentObjectCallbackWithTrace, this,
                       std::placeholders::_1));
-      } else if (configuration_.input_stream_mode_) {
+      } else if (config_.input_stream_mode_) {
         rtc_running_ = true;
         // create socket
         remote_ = asio::ip::udp::endpoint(
-            asio::ip::address::from_string("127.0.0.1"), configuration_.port_);
+            asio::ip::address::from_string("127.0.0.1"), config_.port_);
         socket_.open(asio::ip::udp::v4());
         socket_.bind(remote_);
-        recv_buffer_.first = (uint8_t *)malloc(HIPERF_MTU);
-        recv_buffer_.second = HIPERF_MTU;
         receiveStream();
       } else {
         rtc_running_ = true;
         rtc_timer_.expires_from_now(
-            configuration_.production_rate_.getMicrosecondsForPacket(
-                configuration_.payload_size_));
+            config_.production_rate_.getMicrosecondsForPacket(
+                config_.payload_size_));
         rtc_timer_.async_wait(std::bind(&Impl::sendRTCContentObjectCallback,
                                         this, std::placeholders::_1));
       }
-#else
-      rtc_timer_.expires_from_now(
-          configuration_.production_rate_.getMicrosecondsForPacket(
-              configuration_.payload_size_));
-      rtc_timer_.async_wait(std::bind(&Impl::sendRTCContentObjectCallback, this,
-                                      std::placeholders::_1));
-#endif
+    }
+
+    for (auto &producer_context : producer_contexts_) {
+      producer_context.run();
     }
 
     io_service_.run();
@@ -518,49 +634,31 @@ class HIperfServer::Impl : public ProducerSocket::Callback {
     return ERROR_SUCCESS;
   }
 
+  ServerConfiguration &getConfig() { return config_; }
+
  private:
-  hiperf::ServerConfiguration configuration_;
+  // Variables initialized by the constructor.
+  ServerConfiguration config_;
+
+  // Variable initialized in the in-class initializer list.
   asio::io_service io_service_;
-  asio::signal_set signals_;
-  asio::steady_timer rtc_timer_;
-  std::vector<uint32_t> unsatisfied_interests_;
-  std::vector<std::shared_ptr<ContentObject>> content_objects_;
-  std::uint16_t content_objects_index_;
-  std::uint16_t mask_;
-  std::uint32_t last_segment_;
-  std::unique_ptr<ProducerSocket> producer_socket_;
+  asio::signal_set signals_{io_service_};
+  asio::steady_timer rtc_timer_{io_service_};
+  asio::posix::stream_descriptor input_{io_service_};
+  asio::ip::udp::socket socket_{io_service_};
+  std::vector<ProducerContext> producer_contexts_;
   ::utils::EventThread produce_thread_;
-  std::size_t payload_size_max_;
-#ifndef _WIN32
-  asio::posix::stream_descriptor input_;
   asio::streambuf input_buffer_;
-  bool rtc_running_;
-  Name flow_name_;
-  asio::ip::udp::socket socket_;
+  bool rtc_running_{false};
   asio::ip::udp::endpoint remote_;
-  std::pair<uint8_t *, std::size_t> recv_buffer_;
-#endif
+  utils::MemBuf recv_buffer_{utils::MemBuf::CREATE, HIPERF_MTU};
+  std::array<uint8_t, HIPERF_MTU> rtc_payload_;
 };
 
-HIperfServer::HIperfServer(const ServerConfiguration &conf) {
-  impl_ = new Impl(conf);
-}
-
-HIperfServer::HIperfServer(HIperfServer &&other) {
-  impl_ = other.impl_;
-  other.impl_ = nullptr;
-}
-
-HIperfServer &HIperfServer::operator=(HIperfServer &&other) {
-  if (this != &other) {
-    impl_ = other.impl_;
-    other.impl_ = nullptr;
-  }
-
-  return *this;
-}
+HIperfServer::HIperfServer(const ServerConfiguration &conf)
+    : impl_(std::make_unique<Impl>(conf)) {}
 
-HIperfServer::~HIperfServer() { delete impl_; }
+HIperfServer::~HIperfServer() = default;
 
 int HIperfServer::setup() { return impl_->setup(); }
 
index 73ac721..d7420da 100644 (file)
@@ -21,9 +21,7 @@ namespace hiperf {
 
 class HIperfServer {
  public:
-  HIperfServer(const ServerConfiguration &conf);
-  HIperfServer(HIperfServer &&other);
-  HIperfServer &operator=(HIperfServer &&other);
+  explicit HIperfServer(const ServerConfiguration &conf);
 
   ~HIperfServer();
   int setup();
@@ -31,7 +29,7 @@ class HIperfServer {
 
  private:
   class Impl;
-  Impl *impl_;
+  std::unique_ptr<Impl> impl_;
 };
 
 }  // namespace hiperf
\ No newline at end of file
index 1741aed..0741099 100644 (file)
@@ -23,8 +23,16 @@ extern "C" {
 #ifndef ASIO_STANDALONE
 #define ASIO_STANDALONE 1
 #endif
+
+#ifdef __APPLE__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#endif
 #include <asio.hpp>
 #include <asio/steady_timer.hpp>
+#ifdef __APPLE__
+#pragma clang diagnostic pop
+#endif
 #include <functional>
 #include <thread>
 #include <unordered_map>
index ee9380a..43d10e1 100644 (file)
 
 #include <hicn/transport/core/packet.h>
 
+#ifdef __APPLE__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#endif
 #include <asio.hpp>
+#ifdef __APPLE__
+#pragma clang diagnostic pop
+#endif
 #include <deque>
 #include <functional>
 
index 954861e..f158519 100644 (file)
@@ -37,8 +37,8 @@ AsyncConsumerProducer::AsyncConsumerProducer(
       producer_socket_(),
       ip_address_(origin_address),
       port_(origin_port),
-      cache_size_(std::stoul(cache_size)),
-      mtu_(std::stoul(mtu)),
+      cache_size_((uint32_t)std::stoul(cache_size)),
+      mtu_((uint32_t)std::stoul(mtu)),
       request_counter_(0),
       connector_(io_service_, ip_address_, port_,
                  std::bind(&AsyncConsumerProducer::publishContent, this,
@@ -59,7 +59,7 @@ AsyncConsumerProducer::AsyncConsumerProducer(
   }
 
   ret = producer_socket_.setSocketOption(
-      interface::GeneralTransportOptions::MAKE_MANIFEST, manifest);
+      interface::GeneralTransportOptions::MANIFEST_MAX_CAPACITY, manifest);
 
   if (ret != SOCKET_OPTION_SET) {
     TRANSPORT_LOG_WARNING << "Warning: impossible to enable signatures.";
index 0217f2f..2371e44 100644 (file)
@@ -13,6 +13,7 @@
  * limitations under the License.
  */
 
+#include <hicn/transport/auth/signer.h>
 #include <hicn/transport/auth/verifier.h>
 #include <hicn/transport/core/global_object_pool.h>
 #include <hicn/transport/core/interest.h>
@@ -39,12 +40,14 @@ typedef auth::AsymmetricVerifier Verifier;
 
 class Configuration {
  public:
+  uint64_t num_int_manifest_suffixes_;
   uint64_t interestLifetime_;
   uint64_t pingInterval_;
   uint64_t maxPing_;
   uint64_t first_suffix_;
   std::string name_;
   std::string certificate_;
+  std::string passphrase_;
   uint16_t srcPort_;
   uint16_t dstPort_;
   bool verbose_;
@@ -59,9 +62,10 @@ class Configuration {
   uint8_t ttl_;
 
   Configuration() {
-    interestLifetime_ = 500;  // ms
-    pingInterval_ = 1000000;  // us
-    maxPing_ = 10;            // number of interests
+    num_int_manifest_suffixes_ = 0;  // Number of suffixes in interest manifest
+    interestLifetime_ = 500;         // ms
+    pingInterval_ = 1000000;         // us
+    maxPing_ = 10;                   // number of interests
     first_suffix_ = 0;
     name_ = "b001::1";  // string
     srcPort_ = 9695;
@@ -96,6 +100,13 @@ class Client : interface::Portal::TransportCallback {
     if (!c->certificate_.empty()) {
       verifier_.useCertificate(c->certificate_);
     }
+
+    // If interst manifest, sign it
+    if (c->num_int_manifest_suffixes_ != 0) {
+      assert(!c->passphrase_.empty());
+      signer_ = std::make_unique<auth::SymmetricSigner>(
+          auth::CryptoSuite::HMAC_SHA256, c->passphrase_);
+    }
   }
 
   virtual ~Client() {}
@@ -142,6 +153,7 @@ class Client : interface::Portal::TransportCallback {
     if (config_->verbose_) {
       std::cout << "<<< recevied object. " << std::endl;
       std::cout << "<<< interest name: " << interest.getName()
+                << " (n_suffixes=" << interest.numberOfSuffixes() << ")"
                 << " src port: " << interest.getSrcPort()
                 << " dst port: " << interest.getDstPort()
                 << " flags: " << interest.printFlags() << std::endl;
@@ -221,15 +233,18 @@ class Client : interface::Portal::TransportCallback {
     const Name interest_name(config_->name_, (uint32_t)sequence_number_);
     hicn_format_t format;
     if (interest_name.getAddressFamily() == AF_INET) {
-      format = HF_INET_TCP;
+      format = signer_ ? HF_INET_TCP_AH : HF_INET_TCP;
     } else {
-      format = HF_INET6_TCP;
+      format = signer_ ? HF_INET6_TCP_AH : HF_INET6_TCP;
     }
 
-    auto interest = std::make_shared<Interest>(interest_name, format);
+    size_t additional_header_size = 0;
+    if (signer_) additional_header_size = signer_->getSignatureFieldSize();
+    auto interest = std::make_shared<Interest>(interest_name, format,
+                                               additional_header_size);
 
     interest->setLifetime(uint32_t(config_->interestLifetime_));
-    interest->resetFlags();
+    if (!signer_) interest->resetFlags();
 
     if (config_->open_ || config_->always_syn_) {
       if (state_ == SYN_STATE) {
@@ -244,13 +259,21 @@ class Client : interface::Portal::TransportCallback {
     interest->setSrcPort(config_->srcPort_);
     interest->setDstPort(config_->dstPort_);
     interest->setTTL(config_->ttl_);
+    uint64_t seq_offset = 1;
+    while (seq_offset <= config_->num_int_manifest_suffixes_ &&
+           sequence_number_ + seq_offset < config_->maxPing_) {
+      interest->appendSuffix(sequence_number_ + seq_offset);
+      seq_offset++;
+    }
 
     if (config_->verbose_) {
       std::cout << ">>> send interest " << interest->getName()
                 << " src port: " << interest->getSrcPort()
                 << " dst port: " << interest->getDstPort()
                 << " flags: " << interest->printFlags()
-                << " TTL: " << (int)interest->getTTL() << std::endl;
+                << " TTL: " << (int)interest->getTTL()
+                << " suffixes in manifest: "
+                << config_->num_int_manifest_suffixes_ << std::endl;
     } else if (!config_->quiet_) {
       std::cout << ">>> send interest " << interest->getName() << std::endl;
     }
@@ -264,11 +287,16 @@ class Client : interface::Portal::TransportCallback {
     if (!config_->quiet_) std::cout << std::endl;
 
     send_timestamps_[sequence_number_] = utils::SteadyTime::now();
+    for (uint64_t i = 1; i < seq_offset; i++)
+      send_timestamps_[sequence_number_ + i] = utils::SteadyTime::now();
 
-    portal_.sendInterest(std::move(interest));
+    interest->encodeSuffixes();
+    if (signer_) signer_->signPacket(interest.get());
 
-    sequence_number_++;
-    sent_++;
+    portal_.sendInterest(interest, interest->getLifetime());
+
+    sequence_number_ += seq_offset;
+    sent_ += seq_offset;
 
     if (sent_ < config_->maxPing_) {
       this->timer_->expires_from_now(
@@ -314,6 +342,7 @@ class Client : interface::Portal::TransportCallback {
   std::unique_ptr<asio::steady_timer> timer_;
   Configuration *config_;
   Verifier verifier_;
+  std::unique_ptr<auth::Signer> signer_;
 };
 
 void help() {
@@ -327,6 +356,12 @@ void help() {
   std::cout << "-s <val>          sorce port (default 9695)" << std::endl;
   std::cout << "-d <val>          destination port (default 8080)" << std::endl;
   std::cout << "-t <val>          set packet ttl (default 64)" << std::endl;
+  std::cout << "-a <val> <pass>   set the passphrase and the number of "
+               "suffixes in interest manifest (default 0);"
+            << std::endl;
+  std::cout << "                  e.g. '-m 6 -a -2' sends two interest (0 and "
+               "3) with 2 suffixes each (1,2 and 4,5 respectively)"
+            << std::endl;
   std::cout << "-O                open tcp connection (three way handshake) "
                "(default false)"
             << std::endl;
@@ -362,6 +397,8 @@ int main(int argc, char *argv[]) {
   WSAStartup(MAKEWORD(2, 2), &wsaData);
 #endif
 
+  transport::interface::global_config::GlobalConfigInterface global_conf;
+
   Configuration *c = new Configuration();
   int opt;
   std::string producer_certificate = "";
@@ -370,8 +407,13 @@ int main(int argc, char *argv[]) {
   transport::interface::global_config::IoModuleConfiguration io_config;
   io_config.name = "hicnlightng_module";
 
-  while ((opt = getopt(argc, argv, "j::t:i:m:s:d:n:l:f:c:SAOqVDHz:F:")) != -1) {
+  while ((opt = getopt(argc, argv, "a:j::t:i:m:s:d:n:l:f:c:SAOqVDHz:F:")) !=
+         -1) {
     switch (opt) {
+      case 'a':
+        c->num_int_manifest_suffixes_ = std::stoi(optarg);
+        c->passphrase_ = argv[optind];
+        break;
       case 't':
         c->ttl_ = (uint8_t)std::stoi(optarg);
         break;
@@ -447,7 +489,7 @@ int main(int argc, char *argv[]) {
   /**
    * Parse config file
    */
-  transport::interface::global_config::parseConfigurationFile(conf_file);
+  global_conf.parseConfigurationFile(conf_file);
 
   auto ping = std::make_unique<Client>(c);
 
@@ -456,7 +498,8 @@ int main(int argc, char *argv[]) {
   auto t1 = std::chrono::steady_clock::now();
 
   std::cout << "Elapsed time: "
-            << utils::SteadyTime::getDurationUs(t0, t1).count() << std::endl;
+            << utils::SteadyTime::getDurationMs(t0, t1).count() << "ms"
+            << std::endl;
 
 #ifdef _WIN32
   WSACleanup();
index 3ffbc73..dd7d23b 100644 (file)
@@ -22,6 +22,7 @@
 #endif
 
 #include <hicn/transport/auth/signer.h>
+#include <hicn/transport/auth/verifier.h>
 #include <hicn/transport/core/content_object.h>
 #include <hicn/transport/core/interest.h>
 #include <hicn/transport/interfaces/global_conf_interface.h>
@@ -42,7 +43,8 @@ class CallbackContainer {
  public:
   CallbackContainer(const Name &prefix, uint32_t object_size, bool verbose,
                     bool dump, bool quite, bool flags, bool reset, uint8_t ttl,
-                    auth::Signer *signer, bool sign, uint32_t lifetime)
+                    auth::Signer *signer, bool sign, std::string passphrase,
+                    uint32_t lifetime)
       : buffer_(object_size, 'X'),
         content_objects_((std::uint32_t)(1 << log2_content_object_buffer_size)),
         mask_((std::uint16_t)(1 << log2_content_object_buffer_size) - 1),
@@ -55,8 +57,11 @@ class CallbackContainer {
         ttl_(ttl),
         signer_(signer),
         sign_(sign) {
-    core::Packet::Format format;
+    // Verifier for interest manifests
+    if (!passphrase.empty())
+      verifier_ = std::make_unique<auth::SymmetricVerifier>(passphrase);
 
+    core::Packet::Format format;
     if (prefix.getAddressFamily() == AF_INET) {
       format = core::Packet::Format::HF_INET_TCP;
       if (sign_) {
@@ -76,14 +81,28 @@ class CallbackContainer {
     }
   }
 
-  void processInterest(ProducerSocket &p, const Interest &interest,
+  void processInterest(ProducerSocket &p, Interest &interest,
                        uint32_t lifetime) {
+    if (verifier_ && interest.hasManifest()) {
+      auto t0 = utils::SteadyTime::now();
+      if (verifier_->verifyPacket(&interest)) {
+        auto t1 = utils::SteadyTime::now();
+        auto dt = utils::SteadyTime::getDurationUs(t0, t1);
+        std::cout << "Verification time: " << dt.count() << std::endl;
+        std::cout << "<<< Signature Ok." << std::endl;
+      } else {
+        std::cout << "<<< Signature verification failed!" << std::endl;
+      }
+    }
+
     if (verbose_) {
       std::cout << "<<< received interest " << interest.getName()
                 << " src port: " << interest.getSrcPort()
                 << " dst port: " << interest.getDstPort()
                 << " flags: " << interest.printFlags()
-                << "TTL: " << (int)interest.getTTL() << std::endl;
+                << "TTL: " << (int)interest.getTTL()
+                << " suffixes in manifest: " << interest.numberOfSuffixes()
+                << std::endl;
     } else if (!quite_) {
       std::cout << "<<< received interest " << interest.getName() << std::endl;
     }
@@ -97,54 +116,74 @@ class CallbackContainer {
     if (interest.testRst()) {
       std::cout << "!!!got a reset, I don't reply" << std::endl;
     } else {
-      auto &content_object = content_objects_[content_objects_index_++ & mask_];
-
-      content_object->setName(interest.getName());
-      content_object->setLifetime(lifetime);
-      content_object->setLocator(interest.getLocator());
-      content_object->setSrcPort(interest.getDstPort());
-      content_object->setDstPort(interest.getSrcPort());
-      content_object->setTTL(ttl_);
-
-      if (!sign_) {
-        content_object->resetFlags();
-      }
-
-      if (flags_) {
-        if (interest.testSyn()) {
-          content_object->setSyn();
-          content_object->setAck();
-        } else if (interest.testAck()) {
-          content_object->setAck();
-        }  // here I may need to handle the FIN flag;
-      } else if (reset_) {
-        content_object->setRst();
-      }
-
-      if (verbose_) {
-        std::cout << ">>> send object " << content_object->getName()
-                  << " src port: " << content_object->getSrcPort()
-                  << " dst port: " << content_object->getDstPort()
-                  << " flags: " << content_object->printFlags()
-                  << " TTL: " << (int)content_object->getTTL() << std::endl;
-      } else if (!quite_) {
-        std::cout << ">>> send object " << content_object->getName()
-                  << std::endl;
-      }
-
-      if (dump_) {
-        std::cout << "----- object dump -----" << std::endl;
-        content_object->dump();
-        std::cout << "-----------------------" << std::endl;
-      }
+      uint32_t *suffix = interest.firstSuffix();
+      uint32_t n_suffixes_in_manifest = interest.numberOfSuffixes();
+      uint32_t *request_bitmap = interest.getRequestBitmap();
+      if (!interest.isValid()) throw std::runtime_error("Bad interest format");
+
+      Name name = interest.getName();
+      uint32_t pos = 0;  // Position of current suffix in manifest
+      do {
+        // If suffix can be processed, i.e. no manifest with bitmap excluding it
+        if (!interest.hasManifest() || is_bit_set(request_bitmap, pos)) {
+          auto &content_object =
+              content_objects_[content_objects_index_++ & mask_];
+
+          content_object->setName(interest.getName());
+          content_object->setLifetime(lifetime);
+          content_object->setLocator(interest.getLocator());
+          content_object->setSrcPort(interest.getDstPort());
+          content_object->setDstPort(interest.getSrcPort());
+          content_object->setTTL(ttl_);
+
+          if (!sign_) {
+            content_object->resetFlags();
+          }
+
+          if (flags_) {
+            if (interest.testSyn()) {
+              content_object->setSyn();
+              content_object->setAck();
+            } else if (interest.testAck()) {
+              content_object->setAck();
+            }  // here I may need to handle the FIN flag;
+          } else if (reset_) {
+            content_object->setRst();
+          }
+
+          if (verbose_) {
+            std::cout << ">>> send object " << content_object->getName()
+                      << " src port: " << content_object->getSrcPort()
+                      << " dst port: " << content_object->getDstPort()
+                      << " flags: " << content_object->printFlags()
+                      << " TTL: " << (int)content_object->getTTL() << std::endl;
+          } else if (!quite_) {
+            std::cout << ">>> send object " << content_object->getName()
+                      << std::endl;
+          }
+
+          if (dump_) {
+            std::cout << "----- object dump -----" << std::endl;
+            content_object->dump();
+            std::cout << "-----------------------" << std::endl;
+          }
+
+          if (sign_ && signer_) {
+            signer_->signPacket(content_object.get());
+          }
+
+          p.produce(*content_object);
+        }
+
+        if (interest.hasManifest()) {
+          uint32_t seq = *suffix;
+          suffix++;
+
+          interest.setName(name.setSuffix(seq));
+        }
+      } while (pos++ < n_suffixes_in_manifest);
 
       if (!quite_) std::cout << std::endl;
-
-      if (sign_ && signer_) {
-        signer_->signPacket(content_object.get());
-      }
-
-      p.produce(*content_object);
     }
   }
 
@@ -161,6 +200,7 @@ class CallbackContainer {
   uint8_t ttl_;
   auth::Signer *signer_;
   bool sign_;
+  std::unique_ptr<auth::Verifier> verifier_;
 };
 
 void help() {
@@ -199,6 +239,7 @@ void help() {
 }
 
 int main(int argc, char **argv) {
+  transport::interface::global_config::GlobalConfigInterface global_conf;
 #ifdef _WIN32
   WSADATA wsaData = {0};
   WSAStartup(MAKEWORD(2, 2), &wsaData);
@@ -216,6 +257,7 @@ int main(int argc, char **argv) {
   uint8_t ttl = 64;
   std::string keystore_path = "./rsa_crypto_material.p12";
   std::string keystore_password = "cisco";
+  std::string passphrase = "";
   bool sign = false;
   uint32_t data_lifetime = default_values::content_object_expiry_time;
 
@@ -225,11 +267,14 @@ int main(int argc, char **argv) {
 
   int opt;
 #ifndef _WIN32
-  while ((opt = getopt(argc, argv, "s:n:t:l:qfrVDdHk:p:z:F:")) != -1) {
+  while ((opt = getopt(argc, argv, "a:s:n:t:l:qfrVDdHk:p:z:F:")) != -1) {
 #else
   while ((opt = getopt(argc, argv, "s:n:t:l:qfrVDHk:p:z:F:")) != -1) {
 #endif
     switch (opt) {
+      case 'a':
+        passphrase = optarg;
+        break;
       case 's':
         object_size = std::stoi(optarg);
         break;
@@ -298,7 +343,7 @@ int main(int argc, char **argv) {
   /**
    * Parse config file
    */
-  transport::interface::global_config::parseConfigurationFile(conf_file);
+  global_conf.parseConfigurationFile(conf_file);
 
   core::Prefix producer_namespace(name_prefix);
 
@@ -309,24 +354,25 @@ int main(int argc, char **argv) {
   if (object_size > 1350) object_size = 1350;
 
   CallbackContainer *stubs;
-  std::unique_ptr<auth::AsymmetricSigner> signer;
+  std::unique_ptr<auth::Signer> signer;
 
   if (sign) {
     signer = std::make_unique<auth::AsymmetricSigner>(keystore_path,
                                                       keystore_password);
-    stubs =
-        new CallbackContainer(n, object_size, verbose, dump, quite, flags,
-                              reset, ttl, signer.get(), sign, data_lifetime);
+    stubs = new CallbackContainer(n, object_size, verbose, dump, quite, flags,
+                                  reset, ttl, signer.get(), sign, passphrase,
+                                  data_lifetime);
   } else {
     auth::Signer *signer = nullptr;
     stubs = new CallbackContainer(n, object_size, verbose, dump, quite, flags,
-                                  reset, ttl, signer, sign, data_lifetime);
+                                  reset, ttl, signer, sign, passphrase,
+                                  data_lifetime);
   }
 
   ProducerSocket p;
   p.registerPrefix(producer_namespace);
 
-  p.setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, false);
+  p.setSocketOption(GeneralTransportOptions::MANIFEST_MAX_CAPACITY, 0U);
   p.setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 0U);
   p.setSocketOption(
       ProducerCallbacksOptions::CACHE_MISS,
index d6fe72d..2211218 100644 (file)
@@ -21,6 +21,6 @@ project(ctrl)
 # Subdirectories
 ##############################################################
 add_subdirectory(libhicnctrl)
-if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "Android")
+if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "Android" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "iOS")
   add_subdirectory(facemgr)
 endif ()
\ No newline at end of file
index fee38da..bbbe818 100644 (file)
@@ -163,8 +163,6 @@ int facemgr_cfg_rule_get_overlay_remote_port(const facemgr_cfg_rule_t* rule,
                                              int family, uint16_t* port);
 
 int facemgr_cfg_add_static_facelet(facemgr_cfg_t* cfg, facelet_t* facelet);
-int facemgr_cfg_remove_static_facelet(facemgr_cfg_t* cfg, facelet_t* facelet,
-                                      facelet_t** removed_facelet);
 int facemgr_cfg_get_static_facelet_array(const facemgr_cfg_t* cfg,
                                          facelet_t*** array);
 
index 9c37438..76e1f5e 100644 (file)
@@ -1120,11 +1120,6 @@ int facemgr_cfg_add_static_facelet(facemgr_cfg_t *cfg, facelet_t *facelet) {
   return facelet_array_add(cfg->static_facelets, facelet);
 }
 
-int facemgr_cfg_remove_static_facelet(facemgr_cfg_t *cfg, facelet_t *facelet,
-                                      facelet_t **removed_facelet) {
-  return facelet_array_remove(cfg->static_facelets, facelet, removed_facelet);
-}
-
 int facemgr_cfg_get_static_facelet_array(const facemgr_cfg_t *cfg,
                                          facelet_t ***array) {
   if (facelet_array_get_elements(cfg->static_facelets, array) < 0) {
index 3adba09..e1f5575 100644 (file)
@@ -171,6 +171,7 @@ void dump_endpoint(nw_endpoint_t endpoint, int indent) {
         free(s);
     }
   }
+}
 
   void dump_path(nw_path_t path, int indent) {
     /* nw_path_enumerate_interfaces : not interesting */
index ed4540f..88e1974 100644 (file)
@@ -28,7 +28,7 @@
 
 #include <stdlib.h>
 
-#include <Dispatch/Dispatch.h>
+#include <dispatch/dispatch.h>
 
 #include <hicn/facemgr/loop.h>
 #include <hicn/util/log.h>
index 8a59cf4..c259fc1 100644 (file)
@@ -72,6 +72,7 @@
 #include <hicn/util/ip_address.h>
 #include <hicn/face.h>
 #include <hicn/strategy.h>
+#include <hicn/base.h>
 /*
  * This has to be common between hicn-light and hicn-plugin. We now we keep the
  * minimum of the two
   _(SERVE)             \
   _(STORE)             \
   _(CLEAR)             \
+  _(GET)               \
   _(N)
 
 typedef enum {
@@ -150,6 +152,7 @@ hc_action_t action_from_str(const char *action_str);
   _(LOCAL_PREFIX)      \
   _(PROBE)             \
   _(SUBSCRIPTION)      \
+  _(STATS)             \
   _(N)
 
 typedef enum {
@@ -930,6 +933,13 @@ typedef struct {
   flag_interface_type_t interface_type;
 } hc_event_interface_update_t;
 
+/*----------------------------------------------------------------------------*
+ * Statistics
+ *----------------------------------------------------------------------------*/
+int hc_stats_get(hc_sock_t *s, hc_data_t **pdata);   // General stats
+int hc_stats_list(hc_sock_t *s, hc_data_t **pdata);  // Per-face stats
+int hc_stats_snprintf(char *s, size_t size, const hicn_light_stats_t *stats);
+
 /* Result */
 
 hc_msg_t *hc_result_get_msg(hc_sock_t *s, hc_result_t *result);
index 7d105a8..783eab0 100644 (file)
@@ -90,7 +90,9 @@ typedef enum {
   _(policy_remove, POLICY_REMOVE)                           \
   _(policy_list, POLICY_LIST)                               \
   _(subscription_add, SUBSCRIPTION_ADD)                     \
-  _(subscription_remove, SUBSCRIPTION_REMOVE)
+  _(subscription_remove, SUBSCRIPTION_REMOVE)               \
+  _(stats_get, STATS_GET)                                   \
+  _(stats_list, STATS_LIST)
 
 typedef enum {
   COMMAND_TYPE_UNDEFINED,
@@ -282,6 +284,33 @@ typedef struct {
   cmd_cache_list_reply_t payload;
 } msg_cache_list_reply_t;
 
+/* Statistics */
+
+// General stats
+typedef struct {
+  void *_;
+} cmd_stats_get_t;
+
+typedef struct {
+  cmd_header_t header;
+  hicn_light_stats_t payload;
+} msg_stats_get_reply_t;
+
+// Per-face stats
+typedef struct {
+  void *_;
+} cmd_stats_list_t;
+
+typedef struct {
+  uint32_t id;
+  connection_stats_t stats;
+} cmd_stats_list_item_t;
+
+typedef struct {
+  cmd_header_t header;
+  cmd_stats_list_item_t payload;
+} msg_stats_list_reply_t;
+
 /* WLDR */
 
 typedef struct {
@@ -388,10 +417,10 @@ typedef struct {
     cmd_header_t header; \
     cmd_##l##_t payload; \
   } msg_##l##_t;
-foreach_command_type
+foreach_command_type;
 #undef _
 
-    typedef struct {
+typedef struct {
   cmd_header_t header;
   cmd_listener_list_item_t payload;
 } msg_listener_list_reply_t;
index c8a93c5..1bec03d 100644 (file)
@@ -60,7 +60,8 @@ endif ()
 ##############################################################
 # Do not use modules if Android
 ##############################################################
-if (${CMAKE_SYSTEM_NAME} MATCHES Android)
+
+if (${CMAKE_SYSTEM_NAME} MATCHES Android OR ${CMAKE_SYSTEM_NAME} MATCHES iOS)
   list(APPEND SOURCE_FILES
     ${CMAKE_CURRENT_SOURCE_DIR}/modules/hicn_light_common.c
     ${CMAKE_CURRENT_SOURCE_DIR}/modules/hicn_light_ng_api.c
index 472e07b..d68dc83 100644 (file)
@@ -440,7 +440,7 @@ GENERATE_FIND(connection);
 /* CONNECTION VALIDATE */
 
 int hc_connection_validate(const hc_connection_t *connection) {
-  if (!IS_VALID_NAME(connection->name)) {
+  if (connection->name[0] != '\0' && !IS_VALID_NAME(connection->name)) {
     ERROR("[hc_connection_validate] Invalid name specified");
     return -1;
   }
@@ -1060,6 +1060,28 @@ int hc_cache_snprintf(char *s, size_t size, const hc_cache_info_t *cache_info) {
       (unsigned long)cache_info->num_stale_entries);
 }
 
+int hc_stats_snprintf(char *s, size_t size, const hicn_light_stats_t *stats) {
+  return snprintf(
+      s, size,
+      "pkts processed: %u\n\tinterests: %u\n\t"
+      "data: %u\npkts from cache count: %u\npkts no pit count: "
+      "%u\nexpired:\n\t interests: "
+      "%u\n\t data: %u\ninterests aggregated: "
+      "%u\nlru evictions: "
+      "%u\ndropped: "
+      "%u\ninterests retx: "
+      "%u\npit entries: %u\ncs entries: %u",
+      stats->forwarder.countReceived, stats->forwarder.countInterestsReceived,
+      stats->forwarder.countObjectsReceived,
+      stats->forwarder.countInterestsSatisfiedFromStore,
+      stats->forwarder.countDroppedNoReversePath,
+      stats->forwarder.countInterestsExpired, stats->forwarder.countDataExpired,
+      stats->pkt_cache.n_lru_evictions, stats->forwarder.countDropped,
+      stats->forwarder.countInterestsAggregated,
+      stats->forwarder.countInterestsRetransmitted,
+      stats->pkt_cache.n_pit_entries, stats->pkt_cache.n_cs_entries);
+}
+
 /*----------------------------------------------------------------------------*
  * Strategy
  *----------------------------------------------------------------------------*/
@@ -1160,6 +1182,17 @@ hc_result_t *hc_subscription_delete_conf(hc_sock_t *s,
   return s->hc_subscription_delete_conf(s, subscription);
 }
 
+/*----------------------------------------------------------------------------*
+ * STATISTICS
+ *----------------------------------------------------------------------------*/
+int hc_stats_get(hc_sock_t *s, hc_data_t **pdata) {
+  return s->hc_stats_get(s, pdata);
+}
+
+int hc_stats_list(hc_sock_t *s, hc_data_t **pdata) {
+  return s->hc_stats_list(s, pdata);
+}
+
 /*----------------------------------------------------------------------------*
  * Result
  *----------------------------------------------------------------------------*/
index 65b1758..c708e1e 100644 (file)
@@ -242,6 +242,9 @@ struct hc_sock_s {
   int (*hc_subscription_create)(hc_sock_t *s, hc_subscription_t *subscription);
   int (*hc_subscription_delete)(hc_sock_t *s, hc_subscription_t *subscription);
 
+  int (*hc_stats_get)(hc_sock_t *s, hc_data_t **data);
+  int (*hc_stats_list)(hc_sock_t *s, hc_data_t **data);
+
   hc_result_t *(*hc_listener_create_conf)(hc_sock_t *s,
                                           hc_listener_t *listener);
   hc_result_t *(*hc_listener_list_conf)(hc_sock_t *s, hc_data_t **pdata);
index bc04404..d1fb339 100644 (file)
@@ -15,9 +15,6 @@
 
 #include "hicn_light_common.h"
 
-TYPEDEF_MAP(hc_sock_map, int, hc_sock_request_t *, int_cmp, int_snprintf,
-            generic_snprintf);
-
 hc_sock_request_t *hc_sock_request_create(int seq, hc_data_t *data,
                                           HC_PARSE parse) {
   assert(data);
index 4749474..d24b5bb 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <assert.h>  // assert
 
+#include <hicn/util/khash.h>
 #include "api_private.h"
 
 #define PORT 9695
@@ -39,7 +40,7 @@ typedef struct {
  * outgoing queries so that replied can be demultiplexed and treated
  * appropriately.
  */
-TYPEDEF_MAP_H(hc_sock_map, int, hc_sock_request_t *);
+KHASH_MAP_INIT_INT(sock_map, hc_sock_request_t *);
 
 struct hc_sock_light_s {
   /* This must be the first element of the struct */
@@ -69,7 +70,7 @@ struct hc_sock_light_s {
   hc_sock_request_t *cur_request;
 
   bool async;
-  hc_sock_map_t *map;
+  kh_sock_map_t *map;
 };
 
 typedef struct hc_sock_light_s hc_sock_light_t;
index a58ee90..488b2ed 100644 (file)
@@ -88,7 +88,9 @@
   _(mapme_activator)           \
   _(mapme_timing)              \
   _(subscription_add)          \
-  _(subscription_remove)
+  _(subscription_remove)       \
+  _(stats_get)                 \
+  _(stats_list)
 
 const char *command_type_str[] = {
 #define _(l, u) [COMMAND_TYPE_##u] = STRINGIZE(u),
@@ -169,21 +171,13 @@ static int _hcng_sock_light_reset(hc_sock_t *socket) {
 
 void _hcng_sock_light_free(hc_sock_t *socket) {
   hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket);
-  hc_sock_request_t **request_array = NULL;
-  int n = hc_sock_map_get_value_array(s->map, &request_array);
-  if (n < 0) {
-    ERROR("Could not retrieve pending request array for freeing up resources");
-  } else {
-    for (unsigned i = 0; i < n; i++) {
-      hc_sock_request_t *request = request_array[i];
-      if (hc_sock_map_remove(s->map, request->seq, NULL) < 0)
-        ERROR("[hc_sock_light_process] Error removing request from map");
-      hc_sock_light_request_free(request);
-    }
-    free(request_array);
-  }
 
-  hc_sock_map_free(s->map);
+  unsigned k_seq;
+  hc_sock_request_t *v_request;
+  kh_foreach(s->map, k_seq, v_request,
+             { hc_sock_light_request_free(v_request); });
+
+  kh_destroy_sock_map(s->map);
   if (s->url) free(s->url);
   close(s->fd);
   free(s);
@@ -292,9 +286,13 @@ static void _hcng_sock_light_mark_complete(hc_sock_light_t *s,
                                            hc_data_t **pdata) {
   hc_data_t *data = s->cur_request->data;
 
-  if (hc_sock_map_remove(s->map, s->cur_request->seq, NULL) < 0) {
+  khiter_t k = kh_get_sock_map(s->map, s->cur_request->seq);
+  if (k == kh_end(s->map)) {
     ERROR("[hc_sock_light_mark_complete] Error removing request from map");
+  } else {
+    kh_del_sock_map(s->map, k);
   }
+
   hc_data_set_complete(data);
   if (pdata) *pdata = data;
 
@@ -323,7 +321,7 @@ static int _hcng_sock_light_process_notification(hc_sock_light_t *s,
   /* Copy the packet payload as the single entry in hc_data_t */
   hc_data_push_many(*pdata, s->buf + s->roff, 1);
 
-  return notification_size;
+  return (int)notification_size;
 }
 
 /*
@@ -333,12 +331,16 @@ static hc_sock_request_t *_hcng_sock_light_get_request(hc_sock_light_t *s,
                                                        int seq) {
   hc_sock_request_t *request;
   /* Retrieve request from sock map */
-  if (hc_sock_map_get(s->map, seq, &request) < 0) {
-    ERROR("[hc_sock_light_process] Error searching for matching request");
+  khiter_t k = kh_get_sock_map(s->map, seq);
+  if (k == kh_end(s->map)) {
+    ERROR(
+        "[_hcng_sock_light_get_request] Error searching for matching request");
     return NULL;
   }
+  request = kh_val(s->map, k);
+
   if (!request) {
-    ERROR("[hc_sock_light_process] No request matching sequence number");
+    ERROR("[_hcng_sock_light_get_request] No request matching sequence number");
     return NULL;
   }
   return request;
@@ -593,7 +595,7 @@ int _hcng_sock_prepare_send(hc_sock_t *socket, hc_result_t *result,
   hc_data_t *data =
       hc_data_create(result->params.size_in, result->params.size_out, NULL);
   if (!data) {
-    ERROR("[_hcng_execute_command] Could not create data storage");
+    ERROR("[_hcng_sock_prepare_send] Could not create data storage");
     goto ERR_DATA;
   }
   hc_data_set_callback(data, complete_cb, complete_cb_data);
@@ -606,15 +608,17 @@ int _hcng_sock_prepare_send(hc_sock_t *socket, hc_result_t *result,
   hc_sock_request_t *request = NULL;
   request = hc_sock_request_create(seq, data, result->params.parse);
   if (!request) {
-    ERROR("[_hcng_execute_command] Could not create request state");
+    ERROR("[_hcng_sock_prepare_send] Could not create request state");
     goto ERR_REQUEST;
   }
 
-  // Add state to map
-  if (hc_sock_map_add(s->map, seq, request) < 0) {
-    ERROR("[_hcng_execute_command] Error adding request state to map");
+  int rc;
+  khiter_t k = kh_put_sock_map(s->map, seq, &rc);
+  if (rc != KH_ADDED && rc != KH_RESET) {
+    ERROR("[_hcng_sock_prepare_send] Error adding request state to map");
     goto ERR_MAP;
   }
+  kh_value(s->map, k) = request;
 
   return sizeof(result->msg);
 
@@ -631,7 +635,7 @@ int _hcng_sock_set_recv_timeout_ms(hc_sock_t *socket, long timeout_ms) {
 
   struct timeval tv;
   tv.tv_sec = 0;
-  tv.tv_usec = timeout_ms * 1000;  // Convert ms into us
+  tv.tv_usec = (int)(timeout_ms * 1000);  // Convert ms into us
   if (setsockopt(s->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
     perror("setsockopt");
     return -1;
@@ -659,10 +663,13 @@ static int _hcng_execute_command(hc_sock_t *socket, hc_msg_t *msg,
       assert(params->size_out == 0);
       assert(params->parse == NULL);
       break;
+    case ACTION_GET:
     case ACTION_LIST:
       assert(params->size_in != 0);
       assert(params->size_out != 0);
-      assert(params->parse != NULL);
+      // TODO(eloparco): Parsing should not be necessary after
+      // (pending) refatoring
+      // assert(params->parse != NULL);
       break;
     case ACTION_SET:
     case ACTION_SERVE:
@@ -701,10 +708,13 @@ static int _hcng_execute_command(hc_sock_t *socket, hc_msg_t *msg,
   }
 
   /* Add state to map */
-  if (hc_sock_map_add(s->map, seq, request) < 0) {
+  int rc;
+  khiter_t k = kh_put_sock_map(s->map, seq, &rc);
+  if (rc != KH_ADDED && rc != KH_RESET) {
     ERROR("[_hcng_execute_command] Error adding request state to map");
     goto ERR_MAP;
   }
+  kh_value(s->map, k) = request;
 
   if (_hcng_sock_light_send(socket, msg, msg_len, seq) < 0) {
     ERROR("[_hcng_execute_command] Error sending message");
@@ -1823,7 +1833,7 @@ static int _hcng_face_create(hc_sock_t *socket, hc_face_t *face) {
     case FACE_TYPE_HICN:
     case FACE_TYPE_TCP:
     case FACE_TYPE_UDP:
-      if (hc_face_to_connection(face, &connection, true) < 0) {
+      if (hc_face_to_connection(face, &connection, false) < 0) {
         ERROR("[hc_face_create] Could not convert face to connection.");
         return -1;
       }
@@ -2955,6 +2965,120 @@ static int _hcng_subscription_delete(hc_sock_t *socket,
   return ret;
 }
 
+/*----------------------------------------------------------------------------*
+ * Statistics
+ *----------------------------------------------------------------------------*/
+
+/* STATS GET */
+
+static hc_result_t *_hcng_stats_get_serialize(hc_sock_t *socket,
+                                              hc_data_t **pdata, bool async) {
+  hc_result_t *res = malloc(sizeof(*res));
+  DEBUG("[hc_stats_get] async=%s", BOOLSTR(async));
+
+  msg_stats_get_t msg = {.header = {
+                             .message_type = REQUEST_LIGHT,
+                             .command_id = COMMAND_TYPE_STATS_GET,
+                             .length = 0,
+                             .seq_num = 0,
+                         }};
+
+  hc_command_params_t params = {
+      .cmd = ACTION_GET,
+      .cmd_id = COMMAND_TYPE_STATS_GET,
+      .size_in = sizeof(hicn_light_stats_t),
+      .size_out = sizeof(hicn_light_stats_t),
+  };
+
+  *res = (hc_result_t){
+      .msg =
+          (hc_msg_t){
+              .hdr = msg.header,
+              .payload.stats_get = msg.payload,
+          },
+      .params = params,
+      .async = async,
+      .success = true,
+  };
+  return res;
+}
+
+static int _hcng_stats_get_internal(hc_sock_t *socket, hc_data_t **pdata,
+                                    bool async) {
+  hc_result_t *result = _hcng_stats_get_serialize(socket, pdata, async);
+
+  int ret = INPUT_ERROR;
+  if (result->success) {
+    ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
+                                sizeof(result->msg), &result->params, pdata,
+                                result->async);
+  }
+
+  hc_result_free(result);
+  DEBUG("[_hcng_stats_get] done or error");
+  return ret;
+}
+
+static int _hcng_stats_get(hc_sock_t *s, hc_data_t **pdata) {
+  DEBUG("[_hcng_stats_get]");
+  return _hcng_stats_get_internal(s, pdata, false);
+}
+
+/* STATS LIST */
+
+static hc_result_t *_hcng_stats_list_serialize(hc_sock_t *socket,
+                                               hc_data_t **pdata, bool async) {
+  hc_result_t *res = malloc(sizeof(*res));
+  DEBUG("[hc_stats_list] async=%s", BOOLSTR(async));
+
+  msg_stats_list_t msg = {.header = {
+                              .message_type = REQUEST_LIGHT,
+                              .command_id = COMMAND_TYPE_STATS_LIST,
+                              .length = 0,
+                              .seq_num = 0,
+                          }};
+
+  hc_command_params_t params = {
+      .cmd = ACTION_LIST,
+      .cmd_id = COMMAND_TYPE_STATS_LIST,
+      .size_in = sizeof(cmd_stats_list_item_t),
+      .size_out = sizeof(cmd_stats_list_item_t),
+  };
+
+  *res = (hc_result_t){
+      .msg =
+          (hc_msg_t){
+              .hdr = msg.header,
+              .payload.stats_list = msg.payload,
+          },
+      .params = params,
+      .async = async,
+      .success = true,
+  };
+  return res;
+}
+
+static int _hcng_stats_list_internal(hc_sock_t *socket, hc_data_t **pdata,
+                                     bool async) {
+  hc_result_t *result = _hcng_stats_list_serialize(socket, pdata, async);
+
+  int ret = INPUT_ERROR;
+  if (result->success) {
+    ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg,
+                                sizeof(result->msg), &result->params, pdata,
+                                result->async);
+  }
+
+  hc_result_free(result);
+  DEBUG("[_hcng_stats_list] done or error");
+  return ret;
+}
+
+static int _hcng_stats_list(hc_sock_t *s, hc_data_t **pdata) {
+  DEBUG("[_hcng_stats_list]");
+  return _hcng_stats_list_internal(s, pdata, false);
+}
+
 /* RESULT */
 hc_msg_t *_hcng_result_get_msg(hc_result_t *result) { return &result->msg; }
 int _hcng_result_get_cmd_id(hc_result_t *result) {
@@ -3018,6 +3142,9 @@ static hc_sock_t hc_sock_light_ng_interface = (hc_sock_t){
     .hc_subscription_create = _hcng_subscription_create,
     .hc_subscription_delete = _hcng_subscription_delete,
 
+    .hc_stats_get = _hcng_stats_get,
+    .hc_stats_list = _hcng_stats_list,
+
     .hc_route_create = _hcng_route_create,
     .hc_route_create_async = _hcng_route_create_async,
     .hc_route_delete = _hcng_route_delete,
@@ -3094,7 +3221,7 @@ hc_sock_t *_hc_sock_create_url(const char *url) {
   s->seq = 0;
   s->cur_request = NULL;
 
-  s->map = hc_sock_map_create();
+  s->map = kh_init_sock_map();
   if (!s->map) goto ERR_MAP;
 
   return (hc_sock_t *)(s);
index f81d21e..b4d538d 100644 (file)
@@ -43,7 +43,7 @@ VPP 22.02, Debian packages can be found on
   - libvppinfra-dev
   - vpp-dev
   - hicn-plugin-dev
-- `collectd` and `collectd-dev`: `sudo apt install collectd collectd-dev`
+- `collectd` and `collectd-dev`: `sudo apt install collectd collectd-dev libyajl-dev`
 
 ## Getting started
 
index eb5b9d7..c525002 100644 (file)
@@ -202,7 +202,7 @@ hICN has built-in authentication and integrity features by either:
 To enable per-packet signature with asymmetric signing:
 * On the producer, disable manifests (which are ON by default):
   ```cpp
-  producer_socket->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, 0);
+  producer_socket->setSocketOption(GeneralTransportOptions::MANIFEST_MAX_CAPACITY, 0u);
   ```
 * On the producer, instantiate an `AsymmetricSigner` object by passing either an
   asymmetric pair of keys as
@@ -244,25 +244,49 @@ available suites.
 ### Enabling manifests
 
 * Follow steps 2-5 in [Per-packet signatures](#per-packet-signatures).
-* By default, a manifest holds the digest of 30 packets. To change this value:
+* By default, a manifest has a maximum capacity `C_max` of 30 packets. To change
+  this value:
   ```cpp
-  producer_socket->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, 20);
+  producer_socket->setSocketOption(GeneralTransportOptions::MANIFEST_MAX_CAPACITY, 20u);
   ```
 
 In the case of RTC, manifests are sent after the data they contain and on the
 consumer side, data packets are immediately forwarded to the application, *even
 if they weren't authenticated yet via a manifest*. This is to minimize latency.
 The digest of incoming data packets are kept in a buffer while waiting for
-manifests to arrive. When that buffer goes above a threshold `T`, an alert is
-raised by the verifier object. That threshold is computed as follows:
+manifests to arrive. When the buffer size goes above a threshold `T`, an alert
+is raised by the verifier object. That alert threshold is computed as follows:
 ```
-T(t) = producer_rate(t) * max_unverified_time
+T = manifest_factor_alert * C_max
 ```
 
-`max_unverified_time` is a consumer socket option, in milliseconds. It is set
-to `2000` by default. To change it:
+The value of `C_max` is passed by the producer to the consumer at the start of
+the connection. `manifest_factor_alert` is a consumer socket option. It
+basically acts on the resilience of manifests against networks losses and
+reflects the application's tolerance to unverified packets: a higher value gives
+the transport the time needed to recover from several manifest losses but
+potentially allows a larger number of unverified packet to go the application
+before alerts are triggered. It is set to `20` by default and should always be
+`>= 1`. To change it:
 ```cpp
-consumer_socket_->setSocketOption(GeneralTransportOptions::MAX_UNVERIFIED_TIME, 4000);
+consumer_socket_->setSocketOption(GeneralTransportOptions::MANIFEST_FACTOR_ALERT, 10u);
+```
+
+The buffer does not keep unverified packets indefinitely. After a certain amount
+of packets have been received and processed (and were verified or not), older
+packets still unverified are flushed out. This is to prevent the buffer to grow
+uncontrollably and to raise alerts for packets that are not relevant to the
+application anymore. That threshold of relevance is computed as follows:
+```
+T = manifest_factor_relevant * C_max
+```
+
+`manifest_factor_relevant` is a consumer socket option. It is set to `100` by
+default. Its value must be set so that `manifest_factor_relevant >
+manifest_factor_alert >= 1`. If `manifest_factor_relevant <=
+manifest_factor_alert`, no alert will ever be raised. To change it:
+```cpp
+consumer_socket_->setSocketOption(GeneralTransportOptions::MANIFEST_FACTOR_RELEVANT, 200u);
 ```
 
 ### Handling authentication failures
index 337e22b..241cae7 100644 (file)
@@ -93,6 +93,7 @@ else()
       ${LIBHICNCTRL_STATIC}
     )
   else ()
+  message("qui2!!!")
     set(HICN_LIBRARIES
       ${LIBHICN_SHARED}
       ${LIBHICNCTRL_SHARED}
index 1180ed0..2541ed8 100644 (file)
 # 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 (file)
index 060fd5b..0000000
+++ /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 (file)
index 9f7e3be..0000000
+++ /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 (file)
index 3c54feb..0000000
+++ /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 (file)
index 4c62b02..0000000
+++ /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 (file)
index e5fb7d6..0000000
+++ /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/ring.h b/hicn-light/src/hicn/base/ring.h
deleted file mode 100644 (file)
index 492a8fd..0000000
+++ /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 */
index d14093b..3074016 100644 (file)
@@ -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;
   }
index e73517e..fa1b1c0 100644 (file)
@@ -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"
index 00ee240..90d0a22 100644 (file)
@@ -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 (file)
index 0000000..70f74fd
--- /dev/null
@@ -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
index e99e0b8..be00575 100644 (file)
@@ -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;
 
index cedf4de..3852a76 100644 (file)
@@ -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
index 9861b6c..93b4cf7 100644 (file)
@@ -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>
index 57ffb78..9516a6a 100644 (file)
@@ -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
index 72b92d6..2fd207d 100644 (file)
@@ -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)
 
index c8cc1d0..2108d30 100644 (file)
@@ -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);
index 05dc1d6..ac75428 100644 (file)
@@ -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);
index 09236ae..c723073 100644 (file)
@@ -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
index 4c03aa6..7d4bad7 100644 (file)
 #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 */
index e6290cd..1a6ecbb 100644 (file)
@@ -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);
index edbdc5a..360e6d3 100644 (file)
@@ -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; }
index d47d603..ceaf05e 100644 (file)
@@ -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 */
index 616f129..80d3378 100644 (file)
@@ -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);
     });
 
index 37502f3..74be643 100644 (file)
 #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
index 76c1236..2f940cf 100644 (file)
@@ -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 (file)
index 0000000..1be8a3f
--- /dev/null
@@ -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 (file)
index 0000000..fcb2b98
--- /dev/null
@@ -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 */
index ecdfc38..188f0c3 100644 (file)
@@ -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;
 }
index 346c874..5d03843 100644 (file)
@@ -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.
  *
index 32b8e9d..220b738 100644 (file)
@@ -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);
 }
index 5fed638..7e2e99d 100644 (file)
 #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
index fb5d0a0..a2092aa 100644 (file)
@@ -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) {
index 8886cc9..d30cebe 100644 (file)
 #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
index 1314671..aa43187 100644 (file)
@@ -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
index e3cc108..549b266 100644 (file)
 #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, }
index 203ad4a..8bd188c 100644 (file)
 
 #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;
+}
index ccfc83b..47926fc 100644 (file)
@@ -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
  *
  * 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 *****************************/
 
index fa12b51..aee68e5 100644 (file)
@@ -5,7 +5,6 @@
 #ifdef WITH_POLICY_STATS
 
 #include <hicn/policy.h>
-#include "../base/loop.h"
 
 typedef struct policy_stats_mgr_s {
   void* forwarder;
index 0c4949f..ad40065 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 #include "subscription.h"
-#include <hicn/base/vector.h>
+#include <hicn/util/vector.h>
 #include <hicn/util/log.h>
 
 /*----------------------------------------------------------------------------*
index 71d1002..cd73629 100644 (file)
@@ -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;
index 8b4ad2e..d019a49 100644 (file)
@@ -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 */
 
index 69ad32d..50591c3 100644 (file)
@@ -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);
 
index 3301e21..149d53a 100644 (file)
 
 #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));
 
index 439de0a..bc141e5 100644 (file)
@@ -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;
index 26d6a3a..7a9f3a5 100644 (file)
@@ -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>
 
index 0ded425..65e216c 100644 (file)
@@ -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
index f9cd402..1fd21a1 100644 (file)
@@ -25,7 +25,7 @@
 
 extern "C" {
 #define WITH_TESTS
-#include <hicn/base/bitmap.h>
+#include <hicn/util/bitmap.h>
 }
 
 #define DEFAULT_SIZE 10
index 6bbf478..d17de7c 100644 (file)
@@ -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
index 2b72e19..3b03a08 100644 (file)
 #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 (file)
index 0000000..6408a3f
--- /dev/null
@@ -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
index 4fcb48c..f437f88 100644 (file)
@@ -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)
index 5537aa2..e9c8e64 100644 (file)
@@ -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 {
index bb24dae..0b4b214 100644 (file)
 
 #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
index c631415..8cd891d 100644 (file)
@@ -25,7 +25,7 @@
 
 extern "C" {
 #define WITH_TESTS
-#include <hicn/base/pool.h>
+#include <hicn/util/pool.h>
 }
 
 /*
index 51f1f53..ab96d76 100644 (file)
@@ -25,7 +25,7 @@
 
 extern "C" {
 #define WITH_TESTS
-#include <hicn/base/ring.h>
+#include <hicn/util/ring.h>
 }
 
 #define DEFAULT_SIZE 10UL
index 18ef60c..f89254e 100644 (file)
@@ -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 (file)
index 0000000..5776295
--- /dev/null
@@ -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
index fb30a82..dda71fd 100644 (file)
 
 #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
index a8a941a..af9f5da 100644 (file)
 #define foreach_hicn_error                                                    \
   _ (NONE, 0, "Ok")                                                           \
   _ (UNSPECIFIED, -128, "Unspecified Error")                                  \
-  _ (FACE_NOT_FOUND, -129, "Face not found in Face table")                    \
-  _ (FACE_NULL, -130, "Face null")                                            \
-  _ (FACE_IP_ADJ_NOT_FOUND, -131, "Ip adjacecny for face not found")          \
-  _ (FACE_HW_INT_NOT_FOUND, -132, "Hardware interface not found")             \
-  _ (FACE_NOMEM, -133, "Face table is full")                                  \
-  _ (FACE_NO_GLOBAL_IP, -134, "No global ip address for face")                \
-  _ (FACE_NOT_FOUND_IN_ENTRY, -135, "Face not found in entry")                \
-  _ (FACE_ALREADY_DELETED, -136, "Face alredy deleted")                       \
-  _ (FACE_ALREADY_CREATED, -137, "Face alredy created")                       \
-  _ (FWD_NOT_ENABLED, -138, "hICN forwarder not enabled")                     \
-  _ (FWD_ALREADY_ENABLED, -139, "hICN forwarder alredy enabled")              \
-  _ (PARSER_UNSUPPORTED_PROTO, -140, "Unsupported protocol")                  \
-  _ (PARSER_PKT_INVAL, -141, "Packet null")                                   \
-  _ (PIT_CONFIG_MINLT_OOB, -142, "Min lifetime ouf of bounds")                \
-  _ (PIT_CONFIG_MAXLT_OOB, -143, "Max lifetime ouf of bounds")                \
-  _ (PIT_CONFIG_MINMAXLT, -144, "Min lifetime grater than max lifetime")      \
-  _ (PIT_CONFIG_DFTLT_OOB, -145, "Default lifetime ouf of bounds")            \
-  _ (PIT_CONFIG_SIZE_OOB, -146, "Pit size ouf of bounds")                     \
-  _ (CS_CONFIG_SIZE_OOB, -147, "CS size ouf of bounds")                       \
-  _ (CS_CONFIG_RESERVED_OOB, -148,                                            \
+  _ (FACE_NOT_FOUND, -1000, "Face not found in Face table")                   \
+  _ (FACE_NULL, -1001, "Face null")                                           \
+  _ (FACE_IP_ADJ_NOT_FOUND, -1002, "Ip adjacecny for face not found")         \
+  _ (FACE_HW_INT_NOT_FOUND, -1003, "Hardware interface not found")            \
+  _ (FACE_NOMEM, -1004, "Face table is full")                                 \
+  _ (FACE_NO_GLOBAL_IP, -1005, "No global ip address for face")               \
+  _ (FACE_NOT_FOUND_IN_ENTRY, -1006, "Face not found in entry")               \
+  _ (FACE_ALREADY_DELETED, -1007, "Face alredy deleted")                      \
+  _ (FACE_ALREADY_CREATED, -1008, "Face alredy created")                      \
+  _ (FWD_NOT_ENABLED, -2000, "hICN forwarder not enabled")                    \
+  _ (FWD_ALREADY_ENABLED, -2001, "hICN forwarder alredy enabled")             \
+  _ (PARSER_UNSUPPORTED_PROTO, -3000, "Unsupported protocol")                 \
+  _ (PARSER_PKT_INVAL, -3001, "Packet null")                                  \
+  _ (PARSER_MAPME_PACKET, -3002, "Packet is mapme")                           \
+  _ (PIT_CONFIG_MINLT_OOB, -4000, "Min lifetime ouf of bounds")               \
+  _ (PIT_CONFIG_MAXLT_OOB, -4001, "Max lifetime ouf of bounds")               \
+  _ (PIT_CONFIG_MINMAXLT, -4002, "Min lifetime grater than max lifetime")     \
+  _ (PIT_CONFIG_DFTLT_OOB, -4003, "Default lifetime ouf of bounds")           \
+  _ (PIT_CONFIG_SIZE_OOB, -4004, "Pit size ouf of bounds")                    \
+  _ (CS_CONFIG_SIZE_OOB, -5000, "CS size ouf of bounds")                      \
+  _ (CS_CONFIG_RESERVED_OOB, -5001,                                           \
      "Reseved CS must be between 0 and 100 (excluded)")                       \
-  _ (DPO_CTX_NHOPS_NS, -149, "No space for additional next hop")              \
-  _ (DPO_CTX_NHOPS_EXISTS, -150, "Next hop already in the route")             \
-  _ (DPO_CTX_NOT_FOUND, -151, "Dpo context not found")                        \
-  _ (DPO_MGR_ID_NOT_VALID, -152, "Dpo id for strategy and context not valid") \
-  _ (HASHTB_HASH_NOT_FOUND, -153, "Hash not found in hash table")             \
-  _ (HASHTB_HASH_INVAL, -154, "Error while calculating the hash")             \
-  _ (HASHTB_NOMEM, -155, "Unable to allocate new buckets or nodes")           \
-  _ (HASHTB_INVAL, -156, "Invalid argument")                                  \
-  _ (HASHTB_KEY_INVAL, -157, "Invalid hashtb key")                            \
-  _ (HASHTB_EXIST, -158, "Hash already in hashtable")                         \
-  _ (ROUTE_INVAL, -159, "Invalid face id and weight")                         \
-  _ (ROUTE_NO_LD, -160, "Expected load balance dpo")                          \
-  _ (ROUTE_MLT_LD, -161, "Unexpected mulitple buckets in load balance dpo")   \
-  _ (ROUTE_NO_INSERT, -162, "Unable to insert a new FIB entry")               \
-  _ (ROUTE_DPO_NO_HICN, -163, "Dpo is not of type hICN")                      \
-  _ (ROUTE_NOT_FOUND, -164, "Route not found in FIB")                         \
-  _ (ROUTE_NOT_UPDATED, -165, "Unable to update route")                       \
-  _ (ROUTE_ALREADY_EXISTS, -166, "Route already in FIB")                      \
-  _ (CLI_INVAL, -167, "Invalid input")                                        \
-  _ (IPS_ADDR_TYPE_NONUNIFORM, -168,                                          \
+  _ (DPO_CTX_NHOPS_NS, -6000, "No space for additional next hop")             \
+  _ (DPO_CTX_NHOPS_EXISTS, -6001, "Next hop already in the route")            \
+  _ (DPO_CTX_NOT_FOUND, -6002, "Dpo context not found")                       \
+  _ (DPO_MGR_ID_NOT_VALID, -6003,                                             \
+     "Dpo id for strategy and context not valid")                             \
+  _ (HASHTB_HASH_NOT_FOUND, -7000, "Hash not found in hash table")            \
+  _ (HASHTB_HASH_INVAL, -7001, "Error while calculating the hash")            \
+  _ (HASHTB_NOMEM, -7002, "Unable to allocate new buckets or nodes")          \
+  _ (HASHTB_INVAL, -7003, "Invalid argument")                                 \
+  _ (HASHTB_KEY_INVAL, -7004, "Invalid hashtb key")                           \
+  _ (HASHTB_EXIST, -7005, "Hash already in hashtable")                        \
+  _ (ROUTE_INVAL, -8000, "Invalid face id and weight")                        \
+  _ (ROUTE_NO_LD, -8001, "Expected load balance dpo")                         \
+  _ (ROUTE_MLT_LD, -8002, "Unexpected mulitple buckets in load balance dpo")  \
+  _ (ROUTE_NO_INSERT, -8003, "Unable to insert a new FIB entry")              \
+  _ (ROUTE_DPO_NO_HICN, -8004, "Dpo is not of type hICN")                     \
+  _ (ROUTE_NOT_FOUND, -8005, "Route not found in FIB")                        \
+  _ (ROUTE_NOT_UPDATED, -8006, "Unable to update route")                      \
+  _ (ROUTE_ALREADY_EXISTS, -8007, "Route already in FIB")                     \
+  _ (CLI_INVAL, -9000, "Invalid input")                                       \
+  _ (IPS_ADDR_TYPE_NONUNIFORM, -10000,                                        \
      "Src and dst addr have different ip types")                              \
-  _ (FACE_TYPE_EXISTS, -169, "Face type already registered")                  \
-  _ (NO_BUFFERS, -170, "No vlib_buffer available for packet cloning.")        \
-  _ (NOT_IMPLEMENTED, -171, "Function not yet implemented")                   \
-  _ (IFACE_IP_ADJ_NOT_FOUND, -172,                                            \
+  _ (FACE_TYPE_EXISTS, -11000, "Face type already registered")                \
+  _ (NO_BUFFERS, -12000, "No vlib_buffer available for packet cloning.")      \
+  _ (NOT_IMPLEMENTED, -13000, "Function not yet implemented")                 \
+  _ (IFACE_IP_ADJ_NOT_FOUND, -14000,                                          \
      "IP adjacency on incomplete face not available")                         \
-  _ (APPFACE_ALREADY_ENABLED, -173,                                           \
+  _ (APPFACE_ALREADY_ENABLED, -15000,                                         \
      "Application face already enabled on interface")                         \
-  _ (APPFACE_FEATURE, -174, "Error while enabling app face feature")          \
-  _ (APPFACE_NOT_FOUND, -175, "Application face not found")                   \
-  _ (APPFACE_PROD_PREFIX_NULL, -176,                                          \
+  _ (APPFACE_FEATURE, -15001, "Error while enabling app face feature")        \
+  _ (APPFACE_NOT_FOUND, -15002, "Application face not found")                 \
+  _ (APPFACE_PROD_PREFIX_NULL, -15003,                                        \
      "Prefix must not be null for producer face")                             \
-  _ (STRATEGY_NH_NOT_FOUND, -177, "Next hop not found")                       \
-  _ (MW_STRATEGY_SET, -178, "Error while setting weight for next hop")        \
-  _ (STRATEGY_NOT_FOUND, -179, "Strategy not found")                          \
-  _ (UDP_TUNNEL_NOT_FOUND, -180, "Udp tunnel not found")                      \
-  _ (UDP_TUNNEL_SRC_DST_TYPE, -181,                                           \
+  _ (STRATEGY_NH_NOT_FOUND, -16000, "Next hop not found")                     \
+  _ (MW_STRATEGY_SET, -16001, "Error while setting weight for next hop")      \
+  _ (STRATEGY_NOT_FOUND, -16002, "Strategy not found")                        \
+  _ (UDP_TUNNEL_NOT_FOUND, -17000, "Udp tunnel not found")                    \
+  _ (UDP_TUNNEL_SRC_DST_TYPE, -17001,                                         \
      "Src and dst addresses have different type (ipv4 and ipv6)")             \
-  _ (MAPME_NEXT_HOP_ADDED, -182, "Next hop added to mapme")                   \
-  _ (MAPME_NEXT_HOP_NOT_ADDED, -183, "Next hop added to mapme")
+  _ (MAPME_NEXT_HOP_ADDED, -18000, "Next hop added to mapme")                 \
+  _ (MAPME_NEXT_HOP_NOT_ADDED, -18001, "Next hop added to mapme")
 
 typedef enum
 {
index 2141ec5..e071b3b 100644 (file)
@@ -59,6 +59,7 @@ set(HICN_PLUGIN_SOURCE_FILES
   ${CMAKE_CURRENT_SOURCE_DIR}/faces/app/face_prod_node.c
   ${CMAKE_CURRENT_SOURCE_DIR}/faces/app/face_app_cli.c
   ${CMAKE_CURRENT_SOURCE_DIR}/pg.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/pg_node.c
   ${CMAKE_CURRENT_SOURCE_DIR}/strategies/dpo_mw.c
   ${CMAKE_CURRENT_SOURCE_DIR}/strategies/strategy_mw.c
   ${CMAKE_CURRENT_SOURCE_DIR}/strategies/strategy_mw_cli.c
@@ -83,6 +84,7 @@ set(HICN_PLUGIN_HEADER_FILES
   ${CMAKE_CURRENT_SOURCE_DIR}/pcs.h
   ${CMAKE_CURRENT_SOURCE_DIR}/hicn_api.h
   ${CMAKE_CURRENT_SOURCE_DIR}/hicn.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/hicn_buffer_flags.h
   ${CMAKE_CURRENT_SOURCE_DIR}/state.h
   ${CMAKE_CURRENT_SOURCE_DIR}/infra.h
   ${CMAKE_CURRENT_SOURCE_DIR}/hicn_msg_enum.h
@@ -99,6 +101,7 @@ set(HICN_PLUGIN_HEADER_FILES
   ${CMAKE_CURRENT_SOURCE_DIR}/error.h
   ${CMAKE_CURRENT_SOURCE_DIR}/face_db.h
   ${CMAKE_CURRENT_SOURCE_DIR}/faces/face.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/faces/face_flags.h
   ${CMAKE_CURRENT_SOURCE_DIR}/faces/face_node.h
   ${CMAKE_CURRENT_SOURCE_DIR}/faces/iface_node.h
   ${CMAKE_CURRENT_SOURCE_DIR}/faces/inlines.h
index cd45607..f743f63 100644 (file)
@@ -585,13 +585,15 @@ hicn_cli_pgen_server_set_command_fn (vlib_main_t *vm,
                                     unformat_input_t *main_input,
                                     vlib_cli_command_t *cmd)
 {
-  clib_error_t *cl_err;
-  int rv = HICN_ERROR_NONE;
-  hicnpg_server_main_t *pg_main = &hicnpg_server_main;
   int payload_size = 1440;
   u32 sw_if_index = ~0;
   vnet_main_t *vnm = vnet_get_main ();
-  fib_prefix_t *prefix = calloc (1, sizeof (fib_prefix_t));
+  fib_prefix_t prefix;
+  u32 hicnpg_server_index;
+  ip46_address_t locator;
+
+  locator.as_u64[0] = 0;
+  locator.as_u64[1] = 0;
 
   /* Get a line of input. */
   unformat_input_t _line_input, *line_input = &_line_input;
@@ -601,7 +603,7 @@ hicn_cli_pgen_server_set_command_fn (vlib_main_t *vm,
       while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
        {
          if (unformat (line_input, "name %U/%d", unformat_ip46_address,
-                       &prefix->fp_addr, IP46_TYPE_ANY, &prefix->fp_len))
+                       &prefix.fp_addr, IP46_TYPE_ANY, &prefix.fp_len))
            {
              ;
            }
@@ -618,6 +620,11 @@ hicn_cli_pgen_server_set_command_fn (vlib_main_t *vm,
            {
              ;
            }
+         else if (unformat (line_input, "dst %U", unformat_ip46_address,
+                            &locator, IP46_TYPE_ANY))
+           {
+             ;
+           }
          else
            {
              return (clib_error_return (0, "Unknown input '%U'",
@@ -628,70 +635,45 @@ hicn_cli_pgen_server_set_command_fn (vlib_main_t *vm,
     }
 
   /* Attach our packet-gen node for ip4 udp local traffic */
-  if ((prefix->fp_addr.ip6.as_u64[0] == (u64) 0 &&
-       prefix->fp_addr.ip6.as_u64[1] == 0) ||
-      payload_size == 0 || sw_if_index == ~0)
+  if ((prefix.fp_addr.ip6.as_u64[0] == (u64) 0 &&
+       prefix.fp_addr.ip6.as_u64[1] == 0) ||
+      payload_size == 0 || sw_if_index == ~0 ||
+      ip46_address_is_zero (&locator))
     {
-      return clib_error_return (0, "Error: must supply local port, payload "
+      return clib_error_return (0, "Error: must supply locator, payload "
                                   "size and incoming hICN prefix");
     }
 
   // Remove bits that are out of the subnet
-  if (ip46_address_is_ip4 (&prefix->fp_addr))
+  if (ip46_address_is_ip4 (&prefix.fp_addr))
     {
       ip4_address_t mask;
-      ip4_preflen_to_mask (prefix->fp_len, &mask);
-      prefix->fp_addr.ip4.as_u32 = prefix->fp_addr.ip4.as_u32 & mask.as_u32;
-      prefix->fp_proto = FIB_PROTOCOL_IP4;
+      ip4_preflen_to_mask (prefix.fp_len, &mask);
+      prefix.fp_addr.ip4.as_u32 = prefix.fp_addr.ip4.as_u32 & mask.as_u32;
+      prefix.fp_proto = FIB_PROTOCOL_IP4;
     }
   else
     {
       ip6_address_t mask;
-      ip6_preflen_to_mask (prefix->fp_len, &mask);
-      prefix->fp_addr.ip6.as_u64[0] =
-       prefix->fp_addr.ip6.as_u64[0] & mask.as_u64[0];
-      prefix->fp_addr.ip6.as_u64[1] =
-       prefix->fp_addr.ip6.as_u64[1] & mask.as_u64[1];
-      prefix->fp_proto = FIB_PROTOCOL_IP6;
+      ip6_preflen_to_mask (prefix.fp_len, &mask);
+      prefix.fp_addr.ip6.as_u64[0] =
+       prefix.fp_addr.ip6.as_u64[0] & mask.as_u64[0];
+      prefix.fp_addr.ip6.as_u64[1] =
+       prefix.fp_addr.ip6.as_u64[1] & mask.as_u64[1];
+      prefix.fp_proto = FIB_PROTOCOL_IP6;
     }
 
-  /* Allocate the buffer with the actual content payload TLV */
-  int n_buf = vlib_buffer_alloc (vm, &pg_main->pgen_svr_buffer_idx, 1);
-
-  if (n_buf == 0)
+  fib_protocol_t dest_proto =
+    ip46_address_is_ip4 (&locator) ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
+  if (prefix.fp_proto != dest_proto)
     {
-      return (clib_error_return (0, "Impossible to allocate paylod buffer."));
+      return clib_error_return (0, "Error: prefix and locator must be of the "
+                                  "same protocol");
     }
 
-  vlib_buffer_t *rb = NULL;
-  rb = vlib_get_buffer (vm, pg_main->pgen_svr_buffer_idx);
-
-  pg_main->pgen_srv_hicn_name = prefix;
-
-  /* Initialize the buffer data with zeros */
-  memset (rb->data, 0, payload_size);
-  rb->current_length = payload_size;
-
-  vnet_feature_enable_disable ("ip4-unicast", "hicnpg-server", sw_if_index, 1,
-                              0, 0);
-  vnet_feature_enable_disable ("ip6-unicast", "hicnpg-server", sw_if_index, 1,
-                              0, 0);
-
-  switch (rv)
-    {
-    case 0:
-      cl_err = 0;
-      break;
-
-    case VNET_API_ERROR_UNIMPLEMENTED:
-      cl_err = clib_error_return (0, "Unimplemented, NYI");
-      break;
-
-    default:
-      cl_err = clib_error_return (0, "hicn pgen server returned %d", rv);
-    }
-
-  return cl_err;
+  // Create hicnpg_server
+  return hicnpg_server_add_and_lock (&prefix, &hicnpg_server_index, &locator,
+                                    payload_size);
 }
 
 static clib_error_t *
@@ -855,7 +837,7 @@ VLIB_CLI_COMMAND (hicn_cli_pgen_client_set_command, static) = {
 VLIB_CLI_COMMAND (hicn_cli_pgen_server_set_command, static) = {
   .path = "hicn pgen server",
   .short_help = "hicn pgen server name <prefix> intfc <interest in-interface> "
-               "size <payload_size>",
+               "dst <ip_address> size <payload_size>",
   .long_help = "Run hicn in packet-gen server mode\n",
   .function = hicn_cli_pgen_server_set_command_fn,
 };
index 6acb591..a3f1a59 100644 (file)
@@ -91,7 +91,6 @@ hicn_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
          u16 namelen;
          u32 bi0;
          u32 next0 = HICN_DATA_FWD_NEXT_ERROR_DROP;
-         hicn_name_t name;
          hicn_header_t *hicn0;
          hicn_buffer_t *hicnb0;
          hicn_hash_node_t *node0;
@@ -124,15 +123,15 @@ hicn_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
 
          /* Get hicn buffer and state */
          hicnb0 = hicn_get_buffer (b0);
+         hicn0 = (hicn_header_t *) (vlib_buffer_get_current (b0));
          hicn_get_internal_state (hicnb0, pitcs, &node0, &strategy_vft0,
                                   &dpo_vft0, &dpo_ctx_id0, &hash_entry0);
 
-         ret = hicn_data_parse_pkt (b0, &name, &namelen, &hicn0, &isv6);
+         hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen);
+         isv6 = hicn_buffer_is_v6 (b0);
          pitp = hicn_pit_get_data (node0);
-         nameptr = (u8 *) (&name);
 
          if (PREDICT_FALSE (
-               ret != HICN_ERROR_NONE ||
                !hicn_node_compare (nameptr, namelen, node0) ||
                (hash_entry0->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY)))
            {
@@ -182,7 +181,7 @@ hicn_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
                {
                  hicn_data_fwd_trace_t *t =
                    vlib_add_trace (vm, node, b0, sizeof (*t));
-                 t->pkt_type = HICN_PKT_TYPE_CONTENT;
+                 t->pkt_type = HICN_PACKET_TYPE_DATA;
                  t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
                  t->next_index = next0;
                  clib_memcpy (t->packet_data, vlib_buffer_get_current (b0),
@@ -442,7 +441,7 @@ hicn_satisfy_faces (vlib_main_t *vm, u32 bi0, hicn_pcs_entry_t *pitp,
            {
              hicn_data_fwd_trace_t *t =
                vlib_add_trace (vm, node, h0, sizeof (*t));
-             t->pkt_type = HICN_PKT_TYPE_CONTENT;
+             t->pkt_type = HICN_PACKET_TYPE_DATA;
              t->sw_if_index = vnet_buffer (h0)->sw_if_index[VLIB_RX];
              t->next_index = next0;
              clib_memcpy (t->packet_data, vlib_buffer_get_current (h0),
@@ -453,7 +452,7 @@ hicn_satisfy_faces (vlib_main_t *vm, u32 bi0, hicn_pcs_entry_t *pitp,
            {
              hicn_data_fwd_trace_t *t =
                vlib_add_trace (vm, node, h1, sizeof (*t));
-             t->pkt_type = HICN_PKT_TYPE_CONTENT;
+             t->pkt_type = HICN_PACKET_TYPE_DATA;
              t->sw_if_index = vnet_buffer (h1)->sw_if_index[VLIB_RX];
              t->next_index = next1;
              clib_memcpy (t->packet_data, vlib_buffer_get_current (h1),
@@ -491,7 +490,7 @@ hicn_satisfy_faces (vlib_main_t *vm, u32 bi0, hicn_pcs_entry_t *pitp,
            {
              hicn_data_fwd_trace_t *t =
                vlib_add_trace (vm, node, h0, sizeof (*t));
-             t->pkt_type = HICN_PKT_TYPE_CONTENT;
+             t->pkt_type = HICN_PACKET_TYPE_DATA;
              t->sw_if_index = vnet_buffer (h0)->sw_if_index[VLIB_RX];
              t->next_index = next0;
              clib_memcpy (t->packet_data, vlib_buffer_get_current (h0),
@@ -607,4 +606,4 @@ VLIB_REGISTER_NODE(hicn_data_fwd_node) =
  * fd.io coding-style-patch-verification: ON
  *
  * Local Variables: eval: (c-set-style "gnu") End:
- */
+ */
\ No newline at end of file
index 46fda10..65bba7b 100644 (file)
@@ -80,6 +80,7 @@ hicn_data_input_set_adj_index (vlib_buffer_t *b,
                               const ip46_address_t *dst_addr,
                               const hicn_dpo_ctx_t *dpo_ctx)
 {
+  CLIB_UNUSED (u8 set) = 0;
   for (u8 pos = 0; pos < dpo_ctx->entry_count; pos++)
     {
       hicn_face_t *face = hicn_dpoi_get_from_idx (dpo_ctx->next_hops[pos]);
@@ -87,9 +88,12 @@ hicn_data_input_set_adj_index (vlib_buffer_t *b,
       if (ip46_address_cmp (&(face->nat_addr), dst_addr) == 0)
        {
          vnet_buffer (b)->ip.adj_index[VLIB_RX] = face->dpo.dpoi_index;
+         set = 1;
          break;
        }
     }
+
+  ASSERT (set == 1);
 }
 
 static uword
@@ -147,7 +151,7 @@ hicn_data_input_ip6_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
          src_addr1 = &ip1->src_address;
 
          ip46_address_set_ip6 (&dst_addr0, &ip0->dst_address);
-         ip46_address_set_ip6 (&dst_addr0, &ip1->dst_address);
+         ip46_address_set_ip6 (&dst_addr1, &ip1->dst_address);
 
          ip_lookup_set_buffer_fib_index (im->fib_index_by_sw_if_index, p0);
          ip_lookup_set_buffer_fib_index (im->fib_index_by_sw_if_index, p1);
@@ -701,4 +705,4 @@ VNET_FEATURE_INIT (hicn_data_input_ip4_arc, static) = {
   .arc_name = "ip4-local",
   .node_name = "hicn-data-input-ip4",
   .runs_before = VNET_FEATURES ("ip4-local-end-of-arc"),
-};
+};
\ No newline at end of file
index 69278c3..95db66f 100644 (file)
@@ -63,17 +63,13 @@ hicn_data_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
       while (n_left_from > 0 && n_left_to_next > 0)
        {
          vlib_buffer_t *b0;
-         u8 isv6;
          u8 *nameptr;
          u16 namelen;
          u32 bi0;
          u32 next0 = HICN_DATA_PCSLOOKUP_NEXT_ERROR_DROP;
          u64 name_hash = 0;
-         hicn_name_t name;
-         hicn_header_t *hicn0 = NULL;
          u32 node_id0 = 0;
          index_t dpo_ctx_id0 = 0;
-         int ret0;
          u8 vft_id0 = 0;
          u8 is_cs0;
          u8 hash_entry_id = 0;
@@ -104,13 +100,11 @@ hicn_data_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
          /* Incr packet counter */
          stats.pkts_processed += 1;
 
-         ret0 = hicn_data_parse_pkt (b0, &name, &namelen, &hicn0, &isv6);
-         nameptr = (u8 *) (&name);
+         hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen);
 
          if (PREDICT_TRUE (
-               ret0 == HICN_ERROR_NONE &&
                hicn_hashtb_fullhash (nameptr, namelen, &name_hash) ==
-                 HICN_ERROR_NONE))
+               HICN_ERROR_NONE))
            {
              int res = hicn_hashtb_lookup_node (
                rt->pitcs->pcs_table, nameptr, namelen, name_hash,
@@ -154,7 +148,7 @@ hicn_data_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
            {
              hicn_data_pcslookup_trace_t *t =
                vlib_add_trace (vm, node, b0, sizeof (*t));
-             t->pkt_type = HICN_PKT_TYPE_CONTENT;
+             t->pkt_type = HICN_PACKET_TYPE_DATA;
              t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
              t->next_index = next0;
            }
@@ -216,4 +210,4 @@ VLIB_REGISTER_NODE(hicn_data_pcslookup_node) =
  * fd.io coding-style-patch-verification: ON
  *
  * Local Variables: eval: (c-set-style "gnu") End:
- */
+ */
\ No newline at end of file
index 5d2b540..e3241e4 100644 (file)
@@ -42,12 +42,12 @@ typedef struct
 {
   u32 next_index;
   u32 sw_if_index;
+  hicn_error_t error;
 } hicn_face_prod_input_trace_t;
 
 typedef enum
 {
-  HICN_FACE_PROD_NEXT_DATA_IP4,
-  HICN_FACE_PROD_NEXT_DATA_IP6,
+  HICN_FACE_PROD_NEXT_PCS,
   HICN_FACE_PROD_NEXT_ERROR_DROP,
   HICN_FACE_PROD_N_NEXT,
 } hicn_face_prod_next_t;
@@ -65,11 +65,14 @@ format_face_prod_input_trace (u8 *s, va_list *args)
 
   s = format (s, "prod-face: sw_if_index %d next-index %d", t->sw_if_index,
              t->next_index);
+
+  if (t->error != HICN_ERROR_NONE)
+    s = format (s, " error %s", get_error_string (t->error));
   return s;
 }
 
 static_always_inline int
-match_ip4_name (u32 *name, fib_prefix_t *prefix)
+match_ip4_name (u32 *name, const fib_prefix_t *prefix)
 {
   u32 xor = 0;
 
@@ -79,7 +82,7 @@ match_ip4_name (u32 *name, fib_prefix_t *prefix)
 }
 
 static_always_inline int
-match_ip6_name (u8 *name, fib_prefix_t *prefix)
+match_ip6_name (u8 *name, const fib_prefix_t *prefix)
 {
   union
   {
@@ -96,24 +99,42 @@ match_ip6_name (u8 *name, fib_prefix_t *prefix)
 }
 
 static_always_inline u32
-hicn_face_prod_next_from_data_hdr (vlib_node_runtime_t *node, vlib_buffer_t *b,
-                                  fib_prefix_t *prefix)
+hicn_face_prod_next_from_data_hdr (vlib_buffer_t *b)
 {
-  u8 *ptr = vlib_buffer_get_current (b);
-  u8 v = *ptr & 0xf0;
+  u8 is_v6;
   int match_res = 1;
+  int ret = 0;
+  hicn_name_t *name;
+  hicn_face_prod_state_t *prod_face = NULL;
+
+  // 1 - ensure the packet is hicn and its format is correct
+  ret = hicn_data_parse_pkt (b);
+  if (PREDICT_FALSE (ret))
+    {
+      return HICN_FACE_PROD_NEXT_ERROR_DROP;
+    }
 
-  if (PREDICT_TRUE (v == 0x40 && ip46_address_is_ip4 (&prefix->fp_addr)))
+  // 2 - make sure the packet refers to a valid producer app state and
+  // retrieve app state information
+  prod_face = &face_state_vec[vnet_buffer (b)->sw_if_index[VLIB_RX]];
+  vnet_buffer (b)->ip.adj_index[VLIB_RX] = prod_face->adj_index;
+
+  // 3 - make sure the address in the packet belongs to the producer prefix
+  // of this face
+  const fib_prefix_t *prefix = &prod_face->prefix;
+  is_v6 = hicn_buffer_is_v6 (b);
+  name = &hicn_get_buffer (b)->name;
+  if (PREDICT_TRUE (!is_v6 && ip46_address_is_ip4 (&prefix->fp_addr)))
     {
-      match_res = match_ip4_name ((u32 *) &(ptr[12]), prefix);
+      match_res = match_ip4_name (&name->prefix.ip4.as_u32, prefix);
     }
-  else if (PREDICT_TRUE (v == 0x60 && !ip46_address_is_ip4 (&prefix->fp_addr)))
+  else if (PREDICT_TRUE (is_v6 && !ip46_address_is_ip4 (&prefix->fp_addr)))
     {
-      match_res = match_ip6_name (&(ptr[8]), prefix);
+      match_res = match_ip6_name (name->prefix.ip6.as_u8, prefix);
     }
 
-  return match_res ? HICN_FACE_PROD_NEXT_DATA_IP4 + (v == 0x60) :
-                          HICN_FACE_PROD_NEXT_ERROR_DROP;
+  // 4 - if match found, forward data to next hicn node
+  return match_res ? HICN_FACE_PROD_NEXT_PCS : HICN_FACE_PROD_NEXT_ERROR_DROP;
 }
 
 static_always_inline void
@@ -137,6 +158,7 @@ hicn_face_prod_input_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
   u32 n_left_from, *from, *to_next;
   hicn_face_prod_next_t next_index;
   vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
+  u32 thread_index = vm->thread_index;
 
   from = vlib_frame_vector_args (frame);
   n_left_from = frame->n_vectors;
@@ -152,22 +174,28 @@ hicn_face_prod_input_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
          vlib_buffer_t *b0, *b1, *b2, *b3;
          hicn_buffer_t *hicnb0, *hicnb1, *hicnb2, *hicnb3;
          u32 bi0, bi1, bi2, bi3;
-         hicn_face_prod_state_t *prod_face0 = NULL;
-         hicn_face_prod_state_t *prod_face1 = NULL;
-         hicn_face_prod_state_t *prod_face2 = NULL;
-         hicn_face_prod_state_t *prod_face3 = NULL;
          u32 next0, next1, next2, next3;
 
+         // Prefetch next iteration
          {
            vlib_buffer_t *b4, *b5, *b6, *b7;
            b4 = vlib_get_buffer (vm, from[4]);
            b5 = vlib_get_buffer (vm, from[5]);
            b6 = vlib_get_buffer (vm, from[6]);
            b7 = vlib_get_buffer (vm, from[7]);
-           CLIB_PREFETCH (b4, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (b5, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (b6, CLIB_CACHE_LINE_BYTES, STORE);
-           CLIB_PREFETCH (b7, CLIB_CACHE_LINE_BYTES, STORE);
+           CLIB_PREFETCH (b4, 2 * CLIB_CACHE_LINE_BYTES, WRITE);
+           CLIB_PREFETCH (b5, 2 * CLIB_CACHE_LINE_BYTES, WRITE);
+           CLIB_PREFETCH (b6, 2 * CLIB_CACHE_LINE_BYTES, WRITE);
+           CLIB_PREFETCH (b7, 2 * CLIB_CACHE_LINE_BYTES, WRITE);
+
+           CLIB_PREFETCH (vlib_buffer_get_current (b4),
+                          2 * CLIB_CACHE_LINE_BYTES, WRITE);
+           CLIB_PREFETCH (vlib_buffer_get_current (b5),
+                          2 * CLIB_CACHE_LINE_BYTES, WRITE);
+           CLIB_PREFETCH (vlib_buffer_get_current (b6),
+                          2 * CLIB_CACHE_LINE_BYTES, WRITE);
+           CLIB_PREFETCH (vlib_buffer_get_current (b7),
+                          2 * CLIB_CACHE_LINE_BYTES, WRITE);
          }
 
          bi0 = from[0];
@@ -200,31 +228,39 @@ hicn_face_prod_input_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
          hicnb2->flags = HICN_FACE_FLAGS_DEFAULT;
          hicnb3->flags = HICN_FACE_FLAGS_DEFAULT;
 
-         prod_face0 = &face_state_vec[vnet_buffer (b0)->sw_if_index[VLIB_RX]];
-         prod_face1 = &face_state_vec[vnet_buffer (b1)->sw_if_index[VLIB_RX]];
-         prod_face2 = &face_state_vec[vnet_buffer (b2)->sw_if_index[VLIB_RX]];
-         prod_face3 = &face_state_vec[vnet_buffer (b3)->sw_if_index[VLIB_RX]];
-
-         vnet_buffer (b0)->ip.adj_index[VLIB_RX] =
-           face_state_vec[vnet_buffer (b0)->sw_if_index[VLIB_RX]].adj_index;
-         vnet_buffer (b1)->ip.adj_index[VLIB_RX] =
-           face_state_vec[vnet_buffer (b1)->sw_if_index[VLIB_RX]].adj_index;
-         vnet_buffer (b2)->ip.adj_index[VLIB_RX] =
-           face_state_vec[vnet_buffer (b2)->sw_if_index[VLIB_RX]].adj_index;
-         vnet_buffer (b3)->ip.adj_index[VLIB_RX] =
-           face_state_vec[vnet_buffer (b3)->sw_if_index[VLIB_RX]].adj_index;
-
-         next0 =
-           hicn_face_prod_next_from_data_hdr (node, b0, &prod_face0->prefix);
-         next1 =
-           hicn_face_prod_next_from_data_hdr (node, b1, &prod_face1->prefix);
-         next2 =
-           hicn_face_prod_next_from_data_hdr (node, b2, &prod_face2->prefix);
-         next3 =
-           hicn_face_prod_next_from_data_hdr (node, b3, &prod_face3->prefix);
+         // parse packets and get next node
+         next0 = hicn_face_prod_next_from_data_hdr (b0);
+         next1 = hicn_face_prod_next_from_data_hdr (b1);
+         next2 = hicn_face_prod_next_from_data_hdr (b2);
+         next3 = hicn_face_prod_next_from_data_hdr (b3);
          stats.pkts_data_count += 4;
 
-         /* trace */
+         // counters
+         vlib_increment_combined_counter (
+           &counters[hicnb0->face_id * HICN_N_COUNTER], thread_index,
+           HICN_FACE_COUNTERS_DATA_RX, 1,
+           vlib_buffer_length_in_chain (vm, b0));
+         stats.pkts_data_count += 1;
+
+         vlib_increment_combined_counter (
+           &counters[hicnb1->face_id * HICN_N_COUNTER], thread_index,
+           HICN_FACE_COUNTERS_DATA_RX, 1,
+           vlib_buffer_length_in_chain (vm, b0));
+         stats.pkts_data_count += 1;
+
+         vlib_increment_combined_counter (
+           &counters[hicnb2->face_id * HICN_N_COUNTER], thread_index,
+           HICN_FACE_COUNTERS_DATA_RX, 1,
+           vlib_buffer_length_in_chain (vm, b0));
+         stats.pkts_data_count += 1;
+
+         vlib_increment_combined_counter (
+           &counters[hicnb3->face_id * HICN_N_COUNTER], thread_index,
+           HICN_FACE_COUNTERS_DATA_RX, 1,
+           vlib_buffer_length_in_chain (vm, b0));
+         stats.pkts_data_count += 1;
+
+         // trace
          hicn_face_prod_trace_buffer (
            vm, node, vnet_buffer (b0)->sw_if_index[VLIB_RX], b0, next0);
          hicn_face_prod_trace_buffer (
@@ -234,7 +270,7 @@ hicn_face_prod_input_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
          hicn_face_prod_trace_buffer (
            vm, node, vnet_buffer (b3)->sw_if_index[VLIB_RX], b3, next3);
 
-         /* enqueue */
+         // enqueue
          vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
                                           n_left_to_next, bi0, bi1, bi2, bi3,
                                           next0, next1, next2, next3);
@@ -246,8 +282,7 @@ hicn_face_prod_input_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
        {
          vlib_buffer_t *b0;
          hicn_buffer_t *hicnb0;
-         u32 bi0, swif;
-         hicn_face_prod_state_t *prod_face = NULL;
+         u32 bi0;
          u32 next0;
 
          if (n_left_from > 1)
@@ -267,15 +302,17 @@ hicn_face_prod_input_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
          b0 = vlib_get_buffer (vm, bi0);
          hicnb0 = hicn_get_buffer (b0);
          hicnb0->flags = HICN_FACE_FLAGS_DEFAULT;
-         swif = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-         prod_face = &face_state_vec[swif];
 
-         next0 =
-           hicn_face_prod_next_from_data_hdr (node, b0, &prod_face->prefix);
-         vnet_buffer (b0)->ip.adj_index[VLIB_RX] =
-           face_state_vec[swif].adj_index;
+         next0 = hicn_face_prod_next_from_data_hdr (b0);
          stats.pkts_data_count++;
 
+         // counters
+         vlib_increment_combined_counter (
+           &counters[hicnb0->face_id * HICN_N_COUNTER], thread_index,
+           HICN_FACE_COUNTERS_DATA_RX, 1,
+           vlib_buffer_length_in_chain (vm, b0));
+         stats.pkts_data_count += 1;
+
          /* trace */
          hicn_face_prod_trace_buffer (
            vm, node, vnet_buffer (b0)->sw_if_index[VLIB_RX], b0, next0);
@@ -310,8 +347,7 @@ VLIB_REGISTER_NODE(hicn_face_prod_input_node) =
   .n_next_nodes = HICN_FACE_PROD_N_NEXT,
   .next_nodes =
   {
-    [HICN_FACE_PROD_NEXT_DATA_IP4] = "hicn4-face-input",
-    [HICN_FACE_PROD_NEXT_DATA_IP6] = "hicn6-face-input",
+    [HICN_FACE_PROD_NEXT_PCS] = "hicn-data-pcslookup",
     [HICN_FACE_PROD_NEXT_ERROR_DROP] = "error-drop",
   },
 };
@@ -320,4 +356,4 @@ VLIB_REGISTER_NODE(hicn_face_prod_input_node) =
  * fd.io coding-style-patch-verification: ON
  *
  * Local Variables: eval: (c-set-style "gnu") End:
- */
+ */
\ No newline at end of file
index 854fd81..4ee1c28 100644 (file)
@@ -62,16 +62,12 @@ mhash_t hicn_face_hashtb;
 const static char *const hicn_face6_nodes[] = {
   "hicn6-face-output", // this is the name you give your node in
                        // VLIB_REGISTER_NODE
-  "hicn6-iface-output", // this is the name you give your node in
-                       // VLIB_REGISTER_NODE
   NULL,
 };
 
 const static char *const hicn_face4_nodes[] = {
   "hicn4-face-output", // this is the name you give your node in
                        // VLIB_REGISTER_NODE
-  "hicn4-iface-output", // this is the name you give your node in
-                       // VLIB_REGISTER_NODE
   NULL,
 };
 
@@ -304,7 +300,7 @@ hicn_iface_to_face (hicn_face_t *face, const dpo_id_t *dpo)
  */
 int
 hicn_face_add (const dpo_id_t *dpo_nh, ip46_address_t *nat_address, int sw_if,
-              hicn_face_id_t *pfaceid, u8 is_app_prod)
+              hicn_face_id_t *pfaceid)
 {
 
   hicn_face_flags_t flags = (hicn_face_flags_t) 0;
index 39505c9..e4b759b 100644 (file)
@@ -27,6 +27,8 @@
 
 #include <vpp_plugins/hicn/error.h>
 
+#include "face_flags.h"
+#include "../hicn_buffer_flags.h"
 #include "../udp_tunnels/udp_tunnel.h"
 #include "../hicn_logging.h"
 
@@ -117,40 +119,8 @@ typedef struct __attribute__ ((packed)) hicn_face_s
 /* Pool of faces */
 extern hicn_face_t *hicn_dpoi_face_pool;
 
-/* Flags */
-/* A face is complete and it stores all the information. A iface lacks of the
-   adj index, therefore sending a packet through a iface require a lookup in
-   the FIB. */
-#define HICN_FACE_FLAGS_DEFAULT 0x00
-#define HICN_FACE_FLAGS_FACE   0x01
-#define HICN_FACE_FLAGS_IFACE  0x02
-#define HICN_FACE_FLAGS_APPFACE_PROD                                          \
-  0x04 /* Currently only IP face can be appface */
-#define HICN_FACE_FLAGS_APPFACE_CONS                                          \
-  0x08 /* Currently only IP face can be appface */
-#define HICN_FACE_FLAGS_DELETED 0x10
-#define HICN_FACE_FLAGS_UDP    0x20
-
 #define HICN_FACE_NULL (hicn_face_id_t) ~0
 
-#define HICN_FACE_FLAGS_APPFACE_PROD_BIT 2
-#define HICN_FACE_FLAGS_APPFACE_CONS_BIT 3
-
-#define HICN_BUFFER_FLAGS_DEFAULT         0x00
-#define HICN_BUFFER_FLAGS_NEW_FACE        0x02
-#define HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL 0x04
-#define HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL 0x08
-
-STATIC_ASSERT ((1 << HICN_FACE_FLAGS_APPFACE_PROD_BIT) ==
-                HICN_FACE_FLAGS_APPFACE_PROD,
-              "HICN_FACE_FLAGS_APPFACE_PROD_BIT and  "
-              "HICN_FACE_FLAGS_APPFACE_PROD must correspond");
-
-STATIC_ASSERT ((1 << HICN_FACE_FLAGS_APPFACE_CONS_BIT) ==
-                HICN_FACE_FLAGS_APPFACE_CONS,
-              "HICN_FACE_FLAGS_APPFACE_CONS_BIT and  "
-              "HICN_FACE_FLAGS_APPFACE_CONS must correspond");
-
 /**
  * @brief Definition of the virtual functin table for an hICN FACE DPO.
  */
@@ -484,7 +454,7 @@ hicn_face_get_with_dpo (const ip46_address_t *addr, u32 sw_if,
  * reachable ip address, otherwise HICN_ERROR_NONE
  */
 int hicn_face_add (const dpo_id_t *dpo_nh, ip46_address_t *nat_address,
-                  int sw_if, hicn_face_id_t *pfaceid, u8 is_app_prod);
+                  int sw_if, hicn_face_id_t *pfaceid);
 
 /**
  * @brief Create a new incomplete face ip. (Meant to be used by the data plane)
@@ -497,7 +467,7 @@ int hicn_face_add (const dpo_id_t *dpo_nh, ip46_address_t *nat_address,
  * reachable ip address, otherwise HICN_ERROR_NONE
  */
 always_inline void
-hicn_iface_add (ip46_address_t *nat_address, int sw_if,
+hicn_iface_add (const ip46_address_t *nat_address, int sw_if,
                hicn_face_id_t *pfaceid, u32 adj_index, u8 flags)
 {
   hicn_face_t *face;
@@ -615,7 +585,6 @@ hicn_face_ip4_add_and_lock (hicn_face_id_t *index, u8 *hicnb_flags,
       *hicnb_flags |= HICN_BUFFER_FLAGS_NEW_FACE;
 
       *index = idx;
-      return ret;
     }
   else
     {
@@ -623,15 +592,10 @@ hicn_face_ip4_add_and_lock (hicn_face_id_t *index, u8 *hicnb_flags,
       hicn_face_id_t face_id = hicn_dpoi_get_index (face);
       hicn_face_unlock_with_id (face_id);
       ret = HICN_ERROR_FACE_ALREADY_CREATED;
+      *index = hicn_dpoi_get_index (face);
+      *hicnb_flags = HICN_BUFFER_FLAGS_DEFAULT;
     }
 
-  /* Code replicated on purpose */
-  *hicnb_flags = HICN_BUFFER_FLAGS_DEFAULT;
-  *hicnb_flags |= (face->flags & HICN_FACE_FLAGS_APPFACE_PROD) >>
-                 HICN_FACE_FLAGS_APPFACE_PROD_BIT;
-
-  *index = hicn_dpoi_get_index (face);
-
   return ret;
 }
 
@@ -676,7 +640,7 @@ hicn_face_ip6_add_and_lock (hicn_face_id_t *index, u8 *hicnb_flags,
 
   /*All (complete) faces are indexed by remote addess as well */
   /* if the face exists, it adds a lock */
-  hicn_face_t *face = hicn_face_get ((ip46_address_t *) nat_addr, sw_if,
+  hicn_face_t *face = hicn_face_get ((const ip46_address_t *) nat_addr, sw_if,
                                     &hicn_face_hashtb, adj_index);
 
   if (face == NULL)
@@ -684,8 +648,8 @@ hicn_face_ip6_add_and_lock (hicn_face_id_t *index, u8 *hicnb_flags,
       hicn_face_id_t idx;
       u8 face_flags = 0;
 
-      hicn_iface_add ((ip46_address_t *) nat_addr, sw_if, &idx, adj_index,
-                     face_flags);
+      hicn_iface_add ((const ip46_address_t *) nat_addr, sw_if, &idx,
+                     adj_index, face_flags);
 
       face = hicn_dpoi_get_from_idx (idx);
 
@@ -712,12 +676,8 @@ hicn_face_ip6_add_and_lock (hicn_face_id_t *index, u8 *hicnb_flags,
       adj_nbr_walk (face->sw_if, FIB_PROTOCOL_IP6, hicn6_iface_adj_walk_cb,
                    face);
 
-      *hicnb_flags = HICN_BUFFER_FLAGS_DEFAULT;
-      *hicnb_flags |= HICN_BUFFER_FLAGS_NEW_FACE;
-
+      *hicnb_flags = HICN_BUFFER_FLAGS_NEW_FACE;
       *index = idx;
-
-      return ret;
     }
   else
     {
@@ -725,15 +685,10 @@ hicn_face_ip6_add_and_lock (hicn_face_id_t *index, u8 *hicnb_flags,
       hicn_face_id_t face_id = hicn_dpoi_get_index (face);
       hicn_face_unlock_with_id (face_id);
       ret = HICN_ERROR_FACE_ALREADY_CREATED;
+      *hicnb_flags = HICN_BUFFER_FLAGS_DEFAULT;
+      *index = hicn_dpoi_get_index (face);
     }
 
-  /* Code replicated on purpose */
-  *hicnb_flags = HICN_BUFFER_FLAGS_DEFAULT;
-  *hicnb_flags |= (face->flags & HICN_FACE_FLAGS_APPFACE_PROD) >>
-                 HICN_FACE_FLAGS_APPFACE_PROD_BIT;
-
-  *index = hicn_dpoi_get_index (face);
-
   return ret;
 }
 
diff --git a/hicn-plugin/src/faces/face_flags.h b/hicn-plugin/src/faces/face_flags.h
new file mode 100644 (file)
index 0000000..61dee54
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __HICN_FACE_FLAGS_H__
+#define __HICN_FACE_FLAGS_H__
+
+/* Flags */
+/* A face is complete and it stores all the information. A iface lacks of the
+   adj index, therefore sending a packet through a iface require a lookup in
+   the FIB. */
+#define foreach_face_flag                                                     \
+  _ (0, FACE, "face")                                                         \
+  _ (1, IFACE, "iface")                                                       \
+  _ (2, APPFACE_PROD, "face is consumer face")                                \
+  _ (3, APPFACE_CONS, "face is consumer face")                                \
+  _ (4, DELETED, "face is deleted")                                           \
+  _ (5, UDP, "face is udp")
+
+enum
+{
+  HICN_FACE_FLAGS_DEFAULT = 0,
+#define _(a, b, c) HICN_FACE_FLAGS_##b = (1 << a),
+  foreach_face_flag
+#undef _
+};
+
+#endif /* __HICN_FACE_FLAGS_H__ */
\ No newline at end of file
index dc9bfff..6dedbe1 100644 (file)
@@ -56,6 +56,7 @@ typedef struct
   u32 next_index;
   u32 sw_if_index;
   u8 pkt_type;
+  hicn_error_t error;
   u8 packet_data[60];
 } hicn4_face_input_trace_t;
 
@@ -73,6 +74,7 @@ typedef struct
   u32 next_index;
   u32 sw_if_index;
   u8 pkt_type;
+  hicn_error_t error;
   u8 packet_data[60];
 } hicn6_face_input_trace_t;
 
@@ -86,8 +88,9 @@ typedef enum
 
 #define NEXT_MAPME_IP4 HICN4_FACE_INPUT_NEXT_MAPME
 #define NEXT_MAPME_IP6 HICN6_FACE_INPUT_NEXT_MAPME
-#define NEXT_DATA_IP4  HICN4_FACE_INPUT_NEXT_DATA
-#define NEXT_DATA_IP6  HICN6_FACE_INPUT_NEXT_DATA
+
+#define NEXT_DATA_IP4 HICN4_FACE_INPUT_NEXT_DATA
+#define NEXT_DATA_IP6 HICN6_FACE_INPUT_NEXT_DATA
 
 #define NEXT_ERROR_DROP_IP4 HICN4_FACE_INPUT_NEXT_ERROR_DROP
 #define NEXT_ERROR_DROP_IP6 HICN6_FACE_INPUT_NEXT_ERROR_DROP
@@ -110,10 +113,11 @@ typedef enum
       vlib_buffer_t *b0;                                                      \
       u32 bi0, sw_if0;                                                        \
       u32 next0 = NEXT_ERROR_DROP_IP##ipv;                                    \
+      u8 is_icmp0;                                                            \
       IP_HEADER_##ipv *ip_hdr = NULL;                                         \
       hicn_buffer_t *hicnb0;                                                  \
       int from_tunnel0;                                                       \
-      int ret0;                                                               \
+      int ret0 = HICN_ERROR_NONE;                                             \
       /* Prefetch for next iteration. */                                      \
       if (n_left_from > 1)                                                    \
        {                                                                     \
@@ -134,23 +138,35 @@ typedef enum
       hicnb0 = hicn_get_buffer (b0);                                          \
       ip_hdr = (IP_HEADER_##ipv *) vlib_buffer_get_current (b0);              \
                                                                               \
-      u8 is_icmp = ip_hdr->protocol == IPPROTO_ICMPV##ipv;                    \
-                                                                              \
-      from_tunnel0 =                                                          \
-       (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL ||                \
-        hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0;             \
-      sw_if0 = (from_tunnel0) * ~0 +                                          \
-              (1 - from_tunnel0) * vnet_buffer (b0)->sw_if_index[VLIB_RX];   \
-                                                                              \
-      ret0 = hicn_face_ip##ipv##_add_and_lock (                               \
-       &hicnb0->face_id, &hicnb0->flags, &ip_hdr->dst_address, sw_if0,       \
-       vnet_buffer (b0)->ip.adj_index[VLIB_RX],                              \
-       /* Should not be used */ ~0);                                         \
-      /* Make sure the face is not created here */                            \
-      ASSERT (ret0 == HICN_ERROR_FACE_ALREADY_CREATED);                       \
+      /* Parse packet and cache useful info in opaque2 */                     \
+      ret0 = hicn_data_parse_pkt (b0);                                        \
+      is_icmp0 = ret0 == HICN_ERROR_PARSER_MAPME_PACKET;                      \
+      ret0 = (ret0 == HICN_ERROR_NONE) ||                                     \
+            (ret0 == HICN_ERROR_PARSER_MAPME_PACKET);                        \
                                                                               \
-      next0 =                                                                 \
-       is_icmp * NEXT_MAPME_IP##ipv + (1 - is_icmp) * NEXT_DATA_IP##ipv;     \
+      /* If parsing is ok, send packet to next node */                        \
+      if (PREDICT_FALSE (!ret0))                                              \
+       {                                                                     \
+         next0 = HICN##ipv##_FACE_INPUT_NEXT_ERROR_DROP;                     \
+       }                                                                     \
+      else                                                                    \
+       {                                                                     \
+         next0 = is_icmp0 * NEXT_MAPME_IP##ipv +                             \
+                 (1 - is_icmp0) * NEXT_DATA_IP##ipv;                         \
+         from_tunnel0 =                                                      \
+           (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL ||            \
+            hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0;         \
+         sw_if0 =                                                            \
+           (from_tunnel0) * ~0 +                                             \
+           (1 - from_tunnel0) * vnet_buffer (b0)->sw_if_index[VLIB_RX];      \
+                                                                              \
+         ret0 = hicn_face_ip##ipv##_add_and_lock (                           \
+           &hicnb0->face_id, &hicnb0->flags, &ip_hdr->dst_address, sw_if0,   \
+           vnet_buffer (b0)->ip.adj_index[VLIB_RX],                          \
+           /* Should not be used */ ~0);                                     \
+         /* Make sure the face is not created here */                        \
+         ASSERT (ret0 == HICN_ERROR_FACE_ALREADY_CREATED);                   \
+       }                                                                     \
                                                                               \
       vlib_increment_combined_counter (                                       \
        &counters[hicnb0->face_id * HICN_N_COUNTER], thread_index,            \
@@ -162,8 +178,9 @@ typedef enum
        {                                                                     \
          TRACE_INPUT_PKT_IP##ipv *t =                                        \
            vlib_add_trace (vm, node, b0, sizeof (*t));                       \
-         t->pkt_type = HICN_PKT_TYPE_INTEREST;                               \
+         t->pkt_type = HICN_PACKET_TYPE_INTEREST;                            \
          t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];            \
+         t->error = ret0;                                                    \
          t->next_index = next0;                                              \
          clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0),     \
                            sizeof (t->packet_data));                         \
@@ -182,6 +199,7 @@ typedef enum
       u32 bi0, bi1, sw_if0, sw_if1;                                           \
       u32 next0 = NEXT_ERROR_DROP_IP##ipv;                                    \
       u32 next1 = NEXT_ERROR_DROP_IP##ipv;                                    \
+      u8 is_icmp0, is_icmp1;                                                  \
       IP_HEADER_##ipv *ip_hdr0 = NULL;                                        \
       IP_HEADER_##ipv *ip_hdr1 = NULL;                                        \
       hicn_buffer_t *hicnb0;                                                  \
@@ -215,40 +233,95 @@ typedef enum
       ip_hdr0 = (IP_HEADER_##ipv *) vlib_buffer_get_current (b0);             \
       ip_hdr1 = (IP_HEADER_##ipv *) vlib_buffer_get_current (b1);             \
                                                                               \
-      u8 is_icmp0 = ip_hdr0->protocol == IPPROTO_ICMPV##ipv;                  \
-      u8 is_icmp1 = ip_hdr1->protocol == IPPROTO_ICMPV##ipv;                  \
-                                                                              \
-      from_tunnel0 =                                                          \
-       (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL ||                \
-        hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0;             \
-      sw_if0 = (from_tunnel0) * ~0 +                                          \
-              (1 - from_tunnel0) * vnet_buffer (b0)->sw_if_index[VLIB_RX];   \
-                                                                              \
-      ret0 = hicn_face_ip##ipv##_add_and_lock (                               \
-       &hicnb0->face_id, &hicnb0->flags, &ip_hdr0->dst_address, sw_if0,      \
-       vnet_buffer (b0)->ip.adj_index[VLIB_RX],                              \
-       /* Should not be used */ ~0);                                         \
-      /* Make sure the face is not created here */                            \
-      ASSERT (ret0 == HICN_ERROR_FACE_ALREADY_CREATED);                       \
-                                                                              \
-      from_tunnel1 =                                                          \
-       (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL ||                \
-        hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0;             \
-      sw_if1 = (from_tunnel1) * ~0 +                                          \
-              (1 - from_tunnel1) * vnet_buffer (b1)->sw_if_index[VLIB_RX];   \
-                                                                              \
-      ret1 = hicn_face_ip##ipv##_add_and_lock (                               \
-       &hicnb1->face_id, &hicnb1->flags, &ip_hdr1->dst_address, sw_if1,      \
-       vnet_buffer (b1)->ip.adj_index[VLIB_RX],                              \
-       /* Should not be used */ ~0);                                         \
-      /* Make sure the face is not created here */                            \
-      ASSERT (ret1 == HICN_ERROR_FACE_ALREADY_CREATED);                       \
-                                                                              \
-      next0 =                                                                 \
-       is_icmp0 * NEXT_MAPME_IP##ipv + (1 - is_icmp0) * NEXT_DATA_IP##ipv;   \
-                                                                              \
-      next1 =                                                                 \
-       is_icmp1 * NEXT_MAPME_IP##ipv + (1 - is_icmp1) * NEXT_DATA_IP##ipv;   \
+      /* Parse packet and cache useful info in opaque2 */                     \
+      /* Parse packet and cache useful info in opaque2 */                     \
+      ret0 = hicn_data_parse_pkt (b0);                                        \
+      ret1 = hicn_data_parse_pkt (b1);                                        \
+      is_icmp0 = ret0 == HICN_ERROR_PARSER_MAPME_PACKET;                      \
+      is_icmp1 = ret1 == HICN_ERROR_PARSER_MAPME_PACKET;                      \
+      ret0 = (ret0 == HICN_ERROR_NONE) ||                                     \
+            (ret0 == HICN_ERROR_PARSER_MAPME_PACKET);                        \
+      ret1 = (ret1 == HICN_ERROR_NONE) ||                                     \
+            (ret1 == HICN_ERROR_PARSER_MAPME_PACKET);                        \
+      if (PREDICT_TRUE (ret0 && ret1))                                        \
+       {                                                                     \
+         next0 = is_icmp0 * NEXT_MAPME_IP##ipv +                             \
+                 (1 - is_icmp0) * NEXT_DATA_IP##ipv;                         \
+                                                                              \
+         next1 = is_icmp1 * NEXT_MAPME_IP##ipv +                             \
+                 (1 - is_icmp1) * NEXT_DATA_IP##ipv;                         \
+                                                                              \
+         from_tunnel0 =                                                      \
+           (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL ||            \
+            hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0;         \
+         sw_if0 =                                                            \
+           (from_tunnel0) * ~0 +                                             \
+           (1 - from_tunnel0) * vnet_buffer (b0)->sw_if_index[VLIB_RX];      \
+                                                                              \
+         ret0 = hicn_face_ip##ipv##_add_and_lock (                           \
+           &hicnb0->face_id, &hicnb0->flags, &ip_hdr0->dst_address, sw_if0,  \
+           vnet_buffer (b0)->ip.adj_index[VLIB_RX],                          \
+           /* Should not be used */ ~0);                                     \
+         /* Make sure the face is not created here */                        \
+         ASSERT (ret0 == HICN_ERROR_FACE_ALREADY_CREATED);                   \
+                                                                              \
+         from_tunnel1 =                                                      \
+           (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL ||            \
+            hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0;         \
+         sw_if1 =                                                            \
+           (from_tunnel1) * ~0 +                                             \
+           (1 - from_tunnel1) * vnet_buffer (b1)->sw_if_index[VLIB_RX];      \
+                                                                              \
+         ret1 = hicn_face_ip##ipv##_add_and_lock (                           \
+           &hicnb1->face_id, &hicnb1->flags, &ip_hdr1->dst_address, sw_if1,  \
+           vnet_buffer (b1)->ip.adj_index[VLIB_RX],                          \
+           /* Should not be used */ ~0);                                     \
+         /* Make sure the face is not created here */                        \
+         ASSERT (ret1 == HICN_ERROR_FACE_ALREADY_CREATED);                   \
+       }                                                                     \
+      else if (ret0 && !ret1)                                                 \
+       {                                                                     \
+         next1 = HICN##ipv##_FACE_INPUT_NEXT_ERROR_DROP;                     \
+         from_tunnel0 =                                                      \
+           (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL ||            \
+            hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0;         \
+         sw_if0 =                                                            \
+           (from_tunnel0) * ~0 +                                             \
+           (1 - from_tunnel0) * vnet_buffer (b0)->sw_if_index[VLIB_RX];      \
+                                                                              \
+         ret0 = hicn_face_ip##ipv##_add_and_lock (                           \
+           &hicnb0->face_id, &hicnb0->flags, &ip_hdr0->dst_address, sw_if0,  \
+           vnet_buffer (b0)->ip.adj_index[VLIB_RX],                          \
+           /* Should not be used */ ~0);                                     \
+         /* Make sure the face is not created here */                        \
+         ASSERT (ret0 == HICN_ERROR_FACE_ALREADY_CREATED);                   \
+         next0 = is_icmp0 * NEXT_MAPME_IP##ipv +                             \
+                 (1 - is_icmp0) * NEXT_DATA_IP##ipv;                         \
+       }                                                                     \
+      else if (!ret0 && ret1)                                                 \
+       {                                                                     \
+         next0 = HICN##ipv##_FACE_INPUT_NEXT_ERROR_DROP;                     \
+         from_tunnel1 =                                                      \
+           (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL ||            \
+            hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0;         \
+         sw_if1 =                                                            \
+           (from_tunnel1) * ~0 +                                             \
+           (1 - from_tunnel1) * vnet_buffer (b1)->sw_if_index[VLIB_RX];      \
+                                                                              \
+         ret1 = hicn_face_ip##ipv##_add_and_lock (                           \
+           &hicnb1->face_id, &hicnb1->flags, &ip_hdr1->dst_address, sw_if1,  \
+           vnet_buffer (b1)->ip.adj_index[VLIB_RX],                          \
+           /* Should not be used */ ~0);                                     \
+         /* Make sure the face is not created here */                        \
+         ASSERT (ret1 == HICN_ERROR_FACE_ALREADY_CREATED);                   \
+         next1 = is_icmp1 * NEXT_MAPME_IP##ipv +                             \
+                 (1 - is_icmp1) * NEXT_DATA_IP##ipv;                         \
+       }                                                                     \
+      else                                                                    \
+       {                                                                     \
+         next0 = HICN##ipv##_FACE_INPUT_NEXT_ERROR_DROP;                     \
+         next1 = HICN##ipv##_FACE_INPUT_NEXT_ERROR_DROP;                     \
+       }                                                                     \
                                                                               \
       vlib_increment_combined_counter (                                       \
        &counters[hicnb0->face_id * HICN_N_COUNTER], thread_index,            \
@@ -265,8 +338,9 @@ typedef enum
        {                                                                     \
          TRACE_INPUT_PKT_IP##ipv *t =                                        \
            vlib_add_trace (vm, node, b0, sizeof (*t));                       \
-         t->pkt_type = HICN_PKT_TYPE_INTEREST;                               \
+         t->pkt_type = HICN_PACKET_TYPE_INTEREST;                            \
          t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];            \
+         t->error = ret0;                                                    \
          t->next_index = next0;                                              \
          clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0),     \
                            sizeof (t->packet_data));                         \
@@ -277,8 +351,9 @@ typedef enum
        {                                                                     \
          TRACE_INPUT_PKT_IP##ipv *t =                                        \
            vlib_add_trace (vm, node, b1, sizeof (*t));                       \
-         t->pkt_type = HICN_PKT_TYPE_INTEREST;                               \
+         t->pkt_type = HICN_PACKET_TYPE_INTEREST;                            \
          t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];            \
+         t->error = ret1;                                                    \
          t->next_index = next1;                                              \
          clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b1),     \
                            sizeof (t->packet_data));                         \
@@ -461,80 +536,6 @@ typedef enum
   HICN6_FACE_OUTPUT_N_NEXT,
 } hicn6_face_output_next_t;
 
-/* static_always_inline void */
-/* hicn_reply_probe_v4 (vlib_buffer_t * b, hicn_face_t * face) */
-/* { */
-/*   hicn_header_t *h0 = vlib_buffer_get_current (b); */
-/*   hicn_face_ip_t * face_ip = (hicn_face_ip_t *)(&face->data); */
-/*   h0->v4.ip.saddr = h0->v4.ip.daddr; */
-/*   h0->v4.ip.daddr = face_ip->local_addr.ip4; */
-/*   vnet_buffer (b)->sw_if_index[VLIB_RX] = face->shared.sw_if; */
-
-/*   u16 * dst_port_ptr = (u16 *)(((u8*)h0) + sizeof(ip4_header_t) +
- * sizeof(u16)); */
-/*   u16 dst_port = *dst_port_ptr; */
-/*   u16 * src_port_ptr = (u16 *)(((u8*)h0) + sizeof(ip4_header_t)); */
-
-/*   *dst_port_ptr = *src_port_ptr; */
-/*   *src_port_ptr = dst_port; */
-
-/*   hicn_type_t type = hicn_get_buffer (b)->type; */
-/*   hicn_ops_vft[type.l1]->set_lifetime (type, &h0->protocol, 0); */
-/* } */
-
-/* static_always_inline void */
-/* hicn_reply_probe_v6 (vlib_buffer_t * b, hicn_face_t * face) */
-/* { */
-/*   hicn_header_t *h0 = vlib_buffer_get_current (b); */
-/*   hicn_face_ip_t * face_ip = (hicn_face_ip_t *)(&face->data); */
-/*   h0->v6.ip.saddr = h0->v6.ip.daddr; */
-/*   h0->v6.ip.daddr = face_ip->local_addr.ip6; */
-/*   vnet_buffer (b)->sw_if_index[VLIB_RX] = face->shared.sw_if; */
-
-/*   u16 * dst_port_ptr = (u16 *)(((u8*)h0) + sizeof(ip6_header_t) +
- * sizeof(u16)); */
-/*   u16 dst_port = *dst_port_ptr; */
-/*   u16 * src_port_ptr = (u16 *)(((u8*)h0) + sizeof(ip6_header_t)); */
-
-/*   *dst_port_ptr = *src_port_ptr; */
-/*   *src_port_ptr = dst_port; */
-
-/*   hicn_type_t type = hicn_get_buffer (b)->type; */
-/*   hicn_ops_vft[type.l1]->set_lifetime (type, &h0->protocol, 0); */
-
-/* } */
-
-/* static_always_inline u32 */
-/* hicn_face_match_probe (vlib_buffer_t * b, hicn_face_t * face, u32 * next) */
-/* { */
-
-/*   u8 *ptr = vlib_buffer_get_current (b); */
-/*   u8 v = *ptr & 0xf0; */
-/*   u8 res = 0; */
-
-/*   if ( v == 0x40 ) */
-/*     { */
-/*       u16 * dst_port = (u16 *)(ptr + sizeof(ip4_header_t) + sizeof(u16)); */
-/*       if (*dst_port == clib_net_to_host_u16(DEFAULT_PROBING_PORT)) */
-/*         { */
-/*           hicn_reply_probe_v6(b, face); */
-/*           *next = HICN4_FACE_NEXT_ECHO_REPLY; */
-/*           res = 1; */
-/*         } */
-/*     } */
-/*   else if ( v == 0x60 ) */
-/*     { */
-/*       u16 * dst_port = (u16 *)(ptr + sizeof(ip6_header_t) + sizeof(u16)); */
-/*       if (*dst_port == clib_net_to_host_u16(DEFAULT_PROBING_PORT)) */
-/*         { */
-/*           hicn_reply_probe_v6(b, face); */
-/*           *next = HICN6_FACE_NEXT_ECHO_REPLY; */
-/*           res = 1; */
-/*         } */
-/*     } */
-/*   return res; */
-/* } */
-
 static inline void
 hicn_face_rewrite_interest (vlib_main_t *vm, vlib_buffer_t *b0,
                            hicn_face_t *face, u32 *next)
@@ -546,6 +547,9 @@ hicn_face_rewrite_interest (vlib_main_t *vm, vlib_buffer_t *b0,
 
   hicn_header_t *hicn = vlib_buffer_get_current (b0);
 
+  u8 is_v4 = ip46_address_is_ip4 (&face->nat_addr) &&
+            !ip6_address_is_loopback (&face->nat_addr.ip6);
+
   // hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
 
   ip46_address_t temp_addr;
@@ -553,11 +557,8 @@ hicn_face_rewrite_interest (vlib_main_t *vm, vlib_buffer_t *b0,
   hicn_type_t type = hicn_get_buffer (b0)->type;
   int ret = hicn_ops_vft[type.l1]->rewrite_interest (
     type, &hicn->protocol, &face->nat_addr, &temp_addr);
-
   if (ret == HICN_LIB_ERROR_REWRITE_CKSUM_REQUIRED)
     {
-      u8 is_v4 = ip46_address_is_ip4 (&face->nat_addr) &&
-                !ip6_address_is_loopback (&face->nat_addr.ip6);
       ensure_offload_flags (b0, is_v4);
     }
 
@@ -645,7 +646,7 @@ typedef struct
        {                                                                     \
          TRACE_OUTPUT_PKT_IP##ipv *t =                                       \
            vlib_add_trace (vm, node, b0, sizeof (*t));                       \
-         t->pkt_type = HICN_PKT_TYPE_INTEREST;                               \
+         t->pkt_type = HICN_PACKET_TYPE_INTEREST;                            \
          t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];            \
          t->next_index = next0;                                              \
          clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0),     \
@@ -724,7 +725,7 @@ typedef struct
        {                                                                     \
          TRACE_OUTPUT_PKT_IP##ipv *t =                                       \
            vlib_add_trace (vm, node, b0, sizeof (*t));                       \
-         t->pkt_type = HICN_PKT_TYPE_INTEREST;                               \
+         t->pkt_type = HICN_PACKET_TYPE_INTEREST;                            \
          t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];            \
          t->next_index = next0;                                              \
          clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0),     \
@@ -736,7 +737,7 @@ typedef struct
        {                                                                     \
          TRACE_OUTPUT_PKT_IP##ipv *t =                                       \
            vlib_add_trace (vm, node, b1, sizeof (*t));                       \
-         t->pkt_type = HICN_PKT_TYPE_INTEREST;                               \
+         t->pkt_type = HICN_PACKET_TYPE_INTEREST;                            \
          t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];            \
          t->next_index = next1;                                              \
          clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b1),     \
@@ -812,12 +813,7 @@ VLIB_REGISTER_NODE (hicn4_face_output_node) = {
   .type = VLIB_NODE_TYPE_INTERNAL,
   .n_errors = ARRAY_LEN (hicn4_face_output_error_strings),
   .error_strings = hicn4_face_output_error_strings,
-  .n_next_nodes = HICN4_FACE_OUTPUT_N_NEXT,
-  /* Reusing the list of nodes from lookup to be compatible with arp */
-  .next_nodes = { [HICN4_FACE_OUTPUT_NEXT_ERROR_DROP] = "error-drop",
-                 [HICN4_FACE_OUTPUT_NEXT_ECHO_REPLY] = "hicn4-face-input",
-                 [HICN4_FACE_OUTPUT_NEXT_UDP4_ENCAP] = "udp4-encap",
-                 [HICN4_FACE_OUTPUT_NEXT_UDP6_ENCAP] = "udp6-encap" }
+  .sibling_of = "ip4-lookup",
 };
 
 static uword
@@ -882,13 +878,7 @@ VLIB_REGISTER_NODE (hicn6_face_output_node) = {
   .type = VLIB_NODE_TYPE_INTERNAL,
   .n_errors = ARRAY_LEN (hicn6_face_output_error_strings),
   .error_strings = hicn6_face_output_error_strings,
-  .n_next_nodes = HICN6_FACE_OUTPUT_N_NEXT,
-  /* Reusing the list of nodes from lookup to be compatible with neighbour
-     discovery */
-  .next_nodes = { [HICN6_FACE_OUTPUT_NEXT_ERROR_DROP] = "error-drop",
-                 [HICN6_FACE_OUTPUT_NEXT_ECHO_REPLY] = "hicn6-face-input",
-                 [HICN6_FACE_OUTPUT_NEXT_UDP4_ENCAP] = "udp4-encap",
-                 [HICN6_FACE_OUTPUT_NEXT_UDP6_ENCAP] = "udp6-encap" }
+  .sibling_of = "ip6-lookup",
 };
 
 /*
@@ -897,4 +887,4 @@ VLIB_REGISTER_NODE (hicn6_face_output_node) = {
  * Local Variables:
  * eval: (c-set-style "gnu")
  * End:
- */
+ */
\ No newline at end of file
index 84205af..3b6634d 100644 (file)
@@ -52,6 +52,7 @@ typedef struct
   u32 next_index;
   u32 sw_if_index;
   u8 pkt_type;
+  hicn_error_t error;
   u8 packet_data[60];
 } hicn4_iface_input_trace_t;
 
@@ -69,6 +70,7 @@ typedef struct
   u32 next_index;
   u32 sw_if_index;
   u8 pkt_type;
+  hicn_error_t error;
   u8 packet_data[60];
 } hicn6_iface_input_trace_t;
 
@@ -86,33 +88,9 @@ typedef enum
 #define NEXT_INTEREST_IP4 HICN4_IFACE_INPUT_NEXT_INTEREST
 #define NEXT_INTEREST_IP6 HICN6_IFACE_INPUT_NEXT_INTEREST
 
-#define ADDRESS_IP4                                                           \
-  ip_interface_address_t *ia = 0;                                             \
-  ip4_address_t *local_address =                                              \
-    ip4_interface_first_address (&ip4_main, swif, &ia)
-#define ADDRESS_IP6                                                           \
-  ip6_address_t *local_address = ip6_interface_first_address (&ip6_main, swif)
-
-#define ADDRESSX2_IP4                                                         \
-  ip_interface_address_t *ia0, *ia1;                                          \
-  ia0 = ia1 = 0;                                                              \
-  ip4_address_t *local_address0 =                                             \
-    ip4_interface_first_address (&ip4_main, swif0, &ia0);                     \
-  ip4_address_t *local_address1 =                                             \
-    ip4_interface_first_address (&ip4_main, swif1, &ia1);
-
-#define ADDRESSX2_IP6                                                         \
-  ip6_address_t *local_address0 =                                             \
-    ip6_interface_first_address (&ip6_main, swif0);                           \
-  ip6_address_t *local_address1 =                                             \
-    ip6_interface_first_address (&ip6_main, swif1);
-
 #define DPO_ADD_LOCK_FACE_IP4 hicn_face_ip4_add_and_lock
 #define DPO_ADD_LOCK_FACE_IP6 hicn_face_ip6_add_and_lock
 
-//#define VLIB_EDGE_IP4 data_fwd_iface_ip4_vlib_edge
-//#define VLIB_EDGE_IP6 data_fwd_iface_ip6_vlib_edge
-
 #define IP_HEADER_4 ip4_header_t
 #define IP_HEADER_6 ip6_header_t
 
@@ -148,6 +126,7 @@ typedef enum
   HICN4_IFACE_OUTPUT_NEXT_LOOKUP,
   HICN4_IFACE_OUTPUT_NEXT_UDP4_ENCAP,
   HICN4_IFACE_OUTPUT_NEXT_UDP6_ENCAP,
+  HICN4_IFACE_OUTPUT_NEXT_PG,
   HICN4_IFACE_OUTPUT_N_NEXT,
 } hicn4_iface_output_next_t;
 
@@ -166,6 +145,7 @@ typedef enum
   HICN6_IFACE_OUTPUT_NEXT_LOOKUP,
   HICN6_IFACE_OUTPUT_NEXT_UDP4_ENCAP,
   HICN6_IFACE_OUTPUT_NEXT_UDP6_ENCAP,
+  HICN6_IFACE_OUTPUT_NEXT_PG,
   HICN6_IFACE_OUTPUT_N_NEXT,
 } hicn6_iface_output_next_t;
 
@@ -178,6 +158,9 @@ typedef enum
 #define NEXT_UDP_ENCAP_IP4 HICN4_IFACE_OUTPUT_NEXT_UDP4_ENCAP
 #define NEXT_UDP_ENCAP_IP6 HICN6_IFACE_OUTPUT_NEXT_UDP6_ENCAP
 
+#define NEXT_PG4 HICN4_IFACE_OUTPUT_NEXT_PG
+#define NEXT_PG6 HICN6_IFACE_OUTPUT_NEXT_PG
+
 #define HICN_REWRITE_DATA_IP4 hicn_rewrite_iface_data4
 #define HICN_REWRITE_DATA_IP6 hicn_rewrite_iface_data6
 
@@ -190,9 +173,11 @@ typedef enum
   do                                                                          \
     {                                                                         \
       vlib_buffer_t *b0;                                                      \
-      u32 bi0, next0, next_iface0, sw_if0;                                    \
+      u32 bi0, next0, next_iface0, sw_if0 = ~0;                               \
       IP_HEADER_##ipv *ip_hdr = NULL;                                         \
       hicn_buffer_t *hicnb0;                                                  \
+      int ret0 = HICN_ERROR_NONE;                                             \
+      u8 is_icmp0;                                                            \
       /* Prefetch for next iteration. */                                      \
       if (n_left_from > 1)                                                    \
        {                                                                     \
@@ -213,41 +198,55 @@ typedef enum
       hicnb0 = hicn_get_buffer (b0);                                          \
       ip_hdr = (IP_HEADER_##ipv *) vlib_buffer_get_current (b0);              \
                                                                               \
-      stats.pkts_interest_count += 1;                                         \
-                                                                              \
-      u8 is_icmp = ip_hdr->protocol == IPPROTO_ICMPV##ipv;                    \
-                                                                              \
-      next0 =                                                                 \
-       is_icmp * NEXT_MAPME_IP##ipv + (1 - is_icmp) * NEXT_INTEREST_IP##ipv; \
-                                                                              \
-      next_iface0 = NEXT_DATA_LOOKUP_IP##ipv;                                 \
-      sw_if0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];                        \
-                                                                              \
-      if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL &&               \
-         vnet_buffer (b0)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID)       \
+      /* Parse packet and cache useful info in opaque2 */                     \
+      ret0 = hicn_interest_parse_pkt (b0);                                    \
+      is_icmp0 = (ret0 == HICN_ERROR_PARSER_MAPME_PACKET);                    \
+      ret0 = (ret0 == HICN_ERROR_NONE) ||                                     \
+            (ret0 == HICN_ERROR_PARSER_MAPME_PACKET);                        \
+      if (PREDICT_FALSE (!ret0))                                              \
        {                                                                     \
-         next_iface0 = NEXT_UDP_ENCAP_IP4;                                   \
-         sw_if0 = ~0;                                                        \
+         next0 = HICN##ipv##_IFACE_INPUT_NEXT_ERROR_DROP;                    \
        }                                                                     \
-      else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL &&          \
-              vnet_buffer (b0)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID)  \
+      else                                                                    \
        {                                                                     \
-         next_iface0 = NEXT_UDP_ENCAP_IP6;                                   \
-         sw_if0 = ~0;                                                        \
+         next0 = is_icmp0 * NEXT_MAPME_IP##ipv +                             \
+                 (1 - is_icmp0) * NEXT_INTEREST_IP##ipv;                     \
+                                                                              \
+         next_iface0 = NEXT_DATA_LOOKUP_IP##ipv;                             \
+         sw_if0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];                    \
+                                                                              \
+         if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL &&           \
+             vnet_buffer (b0)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID)   \
+           {                                                                 \
+             next_iface0 = NEXT_UDP_ENCAP_IP4;                               \
+             sw_if0 = ~0;                                                    \
+           }                                                                 \
+         else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL &&      \
+                  vnet_buffer (b0)->ip.adj_index[VLIB_RX] !=                 \
+                    ADJ_INDEX_INVALID)                                       \
+           {                                                                 \
+             next_iface0 = NEXT_UDP_ENCAP_IP6;                               \
+             sw_if0 = ~0;                                                    \
+           }                                                                 \
+         else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_PG)                 \
+           {                                                                 \
+             next_iface0 = NEXT_PG##ipv;                                     \
+           }                                                                 \
+                                                                              \
+         DPO_ADD_LOCK_FACE_IP##ipv (                                         \
+           &(hicnb0->face_id), &hicnb0->flags, &(ip_hdr->src_address),       \
+           sw_if0, vnet_buffer (b0)->ip.adj_index[VLIB_RX], next_iface0);    \
        }                                                                     \
                                                                               \
-      DPO_ADD_LOCK_FACE_IP##ipv (                                             \
-       &(hicnb0->face_id), &hicnb0->flags, &(ip_hdr->src_address), sw_if0,   \
-       vnet_buffer (b0)->ip.adj_index[VLIB_RX], next_iface0);                \
-                                                                              \
       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&              \
                         (b0->flags & VLIB_BUFFER_IS_TRACED)))                \
        {                                                                     \
          TRACE_INPUT_PKT_IP##ipv *t =                                        \
            vlib_add_trace (vm, node, b0, sizeof (*t));                       \
-         t->pkt_type = HICN_PKT_TYPE_INTEREST;                               \
+         t->pkt_type = HICN_PACKET_TYPE_INTEREST;                            \
          t->sw_if_index = sw_if0;                                            \
          t->next_index = next0;                                              \
+         t->error = ret0;                                                    \
          clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0),     \
                            sizeof (t->packet_data));                         \
        }                                                                     \
@@ -267,9 +266,12 @@ typedef enum
   do                                                                          \
     {                                                                         \
       vlib_buffer_t *b0, *b1;                                                 \
-      u32 bi0, bi1, next0, next1, next_iface0, next_iface1, sw_if0, sw_if1;   \
+      u32 bi0, bi1, next0, next1;                                             \
+      u32 next_iface0, next_iface1, sw_if0 = ~0, sw_if1 = ~0;                 \
+      u8 is_icmp0, is_icmp1;                                                  \
       IP_HEADER_##ipv *ip_hdr0 = NULL;                                        \
       IP_HEADER_##ipv *ip_hdr1 = NULL;                                        \
+      int ret0 = HICN_ERROR_NONE, ret1 = HICN_ERROR_NONE;                     \
       hicn_buffer_t *hicnb0, *hicnb1;                                         \
                                                                               \
       /* Prefetch for next iteration. */                                      \
@@ -300,63 +302,149 @@ typedef enum
                                                                               \
       stats.pkts_interest_count += 2;                                         \
                                                                               \
-      u8 is_icmp0 = ip_hdr0->protocol == IPPROTO_ICMPV##ipv;                  \
-      u8 is_icmp1 = ip_hdr1->protocol == IPPROTO_ICMPV##ipv;                  \
-                                                                              \
-      next0 = is_icmp0 * NEXT_MAPME_IP##ipv +                                 \
-             (1 - is_icmp0) * NEXT_INTEREST_IP##ipv;                         \
-                                                                              \
-      next1 = is_icmp1 * NEXT_MAPME_IP##ipv +                                 \
-             (1 - is_icmp1) * NEXT_INTEREST_IP##ipv;                         \
-                                                                              \
-      next_iface0 = NEXT_DATA_LOOKUP_IP##ipv;                                 \
-      sw_if0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];                        \
-                                                                              \
-      if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL &&               \
-         vnet_buffer (b0)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID)       \
+      /* Parse packet and cache useful info in opaque2 */                     \
+      ret0 = hicn_interest_parse_pkt (b0);                                    \
+      ret1 = hicn_interest_parse_pkt (b1);                                    \
+      is_icmp0 = ret0 == HICN_ERROR_PARSER_MAPME_PACKET;                      \
+      is_icmp1 = ret1 == HICN_ERROR_PARSER_MAPME_PACKET;                      \
+      ret0 = (ret0 == HICN_ERROR_NONE) ||                                     \
+            (ret0 == HICN_ERROR_PARSER_MAPME_PACKET);                        \
+      ret1 = (ret1 == HICN_ERROR_NONE) ||                                     \
+            (ret1 == HICN_ERROR_PARSER_MAPME_PACKET);                        \
+                                                                              \
+      if (PREDICT_TRUE (ret0 && ret1))                                        \
        {                                                                     \
-         next_iface0 = NEXT_UDP_ENCAP_IP4;                                   \
-         sw_if0 = ~0;                                                        \
+         next0 = is_icmp0 * NEXT_MAPME_IP##ipv +                             \
+                 (1 - is_icmp0) * NEXT_INTEREST_IP##ipv;                     \
+                                                                              \
+         next1 = is_icmp1 * NEXT_MAPME_IP##ipv +                             \
+                 (1 - is_icmp1) * NEXT_INTEREST_IP##ipv;                     \
+                                                                              \
+         next_iface0 = NEXT_DATA_LOOKUP_IP##ipv;                             \
+         sw_if0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];                    \
+                                                                              \
+         if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL &&           \
+             vnet_buffer (b0)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID)   \
+           {                                                                 \
+             next_iface0 = NEXT_UDP_ENCAP_IP4;                               \
+             sw_if0 = ~0;                                                    \
+           }                                                                 \
+         else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL &&      \
+                  vnet_buffer (b0)->ip.adj_index[VLIB_RX] !=                 \
+                    ADJ_INDEX_INVALID)                                       \
+           {                                                                 \
+             next_iface0 = NEXT_UDP_ENCAP_IP6;                               \
+             sw_if0 = ~0;                                                    \
+           }                                                                 \
+         else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_PG)                 \
+           {                                                                 \
+             next_iface0 = NEXT_PG##ipv;                                     \
+           }                                                                 \
+                                                                              \
+         next_iface1 = NEXT_DATA_LOOKUP_IP##ipv;                             \
+         sw_if1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];                    \
+                                                                              \
+         if (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL &&           \
+             vnet_buffer (b1)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID)   \
+           {                                                                 \
+             next_iface1 = NEXT_UDP_ENCAP_IP4;                               \
+             sw_if1 = ~0;                                                    \
+           }                                                                 \
+         else if (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL &&      \
+                  vnet_buffer (b1)->ip.adj_index[VLIB_RX] !=                 \
+                    ADJ_INDEX_INVALID)                                       \
+           {                                                                 \
+             next_iface1 = NEXT_UDP_ENCAP_IP6;                               \
+             sw_if1 = ~0;                                                    \
+           }                                                                 \
+         else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_PG)                 \
+           {                                                                 \
+             next_iface1 = NEXT_PG##ipv;                                     \
+           }                                                                 \
+                                                                              \
+         DPO_ADD_LOCK_FACE_IP##ipv (                                         \
+           &(hicnb0->face_id), &hicnb0->flags, &(ip_hdr0->src_address),      \
+           sw_if0, vnet_buffer (b0)->ip.adj_index[VLIB_RX], next_iface0);    \
+                                                                              \
+         DPO_ADD_LOCK_FACE_IP##ipv (                                         \
+           &(hicnb1->face_id), &hicnb1->flags, &(ip_hdr1->src_address),      \
+           sw_if1, vnet_buffer (b1)->ip.adj_index[VLIB_RX], next_iface1);    \
        }                                                                     \
-      else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL &&          \
-              vnet_buffer (b0)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID)  \
+      else if (ret0 && !ret1)                                                 \
        {                                                                     \
-         next_iface0 = NEXT_UDP_ENCAP_IP6;                                   \
-         sw_if0 = ~0;                                                        \
+         next1 = HICN##ipv##_IFACE_INPUT_NEXT_ERROR_DROP;                    \
+         next0 = is_icmp0 * NEXT_MAPME_IP##ipv +                             \
+                 (1 - is_icmp0) * NEXT_INTEREST_IP##ipv;                     \
+         next_iface0 = NEXT_DATA_LOOKUP_IP##ipv;                             \
+         sw_if0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];                    \
+                                                                              \
+         if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL &&           \
+             vnet_buffer (b0)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID)   \
+           {                                                                 \
+             next_iface0 = NEXT_UDP_ENCAP_IP4;                               \
+             sw_if0 = ~0;                                                    \
+           }                                                                 \
+         else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL &&      \
+                  vnet_buffer (b0)->ip.adj_index[VLIB_RX] !=                 \
+                    ADJ_INDEX_INVALID)                                       \
+           {                                                                 \
+             next_iface0 = NEXT_UDP_ENCAP_IP6;                               \
+             sw_if0 = ~0;                                                    \
+           }                                                                 \
+         else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_PG)                 \
+           {                                                                 \
+             next_iface0 = NEXT_PG##ipv;                                     \
+           }                                                                 \
+                                                                              \
+         DPO_ADD_LOCK_FACE_IP##ipv (                                         \
+           &(hicnb0->face_id), &hicnb0->flags, &(ip_hdr0->src_address),      \
+           sw_if0, vnet_buffer (b0)->ip.adj_index[VLIB_RX], next_iface0);    \
        }                                                                     \
-                                                                              \
-      next_iface1 = NEXT_DATA_LOOKUP_IP##ipv;                                 \
-      sw_if1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];                        \
-                                                                              \
-      if (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL &&               \
-         vnet_buffer (b1)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID)       \
+      else if (!ret0 && ret1)                                                 \
        {                                                                     \
-         next_iface1 = NEXT_UDP_ENCAP_IP4;                                   \
-         sw_if1 = ~0;                                                        \
+         next0 = HICN##ipv##_IFACE_INPUT_NEXT_ERROR_DROP;                    \
+         next_iface1 = NEXT_DATA_LOOKUP_IP##ipv;                             \
+         sw_if1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];                    \
+         next1 = is_icmp1 * NEXT_MAPME_IP##ipv +                             \
+                 (1 - is_icmp1) * NEXT_INTEREST_IP##ipv;                     \
+                                                                              \
+         if (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL &&           \
+             vnet_buffer (b1)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID)   \
+           {                                                                 \
+             next_iface1 = NEXT_UDP_ENCAP_IP4;                               \
+             sw_if1 = ~0;                                                    \
+           }                                                                 \
+         else if (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL &&      \
+                  vnet_buffer (b1)->ip.adj_index[VLIB_RX] !=                 \
+                    ADJ_INDEX_INVALID)                                       \
+           {                                                                 \
+             next_iface1 = NEXT_UDP_ENCAP_IP6;                               \
+             sw_if1 = ~0;                                                    \
+           }                                                                 \
+         else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_PG)                 \
+           {                                                                 \
+             next_iface1 = NEXT_PG##ipv;                                     \
+           }                                                                 \
+                                                                              \
+         DPO_ADD_LOCK_FACE_IP##ipv (                                         \
+           &(hicnb1->face_id), &hicnb1->flags, &(ip_hdr1->src_address),      \
+           sw_if1, vnet_buffer (b1)->ip.adj_index[VLIB_RX], next_iface1);    \
        }                                                                     \
-      else if (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL &&          \
-              vnet_buffer (b1)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID)  \
+      else                                                                    \
        {                                                                     \
-         next_iface1 = NEXT_UDP_ENCAP_IP6;                                   \
-         sw_if1 = ~0;                                                        \
+         next0 = HICN##ipv##_IFACE_INPUT_NEXT_ERROR_DROP;                    \
+         next1 = HICN##ipv##_IFACE_INPUT_NEXT_ERROR_DROP;                    \
        }                                                                     \
                                                                               \
-      DPO_ADD_LOCK_FACE_IP##ipv (                                             \
-       &(hicnb0->face_id), &hicnb0->flags, &(ip_hdr0->src_address), sw_if0,  \
-       vnet_buffer (b0)->ip.adj_index[VLIB_RX], next_iface0);                \
-                                                                              \
-      DPO_ADD_LOCK_FACE_IP##ipv (                                             \
-       &(hicnb1->face_id), &hicnb1->flags, &(ip_hdr1->src_address), sw_if1,  \
-       vnet_buffer (b1)->ip.adj_index[VLIB_RX], next_iface1);                \
-                                                                              \
       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&              \
                         (b0->flags & VLIB_BUFFER_IS_TRACED)))                \
        {                                                                     \
          TRACE_INPUT_PKT_IP##ipv *t =                                        \
            vlib_add_trace (vm, node, b0, sizeof (*t));                       \
-         t->pkt_type = HICN_PKT_TYPE_INTEREST;                               \
+         t->pkt_type = HICN_PACKET_TYPE_INTEREST;                            \
          t->sw_if_index = sw_if0;                                            \
          t->next_index = next0;                                              \
+         t->error = ret0;                                                    \
          clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0),     \
                            sizeof (t->packet_data));                         \
        }                                                                     \
@@ -366,9 +454,10 @@ typedef enum
        {                                                                     \
          TRACE_INPUT_PKT_IP##ipv *t =                                        \
            vlib_add_trace (vm, node, b1, sizeof (*t));                       \
-         t->pkt_type = HICN_PKT_TYPE_INTEREST;                               \
+         t->pkt_type = HICN_PACKET_TYPE_INTEREST;                            \
          t->sw_if_index = sw_if1;                                            \
          t->next_index = next1;                                              \
+         t->error = ret1;                                                    \
          clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b1),     \
                            sizeof (t->packet_data));                         \
        }                                                                     \
@@ -435,9 +524,17 @@ hicn4_iface_input_format_trace (u8 *s, va_list *args)
   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
   hicn4_iface_input_trace_t *t = va_arg (*args, hicn4_iface_input_trace_t *);
 
-  s = format (s, "IFACE_IP4_INPUT: pkt: %d, sw_if_index %d, next index %d\n%U",
-             (int) t->pkt_type, t->sw_if_index, t->next_index,
-             format_ip4_header, t->packet_data, sizeof (t->packet_data));
+  s = format (s, "IFACE_IP4_INPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+
+  if (t->error)
+    {
+      s = format (s, " drop reason: %s", get_error_string (t->error));
+    }
+
+  s = format (s, "\n%U", format_ip4_header, t->packet_data,
+             sizeof (t->packet_data));
+
   return (s);
 }
 
@@ -544,6 +641,7 @@ hicn_rewrite_iface_data4 (vlib_main_t *vm, vlib_buffer_t *b0,
                          const hicn_face_t *iface, u32 *next)
 {
   ip4_header_t *ip0;
+  int ret = HICN_ERROR_NONE;
 
   /* Get the pointer to the old ip and tcp header */
   ip0 = vlib_buffer_get_current (b0);
@@ -563,9 +661,11 @@ hicn_rewrite_iface_data4 (vlib_main_t *vm, vlib_buffer_t *b0,
   hicn_type_t type = hicn_get_buffer (b0)->type;
   u8 flags = hicn_get_buffer (b0)->flags;
   u8 reset_pl = flags & HICN_BUFFER_FLAGS_FROM_CS;
-  int ret = hicn_ops_vft[type.l1]->rewrite_data (
-    type, &hicn->protocol, &(iface->nat_addr), &(temp_addr), iface->pl_id,
-    reset_pl);
+
+  ret = hicn_ops_vft[type.l1]->rewrite_data (type, &hicn->protocol,
+                                            &(iface->nat_addr), &(temp_addr),
+                                            iface->pl_id, reset_pl);
+
   if (ret == HICN_LIB_ERROR_REWRITE_CKSUM_REQUIRED)
     {
       ensure_offload_flags (b0, 1 /* is_v4 */);
@@ -577,6 +677,7 @@ hicn_rewrite_iface_data6 (vlib_main_t *vm, vlib_buffer_t *b0,
                          const hicn_face_t *iface, u32 *next)
 {
   ip6_header_t *ip0;
+  int ret = HICN_ERROR_NONE;
 
   /* Get the pointer to the old ip and tcp header */
   /* Copy the previous ip and tcp header to the new portion of memory */
@@ -598,9 +699,10 @@ hicn_rewrite_iface_data6 (vlib_main_t *vm, vlib_buffer_t *b0,
   hicn_type_t type = hicn_get_buffer (b0)->type;
   u8 flags = hicn_get_buffer (b0)->flags;
   u8 reset_pl = flags & HICN_BUFFER_FLAGS_FROM_CS;
-  int ret = hicn_ops_vft[type.l1]->rewrite_data (
-    type, &hicn->protocol, &(iface->nat_addr), &(temp_addr), iface->pl_id,
-    reset_pl);
+
+  ret = hicn_ops_vft[type.l1]->rewrite_data (type, &hicn->protocol,
+                                            &(iface->nat_addr), &(temp_addr),
+                                            iface->pl_id, reset_pl);
 
   if (ret == HICN_LIB_ERROR_REWRITE_CKSUM_REQUIRED)
     {
@@ -653,7 +755,7 @@ hicn_rewrite_iface_data6 (vlib_main_t *vm, vlib_buffer_t *b0,
        {                                                                     \
          TRACE_OUTPUT_PKT_IP##ipv *t =                                       \
            vlib_add_trace (vm, node, b0, sizeof (*t));                       \
-         t->pkt_type = HICN_PKT_TYPE_INTEREST;                               \
+         t->pkt_type = HICN_PACKET_TYPE_INTEREST;                            \
          t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];            \
          t->next_index = next0;                                              \
          clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0),     \
@@ -731,7 +833,7 @@ hicn_rewrite_iface_data6 (vlib_main_t *vm, vlib_buffer_t *b0,
        {                                                                     \
          TRACE_OUTPUT_PKT_IP##ipv *t =                                       \
            vlib_add_trace (vm, node, b0, sizeof (*t));                       \
-         t->pkt_type = HICN_PKT_TYPE_INTEREST;                               \
+         t->pkt_type = HICN_PACKET_TYPE_INTEREST;                            \
          t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];            \
          t->next_index = next0;                                              \
          clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0),     \
@@ -743,7 +845,7 @@ hicn_rewrite_iface_data6 (vlib_main_t *vm, vlib_buffer_t *b0,
        {                                                                     \
          TRACE_OUTPUT_PKT_IP##ipv *t =                                       \
            vlib_add_trace (vm, node, b1, sizeof (*t));                       \
-         t->pkt_type = HICN_PKT_TYPE_INTEREST;                               \
+         t->pkt_type = HICN_PACKET_TYPE_INTEREST;                            \
          t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];            \
          t->next_index = next1;                                              \
          clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b1),     \
@@ -824,7 +926,8 @@ VLIB_REGISTER_NODE (hicn4_iface_output_node) = {
   .next_nodes = { [HICN4_IFACE_OUTPUT_NEXT_DROP] = "error-drop",
                  [HICN4_IFACE_OUTPUT_NEXT_LOOKUP] = "ip4-lookup",
                  [HICN4_IFACE_OUTPUT_NEXT_UDP4_ENCAP] = "udp4-encap",
-                 [HICN4_IFACE_OUTPUT_NEXT_UDP6_ENCAP] = "udp6-encap" },
+                 [HICN4_IFACE_OUTPUT_NEXT_UDP6_ENCAP] = "udp6-encap",
+                 [HICN4_IFACE_OUTPUT_NEXT_PG] = "hicnpg-data" },
 };
 
 static uword
@@ -893,7 +996,8 @@ VLIB_REGISTER_NODE (hicn6_iface_output_node) = {
   .next_nodes = { [HICN6_IFACE_OUTPUT_NEXT_DROP] = "error-drop",
                  [HICN6_IFACE_OUTPUT_NEXT_LOOKUP] = "ip6-lookup",
                  [HICN6_IFACE_OUTPUT_NEXT_UDP4_ENCAP] = "udp4-encap",
-                 [HICN6_IFACE_OUTPUT_NEXT_UDP6_ENCAP] = "udp6-encap" },
+                 [HICN6_IFACE_OUTPUT_NEXT_UDP6_ENCAP] = "udp6-encap",
+                 [HICN6_IFACE_OUTPUT_NEXT_PG] = "hicnpg-data" },
 };
 
 /*
@@ -902,4 +1006,4 @@ VLIB_REGISTER_NODE (hicn6_iface_output_node) = {
  * Local Variables:
  * eval: (c-set-style "gnu")
  * End:
- */
+ */
\ No newline at end of file
index 1131d43..1789f54 100644 (file)
@@ -28,6 +28,7 @@
 #include "face_db.h"
 #include "udp_tunnels/udp_tunnel.h"
 #include "route.h"
+#include "pg.h"
 
 hicn_main_t hicn_main;
 /* Module vars */
@@ -223,24 +224,29 @@ hicn_init (vlib_main_t *vm)
 
   hicn_main_t *sm = &hicn_main;
 
-  /* Init other elements in the 'main' struct */
+  // Init other elements in the 'main' struct
   sm->is_enabled = 0;
 
   error = hicn_api_plugin_hookup (vm);
 
-  /* Init the dpo module */
+  // Init the dpo module
   hicn_dpos_init ();
 
-  /* Init the app manager */
+  // Init the app manager
   address_mgr_init ();
 
+  // Init the face module
   hicn_face_module_init (vm);
 
-  /* Init the route module */
+  // Init the route module
   hicn_route_init ();
 
+  // Init the UDP tunnels module
   udp_tunnel_init ();
 
+  // Init the packet generator module
+  hicn_pg_init (vm);
+
   return error;
 }
 
index aaf16c9..22309e3 100644 (file)
@@ -57,32 +57,44 @@ typedef u8 weight_t;
 #define VLIB_BUFFER_MIN_CHAIN_SEG_SIZE (128)
 #endif
 
-/* vlib_buffer cloning utilities impose that current_lentgh is more that
- * 2*CLIB_CACHE_LINE_BYTES.  */
-/* This flag is used to mark packets whose lenght is less that
- * 2*CLIB_CACHE_LINE_BYTES. */
-#define HICN_BUFFER_FLAGS_PKT_LESS_TWO_CL 0x02
-#define HICN_BUFFER_FLAGS_FROM_CS        0x10
-
 /* The following is stored in the opaque2 field in the vlib_buffer_t */
 typedef struct
 {
-  /* hash of the name */
+  /**
+   * Hash of the name (8)
+   */
   u64 name_hash;
 
-  /* ids to prefetch a PIT/CS entry */
+  /**
+   * IDs to prefetch a PIT/CS entry (4+4+1+1)
+   */
   u32 node_id;
   u32 bucket_id;
   u8 hash_entry_id;
   u8 hash_bucket_flags;
 
+  /**
+   * hICN buffer flags (1)
+   */
   u8 flags;
-  u8 dpo_ctx_id; /* used for data path */
-  u8 vft_id;    /* " */
 
-  hicn_face_id_t face_id; /* ingress iface, sizeof(u32) */
+  /**
+   * used for data path (1+1)
+   */
+  u8 dpo_ctx_id;
+  u8 vft_id;
+
+  /**
+   * Ingress face (4)
+   */
+  hicn_face_id_t face_id;
 
+  /**
+   * Cached packet info
+   */
   hicn_type_t type;
+  hicn_name_t name;
+  u16 port;
 } hicn_buffer_t;
 
 STATIC_ASSERT (sizeof (hicn_buffer_t) <=
@@ -101,6 +113,28 @@ hicn_is_v6 (hicn_header_t *pkt_hdr)
   return ((pkt_hdr->v4.ip.version_ihl >> 4) != 4);
 }
 
+always_inline void
+hicn_buffer_get_name_and_namelen (vlib_buffer_t *b0, u8 **nameptr,
+                                 u16 *namelen)
+{
+  *nameptr = (u8 *) (&hicn_get_buffer (b0)->name);
+  *namelen = ip_address_is_v4 (&hicn_get_buffer (b0)->name.prefix) ?
+                    HICN_V4_NAME_LEN :
+                    HICN_V6_NAME_LEN;
+}
+
+always_inline u8
+hicn_buffer_is_v6 (vlib_buffer_t *b0)
+{
+  return hicn_get_buffer (b0)->type.l1 == IPPROTO_IPV6;
+}
+
+always_inline void
+hicn_buffer_set_flags (vlib_buffer_t *b, u8 flags)
+{
+  hicn_buffer_t *hb = hicn_get_buffer (b);
+  hb->flags |= flags;
+}
 #endif /* __HICN_H__ */
 
 /*
diff --git a/hicn-plugin/src/hicn_buffer_flags.h b/hicn-plugin/src/hicn_buffer_flags.h
new file mode 100644 (file)
index 0000000..7d99e6d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __HICN_BUFFER_FLAGS_H__
+#define __HICN_BUFFER_FLAGS_H__
+
+#define foreach_hicn_buffer_flag                                              \
+  _ (0, NEW_FACE, "new face")                                                 \
+  _ (1, PKT_LESS_TWO_CL, "packet is less that 2 cache lines length")          \
+  _ (2, FROM_UDP4_TUNNEL, "packet is from udp4 tunnel")                       \
+  _ (3, FROM_UDP6_TUNNEL, "packet is from udp6 tunnel")                       \
+  _ (4, FROM_CS, "packet is from cs")                                         \
+  _ (5, FROM_PG, "packet is from packet generator")
+
+enum
+{
+  HICN_BUFFER_FLAGS_DEFAULT = 0,
+#define _(a, b, c) HICN_BUFFER_FLAGS_##b = (1 << a),
+  foreach_hicn_buffer_flag
+#undef _
+};
+
+#endif /* __HICN_BUFFER_FLAGS_H__ */
\ No newline at end of file
index 947b4cb..1af2119 100644 (file)
@@ -90,7 +90,6 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
   hicn_interest_hitcs_runtime_t *rt;
   vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
   f64 tnow;
-  int ret;
 
   rt = vlib_node_get_runtime_data (vm, hicn_interest_hitcs_node.index);
 
@@ -116,8 +115,6 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
          u16 namelen;
          u32 bi0;
          u32 next0 = HICN_INTEREST_HITCS_NEXT_ERROR_DROP;
-         hicn_name_t name;
-         hicn_header_t *hicn0;
          hicn_buffer_t *hicnb0;
          hicn_hash_node_t *node0;
          hicn_pcs_entry_t *pitp;
@@ -150,8 +147,8 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
          hicn_get_internal_state (hicnb0, rt->pitcs, &node0, &strategy_vft0,
                                   &dpo_vft0, &dpo_ctx_id0, &hash_entry0);
 
-         ret = hicn_interest_parse_pkt (b0, &name, &namelen, &hicn0, &isv6);
-         nameptr = (u8 *) (&name);
+         hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen);
+         isv6 = hicn_buffer_is_v6 (b0);
          pitp = hicn_pit_get_data (node0);
 
          dpo_id_t hicn_dpo_id0 = { .dpoi_type =
@@ -160,8 +157,7 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
                                    .dpoi_next_node = 0,
                                    .dpoi_index = dpo_ctx_id0 };
 
-         if (PREDICT_FALSE (ret != HICN_ERROR_NONE ||
-                            !hicn_node_compare (nameptr, namelen, node0)))
+         if (PREDICT_FALSE (!hicn_node_compare (nameptr, namelen, node0)))
            {
              /* Remove lock from the entry */
              hicn_pcs_remove_lock (rt->pitcs, &pitp, &node0, vm, hash_entry0,
@@ -209,7 +205,7 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
            {
              hicn_interest_hitcs_trace_t *t =
                vlib_add_trace (vm, node, b0, sizeof (*t));
-             t->pkt_type = HICN_PKT_TYPE_INTEREST;
+             t->pkt_type = HICN_PACKET_TYPE_INTEREST;
              t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
              t->next_index = next0;
            }
@@ -285,4 +281,4 @@ VLIB_REGISTER_NODE (hicn_interest_hitcs_node) = {
  * fd.io coding-style-patch-verification: ON
  *
  * Local Variables: eval: (c-set-style "gnu") End:
- */
+ */
\ No newline at end of file
index 18ef94a..46659e6 100644 (file)
@@ -46,7 +46,7 @@ typedef struct
 {
   u32 next_index;
   u32 sw_if_index;
-  u8 pkt_type;
+  u32 pkt_type;
 } hicn_interest_hitpit_trace_t;
 
 typedef enum
@@ -65,4 +65,4 @@ typedef enum
  * fd.io coding-style-patch-verification: ON
  *
  * Local Variables: eval: (c-set-style "gnu") End:
- */
+ */
\ No newline at end of file
index 33dc782..c98baf7 100644 (file)
@@ -79,8 +79,6 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
          u16 namelen;
          u32 bi0;
          u32 next0 = HICN_INTEREST_HITPIT_NEXT_ERROR_DROP;
-         hicn_name_t name;
-         hicn_header_t *hicn0;
          hicn_hash_node_t *node0;
          const hicn_strategy_vft_t *strategy_vft0;
          const hicn_dpo_vft_t *dpo_vft0;
@@ -92,7 +90,6 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
          u32 outfaces_len;
          hicn_hash_entry_t *hash_entry0;
          hicn_buffer_t *hicnb0;
-         int ret;
 
          /* Prefetch for next iteration. */
          if (n_left_from > 1)
@@ -118,8 +115,9 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
          hicn_get_internal_state (hicnb0, rt->pitcs, &node0, &strategy_vft0,
                                   &dpo_vft0, &dpo_ctx_id0, &hash_entry0);
 
-         ret = hicn_interest_parse_pkt (b0, &name, &namelen, &hicn0, &isv6);
-         nameptr = (u8 *) (&name);
+         hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen);
+         isv6 = hicn_buffer_is_v6 (b0);
+
          pitp = hicn_pit_get_data (node0);
          dpo_id_t hicn_dpo_id0 = { .dpoi_type =
                                      dpo_vft0->hicn_dpo_get_type (),
@@ -131,8 +129,7 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
           * Check if the hit is instead a collision in the
           * hash table. Unlikely to happen.
           */
-         if (PREDICT_FALSE (ret != HICN_ERROR_NONE ||
-                            !hicn_node_compare (nameptr, namelen, node0)))
+         if (PREDICT_FALSE (!hicn_node_compare (nameptr, namelen, node0)))
            {
              stats.interests_hash_collision++;
              /* Remove lock from the entry */
@@ -227,7 +224,7 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
                                  hicn_interest_hitpit_trace_t *t =
                                    vlib_add_trace (vm, node, local_b0,
                                                    sizeof (*t));
-                                 t->pkt_type = HICN_PKT_TYPE_INTEREST;
+                                 t->pkt_type = HICN_PACKET_TYPE_INTEREST;
                                  t->sw_if_index = vnet_buffer (local_b0)
                                                     ->sw_if_index[VLIB_RX];
                                  t->next_index = next0;
@@ -266,7 +263,7 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
            {
              hicn_interest_hitpit_trace_t *t =
                vlib_add_trace (vm, node, b0, sizeof (*t));
-             t->pkt_type = HICN_PKT_TYPE_INTEREST;
+             t->pkt_type = HICN_PACKET_TYPE_INTEREST;
              t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
              t->next_index = next0;
            }
@@ -354,4 +351,4 @@ VLIB_REGISTER_NODE(hicn_interest_hitpit_node) =
  * fd.io coding-style-patch-verification: ON
  *
  * Local Variables: eval: (c-set-style "gnu") End:
- */
+ */
\ No newline at end of file
index ff0da12..e569573 100644 (file)
@@ -57,7 +57,6 @@ hicn_interest_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
   hicn_interest_pcslookup_next_t next_index;
   hicn_interest_pcslookup_runtime_t *rt;
   vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
-  int ret;
 
   rt = vlib_node_get_runtime_data (vm, hicn_interest_pcslookup_node.index);
 
@@ -76,14 +75,11 @@ hicn_interest_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
       while (n_left_from > 0 && n_left_to_next > 0)
        {
          vlib_buffer_t *b0;
-         u8 isv6;
          u8 *nameptr;
          u16 namelen;
          u32 bi0;
          u32 next0 = HICN_INTEREST_PCSLOOKUP_NEXT_ERROR_DROP;
          u64 name_hash = 0;
-         hicn_name_t name;
-         hicn_header_t *hicn0;
          u32 node_id0 = 0;
          index_t dpo_ctx_id0 = 0;
          u8 vft_id0 = 0;
@@ -109,19 +105,15 @@ hicn_interest_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
          n_left_to_next -= 1;
 
          b0 = vlib_get_buffer (vm, bi0);
-         ret = hicn_interest_parse_pkt (b0, &name, &namelen, &hicn0, &isv6);
 
-         if (PREDICT_TRUE (ret == HICN_ERROR_NONE))
-           {
-             next0 = HICN_INTEREST_PCSLOOKUP_NEXT_STRATEGY;
-           }
-         nameptr = (u8 *) (&name);
+         hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen);
+
+         next0 = HICN_INTEREST_PCSLOOKUP_NEXT_STRATEGY;
          stats.pkts_processed++;
 
          if (PREDICT_FALSE (
-               ret != HICN_ERROR_NONE ||
                hicn_hashtb_fullhash (nameptr, namelen, &name_hash) !=
-                 HICN_ERROR_NONE))
+               HICN_ERROR_NONE))
            {
              next0 = HICN_INTEREST_PCSLOOKUP_NEXT_ERROR_DROP;
            }
@@ -149,7 +141,7 @@ hicn_interest_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
            {
              hicn_interest_pcslookup_trace_t *t =
                vlib_add_trace (vm, node, b0, sizeof (*t));
-             t->pkt_type = HICN_PKT_TYPE_INTEREST;
+             t->pkt_type = HICN_PACKET_TYPE_INTEREST;
              t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
              t->next_index = next0;
            }
@@ -226,4 +218,4 @@ VLIB_REGISTER_NODE(hicn_interest_pcslookup_node) =
  * fd.io coding-style-patch-verification: ON
  *
  * Local Variables: eval: (c-set-style "gnu") End:
- */
+ */
\ No newline at end of file
index 0e60c52..29405eb 100644 (file)
  * @file parser.h
  */
 
-/*
- * Key type codes for header, header tlvs, body tlvs, and child tlvs
- */
-
-// FIXME(reuse lib struct, no more control ?)
-enum hicn_pkt_type_e
-{
-  HICN_PKT_TYPE_INTEREST = 0,
-  HICN_PKT_TYPE_CONTENT = 1,
-};
-
 /**
- * @brief Parse an interest packet
+ * @brief Parse a interest packet
  *
  * @param pkt vlib buffer holding the interest
- * @param name return variable that will point to the hicn name
- * @param namelen return valiable that will hold the length of the name
- * @param pkt_hdrp return valiable that will point to the packet header
- * @param isv6 return variable that will be equale to 1 is the header is ipv6
+ * @param name [RETURNED] variable that will point to the hicn name
+ * @param namelen [RETURNED] variable that will hold the length of the name
+ * @param port [RETURNED] variable that will hold the source port of the packet
+ * @param pkt_hdrp [RETURNED] valiable that will point to the packet header
+ * @param isv6 [RETURNED] variable that will be equale to 1 is the header is
+ * ipv6
  */
 always_inline int
-hicn_interest_parse_pkt (vlib_buffer_t *pkt, hicn_name_t *name, u16 *namelen,
-                        hicn_header_t **pkt_hdrp, u8 *isv6)
+hicn_interest_parse_pkt (vlib_buffer_t *pkt)
 {
   if (pkt == NULL)
     return HICN_ERROR_PARSER_PKT_INVAL;
-  hicn_header_t *pkt_hdr = vlib_buffer_get_current (pkt);
-  *pkt_hdrp = pkt_hdr;
-  u8 *ip_pkt = vlib_buffer_get_current (pkt);
-  *isv6 = hicn_is_v6 (pkt_hdr);
-  u8 ip_proto = (*isv6) * IPPROTO_IPV6;
-  u8 next_proto_offset = 6 + (1 - *isv6) * 3;
-  // in the ipv6 header the next header field is at byte 6
-  // in the ipv4 header the protocol field is at byte 9
-  hicn_type_t type =
-    (hicn_type_t){ { .l4 = IPPROTO_NONE,
-                    .l3 = ip_pkt[next_proto_offset] == IPPROTO_UDP ?
-                                  IPPROTO_ENCAP :
-                                  IPPROTO_NONE,
-                    .l2 = ip_pkt[next_proto_offset],
-                    .l1 = ip_proto } };
+
+  int ret = HICN_LIB_ERROR_NONE;
+
+  hicn_header_t *pkt_hdr;
+  u8 *ip_pkt;
+  u8 ip_proto;
+  u8 next_proto_offset;
+  hicn_type_t type;
+  hicn_name_t *name;
+  u16 *port;
+  int isv6;
+
+  // start parsing first fields to get the protocols
+  pkt_hdr = vlib_buffer_get_current (pkt);
+  isv6 = hicn_is_v6 (pkt_hdr);
+
+  ip_pkt = vlib_buffer_get_current (pkt);
+  ip_proto = (1 - isv6) * IPPROTO_IP + (isv6) *IPPROTO_IPV6;
+
+  // in the ipv6 header the next header field is at byte 6 in the ipv4
+  // header the protocol field is at byte 9
+  next_proto_offset = 6 + (1 - isv6) * 3;
+
+  // get type info
+  type.l4 = IPPROTO_NONE;
+  type.l3 =
+    ip_pkt[next_proto_offset] == IPPROTO_UDP ? IPPROTO_ENCAP : IPPROTO_NONE;
+  type.l2 = ip_pkt[next_proto_offset];
+  type.l1 = ip_proto;
+
+  // cache hicn packet type in opaque2
   hicn_get_buffer (pkt)->type = type;
 
-  hicn_ops_vft[type.l1]->get_interest_name (type, &pkt_hdr->protocol, name);
-  *namelen = (1 - (*isv6)) * HICN_V4_NAME_LEN + (*isv6) * HICN_V6_NAME_LEN;
+  // get name and name length
+  name = &hicn_get_buffer (pkt)->name;
+  ret =
+    hicn_ops_vft[type.l1]->get_interest_name (type, &pkt_hdr->protocol, name);
+  if (PREDICT_FALSE (ret))
+    {
+      if (type.l2 == IPPROTO_ICMPV4 || type.l2 == IPPROTO_ICMPV6)
+       {
+         return HICN_ERROR_PARSER_MAPME_PACKET;
+       }
+      return HICN_ERROR_PARSER_PKT_INVAL;
+    }
 
-  return HICN_ERROR_NONE;
+  // get source port
+  port = &hicn_get_buffer (pkt)->port;
+  hicn_ops_vft[type.l1]->get_source_port (type, &pkt_hdr->protocol, port);
+  if (PREDICT_FALSE (ret))
+    {
+      return HICN_ERROR_PARSER_PKT_INVAL;
+    }
+
+  return ret;
 }
 
 /**
  * @brief Parse a data packet
  *
- * @param pkt vlib buffer holding the interest
- * @param name return variable that will point to the hicn name
- * @param namelen return valiable that will hold the length of the name
- * @param pkt_hdrp return valiable that will point to the packet header
- * @param isv6 return variable that will be equale to 1 is the header is ipv6
+ * @param pkt vlib buffer holding the data
+ * @param name [RETURNED] variable that will point to the hicn name
+ * @param namelen [RETURNED] variable that will hold the length of the name
+ * @param port [RETURNED] variable that will hold the source port of the packet
+ * @param pkt_hdrp [RETURNED] valiable that will point to the packet header
+ * @param isv6 [RETURNED] variable that will be equale to 1 is the header is
+ * ipv6
  */
 always_inline int
-hicn_data_parse_pkt (vlib_buffer_t *pkt, hicn_name_t *name, u16 *namelen,
-                    hicn_header_t **pkt_hdrp, u8 *isv6)
+hicn_data_parse_pkt (vlib_buffer_t *pkt)
 {
   if (pkt == NULL)
     return HICN_ERROR_PARSER_PKT_INVAL;
-  hicn_header_t *pkt_hdr = vlib_buffer_get_current (pkt);
-  *pkt_hdrp = pkt_hdr;
-  *pkt_hdrp = pkt_hdr;
-  u8 *ip_pkt = vlib_buffer_get_current (pkt);
-  *isv6 = hicn_is_v6 (pkt_hdr);
-  u8 ip_proto = (*isv6) * IPPROTO_IPV6;
-  /*
-   * in the ipv6 header the next header field is at byte 6 in the ipv4
-   * header the protocol field is at byte 9
-   */
-  u8 next_proto_offset = 6 + (1 - *isv6) * 3;
-  hicn_type_t type =
-    (hicn_type_t){ { .l4 = IPPROTO_NONE,
-                    .l3 = ip_pkt[next_proto_offset] == IPPROTO_UDP ?
-                                  IPPROTO_ENCAP :
-                                  IPPROTO_NONE,
-                    .l2 = ip_pkt[next_proto_offset],
-                    .l1 = ip_proto } };
+
+  int ret = HICN_LIB_ERROR_NONE;
+
+  hicn_header_t *pkt_hdr;
+  u8 *ip_pkt;
+  u8 ip_proto;
+  int isv6;
+  u8 next_proto_offset;
+  hicn_type_t type;
+  hicn_name_t *name;
+  u16 *port;
+
+  // start parsing first fields to get the protocols
+  pkt_hdr = vlib_buffer_get_current (pkt);
+  isv6 = hicn_is_v6 (pkt_hdr);
+
+  ip_pkt = vlib_buffer_get_current (pkt);
+  ip_proto = (1 - isv6) * IPPROTO_IP + (isv6) *IPPROTO_IPV6;
+
+  // in the ipv6 header the next header field is at byte 6 in the ipv4
+  // header the protocol field is at byte 9
+  next_proto_offset = 6 + (1 - isv6) * 3;
+
+  // get type info
+  type.l4 = IPPROTO_NONE;
+  type.l3 =
+    ip_pkt[next_proto_offset] == IPPROTO_UDP ? IPPROTO_ENCAP : IPPROTO_NONE;
+  type.l2 = ip_pkt[next_proto_offset];
+  type.l1 = ip_proto;
+
+  // cache hicn packet type in opaque2
   hicn_get_buffer (pkt)->type = type;
-  hicn_ops_vft[type.l1]->get_data_name (type, &pkt_hdr->protocol, name);
-  *namelen = (1 - (*isv6)) * HICN_V4_NAME_LEN + (*isv6) * HICN_V6_NAME_LEN;
 
-  return HICN_ERROR_NONE;
+  // get name and name length
+  name = &hicn_get_buffer (pkt)->name;
+  ret = hicn_ops_vft[type.l1]->get_data_name (type, &pkt_hdr->protocol, name);
+  if (PREDICT_FALSE (ret))
+    {
+      if (type.l2 == IPPROTO_ICMPV4 || type.l2 == IPPROTO_ICMPV6)
+       {
+         return HICN_ERROR_PARSER_MAPME_PACKET;
+       }
+      return HICN_ERROR_PARSER_PKT_INVAL;
+    }
+
+  // get source port
+  port = &hicn_get_buffer (pkt)->port;
+  hicn_ops_vft[type.l1]->get_source_port (type, &pkt_hdr->protocol, port);
+  if (PREDICT_FALSE (ret))
+    {
+      return HICN_ERROR_PARSER_PKT_INVAL;
+    }
+
+  return ret;
 }
 
 #endif /* // __HICN_PARSER_H__ */
@@ -120,4 +176,4 @@ hicn_data_parse_pkt (vlib_buffer_t *pkt, hicn_name_t *name, u16 *namelen,
  * fd.io coding-style-patch-verification: ON
  *
  * Local Variables: eval: (c-set-style "gnu") End:
- */
+ */
\ No newline at end of file
index b77e8fc..0517234 100644 (file)
 #include <vnet/pg/pg.h>
 #include <vnet/ip/ip.h>
 #include <vnet/ethernet/ethernet.h>
+#include <vnet/fib/fib_entry_track.h>
 
 #include "hicn.h"
 #include "pg.h"
 #include "parser.h"
 #include "infra.h"
-
-/* Registration struct for a graph node */
-vlib_node_registration_t hicn_pg_interest_node;
-vlib_node_registration_t hicn_pg_data_node;
-
-/* Stats, which end up called "error" even though they aren't... */
-#define foreach_hicnpg_error                                                  \
-  _ (PROCESSED, "hICN PG packets processed")                                  \
-  _ (DROPPED, "hICN PG packets dropped")                                      \
-  _ (INTEREST_MSGS_GENERATED, "hICN PG Interests generated")                  \
-  _ (CONTENT_MSGS_RECEIVED, "hICN PG Content msgs received")
-
-typedef enum
-{
-#define _(sym, str) HICNPG_ERROR_##sym,
-  foreach_hicnpg_error
-#undef _
-    HICNPG_N_ERROR,
-} hicnpg_error_t;
-
-static char *hicnpg_error_strings[] = {
-#define _(sym, string) string,
-  foreach_hicnpg_error
-#undef _
-};
-
-/*
- * Next graph nodes, which reference the list in the actual registration
- * block below
- */
-typedef enum
-{
-  HICNPG_INTEREST_NEXT_V4_LOOKUP,
-  HICNPG_INTEREST_NEXT_V6_LOOKUP,
-  HICNPG_INTEREST_NEXT_DROP,
-  HICNPG_N_NEXT,
-} hicnpg_interest_next_t;
-
-/* Trace context struct */
-typedef struct
-{
-  u32 next_index;
-  u32 sw_if_index;
-  u8 pkt_type;
-  u16 msg_type;
-} hicnpg_trace_t;
+#include "route.h"
 
 hicnpg_main_t hicnpg_main = { .index = (u32) 0,
                              .index_ifaces = (u32) 1,
@@ -78,1183 +34,281 @@ hicnpg_main_t hicnpg_main = { .index = (u32) 0,
                              .n_ifaces = (u32) 1,
                              .sw_if = (u32) 0 };
 
-hicnpg_server_main_t hicnpg_server_main = {
-  .node_index = 0,
-};
-
-/* packet trace format function */
-static u8 *
-format_hicnpg_trace (u8 *s, va_list *args)
-{
-  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
-  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-  hicnpg_trace_t *t = va_arg (*args, hicnpg_trace_t *);
-
-  s = format (s, "HICNPG: pkt: %d, msg %d, sw_if_index %d, next index %d",
-             (int) t->pkt_type, (int) t->msg_type, t->sw_if_index,
-             t->next_index);
-  return (s);
-}
-
-always_inline void hicn_rewrite_interestv4 (vlib_main_t *vm, vlib_buffer_t *b0,
-                                           u32 seq_number, u16 lifetime,
-                                           u32 next_flow, u32 iface);
-
-always_inline void hicn_rewrite_interestv6 (vlib_main_t *vm, vlib_buffer_t *b0,
-                                           u32 seq_number, u16 lifetime,
-                                           u32 next_flow, u32 iface);
-
-always_inline void convert_interest_to_data_v4 (vlib_main_t *vm,
-                                               vlib_buffer_t *b0,
-                                               vlib_buffer_t *rb, u32 bi0);
-
-always_inline void convert_interest_to_data_v6 (vlib_main_t *vm,
-                                               vlib_buffer_t *b0,
-                                               vlib_buffer_t *rb, u32 bi0);
-
-always_inline void calculate_tcp_checksum_v4 (vlib_main_t *vm,
-                                             vlib_buffer_t *b0);
+/**
+ * Pool of hicnpg_server_t
+ */
+hicnpg_server_t *hicnpg_server_pool;
 
-always_inline void calculate_tcp_checksum_v6 (vlib_main_t *vm,
-                                             vlib_buffer_t *b0);
 /*
- * Node function for the icn packet-generator client. The goal here is to
- * manipulate/tweak a stream of packets that have been injected by the vpp
- * packet generator to generate icn request traffic.
+ * hicnph servrer FIB node type
  */
-static uword
-hicnpg_client_interest_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
-                               vlib_frame_t *frame)
-{
-  u32 n_left_from, *from, *to_next;
-  hicnpg_interest_next_t next_index;
-  u32 pkts_processed = 0, pkts_dropped = 0;
-  u32 interest_msgs_generated = 0;
-  u32 bi0, bi1;
-  vlib_buffer_t *b0, *b1;
-  u8 pkt_type0 = 0, pkt_type1 = 0;
-  u16 msg_type0 = 0, msg_type1 = 0;
-  hicn_header_t *hicn0 = NULL, *hicn1 = NULL;
-  hicn_name_t name0, name1;
-  u16 namelen0, namelen1;
-  hicnpg_main_t *hpgm = &hicnpg_main;
-  int iface = 0;
-
-  from = vlib_frame_vector_args (frame);
-  n_left_from = frame->n_vectors;
-  next_index = node->cached_next_index;
-
-  while (n_left_from > 0)
-    {
-      u32 n_left_to_next;
-
-      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
-
-      while (n_left_from >= 4 && n_left_to_next >= 2)
-       {
-         u32 next0 = HICNPG_INTEREST_NEXT_DROP;
-         u32 next1 = HICNPG_INTEREST_NEXT_DROP;
-         u32 sw_if_index0 = ~0, sw_if_index1 = ~0;
-         u8 isv6_0;
-         u8 isv6_1;
-
-         /* Prefetch next iteration. */
-         {
-           vlib_buffer_t *p2, *p3;
-
-           p2 = vlib_get_buffer (vm, from[2]);
-           p3 = vlib_get_buffer (vm, from[3]);
-
-           vlib_prefetch_buffer_header (p2, LOAD);
-           vlib_prefetch_buffer_header (p3, LOAD);
-
-           CLIB_PREFETCH (p2->data, (2 * CLIB_CACHE_LINE_BYTES), STORE);
-           CLIB_PREFETCH (p3->data, (2 * CLIB_CACHE_LINE_BYTES), STORE);
-         }
-
-         /*
-          * speculatively enqueue b0 and b1 to the current
-          * next frame
-          */
-         to_next[0] = bi0 = from[0];
-         to_next[1] = bi1 = from[1];
-         from += 2;
-         to_next += 2;
-         n_left_from -= 2;
-         n_left_to_next -= 2;
-
-         b0 = vlib_get_buffer (vm, bi0);
-         b1 = vlib_get_buffer (vm, bi1);
-
-         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-         sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
-         vnet_buffer (b0)->sw_if_index[VLIB_RX] = hpgm->sw_if;
-         vnet_buffer (b1)->sw_if_index[VLIB_RX] = hpgm->sw_if;
-
-         /* Check icn packets, locate names */
-         if (hicn_interest_parse_pkt (b0, &name0, &namelen0, &hicn0,
-                                      &isv6_0) == HICN_ERROR_NONE)
-           {
-             /* this node grabs only interests */
-
-             /* Increment the appropriate message counter */
-             interest_msgs_generated++;
-
-             iface = (hpgm->index_ifaces % hpgm->n_ifaces);
-             /* Rewrite and send */
-             isv6_0 ?
-                     hicn_rewrite_interestv6 (
-                 vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number,
-                 hpgm->interest_lifetime, hpgm->index % hpgm->n_flows,
-                 iface) :
-                     hicn_rewrite_interestv4 (
-                 vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number,
-                 hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, iface);
-
-             hpgm->index_ifaces++;
-             if (iface == (hpgm->n_ifaces - 1))
-               hpgm->index++;
-
-             next0 = isv6_0 ? HICNPG_INTEREST_NEXT_V6_LOOKUP :
-                                    HICNPG_INTEREST_NEXT_V4_LOOKUP;
-           }
-         if (hicn_interest_parse_pkt (b1, &name1, &namelen1, &hicn1,
-                                      &isv6_1) == HICN_ERROR_NONE)
-           {
-             /* this node grabs only interests */
-
-             /* Increment the appropriate message counter */
-             interest_msgs_generated++;
-
-             iface = (hpgm->index_ifaces % hpgm->n_ifaces);
-             /* Rewrite and send */
-             isv6_1 ?
-                     hicn_rewrite_interestv6 (
-                 vm, b1, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number,
-                 hpgm->interest_lifetime, hpgm->index % hpgm->n_flows,
-                 iface) :
-                     hicn_rewrite_interestv4 (
-                 vm, b1, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number,
-                 hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, iface);
-
-             hpgm->index_ifaces++;
-             if (iface == (hpgm->n_ifaces - 1))
-               hpgm->index++;
-
-             next1 = isv6_1 ? HICNPG_INTEREST_NEXT_V6_LOOKUP :
-                                    HICNPG_INTEREST_NEXT_V4_LOOKUP;
-           }
-         /* Send pkt to next node */
-         vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
-         vnet_buffer (b1)->sw_if_index[VLIB_TX] = ~0;
-
-         pkts_processed += 2;
-
-         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
-           {
-             if (b0->flags & VLIB_BUFFER_IS_TRACED)
-               {
-                 hicnpg_trace_t *t =
-                   vlib_add_trace (vm, node, b0, sizeof (*t));
-                 t->pkt_type = pkt_type0;
-                 t->msg_type = msg_type0;
-                 t->sw_if_index = sw_if_index0;
-                 t->next_index = next0;
-               }
-             if (b1->flags & VLIB_BUFFER_IS_TRACED)
-               {
-                 hicnpg_trace_t *t =
-                   vlib_add_trace (vm, node, b1, sizeof (*t));
-                 t->pkt_type = pkt_type1;
-                 t->msg_type = msg_type1;
-                 t->sw_if_index = sw_if_index1;
-                 t->next_index = next1;
-               }
-           }
-         if (next0 == HICNPG_INTEREST_NEXT_DROP)
-           {
-             pkts_dropped++;
-           }
-         if (next1 == HICNPG_INTEREST_NEXT_DROP)
-           {
-             pkts_dropped++;
-           }
-         /*
-          * verify speculative enqueues, maybe switch current
-          * next frame
-          */
-         vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
-                                          n_left_to_next, bi0, bi1, next0,
-                                          next1);
-       }
-
-      while (n_left_from > 0 && n_left_to_next > 0)
-       {
-         u32 next0 = HICNPG_INTEREST_NEXT_DROP;
-         u32 sw_if_index0;
-         u8 isv6_0;
-
-         /* speculatively enqueue b0 to the current next frame */
-         bi0 = from[0];
-         to_next[0] = bi0;
-         from += 1;
-         to_next += 1;
-         n_left_from -= 1;
-         n_left_to_next -= 1;
-
-         b0 = vlib_get_buffer (vm, bi0);
-
-         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-         vnet_buffer (b0)->sw_if_index[VLIB_RX] = hpgm->sw_if;
-
-         /* Check icn packets, locate names */
-         if (hicn_interest_parse_pkt (b0, &name0, &namelen0, &hicn0,
-                                      &isv6_0) == HICN_ERROR_NONE)
-           {
-             /* this node grabs only interests */
-
-             /* Increment the appropriate message counter */
-             interest_msgs_generated++;
-
-             iface = (hpgm->index_ifaces % hpgm->n_ifaces);
-
-             /* Rewrite and send */
-             isv6_0 ?
-                     hicn_rewrite_interestv6 (
-                 vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number,
-                 hpgm->interest_lifetime, hpgm->index % hpgm->n_flows,
-                 iface) :
-                     hicn_rewrite_interestv4 (
-                 vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number,
-                 hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, iface);
-
-             hpgm->index_ifaces++;
-             if (iface == (hpgm->n_ifaces - 1))
-               hpgm->index++;
-
-             next0 = isv6_0 ? HICNPG_INTEREST_NEXT_V6_LOOKUP :
-                                    HICNPG_INTEREST_NEXT_V4_LOOKUP;
-           }
-         /* Send pkt to ip lookup */
-         vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
+fib_node_type_t hicnpg_server_fib_node_type;
 
-         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
-                            (b0->flags & VLIB_BUFFER_IS_TRACED)))
-           {
-             hicnpg_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
-             t->pkt_type = pkt_type0;
-             t->msg_type = msg_type0;
-             t->sw_if_index = sw_if_index0;
-             t->next_index = next0;
-           }
-         pkts_processed += 1;
-
-         if (next0 == HICNPG_INTEREST_NEXT_DROP)
-           {
-             pkts_dropped++;
-           }
-         /*
-          * verify speculative enqueue, maybe switch current
-          * next frame
-          */
-         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
-                                          n_left_to_next, bi0, next0);
-       }
-
-      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
-    }
-
-  vlib_node_increment_counter (vm, hicn_pg_interest_node.index,
-                              HICNPG_ERROR_PROCESSED, pkts_processed);
-  vlib_node_increment_counter (vm, hicn_pg_interest_node.index,
-                              HICNPG_ERROR_DROPPED, pkts_dropped);
-  vlib_node_increment_counter (vm, hicn_pg_interest_node.index,
-                              HICNPG_ERROR_INTEREST_MSGS_GENERATED,
-                              interest_msgs_generated);
+/**
+ * Registered DPO type.
+ */
+dpo_type_t hicnpg_server_dpo_type;
 
-  return (frame->n_vectors);
+static void
+hicnpg_server_restack (hicnpg_server_t *hicnpg_server)
+{
+  dpo_stack (
+    hicnpg_server_dpo_type, fib_proto_to_dpo (hicnpg_server->prefix.fp_proto),
+    &hicnpg_server->dpo,
+    fib_entry_contribute_ip_forwarding (hicnpg_server->fib_entry_index));
 }
 
-void
-hicn_rewrite_interestv4 (vlib_main_t *vm, vlib_buffer_t *b0, u32 seq_number,
-                        u16 interest_lifetime, u32 next_flow, u32 iface)
+static hicnpg_server_t *
+hicnpg_server_from_fib_node (fib_node_t *node)
 {
-  hicn_header_t *h0 = vlib_buffer_get_current (b0);
-
-  /* Generate the right src and dst corresponding to flow and iface */
-  ip46_address_t src_addr = {
-    .ip4 = hicnpg_main.pgen_clt_src_addr.ip4,
-  };
-  hicn_name_t dst_name = {
-    .prefix.ip4 = hicnpg_main.pgen_clt_hicn_name->fp_addr.ip4,
-    .suffix = seq_number,
-  };
-
-  src_addr.ip4.as_u32 += clib_host_to_net_u32 (iface);
-  dst_name.prefix.ip4.as_u32 += clib_net_to_host_u32 (next_flow);
-
-  /* Update locator and name */
-  hicn_type_t type = hicn_get_buffer (b0)->type;
-  HICN_OPS4->set_interest_locator (type, &h0->protocol, &src_addr);
-  HICN_OPS4->set_interest_name (type, &h0->protocol, &dst_name);
-
-  /* Update lifetime  (currently L4 checksum is not updated) */
-  HICN_OPS4->set_lifetime (type, &h0->protocol, interest_lifetime);
-
-  /* Update checksums */
-  HICN_OPS4->update_checksums (type, &h0->protocol, 0, 0);
+  ASSERT (hicnpg_server_fib_node_type == node->fn_type);
+  return ((hicnpg_server_t *) (((char *) node) -
+                              STRUCT_OFFSET_OF (hicnpg_server_t, fib_node)));
 }
 
 /**
- * @brief Rewrite the IPv6 header as the next generated packet
- *
- * Set up a name prefix
- *  - etiher generate interest in which the name varies only after the prefix
- *  (inc : seq_number), then the flow acts on the prefix (CHECK)
- *  seq_number => TCP, FLOW =>
- *
- *  SRC : pgen_clt_src_addr.ip6 DST = generate name (pgen_clt_hicn_name.ip6)
- *  ffff:ffff:ffff:ffff         ffff:ffff:ffff:ffff
- *                 \__/                        \__/
- *                 +iface                      + flow
- *  Source is used to emulate different consumers.
- *    FIXME iface is ill-named, better name it consumer id
- *  Destination is used to iterate on the content.
+ * Function definition to backwalk a FIB node
  */
-void
-hicn_rewrite_interestv6 (vlib_main_t *vm, vlib_buffer_t *b0, u32 seq_number,
-                        u16 interest_lifetime, u32 next_flow, u32 iface)
+static fib_node_back_walk_rc_t
+hicnpg_server_fib_back_walk (fib_node_t *node, fib_node_back_walk_ctx_t *ctx)
 {
-  hicn_header_t *h0 = vlib_buffer_get_current (b0);
-
-  /* Generate the right src and dst corresponding to flow and iface */
-  ip46_address_t src_addr = {
-    .ip6 = hicnpg_main.pgen_clt_src_addr.ip6,
-  };
-  hicn_name_t dst_name = {
-    .prefix.ip6 = hicnpg_main.pgen_clt_hicn_name->fp_addr.ip6,
-    .suffix = seq_number,
-  };
-  src_addr.ip6.as_u32[3] += clib_host_to_net_u32 (iface);
-  dst_name.prefix.ip6.as_u32[3] += clib_net_to_host_u32 (next_flow);
+  hicnpg_server_restack (hicnpg_server_from_fib_node (node));
 
-  /* Update locator and name */
-  hicn_type_t type = hicn_get_buffer (b0)->type;
-  HICN_OPS6->set_interest_locator (type, &h0->protocol, &src_addr);
-  HICN_OPS6->set_interest_name (type, &h0->protocol, &dst_name);
-
-  /* Update lifetime */
-  HICN_OPS6->set_lifetime (type, &h0->protocol, interest_lifetime);
-
-  /* Update checksums */
-  calculate_tcp_checksum_v6 (vm, b0);
+  return FIB_NODE_BACK_WALK_CONTINUE;
 }
 
-void
-calculate_tcp_checksum_v4 (vlib_main_t *vm, vlib_buffer_t *b0)
+/**
+ * Function definition to get a FIB node from its index
+ */
+static fib_node_t *
+hicnpg_server_fib_node_get (fib_node_index_t index)
 {
-  ip4_header_t *ip0;
-  tcp_header_t *tcp0;
-  ip_csum_t sum0;
-  u32 tcp_len0;
-
-  ip0 = (ip4_header_t *) (vlib_buffer_get_current (b0));
-  tcp0 =
-    (tcp_header_t *) (vlib_buffer_get_current (b0) + sizeof (ip4_header_t));
-  tcp_len0 = clib_net_to_host_u16 (ip0->length) - sizeof (ip4_header_t);
-
-  /* Initialize checksum with header. */
-  if (BITS (sum0) == 32)
-    {
-      sum0 = clib_mem_unaligned (&ip0->src_address, u32);
-      sum0 =
-       ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->dst_address, u32));
-    }
-  else
-    sum0 = clib_mem_unaligned (&ip0->src_address, u64);
-
-  sum0 = ip_csum_with_carry (
-    sum0, clib_host_to_net_u32 (tcp_len0 + (ip0->protocol << 16)));
-
-  /* Invalidate possibly old checksum. */
-  tcp0->checksum = 0;
+  hicnpg_server_t *hpg_server;
 
-  u32 tcp_offset = sizeof (ip4_header_t);
-  sum0 = ip_incremental_checksum_buffer (vm, b0, tcp_offset, tcp_len0, sum0);
+  hpg_server = pool_elt_at_index (hicnpg_server_pool, index);
 
-  tcp0->checksum = ~ip_csum_fold (sum0);
+  return (&hpg_server->fib_node);
 }
 
-void
-calculate_tcp_checksum_v6 (vlib_main_t *vm, vlib_buffer_t *b0)
+/**
+ * Function definition to inform the FIB node that its last lock has gone.
+ */
+static void
+hicnpg_server_fib_last_lock_gone (fib_node_t *node)
 {
-  ip6_header_t *ip0;
-  tcp_header_t *tcp0;
-  ip_csum_t sum0;
-  u32 tcp_len0;
-
-  ip0 = (ip6_header_t *) (vlib_buffer_get_current (b0));
-  tcp0 =
-    (tcp_header_t *) (vlib_buffer_get_current (b0) + sizeof (ip6_header_t));
-  tcp_len0 = clib_net_to_host_u16 (ip0->payload_length);
+  hicnpg_server_t *hpg_server;
 
-  /* Initialize checksum with header. */
-  if (BITS (sum0) == 32)
-    {
-      sum0 = clib_mem_unaligned (&ip0->src_address, u32);
-      sum0 =
-       ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->dst_address, u32));
-    }
-  else
-    sum0 = clib_mem_unaligned (&ip0->src_address, u64);
-
-  sum0 = ip_csum_with_carry (
-    sum0, clib_host_to_net_u32 (tcp_len0 + (ip0->protocol << 16)));
+  hpg_server = hicnpg_server_from_fib_node (node);
 
-  /* Invalidate possibly old checksum. */
-  tcp0->checksum = 0;
-
-  u32 tcp_offset = sizeof (ip6_header_t);
-  sum0 = ip_incremental_checksum_buffer (vm, b0, tcp_offset, tcp_len0, sum0);
+  /**
+   * reset the stacked DPO to unlock it
+   */
+  dpo_reset (&hpg_server->dpo);
 
-  tcp0->checksum = ~ip_csum_fold (sum0);
+  pool_put (hicnpg_server_pool, hpg_server);
 }
 
-VLIB_REGISTER_NODE (hicn_pg_interest_node) = {
-  .function = hicnpg_client_interest_node_fn,
-  .name = "hicnpg-interest",
-  .vector_size = sizeof (u32),
-  .format_trace = format_hicnpg_trace,
-  .type = VLIB_NODE_TYPE_INTERNAL,
-  .n_errors = ARRAY_LEN (hicnpg_error_strings),
-  .error_strings = hicnpg_error_strings,
-  .n_next_nodes = HICNPG_N_NEXT,
-  .next_nodes = { [HICNPG_INTEREST_NEXT_V4_LOOKUP] = "ip4-lookup",
-                 [HICNPG_INTEREST_NEXT_V6_LOOKUP] = "ip6-lookup",
-                 [HICNPG_INTEREST_NEXT_DROP] = "error-drop" },
-};
-
-/*
- * Next graph nodes, which reference the list in the actual registration
- * block below
- */
-typedef enum
-{
-  HICNPG_DATA_NEXT_DROP,
-  HICNPG_DATA_NEXT_LOOKUP4,
-  HICNPG_DATA_NEXT_LOOKUP6,
-  HICNPG_DATA_N_NEXT,
-} hicnpg_data_next_t;
-
-/* Trace context struct */
-typedef struct
-{
-  u32 next_index;
-  u32 sw_if_index;
-  u8 pkt_type;
-  u16 msg_type;
-} icnpg_data_trace_t;
-
-/* packet trace format function */
-static u8 *
-format_hicnpg_data_trace (u8 *s, va_list *args)
+static void
+hicnpg_server_dpo_lock (dpo_id_t *dpo)
 {
-  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
-  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-  hicnpg_trace_t *t = va_arg (*args, hicnpg_trace_t *);
-
-  s = format (s, "HICNPG: pkt: %d, msg %d, sw_if_index %d, next index %d",
-             (int) t->pkt_type, (int) t->msg_type, t->sw_if_index,
-             t->next_index);
-  return (s);
+  hicnpg_server_t *hpg_server;
+  hpg_server = hicnpg_server_get (dpo->dpoi_index);
+  fib_node_lock (&hpg_server->fib_node);
 }
 
-static_always_inline int
-match_ip4_name (u32 *name, fib_prefix_t *prefix)
+static void
+hicnpg_server_dpo_unlock (dpo_id_t *dpo)
 {
-  u32 xor = 0;
-
-  xor = *name & prefix->fp_addr.ip4.data_u32;
-
-  return xor == prefix->fp_addr.ip4.data_u32;
+  hicnpg_server_t *hpg_server;
+  hpg_server = hicnpg_server_get (dpo->dpoi_index);
+  fib_node_unlock (&hpg_server->fib_node);
 }
 
-static_always_inline int
-match_ip6_name (u8 *name, fib_prefix_t *prefix)
+static u8 *
+format_hicnpg_server_i (u8 *s, va_list *args)
 {
-  union
-  {
-    u32x4 as_u32x4;
-    u64 as_u64[2];
-    u32 as_u32[4];
-  } xor_sum __attribute__ ((aligned (sizeof (u32x4))));
+  index_t hicnpg_server_i = va_arg (*args, index_t);
+  //   u32 indent = va_arg (*args, u32);
+  u32 details = va_arg (*args, u32);
+  //   vlib_counter_t to;
+  hicnpg_server_t *hpg;
 
-  xor_sum.as_u64[0] = ((u64 *) name)[0] & prefix->fp_addr.ip6.as_u64[0];
-  xor_sum.as_u64[1] = ((u64 *) name)[1] & prefix->fp_addr.ip6.as_u64[1];
+  hpg = hicnpg_server_get (hicnpg_server_i);
 
-  return (xor_sum.as_u64[0] == prefix->fp_addr.ip6.as_u64[0]) &&
-        (xor_sum.as_u64[1] == prefix->fp_addr.ip6.as_u64[1]);
-}
-
-/*
- * Return 0,1,2.
- * 0 matches
- * 1 does not match and the prefix is ip4
- * 2 does not match and the prefix is ip6
- */
-static_always_inline u32
-match_data (vlib_buffer_t *b, fib_prefix_t *prefix)
-{
-  u8 *ptr = vlib_buffer_get_current (b);
-  u8 v = *ptr & 0xf0;
-  u32 next = 0;
+  // FIXME
+  s = format (s, "dpo-hicnpg-server:[%d]: ip-fib-index:%d ", hicnpg_server_i,
+             hpg->fib_index);
 
-  if (PREDICT_TRUE (v == 0x40 && ip46_address_is_ip4 (&prefix->fp_addr)))
+  if (FIB_PROTOCOL_IP4 == hpg->prefix.fp_proto)
     {
-      if (!match_ip4_name ((u32 *) &(ptr[12]), prefix))
-       next = 1;
+      s = format (s, "protocol:FIB_PROTOCOL_IP4  prefix: %U",
+                 format_fib_prefix, &hpg->prefix);
     }
-  else if (PREDICT_TRUE (v == 0x60 && !ip46_address_is_ip4 (&prefix->fp_addr)))
+  else
     {
-      if (!match_ip6_name (&(ptr[8]), prefix))
-       next = 2;
+      s = format (s, "protocol:FIB_PROTOCOL_IP6  prefix: %U",
+                 format_fib_prefix, &hpg->prefix);
     }
 
-  return next;
-}
-
-/*
- * Return 0,1,2.
- * 0 matches
- * 1 does not match and the prefix is ip4
- * 2 does not match and the prefix is ip6
- */
-static_always_inline u32
-match_interest (vlib_buffer_t *b, fib_prefix_t *prefix)
-{
-  u8 *ptr = vlib_buffer_get_current (b);
-  u8 v = *ptr & 0xf0;
-  u32 next = 0;
+#if 0
+  vlib_get_combined_counter (&(udp_encap_counters), uei, &to);
+  s = format (s, " to:[%Ld:%Ld]]", to.packets, to.bytes);s
+#endif
 
-  if (PREDICT_TRUE (v == 0x40 && ip46_address_is_ip4 (&prefix->fp_addr)))
-    {
-      if (!match_ip4_name ((u32 *) &(ptr[16]), prefix))
-       next = 1;
-    }
-  else if (PREDICT_TRUE (v == 0x60 && !ip46_address_is_ip4 (&prefix->fp_addr)))
+  if (details)
     {
-      if (!match_ip6_name (&(ptr[24]), prefix))
-       next = 2;
+      s = format (s, " locks:%d", hpg->fib_node.fn_locks);
+      //       s = format (s, "\n%UStacked on:", format_white_space, indent +
+      //       1); s = format (s, "\n%U%U", format_white_space, indent + 2,
+      //       format_dpo_id,
+      //                 &hpg->dpo, indent + 3);
     }
 
-  return next;
+  return s;
 }
 
-/*
- * Node function for the icn packet-generator client. The goal here is to
- * manipulate/tweak a stream of packets that have been injected by the vpp
- * packet generator to generate icn request traffic.
- */
-static uword
-hicnpg_client_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
-                           vlib_frame_t *frame)
+static u8 *
+format_hicnpg_server_dpo (u8 *s, va_list *args)
 {
-  u32 n_left_from, *from, *to_next;
-  hicnpg_data_next_t next_index;
-  u32 pkts_processed = 0;
-  u32 content_msgs_received = 0;
-  u32 bi0, bi1;
-  vlib_buffer_t *b0, *b1;
-  u8 pkt_type0 = 0, pkt_type1 = 0;
-  u16 msg_type0 = 1, msg_type1 = 1;
-  hicnpg_main_t *hpgm = &hicnpg_main;
-
-  from = vlib_frame_vector_args (frame);
-  n_left_from = frame->n_vectors;
-  next_index = node->cached_next_index;
-
-  while (n_left_from > 0)
-    {
-      u32 n_left_to_next;
-      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
-
-      while (n_left_from >= 4 && n_left_to_next >= 2)
-       {
-         u32 next0 = HICNPG_DATA_NEXT_DROP;
-         u32 next1 = HICNPG_DATA_NEXT_DROP;
-         u32 sw_if_index0, sw_if_index1;
-
-         /* Prefetch next iteration. */
-         {
-           vlib_buffer_t *p2, *p3;
-
-           p2 = vlib_get_buffer (vm, from[2]);
-           p3 = vlib_get_buffer (vm, from[3]);
-
-           vlib_prefetch_buffer_header (p2, LOAD);
-           vlib_prefetch_buffer_header (p3, LOAD);
-
-           CLIB_PREFETCH (p2->data, (2 * CLIB_CACHE_LINE_BYTES), STORE);
-           CLIB_PREFETCH (p3->data, (2 * CLIB_CACHE_LINE_BYTES), STORE);
-         }
-
-         /*
-          * speculatively enqueue b0 and b1 to the current
-          * next frame
-          */
-         to_next[0] = bi0 = from[0];
-         to_next[1] = bi1 = from[1];
-         from += 2;
-         to_next += 2;
-         n_left_from -= 2;
-         n_left_to_next -= 2;
-
-         b0 = vlib_get_buffer (vm, bi0);
-         b1 = vlib_get_buffer (vm, bi1);
-
-         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-         sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
-
-         next0 =
-           HICNPG_DATA_NEXT_DROP + match_data (b0, hpgm->pgen_clt_hicn_name);
-         next1 =
-           HICNPG_DATA_NEXT_DROP + match_data (b1, hpgm->pgen_clt_hicn_name);
-
-         if (PREDICT_FALSE (vnet_get_feature_count (
-                              vnet_buffer (b0)->feature_arc_index,
-                              vnet_buffer (b0)->sw_if_index[VLIB_RX]) > 1))
-           vnet_feature_next (&next0, b0);
-
-         if (PREDICT_FALSE (vnet_get_feature_count (
-                              vnet_buffer (b1)->feature_arc_index,
-                              vnet_buffer (b1)->sw_if_index[VLIB_RX]) > 1))
-           vnet_feature_next (&next1, b1);
-
-         if (next0 == HICNPG_DATA_NEXT_DROP)
-           {
-             /* Increment a counter */
-             content_msgs_received++;
-           }
-
-         if (next1 == HICNPG_DATA_NEXT_DROP)
-           {
-             /* Increment a counter */
-             content_msgs_received++;
-           }
-
-         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
-           {
-             if (b0->flags & VLIB_BUFFER_IS_TRACED)
-               {
-                 icnpg_data_trace_t *t =
-                   vlib_add_trace (vm, node, b0, sizeof (*t));
-                 t->pkt_type = pkt_type0;
-                 t->msg_type = msg_type0;
-                 t->sw_if_index = sw_if_index0;
-                 t->next_index = next0;
-               }
-             if (b1->flags & VLIB_BUFFER_IS_TRACED)
-               {
-                 icnpg_data_trace_t *t =
-                   vlib_add_trace (vm, node, b1, sizeof (*t));
-                 t->pkt_type = pkt_type1;
-                 t->msg_type = msg_type1;
-                 t->sw_if_index = sw_if_index1;
-                 t->next_index = next1;
-               }
-           }
-
-         vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
-                                          n_left_to_next, bi0, bi1, next0,
-                                          next1);
-         pkts_processed += 2;
-       }
-
-      while (n_left_from > 0 && n_left_to_next > 0)
-       {
-         u32 next0 = HICNPG_DATA_NEXT_DROP;
-         u32 sw_if_index0;
-
-         /* speculatively enqueue b0 to the current next frame */
-         bi0 = from[0];
-         to_next[0] = bi0;
-         from += 1;
-         to_next += 1;
-         n_left_from -= 1;
-         n_left_to_next -= 1;
-
-         b0 = vlib_get_buffer (vm, bi0);
-
-         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-
-         next0 =
-           HICNPG_DATA_NEXT_DROP + match_data (b0, hpgm->pgen_clt_hicn_name);
-
-         if (PREDICT_FALSE (vnet_get_feature_count (
-                              vnet_buffer (b0)->feature_arc_index,
-                              vnet_buffer (b0)->sw_if_index[VLIB_RX]) > 1))
-           vnet_feature_next (&next0, b0);
+  index_t hpg_server_i = va_arg (*args, index_t);
+  u32 indent = va_arg (*args, u32);
 
-         if (next0 == HICNPG_DATA_NEXT_DROP)
-           {
-             /* Increment a counter */
-             content_msgs_received++;
-           }
-
-         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
-                            (b0->flags & VLIB_BUFFER_IS_TRACED)))
-           {
-             icnpg_data_trace_t *t =
-               vlib_add_trace (vm, node, b0, sizeof (*t));
-             t->pkt_type = pkt_type0;
-             t->msg_type = msg_type0;
-             t->sw_if_index = sw_if_index0;
-             t->next_index = next0;
-           }
-
-         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
-                                          n_left_to_next, bi0, next0);
-
-         pkts_processed++;
-       }
-      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
-    }
-
-  vlib_node_increment_counter (vm, hicn_pg_data_node.index,
-                              HICNPG_ERROR_PROCESSED, pkts_processed);
-  vlib_node_increment_counter (vm, hicn_pg_data_node.index,
-                              HICNPG_ERROR_CONTENT_MSGS_RECEIVED,
-                              content_msgs_received);
-  return (frame->n_vectors);
+  return (format (s, "%U", format_hicnpg_server_i, hpg_server_i, indent, 1));
 }
 
-VLIB_REGISTER_NODE(hicn_pg_data_node) =
-{
-  .function = hicnpg_client_data_node_fn,
-  .name = "hicnpg-data",
-  .vector_size = sizeof(u32),
-  .format_trace = format_hicnpg_data_trace,
-  .type = VLIB_NODE_TYPE_INTERNAL,
-  .n_errors = ARRAY_LEN(hicnpg_error_strings),
-  .error_strings = hicnpg_error_strings,
-  .n_next_nodes = HICNPG_DATA_N_NEXT,
-  .next_nodes =
-  {
-   [HICNPG_DATA_NEXT_DROP] = "error-drop",
-   [HICNPG_DATA_NEXT_LOOKUP4] = "ip4-lookup",
-   [HICNPG_DATA_NEXT_LOOKUP6] = "ip6-lookup",
-  },
+/*
+ * Virtual function table registered by hicn pg server
+ * for participation in the FIB object graph.
+ */
+const static fib_node_vft_t hicnpg_server_fib_vft = {
+  .fnv_get = hicnpg_server_fib_node_get,
+  .fnv_last_lock = hicnpg_server_fib_last_lock_gone,
+  .fnv_back_walk = hicnpg_server_fib_back_walk,
 };
 
-VNET_FEATURE_INIT (hicn_data_input_ip4_arc, static) = {
-  .arc_name = "ip4-unicast",
-  .node_name = "hicnpg-data",
-  .runs_before = VNET_FEATURES ("ip4-inacl"),
+const static dpo_vft_t hicnpg_server_dpo_vft = {
+  .dv_lock = hicnpg_server_dpo_lock,
+  .dv_unlock = hicnpg_server_dpo_unlock,
+  .dv_format = format_hicnpg_server_dpo,
 };
 
-VNET_FEATURE_INIT (hicn_data_input_ip6_arc, static) = {
-  .arc_name = "ip6-unicast",
-  .node_name = "hicnpg-data",
-  .runs_before = VNET_FEATURES ("ip6-inacl"),
+const static char *const hicnpg_server_ip4_nodes[] = {
+  "hicnpg-server-4",
+  NULL,
 };
 
-/*
- * End of packet-generator client node
- */
-
-/*
- * Beginning of packet-generation server node
- */
-
-/* Registration struct for a graph node */
-vlib_node_registration_t hicn_pg_server_node;
-
-/* Stats, which end up called "error" even though they aren't... */
-#define foreach_icnpg_server_error                                            \
-  _ (PROCESSED, "hICN PG Server packets processed")                           \
-  _ (DROPPED, "hICN PG Server packets dropped")
-
-typedef enum
-{
-#define _(sym, str) HICNPG_SERVER_ERROR_##sym,
-  foreach_icnpg_server_error
-#undef _
-    HICNPG_SERVER_N_ERROR,
-} icnpg_server_error_t;
-
-static char *icnpg_server_error_strings[] = {
-#define _(sym, string) string,
-  foreach_icnpg_server_error
-#undef _
+const static char *const hicnpg_server_ip6_nodes[] = {
+  "hicnpg-server-6",
+  NULL,
 };
 
-/*
- * Next graph nodes, which reference the list in the actual registration
- * block below
- */
-typedef enum
-{
-  HICNPG_SERVER_NEXT_V4_LOOKUP,
-  HICNPG_SERVER_NEXT_V6_LOOKUP,
-  HICNPG_SERVER_NEXT_DROP,
-  HICNPG_SERVER_N_NEXT,
-} icnpg_server_next_t;
-
-/* Trace context struct */
-typedef struct
-{
-  u32 next_index;
-  u32 sw_if_index;
-  u8 pkt_type;
-  u16 msg_type;
-} hicnpg_server_trace_t;
+const static char *const *const hicnpg_server_nodes[DPO_PROTO_NUM] = {
+  [DPO_PROTO_IP4] = hicnpg_server_ip4_nodes,
+  [DPO_PROTO_IP6] = hicnpg_server_ip6_nodes
+};
 
-/* packet trace format function */
-static u8 *
-format_icnpg_server_trace (u8 *s, va_list *args)
+clib_error_t *
+hicnpg_server_add_and_lock (fib_prefix_t *prefix, u32 *hicnpg_server_index,
+                           ip46_address_t *locator, size_t payload_size)
 {
-  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
-  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-  hicnpg_server_trace_t *t = va_arg (*args, hicnpg_server_trace_t *);
+  hicnpg_server_t *hpg;
+  index_t hpgi;
+  u32 fib_index;
+  fib_node_index_t fib_entry_index;
+  u32 buffer_index;
+  vlib_buffer_t *rb = NULL;
 
-  s = format (
-    s, "HICNPG SERVER: pkt: %d, msg %d, sw_if_index %d, next index %d",
-    (int) t->pkt_type, (int) t->msg_type, t->sw_if_index, t->next_index);
-  return (s);
-}
+  // Retrieve hicn fib table
+  fib_index =
+    fib_table_find_or_create_and_lock (prefix->fp_proto, 0, hicn_fib_src);
 
-/*
- * Node function for the icn packet-generator server.
- */
-static uword
-hicnpg_node_server_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
-                      vlib_frame_t *frame)
-{
-  u32 n_left_from, *from, *to_next;
-  icnpg_server_next_t next_index;
-  u32 pkts_processed = 0, pkts_dropped = 0;
-  u32 bi0, bi1;
-  vlib_buffer_t *b0, *b1;
-  u8 pkt_type0 = 0, pkt_type1 = 0;
-  u16 msg_type0 = 0, msg_type1 = 0;
-  hicn_header_t *hicn0 = NULL, *hicn1 = NULL;
-  hicn_name_t name0, name1;
-  u16 namelen0, namelen1;
+  // Check the prefix we are adding is not already in the table
+  fib_entry_index = fib_table_lookup_exact_match (fib_index, prefix);
 
-  hicnpg_server_main_t *hpgsm = &hicnpg_server_main;
-
-  from = vlib_frame_vector_args (frame);
-
-  n_left_from = frame->n_vectors;
-  next_index = node->cached_next_index;
-
-  while (n_left_from > 0)
+  if (fib_entry_index != FIB_NODE_INDEX_INVALID)
     {
-      u32 n_left_to_next;
-
-      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
-
-      while (n_left_from >= 4 && n_left_to_next >= 2)
-       {
-         u32 next0 = HICNPG_SERVER_NEXT_DROP;
-         u32 next1 = HICNPG_SERVER_NEXT_DROP;
-         u8 isv6_0 = 0;
-         u8 isv6_1 = 0;
-         u32 sw_if_index0, sw_if_index1;
-
-         /* Prefetch next iteration. */
-         {
-           vlib_buffer_t *p2, *p3;
-
-           p2 = vlib_get_buffer (vm, from[2]);
-           p3 = vlib_get_buffer (vm, from[3]);
-
-           vlib_prefetch_buffer_header (p2, LOAD);
-           vlib_prefetch_buffer_header (p3, LOAD);
-
-           CLIB_PREFETCH (p2->data, (2 * CLIB_CACHE_LINE_BYTES), STORE);
-           CLIB_PREFETCH (p3->data, (2 * CLIB_CACHE_LINE_BYTES), STORE);
-         }
-
-         /*
-          * speculatively enqueue b0 and b1 to the current
-          * next frame
-          */
-         to_next[0] = bi0 = from[0];
-         to_next[1] = bi1 = from[1];
-         from += 2;
-         to_next += 2;
-         n_left_from -= 2;
-         n_left_to_next -= 2;
-
-         b0 = vlib_get_buffer (vm, bi0);
-         b1 = vlib_get_buffer (vm, bi1);
-
-         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-         sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
-
-         vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
-         vnet_buffer (b1)->sw_if_index[VLIB_TX] = ~0;
-
-         u32 match0 = match_interest (b0, hpgsm->pgen_srv_hicn_name);
-         u32 match1 = match_interest (b1, hpgsm->pgen_srv_hicn_name);
-
-         if (match0)
-           {
-             next0 = match0 - 1;
-           }
-         else if (hicn_interest_parse_pkt (b0, &name0, &namelen0, &hicn0,
-                                           &isv6_0) == HICN_ERROR_NONE)
-           {
-             /* this node grabs only interests */
-             vlib_buffer_t *rb = NULL;
-             rb = vlib_get_buffer (vm, hpgsm->pgen_svr_buffer_idx);
-
-             isv6_0 ? convert_interest_to_data_v6 (vm, b0, rb, bi0) :
-                            convert_interest_to_data_v4 (vm, b0, rb, bi0);
-
-             next0 = isv6_0 ? HICNPG_SERVER_NEXT_V6_LOOKUP :
-                                    HICNPG_SERVER_NEXT_V4_LOOKUP;
-           }
-
-         if (match1)
-           {
-             next1 = match1 - 1;
-           }
-         else if (hicn_interest_parse_pkt (b1, &name1, &namelen1, &hicn1,
-                                           &isv6_1) == HICN_ERROR_NONE)
-           {
-             /* this node grabs only interests */
-             vlib_buffer_t *rb = NULL;
-             rb = vlib_get_buffer (vm, hpgsm->pgen_svr_buffer_idx);
-
-             isv6_1 ? convert_interest_to_data_v6 (vm, b1, rb, bi1) :
-                            convert_interest_to_data_v4 (vm, b1, rb, bi1);
-
-             next1 = isv6_1 ? HICNPG_SERVER_NEXT_V6_LOOKUP :
-                                    HICNPG_SERVER_NEXT_V4_LOOKUP;
-           }
-         pkts_processed += 2;
-
-         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
-           {
-             if (b0->flags & VLIB_BUFFER_IS_TRACED)
-               {
-                 hicnpg_server_trace_t *t =
-                   vlib_add_trace (vm, node, b0, sizeof (*t));
-                 t->pkt_type = pkt_type0;
-                 t->msg_type = msg_type0;
-                 t->sw_if_index = sw_if_index0;
-                 t->next_index = next0;
-               }
-             if (b1->flags & VLIB_BUFFER_IS_TRACED)
-               {
-                 hicnpg_server_trace_t *t =
-                   vlib_add_trace (vm, node, b1, sizeof (*t));
-                 t->pkt_type = pkt_type1;
-                 t->msg_type = msg_type1;
-                 t->sw_if_index = sw_if_index1;
-                 t->next_index = next1;
-               }
-           }
-         if (next0 == HICNPG_SERVER_NEXT_DROP)
-           {
-             pkts_dropped++;
-           }
-         if (next1 == HICNPG_SERVER_NEXT_DROP)
-           {
-             pkts_dropped++;
-           }
-         /*
-          * verify speculative enqueues, maybe switch current
-          * next frame
-          */
-         vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
-                                          n_left_to_next, bi0, bi1, next0,
-                                          next1);
-       }
-
-      while (n_left_from > 0 && n_left_to_next > 0)
-       {
-         u32 next0 = HICNPG_SERVER_NEXT_DROP;
-         u32 sw_if_index0 = ~0;
-         u8 isv6_0 = 0;
-
-         /* speculatively enqueue b0 to the current next frame */
-         bi0 = from[0];
-         to_next[0] = bi0;
-         from += 1;
-         to_next += 1;
-         n_left_from -= 1;
-         n_left_to_next -= 1;
-
-         b0 = vlib_get_buffer (vm, bi0);
-
-         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-         vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
-
-         u32 match0 = match_interest (b0, hpgsm->pgen_srv_hicn_name);
-
-         if (match0)
-           {
-             next0 = match0 - 1;
-           }
-         else if (hicn_interest_parse_pkt (b0, &name0, &namelen0, &hicn0,
-                                           &isv6_0) == HICN_ERROR_NONE)
-           {
-             /* this node grabs only interests */
-             vlib_buffer_t *rb = NULL;
-             rb = vlib_get_buffer (vm, hpgsm->pgen_svr_buffer_idx);
-
-             isv6_0 ? convert_interest_to_data_v6 (vm, b0, rb, bi0) :
-                            convert_interest_to_data_v4 (vm, b0, rb, bi0);
-
-             next0 = isv6_0 ? HICNPG_SERVER_NEXT_V6_LOOKUP :
-                                    HICNPG_SERVER_NEXT_V4_LOOKUP;
-           }
-         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
-                            (b0->flags & VLIB_BUFFER_IS_TRACED)))
-           {
-             hicnpg_server_trace_t *t =
-               vlib_add_trace (vm, node, b0, sizeof (*t));
-             t->pkt_type = pkt_type0;
-             t->msg_type = msg_type0;
-             t->sw_if_index = sw_if_index0;
-             t->next_index = next0;
-           }
-         pkts_processed += 1;
-
-         if (next0 == HICNPG_SERVER_NEXT_DROP)
-           {
-             pkts_dropped++;
-           }
-         /*
-          * verify speculative enqueue, maybe switch current
-          * next frame
-          */
-         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
-                                          n_left_to_next, bi0, next0);
-       }
-
-      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+      // Route already existing.
+      return clib_error_return (0, "Route exist already.");
     }
 
-  vlib_node_increment_counter (vm, hicn_pg_server_node.index,
-                              HICNPG_SERVER_ERROR_PROCESSED, pkts_processed);
-  vlib_node_increment_counter (vm, hicn_pg_server_node.index,
-                              HICNPG_SERVER_ERROR_DROPPED, pkts_dropped);
-
-  return (frame->n_vectors);
-}
-
-void
-convert_interest_to_data_v4 (vlib_main_t *vm, vlib_buffer_t *b0,
-                            vlib_buffer_t *rb, u32 bi0)
-{
-  hicn_header_t *h0 = vlib_buffer_get_current (b0);
-
-  /* Get the packet length */
-  u16 pkt_len = clib_net_to_host_u16 (h0->v4.ip.len);
+  // Allocate packet buffer
+  int n_buf = vlib_buffer_alloc (vlib_get_main (), &buffer_index, 1);
 
-  /*
-   * Rule of thumb: We want the size of the IP packet to be <= 1500 bytes
-   */
-  u16 bytes_to_copy = rb->current_length;
-  if ((bytes_to_copy + pkt_len) > 1500)
+  if (n_buf == 0)
     {
-      bytes_to_copy = 1500 - pkt_len;
+      return clib_error_return (0, "Impossible to allocate paylod buffer.");
     }
-  /* Add content to the data packet */
-  vlib_buffer_add_data (vm, &bi0, rb->data, bytes_to_copy);
 
-  b0 = vlib_get_buffer (vm, bi0);
-
-  h0 = vlib_buffer_get_current (b0);
-
-  ip4_address_t src_addr = h0->v4.ip.saddr;
-  h0->v4.ip.saddr = h0->v4.ip.daddr;
-  h0->v4.ip.daddr = src_addr;
-
-  h0->v4.ip.len = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
-  h0->v4.ip.csum = ip4_header_checksum ((ip4_header_t *) &(h0->v4.ip));
-  calculate_tcp_checksum_v4 (vm, b0);
+  // Initialize the buffer data with zeros
+  rb = vlib_get_buffer (vlib_get_main (), buffer_index);
+  memset (rb->data, 0, payload_size);
+  rb->current_length = payload_size;
+
+  // We can proceed. Get a new hicnpg_server_t
+  pool_get_aligned_zero (hicnpg_server_pool, hpg, 2 * CLIB_CACHE_LINE_BYTES);
+  hpgi = hpg - hicnpg_server_pool;
+
+  // Set DPO
+  dpo_set (
+    &hpg->dpo, hicnpg_server_dpo_type,
+    (ip46_address_is_ip4 (&prefix->fp_addr) ? DPO_PROTO_IP4 : DPO_PROTO_IP6),
+    hpgi);
+
+  // Add the route via the hicnpg_server_dpo_type. In this way packets will
+  // endup in the hicnpg_server node
+  CLIB_UNUSED (fib_node_index_t new_fib_node_index) =
+    fib_table_entry_special_dpo_add (
+      fib_index, prefix, hicn_fib_src,
+      (FIB_ENTRY_FLAG_EXCLUSIVE | FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT),
+      &hpg->dpo);
+
+#if 0
+  vlib_validate_combined_counter (&(udp_encap_counters), uei);
+  vlib_zero_combined_counter (&(udp_encap_counters), uei);
+#endif
+
+  // Init remaining struct fields
+  fib_node_init (&hpg->fib_node, hicnpg_server_fib_node_type);
+  fib_node_lock (&hpg->fib_node);
+  hpg->fib_index = fib_index;
+  hpg->prefix = *prefix;
+  hpg->buffer_index = buffer_index;
+  hpg->fib_entry_index = fib_entry_index;
+  hpg->hicn_locator = *locator;
+
+  // track the destination address
+  //   hpg->fib_entry_index =
+  //     fib_entry_track (fib_index, &hpg->prefix,
+  //                hicnpg_server_fib_node_type, hpgi, &hpg->fib_sibling);
+  //   hicnpg_server_restack (hpg);
+
+  HICN_DEBUG ("Calling hicn enable for pg-server face");
+
+  hicn_face_id_t *vec_faces = NULL;
+  hicn_route_enable (prefix, &vec_faces);
+  if (vec_faces != NULL)
+    vec_free (vec_faces);
+
+  // Return the index of the hicnpg_server_t
+  *hicnpg_server_index = hpgi;
+
+  return NULL;
 }
 
-void
-convert_interest_to_data_v6 (vlib_main_t *vm, vlib_buffer_t *b0,
-                            vlib_buffer_t *rb, u32 bi0)
+clib_error_t *
+hicn_pg_init (vlib_main_t *vm)
 {
-  hicn_header_t *h0 = vlib_buffer_get_current (b0);
-
-  /* Get the packet length */
-  uint16_t pkt_len =
-    clib_net_to_host_u16 (h0->v6.ip.len) + sizeof (ip6_header_t);
+  hicnpg_server_fib_node_type = fib_node_register_new_type (
+    "hicnpg_server_fib_node", &hicnpg_server_fib_vft);
 
-  /*
-   * Figure out how many bytes we can add to the content
-   *
-   * Rule of thumb: We want the size of the IP packet to be <= 1400 bytes
-   */
-  u16 bytes_to_copy = rb->current_length;
-  if ((bytes_to_copy + pkt_len) > 1500)
-    {
-      bytes_to_copy = 1500 - pkt_len;
-    }
-  /* Add content to the data packet */
-  vlib_buffer_add_data (vm, &bi0, rb->data, bytes_to_copy);
+  hicnpg_server_dpo_type =
+    dpo_register_new_type (&hicnpg_server_dpo_vft, hicnpg_server_nodes);
 
-  b0 = vlib_get_buffer (vm, bi0);
-
-  h0 = vlib_buffer_get_current (b0);
-  ip6_address_t src_addr = h0->v6.ip.saddr;
-  h0->v6.ip.saddr = h0->v6.ip.daddr;
-  h0->v6.ip.daddr = src_addr;
-
-  h0->v6.ip.len = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
-                                       sizeof (ip6_header_t));
-  h0->v6.tcp.data_offset_and_reserved |= 0x0f;
-  h0->v6.tcp.urg_ptr = htons (0xffff);
-
-  calculate_tcp_checksum_v6 (vm, b0);
+  return NULL;
 }
 
-VLIB_REGISTER_NODE(hicn_pg_server_node) =
-{
-  .function = hicnpg_node_server_fn,
-  .name = "hicnpg-server",
-  .vector_size = sizeof(u32),
-  .format_trace = format_icnpg_server_trace,
-  .type = VLIB_NODE_TYPE_INTERNAL,
-  .n_errors = ARRAY_LEN(icnpg_server_error_strings),
-  .error_strings = icnpg_server_error_strings,
-  .n_next_nodes = HICNPG_SERVER_N_NEXT,
-  /* edit / add dispositions here */
-  .next_nodes =
-  {
-    [HICNPG_SERVER_NEXT_V4_LOOKUP] = "ip4-lookup",
-    [HICNPG_SERVER_NEXT_V6_LOOKUP] = "ip6-lookup",
-    [HICNPG_SERVER_NEXT_DROP] = "error-drop",
-  },
-};
-
-VNET_FEATURE_INIT (hicn_pg_server_ip6, static) = {
-  .arc_name = "ip6-unicast",
-  .node_name = "hicnpg-server",
-  .runs_before = VNET_FEATURES ("ip6-inacl"),
-};
-
-VNET_FEATURE_INIT (hicn_pg_server_ip4, static) = {
-  .arc_name = "ip4-unicast",
-  .node_name = "hicnpg-server",
-  .runs_before = VNET_FEATURES ("ip4-inacl"),
-};
-
-/*
- * End of packet-generator server node
- */
-
 /*
  * fd.io coding-style-patch-verification: ON
  *
  * Local Variables: eval: (c-set-style "gnu") End:
- */
+ */
\ No newline at end of file
index 7855248..deb5857 100644 (file)
@@ -16,6 +16,8 @@
 #ifndef __HICN_PG_H__
 #define __HICN_PG_H__
 
+#include <vppinfra/pool.h>
+
 /**
  * @file pg.h
  *
  */
 typedef struct hicnpg_main_s
 {
-  u32 index;                       // used to compute the sequence number
-  fib_prefix_t *pgen_clt_hicn_name; // hICN name to put in the destiantion
-                                   // addess of an interest
-  u32
-    index_ifaces; /* used to mimic interests coming from different consumer */
-  u32 n_ifaces; /* The source address will change from interest to interest */
-  /* index_ifaces is used to keep a global reference to the iface used */
-  /* and it is incremented when we want to change "consumer" */
-  /* n_ifaces identifies how many consumers to simulate */
-  u32 max_seq_number; // Use to limit the max sequence number
-  u32 n_flows; // Use to simulate multiple flows (a flow always have the same
-              // hICN name)
-  ip46_address_t pgen_clt_src_addr; // Source addess base to use in the
-                                   // interest
-
-  u16 interest_lifetime; // Interest lifetime
-  u32 sw_if;            // Interface where to send interest and receives data
+  /*
+   * used to compute the sequence number
+   */
+  u32 index;
+
+  /*
+   * hICN name to put in the destination addess of an interest
+   */
+  fib_prefix_t *pgen_clt_hicn_name;
+
+  /*
+   * Used to mimic interests coming from different consumer. The source address
+   * will change from interest to interest index_ifaces is used to keep a
+   * global reference to the iface used and it is incremented when we want to
+   * change "consumer"
+   */
+  u32 index_ifaces;
+
+  /*
+   * n_ifaces identifies how many consumers to simulate
+   */
+  u32 n_ifaces;
+
+  /*
+   * Use to limit the max sequence number
+   */
+  u32 max_seq_number;
+
+  /*
+   * Use to simulate multiple flows (a flow always have the same hICN name)
+   */
+  u32 n_flows;
+
+  /*
+   * Source addess base to use in the interest
+   */
+  ip46_address_t pgen_clt_src_addr;
+
+  /*
+   * Interest lifetime
+   */
+  u16 interest_lifetime;
+
+  /*
+   * Interface where to send interest and receives data.
+   */
+  u32 sw_if;
+
+  /*
+   * Fib node type
+   */
+  fib_node_type_t hicn_fib_node_type;
 } hicnpg_main_t;
 
 extern hicnpg_main_t hicnpg_main;
@@ -83,18 +120,75 @@ extern hicnpg_main_t hicnpg_main;
  *
  * It stores the configuration and make it availables to the pg server node.
  */
-typedef struct hicnpg_server_main_s
+typedef struct hicnpg_server_s
 {
-  u32 node_index;
-  /* Arbitrary content */
-  u32 pgen_svr_buffer_idx;
-  fib_prefix_t *pgen_srv_hicn_name;
-} hicnpg_server_main_t;
+  /*
+   * Prefix served by this packet generator server
+   */
+  fib_prefix_t prefix;
+
+  /*
+   * IP address to put in the destination addess of the data
+   */
+  ip46_address_t hicn_locator;
+
+  /*
+   * Buffer index
+   */
+  u32 buffer_index;
+
+  /**
+   * The DPO used to forward to the next node in the VLIB graph
+   */
+  dpo_id_t dpo;
 
-extern hicnpg_server_main_t hicnpg_server_main;
+  /*
+   * linkage into the FIB graph
+   */
+  fib_node_t fib_node;
 
+  /*
+   * Tracking information for the IP destination
+   */
+  fib_node_index_t fib_entry_index;
+
+  /*
+   * The FIB index
+   */
+  index_t fib_index;
+} hicnpg_server_t;
+
+STATIC_ASSERT (sizeof (hicnpg_server_t) <= 2 * CLIB_CACHE_LINE_BYTES,
+              "hicnpg_server_t is too large");
+
+extern hicnpg_server_t hicnpg_server_main;
 extern vlib_node_registration_t hicn_pg_interest_node;
 extern vlib_node_registration_t hicn_pg_data_node;
+extern dpo_type_t hicnpg_server_dpo_type;
+
+/**
+ * Pool of hicnpg_servers
+ */
+extern hicnpg_server_t *hicnpg_server_pool;
+
+always_inline hicnpg_server_t *
+hicnpg_server_get (index_t hpgi)
+{
+  return pool_elt_at_index (hicnpg_server_pool, hpgi);
+}
+
+always_inline u8
+dpo_is_pgserver (const dpo_id_t *dpo)
+{
+  return (dpo->dpoi_type == hicnpg_server_dpo_type);
+}
+
+clib_error_t *hicnpg_server_add_and_lock (fib_prefix_t *prefix,
+                                         u32 *hicnpg_server_index,
+                                         ip46_address_t *locator,
+                                         size_t payload_size);
+
+clib_error_t *hicn_pg_init (vlib_main_t *vm);
 
 #endif // __HICN_PG_H__
 
diff --git a/hicn-plugin/src/pg_node.c b/hicn-plugin/src/pg_node.c
new file mode 100644 (file)
index 0000000..3672a6b
--- /dev/null
@@ -0,0 +1,1132 @@
+/*
+ * 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 <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/pg/pg.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ethernet/ethernet.h>
+
+#include "hicn.h"
+#include "pg.h"
+#include "parser.h"
+#include "infra.h"
+
+/* Registration struct for a graph node */
+vlib_node_registration_t hicn_pg_interest_node;
+vlib_node_registration_t hicn_pg_data_node;
+
+/* Stats, which end up called "error" even though they aren't... */
+#define foreach_hicnpg_error                                                  \
+  _ (PROCESSED, "hICN PG packets processed")                                  \
+  _ (DROPPED, "hICN PG packets dropped")                                      \
+  _ (INTEREST_MSGS_GENERATED, "hICN PG Interests generated")                  \
+  _ (CONTENT_MSGS_RECEIVED, "hICN PG Content msgs received")
+
+typedef enum
+{
+#define _(sym, str) HICNPG_ERROR_##sym,
+  foreach_hicnpg_error
+#undef _
+    HICNPG_N_ERROR,
+} hicnpg_error_t;
+
+static char *hicnpg_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnpg_error
+#undef _
+};
+
+/*
+ * Next graph nodes, which reference the list in the actual registration
+ * block below
+ */
+typedef enum
+{
+  HICNPG_INTEREST_NEXT_V4_LOOKUP,
+  HICNPG_INTEREST_NEXT_V6_LOOKUP,
+  HICNPG_INTEREST_NEXT_DROP,
+  HICNPG_N_NEXT,
+} hicnpg_interest_next_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+  u16 msg_type;
+} hicnpg_trace_t;
+
+/* packet trace format function */
+static u8 *
+format_hicnpg_trace (u8 *s, va_list *args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  hicnpg_trace_t *t = va_arg (*args, hicnpg_trace_t *);
+
+  s = format (s, "HICNPG: pkt: %d, msg %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, (int) t->msg_type, t->sw_if_index,
+             t->next_index);
+  return (s);
+}
+
+always_inline void hicn_rewrite_interestv4 (vlib_main_t *vm, vlib_buffer_t *b0,
+                                           u32 seq_number, u16 lifetime,
+                                           u32 next_flow, u32 iface);
+
+always_inline void hicn_rewrite_interestv6 (vlib_main_t *vm, vlib_buffer_t *b0,
+                                           u32 seq_number, u16 lifetime,
+                                           u32 next_flow, u32 iface);
+
+always_inline void convert_interest_to_data_v4 (vlib_main_t *vm,
+                                               vlib_buffer_t *b0,
+                                               vlib_buffer_t *rb, u32 bi0);
+
+always_inline void convert_interest_to_data_v6 (vlib_main_t *vm,
+                                               vlib_buffer_t *b0,
+                                               vlib_buffer_t *rb, u32 bi0);
+
+always_inline void calculate_tcp_checksum_v4 (vlib_main_t *vm,
+                                             vlib_buffer_t *b0);
+
+always_inline void calculate_tcp_checksum_v6 (vlib_main_t *vm,
+                                             vlib_buffer_t *b0);
+/*
+ * Node function for the icn packet-generator client. The goal here is to
+ * manipulate/tweak a stream of packets that have been injected by the vpp
+ * packet generator to generate icn request traffic.
+ */
+static uword
+hicnpg_client_interest_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
+                               vlib_frame_t *frame)
+{
+  u32 n_left_from, *from, *to_next;
+  hicnpg_interest_next_t next_index;
+  u32 pkts_processed = 0, pkts_dropped = 0;
+  u32 interest_msgs_generated = 0;
+  u32 bi0, bi1;
+  vlib_buffer_t *b0, *b1;
+  u8 pkt_type0 = 0, pkt_type1 = 0;
+  u16 msg_type0 = 0, msg_type1 = 0;
+  hicnpg_main_t *hpgm = &hicnpg_main;
+  int iface = 0;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         u32 next0 = HICNPG_INTEREST_NEXT_DROP;
+         u32 next1 = HICNPG_INTEREST_NEXT_DROP;
+         u32 sw_if_index0 = ~0, sw_if_index1 = ~0;
+         u8 isv6_0;
+         u8 isv6_1;
+
+         /* Prefetch next iteration. */
+         {
+           vlib_buffer_t *p2, *p3;
+
+           p2 = vlib_get_buffer (vm, from[2]);
+           p3 = vlib_get_buffer (vm, from[3]);
+
+           vlib_prefetch_buffer_header (p2, LOAD);
+           vlib_prefetch_buffer_header (p3, LOAD);
+
+           CLIB_PREFETCH (p2->data, (2 * CLIB_CACHE_LINE_BYTES), STORE);
+           CLIB_PREFETCH (p3->data, (2 * CLIB_CACHE_LINE_BYTES), STORE);
+         }
+
+         /*
+          * speculatively enqueue b0 and b1 to the current
+          * next frame
+          */
+         to_next[0] = bi0 = from[0];
+         to_next[1] = bi1 = from[1];
+         from += 2;
+         to_next += 2;
+         n_left_from -= 2;
+         n_left_to_next -= 2;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         b1 = vlib_get_buffer (vm, bi1);
+
+         hicn_buffer_set_flags (b0, HICN_BUFFER_FLAGS_FROM_PG);
+         hicn_buffer_set_flags (b1, HICN_BUFFER_FLAGS_FROM_PG);
+
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+         sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
+         vnet_buffer (b0)->sw_if_index[VLIB_RX] = hpgm->sw_if;
+         vnet_buffer (b1)->sw_if_index[VLIB_RX] = hpgm->sw_if;
+
+         /* Check icn packets, locate names */
+         if (hicn_interest_parse_pkt (b0) == HICN_ERROR_NONE)
+           {
+             /* this node grabs only interests */
+             isv6_0 = hicn_buffer_is_v6 (b0);
+
+             /* Increment the appropriate message counter */
+             interest_msgs_generated++;
+
+             iface = (hpgm->index_ifaces % hpgm->n_ifaces);
+             /* Rewrite and send */
+             isv6_0 ?
+                     hicn_rewrite_interestv6 (
+                 vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number,
+                 hpgm->interest_lifetime, hpgm->index % hpgm->n_flows,
+                 iface) :
+                     hicn_rewrite_interestv4 (
+                 vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number,
+                 hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, iface);
+
+             hpgm->index_ifaces++;
+             if (iface == (hpgm->n_ifaces - 1))
+               hpgm->index++;
+
+             next0 = isv6_0 ? HICNPG_INTEREST_NEXT_V6_LOOKUP :
+                                    HICNPG_INTEREST_NEXT_V4_LOOKUP;
+           }
+         if (hicn_interest_parse_pkt (b1) == HICN_ERROR_NONE)
+           {
+             /* this node grabs only interests */
+             isv6_1 = hicn_buffer_is_v6 (b1);
+
+             /* Increment the appropriate message counter */
+             interest_msgs_generated++;
+
+             iface = (hpgm->index_ifaces % hpgm->n_ifaces);
+             /* Rewrite and send */
+             isv6_1 ?
+                     hicn_rewrite_interestv6 (
+                 vm, b1, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number,
+                 hpgm->interest_lifetime, hpgm->index % hpgm->n_flows,
+                 iface) :
+                     hicn_rewrite_interestv4 (
+                 vm, b1, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number,
+                 hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, iface);
+
+             hpgm->index_ifaces++;
+             if (iface == (hpgm->n_ifaces - 1))
+               hpgm->index++;
+
+             next1 = isv6_1 ? HICNPG_INTEREST_NEXT_V6_LOOKUP :
+                                    HICNPG_INTEREST_NEXT_V4_LOOKUP;
+           }
+         /* Send pkt to next node */
+         vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
+         vnet_buffer (b1)->sw_if_index[VLIB_TX] = ~0;
+
+         pkts_processed += 2;
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+           {
+             if (b0->flags & VLIB_BUFFER_IS_TRACED)
+               {
+                 hicnpg_trace_t *t =
+                   vlib_add_trace (vm, node, b0, sizeof (*t));
+                 t->pkt_type = pkt_type0;
+                 t->msg_type = msg_type0;
+                 t->sw_if_index = sw_if_index0;
+                 t->next_index = next0;
+               }
+             if (b1->flags & VLIB_BUFFER_IS_TRACED)
+               {
+                 hicnpg_trace_t *t =
+                   vlib_add_trace (vm, node, b1, sizeof (*t));
+                 t->pkt_type = pkt_type1;
+                 t->msg_type = msg_type1;
+                 t->sw_if_index = sw_if_index1;
+                 t->next_index = next1;
+               }
+           }
+         if (next0 == HICNPG_INTEREST_NEXT_DROP)
+           {
+             pkts_dropped++;
+           }
+         if (next1 == HICNPG_INTEREST_NEXT_DROP)
+           {
+             pkts_dropped++;
+           }
+         /*
+          * verify speculative enqueues, maybe switch current
+          * next frame
+          */
+         vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, bi1, next0,
+                                          next1);
+       }
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         u32 next0 = HICNPG_INTEREST_NEXT_DROP;
+         u32 sw_if_index0;
+         u8 isv6_0;
+
+         /* speculatively enqueue b0 to the current next frame */
+         bi0 = from[0];
+         to_next[0] = bi0;
+         from += 1;
+         to_next += 1;
+         n_left_from -= 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+
+         hicn_buffer_set_flags (b0, HICN_BUFFER_FLAGS_FROM_PG);
+
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+         vnet_buffer (b0)->sw_if_index[VLIB_RX] = hpgm->sw_if;
+
+         /* Check icn packets, locate names */
+         if (hicn_interest_parse_pkt (b0) == HICN_ERROR_NONE)
+           {
+             /* this node grabs only interests */
+             isv6_0 = hicn_buffer_is_v6 (b0);
+
+             /* Increment the appropriate message counter */
+             interest_msgs_generated++;
+
+             iface = (hpgm->index_ifaces % hpgm->n_ifaces);
+
+             /* Rewrite and send */
+             isv6_0 ?
+                     hicn_rewrite_interestv6 (
+                 vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number,
+                 hpgm->interest_lifetime, hpgm->index % hpgm->n_flows,
+                 iface) :
+                     hicn_rewrite_interestv4 (
+                 vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number,
+                 hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, iface);
+
+             hpgm->index_ifaces++;
+             if (iface == (hpgm->n_ifaces - 1))
+               hpgm->index++;
+
+             next0 = isv6_0 ? HICNPG_INTEREST_NEXT_V6_LOOKUP :
+                                    HICNPG_INTEREST_NEXT_V4_LOOKUP;
+           }
+         /* Send pkt to ip lookup */
+         vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicnpg_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->pkt_type = pkt_type0;
+             t->msg_type = msg_type0;
+             t->sw_if_index = sw_if_index0;
+             t->next_index = next0;
+           }
+         pkts_processed += 1;
+
+         if (next0 == HICNPG_INTEREST_NEXT_DROP)
+           {
+             pkts_dropped++;
+           }
+         /*
+          * verify speculative enqueue, maybe switch current
+          * next frame
+          */
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, hicn_pg_interest_node.index,
+                              HICNPG_ERROR_PROCESSED, pkts_processed);
+  vlib_node_increment_counter (vm, hicn_pg_interest_node.index,
+                              HICNPG_ERROR_DROPPED, pkts_dropped);
+  vlib_node_increment_counter (vm, hicn_pg_interest_node.index,
+                              HICNPG_ERROR_INTEREST_MSGS_GENERATED,
+                              interest_msgs_generated);
+
+  return (frame->n_vectors);
+}
+
+void
+hicn_rewrite_interestv4 (vlib_main_t *vm, vlib_buffer_t *b0, u32 seq_number,
+                        u16 interest_lifetime, u32 next_flow, u32 iface)
+{
+  hicn_header_t *h0 = vlib_buffer_get_current (b0);
+
+  /* Generate the right src and dst corresponding to flow and iface */
+  ip46_address_t src_addr = {
+    .ip4 = hicnpg_main.pgen_clt_src_addr.ip4,
+  };
+  hicn_name_t dst_name = {
+    .prefix.ip4 = hicnpg_main.pgen_clt_hicn_name->fp_addr.ip4,
+    .suffix = seq_number,
+  };
+
+  src_addr.ip4.as_u32 += clib_host_to_net_u32 (iface);
+  dst_name.prefix.ip4.as_u32 += clib_net_to_host_u32 (next_flow);
+
+  /* Update locator and name */
+  hicn_type_t type = hicn_get_buffer (b0)->type;
+  HICN_OPS4->set_interest_locator (type, &h0->protocol, &src_addr);
+  HICN_OPS4->set_interest_name (type, &h0->protocol, &dst_name);
+
+  /* Update lifetime  (currently L4 checksum is not updated) */
+  HICN_OPS4->set_lifetime (type, &h0->protocol, interest_lifetime);
+
+  /* Update checksums */
+  HICN_OPS4->update_checksums (type, &h0->protocol, 0, 0);
+}
+
+/**
+ * @brief Rewrite the IPv6 header as the next generated packet
+ *
+ * Set up a name prefix
+ *  - etiher generate interest in which the name varies only after the prefix
+ *  (inc : seq_number), then the flow acts on the prefix (CHECK)
+ *  seq_number => TCP, FLOW =>
+ *
+ *  SRC : pgen_clt_src_addr.ip6 DST = generate name (pgen_clt_hicn_name.ip6)
+ *  ffff:ffff:ffff:ffff         ffff:ffff:ffff:ffff
+ *                 \__/                        \__/
+ *                 +iface                      + flow
+ *  Source is used to emulate different consumers.
+ *    FIXME iface is ill-named, better name it consumer id
+ *  Destination is used to iterate on the content.
+ */
+void
+hicn_rewrite_interestv6 (vlib_main_t *vm, vlib_buffer_t *b0, u32 seq_number,
+                        u16 interest_lifetime, u32 next_flow, u32 iface)
+{
+  hicn_header_t *h0 = vlib_buffer_get_current (b0);
+
+  /* Generate the right src and dst corresponding to flow and iface */
+  ip46_address_t src_addr = {
+    .ip6 = hicnpg_main.pgen_clt_src_addr.ip6,
+  };
+  hicn_name_t dst_name = {
+    .prefix.ip6 = hicnpg_main.pgen_clt_hicn_name->fp_addr.ip6,
+    .suffix = seq_number,
+  };
+  src_addr.ip6.as_u32[3] += clib_host_to_net_u32 (iface);
+  dst_name.prefix.ip6.as_u32[3] += clib_net_to_host_u32 (next_flow);
+
+  /* Update locator and name */
+  hicn_type_t type = hicn_get_buffer (b0)->type;
+  HICN_OPS6->set_interest_locator (type, &h0->protocol, &src_addr);
+  HICN_OPS6->set_interest_name (type, &h0->protocol, &dst_name);
+
+  /* Update lifetime */
+  HICN_OPS6->set_lifetime (type, &h0->protocol, interest_lifetime);
+
+  /* Update checksums */
+  calculate_tcp_checksum_v6 (vm, b0);
+}
+
+void
+calculate_tcp_checksum_v4 (vlib_main_t *vm, vlib_buffer_t *b0)
+{
+  ip4_header_t *ip0;
+  tcp_header_t *tcp0;
+  ip_csum_t sum0;
+  u32 tcp_len0;
+
+  ip0 = (ip4_header_t *) (vlib_buffer_get_current (b0));
+  tcp0 =
+    (tcp_header_t *) (vlib_buffer_get_current (b0) + sizeof (ip4_header_t));
+  tcp_len0 = clib_net_to_host_u16 (ip0->length) - sizeof (ip4_header_t);
+
+  /* Initialize checksum with header. */
+  if (BITS (sum0) == 32)
+    {
+      sum0 = clib_mem_unaligned (&ip0->src_address, u32);
+      sum0 =
+       ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->dst_address, u32));
+    }
+  else
+    sum0 = clib_mem_unaligned (&ip0->src_address, u64);
+
+  sum0 = ip_csum_with_carry (
+    sum0, clib_host_to_net_u32 (tcp_len0 + (ip0->protocol << 16)));
+
+  /* Invalidate possibly old checksum. */
+  tcp0->checksum = 0;
+
+  u32 tcp_offset = sizeof (ip4_header_t);
+  sum0 = ip_incremental_checksum_buffer (vm, b0, tcp_offset, tcp_len0, sum0);
+
+  tcp0->checksum = ~ip_csum_fold (sum0);
+}
+
+void
+calculate_tcp_checksum_v6 (vlib_main_t *vm, vlib_buffer_t *b0)
+{
+  ip6_header_t *ip0;
+  tcp_header_t *tcp0;
+  ip_csum_t sum0;
+  u32 tcp_len0;
+
+  ip0 = (ip6_header_t *) (vlib_buffer_get_current (b0));
+  tcp0 =
+    (tcp_header_t *) (vlib_buffer_get_current (b0) + sizeof (ip6_header_t));
+  tcp_len0 = clib_net_to_host_u16 (ip0->payload_length);
+
+  /* Initialize checksum with header. */
+  if (BITS (sum0) == 32)
+    {
+      sum0 = clib_mem_unaligned (&ip0->src_address, u32);
+      sum0 =
+       ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->dst_address, u32));
+    }
+  else
+    sum0 = clib_mem_unaligned (&ip0->src_address, u64);
+
+  sum0 = ip_csum_with_carry (
+    sum0, clib_host_to_net_u32 (tcp_len0 + (ip0->protocol << 16)));
+
+  /* Invalidate possibly old checksum. */
+  tcp0->checksum = 0;
+
+  u32 tcp_offset = sizeof (ip6_header_t);
+  sum0 = ip_incremental_checksum_buffer (vm, b0, tcp_offset, tcp_len0, sum0);
+
+  tcp0->checksum = ~ip_csum_fold (sum0);
+}
+
+VLIB_REGISTER_NODE (hicn_pg_interest_node) = {
+  .function = hicnpg_client_interest_node_fn,
+  .name = "hicnpg-interest",
+  .vector_size = sizeof (u32),
+  .format_trace = format_hicnpg_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicnpg_error_strings),
+  .error_strings = hicnpg_error_strings,
+  .n_next_nodes = HICNPG_N_NEXT,
+  .next_nodes = { [HICNPG_INTEREST_NEXT_V4_LOOKUP] = "ip4-lookup",
+                 [HICNPG_INTEREST_NEXT_V6_LOOKUP] = "ip6-lookup",
+                 [HICNPG_INTEREST_NEXT_DROP] = "error-drop" },
+};
+
+/*
+ * Next graph nodes, which reference the list in the actual registration
+ * block below
+ */
+typedef enum
+{
+  HICNPG_DATA_NEXT_DROP,
+  HICNPG_DATA_NEXT_LOOKUP4,
+  HICNPG_DATA_NEXT_LOOKUP6,
+  HICNPG_DATA_N_NEXT,
+} hicnpg_data_next_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+  u16 msg_type;
+} icnpg_data_trace_t;
+
+/* packet trace format function */
+static u8 *
+format_hicnpg_data_trace (u8 *s, va_list *args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  hicnpg_trace_t *t = va_arg (*args, hicnpg_trace_t *);
+
+  s = format (s, "HICNPG: pkt: %d, msg %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, (int) t->msg_type, t->sw_if_index,
+             t->next_index);
+  return (s);
+}
+
+/*
+ * Node function for the icn packet-generator client. The goal here is to
+ * manipulate/tweak a stream of packets that have been injected by the vpp
+ * packet generator to generate icn request traffic.
+ */
+static uword
+hicnpg_client_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
+                           vlib_frame_t *frame)
+{
+  u32 n_left_from, *from, *to_next;
+  hicnpg_data_next_t next_index;
+  u32 pkts_processed = 0;
+  u32 content_msgs_received = 0;
+  u32 bi0, bi1;
+  vlib_buffer_t *b0, *b1;
+  u8 pkt_type0 = 0, pkt_type1 = 0;
+  u16 msg_type0 = 1, msg_type1 = 1;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         u32 next0 = HICNPG_DATA_NEXT_DROP;
+         u32 next1 = HICNPG_DATA_NEXT_DROP;
+         u32 sw_if_index0, sw_if_index1;
+
+         /* Prefetch next iteration. */
+         {
+           vlib_buffer_t *p2, *p3;
+
+           p2 = vlib_get_buffer (vm, from[2]);
+           p3 = vlib_get_buffer (vm, from[3]);
+
+           vlib_prefetch_buffer_header (p2, LOAD);
+           vlib_prefetch_buffer_header (p3, LOAD);
+
+           CLIB_PREFETCH (p2->data, (2 * CLIB_CACHE_LINE_BYTES), STORE);
+           CLIB_PREFETCH (p3->data, (2 * CLIB_CACHE_LINE_BYTES), STORE);
+         }
+
+         /*
+          * speculatively enqueue b0 and b1 to the current
+          * next frame
+          */
+         to_next[0] = bi0 = from[0];
+         to_next[1] = bi1 = from[1];
+         from += 2;
+         to_next += 2;
+         n_left_from -= 2;
+         n_left_to_next -= 2;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         b1 = vlib_get_buffer (vm, bi1);
+
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+         sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
+
+         next0 = HICNPG_DATA_NEXT_DROP;
+         next1 = HICNPG_DATA_NEXT_DROP;
+
+         // Increment counter
+         content_msgs_received += 2;
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+           {
+             if (b0->flags & VLIB_BUFFER_IS_TRACED)
+               {
+                 icnpg_data_trace_t *t =
+                   vlib_add_trace (vm, node, b0, sizeof (*t));
+                 t->pkt_type = pkt_type0;
+                 t->msg_type = msg_type0;
+                 t->sw_if_index = sw_if_index0;
+                 t->next_index = next0;
+               }
+             if (b1->flags & VLIB_BUFFER_IS_TRACED)
+               {
+                 icnpg_data_trace_t *t =
+                   vlib_add_trace (vm, node, b1, sizeof (*t));
+                 t->pkt_type = pkt_type1;
+                 t->msg_type = msg_type1;
+                 t->sw_if_index = sw_if_index1;
+                 t->next_index = next1;
+               }
+           }
+
+         vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, bi1, next0,
+                                          next1);
+         pkts_processed += 2;
+       }
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         u32 next0 = HICNPG_DATA_NEXT_DROP;
+         u32 sw_if_index0;
+
+         /* speculatively enqueue b0 to the current next frame */
+         bi0 = from[0];
+         to_next[0] = bi0;
+         from += 1;
+         to_next += 1;
+         n_left_from -= 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+
+         next0 = HICNPG_DATA_NEXT_DROP;
+
+         // Increment a counter
+         content_msgs_received += 1;
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             icnpg_data_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->pkt_type = pkt_type0;
+             t->msg_type = msg_type0;
+             t->sw_if_index = sw_if_index0;
+             t->next_index = next0;
+           }
+
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
+
+         pkts_processed++;
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, hicn_pg_data_node.index,
+                              HICNPG_ERROR_PROCESSED, pkts_processed);
+  vlib_node_increment_counter (vm, hicn_pg_data_node.index,
+                              HICNPG_ERROR_CONTENT_MSGS_RECEIVED,
+                              content_msgs_received);
+  return (frame->n_vectors);
+}
+
+VLIB_REGISTER_NODE(hicn_pg_data_node) =
+{
+  .function = hicnpg_client_data_node_fn,
+  .name = "hicnpg-data",
+  .vector_size = sizeof(u32),
+  .format_trace = format_hicnpg_data_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(hicnpg_error_strings),
+  .error_strings = hicnpg_error_strings,
+  .n_next_nodes = HICNPG_DATA_N_NEXT,
+  .next_nodes =
+  {
+   [HICNPG_DATA_NEXT_DROP] = "error-drop",
+   [HICNPG_DATA_NEXT_LOOKUP4] = "ip4-lookup",
+   [HICNPG_DATA_NEXT_LOOKUP6] = "ip6-lookup",
+  },
+};
+
+VNET_FEATURE_INIT (hicn_data_input_ip4_arc, static) = {
+  .arc_name = "ip4-unicast",
+  .node_name = "hicnpg-data",
+  .runs_before = VNET_FEATURES ("ip4-inacl"),
+};
+
+VNET_FEATURE_INIT (hicn_data_input_ip6_arc, static) = {
+  .arc_name = "ip6-unicast",
+  .node_name = "hicnpg-data",
+  .runs_before = VNET_FEATURES ("ip6-inacl"),
+};
+
+/*
+ * End of packet-generator client node
+ */
+
+/*
+ * Beginning of packet-generation server node
+ */
+
+/* Registration struct for a graph node */
+vlib_node_registration_t hicn_pg_server_node;
+
+/* Stats, which end up called "error" even though they aren't... */
+#define foreach_icnpg_server_error                                            \
+  _ (PROCESSED, "hICN PG Server packets processed")                           \
+  _ (DROPPED, "hICN PG Server packets dropped")
+
+typedef enum
+{
+#define _(sym, str) HICNPG_SERVER_ERROR_##sym,
+  foreach_icnpg_server_error
+#undef _
+    HICNPG_SERVER_N_ERROR,
+} icnpg_server_error_t;
+
+static char *icnpg_server_error_strings[] = {
+#define _(sym, string) string,
+  foreach_icnpg_server_error
+#undef _
+};
+
+/*
+ * Next graph nodes, which reference the list in the actual registration
+ * block below
+ */
+typedef enum
+{
+  HICNPG_SERVER_NEXT_V4_LOOKUP,
+  HICNPG_SERVER_NEXT_V6_LOOKUP,
+  HICNPG_SERVER_NEXT_DROP,
+  HICNPG_SERVER_N_NEXT,
+} icnpg_server_next_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+  u16 msg_type;
+} hicnpg_server_trace_t;
+
+/* packet trace format function */
+static u8 *
+format_icnpg_server_trace (u8 *s, va_list *args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  hicnpg_server_trace_t *t = va_arg (*args, hicnpg_server_trace_t *);
+
+  s = format (
+    s, "HICNPG SERVER: pkt: %d, msg %d, sw_if_index %d, next index %d",
+    (int) t->pkt_type, (int) t->msg_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node function for the icn packet-generator server.
+ */
+static uword
+hicnpg_node_server_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
+                      vlib_frame_t *frame, int isv6)
+{
+  u32 n_left_from, *from, *to_next;
+  icnpg_server_next_t next_index;
+  u32 pkts_processed = 0, pkts_dropped = 0;
+  u32 bi0, bi1;
+  vlib_buffer_t *b0, *b1;
+  u8 pkt_type0 = 0, pkt_type1 = 0;
+  u16 msg_type0 = 0, msg_type1 = 0;
+
+  from = vlib_frame_vector_args (frame);
+
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         u32 next0 = HICNPG_SERVER_NEXT_DROP;
+         u32 next1 = HICNPG_SERVER_NEXT_DROP;
+         u32 sw_if_index0, sw_if_index1;
+         u32 hpgi0, hpgi1;
+         hicnpg_server_t *hpg0, *hpg1;
+
+         /* Prefetch next iteration. */
+         {
+           vlib_buffer_t *p2, *p3;
+
+           p2 = vlib_get_buffer (vm, from[2]);
+           p3 = vlib_get_buffer (vm, from[3]);
+
+           vlib_prefetch_buffer_header (p2, LOAD);
+           vlib_prefetch_buffer_header (p3, LOAD);
+
+           CLIB_PREFETCH (p2->data, (2 * CLIB_CACHE_LINE_BYTES), STORE);
+           CLIB_PREFETCH (p3->data, (2 * CLIB_CACHE_LINE_BYTES), STORE);
+         }
+
+         /*
+          * speculatively enqueue b0 and b1 to the current
+          * next frame
+          */
+         to_next[0] = bi0 = from[0];
+         to_next[1] = bi1 = from[1];
+         from += 2;
+         to_next += 2;
+         n_left_from -= 2;
+         n_left_to_next -= 2;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         b1 = vlib_get_buffer (vm, bi1);
+
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+         sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
+
+         vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
+         vnet_buffer (b1)->sw_if_index[VLIB_TX] = ~0;
+
+         hpgi0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
+         hpgi1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
+
+         hpg0 = hicnpg_server_get (hpgi0);
+         hpg1 = hicnpg_server_get (hpgi1);
+
+         if (hicn_interest_parse_pkt (b0) == HICN_ERROR_NONE)
+           {
+             vlib_buffer_t *rb = NULL;
+             rb = vlib_get_buffer (vm, hpg0->buffer_index);
+
+             isv6 ? convert_interest_to_data_v6 (vm, b0, rb, bi0) :
+                          convert_interest_to_data_v4 (vm, b0, rb, bi0);
+
+             next0 = isv6 ? HICNPG_SERVER_NEXT_V6_LOOKUP :
+                                  HICNPG_SERVER_NEXT_V4_LOOKUP;
+           }
+
+         if (hicn_interest_parse_pkt (b1) == HICN_ERROR_NONE)
+           {
+             vlib_buffer_t *rb = NULL;
+             rb = vlib_get_buffer (vm, hpg1->buffer_index);
+
+             isv6 ? convert_interest_to_data_v6 (vm, b1, rb, bi1) :
+                          convert_interest_to_data_v4 (vm, b1, rb, bi1);
+
+             next1 = isv6 ? HICNPG_SERVER_NEXT_V6_LOOKUP :
+                                  HICNPG_SERVER_NEXT_V4_LOOKUP;
+           }
+         pkts_processed += 2;
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+           {
+             if (b0->flags & VLIB_BUFFER_IS_TRACED)
+               {
+                 hicnpg_server_trace_t *t =
+                   vlib_add_trace (vm, node, b0, sizeof (*t));
+                 t->pkt_type = pkt_type0;
+                 t->msg_type = msg_type0;
+                 t->sw_if_index = sw_if_index0;
+                 t->next_index = next0;
+               }
+             if (b1->flags & VLIB_BUFFER_IS_TRACED)
+               {
+                 hicnpg_server_trace_t *t =
+                   vlib_add_trace (vm, node, b1, sizeof (*t));
+                 t->pkt_type = pkt_type1;
+                 t->msg_type = msg_type1;
+                 t->sw_if_index = sw_if_index1;
+                 t->next_index = next1;
+               }
+           }
+         if (next0 == HICNPG_SERVER_NEXT_DROP)
+           {
+             pkts_dropped++;
+           }
+         if (next1 == HICNPG_SERVER_NEXT_DROP)
+           {
+             pkts_dropped++;
+           }
+         /*
+          * verify speculative enqueues, maybe switch current
+          * next frame
+          */
+         vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, bi1, next0,
+                                          next1);
+       }
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         u32 next0 = HICNPG_SERVER_NEXT_DROP;
+         u32 sw_if_index0 = ~0;
+         u32 hpgi0;
+         hicnpg_server_t *hpg0;
+
+         /* speculatively enqueue b0 to the current next frame */
+         bi0 = from[0];
+         to_next[0] = bi0;
+         from += 1;
+         to_next += 1;
+         n_left_from -= 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+         vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
+
+         hpgi0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
+         hpg0 = hicnpg_server_get (hpgi0);
+
+         if (hicn_interest_parse_pkt (b0) == HICN_ERROR_NONE)
+           {
+             /* this node grabs only interests */
+             vlib_buffer_t *rb = NULL;
+             rb = vlib_get_buffer (vm, hpg0->buffer_index);
+
+             isv6 ? convert_interest_to_data_v6 (vm, b0, rb, bi0) :
+                          convert_interest_to_data_v4 (vm, b0, rb, bi0);
+
+             next0 = isv6 ? HICNPG_SERVER_NEXT_V6_LOOKUP :
+                                  HICNPG_SERVER_NEXT_V4_LOOKUP;
+           }
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicnpg_server_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->pkt_type = pkt_type0;
+             t->msg_type = msg_type0;
+             t->sw_if_index = sw_if_index0;
+             t->next_index = next0;
+           }
+         pkts_processed += 1;
+
+         if (next0 == HICNPG_SERVER_NEXT_DROP)
+           {
+             pkts_dropped++;
+           }
+         /*
+          * verify speculative enqueue, maybe switch current
+          * next frame
+          */
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, hicn_pg_server_node.index,
+                              HICNPG_SERVER_ERROR_PROCESSED, pkts_processed);
+  vlib_node_increment_counter (vm, hicn_pg_server_node.index,
+                              HICNPG_SERVER_ERROR_DROPPED, pkts_dropped);
+
+  return (frame->n_vectors);
+}
+
+void
+convert_interest_to_data_v4 (vlib_main_t *vm, vlib_buffer_t *b0,
+                            vlib_buffer_t *rb, u32 bi0)
+{
+  hicn_header_t *h0 = vlib_buffer_get_current (b0);
+
+  /* Get the packet length */
+  u16 pkt_len = clib_net_to_host_u16 (h0->v4.ip.len);
+
+  /*
+   * Rule of thumb: We want the size of the IP packet to be <= 1500 bytes
+   */
+  u16 bytes_to_copy = rb->current_length;
+  if ((bytes_to_copy + pkt_len) > 1500)
+    {
+      bytes_to_copy = 1500 - pkt_len;
+    }
+  /* Add content to the data packet */
+  vlib_buffer_add_data (vm, &bi0, rb->data, bytes_to_copy);
+
+  b0 = vlib_get_buffer (vm, bi0);
+
+  h0 = vlib_buffer_get_current (b0);
+
+  ip4_address_t src_addr = h0->v4.ip.saddr;
+  h0->v4.ip.saddr = h0->v4.ip.daddr;
+  h0->v4.ip.daddr = src_addr;
+
+  h0->v4.ip.len = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
+  h0->v4.ip.csum = ip4_header_checksum ((ip4_header_t *) &(h0->v4.ip));
+  calculate_tcp_checksum_v4 (vm, b0);
+}
+
+void
+convert_interest_to_data_v6 (vlib_main_t *vm, vlib_buffer_t *b0,
+                            vlib_buffer_t *rb, u32 bi0)
+{
+  hicn_header_t *h0 = vlib_buffer_get_current (b0);
+
+  /* Get the packet length */
+  uint16_t pkt_len =
+    clib_net_to_host_u16 (h0->v6.ip.len) + sizeof (ip6_header_t);
+
+  /*
+   * Figure out how many bytes we can add to the content
+   *
+   * Rule of thumb: We want the size of the IP packet to be <= 1400 bytes
+   */
+  u16 bytes_to_copy = rb->current_length;
+  if ((bytes_to_copy + pkt_len) > 1500)
+    {
+      bytes_to_copy = 1500 - pkt_len;
+    }
+  /* Add content to the data packet */
+  vlib_buffer_add_data (vm, &bi0, rb->data, bytes_to_copy);
+
+  b0 = vlib_get_buffer (vm, bi0);
+
+  h0 = vlib_buffer_get_current (b0);
+  ip6_address_t src_addr = h0->v6.ip.saddr;
+  h0->v6.ip.saddr = h0->v6.ip.daddr;
+  h0->v6.ip.daddr = src_addr;
+
+  h0->v6.ip.len = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
+                                       sizeof (ip6_header_t));
+  h0->v6.tcp.data_offset_and_reserved |= 0x0f;
+  h0->v6.tcp.urg_ptr = htons (0xffff);
+
+  calculate_tcp_checksum_v6 (vm, b0);
+}
+
+VLIB_NODE_FN (hicn_pg_server6_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return hicnpg_node_server_fn (vm, node, frame, 1 /* is_v6 */);
+}
+
+VLIB_NODE_FN (hicn_pg_server4_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return hicnpg_node_server_fn (vm, node, frame, 0 /* is_v6 */);
+}
+
+VLIB_REGISTER_NODE(hicn_pg_server6_node) =
+{
+  .name = "hicnpg-server-6",
+  .vector_size = sizeof(u32),
+  .format_trace = format_icnpg_server_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(icnpg_server_error_strings),
+  .error_strings = icnpg_server_error_strings,
+  .n_next_nodes = HICNPG_SERVER_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes =
+  {
+    [HICNPG_SERVER_NEXT_V4_LOOKUP] = "ip4-lookup",
+    [HICNPG_SERVER_NEXT_V6_LOOKUP] = "ip6-lookup",
+    [HICNPG_SERVER_NEXT_DROP] = "error-drop",
+  },
+};
+
+VLIB_REGISTER_NODE(hicn_pg_server4_node) =
+{
+  .name = "hicnpg-server-4",
+  .vector_size = sizeof(u32),
+  .format_trace = format_icnpg_server_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(icnpg_server_error_strings),
+  .error_strings = icnpg_server_error_strings,
+  .n_next_nodes = HICNPG_SERVER_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes =
+  {
+    [HICNPG_SERVER_NEXT_V4_LOOKUP] = "ip4-lookup",
+    [HICNPG_SERVER_NEXT_V6_LOOKUP] = "ip6-lookup",
+    [HICNPG_SERVER_NEXT_DROP] = "error-drop",
+  },
+};
+
+/*
+ * End of packet-generator server node
+ */
\ No newline at end of file
index a84891b..0c96e14 100644 (file)
@@ -34,6 +34,7 @@
 #include "infra.h"
 #include "udp_tunnels/udp_tunnel.h"
 #include "mapme.h"
+#include "pg.h"
 
 #define FIB_SOURCE_HICN 0x04 // Right after the FIB_SOURCE_INTERFACE priority
 
@@ -234,7 +235,7 @@ sync_hicn_fib_entry (hicn_dpo_ctx_t *fib_entry, hicn_face_id_t **pvec_faces)
   do                                                                          \
     {                                                                         \
       /* Careful, this adds a lock on the face if it exists */                \
-      hicn_face_add (dpo, nh, sw_if, &face_id, 0);                            \
+      hicn_face_add (dpo, nh, sw_if, &face_id);                               \
       vec_validate (vec_faces, index);                                        \
       vec_faces[index] = face_id;                                             \
       (index)++;                                                              \
@@ -294,10 +295,15 @@ sync_hicn_fib_entry (hicn_dpo_ctx_t *fib_entry, hicn_face_id_t **pvec_faces)
            default:
              continue;
            }
-         HICN_DEBUG ("Added new UDP face: %d because of route prefix %s",
+         HICN_DEBUG ("Added new UDP face: %d because of route prefix %U",
                      face_id, format_ip_prefix, &_fib_entry->fe_prefix);
          udp_tunnel_add_existing (dpo->dpoi_index, proto);
        }
+      else if (dpo_is_pgserver (dpo))
+       {
+         hicnpg_server_t *pg_server = hicnpg_server_get (dpo->dpoi_index);
+         ADD_FACE (&pg_server->hicn_locator);
+       }
     }
 
   const hicn_dpo_vft_t *strategy_vft = hicn_dpo_get_vft (fib_entry->dpo_type);
index 66d9c2d..3ff2d02 100644 (file)
@@ -66,7 +66,7 @@ hicn_new_interest (hicn_strategy_runtime_t *rt, vlib_buffer_t *b0, u32 *next,
                   f64 tnow, u8 *nameptr, u16 namelen, hicn_face_id_t outface,
                   int nh_idx, index_t dpo_ctx_id0,
                   const hicn_strategy_vft_t *strategy, dpo_type_t dpo_type,
-                  u8 isv6, vl_api_hicn_api_node_stats_get_reply_t *stats,
+                  vl_api_hicn_api_node_stats_get_reply_t *stats,
                   u8 is_replication)
 {
   int ret;
@@ -81,6 +81,7 @@ hicn_new_interest (hicn_strategy_runtime_t *rt, vlib_buffer_t *b0, u32 *next,
   u8 hash_entry_id = 0;
   u8 bucket_is_overflow = 0;
   u32 bucket_id = ~0;
+  u8 isv6 = hicn_buffer_is_v6 (b0);
 
   if (is_replication)
     {
@@ -202,27 +203,22 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
       while (n_left_from > 0 && n_left_to_next > 0)
        {
-         u8 isv6;
          u8 *nameptr;
          u16 namelen;
-         hicn_name_t name;
-         hicn_header_t *hicn0;
          vlib_buffer_t *b0;
          u32 bi0;
          hicn_face_id_t outfaces[MAX_OUT_FACES];
          u32 outfaces_len;
          int nh_idx;
          u32 next0 = next_index;
-         int ret;
 
          /* Prefetch for next iteration. */
          if (n_left_from > 1)
            {
              vlib_buffer_t *b1;
              b1 = vlib_get_buffer (vm, from[1]);
-             CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, LOAD);
-             CLIB_PREFETCH (&b1->trace_handle, 2 * CLIB_CACHE_LINE_BYTES,
-                            STORE);
+             CLIB_PREFETCH (b1, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
+             CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, LOAD);
            }
          /* Dequeue a packet buffer */
          bi0 = from[0];
@@ -248,7 +244,8 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
          const hicn_strategy_vft_t *strategy =
            hicn_dpo_get_strategy_vft (dpo_ctx->dpo_type);
 
-         ret = hicn_interest_parse_pkt (b0, &name, &namelen, &hicn0, &isv6);
+         hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen);
+
          stats.pkts_processed++;
          /* Select next hop */
          /*
@@ -256,8 +253,7 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
           * the interest-pcslookup node due to misconfiguration in
           * the punting rules.
           */
-         if (PREDICT_TRUE (ret == HICN_ERROR_NONE &&
-                           HICN_IS_NAMEHASH_CACHED (b0) &&
+         if (PREDICT_TRUE (HICN_IS_NAMEHASH_CACHED (b0) &&
                            strategy->hicn_select_next_hop (
                              vnet_buffer (b0)->ip.adj_index[VLIB_TX], &nh_idx,
                              outfaces, &outfaces_len) == HICN_ERROR_NONE))
@@ -267,7 +263,6 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
               * here. Already checked in the interest_pcslookup
               * node
               */
-             nameptr = (u8 *) (&name);
              u32 clones[outfaces_len];
              if (outfaces_len > 1)
                {
@@ -295,7 +290,7 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
                        rt, local_b0, &next0, tnow, nameptr, namelen,
                        outfaces[nh], nh_idx,
                        vnet_buffer (local_b0)->ip.adj_index[VLIB_TX],
-                       strategy, dpo_ctx->dpo_type, isv6, &stats, 0);
+                       strategy, dpo_ctx->dpo_type, &stats, 0);
                    }
                  else
                    {
@@ -304,7 +299,7 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
                        rt, local_b0, &next0, tnow, nameptr, namelen,
                        outfaces[nh], nh_idx,
                        vnet_buffer (local_b0)->ip.adj_index[VLIB_TX],
-                       strategy, dpo_ctx->dpo_type, isv6, &stats, 1);
+                       strategy, dpo_ctx->dpo_type, &stats, 1);
                    }
 
                  /* Maybe trace */
@@ -314,7 +309,7 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
                    {
                      hicn_strategy_trace_t *t =
                        vlib_add_trace (vm, node, local_b0, sizeof (*t));
-                     t->pkt_type = HICN_PKT_TYPE_CONTENT;
+                     t->pkt_type = HICN_PACKET_TYPE_DATA;
                      t->sw_if_index =
                        vnet_buffer (local_b0)->sw_if_index[VLIB_RX];
                      t->next_index = next0;
@@ -376,4 +371,4 @@ VLIB_REGISTER_NODE (hicn_strategy_node) =
  * fd.io coding-style-patch-verification: ON
  *
  * Local Variables: eval: (c-set-style "gnu") End:
- */
+ */
\ No newline at end of file
index 821feb2..392c2c9 100644 (file)
@@ -48,12 +48,18 @@ set(LIBHICN_HEADER_FILES_PROTOCOL
   ${CMAKE_CURRENT_SOURCE_DIR}/hicn/protocol/udp.h
   ${CMAKE_CURRENT_SOURCE_DIR}/hicn/protocol/new.h
   ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/array.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/bitmap.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/hash.h
   ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/ip_address.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/khash.h
   ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/log.h
   ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/map.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/pool.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/ring.h
   ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/set.h
   ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/sstrncpy.h
   ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/token.h
   ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/types.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/vector.h
   PARENT_SCOPE
 )
index 844814d..b825619 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef HICN_BASE_H
 #define HICN_BASE_H
 
+#include <stdio.h>
+#include <stdbool.h>
 #include "common.h"
 #ifdef _WIN32
 #include <Winsock2.h>
@@ -147,6 +149,16 @@ hicn_type_is_none (hicn_type_t type)
         (type.l3 == IPPROTO_NONE) && (type.l4 == IPPROTO_NONE);
 }
 
+/**
+ * @brief hICN Packet type
+ */
+typedef enum
+{
+  HICN_PACKET_TYPE_INTEREST,
+  HICN_PACKET_TYPE_DATA,
+  HICN_PACKET_N_TYPE,
+} hicn_packet_type_t;
+
 /**
  * @brief hICN Payload type
  *
@@ -160,6 +172,61 @@ typedef enum
   HPT_UNSPEC = 999
 } hicn_payload_type_t;
 
+/***************************************************************
+ * Interest Manifest
+ ***************************************************************/
+
+#define MAX_SUFFIXES_IN_MANIFEST 255
+#define WORD_WIDTH              (sizeof (uint32_t) * 8)
+#define BITMAP_SIZE             ((MAX_SUFFIXES_IN_MANIFEST + 1) / WORD_WIDTH)
+
+typedef struct
+{
+  /* This can be 16 bits, but we use 32 bits for alignment */
+  uint32_t n_suffixes;
+
+  uint32_t request_bitmap[BITMAP_SIZE];
+
+  /* Followed by the list of prefixes to ask */
+  /* ... */
+} interest_manifest_header_t;
+
+// Bitmap operations
+
+static inline void
+set_bit (uint32_t *bitmap, int i)
+{
+  size_t offset = i / WORD_WIDTH;
+  size_t pos = i % WORD_WIDTH;
+  bitmap[offset] |= ((uint32_t) 1 << pos);
+}
+
+static inline void
+unset_bit (uint32_t *bitmap, int i)
+{
+  size_t offset = i / WORD_WIDTH;
+  size_t pos = i % WORD_WIDTH;
+  bitmap[offset] &= ~((uint32_t) 1 << pos);
+}
+
+static inline bool
+is_bit_set (const uint32_t *bitmap, int i)
+{
+  size_t offset = i / WORD_WIDTH;
+  size_t pos = i % WORD_WIDTH;
+  return bitmap[offset] & ((uint32_t) 1 << pos);
+}
+
+static inline void
+bitmap_print (u32 *bitmap, size_t n_words)
+{
+  for (size_t word = 0; word < n_words; word++)
+    {
+      for (int bit = 31; bit >= 0; bit--)
+       (is_bit_set (&bitmap[word], bit)) ? printf ("1") : printf ("0");
+    }
+}
+
 /**
  * @brief Path label computations
  *
@@ -194,6 +261,79 @@ update_pathlabel (hicn_pathlabel_t current_label, hicn_faceid_t face_id,
     pl_face_id;
 }
 
+/***************************************************************
+ * Statistics
+ ***************************************************************/
+
+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;
+
+  // Data processing
+  uint32_t countDroppedNoReversePath;
+  uint32_t countDataExpired;
+
+  // TODO(eloparco): Currently not used
+  // uint32_t countDroppedNoHopLimit;
+  // uint32_t countDroppedZeroHopLimitFromRemote;
+  // uint32_t countDroppedZeroHopLimitToRemote;
+} forwarder_stats_t;
+
+typedef struct
+{
+  uint32_t n_pit_entries;
+  uint32_t n_cs_entries;
+  uint32_t n_lru_evictions;
+} pkt_cache_stats_t;
+
+typedef struct
+{
+  forwarder_stats_t forwarder;
+  pkt_cache_stats_t pkt_cache;
+} hicn_light_stats_t;
+
+typedef struct
+{
+  struct
+  {
+    uint32_t rx_pkts;
+    uint32_t rx_bytes;
+    uint32_t tx_pkts;
+    uint32_t tx_bytes;
+  } interests;
+  struct
+  {
+    uint32_t rx_pkts;
+    uint32_t rx_bytes;
+    uint32_t tx_pkts;
+    uint32_t tx_bytes;
+  } data;
+} connection_stats_t;
+
 #endif /* HICN_BASE_H */
 
 /*
index b0898ce..1998099 100644 (file)
@@ -224,8 +224,6 @@ ip_csum_sub_even (ip_csum_t c, ip_csum_t x)
 
 u32 cumulative_hash32 (const void *data, size_t len, u32 lastValue);
 u32 hash32 (const void *data, size_t len);
-u64 cumulative_hash64 (const void *data, size_t len, u64 lastValue);
-u64 hash64 (const void *data, size_t len);
 void hicn_packet_dump (const uint8_t *buffer, size_t len);
 
 /**
@@ -270,23 +268,75 @@ csum (const void *addr, size_t size, u16 init)
 #define HICN_IP_VERSION(packet)                                               \
   ((hicn_header_t *) packet)->protocol.ipv4.version
 
-/*
- * ntohll / htonll allows byte swapping for 64 bits integers
- */
-#ifndef htonll
-#define htonll(x)                                                             \
-  ((1 == htonl (1)) ?                                                         \
-          (x) :                                                                    \
-          ((uint64_t) htonl ((x) &0xFFFFFFFF) << 32) | htonl ((x) >> 32))
+#ifndef ntohll
+static inline uint64_t
+ntohll (uint64_t input)
+{
+  uint64_t return_val = input;
+#if (__BYTE_ORDER__) == (__ORDER_LITTLE_ENDIAN__)
+  uint8_t *tmp = (uint8_t *) &return_val;
+
+  tmp[0] = (uint8_t) (input >> 56);
+  tmp[1] = (uint8_t) (input >> 48);
+  tmp[2] = (uint8_t) (input >> 40);
+  tmp[3] = (uint8_t) (input >> 32);
+  tmp[4] = (uint8_t) (input >> 24);
+  tmp[5] = (uint8_t) (input >> 16);
+  tmp[6] = (uint8_t) (input >> 8);
+  tmp[7] = (uint8_t) (input >> 0);
 #endif
 
-#ifndef ntohll
-#define ntohll(x)                                                             \
-  ((1 == ntohl (1)) ?                                                         \
-          (x) :                                                                    \
-          ((uint64_t) ntohl ((x) &0xFFFFFFFF) << 32) | ntohl ((x) >> 32))
+  return return_val;
+}
+
+static inline uint64_t
+htonll (uint64_t input)
+{
+  return (ntohll (input));
+}
+#endif
+
+#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 /* HICN_COMMON_H */
 
 /*
index 8de3f9d..98c035b 100644 (file)
@@ -93,6 +93,8 @@ hicn_get_ah_format (hicn_format_t format)
 // HICN_V6_MIN_HDR_LEN : HICN_V4_MIN_HDR_LEN)
 #define HICN_MIN_HDR_LEN HICN_V6_MIN_HDR_LEN
 
+hicn_type_t hicn_header_to_type (const hicn_header_t *h);
+
 /**
  * @brief Parse packet headers and return hICN format
  * @param [in] format - hICN Format
index 8af9170..208e35d 100644 (file)
@@ -135,6 +135,8 @@ typedef union
 #define HICN_V4_TCP_AH_HDRLEN  (HICN_V4_TCP_HDRLEN + AH_HDRLEN)
 #define HICN_V4_ICMP_AH_HDRLEN (HICN_V4_ICMP_HDRLEN + AH_HDRLEN)
 
+#define HICN_DEFAULT_PORT 9695
+
 #endif /* HICN_HEADER_H */
 
 /*
index e9eebc7..4efef65 100644 (file)
@@ -256,6 +256,45 @@ typedef struct hicn_ops_s
   int (*set_lifetime) (hicn_type_t type, hicn_protocol_t *h,
                       const hicn_lifetime_t lifetime);
 
+  /**
+   * @brief Get the source port of the hicn packet.
+   * @param [in] type - hICN packet type
+   * @param [in] h - Buffer holding the Interest or Data packet
+   * @param [out] source_port - Retrieved source port
+   * @return hICN error code
+   */
+  int (*get_source_port) (hicn_type_t type, const hicn_protocol_t *h,
+                         u16 *source_port);
+
+  /**
+   * @brief Get the destination port of the hicn packet.
+   * @param [in] type - hICN packet type
+   * @param [in] h - Buffer holding the Interest or Data packet
+   * @param [out] source_port - Retrieved destination port
+   * @return hICN error code
+   */
+  int (*get_dest_port) (hicn_type_t type, const hicn_protocol_t *h,
+                       u16 *dest_port);
+
+  /**
+   * @brief Set the source port of the hicn packet.
+   * @param [in] type - hICN packet type
+   * @param [in] h - Buffer holding the Interest or Data packet
+   * @param [out] source_port - Source port to set
+   * @return hICN error code
+   */
+  int (*set_source_port) (hicn_type_t type, hicn_protocol_t *h,
+                         u16 source_port);
+
+  /**
+   * @brief Set the destination port of the hicn packet.
+   * @param [in] type - hICN packet type
+   * @param [in] h - Buffer holding the Interest or Data packet
+   * @param [out] source_port - Destination port to set
+   * @return hICN error code
+   */
+  int (*set_dest_port) (hicn_type_t type, hicn_protocol_t *h, u16 dest_port);
+
   /**
    * @brief Update all checksums in packet headers
    * @param [in] type - hICN packet type
@@ -540,6 +579,10 @@ typedef struct hicn_ops_s
     ATTR_INIT (reset_data_for_hash, protocol##_reset_data_for_hash),          \
     ATTR_INIT (get_lifetime, protocol##_get_lifetime),                        \
     ATTR_INIT (set_lifetime, protocol##_set_lifetime),                        \
+    ATTR_INIT (get_source_port, protocol##_get_source_port),                  \
+    ATTR_INIT (get_dest_port, protocol##_get_dest_port),                      \
+    ATTR_INIT (set_source_port, protocol##_set_source_port),                  \
+    ATTR_INIT (set_dest_port, protocol##_set_dest_port),                      \
     ATTR_INIT (update_checksums, protocol##_update_checksums),                \
     ATTR_INIT (verify_checksums, protocol##_verify_checksums),                \
     ATTR_INIT (rewrite_interest, protocol##_rewrite_interest),                \
@@ -775,6 +818,34 @@ PAYLOAD (hicn_type_t type, const hicn_protocol_t *h)
     return HICN_LIB_ERROR_##error;                                            \
   }
 
+#define DECLARE_get_source_port(protocol, error)                              \
+  int protocol##_get_source_port (hicn_type_t type, const hicn_protocol_t *h, \
+                                 u16 *source_port)                           \
+  {                                                                           \
+    return HICN_LIB_ERROR_##error;                                            \
+  }
+
+#define DECLARE_get_dest_port(protocol, error)                                \
+  int protocol##_get_dest_port (hicn_type_t type, const hicn_protocol_t *h,   \
+                               u16 *dest_port)                               \
+  {                                                                           \
+    return HICN_LIB_ERROR_##error;                                            \
+  }
+
+#define DECLARE_set_source_port(protocol, error)                              \
+  int protocol##_set_source_port (hicn_type_t type, hicn_protocol_t *h,       \
+                                 u16 source_port)                            \
+  {                                                                           \
+    return HICN_LIB_ERROR_##error;                                            \
+  }
+
+#define DECLARE_set_dest_port(protocol, error)                                \
+  int protocol##_set_dest_port (hicn_type_t type, hicn_protocol_t *h,         \
+                               u16 dest_port)                                \
+  {                                                                           \
+    return HICN_LIB_ERROR_##error;                                            \
+  }
+
 #define DECLARE_update_checksums(protocol, error)                             \
   int protocol##_update_checksums (hicn_type_t type, hicn_protocol_t *h,      \
                                   u16 partial_csum, size_t payload_length)   \
index 46d6097..f56c131 100644 (file)
@@ -28,8 +28,6 @@
 
 #define BUFSIZE 1024
 
-typedef int (*cmp_t) (const void *x, const void *y);
-
 #define TYPEDEF_ARRAY_H(NAME, T)                                              \
                                                                               \
   typedef struct                                                              \
@@ -151,7 +149,7 @@ typedef int (*cmp_t) (const void *x, const void *y);
     for (unsigned i = 0; i < array->size; i++)                                \
       {                                                                       \
        if (CMP (search, array->elements[i]) == 0)                            \
-         return facelet_array_remove_index (array, i, element);              \
+         return NAME##_remove_index (array, i, element);                     \
       }                                                                       \
     /* Not found */                                                           \
     if (element)                                                              \
diff --git a/lib/includes/hicn/util/bitmap.h b/lib/includes/hicn/util/bitmap.h
new file mode 100644 (file)
index 0000000..11eb787
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * 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 <hicn/common.h>
+#include <hicn/util/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/lib/includes/hicn/util/hash.h b/lib/includes/hicn/util/hash.h
new file mode 100644 (file)
index 0000000..ded8fc3
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * 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
+
+#include <stdint.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/lib/includes/hicn/util/khash.h b/lib/includes/hicn/util/khash.h
new file mode 100644 (file)
index 0000000..1740109
--- /dev/null
@@ -0,0 +1,826 @@
+/* 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 return codes
+ ******************************************************************************/
+
+// RESET: same as added, but the key was already added in the past
+#define foreach_kh_rc                                                         \
+  _ (REPLACED)                                                                \
+  _ (ADDED)                                                                   \
+  _ (RESET)                                                                   \
+  _ (NOT_FOUND)                                                               \
+  _ (FOUND)                                                                   \
+  _ (FAIL)
+
+typedef enum
+{
+#define _(x) KH_##x,
+  foreach_kh_rc
+#undef _
+} kh_rc;
+
+/******************************************************************************
+ *                                                                                     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 */
similarity index 63%
rename from hicn-light/src/hicn/base/pool.h
rename to lib/includes/hicn/util/pool.h
index b657319..7488e08 100644 (file)
 #include <stdbool.h>
 
 #include "bitmap.h"
-#include "vector.h"
+#include <hicn/util/vector.h>
+#include "../common.h"
 
 /* Pool header */
 
-typedef struct {
+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 */
+  off_t *free_indices;  /* vector of free indices */
 } pool_hdr_t;
 
-#define POOL_HDRLEN SIZEOF_ALIGNED(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))
+#define pool_hdr(pool) ((pool_hdr_t *) ((uint8_t *) (pool) -POOL_HDRLEN))
 
 /******************************************************************************/
 /* Helpers */
@@ -79,15 +81,15 @@ typedef struct {
  *
  * 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);
+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);
+void _pool_free (void **pool_ptr);
 
 /**
  * @brief Resize a pool data structure (helper).
@@ -97,7 +99,7 @@ void _pool_free(void **pool_ptr);
  * 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);
+void _pool_resize (void **pool_ptr, size_t elt_size);
 
 /**
  * @brief Get a free element from the pool data structure (helper).
@@ -109,7 +111,7 @@ void _pool_resize(void **pool_ptr, size_t elt_size);
  * NOTES:
  *  - The memory chunk is cleared upon attribution
  */
-off_t _pool_get(void **pool, void **elt, size_t elt_size);
+off_t _pool_get (void **pool, void **elt, size_t elt_size);
 
 /**
  * @brief Put an element back into the pool data structure (helper).
@@ -117,7 +119,7 @@ off_t _pool_get(void **pool, void **elt, size_t elt_size);
  * @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);
+void _pool_put (void **pool, void **elt, size_t elt_size);
 
 /**
  * @brief Validate a pool element by index (helper).
@@ -127,7 +129,7 @@ void _pool_put(void **pool, void **elt, size_t elt_size);
  *
  * @return bool A flag indicating whether the index is valid or not.
  */
-bool _pool_validate_id(void **pool_ptr, off_t id);
+bool _pool_validate_id (void **pool_ptr, off_t id);
 /******************************************************************************/
 /* Public API */
 
@@ -140,15 +142,15 @@ bool _pool_validate_id(void **pool_ptr, off_t id);
  *
  * 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);
+#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);
+#define pool_free(pool) _pool_free ((void **) &pool);
 
 /**
  * @brief Get a free element from the pool data structure.
@@ -160,8 +162,8 @@ bool _pool_validate_id(void **pool_ptr, off_t id);
  * NOTES:
  *  - The memory chunk is cleared upon attribution
  */
-#define pool_get(pool, elt) \
-  _pool_get((void **)&pool, (void **)&elt, sizeof(*elt))
+#define pool_get(pool, elt)                                                   \
+  _pool_get ((void **) &pool, (void **) &elt, sizeof (*elt))
 
 /**
  * @brief Put an element back into the pool data structure.
@@ -169,8 +171,8 @@ bool _pool_validate_id(void **pool_ptr, off_t id);
  * @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))
+#define pool_put(pool, elt)                                                   \
+  _pool_put ((void **) &pool, (void **) &elt, sizeof (*elt))
 
 /**
  * @brief Validate a pool element by index.
@@ -180,10 +182,10 @@ bool _pool_validate_id(void **pool_ptr, off_t id);
  *
  * @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_validate_id(pool, id) _pool_validate_id ((void **) &pool, (id))
 
-#define pool_get_free_indices_size(pool) \
-  vector_len(pool_hdr(pool)->free_indices)
+#define pool_get_free_indices_size(pool)                                      \
+  vector_len (pool_hdr (pool)->free_indices)
 
 /**
  * @brief Returns the current length of the pool.
@@ -196,8 +198,8 @@ bool _pool_validate_id(void **pool_ptr, off_t id);
  *  - 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))
+#define pool_len(pool)                                                        \
+  (pool_hdr (pool)->alloc_size - pool_get_free_indices_size (pool))
 
 /**
  * @brief Enumerate elements from a pool.
@@ -213,18 +215,24 @@ bool _pool_validate_id(void **pool_ptr, off_t id);
  *
  * 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)
+#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.
@@ -238,17 +246,19 @@ bool _pool_validate_id(void **pool_ptr, off_t id);
  * 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_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
+#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
+#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/lib/includes/hicn/util/ring.h b/lib/includes/hicn/util/ring.h
new file mode 100644 (file)
index 0000000..9510672
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * 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 (unsigned int) (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 */
similarity index 51%
rename from hicn-light/src/hicn/base/vector.h
rename to lib/includes/hicn/util/vector.h
index 0b7a74a..46f195c 100644 (file)
 #include <stdint.h>
 #include <string.h>
 #include <sys/types.h>
+#include <stdbool.h>
 
-#include "common.h"
+#include "../common.h"
 
 /******************************************************************************/
 /* Vector header */
 
-typedef struct {
+typedef struct
+{
   size_t cur_size;   /** Vector current size (corresponding to the highest used
-                        element). */
+                       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)
+#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))
+#define vector_hdr(vector)                                                    \
+  ((vector_hdr_t *) ((uint8_t *) vector - VECTOR_HDRLEN))
 
 /******************************************************************************/
 /* Helpers */
@@ -82,16 +85,17 @@ typedef struct {
  * @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).
+ * @return int 0 if successful, -1 otherwise
  */
-void _vector_init(void **vector_ptr, size_t elt_size, size_t init_size,
-                  size_t max_size);
+int _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);
+void _vector_free (void **vector_ptr);
 
 /**
  * @brief Resize a vector data structure.
@@ -109,7 +113,7 @@ void _vector_free(void **vector_ptr);
  * 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);
+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
@@ -127,11 +131,12 @@ int _vector_resize(void **vector_ptr, size_t elt_size, off_t pos);
  *  - 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);
+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;
 }
 
@@ -147,14 +152,17 @@ static inline int _vector_ensure_pos(void **vector_ptr, size_t elt_size,
  *  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;
+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 = 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;
 }
@@ -168,19 +176,91 @@ static inline int _vector_push(void **vector_ptr, size_t elt_size, void *elt) {
  * @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) {
+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++;
+  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--;
+         // Copy last element to current position (hence order is not
+         // maintained)
+         memcpy ((uint8_t *) vector + i * elt_size,
+                 (uint8_t *) vector + vh->cur_size * elt_size, elt_size);
+         num_removed++;
+       }
     }
-  }
-  return num_removed;
+  return (int) num_removed;
+}
+
+/**
+ * @brief Get the element at the specified position and store in 'elt'.
+ *
+ * @param[in] vector Pointer to the vector data structure to use
+ * @param[in] pos Position of the element to retrieve
+ * @param[in] elt_size The size of a vector element
+ * @param[in] elt The element where the result is stored
+ * @return int 0 if successful, -1 otherwise
+ */
+static inline int
+_vector_get (void *vector, off_t pos, size_t elt_size, void *elt)
+{
+  vector_hdr_t *vh = vector_hdr (vector);
+  if (pos >= vh->alloc_size)
+    return -1;
+
+  memcpy (elt, (uint8_t *) vector + pos * elt_size, elt_size);
+  return 0;
+}
+
+/**
+ * @brief Check if specified element is present in vector.
+ *
+ * @param[in] vector Pointer to the vector data structure to use
+ * @param[in] elt_size The size of a vector element
+ * @param[in] elt The element to search for
+ * @return true If specified element is contained in the vector
+ * @return false
+ */
+static inline bool
+_vector_contains (void *vector, size_t elt_size, void *elt)
+{
+  for (int i = 0; i < vector_hdr (vector)->cur_size; i++)
+    {
+      if (memcmp ((uint8_t *) vector + i * elt_size, elt, elt_size) == 0)
+       return true;
+    }
+
+  return false;
+}
+
+/**
+ * @brief Remove the element at the specified position from the vector.
+ * Relative element order is preserved by shifting left the elements after the
+ * target.
+ *
+ * @param[in, out] vector Pointer to the vector data structure to use
+ * @param[in] elt_size The size of a vector element
+ * @param[in] pos Position of the element to remove
+ * @return int 0 if successful, -1 otherwise
+ */
+static inline int
+_vector_remove_at (void **vector_ptr, size_t elt_size, off_t pos)
+{
+  vector_hdr_t *vh = vector_hdr (*vector_ptr);
+  if (pos >= vh->cur_size)
+    return -1;
+
+  // Shift backward by one position all the elements after the one specified
+  memmove ((uint8_t *) (*vector_ptr) + pos * elt_size,
+          (uint8_t *) (*vector_ptr) + (pos + 1) * elt_size,
+          (vh->cur_size - 1 - pos) * elt_size);
+  vh->cur_size--;
+
+  return 0;
 }
 
 /******************************************************************************/
@@ -197,15 +277,15 @@ static inline int _vector_remove_unordered(void *vector, size_t elt_size,
  *  - 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)
+#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)
+#define vector_free(vector) _vector_free ((void **) &vector)
 
 /**
  * @brief Resize a vector data structure.
@@ -225,8 +305,8 @@ static inline int _vector_remove_unordered(void *vector, size_t elt_size,
  *  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)
+#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
@@ -239,8 +319,8 @@ static inline int _vector_remove_unordered(void *vector, size_t elt_size,
  *  - 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);
+#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.
@@ -253,12 +333,72 @@ static inline int _vector_remove_unordered(void *vector, size_t elt_size,
  *  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)); \
+#define vector_push(vector, elt)                                              \
+  ({                                                                          \
+    typeof (elt) _vector_var (x) = elt;                                       \
+    _vector_push ((void **) &(vector), sizeof ((vector)[0]),                  \
+                 (void *) (&_vector_var (x)));                               \
+  })
+
+#define vector_at(vector, pos)                                                \
+  ({                                                                          \
+    assert (pos < vector_hdr (vector)->cur_size);                             \
+    (vector)[(pos)];                                                          \
+  })
+
+#define vector_set(vector, pos, elt)                                          \
+  ({                                                                          \
+    assert (pos < vector_hdr (vector)->cur_size);                             \
+    (vector)[(pos)] = elt;                                                    \
   })
 
+/**
+ * @brief Clear the vector content, i.e. new pushes will insert starting from
+ * position 0.
+ *
+ * @param[in, out] vector The vector to reset
+ */
+#define vector_reset(vector) (vector_len (vector) = 0)
+
+/**
+ * @brief Get the element at the specified position and store in 'elt'.
+ *
+ * @param[in] vector The vector data structure to use
+ * @param[in] pos Position of the element to retrieve
+ * @param[in] elt The element where the result is stored
+ * @return int 0 if successful, -1 otherwise
+ */
+#define vector_get(vector, pos, elt)                                          \
+  _vector_get ((void *) (vector), (pos), sizeof ((vector)[0]),                \
+              (void *) (&elt));
+
+/**
+ * @brief Check if specified element is present in vector.
+ *
+ * @param[in] vector The vector data structure to use
+ * @param[in] elt The element to search for
+ * @return true If specified element is contained in the vector
+ * @return false
+ */
+#define vector_contains(vector, elt)                                          \
+  ({                                                                          \
+    typeof (elt) _vector_var (x) = elt;                                       \
+    _vector_contains ((void *) (vector), sizeof ((vector)[0]),                \
+                     (void *) (&_vector_var (x)));                           \
+  })
+
+/**
+ * @brief Remove the element at the specified position from the vector.
+ * Relative element order is preserved by shifting left the elements after the
+ * target.
+ *
+ * @param[in, out] vector The vector data structure to use
+ * @param[in] pos Position of the element to remove
+ * @return int 0 if successful, -1 otherwise
+ */
+#define vector_remove_at(vector, pos)                                         \
+  _vector_remove_at ((void **) &(vector), sizeof ((vector)[0]), (pos))
+
 /**
  * @brief Remove all the occurrencies of an element from the vector.
  * The order of the elements is NOT maintained.
@@ -267,11 +407,11 @@ static inline int _vector_remove_unordered(void *vector, size_t elt_size,
  * @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));                         \
+#define vector_remove_unordered(vector, elt)                                  \
+  ({                                                                          \
+    typeof (elt) x = elt;                                                     \
+    _vector_remove_unordered ((void *) (vector), sizeof ((vector)[0]),        \
+                             (void *) (&x));                                 \
   })
 
 /**
@@ -288,12 +428,12 @@ static inline int _vector_remove_unordered(void *vector, size_t elt_size,
  *  - 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
+#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
+#define vector_get_alloc_size(vector) vector_hdr (vector)->alloc_size
 
 /**
  * @brief Iterate over elements in a vector.
@@ -303,25 +443,28 @@ static inline int _vector_remove_unordered(void *vector, size_t elt_size,
  * 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
+ * @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); \
+#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; }                                      \
-    }                                                \
+#define vector_enumerate(vector, i, eltp, BODY)                               \
+  ({                                                                          \
+    for ((i) = 0; (i) < vector_len (vector); (i)++)                           \
+      {                                                                       \
+       eltp = (vector) + (i);                                                \
+       {                                                                     \
+         BODY;                                                               \
+       }                                                                     \
+      }                                                                       \
   })
 
 #endif /* UTIL_VECTOR_H */
index ef74127..8e81aa4 100644 (file)
@@ -33,6 +33,9 @@ list(APPEND LIBHICN_SOURCE_FILES
   protocol/new.c
   util/ip_address.c
   util/log.c
+  util/pool.c
+  util/ring.c
+  util/vector.c
 )
 
 if (WIN32)
index c4cb8bc..3620349 100644 (file)
@@ -54,61 +54,44 @@ get_addr_family (const char *ip_address)
 
 /* hashes */
 
-u32
-cumulative_hash32 (const void *data, size_t len, u32 lastValue)
+// FNV-1a 32-bit http://www.isthe.com/chongo/tech/comp/fnv/
+typedef u_int32_t Fnv32_t;
+#define FNV_32_PRIME  ((Fnv32_t) 0x01000193)
+#define FNV1_32_INIT  ((Fnv32_t) 0x811c9dc5)
+#define FNV1_32A_INIT FNV1_32_INIT
+
+Fnv32_t
+cumulative_hash32 (const void *buf, size_t len, Fnv32_t hval)
 {
-  // Standard FNV 32-bit prime: see
-  // http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
-  const u32 fnv1a_prime = 0x01000193;
-  u32 hash = lastValue;
-  size_t i;
-
-  const char *chardata = data;
+  unsigned char *bp = (unsigned char *) buf; /* start of buffer */
+  unsigned char *be = bp + len;                     /* beyond end of buffer */
 
-  for (i = 0; i < len; i++)
+  /*
+   * FNV-1a hash each octet in the buffer
+   */
+  while (bp < be)
     {
-      hash = hash ^ chardata[i];
-      hash = hash * fnv1a_prime;
-    }
 
-  return hash;
-}
+      /* xor the bottom with the current octet */
+      hval ^= (Fnv32_t) *bp++;
 
-u32
-hash32 (const void *data, size_t len)
-{
-  // Standard FNV 32-bit offset: see
-  // http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
-  const u32 fnv1a_offset = 0x811C9DC5;
-  return cumulative_hash32 (data, len, fnv1a_offset);
-}
-
-u64
-cumulative_hash64 (const void *data, size_t len, u64 lastValue)
-{
-  // Standard FNV 64-bit prime: see
-  // http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
-  const u64 fnv1a_prime = 0x00000100000001B3ULL;
-  u64 hash = lastValue;
-  const char *chardata = data;
-  size_t i;
-
-  for (i = 0; i < len; i++)
-    {
-      hash = hash ^ chardata[i];
-      hash = hash * fnv1a_prime;
+      /* multiply by the 32 bit FNV magic prime mod 2^32 */
+#if defined(NO_FNV_GCC_OPTIMIZATION)
+      hval *= FNV_32_PRIME;
+#else
+      hval +=
+       (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
+#endif
     }
 
-  return hash;
+  /* return our new hash value */
+  return hval;
 }
 
-u64
-hash64 (const void *data, size_t len)
+u32
+hash32 (const void *data, size_t len)
 {
-  // Standard FNV 64-bit offset: see
-  // http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
-  const u64 fnv1a_offset = 0xCBF29CE484222325ULL;
-  return cumulative_hash64 (data, len, fnv1a_offset);
+  return cumulative_hash32 (data, len, FNV1_32A_INIT);
 }
 
 void
index 80ffcf3..20362d6 100644 (file)
@@ -57,6 +57,10 @@ DECLARE_update_data_pathlabel (none, NONE);
 DECLARE_reset_data_for_hash (none, NONE);
 DECLARE_get_lifetime (none, NONE);
 DECLARE_set_lifetime (none, NONE);
+DECLARE_get_source_port (none, NONE);
+DECLARE_get_dest_port (none, NONE);
+DECLARE_set_source_port (none, NONE);
+DECLARE_set_dest_port (none, NONE);
 DECLARE_update_checksums (none, NONE);
 DECLARE_verify_checksums (none, NONE);
 DECLARE_rewrite_interest (none, NONE);
index b3d2416..c9ed401 100644 (file)
@@ -45,6 +45,10 @@ DECLARE_set_data_pathlabel (ah, UNEXPECTED);
 DECLARE_update_data_pathlabel (ah, UNEXPECTED);
 DECLARE_get_lifetime (ah, UNEXPECTED);
 DECLARE_set_lifetime (ah, UNEXPECTED);
+DECLARE_get_source_port (ah, UNEXPECTED);
+DECLARE_get_dest_port (ah, UNEXPECTED);
+DECLARE_set_source_port (ah, UNEXPECTED);
+DECLARE_set_dest_port (ah, UNEXPECTED);
 DECLARE_get_payload_length (ah, UNEXPECTED);
 DECLARE_set_payload_length (ah, UNEXPECTED);
 DECLARE_get_payload_type (ah, UNEXPECTED);
index 0452e4f..1fc6c7d 100644 (file)
@@ -38,6 +38,10 @@ DECLARE_set_data_pathlabel (icmp, UNEXPECTED);
 DECLARE_update_data_pathlabel (icmp, UNEXPECTED);
 DECLARE_get_lifetime (icmp, UNEXPECTED);
 DECLARE_set_lifetime (icmp, UNEXPECTED);
+DECLARE_get_source_port (icmp, UNEXPECTED);
+DECLARE_get_dest_port (icmp, UNEXPECTED);
+DECLARE_set_source_port (icmp, UNEXPECTED);
+DECLARE_set_dest_port (icmp, UNEXPECTED);
 DECLARE_get_length (icmp, UNEXPECTED);
 DECLARE_get_payload_length (icmp, UNEXPECTED);
 DECLARE_set_payload_length (icmp, UNEXPECTED);
index 5d445f0..840fbe3 100644 (file)
@@ -227,6 +227,31 @@ ipv4_set_lifetime (hicn_type_t type, hicn_protocol_t *h,
   return CHILD_OPS (set_lifetime, type, h, lifetime);
 }
 
+int
+ipv4_get_source_port (hicn_type_t type, const hicn_protocol_t *h,
+                     u16 *source_port)
+{
+  return CHILD_OPS (get_source_port, type, h, source_port);
+}
+
+int
+ipv4_get_dest_port (hicn_type_t type, const hicn_protocol_t *h, u16 *dest_port)
+{
+  return CHILD_OPS (get_dest_port, type, h, dest_port);
+}
+
+int
+ipv4_set_source_port (hicn_type_t type, hicn_protocol_t *h, u16 source_port)
+{
+  return CHILD_OPS (set_source_port, type, h, source_port);
+}
+
+int
+ipv4_set_dest_port (hicn_type_t type, hicn_protocol_t *h, u16 dest_port)
+{
+  return CHILD_OPS (set_dest_port, type, h, dest_port);
+}
+
 int
 ipv4_update_checksums (hicn_type_t type, hicn_protocol_t *h, u16 partial_csum,
                       size_t payload_length)
index b3a107a..b3c5432 100644 (file)
@@ -211,6 +211,31 @@ ipv6_set_lifetime (hicn_type_t type, hicn_protocol_t *h,
   return CHILD_OPS (set_lifetime, type, h, lifetime);
 }
 
+int
+ipv6_get_source_port (hicn_type_t type, const hicn_protocol_t *h,
+                     u16 *source_port)
+{
+  return CHILD_OPS (get_source_port, type, h, source_port);
+}
+
+int
+ipv6_get_dest_port (hicn_type_t type, const hicn_protocol_t *h, u16 *dest_port)
+{
+  return CHILD_OPS (get_dest_port, type, h, dest_port);
+}
+
+int
+ipv6_set_source_port (hicn_type_t type, hicn_protocol_t *h, u16 source_port)
+{
+  return CHILD_OPS (set_source_port, type, h, source_port);
+}
+
+int
+ipv6_set_dest_port (hicn_type_t type, hicn_protocol_t *h, u16 dest_port)
+{
+  return CHILD_OPS (set_dest_port, type, h, dest_port);
+}
+
 int
 ipv6_update_checksums (hicn_type_t type, hicn_protocol_t *h, u16 partial_csum,
                       size_t payload_length)
index 8c79963..07c1d0d 100644 (file)
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-function"
 
+DECLARE_get_source_port (new, UNEXPECTED);
+DECLARE_get_dest_port (new, UNEXPECTED);
+DECLARE_set_source_port (new, UNEXPECTED);
+DECLARE_set_dest_port (new, UNEXPECTED);
+
 static int
 is_interest (u8 flags)
 {
index 8097cfd..82fc461 100644 (file)
@@ -250,6 +250,35 @@ tcp_set_lifetime (hicn_type_t type, hicn_protocol_t *h,
   return HICN_LIB_ERROR_NONE;
 }
 
+int
+tcp_get_source_port (hicn_type_t type, const hicn_protocol_t *h,
+                    u16 *source_port)
+{
+  *source_port = ntohs (h->tcp.sport);
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_get_dest_port (hicn_type_t type, const hicn_protocol_t *h, u16 *dest_port)
+{
+  *dest_port = ntohs (h->tcp.dport);
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_set_source_port (hicn_type_t type, hicn_protocol_t *h, u16 source_port)
+{
+  h->tcp.sport = htons (source_port);
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_set_dest_port (hicn_type_t type, hicn_protocol_t *h, u16 dest_port)
+{
+  h->tcp.dport = htons (dest_port);
+  return HICN_LIB_ERROR_NONE;
+}
+
 int
 tcp_update_checksums (hicn_type_t type, hicn_protocol_t *h, u16 partial_csum,
                      size_t payload_length)
index ee46b8e..7a14b09 100644 (file)
@@ -142,6 +142,35 @@ udp_set_lifetime (hicn_type_t type, hicn_protocol_t *h,
   return CHILD_OPS (set_lifetime, type, h, lifetime);
 }
 
+int
+udp_get_source_port (hicn_type_t type, const hicn_protocol_t *h,
+                    u16 *source_port)
+{
+  *source_port = ntohs (h->udp.src_port);
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+udp_get_dest_port (hicn_type_t type, const hicn_protocol_t *h, u16 *dest_port)
+{
+  *dest_port = ntohs (h->udp.dst_port);
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+udp_set_source_port (hicn_type_t type, hicn_protocol_t *h, u16 source_port)
+{
+  h->udp.src_port = htons (source_port);
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+udp_set_dest_port (hicn_type_t type, hicn_protocol_t *h, u16 dest_port)
+{
+  h->udp.dst_port = htons (dest_port);
+  return HICN_LIB_ERROR_NONE;
+}
+
 int
 udp_update_checksums (hicn_type_t type, hicn_protocol_t *h, u16 partial_csum,
                      size_t payload_length)
index 9757626..91a87e8 100644 (file)
@@ -30,6 +30,10 @@ log_conf_t log_conf = DEFAULT_LOG_CONF;
 #define FMT_DATETIME_LEN     20
 #define snprintf_nowarn(...) (snprintf (__VA_ARGS__) < 0 ? abort () : (void) 0)
 
+#define COLOR_RED    "\033[31m"
+#define COLOR_YELLOW "\033[33m"
+#define COLOR_RESET  "\033[0m"
+
 static char ts[FMT_DATETIME_LEN];
 
 static char *
@@ -104,7 +108,7 @@ _log_va (int level, const char *fmt, va_list ap)
     }
   else
     {
-      __android_log_vprint (ANDROID_LOG_INFO, "HICN FACEMGR", fmt, ap);
+      __android_log_vprint (prio, "HICN FACEMGR", fmt, ap);
     }
 
 #else
@@ -112,6 +116,7 @@ _log_va (int level, const char *fmt, va_list ap)
   if (level > log_conf.log_level)
     return;
 
+  char *color = COLOR_RESET;
   switch (level)
     {
     case LOG_FATAL:
@@ -119,9 +124,11 @@ _log_va (int level, const char *fmt, va_list ap)
       break;
     case LOG_ERROR:
       prefix = "ERROR: ";
+      color = COLOR_RED;
       break;
     case LOG_WARN:
       prefix = "WARNING: ";
+      color = COLOR_YELLOW;
       break;
     case LOG_INFO:
       prefix = "";
@@ -137,9 +144,9 @@ _log_va (int level, const char *fmt, va_list ap)
       break;
     }
   FILE *f = log_conf.log_file ? log_conf.log_file : stdout;
-  fprintf (f, "%s %s", timestamp (), prefix);
+  fprintf (f, "%s%s %s", color, timestamp (), prefix);
   vfprintf (f, fmt, ap);
-  fprintf (f, "\n");
+  fprintf (f, "%s\n", COLOR_RESET);
 #ifdef DEBUG
   fflush (f);
 #endif
diff --git a/lib/src/util/pool.c b/lib/src/util/pool.c
new file mode 100644 (file)
index 0000000..c6be92c
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * 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 <hicn/util/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;
+
+  WARN ("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;
+  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);
+}
similarity index 71%
rename from hicn-light/src/hicn/base/ring.c
rename to lib/src/util/ring.c
index 2972788..2c722a8 100644 (file)
 
 #include <stdlib.h>
 
-#include "ring.h"
+#include <hicn/util/ring.h>
 
-void _ring_init(void** ring_ptr, size_t elt_size, size_t max_size) {
-  assert(ring_ptr);
-  assert(elt_size > 0);
+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);
+  assert (max_size != 0);
 
-  ring_hdr_t* rh = malloc(RING_HDRLEN + max_size * elt_size);
+  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;
+  *ring_ptr = (uint8_t *) rh + RING_HDRLEN;
 }
 
-void _ring_free(void** ring_ptr) {
-  free(ring_hdr(*ring_ptr));
+void
+_ring_free (void **ring_ptr)
+{
+  free (ring_hdr (*ring_ptr));
   *ring_ptr = NULL;
 }
similarity index 51%
rename from hicn-light/src/hicn/base/vector.c
rename to lib/src/util/vector.c
index 36d8089..1f5cd02 100644 (file)
  */
 
 #include <assert.h>
-#include <stddef.h>  // size_t
-#include <stdlib.h>  // calloc
+#include <stddef.h> // size_t
+#include <stdlib.h> // calloc
 #include <stdio.h>
 
-#include "vector.h"
+#include <hicn/util/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);
+int
+_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;
+  if (init_size == 0)
+    init_size = DEFAULT_VECTOR_SIZE;
 
   *vector_ptr = NULL;
-  _vector_resize(vector_ptr, elt_size, init_size);
+  int rc = _vector_resize (vector_ptr, elt_size, init_size);
+  if (rc < 0)
+    return -1;
 
-  vector_hdr_t* vh = vector_hdr(*vector_ptr);
+  vector_hdr_t *vh = vector_hdr (*vector_ptr);
   vh->cur_size = 0;
   vh->max_size = max_size;
+
+  return 0;
 }
 
-void _vector_free(void** vector_ptr) {
-  free(vector_hdr(*vector_ptr));
+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;
-
+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;
-  }
+  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);
+  size_t new_size = next_pow2 (pos);
 
   /* Don't grow the vector back */
-  if (new_size < old_size) return 0;
+  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;
+  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 = 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);
+  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;
+  *vector_ptr = (uint8_t *) vh + VECTOR_HDRLEN;
 
   return 0;
 }
index 78cad35..41b6605 100644 (file)
@@ -23,6 +23,9 @@ TRANSPORT_CLANG_DISABLE_WARNING("-Wdeprecated-declarations")
 #ifndef ASIO_STANDALONE
 #define ASIO_STANDALONE
 #endif
+#ifdef __APPLE__
+TRANSPORT_CLANG_DISABLE_WARNING("-Wshorten-64-to-32")
+#endif
 #include <asio.hpp>
 
 TRANSPORT_POP_WARNING
index b671a7d..ad0d4f0 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <deque>
 #include <functional>
+#include <system_error>
 
 namespace transport {
 
@@ -57,10 +58,10 @@ class Connector : public std::enable_shared_from_this<Connector> {
   static constexpr std::uint16_t max_burst = 256;
 
   using Ptr = std::shared_ptr<Connector>;
+  using ReceptionBuffer = std::vector<utils::MemBuf::Ptr>;
   using PacketQueue = std::deque<utils::MemBuf::Ptr>;
-  using PacketReceivedCallback =
-      std::function<void(Connector *, const std::vector<utils::MemBuf::Ptr> &,
-                         const std::error_code &)>;
+  using PacketReceivedCallback = std::function<void(
+      Connector *, const ReceptionBuffer &, const std::error_code &)>;
   using PacketSentCallback =
       std::function<void(Connector *, const std::error_code &)>;
   using OnCloseCallback = std::function<void(Connector *)>;
@@ -118,6 +119,14 @@ class Connector : public std::enable_shared_from_this<Connector> {
 
   virtual void send(const utils::MemBuf::Ptr &buffer) = 0;
 
+  virtual void receive(const std::vector<utils::MemBuf::Ptr> &buffers) {
+    receive_callback_(this, buffers, std::make_error_code(std::errc()));
+  }
+
+  virtual void reconnect() {
+    on_reconnect_callback_(this, std::make_error_code(std::errc()));
+  }
+
   virtual void close() = 0;
 
   virtual State state() { return state_; };
@@ -134,6 +143,11 @@ class Connector : public std::enable_shared_from_this<Connector> {
 
   std::string getConnectorName() { return connector_name_; }
 
+  template <typename EP>
+  void setLocalEndpoint(EP &&endpoint) {
+    local_endpoint_ = std::forward<EP>(endpoint);
+  }
+
   Endpoint getLocalEndpoint() { return local_endpoint_; }
 
   Endpoint getRemoteEndpoint() { return remote_endpoint_; }
index a8df1e8..f8d9584 100644 (file)
@@ -43,8 +43,8 @@ class ContentObject : public Packet {
   template <typename... Args>
   ContentObject(CopyBufferOp op, Args &&...args)
       : Packet(op, std::forward<Args>(args)...) {
-    if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) <
-        0) {
+    if (hicn_data_get_name(format_, packet_start_,
+                           &name_.getStructReference()) < 0) {
       throw errors::MalformedPacketException();
     }
   }
@@ -52,8 +52,8 @@ class ContentObject : public Packet {
   template <typename... Args>
   ContentObject(WrapBufferOp op, Args &&...args)
       : Packet(op, std::forward<Args>(args)...) {
-    if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) <
-        0) {
+    if (hicn_data_get_name(format_, packet_start_,
+                           &name_.getStructReference()) < 0) {
       throw errors::MalformedPacketException();
     }
   }
@@ -65,8 +65,8 @@ class ContentObject : public Packet {
       throw errors::MalformedPacketException();
     }
 
-    if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) <
-        0) {
+    if (hicn_data_get_name(format_, packet_start_,
+                           &name_.getStructReference()) < 0) {
       throw errors::MalformedPacketException();
     }
   }
index b7ce3c3..9e6cdcc 100644 (file)
@@ -29,14 +29,6 @@ const uint32_t MAX_AGGREGATED_INTEREST = 128;
 
 class Interest
     : public Packet /*, public std::enable_shared_from_this<Interest>*/ {
- private:
-  struct InterestManifestHeader {
-    /* This can be 16 bits, but we use 32 bits for alignment */
-    uint32_t n_suffixes;
-    /* Followed by the list of prefixes to ask */
-    /* ... */
-  };
-
  public:
   using Ptr = std::shared_ptr<Interest>;
 
@@ -51,7 +43,7 @@ class Interest
   Interest(CopyBufferOp op, Args &&...args)
       : Packet(op, std::forward<Args>(args)...) {
     if (hicn_interest_get_name(format_, packet_start_,
-                               name_.getStructReference()) < 0) {
+                               &name_.getStructReference()) < 0) {
       throw errors::MalformedPacketException();
     }
   }
@@ -60,7 +52,7 @@ class Interest
   Interest(WrapBufferOp op, Args &&...args)
       : Packet(op, std::forward<Args>(args)...) {
     if (hicn_interest_get_name(format_, packet_start_,
-                               name_.getStructReference()) < 0) {
+                               &name_.getStructReference()) < 0) {
       throw errors::MalformedPacketException();
     }
   }
@@ -108,6 +100,12 @@ class Interest
 
   uint32_t numberOfSuffixes();
 
+  uint32_t *getRequestBitmap();
+
+  void setRequestBitmap(const uint32_t *request_bitmap);
+
+  bool isValid();
+
   auto shared_from_this() { return utils::shared_from(this); }
 
  private:
index 817d96d..31da0b8 100644 (file)
@@ -19,6 +19,7 @@
 #include <hicn/transport/core/connector.h>
 #include <hicn/transport/core/packet.h>
 #include <hicn/transport/core/prefix.h>
+#include <hicn/transport/portability/endianess.h>
 #include <hicn/transport/portability/portability.h>
 #include <hicn/transport/utils/chrono_typedefs.h>
 #include <hicn/transport/utils/membuf.h>
@@ -48,13 +49,12 @@ class IoModule : utils::NonCopyable {
         mtu_(1500),
         output_interface_(""),
         content_store_reserved_(5000) {
-    inet_address_.v4.as_u32 = htonl(0x7f00001);
+    inet_address_.v4.as_u32 = portability::host_to_net(0x7f00001);
     inet6_address_.v6.as_u8[15] = 0x01;
   }
 
  public:
   static IoModule *load(const char *);
-  static bool unload(IoModule *);
 
  public:
   virtual ~IoModule();
@@ -65,6 +65,7 @@ class IoModule : utils::NonCopyable {
 
   virtual void init(Connector::PacketReceivedCallback &&receive_callback,
                     Connector::PacketSentCallback &&sent_callback,
+                    Connector::OnCloseCallback &&close_callback,
                     Connector::OnReconnectCallback &&reconnect_callback,
                     asio::io_service &io_service,
                     const std::string &app_name = "Libtransport") = 0;
@@ -108,11 +109,6 @@ class IoModule : utils::NonCopyable {
 
   const std::string &getOutputInterface() { return output_interface_; }
 
-#ifndef ANDROID
- private:
-  void *handle_;
-#endif
-
  protected:
   ip_address_t inet_address_;
   ip_address_t inet6_address_;
index 5cb4efd..cf6d309 100644 (file)
@@ -46,6 +46,7 @@ class Name {
   friend class Packet;
   friend class ContentObject;
   friend class Interest;
+  friend class Prefix;
 
   static const uint32_t standard_name_string_length = 100;
 
@@ -102,11 +103,11 @@ class Name {
   int getAddressFamily() const;
 
  private:
-  TRANSPORT_ALWAYS_INLINE const NameStruct *getConstStructReference() const {
-    return &name_;
+  TRANSPORT_ALWAYS_INLINE const NameStruct &getConstStructReference() const {
+    return name_;
   }
 
-  TRANSPORT_ALWAYS_INLINE NameStruct *getStructReference() { return &name_; }
+  TRANSPORT_ALWAYS_INLINE NameStruct &getStructReference() { return name_; }
 
   NameStruct name_;
 };
index 13401e1..778491a 100644 (file)
@@ -25,13 +25,9 @@ class Prefix {
  public:
   Prefix();
 
-  Prefix(const char *prefix);
-
   Prefix(const std::string &prefix);
 
-  Prefix(std::string &&prefix);
-
-  Prefix(std::string &prefix, uint16_t prefix_length);
+  Prefix(const std::string &prefix, uint16_t prefix_length);
 
   Prefix(const core::Name &content_name, uint16_t prefix_length);
 
@@ -39,6 +35,8 @@ class Prefix {
 
   bool operator==(const Prefix &prefix) const;
 
+  bool operator!=(const Prefix &prefix) const { return !operator==(prefix); }
+
   std::unique_ptr<Sockaddr> toSockaddr() const;
 
   uint16_t getPrefixLength() const;
@@ -47,26 +45,22 @@ class Prefix {
 
   std::string getNetwork() const;
 
-  int contains(const ip_address_t &content_name) const;
+  Prefix &setNetwork(const std::string &network);
 
-  int contains(const core::Name &content_name) const;
+  int getAddressFamily() const;
 
-  Name getName() const;
+  bool contains(const ip_address_t &content_name) const;
 
-  Name getRandomName() const;
+  bool contains(const core::Name &content_name) const;
 
   Name getName(const core::Name &mask, const core::Name &components,
                const core::Name &content_name) const;
 
   Name mapName(const core::Name &content_name) const;
 
-  Prefix &setNetwork(std::string &network);
-
-  int getAddressFamily() const;
-
-  Prefix &setAddressFamily(int address_family);
-
+  Name makeName() const;
   Name makeRandomName() const;
+  Name makeNameWithIndex(std::uint64_t index) const;
 
   const ip_prefix_t &toIpPrefixStruct() const;
 
@@ -74,8 +68,10 @@ class Prefix {
   static bool checkPrefixLengthAndAddressFamily(uint16_t prefix_length,
                                                 int family);
 
-  void buildPrefix(std::string &prefix, uint16_t prefix_length, int family);
+  void buildPrefix(const std::string &prefix, uint16_t prefix_length,
+                   int family);
 
+ private:
   ip_prefix_t ip_prefix_;
 };
 
index 1acaadc..43f95a4 100644 (file)
@@ -24,11 +24,4 @@ list(APPEND HEADER_FILES
   ${CMAKE_CURRENT_SOURCE_DIR}/notification.h
 )
 
-if (${OPENSSL_VERSION} VERSION_EQUAL "1.1.1a" OR ${OPENSSL_VERSION} VERSION_GREATER "1.1.1a")
-  list(APPEND HEADER_FILES
-    ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.h
-    ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.h
-  )
-endif()
-
 set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
index a9fe6fa..e1465d3 100644 (file)
@@ -26,8 +26,16 @@ namespace transport {
 namespace interface {
 namespace global_config {
 
-static const constexpr char io_module_section[] = "io_module";
-void parseConfigurationFile(const std::string& path = "");
+class GlobalConfigInterface {
+ public:
+  GlobalConfigInterface();
+  ~GlobalConfigInterface();
+  void parseConfigurationFile(const std::string& path = "") const;
+
+ private:
+  void libtransportConfigInit() const;
+  void libtransportConfigTerminate() const;
+};
 
 class ConfigurationObject {
  public:
@@ -49,7 +57,9 @@ class ConfigurationObject {
 
 class IoModuleConfiguration : public ConfigurationObject {
  public:
-  std::string getKey() const override { return io_module_section; }
+  static inline char section[] = "io_module";
+
+  std::string getKey() const override { return section; }
 
   std::string name;
   std::vector<std::string> search_path;
diff --git a/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h
deleted file mode 100644 (file)
index a67634c..0000000
+++ /dev/null
@@ -1,32 +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.
- */
-
-#pragma once
-
-#include <hicn/transport/interfaces/socket_consumer.h>
-
-namespace transport {
-
-namespace interface {
-
-class P2PSecureConsumerSocket : public ConsumerSocket {
- public:
-  P2PSecureConsumerSocket(int handshake_protocol, int transport_protocol);
-  ~P2PSecureConsumerSocket() = default;
-  void registerPrefix(const Prefix &producer_namespace);
-};
-
-}  // namespace interface
-}  // end namespace transport
diff --git a/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h
deleted file mode 100644 (file)
index e197a36..0000000
+++ /dev/null
@@ -1,34 +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.
- */
-
-#pragma once
-
-#include <hicn/transport/interfaces/socket_producer.h>
-
-namespace transport {
-
-namespace interface {
-
-class P2PSecureProducerSocket : public ProducerSocket {
- public:
-  P2PSecureProducerSocket();
-  P2PSecureProducerSocket(bool rtc, std::string &keystore_path,
-                          std::string &keystore_pwd);
-  ~P2PSecureProducerSocket() = default;
-};
-
-}  // namespace interface
-
-}  // end namespace transport
index 1a22b1f..bca78cb 100644 (file)
@@ -95,7 +95,7 @@ class Portal : private utils::NonCopyable {
    * parameter. Otherwise ConsumerCallback::onTimeout will be used.
    */
   void sendInterest(
-      core::Interest::Ptr &&interest,
+      core::Interest::Ptr &interest, uint32_t lifetime,
       OnContentObjectCallback &&on_content_object_callback = UNSET_CALLBACK,
       OnInterestTimeoutCallback &&on_interest_timeout_callback =
           UNSET_CALLBACK);
index e26fe5a..d997634 100644 (file)
@@ -250,6 +250,9 @@ class ConsumerSocket : private utils::NonCopyable {
   int setSocketOption(int socket_option_key,
                       interface::IcnObserver *socket_option_value);
 
+  int setSocketOption(int socket_option_key,
+                      const std::shared_ptr<auth::Signer> &socket_option_value);
+
   int setSocketOption(
       int socket_option_key,
       const std::shared_ptr<auth::Verifier> &socket_option_value);
@@ -282,6 +285,9 @@ class ConsumerSocket : private utils::NonCopyable {
 
   int getSocketOption(int socket_option_key, IcnObserver **socket_option_value);
 
+  int getSocketOption(int socket_option_key,
+                      std::shared_ptr<auth::Signer> &socket_option_value);
+
   int getSocketOption(int socket_option_key,
                       std::shared_ptr<auth::Verifier> &socket_option_value);
 
index 0e19ae6..da8eafc 100644 (file)
@@ -53,9 +53,9 @@ static constexpr uint32_t key_locator_size = 60;          // bytes
 static constexpr uint32_t limit_guard = 80;               // bytes
 static constexpr uint32_t digest_size = 34;               // bytes
 static constexpr uint32_t max_out_of_order_segments = 3;  // content object
-static constexpr uint32_t unverified_interval = 60000;    // milliseconds
-static constexpr double unverified_ratio = 0.2;
-static constexpr uint32_t manifest_capacity = 20;
+static constexpr uint32_t manifest_max_capacity = 30;
+static constexpr uint32_t manifest_factor_relevant = 100;
+static constexpr uint32_t manifest_factor_alert = 20;
 
 // RAAQM
 static constexpr int sample_number = 30;
index 6cba50d..a14c841 100644 (file)
@@ -46,6 +46,9 @@ typedef enum {
   LOW_RATE_AND_BESTPATH = 25,
   LOW_RATE_AND_REPLICATION = 26,
   LOW_RATE_AND_ALL_FWD_STRATEGIES = 27,
+  FEC_ONLY_LOW_RES_LOSSES = 28,
+  DELAY_AND_BESTPATH = 29,
+  DELAY_AND_REPLICATION = 30,
 } RtcTransportRecoveryStrategies;
 
 typedef enum {
@@ -58,23 +61,23 @@ typedef enum {
   INTEREST_LIFETIME = 107,
   CONTENT_OBJECT_EXPIRY_TIME = 108,
   MAX_SEGMENT_SIZE = 109,
-  MIN_WINDOW_SIZE = 111,
-  MAX_WINDOW_SIZE = 112,
-  CURRENT_WINDOW_SIZE = 113,
-  ASYNC_MODE = 114,
-  MAKE_MANIFEST = 115,
-  PORTAL = 116,
-  RUNNING = 117,
-  APPLICATION_BUFFER = 118,
-  HASH_ALGORITHM = 119,
-  SIGNER = 121,
-  VERIFIER = 122,
-  UNVERIFIED_INTERVAL = 123,
-  UNVERIFIED_RATIO = 124,
-  STATS_INTERVAL = 125,
-  SUFFIX_STRATEGY = 126,
-  PACKET_FORMAT = 127,
-  FEC_TYPE = 128,
+  MIN_WINDOW_SIZE = 110,
+  MAX_WINDOW_SIZE = 111,
+  CURRENT_WINDOW_SIZE = 112,
+  ASYNC_MODE = 113,
+  PORTAL = 114,
+  RUNNING = 115,
+  APPLICATION_BUFFER = 116,
+  HASH_ALGORITHM = 117,
+  SIGNER = 118,
+  VERIFIER = 119,
+  MANIFEST_MAX_CAPACITY = 120,
+  MANIFEST_FACTOR_RELEVANT = 121,
+  MANIFEST_FACTOR_ALERT = 122,
+  STATS_INTERVAL = 123,
+  SUFFIX_STRATEGY = 124,
+  PACKET_FORMAT = 125,
+  FEC_TYPE = 126,
 } GeneralTransportOptions;
 
 typedef enum {
@@ -139,6 +142,8 @@ typedef enum {
 typedef enum {
   RECOVERY_STRATEGY = 901,
   AGGREGATED_DATA = 902,
+  CONTENT_SHARING_MODE = 903,
+  AGGREGATED_INTERESTS = 904,
 } RtcTransportOptions;
 
 }  // namespace interface
index 77b8974..be08c9a 100644 (file)
@@ -123,6 +123,10 @@ class ProducerSocket : private utils::NonCopyable {
   int setSocketOption(int socket_option_key,
                       const std::shared_ptr<auth::Signer> &socket_option_value);
 
+  int setSocketOption(
+      int socket_option_key,
+      const std::shared_ptr<auth::Verifier> &socket_option_value);
+
   int setSocketOption(int socket_option_key,
                       const std::string &socket_option_value);
 
@@ -154,6 +158,9 @@ class ProducerSocket : private utils::NonCopyable {
   int getSocketOption(int socket_option_key,
                       std::shared_ptr<auth::Signer> &socket_option_value);
 
+  int getSocketOption(int socket_option_key,
+                      std::shared_ptr<auth::Verifier> &socket_option_value);
+
   int getSocketOption(int socket_option_key, std::string &socket_option_value);
 
   int getSocketOption(int socket_option_key,
index 4d9e1bf..e83aa9a 100644 (file)
@@ -73,10 +73,10 @@ class TransportStatistics {
   }
 
   TRANSPORT_ALWAYS_INLINE void updateAverageRtt(
-      const utils::SteadyTime::Milliseconds &rtt) {
-    auto rtt_milliseconds = rtt.count();
-    average_rtt_ =
-        (alpha_ * average_rtt_) + ((1. - alpha_) * double(rtt_milliseconds));
+      const utils::SteadyTime::Microseconds &rtt) {
+    double rtt_milliseconds = double(rtt.count()) / 1000.0;
+
+    average_rtt_ = (alpha_ * average_rtt_) + ((1. - alpha_) * rtt_milliseconds);
   }
 
   TRANSPORT_ALWAYS_INLINE void updateAverageWindowSize(double current_window) {
index 7a688b1..d29ec73 100644 (file)
@@ -15,6 +15,8 @@ list(APPEND HEADER_FILES
   ${CMAKE_CURRENT_SOURCE_DIR}/c_portability.h
   ${CMAKE_CURRENT_SOURCE_DIR}/portability.h
   ${CMAKE_CURRENT_SOURCE_DIR}/cpu.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/cache.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/endianess.h
 )
 
 list(APPEND SOURCE_FILES
diff --git a/libtransport/includes/hicn/transport/portability/cache.h b/libtransport/includes/hicn/transport/portability/cache.h
new file mode 100644 (file)
index 0000000..ae113c7
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/portability/platform.h>
+
+namespace transport {
+namespace portability {
+namespace cache {
+
+/**
+ * @Prefetch utilities
+ */
+
+/* Default cache line size of 64 bytes. */
+#ifndef LOG2_CACHE_LINE_BYTES
+static constexpr const std::size_t klog2_cache_line_bytes = 6;
+#else
+static constexpr const std::size_t klog2_cache_line_bytes =
+    LOG2_CACHE_LINE_BYTES;
+#endif
+
+/* How much data prefetch instruction prefetches */
+#ifndef LOG2_CACHE_PREFETCH_BYTES
+static constexpr const std::size_t klog2_cache_prefetch_bytes =
+    klog2_cache_line_bytes;
+#else
+static constexpr const std::size_t klog2_cache_prefetch_bytes =
+    LOG2_CACHE_PREFETCH_BYTES;
+#endif
+
+/* Default cache line fill buffers. */
+#ifndef N_PREFETCHES
+static constexpr const std::size_t kn_prefetches = 16;
+#else
+static constexpr const std::size_t kn_prefetches = N_PREFETCHES;
+#endif
+
+static constexpr const std::size_t kcache_line_bytes =
+    (1 << klog2_cache_line_bytes);
+static constexpr const std::size_t kcache_prefetch_bytes =
+    (1 << klog2_cache_prefetch_bytes);
+
+static constexpr const int READ = 0;
+static constexpr const int LOAD = 0; /* alias for read */
+static constexpr const int WRITE = 1;
+static constexpr const int STORE = 1; /* alias for write */
+
+#if defined(__GNUC__) || defined(__clang__)
+// Clang & GCC
+
+template <int type>
+static inline void _prefetch(uint8_t *addr, std::size_t n, std::size_t size) {
+  if (size > n * kcache_prefetch_bytes) {
+    __builtin_prefetch(addr + n * kcache_prefetch_bytes, type,
+                       /* locality */ 3);
+  }
+}
+
+template <typename T, int type>
+static inline void prefetch(T *addr, std::size_t size) {
+  uint8_t *_addr = reinterpret_cast<uint8_t *>(addr);
+
+  _prefetch<type>(_addr, 0, size);
+  _prefetch<type>(_addr, 1, size);
+  _prefetch<type>(_addr, 2, size);
+  _prefetch<type>(_addr, 3, size);
+}
+#endif
+
+}  // namespace cache
+}  // namespace portability
+}  // namespace transport
\ No newline at end of file
diff --git a/libtransport/includes/hicn/transport/portability/endianess.h b/libtransport/includes/hicn/transport/portability/endianess.h
new file mode 100644 (file)
index 0000000..c18ac82
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/errors/errors.h>
+
+namespace transport {
+namespace portability {
+
+#if (__BYTE_ORDER__) == (__ORDER_LITTLE_ENDIAN__)
+static constexpr const bool kIsBigEndian = false;
+static constexpr const bool kIsLittleEndian = true;
+#else
+static constexpr const bool kIsBigEndian = true;
+static constexpr const bool kIsLittleEndian = false;
+#endif
+
+template <typename T>
+inline T bswap(T value) {
+  throw errors::RuntimeException("Not implemented");
+}
+
+template <>
+inline int16_t bswap(int16_t value) {
+  return __builtin_bswap16(value);
+}
+
+template <>
+inline int32_t bswap(int32_t value) {
+  return __builtin_bswap32(value);
+}
+
+template <>
+inline int64_t bswap(int64_t value) {
+  return __builtin_bswap64(value);
+}
+
+template <>
+inline uint16_t bswap(uint16_t value) {
+  return __builtin_bswap16(value);
+}
+
+template <>
+inline uint32_t bswap(uint32_t value) {
+  return __builtin_bswap32(value);
+}
+
+template <>
+inline uint64_t bswap(uint64_t value) {
+  return __builtin_bswap64(value);
+}
+
+template <typename T>
+inline T host_to_net(T value) {
+  if constexpr (kIsLittleEndian) {
+    return bswap(value);
+  }
+
+  return value;
+}
+
+template <typename T>
+inline T net_to_host(T value) {
+  if constexpr (kIsLittleEndian) {
+    return bswap(value);
+  }
+
+  return value;
+}
+
+}  // namespace portability
+}  // namespace transport
\ No newline at end of file
index b093f88..fd6eca4 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <cstddef>
 
+namespace transport {
 namespace portability {
 
 // Generalize warning push/pop.
@@ -66,3 +67,4 @@ namespace portability {
 #endif
 
 }  // namespace portability
+}  // namespace transport
\ No newline at end of file
index ddfbd00..14234ea 100644 (file)
@@ -79,7 +79,7 @@ class Time {
  public:
   using Clock = T;
   using TimePoint = typename Clock::time_point;
-  using Rep = double;
+  using Rep = uint64_t;
   using Seconds = std::chrono::duration<Rep>;
   using Milliseconds = std::chrono::duration<Rep, std::milli>;
   using Microseconds = std::chrono::duration<Rep, std::micro>;
diff --git a/libtransport/includes/hicn/transport/utils/color.h b/libtransport/includes/hicn/transport/utils/color.h
new file mode 100644 (file)
index 0000000..3e8d93e
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <array>
+#include <ostream>
+#include <random>
+#include <sstream>
+
+namespace utils {
+
+#define foreach_modifier  \
+  _(RESET, 0)             \
+  _(BOLD, 1)              \
+  _(FG_DEFAULT, 39)       \
+  _(FG_BLACK, 30)         \
+  _(FG_RED, 31)           \
+  _(FG_GREEN, 32)         \
+  _(FG_YELLOW, 33)        \
+  _(FG_BLUE, 34)          \
+  _(FG_MAGENTA, 35)       \
+  _(FG_CYAN, 36)          \
+  _(FG_LIGHT_GRAY, 37)    \
+  _(FG_DARK_GRAY, 90)     \
+  _(FG_LIGHT_RED, 91)     \
+  _(FG_LIGHT_GREEN, 92)   \
+  _(FG_LIGHT_YELLOW, 93)  \
+  _(FG_LIGHT_BLUE, 94)    \
+  _(FG_LIGHT_MAGENTA, 95) \
+  _(FG_LIGHT_CYAN, 96)    \
+  _(FG_WHITE, 97)         \
+  _(BG_RED, 41)           \
+  _(BG_GREEN, 42)         \
+  _(BG_BLUE, 44)          \
+  _(BG_DEFAULT, 49)
+
+class ColorModifier {
+  static inline const std::size_t n_modifiers = 23;
+  static inline const char format_string_start[] = "\033[";
+  static inline const char format_string_end[] = "m";
+
+ public:
+  enum class Code {
+#define _(name, value) name = value,
+    foreach_modifier
+#undef _
+  };
+
+  static inline std::array<Code, n_modifiers> code_array = {
+#define _(name, value) Code::name,
+      foreach_modifier
+#undef _
+  };
+
+  static Code getRandomModifier() {
+    static std::random_device rd;
+    static std::mt19937 gen(rd());
+    static std::uniform_int_distribution<> distr(4, 17);
+
+    return code_array[distr(gen)];
+  }
+
+  ColorModifier(Code code) : code_(code), color_string_() {
+    std::stringstream ss;
+    if (std::getenv("COLORTERM") != nullptr) {
+      ss << format_string_start << static_cast<int>(code_) << format_string_end;
+      color_string_ = ss.str();
+    }
+  }
+
+  ColorModifier() : ColorModifier(getRandomModifier()) {}
+
+  friend std::ostream& operator<<(std::ostream& os, const ColorModifier& mod) {
+    return os << mod.color_string_;
+  }
+
+ private:
+  Code code_;
+  std::string color_string_;
+};
+
+}  // namespace utils
\ No newline at end of file
index 2cd2f3a..164c853 100644 (file)
@@ -29,16 +29,16 @@ class EventThread {
   EventThread(asio::io_service& io_service, bool detached = false)
       : internal_io_service_(nullptr),
         io_service_(std::ref(io_service)),
-        work_(std::make_unique<asio::io_service::work>(io_service_)),
+        work_guard_(asio::make_work_guard(io_service_.get())),
         thread_(nullptr),
         detached_(detached) {
     run();
   }
 
-  EventThread(bool detached = false)
+  explicit EventThread(bool detached = false)
       : internal_io_service_(std::make_unique<asio::io_service>()),
         io_service_(std::ref(*internal_io_service_)),
-        work_(std::make_unique<asio::io_service::work>(io_service_)),
+        work_guard_(asio::make_work_guard(io_service_.get())),
         thread_(nullptr),
         detached_(detached) {
     run();
@@ -47,22 +47,12 @@ class EventThread {
   EventThread(const EventThread&) = delete;
   EventThread& operator=(const EventThread&) = delete;
 
-  EventThread(EventThread&& other)
+  EventThread(EventThread&& other) noexcept
       : internal_io_service_(std::move(other.internal_io_service_)),
         io_service_(std::move(other.io_service_)),
-        work_(std::move(other.work_)),
+        work_guard_(std::move(other.work_guard_)),
         thread_(std::move(other.thread_)),
-        detached_(std::move(other.detached_)) {}
-
-  EventThread& operator=(EventThread&& other) {
-    internal_io_service_ = std::move(other.internal_io_service_);
-    io_service_ = std::move(other.io_service_);
-    work_ = std::move(other.work_);
-    thread_ = std::move(other.thread_);
-    detached_ = other.detached_;
-
-    return *this;
-  }
+        detached_(other.detached_) {}
 
   ~EventThread() { stop(); }
 
@@ -89,16 +79,16 @@ class EventThread {
 
   template <typename Func>
   void add(Func&& f) {
-    io_service_.get().post(std::forward<Func&&>(f));
+    io_service_.get().post(std::forward<Func>(f));
   }
 
   template <typename Func>
   void tryRunHandlerNow(Func&& f) {
-    io_service_.get().dispatch(std::forward<Func&&>(f));
+    io_service_.get().dispatch(std::forward<Func>(f));
   }
 
   template <typename Func>
-  void addAndWaitForExecution(Func&& f) {
+  void addAndWaitForExecution(Func&& f) const {
     auto promise = std::promise<void>();
     auto future = promise.get_future();
 
@@ -111,7 +101,7 @@ class EventThread {
   }
 
   void stop() {
-    work_.reset();
+    add([this]() { work_guard_.reset(); });
 
     if (thread_ && thread_->joinable()) {
       thread_->join();
@@ -120,14 +110,14 @@ class EventThread {
     thread_.reset();
   }
 
-  bool stopped() { return io_service_.get().stopped(); }
+  bool stopped() const { return io_service_.get().stopped(); }
 
   asio::io_service& getIoService() { return io_service_; }
 
  private:
   std::unique_ptr<asio::io_service> internal_io_service_;
   std::reference_wrapper<asio::io_service> io_service_;
-  std::unique_ptr<asio::io_service::work> work_;
+  asio::executor_work_guard<asio::io_context::executor_type> work_guard_;
   std::unique_ptr<std::thread> thread_;
   bool detached_;
 };
index 03d29c1..14ef179 100644 (file)
@@ -44,7 +44,7 @@ static TRANSPORT_ALWAYS_INLINE int retrieveInterfaceAddress(
       uint16_t prefix = 0;
       memcpy(&prefix, tmp->sin6_addr.s6_addr, sizeof(uint16_t));
 
-      if (htons(LINK_LOCAL_PREFIX) != prefix) {
+      if (portability::host_to_net(LINK_LOCAL_PREFIX) != prefix) {
         *address = *(struct sockaddr_in6 *)ifa->ifa_addr;
         getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), addr,
                     sizeof(addr), NULL, 0, NI_NUMERICHOST);
index e4e4720..76218ff 100644 (file)
@@ -29,8 +29,11 @@ class ThreadPool : public NonCopyable {
       std::size_t n_threads = std::thread::hardware_concurrency())
       : workers_(n_threads > 0 ? n_threads : 1) {}
 
+  ~ThreadPool() = default;
+
   std::size_t getNThreads() const { return workers_.size(); }
   EventThread &getWorker(std::size_t i) { return workers_.at(i); }
+  std::vector<EventThread> &getWorkers() { return workers_; }
 
  private:
   std::vector<EventThread> workers_;
index 918e271..f13df53 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <glog/logging.h>
 #include <hicn/transport/auth/signer.h>
+#include <hicn/transport/core/interest.h>
 #include <hicn/transport/utils/chrono_typedefs.h>
 
 #include "hicn/transport/core/global_object_pool.h"
@@ -50,6 +51,15 @@ void Signer::signPacket(PacketPtr packet) {
   hicn_header_t header_copy;
   hicn_packet_copy_header(format, packet->packet_start_, &header_copy, false);
 
+  // Copy bitmap from interest manifest
+  uint32_t request_bitmap[BITMAP_SIZE] = {0};
+  if (packet->isInterest()) {
+    core::Interest *interest = dynamic_cast<core::Interest *>(packet);
+    if (interest->hasManifest())
+      memcpy(request_bitmap, interest->getRequestBitmap(),
+             BITMAP_SIZE * sizeof(uint32_t));
+  }
+
   // Fill in the hICN AH header
   auto now = utils::SteadyTime::nowMs().count();
   packet->setSignatureTimestamp(now);
@@ -69,6 +79,12 @@ void Signer::signPacket(PacketPtr packet) {
 
   // Restore header
   hicn_packet_copy_header(format, &header_copy, packet->packet_start_, false);
+
+  // Restore bitmap in interest manifest
+  if (packet->isInterest()) {
+    core::Interest *interest = dynamic_cast<core::Interest *>(packet);
+    interest->setRequestBitmap(request_bitmap);
+  }
 }
 
 void Signer::signBuffer(const std::vector<uint8_t> &buffer) {
@@ -241,16 +257,23 @@ void AsymmetricSigner::setKey(CryptoSuite suite, std::shared_ptr<EVP_PKEY> key,
                               std::shared_ptr<EVP_PKEY> pub_key) {
   suite_ = suite;
   key_ = key;
-  signature_len_ = EVP_PKEY_size(key.get());
+
+  signature_len_ = EVP_PKEY_size(key_.get());
   DCHECK(signature_len_ <= signature_->tailroom());
+
   signature_->setLength(signature_len_);
 
-  std::vector<uint8_t> pbk(i2d_PublicKey(pub_key.get(), nullptr));
-  uint8_t *pbk_ptr = pbk.data();
-  int len = i2d_PublicKey(pub_key.get(), &pbk_ptr);
+  size_t enc_pbk_len = i2d_PublicKey(pub_key.get(), nullptr);
+  DCHECK(enc_pbk_len >= 0);
+
+  uint8_t *enc_pbkey_raw = nullptr;
+  i2d_PublicKey(pub_key.get(), &enc_pbkey_raw);
+  DCHECK(enc_pbkey_raw != nullptr);
 
   key_id_ = CryptoHash(getHashType());
-  key_id_.computeDigest(pbk_ptr, len);
+  key_id_.computeDigest(enc_pbkey_raw, enc_pbk_len);
+
+  OPENSSL_free(enc_pbkey_raw);
 }
 
 size_t AsymmetricSigner::getSignatureFieldSize() const {
index 5d5f017..e257582 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <hicn/transport/auth/verifier.h>
 #include <hicn/transport/core/global_object_pool.h>
+#include <hicn/transport/core/interest.h>
 #include <protocols/errors.h>
 
 #include "glog/logging.h"
@@ -51,6 +52,14 @@ bool Verifier::verifyPacket(PacketPtr packet) {
   hicn_header_t header_copy;
   hicn_packet_copy_header(format, packet->packet_start_, &header_copy, false);
 
+  // Copy bitmap from interest manifest
+  uint32_t request_bitmap[BITMAP_SIZE] = {0};
+  if (packet->isInterest()) {
+    core::Interest *interest = dynamic_cast<core::Interest *>(packet);
+    memcpy(request_bitmap, interest->getRequestBitmap(),
+           BITMAP_SIZE * sizeof(uint32_t));
+  }
+
   // Retrieve packet signature
   utils::MemBuf::Ptr signature_raw = packet->getSignature();
   std::size_t signature_len = packet->getSignatureSize();
@@ -69,6 +78,12 @@ bool Verifier::verifyPacket(PacketPtr packet) {
   packet->setSignature(signature_raw);
   packet->setSignatureSize(signature_raw->length());
 
+  // Restore bitmap in interest manifest
+  if (packet->isInterest()) {
+    core::Interest *interest = dynamic_cast<core::Interest *>(packet);
+    interest->setRequestBitmap(request_bitmap);
+  }
+
   return valid_packet;
 }
 
index b9b024d..777772a 100644 (file)
 list(APPEND HEADER_FILES
   ${CMAKE_CURRENT_SOURCE_DIR}/facade.h
   ${CMAKE_CURRENT_SOURCE_DIR}/manifest.h
-  ${CMAKE_CURRENT_SOURCE_DIR}/manifest_inline.h
   ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format_fixed.h
   ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format.h
   ${CMAKE_CURRENT_SOURCE_DIR}/pending_interest.h
   ${CMAKE_CURRENT_SOURCE_DIR}/portal.h
   ${CMAKE_CURRENT_SOURCE_DIR}/errors.h
   ${CMAKE_CURRENT_SOURCE_DIR}/global_configuration.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/global_id_counter.h
   ${CMAKE_CURRENT_SOURCE_DIR}/local_connector.h
   ${CMAKE_CURRENT_SOURCE_DIR}/global_workers.h
   ${CMAKE_CURRENT_SOURCE_DIR}/udp_connector.h
   ${CMAKE_CURRENT_SOURCE_DIR}/udp_listener.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/global_module_manager.h
 )
 
 list(APPEND SOURCE_FILES
@@ -38,9 +39,9 @@ list(APPEND SOURCE_FILES
   ${CMAKE_CURRENT_SOURCE_DIR}/portal.cc
   ${CMAKE_CURRENT_SOURCE_DIR}/global_configuration.cc
   ${CMAKE_CURRENT_SOURCE_DIR}/io_module.cc
-  ${CMAKE_CURRENT_SOURCE_DIR}/local_connector.cc
   ${CMAKE_CURRENT_SOURCE_DIR}/udp_connector.cc
   ${CMAKE_CURRENT_SOURCE_DIR}/udp_listener.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/constructor.cc
 )
 
 if (NOT ${CMAKE_SYSTEM_NAME} MATCHES Android)
@@ -56,4 +57,4 @@ if (NOT ${CMAKE_SYSTEM_NAME} MATCHES Android)
 endif()
 
 set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
-set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
diff --git a/libtransport/src/core/constructor.cc b/libtransport/src/core/constructor.cc
new file mode 100644 (file)
index 0000000..0c7f0df
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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 <core/global_configuration.h>
+#include <core/global_module_manager.h>
+#include <core/global_workers.h>
+#include <hicn/transport/core/global_object_pool.h>
+
+namespace transport {
+namespace core {
+
+void __attribute__((constructor)) libtransportInit() {
+  // First the global module manager is initialized
+  GlobalModuleManager::getInstance();
+  // Then the packet allocator is initialized
+  PacketManager<>::getInstance();
+  // Then the global configuration is initialized
+  GlobalConfiguration::getInstance();
+  // Then the global workers are initialized
+  GlobalWorkers::getInstance();
+}
+
+}  // namespace core
+}  // namespace transport
\ No newline at end of file
index 643e038..e66b2a6 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <hicn/transport/core/content_object.h>
 #include <hicn/transport/errors/errors.h>
+#include <hicn/transport/portability/endianess.h>
 #include <hicn/transport/utils/branch_prediction.h>
 
 extern "C" {
@@ -46,7 +47,7 @@ ContentObject::ContentObject(const Name &name, Packet::Format format,
   }
 
   if (TRANSPORT_EXPECT_FALSE(hicn_data_get_name(format_, packet_start_,
-                                                name_.getStructReference()) <
+                                                &name_.getStructReference()) <
                              0)) {
     throw errors::MalformedPacketException();
   }
@@ -91,7 +92,7 @@ ContentObject::~ContentObject() {}
 const Name &ContentObject::getName() const {
   if (!name_) {
     if (hicn_data_get_name(format_, packet_start_,
-                           (hicn_name_t *)name_.getConstStructReference()) <
+                           (hicn_name_t *)&name_.getConstStructReference()) <
         0) {
       throw errors::MalformedPacketException();
     }
@@ -104,11 +105,11 @@ Name &ContentObject::getWritableName() { return const_cast<Name &>(getName()); }
 
 void ContentObject::setName(const Name &name) {
   if (hicn_data_set_name(format_, packet_start_,
-                         name.getConstStructReference()) < 0) {
+                         &name.getConstStructReference()) < 0) {
     throw errors::RuntimeException("Error setting content object name.");
   }
 
-  if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) <
+  if (hicn_data_get_name(format_, packet_start_, &name_.getStructReference()) <
       0) {
     throw errors::MalformedPacketException();
   }
@@ -121,11 +122,11 @@ uint32_t ContentObject::getPathLabel() const {
         "Error retrieving the path label from content object");
   }
 
-  return ntohl(path_label);
+  return portability::net_to_host(path_label);
 }
 
 ContentObject &ContentObject::setPathLabel(uint32_t path_label) {
-  path_label = htonl(path_label);
+  path_label = portability::host_to_net(path_label);
   if (hicn_data_set_path_label((hicn_header_t *)packet_start_, path_label) <
       0) {
     throw errors::RuntimeException(
index 1ad4437..77c1d16 100644 (file)
 
 #pragma once
 
+#include <core/manifest.h>
 #include <core/manifest_format_fixed.h>
-#include <core/manifest_inline.h>
 #include <core/portal.h>
 
 namespace transport {
 
 namespace core {
 
-using ContentObjectManifest = core::ManifestInline<ContentObject, Fixed>;
-using InterestManifest = core::ManifestInline<Interest, Fixed>;
+using ContentObjectManifest = core::Manifest<Fixed>;
+using InterestManifest = core::Manifest<Fixed>;
 
 }  // namespace core
 
diff --git a/libtransport/src/core/global_module_manager.h b/libtransport/src/core/global_module_manager.h
new file mode 100644 (file)
index 0000000..c9d272c
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <glog/logging.h>
+#include <hicn/transport/utils/singleton.h>
+
+#ifndef _WIN32
+#include <dlfcn.h>
+#endif
+
+#include <atomic>
+#include <iostream>
+#include <mutex>
+#include <unordered_map>
+
+namespace transport {
+namespace core {
+
+class GlobalModuleManager : public utils::Singleton<GlobalModuleManager> {
+ public:
+  friend class utils::Singleton<GlobalModuleManager>;
+
+  ~GlobalModuleManager() {
+    for (const auto &[key, value] : modules_) {
+      unload(value);
+    }
+  }
+
+  void *loadModule(const std::string &module_name) {
+    void *handle = nullptr;
+    const char *error = nullptr;
+
+    // Lock
+    std::unique_lock lck(mtx_);
+
+    auto it = modules_.find(module_name);
+    if (it != modules_.end()) {
+      return it->second;
+    }
+
+    // open module
+    handle = dlopen(module_name.c_str(), RTLD_NOW);
+    if (!handle) {
+      if ((error = dlerror()) != nullptr) {
+        LOG(ERROR) << error;
+      }
+      return nullptr;
+    }
+
+    auto ret = modules_.try_emplace(module_name, handle);
+    DCHECK(ret.second);
+
+    return handle;
+  }
+
+  void unload(void *handle) {
+    // destroy object and close module
+    dlclose(handle);
+  }
+
+  bool unloadModule(const std::string &module_name) {
+    // Lock
+    std::unique_lock lck(mtx_);
+    auto it = modules_.find(module_name);
+    if (it != modules_.end()) {
+      unload(it->second);
+      return true;
+    }
+
+    return false;
+  }
+
+ private:
+  GlobalModuleManager() = default;
+  std::mutex mtx_;
+  std::unordered_map<std::string, void *> modules_;
+};
+
+}  // namespace core
+}  // namespace transport
\ No newline at end of file
index 1ac2541..c5d794e 100644 (file)
@@ -32,6 +32,8 @@ class GlobalWorkers : public utils::Singleton<GlobalWorkers> {
     return thread_pool_.getWorker(counter_++ % thread_pool_.getNThreads());
   }
 
+  auto& getWorkers() { return thread_pool_.getWorkers(); }
+
  private:
   GlobalWorkers() : counter_(0), thread_pool_() {}
 
index b7719b3..8b9dcf2 100644 (file)
@@ -21,6 +21,7 @@ extern "C" {
 #ifndef _WIN32
 TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
 #endif
+#include <hicn/base.h>
 #include <hicn/hicn.h>
 }
 
@@ -39,12 +40,12 @@ Interest::Interest(const Name &interest_name, Packet::Format format,
   }
 
   if (hicn_interest_set_name(format_, packet_start_,
-                             interest_name.getConstStructReference()) < 0) {
+                             &interest_name.getConstStructReference()) < 0) {
     throw errors::MalformedPacketException();
   }
 
   if (hicn_interest_get_name(format_, packet_start_,
-                             name_.getStructReference()) < 0) {
+                             &name_.getStructReference()) < 0) {
     throw errors::MalformedPacketException();
   }
 }
@@ -64,7 +65,7 @@ Interest::Interest(hicn_format_t format, std::size_t additional_header_size)
 
 Interest::Interest(MemBuf &&buffer) : Packet(std::move(buffer)) {
   if (hicn_interest_get_name(format_, packet_start_,
-                             name_.getStructReference()) < 0) {
+                             &name_.getStructReference()) < 0) {
     throw errors::MalformedPacketException();
   }
 }
@@ -86,9 +87,9 @@ Interest::~Interest() {}
 
 const Name &Interest::getName() const {
   if (!name_) {
-    if (hicn_interest_get_name(format_, packet_start_,
-                               (hicn_name_t *)name_.getConstStructReference()) <
-        0) {
+    if (hicn_interest_get_name(
+            format_, packet_start_,
+            (hicn_name_t *)&name_.getConstStructReference()) < 0) {
       throw errors::MalformedPacketException();
     }
   }
@@ -100,12 +101,12 @@ Name &Interest::getWritableName() { return const_cast<Name &>(getName()); }
 
 void Interest::setName(const Name &name) {
   if (hicn_interest_set_name(format_, packet_start_,
-                             name.getConstStructReference()) < 0) {
+                             &name.getConstStructReference()) < 0) {
     throw errors::RuntimeException("Error setting interest name.");
   }
 
   if (hicn_interest_get_name(format_, packet_start_,
-                             name_.getStructReference()) < 0) {
+                             &name_.getStructReference()) < 0) {
     throw errors::MalformedPacketException();
   }
 }
@@ -150,6 +151,13 @@ void Interest::resetForHash() {
     throw errors::RuntimeException(
         "Error resetting interest fields for hash computation.");
   }
+
+  // Reset request bitmap in manifest
+  if (hasManifest()) {
+    auto int_manifest_header =
+        (interest_manifest_header_t *)(writableData() + headerSize());
+    memset(int_manifest_header->request_bitmap, 0, BITMAP_SIZE * sizeof(u32));
+  }
 }
 
 bool Interest::hasManifest() {
@@ -171,19 +179,21 @@ void Interest::encodeSuffixes() {
 
   // We assume interest does not hold signature for the moment.
   auto int_manifest_header =
-      (InterestManifestHeader *)(writableData() + headerSize());
-  int_manifest_header->n_suffixes = suffix_set_.size();
-  std::size_t additional_length =
-      sizeof(InterestManifestHeader) +
-      int_manifest_header->n_suffixes * sizeof(uint32_t);
+      (interest_manifest_header_t *)(writableData() + headerSize());
+  int_manifest_header->n_suffixes = (uint32_t)suffix_set_.size();
+  memset(int_manifest_header->request_bitmap, 0xFFFFFFFF,
+         BITMAP_SIZE * sizeof(u32));
 
   uint32_t *suffix = (uint32_t *)(int_manifest_header + 1);
   for (auto it = suffix_set_.begin(); it != suffix_set_.end(); it++, suffix++) {
     *suffix = *it;
   }
 
+  std::size_t additional_length =
+      sizeof(interest_manifest_header_t) +
+      int_manifest_header->n_suffixes * sizeof(uint32_t);
   append(additional_length);
-  updateLength(additional_length);
+  updateLength();
 }
 
 uint32_t *Interest::firstSuffix() {
@@ -191,7 +201,7 @@ uint32_t *Interest::firstSuffix() {
     return nullptr;
   }
 
-  auto ret = (InterestManifestHeader *)(writableData() + headerSize());
+  auto ret = (interest_manifest_header_t *)(writableData() + headerSize());
   ret += 1;
 
   return (uint32_t *)ret;
@@ -202,11 +212,48 @@ uint32_t Interest::numberOfSuffixes() {
     return 0;
   }
 
-  auto header = (InterestManifestHeader *)(writableData() + headerSize());
+  auto header = (interest_manifest_header_t *)(writableData() + headerSize());
 
   return header->n_suffixes;
 }
 
+uint32_t *Interest::getRequestBitmap() {
+  if (!hasManifest()) return nullptr;
+
+  auto header = (interest_manifest_header_t *)(writableData() + headerSize());
+  return header->request_bitmap;
+}
+
+void Interest::setRequestBitmap(const uint32_t *request_bitmap) {
+  if (!hasManifest()) return;
+
+  auto header = (interest_manifest_header_t *)(writableData() + headerSize());
+  memcpy(header->request_bitmap, request_bitmap,
+         BITMAP_SIZE * sizeof(uint32_t));
+}
+
+bool Interest::isValid() {
+  if (!hasManifest()) return true;
+
+  auto header = (interest_manifest_header_t *)(writableData() + headerSize());
+
+  if (header->n_suffixes == 0 ||
+      header->n_suffixes > MAX_SUFFIXES_IN_MANIFEST) {
+    std::cerr << "Manifest with invalid number of suffixes "
+              << header->n_suffixes;
+    return false;
+  }
+
+  uint32_t empty_bitmap[BITMAP_SIZE];
+  memset(empty_bitmap, 0, sizeof(empty_bitmap));
+  if (memcmp(empty_bitmap, header->request_bitmap, sizeof(empty_bitmap)) == 0) {
+    std::cerr << "Manifest with empty bitmap";
+    return false;
+  }
+
+  return true;
+}
+
 }  // end namespace core
 
 }  // end namespace transport
index 69e4e8b..0f92cc4 100644 (file)
@@ -16,6 +16,7 @@
 #ifndef _WIN32
 #include <dlfcn.h>
 #endif
+#include <core/global_module_manager.h>
 #include <glog/logging.h>
 #include <hicn/transport/core/io_module.h>
 
@@ -38,54 +39,28 @@ IoModule *IoModule::load(const char *module_name) {
 #ifdef ANDROID
   return new HicnForwarderModule();
 #else
-  void *handle = 0;
-  IoModule *module = 0;
-  IoModule *(*creator)(void) = 0;
-  const char *error = 0;
+  IoModule *iomodule = nullptr;
+  IoModule *(*creator)(void) = nullptr;
+  const char *error = nullptr;
 
-  // open module
-  handle = dlopen(module_name, RTLD_NOW);
-  if (!handle) {
-    if ((error = dlerror()) != 0) {
-      LOG(ERROR) << error;
-    }
-    return 0;
-  }
+  auto handle = GlobalModuleManager::getInstance().loadModule(module_name);
 
   // get factory method
   creator = (IoModule * (*)(void)) dlsym(handle, "create_module");
   if (!creator) {
-    if ((error = dlerror()) != 0) {
+    if ((error = dlerror()) != nullptr) {
       LOG(ERROR) << error;
     }
 
-    return 0;
+    return nullptr;
   }
 
   // create object and return it
-  module = (*creator)();
-  module->handle_ = handle;
+  iomodule = (*creator)();
 
-  return module;
+  return iomodule;
 #endif
 }
 
-bool IoModule::unload(IoModule *module) {
-  if (!module) {
-    return false;
-  }
-
-#ifdef ANDROID
-  delete module;
-#else
-  // destroy object and close module
-  void *handle = module->handle_;
-  delete module;
-  dlclose(handle);
-#endif
-
-  return true;
-}
-
 }  // namespace core
 }  // namespace transport
diff --git a/libtransport/src/core/local_connector.cc b/libtransport/src/core/local_connector.cc
deleted file mode 100644 (file)
index f27be2e..0000000
+++ /dev/null
@@ -1,50 +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.
- */
-
-#include <core/local_connector.h>
-#include <glog/logging.h>
-#include <hicn/transport/core/asio_wrapper.h>
-#include <hicn/transport/core/content_object.h>
-#include <hicn/transport/core/interest.h>
-#include <hicn/transport/errors/not_implemented_exception.h>
-
-namespace transport {
-namespace core {
-
-LocalConnector::~LocalConnector() {}
-
-void LocalConnector::close() { state_ = State::CLOSED; }
-
-void LocalConnector::send(Packet &packet) {
-  if (!isConnected()) {
-    return;
-  }
-
-  auto buffer =
-      std::static_pointer_cast<utils::MemBuf>(packet.shared_from_this());
-
-  DLOG_IF(INFO, VLOG_IS_ON(3)) << "Sending packet to local socket.";
-  io_service_.get().post([this, buffer]() mutable {
-    std::vector<utils::MemBuf::Ptr> v{std::move(buffer)};
-    receive_callback_(this, v, std::make_error_code(std::errc(0)));
-  });
-}
-
-void LocalConnector::send(const utils::MemBuf::Ptr &buffer) {
-  throw errors::NotImplementedException();
-}
-
-}  // namespace core
-}  // namespace transport
\ No newline at end of file
index eede89e..963f455 100644 (file)
 
 #pragma once
 
+#include <core/errors.h>
 #include <hicn/transport/core/asio_wrapper.h>
 #include <hicn/transport/core/connector.h>
 #include <hicn/transport/core/global_object_pool.h>
+#include <hicn/transport/errors/not_implemented_exception.h>
 #include <hicn/transport/utils/move_wrapper.h>
 #include <hicn/transport/utils/shared_ptr_utils.h>
 #include <io_modules/forwarder/errors.h>
@@ -34,19 +36,48 @@ class LocalConnector : public Connector {
                  OnClose &&close_callback, OnReconnect &&on_reconnect)
       : Connector(receive_callback, packet_sent, close_callback, on_reconnect),
         io_service_(io_service),
-        io_service_work_(io_service_.get()) {
-    state_ = State::CONNECTED;
-  }
+        io_service_work_(io_service_.get()) {}
 
-  ~LocalConnector() override;
+  ~LocalConnector() override = default;
 
-  void send(Packet &packet) override;
+  auto shared_from_this() { return utils::shared_from(this); }
 
-  void send(const utils::MemBuf::Ptr &buffer) override;
+  void send(Packet &packet) override { send(packet.shared_from_this()); }
 
-  void close() override;
+  void send(const utils::MemBuf::Ptr &buffer) override {
+    throw errors::NotImplementedException();
+  }
 
-  auto shared_from_this() { return utils::shared_from(this); }
+  void receive(const std::vector<utils::MemBuf::Ptr> &buffers) override {
+    DLOG_IF(INFO, VLOG_IS_ON(3)) << "Sending packet to local socket.";
+    std::weak_ptr<LocalConnector> self = shared_from_this();
+    io_service_.get().post([self, _buffers{std::move(buffers)}]() mutable {
+      if (auto ptr = self.lock()) {
+        ptr->receive_callback_(ptr.get(), _buffers,
+                               make_error_code(core_error::success));
+      }
+    });
+  }
+
+  void reconnect() override {
+    state_ = State::CONNECTED;
+    std::weak_ptr<LocalConnector> self = shared_from_this();
+    io_service_.get().post([self]() {
+      if (auto ptr = self.lock()) {
+        ptr->on_reconnect_callback_(ptr.get(),
+                                    make_error_code(core_error::success));
+      }
+    });
+  }
+
+  void close() override {
+    std::weak_ptr<LocalConnector> self = shared_from_this();
+    io_service_.get().post([self]() mutable {
+      if (auto ptr = self.lock()) {
+        ptr->on_close_callback_(ptr.get());
+      }
+    });
+  }
 
  private:
   std::reference_wrapper<asio::io_service> io_service_;
diff --git a/libtransport/src/core/manifest.cc b/libtransport/src/core/manifest.cc
deleted file mode 100644 (file)
index da26894..0000000
+++ /dev/null
@@ -1,33 +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.
- */
-
-#include <hicn/transport/core/manifest.h>
-
-namespace transport {
-
-namespace core {
-
-std::string ManifestEncoding::manifest_type = std::string("manifest_type");
-
-std::map<ManifestType, std::string> ManifestEncoding::manifest_types = {
-    {FINAL_CHUNK_NUMBER, "FinalChunkNumber"}, {NAME_LIST, "NameList"}};
-
-std::string ManifestEncoding::final_chunk_number =
-    std::string("final_chunk_number");
-std::string ManifestEncoding::content_name = std::string("content_name");
-
-}  // end namespace core
-
-}  // end namespace transport
\ No newline at end of file
index 5bdbfc6..40832bb 100644 (file)
 
 #include <core/manifest_format.h>
 #include <glog/logging.h>
-#include <hicn/transport/core/content_object.h>
-#include <hicn/transport/core/name.h>
-
-#include <set>
+#include <hicn/transport/auth/verifier.h>
+#include <hicn/transport/core/global_object_pool.h>
+#include <hicn/transport/core/packet.h>
 
 namespace transport {
-
 namespace core {
 
-using typename core::Name;
-using typename core::Packet;
-using typename core::PayloadType;
-
-template <typename Base, typename FormatTraits, typename ManifestImpl>
-class Manifest : public Base {
-  static_assert(std::is_base_of<Packet, Base>::value,
-                "Base must inherit from packet!");
-
+template <typename FormatTraits>
+class Manifest : public FormatTraits::Encoder, public FormatTraits::Decoder {
  public:
-  // core::ContentObjectManifest::Ptr
+  using Ptr = std::shared_ptr<Manifest>;
 
   using Encoder = typename FormatTraits::Encoder;
   using Decoder = typename FormatTraits::Decoder;
 
-  Manifest(Packet::Format format, std::size_t signature_size = 0)
-      : Base(format, signature_size),
-        encoder_(*this, signature_size),
-        decoder_(*this) {
-    DCHECK(_is_ah(format));
-    Base::setPayloadType(PayloadType::MANIFEST);
-  }
+  using Hash = typename FormatTraits::Hash;
+  using HashType = typename FormatTraits::HashType;
+  using Suffix = typename FormatTraits::Suffix;
+  using SuffixList = typename FormatTraits::SuffixList;
+  using HashEntry = std::pair<auth::CryptoHashType, std::vector<uint8_t>>;
 
-  Manifest(Packet::Format format, const core::Name &name,
-           std::size_t signature_size = 0)
-      : Base(name, format, signature_size),
-        encoder_(*this, signature_size),
-        decoder_(*this) {
-    DCHECK(_is_ah(format));
-    Base::setPayloadType(PayloadType::MANIFEST);
+  Manifest(Packet::Ptr packet, bool clear = false)
+      : Encoder(packet, clear), Decoder(packet), packet_(packet) {
+    packet->setPayloadType(PayloadType::MANIFEST);
   }
 
-  template <typename T>
-  Manifest(T &&base)
-      : Base(std::forward<T &&>(base)),
-        encoder_(*this, 0, false),
-        decoder_(*this) {
-    Base::setPayloadType(PayloadType::MANIFEST);
-  }
-
-  // Useful for decoding manifests while avoiding packet copy
-  template <typename T>
-  Manifest(T &base)
-      : Base(base.getFormat()), encoder_(base, 0, false), decoder_(base) {}
-
   virtual ~Manifest() = default;
 
-  std::size_t estimateManifestSize(std::size_t additional_entries = 0) {
-    return static_cast<ManifestImpl &>(*this).estimateManifestSizeImpl(
-        additional_entries);
-  }
-
-  /*
-   * After the call to encode, users MUST call clear before adding data
-   * to the manifest.
-   */
-  Manifest &encode() { return static_cast<ManifestImpl &>(*this).encodeImpl(); }
-
-  Manifest &decode() {
-    Manifest::decoder_.decode();
-
-    manifest_type_ = decoder_.getType();
-    manifest_transport_type_ = decoder_.getTransportType();
-    hash_algorithm_ = decoder_.getHashAlgorithm();
-    is_last_ = decoder_.getIsLast();
+  Packet::Ptr getPacket() const { return packet_; }
 
-    return static_cast<ManifestImpl &>(*this).decodeImpl();
+  void setHeaders(ManifestType type, uint8_t max_capacity, HashType hash_algo,
+                  bool is_last, const Name &base_name) {
+    Encoder::setType(type);
+    Encoder::setMaxCapacity(max_capacity);
+    Encoder::setHashAlgorithm(hash_algo);
+    Encoder::setIsLast(is_last);
+    Encoder::setBaseName(base_name);
   }
 
-  static std::size_t manifestHeaderSize(
-      interface::ProductionProtocolAlgorithms transport_type =
-          interface::ProductionProtocolAlgorithms::UNKNOWN) {
-    return Encoder::manifestHeaderSize(transport_type);
-  }
+  auth::Verifier::SuffixMap getSuffixMap() const {
+    auth::Verifier::SuffixMap suffix_map;
 
-  static std::size_t manifestEntrySize() {
-    return Encoder::manifestEntrySize();
-  }
+    HashType hash_algo = Decoder::getHashAlgorithm();
+    SuffixList suffix_list = Decoder::getEntries();
 
-  Manifest &setType(ManifestType type) {
-    manifest_type_ = type;
-    encoder_.setType(manifest_type_);
-    return *this;
-  }
+    for (auto it = suffix_list.begin(); it != suffix_list.end(); ++it) {
+      Hash hash(it->second, Hash::getSize(hash_algo), hash_algo);
+      suffix_map[it->first] = hash;
+    }
 
-  Manifest &setHashAlgorithm(auth::CryptoHashType hash_algorithm) {
-    hash_algorithm_ = hash_algorithm;
-    encoder_.setHashAlgorithm(hash_algorithm_);
-    return *this;
+    return suffix_map;
   }
 
-  auth::CryptoHashType getHashAlgorithm() const { return hash_algorithm_; }
-
-  ManifestType getType() const { return manifest_type_; }
-
-  interface::ProductionProtocolAlgorithms getTransportType() const {
-    return manifest_transport_type_;
-  }
-
-  bool getIsLast() const { return is_last_; }
-
-  Manifest &setVersion(ManifestVersion version) {
-    encoder_.setVersion(version);
-    return *this;
-  }
-
-  Manifest &setParamsBytestream(const ParamsBytestream &params) {
-    manifest_transport_type_ =
-        interface::ProductionProtocolAlgorithms::BYTE_STREAM;
-    encoder_.setParamsBytestream(params);
-    return *this;
-  }
-
-  Manifest &setParamsRTC(const ParamsRTC &params) {
-    manifest_transport_type_ =
-        interface::ProductionProtocolAlgorithms::RTC_PROD;
-    encoder_.setParamsRTC(params);
-    return *this;
-  }
-
-  ParamsBytestream getParamsBytestream() const {
-    return decoder_.getParamsBytestream();
-  }
-
-  ParamsRTC getParamsRTC() const { return decoder_.getParamsRTC(); }
-
-  ManifestVersion getVersion() const { return decoder_.getVersion(); }
-
-  Manifest &setIsLast(bool is_last) {
-    encoder_.setIsLast(is_last);
-    is_last_ = is_last;
-    return *this;
-  }
-
-  Manifest &clear() {
-    encoder_.clear();
-    decoder_.clear();
-    return *this;
-  }
+  static Manifest::Ptr createContentManifest(Packet::Format format,
+                                             const core::Name &manifest_name,
+                                             std::size_t signature_size) {
+    ContentObject::Ptr content_object =
+        core::PacketManager<>::getInstance().getPacket<ContentObject>(
+            format, signature_size);
+    content_object->setName(manifest_name);
+    return std::make_shared<Manifest>(content_object, true);
+  };
 
  protected:
-  ManifestType manifest_type_;
-  interface::ProductionProtocolAlgorithms manifest_transport_type_;
-  auth::CryptoHashType hash_algorithm_;
-  bool is_last_;
-
-  Encoder encoder_;
-  Decoder decoder_;
+  Packet::Ptr packet_;
 };
 
 }  // end namespace core
-
 }  // end namespace transport
index caee210..8941231 100644 (file)
 #include <unordered_map>
 
 namespace transport {
-
 namespace core {
 
-enum class ManifestVersion : uint8_t {
-  VERSION_1 = 1,
-};
-
 enum class ManifestType : uint8_t {
   INLINE_MANIFEST = 1,
   FINAL_CHUNK_NUMBER = 2,
@@ -83,14 +78,27 @@ class ManifestEncoder {
     return static_cast<Implementation &>(*this).clearImpl();
   }
 
+  bool isEncoded() const {
+    return static_cast<const Implementation &>(*this).isEncodedImpl();
+  }
+
   ManifestEncoder &setType(ManifestType type) {
     return static_cast<Implementation &>(*this).setTypeImpl(type);
   }
 
+  ManifestEncoder &setMaxCapacity(uint8_t max_capacity) {
+    return static_cast<Implementation &>(*this).setMaxCapacityImpl(
+        max_capacity);
+  }
+
   ManifestEncoder &setHashAlgorithm(auth::CryptoHashType hash) {
     return static_cast<Implementation &>(*this).setHashAlgorithmImpl(hash);
   }
 
+  ManifestEncoder &setIsLast(bool is_last) {
+    return static_cast<Implementation &>(*this).setIsLastImpl(is_last);
+  }
+
   template <
       typename T,
       typename = std::enable_if_t<std::is_same<
@@ -99,45 +107,36 @@ class ManifestEncoder {
     return static_cast<Implementation &>(*this).setBaseNameImpl(name);
   }
 
-  template <typename Hash>
-  ManifestEncoder &addSuffixAndHash(uint32_t suffix, Hash &&hash) {
-    return static_cast<Implementation &>(*this).addSuffixAndHashImpl(
-        suffix, std::forward<Hash &&>(hash));
+  ManifestEncoder &setParamsBytestream(const ParamsBytestream &params) {
+    return static_cast<Implementation &>(*this).setParamsBytestreamImpl(params);
   }
 
-  ManifestEncoder &setIsLast(bool is_last) {
-    return static_cast<Implementation &>(*this).setIsLastImpl(is_last);
+  ManifestEncoder &setParamsRTC(const ParamsRTC &params) {
+    return static_cast<Implementation &>(*this).setParamsRTCImpl(params);
   }
 
-  ManifestEncoder &setVersion(ManifestVersion version) {
-    return static_cast<Implementation &>(*this).setVersionImpl(version);
+  template <typename Hash>
+  ManifestEncoder &addEntry(uint32_t suffix, Hash &&hash) {
+    return static_cast<Implementation &>(*this).addEntryImpl(
+        suffix, std::forward<Hash>(hash));
   }
 
-  std::size_t estimateSerializedLength(std::size_t number_of_entries) {
-    return static_cast<Implementation &>(*this).estimateSerializedLengthImpl(
-        number_of_entries);
+  ManifestEncoder &removeEntry(uint32_t suffix) {
+    return static_cast<Implementation &>(*this).removeEntryImpl(suffix);
   }
 
-  ManifestEncoder &update() {
-    return static_cast<Implementation &>(*this).updateImpl();
+  std::size_t manifestHeaderSize() const {
+    return static_cast<const Implementation &>(*this).manifestHeaderSizeImpl();
   }
 
-  ManifestEncoder &setParamsBytestream(const ParamsBytestream &params) {
-    return static_cast<Implementation &>(*this).setParamsBytestreamImpl(params);
+  std::size_t manifestPayloadSize(size_t additional_entries = 0) const {
+    return static_cast<const Implementation &>(*this).manifestPayloadSizeImpl(
+        additional_entries);
   }
 
-  ManifestEncoder &setParamsRTC(const ParamsRTC &params) {
-    return static_cast<Implementation &>(*this).setParamsRTCImpl(params);
-  }
-
-  static std::size_t manifestHeaderSize(
-      interface::ProductionProtocolAlgorithms transport_type =
-          interface::ProductionProtocolAlgorithms::UNKNOWN) {
-    return Implementation::manifestHeaderSizeImpl(transport_type);
-  }
-
-  static std::size_t manifestEntrySize() {
-    return Implementation::manifestEntrySizeImpl();
+  std::size_t manifestSize(size_t additional_entries = 0) const {
+    return static_cast<const Implementation &>(*this).manifestSizeImpl(
+        additional_entries);
   }
 };
 
@@ -146,11 +145,17 @@ class ManifestDecoder {
  public:
   virtual ~ManifestDecoder() = default;
 
+  ManifestDecoder &decode() {
+    return static_cast<Implementation &>(*this).decodeImpl();
+  }
+
   ManifestDecoder &clear() {
     return static_cast<Implementation &>(*this).clearImpl();
   }
 
-  void decode() { static_cast<Implementation &>(*this).decodeImpl(); }
+  bool isDecoded() const {
+    return static_cast<const Implementation &>(*this).isDecodedImpl();
+  }
 
   ManifestType getType() const {
     return static_cast<const Implementation &>(*this).getTypeImpl();
@@ -160,40 +165,48 @@ class ManifestDecoder {
     return static_cast<const Implementation &>(*this).getTransportTypeImpl();
   }
 
+  uint8_t getMaxCapacity() const {
+    return static_cast<const Implementation &>(*this).getMaxCapacityImpl();
+  }
+
   auth::CryptoHashType getHashAlgorithm() const {
     return static_cast<const Implementation &>(*this).getHashAlgorithmImpl();
   }
 
+  bool getIsLast() const {
+    return static_cast<const Implementation &>(*this).getIsLastImpl();
+  }
+
   core::Name getBaseName() const {
     return static_cast<const Implementation &>(*this).getBaseNameImpl();
   }
 
-  auto getSuffixHashList() {
-    return static_cast<Implementation &>(*this).getSuffixHashListImpl();
+  ParamsBytestream getParamsBytestream() const {
+    return static_cast<const Implementation &>(*this).getParamsBytestreamImpl();
   }
 
-  bool getIsLast() const {
-    return static_cast<const Implementation &>(*this).getIsLastImpl();
+  ParamsRTC getParamsRTC() const {
+    return static_cast<const Implementation &>(*this).getParamsRTCImpl();
   }
 
-  ManifestVersion getVersion() const {
-    return static_cast<const Implementation &>(*this).getVersionImpl();
+  auto getEntries() const {
+    return static_cast<const Implementation &>(*this).getEntriesImpl();
   }
 
-  std::size_t estimateSerializedLength(std::size_t number_of_entries) const {
-    return static_cast<const Implementation &>(*this)
-        .estimateSerializedLengthImpl(number_of_entries);
+  std::size_t manifestHeaderSize() const {
+    return static_cast<const Implementation &>(*this).manifestHeaderSizeImpl();
   }
 
-  ParamsBytestream getParamsBytestream() const {
-    return static_cast<const Implementation &>(*this).getParamsBytestreamImpl();
+  std::size_t manifestPayloadSize(size_t additional_entries = 0) const {
+    return static_cast<const Implementation &>(*this).manifestPayloadSizeImpl(
+        additional_entries);
   }
 
-  ParamsRTC getParamsRTC() const {
-    return static_cast<const Implementation &>(*this).getParamsRTCImpl();
+  std::size_t manifestSize(size_t additional_entries = 0) const {
+    return static_cast<const Implementation &>(*this).manifestSizeImpl(
+        additional_entries);
   }
 };
 
 }  // namespace core
-
 }  // namespace transport
index 428d6ad..6681696 100644 (file)
 #include <hicn/transport/utils/literals.h>
 
 namespace transport {
-
 namespace core {
 
-// TODO use preallocated pool of membufs
-FixedManifestEncoder::FixedManifestEncoder(Packet &packet,
-                                           std::size_t signature_size,
-                                           bool clear)
+// ---------------------------------------------------------
+// FixedManifest
+// ---------------------------------------------------------
+size_t FixedManifest::manifestHeaderSize(
+    interface::ProductionProtocolAlgorithms transport_type) {
+  uint32_t params_size = 0;
+
+  switch (transport_type) {
+    case interface::ProductionProtocolAlgorithms::BYTE_STREAM:
+      params_size = MANIFEST_PARAMS_BYTESTREAM_SIZE;
+      break;
+    case interface::ProductionProtocolAlgorithms::RTC_PROD:
+      params_size = MANIFEST_PARAMS_RTC_SIZE;
+      break;
+    default:
+      break;
+  }
+
+  return MANIFEST_META_SIZE + MANIFEST_ENTRY_META_SIZE + params_size;
+}
+
+size_t FixedManifest::manifestPayloadSize(size_t nb_entries) {
+  return nb_entries * MANIFEST_ENTRY_SIZE;
+}
+
+// ---------------------------------------------------------
+// FixedManifestEncoder
+// ---------------------------------------------------------
+FixedManifestEncoder::FixedManifestEncoder(Packet::Ptr packet, bool clear)
     : packet_(packet),
-      max_size_(Packet::default_mtu - packet_.headerSize()),
-      signature_size_(signature_size),
       transport_type_(interface::ProductionProtocolAlgorithms::UNKNOWN),
-      encoded_(false),
-      params_bytestream_({0}),
-      params_rtc_({0}) {
-  manifest_meta_ = reinterpret_cast<ManifestMeta *>(packet_.writableData() +
-                                                    packet_.headerSize());
+      encoded_(false) {
+  manifest_meta_ = reinterpret_cast<ManifestMeta *>(packet_->writableData() +
+                                                    packet_->headerSize());
   manifest_entry_meta_ =
       reinterpret_cast<ManifestEntryMeta *>(manifest_meta_ + 1);
 
@@ -50,32 +70,34 @@ FixedManifestEncoder &FixedManifestEncoder::encodeImpl() {
     return *this;
   }
 
+  // Copy manifest header
   manifest_meta_->transport_type = static_cast<uint8_t>(transport_type_);
   manifest_entry_meta_->nb_entries = manifest_entries_.size();
 
-  packet_.append(FixedManifestEncoder::manifestHeaderSizeImpl());
-  packet_.updateLength();
+  packet_->append(manifestHeaderSizeImpl());
+  packet_->updateLength();
+  auto params = reinterpret_cast<uint8_t *>(manifest_entry_meta_ + 1);
 
   switch (transport_type_) {
-    case interface::ProductionProtocolAlgorithms::BYTE_STREAM:
-      packet_.appendPayload(
-          reinterpret_cast<const uint8_t *>(&params_bytestream_),
-          MANIFEST_PARAMS_BYTESTREAM_SIZE);
+    case interface::ProductionProtocolAlgorithms::BYTE_STREAM: {
+      auto bytestream = reinterpret_cast<const uint8_t *>(&params_bytestream_);
+      std::memcpy(params, bytestream, MANIFEST_PARAMS_BYTESTREAM_SIZE);
       break;
-    case interface::ProductionProtocolAlgorithms::RTC_PROD:
-      packet_.appendPayload(reinterpret_cast<const uint8_t *>(&params_rtc_),
-                            MANIFEST_PARAMS_RTC_SIZE);
+    }
+    case interface::ProductionProtocolAlgorithms::RTC_PROD: {
+      auto rtc = reinterpret_cast<const uint8_t *>(&params_rtc_);
+      std::memcpy(params, rtc, MANIFEST_PARAMS_RTC_SIZE);
       break;
+    }
     default:
       break;
   }
 
-  packet_.appendPayload(
-      reinterpret_cast<const uint8_t *>(manifest_entries_.data()),
-      manifest_entries_.size() * FixedManifestEncoder::manifestEntrySizeImpl());
+  // Copy manifest entries
+  auto payload = reinterpret_cast<const uint8_t *>(manifest_entries_.data());
+  packet_->appendPayload(payload, manifestPayloadSizeImpl());
 
-  if (TRANSPORT_EXPECT_FALSE(packet_.payloadSize() <
-                             estimateSerializedLengthImpl())) {
+  if (TRANSPORT_EXPECT_FALSE(packet_->payloadSize() < manifestSizeImpl())) {
     throw errors::RuntimeException("Error encoding the manifest");
   }
 
@@ -85,32 +107,21 @@ FixedManifestEncoder &FixedManifestEncoder::encodeImpl() {
 
 FixedManifestEncoder &FixedManifestEncoder::clearImpl() {
   if (encoded_) {
-    packet_.trimEnd(FixedManifestEncoder::manifestHeaderSizeImpl() +
-                    manifest_entries_.size() *
-                        FixedManifestEncoder::manifestEntrySizeImpl());
+    packet_->trimEnd(manifestSizeImpl());
   }
 
   transport_type_ = interface::ProductionProtocolAlgorithms::UNKNOWN;
   encoded_ = false;
-  params_bytestream_ = {0};
-  params_rtc_ = {0};
   *manifest_meta_ = {0};
   *manifest_entry_meta_ = {0};
+  params_bytestream_ = {0};
+  params_rtc_ = {0};
   manifest_entries_.clear();
 
   return *this;
 }
 
-FixedManifestEncoder &FixedManifestEncoder::updateImpl() {
-  max_size_ = Packet::default_mtu - packet_.headerSize() - signature_size_;
-  return *this;
-}
-
-FixedManifestEncoder &FixedManifestEncoder::setVersionImpl(
-    ManifestVersion version) {
-  manifest_meta_->version = static_cast<uint8_t>(version);
-  return *this;
-}
+bool FixedManifestEncoder::isEncodedImpl() const { return encoded_; }
 
 FixedManifestEncoder &FixedManifestEncoder::setTypeImpl(
     ManifestType manifest_type) {
@@ -118,6 +129,12 @@ FixedManifestEncoder &FixedManifestEncoder::setTypeImpl(
   return *this;
 }
 
+FixedManifestEncoder &FixedManifestEncoder::setMaxCapacityImpl(
+    uint8_t max_capacity) {
+  manifest_meta_->max_capacity = max_capacity;
+  return *this;
+}
+
 FixedManifestEncoder &FixedManifestEncoder::setHashAlgorithmImpl(
     auth::CryptoHashType algorithm) {
   manifest_meta_->hash_algorithm = static_cast<uint8_t>(algorithm);
@@ -159,61 +176,68 @@ FixedManifestEncoder &FixedManifestEncoder::setParamsRTCImpl(
   return *this;
 }
 
-FixedManifestEncoder &FixedManifestEncoder::addSuffixAndHashImpl(
+FixedManifestEncoder &FixedManifestEncoder::addEntryImpl(
     uint32_t suffix, const auth::CryptoHash &hash) {
-  manifest_entries_.push_back(ManifestEntry{
-      .suffix = htonl(suffix),
+  ManifestEntry last_entry = {
+      .suffix = portability::host_to_net(suffix),
       .hash = {0},
-  });
+  };
 
-  std::memcpy(reinterpret_cast<uint8_t *>(manifest_entries_.back().hash),
-              hash.getDigest()->data(), hash.getSize());
-
-  if (TRANSPORT_EXPECT_FALSE(estimateSerializedLengthImpl() > max_size_)) {
-    throw errors::RuntimeException("Manifest size exceeded the packet MTU!");
-  }
+  auto last_hash = reinterpret_cast<uint8_t *>(last_entry.hash);
+  std::memcpy(last_hash, hash.getDigest()->data(), hash.getSize());
 
+  manifest_entries_.push_back(last_entry);
   return *this;
 }
 
-std::size_t FixedManifestEncoder::estimateSerializedLengthImpl(
-    std::size_t additional_entries) {
-  return FixedManifestEncoder::manifestHeaderSizeImpl(transport_type_) +
-         (manifest_entries_.size() + additional_entries) *
-             FixedManifestEncoder::manifestEntrySizeImpl();
+FixedManifestEncoder &FixedManifestEncoder::removeEntryImpl(uint32_t suffix) {
+  for (auto it = manifest_entries_.begin(); it != manifest_entries_.end();) {
+    if (it->suffix == suffix)
+      it = manifest_entries_.erase(it);
+    else
+      ++it;
+  }
+  return *this;
 }
 
-std::size_t FixedManifestEncoder::manifestHeaderSizeImpl(
-    interface::ProductionProtocolAlgorithms transport_type) {
-  uint32_t params_size = 0;
-
-  switch (transport_type) {
-    case interface::ProductionProtocolAlgorithms::BYTE_STREAM:
-      params_size = MANIFEST_PARAMS_BYTESTREAM_SIZE;
-      break;
-    case interface::ProductionProtocolAlgorithms::RTC_PROD:
-      params_size = MANIFEST_PARAMS_RTC_SIZE;
-      break;
-    default:
-      break;
-  }
+size_t FixedManifestEncoder::manifestHeaderSizeImpl() const {
+  return FixedManifest::manifestHeaderSize(transport_type_);
+}
 
-  return MANIFEST_META_SIZE + MANIFEST_ENTRY_META_SIZE + params_size;
+size_t FixedManifestEncoder::manifestPayloadSizeImpl(
+    size_t additional_entries) const {
+  return FixedManifest::manifestPayloadSize(manifest_entries_.size() +
+                                            additional_entries);
 }
 
-std::size_t FixedManifestEncoder::manifestEntrySizeImpl() {
-  return MANIFEST_ENTRY_SIZE;
+size_t FixedManifestEncoder::manifestSizeImpl(size_t additional_entries) const {
+  return manifestHeaderSizeImpl() + manifestPayloadSizeImpl(additional_entries);
 }
 
-FixedManifestDecoder::FixedManifestDecoder(Packet &packet)
+// ---------------------------------------------------------
+// FixedManifestDecoder
+// ---------------------------------------------------------
+FixedManifestDecoder::FixedManifestDecoder(Packet::Ptr packet)
     : packet_(packet), decoded_(false) {
   manifest_meta_ =
-      reinterpret_cast<ManifestMeta *>(packet_.getPayload()->writableData());
+      reinterpret_cast<ManifestMeta *>(packet_->getPayload()->writableData());
   manifest_entry_meta_ =
       reinterpret_cast<ManifestEntryMeta *>(manifest_meta_ + 1);
-  transport_type_ = getTransportTypeImpl();
+}
 
-  switch (transport_type_) {
+FixedManifestDecoder::~FixedManifestDecoder() {}
+
+FixedManifestDecoder &FixedManifestDecoder::decodeImpl() {
+  if (decoded_) {
+    return *this;
+  }
+
+  if (packet_->payloadSize() < manifestSizeImpl()) {
+    throw errors::RuntimeException(
+        "The packet payload size does not match expected manifest size");
+  }
+
+  switch (getTransportTypeImpl()) {
     case interface::ProductionProtocolAlgorithms::BYTE_STREAM:
       params_bytestream_ = reinterpret_cast<TransportParamsBytestream *>(
           manifest_entry_meta_ + 1);
@@ -230,25 +254,9 @@ FixedManifestDecoder::FixedManifestDecoder(Packet &packet)
           reinterpret_cast<ManifestEntry *>(manifest_entry_meta_ + 1);
       break;
   }
-}
-
-FixedManifestDecoder::~FixedManifestDecoder() {}
-
-void FixedManifestDecoder::decodeImpl() {
-  if (decoded_) {
-    return;
-  }
-
-  std::size_t packet_size = packet_.payloadSize();
-
-  if (packet_size <
-          FixedManifestEncoder::manifestHeaderSizeImpl(transport_type_) ||
-      packet_size < estimateSerializedLengthImpl()) {
-    throw errors::RuntimeException(
-        "The packet does not match expected manifest size.");
-  }
 
   decoded_ = true;
+  return *this;
 }
 
 FixedManifestDecoder &FixedManifestDecoder::clearImpl() {
@@ -256,20 +264,22 @@ FixedManifestDecoder &FixedManifestDecoder::clearImpl() {
   return *this;
 }
 
+bool FixedManifestDecoder::isDecodedImpl() const { return decoded_; }
+
 ManifestType FixedManifestDecoder::getTypeImpl() const {
   return static_cast<ManifestType>(manifest_meta_->type);
 }
 
-ManifestVersion FixedManifestDecoder::getVersionImpl() const {
-  return static_cast<ManifestVersion>(manifest_meta_->version);
-}
-
 interface::ProductionProtocolAlgorithms
 FixedManifestDecoder::getTransportTypeImpl() const {
   return static_cast<interface::ProductionProtocolAlgorithms>(
       manifest_meta_->transport_type);
 }
 
+uint8_t FixedManifestDecoder::getMaxCapacityImpl() const {
+  return manifest_meta_->max_capacity;
+}
+
 auth::CryptoHashType FixedManifestDecoder::getHashAlgorithmImpl() const {
   return static_cast<auth::CryptoHashType>(manifest_meta_->hash_algorithm);
 }
@@ -303,26 +313,34 @@ ParamsRTC FixedManifestDecoder::getParamsRTCImpl() const {
   };
 }
 
-typename Fixed::SuffixList FixedManifestDecoder::getSuffixHashListImpl() {
+typename Fixed::SuffixList FixedManifestDecoder::getEntriesImpl() const {
   typename Fixed::SuffixList hash_list;
 
   for (int i = 0; i < manifest_entry_meta_->nb_entries; i++) {
-    hash_list.insert(hash_list.end(),
-                     std::make_pair(ntohl(manifest_entries_[i].suffix),
-                                    reinterpret_cast<uint8_t *>(
-                                        &manifest_entries_[i].hash[0])));
+    hash_list.insert(
+        hash_list.end(),
+        std::make_pair(
+            portability::net_to_host(manifest_entries_[i].suffix),
+            reinterpret_cast<uint8_t *>(&manifest_entries_[i].hash[0])));
   }
 
   return hash_list;
 }
 
-std::size_t FixedManifestDecoder::estimateSerializedLengthImpl(
-    std::size_t additional_entries) const {
-  return FixedManifestEncoder::manifestHeaderSizeImpl(transport_type_) +
-         (manifest_entry_meta_->nb_entries + additional_entries) *
-             FixedManifestEncoder::manifestEntrySizeImpl();
+size_t FixedManifestDecoder::manifestHeaderSizeImpl() const {
+  interface::ProductionProtocolAlgorithms type = getTransportTypeImpl();
+  return FixedManifest::manifestHeaderSize(type);
 }
 
-}  // end namespace core
+size_t FixedManifestDecoder::manifestPayloadSizeImpl(
+    size_t additional_entries) const {
+  size_t nb_entries = manifest_entry_meta_->nb_entries + additional_entries;
+  return FixedManifest::manifestPayloadSize(nb_entries);
+}
 
+size_t FixedManifestDecoder::manifestSizeImpl(size_t additional_entries) const {
+  return manifestHeaderSizeImpl() + manifestPayloadSizeImpl(additional_entries);
+}
+
+}  // end namespace core
 }  // end namespace transport
index 5fd2a67..7ab3719 100644 (file)
@@ -28,7 +28,7 @@ namespace core {
 //  0                   1                   2                   3
 //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |Version|  Type | Transport Type| Hash Algorithm|L|   Reserved  |
+// | Type  | TTYpe |  Max Capacity |   Hash Algo   |L|   Reserved  |
 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
 // Manifest Entry Metadata:
@@ -106,9 +106,9 @@ struct Fixed {
 
 const size_t MANIFEST_META_SIZE = 4;
 struct __attribute__((__packed__)) ManifestMeta {
-  std::uint8_t version : 4;
   std::uint8_t type : 4;
-  std::uint8_t transport_type;
+  std::uint8_t transport_type : 4;
+  std::uint8_t max_capacity;
   std::uint8_t hash_algorithm;
   std::uint8_t is_last;
 };
@@ -146,22 +146,26 @@ struct __attribute__((__packed__)) ManifestEntry {
 };
 static_assert(sizeof(ManifestEntry) == MANIFEST_ENTRY_SIZE);
 
-static const constexpr std::uint8_t manifest_version = 1;
+class FixedManifest {
+ public:
+  static size_t manifestHeaderSize(
+      interface::ProductionProtocolAlgorithms transport_type);
+  static size_t manifestPayloadSize(size_t nb_entries);
+};
 
 class FixedManifestEncoder : public ManifestEncoder<FixedManifestEncoder> {
  public:
-  FixedManifestEncoder(Packet &packet, std::size_t signature_size = 0,
-                       bool clear = true);
+  FixedManifestEncoder(Packet::Ptr packet, bool clear = false);
 
   ~FixedManifestEncoder();
 
   FixedManifestEncoder &encodeImpl();
   FixedManifestEncoder &clearImpl();
-  FixedManifestEncoder &updateImpl();
+  bool isEncodedImpl() const;
 
   // ManifestMeta
-  FixedManifestEncoder &setVersionImpl(ManifestVersion version);
   FixedManifestEncoder &setTypeImpl(ManifestType manifest_type);
+  FixedManifestEncoder &setMaxCapacityImpl(uint8_t max_capacity);
   FixedManifestEncoder &setHashAlgorithmImpl(Fixed::HashType algorithm);
   FixedManifestEncoder &setIsLastImpl(bool is_last);
 
@@ -173,20 +177,15 @@ class FixedManifestEncoder : public ManifestEncoder<FixedManifestEncoder> {
   FixedManifestEncoder &setParamsRTCImpl(const ParamsRTC &params);
 
   // ManifestEntry
-  FixedManifestEncoder &addSuffixAndHashImpl(uint32_t suffix,
-                                             const Fixed::Hash &hash);
+  FixedManifestEncoder &addEntryImpl(uint32_t suffix, const Fixed::Hash &hash);
+  FixedManifestEncoder &removeEntryImpl(uint32_t suffix);
 
-  std::size_t estimateSerializedLengthImpl(std::size_t additional_entries = 0);
-
-  static std::size_t manifestHeaderSizeImpl(
-      interface::ProductionProtocolAlgorithms transport_type =
-          interface::ProductionProtocolAlgorithms::UNKNOWN);
-  static std::size_t manifestEntrySizeImpl();
+  size_t manifestHeaderSizeImpl() const;
+  size_t manifestPayloadSizeImpl(size_t additional_entries = 0) const;
+  size_t manifestSizeImpl(size_t additional_entries = 0) const;
 
  private:
-  Packet &packet_;
-  std::size_t max_size_;
-  std::size_t signature_size_;
+  Packet::Ptr packet_;
   interface::ProductionProtocolAlgorithms transport_type_;
   bool encoded_;
 
@@ -202,17 +201,18 @@ class FixedManifestEncoder : public ManifestEncoder<FixedManifestEncoder> {
 
 class FixedManifestDecoder : public ManifestDecoder<FixedManifestDecoder> {
  public:
-  FixedManifestDecoder(Packet &packet);
+  FixedManifestDecoder(Packet::Ptr packet);
 
   ~FixedManifestDecoder();
 
-  void decodeImpl();
+  FixedManifestDecoder &decodeImpl();
   FixedManifestDecoder &clearImpl();
+  bool isDecodedImpl() const;
 
   // ManifestMeta
-  ManifestVersion getVersionImpl() const;
   ManifestType getTypeImpl() const;
   interface::ProductionProtocolAlgorithms getTransportTypeImpl() const;
+  uint8_t getMaxCapacityImpl() const;
   Fixed::HashType getHashAlgorithmImpl() const;
   bool getIsLastImpl() const;
 
@@ -224,14 +224,14 @@ class FixedManifestDecoder : public ManifestDecoder<FixedManifestDecoder> {
   ParamsRTC getParamsRTCImpl() const;
 
   // ManifestEntry
-  typename Fixed::SuffixList getSuffixHashListImpl();
+  typename Fixed::SuffixList getEntriesImpl() const;
 
-  std::size_t estimateSerializedLengthImpl(
-      std::size_t additional_entries = 0) const;
+  size_t manifestHeaderSizeImpl() const;
+  size_t manifestPayloadSizeImpl(size_t additional_entries = 0) const;
+  size_t manifestSizeImpl(size_t additional_entries = 0) const;
 
  private:
-  Packet &packet_;
-  interface::ProductionProtocolAlgorithms transport_type_;
+  Packet::Ptr packet_;
   bool decoded_;
 
   // Manifest Header
diff --git a/libtransport/src/core/manifest_inline.h b/libtransport/src/core/manifest_inline.h
deleted file mode 100644 (file)
index ca48a4a..0000000
+++ /dev/null
@@ -1,128 +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.
- */
-
-#pragma once
-
-#include <core/manifest.h>
-#include <core/manifest_format.h>
-#include <hicn/transport/portability/portability.h>
-
-#include <set>
-
-namespace transport {
-
-namespace core {
-
-template <typename Base, typename FormatTraits>
-class ManifestInline
-    : public Manifest<Base, FormatTraits, ManifestInline<Base, FormatTraits>> {
-  using ManifestBase =
-      Manifest<Base, FormatTraits, ManifestInline<Base, FormatTraits>>;
-
-  using Hash = typename FormatTraits::Hash;
-  using HashType = typename FormatTraits::HashType;
-  using Suffix = typename FormatTraits::Suffix;
-  using SuffixList = typename FormatTraits::SuffixList;
-  using HashEntry = std::pair<auth::CryptoHashType, std::vector<uint8_t>>;
-
- public:
-  ManifestInline() : ManifestBase() {}
-
-  ManifestInline(Packet::Format format, const core::Name &name,
-                 std::size_t signature_size = 0)
-      : ManifestBase(format, name, signature_size) {}
-
-  template <typename T>
-  ManifestInline(T &&base) : ManifestBase(std::forward<T &&>(base)) {}
-
-  template <typename T>
-  ManifestInline(T &base) : ManifestBase(base) {}
-
-  static TRANSPORT_ALWAYS_INLINE ManifestInline *createManifest(
-      Packet::Format format, const core::Name &manifest_name,
-      ManifestVersion version, ManifestType type, bool is_last,
-      const Name &base_name, HashType hash_algo, std::size_t signature_size) {
-    auto manifest = new ManifestInline(format, manifest_name, signature_size);
-    manifest->setVersion(version);
-    manifest->setType(type);
-    manifest->setHashAlgorithm(hash_algo);
-    manifest->setIsLast(is_last);
-    manifest->setBaseName(base_name);
-    return manifest;
-  }
-
-  ManifestInline &encodeImpl() {
-    ManifestBase::encoder_.encode();
-    return *this;
-  }
-
-  ManifestInline &decodeImpl() {
-    base_name_ = ManifestBase::decoder_.getBaseName();
-    suffix_hash_map_ = ManifestBase::decoder_.getSuffixHashList();
-
-    return *this;
-  }
-
-  std::size_t estimateManifestSizeImpl(std::size_t additional_entries = 0) {
-    return ManifestBase::encoder_.estimateSerializedLength(additional_entries);
-  }
-
-  ManifestInline &setBaseName(const Name &name) {
-    base_name_ = name;
-    ManifestBase::encoder_.setBaseName(base_name_);
-    return *this;
-  }
-
-  const Name &getBaseName() { return base_name_; }
-
-  ManifestInline &addSuffixHash(Suffix suffix, const Hash &hash) {
-    ManifestBase::encoder_.addSuffixAndHash(suffix, hash);
-    return *this;
-  }
-
-  // Call this function only after the decode function!
-  const SuffixList &getSuffixList() { return suffix_hash_map_; }
-
-  // Convert several manifests into a single map from suffixes to packet hashes.
-  // All manifests must have been decoded beforehand.
-  static std::unordered_map<Suffix, Hash> getSuffixMap(
-      const std::vector<ManifestInline *> &manifests) {
-    std::unordered_map<Suffix, Hash> suffix_map;
-
-    for (auto manifest_ptr : manifests) {
-      HashType hash_type = manifest_ptr->getHashAlgorithm();
-      SuffixList suffix_list = manifest_ptr->getSuffixList();
-
-      for (auto it = suffix_list.begin(); it != suffix_list.end(); ++it) {
-        Hash hash(it->second, Hash::getSize(hash_type), hash_type);
-        suffix_map[it->first] = hash;
-      }
-    }
-
-    return suffix_map;
-  }
-
-  static std::unordered_map<Suffix, Hash> getSuffixMap(
-      ManifestInline *manifest) {
-    return getSuffixMap(std::vector<ManifestInline *>{manifest});
-  }
-
- private:
-  core::Name base_name_;
-  SuffixList suffix_hash_map_;
-};
-
-}  // namespace core
-}  // namespace transport
index 98091ee..960947c 100644 (file)
@@ -24,7 +24,7 @@ namespace transport {
 
 namespace core {
 
-Name::Name() { name_ = {}; }
+Name::Name() { std::memset(&name_, 0, sizeof(name_)); }
 
 /**
  * XXX This function does not use the name API provided by libhicn
@@ -47,6 +47,7 @@ Name::Name(int family, const uint8_t *ip_address, std::uint32_t suffix)
   std::memcpy(dst, ip_address, length);
   name_.suffix = suffix;
 }
+
 Name::Name(const char *name, uint32_t segment) {
   if (hicn_name_create(name, segment, &name_) < 0) {
     throw errors::InvalidIpAddressException();
index f8a4ba1..fb10405 100644 (file)
@@ -42,17 +42,9 @@ class PendingInterest {
 
  public:
   using Ptr = utils::ObjectPool<PendingInterest>::Ptr;
-  // PendingInterest()
-  //     : interest_(nullptr, nullptr),
-  //       timer_(),
-  //       on_content_object_callback_(),
-  //       on_interest_timeout_callback_() {}
 
   PendingInterest(asio::io_service &io_service, const Interest::Ptr &interest)
-      : interest_(interest),
-        timer_(io_service),
-        on_content_object_callback_(),
-        on_interest_timeout_callback_() {}
+      : interest_(interest), timer_(io_service) {}
 
   PendingInterest(asio::io_service &io_service, const Interest::Ptr &interest,
                   OnContentObjectCallback &&on_content_object,
@@ -65,10 +57,9 @@ class PendingInterest {
   ~PendingInterest() = default;
 
   template <typename Handler>
-  TRANSPORT_ALWAYS_INLINE void startCountdown(Handler &&cb) {
-    timer_.expires_from_now(
-        std::chrono::milliseconds(interest_->getLifetime()));
-    timer_.async_wait(std::forward<Handler &&>(cb));
+  TRANSPORT_ALWAYS_INLINE void startCountdown(uint32_t lifetime, Handler &&cb) {
+    timer_.expires_from_now(std::chrono::milliseconds(lifetime));
+    timer_.async_wait(std::forward<Handler>(cb));
   }
 
   TRANSPORT_ALWAYS_INLINE void cancelTimer() { timer_.cancel(); }
@@ -77,7 +68,7 @@ class PendingInterest {
     return std::move(interest_);
   }
 
-  TRANSPORT_ALWAYS_INLINE void setInterest(Interest::Ptr &interest) {
+  TRANSPORT_ALWAYS_INLINE void setInterest(const Interest::Ptr &interest) {
     interest_ = interest;
   }
 
@@ -88,7 +79,7 @@ class PendingInterest {
 
   TRANSPORT_ALWAYS_INLINE void setOnContentObjectCallback(
       OnContentObjectCallback &&on_content_object) {
-    PendingInterest::on_content_object_callback_ = on_content_object;
+    PendingInterest::on_content_object_callback_ = std::move(on_content_object);
   }
 
   TRANSPORT_ALWAYS_INLINE const OnInterestTimeoutCallback &
@@ -98,7 +89,8 @@ class PendingInterest {
 
   TRANSPORT_ALWAYS_INLINE void setOnTimeoutCallback(
       OnInterestTimeoutCallback &&on_interest_timeout) {
-    PendingInterest::on_interest_timeout_callback_ = on_interest_timeout;
+    PendingInterest::on_interest_timeout_callback_ =
+        std::move(on_interest_timeout);
   }
 
  private:
index d8e8d78..c06969f 100644 (file)
@@ -43,12 +43,14 @@ std::string Portal::io_module_path_ = defaultIoModule();
 std::string Portal::defaultIoModule() {
   using namespace std::placeholders;
   GlobalConfiguration::getInstance().registerConfigurationParser(
-      io_module_section,
+      IoModuleConfiguration::section,
       std::bind(&Portal::parseIoModuleConfiguration, _1, _2));
   GlobalConfiguration::getInstance().registerConfigurationGetter(
-      io_module_section, std::bind(&Portal::getModuleConfiguration, _1, _2));
+      IoModuleConfiguration::section,
+      std::bind(&Portal::getModuleConfiguration, _1, _2));
   GlobalConfiguration::getInstance().registerConfigurationSetter(
-      io_module_section, std::bind(&Portal::setModuleConfiguration, _1, _2));
+      IoModuleConfiguration::section,
+      std::bind(&Portal::setModuleConfiguration, _1, _2));
 
   // return default
   conf_.name = default_module;
@@ -57,7 +59,7 @@ std::string Portal::defaultIoModule() {
 
 void Portal::getModuleConfiguration(ConfigurationObject& object,
                                     std::error_code& ec) {
-  DCHECK(object.getKey() == io_module_section);
+  DCHECK(object.getKey() == IoModuleConfiguration::section);
 
   auto conf = dynamic_cast<const IoModuleConfiguration&>(object);
   conf = conf_;
@@ -103,7 +105,7 @@ std::string getIoModulePath(const std::string& name,
 
 void Portal::setModuleConfiguration(const ConfigurationObject& object,
                                     std::error_code& ec) {
-  DCHECK(object.getKey() == io_module_section);
+  DCHECK(object.getKey() == IoModuleConfiguration::section);
 
   const IoModuleConfiguration& conf =
       dynamic_cast<const IoModuleConfiguration&>(object);
index aae4c57..6f3a48e 100644 (file)
 #include <hicn/transport/utils/event_thread.h>
 #include <hicn/transport/utils/fixed_block_allocator.h>
 
+extern "C" {
+#include <hicn/header.h>
+}
+
 #include <future>
 #include <memory>
 #include <queue>
@@ -179,19 +183,11 @@ class Portal : public ::utils::NonCopyable,
   Portal() : Portal(GlobalWorkers::getInstance().getWorker()) {}
 
   Portal(::utils::EventThread &worker)
-      : io_module_(nullptr, [](IoModule *module) { IoModule::unload(module); }),
+      : io_module_(nullptr),
         worker_(worker),
         app_name_("libtransport_application"),
         transport_callback_(nullptr),
-        is_consumer_(false) {
-    /**
-     * This workaroung allows to initialize memory for packet buffers *before*
-     * any static variables that may be initialized in the io_modules. In this
-     * way static variables in modules will be destroyed before the packet
-     * memory.
-     */
-    PacketManager<>::getInstance();
-  }
+        is_consumer_(false) {}
 
  public:
   using TransportCallback = interface::Portal::TransportCallback;
@@ -275,6 +271,7 @@ class Portal : public ::utils::NonCopyable,
                 ptr->transport_callback_->onError(ec);
               }
             },
+            [self]([[maybe_unused]] Connector *c) { /* Nothing to do here */ },
             [self](Connector *c, const std::error_code &ec) {
               auto ptr = self.lock();
               if (ptr) {
@@ -315,76 +312,113 @@ class Portal : public ::utils::NonCopyable,
   }
 
   /**
-   * Send an interest through to the local forwarder.
-   *
-   * @param interest - The pointer to the interest. The ownership of the
-   * interest is transferred by the caller to portal.
-   *
-   * @param on_content_object_callback - If the caller wishes to use a
-   * different callback to be called for this interest, it can set this
-   * parameter. Otherwise ConsumerCallback::onContentObject will be used.
+   * @brief Add interest to PIT
    *
-   * @param on_interest_timeout_callback - If the caller wishes to use a
-   * different callback to be called for this interest, it can set this
-   * parameter. Otherwise ConsumerCallback::onTimeout will be used.
    */
-  void sendInterest(
-      Interest::Ptr &&interest,
+  void addInterestToPIT(
+      const Interest::Ptr &interest, uint32_t lifetime,
       OnContentObjectCallback &&on_content_object_callback = UNSET_CALLBACK,
       OnInterestTimeoutCallback &&on_interest_timeout_callback =
           UNSET_CALLBACK) {
-    DCHECK(std::this_thread::get_id() == worker_.getThreadId());
-
-    // Send it
-    interest->encodeSuffixes();
-    io_module_->send(*interest);
-
     uint32_t initial_hash = interest->getName().getHash32(false);
     auto hash = initial_hash + interest->getName().getSuffix();
     uint32_t seq = interest->getName().getSuffix();
-    uint32_t *suffix = interest->firstSuffix();
+    const uint32_t *suffix = interest->firstSuffix();
     auto n_suffixes = interest->numberOfSuffixes();
     uint32_t counter = 0;
     // Set timers
     do {
+      auto pend_int = pending_interest_hash_table_.try_emplace(
+          hash, worker_.getIoService(), interest);
+      PendingInterest &pending_interest = pend_int.first->second;
+      if (!pend_int.second) {
+        // element was already in map
+        pend_int.first->second.cancelTimer();
+        pending_interest.setInterest(interest);
+      }
+
+      pending_interest.setOnContentObjectCallback(
+          std::move(on_content_object_callback));
+      pending_interest.setOnTimeoutCallback(
+          std::move(on_interest_timeout_callback));
+
+      if (is_consumer_) {
+        auto self = weak_from_this();
+        pending_interest.startCountdown(
+            lifetime, portal_details::makeCustomAllocatorHandler(
+                          async_callback_memory_,
+                          [self, hash, seq](const std::error_code &ec) {
+                            if (TRANSPORT_EXPECT_FALSE(ec.operator bool())) {
+                              return;
+                            }
+
+                            if (auto ptr = self.lock()) {
+                              ptr->timerHandler(hash, seq);
+                            }
+                          }));
+      }
+
       if (suffix) {
         hash = initial_hash + *suffix;
         seq = *suffix;
         suffix++;
       }
+    } while (counter++ < n_suffixes);
+  }
 
-      auto it = pending_interest_hash_table_.find(hash);
-      PendingInterest *pending_interest = nullptr;
-      if (it != pending_interest_hash_table_.end()) {
-        it->second.cancelTimer();
-        pending_interest = &it->second;
-        pending_interest->setInterest(interest);
-      } else {
-        auto pend_int = pending_interest_hash_table_.try_emplace(
-            hash, worker_.getIoService(), interest);
-        pending_interest = &pend_int.first->second;
-      }
+  void matchContentObjectInPIT(ContentObject &content_object) {
+    uint32_t hash = getHash(content_object.getName());
+    auto it = pending_interest_hash_table_.find(hash);
+    if (it != pending_interest_hash_table_.end()) {
+      DLOG_IF(INFO, VLOG_IS_ON(3)) << "Found pending interest.";
 
-      pending_interest->setOnContentObjectCallback(
-          std::move(on_content_object_callback));
-      pending_interest->setOnTimeoutCallback(
-          std::move(on_interest_timeout_callback));
+      PendingInterest &pend_interest = it->second;
+      pend_interest.cancelTimer();
+      auto _int = pend_interest.getInterest();
+      auto callback = pend_interest.getOnDataCallback();
+      pending_interest_hash_table_.erase(it);
 
-      auto self = weak_from_this();
-      pending_interest->startCountdown(
-          portal_details::makeCustomAllocatorHandler(
-              async_callback_memory_,
-              [self, hash, seq](const std::error_code &ec) {
-                if (TRANSPORT_EXPECT_FALSE(ec.operator bool())) {
-                  return;
-                }
+      if (is_consumer_) {
+        // Send object is for the app
+        if (callback != UNSET_CALLBACK) {
+          callback(*_int, content_object);
+        } else if (transport_callback_) {
+          transport_callback_->onContentObject(*_int, content_object);
+        }
+      } else {
+        // Send content object to the network
+        io_module_->send(content_object);
+      }
+    } else if (is_consumer_) {
+      DLOG_IF(INFO, VLOG_IS_ON(3))
+          << "No interest pending for received content object.";
+    }
+  }
 
-                if (auto ptr = self.lock()) {
-                  ptr->timerHandler(hash, seq);
-                }
-              }));
+  /**
+   * Send an interest through to the local forwarder.
+   *
+   * @param interest - The pointer to the interest. The ownership of the
+   * interest is transferred by the caller to portal.
+   *
+   * @param on_content_object_callback - If the caller wishes to use a
+   * different callback to be called for this interest, it can set this
+   * parameter. Otherwise ConsumerCallback::onContentObject will be used.
+   *
+   * @param on_interest_timeout_callback - If the caller wishes to use a
+   * different callback to be called for this interest, it can set this
+   * parameter. Otherwise ConsumerCallback::onTimeout will be used.
+   */
+  void sendInterest(
+      Interest::Ptr &interest, uint32_t lifetime,
+      OnContentObjectCallback &&on_content_object_callback = UNSET_CALLBACK,
+      OnInterestTimeoutCallback &&on_interest_timeout_callback =
+          UNSET_CALLBACK) {
+    DCHECK(std::this_thread::get_id() == worker_.getThreadId());
 
-    } while (counter++ < n_suffixes);
+    io_module_->send(*interest);
+    addInterestToPIT(interest, lifetime, std::move(on_content_object_callback),
+                     std::move(on_interest_timeout_callback));
   }
 
   /**
@@ -423,8 +457,7 @@ class Portal : public ::utils::NonCopyable,
   void sendContentObject(ContentObject &content_object) {
     DCHECK(io_module_);
     DCHECK(std::this_thread::get_id() == worker_.getThreadId());
-
-    io_module_->send(content_object);
+    matchContentObjectInPIT(content_object);
   }
 
   /**
@@ -582,6 +615,9 @@ class Portal : public ::utils::NonCopyable,
   void processInterest(Interest &interest) {
     // Interest for a producer
     DLOG_IF(INFO, VLOG_IS_ON(3)) << "processInterest " << interest.getName();
+
+    // Save interest in PIT
+    addInterestToPIT(interest.shared_from_this(), interest.getLifetime());
     if (TRANSPORT_EXPECT_TRUE(transport_callback_ != nullptr)) {
       transport_callback_->onInterest(interest);
     }
@@ -598,27 +634,7 @@ class Portal : public ::utils::NonCopyable,
   void processContentObject(ContentObject &content_object) {
     DLOG_IF(INFO, VLOG_IS_ON(3))
         << "processContentObject " << content_object.getName();
-    uint32_t hash = getHash(content_object.getName());
-
-    auto it = pending_interest_hash_table_.find(hash);
-    if (it != pending_interest_hash_table_.end()) {
-      DLOG_IF(INFO, VLOG_IS_ON(3)) << "Found pending interest.";
-
-      PendingInterest &pend_interest = it->second;
-      pend_interest.cancelTimer();
-      auto _int = pend_interest.getInterest();
-      auto callback = pend_interest.getOnDataCallback();
-      pending_interest_hash_table_.erase(it);
-
-      if (callback != UNSET_CALLBACK) {
-        callback(*_int, content_object);
-      } else if (transport_callback_) {
-        transport_callback_->onContentObject(*_int, content_object);
-      }
-    } else {
-      DLOG_IF(INFO, VLOG_IS_ON(3))
-          << "No interest pending for received content object.";
-    }
+    matchContentObjectInPIT(content_object);
   }
 
   /**
@@ -632,7 +648,7 @@ class Portal : public ::utils::NonCopyable,
 
  private:
   portal_details::HandlerMemory async_callback_memory_;
-  std::unique_ptr<IoModule, void (*)(IoModule *)> io_module_;
+  std::unique_ptr<IoModule> io_module_;
 
   ::utils::EventThread &worker_;
 
index 4c1e191..0074814 100644 (file)
  * limitations under the License.
  */
 
+#include <glog/logging.h>
 #include <hicn/transport/core/prefix.h>
 #include <hicn/transport/errors/errors.h>
+#include <hicn/transport/portability/endianess.h>
 #include <hicn/transport/utils/string_tokenizer.h>
 
 #ifndef _WIN32
@@ -37,10 +39,6 @@ namespace core {
 
 Prefix::Prefix() { std::memset(&ip_prefix_, 0, sizeof(ip_prefix_t)); }
 
-Prefix::Prefix(const char *prefix) : Prefix(std::string(prefix)) {}
-
-Prefix::Prefix(std::string &&prefix) : Prefix(prefix) {}
-
 Prefix::Prefix(const std::string &prefix) {
   utils::StringTokenizer st(prefix, "/");
 
@@ -56,7 +54,7 @@ Prefix::Prefix(const std::string &prefix) {
   buildPrefix(ip_address, uint16_t(atoi(prefix_length.c_str())), family);
 }
 
-Prefix::Prefix(std::string &prefix, uint16_t prefix_length) {
+Prefix::Prefix(const std::string &prefix, uint16_t prefix_length) {
   int family = get_addr_family(prefix.c_str());
   buildPrefix(prefix, prefix_length, family);
 }
@@ -73,12 +71,14 @@ Prefix::Prefix(const core::Name &content_name, uint16_t prefix_length) {
   ip_prefix_.family = family;
 }
 
-void Prefix::buildPrefix(std::string &prefix, uint16_t prefix_length,
+void Prefix::buildPrefix(const std::string &prefix, uint16_t prefix_length,
                          int family) {
   if (!checkPrefixLengthAndAddressFamily(prefix_length, family)) {
     throw errors::InvalidIpAddressException();
   }
 
+  std::memset(&ip_prefix_, 0, sizeof(ip_prefix_t));
+
   int ret;
   switch (family) {
     case AF_INET:
@@ -131,62 +131,67 @@ std::unique_ptr<Sockaddr> Prefix::toSockaddr() const {
 uint16_t Prefix::getPrefixLength() const { return ip_prefix_.len; }
 
 Prefix &Prefix::setPrefixLength(uint16_t prefix_length) {
+  if (!checkPrefixLengthAndAddressFamily(prefix_length, ip_prefix_.family)) {
+    throw errors::InvalidIpAddressException();
+  }
+
   ip_prefix_.len = (u8)prefix_length;
   return *this;
 }
 
 int Prefix::getAddressFamily() const { return ip_prefix_.family; }
 
-Prefix &Prefix::setAddressFamily(int address_family) {
-  ip_prefix_.family = address_family;
-  return *this;
-}
-
 std::string Prefix::getNetwork() const {
   if (!checkPrefixLengthAndAddressFamily(ip_prefix_.len, ip_prefix_.family)) {
     throw errors::InvalidIpAddressException();
   }
 
-  std::size_t size =
-      ip_prefix_.family == 4 + AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
-
-  std::string network(size, 0);
+  char buffer[INET6_ADDRSTRLEN];
 
-  if (ip_prefix_ntop_short(&ip_prefix_, (char *)network.c_str(), size) < 0) {
+  if (ip_prefix_ntop_short(&ip_prefix_, buffer, INET6_ADDRSTRLEN) < 0) {
     throw errors::RuntimeException(
         "Impossible to retrieve network from ip address.");
   }
 
-  return network;
+  return buffer;
 }
 
-int Prefix::contains(const ip_address_t &content_name) const {
-  int res =
-      ip_address_cmp(&content_name, &(ip_prefix_.address), ip_prefix_.family);
+bool Prefix::contains(const ip_address_t &content_name) const {
+  uint64_t mask[2] = {0, 0};
+  auto content_name_copy = content_name;
+  auto network_copy = ip_prefix_.address;
 
-  if (ip_prefix_.len != (ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN_BITS
-                                                       : IPV4_ADDR_LEN_BITS)) {
-    const u8 *ip_prefix_buffer =
-        ip_address_get_buffer(&(ip_prefix_.address), ip_prefix_.family);
-    const u8 *content_name_buffer =
-        ip_address_get_buffer(&content_name, ip_prefix_.family);
-    uint8_t mask = 0xFF >> (ip_prefix_.len % 8);
-    mask = ~mask;
+  auto prefix_length = getPrefixLength();
+  if (ip_prefix_.family == AF_INET) {
+    prefix_length += 3 * IPV4_ADDR_LEN_BITS;
+  }
 
-    res += (ip_prefix_buffer[ip_prefix_.len] & mask) ==
-           (content_name_buffer[ip_prefix_.len] & mask);
+  if (prefix_length == 0) {
+    mask[0] = mask[1] = 0;
+  } else if (prefix_length <= 64) {
+    mask[0] = portability::host_to_net((uint64_t)(~0) << (64 - prefix_length));
+    mask[1] = 0;
+  } else if (prefix_length == 128) {
+    mask[0] = mask[1] = 0xffffffffffffffff;
+  } else {
+    prefix_length -= 64;
+    mask[0] = 0xffffffffffffffff;
+    mask[1] = portability::host_to_net((uint64_t)(~0) << (64 - prefix_length));
   }
 
-  return res;
-}
+  // Apply mask
+  content_name_copy.v6.as_u64[0] &= mask[0];
+  content_name_copy.v6.as_u64[1] &= mask[1];
 
-int Prefix::contains(const core::Name &content_name) const {
-  return contains(content_name.toIpAddress().address);
+  network_copy.v6.as_u64[0] &= mask[0];
+  network_copy.v6.as_u64[1] &= mask[1];
+
+  return ip_address_cmp(&network_copy, &content_name_copy, ip_prefix_.family) ==
+         0;
 }
 
-Name Prefix::getName() const {
-  std::string s(getNetwork());
-  return Name(s);
+bool Prefix::contains(const core::Name &content_name) const {
+  return contains(content_name.toIpAddress().address);
 }
 
 /*
@@ -199,8 +204,8 @@ Name Prefix::getName(const core::Name &mask, const core::Name &components,
       ip_prefix_.family != components.getAddressFamily() ||
       ip_prefix_.family != content_name.getAddressFamily())
     throw errors::RuntimeException(
-        "Prefix, mask, components and content name are not of the same address "
-        "family");
+        "Prefix, mask, components and content name are not of the same"
+        "address family");
 
   ip_address_t mask_ip = mask.toIpAddress().address;
   ip_address_t component_ip = components.toIpAddress().address;
@@ -222,32 +227,6 @@ Name Prefix::getName(const core::Name &mask, const core::Name &components,
   return Name(ip_prefix_.family, (uint8_t *)&name_ip);
 }
 
-Name Prefix::getRandomName() const {
-  ip_address_t name_ip = ip_prefix_.address;
-  u8 *name_ip_buffer =
-      const_cast<u8 *>(ip_address_get_buffer(&name_ip, ip_prefix_.family));
-
-  int addr_len =
-      (ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN * 8 : IPV4_ADDR_LEN * 8) -
-      ip_prefix_.len;
-
-  size_t size = (size_t)ceil((float)addr_len / 8.0);
-  uint8_t *buffer = (uint8_t *)malloc(sizeof(uint8_t) * size);
-
-  RAND_bytes(buffer, (int)size);
-
-  int j = 0;
-  for (uint8_t i = (uint8_t)ceil((float)ip_prefix_.len / 8.0);
-       i < (ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN : IPV4_ADDR_LEN);
-       i++) {
-    name_ip_buffer[i] = buffer[j];
-    j++;
-  }
-  free(buffer);
-
-  return Name(ip_prefix_.family, (uint8_t *)&name_ip);
-}
-
 /*
  * Map a name in a different name prefix to this name prefix
  */
@@ -276,47 +255,66 @@ Name Prefix::mapName(const core::Name &content_name) const {
   return Name(ip_prefix_.family, (uint8_t *)&name_ip);
 }
 
-Prefix &Prefix::setNetwork(std::string &network) {
-  if (!inet_pton(AF_INET6, network.c_str(), ip_prefix_.address.v6.buffer)) {
+Prefix &Prefix::setNetwork(const std::string &network) {
+  if (!ip_address_pton(network.c_str(), &ip_prefix_.address)) {
     throw errors::RuntimeException("The network name is not valid.");
   }
 
   return *this;
 }
 
+Name Prefix::makeName() const { return makeNameWithIndex(0); }
+
 Name Prefix::makeRandomName() const {
-  if (ip_prefix_.family == AF_INET6) {
-    std::default_random_engine eng((std::random_device())());
-    std::uniform_int_distribution<uint32_t> idis(
-        0, std::numeric_limits<uint32_t>::max());
-    uint64_t random_number = idis(eng);
-
-    uint32_t hash_size_bits = IPV6_ADDR_LEN_BITS - ip_prefix_.len;
-    uint64_t ip_address[2];
-    memcpy(ip_address, ip_prefix_.address.v6.buffer, sizeof(uint64_t));
-    memcpy(ip_address + 1, ip_prefix_.address.v6.buffer + 8, sizeof(uint64_t));
-    std::string network(IPV6_ADDR_LEN * 3, 0);
-
-    // Let's do the magic ;)
-    int shift_size = hash_size_bits > sizeof(random_number) * 8
-                         ? sizeof(random_number) * 8
-                         : hash_size_bits;
-
-    ip_address[1] >>= shift_size;
-    ip_address[1] <<= shift_size;
-
-    ip_address[1] |= random_number >> (sizeof(uint64_t) * 8 - shift_size);
-
-    if (!inet_ntop(ip_prefix_.family, ip_address, (char *)network.c_str(),
-                   IPV6_ADDR_LEN * 3)) {
-      throw errors::RuntimeException(
-          "Impossible to retrieve network from ip address.");
-    }
+  std::default_random_engine eng((std::random_device())());
+  std::uniform_int_distribution<uint32_t> idis(
+      0, std::numeric_limits<uint32_t>::max());
+  uint64_t random_number = idis(eng);
+
+  return makeNameWithIndex(random_number);
+}
+
+Name Prefix::makeNameWithIndex(std::uint64_t index) const {
+  uint16_t prefix_length = getPrefixLength();
 
-    return Name(network);
+  Name ret;
+
+  // Adjust prefix length depending on the address family
+  if (getAddressFamily() == AF_INET) {
+    // Sanity check
+    DCHECK(prefix_length <= 32);
+    // Convert prefix length to ip46_address_t prefix length
+    prefix_length += IPV4_ADDR_LEN_BITS * 3;
+  }
+
+  std::memcpy(ret.getStructReference().prefix.v6.as_u8,
+              ip_prefix_.address.v6.as_u8, sizeof(ip_address_t));
+
+  // Convert index in network byte order
+  index = portability::host_to_net(index);
+
+  // Apply mask
+  uint64_t mask;
+  if (prefix_length == 0) {
+    mask = 0;
+  } else if (prefix_length <= 64) {
+    mask = 0;
+  } else if (prefix_length == 128) {
+    mask = 0xffffffffffffffff;
+  } else {
+    prefix_length -= 64;
+    mask = portability::host_to_net((uint64_t)(~0) << (64 - prefix_length));
   }
 
-  return Name();
+  ret.getStructReference().prefix.v6.as_u64[1] &= mask;
+  // Eventually truncate index if too big
+  index &= ~mask;
+
+  // Apply index
+  ret.getStructReference().prefix.v6.as_u64[1] |= index;
+
+  // Done
+  return ret;
 }
 
 bool Prefix::checkPrefixLengthAndAddressFamily(uint16_t prefix_length,
index ee0c7ea..5d8e76b 100644 (file)
@@ -56,9 +56,9 @@ void UdpTunnelConnector::send(Packet &packet) {
 
 void UdpTunnelConnector::send(const utils::MemBuf::Ptr &buffer) {
   auto self = shared_from_this();
-  io_service_.post([self, pkt{buffer}]() {
+  io_service_.post([self, buffer]() {
     bool write_in_progress = !self->output_buffer_.empty();
-    self->output_buffer_.push_back(std::move(pkt));
+    self->output_buffer_.push_back(std::move(buffer));
     if (TRANSPORT_EXPECT_TRUE(self->state_ == State::CONNECTED)) {
       if (!write_in_progress) {
         self->doSendPacket(self);
@@ -201,6 +201,8 @@ void UdpTunnelConnector::writeHandler() {
         ptr->writeHandler();
       }
     });
+  } else {
+    sent_callback_(this, make_error_code(core_error::success));
   }
 }
 
index 6582185..002f4ca 100644 (file)
@@ -62,7 +62,7 @@ class UdpTunnelConnector : public Connector {
 #endif
         socket_(socket),
         resolver_(io_service_),
-        remote_endpoint_send_(std::forward<EndpointType &&>(remote_endpoint)),
+        remote_endpoint_send_(std::forward<EndpointType>(remote_endpoint)),
         timer_(io_service_),
 #ifdef LINUX
         send_timer_(io_service_),
index c676733..caa97e0 100644 (file)
@@ -5,6 +5,7 @@
 #include <core/udp_connector.h>
 #include <core/udp_listener.h>
 #include <glog/logging.h>
+#include <hicn/transport/portability/endianess.h>
 #include <hicn/transport/utils/hash.h>
 
 #ifndef LINUX
@@ -16,7 +17,7 @@ size_t hash<asio::ip::udp::endpoint>::operator()(
                      : utils::hash::fnv32_buf(
                            endpoint.address().to_v6().to_bytes().data(), 16);
   uint16_t port = endpoint.port();
-  return utils::hash::fnv32_buf(&port, 2, hash_ip);
+  return utils::hash::fnv32_buf(&port, 2, (unsigned int)hash_ip);
 }
 }  // namespace std
 #endif
@@ -83,7 +84,8 @@ void UdpTunnelListener::readHandler(const std::error_code &ec) {
           std::copy_n(reinterpret_cast<uint8_t *>(&addr->sin_addr),
                       address_bytes.size(), address_bytes.begin());
           address_v4 address(address_bytes);
-          remote_endpoint_ = udp::endpoint(address, ntohs(addr->sin_port));
+          remote_endpoint_ =
+              udp::endpoint(address, portability::net_to_host(addr->sin_port));
         } else {
           auto addr = reinterpret_cast<struct sockaddr_in6 *>(
               &remote_endpoints_[current_position_]);
@@ -91,7 +93,8 @@ void UdpTunnelListener::readHandler(const std::error_code &ec) {
           std::copy_n(reinterpret_cast<uint8_t *>(&addr->sin6_addr),
                       address_bytes.size(), address_bytes.begin());
           address_v6 address(address_bytes);
-          remote_endpoint_ = udp::endpoint(address, ntohs(addr->sin6_port));
+          remote_endpoint_ =
+              udp::endpoint(address, portability::net_to_host(addr->sin6_port));
         }
 
         /**
index 8135203..d8095a2 100644 (file)
@@ -40,7 +40,7 @@ class UdpTunnelListener
         socket_(std::make_shared<asio::ip::udp::socket>(io_service_,
                                                         endpoint.protocol())),
         local_endpoint_(endpoint),
-        receive_callback_(std::forward<ReceiveCallback &&>(receive_callback)),
+        receive_callback_(std::forward<ReceiveCallback>(receive_callback)),
 #ifndef LINUX
         read_msg_(nullptr, 0)
 #else
@@ -63,12 +63,12 @@ class UdpTunnelListener
   void close();
 
   int deleteConnector(Connector *connector) {
-    return connectors_.erase(connector->getConnectorId());
+    return (int)connectors_.erase(connector->getConnectorId());
   }
 
   template <typename ReceiveCallback>
   void setReceiveCallback(ReceiveCallback &&callback) {
-    receive_callback_ = std::forward<ReceiveCallback &&>(callback);
+    receive_callback_ = std::forward<ReceiveCallback>(callback);
   }
 
   Connector *findConnector(Connector::Id connId) {
index 1f2a33a..c759dd9 100644 (file)
@@ -19,21 +19,8 @@ list(APPEND HEADER_FILES
 
 if (${OPENSSL_VERSION} VERSION_EQUAL "1.1.1a" OR ${OPENSSL_VERSION} VERSION_GREATER "1.1.1a")
   list(APPEND SOURCE_FILES
-    ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.cc
-    # ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.cc
-    ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.cc
-    ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.cc
-    ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.cc
     ${CMAKE_CURRENT_SOURCE_DIR}/socket.cc
   )
-
-  list(APPEND HEADER_FILES
-    ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.h
-    # ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.h
-    ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.h
-    ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.h
-    ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.h
-  )
 endif()
 
 set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
diff --git a/libtransport/src/implementation/p2psecure_socket_consumer.cc b/libtransport/src/implementation/p2psecure_socket_consumer.cc
deleted file mode 100644 (file)
index 6b67a54..0000000
+++ /dev/null
@@ -1,370 +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.
- */
-
-#include <implementation/p2psecure_socket_consumer.h>
-#include <interfaces/tls_socket_consumer.h>
-#include <openssl/bio.h>
-#include <openssl/ssl.h>
-#include <openssl/tls1.h>
-
-#include <random>
-
-namespace transport {
-namespace implementation {
-
-void P2PSecureConsumerSocket::setInterestPayload(
-    interface::ConsumerSocket &c, const core::Interest &interest) {
-  Interest &int2 = const_cast<Interest &>(interest);
-  random_suffix_ = int2.getName().getSuffix();
-
-  if (payload_ != NULL) int2.appendPayload(std::move(payload_));
-}
-
-/* Return the number of read bytes in the return param */
-int readOld(BIO *b, char *buf, int size) {
-  if (size < 0) return size;
-
-  P2PSecureConsumerSocket *socket;
-  socket = (P2PSecureConsumerSocket *)BIO_get_data(b);
-
-  std::unique_lock<std::mutex> lck(socket->mtx_);
-
-  if (!socket->something_to_read_) {
-    if (!socket->transport_protocol_->isRunning()) {
-      socket->network_name_.setSuffix(socket->random_suffix_);
-      socket->ConsumerSocket::consume(socket->network_name_);
-    }
-
-    if (!socket->something_to_read_) socket->cv_.wait(lck);
-  }
-
-  size_t size_to_read, read;
-  size_t chain_size = socket->head_->length();
-
-  if (socket->head_->isChained())
-    chain_size = socket->head_->computeChainDataLength();
-
-  if (chain_size > (size_t)size) {
-    read = size_to_read = (size_t)size;
-  } else {
-    read = size_to_read = chain_size;
-    socket->something_to_read_ = false;
-  }
-
-  while (size_to_read) {
-    if (socket->head_->length() < size_to_read) {
-      std::memcpy(buf, socket->head_->data(), socket->head_->length());
-      size_to_read -= socket->head_->length();
-      buf += socket->head_->length();
-      socket->head_ = socket->head_->pop();
-    } else {
-      std::memcpy(buf, socket->head_->data(), size_to_read);
-      socket->head_->trimStart(size_to_read);
-      size_to_read = 0;
-    }
-  }
-
-  return (int)read;
-}
-
-/* Return the number of read bytes in readbytes */
-int read(BIO *b, char *buf, size_t size, size_t *readbytes) {
-  int ret;
-
-  if (size > INT_MAX) size = INT_MAX;
-
-  ret = readOld(b, buf, (int)size);
-
-  if (ret <= 0) {
-    *readbytes = 0;
-    return ret;
-  }
-
-  *readbytes = (size_t)ret;
-
-  return 1;
-}
-
-/* Return the number of written bytes in the return param */
-int writeOld(BIO *b, const char *buf, int num) {
-  P2PSecureConsumerSocket *socket;
-  socket = (P2PSecureConsumerSocket *)BIO_get_data(b);
-
-  socket->payload_ = utils::MemBuf::copyBuffer(buf, num);
-
-  socket->ConsumerSocket::setSocketOption(
-      ConsumerCallbacksOptions::INTEREST_OUTPUT,
-      (ConsumerInterestCallback)std::bind(
-          &P2PSecureConsumerSocket::setInterestPayload, socket,
-          std::placeholders::_1, std::placeholders::_2));
-
-  return num;
-}
-
-/* Return the number of written bytes in written */
-int write(BIO *b, const char *buf, size_t size, size_t *written) {
-  int ret;
-
-  if (size > INT_MAX) size = INT_MAX;
-
-  ret = writeOld(b, buf, (int)size);
-
-  if (ret <= 0) {
-    *written = 0;
-    return ret;
-  }
-
-  *written = (size_t)ret;
-
-  return 1;
-}
-
-long ctrl(BIO *b, int cmd, long num, void *ptr) { return 1; }
-
-int P2PSecureConsumerSocket::addHicnKeyIdCb(SSL *s, unsigned int ext_type,
-                                            unsigned int context,
-                                            const unsigned char **out,
-                                            size_t *outlen, X509 *x,
-                                            size_t chainidx, int *al,
-                                            void *add_arg) {
-  if (ext_type == 100) {
-    *out = (unsigned char *)malloc(4);
-    *(uint32_t *)*out = 10;
-    *outlen = 4;
-  }
-  return 1;
-}
-
-void P2PSecureConsumerSocket::freeHicnKeyIdCb(SSL *s, unsigned int ext_type,
-                                              unsigned int context,
-                                              const unsigned char *out,
-                                              void *add_arg) {
-  free(const_cast<unsigned char *>(out));
-}
-
-int P2PSecureConsumerSocket::parseHicnKeyIdCb(SSL *s, unsigned int ext_type,
-                                              unsigned int context,
-                                              const unsigned char *in,
-                                              size_t inlen, X509 *x,
-                                              size_t chainidx, int *al,
-                                              void *add_arg) {
-  P2PSecureConsumerSocket *socket =
-      reinterpret_cast<P2PSecureConsumerSocket *>(add_arg);
-  if (ext_type == 100) {
-    memcpy(&socket->secure_prefix_, in, sizeof(ip_prefix_t));
-  }
-  return 1;
-}
-
-P2PSecureConsumerSocket::P2PSecureConsumerSocket(
-    interface::ConsumerSocket *consumer, int handshake_protocol,
-    int transport_protocol)
-    : ConsumerSocket(consumer, handshake_protocol),
-      name_(),
-      tls_consumer_(nullptr),
-      decrypted_content_(),
-      payload_(),
-      head_(),
-      something_to_read_(false),
-      content_downloaded_(false),
-      random_suffix_(),
-      secure_prefix_(),
-      producer_namespace_(),
-      read_callback_decrypted_(),
-      mtx_(),
-      cv_(),
-      protocol_(transport_protocol) {
-  /* Create the (d)TLS state */
-  const SSL_METHOD *meth = TLS_client_method();
-  ctx_ = SSL_CTX_new(meth);
-
-  int result =
-      SSL_CTX_set_ciphersuites(ctx_,
-                               "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_"
-                               "SHA256:TLS_AES_128_GCM_SHA256");
-  if (result != 1) {
-    throw errors::RuntimeException(
-        "Unable to set cipher list on TLS subsystem. Aborting.");
-  }
-
-  SSL_CTX_set_min_proto_version(ctx_, TLS1_3_VERSION);
-  SSL_CTX_set_max_proto_version(ctx_, TLS1_3_VERSION);
-  SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, NULL);
-  SSL_CTX_set_ssl_version(ctx_, meth);
-
-  result = SSL_CTX_add_custom_ext(
-      ctx_, 100, SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
-      P2PSecureConsumerSocket::addHicnKeyIdCb,
-      P2PSecureConsumerSocket::freeHicnKeyIdCb, NULL,
-      P2PSecureConsumerSocket::parseHicnKeyIdCb, this);
-
-  ssl_ = SSL_new(ctx_);
-
-  bio_meth_ = BIO_meth_new(BIO_TYPE_CONNECT, "secure consumer socket");
-  BIO_meth_set_read(bio_meth_, readOld);
-  BIO_meth_set_write(bio_meth_, writeOld);
-  BIO_meth_set_ctrl(bio_meth_, ctrl);
-  BIO *bio = BIO_new(bio_meth_);
-  BIO_set_init(bio, 1);
-  BIO_set_data(bio, this);
-  SSL_set_bio(ssl_, bio, bio);
-
-  std::default_random_engine generator;
-  std::uniform_int_distribution<int> distribution(
-      1, std::numeric_limits<uint32_t>::max());
-  random_suffix_ = 0;
-
-  this->ConsumerSocket::setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK,
-                                        this);
-};
-
-P2PSecureConsumerSocket::~P2PSecureConsumerSocket() {
-  BIO_meth_free(bio_meth_);
-  SSL_shutdown(ssl_);
-}
-
-int P2PSecureConsumerSocket::handshake() {
-  int result = 1;
-
-  if (!(SSL_in_before(this->ssl_) || SSL_in_init(this->ssl_))) {
-    return 1;
-  }
-
-  ConsumerSocket::getSocketOption(MAX_WINDOW_SIZE, old_max_win_);
-  ConsumerSocket::getSocketOption(CURRENT_WINDOW_SIZE, old_current_win_);
-
-  ConsumerSocket::setSocketOption(MAX_WINDOW_SIZE, (double)1.0);
-  ConsumerSocket::setSocketOption(CURRENT_WINDOW_SIZE, (double)1.0);
-
-  network_name_ = producer_namespace_.getRandomName();
-  network_name_.setSuffix(0);
-
-  DLOG_IF(INFO, VLOG_IS_ON(2)) << "Start handshake at " << network_name_;
-  result = SSL_connect(this->ssl_);
-
-  return result;
-}
-
-void P2PSecureConsumerSocket::initSessionSocket() {
-  tls_consumer_ =
-      std::make_shared<TLSConsumerSocket>(nullptr, this->protocol_, this->ssl_);
-  tls_consumer_->setInterface(
-      new interface::TLSConsumerSocket(tls_consumer_.get()));
-
-  ConsumerTimerCallback *stats_summary_callback = nullptr;
-  this->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY,
-                        &stats_summary_callback);
-
-  uint32_t lifetime;
-  this->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, lifetime);
-
-  tls_consumer_->setSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
-                                 lifetime);
-  tls_consumer_->setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK,
-                                 read_callback_decrypted_);
-  tls_consumer_->setSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY,
-                                 *stats_summary_callback);
-  tls_consumer_->setSocketOption(GeneralTransportOptions::STATS_INTERVAL,
-                                 this->timer_interval_milliseconds_);
-  tls_consumer_->setSocketOption(MAX_WINDOW_SIZE, old_max_win_);
-  tls_consumer_->setSocketOption(CURRENT_WINDOW_SIZE, old_current_win_);
-  tls_consumer_->connect();
-}
-
-int P2PSecureConsumerSocket::consume(const Name &name) {
-  if (transport_protocol_->isRunning()) {
-    return CONSUMER_BUSY;
-  }
-
-  if (handshake() != 1) {
-    throw errors::RuntimeException("Unable to perform client handshake");
-  } else {
-    DLOG_IF(INFO, VLOG_IS_ON(2)) << "Handshake performed!";
-  }
-
-  initSessionSocket();
-
-  if (tls_consumer_ == nullptr) {
-    throw errors::RuntimeException("TLS socket does not exist");
-  }
-
-  std::shared_ptr<Name> prefix_name = std::make_shared<Name>(
-      secure_prefix_.family,
-      ip_address_get_buffer(&(secure_prefix_.address), secure_prefix_.family));
-  std::shared_ptr<Prefix> prefix =
-      std::make_shared<Prefix>(*prefix_name, secure_prefix_.len);
-
-  if (payload_ != nullptr)
-    return tls_consumer_->consume((prefix->mapName(name)), std::move(payload_));
-  else
-    return tls_consumer_->consume((prefix->mapName(name)));
-}
-
-void P2PSecureConsumerSocket::registerPrefix(const Prefix &producer_namespace) {
-  producer_namespace_ = producer_namespace;
-}
-
-int P2PSecureConsumerSocket::setSocketOption(
-    int socket_option_key, ReadCallback *socket_option_value) {
-  return rescheduleOnIOService(
-      socket_option_key, socket_option_value,
-      [this](int socket_option_key, ReadCallback *socket_option_value) -> int {
-        switch (socket_option_key) {
-          case ConsumerCallbacksOptions::READ_CALLBACK:
-            read_callback_decrypted_ = socket_option_value;
-            break;
-          default:
-            return SOCKET_OPTION_NOT_SET;
-        }
-
-        return SOCKET_OPTION_SET;
-      });
-}
-
-void P2PSecureConsumerSocket::getReadBuffer(uint8_t **application_buffer,
-                                            size_t *max_length){};
-
-void P2PSecureConsumerSocket::readDataAvailable(size_t length) noexcept {};
-
-size_t P2PSecureConsumerSocket::maxBufferSize() const {
-  return SSL3_RT_MAX_PLAIN_LENGTH;
-}
-
-void P2PSecureConsumerSocket::readBufferAvailable(
-    std::unique_ptr<utils::MemBuf> &&buffer) noexcept {
-  std::unique_lock<std::mutex> lck(this->mtx_);
-  if (head_) {
-    head_->prependChain(std::move(buffer));
-  } else {
-    head_ = std::move(buffer);
-  }
-
-  something_to_read_ = true;
-  cv_.notify_one();
-}
-
-void P2PSecureConsumerSocket::readError(const std::error_code &ec) noexcept {};
-
-void P2PSecureConsumerSocket::readSuccess(std::size_t total_size) noexcept {
-  std::unique_lock<std::mutex> lck(this->mtx_);
-  content_downloaded_ = true;
-  something_to_read_ = true;
-  cv_.notify_one();
-}
-
-bool P2PSecureConsumerSocket::isBufferMovable() noexcept { return true; }
-
-}  // namespace implementation
-}  // namespace transport
diff --git a/libtransport/src/implementation/p2psecure_socket_consumer.h b/libtransport/src/implementation/p2psecure_socket_consumer.h
deleted file mode 100644 (file)
index a5e69f6..0000000
+++ /dev/null
@@ -1,134 +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.
- */
-
-#pragma once
-
-#include <hicn/transport/interfaces/socket_consumer.h>
-#include <implementation/tls_socket_consumer.h>
-#include <openssl/bio.h>
-#include <openssl/ssl.h>
-
-namespace transport {
-namespace implementation {
-
-class P2PSecureConsumerSocket : public ConsumerSocket,
-                                public interface::ConsumerSocket::ReadCallback {
-  /* Return the number of read bytes in readbytes */
-  friend int read(BIO *b, char *buf, size_t size, size_t *readbytes);
-
-  /* Return the number of read bytes in the return param */
-  friend int readOld(BIO *h, char *buf, int size);
-
-  /* Return the number of written bytes in written */
-  friend int write(BIO *b, const char *buf, size_t size, size_t *written);
-
-  /* Return the number of written bytes in the return param */
-  friend int writeOld(BIO *h, const char *buf, int num);
-
-  friend long ctrl(BIO *b, int cmd, long num, void *ptr);
-
- public:
-  explicit P2PSecureConsumerSocket(interface::ConsumerSocket *consumer,
-                                   int handshake_protocol,
-                                   int transport_protocol);
-
-  ~P2PSecureConsumerSocket();
-
-  int consume(const Name &name) override;
-
-  void registerPrefix(const Prefix &producer_namespace);
-
-  int setSocketOption(
-      int socket_option_key,
-      interface::ConsumerSocket::ReadCallback *socket_option_value) override;
-
-  using ConsumerSocket::getSocketOption;
-  using ConsumerSocket::setSocketOption;
-
- protected:
-  /* Callback invoked once an interest has been received and its payload
-   * decrypted */
-  ConsumerInterestCallback on_interest_input_decrypted_;
-  ConsumerInterestCallback on_interest_process_decrypted_;
-
- private:
-  Name name_;
-  std::shared_ptr<TLSConsumerSocket> tls_consumer_;
-  /* SSL handle */
-  SSL *ssl_;
-  SSL_CTX *ctx_;
-  BIO_METHOD *bio_meth_;
-  /* Chain of MemBuf to be used as a temporary buffer to pass descypted data
-   * from the underlying layer to the application */
-  std::unique_ptr<utils::MemBuf> decrypted_content_;
-  /* Chain of MemBuf holding the payload to be written into interest or data */
-  std::unique_ptr<utils::MemBuf> payload_;
-  /* Chain of MemBuf holding the data retrieved from the underlying layer */
-  std::unique_ptr<utils::MemBuf> head_;
-  bool something_to_read_;
-  bool content_downloaded_;
-  double old_max_win_;
-  double old_current_win_;
-  uint32_t random_suffix_;
-  ip_prefix_t secure_prefix_;
-  Prefix producer_namespace_;
-  interface::ConsumerSocket::ReadCallback *read_callback_decrypted_;
-  std::mutex mtx_;
-
-  /* Condition variable for the wait */
-  std::condition_variable cv_;
-
-  int protocol_;
-
-  void setInterestPayload(interface::ConsumerSocket &c,
-                          const core::Interest &interest);
-
-  static int addHicnKeyIdCb(SSL *s, unsigned int ext_type, unsigned int context,
-                            const unsigned char **out, size_t *outlen, X509 *x,
-                            size_t chainidx, int *al, void *add_arg);
-
-  static void freeHicnKeyIdCb(SSL *s, unsigned int ext_type,
-                              unsigned int context, const unsigned char *out,
-                              void *add_arg);
-
-  static int parseHicnKeyIdCb(SSL *s, unsigned int ext_type,
-                              unsigned int context, const unsigned char *in,
-                              size_t inlen, X509 *x, size_t chainidx, int *al,
-                              void *add_arg);
-
-  virtual void getReadBuffer(uint8_t **application_buffer,
-                             size_t *max_length) override;
-
-  virtual void readDataAvailable(size_t length) noexcept override;
-
-  virtual size_t maxBufferSize() const override;
-
-  virtual void readBufferAvailable(
-      std::unique_ptr<utils::MemBuf> &&buffer) noexcept override;
-
-  virtual void readError(const std::error_code &ec) noexcept override;
-
-  virtual void readSuccess(std::size_t total_size) noexcept override;
-
-  virtual bool isBufferMovable() noexcept override;
-
-  int handshake();
-
-  void initSessionSocket();
-};
-
-}  // namespace implementation
-
-}  // end namespace transport
diff --git a/libtransport/src/implementation/p2psecure_socket_producer.cc b/libtransport/src/implementation/p2psecure_socket_producer.cc
deleted file mode 100644 (file)
index ee78ea5..0000000
+++ /dev/null
@@ -1,347 +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.
- */
-
-#include <hicn/transport/core/interest.h>
-#include <implementation/p2psecure_socket_producer.h>
-// #include <implementation/tls_rtc_socket_producer.h>
-#include <implementation/tls_socket_producer.h>
-#include <interfaces/tls_rtc_socket_producer.h>
-#include <interfaces/tls_socket_producer.h>
-#include <openssl/bio.h>
-#include <openssl/pkcs12.h>
-#include <openssl/rand.h>
-#include <openssl/ssl.h>
-
-namespace transport {
-namespace implementation {
-
-/* Workaround to prevent content with expiry time equal to 0 to be lost when
- * pushed in the forwarder */
-#define HICN_HANDSHAKE_CONTENT_EXPIRY_TIME 100;
-
-P2PSecureProducerSocket::P2PSecureProducerSocket(
-    interface::ProducerSocket *producer_socket)
-    : ProducerSocket(producer_socket,
-                     ProductionProtocolAlgorithms::BYTE_STREAM),
-      mtx_(),
-      cv_(),
-      map_producers(),
-      list_producers() {}
-
-P2PSecureProducerSocket::P2PSecureProducerSocket(
-    interface::ProducerSocket *producer_socket, bool rtc,
-    std::string &keystore_path, std::string &keystore_pwd)
-    : ProducerSocket(producer_socket,
-                     ProductionProtocolAlgorithms::BYTE_STREAM),
-      rtc_(rtc),
-      mtx_(),
-      cv_(),
-      map_producers(),
-      list_producers() {
-  /* Setup SSL context (identity and parameter to use TLS 1.3) */
-  FILE *p12file = fopen(keystore_path.c_str(), "r");
-  if (p12file == NULL)
-    throw errors::RuntimeException("impossible open keystore");
-  std::unique_ptr<PKCS12, decltype(&::PKCS12_free)> p12(
-      d2i_PKCS12_fp(p12file, NULL), ::PKCS12_free);
-  // now we parse the file to get the first key and certificate
-  if (1 != PKCS12_parse(p12.get(), keystore_pwd.c_str(), &pkey_rsa_, &cert_509_,
-                        NULL))
-    throw errors::RuntimeException("impossible to get the private key");
-  fclose(p12file);
-
-  /* Set the callback so that when an interest is received we catch it and we
-   * decrypt the payload before passing it to the application.  */
-  ProducerSocket::setSocketOption(
-      ProducerCallbacksOptions::INTEREST_INPUT,
-      (ProducerInterestCallback)std::bind(
-          &P2PSecureProducerSocket::onInterestCallback, this,
-          std::placeholders::_1, std::placeholders::_2));
-}
-
-P2PSecureProducerSocket::~P2PSecureProducerSocket() {}
-
-void P2PSecureProducerSocket::initSessionSocket(
-    std::unique_ptr<TLSProducerSocket> &producer) {
-  producer->on_content_produced_application_ =
-      this->on_content_produced_application_;
-  producer->setSocketOption(CONTENT_OBJECT_EXPIRY_TIME,
-                            this->content_object_expiry_time_);
-  producer->setSocketOption(SIGNER, this->signer_);
-  producer->setSocketOption(MAKE_MANIFEST, this->making_manifest_);
-  producer->setSocketOption(DATA_PACKET_SIZE,
-                            (uint32_t)(this->data_packet_size_));
-  uint32_t output_buffer_size = 0;
-  this->getSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE,
-                        output_buffer_size);
-  producer->setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE,
-                            output_buffer_size);
-
-  if (!rtc_) {
-    producer->setInterface(new interface::TLSProducerSocket(producer.get()));
-  } else {
-    // TODO
-    // TLSRTCProducerSocket *rtc_producer =
-    //     dynamic_cast<TLSRTCProducerSocket *>(producer.get());
-    // rtc_producer->setInterface(
-    //     new interface::TLSRTCProducerSocket(rtc_producer));
-  }
-}
-
-void P2PSecureProducerSocket::onInterestCallback(interface::ProducerSocket &p,
-                                                 Interest &interest) {
-  std::unique_lock<std::mutex> lck(mtx_);
-  std::unique_ptr<TLSProducerSocket> tls_producer;
-  auto it = map_producers.find(interest.getName());
-
-  if (it != map_producers.end()) {
-    return;
-  }
-
-  if (!rtc_) {
-    tls_producer =
-        std::make_unique<TLSProducerSocket>(nullptr, this, interest.getName());
-  } else {
-    // TODO
-    // tls_producer = std::make_unique<TLSRTCProducerSocket>(nullptr, this,
-    //                                                       interest.getName());
-  }
-
-  initSessionSocket(tls_producer);
-  TLSProducerSocket *tls_producer_ptr = tls_producer.get();
-  map_producers.insert({interest.getName(), move(tls_producer)});
-
-  DLOG_IF(INFO, VLOG_IS_ON(3)) << "Start handshake at " << interest.getName();
-
-  if (!rtc_) {
-    tls_producer_ptr->onInterest(*tls_producer_ptr, interest);
-    tls_producer_ptr->async_accept();
-  } else {
-    // TODO
-    // TLSRTCProducerSocket *rtc_producer_ptr =
-    //     dynamic_cast<TLSRTCProducerSocket *>(tls_producer_ptr);
-    // rtc_producer_ptr->onInterest(*rtc_producer_ptr, interest);
-    // rtc_producer_ptr->async_accept();
-  }
-}
-
-uint32_t P2PSecureProducerSocket::produceDatagram(
-    const Name &content_name, std::unique_ptr<utils::MemBuf> &&buffer) {
-  // TODO
-  throw errors::NotImplementedException();
-
-  // if (!rtc_) {
-  //   throw errors::RuntimeException(
-  //       "RTC must be the transport protocol to start the production of
-  //       current " "data. Aborting.");
-  // }
-
-  // std::unique_lock<std::mutex> lck(mtx_);
-
-  // if (list_producers.empty()) cv_.wait(lck);
-
-  // TODO
-  // for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++)
-  // {
-  //   TLSRTCProducerSocket *rtc_producer =
-  //       dynamic_cast<TLSRTCProducerSocket *>(it->get());
-  //   rtc_producer->produce(utils::MemBuf::copyBuffer(buffer, buffer_size));
-  // }
-
-  // return 0;
-}
-
-uint32_t P2PSecureProducerSocket::produceStream(
-    const Name &content_name, std::unique_ptr<utils::MemBuf> &&buffer,
-    bool is_last, uint32_t start_offset) {
-  if (rtc_) {
-    throw errors::RuntimeException(
-        "RTC transport protocol is not compatible with the production of "
-        "current data. Aborting.");
-  }
-
-  std::unique_lock<std::mutex> lck(mtx_);
-  uint32_t segments = 0;
-
-  if (list_producers.empty()) cv_.wait(lck);
-
-  for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++)
-    segments += (*it)->produceStream(content_name, buffer->clone(), is_last,
-                                     start_offset);
-
-  return segments;
-}
-
-uint32_t P2PSecureProducerSocket::produceStream(const Name &content_name,
-                                                const uint8_t *buffer,
-                                                size_t buffer_size,
-                                                bool is_last,
-                                                uint32_t start_offset) {
-  if (rtc_) {
-    throw errors::RuntimeException(
-        "RTC transport protocol is not compatible with the production of "
-        "current data. Aborting.");
-  }
-
-  std::unique_lock<std::mutex> lck(mtx_);
-  uint32_t segments = 0;
-  if (list_producers.empty()) cv_.wait(lck);
-
-  for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++)
-    segments += (*it)->produceStream(content_name, buffer, buffer_size, is_last,
-                                     start_offset);
-
-  return segments;
-}
-
-/* Redefinition of socket options to avoid name hiding */
-int P2PSecureProducerSocket::setSocketOption(
-    int socket_option_key, ProducerInterestCallback socket_option_value) {
-  if (!list_producers.empty()) {
-    for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++)
-      (*it)->setSocketOption(socket_option_key, socket_option_value);
-  }
-
-  switch (socket_option_key) {
-    case ProducerCallbacksOptions::INTEREST_INPUT:
-      on_interest_input_decrypted_ = socket_option_value;
-      return SOCKET_OPTION_SET;
-
-    case ProducerCallbacksOptions::INTEREST_DROP:
-      on_interest_dropped_input_buffer_ = socket_option_value;
-      return SOCKET_OPTION_SET;
-
-    case ProducerCallbacksOptions::INTEREST_PASS:
-      on_interest_inserted_input_buffer_ = socket_option_value;
-      return SOCKET_OPTION_SET;
-
-    case ProducerCallbacksOptions::CACHE_HIT:
-      on_interest_satisfied_output_buffer_ = socket_option_value;
-      return SOCKET_OPTION_SET;
-
-    case ProducerCallbacksOptions::CACHE_MISS:
-      on_interest_process_decrypted_ = socket_option_value;
-      return SOCKET_OPTION_SET;
-
-    default:
-      return SOCKET_OPTION_NOT_SET;
-  }
-}
-
-int P2PSecureProducerSocket::setSocketOption(
-    int socket_option_key,
-    const std::shared_ptr<auth::Signer> &socket_option_value) {
-  if (!list_producers.empty())
-    for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++)
-      (*it)->setSocketOption(socket_option_key, socket_option_value);
-
-  switch (socket_option_key) {
-    case GeneralTransportOptions::SIGNER: {
-      signer_.reset();
-      signer_ = socket_option_value;
-
-      return SOCKET_OPTION_SET;
-    }
-    default:
-      return SOCKET_OPTION_NOT_SET;
-  }
-}
-
-int P2PSecureProducerSocket::setSocketOption(int socket_option_key,
-                                             uint32_t socket_option_value) {
-  if (!list_producers.empty()) {
-    for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++)
-      (*it)->setSocketOption(socket_option_key, socket_option_value);
-  }
-  switch (socket_option_key) {
-    case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME:
-      content_object_expiry_time_ =
-          socket_option_value;  // HICN_HANDSHAKE_CONTENT_EXPIRY_TIME;
-      return SOCKET_OPTION_SET;
-  }
-  return ProducerSocket::setSocketOption(socket_option_key,
-                                         socket_option_value);
-}
-
-int P2PSecureProducerSocket::setSocketOption(int socket_option_key,
-                                             bool socket_option_value) {
-  if (!list_producers.empty())
-    for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++)
-      (*it)->setSocketOption(socket_option_key, socket_option_value);
-
-  return ProducerSocket::setSocketOption(socket_option_key,
-                                         socket_option_value);
-}
-
-int P2PSecureProducerSocket::setSocketOption(int socket_option_key,
-                                             Name *socket_option_value) {
-  if (!list_producers.empty())
-    for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++)
-      (*it)->setSocketOption(socket_option_key, socket_option_value);
-
-  return ProducerSocket::setSocketOption(socket_option_key,
-                                         socket_option_value);
-}
-
-int P2PSecureProducerSocket::setSocketOption(
-    int socket_option_key, ProducerContentObjectCallback socket_option_value) {
-  if (!list_producers.empty())
-    for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++)
-      (*it)->setSocketOption(socket_option_key, socket_option_value);
-
-  return ProducerSocket::setSocketOption(socket_option_key,
-                                         socket_option_value);
-}
-
-int P2PSecureProducerSocket::setSocketOption(
-    int socket_option_key, ProducerContentCallback socket_option_value) {
-  if (!list_producers.empty())
-    for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++)
-      (*it)->setSocketOption(socket_option_key, socket_option_value);
-
-  switch (socket_option_key) {
-    case ProducerCallbacksOptions::CONTENT_PRODUCED:
-      on_content_produced_application_ = socket_option_value;
-      break;
-
-    default:
-      return SOCKET_OPTION_NOT_SET;
-  }
-
-  return SOCKET_OPTION_SET;
-}
-
-int P2PSecureProducerSocket::setSocketOption(
-    int socket_option_key, auth::CryptoHashType socket_option_value) {
-  if (!list_producers.empty())
-    for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++)
-      (*it)->setSocketOption(socket_option_key, socket_option_value);
-
-  return ProducerSocket::setSocketOption(socket_option_key,
-                                         socket_option_value);
-}
-
-int P2PSecureProducerSocket::setSocketOption(
-    int socket_option_key, const std::string &socket_option_value) {
-  if (!list_producers.empty())
-    for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++)
-      (*it)->setSocketOption(socket_option_key, socket_option_value);
-
-  return ProducerSocket::setSocketOption(socket_option_key,
-                                         socket_option_value);
-}
-
-}  // namespace implementation
-}  // namespace transport
diff --git a/libtransport/src/implementation/p2psecure_socket_producer.h b/libtransport/src/implementation/p2psecure_socket_producer.h
deleted file mode 100644 (file)
index 00f407a..0000000
+++ /dev/null
@@ -1,114 +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.
- */
-
-#pragma once
-
-#include <hicn/transport/auth/signer.h>
-#include <implementation/socket_producer.h>
-// #include <implementation/tls_rtc_socket_producer.h>
-#include <implementation/tls_socket_producer.h>
-#include <openssl/ssl.h>
-#include <utils/content_store.h>
-
-#include <condition_variable>
-#include <forward_list>
-#include <mutex>
-
-namespace transport {
-namespace implementation {
-
-class P2PSecureProducerSocket : public ProducerSocket {
-  friend class TLSProducerSocket;
-  // TODO
-  //   friend class TLSRTCProducerSocket;
-
- public:
-  explicit P2PSecureProducerSocket(interface::ProducerSocket *producer_socket);
-
-  explicit P2PSecureProducerSocket(interface::ProducerSocket *producer_socket,
-                                   bool rtc, std::string &keystore_path,
-                                   std::string &keystore_pwd);
-
-  ~P2PSecureProducerSocket();
-
-  uint32_t produceDatagram(const Name &content_name,
-                           std::unique_ptr<utils::MemBuf> &&buffer) override;
-
-  uint32_t produceStream(const Name &content_name, const uint8_t *buffer,
-                         size_t buffer_size, bool is_last = true,
-                         uint32_t start_offset = 0) override;
-
-  uint32_t produceStream(const Name &content_name,
-                         std::unique_ptr<utils::MemBuf> &&buffer,
-                         bool is_last = true,
-                         uint32_t start_offset = 0) override;
-
-  int setSocketOption(int socket_option_key,
-                      ProducerInterestCallback socket_option_value) override;
-
-  int setSocketOption(
-      int socket_option_key,
-      const std::shared_ptr<auth::Signer> &socket_option_value) override;
-
-  int setSocketOption(int socket_option_key,
-                      uint32_t socket_option_value) override;
-
-  int setSocketOption(int socket_option_key, bool socket_option_value) override;
-
-  int setSocketOption(int socket_option_key,
-                      Name *socket_option_value) override;
-
-  int setSocketOption(
-      int socket_option_key,
-      ProducerContentObjectCallback socket_option_value) override;
-
-  int setSocketOption(int socket_option_key,
-                      ProducerContentCallback socket_option_value) override;
-
-  int setSocketOption(int socket_option_key,
-                      auth::CryptoHashType socket_option_value) override;
-
-  int setSocketOption(int socket_option_key,
-                      const std::string &socket_option_value) override;
-
-  using ProducerSocket::getSocketOption;
-  //   using ProducerSocket::onInterest;
-
- protected:
-  /* Callback invoked once an interest has been received and its payload
-   * decrypted */
-  ProducerInterestCallback on_interest_input_decrypted_;
-  ProducerInterestCallback on_interest_process_decrypted_;
-  ProducerContentCallback on_content_produced_application_;
-
- private:
-  bool rtc_;
-  std::mutex mtx_;
-  /* Condition variable for the wait */
-  std::condition_variable cv_;
-  X509 *cert_509_;
-  EVP_PKEY *pkey_rsa_;
-  std::unordered_map<core::Name, std::unique_ptr<TLSProducerSocket>,
-                     core::hash<core::Name>, core::compare2<core::Name>>
-      map_producers;
-  std::list<std::unique_ptr<TLSProducerSocket>> list_producers;
-
-  void onInterestCallback(interface::ProducerSocket &p, Interest &interest);
-
-  void initSessionSocket(std::unique_ptr<TLSProducerSocket> &producer);
-};
-
-}  // namespace implementation
-}  // namespace transport
index 95941da..b80fbb5 100644 (file)
@@ -23,7 +23,9 @@ namespace implementation {
 Socket::Socket(std::shared_ptr<core::Portal> &&portal)
     : portal_(std::move(portal)),
       is_async_(false),
-      packet_format_(interface::default_values::packet_format) {}
+      packet_format_(interface::default_values::packet_format),
+      signer_(std::make_shared<auth::VoidSigner>()),
+      verifier_(std::make_shared<auth::VoidVerifier>()) {}
 
 int Socket::setSocketOption(int socket_option_key,
                             hicn_format_t packet_format) {
index 11c9a70..3eb93cf 100644 (file)
@@ -16,6 +16,8 @@
 #pragma once
 
 #include <core/facade.h>
+#include <hicn/transport/auth/signer.h>
+#include <hicn/transport/auth/verifier.h>
 #include <hicn/transport/config.h>
 #include <hicn/transport/interfaces/callbacks.h>
 #include <hicn/transport/interfaces/socket_options_default_values.h>
@@ -68,6 +70,8 @@ class Socket {
   std::shared_ptr<core::Portal> portal_;
   bool is_async_;
   hicn_format_t packet_format_;
+  std::shared_ptr<auth::Signer> signer_;
+  std::shared_ptr<auth::Verifier> verifier_;
 };
 
 }  // namespace implementation
index 33e7088..4721f42 100644 (file)
@@ -56,8 +56,8 @@ class ConsumerSocket : public Socket {
         rate_estimation_observer_(nullptr),
         rate_estimation_batching_parameter_(default_values::batch),
         rate_estimation_choice_(0),
-        unverified_interval_(default_values::unverified_interval),
-        unverified_ratio_(default_values::unverified_ratio),
+        manifest_factor_relevant_(default_values::manifest_factor_relevant),
+        manifest_factor_alert_(default_values::manifest_factor_alert),
         verifier_(std::make_shared<auth::VoidVerifier>()),
         verify_signature_(false),
         reset_window_(false),
@@ -72,6 +72,8 @@ class ConsumerSocket : public Socket {
         timer_interval_milliseconds_(0),
         recovery_strategy_(RtcTransportRecoveryStrategies::RTX_ONLY),
         aggregated_data_(false),
+        content_sharing_mode_(false),
+        aggregated_interests_(false),
         guard_raaqm_params_() {
     switch (protocol) {
       case TransportProtocolAlgorithms::CBR:
@@ -197,10 +199,6 @@ class ConsumerSocket : public Socket {
         current_window_size_ = socket_option_value;
         break;
 
-      case UNVERIFIED_RATIO:
-        unverified_ratio_ = socket_option_value;
-        break;
-
       case GAMMA_VALUE:
         gamma_ = socket_option_value;
         break;
@@ -242,10 +240,6 @@ class ConsumerSocket : public Socket {
         interest_lifetime_ = socket_option_value;
         break;
 
-      case GeneralTransportOptions::UNVERIFIED_INTERVAL:
-        unverified_interval_ = socket_option_value;
-        break;
-
       case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER:
         if (socket_option_value > 0) {
           rate_estimation_batching_parameter_ = socket_option_value;
@@ -271,6 +265,14 @@ class ConsumerSocket : public Socket {
             (RtcTransportRecoveryStrategies)socket_option_value;
         break;
 
+      case MANIFEST_FACTOR_RELEVANT:
+        manifest_factor_relevant_ = socket_option_value;
+        break;
+
+      case MANIFEST_FACTOR_ALERT:
+        manifest_factor_alert_ = socket_option_value;
+        break;
+
       default:
         return SOCKET_OPTION_NOT_SET;
     }
@@ -339,6 +341,16 @@ class ConsumerSocket : public Socket {
           result = SOCKET_OPTION_SET;
           break;
 
+        case RtcTransportOptions::CONTENT_SHARING_MODE:
+          content_sharing_mode_ = socket_option_value;
+          result = SOCKET_OPTION_SET;
+          break;
+
+        case RtcTransportOptions::AGGREGATED_INTERESTS:
+          aggregated_interests_ = socket_option_value;
+          result = SOCKET_OPTION_SET;
+          break;
+
         default:
           return result;
       }
@@ -414,6 +426,22 @@ class ConsumerSocket : public Socket {
     return SOCKET_OPTION_SET;
   }
 
+  int setSocketOption(
+      int socket_option_key,
+      const std::shared_ptr<auth::Signer> &socket_option_value) {
+    if (!transport_protocol_->isRunning()) {
+      switch (socket_option_key) {
+        case GeneralTransportOptions::SIGNER:
+          signer_.reset();
+          signer_ = socket_option_value;
+          break;
+        default:
+          return SOCKET_OPTION_NOT_SET;
+      }
+    }
+    return SOCKET_OPTION_SET;
+  }
+
   int setSocketOption(
       int socket_option_key,
       const std::shared_ptr<auth::Verifier> &socket_option_value) {
@@ -506,10 +534,6 @@ class ConsumerSocket : public Socket {
         socket_option_value = current_window_size_;
         break;
 
-      case GeneralTransportOptions::UNVERIFIED_RATIO:
-        socket_option_value = unverified_ratio_;
-        break;
-
         // RAAQM parameters
 
       case RaaqmTransportOptions::GAMMA_VALUE:
@@ -550,10 +574,6 @@ class ConsumerSocket : public Socket {
         socket_option_value = interest_lifetime_;
         break;
 
-      case GeneralTransportOptions::UNVERIFIED_INTERVAL:
-        socket_option_value = unverified_interval_;
-        break;
-
       case RaaqmTransportOptions::SAMPLE_NUMBER:
         socket_option_value = sample_number_;
         break;
@@ -574,6 +594,14 @@ class ConsumerSocket : public Socket {
         socket_option_value = recovery_strategy_;
         break;
 
+      case GeneralTransportOptions::MANIFEST_FACTOR_RELEVANT:
+        socket_option_value = manifest_factor_relevant_;
+        break;
+
+      case GeneralTransportOptions::MANIFEST_FACTOR_ALERT:
+        socket_option_value = manifest_factor_alert_;
+        break;
+
       default:
         return SOCKET_OPTION_NOT_GET;
     }
@@ -599,6 +627,14 @@ class ConsumerSocket : public Socket {
         socket_option_value = aggregated_data_;
         break;
 
+      case RtcTransportOptions::CONTENT_SHARING_MODE:
+        socket_option_value = content_sharing_mode_;
+        break;
+
+      case RtcTransportOptions::AGGREGATED_INTERESTS:
+        socket_option_value = aggregated_interests_;
+        break;
+
       default:
         return SOCKET_OPTION_NOT_GET;
     }
@@ -688,6 +724,18 @@ class ConsumerSocket : public Socket {
     return SOCKET_OPTION_GET;
   }
 
+  int getSocketOption(int socket_option_key,
+                      std::shared_ptr<auth::Signer> &socket_option_value) {
+    switch (socket_option_key) {
+      case GeneralTransportOptions::SIGNER:
+        socket_option_value = signer_;
+        return SOCKET_OPTION_GET;
+
+      default:
+        return SOCKET_OPTION_NOT_GET;
+    }
+  }
+
   int getSocketOption(int socket_option_key,
                       std::shared_ptr<auth::Verifier> &socket_option_value) {
     switch (socket_option_key) {
@@ -827,8 +875,8 @@ class ConsumerSocket : public Socket {
   int rate_estimation_choice_;
 
   // Verification parameters
-  uint32_t unverified_interval_;
-  double unverified_ratio_;
+  uint32_t manifest_factor_relevant_;
+  uint32_t manifest_factor_alert_;
   std::shared_ptr<auth::Verifier> verifier_;
   transport::auth::KeyId *key_id_;
   std::atomic_bool verify_signature_;
@@ -856,6 +904,8 @@ class ConsumerSocket : public Socket {
   // RTC protocol
   RtcTransportRecoveryStrategies recovery_strategy_;
   bool aggregated_data_;
+  bool content_sharing_mode_;
+  bool aggregated_interests_;
 
   utils::SpinLock guard_raaqm_params_;
   std::string output_interface_;
index 37151d4..53ce287 100644 (file)
@@ -51,9 +51,8 @@ class ProducerSocket : public Socket {
         data_packet_size_(default_values::content_object_packet_size),
         max_segment_size_(default_values::content_object_packet_size),
         content_object_expiry_time_(default_values::content_object_expiry_time),
-        making_manifest_(default_values::manifest_capacity),
+        manifest_max_capacity_(default_values::manifest_max_capacity),
         hash_algorithm_(auth::CryptoHashType::SHA256),
-        signer_(std::make_shared<auth::VoidSigner>()),
         suffix_strategy_(std::make_shared<utils::IncrementalSuffixStrategy>(0)),
         aggregated_data_(false),
         fec_setting_(""),
@@ -181,8 +180,8 @@ class ProducerSocket : public Socket {
         }
         break;
 
-      case GeneralTransportOptions::MAKE_MANIFEST:
-        making_manifest_ = socket_option_value;
+      case GeneralTransportOptions::MANIFEST_MAX_CAPACITY:
+        manifest_max_capacity_ = socket_option_value;
         break;
 
       case GeneralTransportOptions::MAX_SEGMENT_SIZE:
@@ -433,6 +432,20 @@ class ProducerSocket : public Socket {
     return SOCKET_OPTION_SET;
   }
 
+  virtual int setSocketOption(
+      int socket_option_key,
+      const std::shared_ptr<auth::Verifier> &socket_option_value) {
+    switch (socket_option_key) {
+      case GeneralTransportOptions::VERIFIER:
+        verifier_.reset();
+        verifier_ = socket_option_value;
+        return SOCKET_OPTION_SET;
+
+      default:
+        return SOCKET_OPTION_NOT_SET;
+    }
+  }
+
   int getSocketOption(int socket_option_key,
                       ProducerCallback **socket_option_value) {
     // Reschedule the function on the io_service to avoid race condition in
@@ -456,12 +469,13 @@ class ProducerSocket : public Socket {
   virtual int getSocketOption(int socket_option_key,
                               uint32_t &socket_option_value) {
     switch (socket_option_key) {
-      case GeneralTransportOptions::MAKE_MANIFEST:
-        socket_option_value = making_manifest_;
+      case GeneralTransportOptions::MANIFEST_MAX_CAPACITY:
+        socket_option_value = (uint32_t)manifest_max_capacity_;
         break;
 
       case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
-        socket_option_value = production_protocol_->getOutputBufferSize();
+        socket_option_value =
+            (uint32_t)production_protocol_->getOutputBufferSize();
         break;
 
       case GeneralTransportOptions::DATA_PACKET_SIZE:
@@ -636,6 +650,18 @@ class ProducerSocket : public Socket {
     return SOCKET_OPTION_GET;
   }
 
+  int getSocketOption(int socket_option_key,
+                      std::shared_ptr<auth::Verifier> &socket_option_value) {
+    switch (socket_option_key) {
+      case GeneralTransportOptions::VERIFIER:
+        socket_option_value = verifier_;
+        return SOCKET_OPTION_GET;
+
+      default:
+        return SOCKET_OPTION_NOT_GET;
+    }
+  }
+
   int getSocketOption(int socket_option_key, std::string &socket_option_value) {
     switch (socket_option_key) {
       case GeneralTransportOptions::FEC_TYPE:
@@ -736,11 +762,10 @@ class ProducerSocket : public Socket {
   std::atomic<size_t> max_segment_size_;
   std::atomic<uint32_t> content_object_expiry_time_;
 
-  std::atomic<uint32_t> making_manifest_;
+  std::atomic<uint32_t> manifest_max_capacity_;
   std::atomic<auth::CryptoHashType> hash_algorithm_;
   std::atomic<auth::CryptoSuite> crypto_suite_;
   utils::SpinLock signer_lock_;
-  std::shared_ptr<auth::Signer> signer_;
   std::shared_ptr<utils::SuffixStrategy> suffix_strategy_;
 
   std::shared_ptr<protocol::ProductionProtocol> production_protocol_;
diff --git a/libtransport/src/implementation/tls_rtc_socket_producer.cc b/libtransport/src/implementation/tls_rtc_socket_producer.cc
deleted file mode 100644 (file)
index 06d613e..0000000
+++ /dev/null
@@ -1,208 +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.
- */
-
-#include <hicn/transport/core/interest.h>
-#include <hicn/transport/interfaces/p2psecure_socket_producer.h>
-#include <implementation/p2psecure_socket_producer.h>
-#include <implementation/tls_rtc_socket_producer.h>
-#include <openssl/bio.h>
-#include <openssl/rand.h>
-#include <openssl/ssl.h>
-
-namespace transport {
-namespace implementation {
-
-int TLSRTCProducerSocket::read(BIO *b, char *buf, size_t size,
-                               size_t *readbytes) {
-  int ret;
-
-  if (size > INT_MAX) size = INT_MAX;
-
-  ret = TLSRTCProducerSocket::readOld(b, buf, (int)size);
-
-  if (ret <= 0) {
-    *readbytes = 0;
-    return ret;
-  }
-
-  *readbytes = (size_t)ret;
-
-  return 1;
-}
-
-int TLSRTCProducerSocket::readOld(BIO *b, char *buf, int size) {
-  TLSRTCProducerSocket *socket;
-  socket = (TLSRTCProducerSocket *)BIO_get_data(b);
-
-  std::unique_lock<std::mutex> lck(socket->mtx_);
-  if (!socket->something_to_read_) {
-    (socket->cv_).wait(lck);
-  }
-
-  utils::MemBuf *membuf = socket->handshake_packet_->next();
-  int size_to_read;
-
-  if ((int)membuf->length() > size) {
-    size_to_read = size;
-  } else {
-    size_to_read = membuf->length();
-    socket->something_to_read_ = false;
-  }
-
-  std::memcpy(buf, membuf->data(), size_to_read);
-  membuf->trimStart(size_to_read);
-
-  return size_to_read;
-}
-
-int TLSRTCProducerSocket::write(BIO *b, const char *buf, size_t size,
-                                size_t *written) {
-  int ret;
-
-  if (size > INT_MAX) size = INT_MAX;
-
-  ret = TLSRTCProducerSocket::writeOld(b, buf, (int)size);
-
-  if (ret <= 0) {
-    *written = 0;
-    return ret;
-  }
-
-  *written = (size_t)ret;
-
-  return 1;
-}
-
-int TLSRTCProducerSocket::writeOld(BIO *b, const char *buf, int num) {
-  TLSRTCProducerSocket *socket;
-  socket = (TLSRTCProducerSocket *)BIO_get_data(b);
-
-  if (socket->getHandshakeState() != SERVER_FINISHED && socket->first_) {
-    uint32_t making_manifest = socket->parent_->making_manifest_;
-
-    socket->tls_chunks_--;
-    socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST,
-                                     0U);
-    socket->parent_->ProducerSocket::produce(
-        socket->name_, (const uint8_t *)buf, num, socket->tls_chunks_ == 0, 0);
-    socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST,
-                                     making_manifest);
-    socket->first_ = false;
-
-  } else {
-    std::unique_ptr<utils::MemBuf> mbuf =
-        utils::MemBuf::copyBuffer(buf, (std::size_t)num, 0, 0);
-    auto a = mbuf.release();
-
-    socket->async_thread_.add([socket = socket, a]() {
-      socket->to_call_oncontentproduced_--;
-      auto mbuf = std::unique_ptr<utils::MemBuf>(a);
-
-      socket->RTCProducerSocket::produce(std::move(mbuf));
-
-      ProducerContentCallback on_content_produced_application;
-      socket->getSocketOption(ProducerCallbacksOptions::CONTENT_PRODUCED,
-                              on_content_produced_application);
-
-      if (socket->to_call_oncontentproduced_ == 0 &&
-          on_content_produced_application) {
-        on_content_produced_application(
-            (transport::interface::ProducerSocket &)(*socket->getInterface()),
-            std::error_code(), 0);
-      }
-    });
-  }
-
-  return num;
-}
-
-TLSRTCProducerSocket::TLSRTCProducerSocket(
-    interface::ProducerSocket *producer_socket, P2PSecureProducerSocket *parent,
-    const Name &handshake_name)
-    : ProducerSocket(producer_socket),
-      RTCProducerSocket(producer_socket),
-      TLSProducerSocket(producer_socket, parent, handshake_name) {
-  BIO_METHOD *bio_meth =
-      BIO_meth_new(BIO_TYPE_ACCEPT, "secure rtc producer socket");
-  BIO_meth_set_read(bio_meth, TLSRTCProducerSocket::readOld);
-  BIO_meth_set_write(bio_meth, TLSRTCProducerSocket::writeOld);
-  BIO_meth_set_ctrl(bio_meth, TLSProducerSocket::ctrl);
-  BIO *bio = BIO_new(bio_meth);
-  BIO_set_init(bio, 1);
-  BIO_set_data(bio, this);
-  SSL_set_bio(ssl_, bio, bio);
-}
-
-void TLSRTCProducerSocket::accept() {
-  HandshakeState handshake_state = getHandshakeState();
-
-  if (handshake_state == UNINITIATED || handshake_state == CLIENT_HELLO) {
-    tls_chunks_ = 1;
-    int result = SSL_accept(ssl_);
-
-    if (result != 1)
-      throw errors::RuntimeException("Unable to perform client handshake");
-  }
-
-  DLOG_IF(INFO, VLOG_IS_ON(2)) << "Handshake performed!";
-
-  parent_->list_producers.push_front(
-      std::move(parent_->map_producers[handshake_name_]));
-  parent_->map_producers.erase(handshake_name_);
-
-  ProducerInterestCallback on_interest_process_decrypted;
-  getSocketOption(ProducerCallbacksOptions::CACHE_MISS,
-                  on_interest_process_decrypted);
-
-  if (on_interest_process_decrypted) {
-    Interest inter(std::move(handshake_packet_));
-    on_interest_process_decrypted(
-        (transport::interface::ProducerSocket &)(*getInterface()), inter);
-  }
-
-  parent_->cv_.notify_one();
-}
-
-int TLSRTCProducerSocket::async_accept() {
-  if (!async_thread_.stopped()) {
-    async_thread_.add([this]() { this->TLSRTCProducerSocket::accept(); });
-  } else {
-    throw errors::RuntimeException(
-        "Async thread not running, impossible to perform handshake");
-  }
-
-  return 1;
-}
-
-void TLSRTCProducerSocket::produce(std::unique_ptr<utils::MemBuf> &&buffer) {
-  HandshakeState handshake_state = getHandshakeState();
-
-  if (handshake_state != SERVER_FINISHED) {
-    throw errors::RuntimeException(
-        "New handshake on the same P2P secure producer socket not supported");
-  }
-
-  size_t buf_size = buffer->length();
-  tls_chunks_ = ceil((float)buf_size / (float)SSL3_RT_MAX_PLAIN_LENGTH);
-  to_call_oncontentproduced_ = tls_chunks_;
-
-  SSL_write(ssl_, buffer->data(), buf_size);
-  BIO *wbio = SSL_get_wbio(ssl_);
-  int i = BIO_flush(wbio);
-  (void)i;  // To shut up gcc 5
-}
-
-}  // namespace implementation
-}  // namespace transport
diff --git a/libtransport/src/implementation/tls_rtc_socket_producer.h b/libtransport/src/implementation/tls_rtc_socket_producer.h
deleted file mode 100644 (file)
index f6dc425..0000000
+++ /dev/null
@@ -1,57 +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.
- */
-
-#pragma once
-
-#include <implementation/tls_socket_producer.h>
-
-namespace transport {
-namespace implementation {
-
-class P2PSecureProducerSocket;
-
-class TLSRTCProducerSocket : public TLSProducerSocket {
-  friend class P2PSecureProducerSocket;
-
- public:
-  explicit TLSRTCProducerSocket(interface::ProducerSocket *producer_socket,
-                                P2PSecureProducerSocket *parent,
-                                const Name &handshake_name);
-
-  ~TLSRTCProducerSocket() = default;
-
-  uint32_t produceDatagram(const Name &content_name,
-                           std::unique_ptr<utils::MemBuf> &&buffer) override;
-
-  void accept() override;
-
-  int async_accept() override;
-
-  using TLSProducerSocket::onInterest;
-  using TLSProducerSocket::produce;
-
- protected:
-  static int read(BIO *b, char *buf, size_t size, size_t *readbytes);
-
-  static int readOld(BIO *h, char *buf, int size);
-
-  static int write(BIO *b, const char *buf, size_t size, size_t *written);
-
-  static int writeOld(BIO *h, const char *buf, int num);
-};
-
-}  // namespace implementation
-
-}  // end namespace transport
diff --git a/libtransport/src/implementation/tls_socket_consumer.cc b/libtransport/src/implementation/tls_socket_consumer.cc
deleted file mode 100644 (file)
index b368c4b..0000000
+++ /dev/null
@@ -1,343 +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.
- */
-
-#include <implementation/tls_socket_consumer.h>
-#include <openssl/bio.h>
-#include <openssl/ssl.h>
-#include <openssl/tls1.h>
-
-#include <random>
-
-namespace transport {
-namespace implementation {
-
-void TLSConsumerSocket::setInterestPayload(interface::ConsumerSocket &c,
-                                           const core::Interest &interest) {
-  Interest &int2 = const_cast<Interest &>(interest);
-  random_suffix_ = int2.getName().getSuffix();
-
-  if (payload_ != NULL) int2.appendPayload(std::move(payload_));
-}
-
-/* Return the number of read bytes in the return param */
-int readOldTLS(BIO *b, char *buf, int size) {
-  if (size < 0) return size;
-
-  TLSConsumerSocket *socket;
-  socket = (TLSConsumerSocket *)BIO_get_data(b);
-
-  std::unique_lock<std::mutex> lck(socket->mtx_);
-
-  if (!socket->something_to_read_) {
-    if (!socket->transport_protocol_->isRunning()) {
-      socket->network_name_.setSuffix(socket->random_suffix_);
-      socket->ConsumerSocket::consume(socket->network_name_);
-    }
-
-    if (!socket->something_to_read_) socket->cv_.wait(lck);
-  }
-
-  size_t size_to_read, read;
-  size_t chain_size = socket->head_->length();
-
-  if (socket->head_->isChained())
-    chain_size = socket->head_->computeChainDataLength();
-
-  if (chain_size > (size_t)size) {
-    read = size_to_read = (size_t)size;
-  } else {
-    read = size_to_read = chain_size;
-    socket->something_to_read_ = false;
-  }
-
-  while (size_to_read) {
-    if (socket->head_->length() < size_to_read) {
-      std::memcpy(buf, socket->head_->data(), socket->head_->length());
-      size_to_read -= socket->head_->length();
-      buf += socket->head_->length();
-      socket->head_ = socket->head_->pop();
-    } else {
-      std::memcpy(buf, socket->head_->data(), size_to_read);
-      socket->head_->trimStart(size_to_read);
-      size_to_read = 0;
-    }
-  }
-
-  return (int)read;
-}
-
-/* Return the number of read bytes in readbytes */
-int readTLS(BIO *b, char *buf, size_t size, size_t *readbytes) {
-  int ret;
-
-  if (size > INT_MAX) size = INT_MAX;
-
-  ret = readOldTLS(b, buf, (int)size);
-
-  if (ret <= 0) {
-    *readbytes = 0;
-    return ret;
-  }
-
-  *readbytes = (size_t)ret;
-
-  return 1;
-}
-
-/* Return the number of written bytes in the return param */
-int writeOldTLS(BIO *b, const char *buf, int num) {
-  TLSConsumerSocket *socket;
-  socket = (TLSConsumerSocket *)BIO_get_data(b);
-
-  socket->payload_ = utils::MemBuf::copyBuffer(buf, num);
-
-  socket->ConsumerSocket::setSocketOption(
-      ConsumerCallbacksOptions::INTEREST_OUTPUT,
-      (ConsumerInterestCallback)std::bind(
-          &TLSConsumerSocket::setInterestPayload, socket, std::placeholders::_1,
-          std::placeholders::_2));
-
-  return num;
-}
-
-/* Return the number of written bytes in written */
-int writeTLS(BIO *b, const char *buf, size_t size, size_t *written) {
-  int ret;
-
-  if (size > INT_MAX) size = INT_MAX;
-
-  ret = writeOldTLS(b, buf, (int)size);
-
-  if (ret <= 0) {
-    *written = 0;
-    return ret;
-  }
-
-  *written = (size_t)ret;
-
-  return 1;
-}
-
-long ctrlTLS(BIO *b, int cmd, long num, void *ptr) { return 1; }
-
-TLSConsumerSocket::TLSConsumerSocket(interface::ConsumerSocket *consumer_socket,
-                                     int protocol, SSL *ssl)
-    : ConsumerSocket(consumer_socket, protocol),
-      name_(),
-      decrypted_content_(),
-      payload_(),
-      head_(),
-      something_to_read_(false),
-      content_downloaded_(false),
-      random_suffix_(),
-      producer_namespace_(),
-      read_callback_decrypted_(),
-      mtx_(),
-      cv_(),
-      async_downloader_tls_() {
-  /* Create the (d)TLS state */
-  const SSL_METHOD *meth = TLS_client_method();
-  ctx_ = SSL_CTX_new(meth);
-
-  int result =
-      SSL_CTX_set_ciphersuites(ctx_,
-                               "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_"
-                               "SHA256:TLS_AES_128_GCM_SHA256");
-  if (result != 1) {
-    throw errors::RuntimeException(
-        "Unable to set cipher list on TLS subsystem. Aborting.");
-  }
-
-  SSL_CTX_set_min_proto_version(ctx_, TLS1_3_VERSION);
-  SSL_CTX_set_max_proto_version(ctx_, TLS1_3_VERSION);
-  SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, NULL);
-  SSL_CTX_set_ssl_version(ctx_, meth);
-
-  ssl_ = ssl;
-
-  BIO_METHOD *bio_meth =
-      BIO_meth_new(BIO_TYPE_CONNECT, "secure consumer socket");
-  BIO_meth_set_read(bio_meth, readOldTLS);
-  BIO_meth_set_write(bio_meth, writeOldTLS);
-  BIO_meth_set_ctrl(bio_meth, ctrlTLS);
-  BIO *bio = BIO_new(bio_meth);
-  BIO_set_init(bio, 1);
-  BIO_set_data(bio, this);
-  SSL_set_bio(ssl_, bio, bio);
-
-  std::default_random_engine generator;
-  std::uniform_int_distribution<int> distribution(
-      1, std::numeric_limits<uint32_t>::max());
-  random_suffix_ = 0;
-
-  this->ConsumerSocket::setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK,
-                                        this);
-};
-
-/* The producer interface is not owned by the application, so is TLSSocket task
- * to deallocate the memory */
-TLSConsumerSocket::~TLSConsumerSocket() { delete consumer_interface_; }
-
-int TLSConsumerSocket::consume(const Name &name,
-                               std::unique_ptr<utils::MemBuf> &&buffer) {
-  this->payload_ = std::move(buffer);
-
-  this->ConsumerSocket::setSocketOption(
-      ConsumerCallbacksOptions::INTEREST_OUTPUT,
-      (ConsumerInterestCallback)std::bind(
-          &TLSConsumerSocket::setInterestPayload, this, std::placeholders::_1,
-          std::placeholders::_2));
-
-  return consume(name);
-}
-
-int TLSConsumerSocket::consume(const Name &name) {
-  if (transport_protocol_->isRunning()) {
-    return CONSUMER_BUSY;
-  }
-
-  if ((SSL_in_before(this->ssl_) || SSL_in_init(this->ssl_))) {
-    throw errors::RuntimeException("Handshake not performed");
-  }
-
-  return download_content(name);
-}
-
-int TLSConsumerSocket::download_content(const Name &name) {
-  network_name_ = name;
-  network_name_.setSuffix(0);
-  something_to_read_ = false;
-  content_downloaded_ = false;
-
-  std::size_t max_buffer_size = read_callback_decrypted_->maxBufferSize();
-  std::size_t buffer_size =
-      read_callback_decrypted_->maxBufferSize() + SSL3_RT_MAX_PLAIN_LENGTH;
-  decrypted_content_ = utils::MemBuf::createCombined(buffer_size);
-  int result = -1;
-  std::size_t size = 0;
-
-  while (!content_downloaded_ || something_to_read_) {
-    result = SSL_read(this->ssl_, decrypted_content_->writableTail(),
-                      SSL3_RT_MAX_PLAIN_LENGTH);
-
-    /* SSL_read returns the data only if there were SSL3_RT_MAX_PLAIN_LENGTH of
-     * the data has been fully downloaded */
-
-    /* ASSERT((result < SSL3_RT_MAX_PLAIN_LENGTH && content_downloaded_) || */
-    /*         result == SSL3_RT_MAX_PLAIN_LENGTH); */
-
-    if (result >= 0) {
-      size += result;
-      decrypted_content_->append(result);
-    } else {
-      throw errors::RuntimeException("Unable to download content");
-    }
-
-    if (decrypted_content_->length() >= max_buffer_size) {
-      if (read_callback_decrypted_->isBufferMovable()) {
-        /* No need to perform an additional copy. The whole buffer will be
-         * tranferred to the application. */
-        read_callback_decrypted_->readBufferAvailable(
-            std::move(decrypted_content_));
-        decrypted_content_ = utils::MemBuf::create(buffer_size);
-      } else {
-        /* The buffer will be copied into the application-provided buffer */
-        uint8_t *buffer;
-        std::size_t length;
-        std::size_t total_length = decrypted_content_->length();
-
-        while (decrypted_content_->length()) {
-          buffer = nullptr;
-          length = 0;
-          read_callback_decrypted_->getReadBuffer(&buffer, &length);
-
-          if (!buffer || !length) {
-            throw errors::RuntimeException(
-                "Invalid buffer provided by the application.");
-          }
-
-          auto to_copy = std::min(decrypted_content_->length(), length);
-          std::memcpy(buffer, decrypted_content_->data(), to_copy);
-          decrypted_content_->trimStart(to_copy);
-        }
-
-        read_callback_decrypted_->readDataAvailable(total_length);
-        decrypted_content_->clear();
-      }
-    }
-  }
-
-  read_callback_decrypted_->readSuccess(size);
-
-  return CONSUMER_FINISHED;
-}
-
-void TLSConsumerSocket::registerPrefix(const Prefix &producer_namespace) {
-  producer_namespace_ = producer_namespace;
-}
-
-int TLSConsumerSocket::setSocketOption(int socket_option_key,
-                                       ReadCallback *socket_option_value) {
-  return rescheduleOnIOService(
-      socket_option_key, socket_option_value,
-      [this](int socket_option_key, ReadCallback *socket_option_value) -> int {
-        switch (socket_option_key) {
-          case ConsumerCallbacksOptions::READ_CALLBACK:
-            read_callback_decrypted_ = socket_option_value;
-            break;
-          default:
-            return SOCKET_OPTION_NOT_SET;
-        }
-
-        return SOCKET_OPTION_SET;
-      });
-}
-
-void TLSConsumerSocket::getReadBuffer(uint8_t **application_buffer,
-                                      size_t *max_length) {}
-
-void TLSConsumerSocket::readDataAvailable(size_t length) noexcept {}
-
-size_t TLSConsumerSocket::maxBufferSize() const {
-  return SSL3_RT_MAX_PLAIN_LENGTH;
-}
-
-void TLSConsumerSocket::readBufferAvailable(
-    std::unique_ptr<utils::MemBuf> &&buffer) noexcept {
-  std::unique_lock<std::mutex> lck(this->mtx_);
-
-  if (head_) {
-    head_->prependChain(std::move(buffer));
-  } else {
-    head_ = std::move(buffer);
-  }
-
-  something_to_read_ = true;
-  cv_.notify_one();
-}
-
-void TLSConsumerSocket::readError(const std::error_code &ec) noexcept {}
-
-void TLSConsumerSocket::readSuccess(std::size_t total_size) noexcept {
-  std::unique_lock<std::mutex> lck(this->mtx_);
-  content_downloaded_ = true;
-  something_to_read_ = true;
-  cv_.notify_one();
-}
-
-bool TLSConsumerSocket::isBufferMovable() noexcept { return true; }
-
-}  // namespace implementation
-}  // namespace transport
diff --git a/libtransport/src/implementation/tls_socket_consumer.h b/libtransport/src/implementation/tls_socket_consumer.h
deleted file mode 100644 (file)
index a74f1ee..0000000
+++ /dev/null
@@ -1,110 +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.
- */
-
-#pragma once
-
-#include <hicn/transport/interfaces/socket_consumer.h>
-#include <implementation/socket_consumer.h>
-#include <openssl/ssl.h>
-
-namespace transport {
-namespace implementation {
-
-class TLSConsumerSocket : public ConsumerSocket,
-                          public interface::ConsumerSocket::ReadCallback {
-  /* Return the number of read bytes in readbytes */
-  friend int readTLS(BIO *b, char *buf, size_t size, size_t *readbytes);
-
-  /* Return the number of read bytes in the return param */
-  friend int readOldTLS(BIO *h, char *buf, int size);
-
-  /* Return the number of written bytes in written */
-  friend int writeTLS(BIO *b, const char *buf, size_t size, size_t *written);
-
-  /* Return the number of written bytes in the return param */
-  friend int writeOldTLS(BIO *h, const char *buf, int num);
-
-  friend long ctrlTLS(BIO *b, int cmd, long num, void *ptr);
-
- public:
-  explicit TLSConsumerSocket(interface::ConsumerSocket *consumer_socket,
-                             int protocol, SSL *ssl_);
-
-  ~TLSConsumerSocket();
-
-  int consume(const Name &name, std::unique_ptr<utils::MemBuf> &&buffer);
-  int consume(const Name &name) override;
-
-  void registerPrefix(const Prefix &producer_namespace);
-
-  int setSocketOption(
-      int socket_option_key,
-      interface::ConsumerSocket::ReadCallback *socket_option_value) override;
-
-  using ConsumerSocket::getSocketOption;
-  using ConsumerSocket::setSocketOption;
-
- protected:
-  /* Callback invoked once an interest has been received and its payload
-   * decrypted */
-  ConsumerInterestCallback on_interest_input_decrypted_;
-  ConsumerInterestCallback on_interest_process_decrypted_;
-
- private:
-  Name name_;
-  /* SSL handle */
-  SSL *ssl_;
-  SSL_CTX *ctx_;
-  /* Chain of MemBuf to be used as a temporary buffer to pass descypted data
-   * from the underlying layer to the application */
-  std::unique_ptr<utils::MemBuf> decrypted_content_;
-  /* Chain of MemBuf holding the payload to be written into interest or data */
-  std::unique_ptr<utils::MemBuf> payload_;
-  /* Chain of MemBuf holding the data retrieved from the underlying layer */
-  std::unique_ptr<utils::MemBuf> head_;
-  bool something_to_read_;
-  bool content_downloaded_;
-  uint32_t random_suffix_;
-  Prefix producer_namespace_;
-  interface::ConsumerSocket::ReadCallback *read_callback_decrypted_;
-  std::mutex mtx_;
-  /* Condition variable for the wait */
-  std::condition_variable cv_;
-  utils::EventThread async_downloader_tls_;
-
-  void setInterestPayload(interface::ConsumerSocket &c,
-                          const core::Interest &interest);
-
-  virtual void getReadBuffer(uint8_t **application_buffer,
-                             size_t *max_length) override;
-
-  virtual void readDataAvailable(size_t length) noexcept override;
-
-  virtual size_t maxBufferSize() const override;
-
-  virtual void readBufferAvailable(
-      std::unique_ptr<utils::MemBuf> &&buffer) noexcept override;
-
-  virtual void readError(const std::error_code &ec) noexcept override;
-
-  virtual void readSuccess(std::size_t total_size) noexcept override;
-
-  virtual bool isBufferMovable() noexcept override;
-
-  int download_content(const Name &name);
-};
-
-}  // namespace implementation
-}  // end namespace transport
diff --git a/libtransport/src/implementation/tls_socket_producer.cc b/libtransport/src/implementation/tls_socket_producer.cc
deleted file mode 100644 (file)
index 47f3b43..0000000
+++ /dev/null
@@ -1,550 +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.
- */
-
-#include <hicn/transport/interfaces/socket_producer.h>
-#include <implementation/p2psecure_socket_producer.h>
-#include <implementation/tls_socket_producer.h>
-#include <openssl/bio.h>
-#include <openssl/rand.h>
-#include <openssl/ssl.h>
-
-namespace transport {
-namespace implementation {
-
-/* Return the number of read bytes in readbytes */
-int TLSProducerSocket::read(BIO *b, char *buf, size_t size, size_t *readbytes) {
-  int ret;
-
-  if (size > INT_MAX) size = INT_MAX;
-
-  ret = TLSProducerSocket::readOld(b, buf, (int)size);
-
-  if (ret <= 0) {
-    *readbytes = 0;
-    return ret;
-  }
-
-  *readbytes = (size_t)ret;
-
-  return 1;
-}
-
-/* Return the number of read bytes in the return param */
-int TLSProducerSocket::readOld(BIO *b, char *buf, int size) {
-  TLSProducerSocket *socket;
-  socket = (TLSProducerSocket *)BIO_get_data(b);
-
-  std::unique_lock<std::mutex> lck(socket->mtx_);
-
-  DLOG_IF(INFO, VLOG_IS_ON(4)) << "Start wait on the CV.";
-
-  if (!socket->something_to_read_) {
-    (socket->cv_).wait(lck);
-  }
-
-  DLOG_IF(INFO, VLOG_IS_ON(4)) << "CV unlocked.";
-
-  /* Either there already is something to read, or the thread has been waken up.
-   * We must return the payload in the interest anyway */
-  utils::MemBuf *membuf = socket->handshake_packet_->next();
-  int size_to_read;
-
-  if ((int)membuf->length() > size) {
-    size_to_read = size;
-  } else {
-    size_to_read = (int)membuf->length();
-    socket->something_to_read_ = false;
-  }
-
-  std::memcpy(buf, membuf->data(), size_to_read);
-  membuf->trimStart(size_to_read);
-
-  return size_to_read;
-}
-
-/* Return the number of written bytes in written */
-int TLSProducerSocket::write(BIO *b, const char *buf, size_t size,
-                             size_t *written) {
-  int ret;
-
-  if (size > INT_MAX) size = INT_MAX;
-
-  ret = TLSProducerSocket::writeOld(b, buf, (int)size);
-
-  if (ret <= 0) {
-    *written = 0;
-    return ret;
-  }
-
-  *written = (size_t)ret;
-
-  return 1;
-}
-
-/* Return the number of written bytes in the return param */
-int TLSProducerSocket::writeOld(BIO *b, const char *buf, int num) {
-  TLSProducerSocket *socket;
-  socket = (TLSProducerSocket *)BIO_get_data(b);
-
-  if (socket->getHandshakeState() != SERVER_FINISHED && socket->first_) {
-    uint32_t making_manifest = socket->parent_->making_manifest_;
-
-    //! socket->tls_chunks_ corresponds to is_last
-    socket->tls_chunks_--;
-    socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST,
-                                     0U);
-    socket->parent_->ProducerSocket::produceStream(
-        socket->name_, (const uint8_t *)buf, num, socket->tls_chunks_ == 0,
-        socket->last_segment_);
-    socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST,
-                                     making_manifest);
-    socket->first_ = false;
-  } else {
-    socket->still_writing_ = true;
-
-    std::unique_ptr<utils::MemBuf> mbuf =
-        utils::MemBuf::copyBuffer(buf, (std::size_t)num, 0, 0);
-    auto a = mbuf.release();
-
-    socket->async_thread_.add([socket = socket, a]() {
-      auto mbuf = std::unique_ptr<utils::MemBuf>(a);
-
-      socket->tls_chunks_--;
-      socket->to_call_oncontentproduced_--;
-
-      socket->last_segment_ += socket->ProducerSocket::produceStream(
-          socket->name_, std::move(mbuf), socket->tls_chunks_ == 0,
-          socket->last_segment_);
-
-      ProducerContentCallback *on_content_produced_application;
-      socket->getSocketOption(ProducerCallbacksOptions::CONTENT_PRODUCED,
-                              &on_content_produced_application);
-
-      if (socket->to_call_oncontentproduced_ == 0 &&
-          on_content_produced_application) {
-        on_content_produced_application->operator()(*socket->getInterface(),
-                                                    std::error_code(), 0);
-      }
-    });
-  }
-
-  return num;
-}
-
-TLSProducerSocket::TLSProducerSocket(interface::ProducerSocket *producer_socket,
-                                     P2PSecureProducerSocket *parent,
-                                     const Name &handshake_name)
-    : ProducerSocket(producer_socket,
-                     ProductionProtocolAlgorithms::BYTE_STREAM),
-      on_content_produced_application_(),
-      mtx_(),
-      cv_(),
-      something_to_read_(false),
-      handshake_state_(UNINITIATED),
-      name_(),
-      handshake_packet_(),
-      last_segment_(0),
-      parent_(parent),
-      first_(true),
-      handshake_name_(handshake_name),
-      tls_chunks_(0),
-      to_call_oncontentproduced_(0),
-      still_writing_(false),
-      encryption_thread_() {
-  const SSL_METHOD *meth = TLS_server_method();
-  ctx_ = SSL_CTX_new(meth);
-
-  /* Setup SSL context (identity and parameter to use TLS 1.3) */
-  SSL_CTX_use_certificate(ctx_, parent->cert_509_);
-  SSL_CTX_use_PrivateKey(ctx_, parent->pkey_rsa_);
-
-  int result =
-      SSL_CTX_set_ciphersuites(ctx_,
-                               "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_"
-                               "SHA256:TLS_AES_128_GCM_SHA256");
-
-  if (result != 1) {
-    throw errors::RuntimeException(
-        "Unable to set cipher list on TLS subsystem. Aborting.");
-  }
-
-  // We force it to be TLS 1.3
-  SSL_CTX_set_min_proto_version(ctx_, TLS1_3_VERSION);
-  SSL_CTX_set_max_proto_version(ctx_, TLS1_3_VERSION);
-  SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, NULL);
-  SSL_CTX_set_num_tickets(ctx_, 0);
-
-  result = SSL_CTX_add_custom_ext(
-      ctx_, 100, SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
-      TLSProducerSocket::addHicnKeyIdCb, TLSProducerSocket::freeHicnKeyIdCb,
-      this, TLSProducerSocket::parseHicnKeyIdCb, NULL);
-
-  ssl_ = SSL_new(ctx_);
-
-  /* Setup this producer socker as the bio that TLS will use to write and read
-   * data (in stream mode) */
-  BIO_METHOD *bio_meth =
-      BIO_meth_new(BIO_TYPE_ACCEPT, "secure producer socket");
-  BIO_meth_set_read(bio_meth, TLSProducerSocket::readOld);
-  BIO_meth_set_write(bio_meth, TLSProducerSocket::writeOld);
-  BIO_meth_set_ctrl(bio_meth, TLSProducerSocket::ctrl);
-  BIO *bio = BIO_new(bio_meth);
-  BIO_set_init(bio, 1);
-  BIO_set_data(bio, this);
-  SSL_set_bio(ssl_, bio, bio);
-
-  /* Set the callback so that when an interest is received we catch it and we
-   * decrypt the payload before passing it to the application.  */
-  this->ProducerSocket::setSocketOption(
-      ProducerCallbacksOptions::CACHE_MISS,
-      (ProducerInterestCallback)std::bind(&TLSProducerSocket::cacheMiss, this,
-                                          std::placeholders::_1,
-                                          std::placeholders::_2));
-
-  this->ProducerSocket::setSocketOption(
-      ProducerCallbacksOptions::CONTENT_PRODUCED,
-      (ProducerContentCallback)bind(
-          &TLSProducerSocket::onContentProduced, this, std::placeholders::_1,
-          std::placeholders::_2, std::placeholders::_3));
-}
-
-/* The producer interface is not owned by the application, so is TLSSocket task
- * to deallocate the memory */
-TLSProducerSocket::~TLSProducerSocket() { delete producer_interface_; }
-
-void TLSProducerSocket::accept() {
-  HandshakeState handshake_state = getHandshakeState();
-
-  if (handshake_state == UNINITIATED || handshake_state == CLIENT_HELLO) {
-    tls_chunks_ = 1;
-    int result = SSL_accept(ssl_);
-
-    if (result != 1)
-      throw errors::RuntimeException("Unable to perform client handshake");
-  }
-
-  parent_->list_producers.push_front(
-      std::move(parent_->map_producers[handshake_name_]));
-  parent_->map_producers.erase(handshake_name_);
-
-  ProducerInterestCallback *on_interest_process_decrypted;
-  getSocketOption(ProducerCallbacksOptions::CACHE_MISS,
-                  &on_interest_process_decrypted);
-
-  if (*on_interest_process_decrypted) {
-    Interest inter(std::move(*handshake_packet_));
-    handshake_packet_.reset();
-    on_interest_process_decrypted->operator()(*getInterface(), inter);
-  } else {
-    throw errors::RuntimeException(
-        "On interest process unset: unable to perform handshake");
-  }
-
-  handshake_state_ = SERVER_FINISHED;
-  DLOG_IF(INFO, VLOG_IS_ON(2)) << "Handshake performed!";
-}
-
-int TLSProducerSocket::async_accept() {
-  if (!async_thread_.stopped()) {
-    async_thread_.add([this]() { this->accept(); });
-  } else {
-    throw errors::RuntimeException(
-        "Async thread not running: unable to perform handshake");
-  }
-
-  return 1;
-}
-
-void TLSProducerSocket::onInterest(ProducerSocket &p, Interest &interest) {
-  HandshakeState handshake_state = getHandshakeState();
-
-  if (handshake_state == UNINITIATED || handshake_state == CLIENT_HELLO) {
-    std::unique_lock<std::mutex> lck(mtx_);
-
-    name_ = interest.getName();
-    // interest.separateHeaderPayload();
-    handshake_packet_ = interest.acquireMemBufReference();
-    something_to_read_ = true;
-
-    cv_.notify_one();
-    return;
-  } else if (handshake_state == SERVER_FINISHED) {
-    // interest.separateHeaderPayload();
-    handshake_packet_ = interest.acquireMemBufReference();
-    something_to_read_ = true;
-
-    if (interest.getPayload()->length() > 0) {
-      SSL_read(
-          ssl_,
-          const_cast<unsigned char *>(interest.getPayload()->writableData()),
-          (int)interest.getPayload()->length());
-    }
-
-    ProducerInterestCallback *on_interest_input_decrypted;
-    getSocketOption(ProducerCallbacksOptions::INTEREST_INPUT,
-                    &on_interest_input_decrypted);
-
-    if (*on_interest_input_decrypted)
-      (*on_interest_input_decrypted)(*getInterface(), interest);
-  }
-}
-
-void TLSProducerSocket::cacheMiss(interface::ProducerSocket &p,
-                                  Interest &interest) {
-  HandshakeState handshake_state = getHandshakeState();
-
-  DLOG_IF(INFO, VLOG_IS_ON(3)) << "On cache miss in TLS socket producer.";
-
-  if (handshake_state == CLIENT_HELLO) {
-    std::unique_lock<std::mutex> lck(mtx_);
-
-    // interest.separateHeaderPayload();
-    handshake_packet_ = interest.acquireMemBufReference();
-    something_to_read_ = true;
-    handshake_state_ = CLIENT_FINISHED;
-
-    cv_.notify_one();
-  } else if (handshake_state == SERVER_FINISHED) {
-    // interest.separateHeaderPayload();
-    handshake_packet_ = interest.acquireMemBufReference();
-    something_to_read_ = true;
-
-    if (interest.getPayload()->length() > 0) {
-      SSL_read(
-          ssl_,
-          const_cast<unsigned char *>(interest.getPayload()->writableData()),
-          (int)interest.getPayload()->length());
-    }
-
-    if (on_interest_process_decrypted_ != VOID_HANDLER)
-      on_interest_process_decrypted_(*getInterface(), interest);
-  }
-}
-
-TLSProducerSocket::HandshakeState TLSProducerSocket::getHandshakeState() {
-  if (SSL_in_before(ssl_)) {
-    handshake_state_ = UNINITIATED;
-  }
-
-  if (SSL_in_init(ssl_) && handshake_state_ == UNINITIATED) {
-    handshake_state_ = CLIENT_HELLO;
-  }
-
-  return handshake_state_;
-}
-
-void TLSProducerSocket::onContentProduced(interface::ProducerSocket &p,
-                                          const std::error_code &err,
-                                          uint64_t bytes_written) {}
-
-uint32_t TLSProducerSocket::produceStream(
-    const Name &content_name, std::unique_ptr<utils::MemBuf> &&buffer,
-    bool is_last, uint32_t start_offset) {
-  if (getHandshakeState() != SERVER_FINISHED) {
-    throw errors::RuntimeException(
-        "New handshake on the same P2P secure producer socket not supported");
-  }
-
-  size_t buf_size = buffer->length();
-  name_ = portal_->getServedNamespaces().begin()->mapName(content_name);
-  tls_chunks_ = to_call_oncontentproduced_ =
-      (int)ceil((float)buf_size / (float)SSL3_RT_MAX_PLAIN_LENGTH);
-
-  if (!is_last) {
-    tls_chunks_++;
-  }
-
-  last_segment_ = start_offset;
-
-  SSL_write(ssl_, buffer->data(), (int)buf_size);
-  BIO *wbio = SSL_get_wbio(ssl_);
-  int i = BIO_flush(wbio);
-  (void)i;  // To shut up gcc 5
-
-  return 0;
-}
-
-long TLSProducerSocket::ctrl(BIO *b, int cmd, long num, void *ptr) {
-  if (cmd == BIO_CTRL_FLUSH) {
-  }
-
-  return 1;
-}
-
-int TLSProducerSocket::addHicnKeyIdCb(SSL *s, unsigned int ext_type,
-                                      unsigned int context,
-                                      const unsigned char **out, size_t *outlen,
-                                      X509 *x, size_t chainidx, int *al,
-                                      void *add_arg) {
-  TLSProducerSocket *socket = reinterpret_cast<TLSProducerSocket *>(add_arg);
-
-  DLOG_IF(INFO, VLOG_IS_ON(3))
-      << "On addHicnKeyIdCb, for the prefix registration.";
-
-  if (ext_type == 100) {
-    auto &prefix = *socket->parent_->portal_->getServedNamespaces().begin();
-    const ip_prefix_t &ip_prefix = prefix.toIpPrefixStruct();
-    int inet_family = prefix.getAddressFamily();
-    uint16_t prefix_len_bits = prefix.getPrefixLength();
-    uint8_t prefix_len_bytes = prefix_len_bits / 8;
-    uint8_t prefix_len_u32 = prefix_len_bits / 32;
-
-    ip_prefix_t *out_ip = (ip_prefix_t *)malloc(sizeof(ip_prefix_t));
-    out_ip->family = inet_family;
-    out_ip->len = prefix_len_bits + 32;
-    u8 *out_ip_buf = const_cast<u8 *>(
-        ip_address_get_buffer(&(out_ip->address), inet_family));
-    *out = reinterpret_cast<unsigned char *>(out_ip);
-
-    RAND_bytes((unsigned char *)&socket->key_id_, 4);
-
-    memcpy(out_ip_buf, ip_address_get_buffer(&(ip_prefix.address), inet_family),
-           prefix_len_bytes);
-    memcpy((out_ip_buf + prefix_len_bytes), &socket->key_id_, 4);
-    *outlen = sizeof(ip_prefix_t);
-
-    ip_address_t mask = {};
-    ip_address_t keyId_component = {};
-    u32 *mask_buf;
-    u32 *keyId_component_buf;
-
-    switch (inet_family) {
-      case AF_INET:
-        mask_buf = &(mask.v4.as_u32);
-        keyId_component_buf = &(keyId_component.v4.as_u32);
-        break;
-      case AF_INET6:
-        mask_buf = mask.v6.as_u32;
-        keyId_component_buf = keyId_component.v6.as_u32;
-        break;
-      default:
-        throw errors::RuntimeException("Unknown protocol");
-    }
-
-    if (prefix_len_bits > (inet_family == AF_INET6 ? IPV6_ADDR_LEN_BITS - 32
-                                                   : IPV4_ADDR_LEN_BITS - 32))
-      throw errors::RuntimeException(
-          "Not enough space in the content name to add key_id");
-
-    mask_buf[prefix_len_u32] = 0xffffffff;
-    keyId_component_buf[prefix_len_u32] = socket->key_id_;
-    socket->last_segment_ = 0;
-
-    socket->on_interest_process_decrypted_ =
-        socket->parent_->on_interest_process_decrypted_;
-
-    socket->registerPrefix(
-        Prefix(prefix.getName(Name(inet_family, (uint8_t *)&mask),
-                              Name(inet_family, (uint8_t *)&keyId_component),
-                              prefix.getName()),
-               out_ip->len));
-    socket->connect();
-  }
-  return 1;
-}
-
-void TLSProducerSocket::freeHicnKeyIdCb(SSL *s, unsigned int ext_type,
-                                        unsigned int context,
-                                        const unsigned char *out,
-                                        void *add_arg) {
-  free(const_cast<unsigned char *>(out));
-}
-
-int TLSProducerSocket::parseHicnKeyIdCb(SSL *s, unsigned int ext_type,
-                                        unsigned int context,
-                                        const unsigned char *in, size_t inlen,
-                                        X509 *x, size_t chainidx, int *al,
-                                        void *add_arg) {
-  return 1;
-}
-
-int TLSProducerSocket::setSocketOption(
-    int socket_option_key, ProducerInterestCallback socket_option_value) {
-  return rescheduleOnIOService(
-      socket_option_key, socket_option_value,
-      [this](int socket_option_key,
-             ProducerInterestCallback socket_option_value) -> int {
-        int result = SOCKET_OPTION_SET;
-
-        switch (socket_option_key) {
-          case ProducerCallbacksOptions::INTEREST_INPUT:
-            on_interest_input_decrypted_ = socket_option_value;
-            break;
-
-          case ProducerCallbacksOptions::INTEREST_DROP:
-            on_interest_dropped_input_buffer_ = socket_option_value;
-            break;
-
-          case ProducerCallbacksOptions::INTEREST_PASS:
-            on_interest_inserted_input_buffer_ = socket_option_value;
-            break;
-
-          case ProducerCallbacksOptions::CACHE_HIT:
-            on_interest_satisfied_output_buffer_ = socket_option_value;
-            break;
-
-          case ProducerCallbacksOptions::CACHE_MISS:
-            on_interest_process_decrypted_ = socket_option_value;
-            break;
-
-          default:
-            result = SOCKET_OPTION_NOT_SET;
-            break;
-        }
-
-        return result;
-      });
-}
-
-int TLSProducerSocket::setSocketOption(
-    int socket_option_key, ProducerContentCallback socket_option_value) {
-  return rescheduleOnIOService(
-      socket_option_key, socket_option_value,
-      [this](int socket_option_key,
-             ProducerContentCallback socket_option_value) -> int {
-        switch (socket_option_key) {
-          case ProducerCallbacksOptions::CONTENT_PRODUCED:
-            on_content_produced_application_ = socket_option_value;
-            break;
-
-          default:
-            return SOCKET_OPTION_NOT_SET;
-        }
-
-        return SOCKET_OPTION_SET;
-      });
-}
-
-int TLSProducerSocket::getSocketOption(
-    int socket_option_key, ProducerContentCallback **socket_option_value) {
-  return rescheduleOnIOService(
-      socket_option_key, socket_option_value,
-      [this](int socket_option_key,
-             ProducerContentCallback **socket_option_value) -> int {
-        switch (socket_option_key) {
-          case ProducerCallbacksOptions::CONTENT_PRODUCED:
-            *socket_option_value = &on_content_produced_application_;
-            break;
-
-          default:
-            return SOCKET_OPTION_NOT_GET;
-        }
-
-        return SOCKET_OPTION_GET;
-      });
-}
-
-}  // namespace implementation
-}  // namespace transport
diff --git a/libtransport/src/implementation/tls_socket_producer.h b/libtransport/src/implementation/tls_socket_producer.h
deleted file mode 100644 (file)
index 0e958b3..0000000
+++ /dev/null
@@ -1,154 +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.
- */
-
-#pragma once
-
-#include <implementation/socket_producer.h>
-#include <openssl/ssl.h>
-
-#include <condition_variable>
-#include <mutex>
-
-namespace transport {
-namespace implementation {
-
-class P2PSecureProducerSocket;
-
-class TLSProducerSocket : virtual public ProducerSocket {
-  friend class P2PSecureProducerSocket;
-
- public:
-  explicit TLSProducerSocket(interface::ProducerSocket *producer_socket,
-                             P2PSecureProducerSocket *parent,
-                             const Name &handshake_name);
-
-  ~TLSProducerSocket();
-
-  uint32_t produceStream(const Name &content_name, const uint8_t *buffer,
-                         size_t buffer_size, bool is_last = true,
-                         uint32_t start_offset = 0) override {
-    return produceStream(content_name,
-                         utils::MemBuf::copyBuffer(buffer, buffer_size),
-                         is_last, start_offset);
-  }
-
-  uint32_t produceStream(const Name &content_name,
-                         std::unique_ptr<utils::MemBuf> &&buffer,
-                         bool is_last = true,
-                         uint32_t start_offset = 0) override;
-
-  virtual void accept();
-
-  virtual int async_accept();
-
-  virtual int setSocketOption(
-      int socket_option_key,
-      ProducerInterestCallback socket_option_value) override;
-
-  virtual int setSocketOption(
-      int socket_option_key,
-      ProducerContentCallback socket_option_value) override;
-
-  virtual int getSocketOption(
-      int socket_option_key,
-      ProducerContentCallback **socket_option_value) override;
-
-  int getSocketOption(int socket_option_key,
-                      ProducerContentCallback &socket_option_value);
-
-  int getSocketOption(int socket_option_key,
-                      ProducerInterestCallback &socket_option_value);
-
-  using ProducerSocket::getSocketOption;
-  // using ProducerSocket::onInterest;
-  using ProducerSocket::setSocketOption;
-
- protected:
-  enum HandshakeState {
-    UNINITIATED,
-    CLIENT_HELLO,     // when CLIENT_HELLO interest has been received
-    CLIENT_FINISHED,  // when CLIENT_FINISHED interest has been received
-    SERVER_FINISHED,  // when handshake is done
-  };
-  /* Callback invoked once an interest has been received and its payload
-   * decrypted */
-  ProducerInterestCallback on_interest_input_decrypted_;
-  ProducerInterestCallback on_interest_process_decrypted_;
-  ProducerContentCallback on_content_produced_application_;
-  std::mutex mtx_;
-  /* Condition variable for the wait */
-  std::condition_variable cv_;
-  /* Bool variable, true if there is something to read (an interest arrived) */
-  bool something_to_read_;
-  /* Bool variable, true if CLIENT_FINISHED interest has been received */
-  HandshakeState handshake_state_;
-  /* First interest that open a secure connection */
-  transport::core::Name name_;
-  /* SSL handle */
-  SSL *ssl_;
-  SSL_CTX *ctx_;
-  Packet::MemBufPtr handshake_packet_;
-  std::unique_ptr<utils::MemBuf> head_;
-  std::uint32_t last_segment_;
-  std::uint32_t key_id_;
-  std::thread *handshake;
-  P2PSecureProducerSocket *parent_;
-  bool first_;
-  Name handshake_name_;
-  int tls_chunks_;
-  int to_call_oncontentproduced_;
-  bool still_writing_;
-  utils::EventThread encryption_thread_;
-  utils::EventThread async_thread_;
-
-  void onInterest(ProducerSocket &p, Interest &interest);
-
-  void cacheMiss(interface::ProducerSocket &p, Interest &interest);
-
-  /* Return the number of read bytes in readbytes */
-  static int read(BIO *b, char *buf, size_t size, size_t *readbytes);
-
-  /* Return the number of read bytes in the return param */
-  static int readOld(BIO *h, char *buf, int size);
-
-  /* Return the number of written bytes in written */
-  static int write(BIO *b, const char *buf, size_t size, size_t *written);
-
-  /* Return the number of written bytes in the return param */
-  static int writeOld(BIO *h, const char *buf, int num);
-
-  static long ctrl(BIO *b, int cmd, long num, void *ptr);
-
-  static int addHicnKeyIdCb(SSL *s, unsigned int ext_type, unsigned int context,
-                            const unsigned char **out, size_t *outlen, X509 *x,
-                            size_t chainidx, int *al, void *add_arg);
-
-  static void freeHicnKeyIdCb(SSL *s, unsigned int ext_type,
-                              unsigned int context, const unsigned char *out,
-                              void *add_arg);
-
-  static int parseHicnKeyIdCb(SSL *s, unsigned int ext_type,
-                              unsigned int context, const unsigned char *in,
-                              size_t inlen, X509 *x, size_t chainidx, int *al,
-                              void *add_arg);
-
-  void onContentProduced(interface::ProducerSocket &p,
-                         const std::error_code &err, uint64_t bytes_written);
-
-  HandshakeState getHandshakeState();
-};
-
-}  // namespace implementation
-}  // end namespace transport
index 0a0603a..bf8f8dc 100644 (file)
@@ -19,20 +19,4 @@ list(APPEND SOURCE_FILES
   ${CMAKE_CURRENT_SOURCE_DIR}/global_configuration.cc
 )
 
-if (${OPENSSL_VERSION} VERSION_EQUAL "1.1.1a" OR ${OPENSSL_VERSION} VERSION_GREATER "1.1.1a")
-  list(APPEND SOURCE_FILES
-    ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.cc
-    ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.cc
-    # ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.cc
-    ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.cc
-    ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.cc
-  )
-
-  list(APPEND HEADER_FILES
-    # ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.h
-    ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.h
-    ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.h
-  )
-endif()
-
 set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
index cecdacc..f8e7a90 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <core/global_configuration.h>
+#include <core/global_workers.h>
 #include <glog/logging.h>
 #include <hicn/transport/interfaces/global_conf_interface.h>
 
@@ -23,10 +24,29 @@ namespace transport {
 namespace interface {
 namespace global_config {
 
-void parseConfigurationFile(const std::string& path) {
+GlobalConfigInterface::GlobalConfigInterface() { libtransportConfigInit(); }
+
+GlobalConfigInterface::~GlobalConfigInterface() {
+  libtransportConfigTerminate();
+}
+
+void GlobalConfigInterface::parseConfigurationFile(
+    const std::string &path) const {
   core::GlobalConfiguration::getInstance().parseConfiguration(path);
 }
 
+void GlobalConfigInterface::libtransportConfigInit() const {
+  // nothing to do
+}
+
+void GlobalConfigInterface::libtransportConfigTerminate() const {
+  // cleanup workers
+  auto &workers = core::GlobalWorkers::getInstance().getWorkers();
+  for (auto &worker : workers) {
+    worker.stop();
+  }
+}
+
 void ConfigurationObject::get() {
   std::error_code ec;
   core::GlobalConfiguration::getInstance().getConfiguration(*this, ec);
diff --git a/libtransport/src/interfaces/p2psecure_socket_consumer.cc b/libtransport/src/interfaces/p2psecure_socket_consumer.cc
deleted file mode 100644 (file)
index e329a50..0000000
+++ /dev/null
@@ -1,37 +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.
- */
-
-#include <hicn/transport/interfaces/p2psecure_socket_consumer.h>
-#include <implementation/p2psecure_socket_consumer.h>
-
-namespace transport {
-namespace interface {
-
-P2PSecureConsumerSocket::P2PSecureConsumerSocket(int handshake_protocol,
-                                                 int transport_protocol)
-    : ConsumerSocket() {
-  socket_ = std::unique_ptr<implementation::ConsumerSocket>(
-      new implementation::P2PSecureConsumerSocket(this, handshake_protocol,
-                                                  transport_protocol));
-}
-
-void P2PSecureConsumerSocket::registerPrefix(const Prefix &producer_namespace) {
-  implementation::P2PSecureConsumerSocket &secure_consumer_socket =
-      *(static_cast<implementation::P2PSecureConsumerSocket *>(socket_.get()));
-  secure_consumer_socket.registerPrefix(producer_namespace);
-}
-
-}  // namespace interface
-}  // namespace transport
diff --git a/libtransport/src/interfaces/p2psecure_socket_producer.cc b/libtransport/src/interfaces/p2psecure_socket_producer.cc
deleted file mode 100644 (file)
index 5f98302..0000000
+++ /dev/null
@@ -1,34 +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.
- */
-
-#include <hicn/transport/interfaces/p2psecure_socket_producer.h>
-#include <implementation/p2psecure_socket_producer.h>
-
-namespace transport {
-namespace interface {
-
-P2PSecureProducerSocket::P2PSecureProducerSocket() {
-  socket_ = std::make_unique<implementation::P2PSecureProducerSocket>(this);
-}
-
-P2PSecureProducerSocket::P2PSecureProducerSocket(bool rtc,
-                                                 std::string &keystore_path,
-                                                 std::string &keystore_pwd) {
-  socket_ = std::make_unique<implementation::P2PSecureProducerSocket>(
-      this, rtc, keystore_path, keystore_pwd);
-}
-
-}  // namespace interface
-}  // namespace transport
index 84634a2..898766c 100644 (file)
@@ -35,10 +35,10 @@ class Portal::Impl {
     return portal_->interestIsPending(name);
   }
 
-  void sendInterest(core::Interest::Ptr &&interest,
+  void sendInterest(core::Interest::Ptr &interest, uint32_t lifetime,
                     OnContentObjectCallback &&on_content_object_callback,
                     OnInterestTimeoutCallback &&on_interest_timeout_callback) {
-    portal_->sendInterest(std::move(interest),
+    portal_->sendInterest(interest, lifetime,
                           std::move(on_content_object_callback),
                           std::move(on_interest_timeout_callback));
   }
@@ -86,10 +86,10 @@ bool Portal::interestIsPending(const core::Name &name) {
 }
 
 void Portal::sendInterest(
-    core::Interest::Ptr &&interest,
+    core::Interest::Ptr &interest, uint32_t lifetime,
     OnContentObjectCallback &&on_content_object_callback,
     OnInterestTimeoutCallback &&on_interest_timeout_callback) {
-  implementation_->sendInterest(std::move(interest),
+  implementation_->sendInterest(interest, lifetime,
                                 std::move(on_content_object_callback),
                                 std::move(on_interest_timeout_callback));
 }
index 747dc09..cc496c8 100644 (file)
@@ -100,6 +100,12 @@ int ConsumerSocket::setSocketOption(int socket_option_key,
   return socket_->setSocketOption(socket_option_key, socket_option_value);
 }
 
+int ConsumerSocket::setSocketOption(
+    int socket_option_key,
+    const std::shared_ptr<auth::Signer> &socket_option_value) {
+  return socket_->setSocketOption(socket_option_key, socket_option_value);
+}
+
 int ConsumerSocket::setSocketOption(
     int socket_option_key,
     const std::shared_ptr<auth::Verifier> &socket_option_value) {
@@ -162,6 +168,11 @@ int ConsumerSocket::getSocketOption(int socket_option_key,
   return socket_->getSocketOption(socket_option_key, socket_option_value);
 }
 
+int ConsumerSocket::getSocketOption(
+    int socket_option_key, std::shared_ptr<auth::Signer> &socket_option_value) {
+  return socket_->getSocketOption(socket_option_key, socket_option_value);
+}
+
 int ConsumerSocket::getSocketOption(
     int socket_option_key,
     std::shared_ptr<auth::Verifier> &socket_option_value) {
index 10613c0..2155ebd 100644 (file)
@@ -148,6 +148,12 @@ int ProducerSocket::setSocketOption(
   return socket_->setSocketOption(socket_option_key, socket_option_value);
 }
 
+int ProducerSocket::setSocketOption(
+    int socket_option_key,
+    const std::shared_ptr<auth::Verifier> &socket_option_value) {
+  return socket_->setSocketOption(socket_option_key, socket_option_value);
+}
+
 int ProducerSocket::setSocketOption(int socket_option_key,
                                     Packet::Format socket_option_value) {
   return socket_->setSocketOption(socket_option_key, socket_option_value);
@@ -194,6 +200,12 @@ int ProducerSocket::getSocketOption(
   return socket_->getSocketOption(socket_option_key, socket_option_value);
 }
 
+int ProducerSocket::getSocketOption(
+    int socket_option_key,
+    std::shared_ptr<auth::Verifier> &socket_option_value) {
+  return socket_->getSocketOption(socket_option_key, socket_option_value);
+}
+
 int ProducerSocket::getSocketOption(int socket_option_key,
                                     Packet::Format &socket_option_value) {
   return socket_->getSocketOption(socket_option_key, socket_option_value);
diff --git a/libtransport/src/interfaces/tls_rtc_socket_producer.cc b/libtransport/src/interfaces/tls_rtc_socket_producer.cc
deleted file mode 100644 (file)
index 6bf1b01..0000000
+++ /dev/null
@@ -1,31 +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.
- */
-
-#include <implementation/tls_rtc_socket_producer.h>
-#include <interfaces/tls_rtc_socket_producer.h>
-
-namespace transport {
-namespace interface {
-
-TLSRTCProducerSocket::TLSRTCProducerSocket(
-    implementation::TLSRTCProducerSocket *implementation) {
-  socket_ =
-      std::unique_ptr<implementation::TLSRTCProducerSocket>(implementation);
-}
-
-TLSRTCProducerSocket::~TLSRTCProducerSocket() { socket_.release(); }
-
-}  // namespace interface
-}  // namespace transport
diff --git a/libtransport/src/interfaces/tls_rtc_socket_producer.h b/libtransport/src/interfaces/tls_rtc_socket_producer.h
deleted file mode 100644 (file)
index b8b6ec2..0000000
+++ /dev/null
@@ -1,36 +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.
- */
-
-#pragma once
-
-#include <hicn/transport/interfaces/socket_producer.h>
-
-namespace transport {
-
-namespace implementation {
-class TLSRTCProducerSocket;
-}
-
-namespace interface {
-
-class TLSRTCProducerSocket : public ProducerSocket {
- public:
-  TLSRTCProducerSocket(implementation::TLSRTCProducerSocket *implementation);
-
-  ~TLSRTCProducerSocket();
-};
-
-}  // namespace interface
-}  // end namespace transport
diff --git a/libtransport/src/interfaces/tls_socket_consumer.cc b/libtransport/src/interfaces/tls_socket_consumer.cc
deleted file mode 100644 (file)
index 24060d1..0000000
+++ /dev/null
@@ -1,30 +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.
- */
-
-#include <implementation/tls_socket_consumer.h>
-#include <interfaces/tls_socket_consumer.h>
-
-namespace transport {
-namespace interface {
-
-TLSConsumerSocket::TLSConsumerSocket(
-    implementation::TLSConsumerSocket *implementation) {
-  socket_ = std::unique_ptr<implementation::TLSConsumerSocket>(implementation);
-}
-
-TLSConsumerSocket::~TLSConsumerSocket() { socket_.release(); }
-
-}  // namespace interface
-}  // namespace transport
diff --git a/libtransport/src/interfaces/tls_socket_consumer.h b/libtransport/src/interfaces/tls_socket_consumer.h
deleted file mode 100644 (file)
index 242dc91..0000000
+++ /dev/null
@@ -1,36 +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.
- */
-
-#pragma once
-
-#include <hicn/transport/interfaces/socket_consumer.h>
-
-namespace transport {
-
-namespace implementation {
-class TLSConsumerSocket;
-}
-
-namespace interface {
-
-class TLSConsumerSocket : public ConsumerSocket {
- public:
-  TLSConsumerSocket(implementation::TLSConsumerSocket *implementation);
-  ~TLSConsumerSocket();
-};
-
-}  // namespace interface
-
-}  // end namespace transport
diff --git a/libtransport/src/interfaces/tls_socket_producer.cc b/libtransport/src/interfaces/tls_socket_producer.cc
deleted file mode 100644 (file)
index b2b9e72..0000000
+++ /dev/null
@@ -1,30 +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.
- */
-
-#include <implementation/tls_socket_producer.h>
-#include <interfaces/tls_socket_producer.h>
-
-namespace transport {
-namespace interface {
-
-TLSProducerSocket::TLSProducerSocket(
-    implementation::TLSProducerSocket *implementation) {
-  socket_ = std::unique_ptr<implementation::TLSProducerSocket>(implementation);
-}
-
-TLSProducerSocket::~TLSProducerSocket() { socket_.release(); }
-
-}  // namespace interface
-}  // namespace transport
diff --git a/libtransport/src/interfaces/tls_socket_producer.h b/libtransport/src/interfaces/tls_socket_producer.h
deleted file mode 100644 (file)
index 9b31cb4..0000000
+++ /dev/null
@@ -1,36 +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.
- */
-
-#pragma once
-
-#include <hicn/transport/interfaces/socket_producer.h>
-
-namespace transport {
-
-namespace implementation {
-class TLSProducerSocket;
-}
-
-namespace interface {
-
-class TLSProducerSocket : public ProducerSocket {
- public:
-  TLSProducerSocket(implementation::TLSProducerSocket *implementation);
-  ~TLSProducerSocket();
-};
-
-}  // namespace interface
-
-}  // end namespace transport
index f4143de..f1a27d3 100644 (file)
@@ -15,7 +15,7 @@
 ##############################################################
 # Android case: no submodules
 ##############################################################
-if (${CMAKE_SYSTEM_NAME} MATCHES Android)
+if (${CMAKE_SYSTEM_NAME} MATCHES Android OR ${CMAKE_SYSTEM_NAME} MATCHES iOS)
   list(APPEND SOURCE_FILES
     ${CMAKE_CURRENT_SOURCE_DIR}/hicn-light-ng/hicn_forwarder_module.cc
   )
index 3922316..2235d84 100644 (file)
@@ -17,7 +17,6 @@ list(APPEND MODULE_HEADER_FILES
   ${CMAKE_CURRENT_SOURCE_DIR}/errors.h
   ${CMAKE_CURRENT_SOURCE_DIR}/forwarder_module.h
   ${CMAKE_CURRENT_SOURCE_DIR}/forwarder.h
-  ${CMAKE_CURRENT_SOURCE_DIR}/global_counter.h
 )
 
 list(APPEND MODULE_SOURCE_FILES
index 3ae5bf3..bfe4dd5 100644 (file)
  */
 
 #include <core/global_configuration.h>
+#include <core/global_id_counter.h>
 #include <core/local_connector.h>
 #include <core/udp_connector.h>
 #include <core/udp_listener.h>
 #include <glog/logging.h>
 #include <io_modules/forwarder/forwarder.h>
-#include <io_modules/forwarder/global_id_counter.h>
 
 namespace transport {
 
@@ -90,11 +90,13 @@ Connector::Id Forwarder::registerLocalConnector(
     asio::io_service &io_service,
     Connector::PacketReceivedCallback &&receive_callback,
     Connector::PacketSentCallback &&sent_callback,
+    Connector::OnCloseCallback &&close_callback,
     Connector::OnReconnectCallback &&reconnect_callback) {
   utils::SpinLock::Acquire locked(connector_lock_);
   auto id = GlobalCounter<Connector::Id>::getInstance().getNext();
   auto connector = std::make_shared<LocalConnector>(
-      io_service, receive_callback, sent_callback, nullptr, reconnect_callback);
+      io_service, std::move(receive_callback), std::move(sent_callback),
+      std::move(close_callback), std::move(reconnect_callback));
   connector->setConnectorId(id);
   local_connectors_.emplace(id, std::move(connector));
   return id;
@@ -150,34 +152,13 @@ void Forwarder::onPacketReceived(Connector *connector,
     return;
   }
 
-  for (auto &packet_buffer_ptr : packets) {
-    auto &packet_buffer = *packet_buffer_ptr;
-
-    // Figure out the type of packet we received
-    bool is_interest = Packet::isInterest(packet_buffer.data());
-
-    Packet *packet = nullptr;
-    if (is_interest) {
-      packet = static_cast<Interest *>(&packet_buffer);
-    } else {
-      packet = static_cast<ContentObject *>(&packet_buffer);
-    }
-
-    for (auto &c : local_connectors_) {
-      auto role = c.second->getRole();
-      auto is_producer = role == Connector::Role::PRODUCER;
-      if ((is_producer && is_interest) || (!is_producer && !is_interest)) {
-        c.second->send(*packet);
-      } else {
-        LOG(ERROR) << "Error sending packet to local connector. is_interest = "
-                   << is_interest << " - is_producer = " << is_producer;
-      }
-    }
+  for (auto &c : local_connectors_) {
+    c.second->receive(packets);
+  }
 
-    // PCS Lookup + FIB lookup. Skip for now
+  // PCS Lookup + FIB lookup. Skip for now
 
-    // Forward packet to local connectors
-  }
+  // Forward packet to local connectors
 }
 
 void Forwarder::send(Packet &packet) {
@@ -304,4 +285,4 @@ void Forwarder::parseForwarderConfiguration(
 }
 
 }  // namespace core
-}  // namespace transport
\ No newline at end of file
+}  // namespace transport
index 38b4260..9ad989f 100644 (file)
@@ -47,6 +47,7 @@ class Forwarder {
       asio::io_service &io_service,
       Connector::PacketReceivedCallback &&receive_callback,
       Connector::PacketSentCallback &&sent_callback,
+      Connector::OnCloseCallback &&close_callback,
       Connector::OnReconnectCallback &&reconnect_callback);
 
   Forwarder &deleteConnector(Connector::Id id);
index 0ced84a..77d2b5e 100644 (file)
@@ -37,8 +37,6 @@ void ForwarderModule::send(Packet &packet) {
   forwarder_.send(packet);
   DLOG_IF(INFO, VLOG_IS_ON(3))
       << "Sending from " << connector_id_ << " to " << 1 - connector_id_;
-
-  // local_faces_.at(1 - local_id_).onPacket(packet);
 }
 
 void ForwarderModule::send(const utils::MemBuf::Ptr &buffer) {
@@ -58,12 +56,13 @@ void ForwarderModule::closeConnection() {
 
 void ForwarderModule::init(Connector::PacketReceivedCallback &&receive_callback,
                            Connector::PacketSentCallback &&sent_callback,
+                           Connector::OnCloseCallback &&close_callback,
                            Connector::OnReconnectCallback &&reconnect_callback,
                            asio::io_service &io_service,
                            const std::string &app_name) {
   connector_id_ = forwarder_.registerLocalConnector(
       io_service, std::move(receive_callback), std::move(sent_callback),
-      std::move(reconnect_callback));
+      std::move(close_callback), std::move(reconnect_callback));
   name_ = app_name;
 }
 
index 52a12b6..a487011 100644 (file)
@@ -44,6 +44,7 @@ class ForwarderModule : public IoModule {
 
   void init(Connector::PacketReceivedCallback &&receive_callback,
             Connector::PacketSentCallback &&sent_callback,
+            Connector::OnCloseCallback &&close_callback,
             Connector::OnReconnectCallback &&reconnect_callback,
             asio::io_service &io_service,
             const std::string &app_name = "Libtransport") override;
index f67bd94..95f0482 100644 (file)
@@ -100,12 +100,13 @@ void HicnForwarderModule::closeConnection() {
 void HicnForwarderModule::init(
     Connector::PacketReceivedCallback &&receive_callback,
     Connector::PacketSentCallback &&sent_callback,
+    Connector::OnCloseCallback &&close_callback,
     Connector::OnReconnectCallback &&reconnect_callback,
     asio::io_service &io_service, const std::string &app_name) {
   if (!connector_) {
     connector_.reset(new UdpTunnelConnector(
         io_service, std::move(receive_callback), std::move(sent_callback),
-        nullptr, std::move(reconnect_callback)));
+        std::move(close_callback), std::move(reconnect_callback)));
   }
 }
 
@@ -130,7 +131,7 @@ bool HicnForwarderModule::isControlMessage(utils::MemBuf &packet_buffer) {
  */
 utils::MemBuf::Ptr HicnForwarderModule::createCommandRoute(
     std::unique_ptr<sockaddr> &&addr, uint8_t prefix_length) {
-  utils::MemBuf::Ptr ret = utils::MemBuf::create(sizeof(msg_route_add_t));
+  auto ret = PacketManager<>::getInstance().getMemBuf();
   auto command = reinterpret_cast<msg_route_add_t *>(ret->writableData());
   ret->append(sizeof(msg_route_add_t));
   std::memset(command, 0, sizeof(*command));
@@ -170,8 +171,7 @@ utils::MemBuf::Ptr HicnForwarderModule::createCommandRoute(
 }
 
 utils::MemBuf::Ptr HicnForwarderModule::createCommandDeleteConnection() {
-  utils::MemBuf::Ptr ret =
-      utils::MemBuf::create(sizeof(msg_connection_remove_t));
+  auto ret = PacketManager<>::getInstance().getMemBuf();
   auto command =
       reinterpret_cast<msg_connection_remove_t *>(ret->writableData());
   ret->append(sizeof(msg_connection_remove_t));
@@ -194,8 +194,7 @@ utils::MemBuf::Ptr HicnForwarderModule::createCommandDeleteConnection() {
 }
 
 utils::MemBuf::Ptr HicnForwarderModule::createCommandMapmeSendUpdate() {
-  utils::MemBuf::Ptr ret =
-      utils::MemBuf::create(sizeof(msg_mapme_send_update_t));
+  auto ret = PacketManager<>::getInstance().getMemBuf();
   auto command =
       reinterpret_cast<msg_mapme_send_update_t *>(ret->writableData());
   ret->append(sizeof(msg_mapme_send_update_t));
@@ -217,7 +216,7 @@ utils::MemBuf::Ptr HicnForwarderModule::createCommandMapmeSendUpdate() {
 utils::MemBuf::Ptr HicnForwarderModule::createCommandSetForwardingStrategy(
     std::unique_ptr<sockaddr> &&addr, uint32_t prefix_len,
     std::string strategy) {
-  utils::MemBuf::Ptr ret = utils::MemBuf::create(sizeof(msg_strategy_set_t));
+  auto ret = PacketManager<>::getInstance().getMemBuf();
   auto command = reinterpret_cast<msg_strategy_set_t *>(ret->writableData());
   ret->append(sizeof(msg_strategy_set_t));
   std::memset(command, 0, sizeof(*command));
index 0bf8275..7f0e7ac 100644 (file)
@@ -64,6 +64,7 @@ class HicnForwarderModule : public IoModule {
 
   void init(Connector::PacketReceivedCallback &&receive_callback,
             Connector::PacketSentCallback &&sent_callback,
+            Connector::OnCloseCallback &&close_callback,
             Connector::OnReconnectCallback &&reconnect_callback,
             asio::io_service &io_service,
             const std::string &app_name = "Libtransport") override;
index 5b7ed5f..a7f30eb 100644 (file)
@@ -58,6 +58,7 @@ void LoopbackModule::closeConnection() {
 
 void LoopbackModule::init(Connector::PacketReceivedCallback &&receive_callback,
                           Connector::PacketSentCallback &&sent_callback,
+                          Connector::OnCloseCallback &&close_callback,
                           Connector::OnReconnectCallback &&reconnect_callback,
                           asio::io_service &io_service,
                           const std::string &app_name) {
@@ -66,7 +67,7 @@ void LoopbackModule::init(Connector::PacketReceivedCallback &&receive_callback,
     local_faces_.emplace(
         local_faces_.begin() + local_id_,
         new LocalConnector(io_service, std::move(receive_callback),
-                           std::move(sent_callback), nullptr,
+                           std::move(sent_callback), std::move(close_callback),
                            std::move(reconnect_callback)));
   }
 }
index 2779ae7..d51f237 100644 (file)
@@ -42,6 +42,7 @@ class LoopbackModule : public IoModule {
 
   void init(Connector::PacketReceivedCallback &&receive_callback,
             Connector::PacketSentCallback &&sent_callback,
+            Connector::OnCloseCallback &&close_callback,
             Connector::OnReconnectCallback &&reconnect_callback,
             asio::io_service &io_service,
             const std::string &app_name = "Libtransport") override;
index 6526007..c096a71 100644 (file)
@@ -50,13 +50,14 @@ VPPForwarderModule::~VPPForwarderModule() {}
 void VPPForwarderModule::init(
     Connector::PacketReceivedCallback &&receive_callback,
     Connector::PacketSentCallback &&sent_callback,
+    Connector::OnCloseCallback &&close_callback,
     Connector::OnReconnectCallback &&reconnect_callback,
     asio::io_service &io_service, const std::string &app_name) {
   if (!connector_) {
     connector_ = std::make_unique<MemifConnector>(
         std::move(receive_callback), std::move(sent_callback),
-        Connector::OnCloseCallback(0), std::move(reconnect_callback),
-        io_service, app_name);
+        std::move(close_callback), std::move(reconnect_callback), io_service,
+        app_name);
   }
 }
 
index 162ee0c..5a53580 100644 (file)
@@ -48,6 +48,7 @@ class VPPForwarderModule : public IoModule {
 
   void init(Connector::PacketReceivedCallback &&receive_callback,
             Connector::PacketSentCallback &&sent_callback,
+            Connector::OnCloseCallback &&close_callback,
             Connector::OnReconnectCallback &&reconnect_callback,
             asio::io_service &io_service,
             const std::string &app_name = "Libtransport") override;
index 3278595..b9eaf3b 100644 (file)
@@ -36,15 +36,6 @@ ByteStreamReassembly::ByteStreamReassembly(
       index_(Indexer::invalid_index),
       download_complete_(false) {}
 
-void ByteStreamReassembly::reassemble(
-    std::unique_ptr<ContentObjectManifest> &&manifest) {
-  if (TRANSPORT_EXPECT_TRUE(manifest != nullptr) && read_buffer_->capacity()) {
-    received_packets_.emplace(
-        std::make_pair(manifest->getName().getSuffix(), nullptr));
-    assembleContent();
-  }
-}
-
 void ByteStreamReassembly::reassemble(ContentObject &content_object) {
   if (TRANSPORT_EXPECT_TRUE(read_buffer_->capacity())) {
     received_packets_.emplace(
index bfcac31..a1f965d 100644 (file)
@@ -29,9 +29,6 @@ class ByteStreamReassembly : public Reassembly {
  protected:
   void reassemble(core::ContentObject &content_object) override;
 
-  void reassemble(
-      std::unique_ptr<core::ContentObjectManifest> &&manifest) override;
-
   void reassemble(utils::MemBuf &buffer, uint32_t suffix) override;
 
   bool copyContent(core::ContentObject &content_object);
index 446ea8b..e3f0f13 100644 (file)
@@ -38,7 +38,7 @@ void CbrTransportProtocol::afterContentReception(
     const Interest &interest, const ContentObject &content_object) {
   auto segment = content_object.getName().getSuffix();
   auto now = utils::SteadyTime::Clock::now();
-  auto rtt = utils::SteadyTime::getDurationMs(
+  auto rtt = utils::SteadyTime::getDurationUs(
       interest_timepoints_[segment & mask], now);
   // Update stats
   updateStats(segment, rtt, now);
index 3a32c81..a04b0ee 100644 (file)
@@ -29,8 +29,9 @@ void DatagramReassembly::reassemble(core::ContentObject& content_object) {
   auto read_buffer = content_object.getPayload();
   DLOG_IF(INFO, VLOG_IS_ON(4))
       << "Size of payload: " << read_buffer->length() << ". Trimming "
-      << transport_protocol_->transportHeaderLength();
-  read_buffer->trimStart(transport_protocol_->transportHeaderLength());
+      << transport_protocol_->transportHeaderLength(false);
+  // here we have only src data packet
+  read_buffer->trimStart(transport_protocol_->transportHeaderLength(false));
   Reassembly::read_buffer_ = std::move(read_buffer);
   Reassembly::notifyApplication();
 }
index 0def32d..cefdca9 100644 (file)
@@ -29,10 +29,6 @@ class DatagramReassembly : public Reassembly {
   virtual void reassemble(core::ContentObject &content_object) override;
   void reassemble(utils::MemBuf &buffer, uint32_t suffix) override;
   virtual void reInitialize() override;
-  virtual void reassemble(
-      std::unique_ptr<core::ContentObjectManifest> &&manifest) override {
-    return;
-  }
   bool reassembleUnverified() override { return true; }
 };
 
index d4d98a9..9e0a06d 100644 (file)
@@ -79,7 +79,7 @@ void RelyEncoder::onPacketProduced(core::ContentObject &content_object,
 
     // Check new payload size and make sure it fits in packet buffer
     auto new_payload_size = produce_bytes();
-    int difference = new_payload_size - length;
+    int difference = (int)(new_payload_size - length);
 
     DCHECK(difference > 0);
     DCHECK(content_object.ensureCapacity(difference));
index 001a260..cc81222 100644 (file)
@@ -15,6 +15,7 @@
 
 #pragma once
 
+#include <hicn/transport/portability/endianess.h>
 #include <hicn/transport/utils/chrono_typedefs.h>
 #include <hicn/transport/utils/membuf.h>
 #include <protocols/fec/fec_info.h>
@@ -80,11 +81,19 @@ class RelyBase : public virtual FECBase {
    */
   class fec_metadata {
    public:
-    void setSeqNumberBase(uint32_t suffix) { seq_number = htonl(suffix); }
-    uint32_t getSeqNumberBase() const { return ntohl(seq_number); }
-
-    void setMetadataBase(uint32_t value) { metadata = htonl(value); }
-    uint32_t getMetadataBase() const { return ntohl(metadata); }
+    void setSeqNumberBase(uint32_t suffix) {
+      seq_number = portability::host_to_net(suffix);
+    }
+    uint32_t getSeqNumberBase() const {
+      return portability::net_to_host(seq_number);
+    }
+
+    void setMetadataBase(uint32_t value) {
+      metadata = portability::host_to_net(value);
+    }
+    uint32_t getMetadataBase() const {
+      return portability::net_to_host(metadata);
+    }
 
    private:
     uint32_t seq_number;
@@ -162,8 +171,9 @@ class RelyEncoder : RelyBase, rely::encoder, public ProducerFEC {
 
   /**
    * @brief Get the fec header size, if added to source packets
+   * there is not need to distinguish between source and FEC packets here
    */
-  std::size_t getFecHeaderSize() override {
+  std::size_t getFecHeaderSize(bool isFEC) override {
     return header_bytes() + sizeof(fec_metadata) + 4;
   }
 
@@ -184,8 +194,9 @@ class RelyDecoder : RelyBase, rely::decoder, public ConsumerFEC {
 
   /**
    * @brief Get the fec header size, if added to source packets
+   * there is not need to distinguish between source and FEC packets here
    */
-  std::size_t getFecHeaderSize() override {
+  std::size_t getFecHeaderSize(bool isFEC) override {
     return header_bytes() + sizeof(fec_metadata);
   }
 
index 9c0a3d4..d42740c 100644 (file)
@@ -146,7 +146,8 @@ void BlockCode::encode() {
   DLOG_IF(INFO, VLOG_IS_ON(4))
       << "Calling encode with max_buffer_size_ = " << max_buffer_size_;
   for (uint32_t i = k_; i < n_; i++) {
-    fec_encode(code_, data, data[i], i, max_buffer_size_ + METADATA_BYTES);
+    fec_encode(code_, data, data[i], i,
+               (int)(max_buffer_size_ + METADATA_BYTES));
   }
 
   // Re-include header in repair packets
@@ -213,7 +214,8 @@ void BlockCode::decode() {
   DLOG_IF(INFO, VLOG_IS_ON(4))
       << "Calling decode with max_buffer_size_ = " << max_buffer_size_;
 
-  fec_decode(code_, data, reinterpret_cast<int *>(index), max_buffer_size_);
+  fec_decode(code_, data, reinterpret_cast<int *>(index),
+             (int)max_buffer_size_);
 
   // Find the index in the block for recovered packets
   for (uint32_t i = 0, j = 0; i < k_; i++) {
@@ -228,6 +230,7 @@ void BlockCode::decode() {
     auto &packet = operator[](i).getBuffer();
     fec_metadata *metadata = reinterpret_cast<fec_metadata *>(
         packet->writableData() + max_buffer_size_ - METADATA_BYTES);
+    DCHECK(metadata->getPacketLength() <= packet->capacity());
     // Adjust buffer length
     packet->setLength(metadata->getPacketLength());
     // Adjust metadata
index 034c32b..6672eaa 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <arpa/inet.h>
 #include <hicn/transport/portability/c_portability.h>
+#include <hicn/transport/portability/endianess.h>
 #include <hicn/transport/utils/membuf.h>
 #include <protocols/fec/fec_info.h>
 #include <protocols/fec_base.h>
@@ -153,8 +154,10 @@ struct fec_header {
    */
   uint8_t padding;
 
-  void setSeqNumberBase(uint32_t suffix) { seq_number = htonl(suffix); }
-  uint32_t getSeqNumberBase() { return ntohl(seq_number); }
+  void setSeqNumberBase(uint32_t suffix) {
+    seq_number = portability::host_to_net(suffix);
+  }
+  uint32_t getSeqNumberBase() { return portability::net_to_host(seq_number); }
   void setEncodedSymbolId(uint8_t esi) { encoded_symbol_id = esi; }
   uint8_t getEncodedSymbolId() { return encoded_symbol_id; }
   void setSourceBlockLen(uint8_t k) { source_block_len = k; }
@@ -163,6 +166,8 @@ struct fec_header {
   uint8_t getNFecSymbols() { return n_fec_symbols; }
 };
 
+static_assert(sizeof(fec_header) <= 8, "fec_header is too large");
+
 class rs;
 
 /**
@@ -177,11 +182,17 @@ class BlockCode : public Packets {
    */
   class __attribute__((__packed__)) fec_metadata {
    public:
-    void setPacketLength(uint16_t length) { packet_length = htons(length); }
-    uint32_t getPacketLength() { return ntohs(packet_length); }
+    void setPacketLength(uint16_t length) {
+      packet_length = portability::host_to_net(length);
+    }
+    uint32_t getPacketLength() {
+      return portability::net_to_host(packet_length);
+    }
 
-    void setMetadataBase(uint32_t value) { metadata = htonl(value); }
-    uint32_t getMetadataBase() { return ntohl(metadata); }
+    void setMetadataBase(uint32_t value) {
+      metadata = portability::host_to_net(value);
+    }
+    uint32_t getMetadataBase() { return portability::net_to_host(metadata); }
 
    private:
     uint16_t packet_length; /* Used to get the real size of the packet after we
@@ -388,8 +399,11 @@ class RSEncoder : public rs, public ProducerFEC {
 
   /**
    * @brief Get the fec header size, if added to source packets
+   * in RS the source packets do not transport any FEC header
    */
-  std::size_t getFecHeaderSize() override { return 0; }
+  std::size_t getFecHeaderSize(bool isFEC) override {
+    return isFEC ? sizeof(fec_header) : 0;
+  }
 
   void clear() override {
     rs::clear();
@@ -435,8 +449,11 @@ class RSDecoder : public rs, public ConsumerFEC {
 
   /**
    * @brief Get the fec header size, if added to source packets
+   * in RS the source packets do not transport any FEC header
    */
-  std::size_t getFecHeaderSize() override { return 0; }
+  std::size_t getFecHeaderSize(bool isFEC) override {
+    return isFEC ? sizeof(fec_header) : 0;
+  }
 
   /**
    * Clear decoder to reuse
index bda3ee7..28f6a82 100644 (file)
@@ -101,8 +101,10 @@ class FECBase {
 
   /**
    * @brief Get size of FEC header.
+   * the fec header size may be different if a packet is a data packet or a FEC
+   * packet
    */
-  virtual std::size_t getFecHeaderSize() = 0;
+  virtual std::size_t getFecHeaderSize(bool isFEC) = 0;
 
   /**
    * Set callback to call after packet encoding / decoding
index b5ab818..0b15559 100644 (file)
@@ -66,40 +66,33 @@ void ManifestIncrementalIndexer::onUntrustedManifest(
     return;
   }
 
-  auto manifest =
-      std::make_unique<ContentObjectManifest>(std::move(content_object));
-  manifest->decode();
+  core::ContentObjectManifest manifest(content_object.shared_from_this());
+  manifest.decode();
 
-  processTrustedManifest(interest, std::move(manifest), reassembly);
+  processTrustedManifest(interest, manifest, reassembly);
 }
 
 void ManifestIncrementalIndexer::processTrustedManifest(
-    core::Interest &interest, std::unique_ptr<ContentObjectManifest> manifest,
+    core::Interest &interest, core::ContentObjectManifest &manifest,
     bool reassembly) {
-  if (TRANSPORT_EXPECT_FALSE(manifest->getVersion() !=
-                             core::ManifestVersion::VERSION_1)) {
-    throw errors::RuntimeException("Received manifest with unknown version.");
-  }
-
-  switch (manifest->getType()) {
+  switch (manifest.getType()) {
     case core::ManifestType::INLINE_MANIFEST: {
       suffix_strategy_->setFinalSuffix(
-          manifest->getParamsBytestream().final_segment);
+          manifest.getParamsBytestream().final_segment);
 
       // The packets to verify with the received manifest
       std::vector<auth::PacketPtr> packets;
 
       // Convert the received manifest to a map of packet suffixes to hashes
-      auth::Verifier::SuffixMap current_manifest =
-          core::ContentObjectManifest::getSuffixMap(manifest.get());
+      auth::Verifier::SuffixMap suffix_map = manifest.getSuffixMap();
 
       // Update 'suffix_map_' with new hashes from the received manifest and
       // build 'packets'
-      for (auto it = current_manifest.begin(); it != current_manifest.end();) {
+      for (auto it = suffix_map.begin(); it != suffix_map.end();) {
         if (unverified_segments_.find(it->first) ==
             unverified_segments_.end()) {
           suffix_map_[it->first] = std::move(it->second);
-          current_manifest.erase(it++);
+          suffix_map.erase(it++);
           continue;
         }
 
@@ -109,7 +102,7 @@ void ManifestIncrementalIndexer::processTrustedManifest(
 
       // Verify unverified segments using the received manifest
       auth::Verifier::PolicyMap policies =
-          verifier_->verifyPackets(packets, current_manifest);
+          verifier_->verifyPackets(packets, suffix_map);
 
       for (unsigned int i = 0; i < packets.size(); ++i) {
         auth::Suffix suffix = packets[i]->getName().getSuffix();
@@ -126,7 +119,9 @@ void ManifestIncrementalIndexer::processTrustedManifest(
       }
 
       if (reassembly) {
-        reassembly_->reassemble(std::move(manifest));
+        auto manifest_co =
+            std::dynamic_pointer_cast<ContentObject>(manifest.getPacket());
+        reassembly_->reassemble(*manifest_co);
       }
       break;
     }
index 12876f3..8527b55 100644 (file)
@@ -76,7 +76,7 @@ class ManifestIncrementalIndexer : public IncrementalIndexer {
                            core::ContentObject &content_object,
                            bool reassembly);
   void processTrustedManifest(core::Interest &interest,
-                              std::unique_ptr<ContentObjectManifest> manifest,
+                              core::ContentObjectManifest &manifest,
                               bool reassembly);
   void onUntrustedContentObject(core::Interest &interest,
                                 core::ContentObject &content_object,
index 2a3ec07..7f103e1 100644 (file)
@@ -111,18 +111,18 @@ uint32_t ByteStreamProductionProtocol::produceStream(
   uint64_t manifest_free_space;
   uint32_t nb_manifests;
   std::shared_ptr<core::ContentObjectManifest> manifest;
-  uint32_t manifest_capacity = making_manifest_;
+  uint32_t manifest_capacity = manifest_max_capacity_;
   bool is_last_manifest = false;
   ParamsBytestream transport_params;
 
   manifest_format = Packet::toAHFormat(default_format);
-  content_format =
-      !making_manifest_ ? Packet::toAHFormat(default_format) : default_format;
+  content_format = !manifest_max_capacity_ ? Packet::toAHFormat(default_format)
+                                           : default_format;
 
-  content_header_size =
-      core::Packet::getHeaderSizeFromFormat(content_format, signature_length);
-  manifest_header_size =
-      core::Packet::getHeaderSizeFromFormat(manifest_format, signature_length);
+  content_header_size = (uint32_t)core::Packet::getHeaderSizeFromFormat(
+      content_format, signature_length);
+  manifest_header_size = (uint32_t)core::Packet::getHeaderSizeFromFormat(
+      manifest_format, signature_length);
   content_free_space =
       std::min(max_segment_size, data_packet_size - content_header_size);
   manifest_free_space =
@@ -135,34 +135,39 @@ uint32_t ByteStreamProductionProtocol::produceStream(
     nb_segments++;
   }
 
-  if (making_manifest_) {
+  if (manifest_max_capacity_) {
     nb_manifests = static_cast<uint32_t>(
         std::ceil(float(nb_segments) / manifest_capacity));
     final_block_number += nb_segments + nb_manifests - 1;
     transport_params.final_segment =
         is_last ? final_block_number : utils::SuffixStrategy::MAX_SUFFIX;
 
-    manifest.reset(ContentObjectManifest::createManifest(
+    manifest = ContentObjectManifest::createContentManifest(
         manifest_format,
         name.setSuffix(suffix_strategy->getNextManifestSuffix()),
-        core::ManifestVersion::VERSION_1, core::ManifestType::INLINE_MANIFEST,
-        is_last_manifest, name, hash_algo, signature_length));
-
-    manifest->setLifetime(content_object_expiry_time);
+        signature_length);
+    manifest->setHeaders(core::ManifestType::INLINE_MANIFEST,
+                         manifest_max_capacity_, hash_algo, is_last_manifest,
+                         name);
     manifest->setParamsBytestream(transport_params);
+    manifest->getPacket()->setLifetime(content_object_expiry_time);
   }
 
   auto self = shared_from_this();
   for (unsigned int packaged_segments = 0; packaged_segments < nb_segments;
        packaged_segments++) {
-    if (making_manifest_) {
-      if (manifest->estimateManifestSize(1) > manifest_free_space) {
+    if (manifest_max_capacity_) {
+      if (manifest->Encoder::manifestSize(1) > manifest_free_space) {
         manifest->encode();
-        signer_->signPacket(manifest.get());
+        auto manifest_co =
+            std::dynamic_pointer_cast<ContentObject>(manifest->getPacket());
+
+        signer_->signPacket(manifest_co.get());
 
         // Send the current manifest
-        passContentObjectToCallbacks(manifest, self);
-        DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send manifest " << manifest->getName();
+        passContentObjectToCallbacks(manifest_co, self);
+        DLOG_IF(INFO, VLOG_IS_ON(3))
+            << "Send manifest " << manifest_co->getName();
 
         // Send content objects stored in the queue
         while (!content_queue_.empty()) {
@@ -175,15 +180,15 @@ uint32_t ByteStreamProductionProtocol::produceStream(
         // Create new manifest. The reference to the last manifest has been
         // acquired in the passContentObjectToCallbacks function, so we can
         // safely release this reference.
-        manifest.reset(ContentObjectManifest::createManifest(
+        manifest = ContentObjectManifest::createContentManifest(
             manifest_format,
             name.setSuffix(suffix_strategy->getNextManifestSuffix()),
-            core::ManifestVersion::VERSION_1,
-            core::ManifestType::INLINE_MANIFEST, is_last_manifest, name,
-            hash_algo, signature_length));
-
-        manifest->setLifetime(content_object_expiry_time);
+            signature_length);
+        manifest->setHeaders(core::ManifestType::INLINE_MANIFEST,
+                             manifest_max_capacity_, hash_algo,
+                             is_last_manifest, name);
         manifest->setParamsBytestream(transport_params);
+        manifest->getPacket()->setLifetime(content_object_expiry_time);
       }
     }
 
@@ -191,7 +196,7 @@ uint32_t ByteStreamProductionProtocol::produceStream(
     uint32_t content_suffix = suffix_strategy->getNextContentSuffix();
     auto content_object = std::make_shared<ContentObject>(
         name.setSuffix(content_suffix), content_format,
-        !making_manifest_ ? signature_length : 0);
+        !manifest_max_capacity_ ? signature_length : 0);
     content_object->setLifetime(content_object_expiry_time);
 
     auto b = buffer->cloneOne();
@@ -203,7 +208,7 @@ uint32_t ByteStreamProductionProtocol::produceStream(
       b->append(buffer_size - bytes_segmented);
       bytes_segmented += (int)(buffer_size - bytes_segmented);
 
-      if (is_last && making_manifest_) {
+      if (is_last && manifest_max_capacity_) {
         is_last_manifest = true;
       } else if (is_last) {
         content_object->setLast();
@@ -219,9 +224,9 @@ uint32_t ByteStreamProductionProtocol::produceStream(
 
     // Either we sign the content object or we save its hash into the current
     // manifest
-    if (making_manifest_) {
+    if (manifest_max_capacity_) {
       auth::CryptoHash hash = content_object->computeDigest(hash_algo);
-      manifest->addSuffixHash(content_suffix, hash);
+      manifest->addEntry(content_suffix, hash);
       content_queue_.push(content_object);
     } else {
       signer_->signPacket(content_object.get());
@@ -232,16 +237,19 @@ uint32_t ByteStreamProductionProtocol::produceStream(
   }
 
   // We send the manifest that hasn't been fully filled yet
-  if (making_manifest_) {
+  if (manifest_max_capacity_) {
     if (is_last_manifest) {
       manifest->setIsLast(is_last_manifest);
     }
 
     manifest->encode();
-    signer_->signPacket(manifest.get());
+    auto manifest_co =
+        std::dynamic_pointer_cast<ContentObject>(manifest->getPacket());
+
+    signer_->signPacket(manifest_co.get());
 
-    passContentObjectToCallbacks(manifest, self);
-    DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send manifest " << manifest->getName();
+    passContentObjectToCallbacks(manifest_co, self);
+    DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send manifest " << manifest_co->getName();
 
     while (!content_queue_.empty()) {
       passContentObjectToCallbacks(content_queue_.front(), self);
index e49f581..cb8dff6 100644 (file)
@@ -43,9 +43,6 @@ RTCProductionProtocol::RTCProductionProtocol(
       last_produced_data_ts_(0),
       last_round_(utils::SteadyTime::nowMs().count()),
       allow_delayed_nacks_(false),
-      queue_timer_on_(false),
-      consumer_in_sync_(false),
-      on_consumer_in_sync_(nullptr),
       pending_fec_pace_(false),
       max_len_(0),
       queue_len_(0),
@@ -54,8 +51,6 @@ RTCProductionProtocol::RTCProductionProtocol(
   std::uniform_int_distribution<> dis(0, 255);
   prod_label_ = dis(gen_);
   cache_label_ = (prod_label_ + 1) % 256;
-  interests_queue_timer_ =
-      std::make_unique<asio::steady_timer>(portal_->getThread().getIoService());
   round_timer_ =
       std::make_unique<asio::steady_timer>(portal_->getThread().getIoService());
   fec_pacing_timer_ =
@@ -69,16 +64,7 @@ RTCProductionProtocol::~RTCProductionProtocol() {}
 
 void RTCProductionProtocol::setProducerParam() {
   // Flow name: here we assume there is only one prefix registered in the portal
-  flow_name_ = portal_->getServedNamespaces().begin()->getName();
-
-  // Manifest
-  uint32_t making_manifest;
-  socket_->getSocketOption(interface::GeneralTransportOptions::MAKE_MANIFEST,
-                           making_manifest);
-
-  // Signer
-  std::shared_ptr<auth::Signer> signer;
-  socket_->getSocketOption(interface::GeneralTransportOptions::SIGNER, signer);
+  flow_name_ = portal_->getServedNamespaces().begin()->makeName();
 
   // Default format
   core::Packet::Format default_format;
@@ -94,15 +80,22 @@ void RTCProductionProtocol::setProducerParam() {
   socket_->getSocketOption(interface::RtcTransportOptions::AGGREGATED_DATA,
                            data_aggregation_);
 
-  size_t signature_size = signer->getSignatureFieldSize();
-  data_header_format_ = {
-      !making_manifest ? Packet::toAHFormat(default_format) : default_format,
-      !making_manifest ? signature_size : 0};
+  size_t signature_size = signer_->getSignatureFieldSize();
+  data_header_format_ = {!manifest_max_capacity_
+                             ? Packet::toAHFormat(default_format)
+                             : default_format,
+                         !manifest_max_capacity_ ? signature_size : 0};
   manifest_header_format_ = {Packet::toAHFormat(default_format),
                              signature_size};
   nack_header_format_ = {Packet::toAHFormat(default_format), signature_size};
   fec_header_format_ = {Packet::toAHFormat(default_format), signature_size};
 
+  // Initialize verifier for aggregated interests
+  std::shared_ptr<auth::Verifier> verifier;
+  socket_->getSocketOption(implementation::GeneralTransportOptions::VERIFIER,
+                           verifier);
+  verifier_ = std::make_shared<rtc::RTCVerifier>(verifier, 0, 0);
+
   // Schedule round timer
   scheduleRoundTimer();
 }
@@ -143,15 +136,17 @@ void RTCProductionProtocol::updateStats(bool new_round) {
   packets_production_rate_ =
       ceil((double)(produced_packets_ + prev_produced_packets_) * per_second);
 
-  // add fec packets looking at the fec code. we don't use directly the number
-  // of fec packets produced in 1 round because it may happen that different
-  // numbers of blocks are generated during the rounds and this creates
-  // inconsistencies in the estimation of the production rate
-  uint32_t k = fec::FECUtils::getSourceSymbols(fec_type_);
-  uint32_t n = fec::FECUtils::getBlockSymbols(fec_type_);
+  if (fec_encoder_ && fec_type_ != fec::FECType::UNKNOWN) {
+    // add fec packets looking at the fec code. we don't use directly the number
+    // of fec packets produced in 1 round because it may happen that different
+    // numbers of blocks are generated during the rounds and this creates
+    // inconsistencies in the estimation of the production rate
+    uint32_t k = fec::FECUtils::getSourceSymbols(fec_type_);
+    uint32_t n = fec::FECUtils::getBlockSymbols(fec_type_);
 
-  packets_production_rate_ +=
-      ceil((double)packets_production_rate_ / (double)k) * (n - k);
+    packets_production_rate_ +=
+        ceil((double)packets_production_rate_ / (double)k) * (n - k);
+  }
 
   // update the production rate as soon as it increases by 10% with respect to
   // the last round
@@ -168,11 +163,6 @@ void RTCProductionProtocol::updateStats(bool new_round) {
     allow_delayed_nacks_ = false;
   }
 
-  // check if the production rate is decreased. if yes send nacks if needed
-  if (prev_packets_production_rate < packets_production_rate_) {
-    sendNacksForPendingInterests();
-  }
-
   if (new_round) {
     prev_produced_bytes_ = produced_bytes_;
     prev_produced_packets_ = produced_packets_;
@@ -203,16 +193,25 @@ void RTCProductionProtocol::produce(ContentObject &content_object) {
 uint32_t RTCProductionProtocol::produceDatagram(
     const Name &content_name, std::unique_ptr<utils::MemBuf> &&buffer) {
   std::size_t buffer_size = buffer->length();
+  DLOG_IF(INFO, VLOG_IS_ON(3))
+      << "Maybe Sending content object: " << content_name;
+
   if (TRANSPORT_EXPECT_FALSE(buffer_size == 0)) return 0;
 
+  DLOG_IF(INFO, VLOG_IS_ON(3)) << "Sending content object: " << content_name;
+
   uint32_t data_packet_size;
   socket_->getSocketOption(interface::GeneralTransportOptions::DATA_PACKET_SIZE,
                            data_packet_size);
-
-  if (TRANSPORT_EXPECT_FALSE(
-          (Packet::getHeaderSizeFromFormat(data_header_format_.first,
-                                           data_header_format_.second) +
-           rtc::DATA_HEADER_SIZE + buffer_size) > data_packet_size)) {
+  // this is a source packet but we check the fec header size of FEC packet in
+  // order to leave room for the header when FEC packets will be generated
+  uint32_t fec_header = 0;
+  if (fec_encoder_) fec_encoder_->getFecHeaderSize(true);
+  uint32_t headers_size =
+      (uint32_t)Packet::getHeaderSizeFromFormat(data_header_format_.first,
+                                                data_header_format_.second) +
+      rtc::DATA_HEADER_SIZE + fec_header;
+  if (TRANSPORT_EXPECT_FALSE((headers_size + buffer_size) > data_packet_size)) {
     return 0;
   }
 
@@ -338,47 +337,42 @@ void RTCProductionProtocol::emptyQueue() {
 }
 
 void RTCProductionProtocol::sendManifest(const Name &name) {
-  if (!making_manifest_) {
+  if (!manifest_max_capacity_) {
     return;
   }
 
-  Name manifest_name(name);
-
-  uint32_t data_packet_size;
-  socket_->getSocketOption(interface::GeneralTransportOptions::DATA_PACKET_SIZE,
-                           data_packet_size);
-
-  // The maximum number of entries a manifest can hold
-  uint32_t manifest_capacity = making_manifest_;
+  Name manifest_name = name;
 
   // If there is not enough hashes to fill a manifest, return early
-  if (manifest_entries_.size() < manifest_capacity) {
+  if (manifest_entries_.size() < manifest_max_capacity_) {
     return;
   }
 
   // Create a new manifest
   std::shared_ptr<core::ContentObjectManifest> manifest =
       createManifest(manifest_name.setSuffix(current_seg_));
+  auto manifest_co =
+      std::dynamic_pointer_cast<ContentObject>(manifest->getPacket());
 
   // Fill the manifest with packet hashes that were previously saved
   uint32_t nb_entries;
-  for (nb_entries = 0; nb_entries < manifest_capacity; ++nb_entries) {
+  for (nb_entries = 0; nb_entries < manifest_max_capacity_; ++nb_entries) {
     if (manifest_entries_.empty()) {
       break;
     }
     std::pair<uint32_t, auth::CryptoHash> front = manifest_entries_.front();
-    manifest->addSuffixHash(front.first, front.second);
+    manifest->addEntry(front.first, front.second);
     manifest_entries_.pop();
   }
 
   DLOG_IF(INFO, VLOG_IS_ON(3))
-      << "Sending manifest " << manifest->getName().getSuffix() << " of size "
-      << nb_entries;
+      << "Sending manifest " << manifest_co->getName().getSuffix()
+      << " of size " << nb_entries;
 
   // Encode and send the manifest
   manifest->encode();
   portal_->getThread().tryRunHandlerNow(
-      [this, content_object{std::move(manifest)}, manifest_name]() mutable {
+      [this, content_object{std::move(manifest_co)}, manifest_name]() mutable {
         produceInternal(std::move(content_object), manifest_name);
       });
 }
@@ -394,11 +388,12 @@ RTCProductionProtocol::createManifest(const Name &content_name) const {
   uint64_t now = utils::SteadyTime::nowMs().count();
 
   // Create a new manifest
-  std::shared_ptr<core::ContentObjectManifest> manifest(
-      ContentObjectManifest::createManifest(
-          manifest_header_format_.first, name, core::ManifestVersion::VERSION_1,
-          core::ManifestType::INLINE_MANIFEST, false, name, hash_algo,
-          manifest_header_format_.second));
+  std::shared_ptr<core::ContentObjectManifest> manifest =
+      ContentObjectManifest::createContentManifest(
+          manifest_header_format_.first, name, manifest_header_format_.second);
+  manifest->setHeaders(core::ManifestType::INLINE_MANIFEST,
+                       manifest_max_capacity_, hash_algo, false /* is_last */,
+                       name);
 
   // Set connection parameters
   manifest->setParamsRTC(ParamsRTC{
@@ -444,7 +439,15 @@ void RTCProductionProtocol::producePktInternal(
   // set hicn stuff
   Name n(content_name);
   content_object->setName(n.setSuffix(current_seg_));
-  content_object->setLifetime(500);  // XXX this should be set by the APP
+
+  uint32_t expiry_time = 0;
+  socket_->getSocketOption(
+      interface::GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME,
+      expiry_time);
+  if (expiry_time == interface::default_values::content_object_expiry_time)
+    expiry_time = 500;  // the data expiration time should be set by the App. if
+                        // the App does not specify it the default is 500ms
+  content_object->setLifetime(expiry_time);
   content_object->setPathLabel(prod_label_);
 
   // update stats
@@ -466,9 +469,9 @@ void RTCProductionProtocol::producePktInternal(
 
   // pass packet to FEC encoder
   if (fec_encoder_ && !fec) {
-    uint32_t offset =
-        is_manifest ? content_object->headerSize()
-                    : content_object->headerSize() + rtc::DATA_HEADER_SIZE;
+    uint32_t offset = is_manifest ? (uint32_t)content_object->headerSize()
+                                  : (uint32_t)content_object->headerSize() +
+                                        rtc::DATA_HEADER_SIZE;
     uint32_t metadata = static_cast<uint32_t>(content_object->getPayloadType());
 
     fec_encoder_->onPacketProduced(*content_object, offset, metadata);
@@ -481,19 +484,14 @@ void RTCProductionProtocol::producePktInternal(
                                                     *content_object);
   }
 
-  auto seq_it = seqs_map_.find(current_seg_);
-  if (seq_it != seqs_map_.end()) {
-    sendContentObject(content_object, false, fec);
-  }
+  // TODO we may want to send FEC only if an interest is pending in the pit in
+  sendContentObject(content_object, false, fec);
 
   if (*on_content_object_output_) {
     on_content_object_output_->operator()(*socket_->getInterface(),
                                           *content_object);
   }
 
-  // remove interests from the interest cache if it exists
-  removeFromInterestQueue(current_seg_);
-
   if (!fec) last_produced_data_ts_ = now;
 
   // Update current segment
@@ -563,59 +561,65 @@ void RTCProductionProtocol::onInterest(Interest &interest) {
     on_interest_input_->operator()(*socket_->getInterface(), interest);
   }
 
-  auto suffix = interest.firstSuffix();
-  // numberOfSuffixes returns only the prefixes in the payalod
-  // we add + 1 to count also the seq in the name
-  auto n_suffixes = interest.numberOfSuffixes() + 1;
-  Name name = interest.getName();
-  bool prev_consumer_state = consumer_in_sync_;
-
-  for (uint32_t i = 0; i < n_suffixes; i++) {
-    if (i > 0) {
-      name.setSuffix(*(suffix + (i - 1)));
-    }
+  if (!interest.isValid()) throw std::runtime_error("Bad interest format");
+  if (interest.hasManifest() &&
+      verifier_->verify(interest) != auth::VerificationPolicy::ACCEPT)
+    throw std::runtime_error("Interset manifest verification failed");
 
-    DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received interest " << name;
+  uint32_t *suffix = interest.firstSuffix();
+  uint32_t n_suffixes_in_manifest = interest.numberOfSuffixes();
+  uint32_t *request_bitmap = interest.getRequestBitmap();
 
-    const std::shared_ptr<ContentObject> content_object =
-        output_buffer_.find(name);
+  Name name = interest.getName();
+  uint32_t pos = 0;  // Position of current suffix in manifest
 
-    if (content_object) {
-      if (*on_interest_satisfied_output_buffer_) {
-        on_interest_satisfied_output_buffer_->operator()(
-            *socket_->getInterface(), interest);
-      }
+  DLOG_IF(INFO, VLOG_IS_ON(3))
+      << "Received interest " << name << " (" << n_suffixes_in_manifest
+      << " suffixes in manifest)";
+
+  // Process the suffix in the interest header
+  // (first loop iteration), then suffixes in the manifest
+  do {
+    if (!interest.hasManifest() || is_bit_set(request_bitmap, pos)) {
+      const std::shared_ptr<ContentObject> content_object =
+          output_buffer_.find(name);
+
+      if (content_object) {
+        if (*on_interest_satisfied_output_buffer_) {
+          on_interest_satisfied_output_buffer_->operator()(
+              *socket_->getInterface(), interest);
+        }
 
-      if (*on_content_object_output_) {
-        on_content_object_output_->operator()(*socket_->getInterface(),
-                                              *content_object);
-      }
+        if (*on_content_object_output_) {
+          on_content_object_output_->operator()(*socket_->getInterface(),
+                                                *content_object);
+        }
 
-      DLOG_IF(INFO, VLOG_IS_ON(3))
-          << "Send content %u (onInterest) " << content_object->getName();
-      content_object->setPathLabel(cache_label_);
-      sendContentObject(content_object);
-    } else {
-      if (*on_interest_process_) {
-        on_interest_process_->operator()(*socket_->getInterface(), interest);
+        DLOG_IF(INFO, VLOG_IS_ON(3))
+            << "Send content %u (onInterest) " << content_object->getName();
+        content_object->setPathLabel(cache_label_);
+        sendContentObject(content_object);
+      } else {
+        if (*on_interest_process_) {
+          on_interest_process_->operator()(*socket_->getInterface(), interest);
+        }
+        processInterest(name.getSuffix(), interest.getLifetime());
       }
-      processInterest(name.getSuffix(), interest.getLifetime());
     }
-  }
 
-  if (prev_consumer_state != consumer_in_sync_ && consumer_in_sync_)
-    on_consumer_in_sync_(*socket_->getInterface(), interest);
+    // Retrieve next suffix in the manifest
+    if (interest.hasManifest()) {
+      uint32_t seq = *suffix;
+      suffix++;
+
+      name.setSuffix(seq);
+      interest.setName(name);
+    }
+  } while (pos++ < n_suffixes_in_manifest);
 }
 
 void RTCProductionProtocol::processInterest(uint32_t interest_seg,
                                             uint32_t lifetime) {
-  if (interest_seg == 0) {
-    // first packet from the consumer, reset sync state
-    consumer_in_sync_ = false;
-  }
-
-  uint64_t now = utils::SteadyTime::nowMs().count();
-
   switch (rtc::ProbeHandler::getProbeType(interest_seg)) {
     case rtc::ProbeType::INIT:
       DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received init probe " << interest_seg;
@@ -629,183 +633,7 @@ void RTCProductionProtocol::processInterest(uint32_t interest_seg,
       break;
   }
 
-  // if the production rate 0 use delayed nacks
-  if (allow_delayed_nacks_ && interest_seg >= current_seg_) {
-    uint64_t next_timer = UINT64_MAX;
-    if (!timers_map_.empty()) {
-      next_timer = timers_map_.begin()->first;
-    }
-
-    uint64_t expiration = now + rtc::NACK_DELAY;
-    addToInterestQueue(interest_seg, expiration);
-
-    // here we have at least one interest in the queue, we need to start or
-    // update the timer
-    if (!queue_timer_on_) {
-      // set timeout
-      queue_timer_on_ = true;
-      scheduleQueueTimer(timers_map_.begin()->first - now);
-    } else {
-      // re-schedule the timer because a new interest will expires sooner
-      if (next_timer > timers_map_.begin()->first) {
-        interests_queue_timer_->cancel();
-        scheduleQueueTimer(timers_map_.begin()->first - now);
-      }
-    }
-    return;
-  }
-
-  if (queue_timer_on_) {
-    // the producer is producing. Send nacks to packets that will expire
-    // before the data production and remove the timer
-    queue_timer_on_ = false;
-    interests_queue_timer_->cancel();
-    sendNacksForPendingInterests();
-  }
-
-  uint32_t max_gap = (uint32_t)floor(
-      (double)((double)((double)lifetime *
-                        rtc::INTEREST_LIFETIME_REDUCTION_FACTOR /
-                        rtc::MILLI_IN_A_SEC) *
-               (double)(packets_production_rate_)));
-
-  if (interest_seg < current_seg_ || interest_seg > (max_gap + current_seg_)) {
-    sendNack(interest_seg);
-  } else {
-    if (!consumer_in_sync_ && on_consumer_in_sync_) {
-      // we consider the remote consumer to be in sync as soon as it covers
-      // 70% of the production window with interests
-      uint32_t perc = ceil((double)max_gap * 0.7);
-      if (interest_seg > (perc + current_seg_)) {
-        consumer_in_sync_ = true;
-        // on_consumer_in_sync_(*socket_->getInterface(), interest);
-      }
-    }
-    uint64_t expiration =
-        now + floor((double)lifetime * rtc::INTEREST_LIFETIME_REDUCTION_FACTOR);
-    addToInterestQueue(interest_seg, expiration);
-  }
-}
-
-void RTCProductionProtocol::scheduleQueueTimer(uint64_t wait) {
-  interests_queue_timer_->expires_from_now(std::chrono::milliseconds(wait));
-  std::weak_ptr<RTCProductionProtocol> self = shared_from_this();
-  interests_queue_timer_->async_wait([self](const std::error_code &ec) {
-    if (ec) {
-      return;
-    }
-
-    auto sp = self.lock();
-    if (sp && sp->isRunning()) {
-      sp->interestQueueTimer();
-    }
-  });
-}
-
-void RTCProductionProtocol::addToInterestQueue(uint32_t interest_seg,
-                                               uint64_t expiration) {
-  // check if the seq number exists already
-  auto it_seqs = seqs_map_.find(interest_seg);
-  if (it_seqs != seqs_map_.end()) {
-    // the seq already exists
-    if (expiration < it_seqs->second) {
-      // we need to update the timer becasue we got a smaller one
-      // 1) remove the entry from the multimap
-      // 2) update this entry
-      auto range = timers_map_.equal_range(it_seqs->second);
-      for (auto it_timers = range.first; it_timers != range.second;
-           it_timers++) {
-        if (it_timers->second == it_seqs->first) {
-          timers_map_.erase(it_timers);
-          break;
-        }
-      }
-      timers_map_.insert(
-          std::pair<uint64_t, uint32_t>(expiration, interest_seg));
-      it_seqs->second = expiration;
-    } else {
-      // nothing to do here
-      return;
-    }
-  } else {
-    // add the new seq
-    timers_map_.insert(std::pair<uint64_t, uint32_t>(expiration, interest_seg));
-    seqs_map_.insert(std::pair<uint32_t, uint64_t>(interest_seg, expiration));
-  }
-}
-
-void RTCProductionProtocol::sendNacksForPendingInterests() {
-  std::unordered_set<uint32_t> to_remove;
-
-  uint32_t pps = ceil((double)(packets_production_rate_)*rtc::
-                          INTEREST_LIFETIME_REDUCTION_FACTOR);
-
-  uint64_t now = utils::SteadyTime::nowMs().count();
-  for (auto it = seqs_map_.begin(); it != seqs_map_.end(); it++) {
-    if (it->first > current_seg_ && it->second > now) {
-      double exp_time_in_sec =
-          (double)(it->second - now) / (double)rtc::MILLI_IN_A_SEC;
-      uint32_t packets_prod_before_expire = ceil((double)pps * exp_time_in_sec);
-
-      if (it->first > (current_seg_ + packets_prod_before_expire)) {
-        sendNack(it->first);
-        to_remove.insert(it->first);
-      }
-    } else if (TRANSPORT_EXPECT_FALSE(it->first < current_seg_ ||
-                                      it->second <= now)) {
-      // this branch should never be execcuted
-      // first condition: the packet was already prdocued and we have and old
-      // interest pending. send a nack to notify the consumer if needed. the
-      // case it->first = current_seg_ is not handled because
-      // the interest will be satified by the next data packet.
-      // second condition: the interest is expired.
-      sendNack(it->first);
-      to_remove.insert(it->first);
-    }
-  }
-
-  // delete nacked interests
-  for (auto it = to_remove.begin(); it != to_remove.end(); it++) {
-    removeFromInterestQueue(*it);
-  }
-}
-
-void RTCProductionProtocol::removeFromInterestQueue(uint32_t interest_seg) {
-  auto seq_it = seqs_map_.find(interest_seg);
-  if (seq_it != seqs_map_.end()) {
-    auto range = timers_map_.equal_range(seq_it->second);
-    for (auto it_timers = range.first; it_timers != range.second; it_timers++) {
-      if (it_timers->second == seq_it->first) {
-        timers_map_.erase(it_timers);
-        break;
-      }
-    }
-    seqs_map_.erase(seq_it);
-  }
-}
-
-void RTCProductionProtocol::interestQueueTimer() {
-  uint64_t now = utils::SteadyTime::nowMs().count();
-
-  for (auto it_timers = timers_map_.begin(); it_timers != timers_map_.end();) {
-    uint64_t expire = it_timers->first;
-    if (expire <= now) {
-      uint32_t seq = it_timers->second;
-      sendNack(seq);
-      // remove the interest from the other map
-      seqs_map_.erase(seq);
-      it_timers = timers_map_.erase(it_timers);
-    } else {
-      // stop, we are done!
-      break;
-    }
-  }
-  if (timers_map_.empty()) {
-    queue_timer_on_ = false;
-  } else {
-    queue_timer_on_ = true;
-    scheduleQueueTimer(timers_map_.begin()->first - now);
-  }
+  if (interest_seg < current_seg_) sendNack(interest_seg);
 }
 
 void RTCProductionProtocol::sendManifestProbe(uint32_t sequence) {
@@ -814,18 +642,20 @@ void RTCProductionProtocol::sendManifestProbe(uint32_t sequence) {
 
   std::shared_ptr<core::ContentObjectManifest> manifest_probe =
       createManifest(manifest_name);
+  auto manifest_probe_co =
+      std::dynamic_pointer_cast<ContentObject>(manifest_probe->getPacket());
 
-  manifest_probe->setLifetime(0);
-  manifest_probe->setPathLabel(prod_label_);
+  manifest_probe_co->setLifetime(0);
+  manifest_probe_co->setPathLabel(prod_label_);
   manifest_probe->encode();
 
   if (*on_content_object_output_) {
     on_content_object_output_->operator()(*socket_->getInterface(),
-                                          *manifest_probe);
+                                          *manifest_probe_co);
   }
 
   DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send init probe " << sequence;
-  sendContentObject(manifest_probe, true, false);
+  sendContentObject(manifest_probe_co, true, false);
 }
 
 void RTCProductionProtocol::sendNack(uint32_t sequence) {
@@ -847,20 +677,6 @@ void RTCProductionProtocol::sendNack(uint32_t sequence) {
   nack->setLifetime(0);
   nack->setPathLabel(prod_label_);
 
-  if (!consumer_in_sync_ && on_consumer_in_sync_ &&
-      rtc::ProbeHandler::getProbeType(sequence) == rtc::ProbeType::NOT_PROBE &&
-      sequence > next_packet) {
-    consumer_in_sync_ = true;
-    Packet::Format format;
-    socket_->getSocketOption(interface::GeneralTransportOptions::PACKET_FORMAT,
-                             format);
-
-    auto interest =
-        core::PacketManager<>::getInstance().getPacket<Interest>(format);
-    interest->setName(n);
-    on_consumer_in_sync_(*socket_->getInterface(), *interest);
-  }
-
   if (*on_content_object_output_) {
     on_content_object_output_->operator()(*socket_->getInterface(), *nack);
   }
@@ -881,7 +697,7 @@ void RTCProductionProtocol::sendContentObject(
   portal_->sendContentObject(*content_object);
 
   // Compute and save data packet digest
-  if (making_manifest_ && !is_ah) {
+  if (manifest_max_capacity_ && !is_ah) {
     auth::CryptoHashType hash_algo;
     socket_->getSocketOption(interface::GeneralTransportOptions::HASH_ALGORITHM,
                              hash_algo);
index c0424a3..285ccb6 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <hicn/transport/core/name.h>
 #include <protocols/production_protocol.h>
+#include <protocols/rtc/rtc_verifier.h>
 
 #include <atomic>
 #include <map>
@@ -50,11 +51,6 @@ class RTCProductionProtocol : public ProductionProtocol {
                                              buffer, buffer_size, buffer_size));
   }
 
-  void setConsumerInSyncCallback(
-      interface::ProducerInterestCallback &&callback) {
-    on_consumer_in_sync_ = std::move(callback);
-  }
-
   auto shared_from_this() { return utils::shared_from(this); }
 
  private:
@@ -80,13 +76,6 @@ class RTCProductionProtocol : public ProductionProtocol {
   void updateStats(bool new_round);
   void scheduleRoundTimer();
 
-  // pending intersts functions
-  void addToInterestQueue(uint32_t interest_seg, uint64_t expiration);
-  void sendNacksForPendingInterests();
-  void removeFromInterestQueue(uint32_t interest_seg);
-  void scheduleQueueTimer(uint64_t wait);
-  void interestQueueTimer();
-
   // FEC functions
   void onFecPackets(fec::BufferArray &packets);
   fec::buffer getBuffer(std::size_t size);
@@ -111,14 +100,14 @@ class RTCProductionProtocol : public ProductionProtocol {
   uint32_t prev_produced_bytes_;  // XXX clearly explain all these new vars
   uint32_t prev_produced_packets_;
 
-  uint32_t produced_bytes_;        // bytes produced in the last round
-  uint32_t produced_packets_;      // packet produed in the last round
+  uint32_t produced_bytes_;    // bytes produced in the last round
+  uint32_t produced_packets_;  // packet produed in the last round
 
   uint32_t max_packet_production_;  // never exceed this number of packets
                                     // without update stats
 
-  uint32_t bytes_production_rate_;        // bytes per sec
-  uint32_t packets_production_rate_;      // pps
+  uint32_t bytes_production_rate_;    // bytes per sec
+  uint32_t packets_production_rate_;  // pps
 
   uint64_t last_produced_data_ts_;  // ms
 
@@ -134,27 +123,6 @@ class RTCProductionProtocol : public ProductionProtocol {
   // of the new rate.
   bool allow_delayed_nacks_;
 
-  // queue for the received interests
-  // this map maps the expiration time of an interest to
-  // its sequence number. the map is sorted by timeouts
-  // the same timeout may be used for multiple sequence numbers
-  // but for each sequence number we store only the smallest
-  // expiry time. In this way the mapping from seqs_map_ to
-  // timers_map_ is unique
-  std::multimap<uint64_t, uint32_t> timers_map_;
-
-  // this map does the opposite, this map is not ordered
-  std::unordered_map<uint32_t, uint64_t> seqs_map_;
-  bool queue_timer_on_;
-  std::unique_ptr<asio::steady_timer> interests_queue_timer_;
-
-  // this callback is called when the remote consumer is in sync with high
-  // probability. it is called only the first time that the switch happen.
-  // XXX this makes sense only in P2P mode, while in standard mode is
-  // impossible to know the state of the consumers so it should not be used.
-  bool consumer_in_sync_;
-  interface::ProducerInterestCallback on_consumer_in_sync_;
-
   // Save FEC packets here before sending them
   std::queue<ContentObject::Ptr> pending_fec_packets_;
   std::queue<std::pair<uint64_t, ContentObject::Ptr>> paced_fec_packets_;
@@ -172,6 +140,9 @@ class RTCProductionProtocol : public ProductionProtocol {
   // Manifest
   std::queue<std::pair<uint32_t, auth::CryptoHash>>
       manifest_entries_;  // map a packet suffix to a packet hash
+
+  // Verifier for aggregated interests
+  std::shared_ptr<rtc::RTCVerifier> verifier_;
 };
 
 }  // namespace protocol
index 8b781e3..039a6a5 100644 (file)
@@ -78,8 +78,8 @@ int ProductionProtocol::start() {
 
     socket_->getSocketOption(GeneralTransportOptions::ASYNC_MODE, is_async_);
     socket_->getSocketOption(GeneralTransportOptions::SIGNER, signer_);
-    socket_->getSocketOption(GeneralTransportOptions::MAKE_MANIFEST,
-                             making_manifest_);
+    socket_->getSocketOption(GeneralTransportOptions::MANIFEST_MAX_CAPACITY,
+                             manifest_max_capacity_);
 
     std::string fec_type_str = "";
     socket_->getSocketOption(GeneralTransportOptions::FEC_TYPE, fec_type_str);
index 8e10d2f..0971863 100644 (file)
@@ -79,6 +79,7 @@ class ProductionProtocol
       if (fec_str && (fec_type_ == fec::FECType::UNKNOWN)) {
         LOG(INFO) << "Using FEC " << fec_str;
         fec_type_ = fec::FECUtils::fecTypeFromString(fec_str);
+        CHECK(fec_type_ != fec::FECType::UNKNOWN);
       }
 
       if (fec_type_ == fec::FECType::UNKNOWN) {
@@ -123,7 +124,7 @@ class ProductionProtocol
 
   // Signature and manifest
   std::shared_ptr<auth::Signer> signer_;
-  uint32_t making_manifest_;
+  uint32_t manifest_max_capacity_;
 
   bool is_async_;
   fec::FECType fec_type_;
index 131367d..bcbc15a 100644 (file)
@@ -371,7 +371,7 @@ void RaaqmTransportProtocol::onPacketDropped(Interest &interest,
     }
 
     interest_retransmissions_[segment & mask]++;
-    interest_to_retransmit_.push(segment);
+    interest_to_retransmit_.push((unsigned int)segment);
   } else {
     LOG(ERROR) << "Stop: received not trusted packet "
                << interest_retransmissions_[segment & mask] << " times";
@@ -429,7 +429,7 @@ void RaaqmTransportProtocol::onInterestTimeout(Interest::Ptr &interest,
       return;
     }
 
-    interest_to_retransmit_.push(segment);
+    interest_to_retransmit_.push((unsigned int)segment);
     scheduleNextInterests();
   } else {
     LOG(ERROR) << "Stop: reached max retx limit.";
@@ -491,7 +491,7 @@ void RaaqmTransportProtocol::updateRtt(uint64_t segment) {
     throw std::runtime_error("RAAQM ERROR: no current path found, exit");
   } else {
     auto now = utils::SteadyTime::Clock::now();
-    utils::SteadyTime::Milliseconds rtt = utils::SteadyTime::getDurationMs(
+    auto rtt = utils::SteadyTime::getDurationUs(
         interest_timepoints_[segment & mask], now);
 
     // Update stats
@@ -525,7 +525,7 @@ void RaaqmTransportProtocol::RAAQM() {
 }
 
 void RaaqmTransportProtocol::updateStats(
-    uint32_t suffix, const utils::SteadyTime::Milliseconds &rtt,
+    uint32_t suffix, const utils::SteadyTime::Microseconds &rtt,
     utils::SteadyTime::TimePoint &now) {
   // Update RTT statistics
   stats_->updateAverageRtt(rtt);
index ec344c2..a7ef23b 100644 (file)
@@ -57,7 +57,7 @@ class RaaqmTransportProtocol : public TransportProtocol,
   virtual void afterDataUnsatisfied(uint64_t segment);
 
   virtual void updateStats(uint32_t suffix,
-                           const utils::SteadyTime::Milliseconds &rtt,
+                           const utils::SteadyTime::Microseconds &rtt,
                            utils::SteadyTime::TimePoint &now);
 
  private:
index d06fee9..b8e6e62 100644 (file)
@@ -50,9 +50,9 @@ RaaqmDataPath::RaaqmDataPath(double drop_factor,
       alpha_(ALPHA) {}
 
 RaaqmDataPath &RaaqmDataPath::insertNewRtt(
-    const utils::SteadyTime::Milliseconds &new_rtt,
+    const utils::SteadyTime::Microseconds &new_rtt,
     const utils::SteadyTime::TimePoint &now) {
-  rtt_ = new_rtt.count();
+  rtt_ = new_rtt.count() / 1000;
   rtt_samples_.pushBack(rtt_);
 
   rtt_max_ = rtt_samples_.rBegin();
index b6f7c5a..dd24dad 100644 (file)
@@ -49,7 +49,7 @@ class RaaqmDataPath {
    * max of RTT.
    * @param new_rtt is the value of the new RTT
    */
-  RaaqmDataPath &insertNewRtt(const utils::SteadyTime::Milliseconds &new_rtt,
+  RaaqmDataPath &insertNewRtt(const utils::SteadyTime::Microseconds &new_rtt,
                               const utils::SteadyTime::TimePoint &now);
 
   /**
index d834b53..01c18c6 100644 (file)
@@ -107,9 +107,9 @@ InterRttEstimator::~InterRttEstimator() {
 }
 
 void InterRttEstimator::onRttUpdate(
-    const utils::SteadyTime::Milliseconds &rtt) {
+    const utils::SteadyTime::Microseconds &rtt) {
   pthread_mutex_lock(&(this->mutex_));
-  this->rtt_ = rtt.count();
+  this->rtt_ = rtt.count() / 1000.0;
   this->number_of_packets_++;
   this->avg_rtt_ += this->rtt_;
   pthread_mutex_unlock(&(this->mutex_));
@@ -256,7 +256,7 @@ void SimpleEstimator::onDataReceived(int packet_size) {
   this->total_size_ += packet_size;
 }
 
-void SimpleEstimator::onRttUpdate(const utils::SteadyTime::Milliseconds &rtt) {
+void SimpleEstimator::onRttUpdate(const utils::SteadyTime::Microseconds &rtt) {
   this->number_of_packets_++;
 
   if (this->number_of_packets_ == this->batching_param_) {
@@ -300,9 +300,9 @@ BatchingPacketsEstimator::BatchingPacketsEstimator(double alpha_arg,
 }
 
 void BatchingPacketsEstimator::onRttUpdate(
-    const utils::SteadyTime::Milliseconds &rtt) {
+    const utils::SteadyTime::Microseconds &rtt) {
   this->number_of_packets_++;
-  this->avg_rtt_ += rtt.count();
+  this->avg_rtt_ += rtt.count() / 1000.0;
 
   if (number_of_packets_ == this->batching_param_) {
     if (estimation_ == 0) {
index b71de12..d809b2b 100644 (file)
@@ -31,7 +31,7 @@ class IcnRateEstimator : utils::NonCopyable {
 
   virtual ~IcnRateEstimator(){};
 
-  virtual void onRttUpdate(const utils::SteadyTime::Milliseconds &rtt){};
+  virtual void onRttUpdate(const utils::SteadyTime::Microseconds &rtt){};
 
   virtual void onDataReceived(int packetSize){};
 
@@ -66,7 +66,7 @@ class InterRttEstimator : public IcnRateEstimator {
 
   ~InterRttEstimator();
 
-  void onRttUpdate(const utils::SteadyTime::Milliseconds &rtt);
+  void onRttUpdate(const utils::SteadyTime::Microseconds &rtt);
 
   void onDataReceived(int packet_size) {
     if (packet_size > this->max_packet_size_) {
@@ -101,7 +101,7 @@ class BatchingPacketsEstimator : public IcnRateEstimator {
  public:
   BatchingPacketsEstimator(double alpha_arg, int batchingParam);
 
-  void onRttUpdate(const utils::SteadyTime::Milliseconds &rtt);
+  void onRttUpdate(const utils::SteadyTime::Microseconds &rtt);
 
   void onDataReceived(int packet_size) {
     if (packet_size > this->max_packet_size_) {
@@ -148,7 +148,7 @@ class SimpleEstimator : public IcnRateEstimator {
  public:
   SimpleEstimator(double alpha, int batching_param);
 
-  void onRttUpdate(const utils::SteadyTime::Milliseconds &rtt);
+  void onRttUpdate(const utils::SteadyTime::Microseconds &rtt);
 
   void onDataReceived(int packet_size);
 
index b087920..c0c4de3 100644 (file)
@@ -56,12 +56,6 @@ class Reassembly {
    */
   virtual void reassemble(utils::MemBuf &buffer, uint32_t suffix) = 0;
 
-  /**
-   * Handle reassembly of manifest
-   */
-  virtual void reassemble(
-      std::unique_ptr<core::ContentObjectManifest> &&manifest) = 0;
-
   /**
    * Reset reassembler for new round
    */
index 6a84914..60eceeb 100644 (file)
@@ -13,6 +13,7 @@
  * limitations under the License.
  */
 
+#include <glog/logging.h>
 #include <hicn/transport/utils/chrono_typedefs.h>
 #include <protocols/rtc/probe_handler.h>
 #include <protocols/rtc/rtc_consts.h>
@@ -64,7 +65,7 @@ double ProbeHandler::getProbeLossRate() {
 }
 
 void ProbeHandler::setSuffixRange(uint32_t min, uint32_t max) {
-  assert(min <= max && min >= MIN_PROBE_SEQ);
+  DCHECK(min <= max && min >= MIN_PROBE_SEQ);
   distr_ = std::uniform_int_distribution<uint32_t>(min, max);
 }
 
index d2682ed..9a56269 100644 (file)
@@ -38,6 +38,7 @@ RTCTransportProtocol::RTCTransportProtocol(
     implementation::ConsumerSocket *icn_socket)
     : TransportProtocol(icn_socket, new RtcIndexer<>(icn_socket, this),
                         new RtcReassembly(icn_socket, this)),
+      max_aggregated_interest_(1),
       number_(0) {
   icn_socket->getSocketOption(PORTAL, portal_);
   round_timer_ =
@@ -55,9 +56,9 @@ void RTCTransportProtocol::resume() {
   TransportProtocol::resume();
 }
 
-std::size_t RTCTransportProtocol::transportHeaderLength() {
+std::size_t RTCTransportProtocol::transportHeaderLength(bool isFEC) {
   return DATA_HEADER_SIZE +
-         (fec_decoder_ != nullptr ? fec_decoder_->getFecHeaderSize() : 0);
+         (fec_decoder_ != nullptr ? fec_decoder_->getFecHeaderSize(isFEC) : 0);
 }
 
 // private
@@ -75,13 +76,13 @@ void RTCTransportProtocol::initParams() {
   std::shared_ptr<auth::Verifier> verifier;
   socket_->getSocketOption(GeneralTransportOptions::VERIFIER, verifier);
 
-  uint32_t unverified_interval;
-  socket_->getSocketOption(GeneralTransportOptions::UNVERIFIED_INTERVAL,
-                           unverified_interval);
+  uint32_t factor_relevant;
+  socket_->getSocketOption(GeneralTransportOptions::MANIFEST_FACTOR_RELEVANT,
+                           factor_relevant);
 
-  double unverified_ratio;
-  socket_->getSocketOption(GeneralTransportOptions::UNVERIFIED_RATIO,
-                           unverified_ratio);
+  uint32_t factor_alert;
+  socket_->getSocketOption(GeneralTransportOptions::MANIFEST_FACTOR_ALERT,
+                           factor_alert);
 
   rc_ = std::make_shared<RTCRateControlCongestionDetection>();
   ldr_ = std::make_shared<RTCLossDetectionAndRecovery>(
@@ -100,8 +101,8 @@ void RTCTransportProtocol::initParams() {
         }
       });
 
-  verifier_ = std::make_shared<RTCVerifier>(verifier, unverified_interval,
-                                            unverified_ratio);
+  verifier_ =
+      std::make_shared<RTCVerifier>(verifier, factor_relevant, factor_alert);
 
   state_ = std::make_shared<RTCState>(
       indexer_verifier_.get(),
@@ -138,19 +139,20 @@ void RTCTransportProtocol::initParams() {
   last_interest_sent_time_ = 0;
   last_interest_sent_seq_ = 0;
 
-#if 0
-  if(portal_->isConnectedToFwd()){
-    max_aggregated_interest_ = 1;
-  }else{
-    max_aggregated_interest_ = MAX_INTERESTS_IN_BATCH;
-  }
-#else
-  max_aggregated_interest_ = 1;
-  if (const char *max_aggr = std::getenv("MAX_AGGREGATED_INTERESTS")) {
-    LOG(INFO) << "Max Aggregated: " << max_aggr;
-    max_aggregated_interest_ = std::stoul(std::string(max_aggr));
+  // Aggregated interests setup
+  bool aggregated_interests_on;
+  socket_->getSocketOption(RtcTransportOptions::AGGREGATED_INTERESTS,
+                           aggregated_interests_on);
+  if (aggregated_interests_on) {
+    if (const char *max_aggr = std::getenv("MAX_AGGREGATED_INTERESTS"))
+      max_aggregated_interest_ = (uint32_t)std::stoul(std::string(max_aggr));
+    else
+      max_aggregated_interest_ = MAX_INTERESTS_IN_BATCH;
+
+    max_aggregated_interest_ = std::min<uint32_t>(max_aggregated_interest_,
+                                                  1 + MAX_SUFFIXES_IN_MANIFEST);
   }
-#endif
+  LOG(INFO) << "Max Aggregated: " << max_aggregated_interest_;
 
   max_sent_int_ =
       std::ceil((double)MAX_PACING_BATCH / (double)max_aggregated_interest_);
@@ -263,6 +265,11 @@ void RTCTransportProtocol::discoveredRtt() {
   socket_->getSocketOption(RtcTransportOptions::RECOVERY_STRATEGY, strategy);
   ldr_->changeRecoveryStrategy(
       (interface::RtcTransportRecoveryStrategies)strategy);
+
+  bool content_sharing_mode;
+  socket_->getSocketOption(RtcTransportOptions::CONTENT_SHARING_MODE,
+                           content_sharing_mode);
+  if (content_sharing_mode) ldr_->setContentSharingMode();
   ldr_->turnOnRecovery();
   ldr_->onNewRound(false);
 
@@ -270,22 +277,9 @@ void RTCTransportProtocol::discoveredRtt() {
   Name *name = nullptr;
   socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, &name);
   Prefix prefix(*name, 128);
-  if ((interface::RtcTransportRecoveryStrategies)strategy ==
-      interface::RtcTransportRecoveryStrategies::LOW_RATE_AND_BESTPATH) {
-    fwd_strategy_.initFwdStrategy(portal_, prefix, state_.get(),
-                                  RTCForwardingStrategy::BEST_PATH);
-  } else if ((interface::RtcTransportRecoveryStrategies)strategy ==
-             interface::RtcTransportRecoveryStrategies::
-                 LOW_RATE_AND_REPLICATION) {
-    fwd_strategy_.initFwdStrategy(portal_, prefix, state_.get(),
-                                  RTCForwardingStrategy::REPLICATION);
-  } else if ((interface::RtcTransportRecoveryStrategies)strategy ==
-             interface::RtcTransportRecoveryStrategies::
-                 LOW_RATE_AND_ALL_FWD_STRATEGIES) {
-    fwd_strategy_.initFwdStrategy(portal_, prefix, state_.get(),
-                                  RTCForwardingStrategy::BOTH);
-  }
-
+  fwd_strategy_.initFwdStrategy(
+      portal_, prefix, state_.get(),
+      (interface::RtcTransportRecoveryStrategies)strategy);
   updateSyncWindow();
 }
 
@@ -302,6 +296,12 @@ void RTCTransportProtocol::computeMaxSyncWindow() {
     return;
   }
 
+  bool content_sharing_mode;
+  socket_->getSocketOption(RtcTransportOptions::CONTENT_SHARING_MODE,
+                           content_sharing_mode);
+  if (content_sharing_mode && (production_rate < MIN_PROD_RATE_SHARING_MODE))
+    production_rate = MIN_PROD_RATE_SHARING_MODE;
+
   production_rate += (production_rate * indexer_verifier_->getMaxFecOverhead());
 
   uint32_t lifetime = default_values::interest_lifetime;
@@ -330,6 +330,11 @@ void RTCTransportProtocol::updateSyncWindow() {
   double prod_rate = state_->getProducerRate();
   double rtt = (double)state_->getMinRTT() / MILLI_IN_A_SEC;
   double packet_size = state_->getAveragePacketSize();
+  bool content_sharing_mode;
+  socket_->getSocketOption(RtcTransportOptions::CONTENT_SHARING_MODE,
+                           content_sharing_mode);
+  if (content_sharing_mode && (prod_rate < MIN_PROD_RATE_SHARING_MODE))
+    prod_rate = MIN_PROD_RATE_SHARING_MODE;
 
   // if some of the info are not available do not update the current win
   if (prod_rate != 0.0 && rtt != 0.0 && packet_size != 0.0) {
@@ -385,6 +390,19 @@ void RTCTransportProtocol::sendProbeInterest(uint32_t seq) {
   sendInterest(*interest_name);
 }
 
+void RTCTransportProtocol::sendInterestForTimeout(uint32_t seq) {
+  if (!isRunning() && !is_first_) return;
+
+  Name *interest_name = nullptr;
+  socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
+                           &interest_name);
+
+  // we got a timeout for this packet so it is not pending anymore
+  interest_name->setSuffix(seq);
+  state_->onSendNewInterest(interest_name);
+  sendInterest(*interest_name);
+}
+
 void RTCTransportProtocol::scheduleNextInterests() {
   DLOG_IF(INFO, VLOG_IS_ON(3)) << "Schedule next interests";
 
@@ -475,9 +493,9 @@ void RTCTransportProtocol::scheduleNextInterests() {
   }
 
   // skip received packets
-  if (indexer_verifier_->checkNextSuffix() <=
-      state_->getHighestSeqReceivedInOrder()) {
-    indexer_verifier_->jumpToIndex(state_->getHighestSeqReceivedInOrder() + 1);
+  uint32_t max_received = state_->getHighestSeqReceivedInOrder();
+  if (indexer_verifier_->checkNextSuffix() <= max_received) {
+    indexer_verifier_->jumpToIndex(max_received + 1);
   }
 
   uint32_t sent_interests = 0;
@@ -495,7 +513,6 @@ void RTCTransportProtocol::scheduleNextInterests() {
         << "In while loop. Window size: " << current_sync_win_;
 
     uint32_t next_seg = indexer_verifier_->getNextSuffix();
-
     name->setSuffix(next_seg);
 
     // send the packet only if:
@@ -586,7 +603,6 @@ void RTCTransportProtocol::onInterestTimeout(Interest::Ptr &interest,
   }
 
   timeouts_or_nacks_.insert(segment_number);
-
   if (TRANSPORT_EXPECT_TRUE(state_->isProducerActive()) &&
       segment_number <= state_->getHighestSeqReceived()) {
     // we retransmit packets only if the producer is active, otherwise we
@@ -627,11 +643,11 @@ void RTCTransportProtocol::onInterestTimeout(Interest::Ptr &interest,
         << "On timeout next seg = " << indexer_verifier_->checkNextSuffix()
         << ", jump to " << segment_number;
     // add an extra space in the window
-    current_sync_win_++;
     indexer_verifier_->jumpToIndex(segment_number);
   }
 
   state_->onTimeout(segment_number, false);
+  sendInterestForTimeout(segment_number);
   scheduleNextInterests();
 }
 
@@ -672,7 +688,6 @@ void RTCTransportProtocol::onNack(const ContentObject &content_object) {
     if (tn_it != timeouts_or_nacks_.end()) timeouts_or_nacks_.erase(tn_it);
 
     state_->onJumpForward(production_seg);
-    verifier_->onJumpForward(production_seg);
     // the client is asking for content in the past
     // switch to catch up state and increase the window
     // this is true only if the packet is not an RTX
@@ -821,7 +836,8 @@ void RTCTransportProtocol::onContentObjectReceived(
   // Check if the packet is a retransmission
   if (ldr_->isRtx(segment_number) && state != PacketState::RECEIVED) {
     if (is_data || is_manifest) {
-      state_->onPacketRecoveredRtx(segment_number);
+      uint64_t rtt = ldr_->getRtxRtt(segment_number);
+      state_->onPacketRecoveredRtx(content_object, rtt);
 
       if (*on_content_object_input_) {
         (*on_content_object_input_)(*socket_->getInterface(), content_object);
@@ -842,7 +858,7 @@ void RTCTransportProtocol::onContentObjectReceived(
     }
 
     if (is_fec) {
-      state_->onFecPacketRecoveredRtx(segment_number);
+      state_->onFecPacketRecoveredRtx(content_object);
     }
   }
 
@@ -920,7 +936,7 @@ void RTCTransportProtocol::sendStatsToApp(
     stats_->updateAverageWindowSize(state_->getPendingInterestNumber());
     stats_->updateLossRatio(state_->getPerSecondLossRate());
     uint64_t rtt = state_->getAvgRTT();
-    stats_->updateAverageRtt(utils::SteadyTime::Milliseconds(rtt));
+    stats_->updateAverageRtt(utils::SteadyTime::Microseconds(rtt * 1000));
 
     stats_->updateQueuingDelay(state_->getQueuing());
     stats_->updateLostData(lost_data);
@@ -960,9 +976,10 @@ void RTCTransportProtocol::decodePacket(ContentObject &content_object,
   DLOG_IF(INFO, VLOG_IS_ON(4))
       << "Send packet " << content_object.getName() << " to FEC decoder";
 
-  uint32_t offset = is_manifest
-                        ? content_object.headerSize()
-                        : content_object.headerSize() + rtc::DATA_HEADER_SIZE;
+  uint32_t offset =
+      is_manifest
+          ? (uint32_t)content_object.headerSize()
+          : (uint32_t)(content_object.headerSize() + rtc::DATA_HEADER_SIZE);
   uint32_t metadata = static_cast<uint32_t>(content_object.getPayloadType());
 
   fec_decoder_->onDataPacket(content_object, offset, metadata);
@@ -1016,7 +1033,7 @@ void RTCTransportProtocol::onFecPackets(fec::BufferArray &packets) {
           processManifest(*interest, *content_object);
         }
 
-        state_->onPacketRecoveredFec(seq_number, buffer->length());
+        state_->onPacketRecoveredFec(seq_number, (uint32_t)buffer->length());
         ldr_->onPacketRecoveredFec(seq_number);
 
         if (payload_type == PayloadType::DATA) {
@@ -1038,11 +1055,11 @@ void RTCTransportProtocol::processManifest(Interest &interest,
 
 ContentObject::Ptr RTCTransportProtocol::removeFecHeader(
     const ContentObject &content_object) {
-  if (!fec_decoder_ || !fec_decoder_->getFecHeaderSize()) {
+  if (!fec_decoder_ || !fec_decoder_->getFecHeaderSize(false)) {
     return nullptr;
   }
 
-  size_t fec_header_size = fec_decoder_->getFecHeaderSize();
+  size_t fec_header_size = fec_decoder_->getFecHeaderSize(false);
   const uint8_t *payload =
       content_object.data() + content_object.headerSize() + fec_header_size;
   size_t payload_size = content_object.payloadSize() - fec_header_size;
index 3763f33..a8a4742 100644 (file)
@@ -44,7 +44,7 @@ class RTCTransportProtocol : public TransportProtocol {
 
   void resume() override;
 
-  std::size_t transportHeaderLength() override;
+  std::size_t transportHeaderLength(bool isFEC) override;
 
   auto shared_from_this() { return utils::shared_from(this); }
 
@@ -69,6 +69,7 @@ class RTCTransportProtocol : public TransportProtocol {
   // packet functions
   void sendRtxInterest(uint32_t seq);
   void sendProbeInterest(uint32_t seq);
+  void sendInterestForTimeout(uint32_t seq);
   void scheduleNextInterests() override;
   void onInterestTimeout(Interest::Ptr &interest, const Name &name) override;
   void onNack(const ContentObject &content_object);
index 96e39d0..29b5a3a 100644 (file)
@@ -54,7 +54,7 @@ const uint32_t PACING_WAIT = 1000;  // usec to wait betwing two pacing batch. As
 const uint32_t MAX_RTX_IN_BATCH = 10;  // max rtx to send in loop
 
 // packet const
-const uint32_t RTC_INTEREST_LIFETIME = 2000;
+const uint32_t RTC_INTEREST_LIFETIME = 4000;
 
 // probes sequence range
 const uint32_t MIN_PROBE_SEQ = 0xefffffff;
@@ -93,6 +93,7 @@ const double CATCH_UP_WIN_INCREMENT = 1.2;
 // used in rate control
 const double WIN_DECREASE_FACTOR = 0.5;
 const double WIN_INCREASE_FACTOR = 1.5;
+const uint32_t MIN_PROD_RATE_SHARING_MODE = 125000;  // 1Mbps in bytes
 
 // round in congestion
 const double ROUNDS_BEFORE_TAKE_ACTION = 5;
@@ -120,14 +121,14 @@ const uint64_t MAX_TIMER_RTX = ~0;
 const uint32_t SENTINEL_TIMER_INTERVAL = 100;  // ms
 const uint32_t MAX_RTX_WITH_SENTINEL = 10;     // packets
 const double CATCH_UP_RTT_INCREMENT = 1.2;
-const double MAX_RESIDUAL_LOSS_RATE = 2.0;  // %
-const uint32_t WAIT_BEFORE_FEC_UPDATE = ROUNDS_PER_SEC * 5;
+const double MAX_RESIDUAL_LOSS_RATE = 1.0;  // %
+const uint32_t WAIT_BEFORE_FEC_UPDATE = ROUNDS_PER_SEC;
+const uint32_t MAX_RTT_BEFORE_FEC = 60;  // ms
 
 // used by producer
 const uint32_t PRODUCER_STATS_INTERVAL = 200;  // ms
 const uint32_t MIN_PRODUCTION_RATE = 25;       // pps, equal to min window *
                                                // rounds in a second
-const uint32_t NACK_DELAY = 1500;              // ms
 const uint32_t FEC_PACING_TIME = 5;            // ms
 
 // aggregated data consts
@@ -139,6 +140,73 @@ const uint32_t AGGREGATED_PACKETS_TIMER = 2;  // ms
 const uint32_t MAX_RTT = 200;             // ms
 const double MAX_RESIDUAL_LOSSES = 0.05;  // %
 
+const uint8_t FEC_MATRIX[64][10] = {
+    {1, 2, 2, 2, 3, 3, 4, 5, 5, 6},  // k = 1
+    {1, 2, 3, 3, 4, 5, 5, 6, 7, 9},
+    {2, 2, 3, 4, 5, 6, 7, 8, 9, 11},
+    {2, 3, 4, 5, 5, 7, 8, 9, 11, 13},
+    {2, 3, 4, 5, 6, 7, 9, 10, 12, 14},  // k = 5
+    {2, 3, 4, 6, 7, 8, 10, 12, 14, 16},
+    {2, 4, 5, 6, 8, 9, 11, 13, 15, 18},
+    {3, 4, 5, 7, 8, 10, 12, 14, 16, 19},
+    {3, 4, 6, 7, 9, 11, 13, 15, 18, 21},
+    {3, 4, 6, 8, 9, 11, 14, 16, 19, 23},  // k = 10
+    {3, 5, 6, 8, 10, 12, 14, 17, 20, 24},
+    {3, 5, 7, 8, 10, 13, 15, 18, 21, 26},
+    {3, 5, 7, 9, 11, 13, 16, 19, 23, 27},
+    {3, 5, 7, 9, 12, 14, 17, 20, 24, 28},
+    {4, 6, 8, 10, 12, 15, 18, 21, 25, 30},  // k = 15
+    {4, 6, 8, 10, 13, 15, 19, 22, 26, 31},
+    {4, 6, 8, 11, 13, 16, 19, 23, 27, 33},
+    {4, 6, 9, 11, 14, 17, 20, 24, 29, 34},
+    {4, 6, 9, 11, 14, 17, 21, 25, 30, 35},
+    {4, 7, 9, 12, 15, 18, 22, 26, 31, 37},  // k = 20
+    {4, 7, 9, 12, 15, 19, 22, 27, 32, 38},
+    {4, 7, 10, 13, 16, 19, 23, 28, 33, 40},
+    {5, 7, 10, 13, 16, 20, 24, 29, 34, 41},
+    {5, 7, 10, 13, 17, 20, 25, 30, 35, 42},
+    {5, 8, 11, 14, 17, 21, 26, 31, 37, 44},  // k = 25
+    {5, 8, 11, 14, 18, 22, 26, 31, 38, 45},
+    {5, 8, 11, 15, 18, 22, 27, 32, 39, 46},
+    {5, 8, 11, 15, 19, 23, 28, 33, 40, 48},
+    {5, 8, 12, 15, 19, 24, 28, 34, 41, 49},
+    {5, 9, 12, 16, 20, 24, 29, 35, 42, 50},  // k = 30
+    {5, 9, 12, 16, 20, 25, 30, 36, 43, 51},
+    {5, 9, 13, 16, 21, 25, 31, 37, 44, 53},
+    {6, 9, 13, 17, 21, 26, 31, 38, 45, 54},
+    {6, 9, 13, 17, 22, 26, 32, 39, 46, 55},
+    {6, 10, 13, 17, 22, 27, 33, 40, 47, 57},  // k = 35
+    {6, 10, 14, 18, 22, 28, 34, 40, 48, 58},
+    {6, 10, 14, 18, 23, 28, 34, 41, 49, 59},
+    {6, 10, 14, 19, 23, 29, 35, 42, 50, 60},
+    {6, 10, 14, 19, 24, 29, 36, 43, 52, 62},
+    {6, 10, 15, 19, 24, 30, 36, 44, 53, 63},  // k = 40
+    {6, 11, 15, 20, 25, 31, 37, 45, 54, 64},
+    {6, 11, 15, 20, 25, 31, 38, 46, 55, 65},
+    {7, 11, 15, 20, 26, 32, 39, 46, 56, 67},
+    {7, 11, 16, 21, 26, 32, 39, 47, 57, 68},
+    {7, 11, 16, 21, 27, 33, 40, 48, 58, 69},  // k = 45
+    {7, 11, 16, 21, 27, 33, 41, 49, 59, 70},
+    {7, 12, 16, 22, 27, 34, 41, 50, 60, 72},
+    {7, 12, 17, 22, 28, 34, 42, 51, 61, 73},
+    {7, 12, 17, 22, 28, 35, 43, 52, 62, 74},
+    {7, 12, 17, 23, 29, 36, 43, 52, 63, 75},  // k = 50
+    {7, 12, 17, 23, 29, 36, 44, 53, 64, 77},
+    {7, 12, 18, 23, 30, 37, 45, 54, 65, 78},
+    {7, 13, 18, 24, 30, 37, 45, 55, 66, 79},
+    {8, 13, 18, 24, 31, 38, 46, 56, 67, 80},
+    {8, 13, 18, 24, 31, 38, 47, 57, 68, 82},  // k = 55
+    {8, 13, 19, 25, 31, 39, 47, 57, 69, 83},
+    {8, 13, 19, 25, 32, 39, 48, 58, 70, 84},
+    {8, 13, 19, 25, 32, 40, 49, 59, 71, 85},
+    {8, 14, 19, 26, 33, 41, 50, 60, 72, 86},
+    {8, 14, 20, 26, 33, 41, 50, 61, 73, 88},  // k = 60
+    {8, 14, 20, 26, 34, 42, 51, 61, 74, 89},
+    {8, 14, 20, 27, 34, 42, 52, 62, 75, 90},
+    {8, 14, 20, 27, 34, 43, 52, 63, 76, 91},
+    {8, 14, 21, 27, 35, 43, 53, 64, 77, 92},  // k = 64
+};
+
 }  // namespace rtc
 
 }  // namespace protocol
index b3abf5e..a421396 100644 (file)
@@ -91,6 +91,8 @@ void RTCDataPath::insertRttSample(
     rtt_samples_ = 0;
     last_avg_rtt_compute_ = now;
   }
+
+  received_packets_++;
 }
 
 void RTCDataPath::insertOwdSample(int64_t owd) {
@@ -115,10 +117,6 @@ void RTCDataPath::insertOwdSample(int64_t owd) {
   int64_t diff = std::abs(owd - last_owd_);
   last_owd_ = owd;
   jitter_ += (1.0 / 16.0) * ((double)diff - jitter_);
-
-  // owd is computed only for valid data packets so we count only
-  // this for decide if we recevie traffic or not
-  received_packets_++;
 }
 
 void RTCDataPath::computeInterArrivalGap(uint32_t segment_number) {
@@ -150,12 +148,17 @@ double RTCDataPath::getInterArrivalGap() {
   return avg_inter_arrival_;
 }
 
-bool RTCDataPath::isActive() {
+bool RTCDataPath::isValidProducer() {
   if (received_nacks_ && rounds_without_packets_ < MAX_ROUNDS_WITHOUT_PKTS)
     return true;
   return false;
 }
 
+bool RTCDataPath::isActive() {
+  if (rounds_without_packets_ < MAX_ROUNDS_WITHOUT_PKTS) return true;
+  return false;
+}
+
 bool RTCDataPath::pathToProducer() {
   if (received_nacks_) return true;
   return false;
index 5afbbb8..ba5201f 100644 (file)
@@ -49,8 +49,9 @@ class RTCDataPath {
   double getQueuingDealy();
   double getInterArrivalGap();
   double getJitter();
-  bool isActive();
-  bool pathToProducer();
+  bool isActive();         // pakets recevied from this path in the last rounds
+  bool pathToProducer();   // path from a producer
+  bool isValidProducer();  // path from a producer that is also active
   uint64_t getLastPacketTS();
   uint32_t getPacketsLastRound();
 
index c6bc751..4bbd7ea 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <hicn/transport/interfaces/notification.h>
+#include <protocols/rtc/rtc_consts.h>
 #include <protocols/rtc/rtc_forwarding_strategy.h>
 
 namespace transport {
@@ -24,8 +25,13 @@ namespace rtc {
 
 using namespace transport::interface;
 
+const double FWD_MAX_QUEUE = 30.0;              // ms
+const double FWD_MAX_RTT = MAX_RTT_BEFORE_FEC;  // ms
+const double FWD_MAX_LOSS_RATE = 0.1;
+
 RTCForwardingStrategy::RTCForwardingStrategy()
-    : init_(false),
+    : low_rate_app_(false),
+      init_(false),
       forwarder_set_(false),
       selected_strategy_(NONE),
       current_strategy_(NONE),
@@ -42,17 +48,56 @@ void RTCForwardingStrategy::setCallback(
 
 void RTCForwardingStrategy::initFwdStrategy(
     std::shared_ptr<core::Portal> portal, core::Prefix& prefix, RTCState* state,
-    strategy_t strategy) {
-  init_ = true;
-  selected_strategy_ = strategy;
-  if (strategy == BOTH)
-    current_strategy_ = BEST_PATH;
-  else
-    current_strategy_ = strategy;
-  rounds_since_last_set_ = 0;
-  prefix_ = prefix;
-  portal_ = portal;
-  state_ = state;
+    interface::RtcTransportRecoveryStrategies strategy) {
+  switch (strategy) {
+    case interface::RtcTransportRecoveryStrategies::LOW_RATE_AND_BESTPATH:
+      init_ = true;
+      low_rate_app_ = true;
+      selected_strategy_ = BEST_PATH;
+      current_strategy_ = BEST_PATH;
+      break;
+    case interface::RtcTransportRecoveryStrategies::LOW_RATE_AND_REPLICATION:
+      init_ = true;
+      low_rate_app_ = true;
+      selected_strategy_ = REPLICATION;
+      current_strategy_ = REPLICATION;
+      break;
+    case interface::RtcTransportRecoveryStrategies::
+        LOW_RATE_AND_ALL_FWD_STRATEGIES:
+      init_ = true;
+      low_rate_app_ = true;
+      selected_strategy_ = BEST_PATH;
+      current_strategy_ = BEST_PATH;
+      break;
+    case interface::RtcTransportRecoveryStrategies::DELAY_AND_BESTPATH:
+      init_ = true;
+      low_rate_app_ = false;
+      selected_strategy_ = BEST_PATH;
+      current_strategy_ = BEST_PATH;
+      break;
+    case interface::RtcTransportRecoveryStrategies::DELAY_AND_REPLICATION:
+      init_ = true;
+      low_rate_app_ = false;
+      selected_strategy_ = REPLICATION;
+      current_strategy_ = REPLICATION;
+      break;
+    case interface::RtcTransportRecoveryStrategies::RECOVERY_OFF:
+    case interface::RtcTransportRecoveryStrategies::RTX_ONLY:
+    case interface::RtcTransportRecoveryStrategies::FEC_ONLY:
+    case interface::RtcTransportRecoveryStrategies::DELAY_BASED:
+    case interface::RtcTransportRecoveryStrategies::LOW_RATE:
+    case interface::RtcTransportRecoveryStrategies::FEC_ONLY_LOW_RES_LOSSES:
+    default:
+      // fwd strategies are not used
+      init_ = false;
+  }
+
+  if (init_) {
+    rounds_since_last_set_ = 0;
+    prefix_ = prefix;
+    portal_ = portal;
+    state_ = state;
+  }
 }
 
 void RTCForwardingStrategy::checkStrategy() {
@@ -99,16 +144,35 @@ void RTCForwardingStrategy::checkStrategyBestPath() {
     return;
   }
 
-  uint8_t qs = state_->getQualityScore();
+  if (low_rate_app_) {
+    // this is used for gaming
+    uint8_t qs = state_->getQualityScore();
 
-  if (qs >= 4 || rounds_since_last_set_ < 25) {  // wait a least 5 sec
-                                                 // between each switch
-    rounds_since_last_set_++;
-    return;
-  }
+    if (qs >= 4 || rounds_since_last_set_ < 25) {  // wait a least 5 sec
+                                                   // between each switch
+      rounds_since_last_set_++;
+      return;
+    }
 
-  // try to switch path
-  setStrategy(BEST_PATH);
+    // try to switch path
+    setStrategy(BEST_PATH);
+  } else {
+    if (rounds_since_last_set_ < 25) {  // wait a least 5 sec
+                                        // between each switch
+      rounds_since_last_set_++;
+      return;
+    }
+
+    double queue = state_->getQueuing();
+    double rtt = state_->getAvgRTT();
+    double loss_rate = state_->getPerSecondLossRate();
+
+    if (queue >= FWD_MAX_QUEUE || rtt >= FWD_MAX_RTT ||
+        loss_rate > FWD_MAX_LOSS_RATE) {
+      // try to switch path
+      setStrategy(BEST_PATH);
+    }
+  }
 }
 
 void RTCForwardingStrategy::checkStrategyReplication() {
@@ -133,7 +197,7 @@ void RTCForwardingStrategy::checkStrategyBoth() {
 
   // TODO
   // for the moment we use only best path.
-  // but later:
+  // for later:
   // 1. if both paths are bad use replication
   // 2. while using replication compute the effectiveness. if the majority of
   //    the packets are coming from a single path, try to use bestpath
index 9825877..c2227e0 100644 (file)
@@ -41,7 +41,7 @@ class RTCForwardingStrategy {
 
   void initFwdStrategy(std::shared_ptr<core::Portal> portal,
                        core::Prefix& prefix, RTCState* state,
-                       strategy_t strategy);
+                       interface::RtcTransportRecoveryStrategies strategy);
 
   void checkStrategy();
   void setCallback(interface::StrategyCallback&& callback);
@@ -56,6 +56,10 @@ class RTCForwardingStrategy {
   std::array<std::string, 4> string_strategies_ = {"bestpath", "replication",
                                                    "both", "none"};
 
+  bool low_rate_app_;             // if set to true the best path strategy will
+                                  // trigger a path switch based on the quality
+                                  // score, otherwise it will use the RTT,
+                                  // queuing delay and loss rate
   bool init_;                     // true if all val are initializes
   bool forwarder_set_;            // true if the strategy is been set at least
                                   // once
index abf6cda..6e88a86 100644 (file)
@@ -37,16 +37,24 @@ RTCLossDetectionAndRecovery::RTCLossDetectionAndRecovery(
     interface::RtcTransportRecoveryStrategies type,
     RecoveryStrategy::SendRtxCallback &&callback,
     interface::StrategyCallback &&external_callback) {
-  rs_type_ = type;
   if (type == interface::RtcTransportRecoveryStrategies::RECOVERY_OFF) {
     rs_ = std::make_shared<RecoveryStrategyRecoveryOff>(
-        indexer, std::move(callback), io_service, std::move(external_callback));
-  } else if (type == interface::RtcTransportRecoveryStrategies::DELAY_BASED) {
+        indexer, std::move(callback), io_service, type,
+        std::move(external_callback));
+  } else if (type == interface::RtcTransportRecoveryStrategies::DELAY_BASED ||
+             type == interface::RtcTransportRecoveryStrategies::
+                         DELAY_AND_BESTPATH ||
+             type == interface::RtcTransportRecoveryStrategies::
+                         DELAY_AND_REPLICATION) {
     rs_ = std::make_shared<RecoveryStrategyDelayBased>(
-        indexer, std::move(callback), io_service, std::move(external_callback));
-  } else if (type == interface::RtcTransportRecoveryStrategies::FEC_ONLY) {
+        indexer, std::move(callback), io_service, type,
+        std::move(external_callback));
+  } else if (type == interface::RtcTransportRecoveryStrategies::FEC_ONLY ||
+             type == interface::RtcTransportRecoveryStrategies::
+                         FEC_ONLY_LOW_RES_LOSSES) {
     rs_ = std::make_shared<RecoveryStrategyFecOnly>(
-        indexer, std::move(callback), io_service, std::move(external_callback));
+        indexer, std::move(callback), io_service, type,
+        std::move(external_callback));
   } else if (type == interface::RtcTransportRecoveryStrategies::LOW_RATE ||
              type == interface::RtcTransportRecoveryStrategies::
                          LOW_RATE_AND_BESTPATH ||
@@ -55,12 +63,14 @@ RTCLossDetectionAndRecovery::RTCLossDetectionAndRecovery(
              type == interface::RtcTransportRecoveryStrategies::
                          LOW_RATE_AND_ALL_FWD_STRATEGIES) {
     rs_ = std::make_shared<RecoveryStrategyLowRate>(
-        indexer, std::move(callback), io_service, std::move(external_callback));
+        indexer, std::move(callback), io_service, type,
+        std::move(external_callback));
   } else {
     // default
-    rs_type_ = interface::RtcTransportRecoveryStrategies::RTX_ONLY;
+    type = interface::RtcTransportRecoveryStrategies::RTX_ONLY;
     rs_ = std::make_shared<RecoveryStrategyRtxOnly>(
-        indexer, std::move(callback), io_service, std::move(external_callback));
+        indexer, std::move(callback), io_service, type,
+        std::move(external_callback));
   }
 }
 
@@ -68,15 +78,21 @@ RTCLossDetectionAndRecovery::~RTCLossDetectionAndRecovery() {}
 
 void RTCLossDetectionAndRecovery::changeRecoveryStrategy(
     interface::RtcTransportRecoveryStrategies type) {
-  if (type == rs_type_) return;
+  if (type == rs_->getType()) return;
 
-  rs_type_ = type;
+  rs_->updateType(type);
   if (type == interface::RtcTransportRecoveryStrategies::RECOVERY_OFF) {
     rs_ =
         std::make_shared<RecoveryStrategyRecoveryOff>(std::move(*(rs_.get())));
-  } else if (type == interface::RtcTransportRecoveryStrategies::DELAY_BASED) {
+  } else if (type == interface::RtcTransportRecoveryStrategies::DELAY_BASED ||
+             type == interface::RtcTransportRecoveryStrategies::
+                         DELAY_AND_BESTPATH ||
+             type == interface::RtcTransportRecoveryStrategies::
+                         DELAY_AND_REPLICATION) {
     rs_ = std::make_shared<RecoveryStrategyDelayBased>(std::move(*(rs_.get())));
-  } else if (type == interface::RtcTransportRecoveryStrategies::FEC_ONLY) {
+  } else if (type == interface::RtcTransportRecoveryStrategies::FEC_ONLY ||
+             type == interface::RtcTransportRecoveryStrategies::
+                         FEC_ONLY_LOW_RES_LOSSES) {
     rs_ = std::make_shared<RecoveryStrategyFecOnly>(std::move(*(rs_.get())));
   } else if (type == interface::RtcTransportRecoveryStrategies::LOW_RATE ||
              type == interface::RtcTransportRecoveryStrategies::
@@ -116,14 +132,15 @@ bool RTCLossDetectionAndRecovery::onDataPacketReceived(
   uint32_t seq = content_object.getName().getSuffix();
   bool is_rtx = rs_->isRtx(seq);
   rs_->receivedPacket(seq);
+  bool ret = false;
   DLOG_IF(INFO, VLOG_IS_ON(3))
       << "received data. add from "
-      << rs_->getState()->getHighestSeqReceivedInOrder() + 1 << " to " << seq;
+      << rs_->getState()->getHighestSeqReceived() + 1 << " to " << seq;
   if (!is_rtx)
-    return detectLoss(rs_->getState()->getHighestSeqReceivedInOrder() + 1, seq,
-                      false);
+    ret = detectLoss(rs_->getState()->getHighestSeqReceived() + 1, seq, false);
 
-  return false;
+  rs_->getState()->updateHighestSeqReceived(seq);
+  return ret;
 }
 
 bool RTCLossDetectionAndRecovery::onNackPacketReceived(
@@ -141,10 +158,9 @@ bool RTCLossDetectionAndRecovery::onNackPacketReceived(
   // may got lost and we should ask them
 
   rs_->receivedPacket(seq);
-  DLOG_IF(INFO, VLOG_IS_ON(3))
-      << "received nack. add from "
-      << rs_->getState()->getHighestSeqReceivedInOrder() + 1 << " to "
-      << production_seq;
+  DLOG_IF(INFO, VLOG_IS_ON(3)) << "received nack. add from "
+                               << rs_->getState()->getHighestSeqReceived() + 1
+                               << " to " << production_seq;
 
   // if it is a future nack store it in the list set of nacked seq
   if (production_seq <= seq) rs_->receivedFutureNack(seq);
@@ -152,7 +168,7 @@ bool RTCLossDetectionAndRecovery::onNackPacketReceived(
   // call the detectLoss function using the probe flag = true. in fact the
   // losses detected using nacks are the same as the one detected using probes,
   // we should not increase the loss counter
-  return detectLoss(rs_->getState()->getHighestSeqReceivedInOrder() + 1,
+  return detectLoss(rs_->getState()->getHighestSeqReceived() + 1,
                     production_seq, true);
 }
 
@@ -164,12 +180,11 @@ bool RTCLossDetectionAndRecovery::onProbePacketReceived(
 
   uint32_t production_seq = RTCState::getProbeParams(probe).prod_seg;
 
-  DLOG_IF(INFO, VLOG_IS_ON(3))
-      << "received probe. add from "
-      << rs_->getState()->getHighestSeqReceivedInOrder() + 1 << " to "
-      << production_seq;
+  DLOG_IF(INFO, VLOG_IS_ON(3)) << "received probe. add from "
+                               << rs_->getState()->getHighestSeqReceived() + 1
+                               << " to " << production_seq;
 
-  return detectLoss(rs_->getState()->getHighestSeqReceivedInOrder() + 1,
+  return detectLoss(rs_->getState()->getHighestSeqReceived() + 1,
                     production_seq, true);
 }
 
@@ -183,8 +198,8 @@ bool RTCLossDetectionAndRecovery::detectLoss(uint32_t start, uint32_t stop,
   }
 
   // skip received or lost packets
-  if (start <= rs_->getState()->getHighestSeqReceivedInOrder()) {
-    start = rs_->getState()->getHighestSeqReceivedInOrder() + 1;
+  if (start <= rs_->getState()->getHighestSeqReceived()) {
+    start = rs_->getState()->getHighestSeqReceived() + 1;
   }
 
   bool loss_detected = false;
index 7f683ea..24f22ff 100644 (file)
@@ -47,6 +47,7 @@ class RTCLossDetectionAndRecovery
 
   void setFecParams(uint32_t n, uint32_t k) { rs_->setFecParams(n, k); }
 
+  void setContentSharingMode() { rs_->setContentSharingMode(); }
   void turnOnRecovery() { rs_->turnOnRecovery(); }
   bool isRtxOn() { return rs_->isRtxOn(); }
 
@@ -68,11 +69,12 @@ class RTCLossDetectionAndRecovery
     return rs_->isPossibleLossWithNoRtx(seq);
   }
 
+  uint64_t getRtxRtt(uint32_t seq) { return rs_->getRtxRtt(seq); }
+
  private:
   // returns true if a loss is detected, false otherwise
   bool detectLoss(uint32_t start, uint32_t stop, bool recv_probe);
 
-  interface::RtcTransportRecoveryStrategies rs_type_;
   std::shared_ptr<RecoveryStrategy> rs_;
 };
 
index 391aedf..ffbbd78 100644 (file)
@@ -52,6 +52,8 @@
 #include <hicn/transport/portability/win_portability.h>
 #endif
 
+#include <hicn/transport/portability/endianess.h>
+
 #include <cstring>
 
 namespace transport {
@@ -60,24 +62,6 @@ namespace protocol {
 
 namespace rtc {
 
-inline uint64_t _ntohll(const uint64_t *input) {
-  uint64_t return_val;
-  uint8_t *tmp = (uint8_t *)&return_val;
-
-  tmp[0] = (uint8_t)(*input >> 56);
-  tmp[1] = (uint8_t)(*input >> 48);
-  tmp[2] = (uint8_t)(*input >> 40);
-  tmp[3] = (uint8_t)(*input >> 32);
-  tmp[4] = (uint8_t)(*input >> 24);
-  tmp[5] = (uint8_t)(*input >> 16);
-  tmp[6] = (uint8_t)(*input >> 8);
-  tmp[7] = (uint8_t)(*input >> 0);
-
-  return return_val;
-}
-
-inline uint64_t _htonll(const uint64_t *input) { return (_ntohll(input)); }
-
 const uint32_t DATA_HEADER_SIZE = 12;  // bytes
                                        // XXX: sizeof(data_packet_t) is 16
                                        // beacuse of padding
@@ -87,11 +71,19 @@ struct data_packet_t {
   uint64_t timestamp;
   uint32_t prod_rate;
 
-  inline uint64_t getTimestamp() const { return _ntohll(&timestamp); }
-  inline void setTimestamp(uint64_t time) { timestamp = _htonll(&time); }
+  inline uint64_t getTimestamp() const {
+    return portability::net_to_host(timestamp);
+  }
+  inline void setTimestamp(uint64_t time) {
+    timestamp = portability::host_to_net(time);
+  }
 
-  inline uint32_t getProductionRate() const { return ntohl(prod_rate); }
-  inline void setProductionRate(uint32_t rate) { prod_rate = htonl(rate); }
+  inline uint32_t getProductionRate() const {
+    return portability::net_to_host(prod_rate);
+  }
+  inline void setProductionRate(uint32_t rate) {
+    prod_rate = portability::host_to_net(rate);
+  }
 };
 
 struct nack_packet_t {
@@ -99,14 +91,26 @@ struct nack_packet_t {
   uint32_t prod_rate;
   uint32_t prod_seg;
 
-  inline uint64_t getTimestamp() const { return _ntohll(&timestamp); }
-  inline void setTimestamp(uint64_t time) { timestamp = _htonll(&time); }
+  inline uint64_t getTimestamp() const {
+    return portability::net_to_host(timestamp);
+  }
+  inline void setTimestamp(uint64_t time) {
+    timestamp = portability::host_to_net(time);
+  }
 
-  inline uint32_t getProductionRate() const { return ntohl(prod_rate); }
-  inline void setProductionRate(uint32_t rate) { prod_rate = htonl(rate); }
+  inline uint32_t getProductionRate() const {
+    return portability::net_to_host(prod_rate);
+  }
+  inline void setProductionRate(uint32_t rate) {
+    prod_rate = portability::host_to_net(rate);
+  }
 
-  inline uint32_t getProductionSegment() const { return ntohl(prod_seg); }
-  inline void setProductionSegment(uint32_t seg) { prod_seg = htonl(seg); }
+  inline uint32_t getProductionSegment() const {
+    return portability::net_to_host(prod_seg);
+  }
+  inline void setProductionSegment(uint32_t seg) {
+    prod_seg = portability::host_to_net(seg);
+  }
 };
 
 class AggrPktHeader {
@@ -225,7 +229,7 @@ class AggrPktHeader {
       return (uint16_t) * (buf_ + pkt_index);
     } else {  // 16 bits
       uint16_t *buf_16 = (uint16_t *)buf_;
-      return ntohs(*(buf_16 + pkt_index));
+      return portability::net_to_host(*(buf_16 + pkt_index));
     }
   }
 
@@ -235,7 +239,7 @@ class AggrPktHeader {
       *(buf_ + pkt_index) = (uint8_t)len;
     } else {  // 16 bits
       uint16_t *buf_16 = (uint16_t *)buf_;
-      *(buf_16 + pkt_index) = htons(len);
+      *(buf_16 + pkt_index) = portability::host_to_net(len);
     }
   }
 
index 992bab5..b1b0fca 100644 (file)
@@ -40,7 +40,7 @@ void RtcReassembly::reassemble(core::ContentObject& content_object) {
   auto read_buffer = content_object.getPayload();
   DLOG_IF(INFO, VLOG_IS_ON(3)) << "Size of payload: " << read_buffer->length();
 
-  read_buffer->trimStart(transport_protocol_->transportHeaderLength());
+  read_buffer->trimStart(transport_protocol_->transportHeaderLength(false));
 
   if (data_aggregation_) {
     rtc::AggrPktHeader hdr((uint8_t*)read_buffer->data());
index 66ae508..257fdd0 100644 (file)
@@ -29,8 +29,12 @@ using namespace transport::interface;
 
 RecoveryStrategy::RecoveryStrategy(
     Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service,
-    bool use_rtx, bool use_fec, interface::StrategyCallback &&external_callback)
-    : recovery_on_(false),
+    bool use_rtx, bool use_fec,
+    interface::RtcTransportRecoveryStrategies rs_type,
+    interface::StrategyCallback &&external_callback)
+    : rs_type_(rs_type),
+      recovery_on_(false),
+      content_sharing_mode_(false),
       rtx_during_fec_(0),
       next_rtx_timer_(MAX_TIMER_RTX),
       send_rtx_callback_(std::move(callback)),
@@ -43,7 +47,9 @@ RecoveryStrategy::RecoveryStrategy(
 }
 
 RecoveryStrategy::RecoveryStrategy(RecoveryStrategy &&rs)
-    : rtx_during_fec_(0),
+    : rs_type_(rs.rs_type_),
+      content_sharing_mode_(rs.content_sharing_mode_),
+      rtx_during_fec_(0),
       rtx_state_(std::move(rs.rtx_state_)),
       rtx_timers_(std::move(rs.rtx_timers_)),
       recover_with_fec_(std::move(rs.recover_with_fec_)),
@@ -64,25 +70,52 @@ RecoveryStrategy::RecoveryStrategy(RecoveryStrategy &&rs)
 RecoveryStrategy::~RecoveryStrategy() {}
 
 void RecoveryStrategy::setFecParams(uint32_t n, uint32_t k) {
+  // if rs_type == FEC_ONLY_LOW_RES_LOSSES max k == 64
   n_ = n;
   k_ = k;
 
   // XXX for the moment we go in steps of 5% loss rate.
-  // max loss rate = 95%
+  uint32_t i = 0;
   for (uint32_t loss_rate = 5; loss_rate < 100; loss_rate += 5) {
-    double dec_loss_rate = (double)(loss_rate + 5) / 100.0;
-    double exp_losses = (double)k_ * dec_loss_rate;
-    uint32_t fec_to_ask = ceil(exp_losses / (1 - dec_loss_rate));
-
-    fec_state_ f;
-    f.fec_to_ask = std::min(fec_to_ask, (n_ - k_));
-    f.last_update = round_id_;
-    f.avg_residual_losses = 0.0;
-    f.consecutive_use = 0;
-    fec_per_loss_rate_.push_back(f);
+    uint32_t fec_to_ask = 0;
+    if (n_ != 0 && k_ != 0) {
+      if (rs_type_ ==
+          interface::RtcTransportRecoveryStrategies::FEC_ONLY_LOW_RES_LOSSES) {
+        // the max loss rate in the matrix is 50%
+        uint32_t index = i;
+        if (i > 9) index = 9;
+        fec_to_ask = FEC_MATRIX[k_ - 1][index];
+      } else {
+        double dec_loss_rate = (double)(loss_rate + 5);
+        if (dec_loss_rate == 100.0) dec_loss_rate = 95.0;
+        dec_loss_rate = dec_loss_rate / 100.0;
+        double exp_losses = ceil((double)k_ * dec_loss_rate);
+        fec_to_ask = ceil((exp_losses / (1 - dec_loss_rate)) * 1.25);
+      }
+    }
+    fec_to_ask = std::min(fec_to_ask, (n_ - k_));
+    fec_per_loss_rate_.push_back(fec_to_ask);
+
+    i++;
   }
 }
 
+uint64_t RecoveryStrategy::getRtxRtt(uint32_t seq) {
+  auto it = rtx_state_.find(seq);
+
+  if (it == rtx_state_.end()) return 0;
+
+  // we can compute the RTT of an RTX only if it was send once. Infact if the
+  // RTX was sent twice or more the data may be alredy in flight and the RTT
+  // will be underestimated. This may happen also for packets that we
+  // retransmitted too soon. in that case the RTT will be filtered out by
+  // checking the path label
+  if (it->second.rtx_count_ != 1) return 0;
+
+  // this a potentialy valid packet, compute the RTT
+  return (utils::SteadyTime::nowMs().count() - it->second.last_send_);
+}
+
 bool RecoveryStrategy::lossDetected(uint32_t seq) {
   if (isRtx(seq)) {
     // this packet is already in the list of rtx
@@ -141,8 +174,10 @@ void RecoveryStrategy::addNewRtx(uint32_t seq, bool force) {
     state.first_send_ = state_->getInterestSentTime(seq);
     if (state.first_send_ == 0)  // this interest was never sent before
       state.first_send_ = getNow();
-    state.next_send_ = computeNextSend(seq, true);
+    state.last_send_ = state.first_send_;  // we didn't send an RTX for this
+                                           // packet yet
     state.rtx_count_ = 0;
+    state.next_send_ = computeNextSend(seq, state.rtx_count_);
     DLOG_IF(INFO, VLOG_IS_ON(4))
         << "Add " << seq << " to retransmissions. next rtx is in "
         << state.next_send_ - getNow() << " ms";
@@ -158,66 +193,50 @@ void RecoveryStrategy::addNewRtx(uint32_t seq, bool force) {
   }
 }
 
-uint64_t RecoveryStrategy::computeNextSend(uint32_t seq, bool new_rtx) {
+uint64_t RecoveryStrategy::computeNextSend(uint32_t seq, uint32_t rtx_counter) {
   uint64_t now = getNow();
-  if (new_rtx) {
-    // for the new rtx we wait one estimated IAT after the loss detection. this
-    // is bacause, assuming that packets arrive with a constant IAT, we should
-    // get a new packet every IAT
-    double prod_rate = state_->getProducerRate();
-    uint32_t estimated_iat = SENTINEL_TIMER_INTERVAL;
-    uint32_t jitter = 0;
+  if (rtx_counter == 0) {
+    uint32_t wait = 1;
+    if (content_sharing_mode_) return now + wait;
 
-    if (prod_rate != 0) {
-      double packet_size = state_->getAveragePacketSize();
-      estimated_iat = ceil(1000.0 / (prod_rate / packet_size));
-      jitter = ceil(state_->getJitter());
-    }
+    uint32_t jitter = SENTINEL_TIMER_INTERVAL;
+    double prod_rate = state_->getProducerRate();
+    if (prod_rate != 0) jitter = ceil(state_->getJitter());
 
-    uint32_t wait = 1;
-    if (estimated_iat < 18) {
-      // for low rate app we do not wait to send a RTX
-      // we consider low rate stream with less than 50pps (iat >= 20ms)
-      // (e.g. audio in videoconf, mobile games).
-      // in the check we use 18ms to accomodate for measurements errors
-      // for flows with higher rate wait 1 ait + jitter
-      wait = estimated_iat + jitter;
-    }
+    wait += jitter;
 
-    DLOG_IF(INFO, VLOG_IS_ON(3))
-        << "first rtx for " << seq << " in " << wait
-        << " ms, rtt = " << state_->getMinRTT() << " ait = " << estimated_iat
-        << " jttr = " << jitter;
+    DLOG_IF(INFO, VLOG_IS_ON(3)) << "first rtx for " << seq << " in " << wait
+                                 << " ms, jitter = " << jitter;
 
     return now + wait;
   } else {
-    // wait one RTT
-    uint32_t wait = SENTINEL_TIMER_INTERVAL;
-
+    // wait one RTT. if an edge is known use the edge RTT for the first 5 rtx
     double prod_rate = state_->getProducerRate();
     if (prod_rate == 0) {
       return now + SENTINEL_TIMER_INTERVAL;
     }
 
-    double packet_size = state_->getAveragePacketSize();
-    uint32_t estimated_iat = ceil(1000.0 / (prod_rate / packet_size));
+    uint64_t rtt = 0;
+    // if the transport detects an edge we try first to get the RTX from the
+    // edge. if no interest get a reply we move to the full RTT
+    if (rtx_counter < 5 && (state_->getEdgeRtt() != 0)) {
+      rtt = state_->getEdgeRtt();
+    } else {
+      rtt = state_->getAvgRTT();
+    }
 
-    uint64_t rtt = state_->getMinRTT();
     if (rtt == 0) rtt = SENTINEL_TIMER_INTERVAL;
-    wait = rtt;
+
+    if (content_sharing_mode_) return now + rtt;
+
+    uint32_t wait = (uint32_t)rtt;
 
     uint32_t jitter = ceil(state_->getJitter());
     wait += jitter;
 
-    // it may happen that the channel is congested and we have some additional
-    // queuing delay to take into account
-    uint32_t queue = ceil(state_->getQueuing());
-    wait += queue;
-
     DLOG_IF(INFO, VLOG_IS_ON(3))
-        << "next rtx for " << seq << " in " << wait
-        << " ms, rtt = " << state_->getMinRTT() << " ait = " << estimated_iat
-        << " jttr = " << jitter << " queue = " << queue;
+        << "next rtx for " << seq << " in " << wait << " ms, rtt = " << rtt
+        << " jtter = " << jitter;
 
     return now + wait;
   }
@@ -252,7 +271,9 @@ void RecoveryStrategy::retransmit() {
       state_->onRetransmission(seq);
       double prod_rate = state_->getProducerRate();
       if (prod_rate != 0) rtx_it->second.rtx_count_++;
-      rtx_it->second.next_send_ = computeNextSend(seq, false);
+      rtx_it->second.last_send_ = now;
+      rtx_it->second.next_send_ =
+          computeNextSend(seq, rtx_it->second.rtx_count_);
       it = rtx_timers_.erase(it);
       rtx_timers_.insert(
           std::pair<uint64_t, uint32_t>(rtx_it->second.next_send_, seq));
@@ -327,6 +348,7 @@ void RecoveryStrategy::deleteRtx(uint32_t seq) {
     }
     it_timers++;
   }
+
   // remove rtx
   rtx_state_.erase(it_rtx);
 }
@@ -339,53 +361,13 @@ uint32_t RecoveryStrategy::computeFecPacketsToAsk() {
 
   if (loss_rate == 0) return 0;
 
-  // once per minute try to reduce the fec rate. it may happen that for some bin
-  // we ask too many fec packet. here we try to reduce this values gently
-  if (round_id_ % ROUNDS_PER_MIN == 0) {
-    reduceFec();
-  }
-
   // keep track of the last used fec. if we use a new bin on this round reset
   // consecutive use and avg loss in the prev bin
   uint32_t bin = ceil(loss_rate / 5.0) - 1;
-  if (bin > fec_per_loss_rate_.size() - 1) bin = fec_per_loss_rate_.size() - 1;
+  if (bin > fec_per_loss_rate_.size() - 1)
+    bin = (uint32_t)fec_per_loss_rate_.size() - 1;
 
-  if (bin != last_fec_used_) {
-    fec_per_loss_rate_[last_fec_used_].consecutive_use = 0;
-    fec_per_loss_rate_[last_fec_used_].avg_residual_losses = 0.0;
-  }
-  last_fec_used_ = bin;
-  fec_per_loss_rate_[last_fec_used_].consecutive_use++;
-
-  // we update the stats only once very 5 rounds (1sec) that is the rate at
-  // which we compute residual losses
-  if (round_id_ % ROUNDS_PER_SEC == 0) {
-    double residual_losses = state_->getResidualLossRate() * 100;
-    // update residual loss rate
-    fec_per_loss_rate_[bin].avg_residual_losses =
-        (fec_per_loss_rate_[bin].avg_residual_losses * MOVING_AVG_ALPHA) +
-        (1 - MOVING_AVG_ALPHA) * residual_losses;
-
-    if ((fec_per_loss_rate_[bin].last_update - round_id_) <
-        WAIT_BEFORE_FEC_UPDATE) {
-      // this bin is been updated recently so don't modify it  and
-      // return the current state
-      return fec_per_loss_rate_[bin].fec_to_ask;
-    }
-
-    // if the residual loss rate is too high and we can ask more fec packets and
-    // we are using this configuration since at least 5 sec update fec
-    if (fec_per_loss_rate_[bin].avg_residual_losses > MAX_RESIDUAL_LOSS_RATE &&
-        fec_per_loss_rate_[bin].fec_to_ask < (n_ - k_) &&
-        fec_per_loss_rate_[bin].consecutive_use > WAIT_BEFORE_FEC_UPDATE) {
-      // so increase the number of fec packets to ask
-      fec_per_loss_rate_[bin].fec_to_ask++;
-      fec_per_loss_rate_[bin].last_update = round_id_;
-      fec_per_loss_rate_[bin].avg_residual_losses = 0.0;
-    }
-  }
-
-  return fec_per_loss_rate_[bin].fec_to_ask;
+  return fec_per_loss_rate_[bin];
 }
 
 void RecoveryStrategy::setRtxFec(std::optional<bool> rtx_on,
@@ -431,21 +413,6 @@ void RecoveryStrategy::removePacketState(uint32_t seq) {
   deleteRtx(seq);
 }
 
-// private methods
-
-void RecoveryStrategy::reduceFec() {
-  for (uint32_t loss_rate = 5; loss_rate < 100; loss_rate += 5) {
-    double dec_loss_rate = (double)loss_rate / 100.0;
-    double exp_losses = (double)k_ * dec_loss_rate;
-    uint32_t fec_to_ask = ceil(exp_losses / (1 - dec_loss_rate));
-
-    uint32_t bin = ceil(loss_rate / 5.0) - 1;
-    if (fec_per_loss_rate_[bin].fec_to_ask > fec_to_ask) {
-      fec_per_loss_rate_[bin].fec_to_ask--;
-    }
-  }
-}
-
 }  // end namespace rtc
 
 }  // end namespace protocol
index 482aedc..aceb858 100644 (file)
@@ -32,9 +32,10 @@ namespace rtc {
 class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> {
  protected:
   struct rtx_state_ {
-    uint64_t first_send_;
-    uint64_t next_send_;
-    uint32_t rtx_count_;
+    uint64_t first_send_;  // first time this interest was sent
+    uint64_t last_send_;   // last time this rtx was sent
+    uint64_t next_send_;   // next retransmission time
+    uint32_t rtx_count_;   // number or rtx
   };
 
   using rtxState = struct rtx_state_;
@@ -44,6 +45,7 @@ class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> {
 
   RecoveryStrategy(Indexer *indexer, SendRtxCallback &&callback,
                    asio::io_service &io_service, bool use_rtx, bool use_fec,
+                   interface::RtcTransportRecoveryStrategies rs_type,
                    interface::StrategyCallback &&external_callback);
 
   RecoveryStrategy(RecoveryStrategy &&rs);
@@ -55,6 +57,7 @@ class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> {
   void setState(RTCState *state) { state_ = state; }
   void setRateControl(RTCRateControl *rateControl) { rc_ = rateControl; }
   void setFecParams(uint32_t n, uint32_t k);
+  void setContentSharingMode() { content_sharing_mode_ = true; }
 
   bool isRtx(uint32_t seq) {
     if (rtx_state_.find(seq) != rtx_state_.end()) return true;
@@ -71,10 +74,20 @@ class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> {
     return false;
   }
 
+  interface::RtcTransportRecoveryStrategies getType() {
+    return rs_type_;
+  }
+  void updateType(interface::RtcTransportRecoveryStrategies type) {
+    rs_type_ = type;
+  }
   bool isRtxOn() { return rtx_on_; }
   bool isFecOn() { return fec_on_; }
 
   RTCState *getState() { return state_; }
+
+  // if the function returns 0 it means that the packet is not an RTX or it is
+  // not a valid packet to safely compute the RTT
+  uint64_t getRtxRtt(uint32_t seq);
   bool lossDetected(uint32_t seq);
   void notifyNewLossDetedcted(uint32_t seq);
   void requestPossibleLostPacket(uint32_t seq);
@@ -98,7 +111,7 @@ class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> {
  protected:
   // rtx functions
   void addNewRtx(uint32_t seq, bool force);
-  uint64_t computeNextSend(uint32_t seq, bool new_rtx);
+  uint64_t computeNextSend(uint32_t seq, uint32_t rtx_counter);
   void retransmit();
   void scheduleNextRtx();
   void deleteRtx(uint32_t seq);
@@ -109,9 +122,11 @@ class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> {
   // common functons
   void removePacketState(uint32_t seq);
 
+  interface::RtcTransportRecoveryStrategies rs_type_;
   bool recovery_on_;
   bool rtx_on_;
   bool fec_on_;
+  bool content_sharing_mode_;
 
   // number of RTX sent after fec turned on
   // this is used to take into account jitter and out of order packets
@@ -152,19 +167,9 @@ class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> {
   RTCRateControl *rc_;
 
  private:
-  struct fec_state_ {
-    uint32_t fec_to_ask;
-    uint32_t last_update;      // round id of the last update
-                               // (wait 10 ruonds (2sec) between updates)
-    uint32_t consecutive_use;  // consecutive ruonds where this fec was used
-    double avg_residual_losses;
-  };
-
-  void reduceFec();
-
   uint32_t round_id_;  // number of rounds
   uint32_t last_fec_used_;
-  std::vector<fec_state_> fec_per_loss_rate_;
+  std::vector<uint32_t> fec_per_loss_rate_;
   interface::StrategyCallback callback_;
 };
 
index 4be751e..7d7a011 100644 (file)
@@ -25,8 +25,10 @@ namespace rtc {
 
 RecoveryStrategyDelayBased::RecoveryStrategyDelayBased(
     Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service,
+    interface::RtcTransportRecoveryStrategies rs_type,
     interface::StrategyCallback &&external_callback)
     : RecoveryStrategy(indexer, std::move(callback), io_service, true, false,
+                       rs_type,
                        std::move(external_callback)),  // start with rtx
       congestion_state_(false),
       probing_state_(false),
@@ -48,7 +50,7 @@ void RecoveryStrategyDelayBased::turnOnRecovery() {
   recovery_on_ = true;
   uint64_t rtt = state_->getMinRTT();
   uint32_t fec_to_ask = computeFecPacketsToAsk();
-  if (rtt > 80 && fec_to_ask != 0) {
+  if (rtt > MAX_RTT_BEFORE_FEC && fec_to_ask > 0) {
     // we need to start FEC (see fec only strategy for more details)
     setRtxFec(true, true);
     rtx_during_fec_ = 1;  // avoid to stop fec
@@ -84,16 +86,16 @@ void RecoveryStrategyDelayBased::onNewRound(bool in_sync) {
     return;
   }
 
-  uint64_t rtt = state_->getMinRTT();
+  uint64_t rtt = state_->getAvgRTT();
 
-  bool congestion = false;
   // XXX at the moment we are not looking at congestion events
-  // congestion = rc_->inCongestionState();
+  // bool congestion = rc_->inCongestionState();
 
-  if ((!fec_on_ && rtt >= 100) || (fec_on_ && rtt > 80) || congestion) {
+  if ((!fec_on_ && rtt >= MAX_RTT_BEFORE_FEC) ||
+      (fec_on_ && rtt > (MAX_RTT_BEFORE_FEC - 10))) {
     // switch from rtx to fec or keep use fec. Notice that if some rtx are
     // waiting to be scheduled, they will be sent normally, but no new rtx will
-    // be created If the loss rate is 0 keep to use RTX.
+    // be created if the loss rate is 0 keep to use RTX.
     uint32_t fec_to_ask = computeFecPacketsToAsk();
     softSwitchToFec(fec_to_ask);
     if (rtx_during_fec_ == 0)  // if we do not send any RTX the losses
@@ -104,7 +106,8 @@ void RecoveryStrategyDelayBased::onNewRound(bool in_sync) {
     return;
   }
 
-  if ((fec_on_ && rtt <= 80) || (!rtx_on_ && rtt <= 100)) {
+  if ((fec_on_ && rtt <= (MAX_RTT_BEFORE_FEC - 10)) ||
+      (!rtx_on_ && rtt <= MAX_RTT_BEFORE_FEC)) {
     // turn on rtx
     softSwitchToFec(0);
     indexer_->setNFec(0);
index 5ca90f4..9e1c413 100644 (file)
@@ -26,6 +26,7 @@ class RecoveryStrategyDelayBased : public RecoveryStrategy {
  public:
   RecoveryStrategyDelayBased(Indexer *indexer, SendRtxCallback &&callback,
                              asio::io_service &io_service,
+                             interface::RtcTransportRecoveryStrategies rs_type,
                              interface::StrategyCallback &&external_callback);
 
   RecoveryStrategyDelayBased(RecoveryStrategy &&rs);
index c44212b..5b10823 100644 (file)
@@ -25,9 +25,10 @@ namespace rtc {
 
 RecoveryStrategyFecOnly::RecoveryStrategyFecOnly(
     Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service,
+    interface::RtcTransportRecoveryStrategies rs_type,
     interface::StrategyCallback &&external_callback)
     : RecoveryStrategy(indexer, std::move(callback), io_service, true, false,
-                       std::move(external_callback)),
+                       rs_type, std::move(external_callback)),
       congestion_state_(false),
       probing_state_(false),
       switch_rounds_(0) {}
index 1ab78b8..42df25b 100644 (file)
@@ -26,6 +26,7 @@ class RecoveryStrategyFecOnly : public RecoveryStrategy {
  public:
   RecoveryStrategyFecOnly(Indexer *indexer, SendRtxCallback &&callback,
                           asio::io_service &io_service,
+                          interface::RtcTransportRecoveryStrategies rs_type,
                           interface::StrategyCallback &&external_callback);
 
   RecoveryStrategyFecOnly(RecoveryStrategy &&rs);
index 48dd3e3..dbad563 100644 (file)
@@ -25,8 +25,10 @@ namespace rtc {
 
 RecoveryStrategyLowRate::RecoveryStrategyLowRate(
     Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service,
+    interface::RtcTransportRecoveryStrategies rs_type,
     interface::StrategyCallback &&external_callback)
     : RecoveryStrategy(indexer, std::move(callback), io_service, false, true,
+                       rs_type,
                        std::move(external_callback)),  // start with fec
       fec_consecutive_rounds_((MILLI_IN_A_SEC / ROUND_LEN) * 5),  // 5 sec
       rtx_allowed_consecutive_rounds_(0) {
@@ -75,7 +77,7 @@ void RecoveryStrategyLowRate::selectRecoveryStrategy(bool in_sync) {
   }
 
   uint32_t loss_rate = std::round(state_->getPerSecondLossRate() * 100);
-  uint32_t rtt = state_->getAvgRTT();
+  uint32_t rtt = (uint32_t)state_->getAvgRTT();
 
   bool use_rtx = false;
   for (size_t i = 0; i < switch_vector.size(); i++) {
index d66b197..0e76efa 100644 (file)
@@ -34,6 +34,7 @@ class RecoveryStrategyLowRate : public RecoveryStrategy {
  public:
   RecoveryStrategyLowRate(Indexer *indexer, SendRtxCallback &&callback,
                           asio::io_service &io_service,
+                          interface::RtcTransportRecoveryStrategies rs_type,
                           interface::StrategyCallback &&external_callback);
 
   RecoveryStrategyLowRate(RecoveryStrategy &&rs);
index 16b14ef..00c6a05 100644 (file)
@@ -25,9 +25,10 @@ namespace rtc {
 
 RecoveryStrategyRecoveryOff::RecoveryStrategyRecoveryOff(
     Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service,
+    interface::RtcTransportRecoveryStrategies rs_type,
     interface::StrategyCallback &&external_callback)
     : RecoveryStrategy(indexer, std::move(callback), io_service, false, false,
-                       std::move(external_callback)) {}
+                       rs_type, std::move(external_callback)) {}
 
 RecoveryStrategyRecoveryOff::RecoveryStrategyRecoveryOff(RecoveryStrategy &&rs)
     : RecoveryStrategy(std::move(rs)) {
index 3a9e71e..3d59cc4 100644 (file)
@@ -26,6 +26,7 @@ class RecoveryStrategyRecoveryOff : public RecoveryStrategy {
  public:
   RecoveryStrategyRecoveryOff(Indexer *indexer, SendRtxCallback &&callback,
                               asio::io_service &io_service,
+                              interface::RtcTransportRecoveryStrategies rs_type,
                               interface::StrategyCallback &&external_callback);
 
   RecoveryStrategyRecoveryOff(RecoveryStrategy &&rs);
index 8e5db54..4d7cf7a 100644 (file)
@@ -25,9 +25,10 @@ namespace rtc {
 
 RecoveryStrategyRtxOnly::RecoveryStrategyRtxOnly(
     Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service,
+    interface::RtcTransportRecoveryStrategies rs_type,
     interface::StrategyCallback &&external_callback)
     : RecoveryStrategy(indexer, std::move(callback), io_service, true, false,
-                       std::move(external_callback)) {}
+                       rs_type, std::move(external_callback)) {}
 
 RecoveryStrategyRtxOnly::RecoveryStrategyRtxOnly(RecoveryStrategy &&rs)
     : RecoveryStrategy(std::move(rs)) {
index e90e5ba..03dbed1 100644 (file)
@@ -26,6 +26,7 @@ class RecoveryStrategyRtxOnly : public RecoveryStrategy {
  public:
   RecoveryStrategyRtxOnly(Indexer *indexer, SendRtxCallback &&callback,
                           asio::io_service &io_service,
+                          interface::RtcTransportRecoveryStrategies rs_type,
                           interface::StrategyCallback &&external_callback);
 
   RecoveryStrategyRtxOnly(RecoveryStrategy &&rs);
index 5b3b5e4..82ac0b9 100644 (file)
@@ -106,6 +106,7 @@ void RTCState::initParams() {
   // paths stats
   path_table_.clear();
   main_path_ = nullptr;
+  edge_path_ = nullptr;
 
   // packet cache (not pending anymore)
   packet_cache_.clear();
@@ -231,11 +232,9 @@ void RTCState::onDataPacketReceived(const core::ContentObject &content_object,
   }
 
   updatePacketSize(content_object);
-  updateReceivedBytes(content_object);
+  updateReceivedBytes(content_object, false);
   addRecvOrLost(seq, PacketState::RECEIVED);
 
-  if (seq > highest_seq_received_) highest_seq_received_ = seq;
-
   // the producer is responding
   // it is generating valid data packets so we consider it active
   producer_is_active_ = true;
@@ -245,11 +244,7 @@ void RTCState::onDataPacketReceived(const core::ContentObject &content_object,
 
 void RTCState::onFecPacketReceived(const core::ContentObject &content_object) {
   uint32_t seq = content_object.getName().getSuffix();
-  // updateReceivedBytes(content_object);
-  received_fec_bytes_ +=
-      (uint32_t)(content_object.headerSize() + content_object.payloadSize());
-
-  if (seq > highest_seq_received_) highest_seq_received_ = seq;
+  updateReceivedBytes(content_object, true);
 
   PacketState state = getPacketState(seq);
   if (state != PacketState::LOST) {
@@ -328,12 +323,14 @@ void RTCState::onPacketLost(uint32_t seq) {
       DLOG_IF(INFO, VLOG_IS_ON(4)) << "packet " << seq << " is lost";
     }
   }
+
   addRecvOrLost(seq, PacketState::DEFINITELY_LOST);
 }
 
-void RTCState::onPacketRecoveredRtx(uint32_t seq) {
+void RTCState::onPacketRecoveredRtx(const core::ContentObject &content_object,
+                                    uint64_t rtt) {
+  uint32_t seq = content_object.getName().getSuffix();
   packets_sent_to_app_++;
-  if (seq > highest_seq_received_) highest_seq_received_ = seq;
 
   // increase the recovered packet counter only if the packet was marked as LOST
   // before.
@@ -341,13 +338,37 @@ void RTCState::onPacketRecoveredRtx(uint32_t seq) {
   if (state == PacketState::LOST) losses_recovered_++;
 
   addRecvOrLost(seq, PacketState::RECEIVED);
+  updateReceivedBytes(content_object, false);
+
+  if (rtt == 0) return;  // nothing to do
+
+  uint32_t path_label = content_object.getPathLabel();
+  auto path_it = path_table_.find(path_label);
+  if (path_it == path_table_.end()) {
+    // this is a new path and it must be a cache
+    std::shared_ptr<RTCDataPath> newPath =
+        std::make_shared<RTCDataPath>(path_label);
+    auto ret = path_table_.insert(
+        std::pair<uint32_t, std::shared_ptr<RTCDataPath>>(path_label, newPath));
+    path_it = ret.first;
+  }
+
+  auto path = path_it->second;
+  if (path->pathToProducer())
+    return;  // this packet is coming from a producer
+             // even if we sent an RTX. this may happen
+             // for RTX that are sent too fast or in
+             // case of multipath
+
+  path->insertRttSample(utils::SteadyTime::Milliseconds(rtt), true);
 }
 
-void RTCState::onFecPacketRecoveredRtx(uint32_t seq) {
+void RTCState::onFecPacketRecoveredRtx(
+    const core::ContentObject &content_object) {
   // This is the same as onPacketRecoveredRtx, but in this is case the
   // pkt is also a FEC pkt, the addRecvOrLost will be called afterwards
-  if (seq > highest_seq_received_) highest_seq_received_ = seq;
   losses_recovered_++;
+  updateReceivedBytes(content_object, true);
 }
 
 void RTCState::onPacketRecoveredFec(uint32_t seq, uint32_t size) {
@@ -355,8 +376,6 @@ void RTCState::onPacketRecoveredFec(uint32_t seq, uint32_t size) {
   packets_sent_to_app_++;
   recovered_bytes_with_fec_ += size;
 
-  if (seq > highest_seq_received_) highest_seq_received_ = seq;
-
   // adding header to the count
   recovered_bytes_with_fec_ += 60;  // XXX get header size some where
 
@@ -487,21 +506,32 @@ void RTCState::onNewRound(double round_len, bool in_sync) {
   // channel losses
 
   uint32_t last_round_packets = 0;
+  uint64_t min_edge_rtt = UINT_MAX;
   std::shared_ptr<RTCDataPath> old_main_path = main_path_;
   main_path_ = nullptr;
+  edge_path_ = nullptr;
 
   for (auto it = path_table_.begin(); it != path_table_.end(); it++) {
-    if (it->second->isActive()) {
+    if (it->second->isValidProducer()) {
       uint32_t pkt = it->second->getPacketsLastRound();
       if (pkt > last_round_packets) {
         last_round_packets = pkt;
         main_path_ = it->second;
       }
+    } else if (it->second->isActive() && !it->second->pathToProducer()) {
+      // this is a path to a cache from where we are receiving content
+      if (it->second->getMinRtt() < min_edge_rtt) {
+        min_edge_rtt = it->second->getMinRtt();
+        edge_path_ = it->second;
+      }
     }
     it->second->roundEnd();
   }
 
   if (main_path_ == nullptr) main_path_ = old_main_path;
+  if (edge_path_ == nullptr) edge_path_ = main_path_;
+  if (edge_path_->getMinRtt() >= main_path_->getMinRtt())
+    edge_path_ = main_path_;
 
   // in case we get a new main path we reset the stats of the old one. this is
   // beacuse, in case we need to switch back we don't what to take decisions on
@@ -551,9 +581,15 @@ void RTCState::onNewRound(double round_len, bool in_sync) {
   rounds_++;
 }
 
-void RTCState::updateReceivedBytes(const core::ContentObject &content_object) {
-  received_bytes_ +=
-      (uint32_t)(content_object.headerSize() + content_object.payloadSize());
+void RTCState::updateReceivedBytes(const core::ContentObject &content_object,
+                                   bool isFec) {
+  if (isFec) {
+    received_fec_bytes_ +=
+        (uint32_t)(content_object.headerSize() + content_object.payloadSize());
+  } else {
+    received_bytes_ +=
+        (uint32_t)(content_object.headerSize() + content_object.payloadSize());
+  }
 }
 
 void RTCState::updatePacketSize(const core::ContentObject &content_object) {
@@ -703,6 +739,10 @@ void RTCState::dataToBeReceived(uint32_t seq) {
   addToPacketCache(seq, PacketState::TO_BE_RECEIVED);
 }
 
+void RTCState::updateHighestSeqReceived(uint32_t seq) {
+  if (seq > highest_seq_received_) highest_seq_received_ = seq;
+}
+
 void RTCState::addRecvOrLost(uint32_t seq, PacketState state) {
   auto it = pending_interests_.find(seq);
   if (it != pending_interests_.end()) {
@@ -803,7 +843,7 @@ core::ParamsRTC RTCState::getProbeParams(const core::ContentObject &probe) {
   switch (ProbeHandler::getProbeType(seq)) {
     case ProbeType::INIT: {
       core::ContentObjectManifest manifest(
-          const_cast<core::ContentObject &>(probe));
+          const_cast<core::ContentObject &>(probe).shared_from_this());
       manifest.decode();
       params = manifest.getParamsRTC();
       break;
@@ -841,7 +881,7 @@ core::ParamsRTC RTCState::getDataParams(const core::ContentObject &data) {
     }
     case core::PayloadType::MANIFEST: {
       core::ContentObjectManifest manifest(
-          const_cast<core::ContentObject &>(data));
+          const_cast<core::ContentObject &>(data).shared_from_this());
       manifest.decode();
       params = manifest.getParamsRTC();
       break;
index 4bd2f76..ac3cc62 100644 (file)
@@ -84,8 +84,9 @@ class RTCState : public std::enable_shared_from_this<RTCState> {
   void onNackPacketReceived(const core::ContentObject &nack,
                             bool compute_stats);
   void onPacketLost(uint32_t seq);
-  void onPacketRecoveredRtx(uint32_t seq);
-  void onFecPacketRecoveredRtx(uint32_t seq);
+  void onPacketRecoveredRtx(const core::ContentObject &content_object,
+                            uint64_t rtt);
+  void onFecPacketRecoveredRtx(const core::ContentObject &content_object);
   void onPacketRecoveredFec(uint32_t seq, uint32_t size);
   bool onProbePacketReceived(const core::ContentObject &probe);
   void onJumpForward(uint32_t next_seq);
@@ -117,6 +118,11 @@ class RTCState : public std::enable_shared_from_this<RTCState> {
     return 0;
   }
 
+  uint64_t getEdgeRtt() const {
+    if (edge_path_ != nullptr) return edge_path_->getMinRtt();
+    return 0;
+  }
+
   void resetRttStats() {
     if (mainPathIsValid()) main_path_->clearRtt();
   }
@@ -149,7 +155,7 @@ class RTCState : public std::enable_shared_from_this<RTCState> {
   }
 
   uint32_t getPendingInterestNumber() const {
-    return pending_interests_.size();
+    return (uint32_t)pending_interests_.size();
   }
 
   PacketState getPacketState(uint32_t seq) {
@@ -242,6 +248,8 @@ class RTCState : public std::enable_shared_from_this<RTCState> {
   // set it as TO_BE_RECEIVED.
   void dataToBeReceived(uint32_t seq);
 
+  void updateHighestSeqReceived(uint32_t seq);
+
   // Extract RTC parameters from probes (init or RTT probes) and data packets.
   static core::ParamsRTC getProbeParams(const core::ContentObject &probe);
   static core::ParamsRTC getDataParams(const core::ContentObject &data);
@@ -259,7 +267,8 @@ class RTCState : public std::enable_shared_from_this<RTCState> {
 
   // update stats
   void updateState();
-  void updateReceivedBytes(const core::ContentObject &content_object);
+  void updateReceivedBytes(const core::ContentObject &content_object,
+                           bool isFec);
   void updatePacketSize(const core::ContentObject &content_object);
   void updatePathStats(const core::ContentObject &content_object, bool is_nack);
   void updateLossRate(bool in_sycn);
@@ -360,7 +369,12 @@ class RTCState : public std::enable_shared_from_this<RTCState> {
 
   // paths stats
   std::unordered_map<uint32_t, std::shared_ptr<RTCDataPath>> path_table_;
-  std::shared_ptr<RTCDataPath> main_path_;
+  std::shared_ptr<RTCDataPath> main_path_;  // this is the path that connects
+                                            // the consumer to the producer. in
+                                            // case of multipath the trasnport
+                                            // uses the most active path
+  std::shared_ptr<RTCDataPath> edge_path_;  // path to the closest cache if it
+                                            // exists
 
   // packet received
   // cache where to store info about the last MAX_CACHED_PACKETS
index 7b6330a..861ceee 100644 (file)
@@ -22,11 +22,11 @@ namespace protocol {
 namespace rtc {
 
 RTCVerifier::RTCVerifier(std::shared_ptr<auth::Verifier> verifier,
-                         uint32_t max_unverified_interval,
-                         double max_unverified_ratio)
+                         uint32_t factor_relevant, uint32_t factor_alert)
     : verifier_(verifier),
-      max_unverified_interval_(max_unverified_interval),
-      max_unverified_ratio_(max_unverified_ratio) {}
+      factor_relevant_(factor_relevant),
+      factor_alert_(factor_alert),
+      manifest_max_capacity_(std::numeric_limits<uint8_t>::max()) {}
 
 void RTCVerifier::setState(std::shared_ptr<RTCState> rtc_state) {
   rtc_state_ = rtc_state;
@@ -36,12 +36,16 @@ void RTCVerifier::setVerifier(std::shared_ptr<auth::Verifier> verifier) {
   verifier_ = verifier;
 }
 
-void RTCVerifier::setMaxUnverifiedInterval(uint32_t max_unverified_interval) {
-  max_unverified_interval_ = max_unverified_interval;
+void RTCVerifier::setFactorRelevant(uint32_t factor_relevant) {
+  factor_relevant_ = factor_relevant;
 }
 
-void RTCVerifier::setMaxUnverifiedRatio(double max_unverified_ratio) {
-  max_unverified_ratio_ = max_unverified_ratio;
+void RTCVerifier::setFactorAlert(uint32_t factor_alert) {
+  factor_alert_ = factor_alert;
+}
+
+auth::VerificationPolicy RTCVerifier::verify(core::Interest &interest) {
+  return verifier_->verifyPackets(&interest);
 }
 
 auth::VerificationPolicy RTCVerifier::verify(
@@ -108,19 +112,27 @@ auth::VerificationPolicy RTCVerifier::verifyData(
 
   auth::Suffix suffix = content_object.getName().getSuffix();
   auth::VerificationPolicy policy = auth::VerificationPolicy::ABORT;
-  Timestamp now = utils::SteadyTime::nowMs().count();
 
-  // Flush old packets
-  Timestamp oldest = flush_packets(now);
+  uint32_t threshold_relevant = factor_relevant_ * manifest_max_capacity_;
+  uint32_t threshold_alert = factor_alert_ * manifest_max_capacity_;
 
-  // Add packet to map of unverified packets
-  packets_unverif_.add(
-      {.suffix = suffix, .timestamp = now, .size = content_object.length()},
-      content_object.computeDigest(manifest_hash_algo_));
+  // Flush packets outside relevance window
+  for (auto it = packets_unverif_.set().begin();
+       it != packets_unverif_.set().end();) {
+    if (it->first > current_index_ - threshold_relevant) {
+      break;
+    }
+    packets_unverif_erased_.insert((unsigned int)it->first);
+    it = packets_unverif_.remove(it);
+  }
+
+  // Add packet to set of unverified packets
+  packets_unverif_.add({current_index_, suffix},
+                       content_object.computeDigest(manifest_hash_algo_));
+  current_index_++;
 
-  // Check that the ratio of unverified packets stays below the limit
-  if (now - oldest < max_unverified_interval_ ||
-      getBufferRatio() < max_unverified_ratio_) {
+  // Check that the number of unverified packets is below the alert threshold
+  if (packets_unverif_.set().size() <= threshold_alert) {
     policy = auth::VerificationPolicy::ACCEPT;
   }
 
@@ -139,18 +151,13 @@ auth::VerificationPolicy RTCVerifier::processManifest(
   auth::VerificationPolicy accept_policy = auth::VerificationPolicy::ACCEPT;
 
   // Decode manifest
-  core::ContentObjectManifest manifest(content_object);
+  core::ContentObjectManifest manifest(content_object.shared_from_this());
   manifest.decode();
 
-  // Update last manifest
-  if (suffix > last_manifest_) {
-    last_manifest_ = suffix;
-  }
-
-  // Extract hash algorithm and hashes
+  // Extract manifest data
+  manifest_max_capacity_ = manifest.getMaxCapacity();
   manifest_hash_algo_ = manifest.getHashAlgorithm();
-  auth::Verifier::SuffixMap suffix_map =
-      core::ContentObjectManifest::getSuffixMap(&manifest);
+  auth::Verifier::SuffixMap suffix_map = manifest.getSuffixMap();
 
   // Return early if the manifest is empty
   if (suffix_map.empty()) {
@@ -186,10 +193,7 @@ auth::VerificationPolicy RTCVerifier::processManifest(
   for (const auto &p : policies) {
     switch (p.second) {
       case auth::VerificationPolicy::ACCEPT: {
-        auto packet_unverif_it = packets_unverif_.packetIt(p.first);
-        Packet packet_verif = *packet_unverif_it;
-        packets_unverif_.remove(packet_unverif_it);
-        packets_verif_.add(packet_verif);
+        packets_unverif_.remove(packets_unverif_.packet(p.first));
         manifest_digests_.erase(p.first);
         break;
       }
@@ -209,69 +213,20 @@ void RTCVerifier::onDataRecoveredFec(uint32_t suffix) {
   manifest_digests_.erase(suffix);
 }
 
-void RTCVerifier::onJumpForward(uint32_t next_suffix) {
-  if (next_suffix <= last_manifest_ + 1) {
-    return;
-  }
-
-  // When we jump forward in the suffix sequence, we remove packets that won't
-  // be verified. Those packets have a suffix in the range [last_manifest_ + 1,
-  // next_suffix[.
-  for (auth::Suffix suffix = last_manifest_ + 1; suffix < next_suffix;
-       ++suffix) {
-    auto packet_it = packets_unverif_.packetIt(suffix);
-    if (packet_it != packets_unverif_.set().end()) {
-      packets_unverif_.remove(packet_it);
-    }
-  }
-}
-
-double RTCVerifier::getBufferRatio() const {
-  size_t total = packets_verif_.size() + packets_unverif_.size();
-  double total_unverified = static_cast<double>(packets_unverif_.size());
-  return total ? total_unverified / total : 0.0;
-}
-
-RTCVerifier::Timestamp RTCVerifier::flush_packets(Timestamp now) {
-  Timestamp oldest_verified = packets_verif_.set().empty()
-                                  ? now
-                                  : packets_verif_.set().begin()->timestamp;
-  Timestamp oldest_unverified = packets_unverif_.set().empty()
-                                    ? now
-                                    : packets_unverif_.set().begin()->timestamp;
-
-  // Prune verified packets older than the unverified interval
-  for (auto it = packets_verif_.set().begin();
-       it != packets_verif_.set().end();) {
-    if (now - it->timestamp < max_unverified_interval_) {
-      break;
-    }
-    it = packets_verif_.remove(it);
-  }
-
-  // Prune unverified packets older than the unverified interval
-  for (auto it = packets_unverif_.set().begin();
-       it != packets_unverif_.set().end();) {
-    if (now - it->timestamp < max_unverified_interval_) {
-      break;
-    }
-    packets_unverif_erased_.insert(it->suffix);
-    it = packets_unverif_.remove(it);
-  }
-
-  return std::min(oldest_verified, oldest_unverified);
-}
-
 std::pair<RTCVerifier::PacketSet::iterator, bool> RTCVerifier::Packets::add(
-    const Packet &packet) {
+    const Packet &packet, const auth::CryptoHash &digest) {
   auto inserted = packets_.insert(packet);
-  size_ += inserted.second ? packet.size : 0;
+  if (inserted.second) {
+    packets_map_[packet.second] = inserted.first;
+    suffix_map_[packet.second] = digest;
+  }
   return inserted;
 }
 
 RTCVerifier::PacketSet::iterator RTCVerifier::Packets::remove(
     PacketSet::iterator packet_it) {
-  size_ -= packet_it->size;
+  packets_map_.erase(packet_it->second);
+  suffix_map_.erase(packet_it->second);
   return packets_.erase(packet_it);
 }
 
@@ -279,35 +234,13 @@ const std::set<RTCVerifier::Packet> &RTCVerifier::Packets::set() const {
   return packets_;
 };
 
-size_t RTCVerifier::Packets::size() const { return size_; };
-
-std::pair<RTCVerifier::PacketSet::iterator, bool>
-RTCVerifier::PacketsUnverif::add(const Packet &packet,
-                                 const auth::CryptoHash &digest) {
-  auto inserted = add(packet);
-  if (inserted.second) {
-    packets_map_[packet.suffix] = inserted.first;
-    digests_map_[packet.suffix] = digest;
-  }
-  return inserted;
-}
-
-RTCVerifier::PacketSet::iterator RTCVerifier::PacketsUnverif::remove(
-    PacketSet::iterator packet_it) {
-  size_ -= packet_it->size;
-  packets_map_.erase(packet_it->suffix);
-  digests_map_.erase(packet_it->suffix);
-  return packets_.erase(packet_it);
-}
-
-RTCVerifier::PacketSet::iterator RTCVerifier::PacketsUnverif::packetIt(
+RTCVerifier::PacketSet::iterator RTCVerifier::Packets::packet(
     auth::Suffix suffix) {
   return packets_map_.at(suffix);
 };
 
-const auth::Verifier::SuffixMap &RTCVerifier::PacketsUnverif::suffixMap()
-    const {
-  return digests_map_;
+const auth::Verifier::SuffixMap &RTCVerifier::Packets::suffixMap() const {
+  return suffix_map_;
 }
 
 }  // end namespace rtc
index 0989840..c83faf0 100644 (file)
@@ -27,19 +27,16 @@ namespace rtc {
 class RTCVerifier {
  public:
   explicit RTCVerifier(std::shared_ptr<auth::Verifier> verifier,
-                       uint32_t max_unverified_interval,
-                       double max_unverified_ratio);
+                       uint32_t factor_relevant, uint32_t factor_alert);
 
   virtual ~RTCVerifier() = default;
 
   void setState(std::shared_ptr<RTCState> rtc_state);
-
   void setVerifier(std::shared_ptr<auth::Verifier> verifier);
+  void setFactorRelevant(uint32_t factor_relevant);
+  void setFactorAlert(uint32_t factor_alert);
 
-  void setMaxUnverifiedInterval(uint32_t max_unverified_interval);
-
-  void setMaxUnverifiedRatio(double max_unverified_ratio);
-
+  auth::VerificationPolicy verify(core::Interest &interest);
   auth::VerificationPolicy verify(core::ContentObject &content_object,
                                   bool is_fec = false);
   auth::VerificationPolicy verifyProbe(core::ContentObject &content_object);
@@ -51,81 +48,47 @@ class RTCVerifier {
   auth::VerificationPolicy processManifest(core::ContentObject &content_object);
 
   void onDataRecoveredFec(uint32_t suffix);
-  void onJumpForward(uint32_t next_suffix);
-
-  double getBufferRatio() const;
 
  protected:
-  struct Packet;
-  using Timestamp = uint64_t;
+  using Index = uint64_t;
+  using Packet = std::pair<Index, auth::Suffix>;
   using PacketSet = std::set<Packet>;
 
-  struct Packet {
-    auth::Suffix suffix;
-    Timestamp timestamp;
-    size_t size;
-
-    bool operator==(const Packet &b) const {
-      return timestamp == b.timestamp && suffix == b.suffix;
-    }
-    bool operator<(const Packet &b) const {
-      return timestamp == b.timestamp ? suffix < b.suffix
-                                      : timestamp < b.timestamp;
-    }
-  };
-
   class Packets {
    public:
-    virtual std::pair<PacketSet::iterator, bool> add(const Packet &packet);
-    virtual PacketSet::iterator remove(PacketSet::iterator packet_it);
-    const PacketSet &set() const;
-    size_t size() const;
-
-   protected:
-    PacketSet packets_;
-    size_t size_;
-  };
-
-  class PacketsVerif : public Packets {};
-
-  class PacketsUnverif : public Packets {
-   public:
-    using Packets::add;
     std::pair<PacketSet::iterator, bool> add(const Packet &packet,
                                              const auth::CryptoHash &digest);
-    PacketSet::iterator remove(PacketSet::iterator packet_it) override;
-    PacketSet::iterator packetIt(auth::Suffix suffix);
+    PacketSet::iterator remove(PacketSet::iterator packet_it);
+    const PacketSet &set() const;
+    PacketSet::iterator packet(auth::Suffix suffix);
     const auth::Verifier::SuffixMap &suffixMap() const;
 
    private:
+    PacketSet packets_;
     std::unordered_map<auth::Suffix, PacketSet::iterator> packets_map_;
-    auth::Verifier::SuffixMap digests_map_;
+    auth::Verifier::SuffixMap suffix_map_;
   };
 
   // The RTC state.
   std::shared_ptr<RTCState> rtc_state_;
   // The verifier instance.
   std::shared_ptr<auth::Verifier> verifier_;
-  // Window to consider when verifying packets.
-  uint32_t max_unverified_interval_;
-  // Ratio of unverified packets over which an alert is triggered.
-  double max_unverified_ratio_;
-  // The suffix of the last processed manifest.
-  auth::Suffix last_manifest_;
+  // Used to compute the relevance windows size (in packets).
+  uint32_t factor_relevant_;
+  // Used to compute the alert threshold (in packets).
+  uint32_t factor_alert_;
+  // The maximum number of entries a manifest can contain.
+  uint8_t manifest_max_capacity_;
   // Hash algorithm used by manifests.
   auth::CryptoHashType manifest_hash_algo_;
   // Digests extracted from all manifests received.
   auth::Verifier::SuffixMap manifest_digests_;
-  // Verified packets with timestamp >= now - max_unverified_interval_.
-  PacketsVerif packets_verif_;
-  // Unverified packets with timestamp >= now - max_unverified_interval_.
-  PacketsUnverif packets_unverif_;
-  // Unverified erased packets with timestamp < now - max_unverified_interval_.
+  // The number of data packets processed.
+  Index current_index_;
+  // Unverified packets with index in relevance window.
+  Packets packets_unverif_;
+  // Unverified erased packets with index outside relevance window.
   std::unordered_set<auth::Suffix> packets_unverif_erased_;
-
-  // Flushes all packets with timestamp < now - max_unverified_interval_.
-  // Returns the timestamp of the oldest packet, verified or not.
-  Timestamp flush_packets(Timestamp now);
 };
 
 }  // namespace rtc
index a73b9fb..b180370 100644 (file)
@@ -79,6 +79,7 @@ int TransportProtocol::start() {
                              &on_payload_);
 
     socket_->getSocketOption(GeneralTransportOptions::ASYNC_MODE, is_async_);
+    socket_->getSocketOption(GeneralTransportOptions::SIGNER, signer_);
 
     // Set it is the first time we schedule an interest
     is_first_ = true;
@@ -143,14 +144,22 @@ void TransportProtocol::sendInterest(
   Packet::Format format;
   socket_->getSocketOption(interface::GeneralTransportOptions::PACKET_FORMAT,
                            format);
+  size_t signature_size = 0;
 
-  auto interest =
-      core::PacketManager<>::getInstance().getPacket<Interest>(format);
+  // If aggregated interest, add spapce for signature
+  if (len > 0) {
+    format = Packet::toAHFormat(format);
+    signature_size = signer_->getSignatureFieldSize();
+  }
+
+  auto interest = core::PacketManager<>::getInstance().getPacket<Interest>(
+      format, signature_size);
   interest->setName(interest_name);
 
   for (uint32_t i = 0; i < len; i++) {
     interest->appendSuffix(additional_suffixes->at(i));
   }
+  interest->encodeSuffixes();
 
   uint32_t lifetime = default_values::interest_lifetime;
   socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
@@ -165,7 +174,16 @@ void TransportProtocol::sendInterest(
     return;
   }
 
-  portal_->sendInterest(std::move(interest));
+  bool content_sharing_mode;
+  socket_->getSocketOption(RtcTransportOptions::CONTENT_SHARING_MODE,
+                           content_sharing_mode);
+  if (content_sharing_mode) lifetime = ceil((double)lifetime * 0.9);
+
+  // Compute signature
+  bool is_ah = _is_ah(interest->getFormat());
+  if (is_ah) signer_->signPacket(interest.get());
+
+  portal_->sendInterest(interest, lifetime);
 }
 
 void TransportProtocol::onError(const std::error_code &ec) {
index ad8cf03..e719925 100644 (file)
@@ -64,7 +64,7 @@ class TransportProtocol
    *
    * @return The header length in bytes.
    */
-  virtual std::size_t transportHeaderLength() { return 0; }
+  virtual std::size_t transportHeaderLength(bool isFEC) { return 0; }
 
   virtual void scheduleNextInterests() = 0;
 
@@ -141,6 +141,9 @@ class TransportProtocol
   bool is_async_;
 
   fec::FECType fec_type_;
+
+  // Signer for aggregated interests
+  std::shared_ptr<auth::Signer> signer_;
 };
 
 }  // end namespace protocol
index e7018ce..b7f1476 100644 (file)
@@ -31,6 +31,8 @@ list(APPEND TESTS_SRC
   test_quality_score.cc
   test_sessions.cc
   test_thread_pool.cc
+  test_quadloop.cc
+  test_prefix.cc
 )
 
 if (ENABLE_RELY)
index b998ce9..e3d66c1 100644 (file)
@@ -13,8 +13,8 @@
  * limitations under the License.
  */
 
+#include <core/manifest.h>
 #include <core/manifest_format_fixed.h>
-#include <core/manifest_inline.h>
 #include <gtest/gtest.h>
 #include <hicn/transport/auth/crypto_hash.h>
 #include <hicn/transport/auth/signer.h>
@@ -33,10 +33,12 @@ namespace {
 // The fixture for testing class Foo.
 class ManifestTest : public ::testing::Test {
  protected:
-  using ContentObjectManifest = ManifestInline<ContentObject, Fixed>;
+  using ContentObjectManifest = Manifest<Fixed>;
 
-  ManifestTest() : name_("b001::123|321"), manifest1_(HF_INET6_TCP_AH, name_) {
-    // You can do set-up work for each test here.
+  ManifestTest()
+      : format_(HF_INET6_TCP_AH), name_("b001::123|321"), signature_size_(0) {
+    manifest_ = ContentObjectManifest::createContentManifest(format_, name_,
+                                                             signature_size_);
   }
 
   virtual ~ManifestTest() {
@@ -56,10 +58,11 @@ class ManifestTest : public ::testing::Test {
     // before the destructor).
   }
 
+  Packet::Format format_;
   Name name_;
-  ContentObjectManifest manifest1_;
-
-  std::vector<uint8_t> manifest_payload = {
+  std::size_t signature_size_;
+  std::shared_ptr<ContentObjectManifest> manifest_;
+  std::vector<uint8_t> manifest_payload_ = {
       0x11, 0x11, 0x01, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad  // , 0x00, 0x00,
                                                             // 0x00, 0x45, 0xa3,
@@ -75,169 +78,200 @@ class ManifestTest : public ::testing::Test {
 
 }  // namespace
 
-TEST_F(ManifestTest, MoveConstructor) {
+TEST_F(ManifestTest, ManifestConstructor) {
   // Create content object with manifest in payload
-  ContentObject co(HF_INET6_TCP_AH, 128);
-  co.appendPayload(&manifest_payload[0], manifest_payload.size());
-  uint8_t buffer[256];
-  co.appendPayload(buffer, 256);
+  ContentObject::Ptr co =
+      core::PacketManager<>::getInstance().getPacket<ContentObject>(
+          format_, signature_size_);
+  co->setName(name_);
+  co->appendPayload(manifest_payload_.data(), manifest_payload_.size());
+
+  uint8_t buffer[256] = {0};
+  co->appendPayload(buffer, 256);
 
   // Copy packet payload
   uint8_t packet[1500];
-  auto length = co.getPayload()->length();
-  std::memcpy(packet, co.getPayload()->data(), length);
+  auto length = co->getPayload()->length();
+  std::memcpy(packet, co->getPayload()->data(), length);
 
   // Create manifest
-  ContentObjectManifest m(std::move(co));
+  ContentObjectManifest manifest(co);
 
   // Check manifest payload is exactly the same of content object
-  ASSERT_EQ(length, m.getPayload()->length());
-  auto ret = std::memcmp(packet, m.getPayload()->data(), length);
+  ASSERT_EQ(length, manifest.getPacket()->getPayload()->length());
+  auto ret =
+      std::memcmp(packet, manifest.getPacket()->getPayload()->data(), length);
   ASSERT_EQ(ret, 0);
 }
 
-TEST_F(ManifestTest, SetLastManifest) {
-  manifest1_.clear();
-
-  manifest1_.setIsLast(true);
-  bool fcn = manifest1_.getIsLast();
-
-  ASSERT_TRUE(fcn == true);
-}
-
 TEST_F(ManifestTest, SetManifestType) {
-  manifest1_.clear();
+  manifest_->Encoder::clear();
 
   ManifestType type1 = ManifestType::INLINE_MANIFEST;
   ManifestType type2 = ManifestType::FLIC_MANIFEST;
 
-  manifest1_.setType(type1);
-  ManifestType type_returned1 = manifest1_.getType();
+  manifest_->setType(type1);
+  ManifestType type_returned1 = manifest_->getType();
 
-  manifest1_.clear();
+  manifest_->Encoder::clear();
 
-  manifest1_.setType(type2);
-  ManifestType type_returned2 = manifest1_.getType();
+  manifest_->setType(type2);
+  ManifestType type_returned2 = manifest_->getType();
 
   ASSERT_EQ(type1, type_returned1);
   ASSERT_EQ(type2, type_returned2);
 }
 
+TEST_F(ManifestTest, SetMaxCapacity) {
+  manifest_->Encoder::clear();
+
+  uint8_t max_capacity1 = 0;
+  uint8_t max_capacity2 = 20;
+
+  manifest_->setMaxCapacity(max_capacity1);
+  uint8_t max_capacity_returned1 = manifest_->getMaxCapacity();
+
+  manifest_->Encoder::clear();
+
+  manifest_->setMaxCapacity(max_capacity2);
+  uint8_t max_capacity_returned2 = manifest_->getMaxCapacity();
+
+  ASSERT_EQ(max_capacity1, max_capacity_returned1);
+  ASSERT_EQ(max_capacity2, max_capacity_returned2);
+}
+
 TEST_F(ManifestTest, SetHashAlgorithm) {
-  manifest1_.clear();
+  manifest_->Encoder::clear();
 
-  auth::CryptoHashType hash1 = auth::CryptoHashType::SHA512;
-  auth::CryptoHashType hash2 = auth::CryptoHashType::BLAKE2B512;
-  auth::CryptoHashType hash3 = auth::CryptoHashType::SHA256;
+  auth::CryptoHashType hash1 = auth::CryptoHashType::SHA256;
+  auth::CryptoHashType hash2 = auth::CryptoHashType::SHA512;
+  auth::CryptoHashType hash3 = auth::CryptoHashType::BLAKE2B512;
 
-  manifest1_.setHashAlgorithm(hash1);
-  auto type_returned1 = manifest1_.getHashAlgorithm();
+  manifest_->setHashAlgorithm(hash1);
+  auto type_returned1 = manifest_->getHashAlgorithm();
 
-  manifest1_.clear();
+  manifest_->Encoder::clear();
 
-  manifest1_.setHashAlgorithm(hash2);
-  auto type_returned2 = manifest1_.getHashAlgorithm();
+  manifest_->setHashAlgorithm(hash2);
+  auto type_returned2 = manifest_->getHashAlgorithm();
 
-  manifest1_.clear();
+  manifest_->Encoder::clear();
 
-  manifest1_.setHashAlgorithm(hash3);
-  auto type_returned3 = manifest1_.getHashAlgorithm();
+  manifest_->setHashAlgorithm(hash3);
+  auto type_returned3 = manifest_->getHashAlgorithm();
 
   ASSERT_EQ(hash1, type_returned1);
   ASSERT_EQ(hash2, type_returned2);
   ASSERT_EQ(hash3, type_returned3);
 }
 
+TEST_F(ManifestTest, SetLastManifest) {
+  manifest_->Encoder::clear();
+
+  manifest_->setIsLast(true);
+  bool is_last = manifest_->getIsLast();
+
+  ASSERT_TRUE(is_last);
+}
+
+TEST_F(ManifestTest, SetBaseName) {
+  manifest_->Encoder::clear();
+
+  core::Name base_name("b001::dead");
+
+  manifest_->setBaseName(base_name);
+  core::Name ret_name = manifest_->getBaseName();
+
+  ASSERT_EQ(base_name, ret_name);
+}
+
 TEST_F(ManifestTest, setParamsBytestream) {
-  manifest1_.clear();
+  manifest_->Encoder::clear();
 
   ParamsBytestream params{
-      .final_segment = 1,
+      .final_segment = 0x0a,
   };
 
-  manifest1_.setParamsBytestream(params);
-  manifest1_.encode();
+  manifest_->setParamsBytestream(params);
+  auth::CryptoHash hash(auth::CryptoHashType::SHA256);
+  hash.computeDigest({0x01, 0x02, 0x03, 0x04});
+  manifest_->addEntry(1, hash);
+
+  manifest_->encode();
+  manifest_->decode();
 
-  ContentObjectManifest manifest(manifest1_);
-  manifest.decode();
+  auto transport_type_returned = manifest_->getTransportType();
+  auto params_returned = manifest_->getParamsBytestream();
 
   ASSERT_EQ(interface::ProductionProtocolAlgorithms::BYTE_STREAM,
-            manifest.getTransportType());
-  ASSERT_EQ(params, manifest.getParamsBytestream());
+            transport_type_returned);
+  ASSERT_EQ(params, params_returned);
 }
 
 TEST_F(ManifestTest, SetParamsRTC) {
-  manifest1_.clear();
+  manifest_->Encoder::clear();
 
   ParamsRTC params{
-      .timestamp = 1,
-      .prod_rate = 2,
-      .prod_seg = 3,
+      .timestamp = 0x0a,
+      .prod_rate = 0x0b,
+      .prod_seg = 0x0c,
       .fec_type = protocol::fec::FECType::UNKNOWN,
   };
 
-  manifest1_.setParamsRTC(params);
-  manifest1_.encode();
+  manifest_->setParamsRTC(params);
+  auth::CryptoHash hash(auth::CryptoHashType::SHA256);
+  hash.computeDigest({0x01, 0x02, 0x03, 0x04});
+  manifest_->addEntry(1, hash);
 
-  ContentObjectManifest manifest(manifest1_);
-  manifest.decode();
+  manifest_->encode();
+  manifest_->decode();
+
+  auto transport_type_returned = manifest_->getTransportType();
+  auto params_returned = manifest_->getParamsRTC();
 
   ASSERT_EQ(interface::ProductionProtocolAlgorithms::RTC_PROD,
-            manifest.getTransportType());
-  ASSERT_EQ(params, manifest.getParamsRTC());
+            transport_type_returned);
+  ASSERT_EQ(params, params_returned);
 }
 
 TEST_F(ManifestTest, SignManifest) {
-  Name name("b001::", 0);
   auto signer = std::make_shared<auth::SymmetricSigner>(
       auth::CryptoSuite::HMAC_SHA256, "hunter2");
   auto verifier = std::make_shared<auth::SymmetricVerifier>("hunter2");
-  std::shared_ptr<ContentObjectManifest> manifest;
 
-  // Instantiate Manifest
-  manifest.reset(ContentObjectManifest::createManifest(
-      HF_INET6_TCP_AH, name, ManifestVersion::VERSION_1,
-      ManifestType::INLINE_MANIFEST, false, name, signer->getHashType(),
-      signer->getSignatureFieldSize()));
+  // Instantiate manifest
+  uint8_t max_capacity = 30;
+  std::shared_ptr<ContentObjectManifest> manifest =
+      ContentObjectManifest::createContentManifest(
+          format_, name_, signer->getSignatureFieldSize());
+  manifest->setHeaders(ManifestType::INLINE_MANIFEST, max_capacity,
+                       signer->getHashType(), false /* is_last */, name_);
 
-  // Add Manifest entry
+  // Add manifest entry
   auth::CryptoHash hash(signer->getHashType());
-  hash.computeDigest(std::vector<uint8_t>{0x01, 0x02, 0x03, 0x04});
-  manifest->addSuffixHash(1, hash);
+  hash.computeDigest({0x01, 0x02, 0x03, 0x04});
+  manifest->addEntry(1, hash);
 
   // Encode manifest
   manifest->encode();
+  auto manifest_co =
+      std::dynamic_pointer_cast<ContentObject>(manifest->getPacket());
 
   // Sign manifest
-  signer->signPacket(manifest.get());
+  signer->signPacket(manifest_co.get());
 
   // Check size
-  ASSERT_EQ(manifest->payloadSize(), manifest->estimateManifestSize());
-  ASSERT_EQ(manifest->length(),
-            manifest->headerSize() + manifest->payloadSize());
-  ASSERT_EQ(ContentObjectManifest::manifestHeaderSize(
-                interface::ProductionProtocolAlgorithms::UNKNOWN),
-            manifest->manifestHeaderSize());
+  ASSERT_EQ(manifest_co->payloadSize(), manifest->Encoder::manifestSize());
+  ASSERT_EQ(manifest_co->length(),
+            manifest_co->headerSize() + manifest_co->payloadSize());
 
   // Verify manifest
-  auth::VerificationPolicy policy = verifier->verifyPackets(manifest.get());
+  auth::VerificationPolicy policy = verifier->verifyPackets(manifest_co.get());
   ASSERT_EQ(auth::VerificationPolicy::ACCEPT, policy);
 }
 
-TEST_F(ManifestTest, SetBaseName) {
-  manifest1_.clear();
-
-  core::Name base_name("b001::dead");
-  manifest1_.setBaseName(base_name);
-  core::Name ret_name = manifest1_.getBaseName();
-
-  ASSERT_EQ(base_name, ret_name);
-}
-
 TEST_F(ManifestTest, SetSuffixList) {
-  manifest1_.clear();
-
-  core::Name base_name("b001::dead");
+  manifest_->Encoder::clear();
 
   using random_bytes_engine =
       std::independent_bits_engine<std::default_random_engine, CHAR_BIT,
@@ -259,12 +293,13 @@ TEST_F(ManifestTest, SetSuffixList) {
     entries[i] = std::make_pair(suffixes[i],
                                 auth::CryptoHash(data[i].data(), data[i].size(),
                                                  auth::CryptoHashType::SHA256));
-    manifest1_.addSuffixHash(entries[i].first, entries[i].second);
+    manifest_->addEntry(entries[i].first, entries[i].second);
   }
 
-  manifest1_.setBaseName(base_name);
-  core::Name ret_name = manifest1_.getBaseName();
+  core::Name base_name("b001::dead");
+  manifest_->setBaseName(base_name);
 
+  core::Name ret_name = manifest_->getBaseName();
   ASSERT_EQ(base_name, ret_name);
 
   delete[] entries;
index d9c5358..e36ca0f 100644 (file)
@@ -258,5 +258,44 @@ TEST_F(InterestTest, AppendSuffixesEncodeAndIterate) {
   }
 }
 
+TEST_F(InterestTest, AppendSuffixesWithGaps) {
+  // Create interest from buffer
+  Interest interest(HF_INET6_TCP);
+
+  // Appenad some suffixes, out of order and with gaps
+  interest.appendSuffix(6);
+  interest.appendSuffix(2);
+  interest.appendSuffix(5);
+  interest.appendSuffix(1);
+
+  // Encode them in wire format
+  interest.encodeSuffixes();
+  EXPECT_TRUE(interest.hasManifest());
+
+  // Check first suffix correctness
+  auto suffix = interest.firstSuffix();
+  EXPECT_NE(suffix, nullptr);
+  EXPECT_EQ(*suffix, 1U);
+
+  // Iterate over them. They should be in order and without repetitions
+  std::vector<uint32_t> expected = {1, 2, 5, 6};
+  EXPECT_EQ(interest.numberOfSuffixes(), expected.size());
+
+  for (uint32_t seq : expected) {
+    EXPECT_EQ(*suffix, seq);
+    suffix++;
+  }
+}
+
+TEST_F(InterestTest, InterestWithoutManifest) {
+  // Create interest without manifest
+  Interest interest(HF_INET6_TCP);
+  auto suffix = interest.firstSuffix();
+
+  EXPECT_FALSE(interest.hasManifest());
+  EXPECT_EQ(interest.numberOfSuffixes(), 0U);
+  EXPECT_EQ(suffix, nullptr);
+}
+
 }  // namespace core
 }  // namespace transport
index 562a12c..40f4df9 100644 (file)
@@ -83,8 +83,8 @@ class Memif {
       recv_counter_ += buffers.size();
       if (recv_counter_ == total_packets) {
         auto t1 = utils::SteadyTime::now();
-        auto delta = utils::SteadyTime::getDurationS(t0_, t1);
-        auto rate = recv_counter_ / delta.count();
+        auto delta = utils::SteadyTime::getDurationUs(t0_, t1);
+        double rate = double(recv_counter_) * 1.0e6 / double(delta.count());
         LOG(INFO) << "rate: " << rate << " packets/s";
         io_service_.stop();
       }
index b63ddde..744f1bd 100644 (file)
@@ -21,6 +21,7 @@
 #define ALLOCATION_CHECKS
 #include <hicn/transport/core/global_object_pool.h>
 #undef ALLOCATION_CHECKS
+#include <hicn/transport/utils/chrono_typedefs.h>
 #include <hicn/transport/utils/event_thread.h>
 
 namespace transport {
@@ -30,6 +31,8 @@ class PacketAllocatorTest : public ::testing::Test {
  protected:
   static inline const std::size_t default_size = 2048;
   static inline const std::size_t default_n_buffer = 1024;
+  static inline const std::size_t counter = 1024;
+  static inline const std::size_t total_packets = 1024 * counter;
 
   // Get fixed block allocator_ of 1024 buffers of size 2048 bytes
   PacketAllocatorTest() : allocator_(PacketManager<>::getInstance()) {
@@ -102,5 +105,27 @@ TEST_F(PacketAllocatorTest, CheckAllocationIsCorrect) {
                   PacketManager<>::PacketStorage::packet_and_shared_ptr)));
 }
 
+TEST_F(PacketAllocatorTest, CheckAllocationSpeed) {
+  // Check time needed to allocate 1 million packeauto &packet_manager =
+  auto &packet_manager = core::PacketManager<>::getInstance();
+
+  // Send 1 million packets
+  std::array<utils::MemBuf::Ptr, counter> packets;
+  auto t0 = utils::SteadyTime::now();
+  std::size_t sum = 0;
+  for (std::size_t j = 0; j < counter; j++) {
+    for (std::size_t i = 0; i < counter; i++) {
+      packets[i] = packet_manager.getMemBuf();
+      sum++;
+    }
+  }
+  auto t1 = utils::SteadyTime::now();
+
+  auto delta = utils::SteadyTime::getDurationUs(t0, t1);
+  auto rate = double(sum) * 1000000.0 / double(delta.count());
+
+  LOG(INFO) << "rate: " << rate << " packets/s";
+}
+
 }  // namespace core
 }  // namespace transport
\ No newline at end of file
diff --git a/libtransport/src/test/test_prefix.cc b/libtransport/src/test/test_prefix.cc
new file mode 100644 (file)
index 0000000..5de7375
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * 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 <glog/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hicn/transport/core/prefix.h>
+#include <hicn/transport/errors/invalid_ip_address_exception.h>
+#include <hicn/transport/portability/endianess.h>
+
+#include <cstring>
+#include <memory>
+#include <vector>
+
+namespace transport {
+namespace core {
+
+namespace {
+class PrefixTest : public ::testing::Test {
+ protected:
+  static inline const char prefix_str0[] = "2001:db8:1::/64";
+  static inline const char prefix_str1[] = "10.11.12.0/24";
+  static inline const char prefix_str2[] = "2001:db8:1::abcd/64";
+  static inline const char prefix_str3[] = "10.11.12.245/27";
+  static inline const char wrong_prefix_str0[] = "10.11.12.245/45";
+  static inline const char wrong_prefix_str1[] = "10.400.12.13/8";
+  static inline const char wrong_prefix_str2[] = "2001:db8:1::/640";
+  static inline const char wrong_prefix_str3[] = "20011::db8:1::/16";
+  static inline const char wrong_prefix_str4[] = "2001::db8:1::fffff/96";
+
+  PrefixTest() = default;
+
+  ~PrefixTest() override = default;
+
+  // If the constructor and destructor are not enough for setting up
+  // and cleaning up each test, you can define the following methods:
+
+  void SetUp() override {
+    // Code here will be called immediately after the constructor (right
+    // before each test).
+  }
+
+  void TearDown() override {
+    // Code here will be called immediately after each test (right
+    // before the destructor).
+  }
+};
+
+TEST_F(PrefixTest, ConstructorRightString) {
+  // Create empty prefix
+  Prefix p;
+
+  // Create prefix from string
+  Prefix p0(prefix_str0);
+  // Reconstruct string and check it is equal to original address
+  std::string network = p0.getNetwork();
+  std::uint16_t prefix_length = p0.getPrefixLength();
+  EXPECT_THAT(network + "/" + std::to_string(prefix_length),
+              ::testing::StrEq(prefix_str0));
+
+  // Create prefix from string
+  Prefix p1(prefix_str1);
+  // Reconstruct string and check it is equal to original address
+  network = p1.getNetwork();
+  prefix_length = p1.getPrefixLength();
+  EXPECT_THAT(network + "/" + std::to_string(prefix_length),
+              ::testing::StrEq(prefix_str1));
+
+  // Create prefix from string
+  Prefix p2(prefix_str2);
+  // Reconstruct string and check it is equal to original address
+  network = p2.getNetwork();
+  prefix_length = p2.getPrefixLength();
+  EXPECT_THAT(network + "/" + std::to_string(prefix_length),
+              ::testing::StrEq(prefix_str2));
+
+  // Create prefix from string
+  Prefix p3(prefix_str3);
+  // Reconstruct string and check it is equal to original address
+  network = p3.getNetwork();
+  prefix_length = p3.getPrefixLength();
+  EXPECT_THAT(network + "/" + std::to_string(prefix_length),
+              ::testing::StrEq(prefix_str3));
+
+  // Create prefix from string and prefix length
+  Prefix p4("2001::1234", 66);
+  // Reconstruct string and check it is equal to original address
+  network = p4.getNetwork();
+  prefix_length = p4.getPrefixLength();
+  auto af = p4.getAddressFamily();
+  EXPECT_THAT(network, ::testing::StrEq("2001::1234"));
+  EXPECT_THAT(prefix_length, ::testing::Eq(66));
+  EXPECT_THAT(af, ::testing::Eq(AF_INET6));
+}
+
+TEST_F(PrefixTest, ConstructorWrongString) {
+  try {
+    Prefix p0(wrong_prefix_str0);
+    FAIL() << "Expected exception";
+  } catch (const errors::InvalidIpAddressException &) {
+    // Expected exception
+  }
+
+  try {
+    Prefix p1(wrong_prefix_str1);
+    FAIL() << "Expected exception";
+  } catch (const errors::InvalidIpAddressException &) {
+    // Expected exception
+  }
+
+  try {
+    Prefix p2(wrong_prefix_str2);
+    FAIL() << "Expected exception";
+  } catch (const errors::InvalidIpAddressException &) {
+    // Expected exception
+  }
+
+  try {
+    Prefix p3(wrong_prefix_str3);
+    FAIL() << "Expected exception";
+  } catch (const errors::InvalidIpAddressException &) {
+    // Expected exception
+  }
+
+  try {
+    Prefix p4(wrong_prefix_str4);
+    FAIL() << "Expected exception";
+  } catch (const errors::InvalidIpAddressException &) {
+    // Expected exception
+  }
+}
+
+TEST_F(PrefixTest, Comparison) {
+  Prefix p0(prefix_str0);
+  Prefix p1(prefix_str1);
+
+  // Expect they are different
+  EXPECT_THAT(p0, ::testing::Ne(p1));
+
+  auto p2 = p1;
+  // Expect they are equal
+  EXPECT_THAT(p1, ::testing::Eq(p2));
+}
+
+TEST_F(PrefixTest, ToSockAddress) {
+  Prefix p0(prefix_str3);
+
+  auto ret = p0.toSockaddr();
+  auto sockaddr = reinterpret_cast<sockaddr_in *>(ret.get());
+
+  EXPECT_THAT(sockaddr->sin_family, ::testing::Eq(AF_INET));
+  EXPECT_THAT(sockaddr->sin_addr.s_addr, portability::host_to_net(0x0a0b0cf5));
+}
+
+TEST_F(PrefixTest, GetPrefixLength) {
+  Prefix p0(prefix_str3);
+  EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(27));
+}
+
+TEST_F(PrefixTest, SetPrefixLength) {
+  Prefix p0(prefix_str3);
+  EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(27));
+  p0.setPrefixLength(20);
+  EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(20));
+
+  try {
+    p0.setPrefixLength(33);
+    FAIL() << "Expected exception";
+  } catch ([[maybe_unused]] const errors::InvalidIpAddressException &) {
+    // Expected exception
+  }
+}
+
+TEST_F(PrefixTest, SetGetNetwork) {
+  Prefix p0(prefix_str0);
+  EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(64));
+  p0.setNetwork("b001::1234");
+  EXPECT_THAT(p0.getNetwork(), ::testing::StrEq("b001::1234"));
+  EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(64));
+}
+
+TEST_F(PrefixTest, Contains) {
+  // IPv6 prefix
+  Prefix p0(prefix_str0);
+  ip_address_t ip0, ip1;
+
+  ip_address_pton("2001:db8:1::1234", &ip0);
+  ip_address_pton("2001:db9:1::1234", &ip1);
+
+  EXPECT_TRUE(p0.contains(ip0));
+  EXPECT_FALSE(p0.contains(ip1));
+
+  Prefix p1(prefix_str1);
+  ip_address_pton("10.11.12.12", &ip0);
+  ip_address_pton("10.12.12.13", &ip1);
+
+  EXPECT_TRUE(p1.contains(ip0));
+  EXPECT_FALSE(p1.contains(ip1));
+
+  Prefix p2(prefix_str2);
+  ip_address_pton("2001:db8:1::dbca", &ip0);
+  ip_address_pton("10.12.12.12", &ip1);
+
+  EXPECT_TRUE(p2.contains(ip0));
+  EXPECT_FALSE(p2.contains(ip1));
+
+  Prefix p3(prefix_str3);
+  ip_address_pton("10.11.12.245", &ip0);
+  ip_address_pton("10.11.12.1", &ip1);
+
+  EXPECT_TRUE(p3.contains(ip0));
+  EXPECT_FALSE(p3.contains(ip1));
+
+  // Corner cases
+  Prefix p4("::/0");
+  ip_address_pton("7001:db8:1::1234", &ip0);
+  ip_address_pton("8001:db8:1::1234", &ip1);
+
+  EXPECT_TRUE(p4.contains(ip0));
+  EXPECT_TRUE(p4.contains(ip1));
+
+  // Corner cases
+  Prefix p5("b001:a:b:c:d:e:f:1/128");
+  ip_address_pton("b001:a:b:c:d:e:f:1", &ip0);
+  ip_address_pton("b001:a:b:c:d:e:f:2", &ip1);
+
+  EXPECT_TRUE(p5.contains(ip0));
+  EXPECT_FALSE(p5.contains(ip1));
+}
+
+TEST_F(PrefixTest, GetAddressFamily) {
+  Prefix p0(prefix_str0);
+  auto af = p0.getAddressFamily();
+  EXPECT_THAT(af, ::testing::Eq(AF_INET6));
+
+  Prefix p1(prefix_str1);
+  af = p1.getAddressFamily();
+  EXPECT_THAT(af, ::testing::Eq(AF_INET));
+}
+
+TEST_F(PrefixTest, MakeName) {
+  Prefix p0(prefix_str0);
+  auto name0 = p0.makeName();
+  EXPECT_THAT(name0.toString(), ::testing::StrEq("2001:db8:1::|0"));
+
+  Prefix p1(prefix_str1);
+  auto name1 = p1.makeName();
+  EXPECT_THAT(name1.toString(), ::testing::StrEq("10.11.12.0|0"));
+
+  Prefix p2(prefix_str2);
+  auto name2 = p2.makeName();
+  EXPECT_THAT(name2.toString(), ::testing::StrEq("2001:db8:1::|0"));
+
+  Prefix p3(prefix_str3);
+  auto name3 = p3.makeName();
+  EXPECT_THAT(name3.toString(), ::testing::StrEq("10.11.12.224|0"));
+
+  Prefix p4("b001:a:b:c:d:e:f:1/128");
+  auto name4 = p4.makeName();
+  EXPECT_THAT(name4.toString(), ::testing::StrEq("b001:a:b:c:d:e:f:1|0"));
+}
+
+TEST_F(PrefixTest, MakeRandomName) {
+  Prefix p0(prefix_str0);
+  auto name0 = p0.makeRandomName();
+  auto name1 = p0.makeRandomName();
+  auto name2 = p0.makeRandomName();
+  auto name3 = p0.makeRandomName();
+
+  EXPECT_THAT(name0, ::testing::Not(::testing::Eq(name1)));
+  EXPECT_THAT(name0, ::testing::Not(::testing::Eq(name2)));
+  EXPECT_THAT(name0, ::testing::Not(::testing::Eq(name3)));
+  EXPECT_THAT(name1, ::testing::Not(::testing::Eq(name2)));
+  EXPECT_THAT(name1, ::testing::Not(::testing::Eq(name3)));
+  EXPECT_THAT(name2, ::testing::Not(::testing::Eq(name3)));
+
+  // Corner case
+  Prefix p2("b001:a:b:c:d:e:f:1/128");
+  name0 = p2.makeRandomName();
+  name1 = p2.makeRandomName();
+  name2 = p2.makeRandomName();
+  name3 = p2.makeRandomName();
+
+  EXPECT_THAT(name0, ::testing::Eq(name1));
+  EXPECT_THAT(name0, ::testing::Eq(name2));
+  EXPECT_THAT(name0, ::testing::Eq(name3));
+  EXPECT_THAT(name1, ::testing::Eq(name2));
+  EXPECT_THAT(name1, ::testing::Eq(name3));
+  EXPECT_THAT(name2, ::testing::Eq(name3));
+}
+
+TEST_F(PrefixTest, MakeNameWithIndex) {
+  Prefix p0(prefix_str0);
+  auto name0 = p0.makeNameWithIndex(0);
+  EXPECT_THAT(name0.toString(), ::testing::StrEq("2001:db8:1::|0"));
+  auto name1 = p0.makeNameWithIndex(1);
+  EXPECT_THAT(name1.toString(), ::testing::StrEq("2001:db8:1::1|0"));
+  auto name2 = p0.makeNameWithIndex(2);
+  EXPECT_THAT(name2.toString(), ::testing::StrEq("2001:db8:1::2|0"));
+  auto name3 = p0.makeNameWithIndex(3);
+  EXPECT_THAT(name3.toString(), ::testing::StrEq("2001:db8:1::3|0"));
+
+  Prefix p1(prefix_str1);
+  name0 = p1.makeNameWithIndex(0);
+  EXPECT_THAT(name0.toString(), ::testing::StrEq("10.11.12.0|0"));
+  name1 = p1.makeNameWithIndex(1);
+  EXPECT_THAT(name1.toString(), ::testing::StrEq("10.11.12.1|0"));
+  name2 = p1.makeNameWithIndex(2);
+  EXPECT_THAT(name2.toString(), ::testing::StrEq("10.11.12.2|0"));
+  name3 = p1.makeNameWithIndex(3);
+  EXPECT_THAT(name3.toString(), ::testing::StrEq("10.11.12.3|0"));
+
+  // Test truncation
+  Prefix p2("b001::/96");
+  name0 = p2.makeNameWithIndex(0xffffffffffffffff);
+  EXPECT_THAT(name0.toString(), ::testing::StrEq("b001::ffff:ffff|0"));
+}
+
+}  // namespace
+
+}  // namespace core
+}  // namespace transport
\ No newline at end of file
diff --git a/libtransport/src/test/test_quadloop.cc b/libtransport/src/test/test_quadloop.cc
new file mode 100644 (file)
index 0000000..6a08033
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * 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 <glog/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hicn/transport/portability/cache.h>
+
+#include <array>
+#include <cstring>
+#include <memory>
+#include <vector>
+
+namespace utils {
+
+class LoopTest : public ::testing::Test {
+ protected:
+  static inline const std::size_t size = 256;
+
+  LoopTest() = default;
+
+  ~LoopTest() override = default;
+
+  // If the constructor and destructor are not enough for setting up
+  // and cleaning up each test, you can define the following methods:
+
+  void SetUp() override {
+    // Code here will be called immediately after the constructor (right
+    // before each test).
+  }
+
+  void TearDown() override {
+    // Code here will be called immediately after each test (right
+    // before the destructor).
+  }
+};
+
+// 1 cache line struct (64 bytes)
+struct Data {
+  std::array<uint64_t, 8> data;
+};
+
+TEST_F(LoopTest, QuadLoopTest) {
+  // Create 2 arrays of 256 elements
+  std::vector<std::unique_ptr<Data>> _from;
+  std::vector<std::unique_ptr<Data>> _to_next;
+  _from.reserve(size);
+  _to_next.reserve(size);
+
+  int n_left_from = size;
+  int n_left_to_next = size;
+
+  // Initialize the arrays
+  for (std::size_t i = 0; i < size; i++) {
+    _from.push_back(std::make_unique<Data>());
+    _to_next.push_back(std::make_unique<Data>());
+
+    for (int j = 0; j < 8; j++) {
+      _from[i]->data[j] = j;
+      _to_next[i]->data[j] = 0;
+    }
+  }
+
+  const std::unique_ptr<Data> *from = &_from[0];
+  const std::unique_ptr<Data> *to_next = &_to_next[0];
+
+  clock_t start;
+  clock_t end;
+  double clocks;
+
+  start = clock();
+  // Create a quad loop
+  while (n_left_from > 0) {
+    while (n_left_from >= 4 && n_left_to_next >= 4) {
+      {
+        using namespace transport::portability::cache;
+        Data *d2;
+        Data *d3;
+
+        d2 = from[2].get();
+        d3 = from[3].get();
+
+        prefetch<Data, READ>(d2, sizeof(Data));
+        prefetch<Data, READ>(d3, sizeof(Data));
+
+        d2 = to_next[2].get();
+        d3 = to_next[3].get();
+
+        prefetch<Data, WRITE>(d2, sizeof(Data));
+        prefetch<Data, WRITE>(d3, sizeof(Data));
+      }
+
+      // Do 4 iterations
+      std::memcpy(to_next[0].get()->data.data(), from[0].get()->data.data(),
+                  sizeof(Data));
+      std::memcpy(to_next[1].get()->data.data(), from[1].get()->data.data(),
+                  sizeof(Data));
+      n_left_from -= 2;
+      n_left_to_next -= 2;
+      from += 2;
+      to_next += 2;
+    }
+
+    while (n_left_from > 0 && n_left_to_next > 0) {
+      std::memcpy(to_next[0].get()->data.data(), from[0].get()->data.data(),
+                  sizeof(Data));
+      n_left_from -= 1;
+      n_left_to_next -= 1;
+      from += 1;
+      to_next += 1;
+    }
+  }
+  end = clock();
+  clocks = (double)(end - start);
+
+  LOG(INFO) << "Time with quad loop: " << clocks << std::endl;
+}
+
+TEST_F(LoopTest, NormalLoopTest) {
+  // Create 2 arrays of 256 elements
+  std::vector<std::unique_ptr<Data>> _from;
+  std::vector<std::unique_ptr<Data>> _to_next;
+  _from.reserve(size);
+  _to_next.reserve(size);
+
+  int n_left_from = size;
+  int n_left_to_next = size;
+
+  // Initialize the arrays
+  for (std::size_t i = 0; i < size; i++) {
+    _from.push_back(std::make_unique<Data>());
+    _to_next.push_back(std::make_unique<Data>());
+
+    for (int j = 0; j < 8; j++) {
+      _from[i]->data[j] = j;
+      _to_next[i]->data[j] = 0;
+    }
+  }
+
+  const std::unique_ptr<Data> *from = &_from[0];
+  const std::unique_ptr<Data> *to_next = &_to_next[0];
+
+  clock_t start;
+  clock_t end;
+  double clocks;
+
+  start = clock();
+  while (n_left_from > 0) {
+    while (n_left_from > 0 && n_left_to_next > 0) {
+      std::memcpy(to_next[0].get()->data.data(), from[0].get()->data.data(),
+                  sizeof(Data));
+      n_left_from -= 1;
+      n_left_to_next -= 1;
+      from += 1;
+      to_next += 1;
+    }
+  }
+  end = clock();
+  clocks = ((double)(end - start));
+
+  LOG(INFO) << "Time with normal loop: " << clocks << std::endl;
+}
+
+}  // namespace utils
\ No newline at end of file
index 8e7681c..32d99c8 100644 (file)
@@ -49,7 +49,7 @@ class EpollEventReactor : public EventReactor {
     if (it == event_callback_map_.end()) {
       {
         utils::SpinLock::Acquire locked(event_callback_map_lock_);
-        event_callback_map_[fd] = std::forward<EventHandler &&>(callback);
+        event_callback_map_[fd] = std::forward<EventHandler>(callback);
       }
 
       ret = addFileDescriptor(fd, events);
index e15cd4d..cf0cde1 100644 (file)
@@ -57,8 +57,8 @@ class FdDeadlineTimer : public DeadlineTimer<FdDeadlineTimer> {
 
     reactor_.addFileDescriptor(
         timer_fd_, events,
-        [callback = std::forward<WaitHandler &&>(callback)](
-            const Event &event) -> int {
+        [callback =
+             std::forward<WaitHandler>(callback)](const Event &event) -> int {
           uint64_t s = 0;
           std::error_code ec;
 
index 96eaed6..4b3ddbc 100644 (file)
@@ -36,11 +36,11 @@ enum class NextSuffixStrategy : uint8_t {
 class SuffixStrategy {
  public:
   static constexpr uint32_t MAX_SUFFIX = std::numeric_limits<uint32_t>::max();
-  static constexpr uint8_t MAX_MANIFEST_CAPACITY =
+  static constexpr uint8_t MANIFEST_MAX_CAPACITY =
       std::numeric_limits<uint8_t>::max();
 
   SuffixStrategy(NextSuffixStrategy strategy, uint32_t offset = 0,
-                 uint32_t manifest_capacity = MAX_MANIFEST_CAPACITY)
+                 uint32_t manifest_capacity = MANIFEST_MAX_CAPACITY)
       : suffix_stragegy_(strategy),
         next_suffix_(offset),
         manifest_capacity_(manifest_capacity),
@@ -130,7 +130,7 @@ class SuffixStrategyFactory {
  public:
   static std::unique_ptr<SuffixStrategy> getSuffixStrategy(
       NextSuffixStrategy strategy, uint32_t start_offset = 0,
-      uint32_t manifest_capacity = SuffixStrategy::MAX_MANIFEST_CAPACITY) {
+      uint32_t manifest_capacity = SuffixStrategy::MANIFEST_MAX_CAPACITY) {
     switch (strategy) {
       case NextSuffixStrategy::INCREMENTAL:
         return std::make_unique<IncrementalSuffixStrategy>(start_offset);
diff --git a/telemetry/.clang-format b/telemetry/.clang-format
new file mode 100644 (file)
index 0000000..0043ea3
--- /dev/null
@@ -0,0 +1,3 @@
+# Copyright (c) 2022 Cisco and/or its affiliates.
+
+BasedOnStyle:  Google
\ No newline at end of file
index eff8556..181e726 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
+##############################################################
+# Project and cmake version
+##############################################################
 cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
+project(telemetry)
+
+
+##############################################################
+# C Standard
+##############################################################
+set(CMAKE_C_STANDARD 11)
+
+
+##############################################################
+# Cmake modules
+##############################################################
+include("${CMAKE_CURRENT_SOURCE_DIR}/../versions.cmake")
+set(CMAKE_MODULE_PATH
+  ${CMAKE_MODULE_PATH}
+  ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules
+)
+
+
+##############################################################
+# Libs and Bins names
+##############################################################
+set(COLLECTD_PLUGINS hicn-collectd-plugins CACHE INTERNAL "" FORCE)
+set(HICN_LIGHT_TELEMETRY hicn_light)
+set(KAFKA_TELEMETRY write_kafka_line_protocol)
+set(VPP_TELEMETRY vpp)
+set(VPP_HICN_TELEMETRY vpp_hicn)
+
 
 ##############################################################
-# Packaging and versioning
+# Dependencies and third party libs
 ##############################################################
+find_package(Collectd ${COLLECTD_DEFAULT_VERSION} REQUIRED)
+add_subdirectory(third-party)
+
+
+##############################################################
+# Check if building as subproject or as root project
+##############################################################
+if(NOT (CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) AND
+  NOT (BUILD_HICNPLUGIN AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux"))
+  return()
+endif()
+include(CommonSetup)
+
+# Include config.h in all collectd plugins
+set(COLLECTD_COMPILER_OPTIONS -include config.h)
+
+# ##############################################################
+# # Packaging and versioning
+# ##############################################################
 include(${CMAKE_CURRENT_SOURCE_DIR}/../versions.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/packaging.cmake)
 
 
 ##############################################################
 # Subdirectories
 ##############################################################
-if ((CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) OR
-    (BUILD_HICNPLUGIN AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux"))
-    add_subdirectory(vpp-collectd)
-endif ()
+add_subdirectory(hicn-light-collectd)
+add_subdirectory(kafka-collectd)
+add_subdirectory(vpp-collectd)
\ No newline at end of file
similarity index 84%
rename from telemetry/vpp-collectd/cmake/packaging.cmake
rename to telemetry/cmake/packaging.cmake
index 49a6173..d5d2264 100644 (file)
@@ -21,11 +21,11 @@ set(${COLLECTD_PLUGINS}_DESCRIPTION
 )
 
 set(${COLLECTD_PLUGINS}_DEB_DEPENDENCIES
-  "collectd, hicn-plugin-dev (= stable_version)"
+  "collectd, hicn-plugin-dev (= stable_version) libhicnctrl (= stable_version) libyajl-dev"
   CACHE STRING "Dependencies for deb/rpm package."
 )
 
 set(${COLLECTD_PLUGINS}_RPM_DEPENDENCIES
-  "collectd, hicn-plugin-dev = stable_version"
+  "collectd, hicn-plugin-dev (= stable_version) libhicnctrl (= stable_version) libyajl-dev"
   CACHE STRING "Dependencies for deb/rpm package."
 )
\ No newline at end of file
diff --git a/telemetry/collectd.conf b/telemetry/collectd.conf
new file mode 100644 (file)
index 0000000..225c161
--- /dev/null
@@ -0,0 +1,54 @@
+##############################################################################
+# Global                                                                     #
+##############################################################################
+FQDNLookup true
+#Interval 10
+
+# Limit the size of the write queue. Default is no limit. Setting up a limit
+# is recommended for servers handling a high volume of traffic.
+#WriteQueueLimitHigh 1000000
+#WriteQueueLimitLow   800000
+
+##############################################################################
+# Logging                                                                    #
+##############################################################################
+LoadPlugin logfile
+
+<Plugin logfile>
+       LogLevel "info"
+       File STDOUT
+       Timestamp true
+       PrintSeverity true
+</Plugin>
+
+##############################################################################
+# LoadPlugin section                                                         #
+##############################################################################
+LoadPlugin write_log
+
+<LoadPlugin hicn_light>
+       Globals true # Required to find libhicnctrl symbols
+       Interval 5
+</LoadPlugin>
+
+<LoadPlugin write_kafka_line_protocol>
+       Interval 10
+</LoadPlugin>
+
+##############################################################################
+# Plugin configuration                                                       #
+##############################################################################
+<Plugin write_kafka_line_protocol>
+       Property "bootstrap.servers" "localhost:8081"
+       Property "security.protocol" "sasl_plaintext"
+  Property "sasl.mechanism" "SCRAM-SHA-256"
+  Property "sasl.username" "eloparco"
+  Property "sasl.password" "password"
+
+       <Topic "stream">
+               Format InfluxDB
+       </Topic>
+       # <Topic "metadata">
+       #       Format hicnJSON
+       # </Topic>
+</Plugin>
diff --git a/telemetry/data_model.h b/telemetry/data_model.h
new file mode 100644 (file)
index 0000000..b1c4ae7
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2022 Cisco and/or its affiliates.
+ */
+
+#include "utils/common/common.h"
+
+#define KAFKA_TOPIC_KEY "_TOPIC"
+#define KAFKA_STREAM_TOPIC "stream"
+#define KAFKA_METADATA_TOPIC "metadata"
+
+/************** DATA SOURCES ******************************/
+data_source_t packets_dsrc[1] = {
+    {"packets", DS_TYPE_GAUGE, 0, NAN},
+};
+
+data_source_t interests_dsrc[1] = {
+    {"interests", DS_TYPE_GAUGE, 0, NAN},
+};
+
+data_source_t data_dsrc[1] = {
+    {"data", DS_TYPE_GAUGE, 0, NAN},
+};
+
+data_source_t combined_dsrc[2] = {
+    {"packets", DS_TYPE_DERIVE, 0, NAN},
+    {"bytes", DS_TYPE_DERIVE, 0, NAN},
+};
+
+/************** DATA SETS NODE ****************************/
+data_set_t pkts_processed_ds = {
+    "pkts_processed",
+    STATIC_ARRAY_SIZE(packets_dsrc),
+    packets_dsrc,
+};
+
+data_set_t pkts_interest_count_ds = {
+    "pkts_interest_count",
+    STATIC_ARRAY_SIZE(packets_dsrc),
+    packets_dsrc,
+};
+
+data_set_t pkts_data_count_ds = {
+    "pkts_data_count",
+    STATIC_ARRAY_SIZE(packets_dsrc),
+    packets_dsrc,
+};
+
+data_set_t pkts_from_cache_count_ds = {
+    "pkts_from_cache_count",
+    STATIC_ARRAY_SIZE(packets_dsrc),
+    packets_dsrc,
+};
+
+data_set_t pkts_no_pit_count_ds = {
+    "pkts_no_pit_count",
+    STATIC_ARRAY_SIZE(packets_dsrc),
+    packets_dsrc,
+};
+
+data_set_t pit_expired_count_ds = {
+    "pit_expired_count",
+    STATIC_ARRAY_SIZE(interests_dsrc),
+    interests_dsrc,
+};
+
+data_set_t cs_expired_count_ds = {
+    "cs_expired_count",
+    STATIC_ARRAY_SIZE(data_dsrc),
+    data_dsrc,
+};
+
+data_set_t cs_lru_count_ds = {
+    "cs_lru_count",
+    STATIC_ARRAY_SIZE(data_dsrc),
+    data_dsrc,
+};
+
+data_set_t pkts_drop_no_buf_ds = {
+    "pkts_drop_no_buf",
+    STATIC_ARRAY_SIZE(packets_dsrc),
+    packets_dsrc,
+};
+
+data_set_t interests_aggregated_ds = {
+    "interests_aggregated",
+    STATIC_ARRAY_SIZE(interests_dsrc),
+    interests_dsrc,
+};
+
+data_set_t interests_retx_ds = {
+    "interests_retx",
+    STATIC_ARRAY_SIZE(interests_dsrc),
+    interests_dsrc,
+};
+
+data_set_t interests_hash_collision_ds = {
+    "interests_hash_collision",
+    STATIC_ARRAY_SIZE(interests_dsrc),
+    interests_dsrc,
+};
+
+data_set_t pit_entries_count_ds = {
+    "pit_entries_count",
+    STATIC_ARRAY_SIZE(interests_dsrc),
+    interests_dsrc,
+};
+
+data_set_t cs_entries_count_ds = {
+    "cs_entries_count",
+    STATIC_ARRAY_SIZE(data_dsrc),
+    data_dsrc,
+};
+
+data_set_t cs_entries_ntw_count_ds = {
+    "cs_entries_ntw_count",
+    STATIC_ARRAY_SIZE(data_dsrc),
+    data_dsrc,
+};
+
+/************** DATA SETS FACE ****************************/
+data_set_t irx_ds = {
+    "irx",
+    STATIC_ARRAY_SIZE(combined_dsrc),
+    combined_dsrc,
+};
+
+data_set_t itx_ds = {
+    "itx",
+    STATIC_ARRAY_SIZE(combined_dsrc),
+    combined_dsrc,
+};
+
+data_set_t drx_ds = {
+    "drx",
+    STATIC_ARRAY_SIZE(combined_dsrc),
+    combined_dsrc,
+};
+
+data_set_t dtx_ds = {
+    "dtx",
+    STATIC_ARRAY_SIZE(combined_dsrc),
+    combined_dsrc,
+};
diff --git a/telemetry/hicn-light-collectd/CMakeLists.txt b/telemetry/hicn-light-collectd/CMakeLists.txt
new file mode 100644 (file)
index 0000000..984d707
--- /dev/null
@@ -0,0 +1,65 @@
+# Copyright (c) 2022 Cisco and/or its affiliates.
+
+##############################################################
+# Source files
+##############################################################
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light.c
+)
+
+
+##############################################################
+# Include dirs
+##############################################################
+list(APPEND INCLUDE_DIRS
+  ${COLLECTD_INCLUDE_DIRS}
+  ${THIRD_PARTY_INCLUDE_DIRS}
+)
+
+
+##############################################################
+# Libraries
+##############################################################
+find_package(Libhicn ${CURRENT_VERSION} REQUIRED NO_MODULE)
+find_package(Libhicnctrl ${CURRENT_VERSION} REQUIRED NO_MODULE)
+
+if (DISABLE_SHARED_LIBRARIES)
+  set(LIBTYPE static)
+else()
+  set(LIBTYPE shared)
+endif()
+
+list(APPEND LIBHICN_LIBRARIES hicn::hicn.${LIBTYPE})
+list(APPEND LIBHICNCTRL_LIBRARIES hicn::hicnctrl.${LIBTYPE})
+
+list (APPEND LIBRARIES
+  PRIVATE ${LIBHICNCTRL_LIBRARIES}
+  PRIVATE ${LIBHICN_LIBRARIES}
+)
+
+
+##############################################################
+# Compiler options
+##############################################################
+list(APPEND COMPILER_OPTIONS
+  ${DEFAULT_COMPILER_OPTIONS}
+  ${COLLECTD_COMPILER_OPTIONS}
+)
+
+
+##############################################################
+# Build library
+##############################################################
+build_library(${HICN_LIGHT_TELEMETRY}
+  SHARED
+  EMPTY_PREFIX
+  SOURCES ${SOURCE_FILES}
+  LINK_LIBRARIES ${LIBRARIES}
+  INCLUDE_DIRS
+    PRIVATE ${INCLUDE_DIRS}
+  INSTALL_FULL_PATH_DIR ${COLLECTD_PLUGIN_DIR}
+  COMPONENT ${COLLECTD_PLUGINS}
+  DEPENDS ${DEPENDENCIES}
+  LINK_FLAGS ${LINK_FLAGS}
+  COMPILE_OPTIONS ${COMPILER_OPTIONS}
+)
\ No newline at end of file
diff --git a/telemetry/hicn-light-collectd/hicn_light.c b/telemetry/hicn-light-collectd/hicn_light.c
new file mode 100644 (file)
index 0000000..bb4eb57
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2022 Cisco and/or its affiliates.
+ */
+
+#define ntohll hicn_ntohll  // Rename to avoid collision
+#include <hicn/ctrl/api.h>
+#include <hicn/ctrl/hicn-light-ng.h>
+#include <hicn/util/sstrncpy.h>
+#undef ntohll
+
+#include "../data_model.h"
+#include "collectd.h"
+#include "plugin.h"
+#include "utils/common/common.h"
+
+#define PLUGIN_NAME "hicn_light"
+
+static hc_sock_t *s = NULL;
+
+static void submit(const char *type, value_t *values, size_t values_len,
+                   meta_data_t *meta) {
+  assert(type != NULL && values != NULL && values_len != 0);
+
+  value_list_t vl = {.values = values, .values_len = values_len};
+  if (meta) vl.meta = meta;
+
+  int rc = strcpy_s(vl.plugin, sizeof(vl.plugin), PLUGIN_NAME);
+  _ASSERT(rc == EOK);
+  rc = strcpy_s(vl.type, sizeof(vl.type), type);
+  _ASSERT(rc == EOK);
+  rc = strcpy_s(vl.host, sizeof(vl.host), hostname_g);
+  _ASSERT(rc == EOK);
+
+  plugin_dispatch_values(&vl);
+}
+
+static int read_forwarder_global_stats(hc_data_t **pdata, meta_data_t *meta) {
+  // Retrieve global stats from forwarder
+  int rc = hc_stats_get(s, pdata);
+  if (rc < 0) {
+    plugin_log(LOG_ERR, "Could not read global stats from forwarder");
+    return -1;
+  }
+  hicn_light_stats_t stats = *((hicn_light_stats_t *)(*pdata)->buffer);
+
+  // Submit values
+  value_t values[1];
+  values[0] = (value_t){.gauge = stats.forwarder.countReceived};
+  submit(pkts_processed_ds.type, values, 1, meta);
+  values[0] = (value_t){.gauge = stats.forwarder.countInterestsReceived};
+  submit(pkts_interest_count_ds.type, values, 1, meta);
+  values[0] = (value_t){.gauge = stats.forwarder.countObjectsReceived};
+  submit(pkts_data_count_ds.type, values, 1, meta);
+  values[0] =
+      (value_t){.gauge = stats.forwarder.countInterestsSatisfiedFromStore};
+  submit(pkts_from_cache_count_ds.type, values, 1, meta);
+  values[0] = (value_t){.gauge = stats.forwarder.countDroppedNoReversePath};
+  submit(pkts_no_pit_count_ds.type, values, 1, meta);
+  values[0] = (value_t){.gauge = stats.forwarder.countInterestsExpired};
+  submit(pit_expired_count_ds.type, values, 1, meta);
+  values[0] = (value_t){.gauge = stats.forwarder.countDataExpired};
+  submit(cs_expired_count_ds.type, values, 1, meta);
+  values[0] = (value_t){.gauge = stats.pkt_cache.n_lru_evictions};
+  submit(cs_lru_count_ds.type, values, 1, meta);
+  values[0] = (value_t){.gauge = stats.forwarder.countDropped};
+  submit(pkts_drop_no_buf_ds.type, values, 1, meta);
+  values[0] = (value_t){.gauge = stats.forwarder.countInterestsAggregated};
+  submit(interests_aggregated_ds.type, values, 1, meta);
+  values[0] = (value_t){.gauge = stats.forwarder.countInterestsRetransmitted};
+  submit(interests_retx_ds.type, values, 1, meta);
+  values[0] = (value_t){.gauge = stats.pkt_cache.n_pit_entries};
+  submit(pit_entries_count_ds.type, values, 1, meta);
+  values[0] = (value_t){.gauge = stats.pkt_cache.n_cs_entries};
+  submit(cs_entries_count_ds.type, values, 1, meta);
+
+  return 0;
+}
+
+static int read_forwarder_per_face_stats(hc_data_t **pdata, meta_data_t *meta) {
+  // Retrieve per-face stats from forwarder
+  int rc = hc_stats_list(s, pdata);
+  if (rc < 0) {
+    plugin_log(LOG_ERR, "Could not read face stats from forwarder");
+    return -1;
+  }
+  hc_data_t *data = *pdata;
+  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);
+
+  // Submit values
+  while (conn_stats < end) {
+    rc = meta_data_add_unsigned_int(meta, "face_id", conn_stats->id);
+    assert(rc == 0);
+
+    value_t values[2];
+    values[0] = (value_t){.derive = conn_stats->stats.interests.rx_pkts};
+    values[1] = (value_t){.derive = conn_stats->stats.interests.rx_bytes};
+    submit(irx_ds.type, values, 2, meta);
+    values[0] = (value_t){.derive = conn_stats->stats.interests.tx_pkts};
+    values[1] = (value_t){.derive = conn_stats->stats.interests.tx_bytes};
+    submit(itx_ds.type, values, 2, meta);
+    values[0] = (value_t){.derive = conn_stats->stats.data.rx_pkts};
+    values[1] = (value_t){.derive = conn_stats->stats.data.rx_bytes};
+    submit(drx_ds.type, values, 2, meta);
+    values[0] = (value_t){.derive = conn_stats->stats.data.tx_pkts};
+    values[1] = (value_t){.derive = conn_stats->stats.data.tx_bytes};
+    submit(dtx_ds.type, values, 2, meta);
+
+    conn_stats++;
+  }
+
+  return 0;
+}
+
+static int read_forwarder_stats() {
+  // Create metadata
+  meta_data_t *meta = meta_data_create();
+  int rc = meta_data_add_string(meta, KAFKA_TOPIC_KEY, KAFKA_STREAM_TOPIC);
+  assert(rc == 0);
+
+  hc_data_t *data = NULL;
+  rc = read_forwarder_global_stats(&data, meta);
+  if (rc < 0) goto READ_ERROR;
+  rc = read_forwarder_per_face_stats(&data, meta);
+
+READ_ERROR:
+  meta_data_destroy(meta);
+  hc_data_free(data);
+  return rc;
+}
+
+static int connect_to_forwarder() {
+  plugin_log(LOG_INFO, "Connecting to forwarder");
+  s = hc_sock_create_forwarder(HICNLIGHT_NG);
+  if (!s) {
+    plugin_log(LOG_ERR, "Could not create socket");
+    return -1;
+  }
+
+  int rc = hc_sock_connect(s);
+  if (rc < 0) {
+    plugin_log(LOG_ERR, "Could not establish connection to forwarder");
+    hc_sock_free(s);
+    s = NULL;
+    return -1;
+  }
+
+  return 0;
+}
+
+static int disconnect_from_forwarder() {
+  plugin_log(LOG_INFO, "Disconnecting from forwarder");
+
+  if (s == NULL) {
+    plugin_log(LOG_ERR, "Forwarder not connected");
+    return -1;
+  }
+
+  hc_command_t command = {0};
+  command.object.connection.id = 0;
+  int rc = strcpy_s(command.object.connection.name,
+                    sizeof(command.object.connection.name), "SELF");
+  if (rc != EOK || hc_connection_delete(s, &command.object.connection) < 0) {
+    rc = -1;
+    plugin_log(LOG_ERR, "Error removing local connection to forwarder");
+  }
+
+  hc_sock_free(s);
+  return rc;
+}
+
+void module_register() {
+  // Data sets
+  plugin_register_data_set(&pkts_processed_ds);
+  plugin_register_data_set(&pkts_interest_count_ds);
+  plugin_register_data_set(&pkts_data_count_ds);
+  plugin_register_data_set(&pkts_from_cache_count_ds);
+  plugin_register_data_set(&pkts_no_pit_count_ds);
+  plugin_register_data_set(&pit_expired_count_ds);
+  plugin_register_data_set(&cs_expired_count_ds);
+  plugin_register_data_set(&cs_lru_count_ds);
+  plugin_register_data_set(&pkts_drop_no_buf_ds);
+  plugin_register_data_set(&interests_aggregated_ds);
+  plugin_register_data_set(&interests_retx_ds);
+  plugin_register_data_set(&interests_hash_collision_ds);
+  plugin_register_data_set(&pit_entries_count_ds);
+  plugin_register_data_set(&cs_entries_count_ds);
+  plugin_register_data_set(&cs_entries_ntw_count_ds);
+  plugin_register_data_set(&irx_ds);
+  plugin_register_data_set(&itx_ds);
+  plugin_register_data_set(&drx_ds);
+  plugin_register_data_set(&dtx_ds);
+
+  // Callbacks
+  plugin_register_init(PLUGIN_NAME, connect_to_forwarder);
+  plugin_register_read(PLUGIN_NAME, read_forwarder_stats);
+  plugin_register_shutdown(PLUGIN_NAME, disconnect_from_forwarder);
+}
\ No newline at end of file
diff --git a/telemetry/kafka-collectd/CMakeLists.txt b/telemetry/kafka-collectd/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f1ff811
--- /dev/null
@@ -0,0 +1,62 @@
+# Copyright (c) 2022 Cisco and/or its affiliates.
+
+##############################################################
+# Source files
+##############################################################
+file(GLOB_RECURSE COLLECTD_UTILS_SOURCES "${THIRD_PARTY_INCLUDE_DIRS}/utils/cmds/*.c")
+
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/write_kafka_line_protocol.c
+  ${THIRD_PARTY_INCLUDE_DIRS}/utils/format_json/format_json.c
+  ${THIRD_PARTY_INCLUDE_DIRS}/utils/format_graphite/format_graphite.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/format_influxdb.c
+  ${COLLECTD_UTILS_SOURCES}
+)
+
+
+##############################################################
+# Include dirs
+##############################################################
+list(APPEND INCLUDE_DIRS
+  PRIVATE ${COLLECTD_INCLUDE_DIRS}
+  PRIVATE ${THIRD_PARTY_INCLUDE_DIRS}
+)
+
+
+##############################################################
+# Libraries
+##############################################################
+find_package(RdKafka ${RDKAFKA_DEFAULT_VERSION} REQUIRED)
+find_library(YAJL_LIB libyajl.so REQUIRED)
+
+list (APPEND LIBRARIES
+  ${YAJL_LIB}
+  ${RdKafka_LIBRARY_PATH}
+)
+
+
+##############################################################
+# Compiler options
+##############################################################
+list(APPEND COMPILER_OPTIONS
+  ${DEFAULT_COMPILER_OPTIONS}
+  ${COLLECTD_COMPILER_OPTIONS}
+)
+
+
+##############################################################
+# Build library
+##############################################################
+build_library(${KAFKA_TELEMETRY}
+  SHARED
+  EMPTY_PREFIX
+  SOURCES ${SOURCE_FILES}
+  LINK_LIBRARIES ${LIBRARIES}
+  INCLUDE_DIRS
+    PRIVATE ${INCLUDE_DIRS}
+  INSTALL_FULL_PATH_DIR ${COLLECTD_PLUGIN_DIR}
+  COMPONENT ${COLLECTD_PLUGINS}
+  DEPENDS ${DEPENDENCIES}
+  LINK_FLAGS ${LINK_FLAGS}
+  COMPILE_OPTIONS ${COMPILER_OPTIONS}
+)
diff --git a/telemetry/kafka-collectd/format_influxdb.c b/telemetry/kafka-collectd/format_influxdb.c
new file mode 100644 (file)
index 0000000..f7ff295
--- /dev/null
@@ -0,0 +1,190 @@
+/**
+ * collectd - src/utils_format_influxdb.c
+ * Copyright (C) 2007-2009  Florian octo Forster
+ * Copyright (C) 2009       Aman Gupta
+ * Copyright (C) 2019       Carlos Peon Costa
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at collectd.org>
+ *   Aman Gupta <aman at tmm1.net>
+ *   Carlos Peon Costa <carlospeon at gmail.com>
+ *   multiple Server directives by:
+ *   Paul (systemcrash) <newtwen thatfunny_at_symbol gmail.com>
+ **/
+
+#include "format_influxdb.h"
+
+#include "collectd.h"
+#include "plugin.h"
+#include "utils/common/common.h"
+#include "utils/metadata/meta_data.h"
+#include "utils_cache.h"
+
+static int format_influxdb_escape_string(char *buffer, size_t buffer_size,
+                                         const char *string) {
+  if ((buffer == NULL) || (string == NULL)) return -EINVAL;
+
+  if (buffer_size < 3) return -ENOMEM;
+
+  int dst_pos = 0;
+
+#define BUFFER_ADD(c)                   \
+  do {                                  \
+    if (dst_pos >= (buffer_size - 1)) { \
+      buffer[buffer_size - 1] = '\0';   \
+      return -ENOMEM;                   \
+    }                                   \
+    buffer[dst_pos] = (c);              \
+    dst_pos++;                          \
+  } while (0)
+
+  /* Escape special characters */
+  for (int src_pos = 0; string[src_pos] != 0; src_pos++) {
+    if ((string[src_pos] == '\\') || (string[src_pos] == ' ') ||
+        (string[src_pos] == ',') || (string[src_pos] == '=') ||
+        (string[src_pos] == '"')) {
+      BUFFER_ADD('\\');
+      BUFFER_ADD(string[src_pos]);
+    } else
+      BUFFER_ADD(string[src_pos]);
+  } /* for */
+  buffer[dst_pos] = 0;
+
+#undef BUFFER_ADD
+
+  return dst_pos;
+} /* int format_influxdb_escape_string */
+
+int format_influxdb_value_list(
+    char *buffer, int buffer_len, const data_set_t *ds, const value_list_t *vl,
+    bool store_rates, format_influxdb_time_precision_t time_precision) {
+  int status;
+  int offset = 0;
+  gauge_t *rates = NULL;
+  bool have_values = false;
+
+  assert(0 == strcmp(ds->type, vl->type));
+
+#define BUFFER_ADD_ESCAPE(...)                                                \
+  do {                                                                        \
+    status = format_influxdb_escape_string(buffer + offset,                   \
+                                           buffer_len - offset, __VA_ARGS__); \
+    if (status < 0) return status;                                            \
+    offset += status;                                                         \
+  } while (0)
+
+#define BUFFER_ADD(...)                                                   \
+  do {                                                                    \
+    status = snprintf(buffer + offset, buffer_len - offset, __VA_ARGS__); \
+    if ((status < 0) || (status >= (buffer_len - offset))) {              \
+      sfree(rates);                                                       \
+      return -ENOMEM;                                                     \
+    }                                                                     \
+    offset += status;                                                     \
+  } while (0)
+
+  assert(vl->type);
+  BUFFER_ADD_ESCAPE(vl->type);
+  BUFFER_ADD(",host=");
+  BUFFER_ADD_ESCAPE(vl->host);
+  if (vl->meta) {
+    char **toc;
+    int n = meta_data_toc(vl->meta, &toc);
+
+    for (int i = 0; i < n; i++) {
+      char *key = toc[i];
+      char *value;
+
+      if (meta_data_as_string(vl->meta, key, &value) == 0) {
+        BUFFER_ADD(",");
+        BUFFER_ADD_ESCAPE(key);
+        BUFFER_ADD("=");
+        BUFFER_ADD_ESCAPE(value);
+        free(value);
+      }
+      free(toc[i]);
+    }
+
+    if (n != 0) free(toc);
+  }
+
+  BUFFER_ADD(" ");
+  for (size_t i = 0; i < ds->ds_num; i++) {
+    if ((ds->ds[i].type != DS_TYPE_COUNTER) &&
+        (ds->ds[i].type != DS_TYPE_GAUGE) &&
+        (ds->ds[i].type != DS_TYPE_DERIVE) &&
+        (ds->ds[i].type != DS_TYPE_ABSOLUTE)) {
+      sfree(rates);
+      return -EINVAL;
+    }
+
+    if (ds->ds[i].type == DS_TYPE_GAUGE) {
+      if (isnan(vl->values[i].gauge)) continue;
+      if (have_values) BUFFER_ADD(",");
+      BUFFER_ADD("%s=%lf", ds->ds[i].name, vl->values[i].gauge);
+      have_values = true;
+    } else if (store_rates) {
+      if (rates == NULL) rates = uc_get_rate(ds, vl);
+      if (rates == NULL) {
+        WARNING(
+            "format_influxdb: "
+            "uc_get_rate failed.");
+        return -EINVAL;
+      }
+      if (isnan(rates[i])) continue;
+      if (have_values) BUFFER_ADD(",");
+      BUFFER_ADD("%s=%lf", ds->ds[i].name, rates[i]);
+      have_values = true;
+    } else if (ds->ds[i].type == DS_TYPE_COUNTER) {
+      if (have_values) BUFFER_ADD(",");
+      BUFFER_ADD("%s=%" PRIu64 "i", ds->ds[i].name,
+                 (uint64_t)vl->values[i].counter);
+      have_values = true;
+    } else if (ds->ds[i].type == DS_TYPE_DERIVE) {
+      if (have_values) BUFFER_ADD(",");
+      BUFFER_ADD("%s=%" PRIi64 "i", ds->ds[i].name, vl->values[i].derive);
+      have_values = true;
+    } else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) {
+      if (have_values) BUFFER_ADD(",");
+      BUFFER_ADD("%s=%" PRIu64 "i", ds->ds[i].name, vl->values[i].absolute);
+      have_values = true;
+    }
+
+  } /* for ds->ds_num */
+  sfree(rates);
+
+  if (!have_values) return 0;
+
+  uint64_t influxdb_time = 0;
+  switch (time_precision) {
+    case NS:
+      influxdb_time = CDTIME_T_TO_NS(vl->time);
+      break;
+    case US:
+      influxdb_time = CDTIME_T_TO_US(vl->time);
+      break;
+    case MS:
+      influxdb_time = CDTIME_T_TO_MS(vl->time);
+      break;
+  }
+
+  BUFFER_ADD(" %" PRIu64 "\n", influxdb_time);
+
+#undef BUFFER_ADD_ESCAPE
+#undef BUFFER_ADD
+
+  return offset;
+} /* int format_influxdb_value_list */
diff --git a/telemetry/kafka-collectd/format_influxdb.h b/telemetry/kafka-collectd/format_influxdb.h
new file mode 100644 (file)
index 0000000..fd298f1
--- /dev/null
@@ -0,0 +1,45 @@
+/**
+ * collectd - src/utils_format_influxdb.h
+ * Copyright (C) 2007-2009  Florian octo Forster
+ * Copyright (C) 2009       Aman Gupta
+ * Copyright (C) 2019       Carlos Peon Costa
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at collectd.org>
+ *   Aman Gupta <aman at tmm1.net>
+ *   Carlos Peon Costa <carlospeon at gmail.com>
+ *   multiple Server directives by:
+ *   Paul (systemcrash) <newtwen thatfunny_at_symbol gmail.com>
+ **/
+
+#ifndef UTILS_FORMAT_INFLUXDB_H
+#define UTILS_FORMAT_INFLUXDB_H 1
+
+#include "collectd.h"
+#include "plugin.h"
+
+typedef enum {
+  NS,
+  US,
+  MS,
+} format_influxdb_time_precision_t;
+
+int format_influxdb_value_list(char *buffer, int buffer_len,
+                               const data_set_t *ds, const value_list_t *vl,
+                               bool store_rates,
+                               format_influxdb_time_precision_t time_precision);
+
+#endif /* UTILS_FORMAT_INFLUXDB_H */
diff --git a/telemetry/kafka-collectd/write_kafka_line_protocol.c b/telemetry/kafka-collectd/write_kafka_line_protocol.c
new file mode 100644 (file)
index 0000000..5eb7b52
--- /dev/null
@@ -0,0 +1,526 @@
+/**
+ * collectd - src/write_kafka.c
+ * Copyright (C) 2014       Pierre-Yves Ritschard
+ *
+ * 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.
+ *
+ * Authors:
+ *   Pierre-Yves Ritschard <pyr at spootnik.org>
+ */
+
+#include <errno.h>
+#include <librdkafka/rdkafka.h>
+#include <stdint.h>
+
+#include "../data_model.h"
+#include "collectd.h"
+#include "format_influxdb.h"
+#include "plugin.h"
+#include "utils/cmds/putval.h"
+#include "utils/common/common.h"
+#include "utils/format_graphite/format_graphite.h"
+#include "utils/format_json/format_json.h"
+#include "utils_random.h"
+
+struct kafka_topic_context {
+#define KAFKA_FORMAT_JSON 0
+#define KAFKA_FORMAT_COMMAND 1
+#define KAFKA_FORMAT_GRAPHITE 2
+#define KAFKA_FORMAT_INFLUXDB 3
+  uint8_t format;
+  unsigned int graphite_flags;
+  bool store_rates;
+  rd_kafka_topic_conf_t *conf;
+  rd_kafka_topic_t *topic;
+  rd_kafka_conf_t *kafka_conf;
+  rd_kafka_t *kafka;
+  char *key;
+  char *prefix;
+  char *postfix;
+  char escape_char;
+  char *topic_name;
+  pthread_mutex_t lock;
+};
+
+static int kafka_handle(struct kafka_topic_context *);
+static int kafka_write(const data_set_t *, const value_list_t *, user_data_t *);
+static int32_t kafka_partition(const rd_kafka_topic_t *, const void *, size_t,
+                               int32_t, void *, void *);
+
+/* Version 0.9.0 of librdkafka deprecates rd_kafka_set_logger() in favor of
+ * rd_kafka_conf_set_log_cb(). This is to make sure we're not using the
+ * deprecated function. */
+#ifdef HAVE_LIBRDKAFKA_LOG_CB
+#undef HAVE_LIBRDKAFKA_LOGGER
+#endif
+
+#if defined(HAVE_LIBRDKAFKA_LOGGER) || defined(HAVE_LIBRDKAFKA_LOG_CB)
+static void kafka_log(const rd_kafka_t *, int, const char *, const char *);
+
+static void kafka_log(const rd_kafka_t *rkt, int level, const char *fac,
+                      const char *msg) {
+  plugin_log(level, "%s", msg);
+}
+#endif
+
+static rd_kafka_resp_err_t kafka_error() {
+#if RD_KAFKA_VERSION >= 0x000b00ff
+  return rd_kafka_last_error();
+#else
+  return rd_kafka_errno2err(errno);
+#endif
+}
+
+static uint32_t kafka_hash(const char *keydata, size_t keylen) {
+  uint32_t hash = 5381;
+  for (; keylen > 0; keylen--)
+    hash = ((hash << 5) + hash) + keydata[keylen - 1];
+  return hash;
+}
+
+/* 31 bit -> 4 byte -> 8 byte hex string + null byte */
+#define KAFKA_RANDOM_KEY_SIZE 9
+#define KAFKA_RANDOM_KEY_BUFFER \
+  (char[KAFKA_RANDOM_KEY_SIZE]) { "" }
+static char *kafka_random_key(char buffer[static KAFKA_RANDOM_KEY_SIZE]) {
+  ssnprintf(buffer, KAFKA_RANDOM_KEY_SIZE, "%08" PRIX32, cdrand_u());
+  return buffer;
+}
+
+static int32_t kafka_partition(const rd_kafka_topic_t *rkt, const void *keydata,
+                               size_t keylen, int32_t partition_cnt, void *p,
+                               void *m) {
+  uint32_t key = kafka_hash(keydata, keylen);
+  uint32_t target = key % partition_cnt;
+  int32_t i = partition_cnt;
+
+  while (--i > 0 && !rd_kafka_topic_partition_available(rkt, target)) {
+    target = (target + 1) % partition_cnt;
+  }
+  return target;
+}
+
+static int kafka_handle(struct kafka_topic_context *ctx) /* {{{ */
+{
+  char errbuf[1024];
+  rd_kafka_conf_t *conf;
+  rd_kafka_topic_conf_t *topic_conf;
+
+  if (ctx->kafka != NULL && ctx->topic != NULL) return 0;
+
+  if (ctx->kafka == NULL) {
+    if ((conf = rd_kafka_conf_dup(ctx->kafka_conf)) == NULL) {
+      ERROR("write_kafka plugin: cannot duplicate kafka config");
+      return 1;
+    }
+
+    if ((ctx->kafka = rd_kafka_new(RD_KAFKA_PRODUCER, conf, errbuf,
+                                   sizeof(errbuf))) == NULL) {
+      ERROR("write_kafka plugin: cannot create kafka handle.");
+      return 1;
+    }
+
+    rd_kafka_conf_destroy(ctx->kafka_conf);
+    ctx->kafka_conf = NULL;
+
+    INFO("write_kafka plugin: created KAFKA handle : %s",
+         rd_kafka_name(ctx->kafka));
+
+#if defined(HAVE_LIBRDKAFKA_LOGGER) && !defined(HAVE_LIBRDKAFKA_LOG_CB)
+    rd_kafka_set_logger(ctx->kafka, kafka_log);
+#endif
+  }
+
+  if (ctx->topic == NULL) {
+    if ((topic_conf = rd_kafka_topic_conf_dup(ctx->conf)) == NULL) {
+      ERROR("write_kafka plugin: cannot duplicate kafka topic config");
+      return 1;
+    }
+
+    if ((ctx->topic = rd_kafka_topic_new(ctx->kafka, ctx->topic_name,
+                                         topic_conf)) == NULL) {
+      ERROR("write_kafka plugin: cannot create topic : %s\n",
+            rd_kafka_err2str(kafka_error()));
+      return errno;
+    }
+
+    rd_kafka_topic_conf_destroy(ctx->conf);
+    ctx->conf = NULL;
+
+    INFO("write_kafka plugin: handle created for topic : %s",
+         rd_kafka_topic_name(ctx->topic));
+  }
+
+  return 0;
+
+} /* }}} int kafka_handle */
+
+static int kafka_write(const data_set_t *ds, /* {{{ */
+                       const value_list_t *vl, user_data_t *ud) {
+  int status = 0;
+  void *key;
+  size_t keylen = 0;
+  char buffer[8192];
+  size_t bfree = sizeof(buffer);
+  size_t bfill = 0;
+  size_t blen = 0;
+  struct kafka_topic_context *ctx = ud->data;
+
+  if ((ds == NULL) || (vl == NULL) || (ctx == NULL)) return EINVAL;
+
+  pthread_mutex_lock(&ctx->lock);
+  status = kafka_handle(ctx);
+  pthread_mutex_unlock(&ctx->lock);
+  if (status != 0) return status;
+
+  bzero(buffer, sizeof(buffer));
+
+  switch (ctx->format) {
+    case KAFKA_FORMAT_COMMAND:
+      status = cmd_create_putval(buffer, sizeof(buffer), ds, vl);
+      if (status != 0) {
+        ERROR("write_kafka plugin: cmd_create_putval failed with status %i.",
+              status);
+        return status;
+      }
+      blen = strlen(buffer);
+      break;
+    case KAFKA_FORMAT_JSON:
+      format_json_initialize(buffer, &bfill, &bfree);
+      format_json_value_list(buffer, &bfill, &bfree, ds, vl, ctx->store_rates);
+      format_json_finalize(buffer, &bfill, &bfree);
+      blen = strlen(buffer);
+      break;
+    case KAFKA_FORMAT_GRAPHITE:
+      status =
+          format_graphite(buffer, sizeof(buffer), ds, vl, ctx->prefix,
+                          ctx->postfix, ctx->escape_char, ctx->graphite_flags);
+      if (status != 0) {
+        ERROR("write_kafka plugin: format_graphite failed with status %i.",
+              status);
+        return status;
+      }
+      blen = strlen(buffer);
+      break;
+    case KAFKA_FORMAT_INFLUXDB: {
+      // Decide format depending on the topic
+      // (to handle multilple topics w/ different formats);
+      // Comment this part to use the stream topic as default for other
+      // collectd plugins (e.g. cpu, mem)
+      char *topic = NULL;
+      int rc = meta_data_get_string(vl->meta, KAFKA_TOPIC_KEY, &topic);
+      if (rc != 0 || topic == NULL) return 0;
+      if (strcasecmp(KAFKA_STREAM_TOPIC, topic) != 0) {
+        free(topic);
+        return 0;
+      }
+      meta_data_delete(vl->meta, KAFKA_TOPIC_KEY);
+
+      status =
+          format_influxdb_value_list(buffer, sizeof(buffer), ds, vl, false, NS);
+      if (status <= 0) {
+        ERROR("write_kafka plugin: format_influxdb failed with status %i.",
+              status);
+        return status;
+      }
+      blen = strlen(buffer);
+
+      // Print without newline
+      buffer[blen - 1] = 0;
+      INFO("%s", buffer);
+      buffer[blen - 1] = '\n';
+
+      break;
+    }
+    default:
+      ERROR("write_kafka plugin: invalid format %i.", ctx->format);
+      return -1;
+  }
+
+  key =
+      (ctx->key != NULL) ? ctx->key : kafka_random_key(KAFKA_RANDOM_KEY_BUFFER);
+  keylen = strlen(key);
+
+  rd_kafka_produce(ctx->topic, RD_KAFKA_PARTITION_UA, RD_KAFKA_MSG_F_COPY,
+                   buffer, blen, key, keylen, NULL);
+
+  return status;
+} /* }}} int kafka_write */
+
+static void kafka_topic_context_free(void *p) /* {{{ */
+{
+  struct kafka_topic_context *ctx = p;
+
+  if (ctx == NULL) return;
+
+  if (ctx->topic_name != NULL) sfree(ctx->topic_name);
+  if (ctx->topic != NULL) rd_kafka_topic_destroy(ctx->topic);
+  if (ctx->conf != NULL) rd_kafka_topic_conf_destroy(ctx->conf);
+  if (ctx->kafka_conf != NULL) rd_kafka_conf_destroy(ctx->kafka_conf);
+  if (ctx->kafka != NULL) rd_kafka_destroy(ctx->kafka);
+
+  sfree(ctx);
+} /* }}} void kafka_topic_context_free */
+
+static void kafka_config_topic(rd_kafka_conf_t *conf,
+                               oconfig_item_t *ci) /* {{{ */
+{
+  int status;
+  struct kafka_topic_context *tctx;
+  char *key = NULL;
+  char *val;
+  char callback_name[DATA_MAX_NAME_LEN];
+  char errbuf[1024];
+  oconfig_item_t *child;
+  rd_kafka_conf_res_t ret;
+
+  if ((tctx = calloc(1, sizeof(*tctx))) == NULL) {
+    ERROR("write_kafka plugin: calloc failed.");
+    return;
+  }
+
+  tctx->escape_char = '.';
+  tctx->store_rates = true;
+  tctx->format = KAFKA_FORMAT_JSON;
+  tctx->key = NULL;
+
+  if ((tctx->kafka_conf = rd_kafka_conf_dup(conf)) == NULL) {
+    sfree(tctx);
+    ERROR("write_kafka plugin: cannot allocate memory for kafka config");
+    return;
+  }
+
+#ifdef HAVE_LIBRDKAFKA_LOG_CB
+  rd_kafka_conf_set_log_cb(tctx->kafka_conf, kafka_log);
+#endif
+
+  if ((tctx->conf = rd_kafka_topic_conf_new()) == NULL) {
+    rd_kafka_conf_destroy(tctx->kafka_conf);
+    sfree(tctx);
+    ERROR("write_kafka plugin: cannot create topic configuration.");
+    return;
+  }
+
+  if (ci->values_num != 1) {
+    WARNING("kafka topic name needed.");
+    goto errout;
+  }
+
+  if (ci->values[0].type != OCONFIG_TYPE_STRING) {
+    WARNING("kafka topic needs a string argument.");
+    goto errout;
+  }
+
+  if ((tctx->topic_name = strdup(ci->values[0].value.string)) == NULL) {
+    ERROR("write_kafka plugin: cannot copy topic name.");
+    goto errout;
+  }
+
+  for (int i = 0; i < ci->children_num; i++) {
+    /*
+     * The code here could be simplified but makes room
+     * for easy adding of new options later on.
+     */
+    child = &ci->children[i];
+    status = 0;
+
+    if (strcasecmp("Property", child->key) == 0) {
+      if (child->values_num != 2) {
+        WARNING("kafka properties need both a key and a value.");
+        goto errout;
+      }
+      if (child->values[0].type != OCONFIG_TYPE_STRING ||
+          child->values[1].type != OCONFIG_TYPE_STRING) {
+        WARNING("kafka properties needs string arguments.");
+        goto errout;
+      }
+      key = child->values[0].value.string;
+      val = child->values[1].value.string;
+      ret =
+          rd_kafka_topic_conf_set(tctx->conf, key, val, errbuf, sizeof(errbuf));
+      if (ret != RD_KAFKA_CONF_OK) {
+        WARNING("cannot set kafka topic property %s to %s: %s.", key, val,
+                errbuf);
+        goto errout;
+      }
+
+    } else if (strcasecmp("Key", child->key) == 0) {
+      if (cf_util_get_string(child, &tctx->key) != 0) continue;
+      if (strcasecmp("Random", tctx->key) == 0) {
+        sfree(tctx->key);
+        tctx->key = strdup(kafka_random_key(KAFKA_RANDOM_KEY_BUFFER));
+      }
+    } else if (strcasecmp("Format", child->key) == 0) {
+      status = cf_util_get_string(child, &key);
+      if (status != 0) goto errout;
+
+      assert(key != NULL);
+
+      if (strcasecmp(key, "Command") == 0) {
+        tctx->format = KAFKA_FORMAT_COMMAND;
+
+      } else if (strcasecmp(key, "Graphite") == 0) {
+        tctx->format = KAFKA_FORMAT_GRAPHITE;
+
+      } else if (strcasecmp(key, "Json") == 0) {
+        tctx->format = KAFKA_FORMAT_JSON;
+
+      } else if (strcasecmp(key, "InfluxDB") == 0) {
+        tctx->format = KAFKA_FORMAT_INFLUXDB;
+
+      } else {
+        WARNING("write_kafka plugin: Invalid format string: %s", key);
+      }
+
+      sfree(key);
+
+    } else if (strcasecmp("StoreRates", child->key) == 0) {
+      status = cf_util_get_boolean(child, &tctx->store_rates);
+      (void)cf_util_get_flag(child, &tctx->graphite_flags,
+                             GRAPHITE_STORE_RATES);
+
+    } else if (strcasecmp("GraphiteSeparateInstances", child->key) == 0) {
+      status = cf_util_get_flag(child, &tctx->graphite_flags,
+                                GRAPHITE_SEPARATE_INSTANCES);
+
+    } else if (strcasecmp("GraphiteAlwaysAppendDS", child->key) == 0) {
+      status = cf_util_get_flag(child, &tctx->graphite_flags,
+                                GRAPHITE_ALWAYS_APPEND_DS);
+
+    } else if (strcasecmp("GraphitePreserveSeparator", child->key) == 0) {
+      status = cf_util_get_flag(child, &tctx->graphite_flags,
+                                GRAPHITE_PRESERVE_SEPARATOR);
+
+    } else if (strcasecmp("GraphiteUseTags", child->key) == 0) {
+      status =
+          cf_util_get_flag(child, &tctx->graphite_flags, GRAPHITE_USE_TAGS);
+
+    } else if (strcasecmp("GraphitePrefix", child->key) == 0) {
+      status = cf_util_get_string(child, &tctx->prefix);
+    } else if (strcasecmp("GraphitePostfix", child->key) == 0) {
+      status = cf_util_get_string(child, &tctx->postfix);
+    } else if (strcasecmp("GraphiteEscapeChar", child->key) == 0) {
+      char *tmp_buff = NULL;
+      status = cf_util_get_string(child, &tmp_buff);
+      if (strlen(tmp_buff) > 1)
+        WARNING(
+            "write_kafka plugin: The option \"GraphiteEscapeChar\" handles "
+            "only one character. Others will be ignored.");
+      tctx->escape_char = tmp_buff[0];
+      sfree(tmp_buff);
+    } else {
+      WARNING("write_kafka plugin: Invalid directive: %s.", child->key);
+    }
+
+    if (status != 0) break;
+  }
+
+  rd_kafka_topic_conf_set_partitioner_cb(tctx->conf, kafka_partition);
+  rd_kafka_topic_conf_set_opaque(tctx->conf, tctx);
+
+  ssnprintf(callback_name, sizeof(callback_name), "write_kafka/%s",
+            tctx->topic_name);
+
+  status = plugin_register_write(callback_name, kafka_write,
+                                 &(user_data_t){
+                                     .data = tctx,
+                                     .free_func = kafka_topic_context_free,
+                                 });
+  if (status != 0) {
+    WARNING(
+        "write_kafka plugin: plugin_register_write (\"%s\") "
+        "failed with status %i.",
+        callback_name, status);
+    goto errout;
+  }
+
+  pthread_mutex_init(&tctx->lock, /* attr = */ NULL);
+
+  return;
+errout:
+  if (tctx->topic_name != NULL) free(tctx->topic_name);
+  if (tctx->conf != NULL) rd_kafka_topic_conf_destroy(tctx->conf);
+  if (tctx->kafka_conf != NULL) rd_kafka_conf_destroy(tctx->kafka_conf);
+  sfree(tctx);
+} /* }}} int kafka_config_topic */
+
+static int kafka_config(oconfig_item_t *ci) /* {{{ */
+{
+  oconfig_item_t *child;
+  rd_kafka_conf_t *conf;
+  rd_kafka_conf_res_t ret;
+  char errbuf[1024];
+
+  if ((conf = rd_kafka_conf_new()) == NULL) {
+    WARNING("cannot allocate kafka configuration.");
+    return -1;
+  }
+  for (int i = 0; i < ci->children_num; i++) {
+    child = &ci->children[i];
+
+    if (strcasecmp("Topic", child->key) == 0) {
+      kafka_config_topic(conf, child);
+    } else if (strcasecmp(child->key, "Property") == 0) {
+      char *key = NULL;
+      char *val = NULL;
+
+      if (child->values_num != 2) {
+        WARNING("kafka properties need both a key and a value.");
+        goto errout;
+      }
+      if (child->values[0].type != OCONFIG_TYPE_STRING ||
+          child->values[1].type != OCONFIG_TYPE_STRING) {
+        WARNING("kafka properties needs string arguments.");
+        goto errout;
+      }
+      if ((key = strdup(child->values[0].value.string)) == NULL) {
+        WARNING("cannot allocate memory for attribute key.");
+        goto errout;
+      }
+      if ((val = strdup(child->values[1].value.string)) == NULL) {
+        WARNING("cannot allocate memory for attribute value.");
+        sfree(key);
+        goto errout;
+      }
+      ret = rd_kafka_conf_set(conf, key, val, errbuf, sizeof(errbuf));
+      if (ret != RD_KAFKA_CONF_OK) {
+        WARNING("cannot set kafka property %s to %s: %s", key, val, errbuf);
+        sfree(key);
+        sfree(val);
+        goto errout;
+      }
+      sfree(key);
+      sfree(val);
+    } else {
+      WARNING(
+          "write_kafka plugin: Ignoring unknown "
+          "configuration option \"%s\" at top level.",
+          child->key);
+    }
+  }
+  if (conf != NULL) rd_kafka_conf_destroy(conf);
+  return 0;
+errout:
+  if (conf != NULL) rd_kafka_conf_destroy(conf);
+  return -1;
+} /* }}} int kafka_config */
+
+void module_register(void) {
+  plugin_register_complex_config("write_kafka_line_protocol", kafka_config);
+}
diff --git a/telemetry/third-party/CMakeLists.txt b/telemetry/third-party/CMakeLists.txt
new file mode 100644 (file)
index 0000000..26d305d
--- /dev/null
@@ -0,0 +1,18 @@
+# Copyright (c) 2022 Cisco and/or its affiliates.
+
+set(THIRD_PARTY_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR})
+
+include(FetchContent)
+set(FETCHCONTENT_QUIET off)
+FetchContent_Declare(collectd
+  URL https://github.com/collectd/collectd/archive/refs/tags/collectd-${COLLECTD_VERSION}.zip
+  CONFIGURE_COMMAND ""
+  BUILD_COMMAND ""
+  INSTALL_COMMAND ""
+)
+FetchContent_Populate(collectd)
+
+list(APPEND THIRD_PARTY_INCLUDE_DIRS
+  ${collectd_SOURCE_DIR}/src
+)
+set(THIRD_PARTY_INCLUDE_DIRS ${THIRD_PARTY_INCLUDE_DIRS} PARENT_SCOPE)
index 54a1a4b..4ce357f 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-project(hicn-collectd-plugins)
-
-
-##############################################################
-# CMake Modules
-##############################################################
-set(CMAKE_MODULE_PATH
-       ${CMAKE_MODULE_PATH}
-       ${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/Modules/)
-
-
 ##############################################################
 # Dependencies
 ##############################################################
 find_package(Vpp ${VPP_DEFAULT_VERSION} REQUIRED)
-find_package(Collectd ${COLLECTD_DEFAULT_VERSION} REQUIRED)
-
-
-##############################################################
-# Libs and bins names
-##############################################################
-set(COLLECTD_PLUGINS hicn-collectd-plugins)
-
-
-##############################################################
-# Packaging
-##############################################################
-include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/packaging.cmake)
 
 
 ##############################################################
diff --git a/telemetry/vpp-collectd/common/README.md b/telemetry/vpp-collectd/common/README.md
deleted file mode 100644 (file)
index e3b9c74..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# Headers for collectd plugins
-
-These headers are required for plugin development but are not shipped with the
-`collectd` Ubuntu 20.04 package (as of May 2021):
-
-* [common.h](https://github.com/collectd/collectd/blob/main/src/utils/common/common.h)
-* [plugin.h](https://github.com/collectd/collectd/blob/main/src/daemon/plugin.h)
-* [meta_data.h](https://github.com/collectd/collectd/blob/main/src/utils/metadata/meta_data.h)
-
-Related issues:
-* [GitHub](https://github.com/collectd/collectd/issues/3881)
-* [Ubuntu](https://bugs.launchpad.net/ubuntu/+source/collectd/+bug/1929079)
diff --git a/telemetry/vpp-collectd/common/common.h b/telemetry/vpp-collectd/common/common.h
deleted file mode 100644 (file)
index fce2d12..0000000
+++ /dev/null
@@ -1,405 +0,0 @@
-/**
- * collectd - src/common.h
- * Copyright (C) 2005-2014  Florian octo Forster
- *
- * 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.
- *
- * Authors:
- *   Florian octo Forster <octo at collectd.org>
- *   Niki W. Waibel <niki.waibel@gmx.net>
- **/
-
-#ifndef COMMON_H
-#define COMMON_H
-
-#include "collectd.h"
-
-#include "plugin.h"
-
-#if HAVE_PWD_H
-#include <pwd.h>
-#endif
-
-#define sfree(ptr)                                                             \
-  do {                                                                         \
-    free(ptr);                                                                 \
-    (ptr) = NULL;                                                              \
-  } while (0)
-
-#define STATIC_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
-
-#define IS_TRUE(s)                                                             \
-  ((strcasecmp("true", (s)) == 0) || (strcasecmp("yes", (s)) == 0) ||          \
-   (strcasecmp("on", (s)) == 0))
-#define IS_FALSE(s)                                                            \
-  ((strcasecmp("false", (s)) == 0) || (strcasecmp("no", (s)) == 0) ||          \
-   (strcasecmp("off", (s)) == 0))
-
-struct rate_to_value_state_s {
-  value_t last_value;
-  cdtime_t last_time;
-  gauge_t residual;
-};
-typedef struct rate_to_value_state_s rate_to_value_state_t;
-
-struct value_to_rate_state_s {
-  value_t last_value;
-  cdtime_t last_time;
-};
-typedef struct value_to_rate_state_s value_to_rate_state_t;
-
-char *sstrncpy(char *dest, const char *src, size_t n);
-
-__attribute__((format(printf, 3, 4))) int ssnprintf(char *str, size_t size,
-                                                    char const *format, ...);
-
-__attribute__((format(printf, 1, 2))) char *ssnprintf_alloc(char const *format,
-                                                            ...);
-
-char *sstrdup(const char *s);
-size_t sstrnlen(const char *s, size_t n);
-char *sstrndup(const char *s, size_t n);
-void *smalloc(size_t size);
-char *sstrerror(int errnum, char *buf, size_t buflen);
-
-#ifndef ERRBUF_SIZE
-#define ERRBUF_SIZE 256
-#endif
-
-#define STRERROR(e) sstrerror((e), (char[ERRBUF_SIZE]){0}, ERRBUF_SIZE)
-#define STRERRNO STRERROR(errno)
-
-/*
- * NAME
- *   sread
- *
- * DESCRIPTION
- *   Reads exactly `n' bytes or fails. Syntax and other behavior is analogous
- *   to `read(2)'.
- *
- * PARAMETERS
- *   `fd'          File descriptor to write to.
- *   `buf'         Buffer that is to be written.
- *   `count'       Number of bytes in the buffer.
- *
- * RETURN VALUE
- *   Zero upon success or non-zero if an error occurred. `errno' is set in this
- *   case.
- */
-int sread(int fd, void *buf, size_t count);
-
-/*
- * NAME
- *   swrite
- *
- * DESCRIPTION
- *   Writes exactly `n' bytes or fails. Syntax and other behavior is analogous
- *   to `write(2)'.
- *
- * PARAMETERS
- *   `fd'          File descriptor to write to.
- *   `buf'         Buffer that is to be written.
- *   `count'       Number of bytes in the buffer.
- *
- * RETURN VALUE
- *   Zero upon success or non-zero if an error occurred. `errno' is set in this
- *   case.
- */
-int swrite(int fd, const void *buf, size_t count);
-
-/*
- * NAME
- *   strsplit
- *
- * DESCRIPTION
- *   Splits a string into parts and stores pointers to the parts in `fields'.
- *   The characters split at are: " ", "\t", "\r", and "\n".
- *
- * PARAMETERS
- *   `string'      String to split. This string will be modified. `fields' will
- *                 contain pointers to parts of this string, so free'ing it
- *                 will destroy `fields' as well.
- *   `fields'      Array of strings where pointers to the parts will be stored.
- *   `size'        Number of elements in the array. No more than `size'
- *                 pointers will be stored in `fields'.
- *
- * RETURN VALUE
- *    Returns the number of parts stored in `fields'.
- */
-int strsplit(char *string, char **fields, size_t size);
-
-/*
- * NAME
- *   strjoin
- *
- * DESCRIPTION
- *   Joins together several parts of a string using `sep' as a separator. This
- *   is equivalent to the Perl built-in `join'.
- *
- * PARAMETERS
- *   `dst'         Buffer where the result is stored. Can be NULL if you need to
- *                 determine the required buffer size only.
- *   `dst_len'     Length of the destination buffer. No more than this many
- *                 bytes will be written to the memory pointed to by `dst',
- *                 including the trailing null-byte. Must be zero if dst is
- *                 NULL.
- *   `fields'      Array of strings to be joined.
- *   `fields_num'  Number of elements in the `fields' array.
- *   `sep'         String to be inserted between any two elements of `fields'.
- *                 This string is neither prepended nor appended to the result.
- *                 Instead of passing "" (empty string) one can pass NULL.
- *
- * RETURN VALUE
- *   Returns the number of characters in the resulting string, excluding a
- *   tailing null byte. If this value is greater than or equal to "dst_len", the
- *   result in "dst" is truncated (but still null terminated). On error a
- *   negative value is returned.
- */
-int strjoin(char *dst, size_t dst_len, char **fields, size_t fields_num,
-            const char *sep);
-
-/*
- * NAME
- *   escape_slashes
- *
- * DESCRIPTION
- *   Removes slashes ("/") from "buffer". If buffer contains a single slash,
- *   the result will be "root". Leading slashes are removed. All other slashes
- *   are replaced with underscores ("_").
- *   This function is used by plugin_dispatch_values() to escape all parts of
- *   the identifier.
- *
- * PARAMETERS
- *   `buffer'         String to be escaped.
- *   `buffer_size'    Size of the buffer. No more then this many bytes will be
- *                    written to `buffer', including the trailing null-byte.
- *
- * RETURN VALUE
- *   Returns zero upon success and a value smaller than zero upon failure.
- */
-int escape_slashes(char *buffer, size_t buffer_size);
-
-/**
- * NAME
- *   escape_string
- *
- * DESCRIPTION
- *   escape_string quotes and escapes a string to be usable with collectd's
- *   plain text protocol. "simple" strings are left as they are, for example if
- *   buffer is 'simple' before the call, it will remain 'simple'. However, if
- *   buffer contains 'more "complex"' before the call, the returned buffer will
- *   contain '"more \"complex\""'.
- *
- *   If the buffer is too small to contain the escaped string, the string will
- *   be truncated. However, leading and trailing double quotes, as well as an
- *   ending null byte are guaranteed.
- *
- * RETURN VALUE
- *   Returns zero on success, even if the string was truncated. Non-zero on
- *   failure.
- */
-int escape_string(char *buffer, size_t buffer_size);
-
-/*
- * NAME
- *   replace_special
- *
- * DESCRIPTION
- *   Replaces any special characters (anything that's not alpha-numeric or a
- *   dash) with an underscore.
- *
- *   E.g. "foo$bar&" would become "foo_bar_".
- *
- * PARAMETERS
- *   `buffer'      String to be handled.
- *   `buffer_size' Length of the string. The function returns after
- *                 encountering a null-byte or reading this many bytes.
- */
-void replace_special(char *buffer, size_t buffer_size);
-
-/*
- * NAME
- *   strunescape
- *
- * DESCRIPTION
- *   Replaces any escaped characters in a string with the appropriate special
- *   characters. The following escaped characters are recognized:
- *
- *     \t -> <tab>
- *     \n -> <newline>
- *     \r -> <carriage return>
- *
- *   For all other escacped characters only the backslash will be removed.
- *
- * PARAMETERS
- *   `buf'         String to be unescaped.
- *   `buf_len'     Length of the string, including the terminating null-byte.
- *
- * RETURN VALUE
- *   Returns zero upon success, a value less than zero else.
- */
-int strunescape(char *buf, size_t buf_len);
-
-/**
- * Removed trailing newline characters (CR and LF) from buffer, which must be
- * null terminated. Returns the length of the resulting string.
- */
-__attribute__((nonnull(1))) size_t strstripnewline(char *buffer);
-
-/*
- * NAME
- *   timeval_cmp
- *
- * DESCRIPTION
- *   Compare the two time values `tv0' and `tv1' and store the absolut value
- *   of the difference in the time value pointed to by `delta' if it does not
- *   equal NULL.
- *
- * RETURN VALUE
- *   Returns an integer less than, equal to, or greater than zero if `tv0' is
- *   less than, equal to, or greater than `tv1' respectively.
- */
-int timeval_cmp(struct timeval tv0, struct timeval tv1, struct timeval *delta);
-
-/* make sure tv_usec stores less than a second */
-#define NORMALIZE_TIMEVAL(tv)                                                  \
-  do {                                                                         \
-    (tv).tv_sec += (tv).tv_usec / 1000000;                                     \
-    (tv).tv_usec = (tv).tv_usec % 1000000;                                     \
-  } while (0)
-
-/* make sure tv_sec stores less than a second */
-#define NORMALIZE_TIMESPEC(tv)                                                 \
-  do {                                                                         \
-    (tv).tv_sec += (tv).tv_nsec / 1000000000;                                  \
-    (tv).tv_nsec = (tv).tv_nsec % 1000000000;                                  \
-  } while (0)
-
-int check_create_dir(const char *file_orig);
-
-#ifdef HAVE_LIBKSTAT
-#if HAVE_KSTAT_H
-#include <kstat.h>
-#endif
-int get_kstat(kstat_t **ksp_ptr, char *module, int instance, char *name);
-long long get_kstat_value(kstat_t *ksp, char *name);
-#endif
-
-#ifndef HAVE_HTONLL
-unsigned long long ntohll(unsigned long long n);
-unsigned long long htonll(unsigned long long n);
-#endif
-
-#if FP_LAYOUT_NEED_NOTHING
-#define ntohd(d) (d)
-#define htond(d) (d)
-#elif FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP
-double ntohd(double d);
-double htond(double d);
-#else
-#error                                                                         \
-    "Don't know how to convert between host and network representation of doubles."
-#endif
-
-int format_name(char *ret, int ret_len, const char *hostname,
-                const char *plugin, const char *plugin_instance,
-                const char *type, const char *type_instance);
-#define FORMAT_VL(ret, ret_len, vl)                                            \
-  format_name(ret, ret_len, (vl)->host, (vl)->plugin, (vl)->plugin_instance,   \
-              (vl)->type, (vl)->type_instance)
-int format_values(char *ret, size_t ret_len, const data_set_t *ds,
-                  const value_list_t *vl, bool store_rates);
-
-int parse_identifier(char *str, char **ret_host, char **ret_plugin,
-                     char **ret_plugin_instance, char **ret_type,
-                     char **ret_type_instance, char *default_host);
-int parse_identifier_vl(const char *str, value_list_t *vl);
-int parse_value(const char *value, value_t *ret_value, int ds_type);
-int parse_values(char *buffer, value_list_t *vl, const data_set_t *ds);
-
-/* parse_value_file reads "path" and parses its content as an integer or
- * floating point, depending on "ds_type". On success, the value is stored in
- * "ret_value" and zero is returned. On failure, a non-zero value is returned.
- */
-int parse_value_file(char const *path, value_t *ret_value, int ds_type);
-
-#if !HAVE_GETPWNAM_R
-struct passwd;
-int getpwnam_r(const char *name, struct passwd *pwbuf, char *buf, size_t buflen,
-               struct passwd **pwbufp);
-#endif
-
-int notification_init(notification_t *n, int severity, const char *message,
-                      const char *host, const char *plugin,
-                      const char *plugin_instance, const char *type,
-                      const char *type_instance);
-#define NOTIFICATION_INIT_VL(n, vl)                                            \
-  notification_init(n, NOTIF_FAILURE, NULL, (vl)->host, (vl)->plugin,          \
-                    (vl)->plugin_instance, (vl)->type, (vl)->type_instance)
-
-typedef int (*dirwalk_callback_f)(const char *dirname, const char *filename,
-                                  void *user_data);
-int walk_directory(const char *dir, dirwalk_callback_f callback,
-                   void *user_data, int hidden);
-/* Returns the number of bytes read or negative on error. */
-ssize_t read_file_contents(char const *filename, void *buf, size_t bufsize);
-/* Writes the contents of the file into the buffer with a trailing NUL.
- * Returns the number of bytes written to the buffer or negative on error. */
-ssize_t read_text_file_contents(char const *filename, char *buf,
-                                size_t bufsize);
-
-counter_t counter_diff(counter_t old_value, counter_t new_value);
-
-/* Convert a rate back to a value_t. When converting to a derive_t, counter_t
- * or absolute_t, take fractional residuals into account. This is important
- * when scaling counters, for example.
- * Returns zero on success. Returns EAGAIN when called for the first time; in
- * this case the value_t is invalid and the next call should succeed. Other
- * return values indicate an error. */
-int rate_to_value(value_t *ret_value, gauge_t rate,
-                  rate_to_value_state_t *state, int ds_type, cdtime_t t);
-
-int value_to_rate(gauge_t *ret_rate, value_t value, int ds_type, cdtime_t t,
-                  value_to_rate_state_t *state);
-
-/* Converts a service name (a string) to a port number
- * (in the range [1-65535]). Returns less than zero on error. */
-int service_name_to_port_number(const char *service_name);
-
-/* Sets various, non-default, socket options */
-void set_sock_opts(int sockfd);
-
-/** Parse a string to a derive_t value. Returns zero on success or non-zero on
- * failure. If failure is returned, ret_value is not touched. */
-int strtoderive(const char *string, derive_t *ret_value);
-
-/** Parse a string to a gauge_t value. Returns zero on success or non-zero on
- * failure. If failure is returned, ret_value is not touched. */
-int strtogauge(const char *string, gauge_t *ret_value);
-
-int strarray_add(char ***ret_array, size_t *ret_array_len, char const *str);
-void strarray_free(char **array, size_t array_len);
-
-/** Check if the current process benefits from the capability passed in
- * argument. Returns zero if it does, less than zero if it doesn't or on error.
- * See capabilities(7) for the list of possible capabilities.
- * */
-int check_capability(int arg);
-
-#endif /* COMMON_H */
diff --git a/telemetry/vpp-collectd/common/meta_data.h b/telemetry/vpp-collectd/common/meta_data.h
deleted file mode 100644 (file)
index 203b146..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * collectd - src/meta_data.h
- * Copyright (C) 2008-2011  Florian octo Forster
- *
- * 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.
- *
- * Authors:
- *   Florian octo Forster <octo at collectd.org>
- **/
-
-#ifndef META_DATA_H
-#define META_DATA_H
-
-#include "collectd.h"
-
-/*
- * Defines
- */
-#define MD_TYPE_STRING 1
-#define MD_TYPE_SIGNED_INT 2
-#define MD_TYPE_UNSIGNED_INT 3
-#define MD_TYPE_DOUBLE 4
-#define MD_TYPE_BOOLEAN 5
-
-struct meta_data_s;
-typedef struct meta_data_s meta_data_t;
-
-meta_data_t *meta_data_create(void);
-meta_data_t *meta_data_clone(meta_data_t *orig);
-int meta_data_clone_merge(meta_data_t **dest, meta_data_t *orig);
-void meta_data_destroy(meta_data_t *md);
-
-int meta_data_exists(meta_data_t *md, const char *key);
-int meta_data_type(meta_data_t *md, const char *key);
-int meta_data_toc(meta_data_t *md, char ***toc);
-int meta_data_delete(meta_data_t *md, const char *key);
-
-int meta_data_add_string(meta_data_t *md, const char *key, const char *value);
-int meta_data_add_signed_int(meta_data_t *md, const char *key, int64_t value);
-int meta_data_add_unsigned_int(meta_data_t *md, const char *key,
-                               uint64_t value);
-int meta_data_add_double(meta_data_t *md, const char *key, double value);
-int meta_data_add_boolean(meta_data_t *md, const char *key, bool value);
-
-int meta_data_get_string(meta_data_t *md, const char *key, char **value);
-int meta_data_get_signed_int(meta_data_t *md, const char *key, int64_t *value);
-int meta_data_get_unsigned_int(meta_data_t *md, const char *key,
-                               uint64_t *value);
-int meta_data_get_double(meta_data_t *md, const char *key, double *value);
-int meta_data_get_boolean(meta_data_t *md, const char *key, bool *value);
-
-/* Returns the value as a string, regardless of the type. */
-int meta_data_as_string(meta_data_t *md, const char *key, char **value);
-
-#endif /* META_DATA_H */
diff --git a/telemetry/vpp-collectd/common/plugin.h b/telemetry/vpp-collectd/common/plugin.h
deleted file mode 100644 (file)
index bbd69e0..0000000
+++ /dev/null
@@ -1,483 +0,0 @@
-/**
- * collectd - src/daemon/plugin.h
- * Copyright (C) 2005-2014  Florian octo Forster
- *
- * 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.
- *
- * Authors:
- *   Florian octo Forster <octo at collectd.org>
- *   Sebastian Harl <sh at tokkee.org>
- **/
-
-#ifndef PLUGIN_H
-#define PLUGIN_H
-
-#include "collectd.h"
-
-#include "configfile.h"
-#include "meta_data.h"
-#include "utils_time.h"
-
-#include <inttypes.h>
-#include <pthread.h>
-
-#define DS_TYPE_COUNTER 0
-#define DS_TYPE_GAUGE 1
-#define DS_TYPE_DERIVE 2
-#define DS_TYPE_ABSOLUTE 3
-
-#define DS_TYPE_TO_STRING(t)                                                   \
-  (t == DS_TYPE_COUNTER)    ? "counter"                                        \
-  : (t == DS_TYPE_GAUGE)    ? "gauge"                                          \
-  : (t == DS_TYPE_DERIVE)   ? "derive"                                         \
-  : (t == DS_TYPE_ABSOLUTE) ? "absolute"                                       \
-                            : "unknown"
-
-#ifndef LOG_ERR
-#define LOG_ERR 3
-#endif
-#ifndef LOG_WARNING
-#define LOG_WARNING 4
-#endif
-#ifndef LOG_NOTICE
-#define LOG_NOTICE 5
-#endif
-#ifndef LOG_INFO
-#define LOG_INFO 6
-#endif
-#ifndef LOG_DEBUG
-#define LOG_DEBUG 7
-#endif
-
-#define NOTIF_MAX_MSG_LEN 256
-
-#define NOTIF_FAILURE 1
-#define NOTIF_WARNING 2
-#define NOTIF_OKAY 4
-
-#define plugin_interval (plugin_get_ctx().interval)
-
-/*
- * Public data types
- */
-struct identifier_s {
-  char *host;
-  char *plugin;
-  char *plugin_instance;
-  char *type;
-  char *type_instance;
-};
-typedef struct identifier_s identifier_t;
-
-typedef unsigned long long counter_t;
-typedef double gauge_t;
-typedef int64_t derive_t;
-typedef uint64_t absolute_t;
-
-union value_u {
-  counter_t counter;
-  gauge_t gauge;
-  derive_t derive;
-  absolute_t absolute;
-};
-typedef union value_u value_t;
-
-struct value_list_s {
-  value_t *values;
-  size_t values_len;
-  cdtime_t time;
-  cdtime_t interval;
-  char host[DATA_MAX_NAME_LEN];
-  char plugin[DATA_MAX_NAME_LEN];
-  char plugin_instance[DATA_MAX_NAME_LEN];
-  char type[DATA_MAX_NAME_LEN];
-  char type_instance[DATA_MAX_NAME_LEN];
-  meta_data_t *meta;
-};
-typedef struct value_list_s value_list_t;
-
-#define VALUE_LIST_INIT                                                        \
-  { .values = NULL, .meta = NULL }
-
-struct data_source_s {
-  char name[DATA_MAX_NAME_LEN];
-  int type;
-  double min;
-  double max;
-};
-typedef struct data_source_s data_source_t;
-
-struct data_set_s {
-  char type[DATA_MAX_NAME_LEN];
-  size_t ds_num;
-  data_source_t *ds;
-};
-typedef struct data_set_s data_set_t;
-
-enum notification_meta_type_e {
-  NM_TYPE_STRING,
-  NM_TYPE_SIGNED_INT,
-  NM_TYPE_UNSIGNED_INT,
-  NM_TYPE_DOUBLE,
-  NM_TYPE_BOOLEAN
-};
-
-typedef struct notification_meta_s {
-  char name[DATA_MAX_NAME_LEN];
-  enum notification_meta_type_e type;
-  union {
-    const char *nm_string;
-    int64_t nm_signed_int;
-    uint64_t nm_unsigned_int;
-    double nm_double;
-    bool nm_boolean;
-  } nm_value;
-  struct notification_meta_s *next;
-} notification_meta_t;
-
-typedef struct notification_s {
-  int severity;
-  cdtime_t time;
-  char message[NOTIF_MAX_MSG_LEN];
-  char host[DATA_MAX_NAME_LEN];
-  char plugin[DATA_MAX_NAME_LEN];
-  char plugin_instance[DATA_MAX_NAME_LEN];
-  char type[DATA_MAX_NAME_LEN];
-  char type_instance[DATA_MAX_NAME_LEN];
-  notification_meta_t *meta;
-} notification_t;
-
-struct user_data_s {
-  void *data;
-  void (*free_func)(void *);
-};
-typedef struct user_data_s user_data_t;
-
-enum cache_event_type_e { CE_VALUE_NEW, CE_VALUE_UPDATE, CE_VALUE_EXPIRED };
-
-typedef struct cache_event_s {
-  enum cache_event_type_e type;
-  const value_list_t *value_list;
-  const char *value_list_name;
-  int ret;
-} cache_event_t;
-
-struct plugin_ctx_s {
-  char *name;
-  cdtime_t interval;
-  cdtime_t flush_interval;
-  cdtime_t flush_timeout;
-};
-typedef struct plugin_ctx_s plugin_ctx_t;
-
-/*
- * Callback types
- */
-typedef int (*plugin_init_cb)(void);
-typedef int (*plugin_read_cb)(user_data_t *);
-typedef int (*plugin_write_cb)(const data_set_t *, const value_list_t *,
-                               user_data_t *);
-typedef int (*plugin_flush_cb)(cdtime_t timeout, const char *identifier,
-                               user_data_t *);
-/* "missing" callback. Returns less than zero on failure, zero if other
- * callbacks should be called, greater than zero if no more callbacks should be
- * called. */
-typedef int (*plugin_missing_cb)(const value_list_t *, user_data_t *);
-/* "cache event" callback. CE_VALUE_NEW events are sent to all registered
- * callbacks. Callback should check if it interested in further CE_VALUE_UPDATE
- * and CE_VALUE_EXPIRED events for metric and set event->ret = 1 if so.
- */
-typedef int (*plugin_cache_event_cb)(cache_event_t *, user_data_t *);
-typedef void (*plugin_log_cb)(int severity, const char *message, user_data_t *);
-typedef int (*plugin_shutdown_cb)(void);
-typedef int (*plugin_notification_cb)(const notification_t *, user_data_t *);
-/*
- * NAME
- *  plugin_set_dir
- *
- * DESCRIPTION
- *  Sets the current `plugindir'
- *
- * ARGUMENTS
- *  `dir'       Path to the plugin directory
- *
- * NOTES
- *  If `dir' is NULL the compiled in default `PLUGINDIR' is used.
- */
-void plugin_set_dir(const char *dir);
-
-/*
- * NAME
- *  plugin_load
- *
- * DESCRIPTION
- *  Searches the current `plugindir' (see `plugin_set_dir') for the plugin
- *  named $type and loads it. Afterwards the plugin's `module_register'
- *  function is called, which then calls `plugin_register' to register callback
- *  functions.
- *
- * ARGUMENTS
- *  `name'      Name of the plugin to load.
- *  `global'    Make this plugins symbols available for other shared libraries.
- *
- * RETURN VALUE
- *  Returns zero upon success, a value greater than zero if no plugin was found
- *  and a value below zero if an error occurs.
- *
- * NOTES
- *  Re-loading an already loaded module is detected and zero is returned in
- *  this case.
- */
-int plugin_load(const char *name, bool global);
-bool plugin_is_loaded(char const *name);
-
-int plugin_init_all(void);
-void plugin_read_all(void);
-int plugin_read_all_once(void);
-int plugin_shutdown_all(void);
-
-/*
- * NAME
- *  plugin_write
- *
- * DESCRIPTION
- *  Calls the write function of the given plugin with the provided data set and
- *  value list. It differs from `plugin_dispatch_values' in that it does not
- *  update the cache, does not do threshold checking, call the chain subsystem
- *  and so on. It looks up the requested plugin and invokes the function, end
- *  of story.
- *
- * ARGUMENTS
- *  plugin     Name of the plugin. If NULL, the value is sent to all registered
- *             write functions.
- *  ds         Pointer to the data_set_t structure. If NULL, the data set is
- *             looked up according to the `type' member in the `vl' argument.
- *  vl         The actual value to be processed. Must not be NULL.
- *
- * RETURN VALUE
- *  Returns zero upon success or non-zero if an error occurred. If `plugin' is
- *  NULL and more than one plugin is called, an error is only returned if *all*
- *  plugins fail.
- *
- * NOTES
- *  This is the function used by the `write' built-in target. May be used by
- *  other target plugins.
- */
-int plugin_write(const char *plugin, const data_set_t *ds,
-                 const value_list_t *vl);
-
-int plugin_flush(const char *plugin, cdtime_t timeout, const char *identifier);
-
-/*
- * The `plugin_register_*' functions are used to make `config', `init',
- * `read', `write' and `shutdown' functions known to the plugin
- * infrastructure. Also, the data-formats are made public like this.
- */
-int plugin_register_config(const char *name,
-                           int (*callback)(const char *key, const char *val),
-                           const char **keys, int keys_num);
-int plugin_register_complex_config(const char *type,
-                                   int (*callback)(oconfig_item_t *));
-int plugin_register_init(const char *name, plugin_init_cb callback);
-int plugin_register_read(const char *name, int (*callback)(void));
-/* "user_data" will be freed automatically, unless
- * "plugin_register_complex_read" returns an error (non-zero). */
-int plugin_register_complex_read(const char *group, const char *name,
-                                 plugin_read_cb callback, cdtime_t interval,
-                                 user_data_t const *user_data);
-int plugin_register_write(const char *name, plugin_write_cb callback,
-                          user_data_t const *user_data);
-int plugin_register_flush(const char *name, plugin_flush_cb callback,
-                          user_data_t const *user_data);
-int plugin_register_missing(const char *name, plugin_missing_cb callback,
-                            user_data_t const *user_data);
-int plugin_register_cache_event(const char *name,
-                                plugin_cache_event_cb callback,
-                                user_data_t const *ud);
-int plugin_register_shutdown(const char *name, plugin_shutdown_cb callback);
-int plugin_register_data_set(const data_set_t *ds);
-int plugin_register_log(const char *name, plugin_log_cb callback,
-                        user_data_t const *user_data);
-int plugin_register_notification(const char *name,
-                                 plugin_notification_cb callback,
-                                 user_data_t const *user_data);
-
-int plugin_unregister_config(const char *name);
-int plugin_unregister_complex_config(const char *name);
-int plugin_unregister_init(const char *name);
-int plugin_unregister_read(const char *name);
-int plugin_unregister_read_group(const char *group);
-int plugin_unregister_write(const char *name);
-int plugin_unregister_flush(const char *name);
-int plugin_unregister_missing(const char *name);
-int plugin_unregister_cache_event(const char *name);
-int plugin_unregister_shutdown(const char *name);
-int plugin_unregister_data_set(const char *name);
-int plugin_unregister_log(const char *name);
-int plugin_unregister_notification(const char *name);
-
-/*
- * NAME
- *  plugin_log_available_writers
- *
- * DESCRIPTION
- *  This function can be called to output a list of _all_ registered
- *  writers to the logfacility.
- *  Since some writers dynamically build their name it can be hard for
- *  the configuring person to know it. This function will fill this gap.
- */
-void plugin_log_available_writers(void);
-
-/*
- * NAME
- *  plugin_dispatch_values
- *
- * DESCRIPTION
- *  This function is called by reading processes with the values they've
- *  aquired. The function fetches the data-set definition (that has been
- *  registered using `plugin_register_data_set') and calls _all_ registered
- *  write-functions.
- *
- * ARGUMENTS
- *  `vl'        Value list of the values that have been read by a `read'
- *              function.
- */
-int plugin_dispatch_values(value_list_t const *vl);
-
-/*
- * NAME
- *  plugin_dispatch_multivalue
- *
- * SYNOPSIS
- *  plugin_dispatch_multivalue (vl, true, DS_TYPE_GAUGE,
- *                              "free", 42.0,
- *                              "used", 58.0,
- *                              NULL);
- *
- * DESCRIPTION
- *  Takes a list of type instances and values and dispatches that in a batch,
- *  making sure that all values have the same time stamp. If "store_percentage"
- *  is set to true, the "type" is set to "percent" and a percentage is
- *  calculated and dispatched, rather than the absolute values. Values that are
- *  NaN are dispatched as NaN and will not influence the total.
- *
- *  The variadic arguments is a list of type_instance / type pairs, that are
- *  interpreted as type "char const *" and type, encoded by their corresponding
- *  "store_type":
- *
- *     - "gauge_t"    when "DS_TYPE_GAUGE"
- *     - "absolute_t" when "DS_TYPE_ABSOLUTE"
- *     - "derive_t"   when "DS_TYPE_DERIVE"
- *     - "counter_t"  when "DS_TYPE_COUNTER"
- *
- *  The last argument must be
- *  a NULL pointer to signal end-of-list.
- *
- * RETURNS
- *  The number of values it failed to dispatch (zero on success).
- */
-__attribute__((sentinel)) int plugin_dispatch_multivalue(value_list_t const *vl,
-                                                         bool store_percentage,
-                                                         int store_type, ...);
-
-int plugin_dispatch_missing(const value_list_t *vl);
-void plugin_dispatch_cache_event(enum cache_event_type_e event_type,
-                                 unsigned long callbacks_mask, const char *name,
-                                 const value_list_t *vl);
-
-int plugin_dispatch_notification(const notification_t *notif);
-
-void plugin_log(int level, const char *format, ...)
-    __attribute__((format(printf, 2, 3)));
-
-/* These functions return the parsed severity or less than zero on failure. */
-int parse_log_severity(const char *severity);
-int parse_notif_severity(const char *severity);
-
-#define ERROR(...) plugin_log(LOG_ERR, __VA_ARGS__)
-#define WARNING(...) plugin_log(LOG_WARNING, __VA_ARGS__)
-#define NOTICE(...) plugin_log(LOG_NOTICE, __VA_ARGS__)
-#define INFO(...) plugin_log(LOG_INFO, __VA_ARGS__)
-#if COLLECT_DEBUG
-#define DEBUG(...) plugin_log(LOG_DEBUG, __VA_ARGS__)
-#else              /* COLLECT_DEBUG */
-#define DEBUG(...) /* noop */
-#endif             /* ! COLLECT_DEBUG */
-
-/* This will log messages, prefixed by plugin name */
-void daemon_log(int level, const char *format, ...)
-    __attribute__((format(printf, 2, 3)));
-
-#define P_ERROR(...) daemon_log(LOG_ERR, __VA_ARGS__)
-#define P_WARNING(...) daemon_log(LOG_WARNING, __VA_ARGS__)
-#define P_NOTICE(...) daemon_log(LOG_NOTICE, __VA_ARGS__)
-#define P_INFO(...) daemon_log(LOG_INFO, __VA_ARGS__)
-
-const data_set_t *plugin_get_ds(const char *name);
-
-int plugin_notification_meta_add_string(notification_t *n, const char *name,
-                                        const char *value);
-int plugin_notification_meta_add_signed_int(notification_t *n, const char *name,
-                                            int64_t value);
-int plugin_notification_meta_add_unsigned_int(notification_t *n,
-                                              const char *name, uint64_t value);
-int plugin_notification_meta_add_double(notification_t *n, const char *name,
-                                        double value);
-int plugin_notification_meta_add_boolean(notification_t *n, const char *name,
-                                         bool value);
-
-int plugin_notification_meta_copy(notification_t *dst,
-                                  const notification_t *src);
-
-int plugin_notification_meta_free(notification_meta_t *n);
-
-/*
- * Plugin context management.
- */
-
-void plugin_init_ctx(void);
-
-plugin_ctx_t plugin_get_ctx(void);
-plugin_ctx_t plugin_set_ctx(plugin_ctx_t ctx);
-
-/*
- * NAME
- *  plugin_get_interval
- *
- * DESCRIPTION
- *  This function returns the current value of the plugin's interval. The
- *  return value will be strictly greater than zero in all cases. If
- *  everything else fails, it will fall back to 10 seconds.
- */
-cdtime_t plugin_get_interval(void);
-
-/*
- * Context-aware thread management.
- */
-
-int plugin_thread_create(pthread_t *thread, void *(*start_routine)(void *),
-                         void *arg, char const *name);
-
-/*
- * Plugins need to implement this
- */
-
-void module_register(void);
-
-#endif /* PLUGIN_H */
index d55aede..85dd515 100644 (file)
 # limitations under the License.
 
 ##############################################################
-# Check if building as subproject or as root project
+# Dependencies
 ##############################################################
-if(${CMAKE_SOURCE_DIR}/vpp-collectd STREQUAL ${PROJECT_SOURCE_DIR})
-  message (STATUS "not compiling in the same folder")
-  find_package(HicnPlugin ${CURRENT_VERSION} REQUIRED)
-  find_package(Vapisafe ${CURRENT_VERSION} REQUIRED)
-else()
-  message (STATUS "compiling in the same folder")
-  list(APPEND DEPENDENCIES
-    ${HICNPLUGIN_SHARED}
-  )
-endif()
+find_package(HicnPlugin ${CURRENT_VERSION} REQUIRED)
+find_package(Libsafevapi ${CURRENT_VERSION} REQUIRED NO_MODULE)
 
 
 ##############################################################
-# Sources
+# Source files
 ##############################################################
 list(APPEND SOURCE_FILES
   ${CMAKE_CURRENT_SOURCE_DIR}/vpp_hicn.c
 )
 
+
+##############################################################
+# Include dirs
+##############################################################
 list(APPEND INCLUDE_DIRS
   ${COLLECTD_INCLUDE_DIRS}
+  ${THIRD_PARTY_INCLUDE_DIRS}
   ${HICNPLUGIN_INCLUDE_DIRS}
-  ${SAFE_VAPI_INCLUDE_DIRS}
+  ${Libsafe_vapi_INCLUDE_DIRS}
   ${VPP_INCLUDE_DIRS}
-  ${CMAKE_CURRENT_SOURCE_DIR}
-  "${CMAKE_CURRENT_SOURCE_DIR}/../common"
 )
 
 
 ##############################################################
-# Libs
+# Libraries
 ##############################################################
 list(APPEND LIBRARIES
   ${VPP_LIBRARY_VAPICLIENT}
-  ${SAFE_VAPI_LIBRARIES}
+  hicn::safevapi.shared
+)
+
+
+##############################################################
+# Compiler options
+##############################################################
+list(APPEND COMPILER_OPTIONS
+  ${DEFAULT_COMPILER_OPTIONS}
+  ${COLLECTD_COMPILER_OPTIONS}
 )
 
 
 ##############################################################
 # Build library
 ##############################################################
-build_library(vpp_hicn
+build_library(${VPP_HICN_TELEMETRY}
+  SHARED
+  EMPTY_PREFIX
   SOURCES ${SOURCE_FILES}
   LINK_LIBRARIES ${LIBRARIES}
-  INCLUDE_DIRS ${INCLUDE_DIRS}
-  INSTALL_FULL_PATH_DIR ${CMAKE_INSTALL_PREFIX}/lib/collectd
-  COMPONENT "${COLLECTD_PLUGINS}"
+  INCLUDE_DIRS
+    PRIVATE ${INCLUDE_DIRS}
+  INSTALL_FULL_PATH_DIR ${COLLECTD_PLUGIN_DIR}
+  COMPONENT ${COLLECTD_PLUGINS}
   DEPENDS ${DEPENDENCIES}
   COMPILE_OPTIONS ${COMPILER_OPTIONS}
 )
index a724c11..a20bcbc 100644 (file)
  * limitations under the License.
  */
 
-/* Keep order as it is */
-#include "common.h"
-#include <config.h>
+#include "../../data_model.h"
+#include "collectd.h"
+#include "plugin.h"
+#include "utils/common/common.h"
 
 #define counter_t vpp_counter_t
+#include <hicn/vapi/vapi_safe.h>
 #include <vapi/hicn.api.vapi.h>
-#include <vapi/vapi_safe.h>
 #undef counter_t
 
 DEFINE_VAPI_MSG_IDS_HICN_API_JSON
@@ -34,140 +35,6 @@ static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
 static bool verbose = false;
 static char *tag = NULL;
 
-/************** DATA SOURCES ******************************/
-static data_source_t packets_dsrc[1] = {
-    {"packets", DS_TYPE_GAUGE, 0, NAN},
-};
-
-static data_source_t interests_dsrc[1] = {
-    {"interests", DS_TYPE_GAUGE, 0, NAN},
-};
-
-static data_source_t data_dsrc[1] = {
-    {"data", DS_TYPE_GAUGE, 0, NAN},
-};
-
-static data_source_t combined_dsrc[2] = {
-    {"packets", DS_TYPE_DERIVE, 0, NAN},
-    {"bytes", DS_TYPE_DERIVE, 0, NAN},
-};
-
-/************** DATA SETS NODE ****************************/
-static data_set_t pkts_processed_ds = {
-    "pkts_processed",
-    STATIC_ARRAY_SIZE(packets_dsrc),
-    packets_dsrc,
-};
-
-static data_set_t pkts_interest_count_ds = {
-    "pkts_interest_count",
-    STATIC_ARRAY_SIZE(packets_dsrc),
-    packets_dsrc,
-};
-
-static data_set_t pkts_data_count_ds = {
-    "pkts_data_count",
-    STATIC_ARRAY_SIZE(packets_dsrc),
-    packets_dsrc,
-};
-
-static data_set_t pkts_from_cache_count_ds = {
-    "pkts_from_cache_count",
-    STATIC_ARRAY_SIZE(packets_dsrc),
-    packets_dsrc,
-};
-
-static data_set_t pkts_no_pit_count_ds = {
-    "pkts_no_pit_count",
-    STATIC_ARRAY_SIZE(packets_dsrc),
-    packets_dsrc,
-};
-
-static data_set_t pit_expired_count_ds = {
-    "pit_expired_count",
-    STATIC_ARRAY_SIZE(interests_dsrc),
-    interests_dsrc,
-};
-
-static data_set_t cs_expired_count_ds = {
-    "cs_expired_count",
-    STATIC_ARRAY_SIZE(data_dsrc),
-    data_dsrc,
-};
-
-static data_set_t cs_lru_count_ds = {
-    "cs_lru_count",
-    STATIC_ARRAY_SIZE(data_dsrc),
-    data_dsrc,
-};
-
-static data_set_t pkts_drop_no_buf_ds = {
-    "pkts_drop_no_buf",
-    STATIC_ARRAY_SIZE(packets_dsrc),
-    packets_dsrc,
-};
-
-static data_set_t interests_aggregated_ds = {
-    "interests_aggregated",
-    STATIC_ARRAY_SIZE(interests_dsrc),
-    interests_dsrc,
-};
-
-static data_set_t interests_retx_ds = {
-    "interests_retx",
-    STATIC_ARRAY_SIZE(interests_dsrc),
-    interests_dsrc,
-};
-
-static data_set_t interests_hash_collision_ds = {
-    "interests_hash_collision",
-    STATIC_ARRAY_SIZE(interests_dsrc),
-    interests_dsrc,
-};
-
-static data_set_t pit_entries_count_ds = {
-    "pit_entries_count",
-    STATIC_ARRAY_SIZE(interests_dsrc),
-    interests_dsrc,
-};
-
-static data_set_t cs_entries_count_ds = {
-    "cs_entries_count",
-    STATIC_ARRAY_SIZE(data_dsrc),
-    data_dsrc,
-};
-
-static data_set_t cs_entries_ntw_count_ds = {
-    "cs_entries_ntw_count",
-    STATIC_ARRAY_SIZE(data_dsrc),
-    data_dsrc,
-};
-
-/************** DATA SETS FACE ****************************/
-static data_set_t irx_ds = {
-    "irx",
-    STATIC_ARRAY_SIZE(combined_dsrc),
-    combined_dsrc,
-};
-
-static data_set_t itx_ds = {
-    "itx",
-    STATIC_ARRAY_SIZE(combined_dsrc),
-    combined_dsrc,
-};
-
-static data_set_t drx_ds = {
-    "drx",
-    STATIC_ARRAY_SIZE(combined_dsrc),
-    combined_dsrc,
-};
-
-static data_set_t dtx_ds = {
-    "dtx",
-    STATIC_ARRAY_SIZE(combined_dsrc),
-    combined_dsrc,
-};
-
 /**********************************************************/
 /********** UTILITY FUNCTIONS *****************************/
 /**********************************************************/
@@ -189,8 +56,7 @@ static int submit(const char *plugin_instance, const char *type,
   sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance));
   sstrncpy(vl.type, type, sizeof(vl.type));
 
-  if (tag != NULL)
-    sstrncpy(vl.type_instance, tag, sizeof(vl.type_instance));
+  if (tag != NULL) sstrncpy(vl.type_instance, tag, sizeof(vl.type_instance));
 
   return plugin_dispatch_values(&vl);
 }
@@ -223,15 +89,12 @@ static int vpp_hicn_config(const char *key, const char *value) {
 /*
  * Callback called by the hICN plugin API when node stats are ready.
  */
-static vapi_error_e
-parse_node_stats(vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv,
-                 bool is_last,
-                 vapi_payload_hicn_api_node_stats_get_reply *reply) {
-  if (reply == NULL || rv != VAPI_OK)
-    return rv;
+static vapi_error_e parse_node_stats(
+    vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
+    vapi_payload_hicn_api_node_stats_get_reply *reply) {
+  if (reply == NULL || rv != VAPI_OK) return rv;
 
-  if (reply->retval != VAPI_OK)
-    return reply->retval;
+  if (reply->retval != VAPI_OK) return reply->retval;
 
   char *node_name = "node";
   value_t values[1];
@@ -277,15 +140,12 @@ parse_node_stats(vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv,
 /*
  * Callback called by the hICN plugin API when face stats are ready.
  */
-static vapi_error_e
-parse_face_stats(vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv,
-                 bool is_last,
-                 vapi_payload_hicn_api_face_stats_details *reply) {
-  if (reply == NULL || rv != VAPI_OK)
-    return rv;
+static vapi_error_e parse_face_stats(
+    vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last,
+    vapi_payload_hicn_api_face_stats_details *reply) {
+  if (reply == NULL || rv != VAPI_OK) return rv;
 
-  if (reply->retval != VAPI_OK)
-    return reply->retval;
+  if (reply->retval != VAPI_OK) return reply->retval;
 
   char face_name[10];
   snprintf(face_name, 10, "face%u", reply->faceid);
@@ -314,8 +174,7 @@ parse_face_stats(vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv,
 static int vpp_hicn_init(void) {
   int ret = vapi_connect_safe(&vapi_ctx, 0);
 
-  if (ret)
-    plugin_log(LOG_ERR, "vpp_hicn plugin: vapi_connect_safe failed");
+  if (ret) plugin_log(LOG_ERR, "vpp_hicn plugin: vapi_connect_safe failed");
 
   return ret;
 }
index 41c1920..e1cf555 100644 (file)
@@ -20,13 +20,12 @@ list(APPEND SOURCE_FILES
 
 
 ##############################################################
-# Include directories
+# Include dirs
 ##############################################################
 list(APPEND INCLUDE_DIRS
   ${COLLECTD_INCLUDE_DIRS}
+  ${THIRD_PARTY_INCLUDE_DIRS}
   ${VPP_INCLUDE_DIRS}
-  ${CMAKE_CURRENT_SOURCE_DIR}
-  "${CMAKE_CURRENT_SOURCE_DIR}/../common"
 )
 
 
@@ -39,11 +38,26 @@ list(APPEND LIBRARIES
 )
 
 
-build_module(vpp
+##############################################################
+# Compiler options
+##############################################################
+list(APPEND COMPILER_OPTIONS
+  ${DEFAULT_COMPILER_OPTIONS}
+  ${COLLECTD_COMPILER_OPTIONS}
+)
+
+
+##############################################################
+# Build library
+##############################################################
+build_library(${VPP_TELEMETRY}
+  SHARED
+  EMPTY_PREFIX
   SOURCES ${SOURCE_FILES}
   LINK_LIBRARIES ${LIBRARIES}
-  INCLUDE_DIRS ${INCLUDE_DIRS}
-  INSTALL_FULL_PATH_DIR ${CMAKE_INSTALL_PREFIX}/lib/collectd
+  INCLUDE_DIRS
+    PRIVATE ${INCLUDE_DIRS}
+  INSTALL_FULL_PATH_DIR ${COLLECTD_PLUGIN_DIR}
   COMPONENT ${COLLECTD_PLUGINS}
   COMPILE_OPTIONS ${COMPILER_OPTIONS}
 )
index 85d0971..ff70f35 100644 (file)
@@ -13,9 +13,9 @@
  * limitations under the License.
  */
 
-/* Keep order as it is */
-#include "common.h"
-#include <config.h>
+#include "collectd.h"
+#include "plugin.h"
+#include "utils/common/common.h"
 
 #define counter_t vpp_counter_t
 #include <vpp-api/client/stat_client.h>
@@ -165,8 +165,7 @@ static int submit(const char *plugin_instance, const char *type,
   sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance));
   sstrncpy(vl.type, type, sizeof(vl.type));
 
-  if (tag != NULL)
-    sstrncpy(vl.type_instance, tag, sizeof(vl.type_instance));
+  if (tag != NULL) sstrncpy(vl.type_instance, tag, sizeof(vl.type_instance));
 
   return plugin_dispatch_values(&vl);
 }
@@ -261,8 +260,7 @@ static int vpp_init(void) {
   u8 *stat_segment_name = (u8 *)STAT_SEGMENT_SOCKET_FILE;
   int ret = stat_segment_connect((char *)stat_segment_name);
 
-  if (ret)
-    plugin_log(LOG_ERR, "vpp plugin: connecting to segment failed");
+  if (ret) plugin_log(LOG_ERR, "vpp plugin: connecting to segment failed");
 
   return ret;
 }
@@ -296,66 +294,65 @@ static int vpp_read(void) {
   /* Collect results for each interface and submit them */
   for (int i = 0; i < vec_len(res); i++) {
     switch (res[i].type) {
-    case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
-      for (int k = 0; k < vec_len(res[i].simple_counter_vec); k++) {
-        for (int j = 0; j < vec_len(res[i].simple_counter_vec[k]); j++) {
-          if (!interfaces[j]) {
-            continue;
-          }
+      case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
+        for (int k = 0; k < vec_len(res[i].simple_counter_vec); k++) {
+          for (int j = 0; j < vec_len(res[i].simple_counter_vec[k]); j++) {
+            if (!interfaces[j]) {
+              continue;
+            }
 
-          if (get_data_set(res[i].name, &data_set)) {
-            continue;
-          }
+            if (get_data_set(res[i].name, &data_set)) {
+              continue;
+            }
 
-          value_t values[1] = {
-              (value_t){.derive = res[i].simple_counter_vec[k][j]}};
+            value_t values[1] = {
+                (value_t){.derive = res[i].simple_counter_vec[k][j]}};
 
-          err = submit(interfaces[j], data_set.type, values, 1, &timestamp);
+            err = submit(interfaces[j], data_set.type, values, 1, &timestamp);
 
-          if (err)
-            goto END;
+            if (err) goto END;
+          }
         }
-      }
-      break;
+        break;
 
-    case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
-      for (int k = 0; k < vec_len(res[i].combined_counter_vec); k++) {
-        for (int j = 0; j < vec_len(res[i].combined_counter_vec[k]); j++) {
-          if (!interfaces[j]) {
-            continue;
-          }
+      case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
+        for (int k = 0; k < vec_len(res[i].combined_counter_vec); k++) {
+          for (int j = 0; j < vec_len(res[i].combined_counter_vec[k]); j++) {
+            if (!interfaces[j]) {
+              continue;
+            }
 
-          if (get_data_set(res[i].name, &data_set)) {
-            continue;
-          }
+            if (get_data_set(res[i].name, &data_set)) {
+              continue;
+            }
 
-          value_t values[2] = {
-              (value_t){.derive = res[i].combined_counter_vec[k][j].packets},
-              (value_t){.derive = res[i].combined_counter_vec[k][j].bytes},
-          };
+            value_t values[2] = {
+                (value_t){.derive = res[i].combined_counter_vec[k][j].packets},
+                (value_t){.derive = res[i].combined_counter_vec[k][j].bytes},
+            };
 
-          err = submit(interfaces[j], data_set.type, values, 2, &timestamp);
+            err = submit(interfaces[j], data_set.type, values, 2, &timestamp);
 
-          if (err)
-            goto END;
+            if (err) goto END;
+          }
         }
-      }
-      break;
+        break;
 
-    case STAT_DIR_TYPE_SCALAR_INDEX:
-      plugin_log(LOG_INFO, "vpp plugin: %.2f %s", res[i].scalar_value,
-                 res[i].name);
-      break;
+      case STAT_DIR_TYPE_SCALAR_INDEX:
+        plugin_log(LOG_INFO, "vpp plugin: %.2f %s", res[i].scalar_value,
+                   res[i].name);
+        break;
 
-    case STAT_DIR_TYPE_NAME_VECTOR:
-      break;
+      case STAT_DIR_TYPE_NAME_VECTOR:
+        break;
 
-    case STAT_DIR_TYPE_ERROR_INDEX:
-      break;
+      case STAT_DIR_TYPE_ERROR_INDEX:
+        break;
 
-    default:
-      plugin_log(LOG_WARNING, "vpp plugin: unknown stat type %d", res[i].type);
-      break;
+      default:
+        plugin_log(LOG_WARNING, "vpp plugin: unknown stat type %d",
+                   res[i].type);
+        break;
     }
   }
 
index 1d40e4d..f36c667 100644 (file)
@@ -9,6 +9,6 @@ TEST_VPP_MEMIF=vpp-memif
 TEST_VPP_MEMIF_REPLICATION=vpp-memif-replication
 
 # names
-RTC_PRODUCER=b002::1
+RTC_PRODUCER=b002:0:0:0:abcd::/80
 RAAQM_PRODUCER=b002::2
 PING_PRODUCER=b002::3
index 318a5cc..0aee8cf 100644 (file)
@@ -58,8 +58,8 @@ services:
 
         sleep 4
 
-        hiperf -z hicnlightng_module -D -S -R -B 4000kbps ${RTC_PRODUCER}/128
-        hiperf -z hicnlightng_module -D -S ${RAAQM_PRODUCER}/128
-        hicn-ping-server -z hicnlightng_module -d -s 0 -n ${PING_PRODUCER}/128
+        hiperf -q -z hicnlightng_module -S -R -B 4000kbps ${RTC_PRODUCER} -P 2 &
+        hiperf -q -z hicnlightng_module -S ${RAAQM_PRODUCER}/128 &
+        hicn-ping-server -q -z hicnlightng_module -s 0 -n ${PING_PRODUCER}/128 &
 
         tail -f /dev/null
index d942684..db1fa6f 100644 (file)
@@ -98,10 +98,10 @@ services:
         sudo vpp -c /etc/vpp/startup.conf
         sleep 5
 
-        sudo hiperf -D -S -R -B 4000kbps -z memif_module ${RTC_PRODUCER}/128
+        sudo hiperf -q -S -R -B 4000kbps -z memif_module ${RTC_PRODUCER} -P 2 &
         sleep 1
-        sudo hiperf -D -S -z memif_module ${RAAQM_PRODUCER}/128
+        sudo hiperf -q -S -z memif_module ${RAAQM_PRODUCER}/128 &
         sleep 1
-        sudo hicn-ping-server -d -s 0 -n ${PING_PRODUCER}/128 -z memif_module
+        sudo hicn-ping-server -q -s 0 -n ${PING_PRODUCER}/128 -z memif_module &
 
         tail -f /dev/null
index 37f028d..45de824 100644 (file)
@@ -134,10 +134,10 @@ services:
         sudo vpp -c /etc/vpp/startup.conf
         sleep 10
 
-        sudo hiperf -D -S -R -B 4000kbps -z memif_module ${RTC_PRODUCER}/128
+        sudo hiperf -q -S -R -B 4000kbps -z memif_module ${RTC_PRODUCER} -P 2 &
         sleep 5
-        sudo hiperf -D -S -z memif_module ${RAAQM_PRODUCER}/128
+        sudo hiperf -q -S -z memif_module ${RAAQM_PRODUCER}/128 &
         sleep 5
-        sudo hicn-ping-server -d -s 0 -n ${PING_PRODUCER}/128 -z memif_module
+        sudo hicn-ping-server -q -s 0 -n ${PING_PRODUCER}/128 -z memif_module &
 
         tail -f /dev/null
index 034437d..48b4a1c 100644 (file)
@@ -107,10 +107,10 @@ services:
         sudo vpp -c /etc/vpp/startup.conf
         sleep 10
 
-        sudo hiperf -D -S -R -B 4000kbps -z memif_module ${RTC_PRODUCER}/128
+        sudo hiperf -q -S -R -B 4000kbps -z memif_module ${RTC_PRODUCER} -P 2 &
         sleep 5
-        sudo hiperf -D -S -z memif_module ${RAAQM_PRODUCER}/128
+        sudo hiperf -q -S -z memif_module ${RAAQM_PRODUCER}/128 &
         sleep 5
-        sudo hicn-ping-server -d -s 0 -n ${PING_PRODUCER}/128 -z memif_module
+        sudo hicn-ping-server -q -s 0 -n ${PING_PRODUCER}/128 -z memif_module &
 
         tail -f /dev/null
index 6e85a71..0f30d6a 100644 (file)
@@ -30,6 +30,6 @@ down:
 
 functional:
        sleep 1  # Wait for the forwarder to be ready
-       bash config.sh test_listeners
-       bash config.sh test_connections
-       bash config.sh test_routes
\ No newline at end of file
+       bash config.sh ctrl listeners
+       bash config.sh ctrl connections
+       bash config.sh ctrl routes
\ No newline at end of file
index d504b1c..654bad5 100755 (executable)
@@ -16,7 +16,7 @@ BASE_IMAGE=${BASE_IMAGE:-hicn}
 BUILD_SOFTWARE=${BUILD_SOFTWARE:-1}
 set +a
 
-HIPERF_CMD_RTC="hiperf -n 50 -C -H -R ${RTC_PRODUCER}"
+HIPERF_CMD_RTC="hiperf -q -n 50 -C -H -R ${RTC_PRODUCER} -P 2"
 HIPERF_CMD_MEMIF_RTC="${HIPERF_CMD_RTC} -z memif_module"
 POSTPROCESS_COMMAND_RAAQM_RTC='tail -n +3 | \
   tr -s " " |                               \
@@ -34,7 +34,7 @@ POSTPROCESS_COMMAND_RAAQM_RTC='tail -n +3 | \
     print int(a[0]), int(a[n-1]), int(s/n)  \
   }"'
 
-HIPERF_CMD_RAAQM="hiperf -n 50 -i 200 -C -H ${RAAQM_PRODUCER}"
+HIPERF_CMD_RAAQM="hiperf -q -n 50 -i 200 -C -H ${RAAQM_PRODUCER}"
 HIPERF_CMD_CBR="${HIPERF_CMD_RAAQM} -W 350 -M 0"
 HIPERF_CMD_MEMIF_RAAQM="${HIPERF_CMD_RAAQM} -z memif_module"
 HIPERF_CMD_MEMIF_CBR="${HIPERF_CMD_CBR} -z memif_module"
diff --git a/tests/forwarder.robot b/tests/forwarder.robot
deleted file mode 100644 (file)
index 60345db..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-*** Settings ***
-Library                 Process
-Test Template           Run Test
-Test Setup              Setup
-Test Teardown           Teardown
-Test Timeout            5 seconds
-
-*** Variables ***
-${cmd}                  bash test_forwarder.sh
-
-*** Test Cases ***
-# Commands
-Add listener                        test_add_listener
-Remove listener                     test_remove_listener
-Remove non-existing listener        test_remove_non_existing_listener
-Add duplicated listener             test_add_duplicated_listener
-List listeners                      test_list_listeners
-Commands from config file           test_commands_from_config
-
-# Ping
-Ping one packet                     test_ping_one_packet
-Ping two packets                    test_ping_two_packets
-Ping using CS                       test_ping_using_cs
-Ping using CS different order       test_ping_using_cs_different_order
-Ping timeout                        test_ping_timeout
-Ping aggregation                    test_ping_aggregation
-Ping with CS store disabled         test_ping_with_cs_store_disabled
-Ping with CS serve disabled         test_ping_with_cs_serve_disabled
-Ping with eviction                  test_ping_with_eviction
-Ping with zero data lifetime        test_ping_with_zero_data_lifetime
-
-*** Keywords ***
-Setup
-  ${result}=  Run Process  ${cmd} set_up  shell=True
-  Log Many  stdout: ${result.stdout}  stderr: ${result.stderr}
-
-Teardown
-  ${result}=  Run Process  ${cmd} tear_down  shell=True
-  Log Many  stdout: ${result.stdout}  stderr: ${result.stderr}
-
-Run Test
-  [Arguments]  ${test_name}
-  ${result}=  Run Process  ${cmd} ${test_name}  shell=True
-  Log Many  stdout: ${result.stdout}  stderr: ${result.stderr}
-  Should Be Equal As Integers  ${result.rc}  0
\ No newline at end of file
diff --git a/tests/hiperf-local.sh b/tests/hiperf-local.sh
new file mode 100644 (file)
index 0000000..1ef11eb
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+set -eo pipefail
+
+if [[ "$(basename $(pwd))" != build* ]]; then
+  echo "Error: launch script from build dir"
+  exit 1
+fi
+
+# Stop forwarder and hiperf if already running
+sudo killall -9 hicn-light-daemon hiperf 2>/dev/null || true
+
+# Start forwarder and hiperf server in background
+ninja && sudo ./build-root/bin/hicn-light-daemon --daemon --log-file /tmp/lite_client.log >/dev/null
+./build-root/bin/hiperf -z hicnlightng_module -S b001::/16 &
+
+# Run hiperf client for 20 seconds
+sleep 1
+./build-root/bin/hiperf -z hicnlightng_module -C b001:: -W 50 -n 20
+
+# Clean up
+sudo killall -9 hicn-light-daemon hiperf
diff --git a/tests/test_forwarder.sh b/tests/test_forwarder.sh
deleted file mode 100644 (file)
index aba85d8..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-#!/bin/bash
-
-############################################################################
-#                               CONSTANTS
-############################################################################
-INTERFACE_CMD="ip route get 1 | grep -Po '(?<=(dev )).*(?= src| proto)'"
-ADDRESS_CMD="ip route get 1 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'"
-CTRL_CMD="docker exec test-hicn     \
-                /hicn-build/build/build-root/bin/hicn-light-control"
-PING_SERVER_CMD="docker exec -d test-hicn   \
-                    /hicn-build/build/build-root/bin/hicn-ping-server \
-                    -z hicnlightng_module"
-PING_CLIENT_CMD="docker exec test-hicn     \
-                    /hicn-build/build/build-root/bin/hicn-ping-client \
-                    -z hicnlightng_module"
-PING_CLIENT_DETACHED_CMD="docker exec -d test-hicn     \
-                    /hicn-build/build/build-root/bin/hicn-ping-client \
-                    -z hicnlightng_module"
-LISTENER_NAME="udp0"
-CONN_NAME="conn0"
-PREFIX="c001::/64"
-COST=1
-FIVE_SECONDS=5000
-
-############################################################################
-#                                   UTILS
-############################################################################
-set_up() {
-  docker build -t hicn-dev .
-  run_forwarder
-}
-
-tear_down() {
-  docker stop --time 0 test-hicn
-}
-
-get_address() {
-  echo $(docker exec test-hicn sh -c "${ADDRESS_CMD}")
-}
-
-get_interface() {
-  echo $(docker exec test-hicn sh -c "${INTERFACE_CMD}")
-}
-
-#---------------------------------------------------------------------------
-# Exec
-#---------------------------------------------------------------------------
-run_forwarder() {
-  capacity=${1:-"100000"}
-  loglevel=${2:-"trace"}
-  config=${3:-""}
-
-  config_file_arg=""
-  if [[ $config != "" ]]; then
-    config_file_arg="--config ${config}"
-  fi
-
-  docker run --rm -d --name test-hicn \
-    -v $(pwd)/..:/hicn-build \
-    -e LD_LIBRARY_PATH=/hicn-build/build/build-root/lib \
-    hicn-dev \
-    /hicn-build/build/build-root/bin/hicn-light-daemon \
-    --log ${loglevel} --capacity ${capacity} $config_file_arg
-}
-
-exec_controller() {
-  command=$1
-
-  # Redirect stderr to stdout
-  output=$(${CTRL_CMD} ${command} 2>&1)
-  assert_exit_code
-  echo ${output}
-}
-
-exec_ping_server() {
-  data_lifetime=${1:-""}
-
-  lifetime_arg=""
-  if [[ $data_lifetime != "" ]]; then
-    lifetime_arg="-l ${data_lifetime}"
-  fi
-
-  ${PING_SERVER_CMD} ${lifetime_arg}
-}
-
-exec_ping_client() {
-  num_packets=$1
-
-  output=$(${PING_CLIENT_CMD} -m ${num_packets})
-  assert_exit_code
-  echo ${output}
-}
-
-exec_ping_client_detached() {
-  num_packets=$1
-  interest_lifetime=$2
-
-  ${PING_CLIENT_DETACHED_CMD} -m ${num_packets} -l ${interest_lifetime}
-}
-
-#---------------------------------------------------------------------------
-# Asserts
-#---------------------------------------------------------------------------
-assert_exit_code() {
-  if [[ $? -ne 0 ]]; then
-    exit_with_failure
-  fi
-}
-
-assert_forwarder() {
-  # Print forwarder logs for debug info
-  echo "******** Forwarder Logs ********"
-  docker logs test-hicn
-  echo "********************************"
-
-  output=$(docker logs test-hicn)
-  if [[ $output == "" ]]; then
-    exit_with_failure
-  fi
-
-  if [[ "${output}" == *"ERROR"* ]]; then
-    exit_with_failure
-  fi
-
-  if [[ "${output}" == *"Aborted (core dumped)"* ]]; then
-    exit_with_failure
-  fi
-}
-
-assert_ack() {
-  # Print controller logs for debug info
-  echo "******** Controller Logs ********"
-  echo $1
-  echo "********************************"
-
-  output=$1
-
-  if [[ "$output" == *"Error"* ]]; then
-    exit_with_failure
-  fi
-}
-
-assert_nack() {
-  # Print controller logs for debug info
-  echo "******** Controller Logs ********"
-  echo $1
-  echo "********************************"
-
-  output=$1
-
-  if [[ "$output" != *"Error"* ]]; then
-    exit_with_failure
-  fi
-}
-
-assert_ping_client() {
-  # Print ping client logs for debug info
-  echo "******** Ping Client Logs ********"
-  echo $1
-  echo "********************************"
-
-  ping_client_output=$1
-  pkts_sent=$2
-  pkts_recv=$3
-  pkts_timeout=$4
-
-  match_str="Sent: ${pkts_sent} Received: ${pkts_recv} Timeouts: ${pkts_timeout}"
-  if [[ ! ${ping_client_output} == *"${match_str}"* ]]; then
-    exit_with_failure
-  fi
-}
-
-assert_forwarder_stats() {
-  satisfied_from_cs=${1:-""}
-  no_route_in_fib=${2:-""}
-  aggregated=${3:-""}
-
-  fwder_stats=$(docker logs test-hicn | grep "Forwarder: received" | tail -n 1)
-
-  if [[ $satisfied_from_cs != "" &&
-    "${fwder_stats}" != *"satisfied_from_cs = ${satisfied_from_cs}"* ]]; then
-    exit_with_failure
-  fi
-
-  if [[ $no_route_in_fib != "" &&
-    "${fwder_stats}" != *"no_route_in_fib = ${no_route_in_fib}"* ]]; then
-    exit_with_failure
-  fi
-
-  if [[ $aggregated != "" &&
-    "${fwder_stats}" != *"aggregated = ${aggregated}"* ]]; then
-    exit_with_failure
-  fi
-}
-
-assert_pkt_cache_stats() {
-  total_size=${1:-""}
-  pit_size=${2:-""}
-  cs_size=${3:-""}
-
-  pkt_cache_stats=$(docker logs test-hicn | grep "Packet cache:" | tail -n 1)
-
-  if [[ $total_size != "" &&
-    "${pkt_cache_stats}" != *"total size = ${total_size}"* ]]; then
-    exit_with_failure
-  fi
-
-  if [[ $pit_size != "" &&
-    "${pkt_cache_stats}" != *"PIT size = ${pit_size}"* ]]; then
-    exit_with_failure
-  fi
-
-  if [[ $cs_size != "" &&
-    "${pkt_cache_stats}" != *"CS size = ${cs_size}"* ]]; then
-    exit_with_failure
-  fi
-}
-
-assert_cs_stats() {
-  evictions=${1:-""}
-
-  cs_stats=$(docker logs test-hicn | grep "Content store:" | tail -n 1)
-
-  if [[ $evictions != "" &&
-    "${cs_stats}" != *"evictions = ${evictions}"* ]]; then
-    exit_with_failure
-  fi
-}
-
-############################################################################
-#                                TEST SUITE
-############################################################################
-
-#---------------------------------------------------------------------------
-# Commands
-#---------------------------------------------------------------------------
-test_add_listener() {
-  # Exec hicn-light-control command and capture its output
-  INTERFACE=$(get_interface)
-  ADDRESS=$(get_address)
-  command="add listener udp ${LISTENER_NAME} ${ADDRESS} 9695 ${INTERFACE}"
-  ctrl_output=$(exec_controller "${command}")
-
-  # Check hicn-light-control and hicn-light-daemon outputs
-  assert_ack "$ctrl_output"
-  assert_forwarder
-}
-
-test_remove_listener() {
-  INTERFACE=$(get_interface)
-  ADDRESS=$(get_address)
-  command="add listener udp ${LISTENER_NAME} ${ADDRESS} 9695 ${INTERFACE}"
-  ctrl_output=$(exec_controller "${command}")
-  assert_ack "$ctrl_output"
-
-  command="remove listener udp0"
-  ctrl_output=$(exec_controller "${command}")
-
-  assert_ack "$ctrl_output"
-  assert_forwarder
-}
-
-test_remove_non_existing_listener() {
-  command="remove listener udp0"
-  ctrl_output=$(exec_controller "${command}")
-
-  assert_nack "$ctrl_output"
-  assert_forwarder
-}
-
-test_add_duplicated_listener() {
-  # Exec hicn-light-control command and capture its output
-  INTERFACE=$(get_interface)
-  ADDRESS=$(get_address)
-  command="add listener udp ${LISTENER_NAME} ${ADDRESS} 9695 ${INTERFACE}"
-  exec_controller "${command}"
-  ctrl_output=$(exec_controller "${command}")
-
-  # Check hicn-light-control and hicn-light-daemon outputs
-  assert_nack "$ctrl_output"
-  assert_forwarder
-}
-
-test_list_listeners() {
-  # Exec hicn-light-control command and capture its output
-  command="list listener"
-  ctrl_output=$(exec_controller "${command}")
-
-  # Check hicn-light-control and hicn-light-daemon outputs
-  assert_forwarder
-  # Only the local listener should be present
-  [[ "${ctrl_output}" =~ "inet4://127.0.0.1:9695" ]] && return 0 || exit_with_failure
-}
-
-test_commands_from_config() {
-  # Create config file
-  INTERFACE=$(get_interface)
-  ADDRESS=$(get_address)
-  echo "# Teset config file
-    add listener udp $LISTENER_NAME $ADDRESS 9695 ${INTERFACE}
-    add connection udp $CONN_NAME $ADDRESS 12345 $ADDRESS 9695 ${INTERFACE}
-    add route $CONN_NAME $PREFIX $COST
-    set strategy c001::/64 random
-  " >forwarder.conf
-
-  # Restart the forwarder specifying the config file
-  tear_down
-  run_forwarder "" "" "/hicn-build/tests/forwarder.conf"
-  rm forwarder.conf
-
-  # Check for errors in the output
-  assert_forwarder
-}
-
-#---------------------------------------------------------------------------
-# Ping
-#---------------------------------------------------------------------------
-test_ping_one_packet() {
-  # Exec hicn-ping-server
-  exec_ping_server
-  # Exec hicn-ping-client (w/ 1 packet) and capture its output
-  output=$(exec_ping_client 1)
-
-  # Check hicn-ping-client (1 pkt sent, 1 pkt received, 0 timeouts)
-  # and hicn-light-daemon outputs
-  assert_ping_client "${output}" 1 1 0
-  assert_forwarder
-}
-
-test_ping_two_packets() {
-  exec_ping_server
-  output=$(exec_ping_client 2)
-
-  assert_ping_client "${output}" 2 2 0
-  assert_forwarder
-}
-
-test_ping_using_cs() {
-  exec_ping_server
-  exec_ping_client 2
-  output=$(exec_ping_client 1)
-
-  assert_ping_client "${output}" 1 1 0
-  assert_forwarder
-  assert_forwarder_stats 1
-}
-
-test_ping_using_cs_different_order() {
-  exec_ping_server
-  exec_ping_client 1
-  output=$(exec_ping_client 2)
-
-  assert_ping_client "${output}" 2 2 0
-  assert_forwarder
-  assert_forwarder_stats 1
-}
-
-test_ping_timeout() {
-  # Send ping without the ping server being run
-  output=$(exec_ping_client 1)
-
-  assert_ping_client "${output}" 1 0 1
-  assert_forwarder
-  assert_forwarder_stats 0 1
-}
-
-test_ping_aggregation() {
-  # Send ping without server, waiting for a reply
-  exec_ping_client_detached 1 ${FIVE_SECONDS}
-  exec_ping_server
-  # This new ping interest will be aggregated with the previous one
-  # and the forwarder will reply to both ping clients
-  output=$(exec_ping_client 1)
-
-  assert_ping_client "${output}" 1 1 0
-  assert_forwarder
-  assert_forwarder_stats "" "" 1
-}
-
-test_ping_with_cs_store_disabled() {
-  command="store cache off"
-  exec_controller "${command}"
-
-  exec_ping_server
-  exec_ping_client 1
-  output=$(exec_ping_client 1)
-
-  assert_ping_client "${output}" 1 1 0
-  assert_forwarder
-  assert_forwarder_stats 0 "" ""
-  # The packet is not stored in the CS
-  assert_pkt_cache_stats "" "" 0
-}
-
-test_ping_with_cs_serve_disabled() {
-  command="serve cache off"
-  exec_controller "${command}"
-
-  exec_ping_server
-  exec_ping_client 1
-  output=$(exec_ping_client 1)
-
-  assert_ping_client "${output}" 1 1 0
-  assert_forwarder
-  assert_forwarder_stats 0 "" ""
-  # The packet is stored in the CS, but CS is not used
-  assert_pkt_cache_stats "" "" 1
-}
-
-test_ping_with_eviction() {
-  # Restart the forwarder with CS capacity = 1
-  tear_down
-  run_forwarder 1
-
-  exec_ping_server
-  exec_ping_client 1
-  output=$(exec_ping_client 2)
-
-  assert_ping_client "${output}" 2 2 0
-  assert_forwarder
-  # Check if eviction happened
-  assert_cs_stats 1
-  assert_pkt_cache_stats "" "" 1
-}
-
-test_ping_with_zero_data_lifetime() {
-  exec_ping_server 0
-  exec_ping_client 1
-  output=$(exec_ping_client 1)
-
-  assert_ping_client "${output}" 1 1 0
-  assert_forwarder
-  # The data is not taken from the CS because expired
-  assert_forwarder_stats 0 "" ""
-}
-
-"$@"
index 3bce945..97e8432 100644 (file)
@@ -5,4 +5,6 @@ set(VPP_DEFAULT_VERSION "22.02.0" "EXACT")
 set(LIBMEMIF_DEFAULT_VERSION "22.02" "EXACT")
 set(LIBCONFIG_DEFAULT_VERSION "1.5.0")
 set(COLLECTD_DEFAULT_VERSION "5.9.2" "EXACT")
+set(RDKAFKA_DEFAULT_VERSION "1.8.2" "EXACT")
 set(ANDORID_SDK_DEP_DEFAULT_VERSION "2.1.1" "EXACT")
+set(IOS_TOOLCHAIN_DEP_DEFAULT_VERSION "1.0.1" "EXACT")