From bac3da61644515f05663789b122554dc77549286 Mon Sep 17 00:00:00 2001 From: Luca Muscariello Date: Thu, 17 Jan 2019 13:47:57 +0100 Subject: This is the first commit of the hicn project Change-Id: I6f2544ad9b9f8891c88cc4bcce3cf19bd3cc863f Signed-off-by: Luca Muscariello --- .../src/hicn/transport/core/CMakeLists.txt | 87 +++ libtransport/src/hicn/transport/core/connector.cc | 44 ++ libtransport/src/hicn/transport/core/connector.h | 89 +++ .../src/hicn/transport/core/content_object.cc | 170 ++++++ .../src/hicn/transport/core/content_object.h | 69 +++ libtransport/src/hicn/transport/core/facade.h | 53 ++ .../src/hicn/transport/core/forwarder_interface.h | 136 +++++ .../src/hicn/transport/core/hicn_binary_api.c | 228 ++++++++ .../src/hicn/transport/core/hicn_binary_api.h | 103 ++++ .../transport/core/hicn_forwarder_interface.cc | 84 +++ .../hicn/transport/core/hicn_forwarder_interface.h | 67 +++ .../src/hicn/transport/core/hicn_memif_api.c | 0 libtransport/src/hicn/transport/core/interest.cc | 149 +++++ libtransport/src/hicn/transport/core/interest.h | 66 +++ .../src/hicn/transport/core/key_locator.cc | 42 ++ libtransport/src/hicn/transport/core/key_locator.h | 48 ++ .../src/hicn/transport/core/key_locator_type.h | 28 + libtransport/src/hicn/transport/core/manifest.cc | 33 ++ libtransport/src/hicn/transport/core/manifest.h | 164 ++++++ .../src/hicn/transport/core/manifest_format.h | 196 +++++++ .../hicn/transport/core/manifest_format_fixed.cc | 221 ++++++++ .../hicn/transport/core/manifest_format_fixed.h | 168 ++++++ .../transport/core/manifest_format_json_jsoncpp.cc | 244 ++++++++ .../transport/core/manifest_format_json_jsoncpp.h | 162 ++++++ .../manifest_format_json_libparc_deprecated.cc | 298 ++++++++++ .../core/manifest_format_json_libparc_deprecated.h | 152 +++++ .../src/hicn/transport/core/manifest_inline.h | 116 ++++ .../src/hicn/transport/core/memif_binary_api.c | 218 ++++++++ .../src/hicn/transport/core/memif_binary_api.h | 61 ++ .../src/hicn/transport/core/memif_connector.cc | 493 +++++++++++++++++ .../src/hicn/transport/core/memif_connector.h | 162 ++++++ libtransport/src/hicn/transport/core/name.cc | 236 ++++++++ libtransport/src/hicn/transport/core/name.h | 133 +++++ libtransport/src/hicn/transport/core/packet.cc | 614 +++++++++++++++++++++ libtransport/src/hicn/transport/core/packet.h | 195 +++++++ .../src/hicn/transport/core/payload_type.h | 29 + .../src/hicn/transport/core/pending_interest.cc | 49 ++ .../src/hicn/transport/core/pending_interest.h | 81 +++ libtransport/src/hicn/transport/core/portal.h | 343 ++++++++++++ libtransport/src/hicn/transport/core/prefix.cc | 211 +++++++ libtransport/src/hicn/transport/core/prefix.h | 68 +++ .../hicn/transport/core/raw_socket_connector.cc | 214 +++++++ .../src/hicn/transport/core/raw_socket_connector.h | 85 +++ .../hicn/transport/core/raw_socket_interface.cc | 57 ++ .../src/hicn/transport/core/raw_socket_interface.h | 51 ++ .../src/hicn/transport/core/socket_connector.cc | 237 ++++++++ .../src/hicn/transport/core/socket_connector.h | 89 +++ .../src/hicn/transport/core/test/CMakeLists.txt | 10 + .../hicn/transport/core/test/test_core_manifest.cc | 296 ++++++++++ .../src/hicn/transport/core/vpp_binary_api.c | 221 ++++++++ .../src/hicn/transport/core/vpp_binary_api.h | 64 +++ .../hicn/transport/core/vpp_binary_api_internal.h | 61 ++ .../hicn/transport/core/vpp_forwarder_interface.cc | 184 ++++++ .../hicn/transport/core/vpp_forwarder_interface.h | 68 +++ 54 files changed, 7747 insertions(+) create mode 100755 libtransport/src/hicn/transport/core/CMakeLists.txt create mode 100755 libtransport/src/hicn/transport/core/connector.cc create mode 100755 libtransport/src/hicn/transport/core/connector.h create mode 100755 libtransport/src/hicn/transport/core/content_object.cc create mode 100755 libtransport/src/hicn/transport/core/content_object.h create mode 100755 libtransport/src/hicn/transport/core/facade.h create mode 100755 libtransport/src/hicn/transport/core/forwarder_interface.h create mode 100755 libtransport/src/hicn/transport/core/hicn_binary_api.c create mode 100755 libtransport/src/hicn/transport/core/hicn_binary_api.h create mode 100755 libtransport/src/hicn/transport/core/hicn_forwarder_interface.cc create mode 100755 libtransport/src/hicn/transport/core/hicn_forwarder_interface.h create mode 100755 libtransport/src/hicn/transport/core/hicn_memif_api.c create mode 100755 libtransport/src/hicn/transport/core/interest.cc create mode 100755 libtransport/src/hicn/transport/core/interest.h create mode 100755 libtransport/src/hicn/transport/core/key_locator.cc create mode 100755 libtransport/src/hicn/transport/core/key_locator.h create mode 100755 libtransport/src/hicn/transport/core/key_locator_type.h create mode 100755 libtransport/src/hicn/transport/core/manifest.cc create mode 100755 libtransport/src/hicn/transport/core/manifest.h create mode 100755 libtransport/src/hicn/transport/core/manifest_format.h create mode 100755 libtransport/src/hicn/transport/core/manifest_format_fixed.cc create mode 100755 libtransport/src/hicn/transport/core/manifest_format_fixed.h create mode 100755 libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.cc create mode 100755 libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.h create mode 100755 libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.cc create mode 100755 libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.h create mode 100755 libtransport/src/hicn/transport/core/manifest_inline.h create mode 100755 libtransport/src/hicn/transport/core/memif_binary_api.c create mode 100755 libtransport/src/hicn/transport/core/memif_binary_api.h create mode 100755 libtransport/src/hicn/transport/core/memif_connector.cc create mode 100755 libtransport/src/hicn/transport/core/memif_connector.h create mode 100755 libtransport/src/hicn/transport/core/name.cc create mode 100755 libtransport/src/hicn/transport/core/name.h create mode 100755 libtransport/src/hicn/transport/core/packet.cc create mode 100755 libtransport/src/hicn/transport/core/packet.h create mode 100755 libtransport/src/hicn/transport/core/payload_type.h create mode 100755 libtransport/src/hicn/transport/core/pending_interest.cc create mode 100755 libtransport/src/hicn/transport/core/pending_interest.h create mode 100755 libtransport/src/hicn/transport/core/portal.h create mode 100755 libtransport/src/hicn/transport/core/prefix.cc create mode 100755 libtransport/src/hicn/transport/core/prefix.h create mode 100755 libtransport/src/hicn/transport/core/raw_socket_connector.cc create mode 100755 libtransport/src/hicn/transport/core/raw_socket_connector.h create mode 100755 libtransport/src/hicn/transport/core/raw_socket_interface.cc create mode 100755 libtransport/src/hicn/transport/core/raw_socket_interface.h create mode 100755 libtransport/src/hicn/transport/core/socket_connector.cc create mode 100755 libtransport/src/hicn/transport/core/socket_connector.h create mode 100755 libtransport/src/hicn/transport/core/test/CMakeLists.txt create mode 100755 libtransport/src/hicn/transport/core/test/test_core_manifest.cc create mode 100755 libtransport/src/hicn/transport/core/vpp_binary_api.c create mode 100755 libtransport/src/hicn/transport/core/vpp_binary_api.h create mode 100755 libtransport/src/hicn/transport/core/vpp_binary_api_internal.h create mode 100755 libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc create mode 100755 libtransport/src/hicn/transport/core/vpp_forwarder_interface.h (limited to 'libtransport/src/hicn/transport/core') diff --git a/libtransport/src/hicn/transport/core/CMakeLists.txt b/libtransport/src/hicn/transport/core/CMakeLists.txt new file mode 100755 index 000000000..c8dea8328 --- /dev/null +++ b/libtransport/src/hicn/transport/core/CMakeLists.txt @@ -0,0 +1,87 @@ +# Copyright (c) 2017-2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/content_object.h + ${CMAKE_CURRENT_SOURCE_DIR}/facade.h + ${CMAKE_CURRENT_SOURCE_DIR}/interest.h + ${CMAKE_CURRENT_SOURCE_DIR}/key_locator.h + ${CMAKE_CURRENT_SOURCE_DIR}/key_locator_type.h + ${CMAKE_CURRENT_SOURCE_DIR}/socket_connector.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}/name.h + ${CMAKE_CURRENT_SOURCE_DIR}/packet.h + ${CMAKE_CURRENT_SOURCE_DIR}/payload_type.h + ${CMAKE_CURRENT_SOURCE_DIR}/pending_interest.h + ${CMAKE_CURRENT_SOURCE_DIR}/portal.h + ${CMAKE_CURRENT_SOURCE_DIR}/prefix.h + ${CMAKE_CURRENT_SOURCE_DIR}/connector.h + ${CMAKE_CURRENT_SOURCE_DIR}/socket_connector.h + ${CMAKE_CURRENT_SOURCE_DIR}/forwarder_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.h +) + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/content_object.cc + ${CMAKE_CURRENT_SOURCE_DIR}/interest.cc + ${CMAKE_CURRENT_SOURCE_DIR}/key_locator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/socket_connector.cc + ${CMAKE_CURRENT_SOURCE_DIR}/pending_interest.cc + ${CMAKE_CURRENT_SOURCE_DIR}/packet.cc + ${CMAKE_CURRENT_SOURCE_DIR}/name.cc + ${CMAKE_CURRENT_SOURCE_DIR}/prefix.cc + ${CMAKE_CURRENT_SOURCE_DIR}/socket_connector.cc + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_interface.cc + ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format_fixed.cc + ${CMAKE_CURRENT_SOURCE_DIR}/connector.cc +) + +if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + if (BUILD_WITH_VPP OR BUILD_VPP_PLUGIN) + list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_binary_api.h + ${CMAKE_CURRENT_SOURCE_DIR}/vpp_binary_api.h + ${CMAKE_CURRENT_SOURCE_DIR}/memif_binary_api.h + ) + + list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.cc + ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.cc + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_binary_api.c + ${CMAKE_CURRENT_SOURCE_DIR}/vpp_binary_api.c + ${CMAKE_CURRENT_SOURCE_DIR}/memif_binary_api.c + ) + endif() + + list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_connector.h + ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_interface.h + ) + + list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_connector.cc + ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_interface.cc + ) +endif() + +set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/connector.cc b/libtransport/src/hicn/transport/core/connector.cc new file mode 100755 index 000000000..ff567d78a --- /dev/null +++ b/libtransport/src/hicn/transport/core/connector.cc @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace transport { + +namespace core { + +std::once_flag Connector::init_flag_; + +Connector::Connector() : packet_pool_() { init(); } + +void Connector::init() { increasePoolSize(); } + +void Connector::increasePoolSize(std::size_t size) { + // Allocate space for receiving packets + const auto capacity = packet_size * size; + uint8_t *buffer = static_cast(malloc(capacity)); + std::unique_ptr buffer0 = + utils::MemBuf::takeOwnership(buffer, capacity, 0, nullptr, nullptr, true); + + for (std::size_t i = 1; i < size; i++) { + auto b = buffer0->cloneOne(); + b->advance(i * packet_size); + packet_pool_.add(b.release()); + } +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/connector.h b/libtransport/src/hicn/transport/core/connector.h new file mode 100755 index 000000000..14201879c --- /dev/null +++ b/libtransport/src/hicn/transport/core/connector.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace transport { + +namespace core { + +enum class ConnectorType : uint8_t { + SOCKET_CONNECTOR, + RAW_SOCKET_CONNECTOR, + VPP_CONNECTOR, +}; + +static constexpr std::size_t packet_size = 2000; +static constexpr std::size_t queue_size = 4096; +static constexpr std::size_t packet_pool_size = 4096; + +using PacketRing = utils::CircularFifo; +using PacketQueue = std::deque; +using PacketReceivedCallback = std::function; +using OnReconnect = std::function; +using PacketSentCallback = std::function; + +class Connector { + public: + Connector(); + + virtual ~Connector() = default; + + virtual void send(const Packet::MemBufPtr &packet) = 0; + + virtual void send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent = 0) = 0; + + virtual void close() = 0; + + virtual void enableBurst() = 0; + + virtual void state() = 0; + + protected: + void increasePoolSize(std::size_t size = packet_pool_size); + + TRANSPORT_ALWAYS_INLINE utils::ObjectPool::Ptr getPacket() { + auto result = packet_pool_.get(); + + while (TRANSPORT_EXPECT_FALSE(!result.first)) { + // Add packets to the pool + increasePoolSize(); + result = packet_pool_.get(); + } + + result.second->clear(); + return std::move(result.second); + } + + private: + void init(); + + protected: + static std::once_flag init_flag_; + utils::ObjectPool packet_pool_; + PacketQueue output_buffer_; +}; +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/content_object.cc b/libtransport/src/hicn/transport/core/content_object.cc new file mode 100755 index 000000000..dc2056582 --- /dev/null +++ b/libtransport/src/hicn/transport/core/content_object.cc @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +extern "C" { +TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") +#include +} + +#include +#include + +namespace transport { + +namespace core { + +ContentObject::ContentObject(const Name &name, Packet::Format format) + : Packet(format) { + if (TRANSPORT_EXPECT_FALSE( + hicn_data_set_name(format, (hicn_header_t *)packet_start_, + name.getStructReference()) < 0)) { + throw errors::RuntimeException("Error filling the packet name."); + } + + if (TRANSPORT_EXPECT_FALSE( + hicn_data_get_name(format_, (hicn_header_t *)packet_start_, + name_.getStructReference()) < 0)) { + throw errors::MalformedPacketException(); + } +} + +ContentObject::ContentObject(hicn_format_t format) + : ContentObject(Packet::base_name, format) {} + +ContentObject::ContentObject(const Name &name, hicn_format_t format, + const uint8_t *payload, std::size_t size) + : ContentObject(name, format) { + appendPayload(payload, size); +} + +ContentObject::ContentObject(const uint8_t *buffer, std::size_t size) + : Packet(buffer, size) { + if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_, + name_.getStructReference()) < 0) { + throw errors::RuntimeException("Error getting name from content object."); + } +} + +ContentObject::ContentObject(MemBufPtr &&buffer) : Packet(std::move(buffer)) { + if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_, + name_.getStructReference()) < 0) { + throw errors::RuntimeException("Error getting name from content object."); + } +} + +ContentObject::ContentObject(ContentObject &&other) : Packet(std::move(other)) { + name_ = std::move(other.name_); + + if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_, + name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } +} + +ContentObject::~ContentObject() {} + +const Name &ContentObject::getName() const { + if (!name_) { + if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_, + (hicn_name_t *)name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } + } + + return name_; +} + +ContentObject &ContentObject::setName(const Name &name) { + if (hicn_data_set_name(format_, (hicn_header_t *)packet_start_, + name.getStructReference()) < 0) { + throw errors::RuntimeException("Error setting content object name."); + } + + if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_, + name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } + + return *this; +} + +void ContentObject::setName(Name &&name) { + if (hicn_data_set_name(format_, (hicn_header_t *)packet_start_, + name.getStructReference()) < 0) { + throw errors::RuntimeException( + "Error getting the payload length from content object."); + } + + if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_, + name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } +} + +uint32_t ContentObject::getPathLabel() const { + uint32_t path_label; + if (hicn_data_get_path_label((hicn_header_t *)packet_start_, &path_label) < + 0) { + throw errors::RuntimeException( + "Error retrieving the path label from content object"); + } + + return path_label; +} + +ContentObject &ContentObject::setPathLabel(uint32_t path_label) { + if (hicn_data_set_path_label((hicn_header_t *)packet_start_, path_label) < + 0) { + throw errors::RuntimeException( + "Error setting the path label from content object"); + } + + return *this; +} + +void ContentObject::setLocator(const ip_address_t &ip_address) { + if (hicn_data_set_locator(format_, (hicn_header_t *)packet_start_, + &ip_address) < 0) { + throw errors::RuntimeException("Error setting content object locator"); + } + + return; +} + +ip_address_t ContentObject::getLocator() const { + ip_address_t ip; + + if (hicn_data_get_locator(format_, (hicn_header_t *)packet_start_, &ip) < 0) { + throw errors::RuntimeException("Error getting content object locator."); + } + + return ip; +} + +void ContentObject::resetForHash() { + if (hicn_data_reset_for_hash( + format_, reinterpret_cast(packet_start_)) < 0) { + throw errors::RuntimeException( + "Error resetting content object fields for hash computation."); + } +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/content_object.h b/libtransport/src/hicn/transport/core/content_object.h new file mode 100755 index 000000000..c85259f20 --- /dev/null +++ b/libtransport/src/hicn/transport/core/content_object.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace transport { + +namespace core { + +// This class is used just to transfer buffer pointers +// without making a copy, as std::vector<> would do + +class ContentObject : public Packet { + public: + using Ptr = utils::ObjectPool::Ptr; + using HICNContentObject = hicn_header_t; + + ContentObject(Packet::Format format = HF_INET6_TCP); + + ContentObject(const Name &name, Packet::Format format = HF_INET6_TCP); + + ContentObject(const Name &name, hicn_format_t format, const uint8_t *payload, + std::size_t payload_size); + + ContentObject(const uint8_t *buffer, std::size_t size); + ContentObject(MemBufPtr &&buffer); + + ContentObject(const ContentObject &content_object) = delete; + + ContentObject(ContentObject &&content_object); + + ~ContentObject() override; + + const Name &getName() const; + + ContentObject &setName(const Name &name); + + void setName(Name &&name); + + uint32_t getPathLabel() const; + + ContentObject &setPathLabel(uint32_t path_label); + + void setLocator(const ip_address_t &ip_address) override; + + ip_address_t getLocator() const override; + + private: + void resetForHash() override; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/facade.h b/libtransport/src/hicn/transport/core/facade.h new file mode 100755 index 000000000..c28c84671 --- /dev/null +++ b/libtransport/src/hicn/transport/core/facade.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#ifdef __linux__ +#ifndef __ANDROID__ +#include +#ifdef __vpp__ +#include +#endif +#endif +#endif + +namespace transport { + +namespace core { + +using HicnForwarderPortal = Portal; + +#ifdef __linux__ +#ifndef __ANDROID_API__ +using RawSocketPortal = Portal; +#endif +#ifdef __vpp__ +using VPPForwarderPortal = Portal; +#endif +#endif + +using ContentObjectManifest = core::ManifestInline; +using InterestManifest = core::ManifestInline; + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/hicn/transport/core/forwarder_interface.h b/libtransport/src/hicn/transport/core/forwarder_interface.h new file mode 100755 index 000000000..e7b6fb1a6 --- /dev/null +++ b/libtransport/src/hicn/transport/core/forwarder_interface.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include + +namespace transport { + +namespace core { + +typedef struct { + uint64_t rx_packets; + uint64_t tx_packets; + uint64_t rx_bytes; + uint64_t tx_bytes; + uint64_t rx_errors; + uint64_t tx_errors; +} Counters; + +template +class ForwarderInterface { + static_assert(std::is_base_of::value, + "T must inherit from connector!"); + + static constexpr uint32_t standard_cs_reserved = 5000; + + protected: + ForwarderInterface(ConnectorType &c) + : connector_(c), + inet_address_({}), + inet6_address_({}), + mtu_(1500), + output_interface_(""), + content_store_reserved_(standard_cs_reserved) { + inet_address_.family = AF_INET; + inet6_address_.family = AF_INET6; + } + + public: + static constexpr uint8_t ack_code = 102; + + virtual ~ForwarderInterface() {} + + TRANSPORT_ALWAYS_INLINE void connect(bool is_consumer = true) { + static_cast(*this).connect(is_consumer); + } + + TRANSPORT_ALWAYS_INLINE void registerRoute(Prefix &prefix) { + static_cast(*this).registerRoute(); + } + + TRANSPORT_ALWAYS_INLINE std::uint32_t getMtu() { + return static_cast(*this).getMtu(); + } + + template < + typename R, + typename = std::enable_if_t< + std::is_base_of>::value, + R>> + TRANSPORT_ALWAYS_INLINE void send(R &&packet) { + counters_.tx_packets++; + counters_.tx_bytes += packet.payloadSize() + packet.headerSize(); + + if (_is_ipv4(packet.getFormat())) { + packet.setLocator(inet_address_); + } else { + packet.setLocator(inet6_address_); + } + + packet.setChecksum(); + connector_.send(packet.data()); + } + + template + TRANSPORT_ALWAYS_INLINE void send(const uint8_t *packet, std::size_t len, + Handler &&packet_sent) { + // ASIO_COMPLETION_HANDLER_CHECK(Handler, packet_sent) type_check; + counters_.tx_packets++; + counters_.tx_bytes += len; + + // Perfect forwarding + connector_.send(packet, len, std::forward(packet_sent)); + } + + TRANSPORT_ALWAYS_INLINE void shutdown() { connector_.close(); } + + TRANSPORT_ALWAYS_INLINE Connector &getConnector() { return connector_; } + + TRANSPORT_ALWAYS_INLINE void setContentStoreSize(uint32_t cs_size) { + content_store_reserved_ = cs_size; + } + + TRANSPORT_ALWAYS_INLINE uint32_t getContentStoreSize() const { + return content_store_reserved_; + } + + TRANSPORT_ALWAYS_INLINE void setOutputInterface( + const std::string &interface) { + output_interface_ = interface; + } + + TRANSPORT_ALWAYS_INLINE std::string &getOutputInterface() { + return output_interface_; + } + + protected: + ConnectorType &connector_; + ip_address_t inet_address_; + ip_address_t inet6_address_; + uint16_t mtu_; + std::string output_interface_; + uint32_t content_store_reserved_; + Counters counters_; +}; + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/hicn/transport/core/hicn_binary_api.c b/libtransport/src/hicn/transport/core/hicn_binary_api.c new file mode 100755 index 000000000..c49cb5c88 --- /dev/null +++ b/libtransport/src/hicn/transport/core/hicn_binary_api.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#ifdef __vpp__ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +// uword unformat_sw_if_index (unformat_input_t * input, va_list * args); + +/* Declare message IDs */ +#include + +#define vl_endianfun /* define message structures */ +#define vl_print(handle, ...) +#define vl_printfun +#define vl_api_version(n, v) static u32 api_version = (v); +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list +#undef vl_api_version +#undef vl_printfun +#undef vl_endianfun + +///////////////////////////////////////////////////// +const char *HICN_ERROR_STRING[] = { +#define _(a, b, c) c, + foreach_hicn_error +#undef _ +}; +///////////////////////////////////////////////////// + +#define POINTER_MAP_SIZE 32 +static void *global_pointers_map[POINTER_MAP_SIZE]; +static uint8_t global_pointers_map_index = 0; + +#define CONTEXT_SAVE(pointer, mp) \ + do { \ + global_pointers_map[global_pointers_map_index] = pointer; \ + mp->context = global_pointers_map_index++; \ + global_pointers_map_index %= POINTER_MAP_SIZE; \ + } while (0); + +#define CONTEXT_GET(mp, pointer) \ + do { \ + pointer = global_pointers_map[mp->context]; \ + } while (0); + +/* + * Table of message reply handlers, must include boilerplate handlers + * we just generated + */ +#define foreach_hicn_api_reply_msg \ + _(HICN_API_REGISTER_PROD_APP_REPLY, hicn_api_register_prod_app_reply) \ + _(HICN_API_REGISTER_CONS_APP_REPLY, hicn_api_register_cons_app_reply) \ + _(HICN_API_ROUTE_NHOPS_ADD_REPLY, hicn_api_route_nhops_add_reply) + +int hicn_binary_api_register_prod_app( + vpp_plugin_binary_api_t *api, hicn_producer_input_params *input_params, + hicn_producer_output_params *output_params) { + vl_api_hicn_api_register_prod_app_t *mp; + vpp_plugin_binary_api_t *hm = api; + api->vpp_api->user_param = output_params; + + /* Construct the API message */ + M(HICN_API_REGISTER_PROD_APP, mp); + + CONTEXT_SAVE(api, mp) + + mp->len = (u8)input_params->prefix.prefix_length; + mp->swif = clib_host_to_net_u32(input_params->swif); + mp->cs_reserved = clib_host_to_net_u32(input_params->cs_reserved); + + mp->prefix[0] = clib_host_to_net_u64(input_params->prefix.ip6.as_u64[0]); + mp->prefix[1] = clib_host_to_net_u64(input_params->prefix.ip6.as_u64[1]); + + TRANSPORT_LOGI("Prefix length: %u", mp->len); + TRANSPORT_LOGI("Memif ID: %u", mp->swif); + + return vpp_binary_api_send_request_wait_reply(api->vpp_api, mp); +} + +static void vl_api_hicn_api_register_prod_app_reply_t_handler( + vl_api_hicn_api_register_prod_app_reply_t *mp) { + vpp_plugin_binary_api_t *binary_api; + CONTEXT_GET(mp, binary_api); + hicn_producer_output_params *params = binary_api->vpp_api->user_param; + + binary_api->vpp_api->ret_val = clib_net_to_host_u32(mp->retval); + params->cs_reserved = mp->cs_reserved; + params->prod_addr.ip6.as_u64[0] = mp->prod_addr[0]; + params->prod_addr.ip6.as_u64[1] = mp->prod_addr[1]; + params->face_id = clib_net_to_host_u32(mp->faceid); + + TRANSPORT_LOGI("ret :%s", get_error_string(binary_api->vpp_api->ret_val)); + + vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api); +} + +int hicn_binary_api_register_cons_app( + vpp_plugin_binary_api_t *api, hicn_consumer_input_params *input_params, + hicn_consumer_output_params *output_params) { + vl_api_hicn_api_register_cons_app_t *mp; + vpp_plugin_binary_api_t *hm = api; + + hm->vpp_api->user_param = output_params; + + /* Construct the API message */ + M(HICN_API_REGISTER_CONS_APP, mp); + + mp->swif = clib_host_to_net_u32(input_params->swif); + + CONTEXT_SAVE(api, mp) + + TRANSPORT_LOGI("Message created"); + + return vpp_binary_api_send_request_wait_reply(api->vpp_api, mp); +} + +static void vl_api_hicn_api_register_cons_app_reply_t_handler( + vl_api_hicn_api_register_cons_app_reply_t *mp) { + vpp_plugin_binary_api_t *binary_api; + CONTEXT_GET(mp, binary_api); + hicn_consumer_output_params *params = binary_api->vpp_api->user_param; + + binary_api->vpp_api->ret_val = clib_net_to_host_u32(mp->retval); + + params->src4.ip4.as_u32 = clib_net_to_host_u32(mp->src_addr4); + params->src6.ip6.as_u64[0] = clib_net_to_host_u64(mp->src_addr6[0]); + params->src6.ip6.as_u64[1] = clib_net_to_host_u64(mp->src_addr6[1]); + params->face_id = clib_host_to_net_u32(mp->faceid); + + vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api); +} + +int hicn_binary_api_register_route( + vpp_plugin_binary_api_t *api, + hicn_producer_set_route_params *input_params) { + vl_api_hicn_api_route_nhops_add_t *mp; + vpp_plugin_binary_api_t *hm = api; + + /* Construct the API message */ + M(HICN_API_ROUTE_NHOPS_ADD, mp); + + CONTEXT_SAVE(api, mp) + + mp->prefix[0] = input_params->prefix.ip6.as_u64[0]; + mp->prefix[1] = input_params->prefix.ip6.as_u64[1]; + mp->len = input_params->prefix.prefix_length; + mp->face_ids[0] = input_params->face_id; + mp->n_faces = 1; + + return vpp_binary_api_send_request_wait_reply(api->vpp_api, mp); +} + +static void vl_api_hicn_api_route_nhops_add_reply_t_handler( + vl_api_hicn_api_route_nhops_add_reply_t *mp) { + vpp_plugin_binary_api_t *binary_api; + CONTEXT_GET(mp, binary_api); + + binary_api->vpp_api->ret_val = clib_net_to_host_u32(mp->retval); + + vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api); +} + +static int hicn_binary_api_setup_handlers(vpp_plugin_binary_api_t *binary_api) { + vpp_plugin_binary_api_t *sm __attribute__((unused)) = binary_api; +#define _(N, n) \ + vl_msg_api_set_handlers(VL_API_##N + sm->msg_id_base, #n, \ + vl_api_##n##_t_handler, vl_noop_handler, \ + vl_api_##n##_t_endian, vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_hicn_api_reply_msg; +#undef _ + return 0; +} + +char *hicn_binary_api_get_error_string(int ret_val) { + return get_error_string(ret_val); +} + +vpp_plugin_binary_api_t *hicn_binary_api_init(vpp_binary_api_t *api) { + vpp_plugin_binary_api_t *ret = malloc(sizeof(vpp_plugin_binary_api_t)); + u8 *name = format(0, "hicn_%08x%c", api_version, 0); + ret->msg_id_base = vl_client_get_first_plugin_msg_id((char *)name); + ret->vpp_api = api; + ret->my_client_index = api->my_client_index; + hicn_binary_api_setup_handlers(ret); + return ret; +} + +#endif // __vpp__ diff --git a/libtransport/src/hicn/transport/core/hicn_binary_api.h b/libtransport/src/hicn/transport/core/hicn_binary_api.h new file mode 100755 index 000000000..752844153 --- /dev/null +++ b/libtransport/src/hicn/transport/core/hicn_binary_api.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#ifdef __vpp__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdint.h" + +typedef union { + uint8_t data[4]; + uint32_t data_u32; + /* Aliases. */ + uint8_t as_u8[4]; + uint16_t as_u16[2]; + uint32_t as_u32; +} ip4_address; + +typedef union { + uint8_t as_u8[16]; + uint16_t as_u16[8]; + uint32_t as_u32[4]; + uint64_t as_u64[2]; +} ip6_address; + +typedef enum { IP_TYPE_ANY, IP_TYPE_IP4, IP_TYPE_IP6 } ip46_type; + +typedef struct { + ip46_type type; + uint8_t prefix_length; + union { + ip4_address ip4; + ip6_address ip6; + }; +} ip46_address; + +typedef struct { + ip46_address prefix; + uint32_t swif; + uint32_t cs_reserved; +} hicn_producer_input_params; + +typedef struct { + uint32_t swif; +} hicn_consumer_input_params; + +typedef struct { + uint32_t cs_reserved; + ip46_address prod_addr; + uint32_t face_id; +} hicn_producer_output_params; + +typedef struct { + ip46_address src4; + ip46_address src6; + uint32_t face_id; +} hicn_consumer_output_params; + +typedef struct { + ip46_address prefix; + uint32_t face_id; +} hicn_producer_set_route_params; + +vpp_plugin_binary_api_t* hicn_binary_api_init(vpp_binary_api_t* api); + +int hicn_binary_api_register_prod_app( + vpp_plugin_binary_api_t* api, hicn_producer_input_params* input_params, + hicn_producer_output_params* output_params); + +int hicn_binary_api_register_cons_app( + vpp_plugin_binary_api_t* api, hicn_consumer_input_params* input_params, + hicn_consumer_output_params* output_params); + +int hicn_binary_api_register_route( + vpp_plugin_binary_api_t* api, hicn_producer_set_route_params* input_params); + +char* hicn_binary_api_get_error_string(int ret_val); + +#ifdef __cplusplus +} +#endif + +#endif // __vpp__ \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/hicn_forwarder_interface.cc b/libtransport/src/hicn/transport/core/hicn_forwarder_interface.cc new file mode 100755 index 000000000..03a294957 --- /dev/null +++ b/libtransport/src/hicn/transport/core/hicn_forwarder_interface.cc @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define ADDR_INET 1 +#define ADDR_INET6 2 +#define ADD_ROUTE 3 +#define REQUEST_LIGHT 100 + +union AddressLight { + uint32_t ipv4; + struct in6_addr ipv6; +}; + +typedef struct { + uint8_t message_type; + uint8_t command_id; + uint16_t length; + uint32_t seq_num; + char symbolic_or_connid[16]; + union AddressLight address; + uint16_t cost; + uint8_t address_type; + uint8_t len; +} RouteToSelfCommand; + +namespace transport { + +namespace core { + +HicnForwarderInterface::HicnForwarderInterface(SocketConnector &connector) + : ForwarderInterface(connector) {} + +HicnForwarderInterface::~HicnForwarderInterface() {} + +void HicnForwarderInterface::connect(bool is_consumer) { connector_.connect(); } + +void HicnForwarderInterface::registerRoute(Prefix &prefix) { + auto addr = prefix.toSockaddr(); + const char *identifier = {"SELF_ROUTE"}; + + // allocate command payload + RouteToSelfCommand *route_to_self = new RouteToSelfCommand(); + + // check and set IP address + if (addr->sa_family == AF_INET) { + route_to_self->address_type = ADDR_INET; + route_to_self->address.ipv4 = ((Sockaddr4 *)addr.get())->sin_addr.s_addr; + } else if (addr->sa_family == AF_INET6) { + route_to_self->address_type = ADDR_INET6; + route_to_self->address.ipv6 = ((Sockaddr6 *)addr.get())->sin6_addr; + } + + // Fill remaining payload fields + strcpy(route_to_self->symbolic_or_connid, identifier); + route_to_self->cost = 1; + route_to_self->len = prefix.getPrefixLength(); + + // Allocate and fill the header + route_to_self->command_id = ADD_ROUTE; + route_to_self->message_type = REQUEST_LIGHT; + route_to_self->length = 1; + // route_to_self->seq_num not needed for now + + send((uint8_t *)route_to_self, sizeof(RouteToSelfCommand), + [route_to_self]() { delete route_to_self; }); +} + +} // namespace core + +} // namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/hicn_forwarder_interface.h b/libtransport/src/hicn/transport/core/hicn_forwarder_interface.h new file mode 100755 index 000000000..e57fae105 --- /dev/null +++ b/libtransport/src/hicn/transport/core/hicn_forwarder_interface.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include + +namespace transport { + +namespace core { + +class HicnForwarderInterface + : public ForwarderInterface { + public: + union addressLight { + uint32_t ipv4; + struct in6_addr ipv6; + }; + + struct route_to_self_command { + uint8_t messageType; + uint8_t commandID; + uint16_t length; + uint32_t seqNum; + char symbolicOrConnid[16]; + union addressLight address; + uint16_t cost; + uint8_t addressType; + uint8_t len; + }; + + using route_to_self_command = struct route_to_self_command; + using ConnectorType = SocketConnector; + + HicnForwarderInterface(SocketConnector &connector); + + ~HicnForwarderInterface(); + + void connect(bool is_consumer); + + void registerRoute(Prefix &prefix); + + std::uint16_t getMtu() { return interface_mtu; } + + private: + static constexpr std::uint16_t interface_mtu = 1500; +}; + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/hicn/transport/core/hicn_memif_api.c b/libtransport/src/hicn/transport/core/hicn_memif_api.c new file mode 100755 index 000000000..e69de29bb diff --git a/libtransport/src/hicn/transport/core/interest.cc b/libtransport/src/hicn/transport/core/interest.cc new file mode 100755 index 000000000..ff4a5bb34 --- /dev/null +++ b/libtransport/src/hicn/transport/core/interest.cc @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +extern "C" { +TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") +#include +} + +#include +#include + +namespace transport { + +namespace core { + +Interest::Interest(const Name &interest_name, Packet::Format format) + : Packet(format) { + if (hicn_interest_set_name(format_, (hicn_header_t *)packet_start_, + interest_name.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } + + if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_, + name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } +} + +Interest::Interest(hicn_format_t format) : Interest(base_name, format) {} + +Interest::Interest(const uint8_t *buffer, std::size_t size) + : Packet(buffer, size) { + if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_, + name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } +} + +Interest::Interest(MemBufPtr &&buffer) : Packet(std::move(buffer)) { + if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_, + name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } +} + +Interest::Interest(Interest &&other_interest) + : Packet(std::move(other_interest)) { + name_ = std::move(other_interest.name_); +} + +Interest::~Interest() {} + +const Name &Interest::getName() const { + if (!name_) { + if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_, + (hicn_name_t *)name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } + } + + return name_; +} + +Name &Interest::getWritableName() { + if (!name_) { + if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_, + (hicn_name_t *)name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } + } + + return name_; +} + +Interest &Interest::setName(const Name &name) { + if (hicn_interest_set_name(format_, (hicn_header_t *)packet_start_, + name.getStructReference()) < 0) { + throw errors::RuntimeException("Error setting interest name."); + } + + if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_, + name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } + + return *this; +} + +Interest &Interest::setName(Name &&name) { + if (hicn_interest_set_name(format_, (hicn_header_t *)packet_start_, + name.getStructReference()) < 0) { + throw errors::RuntimeException("Error setting interest name."); + } + + if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_, + name_.getStructReference()) < 0) { + throw errors::MalformedPacketException(); + } + + return *this; +} + +void Interest::setLocator(const ip_address_t &ip_address) { + if (hicn_interest_set_locator(format_, (hicn_header_t *)packet_start_, + &ip_address) < 0) { + throw errors::RuntimeException("Error setting interest locator."); + } + + return; +} + +ip_address_t Interest::getLocator() const { + ip_address_t ip; + + if (hicn_interest_get_locator(format_, (hicn_header_t *)packet_start_, &ip) < + 0) { + throw errors::RuntimeException("Error getting interest locator."); + } + + return ip; +} + +void Interest::resetForHash() { + if (hicn_interest_reset_for_hash( + format_, reinterpret_cast(packet_start_)) < 0) { + throw errors::RuntimeException( + "Error resetting interest fields for hash computation."); + } +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/interest.h b/libtransport/src/hicn/transport/core/interest.h new file mode 100755 index 000000000..75fcba8eb --- /dev/null +++ b/libtransport/src/hicn/transport/core/interest.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +namespace transport { + +namespace core { + +class Interest + : public Packet /*, public std::enable_shared_from_this*/ { + public: + using Ptr = utils::ObjectPool::Ptr; + + Interest(Packet::Format format = HF_INET6_TCP); + + Interest(const Name &interest_name, Packet::Format format = HF_INET6_TCP); + + Interest(const uint8_t *buffer, std::size_t size); + Interest(MemBufPtr &&buffer); + + /* + * Enforce zero-copy. + */ + Interest(const Interest &other_interest) = delete; + Interest &operator=(const Interest &other_interest) = delete; + + Interest(Interest &&other_interest); + + ~Interest() override; + + const Name &getName() const; + + Name &getWritableName(); + + Interest &setName(const Name &name); + + Interest &setName(Name &&name); + + void setLocator(const ip_address_t &ip_address) override; + + ip_address_t getLocator() const override; + + private: + void resetForHash() override; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/key_locator.cc b/libtransport/src/hicn/transport/core/key_locator.cc new file mode 100755 index 000000000..509fc35ff --- /dev/null +++ b/libtransport/src/hicn/transport/core/key_locator.cc @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace transport { + +namespace core { + +KeyLocator::KeyLocator() : type_(KeyLocatorType::UNKNOWN) {} + +KeyLocator::KeyLocator(KeyLocatorType type, Name &name) + : type_(type), name_(name) {} + +Name &KeyLocator::getName() { return name_; } + +void KeyLocator::setName(Name &name) { name_ = name; } + +void KeyLocator::setType(KeyLocatorType type) { type_ = type; } + +KeyLocatorType KeyLocator::getType() { return type_; } + +void KeyLocator::clear() { + type_ = KeyLocatorType::UNKNOWN; + name_.clear(); +} + +} // end namespace core + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/key_locator.h b/libtransport/src/hicn/transport/core/key_locator.h new file mode 100755 index 000000000..ae3a4ab08 --- /dev/null +++ b/libtransport/src/hicn/transport/core/key_locator.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace transport { + +namespace core { + +class KeyLocator : public std::enable_shared_from_this { + public: + KeyLocator(); + + KeyLocator(KeyLocatorType type, Name &name); + + KeyLocatorType getType(); + + void setType(KeyLocatorType type); + + void setName(Name &name); + + Name &getName(); + + void clear(); + + private: + KeyLocatorType type_; + Name name_; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/key_locator_type.h b/libtransport/src/hicn/transport/core/key_locator_type.h new file mode 100755 index 000000000..0c84a43ca --- /dev/null +++ b/libtransport/src/hicn/transport/core/key_locator_type.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace transport { + +namespace core { + +enum Type { NAME = 0, KEY_DIGEST = 1, UNKNOWN = 255 }; + +typedef enum Type KeyLocatorType; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/manifest.cc b/libtransport/src/hicn/transport/core/manifest.cc new file mode 100755 index 000000000..3f890f3d0 --- /dev/null +++ b/libtransport/src/hicn/transport/core/manifest.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace transport { + +namespace core { + +std::string ManifestEncoding::manifest_type = std::string("manifest_type"); + +std::map 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 diff --git a/libtransport/src/hicn/transport/core/manifest.h b/libtransport/src/hicn/transport/core/manifest.h new file mode 100755 index 000000000..767addb2e --- /dev/null +++ b/libtransport/src/hicn/transport/core/manifest.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include + +namespace transport { + +namespace core { + +using typename core::Name; +using typename core::Packet; +using typename core::PayloadType; + +template +class Manifest : public Base { + static_assert(std::is_base_of::value, + "Base must inherit from packet!"); + + public: + using Encoder = typename FormatTraits::Encoder; + using Decoder = typename FormatTraits::Decoder; + + Manifest() + : packet_(new Base(HF_INET6_TCP_AH), nullptr), + encoder_(*packet_), + decoder_(*packet_) { + Base::setPayloadType(PayloadType::MANIFEST); + } + + Manifest(const core::Name& name) + : packet_(new Base(name, HF_INET6_TCP_AH), nullptr), + encoder_(*packet_), + decoder_(*packet_) { + Base::setPayloadType(PayloadType::MANIFEST); + } + + Manifest(typename Base::Ptr&& base) + : packet_(std::move(base)), encoder_(*packet_), decoder_(*packet_) { + Base::setPayloadType(PayloadType::MANIFEST); + } + + template + Manifest(T&& base) + : packet_(new Base(std::move(base)), nullptr), + encoder_(*packet_), + decoder_(*packet_) { + Base::setPayloadType(PayloadType::MANIFEST); + } + + virtual ~Manifest() = default; + + bool operator==(const Manifest& other) { + return this->packet_ == other.packet_; + } + + std::size_t estimateManifestSize(std::size_t additional_entries = 0) { + return static_cast(*this).estimateManifestSizeImpl( + additional_entries); + } + + /* + * After the call to encode, users MUST call clear before adding data + * to the manifest. + */ + Manifest& encode() { return static_cast(*this).encodeImpl(); } + + Manifest& decode() { + Manifest::decoder_.decode(); + + manifest_type_ = decoder_.getManifestType(); + hash_algorithm_ = decoder_.getHashAlgorithm(); + is_last_ = decoder_.getIsFinalManifest(); + + return static_cast(*this).decodeImpl(); + } + + static std::size_t getManifestHeaderSize() { + return Encoder::getManifestHeaderSize(); + } + + Manifest& setManifestType(ManifestType type) { + manifest_type_ = type; + encoder_.setManifestType(manifest_type_); + return *this; + } + + Manifest& setHashAlgorithm(HashAlgorithm hash_algorithm) { + hash_algorithm_ = hash_algorithm; + encoder_.setHashAlgorithm(hash_algorithm_); + return *this; + } + + HashAlgorithm getHashAlgorithm() { return hash_algorithm_; } + + ManifestType getManifestType() const { return manifest_type_; } + + bool isFinalManifest() const { return is_last_; } + + Manifest& setVersion(ManifestVersion version) { + encoder_.setVersion(version); + return *this; + } + + Manifest& setFinalBlockNumber(std::uint32_t final_block_number) { + encoder_.setFinalBlockNumber(final_block_number); + return *this; + } + + uint32_t getFinalBlockNumber() const { + return decoder_.getFinalBlockNumber(); + } + + ManifestVersion getVersion() const { return decoder_.getVersion(); } + + Manifest& setFinalManifest(bool is_final_manifest) { + encoder_.setIsFinalManifest(is_final_manifest); + is_last_ = is_final_manifest; + return *this; + } + + Manifest& clear() { + encoder_.clear(); + decoder_.clear(); + return *this; + } + + void setSignatureSize(std::size_t size_bits) { + Packet::setSignatureSize(size_bits); + encoder_.update(); + } + + typename Base::Ptr&& getPacket() { return std::move(packet_); } + + protected: + typename Base::Ptr packet_; + ManifestType manifest_type_; + HashAlgorithm hash_algorithm_; + bool is_last_; + + Encoder encoder_; + Decoder decoder_; +}; + +} // end namespace core + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/manifest_format.h b/libtransport/src/hicn/transport/core/manifest_format.h new file mode 100755 index 000000000..1dcf013dc --- /dev/null +++ b/libtransport/src/hicn/transport/core/manifest_format.h @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace transport { + +namespace core { + +enum class ManifestFields : uint8_t { + VERSION, + HASH_ALGORITHM, + SEGMENT_CALCULATION_STRATEGY, + FINAL_MANIFEST, + NAME_HASH_LIST, + BASE_NAME +}; + +enum class ManifestVersion : uint8_t { + VERSION_1 = 1, +}; + +enum class ManifestType : uint8_t { + INLINE_MANIFEST = 1, + FINAL_CHUNK_NUMBER = 2, + FLIC_MANIFEST = 3, +}; + +enum class HashAlgorithm : uint8_t { + SHA_256 = static_cast(utils::CryptoHashType::SHA_256), + SHA_512 = static_cast(utils::CryptoHashType::SHA_512), + CRC32C = static_cast(utils::CryptoHashType::CRC32C), +}; + +enum class NextSegmentCalculationStrategy : uint8_t { + INCREMENTAL = 1, +}; + +template +struct format_traits { + using Encoder = typename T::Encoder; + using Decoder = typename T::Decoder; + using HashType = typename T::HashType; + using HashList = typename T::HashList; +}; + +class Packet; + +template +class ManifestEncoder { + public: + virtual ~ManifestEncoder() = default; + + ManifestEncoder encode() { + return static_cast(*this).encodeImpl(); + } + + ManifestEncoder& clear() { + return static_cast(*this).clearImpl(); + } + + ManifestEncoder& setManifestType(ManifestType type) { + return static_cast(*this).setManifestTypeImpl(type); + } + + ManifestEncoder& setHashAlgorithm(HashAlgorithm hash) { + return static_cast(*this).setHashAlgorithmImpl(hash); + } + + ManifestEncoder& setFinalChunkNumber(uint32_t final_chunk) { + return static_cast(*this).setFinalChunkImpl(final_chunk); + } + + ManifestEncoder& setNextSegmentCalculationStrategy( + NextSegmentCalculationStrategy strategy) { + return static_cast(*this) + .setNextSegmentCalculationStrategyImpl(strategy); + } + + template < + typename T, + typename = std::enable_if_t>, core::Name>::value>> + ManifestEncoder& setBaseName(T&& name) { + return static_cast(*this).setBaseNameImpl(name); + } + + template + ManifestEncoder& addSuffixAndHash(uint32_t suffix, Hash&& hash) { + return static_cast(*this).addSuffixAndHashImpl( + suffix, std::forward(hash)); + } + + ManifestEncoder& setIsFinalManifest(bool is_last) { + return static_cast(*this).setIsFinalManifestImpl(is_last); + } + + ManifestEncoder& setVersion(ManifestVersion version) { + return static_cast(*this).setVersionImpl(version); + } + + std::size_t estimateSerializedLength(std::size_t number_of_entries) { + return static_cast(*this).estimateSerializedLengthImpl( + number_of_entries); + } + + ManifestEncoder& update() { + return static_cast(*this).updateImpl(); + } + + ManifestEncoder& setFinalBlockNumber(std::uint32_t final_block_number) { + return static_cast(*this).setFinalBlockNumberImpl( + final_block_number); + } + + static std::size_t getManifestHeaderSize() { + return Implementation::getManifestHeaderSizeImpl(); + } +}; + +template +class ManifestDecoder { + public: + virtual ~ManifestDecoder() = default; + + ManifestDecoder& clear() { + return static_cast(*this).clearImpl(); + } + + void decode() { static_cast(*this).decodeImpl(); } + + ManifestType getManifestType() const { + return static_cast(*this).getManifestTypeImpl(); + } + + HashAlgorithm getHashAlgorithm() const { + return static_cast(*this).getHashAlgorithmImpl(); + } + + uint32_t getFinalChunkNumber() const { + return static_cast(*this).getFinalChunkImpl(); + } + + NextSegmentCalculationStrategy getNextSegmentCalculationStrategy() const { + return static_cast(*this) + .getNextSegmentCalculationStrategyImpl(); + } + + core::Name getBaseName() const { + return static_cast(*this).getBaseNameImpl(); + } + + auto getSuffixHashList() { + return static_cast(*this).getSuffixHashListImpl(); + } + + bool getIsFinalManifest() const { + return static_cast(*this).getIsFinalManifestImpl(); + } + + ManifestVersion getVersion() const { + return static_cast(*this).getVersionImpl(); + } + + std::size_t estimateSerializedLength(std::size_t number_of_entries) const { + return static_cast(*this) + .estimateSerializedLengthImpl(number_of_entries); + } + + uint32_t getFinalBlockNumber() const { + return static_cast(*this).getFinalBlockNumberImpl(); + } +}; + +} // namespace core + +} // namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/manifest_format_fixed.cc b/libtransport/src/hicn/transport/core/manifest_format_fixed.cc new file mode 100755 index 000000000..f26f20adb --- /dev/null +++ b/libtransport/src/hicn/transport/core/manifest_format_fixed.cc @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace transport { + +namespace core { + +// TODO use preallocated pool of membufs +FixedManifestEncoder::FixedManifestEncoder(Packet& packet) + : packet_(packet), + max_size_(Packet::default_mtu - packet_.headerSize()), + manifest_( + utils::MemBuf::create(Packet::default_mtu - packet_.headerSize())), + manifest_header_( + reinterpret_cast(manifest_->writableData())), + manifest_entries_(reinterpret_cast( + manifest_->writableData() + sizeof(ManifestHeader))), + current_entry_(0) {} + +FixedManifestEncoder::~FixedManifestEncoder() {} + +FixedManifestEncoder& FixedManifestEncoder::encodeImpl() { + packet_.appendPayload(std::move(manifest_)); + return *this; +} + +FixedManifestEncoder& FixedManifestEncoder::clearImpl() { + manifest_ = utils::MemBuf::create(Packet::default_mtu - packet_.headerSize()); + return *this; +} + +FixedManifestEncoder& FixedManifestEncoder::setHashAlgorithmImpl( + HashAlgorithm algorithm) { + manifest_header_->hash_algorithm = static_cast(algorithm); + return *this; +} + +FixedManifestEncoder& FixedManifestEncoder::setManifestTypeImpl( + ManifestType manifest_type) { + manifest_header_->manifest_type = static_cast(manifest_type); + return *this; +} + +FixedManifestEncoder& +FixedManifestEncoder::setNextSegmentCalculationStrategyImpl( + NextSegmentCalculationStrategy strategy) { + manifest_header_->next_segment_strategy = static_cast(strategy); + return *this; +} + +FixedManifestEncoder& FixedManifestEncoder::setBaseNameImpl( + const core::Name& base_name) { + base_name.copyToDestination( + reinterpret_cast(&manifest_header_->prefix[0]), false); + manifest_header_->flags.ipv6 = + base_name.getAddressFamily() == AF_INET6 ? 1_U8 : 0_U8; + return *this; +} + +FixedManifestEncoder& FixedManifestEncoder::addSuffixAndHashImpl( + uint32_t suffix, const utils::CryptoHash& hash) { + auto _hash = hash.getDigest(); + addSuffixHashBytes(suffix, _hash.data(), _hash.length()); + return *this; +} + +void FixedManifestEncoder::addSuffixHashBytes(uint32_t suffix, + const uint8_t* hash, + std::size_t length) { + manifest_entries_[current_entry_].suffix = utils::hton(suffix); + // std::copy(hash, hash + length, + // manifest_entries_[current_entry_].hash); + std::memcpy( + reinterpret_cast(manifest_entries_[current_entry_].hash), hash, + length); + + manifest_header_->number_of_entries++; + current_entry_++; + + if (TRANSPORT_EXPECT_FALSE(estimateSerializedLengthImpl() > max_size_)) { + throw errors::RuntimeException("Manifest size exceeded the packet MTU!"); + } +} + +FixedManifestEncoder& FixedManifestEncoder::setIsFinalManifestImpl( + bool is_last) { + manifest_header_->flags.is_last = static_cast(is_last); + return *this; +} + +FixedManifestEncoder& FixedManifestEncoder::setVersionImpl( + ManifestVersion version) { + manifest_header_->version = static_cast(version); + return *this; +} + +std::size_t FixedManifestEncoder::estimateSerializedLengthImpl( + std::size_t additional_entries) { + return sizeof(ManifestHeader) + + (manifest_header_->number_of_entries + additional_entries) * + sizeof(ManifestEntry); +} + +FixedManifestEncoder& FixedManifestEncoder::updateImpl() { + max_size_ = Packet::default_mtu - packet_.headerSize(); + manifest_header_ = reinterpret_cast( + const_cast(packet_.getPayload().data())); + manifest_entries_ = reinterpret_cast( + const_cast(packet_.getPayload().data()) + + sizeof(ManifestHeader)); + return *this; +} + +FixedManifestEncoder& FixedManifestEncoder::setFinalBlockNumberImpl( + std::uint32_t final_block_number) { + manifest_header_->final_block_number = utils::hton(final_block_number); + return *this; +} + +std::size_t FixedManifestEncoder::getManifestHeaderSizeImpl() { + return sizeof(ManifestHeader); +} + +FixedManifestDecoder::FixedManifestDecoder(Packet& packet) + : packet_(packet), + manifest_header_(reinterpret_cast( + const_cast(packet_.getPayload().data()))), + manifest_entries_(reinterpret_cast( + const_cast(packet_.getPayload().data()) + + sizeof(ManifestHeader))) {} + +FixedManifestDecoder::~FixedManifestDecoder() {} + +void FixedManifestDecoder::decodeImpl() { + std::size_t packet_size = packet_.payloadSize(); + + if (packet_size < sizeof(ManifestHeader) || + packet_size < estimateSerializedLengthImpl()) { + throw errors::RuntimeException( + "The packet does not match expected manifest size."); + } +} + +FixedManifestDecoder& FixedManifestDecoder::clearImpl() { return *this; } + +ManifestType FixedManifestDecoder::getManifestTypeImpl() const { + return static_cast(manifest_header_->manifest_type); +} + +HashAlgorithm FixedManifestDecoder::getHashAlgorithmImpl() const { + return static_cast(manifest_header_->hash_algorithm); +} + +NextSegmentCalculationStrategy +FixedManifestDecoder::getNextSegmentCalculationStrategyImpl() const { + return static_cast( + manifest_header_->next_segment_strategy); +} + +typename Fixed::SuffixList FixedManifestDecoder::getSuffixHashListImpl() { + typename Fixed::SuffixList hash_list; + + for (int i = 0; i < manifest_header_->number_of_entries; i++) { + hash_list.insert(hash_list.end(), + std::make_pair(utils::ntoh(manifest_entries_[i].suffix), + reinterpret_cast( + &manifest_entries_[i].hash[0]))); + } + + return hash_list; +} + +core::Name FixedManifestDecoder::getBaseNameImpl() const { + if (static_cast(manifest_header_->flags.ipv6)) { + return core::Name(AF_INET6, + reinterpret_cast(&manifest_header_->prefix)); + } else { + return core::Name(AF_INET, + reinterpret_cast(&manifest_header_->prefix)); + } +} + +bool FixedManifestDecoder::getIsFinalManifestImpl() const { + return static_cast(manifest_header_->flags.is_last); +} + +ManifestVersion FixedManifestDecoder::getVersionImpl() const { + return static_cast(manifest_header_->version); +} + +std::size_t FixedManifestDecoder::estimateSerializedLengthImpl( + std::size_t additional_entries) const { + return sizeof(ManifestHeader) + + (additional_entries + manifest_header_->number_of_entries) * + sizeof(ManifestEntry); +} + +uint32_t FixedManifestDecoder::getFinalBlockNumberImpl() const { + return utils::ntoh(manifest_header_->final_block_number); +} + +} // end namespace core + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/manifest_format_fixed.h b/libtransport/src/hicn/transport/core/manifest_format_fixed.h new file mode 100755 index 000000000..66825e2f4 --- /dev/null +++ b/libtransport/src/hicn/transport/core/manifest_format_fixed.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +namespace transport { + +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| MType |HashAlg|NextStr| Flags |NumberOfEntries| +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Final Block Number | +// +---------------------------------------------------------------| +// | | +// + + +// | | +// + Prefix + +// | | +// + + +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Suffix | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Hash Value | +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +class FixedManifestEncoder; +class FixedManifestDecoder; +class Packet; + +struct Fixed { + using Encoder = FixedManifestEncoder; + using Decoder = FixedManifestDecoder; + using HashType = utils::CryptoHash; + using SuffixList = std::list>; +}; + +struct Flags { + std::uint8_t ipv6 : 1; + std::uint8_t is_last : 1; + std::uint8_t unused : 6; +}; + +struct ManifestEntry { + std::uint32_t suffix; + std::uint32_t hash[8]; +}; + +struct ManifestHeader { + std::uint8_t version : 4; + std::uint8_t manifest_type : 4; + std::uint8_t hash_algorithm : 4; + std::uint8_t next_segment_strategy : 4; + Flags flags; + std::uint8_t number_of_entries; + std::uint32_t final_block_number; + std::uint32_t prefix[4]; + ManifestEntry entries[0]; +}; + +static const constexpr std::uint8_t manifest_version = 1; + +class FixedManifestEncoder : public ManifestEncoder { + public: + FixedManifestEncoder(Packet& packet); + + ~FixedManifestEncoder(); + + FixedManifestEncoder& encodeImpl(); + + FixedManifestEncoder& clearImpl(); + + FixedManifestEncoder& setManifestTypeImpl(ManifestType manifest_type); + + FixedManifestEncoder& setHashAlgorithmImpl(HashAlgorithm algorithm); + + FixedManifestEncoder& setNextSegmentCalculationStrategyImpl( + NextSegmentCalculationStrategy strategy); + + FixedManifestEncoder& setBaseNameImpl(const core::Name& base_name); + + FixedManifestEncoder& addSuffixAndHashImpl(uint32_t suffix, + const utils::CryptoHash& hash); + + FixedManifestEncoder& setIsFinalManifestImpl(bool is_last); + + FixedManifestEncoder& setVersionImpl(ManifestVersion version); + + std::size_t estimateSerializedLengthImpl(std::size_t additional_entries = 0); + + FixedManifestEncoder& updateImpl(); + + FixedManifestEncoder& setFinalBlockNumberImpl( + std::uint32_t final_block_number); + + static std::size_t getManifestHeaderSizeImpl(); + + private: + void addSuffixHashBytes(uint32_t suffix, const uint8_t* hash, + std::size_t length); + + Packet& packet_; + std::size_t max_size_; + std::unique_ptr manifest_; + ManifestHeader* manifest_header_; + ManifestEntry* manifest_entries_; + std::size_t current_entry_; +}; + +class FixedManifestDecoder : public ManifestDecoder { + public: + FixedManifestDecoder(Packet& packet); + + ~FixedManifestDecoder(); + + void decodeImpl(); + + FixedManifestDecoder& clearImpl(); + + ManifestType getManifestTypeImpl() const; + + HashAlgorithm getHashAlgorithmImpl() const; + + NextSegmentCalculationStrategy getNextSegmentCalculationStrategyImpl() const; + + typename Fixed::SuffixList getSuffixHashListImpl(); + + core::Name getBaseNameImpl() const; + + bool getIsFinalManifestImpl() const; + + std::size_t estimateSerializedLengthImpl( + std::size_t additional_entries = 0) const; + + ManifestVersion getVersionImpl() const; + + uint32_t getFinalBlockNumberImpl() const; + + private: + Packet& packet_; + ManifestHeader* manifest_header_; + ManifestEntry* manifest_entries_; +}; + +} // namespace core + +} // namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.cc b/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.cc new file mode 100755 index 000000000..512cdba5b --- /dev/null +++ b/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.cc @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +namespace transport { + +namespace core { + +namespace { + +template +TRANSPORT_ALWAYS_INLINE void checkPointer(T* pointer) { + if (pointer == nullptr) { + throw errors::NullPointerException(); + } +} + +template +TRANSPORT_ALWAYS_INLINE void setValueToJson(Json::Value& root, EnumType value) { + root[JSONKey::key] = static_cast(value); +} + +template +TRANSPORT_ALWAYS_INLINE EnumType getValueFromJson(const Json::Value& root) { + return static_cast(root[JSONKey::key].asUInt()); +}; + +} // namespace + +JSONManifestEncoder::JSONManifestEncoder(Packet& packet) : packet_(packet) {} + +JSONManifestEncoder::~JSONManifestEncoder() {} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& JSONManifestEncoder::encodeImpl() { + Json::StreamWriterBuilder writer_builder; + Json::StreamWriter* fast_writer = writer_builder.newStreamWriter(); + + asio::streambuf strbuf; + strbuf.prepare(1500); + std::ostream stream(&strbuf); + fast_writer->write(root_, &stream); + + const uint8_t* buffer = asio::buffer_cast(strbuf.data()); + + packet_.setPayload(buffer, strbuf.size()); + + delete fast_writer; + + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& JSONManifestEncoder::clearImpl() { + root_.clear(); + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& +JSONManifestEncoder::setHashAlgorithmImpl(HashAlgorithm algorithm) { + setValueToJson(root_, algorithm); + return *this; +} + +JSONManifestEncoder& JSONManifestEncoder::setManifestTypeImpl( + ManifestType manifest_type) { + setValueToJson(root_, manifest_type); + return *this; +} + +JSONManifestEncoder& JSONManifestEncoder::setNextSegmentCalculationStrategyImpl( + NextSegmentCalculationStrategy strategy) { + setValueToJson(root_, strategy); + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& +JSONManifestEncoder::setBaseNameImpl(const core::Name& base_name) { + root_[JSONKey::key] = base_name.toString().c_str(); + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& +JSONManifestEncoder::addSuffixAndHashImpl(uint32_t suffix, + const utils::CryptoHash& hash) { + throw errors::NotImplementedException(); + // Json::Value value(Json::arrayValue); + // value.append(Json::Value(suffix)); + // value.append(Json::Value(Json::Value::UInt64 (hash))); + // root_[JSONKey::key].append(value); + + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& +JSONManifestEncoder::setIsFinalManifestImpl(bool is_last) { + root_[JSONKey::final_manifest] = is_last; + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& +JSONManifestEncoder::setVersionImpl(ManifestVersion version) { + setValueToJson(root_, version); + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& +JSONManifestEncoder::setSuffixHashListImpl( + const typename JSON::SuffixList& name_hash_list) { + throw errors::NotImplementedException(); + // for (auto &suffix : name_hash_list) { + // addSuffixAndHashImpl(suffix.first, suffix.second); + // } + // + // return *this; +} + +TRANSPORT_ALWAYS_INLINE std::size_t +JSONManifestEncoder::estimateSerializedLengthImpl( + std::size_t number_of_entries) { + Json::StreamWriterBuilder writer_builder; + Json::StreamWriter* fast_writer = writer_builder.newStreamWriter(); + + asio::streambuf strbuf; + strbuf.prepare(1500); + std::ostream stream(&strbuf); + fast_writer->write(root_, &stream); + + return strbuf.size(); +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& JSONManifestEncoder::updateImpl() { + throw errors::NotImplementedException(); +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& +JSONManifestEncoder::setFinalBlockNumberImpl(std::uint32_t final_block_number) { + throw errors::NotImplementedException(); +} + +TRANSPORT_ALWAYS_INLINE std::size_t +JSONManifestEncoder::getManifestHeaderSizeImpl() { + return 0; +} + +JSONManifestDecoder::JSONManifestDecoder(Packet& packet) : packet_(packet) {} + +JSONManifestDecoder::~JSONManifestDecoder() {} + +TRANSPORT_ALWAYS_INLINE void JSONManifestDecoder::decodeImpl() { + auto array = packet_.getPayload(); + auto payload = array.data(); + auto payload_size = array.length(); + + Json::CharReaderBuilder reader_builder; + Json::CharReader* reader = reader_builder.newCharReader(); + std::string errors; + + if (!reader->parse((char*)payload, (char*)payload + payload_size, &root_, + &errors)) { + TRANSPORT_LOGE("Error parsing manifest!"); + TRANSPORT_LOGE("%s", errors.c_str()); + + delete reader; + + throw errors::MalformedPacketException(); + } + + delete reader; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestDecoder& JSONManifestDecoder::clearImpl() { + root_.clear(); + return *this; +} + +TRANSPORT_ALWAYS_INLINE ManifestType +JSONManifestDecoder::getManifestTypeImpl() const { + return getValueFromJson(root_); +} + +TRANSPORT_ALWAYS_INLINE HashAlgorithm +JSONManifestDecoder::getHashAlgorithmImpl() const { + return getValueFromJson(root_); +} + +TRANSPORT_ALWAYS_INLINE NextSegmentCalculationStrategy +JSONManifestDecoder::getNextSegmentCalculationStrategyImpl() const { + return getValueFromJson(root_); +} + +TRANSPORT_ALWAYS_INLINE typename JSON::SuffixList +JSONManifestDecoder::getSuffixHashListImpl() { + throw errors::NotImplementedException(); + // SuffixHashList hash_list; + // + // Json::Value &array = root_[JSONKey::key]; + // + // for (Json::Value::ArrayIndex i = 0; + // i != array.size(); + // i++) { + // hash_list[array[i][0].asUInt()] = array[i][1].asUInt64(); + // } + // + // return hash_list; +} + +TRANSPORT_ALWAYS_INLINE core::Name JSONManifestDecoder::getBaseNameImpl() + const { + return core::Name(root_[JSONKey::key].asCString()); +} + +TRANSPORT_ALWAYS_INLINE bool JSONManifestDecoder::getIsFinalManifestImpl() + const { + return root_[JSONKey::final_manifest].asBool(); +} + +TRANSPORT_ALWAYS_INLINE ManifestVersion +JSONManifestDecoder::getVersionImpl() const { + return getValueFromJson(root_); +} + +TRANSPORT_ALWAYS_INLINE uint32_t +JSONManifestDecoder::getFinalBlockNumberImpl() const { + return 0; +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.h b/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.h new file mode 100755 index 000000000..39f0cf351 --- /dev/null +++ b/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#if defined(__APPLE__) || defined(__ANDROID__) +#include +#else +#include +#endif /* __APPLE__ || __ANDROID__*/ + +#include + +namespace transport { + +namespace core { + +class JSONManifestEncoder; +class JSONManifestDecoder; +class Packet; + +struct JSON { + using Encoder = JSONManifestEncoder; + using Decoder = JSONManifestDecoder; + using HashType = utils::CryptoHash; + using SuffixList = std::unordered_map; +}; + +template +struct JSONKey; + +template <> +struct JSONKey { + static const constexpr char* key = "manifest_version"; +}; + +template <> +struct JSONKey { + static const constexpr char* key = "hash_algorithm"; +}; + +template <> +struct JSONKey { + static const constexpr char* key = "manifest_type"; +}; + +template <> +struct JSONKey { + static const constexpr char* key = "next_segment_strategy"; +}; + +template <> +struct JSONKey { + static const constexpr char* key = "suffix_hash_list"; +}; + +template <> +struct JSONKey { + static const constexpr char* key = "base_name"; +}; + +template <> +struct JSONKey { + static const constexpr char* final_manifest = "final_manifest"; +}; + +class JSONManifestEncoder : public ManifestEncoder { + public: + JSONManifestEncoder(Packet& packet); + + ~JSONManifestEncoder() override; + + JSONManifestEncoder& encodeImpl(); + + JSONManifestEncoder& clearImpl(); + + JSONManifestEncoder& setManifestTypeImpl(ManifestType manifest_type); + + JSONManifestEncoder& setHashAlgorithmImpl(HashAlgorithm algorithm); + + JSONManifestEncoder& setNextSegmentCalculationStrategyImpl( + NextSegmentCalculationStrategy strategy); + + JSONManifestEncoder& setSuffixHashListImpl( + const typename JSON::SuffixList& name_hash_list); + + JSONManifestEncoder& setBaseNameImpl(const core::Name& base_name); + + JSONManifestEncoder& addSuffixAndHashImpl(uint32_t suffix, + const utils::CryptoHash& hash); + + JSONManifestEncoder& setIsFinalManifestImpl(bool is_last); + + JSONManifestEncoder& setVersionImpl(ManifestVersion version); + + std::size_t estimateSerializedLengthImpl(std::size_t number_of_entries); + + JSONManifestEncoder& updateImpl(); + + JSONManifestEncoder& setFinalBlockNumberImpl( + std::uint32_t final_block_number); + + static std::size_t getManifestHeaderSizeImpl(); + + private: + Packet& packet_; + Json::Value root_; +}; + +class JSONManifestDecoder : public ManifestDecoder { + public: + JSONManifestDecoder(Packet& packet); + + ~JSONManifestDecoder() override; + + void decodeImpl(); + + JSONManifestDecoder& clearImpl(); + + ManifestType getManifestTypeImpl() const; + + HashAlgorithm getHashAlgorithmImpl() const; + + uint32_t getFinalChunkImpl() const; + + NextSegmentCalculationStrategy getNextSegmentCalculationStrategyImpl() const; + + typename JSON::SuffixList getSuffixHashListImpl(); + + core::Name getBaseNameImpl() const; + + bool getIsFinalManifestImpl() const; + + std::size_t estimateSerializedLengthImpl(std::size_t number_of_entries) const; + + ManifestVersion getVersionImpl() const; + + uint32_t getFinalBlockNumberImpl() const; + + private: + Packet& packet_; + Json::Value root_; +}; + +} // namespace core + +} // namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.cc b/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.cc new file mode 100755 index 000000000..d0365d2fe --- /dev/null +++ b/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.cc @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +extern "C" { +#include +} + +namespace transport { + +namespace core { + +namespace { + +template +TRANSPORT_ALWAYS_INLINE void checkPointer(T* pointer) { + if (pointer == nullptr) { + throw errors::NullPointerException(); + } +} + +template +TRANSPORT_ALWAYS_INLINE void setValueToJson(PARCJSON* root, EnumType value) { + parcJSON_AddInteger(root, JSONKey::key, + static_cast(value)); +} + +template +TRANSPORT_ALWAYS_INLINE EnumType getValueFromJson(PARCJSON* root) { + checkPointer(root); + + PARCJSONValue* value = parcJSON_GetValueByName(root, JSONKey::key); + + EnumType ret = static_cast(parcJSONValue_GetInteger(value)); + // parcJSONValue_Release(&value); + + return ret; +}; + +} // namespace + +JSONManifestEncoder::JSONManifestEncoder() : root_(parcJSON_Create()) { + parcJSON_Acquire(root_); +} + +JSONManifestEncoder::~JSONManifestEncoder() { + if (root_) { + parcJSON_Release(&root_); + } +} + +TRANSPORT_ALWAYS_INLINE SONManifestEncoder& JSONManifestEncoder::encodeImpl( + Packet& packet) { + char* json_string = parcJSON_ToString(root_); + packet.setPayload(reinterpret_cast(json_string), + std::strlen(json_string)); + parcMemory_Deallocate(&json_string); + + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& JSONManifestEncoder::clearImpl() { + if (root_) { + parcJSON_Release(&root_); + } + + root_ = parcJSON_Create(); + + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& +JSONManifestEncoder::setHashAlgorithmImpl(HashAlgorithm algorithm) { + setValueToJson(root_, algorithm); + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& +JSONManifestEncoder::setManifestTypeImpl(ManifestType manifest_type) { + setValueToJson(root_, manifest_type); + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& +JSONManifestEncoder::setNextSegmentCalculationStrategyImpl( + NextSegmentCalculationStrategy strategy) { + setValueToJson(root_, strategy); + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& +JSONManifestEncoder::setBaseNameImpl(const core::Name& base_name) { + parcJSON_AddString(root_, JSONKey::key, + base_name.toString().c_str()); + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& +JSONManifestEncoder::addSuffixAndHashImpl(uint32_t suffix, + utils::CryptoHash& hash) { + throw errors::NotImplementedException(); + // PARCJSONValue *value = parcJSON_GetValueByName(root_, + // JSONKey::key); + // + // // Create the pair to store in the array. + // // It will be segment number + Hash of the segment + // PARCJSONArray * pair = parcJSONArray_Create(); + // + // PARCJSONValue *v = parcJSONValue_CreateFromInteger(suffix); + // parcJSONArray_AddValue(pair, v); + // parcJSONValue_Release(&v); + // + // v = parcJSONValue_CreateFromInteger(hash); + // parcJSONArray_AddValue(pair, v); + // parcJSONValue_Release(&v); + // + // if (value == nullptr /* || !parcJSONValue_IsArray(value) */) { + // // Create the array + // PARCJSONArray *array = parcJSONArray_Create(); + // parcJSON_AddArray(root_, + // JSONKey::key, + // array); + // parcJSONArray_Release(&array); + // + // value = parcJSON_GetValueByName(root_, JSONKey::key); + // } + // + // v = parcJSONValue_CreateFromJSONArray(pair); + // parcJSONArray_AddValue(parcJSONValue_GetArray(value), v); + // parcJSONValue_Release(&v); + // + // parcJSONArray_Release(&pair); + // // parcJSONValue_Release(&value); + + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& +JSONManifestEncoder::setIsFinalManifestImpl(bool is_last) { + parcJSON_AddBoolean(root_, JSONKey::final_manifest, is_last); + + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& +JSONManifestEncoder::setSuffixHashListImpl( + const SuffixHashList& name_hash_list) { + for (auto& suffix : name_hash_list) { + addSuffixAndHashImpl(suffix.first, suffix.second); + } + + return *this; +} + +TRANSPORT_ALWAYS_INLINE JSONManifestDecoder::JSONManifestDecoder() + : root_(nullptr) {} + +TRANSPORT_ALWAYS_INLINE JSONManifestDecoder::~JSONManifestDecoder() { + if (root_) { + parcJSON_Release(&root_); + } +} + +TRANSPORT_ALWAYS_INLINE void JSONManifestDecoder::decodeImpl( + const uint8_t* payload, std::size_t payload_size) { + PARCBuffer* b = parcBuffer_Wrap(const_cast(payload), payload_size, + 0, payload_size); + clearImpl(); + + root_ = parcJSON_ParseBuffer(b); + parcBuffer_Release(&b); + + char* str = parcJSON_ToString(root_); +} + +TRANSPORT_ALWAYS_INLINE JSONManifestDecoder& JSONManifestDecoder::clearImpl() { + if (root_) { + parcJSON_Release(&root_); + } + + return *this; +} + +TRANSPORT_ALWAYS_INLINE ManifestType +JSONManifestDecoder::getManifestTypeImpl() const { + return getValueFromJson(root_); +} + +TRANSPORT_ALWAYS_INLINE HashAlgorithm +JSONManifestDecoder::getHashAlgorithmImpl() const { + return getValueFromJson(root_); +} + +TRANSPORT_ALWAYS_INLINE NextSegmentCalculationStrategy +JSONManifestDecoder::getNextSegmentCalculationStrategyImpl() const { + return getValueFromJson(root_); +} + +TRANSPORT_ALWAYS_INLINE SuffixHashList +JSONManifestDecoder::getSuffixHashListImpl() { + throw errors::NotImplementedException(); + // SuffixHashList hash_list; + // + // char * str = parcJSON_ToString(root_); + // + // PARCJSONValue *value = parcJSON_GetValueByName(root_, + // JSONKey::key); + // + // if (value == nullptr || !parcJSONValue_IsArray(value)) { + // throw errors::RuntimeException("Manifest does not contain suffix-hash + // list"); + // } + // + // PARCJSONArray *array = parcJSONValue_GetArray(value); + // std::size_t array_size = parcJSONArray_GetLength(array); + // + // for (std::size_t i = 0; i < array_size; i++) { + // PARCJSONValue *v = parcJSONArray_GetValue(array, i); + // checkPointer(v); + // PARCJSONArray *a = parcJSONValue_GetArray(v); + // PARCJSONValue *_suffix = parcJSONArray_GetValue(a, 0); + // PARCJSONValue *_hash = parcJSONArray_GetValue(a, 1); + // + // uint32_t value1 = + // static_cast(parcJSONValue_GetInteger(_suffix)); uint64_t + // value2 = static_cast(parcJSONValue_GetInteger(_hash)); + // + // hash_list[static_cast(parcJSONValue_GetInteger(_suffix))] = + // static_cast(parcJSONValue_GetInteger(_hash)); + // + //// parcJSONValue_Release(&_hash); + //// parcJSONValue_Release(&_suffix); + //// parcJSONArray_Release(&a); + //// parcJSONValue_Release(&v); + // } + // + //// parcJSONArray_Release(&array); + //// parcJSONValue_Release(&value); + // + // char * str2 = parcJSON_ToString(root_); + // + // return hash_list; +} + +TRANSPORT_ALWAYS_INLINE core::Name JSONManifestDecoder::getBaseNameImpl() + const { + checkPointer(root_); + PARCJSONValue* value = + parcJSON_GetValueByName(root_, JSONKey::key); + + PARCBuffer* b = parcJSONValue_GetString(value); + char* string = parcBuffer_ToString(b); + + core::Name ret(string); + + // parcJSONValue_Release(&value); + parcMemory_Deallocate(&string); + + return ret; +} + +TRANSPORT_ALWAYS_INLINE bool JSONManifestDecoder::getIsFinalManifestImpl() { + checkPointer(root_); + PARCJSONValue* value = + parcJSON_GetValueByName(root_, JSONKey::final_manifest); + + bool ret = parcJSONValue_GetBoolean(value); + + // parcJSONValue_Release(&value); + + return ret; +} + +TRANSPORT_ALWAYS_INLINE std::size_t +JSONManifestDecoder::estimateSerializedLengthImpl( + std::size_t number_of_entries) { + return 0; +} + +} // end namespace core + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.h b/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.h new file mode 100755 index 000000000..28c6c1b40 --- /dev/null +++ b/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +extern "C" { +#include +} + +#include + +namespace transport { + +namespace core { + +class JSONManifestEncoder; +class JSONManifestDecoder; +class Packet; + +struct JSON { + using Encoder = JSONManifestEncoder; + using Decoder = JSONManifestDecoder; +}; + +template +struct JSONKey; + +template <> +struct JSONKey { + static const constexpr char* key = "hash_algorithm"; +}; + +template <> +struct JSONKey { + static const constexpr char* key = "manifest_type"; +}; + +template <> +struct JSONKey { + static const constexpr char* key = "next_segment_strategy"; +}; + +template <> +struct JSONKey { + static const constexpr char* key = "name_hash_list"; +}; + +template <> +struct JSONKey { + static const constexpr char* key = "suffix_hash_list"; +}; + +template <> +struct JSONKey { + static const constexpr char* key = "base_name"; +}; + +template <> +struct JSONKey { + static const constexpr char* final_manifest = "final_manifest"; +}; + +// template <> +// struct JSONKey { +// static const std::string key = "name_hash_list"; +//}; + +// namespace JSONManifestEncoding { +// static const std::string base_name = "base_name"; +// static const std::string final_chunk_number = "final_chunk_number"; +// static const std::string hash_algorithm = "hash_algorithm"; +// static const std::string manifest_type = "manifest_type"; +// static const std::string name_hash_list = "name_hash_list"; +// static const std::string next_segment_strategy = "next_segment_strategy"; +//} + +class JSONManifestEncoder : public ManifestEncoder { + public: + JSONManifestEncoder(); + + ~JSONManifestEncoder(); + + JSONManifestEncoder& encodeImpl(Packet& packet); + + JSONManifestEncoder& clearImpl(); + + JSONManifestEncoder& setManifestTypeImpl(ManifestType manifest_type); + + JSONManifestEncoder& setHashAlgorithmImpl(HashAlgorithm algorithm); + + JSONManifestEncoder& setNextSegmentCalculationStrategyImpl( + NextSegmentCalculationStrategy strategy); + + JSONManifestEncoder& setSuffixHashListImpl( + const SuffixHashList& name_hash_list); + + JSONManifestEncoder& setBaseNameImpl(const core::Name& base_name); + + JSONManifestEncoder& addSuffixAndHashImpl(uint32_t suffix, uint64_t hash); + + JSONManifestEncoder& setIsFinalManifestImpl(bool is_last); + + private: + PARCJSON* root_; +}; + +class JSONManifestDecoder : public ManifestDecoder { + public: + JSONManifestDecoder(); + + ~JSONManifestDecoder(); + + void decodeImpl(const uint8_t* payload, std::size_t payload_size); + + JSONManifestDecoder& clearImpl(); + + ManifestType getManifestTypeImpl() const; + + HashAlgorithm getHashAlgorithmImpl() const; + + uint32_t getFinalChunkImpl() const; + + NextSegmentCalculationStrategy getNextSegmentCalculationStrategyImpl() const; + + SuffixHashList getSuffixHashListImpl(); + + core::Name getBaseNameImpl() const; + + bool getIsFinalManifestImpl(); + + private: + PARCJSON* root_; +}; + +} // namespace core + +} // namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/manifest_inline.h b/libtransport/src/hicn/transport/core/manifest_inline.h new file mode 100755 index 000000000..fd1a9abd3 --- /dev/null +++ b/libtransport/src/hicn/transport/core/manifest_inline.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include + +namespace transport { + +namespace core { + +template +class ManifestInline + : public Manifest> { + using ManifestBase = + Manifest>; + using HashType = typename FormatTraits::HashType; + using SuffixList = typename FormatTraits::SuffixList; + + public: + ManifestInline() : ManifestBase() {} + + ManifestInline(const core::Name& name) : ManifestBase(name) {} + + template + ManifestInline(T&& base) : ManifestBase(std::forward(base)) {} + + static TRANSPORT_ALWAYS_INLINE ManifestInline* createManifest( + const core::Name& manifest_name, ManifestVersion version, + ManifestType type, HashAlgorithm algorithm, bool is_last, + const Name& base_name, NextSegmentCalculationStrategy strategy, + std::size_t signature_size) { + auto manifest = new ManifestInline(manifest_name); + manifest->setSignatureSize(signature_size); + manifest->setVersion(version); + manifest->setManifestType(type); + manifest->setHashAlgorithm(algorithm); + manifest->setFinalManifest(is_last); + manifest->setBaseName(base_name); + manifest->setNextSegmentCalculationStrategy(strategy); + + return manifest; + } + + ManifestInline& encodeImpl() { + ManifestBase::encoder_.encode(); + return *this; + } + + ManifestInline& decodeImpl() { + base_name_ = ManifestBase::decoder_.getBaseName(); + next_segment_strategy_ = + ManifestBase::decoder_.getNextSegmentCalculationStrategy(); + 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(uint32_t suffix, const HashType& hash) { + ManifestBase::encoder_.addSuffixAndHash(suffix, hash); + return *this; + } + + // Call this function only after the decode function! + const SuffixList& getSuffixList() { return suffix_hash_map_; } + + ManifestInline& setNextSegmentCalculationStrategy( + NextSegmentCalculationStrategy strategy) { + next_segment_strategy_ = strategy; + ManifestBase::encoder_.setNextSegmentCalculationStrategy( + next_segment_strategy_); + return *this; + } + + NextSegmentCalculationStrategy getNextSegmentCalculationStrategy() { + return next_segment_strategy_; + } + + private: + core::Name base_name_; + NextSegmentCalculationStrategy next_segment_strategy_; + SuffixList suffix_hash_map_; +}; + +} // end namespace core + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/memif_binary_api.c b/libtransport/src/hicn/transport/core/memif_binary_api.c new file mode 100755 index 000000000..b443b51ce --- /dev/null +++ b/libtransport/src/hicn/transport/core/memif_binary_api.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#ifdef __vpp__ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +// uword unformat_sw_if_index (unformat_input_t * input, va_list * args); + +/* Declare message IDs */ +#include + +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list + +#define vl_typedefs +#define vl_endianfun +#define vl_print(handle, ...) +#define vl_printfun +#define vl_api_version(n, v) static u32 api_version = (v); +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list +#undef vl_api_version +#undef vl_printfun +#undef vl_endianfun +#undef vl_typedefs + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* + * Table of message reply handlers, must include boilerplate handlers + * we just generated + */ +#define foreach_memif_api_reply_msg \ + _(MEMIF_CREATE_REPLY, memif_create_reply) \ + _(MEMIF_DELETE_REPLY, memif_delete_reply) \ + _(MEMIF_DETAILS, memif_details) + +#define POINTER_MAP_SIZE 32 +static void *global_pointers_map[POINTER_MAP_SIZE]; +static uint8_t global_pointers_map_index = 0; + +uint32_t memif_binary_api_get_next_memif_id(vpp_plugin_binary_api_t *api) { + // Dump all the memif interfaces and return the next to the largest memif id + vl_api_memif_dump_t *mp; + vpp_plugin_binary_api_t *hm = api; + + M(MEMIF_DUMP, mp); + api->vpp_api->user_param = malloc(sizeof(uint32_t)); + *(uint32_t *)(api->vpp_api->user_param) = 0; + global_pointers_map[global_pointers_map_index] = api; + mp->context = global_pointers_map_index++; + global_pointers_map_index %= POINTER_MAP_SIZE; + + vpp_binary_api_send_request(api->vpp_api, mp); + + vpp_binary_api_send_receive_ping(api->vpp_api); + + uint32_t ret = *(uint32_t *)(api->vpp_api->user_param); + free(api->vpp_api->user_param); + + return ret; +} + +static void vl_api_memif_details_t_handler(vl_api_memif_details_t *mp) { + vpp_plugin_binary_api_t *binary_api = global_pointers_map[mp->context]; + uint32_t *last_memif_id = binary_api->vpp_api->user_param; + uint32_t current_memif_id = clib_net_to_host_u32(mp->id); + if (current_memif_id >= *last_memif_id) { + *last_memif_id = current_memif_id + 1; + } +} + +int memif_binary_api_create_memif(vpp_plugin_binary_api_t *api, + memif_create_params_t *input_params, + memif_output_params_t *output_params) { + vl_api_memif_create_t *mp; + vpp_plugin_binary_api_t *hm = api; + + if (input_params->socket_id == ~0) { + // invalid socket-id + return -1; + } + + if (!is_pow2(input_params->ring_size)) { + // ring size must be power of 2 + return -1; + } + + if (input_params->rx_queues > 255 || input_params->rx_queues < 1) { + // rx queue must be between 1 - 255 + return -1; + } + + if (input_params->tx_queues > 255 || input_params->tx_queues < 1) { + // tx queue must be between 1 - 255 + return -1; + } + + api->vpp_api->user_param = output_params; + + /* Construct the API message */ + M(MEMIF_CREATE, mp); + + global_pointers_map[global_pointers_map_index] = api; + mp->context = global_pointers_map_index++; + global_pointers_map_index %= POINTER_MAP_SIZE; + + mp->role = input_params->role; + mp->mode = input_params->mode; + mp->rx_queues = input_params->rx_queues; + mp->tx_queues = input_params->tx_queues; + mp->id = clib_host_to_net_u32(input_params->id); + mp->socket_id = clib_host_to_net_u32(input_params->socket_id); + mp->ring_size = clib_host_to_net_u32(input_params->ring_size); + mp->buffer_size = clib_host_to_net_u16(input_params->buffer_size); + + int ret = vpp_binary_api_send_request_wait_reply(api->vpp_api, mp); + if (ret < 0) { + return ret; + } + + return vpp_binary_api_set_int_state(api->vpp_api, output_params->sw_if_index, + UP); +} +int memif_binary_api_delete_memif(vpp_plugin_binary_api_t *api, + uint32_t sw_if_index) { + vl_api_memif_delete_t *mp; + vpp_plugin_binary_api_t *hm = api; + + /* Construct the API message */ + M(MEMIF_DELETE, mp); + + global_pointers_map[global_pointers_map_index] = api; + mp->context = global_pointers_map_index++; + global_pointers_map_index %= POINTER_MAP_SIZE; + + mp->sw_if_index = htonl(sw_if_index); + + return vpp_binary_api_send_request_wait_reply(api->vpp_api, mp); +} + +static void vl_api_memif_create_reply_t_handler( + vl_api_memif_create_reply_t *mp) { + vpp_plugin_binary_api_t *binary_api = global_pointers_map[mp->context]; + memif_output_params_t *params = binary_api->vpp_api->user_param; + + binary_api->vpp_api->ret_val = ntohl(mp->retval); + params->sw_if_index = clib_net_to_host_u32(mp->sw_if_index); + + TRANSPORT_LOGI("ret :%d", binary_api->vpp_api->ret_val); + + vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api); +} + +static void vl_api_memif_delete_reply_t_handler( + vl_api_memif_delete_reply_t *mp) { + vpp_plugin_binary_api_t *binary_api = global_pointers_map[mp->context]; + + binary_api->vpp_api->ret_val = ntohl(mp->retval); + + vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api); +} + +static int memif_binary_api_setup_handlers( + vpp_plugin_binary_api_t *binary_api) { + vpp_plugin_binary_api_t *sm __attribute__((unused)) = binary_api; +#define _(N, n) \ + vl_msg_api_set_handlers(VL_API_##N + sm->msg_id_base, #n, \ + vl_api_##n##_t_handler, vl_noop_handler, \ + vl_api_##n##_t_endian, vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_memif_api_reply_msg; +#undef _ + return 0; +} + +vpp_plugin_binary_api_t *memif_binary_api_init(vpp_binary_api_t *api) { + vpp_plugin_binary_api_t *ret = malloc(sizeof(vpp_plugin_binary_api_t)); + u8 *name = format(0, "memif_%08x%c", api_version, 0); + ret->msg_id_base = vl_client_get_first_plugin_msg_id((char *)name); + ret->vpp_api = api; + ret->my_client_index = api->my_client_index; + memif_binary_api_setup_handlers(ret); + return ret; +} + +#endif // __vpp__ \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/memif_binary_api.h b/libtransport/src/hicn/transport/core/memif_binary_api.h new file mode 100755 index 000000000..582aeb1a0 --- /dev/null +++ b/libtransport/src/hicn/transport/core/memif_binary_api.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#ifdef __vpp__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdint.h" + +typedef struct memif_create_params_s { + uint8_t role; + uint8_t mode; + uint8_t rx_queues; + uint8_t tx_queues; + uint32_t id; + uint32_t socket_id; + uint8_t secret[24]; + uint32_t ring_size; + uint16_t buffer_size; + uint8_t hw_addr[6]; +} memif_create_params_t; + +typedef struct memif_output_params_s { + uint32_t sw_if_index; +} memif_output_params_t; + +vpp_plugin_binary_api_t* memif_binary_api_init(vpp_binary_api_t* api); + +uint32_t memif_binary_api_get_next_memif_id(vpp_plugin_binary_api_t* api); + +int memif_binary_api_create_memif(vpp_plugin_binary_api_t* api, + memif_create_params_t* input_params, + memif_output_params_t* output_params); + +int memif_binary_api_delete_memif(vpp_plugin_binary_api_t* api, + uint32_t sw_if_index); + +#ifdef __cplusplus +} +#endif + +#endif // __vpp__ \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/memif_connector.cc b/libtransport/src/hicn/transport/core/memif_connector.cc new file mode 100755 index 000000000..7a672314e --- /dev/null +++ b/libtransport/src/hicn/transport/core/memif_connector.cc @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#ifdef __vpp__ + +#include +#include + +#define CANCEL_TIMER 1 + +namespace transport { + +namespace core { + +std::once_flag MemifConnector::flag_; +utils::EpollEventReactor MemifConnector::main_event_reactor_; + +MemifConnector::MemifConnector(PacketReceivedCallback &&receive_callback, + OnReconnect &&on_reconnect_callback, + asio::io_service &io_service, + std::string app_name) + : Connector(), + memif_worker_(nullptr), + timer_set_(false), + send_timer_(std::make_unique(event_reactor_)), + io_service_(io_service), + work_(std::make_unique(io_service_)), + packet_counter_(0), + memif_connection_({}), + tx_buf_counter_(0), + is_connecting_(true), + is_reconnection_(false), + data_available_(false), + enable_burst_(false), + app_name_(app_name), + receive_callback_(receive_callback), + on_reconnect_callback_(on_reconnect_callback), + socket_filename_("") { + std::call_once(MemifConnector::flag_, &MemifConnector::init, this); +} + +MemifConnector::~MemifConnector() { close(); } + +void MemifConnector::init() { + /* initialize memory interface */ + int err = memif_init(controlFdUpdate, const_cast(app_name_.c_str()), + nullptr, nullptr, nullptr); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGI("memif_init: %s", memif_strerror(err)); + } +} + +void MemifConnector::connect(uint32_t memif_id, long memif_mode) { + TRANSPORT_LOGI("Creating memif"); + + memif_id_ = memif_id; + socket_filename_ = "/run/vpp/memif.sock"; + + createMemif(memif_id, memif_mode, nullptr); + + while (is_connecting_) { + MemifConnector::main_event_reactor_.runOneEvent(); + } + + int err; + + /* get interrupt queue id */ + int fd = -1; + err = memif_get_queue_efd(memif_connection_.conn, 0, &fd); + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGI("memif_get_queue_efd: %s", memif_strerror(err)); + return; + } + + // Remove fd from main epoll + main_event_reactor_.delFileDescriptor(fd); + + // Add fd to epoll of instance + event_reactor_.addFileDescriptor( + fd, EPOLLIN, [this](const utils::Event &evt) -> int { + return onInterrupt(memif_connection_.conn, this, 0); + }); + + memif_worker_ = std::make_unique( + std::bind(&MemifConnector::threadMain, this)); +} + +int MemifConnector::createMemif(uint32_t index, uint8_t mode, char *s) { + memif_connection_t *c = &memif_connection_; + + /* setting memif connection arguments */ + memif_conn_args_t args; + memset(&args, 0, sizeof(args)); + + args.is_master = mode; + args.log2_ring_size = MEMIF_LOG2_RING_SIZE; + args.buffer_size = MEMIF_BUF_SIZE; + args.num_s2m_rings = 1; + args.num_m2s_rings = 1; + strncpy((char *)args.interface_name, IF_NAME, strlen(IF_NAME)); + // strncpy((char *) args.instance_name, APP_NAME, strlen(APP_NAME)); + args.mode = memif_interface_mode_t::MEMIF_INTERFACE_MODE_IP; + args.socket_filename = (uint8_t *)socket_filename_.c_str(); + + TRANSPORT_LOGI("Socket filename: %s", args.socket_filename); + + args.interface_id = index; + /* last argument for memif_create (void * private_ctx) is used by user + to identify connection. this context is returned with callbacks */ + int err; + /* default interrupt */ + if (s == nullptr) { + err = memif_create(&c->conn, &args, onConnect, onDisconnect, onInterrupt, + this); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + throw errors::RuntimeException(memif_strerror(err)); + } + } + + c->index = (uint16_t)index; + c->tx_qid = 0; + /* alloc memif buffers */ + c->rx_buf_num = 0; + c->rx_bufs = static_cast( + malloc(sizeof(memif_buffer_t) * MAX_MEMIF_BUFS)); + c->tx_buf_num = 0; + c->tx_bufs = static_cast( + malloc(sizeof(memif_buffer_t) * MAX_MEMIF_BUFS)); + + // memif_set_rx_mode (c->conn, MEMIF_RX_MODE_POLLING, 0); + + return 0; +} + +int MemifConnector::deleteMemif() { + memif_connection_t *c = &memif_connection_; + + if (c->rx_bufs) { + free(c->rx_bufs); + } + + c->rx_bufs = nullptr; + c->rx_buf_num = 0; + + if (c->tx_bufs) { + free(c->tx_bufs); + } + + c->tx_bufs = nullptr; + c->tx_buf_num = 0; + + int err; + /* disconenct then delete memif connection */ + err = memif_delete(&c->conn); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGI("memif_delete: %s", memif_strerror(err)); + } + + if (TRANSPORT_EXPECT_FALSE(c->conn != nullptr)) { + TRANSPORT_LOGI("memif delete fail"); + } + + return 0; +} + +int MemifConnector::controlFdUpdate(int fd, uint8_t events) { + /* convert memif event definitions to epoll events */ + if (events & MEMIF_FD_EVENT_DEL) { + return MemifConnector::main_event_reactor_.delFileDescriptor(fd); + } + + uint32_t evt = 0; + + if (events & MEMIF_FD_EVENT_READ) { + evt |= EPOLLIN; + } + + if (events & MEMIF_FD_EVENT_WRITE) { + evt |= EPOLLOUT; + } + + if (events & MEMIF_FD_EVENT_MOD) { + return MemifConnector::main_event_reactor_.modFileDescriptor(fd, evt); + } + + return MemifConnector::main_event_reactor_.addFileDescriptor( + fd, evt, [](const utils::Event &evt) -> int { + uint32_t event = 0; + int memif_err = 0; + + if (evt.events & EPOLLIN) { + event |= MEMIF_FD_EVENT_READ; + } + + if (evt.events & EPOLLOUT) { + event |= MEMIF_FD_EVENT_WRITE; + } + + if (evt.events & EPOLLERR) { + event |= MEMIF_FD_EVENT_ERROR; + } + + memif_err = memif_control_fd_handler(evt.data.fd, event); + + if (TRANSPORT_EXPECT_FALSE(memif_err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGI("memif_control_fd_handler: %s", + memif_strerror(memif_err)); + } + + return 0; + }); +} + +int MemifConnector::bufferAlloc(long n, uint16_t qid) { + memif_connection_t *c = &memif_connection_; + int err; + uint16_t r; + /* set data pointer to shared memory and set buffer_len to shared mmeory + * buffer len */ + err = memif_buffer_alloc(c->conn, qid, c->tx_bufs, n, &r, 2000); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGD("memif_buffer_alloc: %s", memif_strerror(err)); + } + + c->tx_buf_num += r; + TRANSPORT_LOGD("allocated %d/%ld buffers, %u free buffers", r, n, + MAX_MEMIF_BUFS - c->tx_buf_num); + return r; +} + +int MemifConnector::txBurst(uint16_t qid) { + memif_connection_t *c = &memif_connection_; + int err; + uint16_t r; + /* inform peer memif interface about data in shared memory buffers */ + /* mark memif buffers as free */ + err = memif_tx_burst(c->conn, qid, c->tx_bufs, c->tx_buf_num, &r); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGI("memif_tx_burst: %s", memif_strerror(err)); + } + + // err = memif_refill_queue(c->conn, qid, r, 0); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGI("memif_tx_burst: %s", memif_strerror(err)); + c->tx_buf_num -= r; + return -1; + } + + TRANSPORT_LOGD("tx: %d/%u", r, c->tx_buf_num); + c->tx_buf_num -= r; + return 0; +} + +void MemifConnector::sendCallback(const std::error_code &ec) { + if (TRANSPORT_EXPECT_TRUE(!ec && !is_connecting_)) { + doSend(); + } + + if (output_buffer_.size() > 0) { + send_timer_->expiresFromNow(std::chrono::microseconds(50)); + send_timer_->asyncWait( + std::bind(&MemifConnector::sendCallback, this, std::placeholders::_1)); + } else { + timer_set_ = false; + } +} + +void MemifConnector::processInputBuffer() { + Packet::MemBufPtr ptr; + + while (input_buffer_.pop(ptr)) { + receive_callback_(std::move(ptr)); + } +} + +/* informs user about connected status. private_ctx is used by user to identify + connection (multiple connections WIP) */ +int MemifConnector::onConnect(memif_conn_handle_t conn, void *private_ctx) { + TRANSPORT_LOGI("memif connected!\n"); + MemifConnector *connector = (MemifConnector *)private_ctx; + memif_refill_queue(conn, 0, -1, 0); + connector->is_connecting_ = false; + + return 0; +} + +/* informs user about disconnected status. private_ctx is used by user to + identify connection (multiple connections WIP) */ +int MemifConnector::onDisconnect(memif_conn_handle_t conn, void *private_ctx) { + TRANSPORT_LOGI("memif disconnected!"); + MemifConnector *connector = (MemifConnector *)private_ctx; + // TRANSPORT_LOGI ("Packet received: %u", connector->packet_counter_); + TRANSPORT_LOGI("Packet to process: %u", + connector->memif_connection_.tx_buf_num); + return 0; +} + +void MemifConnector::threadMain() { event_reactor_.runEventLoop(1); } + +int MemifConnector::onInterrupt(memif_conn_handle_t conn, void *private_ctx, + uint16_t qid) { + MemifConnector *connector = (MemifConnector *)private_ctx; + + memif_connection_t *c = &connector->memif_connection_; + int err = MEMIF_ERR_SUCCESS, ret_val; + uint16_t rx; + + do { + err = memif_rx_burst(conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx); + ret_val = err; + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS && + err != MEMIF_ERR_NOBUF)) { + TRANSPORT_LOGI("memif_rx_burst: %s", memif_strerror(err)); + goto error; + } + + c->rx_buf_num += rx; + + if (TRANSPORT_EXPECT_TRUE(connector->io_service_.stopped())) { + TRANSPORT_LOGD("socket stopped: ignoring %u packets", rx); + goto error; + } + + for (int i = 0; i < rx; i++) { + auto packet = connector->getPacket(); + std::memcpy(packet->writableData(), + reinterpret_cast((c->rx_bufs + i)->data), + (c->rx_bufs + i)->len); + + if (!connector->input_buffer_.push(std::move(packet))) { + TRANSPORT_LOGI("Error pushing packet. Ring buffer full."); + + // TODO Here we should consider the possibility to signal the congestion + // to the application, that would react properly (e.g. slow down + // message) + } + } + + connector->io_service_.post( + std::bind(&MemifConnector::processInputBuffer, connector)); + + /* mark memif buffers and shared memory buffers as free */ + /* free processed buffers */ + + err = memif_refill_queue(conn, qid, rx, 0); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGI("memif_buffer_free: %s", memif_strerror(err)); + } + + c->rx_buf_num -= rx; + + TRANSPORT_LOGD("freed %d buffers. %u/%u alloc/free buffers", rx, rx, + MAX_MEMIF_BUFS - rx); + + // if (connector->enable_burst_) { + // connector->doSend(); + // } + } while (ret_val == MEMIF_ERR_NOBUF); + + return 0; + +error: + err = memif_refill_queue(c->conn, qid, rx, 0); + + if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) { + TRANSPORT_LOGI("memif_buffer_free: %s", memif_strerror(err)); + } + c->rx_buf_num -= rx; + + TRANSPORT_LOGD("freed %d buffers. %u/%u alloc/free buffers", rx, + c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num); + return 0; +} + +// void MemifConnector::runEventsLoop() { +// io_service_.run(); +//} + +void MemifConnector::close() { + event_reactor_.stop(); + io_service_.stop(); + + if (memif_worker_ && memif_worker_->joinable()) { + memif_worker_->join(); + TRANSPORT_LOGD("Memif worker joined"); + deleteMemif(); + } else { + TRANSPORT_LOGD("Memif worker not joined"); + } +} + +void MemifConnector::enableBurst() { enable_burst_ = true; } + +void MemifConnector::send(const Packet::MemBufPtr &packet) { +#ifdef CANCEL_TIMER + if (!timer_set_) { + timer_set_ = true; + send_timer_->expiresFromNow(std::chrono::microseconds(50)); + send_timer_->asyncWait( + std::bind(&MemifConnector::sendCallback, this, std::placeholders::_1)); + } +#endif + + { + utils::SpinLock::Acquire locked(write_msgs_lock_); + output_buffer_.push_back(packet); + } +} + +int MemifConnector::doSend() { + std::size_t max = 0; + uint16_t n = 0; + std::size_t size = 0; + + { + utils::SpinLock::Acquire locked(write_msgs_lock_); + size = output_buffer_.size(); + } + + do { + max = size < MAX_MEMIF_BUFS ? size : MAX_MEMIF_BUFS; + + if (TRANSPORT_EXPECT_FALSE( + (n = bufferAlloc(max, memif_connection_.tx_qid)) < 0)) { + TRANSPORT_LOGI("Error allocating buffers."); + return -1; + } + + for (uint16_t i = 0; i < n; i++) { + utils::SpinLock::Acquire locked(write_msgs_lock_); + + auto packet = output_buffer_.front().get(); + const utils::MemBuf *current = packet; + std::size_t offset = 0; + uint8_t *shared_buffer = + reinterpret_cast(memif_connection_.tx_bufs[i].data); + do { + std::memcpy(shared_buffer + offset, current->data(), current->length()); + offset += current->length(); + current = current->next(); + } while (current != packet); + + memif_connection_.tx_bufs[i].len = uint32_t(offset); + + TRANSPORT_LOGD("Packet size : %zu", offset); + + output_buffer_.pop_front(); + } + + txBurst(memif_connection_.tx_qid); + + utils::SpinLock::Acquire locked(write_msgs_lock_); + size = output_buffer_.size(); + } while (size > 0); + + return 0; +} + +void MemifConnector::state() { + TRANSPORT_LOGD("Event reactor map: %zu", event_reactor_.mapSize()); + TRANSPORT_LOGD("Output buffer %zu", output_buffer_.size()); +} + +void MemifConnector::send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent) {} + +} // end namespace core + +} // end namespace transport + +#endif // __vpp__ \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/memif_connector.h b/libtransport/src/hicn/transport/core/memif_connector.h new file mode 100755 index 000000000..24c8ac16c --- /dev/null +++ b/libtransport/src/hicn/transport/core/memif_connector.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef __vpp__ + +#define _Static_assert static_assert + +extern "C" { +#include +}; + +namespace transport { + +namespace core { + +typedef struct { + uint16_t index; + /* memif conenction handle */ + memif_conn_handle_t conn; + /* transmit queue id */ + uint16_t tx_qid; + /* tx buffers */ + memif_buffer_t *tx_bufs; + /* allocated tx buffers counter */ + /* number of tx buffers pointing to shared memory */ + uint16_t tx_buf_num; + /* rx buffers */ + memif_buffer_t *rx_bufs; + /* allcoated rx buffers counter */ + /* number of rx buffers pointing to shared memory */ + uint16_t rx_buf_num; + /* interface ip address */ + uint8_t ip_addr[4]; +} memif_connection_t; + +#define APP_NAME "libtransport" +#define IF_NAME "vpp_connection" + +#define MAX_MEMIF_BUFS 1024 +#define MEMIF_BUF_SIZE 2048 +#define MEMIF_LOG2_RING_SIZE 11 + +class MemifConnector : public Connector { + public: + MemifConnector(PacketReceivedCallback &&receive_callback, + OnReconnect &&on_reconnect_callback, + asio::io_service &io_service, + std::string app_name = "Libtransport"); + + ~MemifConnector() override; + + void send(const Packet::MemBufPtr &packet) override; + + void send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent = 0) override; + + void close() override; + + void connect(uint32_t memif_id, long memif_mode); + + // void runEventsLoop(); + + void enableBurst() override; + + void state() override; + + TRANSPORT_ALWAYS_INLINE uint32_t getMemifId() { return memif_id_; }; + + private: + void init(); + + int doSend(); + + int createMemif(uint32_t index, uint8_t mode, char *s); + + uint32_t getMemifConfiguration(); + + int deleteMemif(); + + static int controlFdUpdate(int fd, uint8_t events); + + static int onConnect(memif_conn_handle_t conn, void *private_ctx); + + static int onDisconnect(memif_conn_handle_t conn, void *private_ctx); + + static int onInterrupt(memif_conn_handle_t conn, void *private_ctx, + uint16_t qid); + + void threadMain(); + + int txBurst(uint16_t qid); + + int bufferAlloc(long n, uint16_t qid); + + void sendCallback(const std::error_code &ec); + + void processInputBuffer(); + + private: + static utils::EpollEventReactor main_event_reactor_; + static std::unique_ptr main_worker_; + + int epfd; + std::unique_ptr memif_worker_; + utils::EpollEventReactor event_reactor_; + volatile bool timer_set_; + std::unique_ptr send_timer_; + asio::io_service &io_service_; + std::unique_ptr work_; + uint32_t packet_counter_; + memif_connection_t memif_connection_; + uint16_t tx_buf_counter_; + + PacketRing input_buffer_; + volatile bool is_connecting_; + volatile bool is_reconnection_; + bool data_available_; + bool enable_burst_; + uint32_t memif_id_; + uint8_t memif_mode_; + std::string app_name_; + uint16_t transmission_index_; + PacketReceivedCallback receive_callback_; + OnReconnect on_reconnect_callback_; + utils::SpinLock write_msgs_lock_; + std::string socket_filename_; + + static std::once_flag flag_; +}; + +} // end namespace core + +} // end namespace transport + +#endif // __vpp__ \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/name.cc b/libtransport/src/hicn/transport/core/name.cc new file mode 100755 index 000000000..10c45eb08 --- /dev/null +++ b/libtransport/src/hicn/transport/core/name.cc @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +namespace transport { + +namespace core { + +Name::Name() { name_ = createEmptyName(); } + +Name::Name(int family, const uint8_t *ip_address, std::uint32_t suffix) + : name_(createEmptyName()) { + std::size_t length; + uint8_t *dst = NULL; + + if (family == AF_INET) { + dst = name_->ip4.prefix_as_u8; + length = IPV4_ADDR_LEN; + name_->type = HNT_CONTIGUOUS_V4; + } else if (family == AF_INET6) { + dst = name_->ip6.prefix_as_u8; + length = IPV6_ADDR_LEN; + name_->type = HNT_CONTIGUOUS_V6; + } else { + throw errors::RuntimeException("Specified name family does not exist."); + } + + std::memcpy(dst, ip_address, length); + *reinterpret_cast(dst + length) = suffix; +} + +Name::Name(const char *name, uint32_t segment) { + name_ = createEmptyName(); + + if (hicn_name_create(name, segment, name_.get()) < 0) { + throw errors::InvalidIpAddressException(); + } +} + +Name::Name(const std::string &uri, uint32_t segment) + : Name(uri.c_str(), segment) {} + +Name::Name(const std::string &uri) { + utils::StringTokenizer tokenizer(uri, "|"); + std::string ip_address; + std::string seq_number; + + ip_address = tokenizer.nextToken(); + + try { + seq_number = tokenizer.nextToken(); + } catch (errors::TokenizerException &e) { + seq_number = "0"; + } + + name_ = createEmptyName(); + + if (hicn_name_create(ip_address.c_str(), (uint32_t)atoi(seq_number.c_str()), + name_.get()) < 0) { + throw errors::InvalidIpAddressException(); + } +} + +Name::Name(const Name &name, bool hard_copy) { + name_ = createEmptyName(); + + if (hard_copy) { + if (hicn_name_copy(this->name_.get(), name.name_.get()) < 0) { + throw errors::MalformedNameException(); + } + } else { + *this->name_ = *name.name_; + } +} + +Name::Name(Name &&name) : name_(std::move(name.name_)) {} + +Name &Name::operator=(const Name &name) { + if (hicn_name_copy(this->name_.get(), name.name_.get()) < 0) { + throw errors::MalformedNameException(); + } + + return *this; +} + +bool Name::operator==(const Name &name) const { + return this->equals(name, true); +} + +bool Name::operator!=(const Name &name) const { + return !this->operator==(name); +} + +Name::operator bool() const { + return bool(hicn_name_empty((hicn_name_t *)name_.get())); +} + +bool Name::equals(const Name &name, bool consider_segment) const { + return !hicn_name_compare(name_.get(), name.name_.get(), consider_segment); +} + +std::string Name::toString() const { + char *name = new char[100]; + int ret = hicn_name_ntop(name_.get(), name, standard_name_string_length); + if (ret < 0) { + throw errors::MalformedNameException(); + } + std::string name_string(name); + delete[] name; + + return name_string; +} + +uint32_t Name::getHash32() const { + uint32_t hash; + if (hicn_name_hash((hicn_name_t *)name_.get(), &hash) < 0) { + throw errors::RuntimeException("Error computing the hash of the name!"); + } + return hash; +} + +void Name::clear() { + name_.reset(); + name_ = createEmptyName(); +}; + +Name::Type Name::getType() const { return name_->type; } + +uint32_t Name::getSuffix() const { + uint32_t ret = 0; + if (hicn_name_get_seq_number((hicn_name_t *)name_.get(), &ret) < 0) { + throw errors::RuntimeException( + "Impossible to retrieve the sequence number from the name."); + } + return ret; +} + +Name &Name::setSuffix(uint32_t seq_number) { + if (hicn_name_set_seq_number(name_.get(), seq_number) < 0) { + throw errors::RuntimeException( + "Impossible to set the sequence number to the name."); + } + + return *this; +} + +std::shared_ptr Name::getAddress() const { + Sockaddr *ret = nullptr; + + switch (name_->type) { + case HNT_CONTIGUOUS_V4: + case HNT_IOV_V4: + ret = (Sockaddr *)new Sockaddr4; + break; + case HNT_CONTIGUOUS_V6: + case HNT_IOV_V6: + ret = (Sockaddr *)new Sockaddr6; + break; + default: + throw errors::MalformedNameException(); + } + + if (hicn_name_to_sockaddr_address((hicn_name_t *)name_.get(), ret) < 0) { + throw errors::MalformedNameException(); + } + + return std::shared_ptr(ret); +} + +ip_address_t Name::toIpAddress() const { + ip_address_t ret; + std::memset(&ret, 0, sizeof(ret)); + + if (hicn_name_to_ip_address(name_.get(), &ret) < 0) { + throw errors::InvalidIpAddressException(); + } + + return ret; +} + +int Name::getAddressFamily() const { + int ret = 0; + + if (hicn_name_get_family(name_.get(), &ret) < 0) { + throw errors::InvalidIpAddressException(); + } + + return ret; +} + +void Name::copyToDestination(uint8_t *destination, bool include_suffix) const { + if (hicn_name_copy_to_destination(destination, name_.get(), include_suffix) < + 0) { + throw errors::RuntimeException( + "Impossibe to copy the name into the " + "provided destination"); + } +} + +std::ostream &operator<<(std::ostream &os, const Name &name) { + const std::string &str = name.toString(); + // os << "core:/"; + os << str; + + return os; +} + +} // end namespace core + +} // end namespace transport + +namespace std { +size_t hash::operator()( + const transport::core::Name &name) const { + return name.getHash32(); +} + +} // end namespace std diff --git a/libtransport/src/hicn/transport/core/name.h b/libtransport/src/hicn/transport/core/name.h new file mode 100755 index 000000000..b0da15026 --- /dev/null +++ b/libtransport/src/hicn/transport/core/name.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +extern "C" { +TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") +#include +}; + +#include + +namespace transport { + +namespace core { + +typedef struct sockaddr_in6 Sockaddr6; +typedef struct sockaddr_in Sockaddr4; +typedef struct sockaddr Sockaddr; + +enum class HashAlgorithm : uint8_t; + +class Name { + friend class Packet; + friend class ContentObject; + friend class Interest; + + static const uint32_t standard_name_string_length = 100; + + public: + using NameStruct = hicn_name_t; + using Type = hicn_name_type_t; + + Name(); + + /** + * @brief Create name + * @param name The null-terminated URI string + */ + Name(const char *name, uint32_t segment); + + Name(int family, const uint8_t *ip_address, std::uint32_t suffix = 0); + + Name(const std::string &uri, uint32_t segment); + + Name(const std::string &uri); + + Name(const Name &name, bool hard_copy = false); + + Name(Name &&name); + + Name &operator=(const Name &name); + + bool operator==(const Name &name) const; + + bool operator!=(const Name &name) const; + + operator bool() const; + + std::string toString() const; + + bool equals(const Name &name, bool consider_segment = true) const; + + uint32_t getHash32() const; + + void clear(); + + Type getType() const; + + uint32_t getSuffix() const; + + std::shared_ptr getAddress() const; + + Name &setSuffix(uint32_t seq_number); + + ip_address_t toIpAddress() const; + + void copyToDestination(uint8_t *destination, + bool include_suffix = false) const; + + int getAddressFamily() const; + + private: + TRANSPORT_ALWAYS_INLINE NameStruct *getStructReference() const { + if (TRANSPORT_EXPECT_TRUE(name_ != nullptr)) { + return name_.get(); + } + + return nullptr; + } + + static TRANSPORT_ALWAYS_INLINE std::unique_ptr createEmptyName() { + NameStruct *name = new NameStruct; + name->type = HNT_UNSPEC; + return std::unique_ptr(name); + }; + + std::unique_ptr name_; +}; + +std::ostream &operator<<(std::ostream &os, const Name &name); + +} // end namespace core + +} // end namespace transport + +namespace std { +template <> +struct hash { + size_t operator()(const transport::core::Name &name) const; +}; + +} // end namespace std diff --git a/libtransport/src/hicn/transport/core/packet.cc b/libtransport/src/hicn/transport/core/packet.cc new file mode 100755 index 000000000..74f407ff7 --- /dev/null +++ b/libtransport/src/hicn/transport/core/packet.cc @@ -0,0 +1,614 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +extern "C" { +TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") +#include +} + +namespace transport { + +namespace core { + +const core::Name Packet::base_name("0::0|0"); + +Packet::Packet(Format format) + : packet_(utils::MemBuf::create(getHeaderSizeFromFormat(format)).release()), + packet_start_(packet_->writableData()), + header_head_(packet_.get()), + payload_head_(nullptr), + format_(format) { + if (hicn_packet_init_header(format, (hicn_header_t *)packet_start_) < 0) { + throw errors::RuntimeException("Unexpected error initializing the packet."); + } + + packet_->append(getHeaderSizeFromFormat(format_)); +} + +Packet::Packet(MemBufPtr &&buffer) + : packet_(std::move(buffer)), + packet_start_(packet_->writableData()), + header_head_(packet_.get()), + payload_head_(nullptr), + format_(getFormatFromBuffer(packet_start_)) { + + auto header_size = getHeaderSizeFromFormat(format_); + int signature_size = 0; + + if (_is_ah(format_)) { + signature_size = getSignatureSize(); + } + + auto payload_length = packet_->length() - header_size - signature_size; + + if (!payload_length && !signature_size) { + return; + } + + packet_->trimEnd(packet_->length()); + + if (signature_size) { + auto sig = packet_->cloneOne(); + sig->advance(header_size); + sig->append(signature_size); + packet_->appendChain(std::move(sig)); + } + + if (payload_length) { + auto payload = packet_->cloneOne(); + payload_head_ = payload.get(); + payload_head_->advance(header_size + signature_size); + payload_head_->append(payload_length); + packet_->prependChain(std::move(payload)); + packet_->append(header_size); + } + + +} + +Packet::Packet(const uint8_t *buffer, std::size_t size) + : Packet(MemBufPtr(utils::MemBuf::copyBuffer(buffer, size).release())) {} + +Packet::Packet(Packet &&other) + : packet_(std::move(other.packet_)), + packet_start_(packet_->writableData()), + header_head_(other.header_head_), + payload_head_(other.payload_head_), + format_(other.format_) { + other.packet_start_ = nullptr; + other.header_head_ = nullptr; + other.payload_head_ = nullptr; + other.format_ = HF_UNSPEC; +} + +Packet::~Packet() { + if (packet_->isChained()) { + packet_->separateChain(packet_->next(), packet_->prev()); + } +} + +std::size_t Packet::getHeaderSizeFromFormat(Format format, + size_t signature_size) { + std::size_t header_length; + hicn_packet_get_header_length_from_format(format, &header_length); + int is_ah = _is_ah(format); + return is_ah * (header_length + signature_size) + (!is_ah) * header_length; +} + +std::size_t Packet::getHeaderSizeFromBuffer(Format format, + const uint8_t *buffer) { + size_t header_length; + if (hicn_packet_get_header_length(format, (hicn_header_t *)buffer, + &header_length) < 0) { + throw errors::MalformedPacketException(); + } + return header_length; +} + +bool Packet::isInterest(const uint8_t *buffer) { + bool is_interest = false; + + if (TRANSPORT_EXPECT_FALSE(hicn_packet_test_ece((const hicn_header_t *)buffer, + &is_interest) < 0)) { + throw errors::RuntimeException( + "Impossible to retrieve ece flag from packet"); + } + + return !is_interest; +} + +Packet::Format Packet::getFormatFromBuffer(const uint8_t *buffer) { + Format format = HF_UNSPEC; + + if (TRANSPORT_EXPECT_FALSE( + hicn_packet_get_format((const hicn_header_t *)buffer, &format) < 0)) { + throw errors::MalformedPacketException(); + } + + return format; +} + +std::size_t Packet::getPayloadSizeFromBuffer(Format format, + const uint8_t *buffer) { + std::size_t payload_length; + if (TRANSPORT_EXPECT_FALSE( + hicn_packet_get_payload_length(format, (hicn_header_t *)buffer, + &payload_length) < 0)) { + throw errors::MalformedPacketException(); + } + + return payload_length; +} + +std::size_t Packet::payloadSize() const { + return getPayloadSizeFromBuffer(format_, packet_start_); +} + +std::size_t Packet::headerSize() const { + return getHeaderSizeFromBuffer(format_, packet_start_); +} + +const uint8_t *Packet::start() const { return packet_start_; } + +void Packet::setLifetime(uint32_t lifetime) { + if (hicn_interest_set_lifetime((hicn_header_t *)packet_start_, lifetime) < + 0) { + throw errors::MalformedPacketException(); + } +} + +uint32_t Packet::getLifetime() const { + uint32_t lifetime = 0; + + if (hicn_packet_get_lifetime((hicn_header_t *)packet_start_, &lifetime) < 0) { + throw errors::MalformedPacketException(); + } + + return lifetime; +} + +Packet &Packet::appendPayload(std::unique_ptr &&payload) { + if (!payload_head_) { + payload_head_ = payload.get(); + } + + header_head_->prependChain(std::move(payload)); + updateLength(); + return *this; +} + +Packet &Packet::appendPayload(const uint8_t *buffer, std::size_t length) { + return appendPayload(utils::MemBuf::copyBuffer(buffer, length)); +} + +Packet &Packet::appendHeader(std::unique_ptr &&header) { + if (!payload_head_) { + header_head_->prependChain(std::move(header)); + } else { + payload_head_->prependChain(std::move(header)); + } + + updateLength(); + return *this; +} + +Packet &Packet::appendHeader(const uint8_t *buffer, std::size_t length) { + return appendHeader(utils::MemBuf::copyBuffer(buffer, length)); +} + +utils::Array Packet::getPayload() const { + if (TRANSPORT_EXPECT_FALSE(payload_head_ == nullptr)) { + return utils::Array(); + } + + // Hopefully the payload is contiguous + if (TRANSPORT_EXPECT_FALSE(payload_head_->next() != header_head_)) { + payload_head_->gather(payloadSize()); + } + + return utils::Array(payload_head_->writableData(), + payload_head_->length()); +} + +Packet &Packet::updateLength(std::size_t length) { + std::size_t total_length = length; + + for (utils::MemBuf *current = payload_head_; + current && current != header_head_; current = current->next()) { + total_length += current->length(); + } + + if (hicn_packet_set_payload_length(format_, (hicn_header_t *)packet_start_, + total_length) < 0) { + throw errors::RuntimeException("Error setting the packet payload."); + } + + return *this; +} + +PayloadType Packet::getPayloadType() const { + hicn_payload_type_t ret = HPT_UNSPEC; + + if (hicn_packet_get_payload_type((hicn_header_t *)packet_start_, &ret) < 0) { + throw errors::RuntimeException("Impossible to retrieve payload type."); + } + + return PayloadType(ret); +} + +Packet &Packet::setPayloadType(PayloadType payload_type) { + if (hicn_packet_set_payload_type((hicn_header_t *)packet_start_, + hicn_payload_type_t(payload_type)) < 0) { + throw errors::RuntimeException("Error setting payload type of the packet."); + } + + return *this; +} + +Packet::Format Packet::getFormat() const { + if (format_ == HF_UNSPEC) { + if (hicn_packet_get_format((hicn_header_t *)packet_start_, &format_) < 0) { + throw errors::MalformedPacketException(); + } + } + + return format_; +} + +const std::shared_ptr Packet::data() { return packet_; } + +void Packet::dump() const { + TRANSPORT_LOGI("The header length is: %zu", headerSize()); + TRANSPORT_LOGI("The payload length is: %zu", payloadSize()); + std::cerr << std::endl; + + hicn_packet_dump((uint8_t *)packet_->data(), headerSize()); + // hicn_packet_dump((uint8_t *)packet_->next()->data(), payloadSize()); +} + +void Packet::setSignatureSize(std::size_t size_bytes) { + int ret = hicn_packet_set_signature_size( + format_, (hicn_header_t *)packet_start_, size_bytes); + + if (ret < 0) { + throw errors::RuntimeException("Packet without Authentication Header."); + } +} + +std::size_t Packet::getSignatureSize() const { + size_t size_bytes; + int ret = hicn_packet_get_signature_size( + format_, (hicn_header_t *)packet_start_, &size_bytes); + + if (ret < 0) { + throw errors::RuntimeException("Packet without Authentication Header."); + } + + return size_bytes; +} + +void Packet::setSignature(std::unique_ptr &&signature) { + // Check if packet already contains a signature + auto header = header_head_->next(); + while (header != payload_head_) { + header->unlink(); + header = header->next(); + } + + appendHeader(std::move(signature)); +} + +void Packet::setSignatureTimestamp(const uint64_t ×tamp) { + int ret = hicn_packet_set_signature_timestamp( + format_, (hicn_header_t *)packet_start_, timestamp); + + if (ret < 0) { + throw errors::RuntimeException("Error setting the signature timestamp."); + } +} + +uint64_t Packet::getSignatureTimestamp() const { + uint64_t return_value; + int ret = hicn_packet_get_signature_timestamp( + format_, (hicn_header_t *)packet_start_, &return_value); + + if (ret < 0) { + throw errors::RuntimeException("Error getting the signature timestamp."); + } + + return return_value; +} + +void Packet::setValidationAlgorithm(const utils::CryptoSuite &validation_algorithm) { + int ret = hicn_packet_set_validation_algorithm( + format_, (hicn_header_t *)packet_start_, uint8_t(validation_algorithm)); + + if (ret < 0) { + throw errors::RuntimeException("Error setting the validation algorithm."); + } +} + +utils::CryptoSuite Packet::getValidationAlgorithm() const { + uint8_t return_value; + int ret = hicn_packet_get_validation_algorithm( + format_, (hicn_header_t *)packet_start_, &return_value); + + if (ret < 0) { + throw errors::RuntimeException("Error getting the validation algorithm."); + } + + return utils::CryptoSuite(return_value); +} + +void Packet::setKeyId(const utils::KeyId &key_id) { + int ret = hicn_packet_set_key_id( + format_, (hicn_header_t *)packet_start_, key_id.first); + + if (ret < 0) { + throw errors::RuntimeException("Error setting the key id."); + } +} + +utils::KeyId Packet::getKeyId() const { + utils::KeyId return_value; + int ret = hicn_packet_get_key_id( + format_, (hicn_header_t *)packet_start_, &return_value.first, &return_value.second); + + if (ret < 0) { + throw errors::RuntimeException("Error getting the validation algorithm."); + } + + return return_value; +} + +utils::CryptoHash Packet::computeDigest(HashAlgorithm algorithm) const { + utils::CryptoHasher hasher(static_cast(algorithm)); + hasher.init(); + + // Copy IP+TCP/ICMP header before zeroing them + hicn_header_t header_copy; + + hicn_packet_copy_header(format_, (hicn_header_t *)packet_start_, &header_copy, + false); + + const_cast(this)->resetForHash(); + + std::size_t payload_len = getPayloadSizeFromBuffer(format_, packet_start_); + std::size_t header_length = getHeaderSizeFromFormat(format_); + std::size_t signature_size = _is_ah(format_) ? getSignatureSize() : 0; + + hasher.updateBytes(packet_start_, + payload_len + header_length + signature_size); + + hicn_packet_copy_header(format_, &header_copy, (hicn_header_t *)packet_start_, + false); + + return hasher.finalize(); +} + +void Packet::setChecksum() { + uint16_t partial_csum = 0; + + for (utils::MemBuf *current = header_head_->next(); + current && current != header_head_; current = current->next()) { + if (partial_csum != 0) { + partial_csum = ~partial_csum; + } + partial_csum = csum(current->data(), current->length(), partial_csum); + } + if (hicn_packet_compute_header_checksum( + format_, (hicn_header_t *)packet_start_, partial_csum) < 0) { + throw errors::MalformedPacketException(); + } +} + +bool Packet::checkIntegrity() const { + if (hicn_packet_check_integrity(format_, (hicn_header_t *)packet_start_) < + 0) { + return false; + } + + return true; +} + +Packet &Packet::setSyn() { + if (hicn_packet_set_syn((hicn_header_t *)packet_start_) < 0) { + throw errors::RuntimeException("Error setting syn bit in the packet."); + } + + return *this; +} + +Packet &Packet::resetSyn() { + if (hicn_packet_reset_syn((hicn_header_t *)packet_start_) < 0) { + throw errors::RuntimeException("Error resetting syn bit in the packet."); + } + + return *this; +} + +bool Packet::testSyn() const { + bool res = false; + if (hicn_packet_test_syn((hicn_header_t *)packet_start_, &res) < 0) { + throw errors::RuntimeException("Error testing syn bit in the packet."); + } + + return res; +} + +Packet &Packet::setAck() { + if (hicn_packet_set_ack((hicn_header_t *)packet_start_) < 0) { + throw errors::RuntimeException("Error setting ack bit in the packet."); + } + + return *this; +} + +Packet &Packet::resetAck() { + if (hicn_packet_reset_ack((hicn_header_t *)packet_start_) < 0) { + throw errors::RuntimeException("Error resetting ack bit in the packet."); + } + + return *this; +} + +bool Packet::testAck() const { + bool res = false; + if (hicn_packet_test_ack((hicn_header_t *)packet_start_, &res) < 0) { + throw errors::RuntimeException("Error testing ack bit in the packet."); + } + + return res; +} + +Packet &Packet::setRst() { + if (hicn_packet_set_rst((hicn_header_t *)packet_start_) < 0) { + throw errors::RuntimeException("Error setting rst bit in the packet."); + } + + return *this; +} + +Packet &Packet::resetRst() { + if (hicn_packet_reset_rst((hicn_header_t *)packet_start_) < 0) { + throw errors::RuntimeException("Error resetting rst bit in the packet."); + } + + return *this; +} + +bool Packet::testRst() const { + bool res = false; + if (hicn_packet_test_rst((hicn_header_t *)packet_start_, &res) < 0) { + throw errors::RuntimeException("Error testing rst bit in the packet."); + } + + return res; +} + +Packet &Packet::setFin() { + if (hicn_packet_set_fin((hicn_header_t *)packet_start_) < 0) { + throw errors::RuntimeException("Error setting fin bit in the packet."); + } + + return *this; +} + +Packet &Packet::resetFin() { + if (hicn_packet_reset_fin((hicn_header_t *)packet_start_) < 0) { + throw errors::RuntimeException("Error resetting fin bit in the packet."); + } + + return *this; +} + +bool Packet::testFin() const { + bool res = false; + if (hicn_packet_test_fin((hicn_header_t *)packet_start_, &res) < 0) { + throw errors::RuntimeException("Error testing fin bit in the packet."); + } + + return res; +} + +Packet &Packet::resetFlags() { + resetSyn(); + resetAck(); + resetRst(); + resetFin(); + + return *this; +} + +std::string Packet::printFlags() const { + std::string flags = ""; + if (testSyn()) { + flags += "S"; + } + if (testAck()) { + flags += "A"; + } + if (testRst()) { + flags += "R"; + } + if (testFin()) { + flags += "F"; + } + return flags; +} + +Packet &Packet::setSrcPort(uint16_t srcPort) { + if (hicn_packet_set_src_port((hicn_header_t *)packet_start_, srcPort) < 0) { + throw errors::RuntimeException("Error setting source port in the packet."); + } + + return *this; +} + +Packet &Packet::setDstPort(uint16_t dstPort) { + if (hicn_packet_set_dst_port((hicn_header_t *)packet_start_, dstPort) < 0) { + throw errors::RuntimeException( + "Error setting destination port in the packet."); + } + + return *this; +} + +uint16_t Packet::getSrcPort() const { + uint16_t port = 0; + + if (hicn_packet_get_src_port((hicn_header_t *)packet_start_, &port) < 0) { + throw errors::RuntimeException("Error reading source port in the packet."); + } + + return port; +} + +uint16_t Packet::getDstPort() const { + uint16_t port = 0; + + if (hicn_packet_get_dst_port((hicn_header_t *)packet_start_, &port) < 0) { + throw errors::RuntimeException( + "Error reading destination port in the packet."); + } + + return port; +} + +Packet &Packet::setTTL(uint8_t hops) { + if (hicn_packet_set_hoplimit((hicn_header_t *)packet_start_, hops) < 0) { + throw errors::RuntimeException("Error setting TTL."); + } + + return *this; +} + +uint8_t Packet::getTTL() const { + uint8_t hops = 0; + if (hicn_packet_get_hoplimit((hicn_header_t *)packet_start_, &hops) < 0) { + throw errors::RuntimeException("Error reading TTL."); + } + + return hops; +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/packet.h b/libtransport/src/hicn/transport/core/packet.h new file mode 100755 index 000000000..0a5673401 --- /dev/null +++ b/libtransport/src/hicn/transport/core/packet.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace utils { +class Signer; +class Verifier; +} // namespace utils + +namespace transport { + +namespace core { + +/* + * Basic IP packet, modelled as circular chain of buffers: + * Header = H + * Payload = P + * + * H_0 --> H_1 --> H_2 --> P_0 --> P_1 --> P_2 + * \_______________________________________| + */ + +class Packet : public std::enable_shared_from_this { + friend class utils::Signer; + friend class utils::Verifier; + + public: + using MemBufPtr = std::shared_ptr; + using Format = hicn_format_t; + static constexpr size_t default_mtu = 1500; + + /** + * Create new IP packet. Here we allocate just the header, + * the eventual payload will be added by prepending the payload buffer + * to the buffer chain whose the fist buffer is the header itself. + */ + Packet(Format format = HF_UNSPEC); + + /** + * Create new IP packet using raw buffer. + */ + Packet(const uint8_t *buffer, std::size_t size); + Packet(MemBufPtr &&buffer); + + /* + * Enforce zero-copy lifestyle. + */ + Packet(const Packet &other) = delete; + Packet &operator=(const Packet &other) = delete; + + /* + * Move constructor. + */ + Packet(Packet &&other); + + friend bool operator==(const Packet &l_packet, const Packet &r_packet); + + virtual ~Packet(); + + static std::size_t getHeaderSizeFromFormat(Format format, + std::size_t signature_size = 0); + + static std::size_t getHeaderSizeFromBuffer(Format format, + const uint8_t *buffer); + + static std::size_t getPayloadSizeFromBuffer(Format format, + const uint8_t *buffer); + + static bool isInterest(const uint8_t *buffer); + + static Format getFormatFromBuffer(const uint8_t *buffer); + + std::size_t payloadSize() const; + + std::size_t headerSize() const; + + const std::shared_ptr data(); + + const uint8_t *start() const; + + virtual void setLifetime(uint32_t lifetime); + + virtual uint32_t getLifetime() const; + + Packet &appendPayload(const uint8_t *buffer, std::size_t length); + + Packet &appendPayload(std::unique_ptr &&payload); + + Packet &appendHeader(std::unique_ptr &&header); + + Packet &appendHeader(const uint8_t *buffer, std::size_t length); + + utils::Array getPayload() const; + + Packet &updateLength(std::size_t length = 0); + + PayloadType getPayloadType() const; + + Packet &setPayloadType(PayloadType payload_type); + + Format getFormat() const; + + void dump() const; + + virtual void setLocator(const ip_address_t &locator) = 0; + + virtual ip_address_t getLocator() const = 0; + + void setSignatureSize(std::size_t size_bytes); + + std::size_t getSignatureSize() const; + + void setSignatureTimestamp(const uint64_t ×tamp); + + uint64_t getSignatureTimestamp() const; + + void setValidationAlgorithm(const utils::CryptoSuite &validation_algorithm); + + utils::CryptoSuite getValidationAlgorithm() const; + + void setKeyId(const utils::KeyId &key_id); + + utils::KeyId getKeyId() const; + + void setSignature(std::unique_ptr &&signature); + + virtual utils::CryptoHash computeDigest(HashAlgorithm algorithm) const; + + void setChecksum(); + + bool checkIntegrity() const; + + Packet &setSyn(); + Packet &resetSyn(); + bool testSyn() const; + Packet &setAck(); + Packet &resetAck(); + bool testAck() const; + Packet &setRst(); + Packet &resetRst(); + bool testRst() const; + Packet &setFin(); + Packet &resetFin(); + bool testFin() const; + Packet &resetFlags(); + std::string printFlags() const; + + Packet &setSrcPort(uint16_t srcPort); + Packet &setDstPort(uint16_t dstPort); + uint16_t getSrcPort() const; + uint16_t getDstPort() const; + + Packet &setTTL(uint8_t hops); + uint8_t getTTL() const; + + private: + virtual void resetForHash() = 0; + + protected: + Name name_; + MemBufPtr packet_; + uint8_t *packet_start_; + utils::MemBuf *header_head_; + utils::MemBuf *payload_head_; + mutable Format format_; + + static const core::Name base_name; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/payload_type.h b/libtransport/src/hicn/transport/core/payload_type.h new file mode 100755 index 000000000..fa79db35a --- /dev/null +++ b/libtransport/src/hicn/transport/core/payload_type.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace transport { + +namespace core { + +enum class PayloadType : uint16_t { + CONTENT_OBJECT = HPT_DATA, + MANIFEST = HPT_MANIFEST, +}; + +} // end namespace core + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/pending_interest.cc b/libtransport/src/hicn/transport/core/pending_interest.cc new file mode 100755 index 000000000..8f6de1839 --- /dev/null +++ b/libtransport/src/hicn/transport/core/pending_interest.cc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace transport { + +namespace core { + +PendingInterest::PendingInterest() + : interest_(nullptr, nullptr), timer_(), received_(false) {} + +PendingInterest::PendingInterest(Interest::Ptr &&interest, + std::unique_ptr &&timer) + : interest_(std::move(interest)), + timer_(std::move(timer)), + received_(false) {} + +PendingInterest::~PendingInterest() { + // timer_.reset(); +} + +void PendingInterest::cancelTimer() { timer_->cancel(); } + +bool PendingInterest::isReceived() const { return received_; } + +void PendingInterest::setReceived() { received_ = true; } + +Interest::Ptr &&PendingInterest::getInterest() { return std::move(interest_); } + +void PendingInterest::setReceived(bool received) { + PendingInterest::received_ = received; +} + +} // end namespace core + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/pending_interest.h b/libtransport/src/hicn/transport/core/pending_interest.h new file mode 100755 index 000000000..cbcafb5d9 --- /dev/null +++ b/libtransport/src/hicn/transport/core/pending_interest.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace transport { + +namespace core { + +class HicnForwarderInterface; +class VPPForwarderInterface; +class RawSocketInterface; + +template +class Portal; + +typedef std::function TimerCallback; + +class PendingInterest { + friend class Portal; + friend class Portal; + friend class Portal; + + public: + PendingInterest(); + + PendingInterest(Interest::Ptr &&interest, + std::unique_ptr &&timer); + + ~PendingInterest(); + + bool isReceived() const; + + template + TRANSPORT_ALWAYS_INLINE void startCountdown(Handler &&cb) { + timer_->expires_from_now( + std::chrono::milliseconds(interest_->getLifetime())); + timer_->async_wait(cb); + } + + void cancelTimer(); + + void setReceived(); + + Interest::Ptr &&getInterest(); + + void setReceived(bool received); + + bool isValid() const; + + void setValid(bool valid); + + private: + Interest::Ptr interest_; + std::unique_ptr timer_; + bool received_; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/portal.h b/libtransport/src/hicn/transport/core/portal.h new file mode 100755 index 000000000..88020447f --- /dev/null +++ b/libtransport/src/hicn/transport/core/portal.h @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __vpp__ +#include +#endif + +#include +#include +#include +#include +#include + +#define UNSET_CALLBACK 0 + +namespace transport { + +namespace core { + +typedef std::unordered_map> + PendingInterestHashTable; + +template +class BasicBindConfig { + static_assert(std::is_same::value, + "Prefix must be a Prefix type."); + + const uint32_t standard_cs_reserved = 5000; + + public: + template + BasicBindConfig(T &&prefix) + : prefix_(std::forward(prefix)), + content_store_reserved_(standard_cs_reserved) {} + + template + BasicBindConfig(T &&prefix, uint32_t cs_reserved) + : prefix_(std::forward(prefix)), + content_store_reserved_(cs_reserved) {} + + TRANSPORT_ALWAYS_INLINE const PrefixType &prefix() const { return prefix_; } + + TRANSPORT_ALWAYS_INLINE uint32_t csReserved() const { + return content_store_reserved_; + } + + private: + PrefixType prefix_; + uint32_t content_store_reserved_; +}; + +using BindConfig = BasicBindConfig; + +template +class Portal { + static_assert( + std::is_base_of, + ForwarderInt>::value, + "ForwarderInt must inherit from ForwarderInterface!"); + + public: + class ConsumerCallback { + public: + virtual void onContentObject(Interest::Ptr &&i, ContentObject::Ptr &&c) = 0; + virtual void onTimeout(Interest::Ptr &&i) = 0; + }; + + class ProducerCallback { + public: + virtual void onInterest(Interest::Ptr &&i) = 0; + }; + + Portal() : Portal(internal_io_service_) { + internal_work_ = std::make_unique(io_service_); + } + + Portal(asio::io_service &io_service) + : io_service_(io_service), + is_running_(false), + app_name_("libtransport_application"), + consumer_callback_(nullptr), + producer_callback_(nullptr), + connector_(std::bind(&Portal::processIncomingMessages, this, + std::placeholders::_1), + std::bind(&Portal::setLocalRoutes, this), io_service_, + app_name_), + forwarder_interface_(connector_) {} + + void setConsumerCallback(ConsumerCallback *consumer_callback) { + consumer_callback_ = consumer_callback; + } + + void setProducerCallback(ProducerCallback *producer_callback) { + producer_callback_ = producer_callback; + } + + TRANSPORT_ALWAYS_INLINE void setOutputInterface( + const std::string &output_interface) { + forwarder_interface_.setOutputInterface(output_interface); + } + + TRANSPORT_ALWAYS_INLINE void connect(bool is_consumer = true) { + forwarder_interface_.connect(is_consumer); + } + + ~Portal() { + connector_.close(); + stopEventsLoop(); + } + + TRANSPORT_ALWAYS_INLINE bool interestIsPending(const Name &name) { + auto it = pending_interest_hash_table_.find(name); + if (it != pending_interest_hash_table_.end()) + if (!it->second->isReceived()) return true; + + return false; + } + + TRANSPORT_ALWAYS_INLINE void sendInterest(Interest::Ptr &&interest) { + const Name name(interest->getName(), true); + + // Send it + forwarder_interface_.send(*interest); + + pending_interest_hash_table_[name] = std::make_unique( + std::move(interest), std::make_unique(io_service_)); + + pending_interest_hash_table_[name]->startCountdown( + std::bind(&Portal::timerHandler, this, + std::placeholders::_1, name)); + } + + TRANSPORT_ALWAYS_INLINE void timerHandler(const std::error_code &ec, + const Name &name) { + if (TRANSPORT_EXPECT_FALSE(!is_running_)) { + return; + } + + if (TRANSPORT_EXPECT_TRUE(!ec)) { + std::unordered_map>::iterator it = + pending_interest_hash_table_.find(name); + if (it != pending_interest_hash_table_.end()) { + std::unique_ptr ptr = std::move(it->second); + pending_interest_hash_table_.erase(it); + + if (consumer_callback_) { + consumer_callback_->onTimeout(std::move(ptr->getInterest())); + } + } + } + } + + TRANSPORT_ALWAYS_INLINE void bind(const BindConfig &config) { + connector_.enableBurst(); + forwarder_interface_.setContentStoreSize(config.csReserved()); + served_namespaces_.push_back(config.prefix()); + registerRoute(served_namespaces_.back()); + } + + TRANSPORT_ALWAYS_INLINE void runEventsLoop() { + if (io_service_.stopped()) { + io_service_.reset(); // ensure that run()/poll() will do some work + } + + is_running_ = true; + this->io_service_.run(); + is_running_ = false; + } + + TRANSPORT_ALWAYS_INLINE void runOneEvent() { + if (io_service_.stopped()) { + io_service_.reset(); // ensure that run()/poll() will do some work + } + + is_running_ = true; + this->io_service_.run_one(); + is_running_ = false; + } + + TRANSPORT_ALWAYS_INLINE void sendContentObject( + ContentObject &content_object) { + forwarder_interface_.send(content_object); + } + + TRANSPORT_ALWAYS_INLINE void stopEventsLoop() { + is_running_ = false; + internal_work_.reset(); + + for (auto &pend_interest : pending_interest_hash_table_) { + pend_interest.second->cancelTimer(); + } + + clear(); + + io_service_.post([this]() { io_service_.stop(); }); + } + + TRANSPORT_ALWAYS_INLINE void killConnection() { connector_.close(); } + + TRANSPORT_ALWAYS_INLINE void clear() { pending_interest_hash_table_.clear();} + + TRANSPORT_ALWAYS_INLINE asio::io_service &getIoService() { + return io_service_; + } + + TRANSPORT_ALWAYS_INLINE std::size_t getPITSize() { + connector_.state(); + return pending_interest_hash_table_.size(); + } + + TRANSPORT_ALWAYS_INLINE void registerRoute(Prefix &prefix) { + forwarder_interface_.registerRoute(prefix); + } + + private: + TRANSPORT_ALWAYS_INLINE void processIncomingMessages( + Packet::MemBufPtr &&packet_buffer) { + if (TRANSPORT_EXPECT_FALSE(!is_running_)) { + return; + } + + if (packet_buffer->data()[0] == ForwarderInt::ack_code) { + // Hicn forwarder message + processControlMessage(std::move(packet_buffer)); + return; + } + + bool is_interest = Packet::isInterest(packet_buffer->data()); + Packet::Format format = Packet::getFormatFromBuffer(packet_buffer->data()); + + if (TRANSPORT_EXPECT_TRUE(_is_tcp(format))) { + if (!is_interest) { + processContentObject( + ContentObject::Ptr(new ContentObject(std::move(packet_buffer)))); + } else { + processInterest(Interest::Ptr(new Interest(std::move(packet_buffer)))); + } + } else { + TRANSPORT_LOGE("Received not supported packet. Ignoring it."); + } + } + + TRANSPORT_ALWAYS_INLINE void setLocalRoutes() { + for (auto &name : served_namespaces_) { + registerRoute(name); + } + } + + TRANSPORT_ALWAYS_INLINE void processInterest(Interest::Ptr &&interest) { + // Interest for a producer + if (TRANSPORT_EXPECT_TRUE(producer_callback_ != nullptr)) { + producer_callback_->onInterest(std::move(interest)); + } + } + + TRANSPORT_ALWAYS_INLINE void processContentObject( + ContentObject::Ptr &&content_object) { + PendingInterestHashTable::iterator it = + pending_interest_hash_table_.find(content_object->getName()); + + if (TRANSPORT_EXPECT_TRUE(it != pending_interest_hash_table_.end())) { + std::unique_ptr interest_ptr = std::move(it->second); + interest_ptr->cancelTimer(); + + if (TRANSPORT_EXPECT_TRUE(!interest_ptr->isReceived())) { + interest_ptr->setReceived(); + pending_interest_hash_table_.erase(content_object->getName()); + + if (consumer_callback_) { + consumer_callback_->onContentObject( + std::move(interest_ptr->getInterest()), + std::move(content_object)); + } + + } else { + TRANSPORT_LOGW( + "Content already received (interest already satisfied)."); + } + } else { + TRANSPORT_LOGW("No pending interests for current content (%s)", + content_object->getName().toString().c_str()); + } + } + + TRANSPORT_ALWAYS_INLINE void processControlMessage( + Packet::MemBufPtr &&packet_buffer) { + // Control message as response to the route set by a producer. + // Do nothing + } + + private: + asio::io_service &io_service_; + asio::io_service internal_io_service_; + std::unique_ptr internal_work_; + + volatile bool is_running_; + + std::string app_name_; + + PendingInterestHashTable pending_interest_hash_table_; + + ConsumerCallback *consumer_callback_; + ProducerCallback *producer_callback_; + + typename ForwarderInt::ConnectorType connector_; + ForwarderInt forwarder_interface_; + + std::list served_namespaces_; + + ip_address_t locator4_; + ip_address_t locator6_; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/prefix.cc b/libtransport/src/hicn/transport/core/prefix.cc new file mode 100755 index 000000000..69c2b845a --- /dev/null +++ b/libtransport/src/hicn/transport/core/prefix.cc @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +extern "C" { +#include +} + +#include +#include +#include + +namespace transport { + +namespace core { + +Prefix::Prefix() { std::memset(&ip_address_, 0, sizeof(ip_address_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, "/"); + + std::string ip_address = st.nextToken(); + int family = get_addr_family(ip_address.c_str()); + + std::string prefix_length = family == AF_INET6 ? "128" : "32"; + + if (st.hasMoreTokens()) { + prefix_length = st.nextToken(); + } + + buildPrefix(ip_address, uint16_t(atoi(prefix_length.c_str())), family); +} + +Prefix::Prefix(std::string &prefix, uint16_t prefix_length) { + int family = get_addr_family(prefix.c_str()); + buildPrefix(prefix, prefix_length, family); +} + +Prefix::Prefix(const core::Name &content_name, uint16_t prefix_length) { + int family = content_name.getAddressFamily(); + + if (!checkPrefixLengthAndAddressFamily(prefix_length, family)) { + throw errors::InvalidIpAddressException(); + } + + ip_address_ = content_name.toIpAddress(); + ip_address_.prefix_len = prefix_length; + ip_address_.family = family; +} + +void Prefix::buildPrefix(std::string &prefix, uint16_t prefix_length, + int family) { + if (!checkPrefixLengthAndAddressFamily(prefix_length, family)) { + throw errors::InvalidIpAddressException(); + } + + int ret = inet_pton(family, prefix.c_str(), ip_address_.buffer); + + if (ret != 1) { + throw errors::InvalidIpAddressException(); + } + + ip_address_.prefix_len = prefix_length; + ip_address_.family = family; +} + +std::unique_ptr Prefix::toSockaddr() { + Sockaddr *ret = nullptr; + + switch (ip_address_.family) { + case AF_INET6: + ret = (Sockaddr *)new Sockaddr6; + break; + case AF_INET: + ret = (Sockaddr *)new Sockaddr4; + break; + default: + throw errors::InvalidIpAddressException(); + } + + if (hicn_ip_to_sockaddr_address(&ip_address_, ret) < 0) { + throw errors::InvalidIpAddressException(); + } + + return std::unique_ptr(ret); +} + +uint16_t Prefix::getPrefixLength() { return ip_address_.prefix_len; } + +Prefix &Prefix::setPrefixLength(uint16_t prefix_length) { + ip_address_.prefix_len = prefix_length; + return *this; +} + +int Prefix::getAddressFamily() { return ip_address_.family; } + +Prefix &Prefix::setAddressFamily(int address_family) { + ip_address_.family = address_family; + return *this; +} + +std::string Prefix::getNetwork() const { + if (!checkPrefixLengthAndAddressFamily(ip_address_.prefix_len, + ip_address_.family)) { + throw errors::InvalidIpAddressException(); + } + + std::size_t size = + ip_address_.family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; + + std::string network(size, 0); + + if (hicn_ip_ntop(&ip_address_, (char *)network.c_str(), size) < 0) { + throw errors::RuntimeException( + "Impossible to retrieve network from ip address."); + } + + return network; +} + +Name Prefix::getName() const { + std::string s(getNetwork()); + return Name(s); +} + +Prefix &Prefix::setNetwork(std::string &network) { + if (!inet_pton(AF_INET6, network.c_str(), ip_address_.buffer)) { + throw errors::RuntimeException("The network name is not valid."); + } + + return *this; +} + +Name Prefix::makeRandomName() const { + srand(time(nullptr)); + + if (ip_address_.family == AF_INET6) { + std::default_random_engine eng((std::random_device())()); + std::uniform_int_distribution idis( + 0, std::numeric_limits::max()); + uint64_t random_number = idis(eng); + + uint32_t hash_size_bits = IPV6_ADDR_LEN_BITS - ip_address_.prefix_len; + uint64_t ip_address[2]; + memcpy(ip_address, ip_address_.buffer, sizeof(uint64_t)); + memcpy(ip_address + 1, ip_address_.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_address_.family, ip_address, (char *)network.c_str(), + IPV6_ADDR_LEN * 3)) { + throw errors::RuntimeException( + "Impossible to retrieve network from ip address."); + } + + return Name(network); + } + + return Name(); +} + +bool Prefix::checkPrefixLengthAndAddressFamily(uint16_t prefix_length, + int family) { + // First check the family + if (family != AF_INET6 && family != AF_INET) { + return false; + } + + int max_addr_len_bits = + family == AF_INET6 ? IPV6_ADDR_LEN_BITS : IPV4_ADDR_LEN_BITS; + + if (prefix_length > max_addr_len_bits) { + return false; + } + + return true; +} + +ip_address_t &Prefix::toIpAddressStruct() { return ip_address_; } + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/hicn/transport/core/prefix.h b/libtransport/src/hicn/transport/core/prefix.h new file mode 100755 index 000000000..b68c6bdf6 --- /dev/null +++ b/libtransport/src/hicn/transport/core/prefix.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +namespace transport { + +namespace core { + +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 core::Name &content_name, uint16_t prefix_length); + + std::unique_ptr toSockaddr(); + + uint16_t getPrefixLength(); + + Prefix &setPrefixLength(uint16_t prefix_length); + + std::string getNetwork() const; + + Name getName() const; + + Prefix &setNetwork(std::string &network); + + int getAddressFamily(); + + Prefix &setAddressFamily(int address_family); + + Name makeRandomName() const; + + ip_address_t &toIpAddressStruct(); + + private: + static bool checkPrefixLengthAndAddressFamily(uint16_t prefix_length, + int family); + + void buildPrefix(std::string &prefix, uint16_t prefix_length, int family); + + ip_address_t ip_address_; +}; + +} // end namespace core + +} // end namespace transport \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/raw_socket_connector.cc b/libtransport/src/hicn/transport/core/raw_socket_connector.cc new file mode 100755 index 000000000..5cfff39fb --- /dev/null +++ b/libtransport/src/hicn/transport/core/raw_socket_connector.cc @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MY_DEST_MAC0 0x0a +#define MY_DEST_MAC1 0x7b +#define MY_DEST_MAC2 0x7c +#define MY_DEST_MAC3 0x1c +#define MY_DEST_MAC4 0x4a +#define MY_DEST_MAC5 0x14 + +namespace transport { + +namespace core { + +RawSocketConnector::RawSocketConnector( + PacketReceivedCallback &&receive_callback, + OnReconnect &&on_reconnect_callback, asio::io_service &io_service, + std::string app_name) + : Connector(), + io_service_(io_service), + socket_(io_service_, raw_protocol(PF_PACKET, SOCK_RAW)), + // resolver_(io_service_), + timer_(io_service_), + read_msg_(packet_pool_.makePtr(nullptr)), + data_available_(false), + receive_callback_(receive_callback), + on_reconnect_callback_(on_reconnect_callback), + app_name_(app_name) { + memset(&link_layer_address_, 0, sizeof(link_layer_address_)); +} + +RawSocketConnector::~RawSocketConnector() {} + +void RawSocketConnector::connect(const std::string &interface_name, + const std::string &mac_address_str) { + memset(ðernet_header_, 0, sizeof(ethernet_header_)); + struct ifreq ifr; + struct ifreq if_mac; + uint8_t mac_address[6]; + + utils::convertStringToMacAddress(mac_address_str, mac_address); + + // Get interface mac address + int fd = static_cast(socket_.native_handle()); + + /* Get the index of the interface to send on */ + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_name, interface_name.c_str(), interface_name.size()); + + // if (ioctl(fd, SIOCGIFINDEX, &if_idx) < 0) { + // perror("SIOCGIFINDEX"); + // } + + /* Get the MAC address of the interface to send on */ + memset(&if_mac, 0, sizeof(struct ifreq)); + strncpy(if_mac.ifr_name, interface_name.c_str(), interface_name.size()); + if (ioctl(fd, SIOCGIFHWADDR, &if_mac) < 0) { + perror("SIOCGIFHWADDR"); + throw errors::RuntimeException("Interface does not exist"); + } + + /* Ethernet header */ + for (int i = 0; i < 6; i++) { + ethernet_header_.ether_shost[i] = + ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[i]; + ethernet_header_.ether_dhost[i] = mac_address[i]; + } + + /* Ethertype field */ + ethernet_header_.ether_type = htons(ETH_P_IPV6); + + strcpy(ifr.ifr_name, interface_name.c_str()); + + if (0 == ioctl(fd, SIOCGIFHWADDR, &ifr)) { + memcpy(link_layer_address_.sll_addr, ifr.ifr_hwaddr.sa_data, 6); + } + + // memset(&ifr, 0, sizeof(ifr)); + // ioctl(fd, SIOCGIFFLAGS, &ifr); + // ifr.ifr_flags |= IFF_PROMISC; + // ioctl(fd, SIOCSIFFLAGS, &ifr); + + link_layer_address_.sll_family = AF_PACKET; + link_layer_address_.sll_protocol = htons(ETH_P_ALL); + link_layer_address_.sll_ifindex = if_nametoindex(interface_name.c_str()); + link_layer_address_.sll_hatype = 1; + link_layer_address_.sll_halen = 6; + + // startConnectionTimer(); + doConnect(); + doRecvPacket(); +} + +void RawSocketConnector::state() { return; } + +void RawSocketConnector::send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent) { + // asio::async_write(socket_, asio::buffer(packet, len), + // [packet_sent] (std::error_code ec, + // std::size_t /*length*/) { + // packet_sent(); + // }); +} + +void RawSocketConnector::send(const Packet::MemBufPtr &packet) { + // Packet &p = const_cast(packet); + // p.setTcpChecksum(); + + // if (!p.checkIntegrity()) { + // TRANSPORT_LOGW("Sending message with wrong checksum!!!"); + // } + + // std::shared_ptr ptr; + // try { + // ptr = packet.shared_from_this(); + // } catch (std::bad_weak_ptr& exc) { + // TRANSPORT_LOGW("Sending interest which has not been created using a + // shared PTR! A copy will be made."); ptr = + // std::shared_ptr(packet.clone()); + // } + + io_service_.post([this, packet]() { + bool write_in_progress = !output_buffer_.empty(); + output_buffer_.push_back(std::move(packet)); + if (!write_in_progress) { + doSendPacket(); + } else { + // Tell the handle connect it has data to write + data_available_ = true; + } + }); +} + +void RawSocketConnector::close() { + io_service_.post([this]() { socket_.close(); }); +} + +void RawSocketConnector::doSendPacket() { + auto packet = output_buffer_.front().get(); + auto array = std::vector(); + + const utils::MemBuf *current = packet; + do { + array.push_back(asio::const_buffer(current->data(), current->length())); + current = current->next(); + } while (current != packet); + + socket_.async_send( + std::move(array), + [this /*, packet*/](std::error_code ec, std::size_t bytes_transferred) { + if (TRANSPORT_EXPECT_TRUE(!ec)) { + output_buffer_.pop_front(); + if (!output_buffer_.empty()) { + doSendPacket(); + } + } else { + TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); + } + }); +} + +void RawSocketConnector::doRecvPacket() { + read_msg_ = std::move(getPacket()); + socket_.async_receive( + asio::buffer(read_msg_->writableData(), packet_size), + [this](std::error_code ec, std::size_t bytes_transferred) mutable { + if (!ec) { + // Ignore packets that are not for us + uint8_t *dst_mac_address = const_cast(read_msg_->data()); + if (!std::memcmp(dst_mac_address, ethernet_header_.ether_shost, + ETHER_ADDR_LEN)) { + read_msg_->append(bytes_transferred); + read_msg_->trimStart(sizeof(struct ether_header)); + receive_callback_(std::move(read_msg_)); + } + } else { + TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); + } + doRecvPacket(); + }); +} + +void RawSocketConnector::doConnect() { + socket_.bind(raw_endpoint(&link_layer_address_, sizeof(link_layer_address_))); +} + +void RawSocketConnector::enableBurst() { return; } + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/raw_socket_connector.h b/libtransport/src/hicn/transport/core/raw_socket_connector.h new file mode 100755 index 000000000..5e39efa0e --- /dev/null +++ b/libtransport/src/hicn/transport/core/raw_socket_connector.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +namespace transport { + +namespace core { + +using asio::generic::raw_protocol; +using raw_endpoint = asio::generic::basic_endpoint; + +class RawSocketConnector : public Connector { + public: + RawSocketConnector(PacketReceivedCallback &&receive_callback, + OnReconnect &&reconnect_callback, + asio::io_service &io_service, + std::string app_name = "Libtransport"); + + ~RawSocketConnector() override; + + void send(const Packet::MemBufPtr &packet) override; + + void send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent = 0) override; + + void close() override; + + void enableBurst() override; + + void connect(const std::string &interface_name, + const std::string &mac_address_str); + + void state() override; + + private: + void doConnect(); + + void doRecvPacket(); + + void doSendPacket(); + + private: + asio::io_service &io_service_; + raw_protocol::socket socket_; + + struct ether_header ethernet_header_; + + struct sockaddr_ll link_layer_address_; + + asio::steady_timer timer_; + + utils::ObjectPool::Ptr read_msg_; + + bool data_available_; + + PacketReceivedCallback receive_callback_; + OnReconnect on_reconnect_callback_; + std::string app_name_; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/raw_socket_interface.cc b/libtransport/src/hicn/transport/core/raw_socket_interface.cc new file mode 100755 index 000000000..37aaff7e0 --- /dev/null +++ b/libtransport/src/hicn/transport/core/raw_socket_interface.cc @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +namespace transport { + +namespace core { + +static std::string config_folder_path = "/etc/transport/interface.conf.d"; + +RawSocketInterface::RawSocketInterface(RawSocketConnector &connector) + : ForwarderInterface(connector) {} + +RawSocketInterface::~RawSocketInterface() {} + +void RawSocketInterface::connect(bool is_consumer) { + std::string complete_filename = + config_folder_path + std::string("/") + output_interface_; + + std::ifstream is(complete_filename); + std::string interface; + + if (is) { + is >> remote_mac_address_; + } + + // Get interface ip address + struct sockaddr_in6 address; + utils::retrieveInterfaceAddress(output_interface_, &address); + inet6_address_.family = address.sin6_family; + + std::memcpy(inet6_address_.buffer, &address.sin6_addr, + sizeof(address.sin6_addr)); + connector_.connect(output_interface_, remote_mac_address_); +} + +void RawSocketInterface::registerRoute(Prefix &prefix) { return; } + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/hicn/transport/core/raw_socket_interface.h b/libtransport/src/hicn/transport/core/raw_socket_interface.h new file mode 100755 index 000000000..c030af662 --- /dev/null +++ b/libtransport/src/hicn/transport/core/raw_socket_interface.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include +#include + +namespace transport { + +namespace core { + +class RawSocketInterface + : public ForwarderInterface { + public: + typedef RawSocketConnector ConnectorType; + + RawSocketInterface(RawSocketConnector &connector); + + ~RawSocketInterface(); + + void connect(bool is_consumer); + + void registerRoute(Prefix &prefix); + + std::uint16_t getMtu() { return interface_mtu; } + + private: + static constexpr std::uint16_t interface_mtu = 1500; + std::string remote_mac_address_; +}; + +} // namespace core + +} // namespace transport diff --git a/libtransport/src/hicn/transport/core/socket_connector.cc b/libtransport/src/hicn/transport/core/socket_connector.cc new file mode 100755 index 000000000..332b87ec7 --- /dev/null +++ b/libtransport/src/hicn/transport/core/socket_connector.cc @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include + +namespace transport { + +namespace core { + +namespace { +class NetworkMessage { + public: + static constexpr std::size_t fixed_header_length = 10; + + static std::size_t decodeHeader(const uint8_t *packet) { + // General checks + // CCNX Control packet format + uint8_t first_byte = packet[0]; + uint8_t ip_format = (packet[0] & 0xf0) >> 4; + + if (TRANSPORT_EXPECT_FALSE(first_byte == 102)) { + // Get packet length + return 44; + } else if (TRANSPORT_EXPECT_TRUE(ip_format == 6 || ip_format == 4)) { + Packet::Format format = Packet::getFormatFromBuffer(packet); + return Packet::getHeaderSizeFromBuffer(format, packet) + + Packet::getPayloadSizeFromBuffer(format, packet); + } + + return 0; + } +}; +} // namespace + +SocketConnector::SocketConnector(PacketReceivedCallback &&receive_callback, + OnReconnect &&on_reconnect_callback, + asio::io_service &io_service, + std::string app_name) + : Connector(), + io_service_(io_service), + socket_(io_service_), + resolver_(io_service_), + timer_(io_service_), + read_msg_(packet_pool_.makePtr(nullptr)), + is_connecting_(false), + is_reconnection_(false), + data_available_(false), + receive_callback_(receive_callback), + on_reconnect_callback_(on_reconnect_callback), + app_name_(app_name) {} + +SocketConnector::~SocketConnector() {} + +void SocketConnector::connect(std::string ip_address, std::string port) { + endpoint_iterator_ = resolver_.resolve( + {ip_address, port, asio::ip::resolver_query_base::numeric_service}); + + startConnectionTimer(); + doConnect(); +} + +void SocketConnector::state() { return; } + +void SocketConnector::send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent) { + asio::async_write(socket_, asio::buffer(packet, len), + [packet_sent](std::error_code ec, std::size_t /*length*/) { + packet_sent(); + }); +} + +void SocketConnector::send(const Packet::MemBufPtr &packet) { + io_service_.post([this, packet]() { + bool write_in_progress = !output_buffer_.empty(); + output_buffer_.push_back(std::move(packet)); + if (TRANSPORT_EXPECT_FALSE(!is_connecting_)) { + if (!write_in_progress) { + doWrite(); + } + } else { + // Tell the handle connect it has data to write + data_available_ = true; + } + }); +} + +void SocketConnector::close() { + io_service_.post([this]() { socket_.close(); }); +} + +void SocketConnector::doWrite() { + // TODO improve this piece of code for sending many buffers togethers + // if list contains more than one packet + auto packet = output_buffer_.front().get(); + auto array = std::vector(); + + const utils::MemBuf *current = packet; + do { + array.push_back(asio::const_buffer(current->data(), current->length())); + current = current->next(); + } while (current != packet); + + asio::async_write( + socket_, std::move(array), + [this /*, packet*/](std::error_code ec, std::size_t length) { + if (TRANSPORT_EXPECT_TRUE(!ec)) { + output_buffer_.pop_front(); + if (!output_buffer_.empty()) { + doWrite(); + } + } else { + TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); + tryReconnect(); + } + }); +} + +void SocketConnector::doReadBody(std::size_t body_length) { + asio::async_read( + socket_, asio::buffer(read_msg_->writableTail(), body_length), + asio::transfer_exactly(body_length), + [this](std::error_code ec, std::size_t length) { + read_msg_->append(length); + if (TRANSPORT_EXPECT_TRUE(!ec)) { + receive_callback_(std::move(read_msg_)); + doReadHeader(); + } else { + TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); + tryReconnect(); + } + }); +} + +void SocketConnector::doReadHeader() { + read_msg_ = getPacket(); + asio::async_read( + socket_, + asio::buffer(read_msg_->writableData(), + NetworkMessage::fixed_header_length), + asio::transfer_exactly(NetworkMessage::fixed_header_length), + [this](std::error_code ec, std::size_t length) { + if (TRANSPORT_EXPECT_TRUE(!ec)) { + read_msg_->append(NetworkMessage::fixed_header_length); + std::size_t body_length = 0; + if ((body_length = NetworkMessage::decodeHeader(read_msg_->data())) > + 0) { + doReadBody(body_length - length); + } else { + TRANSPORT_LOGE("Decoding error. Ignoring packet."); + } + } else { + TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str()); + tryReconnect(); + } + }); +} + +void SocketConnector::tryReconnect() { + if (!is_connecting_) { + TRANSPORT_LOGE("Connection lost. Trying to reconnect...\n"); + is_connecting_ = true; + is_reconnection_ = true; + io_service_.post([this]() { + socket_.close(); + startConnectionTimer(); + doConnect(); + }); + } +} + +void SocketConnector::doConnect() { + asio::async_connect(socket_, endpoint_iterator_, + [this](std::error_code ec, tcp::resolver::iterator) { + if (!ec) { + timer_.cancel(); + is_connecting_ = false; + asio::ip::tcp::no_delay noDelayOption(true); + socket_.set_option(noDelayOption); + doReadHeader(); + + if (data_available_) { + data_available_ = false; + doWrite(); + } + + if (is_reconnection_) { + is_reconnection_ = false; + TRANSPORT_LOGI("Connection recovered!\n"); + on_reconnect_callback_(); + } + } else { + sleep(1); + doConnect(); + } + }); +} + +bool SocketConnector::checkConnected() { return !is_connecting_; } + +void SocketConnector::enableBurst() { return; } + +void SocketConnector::startConnectionTimer() { + timer_.expires_from_now(std::chrono::seconds(60)); + timer_.async_wait( + std::bind(&SocketConnector::handleDeadline, this, std::placeholders::_1)); +} + +void SocketConnector::handleDeadline(const std::error_code &ec) { + if (!ec) { + io_service_.post([this]() { + socket_.close(); + TRANSPORT_LOGE("Error connecting. Is the forwarder running?\n"); + io_service_.stop(); + }); + } +} + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/socket_connector.h b/libtransport/src/hicn/transport/core/socket_connector.h new file mode 100755 index 000000000..d7a05aab4 --- /dev/null +++ b/libtransport/src/hicn/transport/core/socket_connector.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include +#include + +namespace transport { +namespace core { + +using asio::ip::tcp; + +class SocketConnector : public Connector { + public: + SocketConnector(PacketReceivedCallback &&receive_callback, + OnReconnect &&reconnect_callback, + asio::io_service &io_service, + std::string app_name = "Libtransport"); + + ~SocketConnector() override; + + void send(const Packet::MemBufPtr &packet) override; + + void send(const uint8_t *packet, std::size_t len, + const PacketSentCallback &packet_sent = 0) override; + + void close() override; + + void enableBurst() override; + + void connect(std::string ip_address = "127.0.0.1", std::string port = "9695"); + + void state() override; + + private: + void doConnect(); + + void doReadHeader(); + + void doReadBody(std::size_t body_length); + + void doWrite(); + + bool checkConnected(); + + private: + void handleDeadline(const std::error_code &ec); + + void startConnectionTimer(); + + void tryReconnect(); + + asio::io_service &io_service_; + asio::ip::tcp::socket socket_; + asio::ip::tcp::resolver resolver_; + asio::ip::tcp::resolver::iterator endpoint_iterator_; + asio::steady_timer timer_; + + utils::ObjectPool::Ptr read_msg_; + + bool is_connecting_; + bool is_reconnection_; + bool data_available_; + + PacketReceivedCallback receive_callback_; + OnReconnect on_reconnect_callback_; + std::string app_name_; +}; + +} // end namespace core + +} // end namespace transport diff --git a/libtransport/src/hicn/transport/core/test/CMakeLists.txt b/libtransport/src/hicn/transport/core/test/CMakeLists.txt new file mode 100755 index 000000000..48c50e9b0 --- /dev/null +++ b/libtransport/src/hicn/transport/core/test/CMakeLists.txt @@ -0,0 +1,10 @@ +# Enable gcov output for the tests +add_definitions(--coverage) +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") + +set(TestsExpectedToPass + test_core_manifest) + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/test/test_core_manifest.cc b/libtransport/src/hicn/transport/core/test/test_core_manifest.cc new file mode 100755 index 000000000..58563d8f9 --- /dev/null +++ b/libtransport/src/hicn/transport/core/test/test_core_manifest.cc @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "../manifest_format_fixed.h" +#include "../manifest_inline.h" + +#include +#include +#include + +namespace transport { + +namespace core { + +namespace { +// The fixture for testing class Foo. +class ManifestTest : public ::testing::Test { + protected: + using ContentObjectManifest = ManifestInline; + + ManifestTest() : name_("b001::123|321"), manifest1_(name_) { + // You can do set-up work for each test here. + } + + virtual ~ManifestTest() { + // You can do clean-up work that doesn't throw exceptions here. + } + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + virtual void SetUp() { + // Code here will be called immediately after the constructor (right + // before each test). + } + + virtual void TearDown() { + // Code here will be called immediately after each test (right + // before the destructor). + } + + Name name_; + ContentObjectManifest manifest1_; + + std::vector 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, + // 0xd1, 0xf2, 0x2b, + // 0x94, 0x41, 0x22, + // 0xc9, 0x00, 0x00, + // 0x00, 0x44, 0xa3, + // 0xd1, 0xf2, 0x2b, + // 0x94, 0x41, 0x22, + // 0xc8 + }; +}; + +} // namespace + +TEST_F(ManifestTest, ManifestCreate) { + ContentObjectManifest manifest2(name_); + ContentObjectManifest manifest3 = manifest2; + + EXPECT_EQ(manifest1_, manifest2); + EXPECT_EQ(manifest1_, manifest3); +} + +TEST_F(ManifestTest, ManifestCreateFromBase) { + ContentObject content_object(name_); + content_object.setPayload(manifest_payload.data(), manifest_payload.size()); + ContentObjectManifest manifest(std::move(content_object)); + + auto manifest4 = ContentObjectManifest::createManifest( + name_, core::ManifestVersion::VERSION_1, + core::ManifestType::INLINE_MANIFEST, HashAlgorithm::SHA_256, true, + core::Name("b001::dead"), + core::NextSegmentCalculationStrategy::INCREMENTAL, 128); + + manifest4->encode(); + manifest4->dump(); + manifest.dump(); + + EXPECT_EQ(manifest1_, manifest); + // EXPECT_EQ(manifest1_, manifest3); +} + +TEST_F(ManifestTest, SetLastManifest) { + manifest1_.clear(); + + manifest1_.setFinalManifest(true); + manifest1_.encode(); + manifest1_.decode(); + bool fcn = manifest1_.isFinalManifest(); + + ASSERT_TRUE(fcn); +} + +TEST_F(ManifestTest, SetManifestType) { + manifest1_.clear(); + + ManifestType type1 = ManifestType::INLINE_MANIFEST; + ManifestType type2 = ManifestType::FLIC_MANIFEST; + + manifest1_.setManifestType(type1); + manifest1_.encode(); + manifest1_.decode(); + ManifestType type_returned1 = manifest1_.getManifestType(); + + manifest1_.clear(); + + manifest1_.setManifestType(type2); + manifest1_.encode(); + manifest1_.decode(); + ManifestType type_returned2 = manifest1_.getManifestType(); + + ASSERT_EQ(type1, type_returned1); + ASSERT_EQ(type2, type_returned2); +} + +TEST_F(ManifestTest, SetHashAlgorithm) { + manifest1_.clear(); + + HashAlgorithm hash1 = HashAlgorithm::SHA_512; + HashAlgorithm hash2 = HashAlgorithm::CRC32C; + HashAlgorithm hash3 = HashAlgorithm::SHA_256; + + manifest1_.setHashAlgorithm(hash1); + manifest1_.encode(); + manifest1_.decode(); + HashAlgorithm type_returned1 = manifest1_.getHashAlgorithm(); + + manifest1_.clear(); + + manifest1_.setHashAlgorithm(hash2); + manifest1_.encode(); + manifest1_.decode(); + HashAlgorithm type_returned2 = manifest1_.getHashAlgorithm(); + + manifest1_.clear(); + + manifest1_.setHashAlgorithm(hash3); + manifest1_.encode(); + manifest1_.decode(); + HashAlgorithm type_returned3 = manifest1_.getHashAlgorithm(); + + ASSERT_EQ(hash1, type_returned1); + ASSERT_EQ(hash2, type_returned2); + ASSERT_EQ(hash3, type_returned3); +} + +TEST_F(ManifestTest, SetNextSegmentCalculationStrategy) { + manifest1_.clear(); + + NextSegmentCalculationStrategy strategy1 = + NextSegmentCalculationStrategy::INCREMENTAL; + + manifest1_.setNextSegmentCalculationStrategy(strategy1); + manifest1_.encode(); + manifest1_.decode(); + NextSegmentCalculationStrategy type_returned1 = + manifest1_.getNextSegmentCalculationStrategy(); + + ASSERT_EQ(strategy1, type_returned1); +} + +TEST_F(ManifestTest, SetBaseName) { + manifest1_.clear(); + + core::Name base_name("b001::dead"); + manifest1_.setBaseName(base_name); + manifest1_.encode(); + manifest1_.decode(); + core::Name ret_name = manifest1_.getBaseName(); + + ASSERT_EQ(base_name, ret_name); +} + +TEST_F(ManifestTest, SetSuffixList) { + manifest1_.clear(); + + core::Name base_name("b001::dead"); + + using random_bytes_engine = + std::independent_bits_engine; + random_bytes_engine rbe; + + std::default_random_engine eng((std::random_device())()); + std::uniform_int_distribution idis( + 0, std::numeric_limits::max()); + + auto entries = new std::pair[3]; + uint32_t suffixes[3]; + std::vector data[3]; + + for (int i = 0; i < 3; i++) { + data[i].resize(32); + std::generate(std::begin(data[i]), std::end(data[i]), std::ref(rbe)); + suffixes[i] = idis(eng); + entries[i] = std::make_pair( + suffixes[i], utils::CryptoHash(data[i].data(), data[i].size(), + utils::CryptoHashType::SHA_256)); + manifest1_.addSuffixHash(entries[i].first, entries[i].second); + } + + manifest1_.setBaseName(base_name); + + manifest1_.encode(); + manifest1_.decode(); + + core::Name ret_name = manifest1_.getBaseName(); + + // auto & hash_list = manifest1_.getSuffixHashList(); + + bool cond; + int i = 0; + + // for (auto & item : manifest1_.getSuffixList()) { + // auto hash = manifest1_.getHash(suffixes[i]); + // cond = utils::CryptoHash::compareBinaryDigest(hash, + // entries[i].second.getDigest().data(), + // entries[i].second.getType()); + // ASSERT_TRUE(cond); + // i++; + // } + + ASSERT_EQ(base_name, ret_name); + + delete[] entries; +} + +TEST_F(ManifestTest, EstimateSize) { + manifest1_.clear(); + + HashAlgorithm hash1 = HashAlgorithm::SHA_256; + NextSegmentCalculationStrategy strategy1 = + NextSegmentCalculationStrategy::INCREMENTAL; + ManifestType type1 = ManifestType::INLINE_MANIFEST; + core::Name base_name1("b001:abcd:fede:baba:cece:d0d0:face:dead"); + + manifest1_.setFinalManifest(true); + manifest1_.setBaseName(base_name1); + manifest1_.setNextSegmentCalculationStrategy(strategy1); + manifest1_.setHashAlgorithm(hash1); + manifest1_.setManifestType(type1); + + std::default_random_engine eng((std::random_device())()); + std::uniform_int_distribution idis( + 0, std::numeric_limits::max()); + + using random_bytes_engine = + std::independent_bits_engine; + random_bytes_engine rbe; + + while (manifest1_.estimateManifestSize(1) < 1440) { + uint32_t suffix = static_cast(idis(eng)); + std::vector data(32); + std::generate(std::begin(data), std::end(data), std::ref(rbe)); + auto hash = utils::CryptoHash(data.data(), data.size(), + utils::CryptoHashType::SHA_256); + manifest1_.addSuffixHash(suffix, hash); + } + + manifest1_.encode(); + manifest1_.decode(); + + manifest1_.dump(); + + ASSERT_GT(manifest1_.estimateManifestSize(), 0); + ASSERT_LT(manifest1_.estimateManifestSize(), 1500); +} + +} // namespace core + +} // namespace transport + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/vpp_binary_api.c b/libtransport/src/hicn/transport/core/vpp_binary_api.c new file mode 100755 index 000000000..ab23d3cf5 --- /dev/null +++ b/libtransport/src/hicn/transport/core/vpp_binary_api.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#ifdef __vpp__ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#define vl_typedefs +#include +#undef vl_typedefs + +#define vl_endianfun +#include +#undef vl_endianfun + +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get CRC codes of the messages */ +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list + +// #define vl_api_version(n,v) static u32 vpe_api_version = (v); +// #include +// #undef vl_api_version + +#define POINTER_MAP_SIZE 32 +static void *global_pointers_map[POINTER_MAP_SIZE]; +static uint8_t global_pointers_map_index = 0; + +/* + * Table of message reply handlers, must include boilerplate handlers + * we just generated + */ +#define foreach_memif_api_reply_msg \ + _(MEMIF_CREATE_REPLY, memif_create_reply) \ + _(MEMIF_DELETE_REPLY, memif_delete_reply) \ + _(MEMIF_DETAILS, memif_details) + +/** + * @brief Generic VPP request structure. + */ +typedef struct __attribute__((packed)) vl_generic_request_s { + u16 _vl_msg_id; + u32 client_index; + u32 context; +} vl_generic_request_t; + +/** + * @brief Generic VPP reply structure (response with a single message). + */ +typedef struct __attribute__((packed)) vl_generic_reply_s { + u16 _vl_msg_id; + u32 context; + i32 retval; +} vl_generic_reply_t; + +static void vl_api_control_ping_reply_t_handler( + vl_api_control_ping_reply_t *mp) { + // Just unblock main thread + vpp_binary_api_t *binary_api = global_pointers_map[mp->context]; + binary_api->ret_val = ntohl(mp->retval); + vpp_binary_api_unlock_waiting_thread(binary_api); +} + +static void vl_api_sw_interface_set_flags_reply_t_handler( + vl_api_control_ping_reply_t *mp) { + // Unblock main thread setting reply message status code + vpp_binary_api_t *binary_api = global_pointers_map[mp->context]; + binary_api->ret_val = ntohl(mp->retval); + vpp_binary_api_unlock_waiting_thread(binary_api); +} + +static int vpp_connect_to_vlib(vpp_binary_api_t *binary_api, char *name) { + clib_mem_init_thread_safe(0, 256 << 20); + if (vl_client_connect_to_vlib("/vpe-api", name, 32) < 0) { + return -1; + } + + binary_api->vl_input_queue = binary_api->api_main->shmem_hdr->vl_input_queue; + binary_api->my_client_index = binary_api->api_main->my_client_index; + + return 0; +} + +vpp_binary_api_t *vpp_binary_api_init(const char *app_name) { + vpp_binary_api_t *ret = malloc(sizeof(vpp_binary_api_t)); + ret->api_main = &api_main; + ret->vlib_main = &vlib_global_main; + + vpp_connect_to_vlib(ret, (char *)app_name); + ret->semaphore = sem_open(app_name, O_CREAT, 0, 0); + + return ret; +} + +void vpp_binary_api_destroy(vpp_binary_api_t *api) { + sem_close(api->semaphore); + free(api); + vl_client_disconnect_from_vlib(); +} + +void vpp_binary_api_unlock_waiting_thread(vpp_binary_api_t *api) { + sem_post(api->semaphore); +} + +void vpp_binary_api_send_receive_ping(vpp_binary_api_t *api) { + /* Use a control ping for synchronization */ + + /* Get the control ping ID */ +#define _(id, n, crc) \ + const char *id##_CRC __attribute__((unused)) = #n "_" #crc; + foreach_vl_msg_name_crc_vpe; +#undef _ + + int ping_reply_id = + vl_msg_api_get_msg_index((u8 *)(VL_API_CONTROL_PING_REPLY_CRC)); + vl_msg_api_set_handlers(ping_reply_id, "control_ping_reply", + vl_api_control_ping_reply_t_handler, vl_noop_handler, + vl_api_control_ping_reply_t_endian, + vl_api_control_ping_reply_t_print, + sizeof(vl_api_control_ping_reply_t), 1); + + vl_api_control_ping_t *mp_ping; + mp_ping = vl_msg_api_alloc_as_if_client(sizeof(*mp_ping)); + mp_ping->_vl_msg_id = clib_host_to_net_u16( + vl_msg_api_get_msg_index((u8 *)(VL_API_CONTROL_PING_CRC))); + mp_ping->client_index = api->my_client_index; + + global_pointers_map[global_pointers_map_index] = api; + mp_ping->context = global_pointers_map_index++; + global_pointers_map_index %= POINTER_MAP_SIZE; + + TRANSPORT_LOGI("Sending ping id %u", mp_ping->_vl_msg_id); + + vpp_binary_api_send_request_wait_reply(api, mp_ping); +} + +int vpp_binary_api_set_int_state(vpp_binary_api_t *api, uint32_t sw_index, + link_state_t state) { +#define _(id, n, crc) \ + const char *id##_CRC __attribute__((unused)) = #n "_" #crc; + foreach_vl_msg_name_crc_vpe; +#undef _ + + int sw_interface_set_flags_reply_id = VL_API_SW_INTERFACE_SET_FLAGS_REPLY; + vl_msg_api_set_handlers( + sw_interface_set_flags_reply_id, "sw_interface_set_flags_reply", + vl_api_sw_interface_set_flags_reply_t_handler, vl_noop_handler, + vl_api_sw_interface_set_flags_reply_t_endian, + vl_api_sw_interface_set_flags_reply_t_print, + sizeof(vl_api_sw_interface_set_flags_reply_t), 1); + + vl_api_sw_interface_set_flags_t *mp; + mp = vl_msg_api_alloc_as_if_client(sizeof(*mp)); + mp->_vl_msg_id = clib_host_to_net_u16(VL_API_SW_INTERFACE_SET_FLAGS); + mp->client_index = api->my_client_index; + mp->sw_if_index = clib_host_to_net_u32(sw_index); + mp->admin_up_down = (u8)state; + + global_pointers_map[global_pointers_map_index] = api; + mp->context = global_pointers_map_index++; + global_pointers_map_index %= POINTER_MAP_SIZE; + + TRANSPORT_LOGI("Sending set int flags id %u", mp->_vl_msg_id); + + return vpp_binary_api_send_request_wait_reply(api, mp); +} + +void vpp_binary_api_send_request(vpp_binary_api_t *api, void *request) { + vl_generic_request_t *req = NULL; + + req = (vl_generic_request_t *)request; + TRANSPORT_LOGI("Sending a request to VPP (id=%d).\n", ntohs(req->_vl_msg_id)); + + S(api, req); +} + +int vpp_binary_api_send_request_wait_reply(vpp_binary_api_t *api, + void *request) { + vpp_binary_api_send_request(api, request); + + sem_wait(api->semaphore); + + return api->ret_val; +} + +#endif // __vpp__ \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/vpp_binary_api.h b/libtransport/src/hicn/transport/core/vpp_binary_api.h new file mode 100755 index 000000000..1eb10e766 --- /dev/null +++ b/libtransport/src/hicn/transport/core/vpp_binary_api.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#ifdef __vpp__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct vpp_binary_api vpp_binary_api_t; +typedef struct vpp_plugin_binary_api vpp_plugin_binary_api_t; + +typedef enum link_state_s { UP = 1, DOWN = 0 } link_state_t; + +/** + * @brief Instantiate a new vpp_binary_api_t data structure and + * connect the application to the local VPP forwarder. + */ +vpp_binary_api_t* vpp_binary_api_init(const char* app_name); + +/** + * @brief Destroy the vpp_binary_api_t and disconnect from VPP. + */ +void vpp_binary_api_destroy(vpp_binary_api_t* api); + +void vpp_binary_api_send_receive_ping(vpp_binary_api_t* api); + +int vpp_binary_api_set_int_state(vpp_binary_api_t* api, uint32_t sw_index, + link_state_t state); + +/** + * @brief Send request to VPP and wait for reply. + */ +int vpp_binary_api_send_request_wait_reply(vpp_binary_api_t* api, + void* request); + +void vpp_binary_api_unlock_waiting_thread(vpp_binary_api_t* api); + +void vpp_binary_api_send_request(vpp_binary_api_t* api, void* request); + +#ifdef __cplusplus +} +#endif + +#endif // __vpp__ \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/vpp_binary_api_internal.h b/libtransport/src/hicn/transport/core/vpp_binary_api_internal.h new file mode 100755 index 000000000..22b665e96 --- /dev/null +++ b/libtransport/src/hicn/transport/core/vpp_binary_api_internal.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#ifdef __vpp__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +struct vpp_binary_api { + api_main_t *api_main; + u32 my_client_index; + unix_shared_memory_queue_t *vl_input_queue; + vlib_main_t *vlib_main; + sem_t *semaphore; + u32 ping_id; + int ret_val; + void *user_param; +}; + +struct vpp_plugin_binary_api { + vpp_binary_api_t *vpp_api; + u16 msg_id_base; + u32 my_client_index; +}; + +#define M(T, mp) \ + do { \ + mp = vl_msg_api_alloc_as_if_client(sizeof(*mp)); \ + memset(mp, 0, sizeof(*mp)); \ + mp->_vl_msg_id = ntohs(VL_API_##T + hm->msg_id_base); \ + mp->client_index = hm->my_client_index; \ + } while (0); + +#define S(api, mp) (vl_msg_api_send_shmem(api->vl_input_queue, (u8 *)&mp)) + +#ifdef __cplusplus +} +#endif + +#endif // __vpp__ \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc b/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc new file mode 100755 index 000000000..3a748c821 --- /dev/null +++ b/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#ifdef __vpp__ + +#include +#include +#include + +typedef enum { MASTER = 0, SLAVE = 1 } memif_role_t; + +#define MEMIF_DEFAULT_RING_SIZE 2048 +#define MEMIF_DEFAULT_RX_QUEUES 1 +#define MEMIF_DEFAULT_TX_QUEUES 1 +#define MEMIF_DEFAULT_BUFFER_SIZE 2048 + +namespace transport { + +namespace core { + +vpp_binary_api_t *VPPForwarderInterface::api_ = nullptr; +vpp_plugin_binary_api_t *VPPForwarderInterface::memif_api_ = nullptr; +vpp_plugin_binary_api_t *VPPForwarderInterface::hicn_api_ = nullptr; +std::mutex VPPForwarderInterface::global_lock_; + +VPPForwarderInterface::VPPForwarderInterface(MemifConnector &connector) + : ForwarderInterface(connector), + sw_if_index_(~0), + face_id_(~0) {} + +VPPForwarderInterface::~VPPForwarderInterface() {} + +/** + * @brief Create a memif interface in the local VPP forwarder. + */ +uint32_t VPPForwarderInterface::getMemifConfiguration() { + memif_create_params_t input_params = {0}; + + memif_id_ = + memif_binary_api_get_next_memif_id(VPPForwarderInterface::memif_api_); + + input_params.id = memif_id_; + input_params.role = memif_role_t::MASTER; + input_params.mode = memif_interface_mode_t::MEMIF_INTERFACE_MODE_IP; + input_params.rx_queues = MEMIF_DEFAULT_RX_QUEUES; + input_params.tx_queues = MEMIF_DEFAULT_TX_QUEUES; + input_params.ring_size = MEMIF_DEFAULT_RING_SIZE; + input_params.buffer_size = MEMIF_DEFAULT_BUFFER_SIZE; + + memif_output_params_t output_params = {0}; + + if (memif_binary_api_create_memif(VPPForwarderInterface::memif_api_, + &input_params, &output_params) < 0) { + throw errors::RuntimeException( + "Error creating memif interface in the local VPP forwarder."); + } + + return output_params.sw_if_index; +} + +void VPPForwarderInterface::consumerConnection() { + hicn_consumer_input_params input = {0}; + hicn_consumer_output_params output; + + std::memset(&output, 0, sizeof(hicn_consumer_output_params)); + + input.swif = sw_if_index_; + + if (int ret = hicn_binary_api_register_cons_app( + VPPForwarderInterface::hicn_api_, &input, &output) < 0) { + throw errors::RuntimeException(hicn_binary_api_get_error_string(ret)); + } + + inet_address_.family = AF_INET; + inet_address_.prefix_len = output.src4.prefix_length; + std::memcpy(inet_address_.buffer, output.src4.ip4.as_u8, IPV4_ADDR_LEN); + + inet6_address_.family = AF_INET6; + inet6_address_.prefix_len = output.src6.prefix_length; + std::memcpy(inet6_address_.buffer, output.src6.ip6.as_u8, IPV6_ADDR_LEN); +} + +void VPPForwarderInterface::producerConnection() { + // Producer connection will be set when we set the first route. +} + +void VPPForwarderInterface::connect(bool is_consumer) { + std::lock_guard connection_lock(global_lock_); + + srand(time(NULL)); + int secret = rand() % (1 << 10); + std::stringstream app_name; + app_name << "Libtransport_" << secret; + + if (!VPPForwarderInterface::memif_api_) { + VPPForwarderInterface::api_ = vpp_binary_api_init(app_name.str().c_str()); + } + + VPPForwarderInterface::memif_api_ = + memif_binary_api_init(VPPForwarderInterface::api_); + + sw_if_index_ = getMemifConfiguration(); + + VPPForwarderInterface::hicn_api_ = + hicn_binary_api_init(VPPForwarderInterface::api_); + if (is_consumer) { + consumerConnection(); + } + + connector_.connect(memif_id_, 0); +} + +void VPPForwarderInterface::registerRoute(Prefix &prefix) { + auto &addr = prefix.toIpAddressStruct(); + + if (face_id_ == uint32_t(~0)) { + hicn_producer_input_params input; + std::memset(&input, 0, sizeof(input)); + + hicn_producer_output_params output; + std::memset(&output, 0, sizeof(output)); + + // Here we have to ask to the actual connector what is the + // memif_id, since this function should be called after the + // memif creation. + input.swif = sw_if_index_; + input.prefix.ip6.as_u64[0] = addr.as_u64[0]; + input.prefix.ip6.as_u64[1] = addr.as_u64[1]; + input.prefix.type = addr.family == AF_INET6 ? IP_TYPE_IP6 : IP_TYPE_IP4; + input.prefix.prefix_length = addr.prefix_len; + input.cs_reserved = content_store_reserved_; + + if (int ret = hicn_binary_api_register_prod_app( + VPPForwarderInterface::hicn_api_, &input, &output) < 0) { + throw errors::RuntimeException(hicn_binary_api_get_error_string(ret)); + } + + if (addr.family == AF_INET6) { + inet6_address_.prefix_len = output.prod_addr.prefix_length; + std::memcpy(inet6_address_.buffer, output.prod_addr.ip6.as_u8, + IPV6_ADDR_LEN); + } else { + inet_address_.prefix_len = output.prod_addr.prefix_length; + // The ipv4 is written in the last 4 bytes of the ipv6 address, so we need + // to copy from the byte 12 + std::memcpy(inet_address_.buffer, output.prod_addr.ip6.as_u8 + 12, + IPV4_ADDR_LEN); + } + + face_id_ = output.face_id; + } else { + hicn_producer_set_route_params params; + params.prefix.ip6.as_u64[0] = addr.as_u64[0]; + params.prefix.ip6.as_u64[1] = addr.as_u64[1]; + params.prefix.type = addr.family == AF_INET6 ? IP_TYPE_IP6 : IP_TYPE_IP4; + params.prefix.prefix_length = addr.prefix_len; + params.face_id = face_id_; + + if (int ret = hicn_binary_api_register_route( + VPPForwarderInterface::hicn_api_, ¶ms) < 0) { + throw errors::RuntimeException(hicn_binary_api_get_error_string(ret)); + } + } +} + +} // namespace core + +} // namespace transport + +#endif \ No newline at end of file diff --git a/libtransport/src/hicn/transport/core/vpp_forwarder_interface.h b/libtransport/src/hicn/transport/core/vpp_forwarder_interface.h new file mode 100755 index 000000000..322cd1f8b --- /dev/null +++ b/libtransport/src/hicn/transport/core/vpp_forwarder_interface.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#ifdef __vpp__ + +#include +#include +#include + +#include + +namespace transport { + +namespace core { + +class VPPForwarderInterface + : public ForwarderInterface { + public: + VPPForwarderInterface(MemifConnector &connector); + + typedef MemifConnector ConnectorType; + + ~VPPForwarderInterface(); + + void connect(bool is_consumer); + + void registerRoute(Prefix &prefix); + + TRANSPORT_ALWAYS_INLINE std::uint16_t getMtu() { return interface_mtu; } + + private: + uint32_t getMemifConfiguration(); + + void consumerConnection(); + + void producerConnection(); + + static vpp_binary_api_t *api_; + static vpp_plugin_binary_api_t *memif_api_; + static vpp_plugin_binary_api_t *hicn_api_; + uint32_t memif_id_; + uint32_t sw_if_index_; + uint32_t face_id_; + static std::mutex global_lock_; + static constexpr std::uint16_t interface_mtu = 1500; +}; + +} // namespace core + +} // namespace transport + +#endif \ No newline at end of file -- cgit 1.2.3-korg