diff options
337 files changed, 13090 insertions, 13478 deletions
@@ -1,5 +1,5 @@ [tool] [tool.commitizen] name = "cz_conventional_commits" -version = "3.11.3" +version = "3.13.0" tag_format = "v$version" diff --git a/.gitignore b/.gitignore index 9099d8d0a..cbdd34811 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ tests/**/*.xml tests/**/*.html tests/**/*.log *.tar +**/env
\ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 27afca29b..41ecda018 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,32 @@ # See the License for the specific language governing permissions and # limitations under the License. + +############################################################## +# Compiler preferences +############################################################## +set(CMAKE_C_COMPILER_NAMES + clang-13 + clang-12 + clang-11 + clang-10 + clang-9 + gcc-10 + gcc-9 + cc +) + +set(CMAKE_CXX_COMPILER_NAMES + clang++-13 + clang++-12 + clang++-11 + clang++-10 + clang++-9 + g++-10 + g++-9 + c++ +) + ############################################################## # Project and cmake version ############################################################## diff --git a/Dockerfile.dev b/Dockerfile.dev index cfb75f1b4..9c96193a9 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,17 +1,16 @@ -FROM dockerhub.cisco.com/icn-docker/hicn-base-devel-focal:x86_64 +FROM ubuntu:focal +ENV DEBIAN_FRONTEND=noninteractive WORKDIR /hicn-build -# Get versions from versions.cmake -ARG VERSION_PATH=/tmp/versions.cmake -COPY versions.cmake ${VERSION_PATH} -ARG INSTALL_VPP_SCRIPT=/tmp/install-vpp.sh -COPY scripts/install-vpp.sh ${INSTALL_VPP_SCRIPT} +COPY Makefile versions.cmake ./ +COPY scripts scripts/ -RUN VERSION_PATH=${VERSION_PATH} bash -x ${INSTALL_VPP_SCRIPT} -RUN apt update && apt-get install -y \ - libssl-dev \ - iproute2 \ - iperf3 \ - iputils-ping \ - tcpdump \ - gdb --no-install-recommends +RUN apt update && apt-get install -y \ + make \ + sudo \ + curl \ + git + +RUN make deps debug-tools + +ENV DEBIAN_FRONTEND= @@ -47,15 +47,18 @@ endif DEB_DEPENDS = cmake ninja-build unzip python3-ply libasio-dev DEB_DEPENDS += libconfig-dev libconfig++-dev libevent-dev DEB_DEPENDS += build-essential vpp-dev libvppinfra-dev -DEB_DEPENDS += vpp-plugin-core libcurl4-openssl-dev +DEB_DEPENDS += vpp-plugin-core libcurl4-openssl-dev libssl-dev DEB_DEPENDS += doxygen -MACOS_DEPENDS = asio libconfig ninja +DEBUG_DEPENDS = iproute2 iperf3 iputils-ping tcpdump gdb + +MACOS_DEPENDS = asio libconfig ninja openssl@1.1 .PHONY = help help: @echo "Targets" @echo " dep - install software dependencies" + @echo " debug-tools - install debug dependencies" @echo " build - build debug binaries. Optional argument: INSTALL_DIR" @echo " build-release - build release binaries" @echo " build-coverage - build with coverage metainformation" @@ -97,6 +100,10 @@ endif .PHONY = deps deps: dep +.PHONY = debug-tools +debug-tools: + @sudo -E apt-get $(APT_ARGS) -y install $(DEBUG_DEPENDS) --no-install-recommends + define build_folder $(eval LOWER_BUILDTYPE=$(shell echo $(2) | tr A-Z a-z)) $(eval BUILD_FOLDER=$(or $(BUILD_PATH), build-$(LOWER_BUILDTYPE)-$(OS_ID))) diff --git a/apps/hiperf/CMakeLists.txt b/apps/hiperf/CMakeLists.txt index 6986c90aa..8a0c46ebc 100644 --- a/apps/hiperf/CMakeLists.txt +++ b/apps/hiperf/CMakeLists.txt @@ -19,7 +19,6 @@ if (NOT DISABLE_EXECUTABLES) ${CMAKE_CURRENT_SOURCE_DIR}/src/client.cc ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cc ${CMAKE_CURRENT_SOURCE_DIR}/src/server.cc - ${CMAKE_CURRENT_SOURCE_DIR}/src/forwarder_interface.cc ) diff --git a/apps/hiperf/src/client.cc b/apps/hiperf/src/client.cc index ba36cd20e..0e1f596c5 100644 --- a/apps/hiperf/src/client.cc +++ b/apps/hiperf/src/client.cc @@ -14,8 +14,7 @@ */ #include <client.h> -#include <forwarder_config.h> -#include <forwarder_interface.h> +#include <hicn/transport/portability/endianess.h> #include <libconfig.h++> @@ -31,1098 +30,831 @@ class Callback; * Hiperf client class: configure and setup an hicn consumer following the * ClientConfiguration. */ -class HIperfClient::Impl : ForwarderInterface::ICallback { +class HIperfClient::Impl { friend class Callback; friend class RTCCallback; - static const constexpr uint16_t log2_header_counter = 4; - - struct nack_packet_t { - uint64_t timestamp; - uint32_t prod_rate; - uint32_t prod_seg; - - inline uint64_t getTimestamp() const { return _ntohll(×tamp); } - inline void setTimestamp(uint64_t time) { timestamp = _htonll(&time); } - - inline uint32_t getProductionRate() const { return ntohl(prod_rate); } - inline void setProductionRate(uint32_t rate) { prod_rate = htonl(rate); } - - inline uint32_t getProductionSegement() const { return ntohl(prod_seg); } - inline void setProductionSegement(uint32_t seg) { prod_seg = htonl(seg); } - }; - - public: - Impl(const hiperf::ClientConfiguration &conf) - : configuration_(conf), - total_duration_milliseconds_(0), - old_bytes_value_(0), - old_interest_tx_value_(0), - old_fec_interest_tx_value_(0), - old_fec_data_rx_value_(0), - old_lost_data_value_(0), - old_bytes_recovered_value_(0), - old_definitely_lost_data_value_(0), - old_retx_value_(0), - old_sent_int_value_(0), - old_received_nacks_value_(0), - old_fec_pkt_(0), - avg_data_delay_(0), - delay_sample_(0), - received_bytes_(0), - received_data_pkt_(0), - auth_alerts_(0), - data_delays_(""), - signals_(io_service_), - rtc_callback_(*this), - callback_(*this), - socket_(io_service_), - // switch_threshold_(~0), - fwd_connected_(false), - use_bestpath_(false), - rtt_threshold_(~0), - loss_threshold_(~0), - prefix_name_(""), - prefix_len_(0), - // done_(false), - header_counter_mask_((1 << log2_header_counter) - 1), - header_counter_(0), - print_headers_(configuration_.print_headers_), - first_(true), - forwarder_interface_(io_service_) { - setForwarderConnection(conf.forwarder_type_); + static inline constexpr uint16_t klog2_header_counter() { return 4; } + static inline constexpr uint16_t kheader_counter_mask() { + return (1 << klog2_header_counter()) - 1; } - virtual ~Impl() {} - - void checkReceivedRtcContent(ConsumerSocket &c, - const ContentObject &contentObject) {} - - void processLeavingInterest(ConsumerSocket &c, const Interest &interest) {} - - void addFace(const std::string &local_address, uint16_t local_port, - const std::string &remote_address, uint16_t remote_port, - std::string interface); - - void handleTimerExpiration(ConsumerSocket &c, - const TransportStatistics &stats) { - const char separator = ' '; - const int width = 18; - - utils::SteadyTime::TimePoint t2 = utils::SteadyTime::Clock::now(); - auto exact_duration = utils::SteadyTime::getDurationMs(t_stats_, t2); - - std::stringstream interval_ms; - interval_ms << total_duration_milliseconds_ << "-" - << total_duration_milliseconds_ + exact_duration.count(); - - std::stringstream bytes_transferred; - bytes_transferred << std::fixed << std::setprecision(3) - << (stats.getBytesRecv() - old_bytes_value_) / 1000000.0 - << std::setfill(separator); - - std::stringstream bandwidth; - bandwidth << ((stats.getBytesRecv() - old_bytes_value_) * 8) / - (exact_duration.count()) / 1000.0 - << std::setfill(separator); - - std::stringstream window; - window << stats.getAverageWindowSize() << std::setfill(separator); + class ConsumerContext + : public Base<ConsumerContext, ClientConfiguration, Impl>, + private ConsumerSocket::ReadCallback { + static inline const std::size_t kmtu = HIPERF_MTU; - std::stringstream avg_rtt; - avg_rtt << stats.getAverageRtt() << std::setfill(separator); - - if (configuration_.rtc_) { - std::stringstream lost_data; - lost_data << stats.getLostData() - old_lost_data_value_ - << std::setfill(separator); - - std::stringstream bytes_recovered_data; - bytes_recovered_data << stats.getBytesRecoveredData() - - old_bytes_recovered_value_ - << std::setfill(separator); - - std::stringstream definitely_lost_data; - definitely_lost_data << stats.getDefinitelyLostData() - - old_definitely_lost_data_value_ - << std::setfill(separator); - - std::stringstream data_delay; - data_delay << std::fixed << std::setprecision(3) << avg_data_delay_ - << std::setfill(separator); - - std::stringstream received_data_pkt; - received_data_pkt << received_data_pkt_ << std::setfill(separator); - - std::stringstream goodput; - goodput << std::fixed << std::setprecision(3) - << (received_bytes_ * 8.0) / (exact_duration.count()) / 1000.0 - << std::setfill(separator); - - std::stringstream loss_rate; - loss_rate << std::fixed << std::setprecision(2) - << stats.getLossRatio() * 100.0 << std::setfill(separator); - - std::stringstream retx_sent; - retx_sent << stats.getRetxCount() - old_retx_value_ - << std::setfill(separator); - - std::stringstream interest_sent; - interest_sent << stats.getInterestTx() - old_sent_int_value_ - << std::setfill(separator); + public: + using ConfType = ClientConfiguration; + using ParentType = typename HIperfClient::Impl; + static inline auto getContextType() -> std::string { + return "ConsumerContext"; + } + + ConsumerContext(Impl &client, int consumer_identifier) + : Base(client, client.io_service_, consumer_identifier), + receive_buffer_( + utils::MemBuf::create(client.config_.receive_buffer_size_)), + socket_(client.io_service_), + payload_size_max_(PayloadSize(client.config_.packet_format_) + .getPayloadSizeMax(RTC_HEADER_SIZE)), + nb_iterations_(client.config_.nb_iterations_) {} + + ConsumerContext(ConsumerContext &&other) noexcept + : Base(std::move(other)), + receive_buffer_(std::move(other.receive_buffer_)), + socket_(std::move(other.socket_)), + payload_size_max_(other.payload_size_max_), + remote_(std::move(other.remote_)), + nb_iterations_(other.nb_iterations_), + saved_stats_(std::move(other.saved_stats_)), + header_counter_(other.header_counter_), + first_(other.first_), + consumer_socket_(std::move(other.consumer_socket_)), + producer_socket_(std::move(other.producer_socket_)) {} + + ~ConsumerContext() override = default; + + /*************************************************************** + * ConsumerSocket::ReadCallback implementation + ***************************************************************/ - std::stringstream nacks; - nacks << stats.getReceivedNacks() - old_received_nacks_value_ - << std::setfill(separator); + bool isBufferMovable() noexcept override { return false; } - std::stringstream fec_pkt; - fec_pkt << stats.getReceivedFEC() - old_fec_pkt_ - << std::setfill(separator); + void getReadBuffer(uint8_t **application_buffer, + size_t *max_length) override { + *application_buffer = receive_buffer_->writableData(); - std::stringstream queuing_delay; - queuing_delay << std::fixed << std::setprecision(3) - << stats.getQueuingDelay() << std::setfill(separator); + if (configuration_.rtc_) { + *max_length = kmtu; + } else { + *max_length = configuration_.receive_buffer_size_; + } + } - std::stringstream residual_losses; - double rl_perc = stats.getResidualLossRate() * 100; - residual_losses << std::fixed << std::setprecision(2) << rl_perc - << std::setfill(separator); + void readBufferAvailable( + std::unique_ptr<utils::MemBuf> &&buffer) noexcept override { + // Nothing to do here + auto ret = std::move(buffer); + } - std::stringstream quality_score; - quality_score << std::fixed << (int)stats.getQualityScore() - << std::setfill(separator); + void readDataAvailable(std::size_t length) noexcept override { + if (configuration_.rtc_) { + saved_stats_.received_bytes_ += length; + saved_stats_.received_data_pkt_++; - std::stringstream alerts; - alerts << stats.getAlerts() << std::setfill(separator); + // collecting delay stats. Just for performance testing + auto senderTimeStamp = + *reinterpret_cast<uint64_t *>(receive_buffer_->writableData()); - std::stringstream auth_alerts; - auth_alerts << auth_alerts_ << std::setfill(separator); + auto now = utils::SystemTime::nowMs().count(); + auto new_delay = double(now - senderTimeStamp); - if (fwd_connected_ && use_bestpath_ && - ((stats.getAverageRtt() > rtt_threshold_) || - ((stats.getResidualLossRate() * 100) > loss_threshold_))) { - forwarder_interface_.setStrategy(prefix_name_, prefix_len_, "bestpath"); - } + if (senderTimeStamp > now) + new_delay = -1 * double(senderTimeStamp - now); - if ((header_counter_ == 0 && print_headers_) || first_) { - std::cout << std::right << std::setw(width) << "Interval[ms]"; - std::cout << std::right << std::setw(width) << "RecvData[pkt]"; - std::cout << std::right << std::setw(width) << "Bandwidth[Mbps]"; - std::cout << std::right << std::setw(width) << "Goodput[Mbps]"; - std::cout << std::right << std::setw(width) << "LossRate[%]"; - std::cout << std::right << std::setw(width) << "Retr[pkt]"; - std::cout << std::right << std::setw(width) << "InterestSent"; - std::cout << std::right << std::setw(width) << "ReceivedNacks"; - std::cout << std::right << std::setw(width) << "SyncWnd[pkt]"; - std::cout << std::right << std::setw(width) << "MinRtt[ms]"; - std::cout << std::right << std::setw(width) << "QueuingDelay[ms]"; - std::cout << std::right << std::setw(width) << "LostData[pkt]"; - std::cout << std::right << std::setw(width) << "RecoveredData"; - std::cout << std::right << std::setw(width) << "DefinitelyLost"; - std::cout << std::right << std::setw(width) << "State"; - std::cout << std::right << std::setw(width) << "DataDelay[ms]"; - std::cout << std::right << std::setw(width) << "FecPkt"; - std::cout << std::right << std::setw(width) << "Congestion"; - std::cout << std::right << std::setw(width) << "ResidualLosses"; - std::cout << std::right << std::setw(width) << "QualityScore"; - std::cout << std::right << std::setw(width) << "Alerts"; - std::cout << std::right << std::setw(width) << "AuthAlerts" - << std::endl; - - first_ = false; - } + saved_stats_.delay_sample_++; + saved_stats_.avg_data_delay_ = + saved_stats_.avg_data_delay_ + + (double(new_delay) - saved_stats_.avg_data_delay_) / + saved_stats_.delay_sample_; - std::cout << std::right << std::setw(width) << interval_ms.str(); - std::cout << std::right << std::setw(width) << received_data_pkt.str(); - std::cout << std::right << std::setw(width) << bandwidth.str(); - std::cout << std::right << std::setw(width) << goodput.str(); - std::cout << std::right << std::setw(width) << loss_rate.str(); - std::cout << std::right << std::setw(width) << retx_sent.str(); - std::cout << std::right << std::setw(width) << interest_sent.str(); - std::cout << std::right << std::setw(width) << nacks.str(); - std::cout << std::right << std::setw(width) << window.str(); - std::cout << std::right << std::setw(width) << avg_rtt.str(); - std::cout << std::right << std::setw(width) << queuing_delay.str(); - std::cout << std::right << std::setw(width) << lost_data.str(); - std::cout << std::right << std::setw(width) << bytes_recovered_data.str(); - std::cout << std::right << std::setw(width) << definitely_lost_data.str(); - std::cout << std::right << std::setw(width) << stats.getCCStatus(); - std::cout << std::right << std::setw(width) << data_delay.str(); - std::cout << std::right << std::setw(width) << fec_pkt.str(); - std::cout << std::right << std::setw(width) << stats.isCongested(); - std::cout << std::right << std::setw(width) << residual_losses.str(); - std::cout << std::right << std::setw(width) << quality_score.str(); - std::cout << std::right << std::setw(width) << alerts.str(); - std::cout << std::right << std::setw(width) << auth_alerts.str(); - std::cout << std::endl; - - if (configuration_.test_mode_) { - if (data_delays_.size() > 0) data_delays_.pop_back(); - - auto now = utils::SteadyTime::nowMs(); - std::cout << std::fixed << std::setprecision(0) << now.count() - << " DATA-DELAYS:[" << data_delays_ << "]" << std::endl; - } + if (configuration_.test_mode_) { + saved_stats_.data_delays_ += std::to_string(int(new_delay)); + saved_stats_.data_delays_ += ","; + } - // statistics not yet available in the transport - // std::cout << std::right << std::setw(width) << interest_fec_tx.str(); - // std::cout << std::right << std::setw(width) << bytes_fec_recv.str(); - } else { - if ((header_counter_ == 0 && print_headers_) || first_) { - std::cout << std::right << std::setw(width) << "Interval[ms]"; - std::cout << std::right << std::setw(width) << "Transfer[MB]"; - std::cout << std::right << std::setw(width) << "Bandwidth[Mbps]"; - std::cout << std::right << std::setw(width) << "Retr[pkt]"; - std::cout << std::right << std::setw(width) << "Cwnd[Int]"; - std::cout << std::right << std::setw(width) << "AvgRtt[ms]" - << std::endl; - - first_ = false; + if (configuration_.relay_ && configuration_.parallel_flows_ == 1) { + producer_socket_->produceDatagram( + configuration_.relay_name_.makeName(), + receive_buffer_->writableData(), + length < payload_size_max_ ? length : payload_size_max_); + } + if (configuration_.output_stream_mode_ && + configuration_.parallel_flows_ == 1) { + const uint8_t *start = receive_buffer_->writableData(); + start += sizeof(uint64_t); + std::size_t pkt_len = length - sizeof(uint64_t); + socket_.send_to(asio::buffer(start, pkt_len), remote_); + } } - - std::cout << std::right << std::setw(width) << interval_ms.str(); - std::cout << std::right << std::setw(width) << bytes_transferred.str(); - std::cout << std::right << std::setw(width) << bandwidth.str(); - std::cout << std::right << std::setw(width) << stats.getRetxCount(); - std::cout << std::right << std::setw(width) << window.str(); - std::cout << std::right << std::setw(width) << avg_rtt.str() << std::endl; - } - - total_duration_milliseconds_ += (uint32_t)exact_duration.count(); - old_bytes_value_ = stats.getBytesRecv(); - old_lost_data_value_ = stats.getLostData(); - old_bytes_recovered_value_ = stats.getBytesRecoveredData(); - old_definitely_lost_data_value_ = stats.getDefinitelyLostData(); - old_fec_interest_tx_value_ = stats.getInterestFecTxCount(); - old_fec_data_rx_value_ = stats.getBytesFecRecv(); - old_retx_value_ = stats.getRetxCount(); - old_sent_int_value_ = stats.getInterestTx(); - old_received_nacks_value_ = stats.getReceivedNacks(); - old_fec_pkt_ = stats.getReceivedFEC(); - delay_sample_ = 0; - avg_data_delay_ = 0; - received_bytes_ = 0; - received_data_pkt_ = 0; - data_delays_ = ""; - - t_stats_ = utils::SteadyTime::Clock::now(); - - header_counter_ = (header_counter_ + 1) & header_counter_mask_; - - if (--configuration_.nb_iterations_ == 0) { - // We reached the maximum nb of runs. Stop now. - io_service_.stop(); - } - } - - bool setForwarderConnection(forwarder_type_t forwarder_type) { - using namespace libconfig; - Config cfg; - - const char *conf_file = getenv("FORWARDER_CONFIG"); - if (!conf_file) return false; - - if ((forwarder_type != HICNLIGHT) && (forwarder_type != HICNLIGHT_NG)) - return false; - - try { - cfg.readFile(conf_file); - } catch (const FileIOException &fioex) { - std::cerr << "I/O error while reading file." << std::endl; - return false; - } catch (const ParseException &pex) { - std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine() - << " - " << pex.getError() << std::endl; - return false; } - Setting &config = cfg.getRoot(); - - /* conf file example - * - * use_bestpath = "ON | OFF" - * rtt_threshold = 200 //ms - * loss_threshold = 20 //% - * name = "b001::/16" - */ - - if (config.exists("use_bestpath")) { - std::string val; - config.lookupValue("use_bestpath", val); - if (val.compare("ON") == 0) use_bestpath_ = true; + size_t maxBufferSize() const override { + return configuration_.rtc_ ? kmtu : configuration_.receive_buffer_size_; } - if (config.exists("rtt_threshold")) { - unsigned val; - config.lookupValue("rtt_threshold", val); - rtt_threshold_ = val; + void readError(const std::error_code &ec) noexcept override { + getOutputStream() << "Error " << ec.message() + << " while reading from socket" << std::endl; + parent_.io_service_.stop(); } - if (config.exists("loss_threshold")) { - unsigned val; - config.lookupValue("loss_threshold", val); - loss_threshold_ = val; - } + void readSuccess(std::size_t total_size) noexcept override { + if (configuration_.rtc_) { + getOutputStream() << "Data successfully read" << std::endl; + } else { + auto t2 = utils::SteadyTime::now(); + auto dt = + utils::SteadyTime::getDurationUs(saved_stats_.t_download_, t2); + auto usec = dt.count(); - if (config.exists("name")) { - std::string route; - config.lookupValue("name", route); + getOutputStream() << "Content retrieved. Size: " << total_size + << " [Bytes]" << std::endl; - std::string delimiter = "/"; - size_t pos = 0; + getOutputStream() << "Elapsed Time: " << usec / 1000000.0 + << " seconds -- " + << double(total_size * 8) * 1.0 / double(usec) * 1.0 + << " [Mbps]" << std::endl; - if ((pos = route.find(delimiter)) != std::string::npos) { - prefix_name_ = route.substr(0, pos); - route.erase(0, pos + delimiter.length()); - prefix_len_ = std::stoul(route.substr(0)); + parent_.io_service_.stop(); } } - forwarder_interface_.initForwarderInterface(this, forwarder_type); - - return true; - } + /*************************************************************** + * End of ConsumerSocket::ReadCallback implementation + ***************************************************************/ - void onHicnServiceReady() override { - std::cout << "Successfully connected to local forwarder!" << std::endl; - fwd_connected_ = true; - } + private: + struct SavedStatistics { + utils::SteadyTime::TimePoint t_stats_{}; + utils::SteadyTime::TimePoint t_download_{}; + uint32_t total_duration_milliseconds_{0}; + uint64_t old_bytes_value_{0}; + uint64_t old_interest_tx_value_{0}; + uint64_t old_fec_interest_tx_value_{0}; + uint64_t old_fec_data_rx_value_{0}; + uint64_t old_lost_data_value_{0}; + uint64_t old_bytes_recovered_value_{0}; + uint64_t old_definitely_lost_data_value_{0}; + uint64_t old_retx_value_{0}; + uint64_t old_sent_int_value_{0}; + uint64_t old_received_nacks_value_{0}; + uint32_t old_fec_pkt_{0}; + // IMPORTANT: to be used only for performance testing, when consumer and + // producer are synchronized. Used for rtc only at the moment + double avg_data_delay_{0}; + uint32_t delay_sample_{0}; + uint32_t received_bytes_{0}; + uint32_t received_data_pkt_{0}; + uint32_t auth_alerts_{0}; + std::string data_delays_{""}; + }; + + /*************************************************************** + * Transport callbacks + ***************************************************************/ + + void checkReceivedRtcContent( + [[maybe_unused]] const ConsumerSocket &c, + [[maybe_unused]] const ContentObject &content_object) const { + // Nothing to do here + } + + void processLeavingInterest(const ConsumerSocket & /*c*/, + const Interest & /*interest*/) const { + // Nothing to do here + } + + transport::auth::VerificationPolicy onAuthFailed( + transport::auth::Suffix /*suffix*/, + transport::auth::VerificationPolicy /*policy*/) { + saved_stats_.auth_alerts_++; + return transport::auth::VerificationPolicy::ACCEPT; + } + + void handleTimerExpiration([[maybe_unused]] const ConsumerSocket &c, + const TransportStatistics &stats) { + const char separator = ' '; + const int width = 18; + + utils::SteadyTime::TimePoint t2 = utils::SteadyTime::Clock::now(); + auto exact_duration = + utils::SteadyTime::getDurationMs(saved_stats_.t_stats_, t2); + + std::stringstream interval_ms; + interval_ms << saved_stats_.total_duration_milliseconds_ << "-" + << saved_stats_.total_duration_milliseconds_ + + exact_duration.count(); + + std::stringstream bytes_transferred; + bytes_transferred << std::fixed << std::setprecision(3) + << double(stats.getBytesRecv() - + saved_stats_.old_bytes_value_) / + 1000000.0 + << std::setfill(separator); + + std::stringstream bandwidth; + bandwidth << (double(stats.getBytesRecv() - + saved_stats_.old_bytes_value_) * + 8) / + (exact_duration.count()) / 1000.0 + << std::setfill(separator); - void onRouteConfigured( - std::vector<ForwarderInterface::RouteInfoPtr> &route_info) override { - std::cout << "Routes successfully configured!" << std::endl; - } + std::stringstream window; + window << stats.getAverageWindowSize() << std::setfill(separator); -#ifdef FORWARDER_INTERFACE - bool parseConfig(const char *conf_file) { - using namespace libconfig; - Config cfg; - - try { - cfg.readFile(conf_file); - } catch (const FileIOException &fioex) { - std::cerr << "I/O error while reading file." << std::endl; - return false; - } catch (const ParseException &pex) { - std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine() - << " - " << pex.getError() << std::endl; - return false; - } + std::stringstream avg_rtt; + avg_rtt << std::setprecision(3) << std::fixed << stats.getAverageRtt() + << std::setfill(separator); - Setting &config = cfg.getRoot(); + if (configuration_.rtc_) { + std::stringstream lost_data; + lost_data << stats.getLostData() - saved_stats_.old_lost_data_value_ + << std::setfill(separator); + + std::stringstream bytes_recovered_data; + bytes_recovered_data << stats.getBytesRecoveredData() - + saved_stats_.old_bytes_recovered_value_ + << std::setfill(separator); + + std::stringstream definitely_lost_data; + definitely_lost_data << stats.getDefinitelyLostData() - + saved_stats_.old_definitely_lost_data_value_ + << std::setfill(separator); + + std::stringstream data_delay; + data_delay << std::fixed << std::setprecision(3) + << saved_stats_.avg_data_delay_ << std::setfill(separator); + + std::stringstream received_data_pkt; + received_data_pkt << saved_stats_.received_data_pkt_ + << std::setfill(separator); + + std::stringstream goodput; + goodput << std::fixed << std::setprecision(3) + << (saved_stats_.received_bytes_ * 8.0) / + (exact_duration.count()) / 1000.0 + << std::setfill(separator); - if (config.exists("switch_threshold")) { - unsigned threshold; - config.lookupValue("switch_threshold", threshold); - switch_threshold_ = threshold; - } + std::stringstream loss_rate; + loss_rate << std::fixed << std::setprecision(2) + << stats.getLossRatio() * 100.0 << std::setfill(separator); - // listeners - if (config.exists("listeners")) { - // get path where looking for modules - const Setting &listeners = config.lookup("listeners"); - auto count = listeners.getLength(); - - for (int i = 0; i < count; i++) { - const Setting &listener = listeners[i]; - ListenerConfig list; - unsigned port; - std::string interface; - - list.name = listener.getName(); - listener.lookupValue("local_address", list.address); - listener.lookupValue("local_port", port); - listener.lookupValue("interface", list.interface); - list.port = (uint16_t)(port); - - std::cout << "Adding listener " << list.name << ", ( " << list.address - << ":" << list.port << ")" << std::endl; - config_.addListener(std::move(list)); - } - } + std::stringstream retx_sent; + retx_sent << stats.getRetxCount() - saved_stats_.old_retx_value_ + << std::setfill(separator); - // connectors - if (config.exists("connectors")) { - // get path where looking for modules - const Setting &connectors = config.lookup("connectors"); - auto count = connectors.getLength(); + std::stringstream interest_sent; + interest_sent << stats.getInterestTx() - + saved_stats_.old_sent_int_value_ + << std::setfill(separator); - for (int i = 0; i < count; i++) { - const Setting &connector = connectors[i]; - ConnectorConfig conn; + std::stringstream nacks; + nacks << stats.getReceivedNacks() - + saved_stats_.old_received_nacks_value_ + << std::setfill(separator); - conn.name = connector.getName(); - unsigned port = 0; + std::stringstream fec_pkt; + fec_pkt << stats.getReceivedFEC() - saved_stats_.old_fec_pkt_ + << std::setfill(separator); - if (!connector.lookupValue("local_address", conn.local_address)) { - conn.local_address = ""; - } + std::stringstream queuing_delay; + queuing_delay << std::fixed << std::setprecision(3) + << stats.getQueuingDelay() << std::setfill(separator); - if (!connector.lookupValue("local_port", port)) { - port = 0; - } + std::stringstream residual_losses; + double rl_perc = stats.getResidualLossRate() * 100; + residual_losses << std::fixed << std::setprecision(2) << rl_perc + << std::setfill(separator); - conn.local_port = (uint16_t)(port); + std::stringstream quality_score; + quality_score << std::fixed << (int)stats.getQualityScore() + << std::setfill(separator); - if (!connector.lookupValue("remote_address", conn.remote_address)) { - std::cerr - << "Error in configuration file: remote_address is a mandatory " - "field of Connectors." - << std::endl; - return false; + std::stringstream alerts; + alerts << stats.getAlerts() << std::setfill(separator); + + std::stringstream auth_alerts; + auth_alerts << saved_stats_.auth_alerts_ << std::setfill(separator); + + if ((header_counter_ == 0 && configuration_.print_headers_) || first_) { + getOutputStream() << std::right << std::setw(width) << "Interval[ms]"; + getOutputStream() + << std::right << std::setw(width) << "RecvData[pkt]"; + getOutputStream() + << std::right << std::setw(width) << "Bandwidth[Mbps]"; + getOutputStream() + << std::right << std::setw(width) << "Goodput[Mbps]"; + getOutputStream() << std::right << std::setw(width) << "LossRate[%]"; + getOutputStream() << std::right << std::setw(width) << "Retr[pkt]"; + getOutputStream() << std::right << std::setw(width) << "InterestSent"; + getOutputStream() + << std::right << std::setw(width) << "ReceivedNacks"; + getOutputStream() << std::right << std::setw(width) << "SyncWnd[pkt]"; + getOutputStream() << std::right << std::setw(width) << "MinRtt[ms]"; + getOutputStream() + << std::right << std::setw(width) << "QueuingDelay[ms]"; + getOutputStream() + << std::right << std::setw(width) << "LostData[pkt]"; + getOutputStream() + << std::right << std::setw(width) << "RecoveredData"; + getOutputStream() + << std::right << std::setw(width) << "DefinitelyLost"; + getOutputStream() << std::right << std::setw(width) << "State"; + getOutputStream() + << std::right << std::setw(width) << "DataDelay[ms]"; + getOutputStream() << std::right << std::setw(width) << "FecPkt"; + getOutputStream() << std::right << std::setw(width) << "Congestion"; + getOutputStream() + << std::right << std::setw(width) << "ResidualLosses"; + getOutputStream() << std::right << std::setw(width) << "QualityScore"; + getOutputStream() << std::right << std::setw(width) << "Alerts"; + getOutputStream() + << std::right << std::setw(width) << "AuthAlerts" << std::endl; + + first_ = false; } - if (!connector.lookupValue("remote_port", port)) { - std::cerr << "Error in configuration file: remote_port is a " - "mandatory field of Connectors." - << std::endl; - return false; + getOutputStream() << std::right << std::setw(width) + << interval_ms.str(); + getOutputStream() << std::right << std::setw(width) + << received_data_pkt.str(); + getOutputStream() << std::right << std::setw(width) << bandwidth.str(); + getOutputStream() << std::right << std::setw(width) << goodput.str(); + getOutputStream() << std::right << std::setw(width) << loss_rate.str(); + getOutputStream() << std::right << std::setw(width) << retx_sent.str(); + getOutputStream() << std::right << std::setw(width) + << interest_sent.str(); + getOutputStream() << std::right << std::setw(width) << nacks.str(); + getOutputStream() << std::right << std::setw(width) << window.str(); + getOutputStream() << std::right << std::setw(width) << avg_rtt.str(); + getOutputStream() << std::right << std::setw(width) + << queuing_delay.str(); + getOutputStream() << std::right << std::setw(width) << lost_data.str(); + getOutputStream() << std::right << std::setw(width) + << bytes_recovered_data.str(); + getOutputStream() << std::right << std::setw(width) + << definitely_lost_data.str(); + getOutputStream() << std::right << std::setw(width) + << stats.getCCStatus(); + getOutputStream() << std::right << std::setw(width) << data_delay.str(); + getOutputStream() << std::right << std::setw(width) << fec_pkt.str(); + getOutputStream() << std::right << std::setw(width) + << stats.isCongested(); + getOutputStream() << std::right << std::setw(width) + << residual_losses.str(); + getOutputStream() << std::right << std::setw(width) + << quality_score.str(); + getOutputStream() << std::right << std::setw(width) << alerts.str(); + getOutputStream() << std::right << std::setw(width) << auth_alerts.str() + << std::endl; + + if (configuration_.test_mode_) { + if (saved_stats_.data_delays_.size() > 0) + saved_stats_.data_delays_.pop_back(); + + auto now = utils::SteadyTime::nowMs(); + getOutputStream() << std::fixed << std::setprecision(0) << now.count() + << " DATA-DELAYS:[" << saved_stats_.data_delays_ + << "]" << std::endl; } - - if (!connector.lookupValue("interface", conn.interface)) { - std::cerr << "Error in configuration file: interface is a " - "mandatory field of Connectors." - << std::endl; - return false; + } else { + if ((header_counter_ == 0 && configuration_.print_headers_) || first_) { + getOutputStream() << std::right << std::setw(width) << "Interval[ms]"; + getOutputStream() << std::right << std::setw(width) << "Transfer[MB]"; + getOutputStream() + << std::right << std::setw(width) << "Bandwidth[Mbps]"; + getOutputStream() << std::right << std::setw(width) << "Retr[pkt]"; + getOutputStream() << std::right << std::setw(width) << "Cwnd[Int]"; + getOutputStream() + << std::right << std::setw(width) << "AvgRtt[ms]" << std::endl; + + first_ = false; } - conn.remote_port = (uint16_t)(port); - - std::cout << "Adding connector " << conn.name << ", (" - << conn.local_address << ":" << conn.local_port << " " - << conn.remote_address << ":" << conn.remote_port << ")" - << std::endl; - config_.addConnector(conn.name, std::move(conn)); + getOutputStream() << std::right << std::setw(width) + << interval_ms.str(); + getOutputStream() << std::right << std::setw(width) + << bytes_transferred.str(); + getOutputStream() << std::right << std::setw(width) << bandwidth.str(); + getOutputStream() << std::right << std::setw(width) + << stats.getRetxCount(); + getOutputStream() << std::right << std::setw(width) << window.str(); + getOutputStream() << std::right << std::setw(width) << avg_rtt.str() + << std::endl; } - } - // Routes - if (config.exists("routes")) { - const Setting &routes = config.lookup("routes"); - auto count = routes.getLength(); - - for (int i = 0; i < count; i++) { - const Setting &route = routes[i]; - RouteConfig r; - unsigned weight; - - r.name = route.getName(); - route.lookupValue("prefix", r.prefix); - route.lookupValue("weight", weight); - route.lookupValue("main_connector", r.main_connector); - route.lookupValue("backup_connector", r.backup_connector); - r.weight = (uint16_t)(weight); - - std::cout << "Adding route " << r.name << " " << r.prefix << " (" - << r.main_connector << " " << r.backup_connector << " " - << r.weight << ")" << std::endl; - config_.addRoute(std::move(r)); + saved_stats_.total_duration_milliseconds_ += + (uint32_t)exact_duration.count(); + saved_stats_.old_bytes_value_ = stats.getBytesRecv(); + saved_stats_.old_lost_data_value_ = stats.getLostData(); + saved_stats_.old_bytes_recovered_value_ = stats.getBytesRecoveredData(); + saved_stats_.old_definitely_lost_data_value_ = + stats.getDefinitelyLostData(); + saved_stats_.old_fec_interest_tx_value_ = stats.getInterestFecTxCount(); + saved_stats_.old_fec_data_rx_value_ = stats.getBytesFecRecv(); + saved_stats_.old_retx_value_ = stats.getRetxCount(); + saved_stats_.old_sent_int_value_ = stats.getInterestTx(); + saved_stats_.old_received_nacks_value_ = stats.getReceivedNacks(); + saved_stats_.old_fec_pkt_ = stats.getReceivedFEC(); + saved_stats_.delay_sample_ = 0; + saved_stats_.avg_data_delay_ = 0; + saved_stats_.received_bytes_ = 0; + saved_stats_.received_data_pkt_ = 0; + saved_stats_.data_delays_ = ""; + saved_stats_.t_stats_ = utils::SteadyTime::Clock::now(); + + header_counter_ = (header_counter_ + 1) & kheader_counter_mask(); + + if (--nb_iterations_ == 0) { + // We reached the maximum nb of runs. Stop now. + parent_.io_service_.stop(); } } - std::cout << "Ok" << std::endl; + /*************************************************************** + * Setup functions + ***************************************************************/ - return true; - } + int setupRTCSocket() { + int ret = ERROR_SUCCESS; - bool splitRoute(std::string route, std::string &prefix, - uint8_t &prefix_length) { - std::string delimiter = "/"; - - size_t pos = 0; - if ((pos = route.find(delimiter)) != std::string::npos) { - prefix = route.substr(0, pos); - route.erase(0, pos + delimiter.length()); - } else { - return false; - } + configuration_.transport_protocol_ = RTC; - prefix_length = std::stoul(route.substr(0)); - return true; - } + if (configuration_.relay_ && configuration_.parallel_flows_ == 1) { + int production_protocol = ProductionProtocolAlgorithms::RTC_PROD; + producer_socket_ = + std::make_unique<ProducerSocket>(production_protocol); + producer_socket_->registerPrefix(configuration_.relay_name_); + producer_socket_->connect(); + producer_socket_->start(); + } - void onHicnServiceReady() override { - std::cout << "Successfully connected to local forwarder!" << std::endl; + if (configuration_.output_stream_mode_ && + configuration_.parallel_flows_ == 1) { + remote_ = asio::ip::udp::endpoint( + asio::ip::address::from_string("127.0.0.1"), configuration_.port_); + socket_.open(asio::ip::udp::v4()); + } - std::cout << "Setting up listeners" << std::endl; - const char *config = getenv("FORWARDER_CONFIG"); + consumer_socket_ = + std::make_unique<ConsumerSocket>(configuration_.transport_protocol_); - if (config) { - if (!parseConfig(config)) { - return; + RtcTransportRecoveryStrategies recovery_strategy = + RtcTransportRecoveryStrategies::RTX_ONLY; + switch (configuration_.recovery_strategy_) { + case 1: + recovery_strategy = RtcTransportRecoveryStrategies::RECOVERY_OFF; + break; + case 2: + recovery_strategy = RtcTransportRecoveryStrategies::RTX_ONLY; + break; + case 3: + recovery_strategy = RtcTransportRecoveryStrategies::FEC_ONLY; + break; + case 4: + recovery_strategy = RtcTransportRecoveryStrategies::DELAY_BASED; + break; + case 5: + recovery_strategy = RtcTransportRecoveryStrategies::LOW_RATE; + break; + case 6: + recovery_strategy = + RtcTransportRecoveryStrategies::LOW_RATE_AND_BESTPATH; + break; + case 7: + recovery_strategy = + RtcTransportRecoveryStrategies::LOW_RATE_AND_REPLICATION; + break; + case 8: + recovery_strategy = + RtcTransportRecoveryStrategies::LOW_RATE_AND_ALL_FWD_STRATEGIES; + break; + case 9: + recovery_strategy = + RtcTransportRecoveryStrategies::FEC_ONLY_LOW_RES_LOSSES; + break; + case 10: + recovery_strategy = + RtcTransportRecoveryStrategies::DELAY_AND_BESTPATH; + break; + case 11: + recovery_strategy = + RtcTransportRecoveryStrategies::DELAY_AND_REPLICATION; + break; + default: + break; } - // Create faces and route using first face in the list. - auto &routes = config_.getRoutes(); - auto &connectors = config_.getConnectors(); + ret = consumer_socket_->setSocketOption( + RtcTransportOptions::RECOVERY_STRATEGY, + static_cast<uint32_t>(recovery_strategy)); - if (routes.size() == 0 || connectors.size() == 0) { - std::cerr << "Nothing to configure" << std::endl; - return; + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; } - for (auto &route : routes) { - auto the_connector_it = connectors.find(route.main_connector); - if (the_connector_it == connectors.end()) { - std::cerr << "No valid main connector found for route " << route.name - << std::endl; - continue; - } - - auto &the_connector = the_connector_it->second; - auto route_info = std::make_shared<ForwarderInterface::RouteInfo>(); - route_info->family = AF_INET; - route_info->local_addr = the_connector.local_address; - route_info->local_port = the_connector.local_port; - route_info->remote_addr = the_connector.remote_address; - route_info->remote_port = the_connector.remote_port; - route_info->interface = the_connector.interface; - route_info->name = the_connector.name; - - std::string prefix; - uint8_t prefix_length; - auto ret = splitRoute(route.prefix, prefix, prefix_length); - - if (!ret) { - std::cerr << "Error parsing route" << std::endl; - return; - } + ret = consumer_socket_->setSocketOption( + RtcTransportOptions::AGGREGATED_DATA, + configuration_.aggregated_data_); - route_info->route_addr = prefix; - route_info->route_len = prefix_length; - - main_routes_.emplace_back(route_info); - - if (!route.backup_connector.empty()) { - // Add also the backup route - auto the_backup_connector_it = - connectors.find(route.backup_connector); - if (the_backup_connector_it == connectors.end()) { - std::cerr << "No valid backup connector found for route " - << route.name << std::endl; - continue; - } - - auto &the_backup_connector = the_backup_connector_it->second; - auto backup_route_info = - std::make_shared<ForwarderInterface::RouteInfo>(); - backup_route_info->family = AF_INET; - backup_route_info->local_addr = the_backup_connector.local_address; - backup_route_info->local_port = the_backup_connector.local_port; - backup_route_info->remote_addr = the_backup_connector.remote_address; - backup_route_info->remote_port = the_backup_connector.remote_port; - backup_route_info->interface = the_backup_connector.interface; - backup_route_info->name = the_backup_connector.name; - - std::string prefix; - uint8_t prefix_length; - auto ret = splitRoute(route.prefix, prefix, prefix_length); - - if (!ret) { - std::cerr << "Error parsing route" << std::endl; - return; - } - - backup_route_info->route_addr = prefix; - backup_route_info->route_len = prefix_length; - - backup_routes_.emplace_back(backup_route_info); - } + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; } - // Create main routes - std::cout << "Creating main routes" << std::endl; - forwarder_interface_.createFaceAndRoutes(main_routes_); - } - } + ret = consumer_socket_->setSocketOption( + RtcTransportOptions::CONTENT_SHARING_MODE, + configuration_.content_sharing_mode_); - void onRouteConfigured( - std::vector<ForwarderInterface::RouteInfoPtr> &route_info) override { - std::cout << "Routes successfully configured!" << std::endl; - } -#endif + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } - transport::auth::VerificationPolicy onAuthFailed( - transport::auth::Suffix suffix, - transport::auth::VerificationPolicy policy) { - auth_alerts_++; - return transport::auth::VerificationPolicy::ACCEPT; - } + ret = consumer_socket_->setSocketOption( + ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT, + (ConsumerContentObjectCallback)std::bind( + &Impl::ConsumerContext::checkReceivedRtcContent, this, + std::placeholders::_1, std::placeholders::_2)); + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } - int setup() { - int ret; + std::shared_ptr<TransportStatistics> transport_stats; + ret = consumer_socket_->getSocketOption( + OtherOptions::STATISTICS, (TransportStatistics **)&transport_stats); + transport_stats->setAlpha(0.0); - if (configuration_.rtc_) { - configuration_.transport_protocol_ = RTC; - } else if (configuration_.window < 0) { - configuration_.transport_protocol_ = RAAQM; - } else { - configuration_.transport_protocol_ = CBR; - } + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } - if (configuration_.relay_ && configuration_.rtc_) { - int production_protocol = ProductionProtocolAlgorithms::RTC_PROD; - producer_socket_ = std::make_unique<ProducerSocket>(production_protocol); - producer_socket_->registerPrefix(configuration_.relay_name_); - producer_socket_->connect(); - producer_socket_->start(); + return ERROR_SUCCESS; } - if (configuration_.output_stream_mode_ && configuration_.rtc_) { - remote_ = asio::ip::udp::endpoint( - asio::ip::address::from_string("127.0.0.1"), configuration_.port_); - socket_.open(asio::ip::udp::v4()); - } + int setupRAAQMSocket() { + int ret = ERROR_SUCCESS; + + configuration_.transport_protocol_ = RAAQM; - if (configuration_.secure_) { - consumer_socket_ = std::make_unique<P2PSecureConsumerSocket>( - RAAQM, configuration_.transport_protocol_); - if (configuration_.producer_prefix_.getPrefixLength() == 0) { - std::cerr << "ERROR -- Missing producer prefix on which perform the " - "handshake." - << std::endl; - } else { - P2PSecureConsumerSocket &secure_consumer_socket = - *(static_cast<P2PSecureConsumerSocket *>(consumer_socket_.get())); - secure_consumer_socket.registerPrefix(configuration_.producer_prefix_); - } - } else { consumer_socket_ = std::make_unique<ConsumerSocket>(configuration_.transport_protocol_); - } - consumer_socket_->setSocketOption( - GeneralTransportOptions::INTEREST_LIFETIME, - configuration_.interest_lifetime_); - - consumer_socket_->setSocketOption( - GeneralTransportOptions::UNVERIFIED_INTERVAL, - configuration_.unverified_interval_); - - consumer_socket_->setSocketOption(GeneralTransportOptions::UNVERIFIED_RATIO, - configuration_.unverified_ratio_); - - if (consumer_socket_->setSocketOption( - GeneralTransportOptions::PACKET_FORMAT, - configuration_.packet_format_) == SOCKET_OPTION_NOT_SET) { - std::cerr << "ERROR -- Impossible to set the packet format." << std::endl; - return ERROR_SETUP; - } - -#if defined(DEBUG) && defined(__linux__) - std::shared_ptr<transport::BasePortal> portal; - consumer_socket_->getSocketOption(GeneralTransportOptions::PORTAL, portal); - signals_ = - std::make_unique<asio::signal_set>(portal->getIoService(), SIGUSR1); - signals_->async_wait([this](const std::error_code &, const int &) { - std::cout << "Signal SIGUSR1!" << std::endl; - mtrace(); - }); - - ret = consumer_socket_->setSocketOption( - ConsumerCallbacksOptions::FWD_STRATEGY_CHANGE, - [this](notification::Strategy strategy) { - std::cout << "Forwarder strategy callback" << std::endl; - }); - if (ret == SOCKET_OPTION_NOT_SET) return ERROR_SETUP; - - ret = consumer_socket_->setSocketOption( - ConsumerCallbacksOptions::REC_STRATEGY_CHANGE, - [this](notification::Strategy strategy) { - std::cout << "Recovery strategy callback" << std::endl; - }); - if (ret == SOCKET_OPTION_NOT_SET) return ERROR_SETUP; -#endif - - if (consumer_socket_->setSocketOption(CURRENT_WINDOW_SIZE, - configuration_.window) == - SOCKET_OPTION_NOT_SET) { - std::cerr << "ERROR -- Impossible to set the size of the window." - << std::endl; - return ERROR_SETUP; - } - - if (configuration_.transport_protocol_ == RAAQM && - configuration_.beta != -1.f) { - if (consumer_socket_->setSocketOption(RaaqmTransportOptions::BETA_VALUE, - configuration_.beta) == - SOCKET_OPTION_NOT_SET) { - return ERROR_SETUP; + if (configuration_.beta_ != -1.f) { + ret = consumer_socket_->setSocketOption( + RaaqmTransportOptions::BETA_VALUE, configuration_.beta_); + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } } - } - if (configuration_.transport_protocol_ == RAAQM && - configuration_.drop_factor != -1.f) { - if (consumer_socket_->setSocketOption(RaaqmTransportOptions::DROP_FACTOR, - configuration_.drop_factor) == - SOCKET_OPTION_NOT_SET) { - return ERROR_SETUP; + if (configuration_.drop_factor_ != -1.f) { + ret = consumer_socket_->setSocketOption( + RaaqmTransportOptions::DROP_FACTOR, configuration_.drop_factor_); + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } } - } - - std::shared_ptr<Verifier> verifier = std::make_shared<VoidVerifier>(); - if (!configuration_.producer_certificate.empty()) { - verifier = std::make_shared<AsymmetricVerifier>( - configuration_.producer_certificate); + return ERROR_SUCCESS; } - if (!configuration_.passphrase.empty()) { - verifier = std::make_shared<SymmetricVerifier>(configuration_.passphrase); - } + int setupCBRSocket() { + configuration_.transport_protocol_ = CBR; - verifier->setVerificationFailedCallback( - std::bind(&HIperfClient::Impl::onAuthFailed, this, - std::placeholders::_1, std::placeholders::_2)); + consumer_socket_ = + std::make_unique<ConsumerSocket>(configuration_.transport_protocol_); - if (consumer_socket_->setSocketOption(GeneralTransportOptions::VERIFIER, - verifier) == SOCKET_OPTION_NOT_SET) { - return ERROR_SETUP; + return ERROR_SUCCESS; } - ret = consumer_socket_->setSocketOption( - ConsumerCallbacksOptions::INTEREST_OUTPUT, - (ConsumerInterestCallback)std::bind(&Impl::processLeavingInterest, this, - std::placeholders::_1, - std::placeholders::_2)); + public: + int setup() { + int ret; + std::shared_ptr<Verifier> verifier = std::make_shared<VoidVerifier>(); + + if (configuration_.rtc_) { + ret = setupRTCSocket(); + } else if (configuration_.window_ < 0) { + ret = setupRAAQMSocket(); + } else { + ret = setupCBRSocket(); + } - if (ret == SOCKET_OPTION_NOT_SET) { - return ERROR_SETUP; - } + if (ret != ERROR_SUCCESS) { + return ret; + } - if (!configuration_.rtc_) { ret = consumer_socket_->setSocketOption( - ConsumerCallbacksOptions::READ_CALLBACK, &callback_); - } else { - ret = consumer_socket_->setSocketOption( - ConsumerCallbacksOptions::READ_CALLBACK, &rtc_callback_); - } - - if (ret == SOCKET_OPTION_NOT_SET) { - return ERROR_SETUP; - } - - if (configuration_.rtc_) { - if (configuration_.recovery_strategy_ == 1) { // unreliable - ret = consumer_socket_->setSocketOption( - RtcTransportOptions::RECOVERY_STRATEGY, - (uint32_t)RtcTransportRecoveryStrategies::RECOVERY_OFF); - } else if (configuration_.recovery_strategy_ == 2) { // rtx only - ret = consumer_socket_->setSocketOption( - RtcTransportOptions::RECOVERY_STRATEGY, - (uint32_t)RtcTransportRecoveryStrategies::RTX_ONLY); - } else if (configuration_.recovery_strategy_ == 3) { // fec only - ret = consumer_socket_->setSocketOption( - RtcTransportOptions::RECOVERY_STRATEGY, - (uint32_t)RtcTransportRecoveryStrategies::FEC_ONLY); - } else if (configuration_.recovery_strategy_ == 4) { // delay based - ret = consumer_socket_->setSocketOption( - RtcTransportOptions::RECOVERY_STRATEGY, - (uint32_t)RtcTransportRecoveryStrategies::DELAY_BASED); - } else if (configuration_.recovery_strategy_ == 5) { // low rate flow - ret = consumer_socket_->setSocketOption( - RtcTransportOptions::RECOVERY_STRATEGY, - (uint32_t)RtcTransportRecoveryStrategies::LOW_RATE); - } else if (configuration_.recovery_strategy_ == - 6) { // low rate + bestpath - ret = consumer_socket_->setSocketOption( - RtcTransportOptions::RECOVERY_STRATEGY, - (uint32_t)RtcTransportRecoveryStrategies::LOW_RATE_AND_BESTPATH); - } else if (configuration_.recovery_strategy_ == - 7) { // low rate + replication - ret = consumer_socket_->setSocketOption( - RtcTransportOptions::RECOVERY_STRATEGY, - (uint32_t)RtcTransportRecoveryStrategies::LOW_RATE_AND_REPLICATION); - } else if (configuration_.recovery_strategy_ == - 8) { // low rate + bestpath or replication - ret = consumer_socket_->setSocketOption( - RtcTransportOptions::RECOVERY_STRATEGY, - (uint32_t)RtcTransportRecoveryStrategies:: - LOW_RATE_AND_ALL_FWD_STRATEGIES); - } else { - // default - ret = consumer_socket_->setSocketOption( - RtcTransportOptions::RECOVERY_STRATEGY, - (uint32_t)RtcTransportRecoveryStrategies::RTX_ONLY); + GeneralTransportOptions::INTEREST_LIFETIME, + configuration_.interest_lifetime_); + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; } + ret = consumer_socket_->setSocketOption( + GeneralTransportOptions::MANIFEST_FACTOR_RELEVANT, + configuration_.manifest_factor_relevant_); if (ret == SOCKET_OPTION_NOT_SET) { return ERROR_SETUP; } - } - if (configuration_.rtc_) { ret = consumer_socket_->setSocketOption( - RtcTransportOptions::AGGREGATED_DATA, - configuration_.aggregated_data_); + GeneralTransportOptions::MANIFEST_FACTOR_ALERT, + configuration_.manifest_factor_alert_); if (ret == SOCKET_OPTION_NOT_SET) { return ERROR_SETUP; } - } - if (configuration_.rtc_) { ret = consumer_socket_->setSocketOption( - ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT, - (ConsumerContentObjectCallback)std::bind( - &Impl::checkReceivedRtcContent, this, std::placeholders::_1, - std::placeholders::_2)); + GeneralTransportOptions::PACKET_FORMAT, + configuration_.packet_format_); if (ret == SOCKET_OPTION_NOT_SET) { + getOutputStream() << "ERROR -- Impossible to set the packet format." + << std::endl; return ERROR_SETUP; } - } - - if (configuration_.rtc_) { - std::shared_ptr<TransportStatistics> transport_stats; - consumer_socket_->getSocketOption( - OtherOptions::STATISTICS, (TransportStatistics **)&transport_stats); - transport_stats->setAlpha(0.0); - } - - ret = consumer_socket_->setSocketOption( - ConsumerCallbacksOptions::STATS_SUMMARY, - (ConsumerTimerCallback)std::bind(&Impl::handleTimerExpiration, this, - std::placeholders::_1, - std::placeholders::_2)); - - if (ret == SOCKET_OPTION_NOT_SET) { - return ERROR_SETUP; - } - - if (consumer_socket_->setSocketOption( - GeneralTransportOptions::STATS_INTERVAL, - configuration_.report_interval_milliseconds_) == - SOCKET_OPTION_NOT_SET) { - return ERROR_SETUP; - } - - consumer_socket_->connect(); - return ERROR_SUCCESS; - } + ret = consumer_socket_->setSocketOption( + ConsumerCallbacksOptions::FWD_STRATEGY_CHANGE, + (StrategyCallback)[]( + [[maybe_unused]] notification::Strategy strategy){ + // nothing to do + }); + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } - int run() { - std::cout << "Starting download of " << configuration_.name << std::endl; + ret = consumer_socket_->setSocketOption( + ConsumerCallbacksOptions::REC_STRATEGY_CHANGE, + (StrategyCallback)[]( + [[maybe_unused]] notification::Strategy strategy){ + // nothing to do + }); + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } - signals_.add(SIGINT); - signals_.async_wait( - [this](const std::error_code &, const int &) { io_service_.stop(); }); + ret = consumer_socket_->setSocketOption(CURRENT_WINDOW_SIZE, + configuration_.window_); + if (ret == SOCKET_OPTION_NOT_SET) { + getOutputStream() + << "ERROR -- Impossible to set the size of the window." + << std::endl; + return ERROR_SETUP; + } - t_download_ = t_stats_ = utils::SteadyTime::now(); - consumer_socket_->consume(configuration_.name); + if (!configuration_.producer_certificate_.empty()) { + verifier = std::make_shared<AsymmetricVerifier>( + configuration_.producer_certificate_); + } - io_service_.run(); - consumer_socket_->stop(); + if (!configuration_.passphrase_.empty()) { + verifier = + std::make_shared<SymmetricVerifier>(configuration_.passphrase_); + } - return ERROR_SUCCESS; - } + verifier->setVerificationFailedCallback( + std::bind(&HIperfClient::Impl::ConsumerContext::onAuthFailed, this, + std::placeholders::_1, std::placeholders::_2)); - private: - class RTCCallback : public ConsumerSocket::ReadCallback { - static constexpr std::size_t mtu = HIPERF_MTU; + ret = consumer_socket_->setSocketOption(GeneralTransportOptions::VERIFIER, + verifier); + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } - public: - RTCCallback(Impl &hiperf_client) : client_(hiperf_client) { - client_.configuration_.receive_buffer = utils::MemBuf::create(mtu); - Packet::Format format = - PayloadSize::getFormatFromName(client_.configuration_.name, false); - payload_size_max_ = - PayloadSize(format).getPayloadSizeMax(RTC_HEADER_SIZE); - } + // Signer for aggregatd interests + std::shared_ptr<Signer> signer = std::make_shared<VoidSigner>(); + if (!configuration_.aggr_interest_passphrase_.empty()) { + signer = std::make_shared<SymmetricSigner>( + CryptoSuite::HMAC_SHA256, configuration_.aggr_interest_passphrase_); + } + ret = consumer_socket_->setSocketOption(GeneralTransportOptions::SIGNER, + signer); + if (ret == SOCKET_OPTION_NOT_SET) return ERROR_SETUP; - bool isBufferMovable() noexcept override { return false; } + if (configuration_.aggregated_interests_) { + ret = consumer_socket_->setSocketOption( + RtcTransportOptions::AGGREGATED_INTERESTS, true); - void getReadBuffer(uint8_t **application_buffer, - size_t *max_length) override { - *application_buffer = - client_.configuration_.receive_buffer->writableData(); - *max_length = mtu; - } + if (ret == SOCKET_OPTION_NOT_SET) return ERROR_SETUP; + } - void readDataAvailable(std::size_t length) noexcept override { - client_.received_bytes_ += length; - client_.received_data_pkt_++; + ret = consumer_socket_->setSocketOption( + ConsumerCallbacksOptions::INTEREST_OUTPUT, + (ConsumerInterestCallback)std::bind( + &ConsumerContext::processLeavingInterest, this, + std::placeholders::_1, std::placeholders::_2)); - // collecting delay stats. Just for performance testing - uint64_t *senderTimeStamp = - (uint64_t *)client_.configuration_.receive_buffer->writableData(); + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } - auto now = utils::SystemTime::nowMs().count(); - double new_delay = (double)(now - *senderTimeStamp); + ret = consumer_socket_->setSocketOption( + ConsumerCallbacksOptions::READ_CALLBACK, this); - if (*senderTimeStamp > now) - new_delay = -1 * (double)(*senderTimeStamp - now); + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } - client_.delay_sample_++; - client_.avg_data_delay_ = - client_.avg_data_delay_ + - (new_delay - client_.avg_data_delay_) / client_.delay_sample_; + ret = consumer_socket_->setSocketOption( + ConsumerCallbacksOptions::STATS_SUMMARY, + (ConsumerTimerCallback)std::bind( + &Impl::ConsumerContext::handleTimerExpiration, this, + std::placeholders::_1, std::placeholders::_2)); - if (client_.configuration_.test_mode_) { - client_.data_delays_ += std::to_string(int(new_delay)); - client_.data_delays_ += ","; + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; } - if (client_.configuration_.relay_) { - client_.producer_socket_->produceDatagram( - client_.configuration_.relay_name_.getName(), - client_.configuration_.receive_buffer->writableData(), - length < payload_size_max_ ? length : payload_size_max_); - } - if (client_.configuration_.output_stream_mode_) { - uint8_t *start = - (uint8_t *)client_.configuration_.receive_buffer->writableData(); - start += sizeof(uint64_t); - std::size_t pkt_len = length - sizeof(uint64_t); - client_.socket_.send_to(asio::buffer(start, pkt_len), client_.remote_); + if (consumer_socket_->setSocketOption( + GeneralTransportOptions::STATS_INTERVAL, + configuration_.report_interval_milliseconds_) == + SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; } - } - size_t maxBufferSize() const override { return mtu; } + consumer_socket_->connect(); - void readError(const std::error_code &ec) noexcept override { - std::cerr << "Error while reading from RTC socket" << std::endl; - client_.io_service_.stop(); + return ERROR_SUCCESS; } - void readSuccess(std::size_t total_size) noexcept override { - std::cout << "Data successfully read" << std::endl; + /*************************************************************** + * Run functions + ***************************************************************/ + + int run() { + getOutputStream() << "Starting download of " << flow_name_ << std::endl; + + saved_stats_.t_download_ = saved_stats_.t_stats_ = + utils::SteadyTime::now(); + consumer_socket_->consume(flow_name_); + + return ERROR_SUCCESS; } - private: - Impl &client_; + // Members initialized by the constructor + std::shared_ptr<utils::MemBuf> receive_buffer_; + asio::ip::udp::socket socket_; std::size_t payload_size_max_; + asio::ip::udp::endpoint remote_; + std::uint32_t nb_iterations_; + + // Members initialized by in-class initializer + SavedStatistics saved_stats_{}; + uint16_t header_counter_{0}; + bool first_{true}; + std::unique_ptr<ConsumerSocket> consumer_socket_; + std::unique_ptr<ProducerSocket> producer_socket_; }; - class Callback : public ConsumerSocket::ReadCallback { - public: - Callback(Impl &hiperf_client) : client_(hiperf_client) { - client_.configuration_.receive_buffer = - utils::MemBuf::create(client_.configuration_.receive_buffer_size_); - } + public: + explicit Impl(const hiperf::ClientConfiguration &conf) + : config_(conf), signals_(io_service_) {} - bool isBufferMovable() noexcept override { return false; } + virtual ~Impl() = default; - void getReadBuffer(uint8_t **application_buffer, - size_t *max_length) override { - *application_buffer = - client_.configuration_.receive_buffer->writableData(); - *max_length = client_.configuration_.receive_buffer_size_; + int setup() { + int ret = ensureFlows(config_.name_, config_.parallel_flows_); + if (ret != ERROR_SUCCESS) { + return ret; } - void readDataAvailable(std::size_t length) noexcept override {} - - void readBufferAvailable( - std::unique_ptr<utils::MemBuf> &&buffer) noexcept override {} + consumer_contexts_.reserve(config_.parallel_flows_); + for (uint32_t i = 0; i < config_.parallel_flows_; i++) { + auto &ctx = consumer_contexts_.emplace_back(*this, i); + ret = ctx.setup(); - size_t maxBufferSize() const override { - return client_.configuration_.receive_buffer_size_; - } - - void readError(const std::error_code &ec) noexcept override { - std::cerr << "Error " << ec.message() << " while reading from socket" - << std::endl; - client_.io_service_.stop(); + if (ret) { + break; + } } - void readSuccess(std::size_t total_size) noexcept override { - auto t2 = utils::SteadyTime::now(); - auto dt = utils::SteadyTime::getDurationUs(client_.t_download_, t2); - long usec = (long)dt.count(); - - std::cout << "Content retrieved. Size: " << total_size << " [Bytes]" - << std::endl; + return ret; + } - std::cerr << "Elapsed Time: " << usec / 1000000.0 << " seconds -- " - << (total_size * 8) * 1.0 / usec * 1.0 << " [Mbps]" - << std::endl; + int run() { + signals_.add(SIGINT); + signals_.async_wait( + [this](const std::error_code &, const int &) { io_service_.stop(); }); - client_.io_service_.stop(); + for (auto &consumer_context : consumer_contexts_) { + consumer_context.run(); } - private: - Impl &client_; - }; + io_service_.run(); - hiperf::ClientConfiguration configuration_; - utils::SteadyTime::TimePoint t_stats_; - utils::SteadyTime::TimePoint t_download_; - uint32_t total_duration_milliseconds_; - uint64_t old_bytes_value_; - uint64_t old_interest_tx_value_; - uint64_t old_fec_interest_tx_value_; - uint64_t old_fec_data_rx_value_; - uint64_t old_lost_data_value_; - uint64_t old_bytes_recovered_value_; - uint64_t old_definitely_lost_data_value_; - uint32_t old_retx_value_; - uint32_t old_sent_int_value_; - uint32_t old_received_nacks_value_; - uint32_t old_fec_pkt_; - - // IMPORTANT: to be used only for performance testing, when consumer and - // producer are synchronized. Used for rtc only at the moment - double avg_data_delay_; - uint32_t delay_sample_; - - uint32_t received_bytes_; - uint32_t received_data_pkt_; - uint32_t auth_alerts_; - - std::string data_delays_; + return ERROR_SUCCESS; + } + ClientConfiguration &getConfig() { return config_; } + + private: asio::io_service io_service_; + hiperf::ClientConfiguration config_; asio::signal_set signals_; - RTCCallback rtc_callback_; - Callback callback_; - std::unique_ptr<ConsumerSocket> consumer_socket_; - std::unique_ptr<ProducerSocket> producer_socket_; - asio::ip::udp::socket socket_; - asio::ip::udp::endpoint remote_; - - ForwarderConfiguration config_; - // uint16_t switch_threshold_; /* ms */ - bool fwd_connected_; - bool use_bestpath_; - uint32_t rtt_threshold_; /* ms */ - uint32_t loss_threshold_; /* ms */ - std::string prefix_name_; // bestpath route - uint32_t prefix_len_; - // bool done_; - - std::vector<ForwarderInterface::RouteInfoPtr> main_routes_; - std::vector<ForwarderInterface::RouteInfoPtr> backup_routes_; - uint16_t header_counter_mask_; - uint16_t header_counter_; - - bool print_headers_; - bool first_; - - ForwarderInterface forwarder_interface_; + std::vector<ConsumerContext> consumer_contexts_; }; -HIperfClient::HIperfClient(const ClientConfiguration &conf) { - impl_ = new Impl(conf); -} - -HIperfClient::HIperfClient(HIperfClient &&other) { - impl_ = other.impl_; - other.impl_ = nullptr; -} - -HIperfClient &HIperfClient::operator=(HIperfClient &&other) { - if (this != &other) { - impl_ = other.impl_; - other.impl_ = nullptr; - } - - return *this; -} +HIperfClient::HIperfClient(const ClientConfiguration &conf) + : impl_(std::make_unique<Impl>(conf)) {} -HIperfClient::~HIperfClient() { delete impl_; } +HIperfClient::~HIperfClient() = default; -int HIperfClient::setup() { return impl_->setup(); } +int HIperfClient::setup() const { return impl_->setup(); } -void HIperfClient::run() { impl_->run(); } +void HIperfClient::run() const { impl_->run(); } } // namespace hiperf diff --git a/apps/hiperf/src/client.h b/apps/hiperf/src/client.h index bc80c874c..c4c6bc2ae 100644 --- a/apps/hiperf/src/client.h +++ b/apps/hiperf/src/client.h @@ -20,19 +20,17 @@ namespace hiperf { -class HIperfClient : ::utils::NonCopyable { +class HIperfClient : private ::utils::NonCopyable { public: - HIperfClient(const ClientConfiguration &conf); - HIperfClient(HIperfClient &&other); - HIperfClient &operator=(HIperfClient &&other); + explicit HIperfClient(const ClientConfiguration &conf); ~HIperfClient(); - int setup(); - void run(); + int setup() const; + void run() const; private: class Impl; - Impl *impl_; + std::unique_ptr<Impl> impl_; }; } // namespace hiperf
\ No newline at end of file diff --git a/apps/hiperf/src/common.h b/apps/hiperf/src/common.h index 3a90f3732..5143afe31 100644 --- a/apps/hiperf/src/common.h +++ b/apps/hiperf/src/common.h @@ -15,17 +15,15 @@ #pragma once -#include <forwarder_interface.h> #include <hicn/transport/auth/signer.h> #include <hicn/transport/config.h> #include <hicn/transport/core/content_object.h> #include <hicn/transport/core/interest.h> #include <hicn/transport/interfaces/global_conf_interface.h> -#include <hicn/transport/interfaces/p2psecure_socket_consumer.h> -#include <hicn/transport/interfaces/p2psecure_socket_producer.h> #include <hicn/transport/interfaces/socket_consumer.h> #include <hicn/transport/interfaces/socket_producer.h> #include <hicn/transport/utils/chrono_typedefs.h> +#include <hicn/transport/utils/color.h> #include <hicn/transport/utils/literals.h> #ifndef _WIN32 @@ -36,6 +34,7 @@ #include <cmath> #include <fstream> #include <iomanip> +#include <iostream> #include <sstream> #include <string> #include <unordered_set> @@ -53,27 +52,112 @@ using namespace transport::interface; using namespace transport::auth; using namespace transport::core; -static inline uint64_t _ntohll(const uint64_t *input) { - uint64_t return_val; - uint8_t *tmp = (uint8_t *)&return_val; +namespace hiperf { - tmp[0] = *input >> 56; - tmp[1] = *input >> 48; - tmp[2] = *input >> 40; - tmp[3] = *input >> 32; - tmp[4] = *input >> 24; - tmp[5] = *input >> 16; - tmp[6] = *input >> 8; - tmp[7] = *input >> 0; +/** + * Logger + */ +static std::ostream &Logger() { return std::cout; } - return return_val; -} +template <typename D, typename ConfType, typename ParentType> +class Base : protected std::stringbuf, protected std::ostream { + protected: + static inline const char separator[] = "| "; -static inline uint64_t _htonll(const uint64_t *input) { - return (_ntohll(input)); -} + Base(ParentType &parent, asio::io_service &io_service, int identifier) + : std::stringbuf(), + std::ostream(this), + parent_(parent), + configuration_(parent_.getConfig()), + io_service_(io_service), + identifier_(identifier), + name_id_(D::getContextType() + std::to_string(identifier_)), + flow_name_(configuration_.name_.makeNameWithIndex(identifier_)) { + std::stringstream begin; + std::stringstream end; + if (configuration_.colored_) { + begin << color_mod_ << bold_mod_; + end << end_mod_; + } else { + begin << ""; + end << ""; + } -namespace hiperf { + begin << "|" << name_id_ << separator; + begin_ = begin.str(); + end_ = end.str(); + } + + Base(Base &&other) + : parent_(other.parent_), + configuration_(other.configuration_), + io_service_(other.io_service_), + identifier_(other.identifier_), + name_id_(std::move(other.name_id_)), + flow_name_(other.flow_name_) {} + + /*************************************************************** + * std::stringbuf sync override + ***************************************************************/ + + int sync() override { + auto string = str(); + asio::post(io_service_, + [this, string]() { Logger() << begin_ << string << end_; }); + str(""); + + return 0; + } + + std::ostream &getOutputStream() { return *this; } + + // Members initialized by the constructor + ParentType &parent_; + ConfType &configuration_; + asio::io_service &io_service_; + int identifier_; + std::string name_id_; + transport::core::Name flow_name_; + std::string begin_; + std::string end_; + + // Members initialized by the in-class initializer + utils::ColorModifier color_mod_; + utils::ColorModifier bold_mod_{utils::ColorModifier::Code::BOLD}; + utils::ColorModifier end_mod_{utils::ColorModifier::Code::RESET}; +}; + +static inline int ensureFlows(const Prefix &prefix, std::size_t flows) { + int ret = ERROR_SUCCESS; + + // Make sure the provided prefix length not allows to accomodate the + // provided number of flows. + uint16_t max_ip_addr_len_bits; + uint16_t log2_n_flow; + u64 max_n_flow; + if (prefix.getAddressFamily() == AF_INET) { + max_ip_addr_len_bits = IPV4_ADDR_LEN_BITS; + } else if (prefix.getAddressFamily() == AF_INET6) { + max_ip_addr_len_bits = IPV6_ADDR_LEN_BITS; + } else { + Logger() << "Error: unknown address family." << std::endl; + ret = ERROR_SETUP; + goto end; + } + + log2_n_flow = max_ip_addr_len_bits - prefix.getPrefixLength(); + max_n_flow = log2_n_flow < 64 ? (1 << log2_n_flow) : ~0ULL; + + if (flows > max_n_flow) { + Logger() << "Error: the provided prefix length does not allow to " + "accomodate the provided number of flows (" + << flows << " > " << max_n_flow << ")." << std::endl; + ret = ERROR_SETUP; + } + +end: + return ret; +} /** * Class to retrieve the maximum payload size given the MTU and packet headers. @@ -90,8 +174,9 @@ class PayloadSize { transport_size - fec_size; } - static Packet::Format getFormatFromName(Name name, bool ah = false) { - switch (name.getAddressFamily()) { + static Packet::Format getFormatFromPrefix(const Prefix &prefix, + bool ah = false) { + switch (prefix.getAddressFamily()) { case AF_INET: return ah ? HF_INET_TCP_AH : HF_INET_TCP; case AF_INET6: @@ -158,124 +243,69 @@ struct packet_t { uint32_t size; }; +struct Configuration { + Prefix name_{"b001::abcd/64"}; + std::string passphrase_; + std::string aggr_interest_passphrase_; + bool rtc_{false}; + uint16_t port_{0}; + bool aggregated_data_{false}; + Packet::Format packet_format_{default_values::packet_format}; + uint32_t parallel_flows_{1}; + bool colored_{true}; +}; + /** * Container for command line configuration for hiperf client. */ -struct ClientConfiguration { - ClientConfiguration() - : name("b001::abcd", 0), - beta(-1.f), - drop_factor(-1.f), - window(-1), - producer_certificate(""), - passphrase(""), - receive_buffer(nullptr), - receive_buffer_size_(128 * 1024), - download_size(0), - report_interval_milliseconds_(1000), - transport_protocol_(CBR), - rtc_(false), - test_mode_(false), - relay_(false), - secure_(false), - producer_prefix_(), - interest_lifetime_(500), - unverified_interval_(10000), - unverified_ratio_(0.2), - relay_name_("c001::abcd/64"), - output_stream_mode_(false), - port_(0), - recovery_strategy_(4), - aggregated_data_(false), - packet_format_(default_values::packet_format), - print_headers_(true), - nb_iterations_(std::numeric_limits<decltype(nb_iterations_)>::max()) {} - - Name name; - double beta; - double drop_factor; - double window; - std::string producer_certificate; - std::string passphrase; - std::shared_ptr<utils::MemBuf> receive_buffer; - std::size_t receive_buffer_size_; - std::size_t download_size; - std::uint32_t report_interval_milliseconds_; - TransportProtocolAlgorithms transport_protocol_; - bool rtc_; - bool test_mode_; - bool relay_; - bool secure_; +struct ClientConfiguration : public Configuration { + double beta_{-1.f}; + double drop_factor_{-1.f}; + double window_{-1.f}; + std::string producer_certificate_; + std::string passphrase_; + std::size_t receive_buffer_size_{128 * 1024}; + std::uint32_t report_interval_milliseconds_{1000}; + TransportProtocolAlgorithms transport_protocol_{CBR}; + bool test_mode_{false}; + bool relay_{false}; Prefix producer_prefix_; - uint32_t interest_lifetime_; - uint32_t unverified_interval_; - double unverified_ratio_; - Prefix relay_name_; - bool output_stream_mode_; - uint16_t port_; - uint32_t recovery_strategy_; - bool aggregated_data_; - Packet::Format packet_format_; - bool print_headers_; - std::uint32_t nb_iterations_; - forwarder_type_t forwarder_type_; + uint32_t interest_lifetime_{500}; + uint32_t manifest_factor_relevant_{100}; + uint32_t manifest_factor_alert_{20}; + Prefix relay_name_{"c001::abcd/64"}; + bool output_stream_mode_{false}; + uint32_t recovery_strategy_{4}; + bool print_headers_{true}; + std::uint32_t nb_iterations_{ + std::numeric_limits<decltype(nb_iterations_)>::max()}; + bool content_sharing_mode_{false}; + bool aggregated_interests_{false}; }; /** * Container for command line configuration for hiperf server. */ -struct ServerConfiguration { - ServerConfiguration() - : name("b001::abcd/64"), - virtual_producer(true), - manifest(0), - live_production(false), - content_lifetime(600000000_U32), - download_size(20 * 1024 * 1024), - hash_algorithm_(CryptoHashType::SHA256), - keystore_name(""), - passphrase(""), - keystore_password("cisco"), - multiphase_produce_(false), - rtc_(false), - interactive_(false), - trace_based_(false), - trace_index_(0), - trace_file_(nullptr), - production_rate_(std::string("2048kbps")), - payload_size_(1384), - secure_(false), - input_stream_mode_(false), - port_(0), - aggregated_data_(false), - fec_type_(""), - packet_format_(default_values::packet_format) {} - - Prefix name; - bool virtual_producer; - std::uint32_t manifest; - bool live_production; - std::uint32_t content_lifetime; - std::uint32_t download_size; - CryptoHashType hash_algorithm_; - std::string keystore_name; - std::string passphrase; - std::string keystore_password; - bool multiphase_produce_; - bool rtc_; - bool interactive_; - bool trace_based_; - std::uint32_t trace_index_; - char *trace_file_; - Rate production_rate_; - std::size_t payload_size_; - bool secure_; - bool input_stream_mode_; - uint16_t port_; +struct ServerConfiguration : public Configuration { + bool virtual_producer_{true}; + std::uint32_t manifest_max_capacity_{0}; + bool live_production_{false}; + std::uint32_t content_lifetime_{ + transport::interface::default_values::content_object_expiry_time}; + std::uint32_t download_size_{20 * 1024 * 1024}; + CryptoHashType hash_algorithm_{CryptoHashType::SHA256}; + std::string keystore_name_; + std::string keystore_password_{"cisco"}; + bool multiphase_produce_{false}; + bool interactive_{false}; + bool trace_based_{false}; + std::uint32_t trace_index_{0}; + char *trace_file_{nullptr}; + Rate production_rate_{"2048kbps"}; + std::size_t payload_size_{1384}; + bool input_stream_mode_{false}; std::vector<struct packet_t> trace_; - bool aggregated_data_; std::string fec_type_; - Packet::Format packet_format_; }; } // namespace hiperf diff --git a/apps/hiperf/src/forwarder_config.h b/apps/hiperf/src/forwarder_config.h deleted file mode 100644 index aaac14839..000000000 --- a/apps/hiperf/src/forwarder_config.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <string> -#include <unordered_map> -#include <vector> - -namespace hiperf { - -struct ListenerConfig { - std::string address; - std::uint16_t port; - std::string interface; - std::string name; -}; - -struct ConnectorConfig { - std::string local_address; - std::uint16_t local_port; - std::string remote_address; - std::uint16_t remote_port; - std::string interface; - std::string name; -}; - -struct RouteConfig { - std::string prefix; - uint16_t weight; - std::string main_connector; - std::string backup_connector; - std::string name; -}; - -class ForwarderConfiguration { - public: - ForwarderConfiguration() : n_threads_(1) {} - - bool empty() { - return listeners_.empty() && connectors_.empty() && routes_.empty(); - } - - ForwarderConfiguration &setThreadNumber(std::size_t threads) { - n_threads_ = threads; - return *this; - } - - std::size_t getThreadNumber() { return n_threads_; } - - template <typename... Args> - ForwarderConfiguration &addListener(Args &&...args) { - listeners_.emplace_back(std::forward<Args>(args)...); - return *this; - } - - template <typename... Args> - ForwarderConfiguration &addConnector(const std::string &name, - Args &&...args) { - connectors_.emplace(name, std::forward<Args>(args)...); - return *this; - } - - template <typename... Args> - ForwarderConfiguration &addRoute(Args &&...args) { - routes_.emplace_back(std::forward<Args>(args)...); - return *this; - } - - std::vector<ListenerConfig> &getListeners() { return listeners_; } - - std::unordered_map<std::string, ConnectorConfig> &getConnectors() { - return connectors_; - } - - std::vector<RouteConfig> &getRoutes() { return routes_; } - - private: - std::vector<ListenerConfig> listeners_; - std::unordered_map<std::string, ConnectorConfig> connectors_; - std::vector<RouteConfig> routes_; - std::size_t n_threads_; -}; - -} // namespace hiperf
\ No newline at end of file diff --git a/apps/hiperf/src/forwarder_interface.cc b/apps/hiperf/src/forwarder_interface.cc deleted file mode 100644 index e87a5953d..000000000 --- a/apps/hiperf/src/forwarder_interface.cc +++ /dev/null @@ -1,696 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <arpa/inet.h> -#include <forwarder_interface.h> -#include <hicn/transport/utils/log.h> - -#include <chrono> -#include <iostream> -#include <thread> -#include <unordered_set> - -extern "C" { -#include <hicn/error.h> -#include <hicn/util/ip_address.h> -#include <hicn/util/sstrncpy.h> -} - -// XXX the main listener should be retrieve in this class at initialization, aka -// when hICN becomes avialable -// -// XXX the main listener port will be retrieved in the forwarder -// interface... everything else will be delayed until we have this -// information - -namespace hiperf { - -ForwarderInterface::ForwarderInterface(asio::io_service &io_service) - : external_ioservice_(io_service), timer_(io_service) {} - -ForwarderInterface::ForwarderInterface(asio::io_service &io_service, - ICallback *callback, - forwarder_type_t fwd_type) - : external_ioservice_(io_service), timer_(io_service) { - initForwarderInterface(callback, fwd_type); -} - -ForwarderInterface::~ForwarderInterface() { - if (thread_ && thread_->joinable()) { - internal_ioservice_.dispatch([this]() { - if (sock_) { - hc_sock_free(sock_); - sock_ = nullptr; - } - - work_.reset(); - }); - - thread_->join(); - } -} - -void ForwarderInterface::initForwarderInterface(ICallback *callback, - forwarder_type_t fwd_type) { - forwarder_interface_callback_ = callback; - work_ = std::make_unique<asio::io_service::work>(internal_ioservice_); - sock_ = nullptr; - thread_ = std::make_unique<std::thread>([this]() { - std::cout << "Starting Forwarder Interface thread" << std::endl; - internal_ioservice_.run(); - std::cout << "Stopping Forwarder Interface thread" << std::endl; - }); - check_routes_timer_ = nullptr; - pending_add_route_counter_ = 0; - hicn_listen_port_ = 9695; - /* We start in disabled state even when a forwarder is always available */ - state_ = State::Disabled; - fwd_type_ = fwd_type; - num_reattempts = 0; - std::cout << "Forwarder interface created... connecting to forwarder...\n"; - internal_ioservice_.post([this]() { onHicnServiceAvailable(true); }); -} - -void ForwarderInterface::onHicnServiceAvailable(bool flag) { - if (flag) { - switch (state_) { - case State::Disabled: - case State::Requested: - state_ = State::Available; - case State::Available: - connectToForwarder(); - /* Synchronous */ - if (state_ != State::Connected) { - std::cout << "ConnectToForwarder failed" << std::endl; - goto REATTEMPT; - } - state_ = State::Ready; - - std::cout << "Connected to forwarder... cancelling reconnection timer" - << std::endl; - - timer_.cancel(); - num_reattempts = 0; - - std::cout << "Forwarder interface is ready... communicate to controller" - << std::endl; - - forwarder_interface_callback_->onHicnServiceReady(); - case State::Connected: - case State::Ready: - break; - } - } else { - if (sock_) { - hc_sock_free(sock_); - sock_ = nullptr; - } - state_ = State::Disabled; // XXX to be checked upon callback to prevent the - // state from going forward (used to manage - // concurrency) - } - return; - -REATTEMPT: - /* Schedule reattempt */ - std::cout << "Failed to connect, scheduling reattempt" << std::endl; - num_reattempts++; - - timer_.expires_from_now( - std::chrono::milliseconds(ForwarderInterface::REATTEMPT_DELAY_MS)); - // timer_.async_wait(std::bind(&ForwarderInterface::onHicnServiceAvailable, - // this, flag, std::placeholders::_1)); - timer_.async_wait([this, flag](const std::error_code &ec) { - if (ec) return; - onHicnServiceAvailable(flag); - }); -} - -int ForwarderInterface::connectToForwarder() { - sock_ = hc_sock_create_forwarder(fwd_type_); - if (!sock_) { - std::cout << "Could not create socket" << std::endl; - goto ERR_SOCK; - } - - if (hc_sock_connect(sock_) < 0) { - std::cout << "Could not connect to forwarder" << std::endl; - goto ERR; - } - - std::cout << "Forwarder interface connected" << std::endl; - state_ = State::Connected; - return 0; - -ERR: - hc_sock_free(sock_); - sock_ = nullptr; -ERR_SOCK: - return -1; -} - -int ForwarderInterface::checkListener() { - if (!sock_) return -1; - - hc_data_t *data; - if (hc_listener_list(sock_, &data) < 0) return -1; - - int ret = -1; - foreach_listener(l, data) { - std::string interface = std::string(l->interface_name); - if (interface.compare("lo") != 0) { - hicn_listen_port_ = l->local_port; - state_ = State::Ready; - ret = 0; - std::cout << "Got listener port" << std::endl; - break; - } - } - - hc_data_free(data); - return ret; -} - -void ForwarderInterface::close() { - std::cout << "ForwarderInterface::close" << std::endl; - - state_ = State::Disabled; - /* Cancelling eventual reattempts */ - timer_.cancel(); - - if (sock_) { - hc_sock_free(sock_); - sock_ = nullptr; - } - - internal_ioservice_.post([this]() { work_.reset(); }); - - if (thread_->joinable()) { - thread_->join(); - } -} - -#if 0 -void ForwarderInterface::enableCheckRoutesTimer() { - if (check_routes_timer_ != nullptr) return; - - check_routes_timer_ = - std::make_unique<asio::steady_timer>(internal_ioservice_); - checkRoutesLoop(); -} - -void ForwarderInterface::removeConnectedUserNow(ProtocolPtr protocol) { - internalRemoveConnectedUser(protocol); -} - -void ForwarderInterface::scheduleRemoveConnectedUser(ProtocolPtr protocol) { - internal_ioservice_.post( - [this, protocol]() { internalRemoveConnectedUser(protocol); }); -} -#endif - -void ForwarderInterface::createFaceAndRoute(const RouteInfoPtr &route_info) { - std::vector<RouteInfoPtr> routes; - routes.push_back(std::move(route_info)); - createFaceAndRoutes(routes); -} - -void ForwarderInterface::createFaceAndRoutes( - const std::vector<RouteInfoPtr> &routes_info) { - pending_add_route_counter_++; - auto timer = new asio::steady_timer(internal_ioservice_); - internal_ioservice_.post([this, routes_info, timer]() { - internalCreateFaceAndRoutes(routes_info, ForwarderInterface::MAX_REATTEMPT, - timer); - }); -} - -void ForwarderInterface::deleteFaceAndRoute(const RouteInfoPtr &route_info) { - std::vector<RouteInfoPtr> routes; - routes.push_back(std::move(route_info)); - deleteFaceAndRoutes(routes); -} - -void ForwarderInterface::deleteFaceAndRoutes( - const std::vector<RouteInfoPtr> &routes_info) { - internal_ioservice_.post([this, routes_info]() { - for (auto &route : routes_info) { - internalDeleteFaceAndRoute(route); - } - }); -} - -void ForwarderInterface::setStrategy(std::string prefix, uint32_t prefix_len, - std::string strategy) { - if (!sock_) return; - - ip_address_t ip_prefix; - if (ip_address_pton(prefix.c_str(), &ip_prefix) < 0) { - return; - } - - strategy_type_t strategy_type = strategy_type_from_str(strategy.c_str()); - if (strategy_type == STRATEGY_TYPE_UNDEFINED) return; - - hc_strategy_t strategy_conf; - strategy_conf.address = ip_prefix; - strategy_conf.len = prefix_len; - strategy_conf.family = AF_INET6; - strategy_conf.type = strategy_type; - - hc_strategy_set(sock_, &strategy_conf); -} - -void ForwarderInterface::internalDeleteFaceAndRoute( - const RouteInfoPtr &route_info) { - if (!sock_) return; - - hc_data_t *data; - if (hc_route_list(sock_, &data) < 0) return; - - std::vector<hc_route_t *> routes_to_remove; - foreach_route(r, data) { - char remote_addr[INET6_ADDRSTRLEN]; - int ret = ip_address_ntop(&r->remote_addr, remote_addr, r->len, r->family); - if (ret < 0) continue; - - std::string route_addr(remote_addr); - if (route_addr.compare(route_info->route_addr) == 0 && - r->len == route_info->route_len) { - // route found - routes_to_remove.push_back(r); - } - } - - if (routes_to_remove.size() == 0) { - // nothing to do here - hc_data_free(data); - return; - } - - std::unordered_set<uint32_t> connids_to_remove; - for (unsigned i = 0; i < routes_to_remove.size(); i++) { - connids_to_remove.insert(routes_to_remove[i]->face_id); - if (hc_route_delete(sock_, routes_to_remove[i]) < 0) { - std::cout << "Error removing route from forwarder." << std::endl; - } - } - - // remove connection - if (hc_connection_list(sock_, &data) < 0) { - hc_data_free(data); - return; - } - - // collects pointerst to the connections using the conn IDs - std::vector<hc_connection_t *> conns_to_remove; - foreach_connection(c, data) { - if (connids_to_remove.find(c->id) != connids_to_remove.end()) { - // conn found - conns_to_remove.push_back(c); - } - } - - if (conns_to_remove.size() == 0) { - // nothing else to do here - hc_data_free(data); - return; - } - - for (unsigned i = 0; i < conns_to_remove.size(); i++) { - if (hc_connection_delete(sock_, conns_to_remove[i]) < 0) { - std::cout << "Error removing connection from forwarder." << std::endl; - } - } - - hc_data_free(data); -} - -void ForwarderInterface::internalCreateFaceAndRoutes( - const std::vector<RouteInfoPtr> &route_info, uint8_t max_try, - asio::steady_timer *timer) { - uint32_t face_id; - - std::vector<RouteInfoPtr> failed; - for (auto &route : route_info) { - int ret = tryToCreateFace(route.get(), &face_id); - if (ret >= 0) { - auto ret = tryToCreateRoute(route.get(), face_id); - if (ret < 0) { - failed.push_back(route); - std::cerr << "Error creating route and face" << std::endl; - continue; - } - } - } - - if (failed.size() > 0) { - if (max_try == 0) { - /* All attempts failed */ - goto RESULT; - } - max_try--; - timer->expires_from_now(std::chrono::milliseconds(500)); - timer->async_wait( - [this, failed, max_try, timer](const std::error_code &ec) { - if (ec) return; - internalCreateFaceAndRoutes(failed, max_try, timer); - }); - return; - } - -#if 0 - // route_status_[protocol] = std::move(route_info); - for (size_t i = 0; i < route_info.size(); i++) { - route_status_.insert( - std::pair<ClientId, RouteInfoPtr>(protocol, std::move(route_info[i]))); - } -#endif - -RESULT: - std::cout << "Face / Route create ok, now calling back protocol" << std::endl; - pending_add_route_counter_--; - external_ioservice_.post([this, r = std::move(route_info)]() mutable { - forwarder_interface_callback_->onRouteConfigured(r); - }); - delete timer; -} - -int ForwarderInterface::tryToCreateFace(RouteInfo *route_info, - uint32_t *face_id) { - bool found = false; - - // check connection with the forwarder - if (!sock_) { - std::cout << "[ForwarderInterface::tryToCreateFace] socket error" - << std::endl; - goto ERR_SOCK; - } - - // get listeners list - hc_data_t *data; - if (hc_listener_list(sock_, &data) < 0) { - std::cout << "[ForwarderInterface::tryToCreateFace] cannot list listeners"; - goto ERR_LIST; - } - - char _local_address[128]; - foreach_listener(l, data) { - std::cout << "Processing " << l->interface_name << std::endl; - std::string interface = std::string(l->interface_name); - int ret = ip_address_ntop(&l->local_addr, _local_address, 128, AF_INET); - if (ret < 0) { - std::cerr << "Error in ip_address_ntop" << std::endl; - goto ERR; - } - - std::string local_address = std::string(_local_address); - uint16_t local_port = l->local_port; - - if (interface.compare(route_info->interface) == 0 && - local_address.compare(route_info->local_addr) == 0 && - local_port == route_info->local_port) { - found = true; - break; - } - } - - std::cout << route_info->remote_addr << std::endl; - - ip_address_t local_address, remote_address; - ip_address_pton(route_info->local_addr.c_str(), &local_address); - ip_address_pton(route_info->remote_addr.c_str(), &remote_address); - - if (!found) { - // Create listener - hc_listener_t listener; - memset(&listener, 0, sizeof(hc_listener_t)); - - std::string name = "l_" + route_info->name; - listener.local_addr = local_address; - listener.type = FACE_TYPE_UDP; - listener.family = AF_INET; - listener.local_port = route_info->local_port; - int ret = strcpy_s(listener.name, SYMBOLIC_NAME_LEN - 1, name.c_str()); - if (ret < EOK) goto ERR; - ret = strcpy_s(listener.interface_name, INTERFACE_LEN - 1, - route_info->interface.c_str()); - if (ret < EOK) goto ERR; - - std::cout << "------------> " << route_info->interface << std::endl; - - ret = hc_listener_create(sock_, &listener); - - if (ret < 0) { - std::cerr << "Error creating listener." << std::endl; - return -1; - } else { - std::cout << "Listener " << listener.id << " created." << std::endl; - } - } - - // Create face - hc_face_t face; - memset(&face, 0, sizeof(hc_face_t)); - - // crate face with the local interest - face.face.type = FACE_TYPE_UDP; - face.face.family = route_info->family; - face.face.local_addr = local_address; - face.face.remote_addr = remote_address; - face.face.local_port = route_info->local_port; - face.face.remote_port = route_info->remote_port; - - if (netdevice_set_name(&face.face.netdevice, route_info->interface.c_str()) < - 0) { - std::cout << "[ForwarderInterface::tryToCreateFaceAndRoute] " - "netdevice_set_name " - "(" - << face.face.netdevice.name << ", " - << route_info->interface << ") error" << std::endl; - goto ERR; - } - - // create face - if (hc_face_create(sock_, &face) < 0) { - std::cout << "[ForwarderInterface::tryToCreateFace] error creating face"; - goto ERR; - } - - std::cout << "Face created successfully" << std::endl; - - // assing face to the return value - *face_id = face.id; - - hc_data_free(data); - return 0; - -ERR: - hc_data_free(data); -ERR_LIST: -ERR_SOCK: - return -1; -} - -int ForwarderInterface::tryToCreateRoute(RouteInfo *route_info, - uint32_t face_id) { - std::cout << "Trying to create route" << std::endl; - - // check connection with the forwarder - if (!sock_) { - std::cout << "[ForwarderInterface::tryToCreateRoute] socket error"; - return -1; - } - - ip_address_t route_ip; - hc_route_t route; - - if (ip_address_pton(route_info->route_addr.c_str(), &route_ip) < 0) { - std::cout << "[ForwarderInterface::tryToCreateRoute] ip_address_pton error"; - return -1; - } - - route.face_id = face_id; - route.family = AF_INET6; - route.remote_addr = route_ip; - route.len = route_info->route_len; - route.cost = 1; - - if (hc_route_create(sock_, &route) < 0) { - std::cout << "[ForwarderInterface::tryToCreateRoute] error creating route"; - return -1; - } - - std::cout << "[ForwarderInterface::tryToCreateRoute] OK" << std::endl; - return 0; -} - -#if 0 // not used -void ForwarderInterface::checkRoutesLoop() { - check_routes_timer_->expires_from_now(std::chrono::milliseconds(1000)); - check_routes_timer_->async_wait([this](const std::error_code &ec) { - if (ec) return; - if (pending_add_route_counter_ == 0) checkRoutes(); - }); -} - -void ForwarderInterface::checkRoutes() { - std::cout << "someone called the checkRoutes function" << std::endl; - if (!sock_) return; - - hc_data_t *data; - if (hc_route_list(sock_, &data) < 0) { - return; - } - - std::unordered_set<std::string> routes_set; - foreach_route(r, data) { - char remote_addr[INET6_ADDRSTRLEN]; - int ret = ip_address_ntop(&r->remote_addr, remote_addr, r->len, r->family); - if (ret < 0) continue; - std::string route(std::string(remote_addr) + "/" + std::to_string(r->len)); - routes_set.insert(route); - } - - for (auto it = route_status_.begin(); it != route_status_.end(); it++) { - std::string route(it->second->route_addr + "/" + - std::to_string(it->second->route_len)); - if (routes_set.find(route) == routes_set.end()) { - // the route is missing - createFaceAndRoute(it->second, it->first); - break; - } - } - - hc_data_free(data); -} -#endif - -#if 0 - using ListenerRetrievedCallback = - std::function<void(std::error_code, uint32_t)>; - - ListenerRetrievedCallback listener_retrieved_callback_; - -#ifdef __ANDROID__ - hicn_listen_port_(9695), -#else - hicn_listen_port_(0), -#endif - timer_(forward_engine_.getIoService()), - - void initConfigurationProtocol(void) - { - // We need the configuration, which is different for every protocol... - // so we move this step down towards the protocol implementation itself. - if (!permanent_hicn) { - doInitConfigurationProtocol(); - } else { - // XXX This should be moved somewhere else - getMainListener( - [this](const std::error_code &ec, uint32_t hicn_listen_port) { - if (!ec) - { - hicn_listen_port_ = hicn_listen_port; - doInitConfigurationProtocol(); - } - }); - } - } - - template <typename Callback> - void getMainListener(Callback &&callback) - { - listener_retrieved_callback_ = std::forward<Callback &&>(callback); - tryToConnectToForwarder(); - } - private: - void doGetMainListener(const std::error_code &ec) - { - if (!ec) - { - // ec == 0 --> timer expired - int ret = forwarder_interface_.getMainListenerPort(); - if (ret <= 0) - { - // Since without the main listener of the forwarder the proxy cannot - // work, we can stop the program here until we get the listener port. - std::cout << - "Could not retrieve main listener port from the forwarder. " - "Retrying."; - - timer_.expires_from_now(std::chrono::milliseconds(RETRY_INTERVAL)); - timer_.async_wait(std::bind(&Protocol::doGetMainListener, this, - std::placeholders::_1)); - } - else - { - timer_.cancel(); - retx_count_ = 0; - hicn_listen_port_ = uint16_t(ret); - listener_retrieved_callback_( - make_error_code(configuration_error::success), hicn_listen_port_); - } - } - else - { - std::cout << "Timer for retrieving main hicn listener canceled." << std::endl; - } - } - - void tryToConnectToForwarder() - { - doTryToConnectToForwarder(std::make_error_code(std::errc(0))); - } - - void doTryToConnectToForwarder(const std::error_code &ec) - { - if (!ec) - { - // ec == 0 --> timer expired - int ret = forwarder_interface_.connect(); - if (ret < 0) - { - // We were not able to connect to the local forwarder. Do not give up - // and retry. - std::cout << "Could not connect to local forwarder. Retrying." << std::endl; - - timer_.expires_from_now(std::chrono::milliseconds(RETRY_INTERVAL)); - timer_.async_wait(std::bind(&Protocol::doTryToConnectToForwarder, this, - std::placeholders::_1)); - } - else - { - timer_.cancel(); - retx_count_ = 0; - doGetMainListener(std::make_error_code(std::errc(0))); - } - } - else - { - std::cout << "Timer for re-trying forwarder connection canceled." << std::endl; - } - } - - - template <typename ProtocolImplementation> - constexpr uint32_t Protocol<ProtocolImplementation>::RETRY_INTERVAL; - -#endif - -constexpr uint32_t ForwarderInterface::REATTEMPT_DELAY_MS; -constexpr uint32_t ForwarderInterface::MAX_REATTEMPT; - -} // namespace hiperf diff --git a/apps/hiperf/src/forwarder_interface.h b/apps/hiperf/src/forwarder_interface.h deleted file mode 100644 index e58989295..000000000 --- a/apps/hiperf/src/forwarder_interface.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <hicn/transport/utils/noncopyable.h> - -extern "C" { -#ifndef WITH_POLICY -#define WITH_POLICY -#endif -#include <hicn/ctrl/api.h> -#include <hicn/util/ip_address.h> -} - -#ifndef ASIO_STANDALONE -#define ASIO_STANDALONE -#endif -#include <asio.hpp> -#include <functional> -#include <thread> -#include <unordered_map> - -namespace hiperf { - -class ForwarderInterface : ::utils::NonCopyable { - static const uint32_t REATTEMPT_DELAY_MS = 500; - static const uint32_t MAX_REATTEMPT = 10; - - public: - struct RouteInfo { - int family; - std::string local_addr; - uint16_t local_port; - std::string remote_addr; - uint16_t remote_port; - std::string route_addr; - uint8_t route_len; - std::string interface; - std::string name; - }; - - using RouteInfoPtr = std::shared_ptr<RouteInfo>; - - class ICallback { - public: - virtual void onHicnServiceReady() = 0; - virtual void onRouteConfigured(std::vector<RouteInfoPtr> &route_info) = 0; - }; - - enum class State { - Disabled, /* Stack is stopped */ - Requested, /* Stack is starting */ - Available, /* Forwarder is running */ - Connected, /* Control socket connected */ - Ready, /* Listener present */ - }; - - public: - explicit ForwarderInterface(asio::io_service &io_service); - explicit ForwarderInterface(asio::io_service &io_service, ICallback *callback, - forwarder_type_t fwd_type); - - ~ForwarderInterface(); - - void initForwarderInterface(ICallback *callback, forwarder_type_t fwd_type); - - State getState(); - - void setState(State state); - - void onHicnServiceAvailable(bool flag); - - void enableCheckRoutesTimer(); - - void createFaceAndRoutes(const std::vector<RouteInfoPtr> &routes_info); - - void createFaceAndRoute(const RouteInfoPtr &route_info); - - void deleteFaceAndRoutes(const std::vector<RouteInfoPtr> &routes_info); - - void deleteFaceAndRoute(const RouteInfoPtr &route_info); - - void setStrategy(std::string prefix, uint32_t prefix_len, - std::string strategy); - - void close(); - - uint16_t getHicnListenerPort() { return hicn_listen_port_; } - - private: - ForwarderInterface &operator=(const ForwarderInterface &other) = delete; - - int connectToForwarder(); - - int checkListener(); - - void internalCreateFaceAndRoutes(const std::vector<RouteInfoPtr> &route_info, - uint8_t max_try, asio::steady_timer *timer); - - void internalDeleteFaceAndRoute(const RouteInfoPtr &routes_info); - - int tryToCreateFace(RouteInfo *RouteInfo, uint32_t *face_id); - int tryToCreateRoute(RouteInfo *RouteInfo, uint32_t face_id); - - void checkRoutesLoop(); - - void checkRoutes(); - - asio::io_service &external_ioservice_; - asio::io_service internal_ioservice_; - ICallback *forwarder_interface_callback_; - std::unique_ptr<asio::io_service::work> work_; - hc_sock_t *sock_; - std::unique_ptr<std::thread> thread_; - // SetRouteCallback set_route_callback_; - // std::unordered_multimap<ProtocolPtr, RouteInfoPtr> route_status_; - std::unique_ptr<asio::steady_timer> check_routes_timer_; - uint32_t pending_add_route_counter_; - uint16_t hicn_listen_port_; - - State state_; - - forwarder_type_t fwd_type_; - - /* Reattempt timer */ - asio::steady_timer timer_; - unsigned num_reattempts; -}; - -} // namespace hiperf diff --git a/apps/hiperf/src/main.cc b/apps/hiperf/src/main.cc index 9c0f0a140..85cadd677 100644 --- a/apps/hiperf/src/main.cc +++ b/apps/hiperf/src/main.cc @@ -14,7 +14,6 @@ */ #include <client.h> -#include <forwarder_interface.h> #include <server.h> namespace hiperf { @@ -44,6 +43,11 @@ void usage() { std::cerr << "-X\t<param>\t\t\t\t" << "Set FEC params. Options are Rely_K#_N# or RS_K#_N#" << std::endl; + std::cerr + << "-J\t<passphrase>\t\t\t" + << "Set the passphrase used to sign/verify aggregated interests. " + "If set on the client, aggregated interests are enable automatically." + << std::endl; #endif std::cerr << std::endl; std::cerr << "SERVER SPECIFIC:" << std::endl; @@ -51,11 +55,17 @@ void usage() { "Sends an application data unit in bytes that is published once " "before exit" << std::endl; + std::cerr << "-E\t<expiry_time>\t\t\t" + "Expiration time for data packets generated by the producer " + "socket" + << std::endl; std::cerr << "-s\t<packet_size>\t\t\tData packet payload size." << std::endl; std::cerr << "-r\t\t\t\t\t" << "Produce real content of <content_size> bytes" << std::endl; - std::cerr << "-m\t<manifest_capacity>\t\t" - << "Produce transport manifest" << std::endl; + std::cerr << "-m\t<manifest_max_capacity>\t\t" + << "The maximum number of entries a manifest can contain. Set it " + "to 0 to disable manifests. Default is 30, max is 255." + << std::endl; std::cerr << "-l\t\t\t\t\t" << "Start producing content upon the reception of the " "first interest" @@ -92,11 +102,6 @@ void usage() { "the packet to generate. To be used with the -R option. -B and -I " "will be ignored." << std::endl; - std::cerr << "-E\t\t\t\t\t" - << "Enable encrypted communication. Requires the path to a p12 " - "file containing the " - "crypto material used for the TLS handshake" - << std::endl; std::cerr << "-G\t<port>\t\t\t\t" << "Input stream from localhost at the specified port" << std::endl; #endif @@ -110,12 +115,27 @@ void usage() { << std::endl; std::cerr << "-L\t<interest lifetime>\t\t" << "Set interest lifetime." << std::endl; - std::cerr << "-u\t<delay>\t\t\t\t" - << "Set max lifetime of unverified packets." << std::endl; + std::cerr << "-U\t<factor>\t\t\t" + << "Update the relevance threshold: if an unverified packet has " + "been received before the last U * manifest_max_capacity_ " + "packets received (verified or not), it will be flushed out. " + "Should be > 1, default is 100." + << std::endl; + std::cerr << "-u\t<factor>\t\t\t" + << "Update the alert threshold: if the " + "number of unverified packet is > u * manifest_max_capacity_, " + "an alert is raised. Should be set such that U > u >= 1, " + "default is 20. If u >= U, no alert will ever be raised." + << std::endl; std::cerr << "-M\t<input_buffer_size>\t\t" << "Size of consumer input buffer. If 0, reassembly of packets " "will be disabled." << std::endl; + std::cerr << "-N\t\t\t\t\t" + << "Enable aggregated interests; the number of suffixes (including " + "the one in the header) can be set through the env variable " + "`MAX_AGGREGATED_INTERESTS`." + << std::endl; std::cerr << "-W\t<window_size>\t\t\t" << "Use a fixed congestion window " "for retrieving the data." @@ -137,7 +157,10 @@ void usage() { "used with the -R (default: false)" << std::endl; std::cerr << "-P\t\t\t\t\t" - << "Prefix of the producer where to do the handshake" << std::endl; + << "Number of parallel streams. For hiperf client, this is the " + "number of consumer to create, while for hiperf server this is " + "the number of producers to create." + << std::endl; std::cerr << "-j\t<relay_name>\t\t\t" << "Publish received content under the name relay_name." "This is an RTC specific option, to be " @@ -145,13 +168,25 @@ void usage() { << std::endl; std::cerr << "-g\t<port>\t\t\t\t" << "Output stream to localhost at the specified port" << std::endl; + std::cerr << "-o\t\t\t\t\t" + << "Content sharing mode: if set the socket work in content sharing" + << "mode. It works only in RTC mode" << std::endl; std::cerr << "-e\t<strategy>\t\t\t" - << "Enhance the network with a reliability strategy. Options 1:" - << " unreliable, 2: rtx only, 3: fec only, " - << "4: delay based, 5: low rate, 6: low rate and best path " - << "7: low rate and replication, 8: low rate and best" - << " path/replication" - << "(default: 2 = rtx only) " << std::endl; + << "Enhance the network with a reliability strategy. Options" + << std::endl; + std::cerr << "\t\t\t\t\t\t1: unreliable " << std::endl; + std::cerr << "\t\t\t\t\t\t2: rtx only " << std::endl; + std::cerr << "\t\t\t\t\t\t3: fec only " << std::endl; + std::cerr << "\t\t\t\t\t\t4: delay based " << std::endl; + std::cerr << "\t\t\t\t\t\t5: low rate " << std::endl; + std::cerr << "\t\t\t\t\t\t6: low rate and best path " << std::endl; + std::cerr << "\t\t\t\t\t\t7: low rate and replication" << std::endl; + std::cerr << "\t\t\t\t\t\t8: low rate and best path/replication " + << std::endl; + std::cerr << "\t\t\t\t\t\t9: only fec low residual losses " << std::endl; + std::cerr << "\t\t\t\t\t\t10: delay and best path " << std::endl; + std::cerr << "\t\t\t\t\t\t11: delay and replication " << std::endl; + std::cerr << "\t\t\t\t\t\t(default: 2 = rtx only) " << std::endl; std::cerr << "-H\t\t\t\t\t" << "Disable periodic print headers in stats report." << std::endl; std::cerr << "-n\t<nb_iterations>\t\t\t" @@ -170,6 +205,8 @@ int main(int argc, char *argv[]) { WSAStartup(MAKEWORD(2, 2), &wsaData); #endif + transport::interface::global_config::GlobalConfigInterface global_conf; + // -1 server, 0 undefined, 1 client int role = 0; int options = 0; @@ -188,9 +225,10 @@ int main(int argc, char *argv[]) { int opt; #ifndef _WIN32 // Please keep in alphabetical order. - while ((opt = getopt(argc, argv, - "A:B:CDE:F:G:HIK:L:M:P:RST:U:W:X:ab:c:d:e:f:g:hi:j:k:lm:" - "n:p:rs:tu:vwxy:z:")) != -1) { + while ( + (opt = getopt(argc, argv, + "A:B:CDE:F:G:HIJ:K:L:M:NP:RST:U:W:X:ab:c:d:e:f:g:hi:j:k:lm:" + "n:op:qrs:tu:vwxy:z:")) != -1) { switch (opt) { // Common case 'D': { @@ -225,10 +263,14 @@ int main(int argc, char *argv[]) { #else // Please keep in alphabetical order. while ((opt = getopt(argc, argv, - "A:B:CE:F:HK:L:M:P:RSU:W:X:ab:c:d:e:f:hi:j:k:lm:n:p:rs:" + "A:B:CE:F:HK:L:M:P:RSU:W:X:ab:c:d:e:f:hi:j:k:lm:n:op:rs:" "tu:vwxy:z:")) != -1) { switch (opt) { #endif + case 'E': { + server_configuration.content_lifetime_ = std::stoul(optarg); + break; + } case 'f': { log_file = optarg; break; @@ -243,14 +285,18 @@ int main(int argc, char *argv[]) { server_configuration.aggregated_data_ = true; break; } + case 'o': { + client_configuration.content_sharing_mode_ = true; + break; + } case 'w': { client_configuration.packet_format_ = Packet::Format::HF_INET6_UDP; server_configuration.packet_format_ = Packet::Format::HF_INET6_UDP; break; } case 'k': { - server_configuration.passphrase = std::string(optarg); - client_configuration.passphrase = std::string(optarg); + server_configuration.passphrase_ = std::string(optarg); + client_configuration.passphrase_ = std::string(optarg); break; } case 'z': { @@ -271,20 +317,31 @@ int main(int argc, char *argv[]) { role += 1; break; } - + case 'q': { + client_configuration.colored_ = server_configuration.colored_ = false; + break; + } + case 'J': { + client_configuration.aggr_interest_passphrase_ = optarg; + server_configuration.aggr_interest_passphrase_ = optarg; + // Consumer signature is only used with aggregated interests, + // hence enabling it also forces usage of aggregated interests + client_configuration.aggregated_interests_ = true; + break; + } // Client specifc case 'b': { - client_configuration.beta = std::stod(optarg); + client_configuration.beta_ = std::stod(optarg); options = 1; break; } case 'd': { - client_configuration.drop_factor = std::stod(optarg); + client_configuration.drop_factor_ = std::stod(optarg); options = 1; break; } case 'W': { - client_configuration.window = std::stod(optarg); + client_configuration.window_ = std::stod(optarg); options = 1; break; } @@ -293,13 +350,17 @@ int main(int argc, char *argv[]) { options = 1; break; } + case 'N': { + client_configuration.aggregated_interests_ = true; + break; + } case 'P': { - client_configuration.producer_prefix_ = Prefix(optarg); - client_configuration.secure_ = true; + client_configuration.parallel_flows_ = + server_configuration.parallel_flows_ = std::stoull(optarg); break; } case 'c': { - client_configuration.producer_certificate = std::string(optarg); + client_configuration.producer_certificate_ = std::string(optarg); options = 1; break; } @@ -318,13 +379,13 @@ int main(int argc, char *argv[]) { options = 1; break; } - case 'u': { - client_configuration.unverified_interval_ = std::stoul(optarg); + case 'U': { + client_configuration.manifest_factor_relevant_ = std::stoul(optarg); options = 1; break; } - case 'U': { - client_configuration.unverified_ratio_ = std::stod(optarg); + case 'u': { + client_configuration.manifest_factor_alert_ = std::stoul(optarg); options = 1; break; } @@ -346,7 +407,7 @@ int main(int argc, char *argv[]) { } // Server specific case 'A': { - server_configuration.download_size = std::stoul(optarg); + server_configuration.download_size_ = std::stoul(optarg); options = -1; break; } @@ -356,22 +417,22 @@ int main(int argc, char *argv[]) { break; } case 'r': { - server_configuration.virtual_producer = false; + server_configuration.virtual_producer_ = false; options = -1; break; } case 'm': { - server_configuration.manifest = std::stoul(optarg); + server_configuration.manifest_max_capacity_ = std::stoul(optarg); options = -1; break; } case 'l': { - server_configuration.live_production = true; + server_configuration.live_production_ = true; options = -1; break; } case 'K': { - server_configuration.keystore_name = std::string(optarg); + server_configuration.keystore_name_ = std::string(optarg); options = -1; break; } @@ -393,7 +454,7 @@ int main(int argc, char *argv[]) { break; } case 'p': { - server_configuration.keystore_password = std::string(optarg); + server_configuration.keystore_password_ = std::string(optarg); options = -1; break; } @@ -409,11 +470,6 @@ int main(int argc, char *argv[]) { options = -1; break; } - case 'E': { - server_configuration.keystore_name = std::string(optarg); - server_configuration.secure_ = true; - break; - } case 'e': { client_configuration.recovery_strategy_ = std::stoul(optarg); options = 1; @@ -457,9 +513,9 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } else { if (role > 0) { - client_configuration.name = Name(argv[optind]); + client_configuration.name_ = Prefix(argv[optind]); } else { - server_configuration.name = Prefix(argv[optind]); + server_configuration.name_ = Prefix(argv[optind]); } } @@ -490,16 +546,9 @@ int main(int argc, char *argv[]) { config.set(); // Parse config file - transport::interface::global_config::parseConfigurationFile(conf_file); + global_conf.parseConfigurationFile(conf_file); if (role > 0) { - // set forwarder type - client_configuration.forwarder_type_ = UNDEFINED; - if (config.name.compare("hicnlightng_module") == 0) - client_configuration.forwarder_type_ = HICNLIGHT; - else if (config.name.compare("hicnlightng_module") == 0) - client_configuration.forwarder_type_ = HICNLIGHT_NG; - HIperfClient c(client_configuration); if (c.setup() != ERROR_SETUP) { c.run(); diff --git a/apps/hiperf/src/server.cc b/apps/hiperf/src/server.cc index 7101e7a4a..afaf5423b 100644 --- a/apps/hiperf/src/server.cc +++ b/apps/hiperf/src/server.cc @@ -21,156 +21,79 @@ namespace hiperf { * Hiperf server class: configure and setup an hicn producer following the * ServerConfiguration. */ -class HIperfServer::Impl : public ProducerSocket::Callback { - const std::size_t log2_content_object_buffer_size = 8; - - public: - Impl(const hiperf::ServerConfiguration &conf) - : configuration_(conf), - signals_(io_service_), - rtc_timer_(io_service_), - unsatisfied_interests_(), - content_objects_((std::uint16_t)(1 << log2_content_object_buffer_size)), - content_objects_index_(0), - mask_((std::uint16_t)(1 << log2_content_object_buffer_size) - 1), - last_segment_(0), -#ifndef _WIN32 - input_(io_service_), - rtc_running_(false), -#endif - flow_name_(configuration_.name.getName()), - socket_(io_service_), - recv_buffer_(nullptr, 0) { - std::string buffer(configuration_.payload_size_, 'X'); - std::cout << "Producing contents under name " << conf.name.getName() - << std::endl; -#ifndef _WIN32 - if (configuration_.interactive_) { - input_.assign(::dup(STDIN_FILENO)); - } -#endif - - for (int i = 0; i < (1 << log2_content_object_buffer_size); i++) { - content_objects_[i] = ContentObject::Ptr(new ContentObject( - configuration_.name.getName(), configuration_.packet_format_, 0, - (const uint8_t *)buffer.data(), buffer.size())); - content_objects_[i]->setLifetime( - default_values::content_object_expiry_time); - } +class HIperfServer::Impl { + static inline constexpr std::size_t klog2_content_object_buffer_size() { + return 8; } - - virtual ~Impl() {} - - void virtualProcessInterest(ProducerSocket &p, const Interest &interest) { - content_objects_[content_objects_index_ & mask_]->setName( - interest.getName()); - producer_socket_->produce( - *content_objects_[content_objects_index_++ & mask_]); + static inline constexpr std::size_t kcontent_object_buffer_size() { + return (1 << klog2_content_object_buffer_size()); } - - void processInterest(ProducerSocket &p, const Interest &interest) { - p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS, - (ProducerInterestCallback)VOID_HANDLER); - p.setSocketOption(GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME, - 5000000_U32); - - produceContent(p, interest.getName(), interest.getName().getSuffix()); - std::cout << "Received interest " << interest.getName().getSuffix() - << std::endl; + static inline constexpr std::size_t kmask() { + return (kcontent_object_buffer_size() - 1); } - void asyncProcessInterest(ProducerSocket &p, const Interest &interest) { - p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS, - (ProducerInterestCallback)bind(&Impl::cacheMiss, this, - std::placeholders::_1, - std::placeholders::_2)); - p.setSocketOption(GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME, - 5000000_U32); - uint32_t suffix = interest.getName().getSuffix(); - - if (suffix == 0) { - last_segment_ = 0; - unsatisfied_interests_.clear(); - } - - // The suffix will either come from the received interest or will be set to - // the smallest suffix of a previous interest not satisfied - if (!unsatisfied_interests_.empty()) { - auto it = std::lower_bound(unsatisfied_interests_.begin(), - unsatisfied_interests_.end(), last_segment_); - if (it != unsatisfied_interests_.end()) { - suffix = *it; + /** + * @brief As we can (potentially) setup many producer sockets, we need to keep + * a separate context for each one of them. The context contains parameters + * and variable that are specific to a single producer socket. + */ + class ProducerContext + : public Base<ProducerContext, ServerConfiguration, Impl>, + public ProducerSocket::Callback { + public: + using ConfType = ServerConfiguration; + using ParentType = typename HIperfServer::Impl; + static inline const auto getContextType() { return "ProducerContext"; } + + ProducerContext(HIperfServer::Impl &server, int producer_identifier) + : Base(server, server.io_service_, producer_identifier) { + // Allocate buffer to copy as content objects payload + std::string buffer(configuration_.payload_size_, 'X'); + + // Allocate array of content objects. They are share_ptr so that the + // transport will only capture a reference to them instead of performing + // an hard copy. + for (std::size_t i = 0; i < kcontent_object_buffer_size(); i++) { + const auto &element = + content_objects_.emplace_back(std::make_shared<ContentObject>( + configuration_.name_.makeName(), configuration_.packet_format_, + 0, (const uint8_t *)buffer.data(), buffer.size())); + element->setLifetime(default_values::content_object_expiry_time); } - unsatisfied_interests_.erase(unsatisfied_interests_.begin(), it); } - std::cout << "Received interest " << interest.getName().getSuffix() - << ", starting production at " << suffix << std::endl; - std::cout << unsatisfied_interests_.size() << " interests still unsatisfied" - << std::endl; - produceContentAsync(p, interest.getName(), suffix); - } + // To make vector happy (move or copy constructor is needed when vector + // resizes) + ProducerContext(ProducerContext &&other) noexcept + : Base(std::move(other)), + content_objects_(std::move(other.content_objects_)), + unsatisfied_interests_(std::move(other.unsatisfied_interests_)), + last_segment_(other.last_segment_), + producer_socket_(std::move(other.producer_socket_)), + content_objects_index_(other.content_objects_index_), + payload_size_max_(other.payload_size_max_) {} - void produceContent(ProducerSocket &p, const Name &content_name, - uint32_t suffix) { - auto b = utils::MemBuf::create(configuration_.download_size); - std::memset(b->writableData(), '?', configuration_.download_size); - b->append(configuration_.download_size); - uint32_t total; - - utils::SteadyTime::TimePoint t0 = utils::SteadyTime::Clock::now(); - total = p.produceStream(content_name, std::move(b), - !configuration_.multiphase_produce_, suffix); - utils::SteadyTime::TimePoint t1 = utils::SteadyTime::Clock::now(); - - std::cout << "Written " << total - << " data packets in output buffer (Segmentation time: " - << utils::SteadyTime::getDurationUs(t0, t1).count() << " us)" - << std::endl; - } + virtual ~ProducerContext() = default; - void produceContentAsync(ProducerSocket &p, Name content_name, - uint32_t suffix) { - produce_thread_.add([this, suffix, content_name]() { - auto b = utils::MemBuf::create(configuration_.download_size); - std::memset(b->writableData(), '?', configuration_.download_size); - b->append(configuration_.download_size); - - last_segment_ = suffix + producer_socket_->produceStream( - content_name, std::move(b), - !configuration_.multiphase_produce_, suffix); - }); - } + /** + * @brief Produce datagram + */ + void produceDatagram(const uint8_t *buffer, std::size_t buffer_size) const { + assert(producer_socket_); - void cacheMiss(ProducerSocket &p, const Interest &interest) { - unsatisfied_interests_.push_back(interest.getName().getSuffix()); - } + auto size = std::min(buffer_size, payload_size_max_); - void onContentProduced(ProducerSocket &p, const std::error_code &err, - uint64_t bytes_written) { - p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS, - (ProducerInterestCallback)bind( - &Impl::asyncProcessInterest, this, - std::placeholders::_1, std::placeholders::_2)); - } + producer_socket_->produceDatagram(flow_name_, buffer, size); + } - void produceError(const std::error_code &err) noexcept override { - std::cerr << "Error from producer transport: " << err.message() - << std::endl; - producer_socket_->stop(); - io_service_.stop(); - } + /** + * @brief Create and setup the producer socket + */ + int setup() { + int ret; + int production_protocol; + std::shared_ptr<Signer> signer = std::make_shared<VoidSigner>(); - int setup() { - int ret; - int production_protocol; - std::shared_ptr<Signer> signer = std::make_shared<VoidSigner>(); - - if (configuration_.secure_) { - producer_socket_ = std::make_unique<P2PSecureProducerSocket>( - configuration_.rtc_, configuration_.keystore_name, - configuration_.keystore_password); - } else { if (!configuration_.rtc_) { production_protocol = ProductionProtocolAlgorithms::BYTE_STREAM; } else { @@ -178,255 +101,466 @@ class HIperfServer::Impl : public ProducerSocket::Callback { } producer_socket_ = std::make_unique<ProducerSocket>(production_protocol); - } - - if (producer_socket_->setSocketOption( - ProducerCallbacksOptions::PRODUCER_CALLBACK, this) == - SOCKET_OPTION_NOT_SET) { - std::cerr << "Failed to set producer callback." << std::endl; - return ERROR_SETUP; - } - - if (producer_socket_->setSocketOption( - GeneralTransportOptions::MAKE_MANIFEST, configuration_.manifest) == - SOCKET_OPTION_NOT_SET) { - return ERROR_SETUP; - } - if (producer_socket_->setSocketOption( - GeneralTransportOptions::HASH_ALGORITHM, - configuration_.hash_algorithm_) == SOCKET_OPTION_NOT_SET) { - return ERROR_SETUP; - } - - if (producer_socket_->setSocketOption(PACKET_FORMAT, - configuration_.packet_format_) == - SOCKET_OPTION_NOT_SET) { - std::cerr << "ERROR -- Impossible to set the packet format." << std::endl; - return ERROR_SETUP; - } + if (producer_socket_->setSocketOption( + ProducerCallbacksOptions::PRODUCER_CALLBACK, this) == + SOCKET_OPTION_NOT_SET) { + getOutputStream() << "Failed to set producer callback." << std::endl; + return ERROR_SETUP; + } - if (!configuration_.passphrase.empty()) { - signer = std::make_shared<SymmetricSigner>(CryptoSuite::HMAC_SHA256, - configuration_.passphrase); - } + if (producer_socket_->setSocketOption( + GeneralTransportOptions::HASH_ALGORITHM, + configuration_.hash_algorithm_) == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } - if (!configuration_.keystore_name.empty()) { - signer = std::make_shared<AsymmetricSigner>( - configuration_.keystore_name, configuration_.keystore_password); - } + if (producer_socket_->setSocketOption( + GeneralTransportOptions::MANIFEST_MAX_CAPACITY, + configuration_.manifest_max_capacity_) == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } - producer_socket_->setSocketOption(GeneralTransportOptions::SIGNER, signer); + if (producer_socket_->setSocketOption(PACKET_FORMAT, + configuration_.packet_format_) == + SOCKET_OPTION_NOT_SET) { + getOutputStream() << "ERROR -- Impossible to set the packet format." + << std::endl; + return ERROR_SETUP; + } - // Compute maximum payload size - Packet::Format format = PayloadSize::getFormatFromName( - configuration_.name.getName(), !configuration_.manifest); - payload_size_max_ = PayloadSize(format).getPayloadSizeMax( - configuration_.rtc_ ? RTC_HEADER_SIZE : 0, - configuration_.fec_type_.empty() ? 0 : FEC_HEADER_MAX_SIZE, - !configuration_.manifest ? signer->getSignatureFieldSize() : 0); + if (!configuration_.passphrase_.empty()) { + signer = std::make_shared<SymmetricSigner>(CryptoSuite::HMAC_SHA256, + configuration_.passphrase_); + } - if (configuration_.payload_size_ > payload_size_max_) { - std::cerr << "WARNING: Payload has size " << configuration_.payload_size_ - << ", maximum is " << payload_size_max_ - << ". Payload will be truncated to fit." << std::endl; - } + if (!configuration_.keystore_name_.empty()) { + signer = std::make_shared<AsymmetricSigner>( + configuration_.keystore_name_, configuration_.keystore_password_); + } - if (configuration_.rtc_) { - ret = producer_socket_->setSocketOption( - RtcTransportOptions::AGGREGATED_DATA, - configuration_.aggregated_data_); + producer_socket_->setSocketOption(GeneralTransportOptions::SIGNER, + signer); + + // Compute maximum payload size + Packet::Format format = PayloadSize::getFormatFromPrefix( + configuration_.name_, !configuration_.manifest_max_capacity_); + payload_size_max_ = PayloadSize(format).getPayloadSizeMax( + configuration_.rtc_ ? RTC_HEADER_SIZE : 0, + configuration_.fec_type_.empty() ? 0 : FEC_HEADER_MAX_SIZE, + !configuration_.manifest_max_capacity_ + ? signer->getSignatureFieldSize() + : 0); + + if (configuration_.payload_size_ > payload_size_max_) { + getOutputStream() << "WARNING: Payload has size " + << configuration_.payload_size_ << ", maximum is " + << payload_size_max_ + << ". Payload will be truncated to fit." << std::endl; + } - if (ret == SOCKET_OPTION_NOT_SET) { - return ERROR_SETUP; + // Verifier for aggregated interests + std::shared_ptr<Verifier> verifier = std::make_shared<VoidVerifier>(); + if (!configuration_.aggr_interest_passphrase_.empty()) { + verifier = std::make_unique<SymmetricVerifier>( + configuration_.aggr_interest_passphrase_); } - } + ret = producer_socket_->setSocketOption(GeneralTransportOptions::VERIFIER, + verifier); + if (ret == SOCKET_OPTION_NOT_SET) return ERROR_SETUP; - if (configuration_.rtc_) { - ret = producer_socket_->setSocketOption(GeneralTransportOptions::FEC_TYPE, - configuration_.fec_type_); + if (configuration_.rtc_) { + ret = producer_socket_->setSocketOption( + RtcTransportOptions::AGGREGATED_DATA, + configuration_.aggregated_data_); - if (ret == SOCKET_OPTION_NOT_SET) { - return ERROR_SETUP; - } - } + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } - producer_socket_->registerPrefix(configuration_.name); - producer_socket_->connect(); - producer_socket_->start(); + ret = producer_socket_->setSocketOption( + GeneralTransportOptions::FEC_TYPE, configuration_.fec_type_); - if (configuration_.rtc_) { - std::cout << "Running RTC producer: the prefix length will be ignored." - " Use /128 by default in RTC mode" - << std::endl; - return ERROR_SUCCESS; - } + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } + } - if (!configuration_.virtual_producer) { if (producer_socket_->setSocketOption( GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME, - configuration_.content_lifetime) == SOCKET_OPTION_NOT_SET) { + configuration_.content_lifetime_) == SOCKET_OPTION_NOT_SET) { return ERROR_SETUP; } - if (producer_socket_->setSocketOption( - GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 200000U) == - SOCKET_OPTION_NOT_SET) { - return ERROR_SETUP; - } + producer_socket_->registerPrefix(Prefix(flow_name_, 128)); + producer_socket_->connect(); + producer_socket_->start(); - if (producer_socket_->setSocketOption( - GeneralTransportOptions::MAX_SEGMENT_SIZE, - static_cast<uint32_t>(configuration_.payload_size_)) == - SOCKET_OPTION_NOT_SET) { - return ERROR_SETUP; + if (configuration_.rtc_) { + return ERROR_SUCCESS; } - if (!configuration_.live_production) { - produceContent(*producer_socket_, configuration_.name.getName(), 0); + if (!configuration_.virtual_producer_) { + if (producer_socket_->setSocketOption( + GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 200000U) == + SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } + + if (producer_socket_->setSocketOption( + GeneralTransportOptions::MAX_SEGMENT_SIZE, + static_cast<uint32_t>(configuration_.payload_size_)) == + SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } + + if (!configuration_.live_production_) { + produceContent(*producer_socket_, configuration_.name_.makeName(), 0); + } else { + ret = producer_socket_->setSocketOption( + ProducerCallbacksOptions::CACHE_MISS, + (ProducerInterestCallback)bind( + &ProducerContext::asyncProcessInterest, this, + std::placeholders::_1, std::placeholders::_2)); + + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } + } } else { ret = producer_socket_->setSocketOption( + GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 0U); + + if (ret == SOCKET_OPTION_NOT_SET) { + return ERROR_SETUP; + } + + ret = producer_socket_->setSocketOption( ProducerCallbacksOptions::CACHE_MISS, - (ProducerInterestCallback)bind(&Impl::asyncProcessInterest, this, - std::placeholders::_1, - std::placeholders::_2)); + (ProducerInterestCallback)bind( + &ProducerContext::virtualProcessInterest, this, + std::placeholders::_1, std::placeholders::_2)); if (ret == SOCKET_OPTION_NOT_SET) { return ERROR_SETUP; } } - } else { - ret = producer_socket_->setSocketOption( - GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 0U); + ret = producer_socket_->setSocketOption( + ProducerCallbacksOptions::CONTENT_PRODUCED, + (ProducerContentCallback)bind( + &ProducerContext::onContentProduced, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3)); if (ret == SOCKET_OPTION_NOT_SET) { return ERROR_SETUP; } - ret = producer_socket_->setSocketOption( - ProducerCallbacksOptions::CACHE_MISS, - (ProducerInterestCallback)bind(&Impl::virtualProcessInterest, this, - std::placeholders::_1, - std::placeholders::_2)); + return ERROR_SUCCESS; + } - if (ret == SOCKET_OPTION_NOT_SET) { - return ERROR_SETUP; + int run() { + getOutputStream() << "started to serve consumers with name " << flow_name_ + << std::endl; + return ERROR_SUCCESS; + } + + void stop() { + getOutputStream() << "stopped to serve consumers" << std::endl; + producer_socket_->stop(); + } + + private: + /** + * @brief Produce an existing content object. Set the name as the + * interest. + */ + void virtualProcessInterest(ProducerSocket &p, const Interest &interest) { + content_objects_[content_objects_index_ & kmask()]->setName( + interest.getName()); + p.produce(*content_objects_[content_objects_index_++ & kmask()]); + } + + /** + * @brief Create and produce a buffer of configuration_.download_size_ + * length. + */ + void produceContent(ProducerSocket &p, const Name &content_name, + uint32_t suffix) const { + uint32_t total; + + auto b = utils::MemBuf::create(configuration_.download_size_); + std::memset(b->writableData(), '?', configuration_.download_size_); + b->append(configuration_.download_size_); + + utils::SteadyTime::TimePoint t0 = utils::SteadyTime::Clock::now(); + total = p.produceStream(content_name, std::move(b), + !configuration_.multiphase_produce_, suffix); + utils::SteadyTime::TimePoint t1 = utils::SteadyTime::Clock::now(); + + Logger() << "Written " << total + << " data packets in output buffer (Segmentation time: " + << utils::SteadyTime::getDurationUs(t0, t1).count() << " us)" + << std::endl; + } + + /** + * @brief Synchronously produce content upon reception of one interest + */ + void processInterest(ProducerSocket &p, const Interest &interest) const { + p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS, + (ProducerInterestCallback)VOID_HANDLER); + p.setSocketOption(GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME, + configuration_.content_lifetime_); + + produceContent(p, interest.getName(), interest.getName().getSuffix()); + Logger() << "Received interest " << interest.getName().getSuffix() + << std::endl; + } + + /** + * @brief Async create and produce a buffer of + * configuration_.download_size_ length. + */ + void produceContentAsync(ProducerSocket &p, Name content_name, + uint32_t suffix) { + parent_.produce_thread_.add([this, suffix, content_name, &p]() { + auto b = utils::MemBuf::create(configuration_.download_size_); + std::memset(b->writableData(), '?', configuration_.download_size_); + b->append(configuration_.download_size_); + + last_segment_ = + suffix + p.produceStream(content_name, std::move(b), + !configuration_.multiphase_produce_, + suffix); + }); + } + + /** + * @brief Asynchronously produce content upon reception of one interest + */ + void asyncProcessInterest(ProducerSocket &p, const Interest &interest) { + p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS, + (ProducerInterestCallback)bind( + &ProducerContext::cacheMiss, this, + std::placeholders::_1, std::placeholders::_2)); + p.setSocketOption(GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME, + configuration_.content_lifetime_); + uint32_t suffix = interest.getName().getSuffix(); + + if (suffix == 0) { + last_segment_ = 0; + unsatisfied_interests_.clear(); + } + + // The suffix will either come from the received interest or will be set + // to the smallest suffix of a previous interest not satisfied + if (!unsatisfied_interests_.empty()) { + auto it = std::lower_bound(unsatisfied_interests_.begin(), + unsatisfied_interests_.end(), last_segment_); + if (it != unsatisfied_interests_.end()) { + suffix = *it; + } + unsatisfied_interests_.erase(unsatisfied_interests_.begin(), it); } + + getOutputStream() << " Received interest " + << interest.getName().getSuffix() + << ", starting production at " << suffix << end_mod_ + << std::endl; + getOutputStream() << unsatisfied_interests_.size() + << " interests still unsatisfied" << end_mod_ + << std::endl; + produceContentAsync(p, interest.getName(), suffix); } - ret = producer_socket_->setSocketOption( - ProducerCallbacksOptions::CONTENT_PRODUCED, - (ProducerContentCallback)bind( - &Impl::onContentProduced, this, std::placeholders::_1, - std::placeholders::_2, std::placeholders::_3)); + /** + * @brief Register cache miss events + */ + void cacheMiss([[maybe_unused]] const ProducerSocket &p, + const Interest &interest) { + unsatisfied_interests_.push_back(interest.getName().getSuffix()); + } - return ERROR_SUCCESS; + /** + * @brief When content is produced, set cache miss callback so that we can + * register any cache miss happening after the production. + */ + void onContentProduced(ProducerSocket &p, + [[maybe_unused]] const std::error_code &err, + [[maybe_unused]] uint64_t bytes_written) { + p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS, + (ProducerInterestCallback)bind( + &ProducerContext::asyncProcessInterest, this, + std::placeholders::_1, std::placeholders::_2)); + } + + /** + * @brief Internal producer error. When this callback is triggered + * something important happened. Here we stop the program. + */ + void produceError(const std::error_code &err) noexcept override { + getOutputStream() << "Error from producer transport: " << err.message() + << std::endl; + parent_.stop(); + } + + // Members initialized in constructor + std::vector<ContentObject::Ptr> content_objects_; + + // Members initialized by in-class initializer + std::vector<uint32_t> unsatisfied_interests_; + std::uint32_t last_segment_{0}; + std::unique_ptr<ProducerSocket> producer_socket_{nullptr}; + std::uint16_t content_objects_index_{0}; + std::size_t payload_size_max_{0}; + }; + + public: + explicit Impl(const hiperf::ServerConfiguration &conf) : config_(conf) { +#ifndef _WIN32 + if (config_.interactive_) { + input_.assign(::dup(STDIN_FILENO)); + } +#endif + + std::memset(rtc_payload_.data(), 'X', rtc_payload_.size()); + } + + ~Impl() = default; + + int setup() { + int ret = ensureFlows(config_.name_, config_.parallel_flows_); + if (ret != ERROR_SUCCESS) { + return ret; + } + + producer_contexts_.reserve(config_.parallel_flows_); + for (uint32_t i = 0; i < config_.parallel_flows_; i++) { + auto &ctx = producer_contexts_.emplace_back(*this, i); + ret = ctx.setup(); + + if (ret) { + break; + } + } + + return ret; } void receiveStream() { socket_.async_receive_from( - asio::buffer(recv_buffer_.first, recv_buffer_.second), remote_, - [this](const std::error_code &ec, std::size_t length) { + asio::buffer(recv_buffer_.writableData(), recv_buffer_.capacity()), + remote_, [this](const std::error_code &ec, std::size_t length) { if (ec) return; - sendRTCContentFromStream(recv_buffer_.first, length); + sendRTCContentFromStream(recv_buffer_.writableData(), length); receiveStream(); }); } - void sendRTCContentFromStream(uint8_t *buff, std::size_t len) { - auto payload = - content_objects_[content_objects_index_++ & mask_]->getPayload(); + void sendRTCContentFromStream(const uint8_t *buff, std::size_t len) { // this is used to compute the data packet delay // Used only for performance evaluation // It requires clock synchronization between producer and consumer - uint64_t now = utils::SystemTime::nowMs().count(); + auto now = utils::SystemTime::nowMs().count(); - uint8_t *start = (uint8_t *)payload->writableData(); + auto start = rtc_payload_.data(); std::memcpy(start, &now, sizeof(uint64_t)); std::memcpy(start + sizeof(uint64_t), buff, len); - producer_socket_->produceDatagram(flow_name_, start, - len + sizeof(uint64_t)); + + for (const auto &producer_context : producer_contexts_) { + producer_context.produceDatagram(start, len + sizeof(uint64_t)); + } } void sendRTCContentObjectCallback(const std::error_code &ec) { if (ec) return; rtc_timer_.expires_from_now( - configuration_.production_rate_.getMicrosecondsForPacket( - configuration_.payload_size_)); + config_.production_rate_.getMicrosecondsForPacket( + config_.payload_size_)); rtc_timer_.async_wait(std::bind(&Impl::sendRTCContentObjectCallback, this, std::placeholders::_1)); - auto payload = - content_objects_[content_objects_index_++ & mask_]->getPayload(); + + auto start = rtc_payload_.data(); // this is used to compute the data packet delay // Used only for performance evaluation // It requires clock synchronization between producer and consumer - uint64_t now = utils::SystemTime::nowMs().count(); - - std::memcpy(payload->writableData(), &now, sizeof(uint64_t)); + auto now = utils::SystemTime::nowMs().count(); + std::memcpy(start, &now, sizeof(uint64_t)); - producer_socket_->produceDatagram(flow_name_, payload->data(), - payload->length() < payload_size_max_ - ? payload->length() - : payload_size_max_); + for (const auto &producer_context : producer_contexts_) { + producer_context.produceDatagram(start, config_.payload_size_); + } } void sendRTCContentObjectCallbackWithTrace(const std::error_code &ec) { if (ec) return; - auto payload = - content_objects_[content_objects_index_++ & mask_]->getPayload(); - - uint32_t packet_len = - configuration_.trace_[configuration_.trace_index_].size; + std::size_t packet_len = config_.trace_[config_.trace_index_].size; // this is used to compute the data packet delay // used only for performance evaluation // it requires clock synchronization between producer and consumer - uint64_t now = utils::SystemTime::nowMs().count(); - std::memcpy(payload->writableData(), &now, sizeof(uint64_t)); + auto now = utils::SystemTime::nowMs().count(); + auto start = rtc_payload_.data(); + std::memcpy(start, &now, sizeof(uint64_t)); - if (packet_len > payload->length()) packet_len = payload->length(); - if (packet_len > payload_size_max_) packet_len = payload_size_max_; + if (packet_len > config_.payload_size_) { + packet_len = config_.payload_size_; + } - producer_socket_->produceDatagram(flow_name_, payload->data(), packet_len); + for (const auto &producer_context : producer_contexts_) { + producer_context.produceDatagram(start, packet_len); + } - uint32_t next_index = configuration_.trace_index_ + 1; + uint32_t next_index = config_.trace_index_ + 1; uint64_t schedule_next; - if (next_index < configuration_.trace_.size()) { - schedule_next = - configuration_.trace_[next_index].timestamp - - configuration_.trace_[configuration_.trace_index_].timestamp; + if (next_index < config_.trace_.size()) { + schedule_next = config_.trace_[next_index].timestamp - + config_.trace_[config_.trace_index_].timestamp; } else { // here we need to loop, schedule in a random time schedule_next = 1000; } - configuration_.trace_index_ = - (configuration_.trace_index_ + 1) % configuration_.trace_.size(); + config_.trace_index_ = (config_.trace_index_ + 1) % config_.trace_.size(); rtc_timer_.expires_from_now(std::chrono::microseconds(schedule_next)); rtc_timer_.async_wait( std::bind(&Impl::sendRTCContentObjectCallbackWithTrace, this, std::placeholders::_1)); } + int parseTraceFile() { + std::ifstream trace(config_.trace_file_); + if (trace.fail()) { + return -1; + } + std::string line; + while (std::getline(trace, line)) { + std::istringstream iss(line); + hiperf::packet_t packet; + iss >> packet.timestamp >> packet.size; + config_.trace_.push_back(packet); + } + return 0; + } + #ifndef _WIN32 void handleInput(const std::error_code &error, std::size_t length) { if (error) { - producer_socket_->stop(); - io_service_.stop(); + stop(); } if (rtc_running_) { - std::cout << "stop real time content production" << std::endl; + Logger() << "stop real time content production" << std::endl; rtc_running_ = false; rtc_timer_.cancel(); } else { - std::cout << "start real time content production" << std::endl; + Logger() << "start real time content production" << std::endl; rtc_running_ = true; rtc_timer_.expires_from_now( - configuration_.production_rate_.getMicrosecondsForPacket( - configuration_.payload_size_)); + config_.production_rate_.getMicrosecondsForPacket( + config_.payload_size_)); rtc_timer_.async_wait(std::bind(&Impl::sendRTCContentObjectCallback, this, std::placeholders::_1)); } @@ -439,46 +573,33 @@ class HIperfServer::Impl : public ProducerSocket::Callback { } #endif - int parseTraceFile() { - std::ifstream trace(configuration_.trace_file_); - if (trace.fail()) { - return -1; - } - std::string line; - while (std::getline(trace, line)) { - std::istringstream iss(line); - hiperf::packet_t packet; - iss >> packet.timestamp >> packet.size; - configuration_.trace_.push_back(packet); + void stop() { + for (auto &producer_context : producer_contexts_) { + producer_context.stop(); } - return 0; + + io_service_.stop(); } int run() { - std::cerr << "Starting to serve consumers" << std::endl; - signals_.add(SIGINT); - signals_.async_wait([this](const std::error_code &, const int &) { - std::cout << "STOPPING!!" << std::endl; - producer_socket_->stop(); - io_service_.stop(); - }); + signals_.async_wait( + [this](const std::error_code &, const int &) { stop(); }); - if (configuration_.rtc_) { -#ifndef _WIN32 - if (configuration_.interactive_) { + if (config_.rtc_) { + if (config_.interactive_) { asio::async_read_until( input_, input_buffer_, '\n', std::bind(&Impl::handleInput, this, std::placeholders::_1, std::placeholders::_2)); - } else if (configuration_.trace_based_) { - std::cout << "trace-based mode enabled" << std::endl; - if (configuration_.trace_file_ == nullptr) { - std::cout << "cannot find the trace file" << std::endl; + } else if (config_.trace_based_) { + Logger() << "trace-based mode enabled" << std::endl; + if (config_.trace_file_ == nullptr) { + Logger() << "cannot find the trace file" << std::endl; return ERROR_SETUP; } if (parseTraceFile() < 0) { - std::cout << "cannot parse the trace file" << std::endl; + Logger() << "cannot parse the trace file" << std::endl; return ERROR_SETUP; } rtc_running_ = true; @@ -486,31 +607,26 @@ class HIperfServer::Impl : public ProducerSocket::Callback { rtc_timer_.async_wait( std::bind(&Impl::sendRTCContentObjectCallbackWithTrace, this, std::placeholders::_1)); - } else if (configuration_.input_stream_mode_) { + } else if (config_.input_stream_mode_) { rtc_running_ = true; // create socket remote_ = asio::ip::udp::endpoint( - asio::ip::address::from_string("127.0.0.1"), configuration_.port_); + asio::ip::address::from_string("127.0.0.1"), config_.port_); socket_.open(asio::ip::udp::v4()); socket_.bind(remote_); - recv_buffer_.first = (uint8_t *)malloc(HIPERF_MTU); - recv_buffer_.second = HIPERF_MTU; receiveStream(); } else { rtc_running_ = true; rtc_timer_.expires_from_now( - configuration_.production_rate_.getMicrosecondsForPacket( - configuration_.payload_size_)); + config_.production_rate_.getMicrosecondsForPacket( + config_.payload_size_)); rtc_timer_.async_wait(std::bind(&Impl::sendRTCContentObjectCallback, this, std::placeholders::_1)); } -#else - rtc_timer_.expires_from_now( - configuration_.production_rate_.getMicrosecondsForPacket( - configuration_.payload_size_)); - rtc_timer_.async_wait(std::bind(&Impl::sendRTCContentObjectCallback, this, - std::placeholders::_1)); -#endif + } + + for (auto &producer_context : producer_contexts_) { + producer_context.run(); } io_service_.run(); @@ -518,49 +634,31 @@ class HIperfServer::Impl : public ProducerSocket::Callback { return ERROR_SUCCESS; } + ServerConfiguration &getConfig() { return config_; } + private: - hiperf::ServerConfiguration configuration_; + // Variables initialized by the constructor. + ServerConfiguration config_; + + // Variable initialized in the in-class initializer list. asio::io_service io_service_; - asio::signal_set signals_; - asio::steady_timer rtc_timer_; - std::vector<uint32_t> unsatisfied_interests_; - std::vector<std::shared_ptr<ContentObject>> content_objects_; - std::uint16_t content_objects_index_; - std::uint16_t mask_; - std::uint32_t last_segment_; - std::unique_ptr<ProducerSocket> producer_socket_; + asio::signal_set signals_{io_service_}; + asio::steady_timer rtc_timer_{io_service_}; + asio::posix::stream_descriptor input_{io_service_}; + asio::ip::udp::socket socket_{io_service_}; + std::vector<ProducerContext> producer_contexts_; ::utils::EventThread produce_thread_; - std::size_t payload_size_max_; -#ifndef _WIN32 - asio::posix::stream_descriptor input_; asio::streambuf input_buffer_; - bool rtc_running_; - Name flow_name_; - asio::ip::udp::socket socket_; + bool rtc_running_{false}; asio::ip::udp::endpoint remote_; - std::pair<uint8_t *, std::size_t> recv_buffer_; -#endif + utils::MemBuf recv_buffer_{utils::MemBuf::CREATE, HIPERF_MTU}; + std::array<uint8_t, HIPERF_MTU> rtc_payload_; }; -HIperfServer::HIperfServer(const ServerConfiguration &conf) { - impl_ = new Impl(conf); -} - -HIperfServer::HIperfServer(HIperfServer &&other) { - impl_ = other.impl_; - other.impl_ = nullptr; -} - -HIperfServer &HIperfServer::operator=(HIperfServer &&other) { - if (this != &other) { - impl_ = other.impl_; - other.impl_ = nullptr; - } - - return *this; -} +HIperfServer::HIperfServer(const ServerConfiguration &conf) + : impl_(std::make_unique<Impl>(conf)) {} -HIperfServer::~HIperfServer() { delete impl_; } +HIperfServer::~HIperfServer() = default; int HIperfServer::setup() { return impl_->setup(); } diff --git a/apps/hiperf/src/server.h b/apps/hiperf/src/server.h index 73ac72123..d7420da48 100644 --- a/apps/hiperf/src/server.h +++ b/apps/hiperf/src/server.h @@ -21,9 +21,7 @@ namespace hiperf { class HIperfServer { public: - HIperfServer(const ServerConfiguration &conf); - HIperfServer(HIperfServer &&other); - HIperfServer &operator=(HIperfServer &&other); + explicit HIperfServer(const ServerConfiguration &conf); ~HIperfServer(); int setup(); @@ -31,7 +29,7 @@ class HIperfServer { private: class Impl; - Impl *impl_; + std::unique_ptr<Impl> impl_; }; } // namespace hiperf
\ No newline at end of file diff --git a/apps/http-proxy/includes/hicn/http-proxy/forwarder_interface.h b/apps/http-proxy/includes/hicn/http-proxy/forwarder_interface.h index 1741aedc6..0741099df 100644 --- a/apps/http-proxy/includes/hicn/http-proxy/forwarder_interface.h +++ b/apps/http-proxy/includes/hicn/http-proxy/forwarder_interface.h @@ -23,8 +23,16 @@ extern "C" { #ifndef ASIO_STANDALONE #define ASIO_STANDALONE 1 #endif + +#ifdef __APPLE__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif #include <asio.hpp> #include <asio/steady_timer.hpp> +#ifdef __APPLE__ +#pragma clang diagnostic pop +#endif #include <functional> #include <thread> #include <unordered_map> diff --git a/apps/http-proxy/includes/hicn/http-proxy/http_session.h b/apps/http-proxy/includes/hicn/http-proxy/http_session.h index ee9380a8c..43d10e156 100644 --- a/apps/http-proxy/includes/hicn/http-proxy/http_session.h +++ b/apps/http-proxy/includes/hicn/http-proxy/http_session.h @@ -17,7 +17,14 @@ #include <hicn/transport/core/packet.h> +#ifdef __APPLE__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif #include <asio.hpp> +#ifdef __APPLE__ +#pragma clang diagnostic pop +#endif #include <deque> #include <functional> diff --git a/apps/http-proxy/src/icn_receiver.cc b/apps/http-proxy/src/icn_receiver.cc index 954861e3a..f15851915 100644 --- a/apps/http-proxy/src/icn_receiver.cc +++ b/apps/http-proxy/src/icn_receiver.cc @@ -37,8 +37,8 @@ AsyncConsumerProducer::AsyncConsumerProducer( producer_socket_(), ip_address_(origin_address), port_(origin_port), - cache_size_(std::stoul(cache_size)), - mtu_(std::stoul(mtu)), + cache_size_((uint32_t)std::stoul(cache_size)), + mtu_((uint32_t)std::stoul(mtu)), request_counter_(0), connector_(io_service_, ip_address_, port_, std::bind(&AsyncConsumerProducer::publishContent, this, @@ -59,7 +59,7 @@ AsyncConsumerProducer::AsyncConsumerProducer( } ret = producer_socket_.setSocketOption( - interface::GeneralTransportOptions::MAKE_MANIFEST, manifest); + interface::GeneralTransportOptions::MANIFEST_MAX_CAPACITY, manifest); if (ret != SOCKET_OPTION_SET) { TRANSPORT_LOG_WARNING << "Warning: impossible to enable signatures."; diff --git a/apps/ping/src/ping_client.cc b/apps/ping/src/ping_client.cc index 0217f2f8c..2371e4453 100644 --- a/apps/ping/src/ping_client.cc +++ b/apps/ping/src/ping_client.cc @@ -13,6 +13,7 @@ * limitations under the License. */ +#include <hicn/transport/auth/signer.h> #include <hicn/transport/auth/verifier.h> #include <hicn/transport/core/global_object_pool.h> #include <hicn/transport/core/interest.h> @@ -39,12 +40,14 @@ typedef auth::AsymmetricVerifier Verifier; class Configuration { public: + uint64_t num_int_manifest_suffixes_; uint64_t interestLifetime_; uint64_t pingInterval_; uint64_t maxPing_; uint64_t first_suffix_; std::string name_; std::string certificate_; + std::string passphrase_; uint16_t srcPort_; uint16_t dstPort_; bool verbose_; @@ -59,9 +62,10 @@ class Configuration { uint8_t ttl_; Configuration() { - interestLifetime_ = 500; // ms - pingInterval_ = 1000000; // us - maxPing_ = 10; // number of interests + num_int_manifest_suffixes_ = 0; // Number of suffixes in interest manifest + interestLifetime_ = 500; // ms + pingInterval_ = 1000000; // us + maxPing_ = 10; // number of interests first_suffix_ = 0; name_ = "b001::1"; // string srcPort_ = 9695; @@ -96,6 +100,13 @@ class Client : interface::Portal::TransportCallback { if (!c->certificate_.empty()) { verifier_.useCertificate(c->certificate_); } + + // If interst manifest, sign it + if (c->num_int_manifest_suffixes_ != 0) { + assert(!c->passphrase_.empty()); + signer_ = std::make_unique<auth::SymmetricSigner>( + auth::CryptoSuite::HMAC_SHA256, c->passphrase_); + } } virtual ~Client() {} @@ -142,6 +153,7 @@ class Client : interface::Portal::TransportCallback { if (config_->verbose_) { std::cout << "<<< recevied object. " << std::endl; std::cout << "<<< interest name: " << interest.getName() + << " (n_suffixes=" << interest.numberOfSuffixes() << ")" << " src port: " << interest.getSrcPort() << " dst port: " << interest.getDstPort() << " flags: " << interest.printFlags() << std::endl; @@ -221,15 +233,18 @@ class Client : interface::Portal::TransportCallback { const Name interest_name(config_->name_, (uint32_t)sequence_number_); hicn_format_t format; if (interest_name.getAddressFamily() == AF_INET) { - format = HF_INET_TCP; + format = signer_ ? HF_INET_TCP_AH : HF_INET_TCP; } else { - format = HF_INET6_TCP; + format = signer_ ? HF_INET6_TCP_AH : HF_INET6_TCP; } - auto interest = std::make_shared<Interest>(interest_name, format); + size_t additional_header_size = 0; + if (signer_) additional_header_size = signer_->getSignatureFieldSize(); + auto interest = std::make_shared<Interest>(interest_name, format, + additional_header_size); interest->setLifetime(uint32_t(config_->interestLifetime_)); - interest->resetFlags(); + if (!signer_) interest->resetFlags(); if (config_->open_ || config_->always_syn_) { if (state_ == SYN_STATE) { @@ -244,13 +259,21 @@ class Client : interface::Portal::TransportCallback { interest->setSrcPort(config_->srcPort_); interest->setDstPort(config_->dstPort_); interest->setTTL(config_->ttl_); + uint64_t seq_offset = 1; + while (seq_offset <= config_->num_int_manifest_suffixes_ && + sequence_number_ + seq_offset < config_->maxPing_) { + interest->appendSuffix(sequence_number_ + seq_offset); + seq_offset++; + } if (config_->verbose_) { std::cout << ">>> send interest " << interest->getName() << " src port: " << interest->getSrcPort() << " dst port: " << interest->getDstPort() << " flags: " << interest->printFlags() - << " TTL: " << (int)interest->getTTL() << std::endl; + << " TTL: " << (int)interest->getTTL() + << " suffixes in manifest: " + << config_->num_int_manifest_suffixes_ << std::endl; } else if (!config_->quiet_) { std::cout << ">>> send interest " << interest->getName() << std::endl; } @@ -264,11 +287,16 @@ class Client : interface::Portal::TransportCallback { if (!config_->quiet_) std::cout << std::endl; send_timestamps_[sequence_number_] = utils::SteadyTime::now(); + for (uint64_t i = 1; i < seq_offset; i++) + send_timestamps_[sequence_number_ + i] = utils::SteadyTime::now(); - portal_.sendInterest(std::move(interest)); + interest->encodeSuffixes(); + if (signer_) signer_->signPacket(interest.get()); - sequence_number_++; - sent_++; + portal_.sendInterest(interest, interest->getLifetime()); + + sequence_number_ += seq_offset; + sent_ += seq_offset; if (sent_ < config_->maxPing_) { this->timer_->expires_from_now( @@ -314,6 +342,7 @@ class Client : interface::Portal::TransportCallback { std::unique_ptr<asio::steady_timer> timer_; Configuration *config_; Verifier verifier_; + std::unique_ptr<auth::Signer> signer_; }; void help() { @@ -327,6 +356,12 @@ void help() { std::cout << "-s <val> sorce port (default 9695)" << std::endl; std::cout << "-d <val> destination port (default 8080)" << std::endl; std::cout << "-t <val> set packet ttl (default 64)" << std::endl; + std::cout << "-a <val> <pass> set the passphrase and the number of " + "suffixes in interest manifest (default 0);" + << std::endl; + std::cout << " e.g. '-m 6 -a -2' sends two interest (0 and " + "3) with 2 suffixes each (1,2 and 4,5 respectively)" + << std::endl; std::cout << "-O open tcp connection (three way handshake) " "(default false)" << std::endl; @@ -362,6 +397,8 @@ int main(int argc, char *argv[]) { WSAStartup(MAKEWORD(2, 2), &wsaData); #endif + transport::interface::global_config::GlobalConfigInterface global_conf; + Configuration *c = new Configuration(); int opt; std::string producer_certificate = ""; @@ -370,8 +407,13 @@ int main(int argc, char *argv[]) { transport::interface::global_config::IoModuleConfiguration io_config; io_config.name = "hicnlightng_module"; - while ((opt = getopt(argc, argv, "j::t:i:m:s:d:n:l:f:c:SAOqVDHz:F:")) != -1) { + while ((opt = getopt(argc, argv, "a:j::t:i:m:s:d:n:l:f:c:SAOqVDHz:F:")) != + -1) { switch (opt) { + case 'a': + c->num_int_manifest_suffixes_ = std::stoi(optarg); + c->passphrase_ = argv[optind]; + break; case 't': c->ttl_ = (uint8_t)std::stoi(optarg); break; @@ -447,7 +489,7 @@ int main(int argc, char *argv[]) { /** * Parse config file */ - transport::interface::global_config::parseConfigurationFile(conf_file); + global_conf.parseConfigurationFile(conf_file); auto ping = std::make_unique<Client>(c); @@ -456,7 +498,8 @@ int main(int argc, char *argv[]) { auto t1 = std::chrono::steady_clock::now(); std::cout << "Elapsed time: " - << utils::SteadyTime::getDurationUs(t0, t1).count() << std::endl; + << utils::SteadyTime::getDurationMs(t0, t1).count() << "ms" + << std::endl; #ifdef _WIN32 WSACleanup(); diff --git a/apps/ping/src/ping_server.cc b/apps/ping/src/ping_server.cc index 3ffbc7325..dd7d23b5e 100644 --- a/apps/ping/src/ping_server.cc +++ b/apps/ping/src/ping_server.cc @@ -22,6 +22,7 @@ #endif #include <hicn/transport/auth/signer.h> +#include <hicn/transport/auth/verifier.h> #include <hicn/transport/core/content_object.h> #include <hicn/transport/core/interest.h> #include <hicn/transport/interfaces/global_conf_interface.h> @@ -42,7 +43,8 @@ class CallbackContainer { public: CallbackContainer(const Name &prefix, uint32_t object_size, bool verbose, bool dump, bool quite, bool flags, bool reset, uint8_t ttl, - auth::Signer *signer, bool sign, uint32_t lifetime) + auth::Signer *signer, bool sign, std::string passphrase, + uint32_t lifetime) : buffer_(object_size, 'X'), content_objects_((std::uint32_t)(1 << log2_content_object_buffer_size)), mask_((std::uint16_t)(1 << log2_content_object_buffer_size) - 1), @@ -55,8 +57,11 @@ class CallbackContainer { ttl_(ttl), signer_(signer), sign_(sign) { - core::Packet::Format format; + // Verifier for interest manifests + if (!passphrase.empty()) + verifier_ = std::make_unique<auth::SymmetricVerifier>(passphrase); + core::Packet::Format format; if (prefix.getAddressFamily() == AF_INET) { format = core::Packet::Format::HF_INET_TCP; if (sign_) { @@ -76,14 +81,28 @@ class CallbackContainer { } } - void processInterest(ProducerSocket &p, const Interest &interest, + void processInterest(ProducerSocket &p, Interest &interest, uint32_t lifetime) { + if (verifier_ && interest.hasManifest()) { + auto t0 = utils::SteadyTime::now(); + if (verifier_->verifyPacket(&interest)) { + auto t1 = utils::SteadyTime::now(); + auto dt = utils::SteadyTime::getDurationUs(t0, t1); + std::cout << "Verification time: " << dt.count() << std::endl; + std::cout << "<<< Signature Ok." << std::endl; + } else { + std::cout << "<<< Signature verification failed!" << std::endl; + } + } + if (verbose_) { std::cout << "<<< received interest " << interest.getName() << " src port: " << interest.getSrcPort() << " dst port: " << interest.getDstPort() << " flags: " << interest.printFlags() - << "TTL: " << (int)interest.getTTL() << std::endl; + << "TTL: " << (int)interest.getTTL() + << " suffixes in manifest: " << interest.numberOfSuffixes() + << std::endl; } else if (!quite_) { std::cout << "<<< received interest " << interest.getName() << std::endl; } @@ -97,54 +116,74 @@ class CallbackContainer { if (interest.testRst()) { std::cout << "!!!got a reset, I don't reply" << std::endl; } else { - auto &content_object = content_objects_[content_objects_index_++ & mask_]; - - content_object->setName(interest.getName()); - content_object->setLifetime(lifetime); - content_object->setLocator(interest.getLocator()); - content_object->setSrcPort(interest.getDstPort()); - content_object->setDstPort(interest.getSrcPort()); - content_object->setTTL(ttl_); - - if (!sign_) { - content_object->resetFlags(); - } - - if (flags_) { - if (interest.testSyn()) { - content_object->setSyn(); - content_object->setAck(); - } else if (interest.testAck()) { - content_object->setAck(); - } // here I may need to handle the FIN flag; - } else if (reset_) { - content_object->setRst(); - } - - if (verbose_) { - std::cout << ">>> send object " << content_object->getName() - << " src port: " << content_object->getSrcPort() - << " dst port: " << content_object->getDstPort() - << " flags: " << content_object->printFlags() - << " TTL: " << (int)content_object->getTTL() << std::endl; - } else if (!quite_) { - std::cout << ">>> send object " << content_object->getName() - << std::endl; - } - - if (dump_) { - std::cout << "----- object dump -----" << std::endl; - content_object->dump(); - std::cout << "-----------------------" << std::endl; - } + uint32_t *suffix = interest.firstSuffix(); + uint32_t n_suffixes_in_manifest = interest.numberOfSuffixes(); + uint32_t *request_bitmap = interest.getRequestBitmap(); + if (!interest.isValid()) throw std::runtime_error("Bad interest format"); + + Name name = interest.getName(); + uint32_t pos = 0; // Position of current suffix in manifest + do { + // If suffix can be processed, i.e. no manifest with bitmap excluding it + if (!interest.hasManifest() || is_bit_set(request_bitmap, pos)) { + auto &content_object = + content_objects_[content_objects_index_++ & mask_]; + + content_object->setName(interest.getName()); + content_object->setLifetime(lifetime); + content_object->setLocator(interest.getLocator()); + content_object->setSrcPort(interest.getDstPort()); + content_object->setDstPort(interest.getSrcPort()); + content_object->setTTL(ttl_); + + if (!sign_) { + content_object->resetFlags(); + } + + if (flags_) { + if (interest.testSyn()) { + content_object->setSyn(); + content_object->setAck(); + } else if (interest.testAck()) { + content_object->setAck(); + } // here I may need to handle the FIN flag; + } else if (reset_) { + content_object->setRst(); + } + + if (verbose_) { + std::cout << ">>> send object " << content_object->getName() + << " src port: " << content_object->getSrcPort() + << " dst port: " << content_object->getDstPort() + << " flags: " << content_object->printFlags() + << " TTL: " << (int)content_object->getTTL() << std::endl; + } else if (!quite_) { + std::cout << ">>> send object " << content_object->getName() + << std::endl; + } + + if (dump_) { + std::cout << "----- object dump -----" << std::endl; + content_object->dump(); + std::cout << "-----------------------" << std::endl; + } + + if (sign_ && signer_) { + signer_->signPacket(content_object.get()); + } + + p.produce(*content_object); + } + + if (interest.hasManifest()) { + uint32_t seq = *suffix; + suffix++; + + interest.setName(name.setSuffix(seq)); + } + } while (pos++ < n_suffixes_in_manifest); if (!quite_) std::cout << std::endl; - - if (sign_ && signer_) { - signer_->signPacket(content_object.get()); - } - - p.produce(*content_object); } } @@ -161,6 +200,7 @@ class CallbackContainer { uint8_t ttl_; auth::Signer *signer_; bool sign_; + std::unique_ptr<auth::Verifier> verifier_; }; void help() { @@ -199,6 +239,7 @@ void help() { } int main(int argc, char **argv) { + transport::interface::global_config::GlobalConfigInterface global_conf; #ifdef _WIN32 WSADATA wsaData = {0}; WSAStartup(MAKEWORD(2, 2), &wsaData); @@ -216,6 +257,7 @@ int main(int argc, char **argv) { uint8_t ttl = 64; std::string keystore_path = "./rsa_crypto_material.p12"; std::string keystore_password = "cisco"; + std::string passphrase = ""; bool sign = false; uint32_t data_lifetime = default_values::content_object_expiry_time; @@ -225,11 +267,14 @@ int main(int argc, char **argv) { int opt; #ifndef _WIN32 - while ((opt = getopt(argc, argv, "s:n:t:l:qfrVDdHk:p:z:F:")) != -1) { + while ((opt = getopt(argc, argv, "a:s:n:t:l:qfrVDdHk:p:z:F:")) != -1) { #else while ((opt = getopt(argc, argv, "s:n:t:l:qfrVDHk:p:z:F:")) != -1) { #endif switch (opt) { + case 'a': + passphrase = optarg; + break; case 's': object_size = std::stoi(optarg); break; @@ -298,7 +343,7 @@ int main(int argc, char **argv) { /** * Parse config file */ - transport::interface::global_config::parseConfigurationFile(conf_file); + global_conf.parseConfigurationFile(conf_file); core::Prefix producer_namespace(name_prefix); @@ -309,24 +354,25 @@ int main(int argc, char **argv) { if (object_size > 1350) object_size = 1350; CallbackContainer *stubs; - std::unique_ptr<auth::AsymmetricSigner> signer; + std::unique_ptr<auth::Signer> signer; if (sign) { signer = std::make_unique<auth::AsymmetricSigner>(keystore_path, keystore_password); - stubs = - new CallbackContainer(n, object_size, verbose, dump, quite, flags, - reset, ttl, signer.get(), sign, data_lifetime); + stubs = new CallbackContainer(n, object_size, verbose, dump, quite, flags, + reset, ttl, signer.get(), sign, passphrase, + data_lifetime); } else { auth::Signer *signer = nullptr; stubs = new CallbackContainer(n, object_size, verbose, dump, quite, flags, - reset, ttl, signer, sign, data_lifetime); + reset, ttl, signer, sign, passphrase, + data_lifetime); } ProducerSocket p; p.registerPrefix(producer_namespace); - p.setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, false); + p.setSocketOption(GeneralTransportOptions::MANIFEST_MAX_CAPACITY, 0U); p.setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 0U); p.setSocketOption( ProducerCallbacksOptions::CACHE_MISS, diff --git a/ctrl/CMakeLists.txt b/ctrl/CMakeLists.txt index d6fe72d3e..221121818 100644 --- a/ctrl/CMakeLists.txt +++ b/ctrl/CMakeLists.txt @@ -21,6 +21,6 @@ project(ctrl) # Subdirectories ############################################################## add_subdirectory(libhicnctrl) -if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "Android") +if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "Android" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "iOS") add_subdirectory(facemgr) endif ()
\ No newline at end of file diff --git a/ctrl/facemgr/includes/hicn/facemgr/cfg.h b/ctrl/facemgr/includes/hicn/facemgr/cfg.h index fee38daf1..bbbe81825 100644 --- a/ctrl/facemgr/includes/hicn/facemgr/cfg.h +++ b/ctrl/facemgr/includes/hicn/facemgr/cfg.h @@ -163,8 +163,6 @@ int facemgr_cfg_rule_get_overlay_remote_port(const facemgr_cfg_rule_t* rule, int family, uint16_t* port); int facemgr_cfg_add_static_facelet(facemgr_cfg_t* cfg, facelet_t* facelet); -int facemgr_cfg_remove_static_facelet(facemgr_cfg_t* cfg, facelet_t* facelet, - facelet_t** removed_facelet); int facemgr_cfg_get_static_facelet_array(const facemgr_cfg_t* cfg, facelet_t*** array); diff --git a/ctrl/facemgr/src/cfg.c b/ctrl/facemgr/src/cfg.c index 9c374388a..76e1f5e72 100644 --- a/ctrl/facemgr/src/cfg.c +++ b/ctrl/facemgr/src/cfg.c @@ -1120,11 +1120,6 @@ int facemgr_cfg_add_static_facelet(facemgr_cfg_t *cfg, facelet_t *facelet) { return facelet_array_add(cfg->static_facelets, facelet); } -int facemgr_cfg_remove_static_facelet(facemgr_cfg_t *cfg, facelet_t *facelet, - facelet_t **removed_facelet) { - return facelet_array_remove(cfg->static_facelets, facelet, removed_facelet); -} - int facemgr_cfg_get_static_facelet_array(const facemgr_cfg_t *cfg, facelet_t ***array) { if (facelet_array_get_elements(cfg->static_facelets, array) < 0) { diff --git a/ctrl/facemgr/src/interfaces/network_framework/network_framework.c b/ctrl/facemgr/src/interfaces/network_framework/network_framework.c index 3adba0969..e1f5575d3 100644 --- a/ctrl/facemgr/src/interfaces/network_framework/network_framework.c +++ b/ctrl/facemgr/src/interfaces/network_framework/network_framework.c @@ -171,6 +171,7 @@ void dump_endpoint(nw_endpoint_t endpoint, int indent) { free(s); } } +} void dump_path(nw_path_t path, int indent) { /* nw_path_enumerate_interfaces : not interesting */ diff --git a/ctrl/facemgr/src/loop_dispatcher.c b/ctrl/facemgr/src/loop_dispatcher.c index ed4540f5c..88e197492 100644 --- a/ctrl/facemgr/src/loop_dispatcher.c +++ b/ctrl/facemgr/src/loop_dispatcher.c @@ -28,7 +28,7 @@ #include <stdlib.h> -#include <Dispatch/Dispatch.h> +#include <dispatch/dispatch.h> #include <hicn/facemgr/loop.h> #include <hicn/util/log.h> diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h index 8a59cf4d8..c259fc10c 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h @@ -72,6 +72,7 @@ #include <hicn/util/ip_address.h> #include <hicn/face.h> #include <hicn/strategy.h> +#include <hicn/base.h> /* * This has to be common between hicn-light and hicn-plugin. We now we keep the * minimum of the two @@ -120,6 +121,7 @@ _(SERVE) \ _(STORE) \ _(CLEAR) \ + _(GET) \ _(N) typedef enum { @@ -150,6 +152,7 @@ hc_action_t action_from_str(const char *action_str); _(LOCAL_PREFIX) \ _(PROBE) \ _(SUBSCRIPTION) \ + _(STATS) \ _(N) typedef enum { @@ -930,6 +933,13 @@ typedef struct { flag_interface_type_t interface_type; } hc_event_interface_update_t; +/*----------------------------------------------------------------------------* + * Statistics + *----------------------------------------------------------------------------*/ +int hc_stats_get(hc_sock_t *s, hc_data_t **pdata); // General stats +int hc_stats_list(hc_sock_t *s, hc_data_t **pdata); // Per-face stats +int hc_stats_snprintf(char *s, size_t size, const hicn_light_stats_t *stats); + /* Result */ hc_msg_t *hc_result_get_msg(hc_sock_t *s, hc_result_t *result); diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/hicn-light-ng.h b/ctrl/libhicnctrl/includes/hicn/ctrl/hicn-light-ng.h index 7d105a84b..783eab086 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/hicn-light-ng.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/hicn-light-ng.h @@ -90,7 +90,9 @@ typedef enum { _(policy_remove, POLICY_REMOVE) \ _(policy_list, POLICY_LIST) \ _(subscription_add, SUBSCRIPTION_ADD) \ - _(subscription_remove, SUBSCRIPTION_REMOVE) + _(subscription_remove, SUBSCRIPTION_REMOVE) \ + _(stats_get, STATS_GET) \ + _(stats_list, STATS_LIST) typedef enum { COMMAND_TYPE_UNDEFINED, @@ -282,6 +284,33 @@ typedef struct { cmd_cache_list_reply_t payload; } msg_cache_list_reply_t; +/* Statistics */ + +// General stats +typedef struct { + void *_; +} cmd_stats_get_t; + +typedef struct { + cmd_header_t header; + hicn_light_stats_t payload; +} msg_stats_get_reply_t; + +// Per-face stats +typedef struct { + void *_; +} cmd_stats_list_t; + +typedef struct { + uint32_t id; + connection_stats_t stats; +} cmd_stats_list_item_t; + +typedef struct { + cmd_header_t header; + cmd_stats_list_item_t payload; +} msg_stats_list_reply_t; + /* WLDR */ typedef struct { @@ -388,10 +417,10 @@ typedef struct { cmd_header_t header; \ cmd_##l##_t payload; \ } msg_##l##_t; -foreach_command_type +foreach_command_type; #undef _ - typedef struct { +typedef struct { cmd_header_t header; cmd_listener_list_item_t payload; } msg_listener_list_reply_t; diff --git a/ctrl/libhicnctrl/src/CMakeLists.txt b/ctrl/libhicnctrl/src/CMakeLists.txt index c8a93c56c..1bec03d50 100644 --- a/ctrl/libhicnctrl/src/CMakeLists.txt +++ b/ctrl/libhicnctrl/src/CMakeLists.txt @@ -60,7 +60,8 @@ endif () ############################################################## # Do not use modules if Android ############################################################## -if (${CMAKE_SYSTEM_NAME} MATCHES Android) + +if (${CMAKE_SYSTEM_NAME} MATCHES Android OR ${CMAKE_SYSTEM_NAME} MATCHES iOS) list(APPEND SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/modules/hicn_light_common.c ${CMAKE_CURRENT_SOURCE_DIR}/modules/hicn_light_ng_api.c diff --git a/ctrl/libhicnctrl/src/api.c b/ctrl/libhicnctrl/src/api.c index 472e07bc4..d68dc830e 100644 --- a/ctrl/libhicnctrl/src/api.c +++ b/ctrl/libhicnctrl/src/api.c @@ -440,7 +440,7 @@ GENERATE_FIND(connection); /* CONNECTION VALIDATE */ int hc_connection_validate(const hc_connection_t *connection) { - if (!IS_VALID_NAME(connection->name)) { + if (connection->name[0] != '\0' && !IS_VALID_NAME(connection->name)) { ERROR("[hc_connection_validate] Invalid name specified"); return -1; } @@ -1060,6 +1060,28 @@ int hc_cache_snprintf(char *s, size_t size, const hc_cache_info_t *cache_info) { (unsigned long)cache_info->num_stale_entries); } +int hc_stats_snprintf(char *s, size_t size, const hicn_light_stats_t *stats) { + return snprintf( + s, size, + "pkts processed: %u\n\tinterests: %u\n\t" + "data: %u\npkts from cache count: %u\npkts no pit count: " + "%u\nexpired:\n\t interests: " + "%u\n\t data: %u\ninterests aggregated: " + "%u\nlru evictions: " + "%u\ndropped: " + "%u\ninterests retx: " + "%u\npit entries: %u\ncs entries: %u", + stats->forwarder.countReceived, stats->forwarder.countInterestsReceived, + stats->forwarder.countObjectsReceived, + stats->forwarder.countInterestsSatisfiedFromStore, + stats->forwarder.countDroppedNoReversePath, + stats->forwarder.countInterestsExpired, stats->forwarder.countDataExpired, + stats->pkt_cache.n_lru_evictions, stats->forwarder.countDropped, + stats->forwarder.countInterestsAggregated, + stats->forwarder.countInterestsRetransmitted, + stats->pkt_cache.n_pit_entries, stats->pkt_cache.n_cs_entries); +} + /*----------------------------------------------------------------------------* * Strategy *----------------------------------------------------------------------------*/ @@ -1161,6 +1183,17 @@ hc_result_t *hc_subscription_delete_conf(hc_sock_t *s, } /*----------------------------------------------------------------------------* + * STATISTICS + *----------------------------------------------------------------------------*/ +int hc_stats_get(hc_sock_t *s, hc_data_t **pdata) { + return s->hc_stats_get(s, pdata); +} + +int hc_stats_list(hc_sock_t *s, hc_data_t **pdata) { + return s->hc_stats_list(s, pdata); +} + +/*----------------------------------------------------------------------------* * Result *----------------------------------------------------------------------------*/ diff --git a/ctrl/libhicnctrl/src/api_private.h b/ctrl/libhicnctrl/src/api_private.h index 65b175810..c708e1eb5 100644 --- a/ctrl/libhicnctrl/src/api_private.h +++ b/ctrl/libhicnctrl/src/api_private.h @@ -242,6 +242,9 @@ struct hc_sock_s { int (*hc_subscription_create)(hc_sock_t *s, hc_subscription_t *subscription); int (*hc_subscription_delete)(hc_sock_t *s, hc_subscription_t *subscription); + int (*hc_stats_get)(hc_sock_t *s, hc_data_t **data); + int (*hc_stats_list)(hc_sock_t *s, hc_data_t **data); + hc_result_t *(*hc_listener_create_conf)(hc_sock_t *s, hc_listener_t *listener); hc_result_t *(*hc_listener_list_conf)(hc_sock_t *s, hc_data_t **pdata); diff --git a/ctrl/libhicnctrl/src/modules/hicn_light_common.c b/ctrl/libhicnctrl/src/modules/hicn_light_common.c index bc04404bf..d1fb33993 100644 --- a/ctrl/libhicnctrl/src/modules/hicn_light_common.c +++ b/ctrl/libhicnctrl/src/modules/hicn_light_common.c @@ -15,9 +15,6 @@ #include "hicn_light_common.h" -TYPEDEF_MAP(hc_sock_map, int, hc_sock_request_t *, int_cmp, int_snprintf, - generic_snprintf); - hc_sock_request_t *hc_sock_request_create(int seq, hc_data_t *data, HC_PARSE parse) { assert(data); diff --git a/ctrl/libhicnctrl/src/modules/hicn_light_common.h b/ctrl/libhicnctrl/src/modules/hicn_light_common.h index 4749474c8..d24b5bb2d 100644 --- a/ctrl/libhicnctrl/src/modules/hicn_light_common.h +++ b/ctrl/libhicnctrl/src/modules/hicn_light_common.h @@ -17,6 +17,7 @@ #include <assert.h> // assert +#include <hicn/util/khash.h> #include "api_private.h" #define PORT 9695 @@ -39,7 +40,7 @@ typedef struct { * outgoing queries so that replied can be demultiplexed and treated * appropriately. */ -TYPEDEF_MAP_H(hc_sock_map, int, hc_sock_request_t *); +KHASH_MAP_INIT_INT(sock_map, hc_sock_request_t *); struct hc_sock_light_s { /* This must be the first element of the struct */ @@ -69,7 +70,7 @@ struct hc_sock_light_s { hc_sock_request_t *cur_request; bool async; - hc_sock_map_t *map; + kh_sock_map_t *map; }; typedef struct hc_sock_light_s hc_sock_light_t; diff --git a/ctrl/libhicnctrl/src/modules/hicn_light_ng_api.c b/ctrl/libhicnctrl/src/modules/hicn_light_ng_api.c index a58ee909e..488b2edbf 100644 --- a/ctrl/libhicnctrl/src/modules/hicn_light_ng_api.c +++ b/ctrl/libhicnctrl/src/modules/hicn_light_ng_api.c @@ -88,7 +88,9 @@ _(mapme_activator) \ _(mapme_timing) \ _(subscription_add) \ - _(subscription_remove) + _(subscription_remove) \ + _(stats_get) \ + _(stats_list) const char *command_type_str[] = { #define _(l, u) [COMMAND_TYPE_##u] = STRINGIZE(u), @@ -169,21 +171,13 @@ static int _hcng_sock_light_reset(hc_sock_t *socket) { void _hcng_sock_light_free(hc_sock_t *socket) { hc_sock_light_t *s = TO_HC_SOCK_LIGHT(socket); - hc_sock_request_t **request_array = NULL; - int n = hc_sock_map_get_value_array(s->map, &request_array); - if (n < 0) { - ERROR("Could not retrieve pending request array for freeing up resources"); - } else { - for (unsigned i = 0; i < n; i++) { - hc_sock_request_t *request = request_array[i]; - if (hc_sock_map_remove(s->map, request->seq, NULL) < 0) - ERROR("[hc_sock_light_process] Error removing request from map"); - hc_sock_light_request_free(request); - } - free(request_array); - } - hc_sock_map_free(s->map); + unsigned k_seq; + hc_sock_request_t *v_request; + kh_foreach(s->map, k_seq, v_request, + { hc_sock_light_request_free(v_request); }); + + kh_destroy_sock_map(s->map); if (s->url) free(s->url); close(s->fd); free(s); @@ -292,9 +286,13 @@ static void _hcng_sock_light_mark_complete(hc_sock_light_t *s, hc_data_t **pdata) { hc_data_t *data = s->cur_request->data; - if (hc_sock_map_remove(s->map, s->cur_request->seq, NULL) < 0) { + khiter_t k = kh_get_sock_map(s->map, s->cur_request->seq); + if (k == kh_end(s->map)) { ERROR("[hc_sock_light_mark_complete] Error removing request from map"); + } else { + kh_del_sock_map(s->map, k); } + hc_data_set_complete(data); if (pdata) *pdata = data; @@ -323,7 +321,7 @@ static int _hcng_sock_light_process_notification(hc_sock_light_t *s, /* Copy the packet payload as the single entry in hc_data_t */ hc_data_push_many(*pdata, s->buf + s->roff, 1); - return notification_size; + return (int)notification_size; } /* @@ -333,12 +331,16 @@ static hc_sock_request_t *_hcng_sock_light_get_request(hc_sock_light_t *s, int seq) { hc_sock_request_t *request; /* Retrieve request from sock map */ - if (hc_sock_map_get(s->map, seq, &request) < 0) { - ERROR("[hc_sock_light_process] Error searching for matching request"); + khiter_t k = kh_get_sock_map(s->map, seq); + if (k == kh_end(s->map)) { + ERROR( + "[_hcng_sock_light_get_request] Error searching for matching request"); return NULL; } + request = kh_val(s->map, k); + if (!request) { - ERROR("[hc_sock_light_process] No request matching sequence number"); + ERROR("[_hcng_sock_light_get_request] No request matching sequence number"); return NULL; } return request; @@ -593,7 +595,7 @@ int _hcng_sock_prepare_send(hc_sock_t *socket, hc_result_t *result, hc_data_t *data = hc_data_create(result->params.size_in, result->params.size_out, NULL); if (!data) { - ERROR("[_hcng_execute_command] Could not create data storage"); + ERROR("[_hcng_sock_prepare_send] Could not create data storage"); goto ERR_DATA; } hc_data_set_callback(data, complete_cb, complete_cb_data); @@ -606,15 +608,17 @@ int _hcng_sock_prepare_send(hc_sock_t *socket, hc_result_t *result, hc_sock_request_t *request = NULL; request = hc_sock_request_create(seq, data, result->params.parse); if (!request) { - ERROR("[_hcng_execute_command] Could not create request state"); + ERROR("[_hcng_sock_prepare_send] Could not create request state"); goto ERR_REQUEST; } - // Add state to map - if (hc_sock_map_add(s->map, seq, request) < 0) { - ERROR("[_hcng_execute_command] Error adding request state to map"); + int rc; + khiter_t k = kh_put_sock_map(s->map, seq, &rc); + if (rc != KH_ADDED && rc != KH_RESET) { + ERROR("[_hcng_sock_prepare_send] Error adding request state to map"); goto ERR_MAP; } + kh_value(s->map, k) = request; return sizeof(result->msg); @@ -631,7 +635,7 @@ int _hcng_sock_set_recv_timeout_ms(hc_sock_t *socket, long timeout_ms) { struct timeval tv; tv.tv_sec = 0; - tv.tv_usec = timeout_ms * 1000; // Convert ms into us + tv.tv_usec = (int)(timeout_ms * 1000); // Convert ms into us if (setsockopt(s->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { perror("setsockopt"); return -1; @@ -659,10 +663,13 @@ static int _hcng_execute_command(hc_sock_t *socket, hc_msg_t *msg, assert(params->size_out == 0); assert(params->parse == NULL); break; + case ACTION_GET: case ACTION_LIST: assert(params->size_in != 0); assert(params->size_out != 0); - assert(params->parse != NULL); + // TODO(eloparco): Parsing should not be necessary after + // (pending) refatoring + // assert(params->parse != NULL); break; case ACTION_SET: case ACTION_SERVE: @@ -701,10 +708,13 @@ static int _hcng_execute_command(hc_sock_t *socket, hc_msg_t *msg, } /* Add state to map */ - if (hc_sock_map_add(s->map, seq, request) < 0) { + int rc; + khiter_t k = kh_put_sock_map(s->map, seq, &rc); + if (rc != KH_ADDED && rc != KH_RESET) { ERROR("[_hcng_execute_command] Error adding request state to map"); goto ERR_MAP; } + kh_value(s->map, k) = request; if (_hcng_sock_light_send(socket, msg, msg_len, seq) < 0) { ERROR("[_hcng_execute_command] Error sending message"); @@ -1823,7 +1833,7 @@ static int _hcng_face_create(hc_sock_t *socket, hc_face_t *face) { case FACE_TYPE_HICN: case FACE_TYPE_TCP: case FACE_TYPE_UDP: - if (hc_face_to_connection(face, &connection, true) < 0) { + if (hc_face_to_connection(face, &connection, false) < 0) { ERROR("[hc_face_create] Could not convert face to connection."); return -1; } @@ -2955,6 +2965,120 @@ static int _hcng_subscription_delete(hc_sock_t *socket, return ret; } +/*----------------------------------------------------------------------------* + * Statistics + *----------------------------------------------------------------------------*/ + +/* STATS GET */ + +static hc_result_t *_hcng_stats_get_serialize(hc_sock_t *socket, + hc_data_t **pdata, bool async) { + hc_result_t *res = malloc(sizeof(*res)); + DEBUG("[hc_stats_get] async=%s", BOOLSTR(async)); + + msg_stats_get_t msg = {.header = { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_STATS_GET, + .length = 0, + .seq_num = 0, + }}; + + hc_command_params_t params = { + .cmd = ACTION_GET, + .cmd_id = COMMAND_TYPE_STATS_GET, + .size_in = sizeof(hicn_light_stats_t), + .size_out = sizeof(hicn_light_stats_t), + }; + + *res = (hc_result_t){ + .msg = + (hc_msg_t){ + .hdr = msg.header, + .payload.stats_get = msg.payload, + }, + .params = params, + .async = async, + .success = true, + }; + return res; +} + +static int _hcng_stats_get_internal(hc_sock_t *socket, hc_data_t **pdata, + bool async) { + hc_result_t *result = _hcng_stats_get_serialize(socket, pdata, async); + + int ret = INPUT_ERROR; + if (result->success) { + ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg, + sizeof(result->msg), &result->params, pdata, + result->async); + } + + hc_result_free(result); + DEBUG("[_hcng_stats_get] done or error"); + return ret; +} + +static int _hcng_stats_get(hc_sock_t *s, hc_data_t **pdata) { + DEBUG("[_hcng_stats_get]"); + return _hcng_stats_get_internal(s, pdata, false); +} + +/* STATS LIST */ + +static hc_result_t *_hcng_stats_list_serialize(hc_sock_t *socket, + hc_data_t **pdata, bool async) { + hc_result_t *res = malloc(sizeof(*res)); + DEBUG("[hc_stats_list] async=%s", BOOLSTR(async)); + + msg_stats_list_t msg = {.header = { + .message_type = REQUEST_LIGHT, + .command_id = COMMAND_TYPE_STATS_LIST, + .length = 0, + .seq_num = 0, + }}; + + hc_command_params_t params = { + .cmd = ACTION_LIST, + .cmd_id = COMMAND_TYPE_STATS_LIST, + .size_in = sizeof(cmd_stats_list_item_t), + .size_out = sizeof(cmd_stats_list_item_t), + }; + + *res = (hc_result_t){ + .msg = + (hc_msg_t){ + .hdr = msg.header, + .payload.stats_list = msg.payload, + }, + .params = params, + .async = async, + .success = true, + }; + return res; +} + +static int _hcng_stats_list_internal(hc_sock_t *socket, hc_data_t **pdata, + bool async) { + hc_result_t *result = _hcng_stats_list_serialize(socket, pdata, async); + + int ret = INPUT_ERROR; + if (result->success) { + ret = _hcng_execute_command(socket, (hc_msg_t *)&result->msg, + sizeof(result->msg), &result->params, pdata, + result->async); + } + + hc_result_free(result); + DEBUG("[_hcng_stats_list] done or error"); + return ret; +} + +static int _hcng_stats_list(hc_sock_t *s, hc_data_t **pdata) { + DEBUG("[_hcng_stats_list]"); + return _hcng_stats_list_internal(s, pdata, false); +} + /* RESULT */ hc_msg_t *_hcng_result_get_msg(hc_result_t *result) { return &result->msg; } int _hcng_result_get_cmd_id(hc_result_t *result) { @@ -3018,6 +3142,9 @@ static hc_sock_t hc_sock_light_ng_interface = (hc_sock_t){ .hc_subscription_create = _hcng_subscription_create, .hc_subscription_delete = _hcng_subscription_delete, + .hc_stats_get = _hcng_stats_get, + .hc_stats_list = _hcng_stats_list, + .hc_route_create = _hcng_route_create, .hc_route_create_async = _hcng_route_create_async, .hc_route_delete = _hcng_route_delete, @@ -3094,7 +3221,7 @@ hc_sock_t *_hc_sock_create_url(const char *url) { s->seq = 0; s->cur_request = NULL; - s->map = hc_sock_map_create(); + s->map = kh_init_sock_map(); if (!s->map) goto ERR_MAP; return (hc_sock_t *)(s); diff --git a/docs/source/telemetry.md b/docs/source/telemetry.md index f81d21ee1..b4d538d76 100644 --- a/docs/source/telemetry.md +++ b/docs/source/telemetry.md @@ -43,7 +43,7 @@ VPP 22.02, Debian packages can be found on - libvppinfra-dev - vpp-dev - hicn-plugin-dev -- `collectd` and `collectd-dev`: `sudo apt install collectd collectd-dev` +- `collectd` and `collectd-dev`: `sudo apt install collectd collectd-dev libyajl-dev` ## Getting started diff --git a/docs/source/transport.md b/docs/source/transport.md index eb5b9d71a..c5250023a 100644 --- a/docs/source/transport.md +++ b/docs/source/transport.md @@ -202,7 +202,7 @@ hICN has built-in authentication and integrity features by either: To enable per-packet signature with asymmetric signing: * On the producer, disable manifests (which are ON by default): ```cpp - producer_socket->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, 0); + producer_socket->setSocketOption(GeneralTransportOptions::MANIFEST_MAX_CAPACITY, 0u); ``` * On the producer, instantiate an `AsymmetricSigner` object by passing either an asymmetric pair of keys as @@ -244,25 +244,49 @@ available suites. ### Enabling manifests * Follow steps 2-5 in [Per-packet signatures](#per-packet-signatures). -* By default, a manifest holds the digest of 30 packets. To change this value: +* By default, a manifest has a maximum capacity `C_max` of 30 packets. To change + this value: ```cpp - producer_socket->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, 20); + producer_socket->setSocketOption(GeneralTransportOptions::MANIFEST_MAX_CAPACITY, 20u); ``` In the case of RTC, manifests are sent after the data they contain and on the consumer side, data packets are immediately forwarded to the application, *even if they weren't authenticated yet via a manifest*. This is to minimize latency. The digest of incoming data packets are kept in a buffer while waiting for -manifests to arrive. When that buffer goes above a threshold `T`, an alert is -raised by the verifier object. That threshold is computed as follows: +manifests to arrive. When the buffer size goes above a threshold `T`, an alert +is raised by the verifier object. That alert threshold is computed as follows: ``` -T(t) = producer_rate(t) * max_unverified_time +T = manifest_factor_alert * C_max ``` -`max_unverified_time` is a consumer socket option, in milliseconds. It is set -to `2000` by default. To change it: +The value of `C_max` is passed by the producer to the consumer at the start of +the connection. `manifest_factor_alert` is a consumer socket option. It +basically acts on the resilience of manifests against networks losses and +reflects the application's tolerance to unverified packets: a higher value gives +the transport the time needed to recover from several manifest losses but +potentially allows a larger number of unverified packet to go the application +before alerts are triggered. It is set to `20` by default and should always be +`>= 1`. To change it: ```cpp -consumer_socket_->setSocketOption(GeneralTransportOptions::MAX_UNVERIFIED_TIME, 4000); +consumer_socket_->setSocketOption(GeneralTransportOptions::MANIFEST_FACTOR_ALERT, 10u); +``` + +The buffer does not keep unverified packets indefinitely. After a certain amount +of packets have been received and processed (and were verified or not), older +packets still unverified are flushed out. This is to prevent the buffer to grow +uncontrollably and to raise alerts for packets that are not relevant to the +application anymore. That threshold of relevance is computed as follows: +``` +T = manifest_factor_relevant * C_max +``` + +`manifest_factor_relevant` is a consumer socket option. It is set to `100` by +default. Its value must be set so that `manifest_factor_relevant > +manifest_factor_alert >= 1`. If `manifest_factor_relevant <= +manifest_factor_alert`, no alert will ever be raised. To change it: +```cpp +consumer_socket_->setSocketOption(GeneralTransportOptions::MANIFEST_FACTOR_RELEVANT, 200u); ``` ### Handling authentication failures diff --git a/hicn-light/CMakeLists.txt b/hicn-light/CMakeLists.txt index 337e22b7f..241cae7f2 100644 --- a/hicn-light/CMakeLists.txt +++ b/hicn-light/CMakeLists.txt @@ -93,6 +93,7 @@ else() ${LIBHICNCTRL_STATIC} ) else () + message("qui2!!!") set(HICN_LIBRARIES ${LIBHICN_SHARED} ${LIBHICNCTRL_SHARED} diff --git a/hicn-light/src/hicn/base/CMakeLists.txt b/hicn-light/src/hicn/base/CMakeLists.txt index 1180ed05b..2541ed830 100644 --- a/hicn-light/src/hicn/base/CMakeLists.txt +++ b/hicn-light/src/hicn/base/CMakeLists.txt @@ -12,21 +12,11 @@ # limitations under the License. list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/bitmap.h - ${CMAKE_CURRENT_SOURCE_DIR}/common.h - ${CMAKE_CURRENT_SOURCE_DIR}/hash.h - ${CMAKE_CURRENT_SOURCE_DIR}/khash.h ${CMAKE_CURRENT_SOURCE_DIR}/loop.h - ${CMAKE_CURRENT_SOURCE_DIR}/pool.h - ${CMAKE_CURRENT_SOURCE_DIR}/ring.h - ${CMAKE_CURRENT_SOURCE_DIR}/vector.h ) list(APPEND SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/loop.c - ${CMAKE_CURRENT_SOURCE_DIR}/pool.c - ${CMAKE_CURRENT_SOURCE_DIR}/ring.c - ${CMAKE_CURRENT_SOURCE_DIR}/vector.c ) set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) diff --git a/hicn-light/src/hicn/base/bitmap.h b/hicn-light/src/hicn/base/bitmap.h deleted file mode 100644 index 060fd5be0..000000000 --- a/hicn-light/src/hicn/base/bitmap.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file bitmap.h - * \brief Bitmap - * - * A bitmap is implemented as a wrapper over a vector made of bit elements - */ - -#ifndef UTIL_BITMAP_H -#define UTIL_BITMAP_H - -#include <assert.h> -#include <string.h> -#include <sys/param.h> // MIN, MAX - -#include <hicn/util/log.h> - -#include "common.h" -#include "vector.h" - -typedef uint_fast32_t bitmap_t; - -#define BITMAP_WIDTH(bitmap) (sizeof((bitmap)[0]) * 8) - -/** - * @brief Allocate and initialize a bitmap - * - * @param[in,out] bitmap Bitmap to allocate and initialize - * @param[in] max_size Bitmap max_size - */ -#define bitmap_init(bitmap, init_size, max_size) \ - vector_init( \ - bitmap, next_pow2((init_size) / BITMAP_WIDTH(bitmap)), \ - max_size == 0 ? 0 : next_pow2((max_size) / BITMAP_WIDTH(bitmap))) - -/* - * @brief Ensures a bitmap is sufficiently large to hold an element at the - * given position. - * - * @param[in] bitmap The bitmap for which to validate the position. - * @param[in] pos The position to validate. - * - * NOTE: - * - This function should always be called before writing to a bitmap element - * to eventually make room for it (the bitmap will eventually be resized). - */ -static inline int bitmap_ensure_pos(bitmap_t** bitmap, off_t pos) { - size_t offset = pos / BITMAP_WIDTH(*bitmap); - return vector_ensure_pos(*bitmap, offset); -} - -/** - * @brief Returns the allocated size of a bitmap. - * - * @see listener_table_get_by_id - */ -#define bitmap_get_alloc_size(bitmap) vector_get_alloc_size(bitmap) - -/** - * @brief Retrieve the state of the i-th bit in the bitmap. - * - * @param[in] bitmap The bitmap to access. - * @param[in] i The bit position. - */ -static inline int bitmap_get(const bitmap_t* bitmap, off_t i) { - size_t offset = i / BITMAP_WIDTH(bitmap); - assert(offset < bitmap_get_alloc_size(bitmap)); - size_t pos = i % BITMAP_WIDTH(bitmap); - size_t shift = BITMAP_WIDTH(bitmap) - pos - 1; - return (bitmap[offset] >> shift) & 1; -} - -/* - * @brief Returns whether the i-th bit is set (equal to 1) in a bitmap. - * - * @param[in] bitmap The bitmap to access. - * @param[in] i The bit position. - * - * @return bool - */ -#define bitmap_is_set(bitmap, i) (bitmap_get((bitmap), (i)) == 1) -#define bitmap_is_unset(bitmap, i) (bitmap_get((bitmap), (i)) == 0) - -/* - * @brief Returns whether the i-th bit is unset (equal to 0) in a bitmap. - * - * @param[in] bitmap The bitmap to access. - * @param[in] i The bit position. - * - * @return bool - */ -#define bitmap_set(bitmap, i) _bitmap_set((bitmap_t**)&bitmap, i) - -/* - * @brief Returns whether the i-th bit is unset (equal to 0) in a bitmap - * (helper). - * - * @param[in] bitmap The bitmap to access. - * @param[in] i The bit position. - * - * @return bool - */ -static inline int _bitmap_set(bitmap_t** bitmap_ptr, off_t i) { - if (bitmap_ensure_pos(bitmap_ptr, i) < 0) return -1; - - bitmap_t* bitmap = *bitmap_ptr; - size_t offset = i / BITMAP_WIDTH(bitmap); - size_t pos = i % BITMAP_WIDTH(bitmap); - size_t shift = BITMAP_WIDTH(bitmap) - pos - 1; - - bitmap[offset] |= (bitmap_t)1 << shift; - return 0; -} - -static inline int bitmap_unset(bitmap_t* bitmap, off_t i) { - if (bitmap_ensure_pos(&bitmap, i) < 0) return -1; - size_t offset = i / BITMAP_WIDTH(bitmap); - size_t pos = i % BITMAP_WIDTH(bitmap); - size_t shift = BITMAP_WIDTH(bitmap) - pos - 1; - bitmap[offset] &= ~(1ul << shift); - return 0; -} - -static inline int bitmap_set_range(bitmap_t* bitmap, off_t from, off_t to) { - assert(from <= to); - ssize_t offset_from = from / BITMAP_WIDTH(bitmap); - ssize_t offset_to = to / BITMAP_WIDTH(bitmap); - size_t pos_from = from % BITMAP_WIDTH(bitmap); - size_t pos_to = to % BITMAP_WIDTH(bitmap); - - /* - * First block initialization is needed if <from> is not aligned with the - * bitmap element size or if to is within the same one. - */ - if ((pos_from != 0) || - ((offset_to == offset_from) && (pos_to != BITMAP_WIDTH(bitmap) - 1))) { - size_t from_end = MIN(to, (offset_from + 1) * BITMAP_WIDTH(bitmap)); - for (size_t k = from; k < from_end; k++) { - if (bitmap_set(bitmap, k) < 0) goto END; - } - } - - /* - * Second block is needed if <to> is not aligned with the bitmap element - * size - */ - if ((pos_to != BITMAP_WIDTH(bitmap) - 1) && (offset_to != offset_from)) { - size_t to_start = MAX(from, offset_to * BITMAP_WIDTH(bitmap)); - for (size_t k = to_start; k < (size_t)to; k++) { - if (bitmap_set(bitmap, k) < 0) goto END; - } - } - - if (pos_from != 0) offset_from += 1; - if (pos_to != BITMAP_WIDTH(bitmap) - 1) offset_to -= 1; - - /* - * We need to cover both elements at position offset_from and offset_to - * provided that offset_from is not bigger - */ - if (offset_to >= offset_from) { - memset(&bitmap[offset_from], 0xFF, - (offset_to - offset_from + 1) * sizeof(bitmap[0])); - } - - return 0; - -END: - ERROR("Error setting bitmap range\n"); - return -1; -} - -#define bitmap_set_to(bitmap, to) bitmap_set_range((bitmap), 0, (to)) - -#define bitmap_free(bitmap) vector_free(bitmap) - -#endif /* UTIL_BITMAP_H */ diff --git a/hicn-light/src/hicn/base/common.h b/hicn-light/src/hicn/base/common.h deleted file mode 100644 index 9f7e3beec..000000000 --- a/hicn-light/src/hicn/base/common.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file array.h - * \brief Fixed-size pool allocator - */ - -#ifndef UTIL_COMMON_H -#define UTIL_COMMON_H - -#define round_pow2(x, pow2) ((x + pow2 - 1) & ~(pow2 - 1)) - -#define _SIZEOF_ALIGNED(x, size) round_pow2(sizeof(x), size) -#define SIZEOF_ALIGNED(x) _SIZEOF_ALIGNED(x, sizeof(void*)) - -/* Definitions for builtins unavailable on MSVC */ -#if defined(_MSC_VER) && !defined(__clang__) -#include <intrin.h> - -uint32_t __inline __builtin_ctz(uint32_t value) { - uint32_t trailing_zero = 0; - if (_BitScanForward(&trailing_zero, value)) - return trailing_zero; - else - return 32; -} - -uint32_t __inline __builtin_clz(uint32_t value) { - uint32_t leading_zero = 0; - if (_BitScanReverse(&leading_zero, value)) - return 31 - leading_zero; - else - return 32; -} - -uint32_t __inline __builtin_clzl2(uint64_t value) { - uint32_t leading_zero = 0; - if (_BitScanReverse64(&leading_zero, value)) - return 63 - leading_zero; - else - return 64; -} - -#define __builtin_clzl __builtin_clzll -#endif - -#define next_pow2(x) (x <= 1 ? 1 : 1ul << (64 - __builtin_clzl(x - 1))) - -#endif /* UTIL_COMMON_H */ diff --git a/hicn-light/src/hicn/base/hash.h b/hicn-light/src/hicn/base/hash.h deleted file mode 100644 index 3c54feb29..000000000 --- a/hicn-light/src/hicn/base/hash.h +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * \file hash.h - * \brief Simple non-cryptographic hash implementation. - * - * Two helpers are provided : - * hash(buf, len) : hash a buffer <buf> of length <len> - * hash_struct(buf) : hash a buffer corresponding to an allocated struct - * - * This file consists in excerpts from Jenkins hash (public domain). - * http://www.burtleburtle.net/bob/c/lookup3.c - */ -#ifndef UTIL_HASH_H -#define UTIL_HASH_H - -#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ - __BYTE_ORDER == __LITTLE_ENDIAN) || \ - (defined(i386) || defined(__i386__) || defined(__i486__) || \ - defined(__i586__) || defined(__i686__) || defined(vax) || \ - defined(MIPSEL)) -#define HASH_LITTLE_ENDIAN 1 -#define HASH_BIG_ENDIAN 0 -#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ - __BYTE_ORDER == __BIG_ENDIAN) || \ - (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) -#define HASH_LITTLE_ENDIAN 0 -#define HASH_BIG_ENDIAN 1 -#else -#define HASH_LITTLE_ENDIAN 0 -#define HASH_BIG_ENDIAN 0 -#endif - -#define hashsize(n) ((uint32_t)1 << (n)) -#define hashmask(n) (hashsize(n) - 1) -#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) - -#define mix(a, b, c) \ - { \ - a -= c; \ - a ^= rot(c, 4); \ - c += b; \ - b -= a; \ - b ^= rot(a, 6); \ - a += c; \ - c -= b; \ - c ^= rot(b, 8); \ - b += a; \ - a -= c; \ - a ^= rot(c, 16); \ - c += b; \ - b -= a; \ - b ^= rot(a, 19); \ - a += c; \ - c -= b; \ - c ^= rot(b, 4); \ - b += a; \ - } - -#define final(a, b, c) \ - { \ - c ^= b; \ - c -= rot(b, 14); \ - a ^= c; \ - a -= rot(c, 11); \ - b ^= a; \ - b -= rot(a, 25); \ - c ^= b; \ - c -= rot(b, 16); \ - a ^= c; \ - a -= rot(c, 4); \ - b ^= a; \ - b -= rot(a, 14); \ - c ^= b; \ - c -= rot(b, 24); \ - } - -static inline uint32_t hashlittle(const void *key, size_t length, - uint32_t initval) { - uint32_t a, b, c; /* internal state */ - union { - const void *ptr; - size_t i; - } u; /* needed for Mac Powerbook G4 */ - - /* Set up the internal state */ - a = b = c = 0xdeadbeef + ((uint32_t)length) + initval; - - u.ptr = key; - if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { - const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ - - /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ - while (length > 12) { - a += k[0]; - b += k[1]; - c += k[2]; - mix(a, b, c); - length -= 12; - k += 3; - } - - /*----------------------------- handle the last (probably partial) block */ - /* - * "k[2]&0xffffff" actually reads beyond the end of the string, but - * then masks off the part it's not allowed to read. Because the - * string is aligned, the masked-off tail is in the same word as the - * rest of the string. Every machine with memory protection I've seen - * does it on word boundaries, so is OK with this. But VALGRIND will - * still catch it and complain. The masking trick does make the hash - * noticably faster for short strings (like English words). - */ -#ifndef VALGRIND - - switch (length) { - case 12: - c += k[2]; - b += k[1]; - a += k[0]; - break; - case 11: - c += k[2] & 0xffffff; - b += k[1]; - a += k[0]; - break; - case 10: - c += k[2] & 0xffff; - b += k[1]; - a += k[0]; - break; - case 9: - c += k[2] & 0xff; - b += k[1]; - a += k[0]; - break; - case 8: - b += k[1]; - a += k[0]; - break; - case 7: - b += k[1] & 0xffffff; - a += k[0]; - break; - case 6: - b += k[1] & 0xffff; - a += k[0]; - break; - case 5: - b += k[1] & 0xff; - a += k[0]; - break; - case 4: - a += k[0]; - break; - case 3: - a += k[0] & 0xffffff; - break; - case 2: - a += k[0] & 0xffff; - break; - case 1: - a += k[0] & 0xff; - break; - case 0: - return c; /* zero length strings require no mixing */ - } - -#else /* make valgrind happy */ - - k8 = (const uint8_t *)k; - switch (length) { - case 12: - c += k[2]; - b += k[1]; - a += k[0]; - break; - case 11: - c += ((uint32_t)k8[10]) << 16; /* fall through */ - case 10: - c += ((uint32_t)k8[9]) << 8; /* fall through */ - case 9: - c += k8[8]; /* fall through */ - case 8: - b += k[1]; - a += k[0]; - break; - case 7: - b += ((uint32_t)k8[6]) << 16; /* fall through */ - case 6: - b += ((uint32_t)k8[5]) << 8; /* fall through */ - case 5: - b += k8[4]; /* fall through */ - case 4: - a += k[0]; - break; - case 3: - a += ((uint32_t)k8[2]) << 16; /* fall through */ - case 2: - a += ((uint32_t)k8[1]) << 8; /* fall through */ - case 1: - a += k8[0]; - break; - case 0: - return c; - } - -#endif /* !valgrind */ - - } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { - const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ - const uint8_t *k8; - - /*--------------- all but last block: aligned reads and different mixing */ - while (length > 12) { - a += k[0] + (((uint32_t)k[1]) << 16); - b += k[2] + (((uint32_t)k[3]) << 16); - c += k[4] + (((uint32_t)k[5]) << 16); - mix(a, b, c); - length -= 12; - k += 6; - } - - /*----------------------------- handle the last (probably partial) block */ - k8 = (const uint8_t *)k; - switch (length) { - case 12: - c += k[4] + (((uint32_t)k[5]) << 16); - b += k[2] + (((uint32_t)k[3]) << 16); - a += k[0] + (((uint32_t)k[1]) << 16); - break; - case 11: - c += ((uint32_t)k8[10]) << 16; /* fall through */ - case 10: - c += k[4]; - b += k[2] + (((uint32_t)k[3]) << 16); - a += k[0] + (((uint32_t)k[1]) << 16); - break; - case 9: - c += k8[8]; /* fall through */ - case 8: - b += k[2] + (((uint32_t)k[3]) << 16); - a += k[0] + (((uint32_t)k[1]) << 16); - break; - case 7: - b += ((uint32_t)k8[6]) << 16; /* fall through */ - case 6: - b += k[2]; - a += k[0] + (((uint32_t)k[1]) << 16); - break; - case 5: - b += k8[4]; /* fall through */ - case 4: - a += k[0] + (((uint32_t)k[1]) << 16); - break; - case 3: - a += ((uint32_t)k8[2]) << 16; /* fall through */ - case 2: - a += k[0]; - break; - case 1: - a += k8[0]; - break; - case 0: - return c; /* zero length requires no mixing */ - } - - } else { /* need to read the key one byte at a time */ - const uint8_t *k = (const uint8_t *)key; - - /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ - while (length > 12) { - a += k[0]; - a += ((uint32_t)k[1]) << 8; - a += ((uint32_t)k[2]) << 16; - a += ((uint32_t)k[3]) << 24; - b += k[4]; - b += ((uint32_t)k[5]) << 8; - b += ((uint32_t)k[6]) << 16; - b += ((uint32_t)k[7]) << 24; - c += k[8]; - c += ((uint32_t)k[9]) << 8; - c += ((uint32_t)k[10]) << 16; - c += ((uint32_t)k[11]) << 24; - mix(a, b, c); - length -= 12; - k += 12; - } - - /*-------------------------------- last block: affect all 32 bits of (c) */ - switch (length) /* all the case statements fall through */ - { - case 12: - c += ((uint32_t)k[11]) << 24; - case 11: - c += ((uint32_t)k[10]) << 16; - case 10: - c += ((uint32_t)k[9]) << 8; - case 9: - c += k[8]; - case 8: - b += ((uint32_t)k[7]) << 24; - case 7: - b += ((uint32_t)k[6]) << 16; - case 6: - b += ((uint32_t)k[5]) << 8; - case 5: - b += k[4]; - case 4: - a += ((uint32_t)k[3]) << 24; - case 3: - a += ((uint32_t)k[2]) << 16; - case 2: - a += ((uint32_t)k[1]) << 8; - case 1: - a += k[0]; - break; - case 0: - return c; - } - } - - final(a, b, c); - return c; -} - -/* Helpers */ - -#define HASH_INITVAL 1 -//#define hash(buf, len) (hash_t)hashlittle(buf, len, HASH_INITVAL) -#define hash(buf, len) hashlittle(buf, len, HASH_INITVAL) -#define hash_struct(buf) hash(buf, sizeof(*buf)) - -#define str_hash(str) (hash(str, strlen(str))) -#define str_hash_eq(a, b) (str_hash(b) - str_hash(a)) - -#endif /* UTIL_JENKINS_HASH_H */ diff --git a/hicn-light/src/hicn/base/khash.h b/hicn-light/src/hicn/base/khash.h deleted file mode 100644 index 4c62b0260..000000000 --- a/hicn-light/src/hicn/base/khash.h +++ /dev/null @@ -1,748 +0,0 @@ -/* The MIT License - - Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk> - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -/* - An example: - -#include "khash.h" -KHASH_MAP_INIT_INT(32, char) -int main() { - int ret, is_missing; - khiter_t k; - khash_t(32) *h = kh_init(32); - k = kh_put(32, h, 5, &ret); - kh_value(h, k) = 10; - k = kh_get(32, h, 10); - is_missing = (k == kh_end(h)); - k = kh_get(32, h, 5); - kh_del(32, h, k); - for (k = kh_begin(h); k != kh_end(h); ++k) - if (kh_exist(h, k)) kh_value(h, k) = 1; - kh_destroy(32, h); - return 0; -} -*/ - -/* - 2013-05-02 (0.2.8): - - * Use quadratic probing. When the capacity is power of 2, stepping - function i*(i+1)/2 guarantees to traverse each bucket. It is better than - double hashing on cache performance and is more robust than linear probing. - - In theory, double hashing should be more robust than quadratic - probing. However, my implementation is probably not for large hash tables, - because the second hash function is closely tied to the first hash function, - which reduce the effectiveness of double hashing. - - Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php - - 2011-12-29 (0.2.7): - - * Minor code clean up; no actual effect. - - 2011-09-16 (0.2.6): - - * The capacity is a power of 2. This seems to dramatically improve the - speed for simple keys. Thank Zilong Tan for the suggestion. Reference: - - - http://code.google.com/p/ulib/ - - http://nothings.org/computer/judy/ - - * Allow to optionally use linear probing which usually has better - performance for random input. Double hashing is still the default as - it is more robust to certain non-random input. - - * Added Wang's integer hash function (not used by default). This hash - function is more robust to certain non-random input. - - 2011-02-14 (0.2.5): - - * Allow to declare global functions. - - 2009-09-26 (0.2.4): - - * Improve portability - - 2008-09-19 (0.2.3): - - * Corrected the example - * Improved interfaces - - 2008-09-11 (0.2.2): - - * Improved speed a little in kh_put() - - 2008-09-10 (0.2.1): - - * Added kh_clear() - * Fixed a compiling error - - 2008-09-02 (0.2.0): - - * Changed to token concatenation which increases flexibility. - - 2008-08-31 (0.1.2): - - * Fixed a bug in kh_get(), which has not been tested previously. - - 2008-08-31 (0.1.1): - - * Added destructor -*/ - -#ifndef __AC_KHASH_H -#define __AC_KHASH_H - -/*! - @header - - Generic hash table library. - */ - -#define AC_VERSION_KHASH_H "0.2.8" - -#include <stdlib.h> -#include <string.h> -#include <limits.h> - -/* compiler specific configuration */ - -#if UINT_MAX == 0xffffffffu -typedef unsigned int khint32_t; -#elif ULONG_MAX == 0xffffffffu -typedef unsigned long khint32_t; -#endif - -#if ULONG_MAX == ULLONG_MAX -typedef unsigned long khint64_t; -#else -typedef unsigned long long khint64_t; -#endif - -#ifndef kh_inline -#ifdef _MSC_VER -#define kh_inline __inline -#else -#define kh_inline inline -#endif -#endif /* kh_inline */ - -#ifndef klib_unused -#if (defined __clang__ && __clang_major__ >= 3) || \ - (defined __GNUC__ && __GNUC__ >= 3) -#define klib_unused __attribute__((__unused__)) -#else -#define klib_unused -#endif -#endif /* klib_unused */ - -typedef khint32_t khint_t; -typedef khint_t khiter_t; - -#define __ac_isempty(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 2) -#define __ac_isdel(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 1) -#define __ac_iseither(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 3) -#define __ac_set_isdel_false(flag, i) \ - (flag[i >> 4] &= ~(1ul << ((i & 0xfU) << 1))) -#define __ac_set_isempty_false(flag, i) \ - (flag[i >> 4] &= ~(2ul << ((i & 0xfU) << 1))) -#define __ac_set_isboth_false(flag, i) \ - (flag[i >> 4] &= ~(3ul << ((i & 0xfU) << 1))) -#define __ac_set_isdel_true(flag, i) (flag[i >> 4] |= 1ul << ((i & 0xfU) << 1)) - -#define __ac_fsize(m) ((m) < 16 ? 1 : (m) >> 4) - -#ifndef kroundup32 -#define kroundup32(x) \ - (--(x), (x) |= (x) >> 1, (x) |= (x) >> 2, (x) |= (x) >> 4, (x) |= (x) >> 8, \ - (x) |= (x) >> 16, ++(x)) -#endif - -#ifndef kcalloc -#define kcalloc(N, Z) calloc(N, Z) -#endif -#ifndef kmalloc -#define kmalloc(Z) malloc(Z) -#endif -#ifndef krealloc -#define krealloc(P, Z) realloc(P, Z) -#endif -#ifndef kfree -#define kfree(P) free(P) -#endif - -static const double __ac_HASH_UPPER = 0.77; - -#define __KHASH_TYPE(name, khkey_t, khval_t) \ - typedef struct kh_##name##_s { \ - khint_t n_buckets, size, n_occupied, upper_bound; \ - khint32_t *flags; \ - khkey_t *keys; \ - khval_t *vals; \ - } kh_##name##_t; - -#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \ - extern kh_##name##_t *kh_init_##name(void); \ - extern void kh_destroy_##name(kh_##name##_t *h); \ - extern void kh_clear_##name(kh_##name##_t *h); \ - extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \ - extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \ - extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \ - extern void kh_del_##name(kh_##name##_t *h, khint_t x); - -#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, \ - __hash_equal) \ - SCOPE kh_##name##_t *kh_init_##name(void) { \ - return (kh_##name##_t *)kcalloc(1, sizeof(kh_##name##_t)); \ - } \ - SCOPE void kh_destroy_##name(kh_##name##_t *h) { \ - if (h) { \ - kfree((void *)h->keys); \ - kfree(h->flags); \ - kfree((void *)h->vals); \ - kfree(h); \ - } \ - } \ - SCOPE void kh_clear_##name(kh_##name##_t *h) { \ - if (h && h->flags) { \ - memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \ - h->size = h->n_occupied = 0; \ - } \ - } \ - SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) { \ - if (h->n_buckets) { \ - khint_t k, i, last, mask, step = 0; \ - mask = h->n_buckets - 1; \ - k = __hash_func(key); \ - i = k & mask; \ - last = i; \ - while (!__ac_isempty(h->flags, i) && \ - (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ - i = (i + (++step)) & mask; \ - if (i == last) return h->n_buckets; \ - } \ - return __ac_iseither(h->flags, i) ? h->n_buckets : i; \ - } else \ - return 0; \ - } \ - SCOPE int kh_resize_##name( \ - kh_##name##_t *h, \ - khint_t new_n_buckets) { /* This function uses 0.25*n_buckets bytes of \ - working space instead of \ - [sizeof(key_t+val_t)+.25]*n_buckets. */ \ - khint32_t *new_flags = 0; \ - khint_t j = 1; \ - { \ - kroundup32(new_n_buckets); \ - if (new_n_buckets < 4) new_n_buckets = 4; \ - if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) \ - j = 0; /* requested size is too small */ \ - else { /* hash table size to be changed (shrink or expand); rehash */ \ - new_flags = (khint32_t *)kmalloc(__ac_fsize(new_n_buckets) * \ - sizeof(khint32_t)); \ - if (!new_flags) return -1; \ - memset(new_flags, 0xaa, \ - __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ - if (h->n_buckets < new_n_buckets) { /* expand */ \ - khkey_t *new_keys = (khkey_t *)krealloc( \ - (void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ - if (!new_keys) { \ - kfree(new_flags); \ - return -1; \ - } \ - h->keys = new_keys; \ - if (kh_is_map) { \ - khval_t *new_vals = (khval_t *)krealloc( \ - (void *)h->vals, new_n_buckets * sizeof(khval_t)); \ - if (!new_vals) { \ - kfree(new_flags); \ - return -1; \ - } \ - h->vals = new_vals; \ - } \ - } /* otherwise shrink */ \ - } \ - } \ - if (j) { /* rehashing is needed */ \ - for (j = 0; j != h->n_buckets; ++j) { \ - if (__ac_iseither(h->flags, j) == 0) { \ - khkey_t key = h->keys[j]; \ - khval_t val; \ - khint_t new_mask; \ - new_mask = new_n_buckets - 1; \ - if (kh_is_map) val = h->vals[j]; \ - __ac_set_isdel_true(h->flags, j); \ - while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \ - khint_t k, i, step = 0; \ - k = __hash_func(key); \ - i = k & new_mask; \ - while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \ - __ac_set_isempty_false(new_flags, i); \ - if (i < h->n_buckets && \ - __ac_iseither(h->flags, i) == \ - 0) { /* kick out the existing element */ \ - { \ - khkey_t tmp = h->keys[i]; \ - h->keys[i] = key; \ - key = tmp; \ - } \ - if (kh_is_map) { \ - khval_t tmp = h->vals[i]; \ - h->vals[i] = val; \ - val = tmp; \ - } \ - __ac_set_isdel_true( \ - h->flags, i); /* mark it as deleted in the old hash table */ \ - } else { /* write the element and jump out of the loop */ \ - h->keys[i] = key; \ - if (kh_is_map) h->vals[i] = val; \ - break; \ - } \ - } \ - } \ - } \ - if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \ - h->keys = (khkey_t *)krealloc((void *)h->keys, \ - new_n_buckets * sizeof(khkey_t)); \ - if (kh_is_map) \ - h->vals = (khval_t *)krealloc((void *)h->vals, \ - new_n_buckets * sizeof(khval_t)); \ - } \ - kfree(h->flags); /* free the working space */ \ - h->flags = new_flags; \ - h->n_buckets = new_n_buckets; \ - h->n_occupied = h->size; \ - h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \ - } \ - return 0; \ - } \ - SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) { \ - khint_t x; \ - if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \ - if (h->n_buckets > (h->size << 1)) { \ - if (kh_resize_##name(h, h->n_buckets - 1) < \ - 0) { /* clear "deleted" elements */ \ - *ret = -1; \ - return h->n_buckets; \ - } \ - } else if (kh_resize_##name(h, h->n_buckets + 1) < \ - 0) { /* expand the hash table */ \ - *ret = -1; \ - return h->n_buckets; \ - } \ - } /* TODO: to implement automatically shrinking; resize() already support \ - shrinking */ \ - { \ - khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \ - x = site = h->n_buckets; \ - k = __hash_func(key); \ - i = k & mask; \ - if (__ac_isempty(h->flags, i)) \ - x = i; /* for speed up */ \ - else { \ - last = i; \ - while (!__ac_isempty(h->flags, i) && \ - (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ - if (__ac_isdel(h->flags, i)) site = i; \ - i = (i + (++step)) & mask; \ - if (i == last) { \ - x = site; \ - break; \ - } \ - } \ - if (x == h->n_buckets) { \ - if (__ac_isempty(h->flags, i) && site != h->n_buckets) \ - x = site; \ - else \ - x = i; \ - } \ - } \ - } \ - if (__ac_isempty(h->flags, x)) { /* not present at all */ \ - h->keys[x] = key; \ - __ac_set_isboth_false(h->flags, x); \ - ++h->size; \ - ++h->n_occupied; \ - *ret = 1; \ - } else if (__ac_isdel(h->flags, x)) { /* deleted */ \ - h->keys[x] = key; \ - __ac_set_isboth_false(h->flags, x); \ - ++h->size; \ - *ret = 2; \ - } else \ - *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \ - return x; \ - } \ - SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) { \ - if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \ - __ac_set_isdel_true(h->flags, x); \ - --h->size; \ - } \ - } - -#define KHASH_DECLARE(name, khkey_t, khval_t) \ - __KHASH_TYPE(name, khkey_t, khval_t) \ - __KHASH_PROTOTYPES(name, khkey_t, khval_t) - -#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, \ - __hash_equal) \ - __KHASH_TYPE(name, khkey_t, khval_t) \ - __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, \ - __hash_equal) - -#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, \ - __hash_equal) \ - KHASH_INIT2(name, static kh_inline klib_unused, khkey_t, khval_t, kh_is_map, \ - __hash_func, __hash_equal) - -/* --- BEGIN OF HASH FUNCTIONS --- */ - -/*! @function - @abstract Integer hash function - @param key The integer [khint32_t] - @return The hash value [khint_t] - */ -#define kh_int_hash_func(key) (khint32_t)(key) -/*! @function - @abstract Integer comparison function - */ -#define kh_int_hash_equal(a, b) ((a) == (b)) -/*! @function - @abstract 64-bit integer hash function - @param key The integer [khint64_t] - @return The hash value [khint_t] - */ -#define kh_int64_hash_func(key) (khint32_t)((key) >> 33 ^ (key) ^ (key) << 11) -/*! @function - @abstract 64-bit integer comparison function - */ -#define kh_int64_hash_equal(a, b) ((a) == (b)) -/*! @function - @abstract const char* hash function - @param s Pointer to a null terminated string - @return The hash value - */ -static kh_inline khint_t __ac_X31_hash_string(const char *s) { - khint_t h = (khint_t)*s; - if (h) - for (++s; *s; ++s) h = (h << 5) - h + (khint_t)*s; - return h; -} -/*! @function - @abstract Another interface to const char* hash function - @param key Pointer to a null terminated string [const char*] - @return The hash value [khint_t] - */ -#define kh_str_hash_func(key) __ac_X31_hash_string(key) -/*! @function - @abstract Const char* comparison function - */ -#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0) - -static kh_inline khint_t __ac_Wang_hash(khint_t key) { - key += ~(key << 15); - key ^= (key >> 10); - key += (key << 3); - key ^= (key >> 6); - key += ~(key << 11); - key ^= (key >> 16); - return key; -} -#define kh_int_hash_func2(key) __ac_Wang_hash((khint_t)key) - -/* --- END OF HASH FUNCTIONS --- */ - -/* Other convenient macros... */ - -/*! - @abstract Type of the hash table. - @param name Name of the hash table [symbol] - */ -#define khash_t(name) kh_##name##_t - -/*! @function - @abstract Initiate a hash table. - @param name Name of the hash table [symbol] - @return Pointer to the hash table [khash_t(name)*] - */ -#define kh_init(name) kh_init_##name() - -/*! @function - @abstract Destroy a hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - */ -#define kh_destroy(name, h) kh_destroy_##name(h) - -/*! @function - @abstract Reset a hash table without deallocating memory. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - */ -#define kh_clear(name, h) kh_clear_##name(h) - -/*! @function - @abstract Resize a hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - @param s New size [khint_t] - */ -#define kh_resize(name, h, s) kh_resize_##name(h, s) - -/*! @function - @abstract Insert a key to the hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - @param k Key [type of keys] - @param r Extra return code: -1 if the operation failed; - 0 if the key is present in the hash table; - 1 if the bucket is empty (never used); 2 if the element in - the bucket has been deleted [int*] - @return Iterator to the inserted element [khint_t] - */ -#define kh_put(name, h, k, r) kh_put_##name(h, k, r) - -/*! @function - @abstract Retrieve a key from the hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - @param k Key [type of keys] - @return Iterator to the found element, or kh_end(h) if the element is - absent [khint_t] - */ -#define kh_get(name, h, k) kh_get_##name(h, k) - -/*! @function - @abstract Remove a key from the hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - @param k Iterator to the element to be deleted [khint_t] - */ -#define kh_del(name, h, k) kh_del_##name(h, k) - -/*! @function - @abstract Test whether a bucket contains data. - @param h Pointer to the hash table [khash_t(name)*] - @param x Iterator to the bucket [khint_t] - @return 1 if containing data; 0 otherwise [int] - */ -#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x))) - -/*! @function - @abstract Get key given an iterator - @param h Pointer to the hash table [khash_t(name)*] - @param x Iterator to the bucket [khint_t] - @return Key [type of keys] - */ -#define kh_key(h, x) ((h)->keys[x]) - -/*! @function - @abstract Get value given an iterator - @param h Pointer to the hash table [khash_t(name)*] - @param x Iterator to the bucket [khint_t] - @return Value [type of values] - @discussion For hash sets, calling this results in segfault. - */ -#define kh_val(h, x) ((h)->vals[x]) - -/*! @function - @abstract Alias of kh_val() - */ -#define kh_value(h, x) ((h)->vals[x]) - -/*! @function - @abstract Get the start iterator - @param h Pointer to the hash table [khash_t(name)*] - @return The start iterator [khint_t] - */ -#define kh_begin(h) (khint_t)(0) - -/*! @function - @abstract Get the end iterator - @param h Pointer to the hash table [khash_t(name)*] - @return The end iterator [khint_t] - */ -#define kh_end(h) ((h)->n_buckets) - -/*! @function - @abstract Get the number of elements in the hash table - @param h Pointer to the hash table [khash_t(name)*] - @return Number of elements in the hash table [khint_t] - */ -#define kh_size(h) ((h)->size) - -/*! @function - @abstract Get the number of buckets in the hash table - @param h Pointer to the hash table [khash_t(name)*] - @return Number of buckets in the hash table [khint_t] - */ -#define kh_n_buckets(h) ((h)->n_buckets) - -/*! @function - @abstract Iterate over the entries in the hash table - @param h Pointer to the hash table [khash_t(name)*] - @param kvar Variable to which key will be assigned - @param vvar Variable to which value will be assigned - @param code Block of code to execute - */ -#define kh_foreach(h, kvar, vvar, code) \ - { \ - khint_t __i; \ - for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ - if (!kh_exist(h, __i)) continue; \ - (kvar) = kh_key(h, __i); \ - (vvar) = kh_val(h, __i); \ - code; \ - } \ - } - -/*! @function - @abstract Iterate over the values in the hash table - @param h Pointer to the hash table [khash_t(name)*] - @param vvar Variable to which value will be assigned - @param code Block of code to execute - */ -#define kh_foreach_value(h, vvar, code) \ - { \ - khint_t __i; \ - for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ - if (!kh_exist(h, __i)) continue; \ - (vvar) = kh_val(h, __i); \ - code; \ - } \ - } - -/* More convenient interfaces */ - -/*! @function - @abstract Instantiate a hash set containing integer keys - @param name Name of the hash table [symbol] - */ -#define KHASH_SET_INIT_INT(name) \ - KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal) - -/*! @function - @abstract Instantiate a hash map containing integer keys - @param name Name of the hash table [symbol] - @param khval_t Type of values [type] - */ -#define KHASH_MAP_INIT_INT(name, khval_t) \ - KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal) - -/*! @function - @abstract Instantiate a hash set containing 64-bit integer keys - @param name Name of the hash table [symbol] - */ -#define KHASH_SET_INIT_INT64(name) \ - KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal) - -/*! @function - @abstract Instantiate a hash map containing 64-bit integer keys - @param name Name of the hash table [symbol] - @param khval_t Type of values [type] - */ -#define KHASH_MAP_INIT_INT64(name, khval_t) \ - KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, \ - kh_int64_hash_equal) - -typedef const char *kh_cstr_t; -/*! @function - @abstract Instantiate a hash map containing const char* keys - @param name Name of the hash table [symbol] - */ -#define KHASH_SET_INIT_STR(name) \ - KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal) - -/*! @function - @abstract Instantiate a hash map containing const char* keys - @param name Name of the hash table [symbol] - @param khval_t Type of values [type] - */ -#define KHASH_MAP_INIT_STR(name, khval_t) \ - KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal) - -/****************************************************************************** - * Custom - *high-level interface - ******************************************************************************/ - -#define _kh_var(x) _kh_var_##x - -/** - * @brief Return the value corresponding to a key in the hashtable. - * @return The value associated with the key or null if not found - */ -#define kh_get_val(kname, hashtable, key, default_val) \ - ({ \ - khiter_t _kh_var(k) = kh_get(kname, hashtable, key); \ - (_kh_var(k) != kh_end(hashtable) ? kh_val(hashtable, _kh_var(k)) \ - : default_val); \ - }) - -/** - * @brief Add key/value pair in the hashtable. - * @return 0 if an existing value (corresponding to the provided key) - * has been replaced; 1 if a new key/value pair has been added - * (the key was not already present in the hash table); - * 2 if a new key/value pair has been added in correspondence - * of a key previously deleted key - */ -#define kh_put_val(kname, hashtable, key, val) \ - ({ \ - int _kh_var(ret); \ - khiter_t _kh_var(k) = kh_put(kname, hashtable, key, &_kh_var(ret)); \ - kh_value(hashtable, _kh_var(k)) = val; \ - _kh_var(ret); \ - }) - -/** - * @brief Remove a key/value pair from the hashtable. - * @return void - */ -#define kh_remove_val(kname, hashtable, key) \ - ({ \ - khiter_t _kh_var(k) = kh_get(kname, hashtable, key); \ - if (_kh_var(k) != kh_end(hashtable)) { \ - free((void *)kh_key(hashtable, _kh_var(k))); \ - kh_del(kname, hashtable, _kh_var(k)); \ - } \ - }) - -/** - * @brief Free the hashtable. - * @return void - */ -#define kh_free(kname, hashtable) \ - ({ \ - const void *_kh_var(key); \ - unsigned _kh_var(val); \ - (void)_kh_var(val); \ - \ - kh_foreach(hashtable, _kh_var(key), _kh_var(val), \ - { free((void *)_kh_var(key)); }) kh_destroy(kname, hashtable); \ - }) - -#endif /* __AC_KHASH_H */ diff --git a/hicn-light/src/hicn/base/pool.c b/hicn-light/src/hicn/base/pool.c deleted file mode 100644 index e5fb7d6ac..000000000 --- a/hicn-light/src/hicn/base/pool.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file pool.c - * \brief Implementation of fixed-size pool allocator. - * - * NOTE: - * - Ideally, we should have a single realloc per resize, that would encompass - * both the free indices vector and bitmap, by nesting data structures. Because - * of the added complexity, and by lack of evidence of the need for this, we - * currently rely on a simpler implementation. - */ - -#include <assert.h> -#include <stdlib.h> // calloc - -#include "common.h" -#include "pool.h" - -#include <stdio.h> // XXX - -void _pool_init(void** pool_ptr, size_t elt_size, size_t init_size, - size_t max_size) { - assert(pool_ptr); - assert(elt_size); - - init_size = next_pow2(init_size); - - if (max_size && init_size > max_size) goto ERR_MAX_SIZE; - - /* The initial pool size is rounded to the next power of two */ - size_t alloc_size = next_pow2(init_size); - - pool_hdr_t* ph = calloc(POOL_HDRLEN + alloc_size * elt_size, 1); - if (!ph) goto ERR_MALLOC; - - ph->elt_size = elt_size; - ph->alloc_size = alloc_size; - ph->max_size = max_size; - - /* Free indices */ - off_t* free_indices; - vector_init(free_indices, init_size, max_size); - for (unsigned i = 0; i < init_size; i++) - free_indices[i] = (init_size - 1) - i; - vector_len(free_indices) = init_size; - ph->free_indices = free_indices; - - /* Free bitmap */ - bitmap_t* fb = ph->free_bitmap; - bitmap_init(fb, init_size, max_size); - bitmap_set_to(fb, init_size); - ph->free_bitmap = fb; - - *pool_ptr = (uint8_t*)ph + POOL_HDRLEN; - - return; - -ERR_MALLOC: -ERR_MAX_SIZE: - *pool_ptr = NULL; - return; -} - -void _pool_free(void** pool_ptr) { - pool_hdr_t* ph = pool_hdr(*pool_ptr); - vector_free(ph->free_indices); - bitmap_free(ph->free_bitmap); - - free(pool_hdr(*pool_ptr)); - *pool_ptr = NULL; -} - -bool _pool_validate_id(void** pool_ptr, off_t id) { - pool_hdr_t* ph = pool_hdr(*pool_ptr); - size_t pool_size = pool_get_alloc_size(*pool_ptr); - if (id >= pool_size || !bitmap_is_unset(ph->free_bitmap, id)) return false; - - return true; -} - -void _pool_resize(void** pool_ptr, size_t elt_size) { - pool_hdr_t* ph = pool_hdr(*pool_ptr); - size_t old_size = ph->alloc_size; - size_t new_size = old_size * 2; - - TRACE("pool_resize to %lu", new_size); - - if (ph->max_size && new_size > ph->max_size) goto ERR_MAX_SIZE; - - /* Double pool storage */ - ph = realloc(ph, POOL_HDRLEN + new_size * elt_size); - if (!ph) goto ERR_REALLOC; - ph->elt_size = elt_size; - ph->alloc_size = new_size; - - /* - * After resize, the pool will have new free indices, ranging from - * old_size to (new_size - 1) - */ - vector_ensure_pos(ph->free_indices, old_size); - for (unsigned i = 0; i < old_size; i++) - ph->free_indices[i] = new_size - 1 - i; - vector_len(ph->free_indices) = old_size; - - /* We also need to update the bitmap */ - bitmap_ensure_pos(&(ph->free_bitmap), new_size - 1); - bitmap_set_range(ph->free_bitmap, old_size, new_size - 1); - - /* Reassign pool pointer */ - *pool_ptr = (uint8_t*)ph + POOL_HDRLEN; - - return; - -ERR_REALLOC: -ERR_MAX_SIZE: - *pool_ptr = NULL; - return; -} - -off_t _pool_get(void** pool_ptr, void** elt, size_t elt_size) { - pool_hdr_t* ph = pool_hdr(*pool_ptr); - uint64_t l = vector_len(ph->free_indices); - if (l == 0) { - _pool_resize(pool_ptr, elt_size); - ph = pool_hdr(*pool_ptr); - l = vector_len(ph->free_indices); - } - off_t free_id = ph->free_indices[l - 1]; - vector_len(ph->free_indices)--; - bitmap_unset(ph->free_bitmap, free_id); - *elt = *pool_ptr + free_id * elt_size; - memset(*elt, 0, elt_size); - return free_id; -} - -void _pool_put(void** pool_ptr, void** elt, size_t elt_size) { - pool_hdr_t* ph = pool_hdr(*pool_ptr); - uint64_t l = vector_len(ph->free_indices); - vector_ensure_pos(ph->free_indices, l); - off_t freed_id = (*elt - *pool_ptr) / elt_size; - ph->free_indices[l] = freed_id; - vector_len(ph->free_indices)++; - bitmap_set(ph->free_bitmap, freed_id); -} diff --git a/hicn-light/src/hicn/base/ring.h b/hicn-light/src/hicn/base/ring.h deleted file mode 100644 index 492a8fdac..000000000 --- a/hicn-light/src/hicn/base/ring.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * \file ring.h - * \brief Fixed-size pool allocator. - */ - -#ifndef UTIL_RING_H -#define UTIL_RING_H - -#include <assert.h> -#include <stdint.h> -#include <string.h> -#include <sys/param.h> // MIN -#include <sys/types.h> - -#include <stdio.h> // XXX debug - -#include "common.h" - -/******************************************************************************/ -/* Ring header */ - -typedef struct { - size_t roff; - size_t woff; - size_t size; - size_t max_size; -} ring_hdr_t; - -/* Make sure elements following the header are aligned */ -#define RING_HDRLEN SIZEOF_ALIGNED(ring_hdr_t) - -/* This header actually prepends the actual content of the vector */ -#define ring_hdr(ring) ((ring_hdr_t *)((uint8_t *)ring - RING_HDRLEN)) - -/******************************************************************************/ -/* Helpers */ - -/** Local variable naming macro. */ -#define _ring_var(v) _ring_##v - -/** - * @brief Allocate and initialize a ring data structure (helper function). - * - * @param[in,out] ring_ptr Ring buffer to allocate and initialize. - * @param[in] elt_size Size of a ring element. - * @param[in] max_size Maximum vector size (O = unlimited). - */ -void _ring_init(void **ring_ptr, size_t elt_size, size_t max_size); - -/** - * @brief Free a ring data structure. - * - * @param ring_ptr[in] Pointer to the ring data structure to free. - */ -void _ring_free(void **ring_ptr); - -static inline int _ring_add(void **ring_ptr, size_t elt_size, void *eltp) { - assert(*ring_ptr); - ring_hdr_t *rh = ring_hdr(*ring_ptr); - - /* We always write ! */ - memcpy((uint8_t *)*ring_ptr + rh->woff * elt_size, eltp, elt_size); - rh->woff++; - if (rh->woff == rh->max_size) rh->woff = 0; - if (rh->size < rh->max_size) { - rh->size++; - } else { - /* One packet was dropped */ - rh->roff++; - if (rh->roff == rh->max_size) rh->roff = 0; - } - return 0; -} - -static inline unsigned _ring_get_fullness(void **ring_ptr) { - assert(*ring_ptr); - ring_hdr_t *rh = ring_hdr(*ring_ptr); - return rh->size * 100 / rh->max_size; -} - -static inline unsigned _ring_is_full(void **ring_ptr) { - assert(*ring_ptr); - ring_hdr_t *rh = ring_hdr(*ring_ptr); - return rh->size == rh->max_size; -} - -static inline size_t _ring_get_size(void **ring_ptr) { - assert(*ring_ptr); - ring_hdr_t *rh = ring_hdr(*ring_ptr); - return rh->size; -} - -static inline int _ring_advance(void **ring_ptr, unsigned n) { - assert(*ring_ptr); - ring_hdr_t *rh = ring_hdr(*ring_ptr); - assert(n <= rh->size); - - rh->roff += n; - rh->size -= n; - while (rh->roff >= rh->max_size) rh->roff -= rh->max_size; - return 0; -} - -static inline int _ring_get(void **ring_ptr, size_t elt_size, unsigned i, - void *eltp) { - assert(*ring_ptr); - ring_hdr_t *rh = ring_hdr(*ring_ptr); - assert(i <= rh->size); - size_t pos = rh->roff + i; - if (pos >= rh->max_size) pos -= rh->max_size; - memcpy(eltp, (uint8_t *)*ring_ptr + pos * elt_size, elt_size); - return 0; -} - -/******************************************************************************/ -/* Public API */ - -/** - * @brief Allocate and initialize a ring data structure. - * - * @param[in,out] ring Ring to allocate and initialize. - * @param[in] max_size Maximum ring size (nonzero). - * - * NOTE: - * - Allocated memory is set to 0 (used by bitmap) - */ - -#define ring_init(RING, MAX_SIZE) \ - _ring_init((void **)&(RING), sizeof((RING)[0]), (MAX_SIZE)) - -#define ring_free(RING) _ring_free((void **)&(RING)) - -#define ring_get_fullness(RING) _ring_get_fullness((void **)&(RING)) - -#define ring_is_full(RING) _ring_is_full((void **)&(RING)) - -#define ring_get_size(RING) _ring_get_size((void **)&(RING)) - -#define ring_add(RING, ELT) _ring_add((void **)&(RING), sizeof(RING[0]), ELT) - -#define ring_add_value(RING, VALUE) \ - do { \ - typeof(VALUE) _ring_var(v) = VALUE; \ - _ring_add((void **)&(RING), sizeof(RING[0]), &_ring_var(v)); \ - } while (0) - -#define ring_advance(RING, N) _ring_advance((void **)&(RING), (N)) - -#define ring_get(RING, I, ELTP) \ - _ring_get((void **)&RING, sizeof(RING[0]), (I), (ELTP)) - -/** - * @brief Helper function used by ring_foreach(). - */ -#define ring_enumerate_n(RING, I, ELTP, COUNT, BODY) \ - ({ \ - for ((I) = 0; (I) < MIN(ring_get_size(RING), (COUNT)); (I)++) { \ - ring_get((RING), (I), (ELTP)); \ - { BODY; } \ - } \ - }) - -#define ring_enumerate(ring, i, eltp, BODY) \ - ring_enumerate_n((ring), (i), (eltp), 1, (BODY)) - -/** - * @brief Iterate over elements in a ring. - * - * @param[in] pool The ring data structure to iterate over - * @param[in, out] eltp A pointer to the element that will be used for - * iteration - * @param[in] BODY Block to execute during iteration - * - * @note Iteration will execute BODY with eltp corresponding successively to all - * elements found in the ring. It is implemented using the more generic - * enumeration function. - */ -#define ring_foreach_n(ring, eltp, count, BODY) \ - ({ \ - unsigned _ring_var(i); \ - ring_enumerate_n((ring), _ring_var(i), (eltp), (count), BODY); \ - }) - -#define ring_foreach(ring, eltp, BODY) ring_foreach_n((ring), (eltp), 1, (BODY)) - -#endif /* UTIL_RING_H */ diff --git a/hicn-light/src/hicn/cli/hicnc.c b/hicn-light/src/hicn/cli/hicnc.c index d14093b6b..3074016c5 100644 --- a/hicn-light/src/hicn/cli/hicnc.c +++ b/hicn-light/src/hicn/cli/hicnc.c @@ -25,6 +25,7 @@ #include "../config/parse.h" #include <hicn/util/log.h> #include <hicn/util/sstrncpy.h> +#include <hicn/ctrl/hicn-light-ng.h> #define PORT 9695 @@ -359,6 +360,70 @@ int main(int argc, char *const *argv) { rc = hc_subscription_delete(s, &command.object.subscription); break; + case OBJECT_STATS: + switch (command.action) { + case ACTION_GET: + rc = hc_stats_get(s, &data); + if (rc < 0) break; + + hc_stats_snprintf(buf, MAX_LEN, (hicn_light_stats_t *)data->buffer); + INFO("\n%s", buf); + break; + + case ACTION_LIST: + rc = hc_stats_list(s, &data); + if (rc < 0) break; + + cmd_stats_list_item_t *conn_stats = + (cmd_stats_list_item_t *)data->buffer; + cmd_stats_list_item_t *end = + (cmd_stats_list_item_t *)(data->buffer + + data->size * data->out_element_size); + while (conn_stats < end) { + INFO("Connection #%d:", conn_stats->id); + INFO("\tinterests received: %d pkts (%d bytes)", + conn_stats->stats.interests.rx_pkts, + conn_stats->stats.interests.rx_bytes); + INFO("\tinterests transmitted: %d pkts (%d bytes)", + conn_stats->stats.interests.tx_pkts, + conn_stats->stats.interests.tx_bytes); + INFO("\tdata received: %d pkts (%d bytes)", + conn_stats->stats.data.rx_pkts, + conn_stats->stats.data.rx_bytes); + INFO("\tdata transmitted: %d pkts (%d bytes)", + conn_stats->stats.data.tx_pkts, + conn_stats->stats.data.tx_bytes); + + conn_stats++; + } + break; + + default: + break; + } + break; + +#ifdef TEST_FACE_CREATION + case OBJECT_FACE: + switch (command.action) { + case ACTION_CREATE: { + hc_face_t face = {0}; + face.face.type = FACE_TYPE_UDP; + face.face.family = AF_INET; + face.face.local_addr = IPV4_LOOPBACK; + face.face.remote_addr = IPV4_LOOPBACK; + face.face.local_port = 9696; + face.face.remote_port = 9696; + + rc = hc_face_create(s, &face); + break; + } + default: + break; + } + break; +#endif + default: break; } diff --git a/hicn-light/src/hicn/cli/hicnd.c b/hicn-light/src/hicn/cli/hicnd.c index e73517e4c..fa1b1c024 100644 --- a/hicn-light/src/hicn/cli/hicnd.c +++ b/hicn-light/src/hicn/cli/hicnd.c @@ -26,9 +26,9 @@ #include <sys/stat.h> #include <hicn/util/log.h> +#include <hicn/base/loop.h> #include "logo.h" -#include "../base/loop.h" #include "../core/forwarder.h" #include "../config/configuration.h" // XXX needed ? #include "../config/configuration_file.h" diff --git a/hicn-light/src/hicn/config/CMakeLists.txt b/hicn-light/src/hicn/config/CMakeLists.txt index 00ee24077..90d0a2229 100644 --- a/hicn-light/src/hicn/config/CMakeLists.txt +++ b/hicn-light/src/hicn/config/CMakeLists.txt @@ -29,6 +29,7 @@ list(APPEND SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/command_policy.c ${CMAKE_CURRENT_SOURCE_DIR}/command_punting.c ${CMAKE_CURRENT_SOURCE_DIR}/command_route.c + ${CMAKE_CURRENT_SOURCE_DIR}/command_stats.c ${CMAKE_CURRENT_SOURCE_DIR}/command_strategy.c ${CMAKE_CURRENT_SOURCE_DIR}/command_subscription.c ${CMAKE_CURRENT_SOURCE_DIR}/command.c diff --git a/hicn-light/src/hicn/config/command_stats.c b/hicn-light/src/hicn/config/command_stats.c new file mode 100644 index 000000000..70f74fd8c --- /dev/null +++ b/hicn-light/src/hicn/config/command_stats.c @@ -0,0 +1,18 @@ +#include <math.h> +#include "command.h" + +/* Commands */ + +static const command_parser_t command_stats_get = { + .action = ACTION_GET, + .object = OBJECT_STATS, + .nparams = 0, +}; +COMMAND_REGISTER(command_stats_get); + +static const command_parser_t command_stats_list = { + .action = ACTION_LIST, + .object = OBJECT_STATS, + .nparams = 0, +}; +COMMAND_REGISTER(command_stats_list);
\ No newline at end of file diff --git a/hicn-light/src/hicn/config/commands.c b/hicn-light/src/hicn/config/commands.c index e99e0b8f5..be00575d7 100644 --- a/hicn-light/src/hicn/config/commands.c +++ b/hicn-light/src/hicn/config/commands.c @@ -90,7 +90,8 @@ static inline unsigned _symbolic_to_conn_id(forwarder_t *forwarder, } } else { // case for symbolic as input: check if symbolic name can be resolved - conn_id = connection_table_get_id_by_name(table, symbolic_or_connid); + conn_id = (unsigned int)connection_table_get_id_by_name(table, + symbolic_or_connid); if (connection_id_is_valid(conn_id)) { DEBUG("Resolved symbolic name '%s' to conn_id %u", symbolic_or_connid, conn_id); @@ -151,6 +152,7 @@ uint8_t *configuration_on_listener_add(forwarder_t *forwarder, uint8_t *packet, } address_t address; + memset(&address, 0, sizeof(address_t)); if (address_from_ip_port(&address, control->family, &control->address, control->port) < 0) { WARN( @@ -206,7 +208,8 @@ unsigned symbolic_to_listener_id(forwarder_t *forwarder, } } else { // case for symbolic as input: check if symbolic name can be resolved - listener_id = listener_table_get_id_by_name(table, symbolic_or_listener_id); + listener_id = (unsigned int)listener_table_get_id_by_name( + table, symbolic_or_listener_id); if (listener_id_is_valid(listener_id)) { DEBUG("Resolved symbolic name '%s' to conn_id %u", symbolic_or_listener_id, listener_id); @@ -262,7 +265,8 @@ uint8_t *configuration_on_listener_remove(forwarder_t *forwarder, address_pair_get_local(pair))) continue; - unsigned conn_id = connection_table_get_connection_id(table, connection); + unsigned conn_id = + (unsigned int)connection_table_get_connection_id(table, connection); /* Remove connection from the FIB */ forwarder_remove_connection_id_from_routes(forwarder, conn_id); @@ -335,8 +339,9 @@ uint8_t *configuration_on_listener_list(forwarder_t *forwarder, uint8_t *packet, uint8_t command_id = msg_received->header.command_id; uint32_t seq_num = msg_received->header.seq_num; - msg_listener_list_reply_t *msg; - msg_malloc_list(msg, command_id, n, seq_num) if (!msg) goto NACK; + msg_listener_list_reply_t *msg = NULL; + msg_malloc_list(msg, command_id, n, seq_num); + if (!msg) goto NACK; cmd_listener_list_item_t *payload = &msg->payload; listener_t *listener; @@ -376,14 +381,23 @@ uint8_t *configuration_on_connection_add(forwarder_t *forwarder, goto NACK; } - const char *symbolic_name = control->symbolic; - if (!face_type_is_defined(control->type)) goto NACK; connection_table_t *table = forwarder_get_connection_table(forwarder); - if (connection_table_get_by_name(table, symbolic_name)) { - ERROR("Connection symbolic name already exists"); - goto NACK; + char *symbolic_name = control->symbolic; + + // Generate connection name if not specified + if (symbolic_name[0] == '\0') { + int rc = connection_table_get_random_name(table, symbolic_name); + if (rc < 0) { + ERROR("Unable to generate new connection name"); + goto NACK; + } + } else { + if (connection_table_get_by_name(table, symbolic_name)) { + ERROR("Connection symbolic name already exists"); + goto NACK; + } } address_pair_t pair; @@ -561,6 +575,14 @@ static inline void fill_connections_command(forwarder_t *forwarder, } } +static inline void fill_connection_stats_command(connection_t *connection, + cmd_stats_list_item_t *cmd) { + assert(connection && cmd); + + cmd->id = connection->id; + cmd->stats = connection->stats; +} + uint8_t *configuration_on_connection_list(forwarder_t *forwarder, uint8_t *packet, unsigned ingress_id, size_t *reply_size) { @@ -576,8 +598,9 @@ uint8_t *configuration_on_connection_list(forwarder_t *forwarder, uint8_t command_id = msg_received->header.command_id; uint32_t seq_num = msg_received->header.seq_num; - msg_connection_list_reply_t *msg; - msg_malloc_list(msg, command_id, n, seq_num) if (!msg) goto NACK; + msg_connection_list_reply_t *msg = NULL; + msg_malloc_list(msg, command_id, n, seq_num); + if (!msg) goto NACK; cmd_connection_list_item_t *payload = &msg->payload; connection_t *connection; @@ -807,7 +830,7 @@ uint8_t *configuration_on_route_list(forwarder_t *forwarder, uint8_t *packet, n += nexthops_get_len(nexthops); }); - msg_route_list_reply_t *msg; + msg_route_list_reply_t *msg = NULL; msg_malloc_list(msg, command_id, n, seq_num); if (!msg) goto NACK; @@ -938,8 +961,9 @@ uint8_t *configuration_on_cache_list(forwarder_t *forwarder, uint8_t *packet, .payload = { .store_in_cs = forwarder_cs_get_store(forwarder), .serve_from_cs = forwarder_cs_get_serve(forwarder), - .cs_size = forwarder_cs_get_size(forwarder), - .num_stale_entries = forwarder_cs_get_num_stale_entries(forwarder)}}; + .cs_size = (unsigned int)forwarder_cs_get_size(forwarder), + .num_stale_entries = + (unsigned int)forwarder_cs_get_num_stale_entries(forwarder)}}; *reply_size = sizeof(*msg); return (uint8_t *)msg; @@ -1068,6 +1092,65 @@ NACK: return (uint8_t *)msg; } +/* Statistics */ + +uint8_t *configuration_on_stats_get(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size) { + assert(forwarder && packet); + INFO("CMD: stats get (ingress=%d)", ingress_id); + + msg_stats_get_t *msg_received = (msg_stats_get_t *)packet; + uint32_t seq_num = msg_received->header.seq_num; + + msg_stats_get_reply_t *msg = malloc(sizeof(*msg)); + *msg = (msg_stats_get_reply_t){ + .header = {.message_type = RESPONSE_LIGHT, + .length = 1, + .seq_num = seq_num}, + .payload = {.forwarder = forwarder_get_stats(forwarder), + .pkt_cache = + pkt_cache_get_stats(forwarder_get_pkt_cache(forwarder))} + + }; + + *reply_size = sizeof(*msg); + return (uint8_t *)msg; +} + +uint8_t *configuration_on_stats_list(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size) { + assert(forwarder && packet); + INFO("CMD: stats list (ingress=%d)", ingress_id); + + connection_table_t *table = forwarder_get_connection_table(forwarder); + // -1 since current connection (i.e. the one used to send + // the command) is not considered + size_t n = connection_table_len(table) - 1; + msg_stats_list_t *msg_received = (msg_stats_list_t *)packet; + uint8_t command_id = msg_received->header.command_id; + uint32_t seq_num = msg_received->header.seq_num; + + msg_stats_list_reply_t *msg = NULL; + msg_malloc_list(msg, command_id, n, seq_num); + if (!msg) goto NACK; + + cmd_stats_list_item_t *payload = &msg->payload; + connection_t *connection; + connection_table_foreach(table, connection, { + if (connection->id == ingress_id) continue; + fill_connection_stats_command(connection, payload); + payload++; + }); + + *reply_size = sizeof(msg->header) + n * sizeof(msg->payload); + return (uint8_t *)msg; + +NACK: + *reply_size = sizeof(msg_header_t); + make_nack(msg); + return (uint8_t *)msg; +} + /* WLDR */ uint8_t *configuration_on_wldr_set(forwarder_t *forwarder, uint8_t *packet, @@ -1365,7 +1448,7 @@ uint8_t *configuration_on_policy_list(forwarder_t *forwarder, uint8_t *packet, uint8_t command_id = msg_received->header.command_id; uint32_t seq_num = msg_received->header.seq_num; - msg_policy_list_reply_t *msg; + msg_policy_list_reply_t *msg = NULL; msg_malloc_list(msg, command_id, n, seq_num); if (!msg) goto NACK; diff --git a/hicn-light/src/hicn/config/commands.h b/hicn-light/src/hicn/config/commands.h index cedf4de01..3852a76ac 100644 --- a/hicn-light/src/hicn/config/commands.h +++ b/hicn-light/src/hicn/config/commands.h @@ -149,4 +149,7 @@ uint8_t *configuration_on_policy_remove(forwarder_t *forwarder, uint8_t *packet, uint8_t *configuration_on_policy_list(forwarder_t *forwarder, uint8_t *packet, unsigned ingress_id, size_t *reply_size); +uint8_t *configuration_on_stats_list(forwarder_t *forwarder, uint8_t *packet, + unsigned ingress_id, size_t *reply_size); + #endif // HICNLIGHT_COMMANDS_H diff --git a/hicn-light/src/hicn/config/configuration.h b/hicn-light/src/hicn/config/configuration.h index 9861b6c9f..93b4cf7c3 100644 --- a/hicn-light/src/hicn/config/configuration.h +++ b/hicn-light/src/hicn/config/configuration.h @@ -26,7 +26,7 @@ #ifndef HICNLIGHT_CONFIGURATION_H #define HICNLIGHT_CONFIGURATION_H -#include "../base/khash.h" +#include <hicn/util/khash.h> #include "../core/msgbuf.h" #include "../core/strategy.h" #include <hicn/ctrl/api.h> diff --git a/hicn-light/src/hicn/core/CMakeLists.txt b/hicn-light/src/hicn/core/CMakeLists.txt index 57ffb780f..9516a6a72 100644 --- a/hicn-light/src/hicn/core/CMakeLists.txt +++ b/hicn-light/src/hicn/core/CMakeLists.txt @@ -21,6 +21,7 @@ list(APPEND HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/fib_entry.h ${CMAKE_CURRENT_SOURCE_DIR}/fib.h ${CMAKE_CURRENT_SOURCE_DIR}/forwarder.h + ${CMAKE_CURRENT_SOURCE_DIR}/interest_manifest.h ${CMAKE_CURRENT_SOURCE_DIR}/listener.h ${CMAKE_CURRENT_SOURCE_DIR}/listener_table.h ${CMAKE_CURRENT_SOURCE_DIR}/listener_vft.h @@ -52,6 +53,7 @@ list(APPEND SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/fib.c ${CMAKE_CURRENT_SOURCE_DIR}/fib_entry.c ${CMAKE_CURRENT_SOURCE_DIR}/forwarder.c + ${CMAKE_CURRENT_SOURCE_DIR}/interest_manifest.c ${CMAKE_CURRENT_SOURCE_DIR}/listener.c ${CMAKE_CURRENT_SOURCE_DIR}/listener_table.c ${CMAKE_CURRENT_SOURCE_DIR}/listener_vft.c diff --git a/hicn-light/src/hicn/core/address_pair.h b/hicn-light/src/hicn/core/address_pair.h index 72b92d6b5..2fd207d34 100644 --- a/hicn-light/src/hicn/core/address_pair.h +++ b/hicn-light/src/hicn/core/address_pair.h @@ -43,6 +43,12 @@ int address_pair_from_ip_port(address_pair_t* pair, int family, ip_address_t* local_addr, uint16_t local_port, ip_address_t* remote_addr, uint16_t remote_port); +static inline int address_pair_equals(const address_pair_t* pair1, + const address_pair_t* pair2) { + return address_equals(&pair1->local, &pair2->local) && + address_equals(&pair1->remote, &pair2->remote); +} + #define address_pair_get_local(pair) (&(pair)->local) #define address_pair_get_remote(pair) (&(pair)->remote) diff --git a/hicn-light/src/hicn/core/connection.c b/hicn-light/src/hicn/core/connection.c index c8cc1d0b9..2108d30af 100644 --- a/hicn-light/src/hicn/core/connection.c +++ b/hicn-light/src/hicn/core/connection.c @@ -28,8 +28,6 @@ #include "connection.h" #include "connection_vft.h" -#define _conn_var(x) _connection_##x - // This is called by configuration connection_t *connection_create(face_type_t type, const char *name, const address_pair_t *pair, @@ -212,18 +210,16 @@ int connection_send_packet(const connection_t *connection, connection, packet, size); } -bool _connection_send(const connection_t *connection, msgbuf_t *msgbuf, - bool queue) { +bool _connection_send(connection_t *connection, msgbuf_t *msgbuf, bool queue) { return connection_vft[get_protocol(connection->type)]->send(connection, msgbuf, queue); } -bool connection_flush(const connection_t *connection) { +bool connection_flush(connection_t *connection) { return connection_vft[get_protocol(connection->type)]->flush(connection); } -bool connection_send(const connection_t *connection, off_t msgbuf_id, - bool queue) { +bool connection_send(connection_t *connection, off_t msgbuf_id, bool queue) { assert(connection); assert(msgbuf_id_is_valid(msgbuf_id)); @@ -254,7 +250,7 @@ bool connection_send(const connection_t *connection, off_t msgbuf_id, * handled inside the MessageProcessor. This is specific to WLDR * retransmittions. This is done only for data packets */ -bool connection_resend(const connection_t *connection, msgbuf_t *msgbuf, +bool connection_resend(connection_t *connection, msgbuf_t *msgbuf, bool notification) { assert(connection); assert(msgbuf); diff --git a/hicn-light/src/hicn/core/connection.h b/hicn-light/src/hicn/core/connection.h index 05dc1d6e2..ac75428dd 100644 --- a/hicn-light/src/hicn/core/connection.h +++ b/hicn-light/src/hicn/core/connection.h @@ -84,6 +84,7 @@ typedef struct { */ struct wldr_s* wldr; + connection_stats_t stats; } connection_t; #if 1 @@ -209,10 +210,9 @@ int connection_finalize(connection_t* connection); int connection_send_packet(const connection_t* connection, const uint8_t* packet, size_t size); -bool connection_flush(const connection_t* connection); +bool connection_flush(connection_t* connection); -bool connection_send(const connection_t* connection, off_t msgbuf_id, - bool queue); +bool connection_send(connection_t* connection, off_t msgbuf_id, bool queue); size_t connection_process_buffer(connection_t* connection, const uint8_t* buffer, size_t size); diff --git a/hicn-light/src/hicn/core/connection_table.c b/hicn-light/src/hicn/core/connection_table.c index 09236ae8e..c723073a1 100644 --- a/hicn-light/src/hicn/core/connection_table.c +++ b/hicn-light/src/hicn/core/connection_table.c @@ -74,6 +74,54 @@ void connection_table_free(connection_table_t *table) { free(table); } +connection_t *connection_table_allocate(const connection_table_t *table, + const address_pair_t *pair, + const char *name) { + connection_t *conn = NULL; + pool_get(table->connections, conn); + if (!conn) return NULL; + + off_t id = conn - table->connections; + int rc; + + // Add in name hash table + khiter_t k = kh_put_ct_name(table->id_by_name, strdup(name), &rc); + assert(rc == KH_ADDED || rc == KH_RESET); + kh_value(table->id_by_name, k) = (unsigned int)id; + + // Add in pair hash table + address_pair_t *pair_copy = (address_pair_t *)malloc(sizeof(address_pair_t)); + memcpy(pair_copy, pair, sizeof(address_pair_t)); + + k = kh_put_ct_pair(table->id_by_pair, pair_copy, &rc); + assert(rc == KH_ADDED || rc == KH_RESET); + kh_value(table->id_by_pair, k) = (unsigned int)id; + + assert(kh_size(table->id_by_name) == kh_size(table->id_by_pair)); + return conn; +} + +void connection_table_deallocate(const connection_table_t *table, + const connection_t *conn) { + const char *name = connection_get_name(conn); + const address_pair_t *pair = connection_get_pair(conn); + + // Remove from name hash table + khiter_t k = kh_get_ct_name(table->id_by_name, name); + assert(k != kh_end(table->id_by_name)); + free((char *)kh_key(table->id_by_name, k)); + kh_del_ct_name(table->id_by_name, k); + + // Remove from pair hash table + k = kh_get_ct_pair(table->id_by_pair, pair); + assert(k != kh_end(table->id_by_pair)); + free((address_pair_t *)kh_key(table->id_by_pair, k)); + kh_del_ct_pair(table->id_by_pair, k); + + assert(kh_size(table->id_by_name) == kh_size(table->id_by_pair)); + pool_put(table->connections, conn); +} + connection_t *connection_table_get_by_pair(const connection_table_t *table, const address_pair_t *pair) { khiter_t k = kh_get_ct_pair(table->id_by_pair, pair); @@ -90,7 +138,7 @@ off_t connection_table_get_id_by_name(const connection_table_t *table, connection_t *connection_table_get_by_name(const connection_table_t *table, const char *name) { - unsigned conn_id = connection_table_get_id_by_name(table, name); + unsigned conn_id = (unsigned int)connection_table_get_id_by_name(table, name); if (!connection_id_is_valid(conn_id)) return NULL; return connection_table_at(table, conn_id); } @@ -141,22 +189,24 @@ connection_t *_connection_table_get_by_id(connection_table_t *table, off_t id) { return connection_table_get_by_id(table, id); } -#define RANDBYTE() (u8)(rand() & 0xFF) - -char *connection_table_get_random_name(const connection_table_t *table) { - char *connection_name = malloc(SYMBOLIC_NAME_LEN * sizeof(char)); - u8 rand_num; +static inline u16 RAND16() { return rand() & 0xFFFF; } - /* Generate a random connection name */ - while (1) { - rand_num = RANDBYTE(); - int rc = snprintf(connection_name, SYMBOLIC_NAME_LEN, "conn%u", rand_num); - _ASSERT(rc < SYMBOLIC_NAME_LEN); +int connection_table_get_random_name(const connection_table_t *table, + char *name) { + int i, n_attempts = 2 * USHRT_MAX; + for (i = 0; i < n_attempts; i++) { + int rc = snprintf(name, SYMBOLIC_NAME_LEN, "conn%u", RAND16()); + if (rc >= SYMBOLIC_NAME_LEN) continue; - // Return if connection name does not already exist - khiter_t k = kh_get_ct_name(table->id_by_name, connection_name); + // Check if generated connection name is a duplicate + khiter_t k = kh_get_ct_name(table->id_by_name, name); if (k == kh_end(table->id_by_name)) break; } - return connection_name; + if (i == n_attempts) { + ERROR("Unable to generate new unique connection name"); + return -1; + } + + return 0; }
\ No newline at end of file diff --git a/hicn-light/src/hicn/core/connection_table.h b/hicn-light/src/hicn/core/connection_table.h index 4c03aa642..7d4bad761 100644 --- a/hicn-light/src/hicn/core/connection_table.h +++ b/hicn-light/src/hicn/core/connection_table.h @@ -30,22 +30,18 @@ #ifndef HICNLIGHT_CONNECTION_TABLE_H #define HICNLIGHT_CONNECTION_TABLE_H +#include <hicn/util/khash.h> +#include <hicn/util/hash.h> #include "address_pair.h" #include "connection.h" -#include "../base/hash.h" -#include "../base/khash.h" -#include "../base/pool.h" - -#define _ct_var(x) _ct_var_##x +#include <hicn/util/pool.h> /* Hash functions for indices. */ #define address_pair_hash(pair) (hash_struct(pair)) -#define address_pair_hash_eq(a, b) \ - (address_pair_hash(b) == address_pair_hash(a)) /* Hash table types for indices. */ KHASH_INIT(ct_pair, const address_pair_t *, unsigned, 1, address_pair_hash, - address_pair_hash_eq); + address_pair_equals); KHASH_MAP_INIT_STR(ct_name, unsigned); typedef struct { @@ -72,34 +68,9 @@ typedef struct { * - You should always check that the returned connection is not NULL, which * would signal that the pool is exhausted and could not be extended. */ -static inline connection_t *connection_table_allocate( - const connection_table_t *table, const address_pair_t *pair, - const char *name) { - connection_t *conn; - pool_get(table->connections, conn); - - if (conn) { - off_t id = conn - table->connections; - int res; - khiter_t k; - - // Add in name hash table - k = kh_put_ct_name(table->id_by_name, strdup(name), &res); - kh_value(table->id_by_name, k) = id; - - // Add in pair hash table - address_pair_t *pair_copy = - (address_pair_t *)malloc(sizeof(address_pair_t)); - memcpy(pair_copy, pair, sizeof(address_pair_t)); - - k = kh_put_ct_pair(table->id_by_pair, pair_copy, &res); - assert(res != -1); - kh_value(table->id_by_pair, k) = id; - } - - return conn; -} - +connection_t *connection_table_allocate(const connection_table_t *table, + const address_pair_t *pair, + const char *name); /** * @brief Deallocate a connection and return it to the connection table pool. * @@ -110,26 +81,8 @@ static inline connection_t *connection_table_allocate( * - Upon returning a connection to the pool, all indices pointing to that * connection are also cleared. */ -static inline void connection_table_deallocate(const connection_table_t *table, - const connection_t *conn) { - const char *name = connection_get_name(conn); - const address_pair_t *pair = connection_get_pair(conn); - khiter_t k; - - // Remove from name hash table - k = kh_get_ct_name(table->id_by_name, name); - assert(k != kh_end(table->id_by_name)); - free((char *)kh_key(table->id_by_name, k)); - kh_del_ct_name(table->id_by_name, k); - - // Remove from pair hash table - k = kh_get_ct_pair(table->id_by_pair, pair); - assert(k != kh_end(table->id_by_pair)); - free((address_pair_t *)kh_key(table->id_by_pair, k)); - kh_del_ct_pair(table->id_by_pair, k); - - pool_put(table->connections, conn); -} +void connection_table_deallocate(const connection_table_t *table, + const connection_t *conn); /** * @brief Returns the length of the connection table, the number of active @@ -292,6 +245,7 @@ void connection_table_print_by_pair(const connection_table_t *table); void connection_table_print_by_name(const connection_table_t *table); -char *connection_table_get_random_name(const connection_table_t *table); +int connection_table_get_random_name(const connection_table_t *table, + char *name); #endif /* HICNLIGHT_CONNECTION_TABLE_H */ diff --git a/hicn-light/src/hicn/core/connection_vft.h b/hicn-light/src/hicn/core/connection_vft.h index e6290cdd4..1a6ecbb78 100644 --- a/hicn-light/src/hicn/core/connection_vft.h +++ b/hicn-light/src/hicn/core/connection_vft.h @@ -28,8 +28,8 @@ typedef struct { void (*finalize)(connection_t* connection); int (*get_socket)(const listener_t* listener, const address_t* local, const address_t* remote, const char* interface_name); - bool (*flush)(const connection_t* connection); - bool (*send)(const connection_t* connection, msgbuf_t* msgbuf, bool queue); + bool (*flush)(connection_t* connection); + bool (*send)(connection_t* connection, msgbuf_t* msgbuf, bool queue); int (*send_packet)(const connection_t* connection, const uint8_t* packet, size_t size); // void (*read_callback)(connection_t * connection, int fd, void * data); diff --git a/hicn-light/src/hicn/core/content_store.c b/hicn-light/src/hicn/core/content_store.c index edbdc5ac1..360e6d333 100644 --- a/hicn-light/src/hicn/core/content_store.c +++ b/hicn-light/src/hicn/core/content_store.c @@ -84,3 +84,5 @@ void cs_log(cs_t *cs) { cs->stats.lru.countUpdates, cs->stats.lru.countLruDeletions, cs->stats.lru.countLruEvictions); } + +cs_lru_stats_t cs_get_lru_stats(cs_t *cs) { return cs->stats.lru; } diff --git a/hicn-light/src/hicn/core/content_store.h b/hicn-light/src/hicn/core/content_store.h index d47d603be..ceaf05e6b 100644 --- a/hicn-light/src/hicn/core/content_store.h +++ b/hicn-light/src/hicn/core/content_store.h @@ -1,7 +1,7 @@ #ifndef HICNLIGHT_CS_H #define HICNLIGHT_CS_H -#include "../base/pool.h" +#include <hicn/util/pool.h> #include "../content_store/lru.h" #include "msgbuf_pool.h" @@ -103,4 +103,6 @@ void cs_miss(cs_t *cs); */ void cs_log(cs_t *cs); +cs_lru_stats_t cs_get_lru_stats(cs_t *cs); + #endif /* HICNLIGHT_CS_H */ diff --git a/hicn-light/src/hicn/core/fib_entry.c b/hicn-light/src/hicn/core/fib_entry.c index 616f12961..80d337884 100644 --- a/hicn-light/src/hicn/core/fib_entry.c +++ b/hicn-light/src/hicn/core/fib_entry.c @@ -378,7 +378,7 @@ nexthops_t *fib_entry_get_available_nexthops(fib_entry_t *entry, connection_table_foreach(table, connection, { if (connection_is_local(connection)) continue; new_nexthops->elts[nexthops_get_len(new_nexthops)] = - connection_table_get_connection_id(table, connection); + (unsigned int)connection_table_get_connection_id(table, connection); nexthops_inc(new_nexthops); }); diff --git a/hicn-light/src/hicn/core/forwarder.c b/hicn-light/src/hicn/core/forwarder.c index 37502f3ac..74be6431a 100644 --- a/hicn-light/src/hicn/core/forwarder.c +++ b/hicn-light/src/hicn/core/forwarder.c @@ -69,45 +69,9 @@ #endif /* WITH_POLICY_STATS */ #include <hicn/core/wldr.h> +#include <hicn/core/interest_manifest.h> #include <hicn/util/log.h> -typedef struct { - // Packets processed - uint32_t countReceived; // Interest and data only - uint32_t countInterestsReceived; - uint32_t countObjectsReceived; - - // Packets Dropped - uint32_t countDropped; - uint32_t countInterestsDropped; - uint32_t countObjectsDropped; - uint32_t countOtherDropped; - - // Forwarding - uint32_t countInterestForwarded; - uint32_t countObjectsForwarded; - - // Errors while forwarding - uint32_t countDroppedConnectionNotFound; - uint32_t countSendFailures; - uint32_t countDroppedNoRoute; - - // Interest processing - uint32_t countInterestsAggregated; - uint32_t countInterestsRetransmitted; - uint32_t countInterestsSatisfiedFromStore; - uint32_t countInterestsExpired; - uint32_t countDataExpired; - - // Data processing - uint32_t countDroppedNoReversePath; - - // TODO(eloparco): Currently not used - // uint32_t countDroppedNoHopLimit; - // uint32_t countDroppedZeroHopLimitFromRemote; - // uint32_t countDroppedZeroHopLimitToRemote; -} forwarder_stats_t; - struct forwarder_s { // uint16_t server_port; @@ -138,13 +102,12 @@ struct forwarder_s { * The message forwarder has to decide whether to queue incoming packets for * batching, or trigger the transmission on the connection */ - unsigned pending_conn[MAX_MSG]; - size_t num_pending_conn; - - // msgbuf_t msgbuf; /* Storage for msgbuf, which are currently processed 1 by - // 1 */ + unsigned *pending_conn; subscription_table_t *subscriptions; + + // Used to store the msgbufs that need to be released + off_t *acquired_msgbuf_ids; }; /** @@ -223,8 +186,12 @@ forwarder_t *forwarder_create(configuration_t *configuration) { #endif /* WITH_POLICY_STATS */ memset(&forwarder->stats, 0, sizeof(forwarder_stats_t)); + vector_init(forwarder->pending_conn, MAX_MSG, 0); + vector_init(forwarder->acquired_msgbuf_ids, MAX_MSG, 0); - forwarder->num_pending_conn = 0; + char *n_suffixes_per_split_str = getenv("N_SUFFIXES_PER_SPIT"); + if (n_suffixes_per_split_str) + N_SUFFIXES_PER_SPIT = atoi(n_suffixes_per_split_str); return forwarder; @@ -267,6 +234,8 @@ void forwarder_free(forwarder_t *forwarder) { listener_table_free(forwarder->listener_table); subscription_table_free(forwarder->subscriptions); configuration_free(forwarder->config); + vector_free(forwarder->pending_conn); + vector_free(forwarder->acquired_msgbuf_ids); free(forwarder); } @@ -295,6 +264,11 @@ listener_table_t *forwarder_get_listener_table(forwarder_t *forwarder) { return forwarder->listener_table; } +pkt_cache_t *forwarder_get_pkt_cache(const forwarder_t *forwarder) { + assert(forwarder); + return forwarder->pkt_cache; +} + void forwarder_cs_set_store(forwarder_t *forwarder, bool val) { assert(forwarder); forwarder->store_in_cs = val; @@ -393,7 +367,7 @@ static ssize_t forwarder_forward_via_connection(forwarder_t *forwarder, const msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); - const connection_t *conn = connection_table_get_by_id(table, conn_id); + connection_t *conn = connection_table_get_by_id(table, conn_id); if (!conn) { forwarder->stats.countDroppedConnectionNotFound++; @@ -429,12 +403,8 @@ static ssize_t forwarder_forward_via_connection(forwarder_t *forwarder, #endif /* ... and mark the connection as pending if this is not yet the case */ - unsigned i; - for (i = 0; i < forwarder->num_pending_conn; i++) { - if (forwarder->pending_conn[i] == conn_id) break; - } - if (i == forwarder->num_pending_conn) // Not found - forwarder->pending_conn[forwarder->num_pending_conn++] = conn_id; + if (!vector_contains(forwarder->pending_conn, conn_id)) + vector_push(forwarder->pending_conn, conn_id); if (!success) { forwarder->stats.countSendFailures++; @@ -457,7 +427,8 @@ static ssize_t forwarder_forward_via_connection(forwarder_t *forwarder, break; } - TRACE("forward msgbuf %p to interface %u", msgbuf, conn_id); + TRACE("forward msgbuf %p (size=%u) to interface %u", msgbuf, + msgbuf_get_len(msgbuf), conn_id); return msgbuf_get_len(msgbuf); } @@ -496,8 +467,7 @@ static unsigned forwarder_forward_to_nexthops(forwarder_t *forwarder, static bool forwarder_forward_via_fib(forwarder_t *forwarder, off_t msgbuf_id, pkt_cache_verdict_t verdict, pkt_cache_entry_t *entry) { - assert(forwarder); - assert(msgbuf_id_is_valid(msgbuf_id)); + assert(forwarder && entry && msgbuf_id_is_valid(msgbuf_id)); const msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); @@ -515,15 +485,8 @@ static bool forwarder_forward_via_fib(forwarder_t *forwarder, off_t msgbuf_id, return false; } - // if this is the first time that we sent this interest the pit entry would be - // NULL. in that case we add the interest to the pit - if (entry == NULL) { - entry = pkt_cache_add_to_pit(forwarder->pkt_cache, msgbuf); - } pit_entry_t *pit_entry = &entry->u.pit_entry; - if (!pit_entry) { - return false; - } + if (!pit_entry) return false; pit_entry_set_fib_entry(pit_entry, fib_entry); @@ -547,21 +510,19 @@ static bool forwarder_forward_via_fib(forwarder_t *forwarder, off_t msgbuf_id, #endif /* ! BYPASS_FIB */ -ssize_t _forwarder_forward_upon_interest(forwarder_t *forwarder, - msgbuf_pool_t *msgbuf_pool, - off_t data_msgbuf_id, - off_t interest_msgbuf_id, - pkt_cache_entry_t *entry, - pkt_cache_verdict_t verdict) { +int _forwarder_forward_upon_interest( + forwarder_t *forwarder, msgbuf_pool_t *msgbuf_pool, off_t data_msgbuf_id, + off_t interest_msgbuf_id, pkt_cache_entry_t *entry, + pkt_cache_verdict_t verdict, bool is_aggregated) { msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, interest_msgbuf_id); + // - Aggregation can be perfomed, do not forward if (verdict == PKT_CACHE_VERDICT_AGGREGATE_INTEREST) { - // the packet shuold not be forwarder forwarder_drop(forwarder, interest_msgbuf_id); return msgbuf_get_len(msgbuf); } - // - Forward reply if a data packet matching the interest was found + // - Data packet matching the interest was found, forward reply if (verdict == PKT_CACHE_VERDICT_FORWARD_DATA) { assert(forwarder->serve_from_cs == true); @@ -569,19 +530,26 @@ ssize_t _forwarder_forward_upon_interest(forwarder_t *forwarder, msgbuf_t *data_msgbuf = msgbuf_pool_at(msgbuf_pool, data_msgbuf_id); msgbuf_reset_pathlabel(data_msgbuf); - forwarder_forward_via_connection(forwarder, data_msgbuf_id, msgbuf_get_connection_id(interest_msgbuf)); + return msgbuf_get_len(msgbuf); + } + + // - For aggregated interest, the interest forwarding is done in + // `_forwarder_forward_aggregated_interest()` + if (is_aggregated) return msgbuf_get_len(msgbuf); - // - Try to forward the interest - } else if (!forwarder_forward_via_fib(forwarder, interest_msgbuf_id, verdict, - entry)) { + // - Try to forward the interest + int rc = + forwarder_forward_via_fib(forwarder, interest_msgbuf_id, verdict, entry); + if (!rc) { + // - Not able to forward, drop the packet forwarder->stats.countDroppedNoRoute++; INFO("Message %lu did not match FIB, no route (count %u)", interest_msgbuf_id, forwarder->stats.countDroppedNoRoute); - // - Drop the packet (no forwarding) forwarder_drop(forwarder, interest_msgbuf_id); + return -1; } return msgbuf_get_len(msgbuf); @@ -590,19 +558,12 @@ ssize_t _forwarder_forward_upon_interest(forwarder_t *forwarder, static void _forwarder_update_interest_stats(forwarder_t *forwarder, pkt_cache_verdict_t verdict, msgbuf_t *msgbuf, - pkt_cache_entry_t *entry) { - long expiration = -1; - if (entry == NULL) - expiration = ticks_now() + msgbuf_get_interest_lifetime(msgbuf); - else if (entry->has_expire_ts) - expiration = entry->expire_ts; - + bool has_expire_ts, + uint64_t expire_ts) { + long expiration = has_expire_ts ? expire_ts : -1; switch (verdict) { case PKT_CACHE_VERDICT_FORWARD_INTEREST: - DEBUG( - "Message will be added to PIT (expiration=%ld), " - "if nexthops are available", - expiration); + DEBUG("Message added to PIT (expiration=%ld)", expiration); break; case PKT_CACHE_VERDICT_AGGREGATE_INTEREST: @@ -632,7 +593,7 @@ static void _forwarder_update_interest_stats(forwarder_t *forwarder, break; case PKT_CACHE_VERDICT_ERROR: - ERROR("Inivalid packet cache content"); + ERROR("Invalid packet cache content"); break; default: @@ -640,6 +601,234 @@ static void _forwarder_update_interest_stats(forwarder_t *forwarder, } } +static interest_manifest_header_t *_forwarder_get_interest_manifest( + msgbuf_t *msgbuf) { + uint8_t *packet = msgbuf_get_packet(msgbuf); + hicn_header_t *header = (hicn_header_t *)packet; + hicn_type_t type = hicn_header_to_type(header); + + hicn_payload_type_t payload_type; + int rc = hicn_ops_vft[type.l1]->get_payload_type(type, &header->protocol, + &payload_type); + _ASSERT(rc == HICN_LIB_ERROR_NONE); + if (payload_type != HPT_MANIFEST) return NULL; + + size_t header_length, payload_length; + rc = hicn_ops_vft[type.l1]->get_header_length(type, &header->protocol, + &header_length); + assert(rc == HICN_LIB_ERROR_NONE); + + rc = hicn_ops_vft[type.l1]->get_payload_length(type, &header->protocol, + &payload_length); + assert(rc == HICN_LIB_ERROR_NONE); + + u8 *payload = (u8 *)header + header_length; + interest_manifest_header_t *int_manifest_header = + (interest_manifest_header_t *)payload; + if (!interest_manifest_is_valid(int_manifest_header, payload_length)) + return NULL; + + return int_manifest_header; +} + +// Manifest is split using splitting strategy, then every +// sub-manifest is sent using the forwarding strategy defined for the prefix +int _forwarder_forward_aggregated_interest( + forwarder_t *forwarder, interest_manifest_header_t *int_manifest_header, + int n_suffixes_to_fwd, msgbuf_t *msgbuf, off_t msgbuf_id, + pkt_cache_entry_t **entries) { + assert(msgbuf_id_is_valid(msgbuf_id) && + msgbuf_get_type(msgbuf) == MSGBUF_TYPE_INTEREST); + + fib_entry_t *fib_entry = fib_match_message(forwarder->fib, msgbuf); + if (!fib_entry) return -1; + + int n_suffixes_per_split = N_SUFFIXES_PER_SPIT; + switch (disaggregation_strategy) { + case INT_MANIFEST_SPLIT_NONE: + n_suffixes_per_split = int_manifest_header->n_suffixes + 1; + + case INT_MANIFEST_SPLIT_MAX_N_SUFFIXES: { + // Generate sub-manifests: same as original manifest, + // but different suffix in the header and different bitmap + + int total_len = 0; + // Suffixes in manifest plus the one in the header + int total_suffixes = int_manifest_header->n_suffixes + 1; + + // Save copy of original bitmap to use as a reference + // to generate bitmaps for sub-manifests + u32 original_bitmap[BITMAP_SIZE] = {0}; + memcpy(&original_bitmap, int_manifest_header->request_bitmap, + BITMAP_SIZE * sizeof(u32)); + + int suffix_index = 0; // Position of suffix in initial manifest + while (suffix_index < total_suffixes) { + // If more than one sub-manifest, + // clone original interest manifest and update suffix + if (suffix_index > 0) { + msgbuf_t *clone; + off_t clone_id = + msgbuf_pool_clone(forwarder->msgbuf_pool, &clone, msgbuf_id); + msgbuf_pool_acquire(clone); + forwarder_acquired_msgbuf_ids_push(forwarder, clone_id); + + msgbuf_id = clone_id; + msgbuf = clone; + } + + u32 curr_bitmap[BITMAP_SIZE] = {0}; + int first_suffix_index_in_submanifest = suffix_index; + suffix_index = interest_manifest_update_bitmap( + original_bitmap, curr_bitmap, suffix_index, total_suffixes, + n_suffixes_per_split); + int first_suffix_index_in_next_submanifest = suffix_index; + + // Update manifest bitmap in current msgbuf + interest_manifest_header_t *manifest = + _forwarder_get_interest_manifest(msgbuf); + assert(manifest != NULL); + memcpy(manifest->request_bitmap, curr_bitmap, + BITMAP_SIZE * sizeof(u32)); + WITH_TRACE({ + bitmap_print(manifest->request_bitmap, BITMAP_SIZE); + printf("\n"); + }); + + // Update PIT entries for suffixes in current sub-manifest + nexthops_t *nexthops = + fib_entry_get_nexthops_from_strategy(fib_entry, msgbuf, false); + if (nexthops_get_curlen(nexthops) == 0) return -1; + + for (int i = first_suffix_index_in_submanifest; + i < first_suffix_index_in_next_submanifest; i++) { + if (!is_bit_set(manifest->request_bitmap, i)) continue; + + pit_entry_t *pit_entry = &(entries[i]->u.pit_entry); + if (!pit_entry) return -1; + + pit_entry_set_fib_entry(pit_entry, fib_entry); + unsigned nexthop; + nexthops_foreach(nexthops, nexthop, + { pit_entry_egress_add(pit_entry, nexthop); }); + } + + if (forwarder_forward_to_nexthops(forwarder, msgbuf_id, nexthops) <= + 0) { + ERROR("Message %p returned an empty next hop set", msgbuf); + continue; + } + + total_len += msgbuf_get_len(msgbuf); + } + + return total_len; + } + + default: + return -1; + } +} + +static ssize_t forwarder_process_single_interest(forwarder_t *forwarder, + msgbuf_pool_t *msgbuf_pool, + msgbuf_t *msgbuf, + off_t msgbuf_id) { + pkt_cache_verdict_t verdict = PKT_CACHE_VERDICT_ERROR; + off_t data_msgbuf_id = INVALID_MSGBUF_ID; + pkt_cache_entry_t *entry = NULL; + + // Update packet cache + pkt_cache_on_interest(forwarder->pkt_cache, msgbuf_pool, msgbuf_id, &verdict, + &data_msgbuf_id, &entry, msgbuf_get_name(msgbuf), + forwarder->serve_from_cs); + _forwarder_update_interest_stats(forwarder, verdict, msgbuf, + entry->has_expire_ts, entry->expire_ts); + + int rc = _forwarder_forward_upon_interest( + forwarder, msgbuf_pool, data_msgbuf_id, msgbuf_id, entry, verdict, false); + + // No route when trying to forward interest, remove from PIT + if (rc == -1) + pkt_cache_pit_remove_entry(forwarder->pkt_cache, entry, + msgbuf_get_name(msgbuf)); + + return msgbuf_get_len(msgbuf); +} + +static ssize_t forwarder_process_aggregated_interest( + forwarder_t *forwarder, interest_manifest_header_t *int_manifest_header, + msgbuf_pool_t *msgbuf_pool, msgbuf_t *msgbuf, off_t msgbuf_id) { + pkt_cache_verdict_t verdict = PKT_CACHE_VERDICT_ERROR; + off_t data_msgbuf_id = INVALID_MSGBUF_ID; + pkt_cache_entry_t *entry = NULL; + // Save PIT entries to avoid re-doing pkt cache lookup in + // `_forwarder_forward_aggregated_interest()` + pkt_cache_entry_t *entries[BITMAP_SIZE * WORD_WIDTH]; + + int pos = 0; // Position of current suffix in manifest + int n_suffixes_to_fwd = 0; + u32 *suffix = (u32 *)(int_manifest_header + 1); + u32 seq = name_GetSegment(msgbuf_get_name(msgbuf)); + + Name name_copy = EMPTY_NAME; + name_Copy(msgbuf_get_name(msgbuf), &name_copy); + + // The fist loop iteration handles the suffix in the header, + // the following ones handle the suffiexes in the manifest + while (true) { + if (!is_bit_set(int_manifest_header->request_bitmap, pos)) goto NEXT_SUFFIX; + + // Update packet cache + pkt_cache_on_interest(forwarder->pkt_cache, msgbuf_pool, msgbuf_id, + &verdict, &data_msgbuf_id, &entry, &name_copy, + forwarder->serve_from_cs); + entries[pos] = entry; + _forwarder_update_interest_stats(forwarder, verdict, msgbuf, + entry->has_expire_ts, entry->expire_ts); + + // Here only data forwarding is performed, interest forwarding is done + // in '_forwarder_forward_aggregated_interest()' + int rc = + _forwarder_forward_upon_interest(forwarder, msgbuf_pool, data_msgbuf_id, + msgbuf_id, entry, verdict, true); + + // No route when trying to forward interest, remove from PIT + if (rc == -1) + pkt_cache_pit_remove_entry(forwarder->pkt_cache, entry, &name_copy); + + // Unset in bitmap if no interest forwarding needed, + // otherwise increase count of suffixes to forward + if (rc == -1 || verdict == PKT_CACHE_VERDICT_AGGREGATE_INTEREST || + verdict == PKT_CACHE_VERDICT_FORWARD_DATA) { + unset_bit(int_manifest_header->request_bitmap, pos); + } else { + n_suffixes_to_fwd++; + } + + NEXT_SUFFIX: + if (pos++ >= int_manifest_header->n_suffixes) break; + + // Use next segment in manifest + seq = *suffix; + suffix++; + name_SetSegment(&name_copy, seq); + + WITH_DEBUG({ + char *nameString = name_ToString(&name_copy); + DEBUG("Next in manifest: %s", nameString); + free(nameString); + }); + } + + // Return if nothing in the manifest to forward + if (n_suffixes_to_fwd == 0) return msgbuf_get_len(msgbuf); + + return _forwarder_forward_aggregated_interest(forwarder, int_manifest_header, + n_suffixes_to_fwd, msgbuf, + msgbuf_id, entries); +} + /** * @function forwarder_process_interest * @abstract Receive an interest from the network @@ -657,29 +846,39 @@ static ssize_t forwarder_process_interest(forwarder_t *forwarder, msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); + const connection_table_t *table = forwarder_get_connection_table(forwarder); + connection_t *conn = + connection_table_get_by_id(table, msgbuf_get_connection_id(msgbuf)); assert(msgbuf_get_type(msgbuf) == MSGBUF_TYPE_INTEREST); - forwarder->stats.countReceived++; + u32 n_suffixes = 0; + interest_manifest_header_t *int_manifest_header = + _forwarder_get_interest_manifest(msgbuf); + if (int_manifest_header) n_suffixes = int_manifest_header->n_suffixes; + + // Update stats forwarder->stats.countInterestsReceived++; + conn->stats.interests.rx_pkts++; + conn->stats.interests.rx_bytes += msgbuf_get_len(msgbuf); WITH_DEBUG({ char *nameString = name_ToString(msgbuf_get_name(msgbuf)); - DEBUG("INTEREST (%s) msgbuf_id=%lu ingress=%u length=%u", nameString, - msgbuf_id, msgbuf_get_connection_id(msgbuf), msgbuf_get_len(msgbuf)); + DEBUG("INTEREST (%s) suffixes=%u msgbuf_id=%lu ingress=%u length=%u", + nameString, n_suffixes, msgbuf_id, msgbuf_get_connection_id(msgbuf), + msgbuf_get_len(msgbuf)); free(nameString); - }) - - pkt_cache_verdict_t verdict = PKT_CACHE_VERDICT_ERROR; - off_t data_msgbuf_id = INVALID_MSGBUF_ID; - pkt_cache_entry_t *entry = NULL; - pkt_cache_on_interest(forwarder->pkt_cache, msgbuf_pool, msgbuf_id, &verdict, - &data_msgbuf_id, &entry, forwarder->serve_from_cs); + }); - _forwarder_update_interest_stats(forwarder, verdict, msgbuf, entry); + // Cache suffixes for current prefix to (possibly) avoid double lookups + pkt_cache_save_suffixes_for_prefix( + forwarder->pkt_cache, name_GetContentName(msgbuf_get_name(msgbuf))); - return _forwarder_forward_upon_interest( - forwarder, msgbuf_pool, data_msgbuf_id, msgbuf_id, entry, verdict); + if (!int_manifest_header) + return forwarder_process_single_interest(forwarder, msgbuf_pool, msgbuf, + msgbuf_id); + return forwarder_process_aggregated_interest(forwarder, int_manifest_header, + msgbuf_pool, msgbuf, msgbuf_id); } static void _forwarder_log_on_data(forwarder_t *forwarder, @@ -700,7 +899,7 @@ static void _forwarder_log_on_data(forwarder_t *forwarder, DEBUG("Message not stored in CS"); break; case PKT_CACHE_VERDICT_ERROR: - ERROR("Inivalid packet cache content"); + ERROR("Invalid packet cache content"); break; default: break; @@ -726,24 +925,31 @@ static ssize_t forwarder_process_data(forwarder_t *forwarder, off_t msgbuf_id) { DEBUG("DATA (%s) msgbuf_id=%lu ingress=%u length=%u", nameString, msgbuf_id, msgbuf_get_connection_id(msgbuf), msgbuf_get_len(msgbuf)); free(nameString); - )} - - forwarder->stats.countReceived++; - forwarder->stats.countObjectsReceived++; + }); const connection_table_t *table = forwarder_get_connection_table(forwarder); - const connection_t *conn = + connection_t *conn = connection_table_get_by_id(table, msgbuf_get_connection_id(msgbuf)); + // Update stats + forwarder->stats.countObjectsReceived++; + conn->stats.data.rx_pkts++; + conn->stats.data.rx_bytes += msgbuf_get_len(msgbuf); + + // Cache suffixes for current prefix to (possibly) avoid double lookups + pkt_cache_save_suffixes_for_prefix( + forwarder->pkt_cache, name_GetContentName(msgbuf_get_name(msgbuf))); + pkt_cache_verdict_t verdict = PKT_CACHE_VERDICT_ERROR; bool wrong_egress; - nexthops_t *ingressSetUnion = - pkt_cache_on_data(forwarder->pkt_cache, msgbuf_pool, msgbuf_id, - forwarder->store_in_cs, connection_is_local(conn), &wrong_egress, &verdict); + nexthops_t *ingressSetUnion = pkt_cache_on_data( + forwarder->pkt_cache, msgbuf_pool, msgbuf_id, forwarder->store_in_cs, + connection_is_local(conn), &wrong_egress, &verdict); _forwarder_log_on_data(forwarder, verdict); - if (wrong_egress) { // Interest sent via a connection but received from another + if (wrong_egress) { // Interest sent via a connection but received from + // another WARN("Data coming from unexpected connection, discarded"); } else if (!ingressSetUnion) { // No match in the PIT forwarder->stats.countDroppedNoReversePath++; @@ -776,15 +982,15 @@ void forwarder_flush_connections(forwarder_t *forwarder) { // DEBUG("[forwarder_flush_connections]"); const connection_table_t *table = forwarder_get_connection_table(forwarder); - for (unsigned i = 0; i < forwarder->num_pending_conn; i++) { + for (unsigned i = 0; i < vector_len(forwarder->pending_conn); i++) { unsigned conn_id = forwarder->pending_conn[i]; - const connection_t *conn = connection_table_at(table, conn_id); + connection_t *conn = connection_table_at(table, conn_id); if (!connection_flush(conn)) { WARN("Could not flush connection queue"); // XXX keep track of non flushed connections... } } - forwarder->num_pending_conn = 0; + vector_reset(forwarder->pending_conn); // DEBUG("[forwarder_flush_connections] done"); } @@ -957,6 +1163,23 @@ cs_t *forwarder_get_cs(const forwarder_t *forwarder) { return pkt_cache_get_cs(forwarder->pkt_cache); } +// IMPORTANT: Use this function ONLY for read-only operations since a realloc +// would otherwise modify the returned copy but not the original msgbuf ids +// vector in the forwarder. This constraint cannot be enforced by returning a +// (const off_t *) because the vector_t macros still cast to (void **). +off_t *forwarder_get_acquired_msgbuf_ids(const forwarder_t *forwarder) { + return forwarder->acquired_msgbuf_ids; +} + +void forwarder_acquired_msgbuf_ids_reset(const forwarder_t *forwarder) { + vector_reset(forwarder->acquired_msgbuf_ids); +} + +void forwarder_acquired_msgbuf_ids_push(const forwarder_t *forwarder, + off_t msgbuf_id) { + vector_push(forwarder->acquired_msgbuf_ids, msgbuf_id); +} + // ======================================================= fib_t *forwarder_get_fib(forwarder_t *forwarder) { return forwarder->fib; } @@ -1052,14 +1275,15 @@ ssize_t forwarder_receive(forwarder_t *forwarder, listener_t *listener, const connection_table_t *table = forwarder_get_connection_table(listener->forwarder); connection_t *connection = connection_table_get_by_pair(table, pair); - unsigned conn_id = connection - ? connection_table_get_connection_id(table, connection) - : CONNECTION_ID_UNDEFINED; + unsigned conn_id = connection ? (unsigned)connection_table_get_connection_id( + table, connection) + : CONNECTION_ID_UNDEFINED; assert((conn_id != CONNECTION_ID_UNDEFINED) || listener); msgbuf_type_t type = get_type_from_packet(msgbuf_get_packet(msgbuf)); + forwarder->stats.countReceived++; msgbuf->type = type; msgbuf->connection_id = conn_id; msgbuf->recv_ts = now; @@ -1067,12 +1291,14 @@ ssize_t forwarder_receive(forwarder_t *forwarder, listener_t *listener, switch (type) { case MSGBUF_TYPE_INTEREST: if (!connection_id_is_valid(msgbuf->connection_id)) { - char *conn_name = connection_table_get_random_name(table); + char conn_name[SYMBOLIC_NAME_LEN]; + int rc = connection_table_get_random_name(table, conn_name); + if (rc < 0) return 0; + unsigned connection_id = listener_create_connection(listener, conn_name, pair); msgbuf->connection_id = connection_id; connection = connection_table_get_by_id(table, connection_id); - free(conn_name); } msgbuf->path_label = 0; // not used for interest packets name_create_from_interest(packet, msgbuf_get_name(msgbuf)); @@ -1102,10 +1328,12 @@ ssize_t forwarder_receive(forwarder_t *forwarder, listener_t *listener, case MSGBUF_TYPE_MAPME: // XXX what about acks ? if (!connection_id_is_valid(msgbuf->connection_id)) { - char *conn_name = connection_table_get_random_name(table); + char conn_name[SYMBOLIC_NAME_LEN]; + int rc = connection_table_get_random_name(table, conn_name); + if (rc < 0) return 0; + msgbuf->connection_id = listener_create_connection(listener, conn_name, pair); - free(conn_name); } mapme_process(forwarder->mapme, msgbuf); return size; @@ -1113,12 +1341,14 @@ ssize_t forwarder_receive(forwarder_t *forwarder, listener_t *listener, case MSGBUF_TYPE_COMMAND: // Create the connection to send the ack back if (!connection_id_is_valid(msgbuf->connection_id)) { - char *conn_name = connection_table_get_random_name(table); + char conn_name[SYMBOLIC_NAME_LEN]; + int rc = connection_table_get_random_name(table, conn_name); + if (rc < 0) return 0; + unsigned connection_id = listener_create_connection(listener, conn_name, pair); msgbuf->connection_id = connection_id; connection = connection_table_get_by_id(table, connection_id); - free(conn_name); } msg_header_t *msg = (msg_header_t *)packet; @@ -1163,3 +1393,7 @@ void forwarder_log(forwarder_t *forwarder) { forwarder->stats.countInterestsExpired, forwarder->stats.countDataExpired, forwarder->stats.countDroppedNoReversePath); } + +forwarder_stats_t forwarder_get_stats(forwarder_t *forwarder) { + return forwarder->stats; +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/core/forwarder.h b/hicn-light/src/hicn/core/forwarder.h index 76c12368a..2f940cf15 100644 --- a/hicn-light/src/hicn/core/forwarder.h +++ b/hicn-light/src/hicn/core/forwarder.h @@ -98,6 +98,8 @@ listener_table_t *forwarder_get_listener_table(forwarder_t *forwarder); connection_table_t *forwarder_get_connection_table( const forwarder_t *forwarder); +pkt_cache_t *forwarder_get_pkt_cache(const forwarder_t *forwarder); + void forwarder_cs_set_store(forwarder_t *forwarder, bool val); bool forwarder_cs_get_store(forwarder_t *forwarder); @@ -159,6 +161,18 @@ void forwarder_set_strategy(forwarder_t *forwarder, Name *name_prefix, cs_t *forwarder_get_cs(const forwarder_t *forwarder); +off_t *forwarder_get_acquired_msgbuf_ids(const forwarder_t *forwarder); + +/** + * @note Acquire msgbuf ids vector ONLY for read-only operations. + */ +off_t *forwarder_get_acquired_msgbuf_ids(const forwarder_t *forwarder); + +void forwarder_acquired_msgbuf_ids_reset(const forwarder_t *forwarder); + +void forwarder_acquired_msgbuf_ids_push(const forwarder_t *forwarder, + off_t msgbuf_id); + /** * @brief Returns the forwarder's FIB. * @param[in] forwarder - Pointer to the forwarder. @@ -226,4 +240,6 @@ ssize_t forwarder_receive(forwarder_t *forwarder, listener_t *listener, */ void forwarder_log(forwarder_t *forwarder); +forwarder_stats_t forwarder_get_stats(forwarder_t *forwarder); + #endif // HICNLIGHT_FORWARDER_H diff --git a/hicn-light/src/hicn/core/interest_manifest.c b/hicn-light/src/hicn/core/interest_manifest.c new file mode 100644 index 000000000..1be8a3fb5 --- /dev/null +++ b/hicn-light/src/hicn/core/interest_manifest.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "interest_manifest.h" + +int_manifest_split_strategy_t disaggregation_strategy = + INT_MANIFEST_SPLIT_MAX_N_SUFFIXES; +unsigned N_SUFFIXES_PER_SPIT = 256; + +bool interest_manifest_is_valid(interest_manifest_header_t *int_manifest_header, + size_t payload_length) { + if (int_manifest_header->n_suffixes == 0 || + int_manifest_header->n_suffixes > MAX_SUFFIXES_IN_MANIFEST) { + ERROR("Manifest with invalid number of suffixes (%d)", + int_manifest_header->n_suffixes); + return false; + } + + uint32_t empty_bitmap[BITMAP_SIZE] = {0}; + if (memcmp(empty_bitmap, int_manifest_header->request_bitmap, + sizeof(empty_bitmap)) == 0) { + ERROR("Manifest with empty bitmap"); + return false; + } + + if (payload_length - sizeof(interest_manifest_header_t) != + int_manifest_header->n_suffixes * sizeof(u32)) { + ERROR("Size of suffixes in intereset manifest (%d) is not equal to %d", + payload_length - sizeof(interest_manifest_header_t), + int_manifest_header->n_suffixes * sizeof(u32)); + return false; + } + + return true; +} + +int interest_manifest_update_bitmap(const u32 *initial_bitmap, + u32 *bitmap_to_update, int start, int n, + int max_suffixes) { + int i = start, n_ones = 0; + while (i < n) { + if (is_bit_set(initial_bitmap, i)) { + set_bit(bitmap_to_update, i); + n_ones++; + } + i++; + + if (n_ones == max_suffixes) break; + } + + return i; +} diff --git a/hicn-light/src/hicn/core/interest_manifest.h b/hicn-light/src/hicn/core/interest_manifest.h new file mode 100644 index 000000000..fcb2b9897 --- /dev/null +++ b/hicn-light/src/hicn/core/interest_manifest.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HICNLIGHT_INTEREST_MANIFEST_H +#define HICNLIGHT_INTEREST_MANIFEST_H + +#include <string.h> +#include <stdbool.h> + +#include <hicn/util/log.h> +#include <hicn/base.h> + +typedef enum { + INT_MANIFEST_SPLIT_NONE, + INT_MANIFEST_SPLIT_MAX_N_SUFFIXES +} int_manifest_split_strategy_t; + +extern int_manifest_split_strategy_t disaggregation_strategy; +extern unsigned N_SUFFIXES_PER_SPIT; + +bool interest_manifest_is_valid(interest_manifest_header_t *int_manifest_header, + size_t payload_length); + +int interest_manifest_update_bitmap(const u32 *initial_bitmap, + u32 *bitmap_to_update, int start, int n, + int max_suffixes); + +#endif /* HICNLIGHT_INTEREST_MANIFEST_H */ diff --git a/hicn-light/src/hicn/core/listener.c b/hicn-light/src/hicn/core/listener.c index ecdfc38f4..188f0c317 100644 --- a/hicn-light/src/hicn/core/listener.c +++ b/hicn-light/src/hicn/core/listener.c @@ -24,7 +24,6 @@ #include "forwarder.h" #include "listener_vft.h" -#include "../base/loop.h" #include "../io/base.h" listener_key_t listener_key_factory(address_t address, face_type_t type) { @@ -44,7 +43,8 @@ listener_t *listener_create(face_type_t type, const address_t *address, listener_key_t key = listener_key_factory(*address, type); listener_t *listener = listener_table_allocate(table, &key, name); - unsigned listener_id = listener_table_get_listener_id(table, listener); + unsigned listener_id = + (unsigned int)listener_table_get_listener_id(table, listener); int ret = listener_initialize(listener, type, name, listener_id, address, interface_name, forwarder); @@ -194,7 +194,7 @@ unsigned listener_create_connection(listener_t *listener, connection_t *connection = connection_table_allocate(table, pair, connection_name); unsigned connection_id = - connection_table_get_connection_id(table, connection); + (unsigned int)connection_table_get_connection_id(table, connection); /* * We create a connected connection with its own fd, instead of returning @@ -337,11 +337,10 @@ ssize_t listener_read_batch(listener_t *listener, int fd) { size_t total_processed_bytes = 0; ssize_t num_msg_received = 0; - off_t *acquired_msgbuf_ids; - vector_init(acquired_msgbuf_ids, MAX_MSG, 0); forwarder_t *forwarder = listener->forwarder; msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); + forwarder_acquired_msgbuf_ids_reset(forwarder); /* Receive messages in the loop as long as we manage to fill the buffers */ do { @@ -381,7 +380,7 @@ ssize_t listener_read_batch(listener_t *listener, int fd) { } msgbuf_pool_acquire(msgbufs[i]); - vector_push(acquired_msgbuf_ids, msgbuf_ids[i]); + forwarder_acquired_msgbuf_ids_push(forwarder, msgbuf_ids[i]); } if (num_msg_received < 0) break; @@ -403,11 +402,12 @@ ssize_t listener_read_batch(listener_t *listener, int fd) { */ forwarder_flush_connections(forwarder); + const off_t *acquired_msgbuf_ids = + forwarder_get_acquired_msgbuf_ids(forwarder); for (int i = 0; i < vector_len(acquired_msgbuf_ids); i++) { msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, acquired_msgbuf_ids[i]); msgbuf_pool_release(msgbuf_pool, &msgbuf); } - vector_free(acquired_msgbuf_ids); return total_processed_bytes; } diff --git a/hicn-light/src/hicn/core/listener.h b/hicn-light/src/hicn/core/listener.h index 346c874c0..5d0384329 100644 --- a/hicn-light/src/hicn/core/listener.h +++ b/hicn-light/src/hicn/core/listener.h @@ -25,7 +25,7 @@ #include "address_pair.h" #include "msgbuf.h" -#include "../base/loop.h" +#include <hicn/base/loop.h> #define LISTENER_ID_UNDEFINED ~0 @@ -36,6 +36,12 @@ typedef struct { face_type_t type; } listener_key_t; +static inline int listener_key_equals(const listener_key_t *key1, + const listener_key_t *key2) { + return address_equals(&key1->address, &key2->address) && + (key1->type == key2->type); +} + /** * @brief Create a listener key starting from an address and a face type. * diff --git a/hicn-light/src/hicn/core/listener_table.c b/hicn-light/src/hicn/core/listener_table.c index 32b8e9d45..220b738bb 100644 --- a/hicn-light/src/hicn/core/listener_table.c +++ b/hicn-light/src/hicn/core/listener_table.c @@ -72,6 +72,54 @@ void listener_table_free(listener_table_t *table) { free(table); } +listener_t *listener_table_allocate(const listener_table_t *table, + const listener_key_t *key, + const char *name) { + listener_t *listener = NULL; + pool_get(table->listeners, listener); + if (!listener) return NULL; + + off_t id = listener - table->listeners; + int rc; + + // Add in name hash table + khiter_t k = kh_put_lt_name(table->id_by_name, strdup(name), &rc); + assert(rc == KH_ADDED || rc == KH_RESET); + kh_value(table->id_by_name, k) = (unsigned int)id; + + // Add in key hash table + listener_key_t *key_copy = (listener_key_t *)malloc(sizeof(listener_key_t)); + memcpy(key_copy, key, sizeof(listener_key_t)); + + k = kh_put_lt_key(table->id_by_key, key_copy, &rc); + assert(rc == KH_ADDED || rc == KH_RESET); + kh_value(table->id_by_key, k) = (unsigned int)id; + + assert(kh_size(table->id_by_name) == kh_size(table->id_by_key)); + return listener; +} + +void listener_table_deallocate(const listener_table_t *table, + listener_t *listener) { + const char *name = listener_get_name(listener); + listener_key_t *key = listener_get_key(listener); + + // Remove from name hash table + khiter_t k = kh_get_lt_name(table->id_by_name, name); + assert(k != kh_end(table->id_by_name)); + free((char *)kh_key(table->id_by_name, k)); + kh_del_lt_name(table->id_by_name, k); + + // Remove from key hash table + k = kh_get_lt_key(table->id_by_key, key); + assert(k != kh_end(table->id_by_key)); + free((listener_key_t *)kh_key(table->id_by_key, k)); + kh_del_lt_key(table->id_by_key, k); + + assert(kh_size(table->id_by_name) == kh_size(table->id_by_key)); + pool_put(table->listeners, listener); +} + listener_t *listener_table_get_by_address(listener_table_t *table, face_type_t type, const address_t *address) { @@ -104,7 +152,8 @@ off_t listener_table_get_id_by_name(const listener_table_t *table, listener_t *listener_table_get_by_name(listener_table_t *table, const char *name) { - unsigned listener_id = listener_table_get_id_by_name(table, name); + unsigned listener_id = + (unsigned int)listener_table_get_id_by_name(table, name); if (!listener_id_is_valid(listener_id)) return NULL; return listener_table_at(table, listener_id); } diff --git a/hicn-light/src/hicn/core/listener_table.h b/hicn-light/src/hicn/core/listener_table.h index 5fed638e8..7e2e99d7f 100644 --- a/hicn-light/src/hicn/core/listener_table.h +++ b/hicn-light/src/hicn/core/listener_table.h @@ -30,22 +30,19 @@ #ifndef HICNLIGHT_LISTENER_TABLE_H #define HICNLIGHT_LISTENER_TABLE_H +#include <hicn/util/khash.h> +#include <hicn/util/hash.h> #include "address.h" #include "listener.h" -#include "../base/common.h" -#include "../base/hash.h" -#include "../base/khash.h" -#include "../base/pool.h" - -#define _lt_var(x) _lt_var_##x +#include <hicn/util/pool.h> /* Hash functions for indices */ #define key_hash(key) (hash_struct(key)) -#define key_hash_eq(a, b) (key_hash(b) == key_hash(a)) /* Hash table types for indices */ KHASH_MAP_INIT_STR(lt_name, unsigned); -KHASH_INIT(lt_key, const listener_key_t *, unsigned, 1, key_hash, key_hash_eq); +KHASH_INIT(lt_key, const listener_key_t *, unsigned, 1, key_hash, + listener_key_equals); typedef struct { size_t max_size; @@ -70,34 +67,9 @@ typedef struct { * - You should always check that the returned listener is not NULL, which * would signal that the pool is exhausted and could not be extended. */ - -static inline listener_t *listener_table_allocate(const listener_table_t *table, - const listener_key_t *key, - const char *name) { - listener_t *listener; - pool_get(table->listeners, listener); - - if (listener) { - off_t id = listener - table->listeners; - int res; - khiter_t k; - - // Add in name hash table - k = kh_put_lt_name(table->id_by_name, strdup(name), &res); - assert(res > 0); - kh_value(table->id_by_name, k) = id; - - // Add in key hash table - listener_key_t *key_copy = (listener_key_t *)malloc(sizeof(listener_key_t)); - memcpy(key_copy, key, sizeof(listener_key_t)); - - k = kh_put_lt_key(table->id_by_key, key_copy, &res); - assert(res > 0); - kh_value(table->id_by_key, k) = id; - } - - return listener; -} +listener_t *listener_table_allocate(const listener_table_t *table, + const listener_key_t *key, + const char *name); /** * @brief Deallocate a listener and return it to the listener table pool. @@ -109,27 +81,8 @@ static inline listener_t *listener_table_allocate(const listener_table_t *table, * - Upon returning a listener to the pool, all indices pointing to that * listener are also cleared. */ - -static inline void listener_table_deallocate(const listener_table_t *table, - listener_t *listener) { - const char *name = listener_get_name(listener); - listener_key_t *key = listener_get_key(listener); - khiter_t k; - - // Remove from name hash table - k = kh_get_lt_name(table->id_by_name, name); - assert(k != kh_end(table->id_by_name)); - free((char *)kh_key(table->id_by_name, k)); - kh_del_lt_name(table->id_by_name, k); - - // Remove from key hash table - k = kh_get_lt_key(table->id_by_key, key); - assert(k != kh_end(table->id_by_key)); - free((listener_key_t *)kh_key(table->id_by_key, k)); - kh_del_lt_key(table->id_by_key, k); - - pool_put(table->listeners, listener); -} +void listener_table_deallocate(const listener_table_t *table, + listener_t *listener); /** * @brief Returns the length of the listener table, the number of active diff --git a/hicn-light/src/hicn/core/msgbuf_pool.c b/hicn-light/src/hicn/core/msgbuf_pool.c index fb5d0a07c..a2092aaf6 100644 --- a/hicn-light/src/hicn/core/msgbuf_pool.c +++ b/hicn-light/src/hicn/core/msgbuf_pool.c @@ -18,9 +18,8 @@ * @brief Implementation of hICN packet pool. */ -#include "../base/pool.h" +#include <hicn/util/pool.h> #include "msgbuf_pool.h" -#include "../core/name.h" // name_Release msgbuf_pool_t *_msgbuf_pool_create(size_t init_size, size_t max_size) { msgbuf_pool_t *msgbuf_pool = malloc(sizeof(msgbuf_pool_t)); @@ -38,7 +37,9 @@ void msgbuf_pool_free(msgbuf_pool_t *msgbuf_pool) { } off_t msgbuf_pool_get(msgbuf_pool_t *msgbuf_pool, msgbuf_t **msgbuf) { - return pool_get(msgbuf_pool->buffers, *msgbuf); + off_t id = pool_get(msgbuf_pool->buffers, *msgbuf); + (*msgbuf)->refs = 0; + return id; } void msgbuf_pool_put(msgbuf_pool_t *msgbuf_pool, msgbuf_t *msgbuf) { diff --git a/hicn-light/src/hicn/core/name.c b/hicn-light/src/hicn/core/name.c index 8886cc929..d30cebefc 100644 --- a/hicn-light/src/hicn/core/name.c +++ b/hicn-light/src/hicn/core/name.c @@ -20,11 +20,10 @@ #include <stdio.h> #include <string.h> -#include <hicn/common.h> // cumulative_hash32 #include <hicn/core/messageHandler.h> #include <hicn/core/name.h> #include <hicn/util/log.h> -#include <hicn/base/hash.h> +#include <hicn/util/hash.h> #define IPv6_TYPE 6 #define IPv4_TYPE 4 diff --git a/hicn-light/src/hicn/core/nameBitvector.c b/hicn-light/src/hicn/core/nameBitvector.c index 1314671db..aa431879c 100644 --- a/hicn-light/src/hicn/core/nameBitvector.c +++ b/hicn-light/src/hicn/core/nameBitvector.c @@ -20,7 +20,7 @@ #include <hicn/core/messageHandler.h> #include <hicn/core/nameBitvector.h> -#include <hicn/base/hash.h> +#include <hicn/util/hash.h> #include <hicn/ctrl/hicn-light-ng.h> #define DEFAULT_PORT 1234 diff --git a/hicn-light/src/hicn/core/nameBitvector.h b/hicn-light/src/hicn/core/nameBitvector.h index e3cc108ac..549b26679 100644 --- a/hicn-light/src/hicn/core/nameBitvector.h +++ b/hicn-light/src/hicn/core/nameBitvector.h @@ -23,11 +23,13 @@ #include "address.h" #define NAME_LEN 2 -typedef struct { +typedef struct __attribute__((__packed__)) { uint64_t bits[NAME_LEN]; - uint8_t len; - uint8_t IPversion; + uint32_t len; + uint32_t IPversion; } NameBitvector; +static_assert(sizeof(NameBitvector) == 24, + "Name prefix should be stored on 24 bytes"); #define EMPTY_NAME_BITVECTOR \ (NameBitvector) { .bits[0] = 0, .bits[1] = 0, .len = 0, .IPversion = 0, } diff --git a/hicn-light/src/hicn/core/packet_cache.c b/hicn-light/src/hicn/core/packet_cache.c index 203ad4a63..8bd188c8b 100644 --- a/hicn-light/src/hicn/core/packet_cache.c +++ b/hicn-light/src/hicn/core/packet_cache.c @@ -20,6 +20,111 @@ #include "packet_cache.h" +/****************************************************************************** + * Low-level operations on the hash table + ******************************************************************************/ + +void _prefix_map_free(kh_pkt_cache_prefix_t *prefix_to_suffixes) { + const NameBitvector *key; + kh_pkt_cache_suffix_t *value; + kh_foreach(prefix_to_suffixes, key, value, { + free((NameBitvector *)key); + kh_destroy_pkt_cache_suffix(value); + }); + kh_destroy_pkt_cache_prefix(prefix_to_suffixes); +} + +kh_pkt_cache_suffix_t *_get_suffixes(kh_pkt_cache_prefix_t *prefix_to_suffixes, + const NameBitvector *prefix) { + khiter_t k = kh_get_pkt_cache_prefix(prefix_to_suffixes, prefix); + + // Return suffixes found + if (k != kh_end(prefix_to_suffixes)) { + kh_pkt_cache_suffix_t *suffixes = kh_val(prefix_to_suffixes, k); + return suffixes; + } + + kh_pkt_cache_suffix_t *suffixes = kh_init_pkt_cache_suffix(); + NameBitvector *nb_copy = (NameBitvector *)malloc(sizeof(NameBitvector)); + *nb_copy = *prefix; + + int rc; + k = kh_put_pkt_cache_prefix(prefix_to_suffixes, nb_copy, &rc); + assert(rc == KH_ADDED || rc == KH_RESET); + kh_value(prefix_to_suffixes, k) = suffixes; + return suffixes; +} + +void _remove_suffix(kh_pkt_cache_prefix_t *prefixes, + const NameBitvector *prefix, uint32_t suffix) { + kh_pkt_cache_suffix_t *suffixes = _get_suffixes(prefixes, prefix); + assert(suffixes != NULL); + + khiter_t k = kh_get_pkt_cache_suffix(suffixes, suffix); + assert(k != kh_end(suffixes)); + kh_del_pkt_cache_suffix(suffixes, k); + + // TODO(eloparco): Remove prefix if no associated suffixes? +} + +void __add_suffix(kh_pkt_cache_suffix_t *suffixes, uint32_t suffix, + unsigned val) { + int rc; + khiter_t k = kh_put_pkt_cache_suffix(suffixes, suffix, &rc); + assert(rc == KH_ADDED || rc == KH_RESET); + kh_value(suffixes, k) = val; +} + +void _add_suffix(kh_pkt_cache_prefix_t *prefixes, const NameBitvector *prefix, + uint32_t suffix, unsigned val) { + kh_pkt_cache_suffix_t *suffixes = _get_suffixes(prefixes, prefix); + assert(suffixes != NULL); + + __add_suffix(suffixes, suffix, val); +} + +unsigned __get_suffix(kh_pkt_cache_suffix_t *suffixes, uint32_t suffix, + int *rc) { + *rc = KH_FOUND; + khiter_t k = kh_get_pkt_cache_suffix(suffixes, suffix); + + // Not Found + if (k == kh_end(suffixes)) { + *rc = KH_NOT_FOUND; + return -1; + } + + unsigned index = kh_val(suffixes, k); + return index; +} + +void pkt_cache_save_suffixes_for_prefix(pkt_cache_t *pkt_cache, + const NameBitvector *prefix) { + // Cached prefix matches the current one + if (nameBitvector_Compare(&pkt_cache->cached_prefix, prefix) == 0) return; + + // Update cached prefix information + pkt_cache->cached_prefix = *prefix; + pkt_cache->cached_suffixes = + _get_suffixes(pkt_cache->prefix_to_suffixes, prefix); +} + +void pkt_cache_reset_suffixes_for_prefix(pkt_cache_t *pkt_cache) { + pkt_cache->cached_suffixes = NULL; +} + +unsigned _get_suffix(kh_pkt_cache_prefix_t *prefixes, + const NameBitvector *prefix, uint32_t suffix, int *rc) { + kh_pkt_cache_suffix_t *suffixes = _get_suffixes(prefixes, prefix); + assert(suffixes != NULL); + + return __get_suffix(suffixes, suffix, rc); +} + +/****************************************************************************** + * Public API + ******************************************************************************/ + pkt_cache_t *pkt_cache_create(size_t cs_size) { pkt_cache_t *pkt_cache = (pkt_cache_t *)malloc(sizeof(pkt_cache_t)); @@ -28,23 +133,20 @@ pkt_cache_t *pkt_cache_create(size_t cs_size) { pkt_cache->cs = cs_create(cs_size); if (!pkt_cache->cs) return NULL; - pkt_cache->index_by_name = kh_init(pkt_cache_name); + pkt_cache->prefix_to_suffixes = kh_init_pkt_cache_prefix(); pool_init(pkt_cache->entries, DEFAULT_PKT_CACHE_SIZE, 0); + pkt_cache->cached_prefix = EMPTY_NAME_BITVECTOR; + pkt_cache->cached_suffixes = NULL; + return pkt_cache; } void pkt_cache_free(pkt_cache_t *pkt_cache) { assert(pkt_cache); - // Free hashmap - const Name *k_name; - unsigned v; - (void)v; - kh_foreach(pkt_cache->index_by_name, k_name, v, { free((Name *)k_name); }); - kh_destroy(pkt_cache_name, pkt_cache->index_by_name); - - // Free pool + // Free prefix hash table and pool + _prefix_map_free(pkt_cache->prefix_to_suffixes); pool_free(pkt_cache->entries); // Free PIT and CS @@ -54,6 +156,30 @@ void pkt_cache_free(pkt_cache_t *pkt_cache) { free(pkt_cache); } +kh_pkt_cache_suffix_t *pkt_cache_get_suffixes(const pkt_cache_t *pkt_cache, + const NameBitvector *prefix) { + return _get_suffixes(pkt_cache->prefix_to_suffixes, prefix); +} + +pkt_cache_entry_t *pkt_cache_allocate(pkt_cache_t *pkt_cache, + const Name *name) { + pkt_cache_entry_t *entry = NULL; + pool_get(pkt_cache->entries, entry); + if (!entry) return NULL; + + off_t id = entry - pkt_cache->entries; + + if (pkt_cache->cached_suffixes) { + __add_suffix(pkt_cache->cached_suffixes, name_GetSegment(name), + (unsigned int)id); + } else { + _add_suffix(pkt_cache->prefix_to_suffixes, name_GetContentName(name), + name_GetSegment(name), (unsigned int)id); + } + + return entry; +} + pit_t *pkt_cache_get_pit(pkt_cache_t *pkt_cache) { return pkt_cache->pit; } cs_t *pkt_cache_get_cs(pkt_cache_t *pkt_cache) { return pkt_cache->cs; } @@ -63,14 +189,22 @@ pkt_cache_entry_t *pkt_cache_lookup(pkt_cache_t *pkt_cache, const Name *name, pkt_cache_lookup_t *lookup_result, off_t *entry_id, bool is_serve_from_cs_enabled) { - Name name_key = name_key_factory(name); - khiter_t k = kh_get_pkt_cache_name(pkt_cache->index_by_name, &name_key); - if (k == kh_end(pkt_cache->index_by_name)) { + int rc; + + unsigned index = -1; + if (pkt_cache->cached_suffixes) { + index = + __get_suffix(pkt_cache->cached_suffixes, name_GetSegment(name), &rc); + } else { + index = _get_suffix(pkt_cache->prefix_to_suffixes, + name_GetContentName(name), name_GetSegment(name), &rc); + } + + if (rc == KH_NOT_FOUND) { *lookup_result = PKT_CACHE_LU_NONE; return NULL; } - off_t index = kh_val(pkt_cache->index_by_name, k); pkt_cache_entry_t *entry = pkt_cache_at(pkt_cache, index); assert(entry); bool expired = false; @@ -103,11 +237,9 @@ void pkt_cache_cs_remove_entry(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, off_t msgbuf_id = entry->u.cs_entry.msgbuf_id; msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); - Name name_key = name_key_factory(msgbuf_get_name(msgbuf)); - khiter_t k = kh_get_pkt_cache_name(pkt_cache->index_by_name, &name_key); - assert(k != kh_end(pkt_cache->index_by_name)); - free((Name *)kh_key(pkt_cache->index_by_name, k)); - kh_del(pkt_cache_name, pkt_cache->index_by_name, k); + const Name *name = msgbuf_get_name(msgbuf); + _remove_suffix(pkt_cache->prefix_to_suffixes, name_GetContentName(name), + name_GetSegment(name)); // Do not update the LRU cache for evicted entries if (!is_evicted) cs_vft[pkt_cache->cs->type]->remove_entry(pkt_cache, entry); @@ -130,12 +262,8 @@ void pkt_cache_pit_remove_entry(pkt_cache_t *pkt_cache, assert(entry); assert(entry->entry_type == PKT_CACHE_PIT_TYPE); - Name name_key = name_key_factory(name); - khiter_t k = kh_get_pkt_cache_name(pkt_cache->index_by_name, &name_key); - assert(k != kh_end(pkt_cache->index_by_name)); - free((Name *)kh_key(pkt_cache->index_by_name, k)); - kh_del(pkt_cache_name, pkt_cache->index_by_name, k); - + _remove_suffix(pkt_cache->prefix_to_suffixes, name_GetContentName(name), + name_GetSegment(name)); pool_put(pkt_cache->entries, entry); WITH_DEBUG({ @@ -158,7 +286,7 @@ void _pkt_cache_add_to_cs(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, pkt_cache->cs->num_entries++; - int tail_id = pkt_cache->cs->lru.tail; + int tail_id = (int)(pkt_cache->cs->lru.tail); int result = cs_vft[pkt_cache->cs->type]->add_entry(pkt_cache, entry_id); if (result == LRU_EVICTION) { // Remove tail (already removed from LRU cache) @@ -237,11 +365,11 @@ void pkt_cache_update_cs(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool, } pkt_cache_entry_t *pkt_cache_add_to_pit(pkt_cache_t *pkt_cache, - const msgbuf_t *msgbuf) { + const msgbuf_t *msgbuf, + const Name *name) { assert(pkt_cache); - pkt_cache_entry_t *entry = - pkt_cache_allocate(pkt_cache, msgbuf_get_name(msgbuf)); + pkt_cache_entry_t *entry = pkt_cache_allocate(pkt_cache, name); _pkt_cache_add_to_pit(pkt_cache, entry, msgbuf); return entry; } @@ -276,7 +404,7 @@ void pkt_cache_update_pit(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, bool pkt_cache_try_aggregate_in_pit(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, - const msgbuf_t *msgbuf) { + const msgbuf_t *msgbuf, const Name *name) { assert(pkt_cache); assert(entry); assert(entry->entry_type == PKT_CACHE_PIT_TYPE); @@ -294,7 +422,7 @@ bool pkt_cache_try_aggregate_in_pit(pkt_cache_t *pkt_cache, if (is_aggregated) pit_entry_ingress_add(pit_entry, connection_id); WITH_DEBUG({ - char *name_str = name_ToString(msgbuf_get_name(msgbuf)); + char *name_str = name_ToString(name); if (is_aggregated) { DEBUG("Interest %s already existing (expiry %lu): aggregate", name_str, entry->expire_ts); @@ -407,7 +535,7 @@ nexthops_t *pkt_cache_on_data(pkt_cache_t *pkt_cache, return NULL; default: - ERROR("Inivalid packet cache content"); + ERROR("Invalid packet cache content"); return NULL; } } @@ -415,7 +543,7 @@ nexthops_t *pkt_cache_on_data(pkt_cache_t *pkt_cache, void pkt_cache_on_interest(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool, off_t msgbuf_id, pkt_cache_verdict_t *verdict, off_t *data_msgbuf_id, pkt_cache_entry_t **entry_ptr, - bool is_serve_from_cs_enabled) { + const Name *name, bool is_serve_from_cs_enabled) { assert(pkt_cache); assert(msgbuf_id_is_valid(msgbuf_id)); @@ -425,8 +553,8 @@ void pkt_cache_on_interest(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool, off_t entry_id; pkt_cache_lookup_t lookup_result; pkt_cache_entry_t *entry = - pkt_cache_lookup(pkt_cache, msgbuf_get_name(msgbuf), msgbuf_pool, - &lookup_result, &entry_id, is_serve_from_cs_enabled); + pkt_cache_lookup(pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, + is_serve_from_cs_enabled); *entry_ptr = entry; cs_entry_t *cs_entry = NULL; @@ -434,6 +562,9 @@ void pkt_cache_on_interest(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool, bool is_aggregated; switch (lookup_result) { case PKT_CACHE_LU_NONE: + entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name); + *entry_ptr = entry; + *verdict = PKT_CACHE_VERDICT_FORWARD_INTEREST; break; @@ -448,7 +579,8 @@ void pkt_cache_on_interest(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool, break; case PKT_CACHE_LU_INTEREST_NOT_EXPIRED: - is_aggregated = pkt_cache_try_aggregate_in_pit(pkt_cache, entry, msgbuf); + is_aggregated = + pkt_cache_try_aggregate_in_pit(pkt_cache, entry, msgbuf, name); *verdict = is_aggregated ? PKT_CACHE_VERDICT_AGGREGATE_INTEREST : PKT_CACHE_VERDICT_RETRANSMIT_INTEREST; @@ -477,36 +609,30 @@ void pkt_cache_on_interest(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool, void pkt_cache_cs_clear(pkt_cache_t *pkt_cache) { assert(pkt_cache); - const Name *k_name; - unsigned v_pool_pos; - kh_foreach(pkt_cache->index_by_name, k_name, v_pool_pos, - { - khiter_t k = - kh_get_pkt_cache_name(pkt_cache->index_by_name, k_name); - assert(k != kh_end(pkt_cache->index_by_name)); - - pkt_cache_entry_t *entry = pkt_cache_at(pkt_cache, v_pool_pos); - if (entry->entry_type == PKT_CACHE_CS_TYPE) { - // Remove from hashmap - free((Name *)kh_key(pkt_cache->index_by_name, k)); - kh_del(pkt_cache_name, pkt_cache->index_by_name, k); - - // Remove from pool - pool_put(pkt_cache->entries, entry); - } - }) - - // Re-create CS - cs_clear(pkt_cache->cs); -} + kh_pkt_cache_suffix_t *v_suffixes; + u32 k_suffix; + u32 v_pkt_cache_entry_id; + kh_foreach_value(pkt_cache->prefix_to_suffixes, v_suffixes, { + kh_foreach(v_suffixes, k_suffix, v_pkt_cache_entry_id, { + pkt_cache_entry_t *entry = pkt_cache_at(pkt_cache, v_pkt_cache_entry_id); + if (entry->entry_type == PKT_CACHE_CS_TYPE) { + // Remove from hash table + khiter_t k = kh_get_pkt_cache_suffix(v_suffixes, k_suffix); + assert(k != kh_end(v_suffixes)); + kh_del_pkt_cache_suffix(v_suffixes, k); + + // Remove from pool + pool_put(pkt_cache->entries, entry); + } + }); + }); -size_t pkt_cache_get_size(pkt_cache_t *pkt_cache) { - uint64_t hashmap_size = kh_size(pkt_cache->index_by_name); - return hashmap_size; -} + // Reset cached prefix + pkt_cache->cached_prefix = EMPTY_NAME_BITVECTOR; + pkt_cache->cached_suffixes = NULL; -size_t pkt_cache_get_cs_size(pkt_cache_t *pkt_cache) { - return pkt_cache->cs->num_entries; + // Re-create CS + cs_clear(pkt_cache->cs); } size_t pkt_cache_get_num_cs_stale_entries(pkt_cache_t *pkt_cache) { @@ -531,17 +657,35 @@ int pkt_cache_set_cs_size(pkt_cache_t *pkt_cache, size_t size) { return 0; } +size_t pkt_cache_get_size(pkt_cache_t *pkt_cache) { + return pool_len(pkt_cache->entries); +} + +size_t pkt_cache_get_cs_size(pkt_cache_t *pkt_cache) { + return pkt_cache->cs->num_entries; +} + size_t pkt_cache_get_pit_size(pkt_cache_t *pkt_cache) { - uint64_t hashmap_size = kh_size(pkt_cache->index_by_name); - uint64_t pit_size = hashmap_size - pkt_cache->cs->num_entries; + uint64_t pkt_cache_size = pkt_cache_get_size(pkt_cache); + uint64_t pit_size = pkt_cache_size - pkt_cache_get_cs_size(pkt_cache); return pit_size; } void pkt_cache_log(pkt_cache_t *pkt_cache) { - uint64_t hashmap_size = kh_size(pkt_cache->index_by_name); - uint64_t pit_size = hashmap_size - pkt_cache->cs->num_entries; DEBUG("Packet cache: total size = %lu, PIT size = %lu, CS size = %u", - hashmap_size, pit_size, pkt_cache->cs->num_entries); + pkt_cache_get_size(pkt_cache), pkt_cache_get_pit_size(pkt_cache), + pkt_cache_get_cs_size(pkt_cache)); cs_log(pkt_cache->cs); } + +pkt_cache_stats_t pkt_cache_get_stats(pkt_cache_t *pkt_cache) { + cs_lru_stats_t lru_stats = cs_get_lru_stats(pkt_cache_get_cs(pkt_cache)); + pkt_cache_stats_t stats = { + .n_pit_entries = (uint32_t)pkt_cache_get_pit_size(pkt_cache), + .n_cs_entries = (uint32_t)pkt_cache_get_cs_size(pkt_cache), + .n_lru_evictions = (uint32_t)lru_stats.countLruEvictions, + }; + + return stats; +} diff --git a/hicn-light/src/hicn/core/packet_cache.h b/hicn-light/src/hicn/core/packet_cache.h index ccfc83b97..47926fcdc 100644 --- a/hicn-light/src/hicn/core/packet_cache.h +++ b/hicn-light/src/hicn/core/packet_cache.h @@ -19,7 +19,7 @@ * * The packet cache is a data structure that merges together the PIT and the CS, * to which it holds a reference. - * It contains PIT and CS entries, indexed in a hashtable by hICN packet names. + * It contains PIT and CS entries, indexed in a two-level hash table. * * Each entry has shared fields, e.g. entry type (PIT or CS) and timestamps, * which are used by both PIT and CS entries. In addition, a C union holds @@ -27,41 +27,64 @@ * * Having a single entry that can hold PIT or CS entries allows to reduce * the number of lookups. + * + * A prefix hash table <prefix, suffix_hashtable> stores the suffixes associated + * to each prefix, where each value in the map points to a separate hash + * table <suffix, packet_cache_reference> that can be used to retrieved the + * packet cache entry. + * When an interest/data packet is received, the prefix and the associated + * suffixes are saved; if the next packet cache operation involves the same + * prefix, no additional lookups in the prefix hash hashtable are needed. */ #ifndef HICNLIGHT_PACKET_CACHE_H #define HICNLIGHT_PACKET_CACHE_H +#include <hicn/util/khash.h> #include "content_store.h" #include "pit.h" #include "msgbuf_pool.h" -#include "../base/khash.h" #include "../content_store/lru.h" #define DEFAULT_PKT_CACHE_SIZE 2048 typedef enum { PKT_CACHE_PIT_TYPE, PKT_CACHE_CS_TYPE } pkt_cache_entry_type_t; -/** - * @brief Return a Name that can be used as key for hash table lookups. - * The returned Name is a copy of the input one but it is "memsetted" - * to ensure successful hash calculation. - */ -static inline Name name_key_factory(const Name *name) { - NameBitvector *content_name = name_GetContentName(name); +#define foreach_kh_verdict \ + _(FORWARD_INTEREST) \ + _(AGGREGATE_INTEREST) \ + _(RETRANSMIT_INTEREST) \ + _(FORWARD_DATA) \ + _(INTEREST_EXPIRED_FORWARD_INTEREST) \ + _(DATA_EXPIRED_FORWARD_INTEREST) \ + _(STORE_DATA) \ + _(CLEAR_DATA) \ + _(UPDATE_DATA) \ + _(IGNORE_DATA) \ + _(ERROR) - Name name_key; - memset(&name_key, 0, sizeof(Name)); +typedef enum { +#define _(x) PKT_CACHE_VERDICT_##x, + foreach_kh_verdict +#undef _ +} pkt_cache_verdict_t; - name_key.content_name = *content_name; - name_key.segment = name_GetSegment(name); - name_key.name_hash = name_HashCode(name); +#define foreach_kh_lookup \ + _(INTEREST_NOT_EXPIRED) \ + _(INTEREST_EXPIRED) \ + _(DATA_NOT_EXPIRED) \ + _(DATA_EXPIRED) \ + _(NONE) - return name_key; -} +typedef enum { +#define _(x) PKT_CACHE_LU_##x, + foreach_kh_lookup +#undef _ +} pkt_cache_lookup_t; -KHASH_INIT(pkt_cache_name, const Name *, unsigned, 1, name_HashCode, - name_Equals); +KHASH_MAP_INIT_INT(pkt_cache_suffix, unsigned); +KHASH_INIT(pkt_cache_prefix, const NameBitvector *, kh_pkt_cache_suffix_t *, 1, + nameBitvector_GetHash32, nameBitvector_Equals); typedef struct { pkt_cache_entry_type_t entry_type; @@ -82,7 +105,12 @@ typedef struct { pit_t *pit; cs_t *cs; pkt_cache_entry_t *entries; - kh_pkt_cache_name_t *index_by_name; + kh_pkt_cache_prefix_t *prefix_to_suffixes; + + // Cached prefix info to avoid double lookups, + // used for both single interest speculation and interest manifest + NameBitvector cached_prefix; + kh_pkt_cache_suffix_t *cached_suffixes; } pkt_cache_t; /** @@ -92,7 +120,6 @@ typedef struct { */ pkt_cache_t *pkt_cache_create(size_t cs_size); -#define _pc_var(x) _pkt_cache_##x /** * @brief Add an entry with the specified name to the packet cache. * @@ -101,29 +128,7 @@ pkt_cache_t *pkt_cache_create(size_t cs_size); * allocated one from the msgbuf pool. * * @param[in] name Name to use */ -static inline pkt_cache_entry_t *pkt_cache_allocate( - const pkt_cache_t *pkt_cache, const Name *name) { - pkt_cache_entry_t *entry = NULL; - pool_get(pkt_cache->entries, entry); - assert(entry); - - off_t id = entry - pkt_cache->entries; - int res; - - // Generate the key (starting from the name) to use in the name hash table - NameBitvector *nb = name_GetContentName(name); - Name *name_copy = (Name *)calloc(1, sizeof(Name)); - name_copy->content_name = *nb; - name_copy->segment = name_GetSegment(name); - name_copy->name_hash = name_HashCode(name); - - // Add in name hash table - khiter_t k = kh_put_pkt_cache_name(pkt_cache->index_by_name, name_copy, &res); - assert(res != -1); - kh_value(pkt_cache->index_by_name, k) = id; - - return entry; -} +pkt_cache_entry_t *pkt_cache_allocate(pkt_cache_t *pkt_cache, const Name *name); /** * @brief Free a packet cache data structure. @@ -189,28 +194,6 @@ size_t pkt_cache_get_cs_size(pkt_cache_t *pkt_cache); */ size_t pkt_cache_get_pit_size(pkt_cache_t *pkt_cache); -typedef enum { - PKT_CACHE_LU_INTEREST_NOT_EXPIRED, - PKT_CACHE_LU_INTEREST_EXPIRED, - PKT_CACHE_LU_DATA_NOT_EXPIRED, - PKT_CACHE_LU_DATA_EXPIRED, - PKT_CACHE_LU_NONE -} pkt_cache_lookup_t; - -typedef enum { - PKT_CACHE_VERDICT_FORWARD_INTEREST, - PKT_CACHE_VERDICT_AGGREGATE_INTEREST, - PKT_CACHE_VERDICT_RETRANSMIT_INTEREST, - PKT_CACHE_VERDICT_FORWARD_DATA, - PKT_CACHE_VERDICT_INTEREST_EXPIRED_FORWARD_INTEREST, - PKT_CACHE_VERDICT_DATA_EXPIRED_FORWARD_INTEREST, - PKT_CACHE_VERDICT_STORE_DATA, - PKT_CACHE_VERDICT_CLEAR_DATA, - PKT_CACHE_VERDICT_UPDATE_DATA, - PKT_CACHE_VERDICT_IGNORE_DATA, - PKT_CACHE_VERDICT_ERROR -} pkt_cache_verdict_t; - #define pkt_cache_entry_get_create_ts(E) ((E)->create_ts) #define pkt_cache_entry_get_expire_ts(E) ((E)->expire_ts) #define pkt_cache_entry_set_expire_ts(E, EXPIRY_TIME) \ @@ -241,7 +224,7 @@ pkt_cache_entry_t *pkt_cache_lookup(pkt_cache_t *pkt_cache, const Name *name, bool is_serve_from_cs_enabled); /** - * @brief Clear the content of the CS. + * @brief Clear the content of the CS (PIT entries are left unmodified). * * @param pkt_cache Pointer to the packet cache data structure to use */ @@ -254,6 +237,8 @@ void pkt_cache_cs_clear(pkt_cache_t *pkt_cache); */ void pkt_cache_log(pkt_cache_t *pkt_cache); +pkt_cache_stats_t pkt_cache_get_stats(pkt_cache_t *pkt_cache); + // TODO(eloparco): To implement void pkt_cache_print(const pkt_cache_t *pkt_cache); @@ -320,10 +305,13 @@ void pkt_cache_cs_to_pit(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, * @param[in] pkt_cache Pointer to the packet cache data structure to use * @param[in] msgbuf Pointer to the msgbuf associated with the PIT entry to * insert + * @param[in] name Interest name to use; in case of aggregated interests, it is + * different from the name stored in the msgbuf * @return pkt_cache_entry_t* Pointer to the packet cache (PIT) entry created */ pkt_cache_entry_t *pkt_cache_add_to_pit(pkt_cache_t *pkt_cache, - const msgbuf_t *msgbuf); + const msgbuf_t *msgbuf, + const Name *name); /** * @brief Add CS entry to the packet cache. @@ -374,6 +362,8 @@ void pkt_cache_update_cs(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool, * @param[in, out] entry Pointer to the PIT entry to update * @param[in] msgbuf Pointer to the msgbuf associated with the PIT entry to * update + * @param[in] name Interest name to use; in case of aggregated interests, it is + * different from the name stored in the msgbuf * @return true If aggregation (interest sent from a connection not stored in * the PIT entry) * @return false If retransmission (interest sent from a connection already @@ -381,7 +371,23 @@ void pkt_cache_update_cs(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool, */ bool pkt_cache_try_aggregate_in_pit(pkt_cache_t *pkt_cache, pkt_cache_entry_t *entry, - const msgbuf_t *msgbuf); + const msgbuf_t *msgbuf, const Name *name); + +/** + * @brief Cache prefix info (prefix + associated suffixes) to speed up lookups. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + * @param[in] prefix Name prefix to cache + */ +void pkt_cache_save_suffixes_for_prefix(pkt_cache_t *pkt_cache, + const NameBitvector *prefix); + +/** + * @brief Reset cached prefix info to force double lookups. + * + * @param[in] pkt_cache Pointer to the packet cache data structure to use + */ +void pkt_cache_reset_suffixes_for_prefix(pkt_cache_t *pkt_cache); /************ Handle data/interest packets received *******/ @@ -413,7 +419,24 @@ nexthops_t *pkt_cache_on_data(pkt_cache_t *pkt_cache, void pkt_cache_on_interest(pkt_cache_t *pkt_cache, msgbuf_pool_t *msgbuf_pool, off_t msgbuf_id, pkt_cache_verdict_t *verdict, off_t *data_msgbuf_id, pkt_cache_entry_t **entry_ptr, - bool is_serve_from_cs_enabled); + const Name *name, bool is_serve_from_cs_enabled); + +/********* Low-level operations on the hash table *********/ +#ifdef WITH_TESTS +unsigned __get_suffix(kh_pkt_cache_suffix_t *suffixes, uint32_t suffix, + int *rc); +unsigned _get_suffix(kh_pkt_cache_prefix_t *prefixes, + const NameBitvector *prefix, uint32_t suffix, int *rc); +void __add_suffix(kh_pkt_cache_suffix_t *suffixes, uint32_t suffix, + unsigned val); +void _add_suffix(kh_pkt_cache_prefix_t *prefixes, const NameBitvector *prefix, + uint32_t suffix, unsigned val); +void _remove_suffix(kh_pkt_cache_prefix_t *prefixes, + const NameBitvector *prefix, uint32_t suffix); +void _prefix_map_free(kh_pkt_cache_prefix_t *prefix_to_suffixes); +kh_pkt_cache_suffix_t *_get_suffixes(kh_pkt_cache_prefix_t *prefix_to_suffixes, + const NameBitvector *prefix); +#endif /************** Content Store *****************************/ diff --git a/hicn-light/src/hicn/core/policy_stats.h b/hicn-light/src/hicn/core/policy_stats.h index fa12b51cb..aee68e515 100644 --- a/hicn-light/src/hicn/core/policy_stats.h +++ b/hicn-light/src/hicn/core/policy_stats.h @@ -5,7 +5,6 @@ #ifdef WITH_POLICY_STATS #include <hicn/policy.h> -#include "../base/loop.h" typedef struct policy_stats_mgr_s { void* forwarder; diff --git a/hicn-light/src/hicn/core/subscription.c b/hicn-light/src/hicn/core/subscription.c index 0c4949f26..ad4006531 100644 --- a/hicn-light/src/hicn/core/subscription.c +++ b/hicn-light/src/hicn/core/subscription.c @@ -3,7 +3,7 @@ */ #include "subscription.h" -#include <hicn/base/vector.h> +#include <hicn/util/vector.h> #include <hicn/util/log.h> /*----------------------------------------------------------------------------* diff --git a/hicn-light/src/hicn/io/base.c b/hicn-light/src/hicn/io/base.c index 71d10021e..cd7362956 100644 --- a/hicn-light/src/hicn/io/base.c +++ b/hicn-light/src/hicn/io/base.c @@ -42,7 +42,7 @@ ssize_t io_read_single_fd(int fd, msgbuf_t *msgbuf, address_t *address) { return -1; } - msgbuf->length = n; + msgbuf->length = (unsigned int)n; *address = ADDRESS_ANY(AF_UNSPEC, 0); // XXX placeholder, see hicn.c } @@ -55,7 +55,7 @@ ssize_t io_read_single_socket(int fd, msgbuf_t *msgbuf, address_t *address) { uint8_t *packet = msgbuf_get_packet(msgbuf); ssize_t n = recvfrom(fd, packet, MTU, 0, (struct sockaddr *)sa, &sa_len); - msgbuf->length = n; + msgbuf->length = (unsigned int)n; return n; } @@ -114,21 +114,6 @@ ssize_t io_read_batch_socket(int fd, msgbuf_t **msgbuf, address_t **address, struct mmsghdr *msg = &msghdr[i]; msgbuf[i]->length = msg->msg_len; - /* - * As is, the address we put in the array has uninitialized - * memory in it: - * *address[i] = *(address_t*)msg->msg_hdr.msg_name; - * - * This can be confirmed by testing with the following - * memset which removes the valgrind errors: - * memset(address[i], 0, sizeof(address_t)); - * - * The solution is to copy only the part which we know is - * initialized (we have compatible types, since the destination, an - * address_t, is effectively a struct sockaddr_storage). We might - * eventually provide a helper for this to avoid similar mistakes. - */ - //*address[i] = *(address_t*)msg->msg_hdr.msg_name; memcpy(address[i], msg->msg_hdr.msg_name, msg->msg_hdr.msg_namelen); } break; diff --git a/hicn-light/src/hicn/io/hicn.c b/hicn-light/src/hicn/io/hicn.c index 8b4ad2e00..d019a49c1 100644 --- a/hicn-light/src/hicn/io/hicn.c +++ b/hicn-light/src/hicn/io/hicn.c @@ -401,12 +401,10 @@ static void connection_hicn_finalize(connection_t *connection) { return; } -static bool connection_hicn_flush(const connection_t *connection) { - return false; -} +static bool connection_hicn_flush(connection_t *connection) { return false; } -static bool connection_hicn_send(const connection_t *connection, - msgbuf_t *msgbuf, bool queue) { +static bool connection_hicn_send(connection_t *connection, msgbuf_t *msgbuf, + bool queue) { assert(connection); /* msgbuf can be NULL */ diff --git a/hicn-light/src/hicn/io/tcp.c b/hicn-light/src/hicn/io/tcp.c index 69ad32d16..50591c3fc 100644 --- a/hicn-light/src/hicn/io/tcp.c +++ b/hicn-light/src/hicn/io/tcp.c @@ -287,9 +287,7 @@ connection_tcp_sendv(connnection_t * connection, struct iovec * iov, } #endif -static bool connection_tcp_flush(const connection_t *connection) { - return true; -} +static bool connection_tcp_flush(connection_t *connection) { return true; } /** * @function streamConnection_Send @@ -303,8 +301,8 @@ static bool connection_tcp_flush(const connection_t *connection) { */ // XXX address not used anywhere // XXX too much repeated code with sendv here -static bool connection_tcp_send(const connection_t *connection, - msgbuf_t *msgbuf, bool queue) { +static bool connection_tcp_send(connection_t *connection, msgbuf_t *msgbuf, + bool queue) { assert(connection); assert(msgbuf); diff --git a/hicn-light/src/hicn/io/udp.c b/hicn-light/src/hicn/io/udp.c index 3301e2178..149d53aea 100644 --- a/hicn-light/src/hicn/io/udp.c +++ b/hicn-light/src/hicn/io/udp.c @@ -49,10 +49,9 @@ #include <hicn/util/log.h> #include <hicn/util/sstrncpy.h> +#include <hicn/util/ring.h> #include "base.h" -#include "../base/loop.h" -#include "../base/ring.h" #include "../core/address_pair.h" #include "../core/connection.h" #include "../core/connection_vft.h" @@ -344,7 +343,7 @@ static void connection_udp_finalize(connection_t *connection) { ring_free(data->ring); } -static bool connection_udp_flush(const connection_t *connection) { +static bool connection_udp_flush(connection_t *connection) { #ifdef __linux__ int retry = 0; off_t msgbuf_id = 0; @@ -375,9 +374,16 @@ SEND: msgbuf_t *msgbuf = msgbuf_pool_at(msgbuf_pool, msgbuf_id); // update path label - if (msgbuf_get_type(msgbuf) == MSGBUF_TYPE_DATA) + if (msgbuf_get_type(msgbuf) == MSGBUF_TYPE_DATA) { msgbuf_update_pathlabel(msgbuf, connection_get_id(connection)); + connection->stats.data.tx_pkts++; + connection->stats.data.tx_bytes += msgbuf_get_len(msgbuf); + } else { + connection->stats.interests.tx_pkts++; + connection->stats.interests.tx_bytes += msgbuf_get_len(msgbuf); + } + data->iovecs[i].iov_base = msgbuf_get_packet(msgbuf); data->iovecs[i].iov_len = msgbuf_get_len(msgbuf); cpt++; @@ -430,8 +436,8 @@ SENDMMSG: * @param dummy is ignored. A udp connection has only one peer. * @return <#return#> */ -static bool connection_udp_send(const connection_t *connection, - msgbuf_t *msgbuf, bool queue) { +static bool connection_udp_send(connection_t *connection, msgbuf_t *msgbuf, + bool queue) { assert(connection); assert(msgbuf); @@ -454,9 +460,16 @@ static bool connection_udp_send(const connection_t *connection, #endif /* __linux__ */ /* Send one */ // update the path label befor send the packet - if (msgbuf_get_type(msgbuf) == MSGBUF_TYPE_DATA) + if (msgbuf_get_type(msgbuf) == MSGBUF_TYPE_DATA) { msgbuf_update_pathlabel(msgbuf, connection_get_id(connection)); + connection->stats.data.tx_pkts++; + connection->stats.data.tx_bytes += msgbuf_get_len(msgbuf); + } else { + connection->stats.interests.tx_pkts++; + connection->stats.interests.tx_bytes += msgbuf_get_len(msgbuf); + } + ssize_t writeLength = write(connection->fd, msgbuf_get_packet(msgbuf), msgbuf_get_len(msgbuf)); diff --git a/hicn-light/src/hicn/strategies/probe_generator.c b/hicn-light/src/hicn/strategies/probe_generator.c index 439de0a12..bc141e518 100644 --- a/hicn-light/src/hicn/strategies/probe_generator.c +++ b/hicn-light/src/hicn/strategies/probe_generator.c @@ -78,7 +78,7 @@ int generate_probe(probe_generator_t *pg, const msgbuf_t *msgbuf, const forwarder_t *forwarder, nexthop_t nexthop) { msgbuf_pool_t *msgbuf_pool = forwarder_get_msgbuf_pool(forwarder); connection_table_t *table = forwarder_get_connection_table(forwarder); - const connection_t *conn = connection_table_get_by_id(table, nexthop); + connection_t *conn = connection_table_get_by_id(table, nexthop); if (!conn) return -1; msgbuf_t *probe; diff --git a/hicn-light/src/hicn/strategies/probe_generator.h b/hicn-light/src/hicn/strategies/probe_generator.h index 26d6a3a22..7a9f3a58a 100644 --- a/hicn-light/src/hicn/strategies/probe_generator.h +++ b/hicn-light/src/hicn/strategies/probe_generator.h @@ -16,7 +16,7 @@ #ifndef HICNLIGHT_PROBE_GENERATOR #define HICNLIGHT_PROBE_GENERATOR -#include "../base/khash.h" +#include <hicn/util/khash.h> #include <hicn/core/ticks.h> #include <hicn/core/msgbuf.h> diff --git a/hicn-light/src/hicn/test/CMakeLists.txt b/hicn-light/src/hicn/test/CMakeLists.txt index 0ded4253d..65e216c1e 100644 --- a/hicn-light/src/hicn/test/CMakeLists.txt +++ b/hicn-light/src/hicn/test/CMakeLists.txt @@ -13,6 +13,7 @@ list(APPEND TESTS_SRC test-ctrl.cc test-ring.cc test-vector.cc + test-interest_manifest.cc test-msgbuf_pool.cc test-nexthops.cc test-connection_table.cc diff --git a/hicn-light/src/hicn/test/test-bitmap.cc b/hicn-light/src/hicn/test/test-bitmap.cc index f9cd4024f..1fd21a1bb 100644 --- a/hicn-light/src/hicn/test/test-bitmap.cc +++ b/hicn-light/src/hicn/test/test-bitmap.cc @@ -25,7 +25,7 @@ extern "C" { #define WITH_TESTS -#include <hicn/base/bitmap.h> +#include <hicn/util/bitmap.h> } #define DEFAULT_SIZE 10 diff --git a/hicn-light/src/hicn/test/test-connection_table.cc b/hicn-light/src/hicn/test/test-connection_table.cc index 6bbf478e2..d17de7c2c 100644 --- a/hicn-light/src/hicn/test/test-connection_table.cc +++ b/hicn-light/src/hicn/test/test-connection_table.cc @@ -35,7 +35,7 @@ extern "C" { class ConnectionTableTest : public ::testing::Test { protected: ConnectionTableTest() { - log_conf.log_level = LOG_INFO; + log_conf.log_level = LOG_WARN; conn_table_ = connection_table_create(); pair_ = @@ -164,6 +164,10 @@ TEST_F(ConnectionTableTest, RemoveConnection) { } TEST_F(ConnectionTableTest, PrintTable) { + // Set verbose log level + int old_log_level = log_conf.log_level; + log_conf.log_level = LOG_INFO; + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); connection_->type = FACE_TYPE_TCP; @@ -184,6 +188,8 @@ TEST_F(ConnectionTableTest, PrintTable) { EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:2")); EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:3")); EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:4")); + + log_conf.log_level = old_log_level; // Restore old log level } TEST_F(ConnectionTableTest, AddMultipleConnections) { @@ -248,3 +254,43 @@ TEST_F(ConnectionTableTest, Iterate) { EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:3")); EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:4")); } + +TEST_F(ConnectionTableTest, GenerateConnName) { + char conn_name[SYMBOLIC_NAME_LEN]; + int rc = connection_table_get_random_name(conn_table_, conn_name); + EXPECT_EQ(rc, 0); + + connection_ = connection_table_allocate(conn_table_, &pair_, conn_name); + connection_->type = FACE_TYPE_TCP; + connection_->pair = pair_; + + char conn_name2[SYMBOLIC_NAME_LEN]; + rc = connection_table_get_random_name(conn_table_, conn_name2); + EXPECT_EQ(rc, 0); + EXPECT_NE(strncmp(conn_name, conn_name2, SYMBOLIC_NAME_LEN), 0); +} + +TEST_F(ConnectionTableTest, GenerateConnNameExhaustion) { + char conn_name[SYMBOLIC_NAME_LEN]; + bool unable_to_allocate = false; + + // Force name exhaustion + int i, n_connections = 1 + USHRT_MAX; + for (int i = 0; i <= n_connections; i++) { + int rc = connection_table_get_random_name(conn_table_, conn_name); + if (rc < 0) { + unable_to_allocate = true; + break; + } + + address_pair_t pair = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(i)); + connection_t *conn = + connection_table_allocate(conn_table_, &pair, conn_name); + memset(conn, 0, sizeof(connection_t)); + conn->type = FACE_TYPE_TCP; + conn->pair = pair; + } + + EXPECT_TRUE(unable_to_allocate); +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/test/test-hash.cc b/hicn-light/src/hicn/test/test-hash.cc index 2b72e194a..3b03a08a6 100644 --- a/hicn-light/src/hicn/test/test-hash.cc +++ b/hicn-light/src/hicn/test/test-hash.cc @@ -22,14 +22,18 @@ #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> -// #include <hicn/transport/utils/hash.h> +#include <unordered_set> +#include <hicn/test/test-utils.h> extern "C" { -#include <hicn/base/hash.h> +#include <hicn/util/hash.h> #include <hicn/core/address_pair.h> #include <hicn/core/listener.h> } +static constexpr uint32_t init_val = 2166136261UL; +static constexpr int N_HASHES = 50000; + TEST(HashTest, MultipleHashesForSameAddrPair) { address_pair_t pair = address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(2)); @@ -108,16 +112,106 @@ TEST(HashTest, SameListenerKeys) { } TEST(HashTest, Collisions) { - uint32_t init_val = 2166136261UL; - (void)init_val; - - std::map<u32, uint32_t> hashes; + std::unordered_set<uint32_t> hashes; + int n_collisions = 0; for (int i = 0; i < 50000; i++) { uint32_t seg = i; - // u32 h = utils::hash::fnv32_buf (&seg, sizeof (seg)); - // u32 h = cumulative_hash32 (&seg, sizeof (seg), init_val); + // u32 h = utils::hash::fnv32_buf(&seg, sizeof(seg)); + // u32 h = cumulative_hash32(&seg, sizeof(uint32_t), init_val); u32 h = hash(&seg, sizeof(seg)); - EXPECT_FALSE(hashes.find(h) != hashes.end()) << seg << " - " << hashes[h]; - hashes[h] = seg; + + if (hashes.find(h) != hashes.end()) n_collisions++; + hashes.insert(h); } + EXPECT_EQ(n_collisions, 0); +} + +/*** Compare FNV with Jenkins ***/ + +typedef struct { + uint32_t data[6]; +} small_struct_t; // Same size as 'NameBitvector' + +typedef struct { + uint64_t data[32]; +} big_struct_t; // Same size as 'address_pair_t' + +TEST(HashTest, PerformanceComparisonSmallStruct) { + small_struct_t small_struct; + + // FNV + auto time_fnv = get_execution_time([&]() { + for (int i = 0; i < N_HASHES; i++) { + small_struct.data[0] = i; + cumulative_hash32(&small_struct, sizeof(small_struct_t), init_val); + } + }); + + // Jenkins + auto time_jenkins = get_execution_time([&]() { + for (int i = 0; i < N_HASHES; i++) { + small_struct.data[0] = i; + hash(&small_struct, sizeof(small_struct_t)); + } + }); + + std::cout << "Small struct (size = " << sizeof(small_struct_t) << " bytes)\n"; + std::cout << "FNV: " << time_fnv << "ms\n"; + std::cout << "Jenkins: " << time_jenkins << "ms\n"; +} + +TEST(HashTest, PerformanceComparisonBigStruct) { + big_struct_t big_struct; + + // FNV + auto time_fnv = get_execution_time([&]() { + for (int i = 0; i < N_HASHES; i++) { + big_struct.data[0] = i; + cumulative_hash32(&big_struct, sizeof(big_struct_t), init_val); + } + }); + + // Jenkins + auto time_jenkins = get_execution_time([&]() { + for (int i = 0; i < N_HASHES; i++) { + big_struct.data[0] = i; + hash(&big_struct, sizeof(big_struct_t)); + } + }); + + std::cout << "Big struct (size = " << sizeof(big_struct_t) << " bytes)\n"; + std::cout << "FNV: " << time_fnv << "ms\n"; + std::cout << "Jenkins: " << time_jenkins << "ms\n"; +} + +TEST(HashTest, CollisionsComparison) { + small_struct_t small_struct = {0}; + std::unordered_set<uint32_t> hashes; + int n_collisions_fnv = 0, n_collisions_jenkins = 0, n_collisions_murmur = 0, + n_collisions_xxhash = 0; + + // FNV + for (int i = 0; i < 10 * N_HASHES; i++) { + small_struct.data[0] = i; + uint32_t h = + cumulative_hash32(&small_struct, sizeof(small_struct_t), init_val); + + if (hashes.find(h) != hashes.end()) n_collisions_fnv++; + hashes.insert(h); + } + + hashes.clear(); + + // Jenkins + for (int i = 0; i < 10 * N_HASHES; i++) { + small_struct.data[0] = i; + uint32_t h = hash(&small_struct, sizeof(small_struct_t)); + + if (hashes.find(h) != hashes.end()) n_collisions_jenkins++; + hashes.insert(h); + } + + std::cout << "Small struct (size = " << sizeof(small_struct_t) << " bytes)\n"; + std::cout << "FNV: " << n_collisions_fnv << " collision/s\n"; + std::cout << "Jenkins: " << n_collisions_jenkins << " collision/s\n"; }
\ No newline at end of file diff --git a/hicn-light/src/hicn/test/test-interest_manifest.cc b/hicn-light/src/hicn/test/test-interest_manifest.cc new file mode 100644 index 000000000..6408a3f2a --- /dev/null +++ b/hicn-light/src/hicn/test/test-interest_manifest.cc @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> + +extern "C" { +#include <hicn/core/interest_manifest.h> +} + +static constexpr size_t WORD_SIZE = 32; + +class InterestManifestTest : public ::testing::Test { + protected: + InterestManifestTest() {} + virtual ~InterestManifestTest() {} +}; + +TEST_F(InterestManifestTest, OneWordBitmapUpdate) { + u32 initial_bitmap[1]; + u32 curr_bitmap[1] = {0}; + initial_bitmap[0] = 0x00000b07; // 000000000000000000000101100000111 + + // Consume first 4 'one' bits (i.e. suffixes), reaching position 9 + int pos = 0, max_suffixes = 4; + pos = interest_manifest_update_bitmap(initial_bitmap, curr_bitmap, pos, + WORD_SIZE, max_suffixes); + EXPECT_EQ(pos, 9); + EXPECT_EQ(curr_bitmap[0], 0x00000107); + + // Consume the remaining 2 'one' bits, reaching end of bitmap + u32 curr_bitmap2[1] = {0}; + pos = interest_manifest_update_bitmap(initial_bitmap, curr_bitmap2, pos, + WORD_SIZE, max_suffixes); + EXPECT_EQ(pos, WORD_SIZE); + EXPECT_EQ(curr_bitmap2[0], 0x00000a00); + + // Consume all suffixes at once + u32 curr_bitmap3[1] = {0}; + max_suffixes = 16; + pos = interest_manifest_update_bitmap(initial_bitmap, curr_bitmap3, 0, + WORD_SIZE, max_suffixes); + EXPECT_EQ(pos, WORD_SIZE); + EXPECT_EQ(curr_bitmap3[0], initial_bitmap[0]); +} + +TEST_F(InterestManifestTest, TwoWordBitmapUpdate) { + u32 initial_bitmap[2]; + initial_bitmap[0] = 0x00000b07; + initial_bitmap[1] = 0x00000b07; + // -> 100000000000000000000101100000111000000000000000000000101100000111 + + int expected_pos[] = {34, 64}; + u32 expected_bitmap[][2] = {{0x00000b07, 0x00000003}, {0x0, 0x00000b04}}; + + // Loop to consume all suffixes + int pos = 0, max_suffixes = 8, i = 0, len = WORD_SIZE * 2; + while (pos != len) { + u32 curr_bitmap[2] = {0}; + pos = interest_manifest_update_bitmap(initial_bitmap, curr_bitmap, pos, len, + max_suffixes); + + EXPECT_EQ(pos, expected_pos[i]); + EXPECT_EQ(curr_bitmap[0], expected_bitmap[i][0]); + EXPECT_EQ(curr_bitmap[1], expected_bitmap[i][1]); + i++; + } +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/test/test-khash.cc b/hicn-light/src/hicn/test/test-khash.cc index 4fcb48c31..f437f8858 100644 --- a/hicn-light/src/hicn/test/test-khash.cc +++ b/hicn-light/src/hicn/test/test-khash.cc @@ -24,7 +24,7 @@ #include <netinet/in.h> extern "C" { -#include <hicn/base/khash.h> +#include <hicn/util/khash.h> } KHASH_MAP_INIT_INT(int, unsigned char) diff --git a/hicn-light/src/hicn/test/test-msgbuf_pool.cc b/hicn-light/src/hicn/test/test-msgbuf_pool.cc index 5537aa216..e9c8e6424 100644 --- a/hicn-light/src/hicn/test/test-msgbuf_pool.cc +++ b/hicn-light/src/hicn/test/test-msgbuf_pool.cc @@ -26,7 +26,7 @@ extern "C" { #define WITH_TESTS #include <hicn/core/msgbuf_pool.h> -#include <hicn/base/pool.h> +#include <hicn/util/pool.h> } class MsgbufPoolTest : public ::testing::Test { diff --git a/hicn-light/src/hicn/test/test-packet_cache.cc b/hicn-light/src/hicn/test/test-packet_cache.cc index bb24daeb8..0b4b214f0 100644 --- a/hicn-light/src/hicn/test/test-packet_cache.cc +++ b/hicn-light/src/hicn/test/test-packet_cache.cc @@ -15,23 +15,26 @@ #include <gtest/gtest.h> -#include <thread> #include <optional> +#include <random> +#include <hicn/test/test-utils.h> extern "C" { #define WITH_TESTS #include <hicn/core/packet_cache.h> } -const unsigned CS_SIZE = 100; -const unsigned CONN_ID = 0; -const unsigned CONN_ID_2 = 1; -const unsigned MSGBUF_ID = 0; -const unsigned MSGBUF_ID_2 = 1; -const unsigned MSGBUF_ID_3 = 2; -const unsigned FIVE_SECONDS = 5000; -const unsigned IPV4_LEN = 32; -const unsigned IPV6_LEN = 128; +static constexpr unsigned CS_SIZE = 100; +static constexpr unsigned CONN_ID = 0; +static constexpr unsigned CONN_ID_2 = 1; +static constexpr unsigned MSGBUF_ID = 0; +static constexpr unsigned MSGBUF_ID_2 = 1; +static constexpr unsigned MSGBUF_ID_3 = 2; +static constexpr unsigned FIVE_SECONDS = 5000; +static constexpr unsigned IPV4_LEN = 32; +static constexpr unsigned IPV6_LEN = 128; + +static constexpr int N_OPS = 50000; class PacketCacheTest : public ::testing::Test { protected: @@ -40,33 +43,78 @@ class PacketCacheTest : public ::testing::Test { name = (Name *)malloc(sizeof(Name)); name_CreateFromAddress(name, AF_INET, IPV4_ANY, IPV4_LEN); msgbuf_pool = msgbuf_pool_create(); + msgbuf = msgbuf_create(msgbuf_pool, CONN_ID, name); } + virtual ~PacketCacheTest() { - pkt_cache_free(pkt_cache); + free(name); msgbuf_pool_free(msgbuf_pool); + pkt_cache_free(pkt_cache); + } + + msgbuf_t *msgbuf_create(msgbuf_pool_t *msgbuf_pool, unsigned conn_id, + Name *name, + std::optional<Ticks> lifetime = FIVE_SECONDS) { + msgbuf_t *msgbuf; + msgbuf_pool_get(msgbuf_pool, &msgbuf); + + msgbuf->connection_id = conn_id; + name_Copy(name, msgbuf_get_name(msgbuf)); + hicn_packet_init_header(HF_INET6_TCP, + (hicn_header_t *)msgbuf_get_packet(msgbuf)); + msgbuf_set_interest_lifetime(msgbuf, *lifetime); + + return msgbuf; + } + + Name get_name_from_prefix(const char *prefix_str) { + ip_address_t prefix; + inet_pton(AF_INET6, prefix_str, (struct in6_addr *)&prefix); + + Name name; + name_CreateFromAddress(&name, AF_INET6, prefix, IPV6_LEN); + + return name; } pkt_cache_t *pkt_cache; pkt_cache_entry_t *entry = nullptr; msgbuf_pool_t *msgbuf_pool; Name *name; -}; - -msgbuf_t *msgbuf_factory(msgbuf_pool_t *msgbuf_pool, unsigned conn_id, - Name *name, - std::optional<Ticks> lifetime = FIVE_SECONDS) { msgbuf_t *msgbuf; - msgbuf_pool_get(msgbuf_pool, &msgbuf); - - msgbuf->connection_id = conn_id; - name_Copy(name, msgbuf_get_name(msgbuf)); - hicn_packet_init_header(HF_INET6_TCP, - (hicn_header_t *)msgbuf_get_packet(msgbuf)); - // Same as 'msgbuf_set_data_expiry_time', - // it would write in the same field - msgbuf_set_interest_lifetime(msgbuf, *lifetime); +}; - return msgbuf; +TEST_F(PacketCacheTest, LowLevelOperations) { + int rc; + kh_pkt_cache_prefix_t *prefix_to_suffixes = kh_init_pkt_cache_prefix(); + NameBitvector *prefix = name_GetContentName(name); + _add_suffix(prefix_to_suffixes, prefix, 1, 11); + _add_suffix(prefix_to_suffixes, prefix, 2, 22); + + unsigned id = _get_suffix(prefix_to_suffixes, prefix, 1, &rc); + EXPECT_EQ(rc, KH_FOUND); + EXPECT_EQ(id, 11); + + id = _get_suffix(prefix_to_suffixes, prefix, 2, &rc); + EXPECT_EQ(rc, KH_FOUND); + EXPECT_EQ(id, 22); + + id = _get_suffix(prefix_to_suffixes, prefix, 5, &rc); + EXPECT_EQ(rc, KH_NOT_FOUND); + EXPECT_EQ(id, -1); + + _add_suffix(prefix_to_suffixes, prefix, 5, 55); + id = _get_suffix(prefix_to_suffixes, prefix, 5, &rc); + EXPECT_EQ(rc, KH_FOUND); + EXPECT_EQ(id, 55); + + _remove_suffix(prefix_to_suffixes, prefix, 2); + _add_suffix(prefix_to_suffixes, prefix, 2, 222); + id = _get_suffix(prefix_to_suffixes, prefix, 2, &rc); + EXPECT_EQ(rc, KH_FOUND); + EXPECT_EQ(id, 222); + + _prefix_map_free(prefix_to_suffixes); } TEST_F(PacketCacheTest, CreatePacketCache) { @@ -89,10 +137,12 @@ TEST_F(PacketCacheTest, AddPacketCacheEntry) { EXPECT_NE(entry, nullptr); ASSERT_EQ(pkt_cache_get_size(pkt_cache), 1u); - // // Get entry by name - Name name_key = name_key_factory(name); - khiter_t k = kh_get_pkt_cache_name(pkt_cache->index_by_name, &name_key); - EXPECT_NE(k, kh_end(pkt_cache->index_by_name)); + // Get entry by name + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *entry = pkt_cache_lookup(pkt_cache, name, msgbuf_pool, + &lookup_result, &entry_id, true); + EXPECT_NE(lookup_result, PKT_CACHE_LU_NONE); } TEST_F(PacketCacheTest, GetCS) { @@ -141,14 +191,11 @@ TEST_F(PacketCacheTest, AddEntryAndLookup) { } TEST_F(PacketCacheTest, AddToPIT) { - // Prepare msgbuf - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); - // Check if entry properly created - pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name); ASSERT_NE(entry, nullptr); EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE); - EXPECT_EQ(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID), true); + EXPECT_TRUE(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID)); ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); @@ -162,9 +209,6 @@ TEST_F(PacketCacheTest, AddToPIT) { } TEST_F(PacketCacheTest, AddToCS) { - // Prepare msgbuf - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); - // Check if entry properly created pkt_cache_entry_t *entry = pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); @@ -191,9 +235,8 @@ TEST_F(PacketCacheTest, AddToCS) { } TEST_F(PacketCacheTest, PitToCS) { - // Prepare msgbuf and PIT entry - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); - pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + // Prepare PIT entry + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name); off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); @@ -224,8 +267,7 @@ TEST_F(PacketCacheTest, PitToCS) { } TEST_F(PacketCacheTest, CsToPIT) { - // Prepare msgbuf and CS entry - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + // Prepare CS entry pkt_cache_entry_t *entry = pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); @@ -237,7 +279,7 @@ TEST_F(PacketCacheTest, CsToPIT) { entry_id); ASSERT_NE(entry, nullptr); EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE); - EXPECT_EQ(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID), true); + EXPECT_TRUE(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID)); ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); @@ -250,14 +292,13 @@ TEST_F(PacketCacheTest, CsToPIT) { } TEST_F(PacketCacheTest, UpdateInPIT) { - // Prepare msgbuf and PIT entry - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); - pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + // Prepare PIT entry + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name); off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); Name new_name; name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); - msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name); + msgbuf_t *new_msgbuf = msgbuf_create(msgbuf_pool, CONN_ID_2, &new_name); // Check if entry properly updated pkt_cache_update_pit(pkt_cache, entry, new_msgbuf); @@ -276,15 +317,14 @@ TEST_F(PacketCacheTest, UpdateInPIT) { } TEST_F(PacketCacheTest, UpdateInCS) { - // Prepare msgbuf and CS entry - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + // Prepare CS entry pkt_cache_entry_t *entry = pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); Name new_name; name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); - msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name); + msgbuf_t *new_msgbuf = msgbuf_create(msgbuf_pool, CONN_ID_2, &new_name); // Check if entry properly updated pkt_cache_update_cs(pkt_cache, msgbuf_pool, entry, new_msgbuf, MSGBUF_ID_2); @@ -304,9 +344,8 @@ TEST_F(PacketCacheTest, UpdateInCS) { } TEST_F(PacketCacheTest, RemoveFromPIT) { - // Prepare msgbuf and PIT entry - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); - pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + // Prepare PIT entry + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name); ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); @@ -324,8 +363,7 @@ TEST_F(PacketCacheTest, RemoveFromPIT) { } TEST_F(PacketCacheTest, RemoveFromCS) { - // Prepare msgbuf and CS entry - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + // Prepare CS entry pkt_cache_entry_t *entry = pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); @@ -351,11 +389,10 @@ TEST_F(PacketCacheTest, RemoveFromCS) { } TEST_F(PacketCacheTest, AddTwoEntriesToCS) { - // Prepare msgbufs - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + // Prepare another msgbuf Name new_name; name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); - msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name); + msgbuf_t *new_msgbuf = msgbuf_create(msgbuf_pool, CONN_ID_2, &new_name); pkt_cache_entry_t *entry_1 = pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); @@ -374,18 +411,17 @@ TEST_F(PacketCacheTest, AddTwoEntriesToCS) { } TEST_F(PacketCacheTest, AggregateInPIT) { - // Prepare msgbufs - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + // Prepare another msgbuf Name new_name; name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); - msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name); + msgbuf_t *new_msgbuf = msgbuf_create(msgbuf_pool, CONN_ID_2, &new_name); // Check if entry properly created (use sleep to get an updated ts) - pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name); Ticks old_lifetime = entry->expire_ts; std::this_thread::sleep_for(std::chrono::milliseconds(100)); bool is_aggregated = - pkt_cache_try_aggregate_in_pit(pkt_cache, entry, new_msgbuf); + pkt_cache_try_aggregate_in_pit(pkt_cache, entry, new_msgbuf, name); Ticks new_lifetime = entry->expire_ts; ASSERT_NE(entry, nullptr); @@ -403,18 +439,17 @@ TEST_F(PacketCacheTest, AggregateInPIT) { } TEST_F(PacketCacheTest, RetransmissionInPIT) { - // Prepare msgbufs (using same connection ID) - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + // Prepare another msgbuf (using same connection ID) Name new_name; name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); - msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, &new_name); + msgbuf_t *new_msgbuf = msgbuf_create(msgbuf_pool, CONN_ID, &new_name); // Check if entry properly created (use sleep to get an updated ts) - pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name); Ticks old_lifetime = entry->expire_ts; std::this_thread::sleep_for(std::chrono::milliseconds(100)); bool is_aggregated = - pkt_cache_try_aggregate_in_pit(pkt_cache, entry, new_msgbuf); + pkt_cache_try_aggregate_in_pit(pkt_cache, entry, new_msgbuf, name); Ticks new_lifetime = entry->expire_ts; ASSERT_NE(entry, nullptr); @@ -433,10 +468,10 @@ TEST_F(PacketCacheTest, RetransmissionInPIT) { TEST_F(PacketCacheTest, LookupExpiredInterest) { // Prepare msgbuf with 0 as interest lifetime - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name, 0); + msgbuf_t *msgbuf = msgbuf_create(msgbuf_pool, CONN_ID, name, 0); // Add to PIT - pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf, name); ASSERT_NE(entry, nullptr); // Wait to make the interest expire @@ -451,7 +486,7 @@ TEST_F(PacketCacheTest, LookupExpiredInterest) { TEST_F(PacketCacheTest, LookupExpiredData) { // Prepare msgbuf with 0 as data expiry time - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name, 0); + msgbuf_t *msgbuf = msgbuf_create(msgbuf_pool, CONN_ID, name, 0); // Add to CS pkt_cache_entry_t *entry = @@ -470,20 +505,20 @@ TEST_F(PacketCacheTest, LookupExpiredData) { TEST_F(PacketCacheTest, GetStaleEntries) { // Add to CS a msgbuf with immediate expiration (i.e. stale) - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name, 0); + msgbuf_t *msgbuf = msgbuf_create(msgbuf_pool, CONN_ID, name, 0); pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); // Add to CS another msgbuf with immediate expiration (i.e. stale) Name name_2; name_CreateFromAddress(&name_2, AF_INET, IPV4_LOOPBACK, IPV4_LEN); - msgbuf_t *msgbuf_2 = msgbuf_factory(msgbuf_pool, CONN_ID, &name_2, 0); + msgbuf_t *msgbuf_2 = msgbuf_create(msgbuf_pool, CONN_ID, &name_2, 0); pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf_2, MSGBUF_ID_2); // Add to CS a msgbuf with 5-seconds expiration (i.e. not stale) Name name_3; name_CreateFromAddress(&name_3, AF_INET6, IPV6_LOOPBACK, IPV6_LEN); msgbuf_t *msgbuf_3 = - msgbuf_factory(msgbuf_pool, CONN_ID, &name_3, FIVE_SECONDS); + msgbuf_create(msgbuf_pool, CONN_ID, &name_3, FIVE_SECONDS); pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf_3, MSGBUF_ID_3); size_t num_stale_entries = pkt_cache_get_num_cs_stale_entries(pkt_cache); @@ -502,7 +537,7 @@ TEST_F(PacketCacheTest, GetMultipleStaleEntries) { inet_pton(AF_INET6, name, (struct in6_addr *)&addr); Name name; name_CreateFromAddress(&name, AF_INET6, addr, IPV6_LEN); - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, i, &name, 0); + msgbuf_t *msgbuf = msgbuf_create(msgbuf_pool, i, &name, 0); pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, i); } @@ -514,7 +549,7 @@ TEST_F(PacketCacheTest, GetMultipleStaleEntries) { inet_pton(AF_INET6, name, (struct in6_addr *)&addr); Name name; name_CreateFromAddress(&name, AF_INET6, addr, IPV6_LEN); - msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, i, &name, FIVE_SECONDS); + msgbuf_t *msgbuf = msgbuf_create(msgbuf_pool, i, &name, FIVE_SECONDS); pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, i); } @@ -522,3 +557,126 @@ TEST_F(PacketCacheTest, GetMultipleStaleEntries) { size_t num_stale_entries = pkt_cache_get_num_cs_stale_entries(pkt_cache); EXPECT_EQ(num_stale_entries, (size_t)NUM_STALES); } + +TEST_F(PacketCacheTest, PerformanceDoubleLookup) { + Name tmp = get_name_from_prefix("b001::0"); + + auto elapsed_time_double = get_execution_time([&]() { + kh_pkt_cache_prefix_t *prefix_to_suffixes = kh_init_pkt_cache_prefix(); + + // Add to hash table + for (int seq = 0; seq < N_OPS; seq++) { + name_SetSegment(&tmp, seq); + _add_suffix(prefix_to_suffixes, name_GetContentName(&tmp), + name_GetSegment(&tmp), name_GetSegment(&tmp)); + } + + // Read from hash table + int rc; + for (int seq = 0; seq < N_OPS; seq++) { + name_SetSegment(&tmp, seq); + _get_suffix(prefix_to_suffixes, name_GetContentName(&tmp), seq, &rc); + } + + _prefix_map_free(prefix_to_suffixes); + }); + std::cout << "Double lookup: " << elapsed_time_double << " ms\n"; +} + +TEST_F(PacketCacheTest, PerformanceCachedLookup) { + Name tmp = get_name_from_prefix("b001::0"); + + auto elapsed_time_single = get_execution_time([&]() { + kh_pkt_cache_prefix_t *prefix_to_suffixes = kh_init_pkt_cache_prefix(); + kh_pkt_cache_suffix_t *suffixes = + _get_suffixes(prefix_to_suffixes, name_GetContentName(&tmp)); + + // Add to hash table + for (int seq = 0; seq < N_OPS; seq++) { + name_SetSegment(&tmp, seq); + __add_suffix(suffixes, name_GetSegment(&tmp), name_GetSegment(&tmp)); + } + + // Read from hash table + int rc; + for (int seq = 0; seq < N_OPS; seq++) { + name_SetSegment(&tmp, seq); + __get_suffix(suffixes, name_GetSegment(&tmp), &rc); + } + + _prefix_map_free(prefix_to_suffixes); + }); + std::cout << "Cached lookup: " << elapsed_time_single << " ms\n"; +} + +TEST_F(PacketCacheTest, PerformanceCachedLookupRandom) { + Name tmp = get_name_from_prefix("b001::0"); + + // Prepare random sequence numbers + std::random_device rd; + std::mt19937 gen(rd()); + uint32_t seqs[N_OPS]; + for (int seq = 0; seq < N_OPS; seq++) seqs[seq] = seq; + std::shuffle(std::begin(seqs), std::end(seqs), gen); + + auto elapsed_time_single_rand = get_execution_time([&]() { + kh_pkt_cache_prefix_t *prefix_to_suffixes = kh_init_pkt_cache_prefix(); + kh_pkt_cache_suffix_t *suffixes = + _get_suffixes(prefix_to_suffixes, name_GetContentName(&tmp)); + + // Add to hash table + for (int seq = 0; seq < N_OPS; seq++) { + name_SetSegment(&tmp, seqs[seq]); + __add_suffix(suffixes, name_GetSegment(&tmp), name_GetSegment(&tmp)); + } + + // Read from hash table + int rc; + for (int seq = 0; seq < N_OPS; seq++) { + name_SetSegment(&tmp, seqs[seq]); + __get_suffix(suffixes, name_GetSegment(&tmp), &rc); + } + + _prefix_map_free(prefix_to_suffixes); + }); + std::cout << "Cached lookup (rand): " << elapsed_time_single_rand << " ms\n"; +} + +TEST_F(PacketCacheTest, Clear) { + Name tmp_name1, tmp_name2; + cs_t *cs = pkt_cache_get_cs(pkt_cache); + + // Create name and add to msgbuf pool + name_Copy(name, &tmp_name1); + name_SetSegment(&tmp_name1, 1); + msgbuf_t *tmp_msgbuf1 = msgbuf_create(msgbuf_pool, CONN_ID_2, &tmp_name1); + + // Create (another) name and add to msgbuf pool + name_Copy(name, &tmp_name2); + name_SetSegment(&tmp_name2, 2); + msgbuf_t *tmp_msgbuf2 = msgbuf_create(msgbuf_pool, CONN_ID_2, &tmp_name2); + + // Add to packet cache (2 entries in the CS, 1 in the PIT) + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + pkt_cache_add_to_pit(pkt_cache, tmp_msgbuf1, &tmp_name1); + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, tmp_msgbuf2, MSGBUF_ID_2); + + // Check stats (before clearing the packet cache) + ASSERT_EQ(pkt_cache_get_size(pkt_cache), 3u); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 2u); + ASSERT_EQ(cs->num_entries, 2u); + ASSERT_EQ(cs->stats.lru.countAdds, 2u); + + // Clear packet cache (i.e. remove content packets from packet cache): + // PIT entry should still be there while CS entries are cleared + pkt_cache_cs_clear(pkt_cache); + cs = pkt_cache_get_cs(pkt_cache); + + // Check stats (after clearing the packet cache) + ASSERT_EQ(pkt_cache_get_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + ASSERT_EQ(cs->num_entries, 0u); + ASSERT_EQ(cs->stats.lru.countAdds, 0u); +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/test/test-pool.cc b/hicn-light/src/hicn/test/test-pool.cc index c631415ca..8cd891d6a 100644 --- a/hicn-light/src/hicn/test/test-pool.cc +++ b/hicn-light/src/hicn/test/test-pool.cc @@ -25,7 +25,7 @@ extern "C" { #define WITH_TESTS -#include <hicn/base/pool.h> +#include <hicn/util/pool.h> } /* diff --git a/hicn-light/src/hicn/test/test-ring.cc b/hicn-light/src/hicn/test/test-ring.cc index 51f1f5327..ab96d76c0 100644 --- a/hicn-light/src/hicn/test/test-ring.cc +++ b/hicn-light/src/hicn/test/test-ring.cc @@ -25,7 +25,7 @@ extern "C" { #define WITH_TESTS -#include <hicn/base/ring.h> +#include <hicn/util/ring.h> } #define DEFAULT_SIZE 10UL diff --git a/hicn-light/src/hicn/test/test-subscription.cc b/hicn-light/src/hicn/test/test-subscription.cc index 18ef60c0d..f89254e67 100644 --- a/hicn-light/src/hicn/test/test-subscription.cc +++ b/hicn-light/src/hicn/test/test-subscription.cc @@ -6,7 +6,7 @@ extern "C" { #include <hicn/core/subscription.h> -#include <hicn/base/vector.h> +#include <hicn/util/vector.h> } static inline unsigned CONN_ID = 1; diff --git a/hicn-light/src/hicn/test/test-utils.h b/hicn-light/src/hicn/test/test-utils.h new file mode 100644 index 000000000..577629584 --- /dev/null +++ b/hicn-light/src/hicn/test/test-utils.h @@ -0,0 +1,26 @@ +#pragma once + +#include <vector> +#include <thread> +#include <numeric> + +static constexpr int N_RUNS = 100; + +// Utility function for time execution calculation +template <typename F, typename... Args> +double get_execution_time(F func, Args &&...args) { + std::vector<float> execution_times; + + for (int i = 0; i < N_RUNS; i++) { + auto start = std::chrono::high_resolution_clock::now(); + func(std::forward<Args>(args)...); + auto end = std::chrono::high_resolution_clock::now(); + + std::chrono::duration<double, std::milli> ms = end - start; + execution_times.emplace_back(ms.count()); + } + + // Calculate average + return std::reduce(execution_times.begin(), execution_times.end()) / + execution_times.size(); +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/test/test-vector.cc b/hicn-light/src/hicn/test/test-vector.cc index fb30a8228..dda71fd0c 100644 --- a/hicn-light/src/hicn/test/test-vector.cc +++ b/hicn-light/src/hicn/test/test-vector.cc @@ -15,26 +15,12 @@ #include <gtest/gtest.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <unistd.h> -#include <netinet/in.h> - extern "C" { -#define WITH_TESTS -#include <hicn/base/vector.h> +#include <hicn/util/vector.h> } -/* - * TODO - * - test max_size - */ - -#define DEFAULT_SIZE 10 -const size_t N_ELEMENTS = 5; +static constexpr size_t DEFAULT_SIZE = 10; +static constexpr size_t N_ELEMENTS = 5; class VectorTest : public ::testing::Test { protected: @@ -44,58 +30,62 @@ class VectorTest : public ::testing::Test { int *vector = NULL; }; -/* TEST: Vector allocation and initialization */ -TEST_F(VectorTest, VectorAllocate) { - /* Allocated size should be the next power of two */ +TEST_F(VectorTest, VectorAllocateAndResize) { + // Allocated size should be the next power of two EXPECT_EQ(vector_get_alloc_size(vector), 16UL); - /* Setting elements within the allocated size should not trigger a resize */ + // Setting elements within the allocated size should not trigger a resize vector_ensure_pos(vector, 15); EXPECT_EQ(vector_get_alloc_size(vector), 16UL); - /* Setting elements after should through */ + // Setting elements after should through vector_ensure_pos(vector, 16); EXPECT_EQ(vector_get_alloc_size(vector), 32UL); - - /* Check that free indices and bitmaps are correctly updated */ } TEST_F(VectorTest, VectorSize) { - vector_push(vector, 109); - int size = vector_len(vector); - EXPECT_EQ(size, 1); - vector_push(vector, 109); - size = vector_len(vector); - EXPECT_EQ(size, 2); - vector_push(vector, 109); - size = vector_len(vector); - EXPECT_EQ(size, 3); + EXPECT_EQ(vector_len(vector), 0); + + // Check size after pushing one element + vector_push(vector, 1); + EXPECT_EQ(vector_len(vector), 1); + + // Check size after pushing additional elements + vector_push(vector, 2); + vector_push(vector, 3); + EXPECT_EQ(vector_len(vector), 3); + + // Try adding multiple elements + const int n_elements_to_add = 5; + size_t expected_new_len = vector_len(vector) + n_elements_to_add; + for (int i = 0; i < n_elements_to_add; i++) vector_push(vector, i); + EXPECT_EQ(vector_len(vector), expected_new_len); } TEST_F(VectorTest, VectorCheckValue) { + // Add elements vector_push(vector, 109); vector_push(vector, 200); - EXPECT_EQ(vector[0], 109); - EXPECT_EQ(vector[1], 200); -} - -TEST_F(VectorTest, VectorEnsurePos) { - printf(" %p\n", vector); - vector_ensure_pos(vector, 1025); - for (int i = 0; i < 1025; i++) { - // printf("i %d\n", i); - // printf (" %p\n", vector); - vector_push(vector, i); - } - int size = vector_len(vector); - EXPECT_EQ(size, 1025); + EXPECT_EQ(vector_at(vector, 0), 109); + EXPECT_EQ(vector_at(vector, 1), 200); + + // Update element + vector_set(vector, 1, 400); + EXPECT_EQ(vector_at(vector, 1), 400); + + // Add at last available position + size_t prev_size = vector_len(vector); + vector_set(vector, vector_len(vector) - 1, 123); + EXPECT_EQ(vector_at(vector, vector_len(vector) - 1), 123); + EXPECT_EQ(prev_size, vector_len(vector)) << "Size should not have changed"; } TEST_F(VectorTest, RemoveElement) { // Populate vector for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(vector, i); EXPECT_EQ(vector_len(vector), N_ELEMENTS); - for (size_t i = 0; i < vector_len(vector); i++) EXPECT_EQ(vector[i], (int)i); + for (size_t i = 0; i < vector_len(vector); i++) + EXPECT_EQ(vector_at(vector, i), (int)i); // Remove element int value_to_remove = 3; @@ -104,15 +94,30 @@ TEST_F(VectorTest, RemoveElement) { EXPECT_EQ(vector_len(vector), N_ELEMENTS - 1); EXPECT_EQ(num_removed, 1); for (size_t i = 0; i < vector_len(vector); i++) - EXPECT_NE(vector[i], value_to_remove); + EXPECT_NE(vector_at(vector, i), value_to_remove); +} + +TEST_F(VectorTest, RemoveNonExistingElement) { + // Push some initial values + vector_push(vector, 1); + vector_push(vector, 2); + vector_push(vector, 3); + EXPECT_EQ(vector_len(vector), 3); + + // Remove non-existing element + int num_removed = vector_remove_unordered(vector, 5); + EXPECT_EQ(num_removed, 0); + size_t prev_size = vector_len(vector); + EXPECT_EQ(prev_size, vector_len(vector)) << "Size should not have changed"; } TEST_F(VectorTest, RemoveDuplicatedElement) { // Populate vector for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(vector, i); EXPECT_EQ(vector_len(vector), N_ELEMENTS); - for (size_t i = 0; i < vector_len(vector); i++) EXPECT_EQ(vector[i], (int)i); - vector[0] = 3; // Duplicate element + for (size_t i = 0; i < vector_len(vector); i++) + EXPECT_EQ(vector_at(vector, i), (int)i); + vector_set(vector, 0, 3); // Duplicate element // Remove (duplicated) elements int value_to_remove = 3; @@ -121,7 +126,7 @@ TEST_F(VectorTest, RemoveDuplicatedElement) { EXPECT_EQ(vector_len(vector), N_ELEMENTS - 2); EXPECT_EQ(num_removed, 2); for (size_t i = 0; i < vector_len(vector); i++) - EXPECT_NE(vector[i], value_to_remove); + EXPECT_NE(vector_at(vector, i), value_to_remove); } TEST_F(VectorTest, Iterate) { @@ -139,10 +144,89 @@ TEST_F(VectorTest, MultipleResize) { for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(small_vector, i); - for (size_t i = 0; i < N_ELEMENTS; i++) EXPECT_EQ(small_vector[i], (int)i); + for (size_t i = 0; i < N_ELEMENTS; i++) + EXPECT_EQ(vector_at(small_vector, i), (int)i); EXPECT_EQ(vector_len(small_vector), 5UL); EXPECT_EQ(vector_get_alloc_size(small_vector), 8UL); vector_free(small_vector); +} + +TEST_F(VectorTest, MaxSize) { + const int max_size = 4; + + // Fill the vector until max size is reached + int *small_vector; + vector_init(small_vector, 2, max_size); + for (int i = 0; i < max_size; i++) vector_push(small_vector, i); + + // Try expanding or appending elements should fail + int rc = vector_ensure_pos(small_vector, max_size); + EXPECT_EQ(rc, -1); + rc = vector_push(small_vector, 123); + EXPECT_EQ(rc, -1); + + vector_free(small_vector); +} + +TEST_F(VectorTest, Contains) { + // No elements + EXPECT_EQ(vector_contains(vector, 1), false); + + // Push one element + vector_push(vector, 1); + EXPECT_EQ(vector_contains(vector, 1), true); + + // Update element + vector_set(vector, 0, 2); + EXPECT_EQ(vector_contains(vector, 1), false); + EXPECT_EQ(vector_contains(vector, 2), true); +} + +TEST_F(VectorTest, Remove) { + // Remove element at invalid position + int rc = vector_remove_at(vector, 2); + EXPECT_EQ(rc, -1); // Failure + + // Push two elements and remove the second one + vector_push(vector, 1); + vector_push(vector, 2); + rc = vector_remove_at(vector, 1); + EXPECT_EQ(rc, 0); // Success + EXPECT_EQ(vector_len(vector), 1); + + // Push another element: it should replace the previous one + vector_push(vector, 3); + EXPECT_EQ(vector_len(vector), 2); + EXPECT_EQ(vector_at(vector, 1), 3); +} + +TEST_F(VectorTest, RemoveInTheMiddle) { + for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(vector, i); + + // Remove element in central position + int rc = vector_remove_at(vector, 2); + EXPECT_EQ(rc, 0); // Success + EXPECT_EQ(vector_contains(vector, 2), false); + EXPECT_EQ(vector_len(vector), N_ELEMENTS - 1); + + // Check if elements have been shifted (preserving the order) + int expected[] = {0, 1, 3, 4}; + for (int i = 0; i < vector_len(vector); i++) + EXPECT_EQ(vector_at(vector, i), expected[i]); +} + +TEST_F(VectorTest, Reset) { + vector_push(vector, 1); + vector_push(vector, 2); + EXPECT_EQ(vector_len(vector), 2); + + vector_reset(vector); + EXPECT_EQ(vector_len(vector), 0); + + vector_push(vector, 5); + EXPECT_EQ(vector_len(vector), 1); + EXPECT_EQ(vector_contains(vector, 5), true); + EXPECT_EQ(vector_at(vector, 0), 5); }
\ No newline at end of file diff --git a/hicn-plugin/includes/vpp_plugins/hicn/error.h b/hicn-plugin/includes/vpp_plugins/hicn/error.h index a8a941a79..af9f5da46 100644 --- a/hicn-plugin/includes/vpp_plugins/hicn/error.h +++ b/hicn-plugin/includes/vpp_plugins/hicn/error.h @@ -25,67 +25,69 @@ #define foreach_hicn_error \ _ (NONE, 0, "Ok") \ _ (UNSPECIFIED, -128, "Unspecified Error") \ - _ (FACE_NOT_FOUND, -129, "Face not found in Face table") \ - _ (FACE_NULL, -130, "Face null") \ - _ (FACE_IP_ADJ_NOT_FOUND, -131, "Ip adjacecny for face not found") \ - _ (FACE_HW_INT_NOT_FOUND, -132, "Hardware interface not found") \ - _ (FACE_NOMEM, -133, "Face table is full") \ - _ (FACE_NO_GLOBAL_IP, -134, "No global ip address for face") \ - _ (FACE_NOT_FOUND_IN_ENTRY, -135, "Face not found in entry") \ - _ (FACE_ALREADY_DELETED, -136, "Face alredy deleted") \ - _ (FACE_ALREADY_CREATED, -137, "Face alredy created") \ - _ (FWD_NOT_ENABLED, -138, "hICN forwarder not enabled") \ - _ (FWD_ALREADY_ENABLED, -139, "hICN forwarder alredy enabled") \ - _ (PARSER_UNSUPPORTED_PROTO, -140, "Unsupported protocol") \ - _ (PARSER_PKT_INVAL, -141, "Packet null") \ - _ (PIT_CONFIG_MINLT_OOB, -142, "Min lifetime ouf of bounds") \ - _ (PIT_CONFIG_MAXLT_OOB, -143, "Max lifetime ouf of bounds") \ - _ (PIT_CONFIG_MINMAXLT, -144, "Min lifetime grater than max lifetime") \ - _ (PIT_CONFIG_DFTLT_OOB, -145, "Default lifetime ouf of bounds") \ - _ (PIT_CONFIG_SIZE_OOB, -146, "Pit size ouf of bounds") \ - _ (CS_CONFIG_SIZE_OOB, -147, "CS size ouf of bounds") \ - _ (CS_CONFIG_RESERVED_OOB, -148, \ + _ (FACE_NOT_FOUND, -1000, "Face not found in Face table") \ + _ (FACE_NULL, -1001, "Face null") \ + _ (FACE_IP_ADJ_NOT_FOUND, -1002, "Ip adjacecny for face not found") \ + _ (FACE_HW_INT_NOT_FOUND, -1003, "Hardware interface not found") \ + _ (FACE_NOMEM, -1004, "Face table is full") \ + _ (FACE_NO_GLOBAL_IP, -1005, "No global ip address for face") \ + _ (FACE_NOT_FOUND_IN_ENTRY, -1006, "Face not found in entry") \ + _ (FACE_ALREADY_DELETED, -1007, "Face alredy deleted") \ + _ (FACE_ALREADY_CREATED, -1008, "Face alredy created") \ + _ (FWD_NOT_ENABLED, -2000, "hICN forwarder not enabled") \ + _ (FWD_ALREADY_ENABLED, -2001, "hICN forwarder alredy enabled") \ + _ (PARSER_UNSUPPORTED_PROTO, -3000, "Unsupported protocol") \ + _ (PARSER_PKT_INVAL, -3001, "Packet null") \ + _ (PARSER_MAPME_PACKET, -3002, "Packet is mapme") \ + _ (PIT_CONFIG_MINLT_OOB, -4000, "Min lifetime ouf of bounds") \ + _ (PIT_CONFIG_MAXLT_OOB, -4001, "Max lifetime ouf of bounds") \ + _ (PIT_CONFIG_MINMAXLT, -4002, "Min lifetime grater than max lifetime") \ + _ (PIT_CONFIG_DFTLT_OOB, -4003, "Default lifetime ouf of bounds") \ + _ (PIT_CONFIG_SIZE_OOB, -4004, "Pit size ouf of bounds") \ + _ (CS_CONFIG_SIZE_OOB, -5000, "CS size ouf of bounds") \ + _ (CS_CONFIG_RESERVED_OOB, -5001, \ "Reseved CS must be between 0 and 100 (excluded)") \ - _ (DPO_CTX_NHOPS_NS, -149, "No space for additional next hop") \ - _ (DPO_CTX_NHOPS_EXISTS, -150, "Next hop already in the route") \ - _ (DPO_CTX_NOT_FOUND, -151, "Dpo context not found") \ - _ (DPO_MGR_ID_NOT_VALID, -152, "Dpo id for strategy and context not valid") \ - _ (HASHTB_HASH_NOT_FOUND, -153, "Hash not found in hash table") \ - _ (HASHTB_HASH_INVAL, -154, "Error while calculating the hash") \ - _ (HASHTB_NOMEM, -155, "Unable to allocate new buckets or nodes") \ - _ (HASHTB_INVAL, -156, "Invalid argument") \ - _ (HASHTB_KEY_INVAL, -157, "Invalid hashtb key") \ - _ (HASHTB_EXIST, -158, "Hash already in hashtable") \ - _ (ROUTE_INVAL, -159, "Invalid face id and weight") \ - _ (ROUTE_NO_LD, -160, "Expected load balance dpo") \ - _ (ROUTE_MLT_LD, -161, "Unexpected mulitple buckets in load balance dpo") \ - _ (ROUTE_NO_INSERT, -162, "Unable to insert a new FIB entry") \ - _ (ROUTE_DPO_NO_HICN, -163, "Dpo is not of type hICN") \ - _ (ROUTE_NOT_FOUND, -164, "Route not found in FIB") \ - _ (ROUTE_NOT_UPDATED, -165, "Unable to update route") \ - _ (ROUTE_ALREADY_EXISTS, -166, "Route already in FIB") \ - _ (CLI_INVAL, -167, "Invalid input") \ - _ (IPS_ADDR_TYPE_NONUNIFORM, -168, \ + _ (DPO_CTX_NHOPS_NS, -6000, "No space for additional next hop") \ + _ (DPO_CTX_NHOPS_EXISTS, -6001, "Next hop already in the route") \ + _ (DPO_CTX_NOT_FOUND, -6002, "Dpo context not found") \ + _ (DPO_MGR_ID_NOT_VALID, -6003, \ + "Dpo id for strategy and context not valid") \ + _ (HASHTB_HASH_NOT_FOUND, -7000, "Hash not found in hash table") \ + _ (HASHTB_HASH_INVAL, -7001, "Error while calculating the hash") \ + _ (HASHTB_NOMEM, -7002, "Unable to allocate new buckets or nodes") \ + _ (HASHTB_INVAL, -7003, "Invalid argument") \ + _ (HASHTB_KEY_INVAL, -7004, "Invalid hashtb key") \ + _ (HASHTB_EXIST, -7005, "Hash already in hashtable") \ + _ (ROUTE_INVAL, -8000, "Invalid face id and weight") \ + _ (ROUTE_NO_LD, -8001, "Expected load balance dpo") \ + _ (ROUTE_MLT_LD, -8002, "Unexpected mulitple buckets in load balance dpo") \ + _ (ROUTE_NO_INSERT, -8003, "Unable to insert a new FIB entry") \ + _ (ROUTE_DPO_NO_HICN, -8004, "Dpo is not of type hICN") \ + _ (ROUTE_NOT_FOUND, -8005, "Route not found in FIB") \ + _ (ROUTE_NOT_UPDATED, -8006, "Unable to update route") \ + _ (ROUTE_ALREADY_EXISTS, -8007, "Route already in FIB") \ + _ (CLI_INVAL, -9000, "Invalid input") \ + _ (IPS_ADDR_TYPE_NONUNIFORM, -10000, \ "Src and dst addr have different ip types") \ - _ (FACE_TYPE_EXISTS, -169, "Face type already registered") \ - _ (NO_BUFFERS, -170, "No vlib_buffer available for packet cloning.") \ - _ (NOT_IMPLEMENTED, -171, "Function not yet implemented") \ - _ (IFACE_IP_ADJ_NOT_FOUND, -172, \ + _ (FACE_TYPE_EXISTS, -11000, "Face type already registered") \ + _ (NO_BUFFERS, -12000, "No vlib_buffer available for packet cloning.") \ + _ (NOT_IMPLEMENTED, -13000, "Function not yet implemented") \ + _ (IFACE_IP_ADJ_NOT_FOUND, -14000, \ "IP adjacency on incomplete face not available") \ - _ (APPFACE_ALREADY_ENABLED, -173, \ + _ (APPFACE_ALREADY_ENABLED, -15000, \ "Application face already enabled on interface") \ - _ (APPFACE_FEATURE, -174, "Error while enabling app face feature") \ - _ (APPFACE_NOT_FOUND, -175, "Application face not found") \ - _ (APPFACE_PROD_PREFIX_NULL, -176, \ + _ (APPFACE_FEATURE, -15001, "Error while enabling app face feature") \ + _ (APPFACE_NOT_FOUND, -15002, "Application face not found") \ + _ (APPFACE_PROD_PREFIX_NULL, -15003, \ "Prefix must not be null for producer face") \ - _ (STRATEGY_NH_NOT_FOUND, -177, "Next hop not found") \ - _ (MW_STRATEGY_SET, -178, "Error while setting weight for next hop") \ - _ (STRATEGY_NOT_FOUND, -179, "Strategy not found") \ - _ (UDP_TUNNEL_NOT_FOUND, -180, "Udp tunnel not found") \ - _ (UDP_TUNNEL_SRC_DST_TYPE, -181, \ + _ (STRATEGY_NH_NOT_FOUND, -16000, "Next hop not found") \ + _ (MW_STRATEGY_SET, -16001, "Error while setting weight for next hop") \ + _ (STRATEGY_NOT_FOUND, -16002, "Strategy not found") \ + _ (UDP_TUNNEL_NOT_FOUND, -17000, "Udp tunnel not found") \ + _ (UDP_TUNNEL_SRC_DST_TYPE, -17001, \ "Src and dst addresses have different type (ipv4 and ipv6)") \ - _ (MAPME_NEXT_HOP_ADDED, -182, "Next hop added to mapme") \ - _ (MAPME_NEXT_HOP_NOT_ADDED, -183, "Next hop added to mapme") + _ (MAPME_NEXT_HOP_ADDED, -18000, "Next hop added to mapme") \ + _ (MAPME_NEXT_HOP_NOT_ADDED, -18001, "Next hop added to mapme") typedef enum { diff --git a/hicn-plugin/src/CMakeLists.txt b/hicn-plugin/src/CMakeLists.txt index 2141ec596..e071b3b9d 100644 --- a/hicn-plugin/src/CMakeLists.txt +++ b/hicn-plugin/src/CMakeLists.txt @@ -59,6 +59,7 @@ set(HICN_PLUGIN_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/faces/app/face_prod_node.c ${CMAKE_CURRENT_SOURCE_DIR}/faces/app/face_app_cli.c ${CMAKE_CURRENT_SOURCE_DIR}/pg.c + ${CMAKE_CURRENT_SOURCE_DIR}/pg_node.c ${CMAKE_CURRENT_SOURCE_DIR}/strategies/dpo_mw.c ${CMAKE_CURRENT_SOURCE_DIR}/strategies/strategy_mw.c ${CMAKE_CURRENT_SOURCE_DIR}/strategies/strategy_mw_cli.c @@ -83,6 +84,7 @@ set(HICN_PLUGIN_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/pcs.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn_api.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_buffer_flags.h ${CMAKE_CURRENT_SOURCE_DIR}/state.h ${CMAKE_CURRENT_SOURCE_DIR}/infra.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn_msg_enum.h @@ -99,6 +101,7 @@ set(HICN_PLUGIN_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/error.h ${CMAKE_CURRENT_SOURCE_DIR}/face_db.h ${CMAKE_CURRENT_SOURCE_DIR}/faces/face.h + ${CMAKE_CURRENT_SOURCE_DIR}/faces/face_flags.h ${CMAKE_CURRENT_SOURCE_DIR}/faces/face_node.h ${CMAKE_CURRENT_SOURCE_DIR}/faces/iface_node.h ${CMAKE_CURRENT_SOURCE_DIR}/faces/inlines.h diff --git a/hicn-plugin/src/cli.c b/hicn-plugin/src/cli.c index cd45607ca..f743f6362 100644 --- a/hicn-plugin/src/cli.c +++ b/hicn-plugin/src/cli.c @@ -585,13 +585,15 @@ hicn_cli_pgen_server_set_command_fn (vlib_main_t *vm, unformat_input_t *main_input, vlib_cli_command_t *cmd) { - clib_error_t *cl_err; - int rv = HICN_ERROR_NONE; - hicnpg_server_main_t *pg_main = &hicnpg_server_main; int payload_size = 1440; u32 sw_if_index = ~0; vnet_main_t *vnm = vnet_get_main (); - fib_prefix_t *prefix = calloc (1, sizeof (fib_prefix_t)); + fib_prefix_t prefix; + u32 hicnpg_server_index; + ip46_address_t locator; + + locator.as_u64[0] = 0; + locator.as_u64[1] = 0; /* Get a line of input. */ unformat_input_t _line_input, *line_input = &_line_input; @@ -601,7 +603,7 @@ hicn_cli_pgen_server_set_command_fn (vlib_main_t *vm, while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat (line_input, "name %U/%d", unformat_ip46_address, - &prefix->fp_addr, IP46_TYPE_ANY, &prefix->fp_len)) + &prefix.fp_addr, IP46_TYPE_ANY, &prefix.fp_len)) { ; } @@ -618,6 +620,11 @@ hicn_cli_pgen_server_set_command_fn (vlib_main_t *vm, { ; } + else if (unformat (line_input, "dst %U", unformat_ip46_address, + &locator, IP46_TYPE_ANY)) + { + ; + } else { return (clib_error_return (0, "Unknown input '%U'", @@ -628,70 +635,45 @@ hicn_cli_pgen_server_set_command_fn (vlib_main_t *vm, } /* Attach our packet-gen node for ip4 udp local traffic */ - if ((prefix->fp_addr.ip6.as_u64[0] == (u64) 0 && - prefix->fp_addr.ip6.as_u64[1] == 0) || - payload_size == 0 || sw_if_index == ~0) + if ((prefix.fp_addr.ip6.as_u64[0] == (u64) 0 && + prefix.fp_addr.ip6.as_u64[1] == 0) || + payload_size == 0 || sw_if_index == ~0 || + ip46_address_is_zero (&locator)) { - return clib_error_return (0, "Error: must supply local port, payload " + return clib_error_return (0, "Error: must supply locator, payload " "size and incoming hICN prefix"); } // Remove bits that are out of the subnet - if (ip46_address_is_ip4 (&prefix->fp_addr)) + if (ip46_address_is_ip4 (&prefix.fp_addr)) { ip4_address_t mask; - ip4_preflen_to_mask (prefix->fp_len, &mask); - prefix->fp_addr.ip4.as_u32 = prefix->fp_addr.ip4.as_u32 & mask.as_u32; - prefix->fp_proto = FIB_PROTOCOL_IP4; + ip4_preflen_to_mask (prefix.fp_len, &mask); + prefix.fp_addr.ip4.as_u32 = prefix.fp_addr.ip4.as_u32 & mask.as_u32; + prefix.fp_proto = FIB_PROTOCOL_IP4; } else { ip6_address_t mask; - ip6_preflen_to_mask (prefix->fp_len, &mask); - prefix->fp_addr.ip6.as_u64[0] = - prefix->fp_addr.ip6.as_u64[0] & mask.as_u64[0]; - prefix->fp_addr.ip6.as_u64[1] = - prefix->fp_addr.ip6.as_u64[1] & mask.as_u64[1]; - prefix->fp_proto = FIB_PROTOCOL_IP6; + ip6_preflen_to_mask (prefix.fp_len, &mask); + prefix.fp_addr.ip6.as_u64[0] = + prefix.fp_addr.ip6.as_u64[0] & mask.as_u64[0]; + prefix.fp_addr.ip6.as_u64[1] = + prefix.fp_addr.ip6.as_u64[1] & mask.as_u64[1]; + prefix.fp_proto = FIB_PROTOCOL_IP6; } - /* Allocate the buffer with the actual content payload TLV */ - int n_buf = vlib_buffer_alloc (vm, &pg_main->pgen_svr_buffer_idx, 1); - - if (n_buf == 0) + fib_protocol_t dest_proto = + ip46_address_is_ip4 (&locator) ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6; + if (prefix.fp_proto != dest_proto) { - return (clib_error_return (0, "Impossible to allocate paylod buffer.")); + return clib_error_return (0, "Error: prefix and locator must be of the " + "same protocol"); } - vlib_buffer_t *rb = NULL; - rb = vlib_get_buffer (vm, pg_main->pgen_svr_buffer_idx); - - pg_main->pgen_srv_hicn_name = prefix; - - /* Initialize the buffer data with zeros */ - memset (rb->data, 0, payload_size); - rb->current_length = payload_size; - - vnet_feature_enable_disable ("ip4-unicast", "hicnpg-server", sw_if_index, 1, - 0, 0); - vnet_feature_enable_disable ("ip6-unicast", "hicnpg-server", sw_if_index, 1, - 0, 0); - - switch (rv) - { - case 0: - cl_err = 0; - break; - - case VNET_API_ERROR_UNIMPLEMENTED: - cl_err = clib_error_return (0, "Unimplemented, NYI"); - break; - - default: - cl_err = clib_error_return (0, "hicn pgen server returned %d", rv); - } - - return cl_err; + // Create hicnpg_server + return hicnpg_server_add_and_lock (&prefix, &hicnpg_server_index, &locator, + payload_size); } static clib_error_t * @@ -855,7 +837,7 @@ VLIB_CLI_COMMAND (hicn_cli_pgen_client_set_command, static) = { VLIB_CLI_COMMAND (hicn_cli_pgen_server_set_command, static) = { .path = "hicn pgen server", .short_help = "hicn pgen server name <prefix> intfc <interest in-interface> " - "size <payload_size>", + "dst <ip_address> size <payload_size>", .long_help = "Run hicn in packet-gen server mode\n", .function = hicn_cli_pgen_server_set_command_fn, }; diff --git a/hicn-plugin/src/data_fwd_node.c b/hicn-plugin/src/data_fwd_node.c index 6acb5915b..a3f1a592f 100644 --- a/hicn-plugin/src/data_fwd_node.c +++ b/hicn-plugin/src/data_fwd_node.c @@ -91,7 +91,6 @@ hicn_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, u16 namelen; u32 bi0; u32 next0 = HICN_DATA_FWD_NEXT_ERROR_DROP; - hicn_name_t name; hicn_header_t *hicn0; hicn_buffer_t *hicnb0; hicn_hash_node_t *node0; @@ -124,15 +123,15 @@ hicn_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, /* Get hicn buffer and state */ hicnb0 = hicn_get_buffer (b0); + hicn0 = (hicn_header_t *) (vlib_buffer_get_current (b0)); hicn_get_internal_state (hicnb0, pitcs, &node0, &strategy_vft0, &dpo_vft0, &dpo_ctx_id0, &hash_entry0); - ret = hicn_data_parse_pkt (b0, &name, &namelen, &hicn0, &isv6); + hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen); + isv6 = hicn_buffer_is_v6 (b0); pitp = hicn_pit_get_data (node0); - nameptr = (u8 *) (&name); if (PREDICT_FALSE ( - ret != HICN_ERROR_NONE || !hicn_node_compare (nameptr, namelen, node0) || (hash_entry0->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY))) { @@ -182,7 +181,7 @@ hicn_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, { hicn_data_fwd_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->pkt_type = HICN_PKT_TYPE_CONTENT; + t->pkt_type = HICN_PACKET_TYPE_DATA; t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; t->next_index = next0; clib_memcpy (t->packet_data, vlib_buffer_get_current (b0), @@ -442,7 +441,7 @@ hicn_satisfy_faces (vlib_main_t *vm, u32 bi0, hicn_pcs_entry_t *pitp, { hicn_data_fwd_trace_t *t = vlib_add_trace (vm, node, h0, sizeof (*t)); - t->pkt_type = HICN_PKT_TYPE_CONTENT; + t->pkt_type = HICN_PACKET_TYPE_DATA; t->sw_if_index = vnet_buffer (h0)->sw_if_index[VLIB_RX]; t->next_index = next0; clib_memcpy (t->packet_data, vlib_buffer_get_current (h0), @@ -453,7 +452,7 @@ hicn_satisfy_faces (vlib_main_t *vm, u32 bi0, hicn_pcs_entry_t *pitp, { hicn_data_fwd_trace_t *t = vlib_add_trace (vm, node, h1, sizeof (*t)); - t->pkt_type = HICN_PKT_TYPE_CONTENT; + t->pkt_type = HICN_PACKET_TYPE_DATA; t->sw_if_index = vnet_buffer (h1)->sw_if_index[VLIB_RX]; t->next_index = next1; clib_memcpy (t->packet_data, vlib_buffer_get_current (h1), @@ -491,7 +490,7 @@ hicn_satisfy_faces (vlib_main_t *vm, u32 bi0, hicn_pcs_entry_t *pitp, { hicn_data_fwd_trace_t *t = vlib_add_trace (vm, node, h0, sizeof (*t)); - t->pkt_type = HICN_PKT_TYPE_CONTENT; + t->pkt_type = HICN_PACKET_TYPE_DATA; t->sw_if_index = vnet_buffer (h0)->sw_if_index[VLIB_RX]; t->next_index = next0; clib_memcpy (t->packet_data, vlib_buffer_get_current (h0), @@ -607,4 +606,4 @@ VLIB_REGISTER_NODE(hicn_data_fwd_node) = * fd.io coding-style-patch-verification: ON * * Local Variables: eval: (c-set-style "gnu") End: - */ + */
\ No newline at end of file diff --git a/hicn-plugin/src/data_input_node.c b/hicn-plugin/src/data_input_node.c index 46fda1080..65bba7b1b 100644 --- a/hicn-plugin/src/data_input_node.c +++ b/hicn-plugin/src/data_input_node.c @@ -80,6 +80,7 @@ hicn_data_input_set_adj_index (vlib_buffer_t *b, const ip46_address_t *dst_addr, const hicn_dpo_ctx_t *dpo_ctx) { + CLIB_UNUSED (u8 set) = 0; for (u8 pos = 0; pos < dpo_ctx->entry_count; pos++) { hicn_face_t *face = hicn_dpoi_get_from_idx (dpo_ctx->next_hops[pos]); @@ -87,9 +88,12 @@ hicn_data_input_set_adj_index (vlib_buffer_t *b, if (ip46_address_cmp (&(face->nat_addr), dst_addr) == 0) { vnet_buffer (b)->ip.adj_index[VLIB_RX] = face->dpo.dpoi_index; + set = 1; break; } } + + ASSERT (set == 1); } static uword @@ -147,7 +151,7 @@ hicn_data_input_ip6_fn (vlib_main_t *vm, vlib_node_runtime_t *node, src_addr1 = &ip1->src_address; ip46_address_set_ip6 (&dst_addr0, &ip0->dst_address); - ip46_address_set_ip6 (&dst_addr0, &ip1->dst_address); + ip46_address_set_ip6 (&dst_addr1, &ip1->dst_address); ip_lookup_set_buffer_fib_index (im->fib_index_by_sw_if_index, p0); ip_lookup_set_buffer_fib_index (im->fib_index_by_sw_if_index, p1); @@ -701,4 +705,4 @@ VNET_FEATURE_INIT (hicn_data_input_ip4_arc, static) = { .arc_name = "ip4-local", .node_name = "hicn-data-input-ip4", .runs_before = VNET_FEATURES ("ip4-local-end-of-arc"), -}; +};
\ No newline at end of file diff --git a/hicn-plugin/src/data_pcslookup_node.c b/hicn-plugin/src/data_pcslookup_node.c index 69278c306..95db66f54 100644 --- a/hicn-plugin/src/data_pcslookup_node.c +++ b/hicn-plugin/src/data_pcslookup_node.c @@ -63,17 +63,13 @@ hicn_data_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, while (n_left_from > 0 && n_left_to_next > 0) { vlib_buffer_t *b0; - u8 isv6; u8 *nameptr; u16 namelen; u32 bi0; u32 next0 = HICN_DATA_PCSLOOKUP_NEXT_ERROR_DROP; u64 name_hash = 0; - hicn_name_t name; - hicn_header_t *hicn0 = NULL; u32 node_id0 = 0; index_t dpo_ctx_id0 = 0; - int ret0; u8 vft_id0 = 0; u8 is_cs0; u8 hash_entry_id = 0; @@ -104,13 +100,11 @@ hicn_data_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, /* Incr packet counter */ stats.pkts_processed += 1; - ret0 = hicn_data_parse_pkt (b0, &name, &namelen, &hicn0, &isv6); - nameptr = (u8 *) (&name); + hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen); if (PREDICT_TRUE ( - ret0 == HICN_ERROR_NONE && hicn_hashtb_fullhash (nameptr, namelen, &name_hash) == - HICN_ERROR_NONE)) + HICN_ERROR_NONE)) { int res = hicn_hashtb_lookup_node ( rt->pitcs->pcs_table, nameptr, namelen, name_hash, @@ -154,7 +148,7 @@ hicn_data_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, { hicn_data_pcslookup_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->pkt_type = HICN_PKT_TYPE_CONTENT; + t->pkt_type = HICN_PACKET_TYPE_DATA; t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; t->next_index = next0; } @@ -216,4 +210,4 @@ VLIB_REGISTER_NODE(hicn_data_pcslookup_node) = * fd.io coding-style-patch-verification: ON * * Local Variables: eval: (c-set-style "gnu") End: - */ + */
\ No newline at end of file diff --git a/hicn-plugin/src/faces/app/face_prod_node.c b/hicn-plugin/src/faces/app/face_prod_node.c index 5d2b54040..e3241e477 100644 --- a/hicn-plugin/src/faces/app/face_prod_node.c +++ b/hicn-plugin/src/faces/app/face_prod_node.c @@ -42,12 +42,12 @@ typedef struct { u32 next_index; u32 sw_if_index; + hicn_error_t error; } hicn_face_prod_input_trace_t; typedef enum { - HICN_FACE_PROD_NEXT_DATA_IP4, - HICN_FACE_PROD_NEXT_DATA_IP6, + HICN_FACE_PROD_NEXT_PCS, HICN_FACE_PROD_NEXT_ERROR_DROP, HICN_FACE_PROD_N_NEXT, } hicn_face_prod_next_t; @@ -65,11 +65,14 @@ format_face_prod_input_trace (u8 *s, va_list *args) s = format (s, "prod-face: sw_if_index %d next-index %d", t->sw_if_index, t->next_index); + + if (t->error != HICN_ERROR_NONE) + s = format (s, " error %s", get_error_string (t->error)); return s; } static_always_inline int -match_ip4_name (u32 *name, fib_prefix_t *prefix) +match_ip4_name (u32 *name, const fib_prefix_t *prefix) { u32 xor = 0; @@ -79,7 +82,7 @@ match_ip4_name (u32 *name, fib_prefix_t *prefix) } static_always_inline int -match_ip6_name (u8 *name, fib_prefix_t *prefix) +match_ip6_name (u8 *name, const fib_prefix_t *prefix) { union { @@ -96,24 +99,42 @@ match_ip6_name (u8 *name, fib_prefix_t *prefix) } static_always_inline u32 -hicn_face_prod_next_from_data_hdr (vlib_node_runtime_t *node, vlib_buffer_t *b, - fib_prefix_t *prefix) +hicn_face_prod_next_from_data_hdr (vlib_buffer_t *b) { - u8 *ptr = vlib_buffer_get_current (b); - u8 v = *ptr & 0xf0; + u8 is_v6; int match_res = 1; + int ret = 0; + hicn_name_t *name; + hicn_face_prod_state_t *prod_face = NULL; + + // 1 - ensure the packet is hicn and its format is correct + ret = hicn_data_parse_pkt (b); + if (PREDICT_FALSE (ret)) + { + return HICN_FACE_PROD_NEXT_ERROR_DROP; + } - if (PREDICT_TRUE (v == 0x40 && ip46_address_is_ip4 (&prefix->fp_addr))) + // 2 - make sure the packet refers to a valid producer app state and + // retrieve app state information + prod_face = &face_state_vec[vnet_buffer (b)->sw_if_index[VLIB_RX]]; + vnet_buffer (b)->ip.adj_index[VLIB_RX] = prod_face->adj_index; + + // 3 - make sure the address in the packet belongs to the producer prefix + // of this face + const fib_prefix_t *prefix = &prod_face->prefix; + is_v6 = hicn_buffer_is_v6 (b); + name = &hicn_get_buffer (b)->name; + if (PREDICT_TRUE (!is_v6 && ip46_address_is_ip4 (&prefix->fp_addr))) { - match_res = match_ip4_name ((u32 *) &(ptr[12]), prefix); + match_res = match_ip4_name (&name->prefix.ip4.as_u32, prefix); } - else if (PREDICT_TRUE (v == 0x60 && !ip46_address_is_ip4 (&prefix->fp_addr))) + else if (PREDICT_TRUE (is_v6 && !ip46_address_is_ip4 (&prefix->fp_addr))) { - match_res = match_ip6_name (&(ptr[8]), prefix); + match_res = match_ip6_name (name->prefix.ip6.as_u8, prefix); } - return match_res ? HICN_FACE_PROD_NEXT_DATA_IP4 + (v == 0x60) : - HICN_FACE_PROD_NEXT_ERROR_DROP; + // 4 - if match found, forward data to next hicn node + return match_res ? HICN_FACE_PROD_NEXT_PCS : HICN_FACE_PROD_NEXT_ERROR_DROP; } static_always_inline void @@ -137,6 +158,7 @@ hicn_face_prod_input_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, u32 n_left_from, *from, *to_next; hicn_face_prod_next_t next_index; vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; + u32 thread_index = vm->thread_index; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -152,22 +174,28 @@ hicn_face_prod_input_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b0, *b1, *b2, *b3; hicn_buffer_t *hicnb0, *hicnb1, *hicnb2, *hicnb3; u32 bi0, bi1, bi2, bi3; - hicn_face_prod_state_t *prod_face0 = NULL; - hicn_face_prod_state_t *prod_face1 = NULL; - hicn_face_prod_state_t *prod_face2 = NULL; - hicn_face_prod_state_t *prod_face3 = NULL; u32 next0, next1, next2, next3; + // Prefetch next iteration { vlib_buffer_t *b4, *b5, *b6, *b7; b4 = vlib_get_buffer (vm, from[4]); b5 = vlib_get_buffer (vm, from[5]); b6 = vlib_get_buffer (vm, from[6]); b7 = vlib_get_buffer (vm, from[7]); - CLIB_PREFETCH (b4, CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (b5, CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (b6, CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (b7, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (b4, 2 * CLIB_CACHE_LINE_BYTES, WRITE); + CLIB_PREFETCH (b5, 2 * CLIB_CACHE_LINE_BYTES, WRITE); + CLIB_PREFETCH (b6, 2 * CLIB_CACHE_LINE_BYTES, WRITE); + CLIB_PREFETCH (b7, 2 * CLIB_CACHE_LINE_BYTES, WRITE); + + CLIB_PREFETCH (vlib_buffer_get_current (b4), + 2 * CLIB_CACHE_LINE_BYTES, WRITE); + CLIB_PREFETCH (vlib_buffer_get_current (b5), + 2 * CLIB_CACHE_LINE_BYTES, WRITE); + CLIB_PREFETCH (vlib_buffer_get_current (b6), + 2 * CLIB_CACHE_LINE_BYTES, WRITE); + CLIB_PREFETCH (vlib_buffer_get_current (b7), + 2 * CLIB_CACHE_LINE_BYTES, WRITE); } bi0 = from[0]; @@ -200,31 +228,39 @@ hicn_face_prod_input_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, hicnb2->flags = HICN_FACE_FLAGS_DEFAULT; hicnb3->flags = HICN_FACE_FLAGS_DEFAULT; - prod_face0 = &face_state_vec[vnet_buffer (b0)->sw_if_index[VLIB_RX]]; - prod_face1 = &face_state_vec[vnet_buffer (b1)->sw_if_index[VLIB_RX]]; - prod_face2 = &face_state_vec[vnet_buffer (b2)->sw_if_index[VLIB_RX]]; - prod_face3 = &face_state_vec[vnet_buffer (b3)->sw_if_index[VLIB_RX]]; - - vnet_buffer (b0)->ip.adj_index[VLIB_RX] = - face_state_vec[vnet_buffer (b0)->sw_if_index[VLIB_RX]].adj_index; - vnet_buffer (b1)->ip.adj_index[VLIB_RX] = - face_state_vec[vnet_buffer (b1)->sw_if_index[VLIB_RX]].adj_index; - vnet_buffer (b2)->ip.adj_index[VLIB_RX] = - face_state_vec[vnet_buffer (b2)->sw_if_index[VLIB_RX]].adj_index; - vnet_buffer (b3)->ip.adj_index[VLIB_RX] = - face_state_vec[vnet_buffer (b3)->sw_if_index[VLIB_RX]].adj_index; - - next0 = - hicn_face_prod_next_from_data_hdr (node, b0, &prod_face0->prefix); - next1 = - hicn_face_prod_next_from_data_hdr (node, b1, &prod_face1->prefix); - next2 = - hicn_face_prod_next_from_data_hdr (node, b2, &prod_face2->prefix); - next3 = - hicn_face_prod_next_from_data_hdr (node, b3, &prod_face3->prefix); + // parse packets and get next node + next0 = hicn_face_prod_next_from_data_hdr (b0); + next1 = hicn_face_prod_next_from_data_hdr (b1); + next2 = hicn_face_prod_next_from_data_hdr (b2); + next3 = hicn_face_prod_next_from_data_hdr (b3); stats.pkts_data_count += 4; - /* trace */ + // counters + vlib_increment_combined_counter ( + &counters[hicnb0->face_id * HICN_N_COUNTER], thread_index, + HICN_FACE_COUNTERS_DATA_RX, 1, + vlib_buffer_length_in_chain (vm, b0)); + stats.pkts_data_count += 1; + + vlib_increment_combined_counter ( + &counters[hicnb1->face_id * HICN_N_COUNTER], thread_index, + HICN_FACE_COUNTERS_DATA_RX, 1, + vlib_buffer_length_in_chain (vm, b0)); + stats.pkts_data_count += 1; + + vlib_increment_combined_counter ( + &counters[hicnb2->face_id * HICN_N_COUNTER], thread_index, + HICN_FACE_COUNTERS_DATA_RX, 1, + vlib_buffer_length_in_chain (vm, b0)); + stats.pkts_data_count += 1; + + vlib_increment_combined_counter ( + &counters[hicnb3->face_id * HICN_N_COUNTER], thread_index, + HICN_FACE_COUNTERS_DATA_RX, 1, + vlib_buffer_length_in_chain (vm, b0)); + stats.pkts_data_count += 1; + + // trace hicn_face_prod_trace_buffer ( vm, node, vnet_buffer (b0)->sw_if_index[VLIB_RX], b0, next0); hicn_face_prod_trace_buffer ( @@ -234,7 +270,7 @@ hicn_face_prod_input_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, hicn_face_prod_trace_buffer ( vm, node, vnet_buffer (b3)->sw_if_index[VLIB_RX], b3, next3); - /* enqueue */ + // enqueue vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next, n_left_to_next, bi0, bi1, bi2, bi3, next0, next1, next2, next3); @@ -246,8 +282,7 @@ hicn_face_prod_input_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, { vlib_buffer_t *b0; hicn_buffer_t *hicnb0; - u32 bi0, swif; - hicn_face_prod_state_t *prod_face = NULL; + u32 bi0; u32 next0; if (n_left_from > 1) @@ -267,15 +302,17 @@ hicn_face_prod_input_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, b0 = vlib_get_buffer (vm, bi0); hicnb0 = hicn_get_buffer (b0); hicnb0->flags = HICN_FACE_FLAGS_DEFAULT; - swif = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - prod_face = &face_state_vec[swif]; - next0 = - hicn_face_prod_next_from_data_hdr (node, b0, &prod_face->prefix); - vnet_buffer (b0)->ip.adj_index[VLIB_RX] = - face_state_vec[swif].adj_index; + next0 = hicn_face_prod_next_from_data_hdr (b0); stats.pkts_data_count++; + // counters + vlib_increment_combined_counter ( + &counters[hicnb0->face_id * HICN_N_COUNTER], thread_index, + HICN_FACE_COUNTERS_DATA_RX, 1, + vlib_buffer_length_in_chain (vm, b0)); + stats.pkts_data_count += 1; + /* trace */ hicn_face_prod_trace_buffer ( vm, node, vnet_buffer (b0)->sw_if_index[VLIB_RX], b0, next0); @@ -310,8 +347,7 @@ VLIB_REGISTER_NODE(hicn_face_prod_input_node) = .n_next_nodes = HICN_FACE_PROD_N_NEXT, .next_nodes = { - [HICN_FACE_PROD_NEXT_DATA_IP4] = "hicn4-face-input", - [HICN_FACE_PROD_NEXT_DATA_IP6] = "hicn6-face-input", + [HICN_FACE_PROD_NEXT_PCS] = "hicn-data-pcslookup", [HICN_FACE_PROD_NEXT_ERROR_DROP] = "error-drop", }, }; @@ -320,4 +356,4 @@ VLIB_REGISTER_NODE(hicn_face_prod_input_node) = * fd.io coding-style-patch-verification: ON * * Local Variables: eval: (c-set-style "gnu") End: - */ + */
\ No newline at end of file diff --git a/hicn-plugin/src/faces/face.c b/hicn-plugin/src/faces/face.c index 854fd81d3..4ee1c283f 100644 --- a/hicn-plugin/src/faces/face.c +++ b/hicn-plugin/src/faces/face.c @@ -62,16 +62,12 @@ mhash_t hicn_face_hashtb; const static char *const hicn_face6_nodes[] = { "hicn6-face-output", // this is the name you give your node in // VLIB_REGISTER_NODE - "hicn6-iface-output", // this is the name you give your node in - // VLIB_REGISTER_NODE NULL, }; const static char *const hicn_face4_nodes[] = { "hicn4-face-output", // this is the name you give your node in // VLIB_REGISTER_NODE - "hicn4-iface-output", // this is the name you give your node in - // VLIB_REGISTER_NODE NULL, }; @@ -304,7 +300,7 @@ hicn_iface_to_face (hicn_face_t *face, const dpo_id_t *dpo) */ int hicn_face_add (const dpo_id_t *dpo_nh, ip46_address_t *nat_address, int sw_if, - hicn_face_id_t *pfaceid, u8 is_app_prod) + hicn_face_id_t *pfaceid) { hicn_face_flags_t flags = (hicn_face_flags_t) 0; diff --git a/hicn-plugin/src/faces/face.h b/hicn-plugin/src/faces/face.h index 39505c942..e4b759bec 100644 --- a/hicn-plugin/src/faces/face.h +++ b/hicn-plugin/src/faces/face.h @@ -27,6 +27,8 @@ #include <vpp_plugins/hicn/error.h> +#include "face_flags.h" +#include "../hicn_buffer_flags.h" #include "../udp_tunnels/udp_tunnel.h" #include "../hicn_logging.h" @@ -117,40 +119,8 @@ typedef struct __attribute__ ((packed)) hicn_face_s /* Pool of faces */ extern hicn_face_t *hicn_dpoi_face_pool; -/* Flags */ -/* A face is complete and it stores all the information. A iface lacks of the - adj index, therefore sending a packet through a iface require a lookup in - the FIB. */ -#define HICN_FACE_FLAGS_DEFAULT 0x00 -#define HICN_FACE_FLAGS_FACE 0x01 -#define HICN_FACE_FLAGS_IFACE 0x02 -#define HICN_FACE_FLAGS_APPFACE_PROD \ - 0x04 /* Currently only IP face can be appface */ -#define HICN_FACE_FLAGS_APPFACE_CONS \ - 0x08 /* Currently only IP face can be appface */ -#define HICN_FACE_FLAGS_DELETED 0x10 -#define HICN_FACE_FLAGS_UDP 0x20 - #define HICN_FACE_NULL (hicn_face_id_t) ~0 -#define HICN_FACE_FLAGS_APPFACE_PROD_BIT 2 -#define HICN_FACE_FLAGS_APPFACE_CONS_BIT 3 - -#define HICN_BUFFER_FLAGS_DEFAULT 0x00 -#define HICN_BUFFER_FLAGS_NEW_FACE 0x02 -#define HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL 0x04 -#define HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL 0x08 - -STATIC_ASSERT ((1 << HICN_FACE_FLAGS_APPFACE_PROD_BIT) == - HICN_FACE_FLAGS_APPFACE_PROD, - "HICN_FACE_FLAGS_APPFACE_PROD_BIT and " - "HICN_FACE_FLAGS_APPFACE_PROD must correspond"); - -STATIC_ASSERT ((1 << HICN_FACE_FLAGS_APPFACE_CONS_BIT) == - HICN_FACE_FLAGS_APPFACE_CONS, - "HICN_FACE_FLAGS_APPFACE_CONS_BIT and " - "HICN_FACE_FLAGS_APPFACE_CONS must correspond"); - /** * @brief Definition of the virtual functin table for an hICN FACE DPO. */ @@ -484,7 +454,7 @@ hicn_face_get_with_dpo (const ip46_address_t *addr, u32 sw_if, * reachable ip address, otherwise HICN_ERROR_NONE */ int hicn_face_add (const dpo_id_t *dpo_nh, ip46_address_t *nat_address, - int sw_if, hicn_face_id_t *pfaceid, u8 is_app_prod); + int sw_if, hicn_face_id_t *pfaceid); /** * @brief Create a new incomplete face ip. (Meant to be used by the data plane) @@ -497,7 +467,7 @@ int hicn_face_add (const dpo_id_t *dpo_nh, ip46_address_t *nat_address, * reachable ip address, otherwise HICN_ERROR_NONE */ always_inline void -hicn_iface_add (ip46_address_t *nat_address, int sw_if, +hicn_iface_add (const ip46_address_t *nat_address, int sw_if, hicn_face_id_t *pfaceid, u32 adj_index, u8 flags) { hicn_face_t *face; @@ -615,7 +585,6 @@ hicn_face_ip4_add_and_lock (hicn_face_id_t *index, u8 *hicnb_flags, *hicnb_flags |= HICN_BUFFER_FLAGS_NEW_FACE; *index = idx; - return ret; } else { @@ -623,15 +592,10 @@ hicn_face_ip4_add_and_lock (hicn_face_id_t *index, u8 *hicnb_flags, hicn_face_id_t face_id = hicn_dpoi_get_index (face); hicn_face_unlock_with_id (face_id); ret = HICN_ERROR_FACE_ALREADY_CREATED; + *index = hicn_dpoi_get_index (face); + *hicnb_flags = HICN_BUFFER_FLAGS_DEFAULT; } - /* Code replicated on purpose */ - *hicnb_flags = HICN_BUFFER_FLAGS_DEFAULT; - *hicnb_flags |= (face->flags & HICN_FACE_FLAGS_APPFACE_PROD) >> - HICN_FACE_FLAGS_APPFACE_PROD_BIT; - - *index = hicn_dpoi_get_index (face); - return ret; } @@ -676,7 +640,7 @@ hicn_face_ip6_add_and_lock (hicn_face_id_t *index, u8 *hicnb_flags, /*All (complete) faces are indexed by remote addess as well */ /* if the face exists, it adds a lock */ - hicn_face_t *face = hicn_face_get ((ip46_address_t *) nat_addr, sw_if, + hicn_face_t *face = hicn_face_get ((const ip46_address_t *) nat_addr, sw_if, &hicn_face_hashtb, adj_index); if (face == NULL) @@ -684,8 +648,8 @@ hicn_face_ip6_add_and_lock (hicn_face_id_t *index, u8 *hicnb_flags, hicn_face_id_t idx; u8 face_flags = 0; - hicn_iface_add ((ip46_address_t *) nat_addr, sw_if, &idx, adj_index, - face_flags); + hicn_iface_add ((const ip46_address_t *) nat_addr, sw_if, &idx, + adj_index, face_flags); face = hicn_dpoi_get_from_idx (idx); @@ -712,12 +676,8 @@ hicn_face_ip6_add_and_lock (hicn_face_id_t *index, u8 *hicnb_flags, adj_nbr_walk (face->sw_if, FIB_PROTOCOL_IP6, hicn6_iface_adj_walk_cb, face); - *hicnb_flags = HICN_BUFFER_FLAGS_DEFAULT; - *hicnb_flags |= HICN_BUFFER_FLAGS_NEW_FACE; - + *hicnb_flags = HICN_BUFFER_FLAGS_NEW_FACE; *index = idx; - - return ret; } else { @@ -725,15 +685,10 @@ hicn_face_ip6_add_and_lock (hicn_face_id_t *index, u8 *hicnb_flags, hicn_face_id_t face_id = hicn_dpoi_get_index (face); hicn_face_unlock_with_id (face_id); ret = HICN_ERROR_FACE_ALREADY_CREATED; + *hicnb_flags = HICN_BUFFER_FLAGS_DEFAULT; + *index = hicn_dpoi_get_index (face); } - /* Code replicated on purpose */ - *hicnb_flags = HICN_BUFFER_FLAGS_DEFAULT; - *hicnb_flags |= (face->flags & HICN_FACE_FLAGS_APPFACE_PROD) >> - HICN_FACE_FLAGS_APPFACE_PROD_BIT; - - *index = hicn_dpoi_get_index (face); - return ret; } diff --git a/hicn-plugin/src/faces/face_flags.h b/hicn-plugin/src/faces/face_flags.h new file mode 100644 index 000000000..61dee5465 --- /dev/null +++ b/hicn-plugin/src/faces/face_flags.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HICN_FACE_FLAGS_H__ +#define __HICN_FACE_FLAGS_H__ + +/* Flags */ +/* A face is complete and it stores all the information. A iface lacks of the + adj index, therefore sending a packet through a iface require a lookup in + the FIB. */ +#define foreach_face_flag \ + _ (0, FACE, "face") \ + _ (1, IFACE, "iface") \ + _ (2, APPFACE_PROD, "face is consumer face") \ + _ (3, APPFACE_CONS, "face is consumer face") \ + _ (4, DELETED, "face is deleted") \ + _ (5, UDP, "face is udp") + +enum +{ + HICN_FACE_FLAGS_DEFAULT = 0, +#define _(a, b, c) HICN_FACE_FLAGS_##b = (1 << a), + foreach_face_flag +#undef _ +}; + +#endif /* __HICN_FACE_FLAGS_H__ */
\ No newline at end of file diff --git a/hicn-plugin/src/faces/face_node.c b/hicn-plugin/src/faces/face_node.c index dc9bfffd0..6dedbe1c4 100644 --- a/hicn-plugin/src/faces/face_node.c +++ b/hicn-plugin/src/faces/face_node.c @@ -56,6 +56,7 @@ typedef struct u32 next_index; u32 sw_if_index; u8 pkt_type; + hicn_error_t error; u8 packet_data[60]; } hicn4_face_input_trace_t; @@ -73,6 +74,7 @@ typedef struct u32 next_index; u32 sw_if_index; u8 pkt_type; + hicn_error_t error; u8 packet_data[60]; } hicn6_face_input_trace_t; @@ -86,8 +88,9 @@ typedef enum #define NEXT_MAPME_IP4 HICN4_FACE_INPUT_NEXT_MAPME #define NEXT_MAPME_IP6 HICN6_FACE_INPUT_NEXT_MAPME -#define NEXT_DATA_IP4 HICN4_FACE_INPUT_NEXT_DATA -#define NEXT_DATA_IP6 HICN6_FACE_INPUT_NEXT_DATA + +#define NEXT_DATA_IP4 HICN4_FACE_INPUT_NEXT_DATA +#define NEXT_DATA_IP6 HICN6_FACE_INPUT_NEXT_DATA #define NEXT_ERROR_DROP_IP4 HICN4_FACE_INPUT_NEXT_ERROR_DROP #define NEXT_ERROR_DROP_IP6 HICN6_FACE_INPUT_NEXT_ERROR_DROP @@ -110,10 +113,11 @@ typedef enum vlib_buffer_t *b0; \ u32 bi0, sw_if0; \ u32 next0 = NEXT_ERROR_DROP_IP##ipv; \ + u8 is_icmp0; \ IP_HEADER_##ipv *ip_hdr = NULL; \ hicn_buffer_t *hicnb0; \ int from_tunnel0; \ - int ret0; \ + int ret0 = HICN_ERROR_NONE; \ /* Prefetch for next iteration. */ \ if (n_left_from > 1) \ { \ @@ -134,23 +138,35 @@ typedef enum hicnb0 = hicn_get_buffer (b0); \ ip_hdr = (IP_HEADER_##ipv *) vlib_buffer_get_current (b0); \ \ - u8 is_icmp = ip_hdr->protocol == IPPROTO_ICMPV##ipv; \ - \ - from_tunnel0 = \ - (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL || \ - hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0; \ - sw_if0 = (from_tunnel0) * ~0 + \ - (1 - from_tunnel0) * vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ - \ - ret0 = hicn_face_ip##ipv##_add_and_lock ( \ - &hicnb0->face_id, &hicnb0->flags, &ip_hdr->dst_address, sw_if0, \ - vnet_buffer (b0)->ip.adj_index[VLIB_RX], \ - /* Should not be used */ ~0); \ - /* Make sure the face is not created here */ \ - ASSERT (ret0 == HICN_ERROR_FACE_ALREADY_CREATED); \ + /* Parse packet and cache useful info in opaque2 */ \ + ret0 = hicn_data_parse_pkt (b0); \ + is_icmp0 = ret0 == HICN_ERROR_PARSER_MAPME_PACKET; \ + ret0 = (ret0 == HICN_ERROR_NONE) || \ + (ret0 == HICN_ERROR_PARSER_MAPME_PACKET); \ \ - next0 = \ - is_icmp * NEXT_MAPME_IP##ipv + (1 - is_icmp) * NEXT_DATA_IP##ipv; \ + /* If parsing is ok, send packet to next node */ \ + if (PREDICT_FALSE (!ret0)) \ + { \ + next0 = HICN##ipv##_FACE_INPUT_NEXT_ERROR_DROP; \ + } \ + else \ + { \ + next0 = is_icmp0 * NEXT_MAPME_IP##ipv + \ + (1 - is_icmp0) * NEXT_DATA_IP##ipv; \ + from_tunnel0 = \ + (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL || \ + hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0; \ + sw_if0 = \ + (from_tunnel0) * ~0 + \ + (1 - from_tunnel0) * vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + \ + ret0 = hicn_face_ip##ipv##_add_and_lock ( \ + &hicnb0->face_id, &hicnb0->flags, &ip_hdr->dst_address, sw_if0, \ + vnet_buffer (b0)->ip.adj_index[VLIB_RX], \ + /* Should not be used */ ~0); \ + /* Make sure the face is not created here */ \ + ASSERT (ret0 == HICN_ERROR_FACE_ALREADY_CREATED); \ + } \ \ vlib_increment_combined_counter ( \ &counters[hicnb0->face_id * HICN_N_COUNTER], thread_index, \ @@ -162,8 +178,9 @@ typedef enum { \ TRACE_INPUT_PKT_IP##ipv *t = \ vlib_add_trace (vm, node, b0, sizeof (*t)); \ - t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->pkt_type = HICN_PACKET_TYPE_INTEREST; \ t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + t->error = ret0; \ t->next_index = next0; \ clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0), \ sizeof (t->packet_data)); \ @@ -182,6 +199,7 @@ typedef enum u32 bi0, bi1, sw_if0, sw_if1; \ u32 next0 = NEXT_ERROR_DROP_IP##ipv; \ u32 next1 = NEXT_ERROR_DROP_IP##ipv; \ + u8 is_icmp0, is_icmp1; \ IP_HEADER_##ipv *ip_hdr0 = NULL; \ IP_HEADER_##ipv *ip_hdr1 = NULL; \ hicn_buffer_t *hicnb0; \ @@ -215,40 +233,95 @@ typedef enum ip_hdr0 = (IP_HEADER_##ipv *) vlib_buffer_get_current (b0); \ ip_hdr1 = (IP_HEADER_##ipv *) vlib_buffer_get_current (b1); \ \ - u8 is_icmp0 = ip_hdr0->protocol == IPPROTO_ICMPV##ipv; \ - u8 is_icmp1 = ip_hdr1->protocol == IPPROTO_ICMPV##ipv; \ - \ - from_tunnel0 = \ - (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL || \ - hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0; \ - sw_if0 = (from_tunnel0) * ~0 + \ - (1 - from_tunnel0) * vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ - \ - ret0 = hicn_face_ip##ipv##_add_and_lock ( \ - &hicnb0->face_id, &hicnb0->flags, &ip_hdr0->dst_address, sw_if0, \ - vnet_buffer (b0)->ip.adj_index[VLIB_RX], \ - /* Should not be used */ ~0); \ - /* Make sure the face is not created here */ \ - ASSERT (ret0 == HICN_ERROR_FACE_ALREADY_CREATED); \ - \ - from_tunnel1 = \ - (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL || \ - hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0; \ - sw_if1 = (from_tunnel1) * ~0 + \ - (1 - from_tunnel1) * vnet_buffer (b1)->sw_if_index[VLIB_RX]; \ - \ - ret1 = hicn_face_ip##ipv##_add_and_lock ( \ - &hicnb1->face_id, &hicnb1->flags, &ip_hdr1->dst_address, sw_if1, \ - vnet_buffer (b1)->ip.adj_index[VLIB_RX], \ - /* Should not be used */ ~0); \ - /* Make sure the face is not created here */ \ - ASSERT (ret1 == HICN_ERROR_FACE_ALREADY_CREATED); \ - \ - next0 = \ - is_icmp0 * NEXT_MAPME_IP##ipv + (1 - is_icmp0) * NEXT_DATA_IP##ipv; \ - \ - next1 = \ - is_icmp1 * NEXT_MAPME_IP##ipv + (1 - is_icmp1) * NEXT_DATA_IP##ipv; \ + /* Parse packet and cache useful info in opaque2 */ \ + /* Parse packet and cache useful info in opaque2 */ \ + ret0 = hicn_data_parse_pkt (b0); \ + ret1 = hicn_data_parse_pkt (b1); \ + is_icmp0 = ret0 == HICN_ERROR_PARSER_MAPME_PACKET; \ + is_icmp1 = ret1 == HICN_ERROR_PARSER_MAPME_PACKET; \ + ret0 = (ret0 == HICN_ERROR_NONE) || \ + (ret0 == HICN_ERROR_PARSER_MAPME_PACKET); \ + ret1 = (ret1 == HICN_ERROR_NONE) || \ + (ret1 == HICN_ERROR_PARSER_MAPME_PACKET); \ + if (PREDICT_TRUE (ret0 && ret1)) \ + { \ + next0 = is_icmp0 * NEXT_MAPME_IP##ipv + \ + (1 - is_icmp0) * NEXT_DATA_IP##ipv; \ + \ + next1 = is_icmp1 * NEXT_MAPME_IP##ipv + \ + (1 - is_icmp1) * NEXT_DATA_IP##ipv; \ + \ + from_tunnel0 = \ + (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL || \ + hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0; \ + sw_if0 = \ + (from_tunnel0) * ~0 + \ + (1 - from_tunnel0) * vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + \ + ret0 = hicn_face_ip##ipv##_add_and_lock ( \ + &hicnb0->face_id, &hicnb0->flags, &ip_hdr0->dst_address, sw_if0, \ + vnet_buffer (b0)->ip.adj_index[VLIB_RX], \ + /* Should not be used */ ~0); \ + /* Make sure the face is not created here */ \ + ASSERT (ret0 == HICN_ERROR_FACE_ALREADY_CREATED); \ + \ + from_tunnel1 = \ + (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL || \ + hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0; \ + sw_if1 = \ + (from_tunnel1) * ~0 + \ + (1 - from_tunnel1) * vnet_buffer (b1)->sw_if_index[VLIB_RX]; \ + \ + ret1 = hicn_face_ip##ipv##_add_and_lock ( \ + &hicnb1->face_id, &hicnb1->flags, &ip_hdr1->dst_address, sw_if1, \ + vnet_buffer (b1)->ip.adj_index[VLIB_RX], \ + /* Should not be used */ ~0); \ + /* Make sure the face is not created here */ \ + ASSERT (ret1 == HICN_ERROR_FACE_ALREADY_CREATED); \ + } \ + else if (ret0 && !ret1) \ + { \ + next1 = HICN##ipv##_FACE_INPUT_NEXT_ERROR_DROP; \ + from_tunnel0 = \ + (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL || \ + hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0; \ + sw_if0 = \ + (from_tunnel0) * ~0 + \ + (1 - from_tunnel0) * vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + \ + ret0 = hicn_face_ip##ipv##_add_and_lock ( \ + &hicnb0->face_id, &hicnb0->flags, &ip_hdr0->dst_address, sw_if0, \ + vnet_buffer (b0)->ip.adj_index[VLIB_RX], \ + /* Should not be used */ ~0); \ + /* Make sure the face is not created here */ \ + ASSERT (ret0 == HICN_ERROR_FACE_ALREADY_CREATED); \ + next0 = is_icmp0 * NEXT_MAPME_IP##ipv + \ + (1 - is_icmp0) * NEXT_DATA_IP##ipv; \ + } \ + else if (!ret0 && ret1) \ + { \ + next0 = HICN##ipv##_FACE_INPUT_NEXT_ERROR_DROP; \ + from_tunnel1 = \ + (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL || \ + hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL) > 0; \ + sw_if1 = \ + (from_tunnel1) * ~0 + \ + (1 - from_tunnel1) * vnet_buffer (b1)->sw_if_index[VLIB_RX]; \ + \ + ret1 = hicn_face_ip##ipv##_add_and_lock ( \ + &hicnb1->face_id, &hicnb1->flags, &ip_hdr1->dst_address, sw_if1, \ + vnet_buffer (b1)->ip.adj_index[VLIB_RX], \ + /* Should not be used */ ~0); \ + /* Make sure the face is not created here */ \ + ASSERT (ret1 == HICN_ERROR_FACE_ALREADY_CREATED); \ + next1 = is_icmp1 * NEXT_MAPME_IP##ipv + \ + (1 - is_icmp1) * NEXT_DATA_IP##ipv; \ + } \ + else \ + { \ + next0 = HICN##ipv##_FACE_INPUT_NEXT_ERROR_DROP; \ + next1 = HICN##ipv##_FACE_INPUT_NEXT_ERROR_DROP; \ + } \ \ vlib_increment_combined_counter ( \ &counters[hicnb0->face_id * HICN_N_COUNTER], thread_index, \ @@ -265,8 +338,9 @@ typedef enum { \ TRACE_INPUT_PKT_IP##ipv *t = \ vlib_add_trace (vm, node, b0, sizeof (*t)); \ - t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->pkt_type = HICN_PACKET_TYPE_INTEREST; \ t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + t->error = ret0; \ t->next_index = next0; \ clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0), \ sizeof (t->packet_data)); \ @@ -277,8 +351,9 @@ typedef enum { \ TRACE_INPUT_PKT_IP##ipv *t = \ vlib_add_trace (vm, node, b1, sizeof (*t)); \ - t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->pkt_type = HICN_PACKET_TYPE_INTEREST; \ t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; \ + t->error = ret1; \ t->next_index = next1; \ clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b1), \ sizeof (t->packet_data)); \ @@ -461,80 +536,6 @@ typedef enum HICN6_FACE_OUTPUT_N_NEXT, } hicn6_face_output_next_t; -/* static_always_inline void */ -/* hicn_reply_probe_v4 (vlib_buffer_t * b, hicn_face_t * face) */ -/* { */ -/* hicn_header_t *h0 = vlib_buffer_get_current (b); */ -/* hicn_face_ip_t * face_ip = (hicn_face_ip_t *)(&face->data); */ -/* h0->v4.ip.saddr = h0->v4.ip.daddr; */ -/* h0->v4.ip.daddr = face_ip->local_addr.ip4; */ -/* vnet_buffer (b)->sw_if_index[VLIB_RX] = face->shared.sw_if; */ - -/* u16 * dst_port_ptr = (u16 *)(((u8*)h0) + sizeof(ip4_header_t) + - * sizeof(u16)); */ -/* u16 dst_port = *dst_port_ptr; */ -/* u16 * src_port_ptr = (u16 *)(((u8*)h0) + sizeof(ip4_header_t)); */ - -/* *dst_port_ptr = *src_port_ptr; */ -/* *src_port_ptr = dst_port; */ - -/* hicn_type_t type = hicn_get_buffer (b)->type; */ -/* hicn_ops_vft[type.l1]->set_lifetime (type, &h0->protocol, 0); */ -/* } */ - -/* static_always_inline void */ -/* hicn_reply_probe_v6 (vlib_buffer_t * b, hicn_face_t * face) */ -/* { */ -/* hicn_header_t *h0 = vlib_buffer_get_current (b); */ -/* hicn_face_ip_t * face_ip = (hicn_face_ip_t *)(&face->data); */ -/* h0->v6.ip.saddr = h0->v6.ip.daddr; */ -/* h0->v6.ip.daddr = face_ip->local_addr.ip6; */ -/* vnet_buffer (b)->sw_if_index[VLIB_RX] = face->shared.sw_if; */ - -/* u16 * dst_port_ptr = (u16 *)(((u8*)h0) + sizeof(ip6_header_t) + - * sizeof(u16)); */ -/* u16 dst_port = *dst_port_ptr; */ -/* u16 * src_port_ptr = (u16 *)(((u8*)h0) + sizeof(ip6_header_t)); */ - -/* *dst_port_ptr = *src_port_ptr; */ -/* *src_port_ptr = dst_port; */ - -/* hicn_type_t type = hicn_get_buffer (b)->type; */ -/* hicn_ops_vft[type.l1]->set_lifetime (type, &h0->protocol, 0); */ - -/* } */ - -/* static_always_inline u32 */ -/* hicn_face_match_probe (vlib_buffer_t * b, hicn_face_t * face, u32 * next) */ -/* { */ - -/* u8 *ptr = vlib_buffer_get_current (b); */ -/* u8 v = *ptr & 0xf0; */ -/* u8 res = 0; */ - -/* if ( v == 0x40 ) */ -/* { */ -/* u16 * dst_port = (u16 *)(ptr + sizeof(ip4_header_t) + sizeof(u16)); */ -/* if (*dst_port == clib_net_to_host_u16(DEFAULT_PROBING_PORT)) */ -/* { */ -/* hicn_reply_probe_v6(b, face); */ -/* *next = HICN4_FACE_NEXT_ECHO_REPLY; */ -/* res = 1; */ -/* } */ -/* } */ -/* else if ( v == 0x60 ) */ -/* { */ -/* u16 * dst_port = (u16 *)(ptr + sizeof(ip6_header_t) + sizeof(u16)); */ -/* if (*dst_port == clib_net_to_host_u16(DEFAULT_PROBING_PORT)) */ -/* { */ -/* hicn_reply_probe_v6(b, face); */ -/* *next = HICN6_FACE_NEXT_ECHO_REPLY; */ -/* res = 1; */ -/* } */ -/* } */ -/* return res; */ -/* } */ - static inline void hicn_face_rewrite_interest (vlib_main_t *vm, vlib_buffer_t *b0, hicn_face_t *face, u32 *next) @@ -546,6 +547,9 @@ hicn_face_rewrite_interest (vlib_main_t *vm, vlib_buffer_t *b0, hicn_header_t *hicn = vlib_buffer_get_current (b0); + u8 is_v4 = ip46_address_is_ip4 (&face->nat_addr) && + !ip6_address_is_loopback (&face->nat_addr.ip6); + // hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data; ip46_address_t temp_addr; @@ -553,11 +557,8 @@ hicn_face_rewrite_interest (vlib_main_t *vm, vlib_buffer_t *b0, hicn_type_t type = hicn_get_buffer (b0)->type; int ret = hicn_ops_vft[type.l1]->rewrite_interest ( type, &hicn->protocol, &face->nat_addr, &temp_addr); - if (ret == HICN_LIB_ERROR_REWRITE_CKSUM_REQUIRED) { - u8 is_v4 = ip46_address_is_ip4 (&face->nat_addr) && - !ip6_address_is_loopback (&face->nat_addr.ip6); ensure_offload_flags (b0, is_v4); } @@ -645,7 +646,7 @@ typedef struct { \ TRACE_OUTPUT_PKT_IP##ipv *t = \ vlib_add_trace (vm, node, b0, sizeof (*t)); \ - t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->pkt_type = HICN_PACKET_TYPE_INTEREST; \ t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ t->next_index = next0; \ clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0), \ @@ -724,7 +725,7 @@ typedef struct { \ TRACE_OUTPUT_PKT_IP##ipv *t = \ vlib_add_trace (vm, node, b0, sizeof (*t)); \ - t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->pkt_type = HICN_PACKET_TYPE_INTEREST; \ t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ t->next_index = next0; \ clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0), \ @@ -736,7 +737,7 @@ typedef struct { \ TRACE_OUTPUT_PKT_IP##ipv *t = \ vlib_add_trace (vm, node, b1, sizeof (*t)); \ - t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->pkt_type = HICN_PACKET_TYPE_INTEREST; \ t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; \ t->next_index = next1; \ clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b1), \ @@ -812,12 +813,7 @@ VLIB_REGISTER_NODE (hicn4_face_output_node) = { .type = VLIB_NODE_TYPE_INTERNAL, .n_errors = ARRAY_LEN (hicn4_face_output_error_strings), .error_strings = hicn4_face_output_error_strings, - .n_next_nodes = HICN4_FACE_OUTPUT_N_NEXT, - /* Reusing the list of nodes from lookup to be compatible with arp */ - .next_nodes = { [HICN4_FACE_OUTPUT_NEXT_ERROR_DROP] = "error-drop", - [HICN4_FACE_OUTPUT_NEXT_ECHO_REPLY] = "hicn4-face-input", - [HICN4_FACE_OUTPUT_NEXT_UDP4_ENCAP] = "udp4-encap", - [HICN4_FACE_OUTPUT_NEXT_UDP6_ENCAP] = "udp6-encap" } + .sibling_of = "ip4-lookup", }; static uword @@ -882,13 +878,7 @@ VLIB_REGISTER_NODE (hicn6_face_output_node) = { .type = VLIB_NODE_TYPE_INTERNAL, .n_errors = ARRAY_LEN (hicn6_face_output_error_strings), .error_strings = hicn6_face_output_error_strings, - .n_next_nodes = HICN6_FACE_OUTPUT_N_NEXT, - /* Reusing the list of nodes from lookup to be compatible with neighbour - discovery */ - .next_nodes = { [HICN6_FACE_OUTPUT_NEXT_ERROR_DROP] = "error-drop", - [HICN6_FACE_OUTPUT_NEXT_ECHO_REPLY] = "hicn6-face-input", - [HICN6_FACE_OUTPUT_NEXT_UDP4_ENCAP] = "udp4-encap", - [HICN6_FACE_OUTPUT_NEXT_UDP6_ENCAP] = "udp6-encap" } + .sibling_of = "ip6-lookup", }; /* @@ -897,4 +887,4 @@ VLIB_REGISTER_NODE (hicn6_face_output_node) = { * Local Variables: * eval: (c-set-style "gnu") * End: - */ + */
\ No newline at end of file diff --git a/hicn-plugin/src/faces/iface_node.c b/hicn-plugin/src/faces/iface_node.c index 84205af9b..3b6634d77 100644 --- a/hicn-plugin/src/faces/iface_node.c +++ b/hicn-plugin/src/faces/iface_node.c @@ -52,6 +52,7 @@ typedef struct u32 next_index; u32 sw_if_index; u8 pkt_type; + hicn_error_t error; u8 packet_data[60]; } hicn4_iface_input_trace_t; @@ -69,6 +70,7 @@ typedef struct u32 next_index; u32 sw_if_index; u8 pkt_type; + hicn_error_t error; u8 packet_data[60]; } hicn6_iface_input_trace_t; @@ -86,33 +88,9 @@ typedef enum #define NEXT_INTEREST_IP4 HICN4_IFACE_INPUT_NEXT_INTEREST #define NEXT_INTEREST_IP6 HICN6_IFACE_INPUT_NEXT_INTEREST -#define ADDRESS_IP4 \ - ip_interface_address_t *ia = 0; \ - ip4_address_t *local_address = \ - ip4_interface_first_address (&ip4_main, swif, &ia) -#define ADDRESS_IP6 \ - ip6_address_t *local_address = ip6_interface_first_address (&ip6_main, swif) - -#define ADDRESSX2_IP4 \ - ip_interface_address_t *ia0, *ia1; \ - ia0 = ia1 = 0; \ - ip4_address_t *local_address0 = \ - ip4_interface_first_address (&ip4_main, swif0, &ia0); \ - ip4_address_t *local_address1 = \ - ip4_interface_first_address (&ip4_main, swif1, &ia1); - -#define ADDRESSX2_IP6 \ - ip6_address_t *local_address0 = \ - ip6_interface_first_address (&ip6_main, swif0); \ - ip6_address_t *local_address1 = \ - ip6_interface_first_address (&ip6_main, swif1); - #define DPO_ADD_LOCK_FACE_IP4 hicn_face_ip4_add_and_lock #define DPO_ADD_LOCK_FACE_IP6 hicn_face_ip6_add_and_lock -//#define VLIB_EDGE_IP4 data_fwd_iface_ip4_vlib_edge -//#define VLIB_EDGE_IP6 data_fwd_iface_ip6_vlib_edge - #define IP_HEADER_4 ip4_header_t #define IP_HEADER_6 ip6_header_t @@ -148,6 +126,7 @@ typedef enum HICN4_IFACE_OUTPUT_NEXT_LOOKUP, HICN4_IFACE_OUTPUT_NEXT_UDP4_ENCAP, HICN4_IFACE_OUTPUT_NEXT_UDP6_ENCAP, + HICN4_IFACE_OUTPUT_NEXT_PG, HICN4_IFACE_OUTPUT_N_NEXT, } hicn4_iface_output_next_t; @@ -166,6 +145,7 @@ typedef enum HICN6_IFACE_OUTPUT_NEXT_LOOKUP, HICN6_IFACE_OUTPUT_NEXT_UDP4_ENCAP, HICN6_IFACE_OUTPUT_NEXT_UDP6_ENCAP, + HICN6_IFACE_OUTPUT_NEXT_PG, HICN6_IFACE_OUTPUT_N_NEXT, } hicn6_iface_output_next_t; @@ -178,6 +158,9 @@ typedef enum #define NEXT_UDP_ENCAP_IP4 HICN4_IFACE_OUTPUT_NEXT_UDP4_ENCAP #define NEXT_UDP_ENCAP_IP6 HICN6_IFACE_OUTPUT_NEXT_UDP6_ENCAP +#define NEXT_PG4 HICN4_IFACE_OUTPUT_NEXT_PG +#define NEXT_PG6 HICN6_IFACE_OUTPUT_NEXT_PG + #define HICN_REWRITE_DATA_IP4 hicn_rewrite_iface_data4 #define HICN_REWRITE_DATA_IP6 hicn_rewrite_iface_data6 @@ -190,9 +173,11 @@ typedef enum do \ { \ vlib_buffer_t *b0; \ - u32 bi0, next0, next_iface0, sw_if0; \ + u32 bi0, next0, next_iface0, sw_if0 = ~0; \ IP_HEADER_##ipv *ip_hdr = NULL; \ hicn_buffer_t *hicnb0; \ + int ret0 = HICN_ERROR_NONE; \ + u8 is_icmp0; \ /* Prefetch for next iteration. */ \ if (n_left_from > 1) \ { \ @@ -213,41 +198,55 @@ typedef enum hicnb0 = hicn_get_buffer (b0); \ ip_hdr = (IP_HEADER_##ipv *) vlib_buffer_get_current (b0); \ \ - stats.pkts_interest_count += 1; \ - \ - u8 is_icmp = ip_hdr->protocol == IPPROTO_ICMPV##ipv; \ - \ - next0 = \ - is_icmp * NEXT_MAPME_IP##ipv + (1 - is_icmp) * NEXT_INTEREST_IP##ipv; \ - \ - next_iface0 = NEXT_DATA_LOOKUP_IP##ipv; \ - sw_if0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ - \ - if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL && \ - vnet_buffer (b0)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID) \ + /* Parse packet and cache useful info in opaque2 */ \ + ret0 = hicn_interest_parse_pkt (b0); \ + is_icmp0 = (ret0 == HICN_ERROR_PARSER_MAPME_PACKET); \ + ret0 = (ret0 == HICN_ERROR_NONE) || \ + (ret0 == HICN_ERROR_PARSER_MAPME_PACKET); \ + if (PREDICT_FALSE (!ret0)) \ { \ - next_iface0 = NEXT_UDP_ENCAP_IP4; \ - sw_if0 = ~0; \ + next0 = HICN##ipv##_IFACE_INPUT_NEXT_ERROR_DROP; \ } \ - else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL && \ - vnet_buffer (b0)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID) \ + else \ { \ - next_iface0 = NEXT_UDP_ENCAP_IP6; \ - sw_if0 = ~0; \ + next0 = is_icmp0 * NEXT_MAPME_IP##ipv + \ + (1 - is_icmp0) * NEXT_INTEREST_IP##ipv; \ + \ + next_iface0 = NEXT_DATA_LOOKUP_IP##ipv; \ + sw_if0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + \ + if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL && \ + vnet_buffer (b0)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID) \ + { \ + next_iface0 = NEXT_UDP_ENCAP_IP4; \ + sw_if0 = ~0; \ + } \ + else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL && \ + vnet_buffer (b0)->ip.adj_index[VLIB_RX] != \ + ADJ_INDEX_INVALID) \ + { \ + next_iface0 = NEXT_UDP_ENCAP_IP6; \ + sw_if0 = ~0; \ + } \ + else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_PG) \ + { \ + next_iface0 = NEXT_PG##ipv; \ + } \ + \ + DPO_ADD_LOCK_FACE_IP##ipv ( \ + &(hicnb0->face_id), &hicnb0->flags, &(ip_hdr->src_address), \ + sw_if0, vnet_buffer (b0)->ip.adj_index[VLIB_RX], next_iface0); \ } \ \ - DPO_ADD_LOCK_FACE_IP##ipv ( \ - &(hicnb0->face_id), &hicnb0->flags, &(ip_hdr->src_address), sw_if0, \ - vnet_buffer (b0)->ip.adj_index[VLIB_RX], next_iface0); \ - \ if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ (b0->flags & VLIB_BUFFER_IS_TRACED))) \ { \ TRACE_INPUT_PKT_IP##ipv *t = \ vlib_add_trace (vm, node, b0, sizeof (*t)); \ - t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->pkt_type = HICN_PACKET_TYPE_INTEREST; \ t->sw_if_index = sw_if0; \ t->next_index = next0; \ + t->error = ret0; \ clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0), \ sizeof (t->packet_data)); \ } \ @@ -267,9 +266,12 @@ typedef enum do \ { \ vlib_buffer_t *b0, *b1; \ - u32 bi0, bi1, next0, next1, next_iface0, next_iface1, sw_if0, sw_if1; \ + u32 bi0, bi1, next0, next1; \ + u32 next_iface0, next_iface1, sw_if0 = ~0, sw_if1 = ~0; \ + u8 is_icmp0, is_icmp1; \ IP_HEADER_##ipv *ip_hdr0 = NULL; \ IP_HEADER_##ipv *ip_hdr1 = NULL; \ + int ret0 = HICN_ERROR_NONE, ret1 = HICN_ERROR_NONE; \ hicn_buffer_t *hicnb0, *hicnb1; \ \ /* Prefetch for next iteration. */ \ @@ -300,63 +302,149 @@ typedef enum \ stats.pkts_interest_count += 2; \ \ - u8 is_icmp0 = ip_hdr0->protocol == IPPROTO_ICMPV##ipv; \ - u8 is_icmp1 = ip_hdr1->protocol == IPPROTO_ICMPV##ipv; \ - \ - next0 = is_icmp0 * NEXT_MAPME_IP##ipv + \ - (1 - is_icmp0) * NEXT_INTEREST_IP##ipv; \ - \ - next1 = is_icmp1 * NEXT_MAPME_IP##ipv + \ - (1 - is_icmp1) * NEXT_INTEREST_IP##ipv; \ - \ - next_iface0 = NEXT_DATA_LOOKUP_IP##ipv; \ - sw_if0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ - \ - if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL && \ - vnet_buffer (b0)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID) \ + /* Parse packet and cache useful info in opaque2 */ \ + ret0 = hicn_interest_parse_pkt (b0); \ + ret1 = hicn_interest_parse_pkt (b1); \ + is_icmp0 = ret0 == HICN_ERROR_PARSER_MAPME_PACKET; \ + is_icmp1 = ret1 == HICN_ERROR_PARSER_MAPME_PACKET; \ + ret0 = (ret0 == HICN_ERROR_NONE) || \ + (ret0 == HICN_ERROR_PARSER_MAPME_PACKET); \ + ret1 = (ret1 == HICN_ERROR_NONE) || \ + (ret1 == HICN_ERROR_PARSER_MAPME_PACKET); \ + \ + if (PREDICT_TRUE (ret0 && ret1)) \ { \ - next_iface0 = NEXT_UDP_ENCAP_IP4; \ - sw_if0 = ~0; \ + next0 = is_icmp0 * NEXT_MAPME_IP##ipv + \ + (1 - is_icmp0) * NEXT_INTEREST_IP##ipv; \ + \ + next1 = is_icmp1 * NEXT_MAPME_IP##ipv + \ + (1 - is_icmp1) * NEXT_INTEREST_IP##ipv; \ + \ + next_iface0 = NEXT_DATA_LOOKUP_IP##ipv; \ + sw_if0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + \ + if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL && \ + vnet_buffer (b0)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID) \ + { \ + next_iface0 = NEXT_UDP_ENCAP_IP4; \ + sw_if0 = ~0; \ + } \ + else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL && \ + vnet_buffer (b0)->ip.adj_index[VLIB_RX] != \ + ADJ_INDEX_INVALID) \ + { \ + next_iface0 = NEXT_UDP_ENCAP_IP6; \ + sw_if0 = ~0; \ + } \ + else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_PG) \ + { \ + next_iface0 = NEXT_PG##ipv; \ + } \ + \ + next_iface1 = NEXT_DATA_LOOKUP_IP##ipv; \ + sw_if1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; \ + \ + if (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL && \ + vnet_buffer (b1)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID) \ + { \ + next_iface1 = NEXT_UDP_ENCAP_IP4; \ + sw_if1 = ~0; \ + } \ + else if (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL && \ + vnet_buffer (b1)->ip.adj_index[VLIB_RX] != \ + ADJ_INDEX_INVALID) \ + { \ + next_iface1 = NEXT_UDP_ENCAP_IP6; \ + sw_if1 = ~0; \ + } \ + else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_PG) \ + { \ + next_iface1 = NEXT_PG##ipv; \ + } \ + \ + DPO_ADD_LOCK_FACE_IP##ipv ( \ + &(hicnb0->face_id), &hicnb0->flags, &(ip_hdr0->src_address), \ + sw_if0, vnet_buffer (b0)->ip.adj_index[VLIB_RX], next_iface0); \ + \ + DPO_ADD_LOCK_FACE_IP##ipv ( \ + &(hicnb1->face_id), &hicnb1->flags, &(ip_hdr1->src_address), \ + sw_if1, vnet_buffer (b1)->ip.adj_index[VLIB_RX], next_iface1); \ } \ - else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL && \ - vnet_buffer (b0)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID) \ + else if (ret0 && !ret1) \ { \ - next_iface0 = NEXT_UDP_ENCAP_IP6; \ - sw_if0 = ~0; \ + next1 = HICN##ipv##_IFACE_INPUT_NEXT_ERROR_DROP; \ + next0 = is_icmp0 * NEXT_MAPME_IP##ipv + \ + (1 - is_icmp0) * NEXT_INTEREST_IP##ipv; \ + next_iface0 = NEXT_DATA_LOOKUP_IP##ipv; \ + sw_if0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + \ + if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL && \ + vnet_buffer (b0)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID) \ + { \ + next_iface0 = NEXT_UDP_ENCAP_IP4; \ + sw_if0 = ~0; \ + } \ + else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL && \ + vnet_buffer (b0)->ip.adj_index[VLIB_RX] != \ + ADJ_INDEX_INVALID) \ + { \ + next_iface0 = NEXT_UDP_ENCAP_IP6; \ + sw_if0 = ~0; \ + } \ + else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_PG) \ + { \ + next_iface0 = NEXT_PG##ipv; \ + } \ + \ + DPO_ADD_LOCK_FACE_IP##ipv ( \ + &(hicnb0->face_id), &hicnb0->flags, &(ip_hdr0->src_address), \ + sw_if0, vnet_buffer (b0)->ip.adj_index[VLIB_RX], next_iface0); \ } \ - \ - next_iface1 = NEXT_DATA_LOOKUP_IP##ipv; \ - sw_if1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; \ - \ - if (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL && \ - vnet_buffer (b1)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID) \ + else if (!ret0 && ret1) \ { \ - next_iface1 = NEXT_UDP_ENCAP_IP4; \ - sw_if1 = ~0; \ + next0 = HICN##ipv##_IFACE_INPUT_NEXT_ERROR_DROP; \ + next_iface1 = NEXT_DATA_LOOKUP_IP##ipv; \ + sw_if1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; \ + next1 = is_icmp1 * NEXT_MAPME_IP##ipv + \ + (1 - is_icmp1) * NEXT_INTEREST_IP##ipv; \ + \ + if (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP4_TUNNEL && \ + vnet_buffer (b1)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID) \ + { \ + next_iface1 = NEXT_UDP_ENCAP_IP4; \ + sw_if1 = ~0; \ + } \ + else if (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL && \ + vnet_buffer (b1)->ip.adj_index[VLIB_RX] != \ + ADJ_INDEX_INVALID) \ + { \ + next_iface1 = NEXT_UDP_ENCAP_IP6; \ + sw_if1 = ~0; \ + } \ + else if (hicnb0->flags & HICN_BUFFER_FLAGS_FROM_PG) \ + { \ + next_iface1 = NEXT_PG##ipv; \ + } \ + \ + DPO_ADD_LOCK_FACE_IP##ipv ( \ + &(hicnb1->face_id), &hicnb1->flags, &(ip_hdr1->src_address), \ + sw_if1, vnet_buffer (b1)->ip.adj_index[VLIB_RX], next_iface1); \ } \ - else if (hicnb1->flags & HICN_BUFFER_FLAGS_FROM_UDP6_TUNNEL && \ - vnet_buffer (b1)->ip.adj_index[VLIB_RX] != ADJ_INDEX_INVALID) \ + else \ { \ - next_iface1 = NEXT_UDP_ENCAP_IP6; \ - sw_if1 = ~0; \ + next0 = HICN##ipv##_IFACE_INPUT_NEXT_ERROR_DROP; \ + next1 = HICN##ipv##_IFACE_INPUT_NEXT_ERROR_DROP; \ } \ \ - DPO_ADD_LOCK_FACE_IP##ipv ( \ - &(hicnb0->face_id), &hicnb0->flags, &(ip_hdr0->src_address), sw_if0, \ - vnet_buffer (b0)->ip.adj_index[VLIB_RX], next_iface0); \ - \ - DPO_ADD_LOCK_FACE_IP##ipv ( \ - &(hicnb1->face_id), &hicnb1->flags, &(ip_hdr1->src_address), sw_if1, \ - vnet_buffer (b1)->ip.adj_index[VLIB_RX], next_iface1); \ - \ if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ (b0->flags & VLIB_BUFFER_IS_TRACED))) \ { \ TRACE_INPUT_PKT_IP##ipv *t = \ vlib_add_trace (vm, node, b0, sizeof (*t)); \ - t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->pkt_type = HICN_PACKET_TYPE_INTEREST; \ t->sw_if_index = sw_if0; \ t->next_index = next0; \ + t->error = ret0; \ clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0), \ sizeof (t->packet_data)); \ } \ @@ -366,9 +454,10 @@ typedef enum { \ TRACE_INPUT_PKT_IP##ipv *t = \ vlib_add_trace (vm, node, b1, sizeof (*t)); \ - t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->pkt_type = HICN_PACKET_TYPE_INTEREST; \ t->sw_if_index = sw_if1; \ t->next_index = next1; \ + t->error = ret1; \ clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b1), \ sizeof (t->packet_data)); \ } \ @@ -435,9 +524,17 @@ hicn4_iface_input_format_trace (u8 *s, va_list *args) CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); hicn4_iface_input_trace_t *t = va_arg (*args, hicn4_iface_input_trace_t *); - s = format (s, "IFACE_IP4_INPUT: pkt: %d, sw_if_index %d, next index %d\n%U", - (int) t->pkt_type, t->sw_if_index, t->next_index, - format_ip4_header, t->packet_data, sizeof (t->packet_data)); + s = format (s, "IFACE_IP4_INPUT: pkt: %d, sw_if_index %d, next index %d", + (int) t->pkt_type, t->sw_if_index, t->next_index); + + if (t->error) + { + s = format (s, " drop reason: %s", get_error_string (t->error)); + } + + s = format (s, "\n%U", format_ip4_header, t->packet_data, + sizeof (t->packet_data)); + return (s); } @@ -544,6 +641,7 @@ hicn_rewrite_iface_data4 (vlib_main_t *vm, vlib_buffer_t *b0, const hicn_face_t *iface, u32 *next) { ip4_header_t *ip0; + int ret = HICN_ERROR_NONE; /* Get the pointer to the old ip and tcp header */ ip0 = vlib_buffer_get_current (b0); @@ -563,9 +661,11 @@ hicn_rewrite_iface_data4 (vlib_main_t *vm, vlib_buffer_t *b0, hicn_type_t type = hicn_get_buffer (b0)->type; u8 flags = hicn_get_buffer (b0)->flags; u8 reset_pl = flags & HICN_BUFFER_FLAGS_FROM_CS; - int ret = hicn_ops_vft[type.l1]->rewrite_data ( - type, &hicn->protocol, &(iface->nat_addr), &(temp_addr), iface->pl_id, - reset_pl); + + ret = hicn_ops_vft[type.l1]->rewrite_data (type, &hicn->protocol, + &(iface->nat_addr), &(temp_addr), + iface->pl_id, reset_pl); + if (ret == HICN_LIB_ERROR_REWRITE_CKSUM_REQUIRED) { ensure_offload_flags (b0, 1 /* is_v4 */); @@ -577,6 +677,7 @@ hicn_rewrite_iface_data6 (vlib_main_t *vm, vlib_buffer_t *b0, const hicn_face_t *iface, u32 *next) { ip6_header_t *ip0; + int ret = HICN_ERROR_NONE; /* Get the pointer to the old ip and tcp header */ /* Copy the previous ip and tcp header to the new portion of memory */ @@ -598,9 +699,10 @@ hicn_rewrite_iface_data6 (vlib_main_t *vm, vlib_buffer_t *b0, hicn_type_t type = hicn_get_buffer (b0)->type; u8 flags = hicn_get_buffer (b0)->flags; u8 reset_pl = flags & HICN_BUFFER_FLAGS_FROM_CS; - int ret = hicn_ops_vft[type.l1]->rewrite_data ( - type, &hicn->protocol, &(iface->nat_addr), &(temp_addr), iface->pl_id, - reset_pl); + + ret = hicn_ops_vft[type.l1]->rewrite_data (type, &hicn->protocol, + &(iface->nat_addr), &(temp_addr), + iface->pl_id, reset_pl); if (ret == HICN_LIB_ERROR_REWRITE_CKSUM_REQUIRED) { @@ -653,7 +755,7 @@ hicn_rewrite_iface_data6 (vlib_main_t *vm, vlib_buffer_t *b0, { \ TRACE_OUTPUT_PKT_IP##ipv *t = \ vlib_add_trace (vm, node, b0, sizeof (*t)); \ - t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->pkt_type = HICN_PACKET_TYPE_INTEREST; \ t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ t->next_index = next0; \ clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0), \ @@ -731,7 +833,7 @@ hicn_rewrite_iface_data6 (vlib_main_t *vm, vlib_buffer_t *b0, { \ TRACE_OUTPUT_PKT_IP##ipv *t = \ vlib_add_trace (vm, node, b0, sizeof (*t)); \ - t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->pkt_type = HICN_PACKET_TYPE_INTEREST; \ t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ t->next_index = next0; \ clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b0), \ @@ -743,7 +845,7 @@ hicn_rewrite_iface_data6 (vlib_main_t *vm, vlib_buffer_t *b0, { \ TRACE_OUTPUT_PKT_IP##ipv *t = \ vlib_add_trace (vm, node, b1, sizeof (*t)); \ - t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->pkt_type = HICN_PACKET_TYPE_INTEREST; \ t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; \ t->next_index = next1; \ clib_memcpy_fast (t->packet_data, vlib_buffer_get_current (b1), \ @@ -824,7 +926,8 @@ VLIB_REGISTER_NODE (hicn4_iface_output_node) = { .next_nodes = { [HICN4_IFACE_OUTPUT_NEXT_DROP] = "error-drop", [HICN4_IFACE_OUTPUT_NEXT_LOOKUP] = "ip4-lookup", [HICN4_IFACE_OUTPUT_NEXT_UDP4_ENCAP] = "udp4-encap", - [HICN4_IFACE_OUTPUT_NEXT_UDP6_ENCAP] = "udp6-encap" }, + [HICN4_IFACE_OUTPUT_NEXT_UDP6_ENCAP] = "udp6-encap", + [HICN4_IFACE_OUTPUT_NEXT_PG] = "hicnpg-data" }, }; static uword @@ -893,7 +996,8 @@ VLIB_REGISTER_NODE (hicn6_iface_output_node) = { .next_nodes = { [HICN6_IFACE_OUTPUT_NEXT_DROP] = "error-drop", [HICN6_IFACE_OUTPUT_NEXT_LOOKUP] = "ip6-lookup", [HICN6_IFACE_OUTPUT_NEXT_UDP4_ENCAP] = "udp4-encap", - [HICN6_IFACE_OUTPUT_NEXT_UDP6_ENCAP] = "udp6-encap" }, + [HICN6_IFACE_OUTPUT_NEXT_UDP6_ENCAP] = "udp6-encap", + [HICN6_IFACE_OUTPUT_NEXT_PG] = "hicnpg-data" }, }; /* @@ -902,4 +1006,4 @@ VLIB_REGISTER_NODE (hicn6_iface_output_node) = { * Local Variables: * eval: (c-set-style "gnu") * End: - */ + */
\ No newline at end of file diff --git a/hicn-plugin/src/hicn.c b/hicn-plugin/src/hicn.c index 1131d4339..1789f5407 100644 --- a/hicn-plugin/src/hicn.c +++ b/hicn-plugin/src/hicn.c @@ -28,6 +28,7 @@ #include "face_db.h" #include "udp_tunnels/udp_tunnel.h" #include "route.h" +#include "pg.h" hicn_main_t hicn_main; /* Module vars */ @@ -223,24 +224,29 @@ hicn_init (vlib_main_t *vm) hicn_main_t *sm = &hicn_main; - /* Init other elements in the 'main' struct */ + // Init other elements in the 'main' struct sm->is_enabled = 0; error = hicn_api_plugin_hookup (vm); - /* Init the dpo module */ + // Init the dpo module hicn_dpos_init (); - /* Init the app manager */ + // Init the app manager address_mgr_init (); + // Init the face module hicn_face_module_init (vm); - /* Init the route module */ + // Init the route module hicn_route_init (); + // Init the UDP tunnels module udp_tunnel_init (); + // Init the packet generator module + hicn_pg_init (vm); + return error; } diff --git a/hicn-plugin/src/hicn.h b/hicn-plugin/src/hicn.h index aaf16c917..22309e3e5 100644 --- a/hicn-plugin/src/hicn.h +++ b/hicn-plugin/src/hicn.h @@ -57,32 +57,44 @@ typedef u8 weight_t; #define VLIB_BUFFER_MIN_CHAIN_SEG_SIZE (128) #endif -/* vlib_buffer cloning utilities impose that current_lentgh is more that - * 2*CLIB_CACHE_LINE_BYTES. */ -/* This flag is used to mark packets whose lenght is less that - * 2*CLIB_CACHE_LINE_BYTES. */ -#define HICN_BUFFER_FLAGS_PKT_LESS_TWO_CL 0x02 -#define HICN_BUFFER_FLAGS_FROM_CS 0x10 - /* The following is stored in the opaque2 field in the vlib_buffer_t */ typedef struct { - /* hash of the name */ + /** + * Hash of the name (8) + */ u64 name_hash; - /* ids to prefetch a PIT/CS entry */ + /** + * IDs to prefetch a PIT/CS entry (4+4+1+1) + */ u32 node_id; u32 bucket_id; u8 hash_entry_id; u8 hash_bucket_flags; + /** + * hICN buffer flags (1) + */ u8 flags; - u8 dpo_ctx_id; /* used for data path */ - u8 vft_id; /* " */ - hicn_face_id_t face_id; /* ingress iface, sizeof(u32) */ + /** + * used for data path (1+1) + */ + u8 dpo_ctx_id; + u8 vft_id; + + /** + * Ingress face (4) + */ + hicn_face_id_t face_id; + /** + * Cached packet info + */ hicn_type_t type; + hicn_name_t name; + u16 port; } hicn_buffer_t; STATIC_ASSERT (sizeof (hicn_buffer_t) <= @@ -101,6 +113,28 @@ hicn_is_v6 (hicn_header_t *pkt_hdr) return ((pkt_hdr->v4.ip.version_ihl >> 4) != 4); } +always_inline void +hicn_buffer_get_name_and_namelen (vlib_buffer_t *b0, u8 **nameptr, + u16 *namelen) +{ + *nameptr = (u8 *) (&hicn_get_buffer (b0)->name); + *namelen = ip_address_is_v4 (&hicn_get_buffer (b0)->name.prefix) ? + HICN_V4_NAME_LEN : + HICN_V6_NAME_LEN; +} + +always_inline u8 +hicn_buffer_is_v6 (vlib_buffer_t *b0) +{ + return hicn_get_buffer (b0)->type.l1 == IPPROTO_IPV6; +} + +always_inline void +hicn_buffer_set_flags (vlib_buffer_t *b, u8 flags) +{ + hicn_buffer_t *hb = hicn_get_buffer (b); + hb->flags |= flags; +} #endif /* __HICN_H__ */ /* diff --git a/hicn-plugin/src/hicn_buffer_flags.h b/hicn-plugin/src/hicn_buffer_flags.h new file mode 100644 index 000000000..7d99e6d33 --- /dev/null +++ b/hicn-plugin/src/hicn_buffer_flags.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HICN_BUFFER_FLAGS_H__ +#define __HICN_BUFFER_FLAGS_H__ + +#define foreach_hicn_buffer_flag \ + _ (0, NEW_FACE, "new face") \ + _ (1, PKT_LESS_TWO_CL, "packet is less that 2 cache lines length") \ + _ (2, FROM_UDP4_TUNNEL, "packet is from udp4 tunnel") \ + _ (3, FROM_UDP6_TUNNEL, "packet is from udp6 tunnel") \ + _ (4, FROM_CS, "packet is from cs") \ + _ (5, FROM_PG, "packet is from packet generator") + +enum +{ + HICN_BUFFER_FLAGS_DEFAULT = 0, +#define _(a, b, c) HICN_BUFFER_FLAGS_##b = (1 << a), + foreach_hicn_buffer_flag +#undef _ +}; + +#endif /* __HICN_BUFFER_FLAGS_H__ */
\ No newline at end of file diff --git a/hicn-plugin/src/interest_hitcs_node.c b/hicn-plugin/src/interest_hitcs_node.c index 947b4cb68..1af21191c 100644 --- a/hicn-plugin/src/interest_hitcs_node.c +++ b/hicn-plugin/src/interest_hitcs_node.c @@ -90,7 +90,6 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, hicn_interest_hitcs_runtime_t *rt; vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; f64 tnow; - int ret; rt = vlib_node_get_runtime_data (vm, hicn_interest_hitcs_node.index); @@ -116,8 +115,6 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, u16 namelen; u32 bi0; u32 next0 = HICN_INTEREST_HITCS_NEXT_ERROR_DROP; - hicn_name_t name; - hicn_header_t *hicn0; hicn_buffer_t *hicnb0; hicn_hash_node_t *node0; hicn_pcs_entry_t *pitp; @@ -150,8 +147,8 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, hicn_get_internal_state (hicnb0, rt->pitcs, &node0, &strategy_vft0, &dpo_vft0, &dpo_ctx_id0, &hash_entry0); - ret = hicn_interest_parse_pkt (b0, &name, &namelen, &hicn0, &isv6); - nameptr = (u8 *) (&name); + hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen); + isv6 = hicn_buffer_is_v6 (b0); pitp = hicn_pit_get_data (node0); dpo_id_t hicn_dpo_id0 = { .dpoi_type = @@ -160,8 +157,7 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, .dpoi_next_node = 0, .dpoi_index = dpo_ctx_id0 }; - if (PREDICT_FALSE (ret != HICN_ERROR_NONE || - !hicn_node_compare (nameptr, namelen, node0))) + if (PREDICT_FALSE (!hicn_node_compare (nameptr, namelen, node0))) { /* Remove lock from the entry */ hicn_pcs_remove_lock (rt->pitcs, &pitp, &node0, vm, hash_entry0, @@ -209,7 +205,7 @@ hicn_interest_hitcs_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, { hicn_interest_hitcs_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->pkt_type = HICN_PKT_TYPE_INTEREST; + t->pkt_type = HICN_PACKET_TYPE_INTEREST; t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; t->next_index = next0; } @@ -285,4 +281,4 @@ VLIB_REGISTER_NODE (hicn_interest_hitcs_node) = { * fd.io coding-style-patch-verification: ON * * Local Variables: eval: (c-set-style "gnu") End: - */ + */
\ No newline at end of file diff --git a/hicn-plugin/src/interest_hitpit.h b/hicn-plugin/src/interest_hitpit.h index 18ef94aa7..46659e67c 100644 --- a/hicn-plugin/src/interest_hitpit.h +++ b/hicn-plugin/src/interest_hitpit.h @@ -46,7 +46,7 @@ typedef struct { u32 next_index; u32 sw_if_index; - u8 pkt_type; + u32 pkt_type; } hicn_interest_hitpit_trace_t; typedef enum @@ -65,4 +65,4 @@ typedef enum * fd.io coding-style-patch-verification: ON * * Local Variables: eval: (c-set-style "gnu") End: - */ + */
\ No newline at end of file diff --git a/hicn-plugin/src/interest_hitpit_node.c b/hicn-plugin/src/interest_hitpit_node.c index 33dc782cd..c98baf7e9 100644 --- a/hicn-plugin/src/interest_hitpit_node.c +++ b/hicn-plugin/src/interest_hitpit_node.c @@ -79,8 +79,6 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, u16 namelen; u32 bi0; u32 next0 = HICN_INTEREST_HITPIT_NEXT_ERROR_DROP; - hicn_name_t name; - hicn_header_t *hicn0; hicn_hash_node_t *node0; const hicn_strategy_vft_t *strategy_vft0; const hicn_dpo_vft_t *dpo_vft0; @@ -92,7 +90,6 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, u32 outfaces_len; hicn_hash_entry_t *hash_entry0; hicn_buffer_t *hicnb0; - int ret; /* Prefetch for next iteration. */ if (n_left_from > 1) @@ -118,8 +115,9 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, hicn_get_internal_state (hicnb0, rt->pitcs, &node0, &strategy_vft0, &dpo_vft0, &dpo_ctx_id0, &hash_entry0); - ret = hicn_interest_parse_pkt (b0, &name, &namelen, &hicn0, &isv6); - nameptr = (u8 *) (&name); + hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen); + isv6 = hicn_buffer_is_v6 (b0); + pitp = hicn_pit_get_data (node0); dpo_id_t hicn_dpo_id0 = { .dpoi_type = dpo_vft0->hicn_dpo_get_type (), @@ -131,8 +129,7 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, * Check if the hit is instead a collision in the * hash table. Unlikely to happen. */ - if (PREDICT_FALSE (ret != HICN_ERROR_NONE || - !hicn_node_compare (nameptr, namelen, node0))) + if (PREDICT_FALSE (!hicn_node_compare (nameptr, namelen, node0))) { stats.interests_hash_collision++; /* Remove lock from the entry */ @@ -227,7 +224,7 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, hicn_interest_hitpit_trace_t *t = vlib_add_trace (vm, node, local_b0, sizeof (*t)); - t->pkt_type = HICN_PKT_TYPE_INTEREST; + t->pkt_type = HICN_PACKET_TYPE_INTEREST; t->sw_if_index = vnet_buffer (local_b0) ->sw_if_index[VLIB_RX]; t->next_index = next0; @@ -266,7 +263,7 @@ hicn_interest_hitpit_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, { hicn_interest_hitpit_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->pkt_type = HICN_PKT_TYPE_INTEREST; + t->pkt_type = HICN_PACKET_TYPE_INTEREST; t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; t->next_index = next0; } @@ -354,4 +351,4 @@ VLIB_REGISTER_NODE(hicn_interest_hitpit_node) = * fd.io coding-style-patch-verification: ON * * Local Variables: eval: (c-set-style "gnu") End: - */ + */
\ No newline at end of file diff --git a/hicn-plugin/src/interest_pcslookup_node.c b/hicn-plugin/src/interest_pcslookup_node.c index ff0da12d7..e569573b7 100644 --- a/hicn-plugin/src/interest_pcslookup_node.c +++ b/hicn-plugin/src/interest_pcslookup_node.c @@ -57,7 +57,6 @@ hicn_interest_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, hicn_interest_pcslookup_next_t next_index; hicn_interest_pcslookup_runtime_t *rt; vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; - int ret; rt = vlib_node_get_runtime_data (vm, hicn_interest_pcslookup_node.index); @@ -76,14 +75,11 @@ hicn_interest_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, while (n_left_from > 0 && n_left_to_next > 0) { vlib_buffer_t *b0; - u8 isv6; u8 *nameptr; u16 namelen; u32 bi0; u32 next0 = HICN_INTEREST_PCSLOOKUP_NEXT_ERROR_DROP; u64 name_hash = 0; - hicn_name_t name; - hicn_header_t *hicn0; u32 node_id0 = 0; index_t dpo_ctx_id0 = 0; u8 vft_id0 = 0; @@ -109,19 +105,15 @@ hicn_interest_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, n_left_to_next -= 1; b0 = vlib_get_buffer (vm, bi0); - ret = hicn_interest_parse_pkt (b0, &name, &namelen, &hicn0, &isv6); - if (PREDICT_TRUE (ret == HICN_ERROR_NONE)) - { - next0 = HICN_INTEREST_PCSLOOKUP_NEXT_STRATEGY; - } - nameptr = (u8 *) (&name); + hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen); + + next0 = HICN_INTEREST_PCSLOOKUP_NEXT_STRATEGY; stats.pkts_processed++; if (PREDICT_FALSE ( - ret != HICN_ERROR_NONE || hicn_hashtb_fullhash (nameptr, namelen, &name_hash) != - HICN_ERROR_NONE)) + HICN_ERROR_NONE)) { next0 = HICN_INTEREST_PCSLOOKUP_NEXT_ERROR_DROP; } @@ -149,7 +141,7 @@ hicn_interest_pcslookup_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, { hicn_interest_pcslookup_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->pkt_type = HICN_PKT_TYPE_INTEREST; + t->pkt_type = HICN_PACKET_TYPE_INTEREST; t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; t->next_index = next0; } @@ -226,4 +218,4 @@ VLIB_REGISTER_NODE(hicn_interest_pcslookup_node) = * fd.io coding-style-patch-verification: ON * * Local Variables: eval: (c-set-style "gnu") End: - */ + */
\ No newline at end of file diff --git a/hicn-plugin/src/parser.h b/hicn-plugin/src/parser.h index 0e60c526f..29405ebec 100644 --- a/hicn-plugin/src/parser.h +++ b/hicn-plugin/src/parser.h @@ -25,93 +25,149 @@ * @file parser.h */ -/* - * Key type codes for header, header tlvs, body tlvs, and child tlvs - */ - -// FIXME(reuse lib struct, no more control ?) -enum hicn_pkt_type_e -{ - HICN_PKT_TYPE_INTEREST = 0, - HICN_PKT_TYPE_CONTENT = 1, -}; - /** - * @brief Parse an interest packet + * @brief Parse a interest packet * * @param pkt vlib buffer holding the interest - * @param name return variable that will point to the hicn name - * @param namelen return valiable that will hold the length of the name - * @param pkt_hdrp return valiable that will point to the packet header - * @param isv6 return variable that will be equale to 1 is the header is ipv6 + * @param name [RETURNED] variable that will point to the hicn name + * @param namelen [RETURNED] variable that will hold the length of the name + * @param port [RETURNED] variable that will hold the source port of the packet + * @param pkt_hdrp [RETURNED] valiable that will point to the packet header + * @param isv6 [RETURNED] variable that will be equale to 1 is the header is + * ipv6 */ always_inline int -hicn_interest_parse_pkt (vlib_buffer_t *pkt, hicn_name_t *name, u16 *namelen, - hicn_header_t **pkt_hdrp, u8 *isv6) +hicn_interest_parse_pkt (vlib_buffer_t *pkt) { if (pkt == NULL) return HICN_ERROR_PARSER_PKT_INVAL; - hicn_header_t *pkt_hdr = vlib_buffer_get_current (pkt); - *pkt_hdrp = pkt_hdr; - u8 *ip_pkt = vlib_buffer_get_current (pkt); - *isv6 = hicn_is_v6 (pkt_hdr); - u8 ip_proto = (*isv6) * IPPROTO_IPV6; - u8 next_proto_offset = 6 + (1 - *isv6) * 3; - // in the ipv6 header the next header field is at byte 6 - // in the ipv4 header the protocol field is at byte 9 - hicn_type_t type = - (hicn_type_t){ { .l4 = IPPROTO_NONE, - .l3 = ip_pkt[next_proto_offset] == IPPROTO_UDP ? - IPPROTO_ENCAP : - IPPROTO_NONE, - .l2 = ip_pkt[next_proto_offset], - .l1 = ip_proto } }; + + int ret = HICN_LIB_ERROR_NONE; + + hicn_header_t *pkt_hdr; + u8 *ip_pkt; + u8 ip_proto; + u8 next_proto_offset; + hicn_type_t type; + hicn_name_t *name; + u16 *port; + int isv6; + + // start parsing first fields to get the protocols + pkt_hdr = vlib_buffer_get_current (pkt); + isv6 = hicn_is_v6 (pkt_hdr); + + ip_pkt = vlib_buffer_get_current (pkt); + ip_proto = (1 - isv6) * IPPROTO_IP + (isv6) *IPPROTO_IPV6; + + // in the ipv6 header the next header field is at byte 6 in the ipv4 + // header the protocol field is at byte 9 + next_proto_offset = 6 + (1 - isv6) * 3; + + // get type info + type.l4 = IPPROTO_NONE; + type.l3 = + ip_pkt[next_proto_offset] == IPPROTO_UDP ? IPPROTO_ENCAP : IPPROTO_NONE; + type.l2 = ip_pkt[next_proto_offset]; + type.l1 = ip_proto; + + // cache hicn packet type in opaque2 hicn_get_buffer (pkt)->type = type; - hicn_ops_vft[type.l1]->get_interest_name (type, &pkt_hdr->protocol, name); - *namelen = (1 - (*isv6)) * HICN_V4_NAME_LEN + (*isv6) * HICN_V6_NAME_LEN; + // get name and name length + name = &hicn_get_buffer (pkt)->name; + ret = + hicn_ops_vft[type.l1]->get_interest_name (type, &pkt_hdr->protocol, name); + if (PREDICT_FALSE (ret)) + { + if (type.l2 == IPPROTO_ICMPV4 || type.l2 == IPPROTO_ICMPV6) + { + return HICN_ERROR_PARSER_MAPME_PACKET; + } + return HICN_ERROR_PARSER_PKT_INVAL; + } - return HICN_ERROR_NONE; + // get source port + port = &hicn_get_buffer (pkt)->port; + hicn_ops_vft[type.l1]->get_source_port (type, &pkt_hdr->protocol, port); + if (PREDICT_FALSE (ret)) + { + return HICN_ERROR_PARSER_PKT_INVAL; + } + + return ret; } /** * @brief Parse a data packet * - * @param pkt vlib buffer holding the interest - * @param name return variable that will point to the hicn name - * @param namelen return valiable that will hold the length of the name - * @param pkt_hdrp return valiable that will point to the packet header - * @param isv6 return variable that will be equale to 1 is the header is ipv6 + * @param pkt vlib buffer holding the data + * @param name [RETURNED] variable that will point to the hicn name + * @param namelen [RETURNED] variable that will hold the length of the name + * @param port [RETURNED] variable that will hold the source port of the packet + * @param pkt_hdrp [RETURNED] valiable that will point to the packet header + * @param isv6 [RETURNED] variable that will be equale to 1 is the header is + * ipv6 */ always_inline int -hicn_data_parse_pkt (vlib_buffer_t *pkt, hicn_name_t *name, u16 *namelen, - hicn_header_t **pkt_hdrp, u8 *isv6) +hicn_data_parse_pkt (vlib_buffer_t *pkt) { if (pkt == NULL) return HICN_ERROR_PARSER_PKT_INVAL; - hicn_header_t *pkt_hdr = vlib_buffer_get_current (pkt); - *pkt_hdrp = pkt_hdr; - *pkt_hdrp = pkt_hdr; - u8 *ip_pkt = vlib_buffer_get_current (pkt); - *isv6 = hicn_is_v6 (pkt_hdr); - u8 ip_proto = (*isv6) * IPPROTO_IPV6; - /* - * in the ipv6 header the next header field is at byte 6 in the ipv4 - * header the protocol field is at byte 9 - */ - u8 next_proto_offset = 6 + (1 - *isv6) * 3; - hicn_type_t type = - (hicn_type_t){ { .l4 = IPPROTO_NONE, - .l3 = ip_pkt[next_proto_offset] == IPPROTO_UDP ? - IPPROTO_ENCAP : - IPPROTO_NONE, - .l2 = ip_pkt[next_proto_offset], - .l1 = ip_proto } }; + + int ret = HICN_LIB_ERROR_NONE; + + hicn_header_t *pkt_hdr; + u8 *ip_pkt; + u8 ip_proto; + int isv6; + u8 next_proto_offset; + hicn_type_t type; + hicn_name_t *name; + u16 *port; + + // start parsing first fields to get the protocols + pkt_hdr = vlib_buffer_get_current (pkt); + isv6 = hicn_is_v6 (pkt_hdr); + + ip_pkt = vlib_buffer_get_current (pkt); + ip_proto = (1 - isv6) * IPPROTO_IP + (isv6) *IPPROTO_IPV6; + + // in the ipv6 header the next header field is at byte 6 in the ipv4 + // header the protocol field is at byte 9 + next_proto_offset = 6 + (1 - isv6) * 3; + + // get type info + type.l4 = IPPROTO_NONE; + type.l3 = + ip_pkt[next_proto_offset] == IPPROTO_UDP ? IPPROTO_ENCAP : IPPROTO_NONE; + type.l2 = ip_pkt[next_proto_offset]; + type.l1 = ip_proto; + + // cache hicn packet type in opaque2 hicn_get_buffer (pkt)->type = type; - hicn_ops_vft[type.l1]->get_data_name (type, &pkt_hdr->protocol, name); - *namelen = (1 - (*isv6)) * HICN_V4_NAME_LEN + (*isv6) * HICN_V6_NAME_LEN; - return HICN_ERROR_NONE; + // get name and name length + name = &hicn_get_buffer (pkt)->name; + ret = hicn_ops_vft[type.l1]->get_data_name (type, &pkt_hdr->protocol, name); + if (PREDICT_FALSE (ret)) + { + if (type.l2 == IPPROTO_ICMPV4 || type.l2 == IPPROTO_ICMPV6) + { + return HICN_ERROR_PARSER_MAPME_PACKET; + } + return HICN_ERROR_PARSER_PKT_INVAL; + } + + // get source port + port = &hicn_get_buffer (pkt)->port; + hicn_ops_vft[type.l1]->get_source_port (type, &pkt_hdr->protocol, port); + if (PREDICT_FALSE (ret)) + { + return HICN_ERROR_PARSER_PKT_INVAL; + } + + return ret; } #endif /* // __HICN_PARSER_H__ */ @@ -120,4 +176,4 @@ hicn_data_parse_pkt (vlib_buffer_t *pkt, hicn_name_t *name, u16 *namelen, * fd.io coding-style-patch-verification: ON * * Local Variables: eval: (c-set-style "gnu") End: - */ + */
\ No newline at end of file diff --git a/hicn-plugin/src/pg.c b/hicn-plugin/src/pg.c index b77e8fcac..05172345b 100644 --- a/hicn-plugin/src/pg.c +++ b/hicn-plugin/src/pg.c @@ -18,57 +18,13 @@ #include <vnet/pg/pg.h> #include <vnet/ip/ip.h> #include <vnet/ethernet/ethernet.h> +#include <vnet/fib/fib_entry_track.h> #include "hicn.h" #include "pg.h" #include "parser.h" #include "infra.h" - -/* Registration struct for a graph node */ -vlib_node_registration_t hicn_pg_interest_node; -vlib_node_registration_t hicn_pg_data_node; - -/* Stats, which end up called "error" even though they aren't... */ -#define foreach_hicnpg_error \ - _ (PROCESSED, "hICN PG packets processed") \ - _ (DROPPED, "hICN PG packets dropped") \ - _ (INTEREST_MSGS_GENERATED, "hICN PG Interests generated") \ - _ (CONTENT_MSGS_RECEIVED, "hICN PG Content msgs received") - -typedef enum -{ -#define _(sym, str) HICNPG_ERROR_##sym, - foreach_hicnpg_error -#undef _ - HICNPG_N_ERROR, -} hicnpg_error_t; - -static char *hicnpg_error_strings[] = { -#define _(sym, string) string, - foreach_hicnpg_error -#undef _ -}; - -/* - * Next graph nodes, which reference the list in the actual registration - * block below - */ -typedef enum -{ - HICNPG_INTEREST_NEXT_V4_LOOKUP, - HICNPG_INTEREST_NEXT_V6_LOOKUP, - HICNPG_INTEREST_NEXT_DROP, - HICNPG_N_NEXT, -} hicnpg_interest_next_t; - -/* Trace context struct */ -typedef struct -{ - u32 next_index; - u32 sw_if_index; - u8 pkt_type; - u16 msg_type; -} hicnpg_trace_t; +#include "route.h" hicnpg_main_t hicnpg_main = { .index = (u32) 0, .index_ifaces = (u32) 1, @@ -78,1183 +34,281 @@ hicnpg_main_t hicnpg_main = { .index = (u32) 0, .n_ifaces = (u32) 1, .sw_if = (u32) 0 }; -hicnpg_server_main_t hicnpg_server_main = { - .node_index = 0, -}; - -/* packet trace format function */ -static u8 * -format_hicnpg_trace (u8 *s, va_list *args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - hicnpg_trace_t *t = va_arg (*args, hicnpg_trace_t *); - - s = format (s, "HICNPG: pkt: %d, msg %d, sw_if_index %d, next index %d", - (int) t->pkt_type, (int) t->msg_type, t->sw_if_index, - t->next_index); - return (s); -} - -always_inline void hicn_rewrite_interestv4 (vlib_main_t *vm, vlib_buffer_t *b0, - u32 seq_number, u16 lifetime, - u32 next_flow, u32 iface); - -always_inline void hicn_rewrite_interestv6 (vlib_main_t *vm, vlib_buffer_t *b0, - u32 seq_number, u16 lifetime, - u32 next_flow, u32 iface); - -always_inline void convert_interest_to_data_v4 (vlib_main_t *vm, - vlib_buffer_t *b0, - vlib_buffer_t *rb, u32 bi0); - -always_inline void convert_interest_to_data_v6 (vlib_main_t *vm, - vlib_buffer_t *b0, - vlib_buffer_t *rb, u32 bi0); - -always_inline void calculate_tcp_checksum_v4 (vlib_main_t *vm, - vlib_buffer_t *b0); +/** + * Pool of hicnpg_server_t + */ +hicnpg_server_t *hicnpg_server_pool; -always_inline void calculate_tcp_checksum_v6 (vlib_main_t *vm, - vlib_buffer_t *b0); /* - * Node function for the icn packet-generator client. The goal here is to - * manipulate/tweak a stream of packets that have been injected by the vpp - * packet generator to generate icn request traffic. + * hicnph servrer FIB node type */ -static uword -hicnpg_client_interest_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, - vlib_frame_t *frame) -{ - u32 n_left_from, *from, *to_next; - hicnpg_interest_next_t next_index; - u32 pkts_processed = 0, pkts_dropped = 0; - u32 interest_msgs_generated = 0; - u32 bi0, bi1; - vlib_buffer_t *b0, *b1; - u8 pkt_type0 = 0, pkt_type1 = 0; - u16 msg_type0 = 0, msg_type1 = 0; - hicn_header_t *hicn0 = NULL, *hicn1 = NULL; - hicn_name_t name0, name1; - u16 namelen0, namelen1; - hicnpg_main_t *hpgm = &hicnpg_main; - int iface = 0; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 next0 = HICNPG_INTEREST_NEXT_DROP; - u32 next1 = HICNPG_INTEREST_NEXT_DROP; - u32 sw_if_index0 = ~0, sw_if_index1 = ~0; - u8 isv6_0; - u8 isv6_1; - - /* Prefetch next iteration. */ - { - vlib_buffer_t *p2, *p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, (2 * CLIB_CACHE_LINE_BYTES), STORE); - CLIB_PREFETCH (p3->data, (2 * CLIB_CACHE_LINE_BYTES), STORE); - } - - /* - * speculatively enqueue b0 and b1 to the current - * next frame - */ - to_next[0] = bi0 = from[0]; - to_next[1] = bi1 = from[1]; - from += 2; - to_next += 2; - n_left_from -= 2; - n_left_to_next -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; - vnet_buffer (b0)->sw_if_index[VLIB_RX] = hpgm->sw_if; - vnet_buffer (b1)->sw_if_index[VLIB_RX] = hpgm->sw_if; - - /* Check icn packets, locate names */ - if (hicn_interest_parse_pkt (b0, &name0, &namelen0, &hicn0, - &isv6_0) == HICN_ERROR_NONE) - { - /* this node grabs only interests */ - - /* Increment the appropriate message counter */ - interest_msgs_generated++; - - iface = (hpgm->index_ifaces % hpgm->n_ifaces); - /* Rewrite and send */ - isv6_0 ? - hicn_rewrite_interestv6 ( - vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number, - hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, - iface) : - hicn_rewrite_interestv4 ( - vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number, - hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, iface); - - hpgm->index_ifaces++; - if (iface == (hpgm->n_ifaces - 1)) - hpgm->index++; - - next0 = isv6_0 ? HICNPG_INTEREST_NEXT_V6_LOOKUP : - HICNPG_INTEREST_NEXT_V4_LOOKUP; - } - if (hicn_interest_parse_pkt (b1, &name1, &namelen1, &hicn1, - &isv6_1) == HICN_ERROR_NONE) - { - /* this node grabs only interests */ - - /* Increment the appropriate message counter */ - interest_msgs_generated++; - - iface = (hpgm->index_ifaces % hpgm->n_ifaces); - /* Rewrite and send */ - isv6_1 ? - hicn_rewrite_interestv6 ( - vm, b1, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number, - hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, - iface) : - hicn_rewrite_interestv4 ( - vm, b1, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number, - hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, iface); - - hpgm->index_ifaces++; - if (iface == (hpgm->n_ifaces - 1)) - hpgm->index++; - - next1 = isv6_1 ? HICNPG_INTEREST_NEXT_V6_LOOKUP : - HICNPG_INTEREST_NEXT_V4_LOOKUP; - } - /* Send pkt to next node */ - vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0; - vnet_buffer (b1)->sw_if_index[VLIB_TX] = ~0; - - pkts_processed += 2; - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) - { - if (b0->flags & VLIB_BUFFER_IS_TRACED) - { - hicnpg_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->pkt_type = pkt_type0; - t->msg_type = msg_type0; - t->sw_if_index = sw_if_index0; - t->next_index = next0; - } - if (b1->flags & VLIB_BUFFER_IS_TRACED) - { - hicnpg_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->pkt_type = pkt_type1; - t->msg_type = msg_type1; - t->sw_if_index = sw_if_index1; - t->next_index = next1; - } - } - if (next0 == HICNPG_INTEREST_NEXT_DROP) - { - pkts_dropped++; - } - if (next1 == HICNPG_INTEREST_NEXT_DROP) - { - pkts_dropped++; - } - /* - * verify speculative enqueues, maybe switch current - * next frame - */ - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, - n_left_to_next, bi0, bi1, next0, - next1); - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 next0 = HICNPG_INTEREST_NEXT_DROP; - u32 sw_if_index0; - u8 isv6_0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - vnet_buffer (b0)->sw_if_index[VLIB_RX] = hpgm->sw_if; - - /* Check icn packets, locate names */ - if (hicn_interest_parse_pkt (b0, &name0, &namelen0, &hicn0, - &isv6_0) == HICN_ERROR_NONE) - { - /* this node grabs only interests */ - - /* Increment the appropriate message counter */ - interest_msgs_generated++; - - iface = (hpgm->index_ifaces % hpgm->n_ifaces); - - /* Rewrite and send */ - isv6_0 ? - hicn_rewrite_interestv6 ( - vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number, - hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, - iface) : - hicn_rewrite_interestv4 ( - vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number, - hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, iface); - - hpgm->index_ifaces++; - if (iface == (hpgm->n_ifaces - 1)) - hpgm->index++; - - next0 = isv6_0 ? HICNPG_INTEREST_NEXT_V6_LOOKUP : - HICNPG_INTEREST_NEXT_V4_LOOKUP; - } - /* Send pkt to ip lookup */ - vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0; +fib_node_type_t hicnpg_server_fib_node_type; - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && - (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - hicnpg_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->pkt_type = pkt_type0; - t->msg_type = msg_type0; - t->sw_if_index = sw_if_index0; - t->next_index = next0; - } - pkts_processed += 1; - - if (next0 == HICNPG_INTEREST_NEXT_DROP) - { - pkts_dropped++; - } - /* - * verify speculative enqueue, maybe switch current - * next frame - */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - vlib_node_increment_counter (vm, hicn_pg_interest_node.index, - HICNPG_ERROR_PROCESSED, pkts_processed); - vlib_node_increment_counter (vm, hicn_pg_interest_node.index, - HICNPG_ERROR_DROPPED, pkts_dropped); - vlib_node_increment_counter (vm, hicn_pg_interest_node.index, - HICNPG_ERROR_INTEREST_MSGS_GENERATED, - interest_msgs_generated); +/** + * Registered DPO type. + */ +dpo_type_t hicnpg_server_dpo_type; - return (frame->n_vectors); +static void +hicnpg_server_restack (hicnpg_server_t *hicnpg_server) +{ + dpo_stack ( + hicnpg_server_dpo_type, fib_proto_to_dpo (hicnpg_server->prefix.fp_proto), + &hicnpg_server->dpo, + fib_entry_contribute_ip_forwarding (hicnpg_server->fib_entry_index)); } -void -hicn_rewrite_interestv4 (vlib_main_t *vm, vlib_buffer_t *b0, u32 seq_number, - u16 interest_lifetime, u32 next_flow, u32 iface) +static hicnpg_server_t * +hicnpg_server_from_fib_node (fib_node_t *node) { - hicn_header_t *h0 = vlib_buffer_get_current (b0); - - /* Generate the right src and dst corresponding to flow and iface */ - ip46_address_t src_addr = { - .ip4 = hicnpg_main.pgen_clt_src_addr.ip4, - }; - hicn_name_t dst_name = { - .prefix.ip4 = hicnpg_main.pgen_clt_hicn_name->fp_addr.ip4, - .suffix = seq_number, - }; - - src_addr.ip4.as_u32 += clib_host_to_net_u32 (iface); - dst_name.prefix.ip4.as_u32 += clib_net_to_host_u32 (next_flow); - - /* Update locator and name */ - hicn_type_t type = hicn_get_buffer (b0)->type; - HICN_OPS4->set_interest_locator (type, &h0->protocol, &src_addr); - HICN_OPS4->set_interest_name (type, &h0->protocol, &dst_name); - - /* Update lifetime (currently L4 checksum is not updated) */ - HICN_OPS4->set_lifetime (type, &h0->protocol, interest_lifetime); - - /* Update checksums */ - HICN_OPS4->update_checksums (type, &h0->protocol, 0, 0); + ASSERT (hicnpg_server_fib_node_type == node->fn_type); + return ((hicnpg_server_t *) (((char *) node) - + STRUCT_OFFSET_OF (hicnpg_server_t, fib_node))); } /** - * @brief Rewrite the IPv6 header as the next generated packet - * - * Set up a name prefix - * - etiher generate interest in which the name varies only after the prefix - * (inc : seq_number), then the flow acts on the prefix (CHECK) - * seq_number => TCP, FLOW => - * - * SRC : pgen_clt_src_addr.ip6 DST = generate name (pgen_clt_hicn_name.ip6) - * ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff - * \__/ \__/ - * +iface + flow - * Source is used to emulate different consumers. - * FIXME iface is ill-named, better name it consumer id - * Destination is used to iterate on the content. + * Function definition to backwalk a FIB node */ -void -hicn_rewrite_interestv6 (vlib_main_t *vm, vlib_buffer_t *b0, u32 seq_number, - u16 interest_lifetime, u32 next_flow, u32 iface) +static fib_node_back_walk_rc_t +hicnpg_server_fib_back_walk (fib_node_t *node, fib_node_back_walk_ctx_t *ctx) { - hicn_header_t *h0 = vlib_buffer_get_current (b0); - - /* Generate the right src and dst corresponding to flow and iface */ - ip46_address_t src_addr = { - .ip6 = hicnpg_main.pgen_clt_src_addr.ip6, - }; - hicn_name_t dst_name = { - .prefix.ip6 = hicnpg_main.pgen_clt_hicn_name->fp_addr.ip6, - .suffix = seq_number, - }; - src_addr.ip6.as_u32[3] += clib_host_to_net_u32 (iface); - dst_name.prefix.ip6.as_u32[3] += clib_net_to_host_u32 (next_flow); + hicnpg_server_restack (hicnpg_server_from_fib_node (node)); - /* Update locator and name */ - hicn_type_t type = hicn_get_buffer (b0)->type; - HICN_OPS6->set_interest_locator (type, &h0->protocol, &src_addr); - HICN_OPS6->set_interest_name (type, &h0->protocol, &dst_name); - - /* Update lifetime */ - HICN_OPS6->set_lifetime (type, &h0->protocol, interest_lifetime); - - /* Update checksums */ - calculate_tcp_checksum_v6 (vm, b0); + return FIB_NODE_BACK_WALK_CONTINUE; } -void -calculate_tcp_checksum_v4 (vlib_main_t *vm, vlib_buffer_t *b0) +/** + * Function definition to get a FIB node from its index + */ +static fib_node_t * +hicnpg_server_fib_node_get (fib_node_index_t index) { - ip4_header_t *ip0; - tcp_header_t *tcp0; - ip_csum_t sum0; - u32 tcp_len0; - - ip0 = (ip4_header_t *) (vlib_buffer_get_current (b0)); - tcp0 = - (tcp_header_t *) (vlib_buffer_get_current (b0) + sizeof (ip4_header_t)); - tcp_len0 = clib_net_to_host_u16 (ip0->length) - sizeof (ip4_header_t); - - /* Initialize checksum with header. */ - if (BITS (sum0) == 32) - { - sum0 = clib_mem_unaligned (&ip0->src_address, u32); - sum0 = - ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->dst_address, u32)); - } - else - sum0 = clib_mem_unaligned (&ip0->src_address, u64); - - sum0 = ip_csum_with_carry ( - sum0, clib_host_to_net_u32 (tcp_len0 + (ip0->protocol << 16))); - - /* Invalidate possibly old checksum. */ - tcp0->checksum = 0; + hicnpg_server_t *hpg_server; - u32 tcp_offset = sizeof (ip4_header_t); - sum0 = ip_incremental_checksum_buffer (vm, b0, tcp_offset, tcp_len0, sum0); + hpg_server = pool_elt_at_index (hicnpg_server_pool, index); - tcp0->checksum = ~ip_csum_fold (sum0); + return (&hpg_server->fib_node); } -void -calculate_tcp_checksum_v6 (vlib_main_t *vm, vlib_buffer_t *b0) +/** + * Function definition to inform the FIB node that its last lock has gone. + */ +static void +hicnpg_server_fib_last_lock_gone (fib_node_t *node) { - ip6_header_t *ip0; - tcp_header_t *tcp0; - ip_csum_t sum0; - u32 tcp_len0; - - ip0 = (ip6_header_t *) (vlib_buffer_get_current (b0)); - tcp0 = - (tcp_header_t *) (vlib_buffer_get_current (b0) + sizeof (ip6_header_t)); - tcp_len0 = clib_net_to_host_u16 (ip0->payload_length); + hicnpg_server_t *hpg_server; - /* Initialize checksum with header. */ - if (BITS (sum0) == 32) - { - sum0 = clib_mem_unaligned (&ip0->src_address, u32); - sum0 = - ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->dst_address, u32)); - } - else - sum0 = clib_mem_unaligned (&ip0->src_address, u64); - - sum0 = ip_csum_with_carry ( - sum0, clib_host_to_net_u32 (tcp_len0 + (ip0->protocol << 16))); + hpg_server = hicnpg_server_from_fib_node (node); - /* Invalidate possibly old checksum. */ - tcp0->checksum = 0; - - u32 tcp_offset = sizeof (ip6_header_t); - sum0 = ip_incremental_checksum_buffer (vm, b0, tcp_offset, tcp_len0, sum0); + /** + * reset the stacked DPO to unlock it + */ + dpo_reset (&hpg_server->dpo); - tcp0->checksum = ~ip_csum_fold (sum0); + pool_put (hicnpg_server_pool, hpg_server); } -VLIB_REGISTER_NODE (hicn_pg_interest_node) = { - .function = hicnpg_client_interest_node_fn, - .name = "hicnpg-interest", - .vector_size = sizeof (u32), - .format_trace = format_hicnpg_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN (hicnpg_error_strings), - .error_strings = hicnpg_error_strings, - .n_next_nodes = HICNPG_N_NEXT, - .next_nodes = { [HICNPG_INTEREST_NEXT_V4_LOOKUP] = "ip4-lookup", - [HICNPG_INTEREST_NEXT_V6_LOOKUP] = "ip6-lookup", - [HICNPG_INTEREST_NEXT_DROP] = "error-drop" }, -}; - -/* - * Next graph nodes, which reference the list in the actual registration - * block below - */ -typedef enum -{ - HICNPG_DATA_NEXT_DROP, - HICNPG_DATA_NEXT_LOOKUP4, - HICNPG_DATA_NEXT_LOOKUP6, - HICNPG_DATA_N_NEXT, -} hicnpg_data_next_t; - -/* Trace context struct */ -typedef struct -{ - u32 next_index; - u32 sw_if_index; - u8 pkt_type; - u16 msg_type; -} icnpg_data_trace_t; - -/* packet trace format function */ -static u8 * -format_hicnpg_data_trace (u8 *s, va_list *args) +static void +hicnpg_server_dpo_lock (dpo_id_t *dpo) { - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - hicnpg_trace_t *t = va_arg (*args, hicnpg_trace_t *); - - s = format (s, "HICNPG: pkt: %d, msg %d, sw_if_index %d, next index %d", - (int) t->pkt_type, (int) t->msg_type, t->sw_if_index, - t->next_index); - return (s); + hicnpg_server_t *hpg_server; + hpg_server = hicnpg_server_get (dpo->dpoi_index); + fib_node_lock (&hpg_server->fib_node); } -static_always_inline int -match_ip4_name (u32 *name, fib_prefix_t *prefix) +static void +hicnpg_server_dpo_unlock (dpo_id_t *dpo) { - u32 xor = 0; - - xor = *name & prefix->fp_addr.ip4.data_u32; - - return xor == prefix->fp_addr.ip4.data_u32; + hicnpg_server_t *hpg_server; + hpg_server = hicnpg_server_get (dpo->dpoi_index); + fib_node_unlock (&hpg_server->fib_node); } -static_always_inline int -match_ip6_name (u8 *name, fib_prefix_t *prefix) +static u8 * +format_hicnpg_server_i (u8 *s, va_list *args) { - union - { - u32x4 as_u32x4; - u64 as_u64[2]; - u32 as_u32[4]; - } xor_sum __attribute__ ((aligned (sizeof (u32x4)))); + index_t hicnpg_server_i = va_arg (*args, index_t); + // u32 indent = va_arg (*args, u32); + u32 details = va_arg (*args, u32); + // vlib_counter_t to; + hicnpg_server_t *hpg; - xor_sum.as_u64[0] = ((u64 *) name)[0] & prefix->fp_addr.ip6.as_u64[0]; - xor_sum.as_u64[1] = ((u64 *) name)[1] & prefix->fp_addr.ip6.as_u64[1]; + hpg = hicnpg_server_get (hicnpg_server_i); - return (xor_sum.as_u64[0] == prefix->fp_addr.ip6.as_u64[0]) && - (xor_sum.as_u64[1] == prefix->fp_addr.ip6.as_u64[1]); -} - -/* - * Return 0,1,2. - * 0 matches - * 1 does not match and the prefix is ip4 - * 2 does not match and the prefix is ip6 - */ -static_always_inline u32 -match_data (vlib_buffer_t *b, fib_prefix_t *prefix) -{ - u8 *ptr = vlib_buffer_get_current (b); - u8 v = *ptr & 0xf0; - u32 next = 0; + // FIXME + s = format (s, "dpo-hicnpg-server:[%d]: ip-fib-index:%d ", hicnpg_server_i, + hpg->fib_index); - if (PREDICT_TRUE (v == 0x40 && ip46_address_is_ip4 (&prefix->fp_addr))) + if (FIB_PROTOCOL_IP4 == hpg->prefix.fp_proto) { - if (!match_ip4_name ((u32 *) &(ptr[12]), prefix)) - next = 1; + s = format (s, "protocol:FIB_PROTOCOL_IP4 prefix: %U", + format_fib_prefix, &hpg->prefix); } - else if (PREDICT_TRUE (v == 0x60 && !ip46_address_is_ip4 (&prefix->fp_addr))) + else { - if (!match_ip6_name (&(ptr[8]), prefix)) - next = 2; + s = format (s, "protocol:FIB_PROTOCOL_IP6 prefix: %U", + format_fib_prefix, &hpg->prefix); } - return next; -} - -/* - * Return 0,1,2. - * 0 matches - * 1 does not match and the prefix is ip4 - * 2 does not match and the prefix is ip6 - */ -static_always_inline u32 -match_interest (vlib_buffer_t *b, fib_prefix_t *prefix) -{ - u8 *ptr = vlib_buffer_get_current (b); - u8 v = *ptr & 0xf0; - u32 next = 0; +#if 0 + vlib_get_combined_counter (&(udp_encap_counters), uei, &to); + s = format (s, " to:[%Ld:%Ld]]", to.packets, to.bytes);s +#endif - if (PREDICT_TRUE (v == 0x40 && ip46_address_is_ip4 (&prefix->fp_addr))) - { - if (!match_ip4_name ((u32 *) &(ptr[16]), prefix)) - next = 1; - } - else if (PREDICT_TRUE (v == 0x60 && !ip46_address_is_ip4 (&prefix->fp_addr))) + if (details) { - if (!match_ip6_name (&(ptr[24]), prefix)) - next = 2; + s = format (s, " locks:%d", hpg->fib_node.fn_locks); + // s = format (s, "\n%UStacked on:", format_white_space, indent + + // 1); s = format (s, "\n%U%U", format_white_space, indent + 2, + // format_dpo_id, + // &hpg->dpo, indent + 3); } - return next; + return s; } -/* - * Node function for the icn packet-generator client. The goal here is to - * manipulate/tweak a stream of packets that have been injected by the vpp - * packet generator to generate icn request traffic. - */ -static uword -hicnpg_client_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, - vlib_frame_t *frame) +static u8 * +format_hicnpg_server_dpo (u8 *s, va_list *args) { - u32 n_left_from, *from, *to_next; - hicnpg_data_next_t next_index; - u32 pkts_processed = 0; - u32 content_msgs_received = 0; - u32 bi0, bi1; - vlib_buffer_t *b0, *b1; - u8 pkt_type0 = 0, pkt_type1 = 0; - u16 msg_type0 = 1, msg_type1 = 1; - hicnpg_main_t *hpgm = &hicnpg_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 next0 = HICNPG_DATA_NEXT_DROP; - u32 next1 = HICNPG_DATA_NEXT_DROP; - u32 sw_if_index0, sw_if_index1; - - /* Prefetch next iteration. */ - { - vlib_buffer_t *p2, *p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, (2 * CLIB_CACHE_LINE_BYTES), STORE); - CLIB_PREFETCH (p3->data, (2 * CLIB_CACHE_LINE_BYTES), STORE); - } - - /* - * speculatively enqueue b0 and b1 to the current - * next frame - */ - to_next[0] = bi0 = from[0]; - to_next[1] = bi1 = from[1]; - from += 2; - to_next += 2; - n_left_from -= 2; - n_left_to_next -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; - - next0 = - HICNPG_DATA_NEXT_DROP + match_data (b0, hpgm->pgen_clt_hicn_name); - next1 = - HICNPG_DATA_NEXT_DROP + match_data (b1, hpgm->pgen_clt_hicn_name); - - if (PREDICT_FALSE (vnet_get_feature_count ( - vnet_buffer (b0)->feature_arc_index, - vnet_buffer (b0)->sw_if_index[VLIB_RX]) > 1)) - vnet_feature_next (&next0, b0); - - if (PREDICT_FALSE (vnet_get_feature_count ( - vnet_buffer (b1)->feature_arc_index, - vnet_buffer (b1)->sw_if_index[VLIB_RX]) > 1)) - vnet_feature_next (&next1, b1); - - if (next0 == HICNPG_DATA_NEXT_DROP) - { - /* Increment a counter */ - content_msgs_received++; - } - - if (next1 == HICNPG_DATA_NEXT_DROP) - { - /* Increment a counter */ - content_msgs_received++; - } - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) - { - if (b0->flags & VLIB_BUFFER_IS_TRACED) - { - icnpg_data_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->pkt_type = pkt_type0; - t->msg_type = msg_type0; - t->sw_if_index = sw_if_index0; - t->next_index = next0; - } - if (b1->flags & VLIB_BUFFER_IS_TRACED) - { - icnpg_data_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->pkt_type = pkt_type1; - t->msg_type = msg_type1; - t->sw_if_index = sw_if_index1; - t->next_index = next1; - } - } - - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, - n_left_to_next, bi0, bi1, next0, - next1); - pkts_processed += 2; - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 next0 = HICNPG_DATA_NEXT_DROP; - u32 sw_if_index0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - - next0 = - HICNPG_DATA_NEXT_DROP + match_data (b0, hpgm->pgen_clt_hicn_name); - - if (PREDICT_FALSE (vnet_get_feature_count ( - vnet_buffer (b0)->feature_arc_index, - vnet_buffer (b0)->sw_if_index[VLIB_RX]) > 1)) - vnet_feature_next (&next0, b0); + index_t hpg_server_i = va_arg (*args, index_t); + u32 indent = va_arg (*args, u32); - if (next0 == HICNPG_DATA_NEXT_DROP) - { - /* Increment a counter */ - content_msgs_received++; - } - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && - (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - icnpg_data_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->pkt_type = pkt_type0; - t->msg_type = msg_type0; - t->sw_if_index = sw_if_index0; - t->next_index = next0; - } - - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - - pkts_processed++; - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - vlib_node_increment_counter (vm, hicn_pg_data_node.index, - HICNPG_ERROR_PROCESSED, pkts_processed); - vlib_node_increment_counter (vm, hicn_pg_data_node.index, - HICNPG_ERROR_CONTENT_MSGS_RECEIVED, - content_msgs_received); - return (frame->n_vectors); + return (format (s, "%U", format_hicnpg_server_i, hpg_server_i, indent, 1)); } -VLIB_REGISTER_NODE(hicn_pg_data_node) = -{ - .function = hicnpg_client_data_node_fn, - .name = "hicnpg-data", - .vector_size = sizeof(u32), - .format_trace = format_hicnpg_data_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(hicnpg_error_strings), - .error_strings = hicnpg_error_strings, - .n_next_nodes = HICNPG_DATA_N_NEXT, - .next_nodes = - { - [HICNPG_DATA_NEXT_DROP] = "error-drop", - [HICNPG_DATA_NEXT_LOOKUP4] = "ip4-lookup", - [HICNPG_DATA_NEXT_LOOKUP6] = "ip6-lookup", - }, +/* + * Virtual function table registered by hicn pg server + * for participation in the FIB object graph. + */ +const static fib_node_vft_t hicnpg_server_fib_vft = { + .fnv_get = hicnpg_server_fib_node_get, + .fnv_last_lock = hicnpg_server_fib_last_lock_gone, + .fnv_back_walk = hicnpg_server_fib_back_walk, }; -VNET_FEATURE_INIT (hicn_data_input_ip4_arc, static) = { - .arc_name = "ip4-unicast", - .node_name = "hicnpg-data", - .runs_before = VNET_FEATURES ("ip4-inacl"), +const static dpo_vft_t hicnpg_server_dpo_vft = { + .dv_lock = hicnpg_server_dpo_lock, + .dv_unlock = hicnpg_server_dpo_unlock, + .dv_format = format_hicnpg_server_dpo, }; -VNET_FEATURE_INIT (hicn_data_input_ip6_arc, static) = { - .arc_name = "ip6-unicast", - .node_name = "hicnpg-data", - .runs_before = VNET_FEATURES ("ip6-inacl"), +const static char *const hicnpg_server_ip4_nodes[] = { + "hicnpg-server-4", + NULL, }; -/* - * End of packet-generator client node - */ - -/* - * Beginning of packet-generation server node - */ - -/* Registration struct for a graph node */ -vlib_node_registration_t hicn_pg_server_node; - -/* Stats, which end up called "error" even though they aren't... */ -#define foreach_icnpg_server_error \ - _ (PROCESSED, "hICN PG Server packets processed") \ - _ (DROPPED, "hICN PG Server packets dropped") - -typedef enum -{ -#define _(sym, str) HICNPG_SERVER_ERROR_##sym, - foreach_icnpg_server_error -#undef _ - HICNPG_SERVER_N_ERROR, -} icnpg_server_error_t; - -static char *icnpg_server_error_strings[] = { -#define _(sym, string) string, - foreach_icnpg_server_error -#undef _ +const static char *const hicnpg_server_ip6_nodes[] = { + "hicnpg-server-6", + NULL, }; -/* - * Next graph nodes, which reference the list in the actual registration - * block below - */ -typedef enum -{ - HICNPG_SERVER_NEXT_V4_LOOKUP, - HICNPG_SERVER_NEXT_V6_LOOKUP, - HICNPG_SERVER_NEXT_DROP, - HICNPG_SERVER_N_NEXT, -} icnpg_server_next_t; - -/* Trace context struct */ -typedef struct -{ - u32 next_index; - u32 sw_if_index; - u8 pkt_type; - u16 msg_type; -} hicnpg_server_trace_t; +const static char *const *const hicnpg_server_nodes[DPO_PROTO_NUM] = { + [DPO_PROTO_IP4] = hicnpg_server_ip4_nodes, + [DPO_PROTO_IP6] = hicnpg_server_ip6_nodes +}; -/* packet trace format function */ -static u8 * -format_icnpg_server_trace (u8 *s, va_list *args) +clib_error_t * +hicnpg_server_add_and_lock (fib_prefix_t *prefix, u32 *hicnpg_server_index, + ip46_address_t *locator, size_t payload_size) { - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - hicnpg_server_trace_t *t = va_arg (*args, hicnpg_server_trace_t *); + hicnpg_server_t *hpg; + index_t hpgi; + u32 fib_index; + fib_node_index_t fib_entry_index; + u32 buffer_index; + vlib_buffer_t *rb = NULL; - s = format ( - s, "HICNPG SERVER: pkt: %d, msg %d, sw_if_index %d, next index %d", - (int) t->pkt_type, (int) t->msg_type, t->sw_if_index, t->next_index); - return (s); -} + // Retrieve hicn fib table + fib_index = + fib_table_find_or_create_and_lock (prefix->fp_proto, 0, hicn_fib_src); -/* - * Node function for the icn packet-generator server. - */ -static uword -hicnpg_node_server_fn (vlib_main_t *vm, vlib_node_runtime_t *node, - vlib_frame_t *frame) -{ - u32 n_left_from, *from, *to_next; - icnpg_server_next_t next_index; - u32 pkts_processed = 0, pkts_dropped = 0; - u32 bi0, bi1; - vlib_buffer_t *b0, *b1; - u8 pkt_type0 = 0, pkt_type1 = 0; - u16 msg_type0 = 0, msg_type1 = 0; - hicn_header_t *hicn0 = NULL, *hicn1 = NULL; - hicn_name_t name0, name1; - u16 namelen0, namelen1; + // Check the prefix we are adding is not already in the table + fib_entry_index = fib_table_lookup_exact_match (fib_index, prefix); - hicnpg_server_main_t *hpgsm = &hicnpg_server_main; - - from = vlib_frame_vector_args (frame); - - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) + if (fib_entry_index != FIB_NODE_INDEX_INVALID) { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 next0 = HICNPG_SERVER_NEXT_DROP; - u32 next1 = HICNPG_SERVER_NEXT_DROP; - u8 isv6_0 = 0; - u8 isv6_1 = 0; - u32 sw_if_index0, sw_if_index1; - - /* Prefetch next iteration. */ - { - vlib_buffer_t *p2, *p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, (2 * CLIB_CACHE_LINE_BYTES), STORE); - CLIB_PREFETCH (p3->data, (2 * CLIB_CACHE_LINE_BYTES), STORE); - } - - /* - * speculatively enqueue b0 and b1 to the current - * next frame - */ - to_next[0] = bi0 = from[0]; - to_next[1] = bi1 = from[1]; - from += 2; - to_next += 2; - n_left_from -= 2; - n_left_to_next -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; - - vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0; - vnet_buffer (b1)->sw_if_index[VLIB_TX] = ~0; - - u32 match0 = match_interest (b0, hpgsm->pgen_srv_hicn_name); - u32 match1 = match_interest (b1, hpgsm->pgen_srv_hicn_name); - - if (match0) - { - next0 = match0 - 1; - } - else if (hicn_interest_parse_pkt (b0, &name0, &namelen0, &hicn0, - &isv6_0) == HICN_ERROR_NONE) - { - /* this node grabs only interests */ - vlib_buffer_t *rb = NULL; - rb = vlib_get_buffer (vm, hpgsm->pgen_svr_buffer_idx); - - isv6_0 ? convert_interest_to_data_v6 (vm, b0, rb, bi0) : - convert_interest_to_data_v4 (vm, b0, rb, bi0); - - next0 = isv6_0 ? HICNPG_SERVER_NEXT_V6_LOOKUP : - HICNPG_SERVER_NEXT_V4_LOOKUP; - } - - if (match1) - { - next1 = match1 - 1; - } - else if (hicn_interest_parse_pkt (b1, &name1, &namelen1, &hicn1, - &isv6_1) == HICN_ERROR_NONE) - { - /* this node grabs only interests */ - vlib_buffer_t *rb = NULL; - rb = vlib_get_buffer (vm, hpgsm->pgen_svr_buffer_idx); - - isv6_1 ? convert_interest_to_data_v6 (vm, b1, rb, bi1) : - convert_interest_to_data_v4 (vm, b1, rb, bi1); - - next1 = isv6_1 ? HICNPG_SERVER_NEXT_V6_LOOKUP : - HICNPG_SERVER_NEXT_V4_LOOKUP; - } - pkts_processed += 2; - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) - { - if (b0->flags & VLIB_BUFFER_IS_TRACED) - { - hicnpg_server_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->pkt_type = pkt_type0; - t->msg_type = msg_type0; - t->sw_if_index = sw_if_index0; - t->next_index = next0; - } - if (b1->flags & VLIB_BUFFER_IS_TRACED) - { - hicnpg_server_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->pkt_type = pkt_type1; - t->msg_type = msg_type1; - t->sw_if_index = sw_if_index1; - t->next_index = next1; - } - } - if (next0 == HICNPG_SERVER_NEXT_DROP) - { - pkts_dropped++; - } - if (next1 == HICNPG_SERVER_NEXT_DROP) - { - pkts_dropped++; - } - /* - * verify speculative enqueues, maybe switch current - * next frame - */ - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, - n_left_to_next, bi0, bi1, next0, - next1); - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 next0 = HICNPG_SERVER_NEXT_DROP; - u32 sw_if_index0 = ~0; - u8 isv6_0 = 0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0; - - u32 match0 = match_interest (b0, hpgsm->pgen_srv_hicn_name); - - if (match0) - { - next0 = match0 - 1; - } - else if (hicn_interest_parse_pkt (b0, &name0, &namelen0, &hicn0, - &isv6_0) == HICN_ERROR_NONE) - { - /* this node grabs only interests */ - vlib_buffer_t *rb = NULL; - rb = vlib_get_buffer (vm, hpgsm->pgen_svr_buffer_idx); - - isv6_0 ? convert_interest_to_data_v6 (vm, b0, rb, bi0) : - convert_interest_to_data_v4 (vm, b0, rb, bi0); - - next0 = isv6_0 ? HICNPG_SERVER_NEXT_V6_LOOKUP : - HICNPG_SERVER_NEXT_V4_LOOKUP; - } - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && - (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - hicnpg_server_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->pkt_type = pkt_type0; - t->msg_type = msg_type0; - t->sw_if_index = sw_if_index0; - t->next_index = next0; - } - pkts_processed += 1; - - if (next0 == HICNPG_SERVER_NEXT_DROP) - { - pkts_dropped++; - } - /* - * verify speculative enqueue, maybe switch current - * next frame - */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); + // Route already existing. + return clib_error_return (0, "Route exist already."); } - vlib_node_increment_counter (vm, hicn_pg_server_node.index, - HICNPG_SERVER_ERROR_PROCESSED, pkts_processed); - vlib_node_increment_counter (vm, hicn_pg_server_node.index, - HICNPG_SERVER_ERROR_DROPPED, pkts_dropped); - - return (frame->n_vectors); -} - -void -convert_interest_to_data_v4 (vlib_main_t *vm, vlib_buffer_t *b0, - vlib_buffer_t *rb, u32 bi0) -{ - hicn_header_t *h0 = vlib_buffer_get_current (b0); - - /* Get the packet length */ - u16 pkt_len = clib_net_to_host_u16 (h0->v4.ip.len); + // Allocate packet buffer + int n_buf = vlib_buffer_alloc (vlib_get_main (), &buffer_index, 1); - /* - * Rule of thumb: We want the size of the IP packet to be <= 1500 bytes - */ - u16 bytes_to_copy = rb->current_length; - if ((bytes_to_copy + pkt_len) > 1500) + if (n_buf == 0) { - bytes_to_copy = 1500 - pkt_len; + return clib_error_return (0, "Impossible to allocate paylod buffer."); } - /* Add content to the data packet */ - vlib_buffer_add_data (vm, &bi0, rb->data, bytes_to_copy); - b0 = vlib_get_buffer (vm, bi0); - - h0 = vlib_buffer_get_current (b0); - - ip4_address_t src_addr = h0->v4.ip.saddr; - h0->v4.ip.saddr = h0->v4.ip.daddr; - h0->v4.ip.daddr = src_addr; - - h0->v4.ip.len = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)); - h0->v4.ip.csum = ip4_header_checksum ((ip4_header_t *) &(h0->v4.ip)); - calculate_tcp_checksum_v4 (vm, b0); + // Initialize the buffer data with zeros + rb = vlib_get_buffer (vlib_get_main (), buffer_index); + memset (rb->data, 0, payload_size); + rb->current_length = payload_size; + + // We can proceed. Get a new hicnpg_server_t + pool_get_aligned_zero (hicnpg_server_pool, hpg, 2 * CLIB_CACHE_LINE_BYTES); + hpgi = hpg - hicnpg_server_pool; + + // Set DPO + dpo_set ( + &hpg->dpo, hicnpg_server_dpo_type, + (ip46_address_is_ip4 (&prefix->fp_addr) ? DPO_PROTO_IP4 : DPO_PROTO_IP6), + hpgi); + + // Add the route via the hicnpg_server_dpo_type. In this way packets will + // endup in the hicnpg_server node + CLIB_UNUSED (fib_node_index_t new_fib_node_index) = + fib_table_entry_special_dpo_add ( + fib_index, prefix, hicn_fib_src, + (FIB_ENTRY_FLAG_EXCLUSIVE | FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT), + &hpg->dpo); + +#if 0 + vlib_validate_combined_counter (&(udp_encap_counters), uei); + vlib_zero_combined_counter (&(udp_encap_counters), uei); +#endif + + // Init remaining struct fields + fib_node_init (&hpg->fib_node, hicnpg_server_fib_node_type); + fib_node_lock (&hpg->fib_node); + hpg->fib_index = fib_index; + hpg->prefix = *prefix; + hpg->buffer_index = buffer_index; + hpg->fib_entry_index = fib_entry_index; + hpg->hicn_locator = *locator; + + // track the destination address + // hpg->fib_entry_index = + // fib_entry_track (fib_index, &hpg->prefix, + // hicnpg_server_fib_node_type, hpgi, &hpg->fib_sibling); + // hicnpg_server_restack (hpg); + + HICN_DEBUG ("Calling hicn enable for pg-server face"); + + hicn_face_id_t *vec_faces = NULL; + hicn_route_enable (prefix, &vec_faces); + if (vec_faces != NULL) + vec_free (vec_faces); + + // Return the index of the hicnpg_server_t + *hicnpg_server_index = hpgi; + + return NULL; } -void -convert_interest_to_data_v6 (vlib_main_t *vm, vlib_buffer_t *b0, - vlib_buffer_t *rb, u32 bi0) +clib_error_t * +hicn_pg_init (vlib_main_t *vm) { - hicn_header_t *h0 = vlib_buffer_get_current (b0); - - /* Get the packet length */ - uint16_t pkt_len = - clib_net_to_host_u16 (h0->v6.ip.len) + sizeof (ip6_header_t); + hicnpg_server_fib_node_type = fib_node_register_new_type ( + "hicnpg_server_fib_node", &hicnpg_server_fib_vft); - /* - * Figure out how many bytes we can add to the content - * - * Rule of thumb: We want the size of the IP packet to be <= 1400 bytes - */ - u16 bytes_to_copy = rb->current_length; - if ((bytes_to_copy + pkt_len) > 1500) - { - bytes_to_copy = 1500 - pkt_len; - } - /* Add content to the data packet */ - vlib_buffer_add_data (vm, &bi0, rb->data, bytes_to_copy); + hicnpg_server_dpo_type = + dpo_register_new_type (&hicnpg_server_dpo_vft, hicnpg_server_nodes); - b0 = vlib_get_buffer (vm, bi0); - - h0 = vlib_buffer_get_current (b0); - ip6_address_t src_addr = h0->v6.ip.saddr; - h0->v6.ip.saddr = h0->v6.ip.daddr; - h0->v6.ip.daddr = src_addr; - - h0->v6.ip.len = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) - - sizeof (ip6_header_t)); - h0->v6.tcp.data_offset_and_reserved |= 0x0f; - h0->v6.tcp.urg_ptr = htons (0xffff); - - calculate_tcp_checksum_v6 (vm, b0); + return NULL; } -VLIB_REGISTER_NODE(hicn_pg_server_node) = -{ - .function = hicnpg_node_server_fn, - .name = "hicnpg-server", - .vector_size = sizeof(u32), - .format_trace = format_icnpg_server_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(icnpg_server_error_strings), - .error_strings = icnpg_server_error_strings, - .n_next_nodes = HICNPG_SERVER_N_NEXT, - /* edit / add dispositions here */ - .next_nodes = - { - [HICNPG_SERVER_NEXT_V4_LOOKUP] = "ip4-lookup", - [HICNPG_SERVER_NEXT_V6_LOOKUP] = "ip6-lookup", - [HICNPG_SERVER_NEXT_DROP] = "error-drop", - }, -}; - -VNET_FEATURE_INIT (hicn_pg_server_ip6, static) = { - .arc_name = "ip6-unicast", - .node_name = "hicnpg-server", - .runs_before = VNET_FEATURES ("ip6-inacl"), -}; - -VNET_FEATURE_INIT (hicn_pg_server_ip4, static) = { - .arc_name = "ip4-unicast", - .node_name = "hicnpg-server", - .runs_before = VNET_FEATURES ("ip4-inacl"), -}; - -/* - * End of packet-generator server node - */ - /* * fd.io coding-style-patch-verification: ON * * Local Variables: eval: (c-set-style "gnu") End: - */ + */
\ No newline at end of file diff --git a/hicn-plugin/src/pg.h b/hicn-plugin/src/pg.h index 7855248e6..deb585714 100644 --- a/hicn-plugin/src/pg.h +++ b/hicn-plugin/src/pg.h @@ -16,6 +16,8 @@ #ifndef __HICN_PG_H__ #define __HICN_PG_H__ +#include <vppinfra/pool.h> + /** * @file pg.h * @@ -57,23 +59,58 @@ */ typedef struct hicnpg_main_s { - u32 index; // used to compute the sequence number - fib_prefix_t *pgen_clt_hicn_name; // hICN name to put in the destiantion - // addess of an interest - u32 - index_ifaces; /* used to mimic interests coming from different consumer */ - u32 n_ifaces; /* The source address will change from interest to interest */ - /* index_ifaces is used to keep a global reference to the iface used */ - /* and it is incremented when we want to change "consumer" */ - /* n_ifaces identifies how many consumers to simulate */ - u32 max_seq_number; // Use to limit the max sequence number - u32 n_flows; // Use to simulate multiple flows (a flow always have the same - // hICN name) - ip46_address_t pgen_clt_src_addr; // Source addess base to use in the - // interest - - u16 interest_lifetime; // Interest lifetime - u32 sw_if; // Interface where to send interest and receives data + /* + * used to compute the sequence number + */ + u32 index; + + /* + * hICN name to put in the destination addess of an interest + */ + fib_prefix_t *pgen_clt_hicn_name; + + /* + * Used to mimic interests coming from different consumer. The source address + * will change from interest to interest index_ifaces is used to keep a + * global reference to the iface used and it is incremented when we want to + * change "consumer" + */ + u32 index_ifaces; + + /* + * n_ifaces identifies how many consumers to simulate + */ + u32 n_ifaces; + + /* + * Use to limit the max sequence number + */ + u32 max_seq_number; + + /* + * Use to simulate multiple flows (a flow always have the same hICN name) + */ + u32 n_flows; + + /* + * Source addess base to use in the interest + */ + ip46_address_t pgen_clt_src_addr; + + /* + * Interest lifetime + */ + u16 interest_lifetime; + + /* + * Interface where to send interest and receives data. + */ + u32 sw_if; + + /* + * Fib node type + */ + fib_node_type_t hicn_fib_node_type; } hicnpg_main_t; extern hicnpg_main_t hicnpg_main; @@ -83,18 +120,75 @@ extern hicnpg_main_t hicnpg_main; * * It stores the configuration and make it availables to the pg server node. */ -typedef struct hicnpg_server_main_s +typedef struct hicnpg_server_s { - u32 node_index; - /* Arbitrary content */ - u32 pgen_svr_buffer_idx; - fib_prefix_t *pgen_srv_hicn_name; -} hicnpg_server_main_t; + /* + * Prefix served by this packet generator server + */ + fib_prefix_t prefix; + + /* + * IP address to put in the destination addess of the data + */ + ip46_address_t hicn_locator; + + /* + * Buffer index + */ + u32 buffer_index; + + /** + * The DPO used to forward to the next node in the VLIB graph + */ + dpo_id_t dpo; -extern hicnpg_server_main_t hicnpg_server_main; + /* + * linkage into the FIB graph + */ + fib_node_t fib_node; + /* + * Tracking information for the IP destination + */ + fib_node_index_t fib_entry_index; + + /* + * The FIB index + */ + index_t fib_index; +} hicnpg_server_t; + +STATIC_ASSERT (sizeof (hicnpg_server_t) <= 2 * CLIB_CACHE_LINE_BYTES, + "hicnpg_server_t is too large"); + +extern hicnpg_server_t hicnpg_server_main; extern vlib_node_registration_t hicn_pg_interest_node; extern vlib_node_registration_t hicn_pg_data_node; +extern dpo_type_t hicnpg_server_dpo_type; + +/** + * Pool of hicnpg_servers + */ +extern hicnpg_server_t *hicnpg_server_pool; + +always_inline hicnpg_server_t * +hicnpg_server_get (index_t hpgi) +{ + return pool_elt_at_index (hicnpg_server_pool, hpgi); +} + +always_inline u8 +dpo_is_pgserver (const dpo_id_t *dpo) +{ + return (dpo->dpoi_type == hicnpg_server_dpo_type); +} + +clib_error_t *hicnpg_server_add_and_lock (fib_prefix_t *prefix, + u32 *hicnpg_server_index, + ip46_address_t *locator, + size_t payload_size); + +clib_error_t *hicn_pg_init (vlib_main_t *vm); #endif // __HICN_PG_H__ diff --git a/hicn-plugin/src/pg_node.c b/hicn-plugin/src/pg_node.c new file mode 100644 index 000000000..3672a6b72 --- /dev/null +++ b/hicn-plugin/src/pg_node.c @@ -0,0 +1,1132 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <vlib/vlib.h> +#include <vnet/vnet.h> +#include <vnet/pg/pg.h> +#include <vnet/ip/ip.h> +#include <vnet/ethernet/ethernet.h> + +#include "hicn.h" +#include "pg.h" +#include "parser.h" +#include "infra.h" + +/* Registration struct for a graph node */ +vlib_node_registration_t hicn_pg_interest_node; +vlib_node_registration_t hicn_pg_data_node; + +/* Stats, which end up called "error" even though they aren't... */ +#define foreach_hicnpg_error \ + _ (PROCESSED, "hICN PG packets processed") \ + _ (DROPPED, "hICN PG packets dropped") \ + _ (INTEREST_MSGS_GENERATED, "hICN PG Interests generated") \ + _ (CONTENT_MSGS_RECEIVED, "hICN PG Content msgs received") + +typedef enum +{ +#define _(sym, str) HICNPG_ERROR_##sym, + foreach_hicnpg_error +#undef _ + HICNPG_N_ERROR, +} hicnpg_error_t; + +static char *hicnpg_error_strings[] = { +#define _(sym, string) string, + foreach_hicnpg_error +#undef _ +}; + +/* + * Next graph nodes, which reference the list in the actual registration + * block below + */ +typedef enum +{ + HICNPG_INTEREST_NEXT_V4_LOOKUP, + HICNPG_INTEREST_NEXT_V6_LOOKUP, + HICNPG_INTEREST_NEXT_DROP, + HICNPG_N_NEXT, +} hicnpg_interest_next_t; + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; + u16 msg_type; +} hicnpg_trace_t; + +/* packet trace format function */ +static u8 * +format_hicnpg_trace (u8 *s, va_list *args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + hicnpg_trace_t *t = va_arg (*args, hicnpg_trace_t *); + + s = format (s, "HICNPG: pkt: %d, msg %d, sw_if_index %d, next index %d", + (int) t->pkt_type, (int) t->msg_type, t->sw_if_index, + t->next_index); + return (s); +} + +always_inline void hicn_rewrite_interestv4 (vlib_main_t *vm, vlib_buffer_t *b0, + u32 seq_number, u16 lifetime, + u32 next_flow, u32 iface); + +always_inline void hicn_rewrite_interestv6 (vlib_main_t *vm, vlib_buffer_t *b0, + u32 seq_number, u16 lifetime, + u32 next_flow, u32 iface); + +always_inline void convert_interest_to_data_v4 (vlib_main_t *vm, + vlib_buffer_t *b0, + vlib_buffer_t *rb, u32 bi0); + +always_inline void convert_interest_to_data_v6 (vlib_main_t *vm, + vlib_buffer_t *b0, + vlib_buffer_t *rb, u32 bi0); + +always_inline void calculate_tcp_checksum_v4 (vlib_main_t *vm, + vlib_buffer_t *b0); + +always_inline void calculate_tcp_checksum_v6 (vlib_main_t *vm, + vlib_buffer_t *b0); +/* + * Node function for the icn packet-generator client. The goal here is to + * manipulate/tweak a stream of packets that have been injected by the vpp + * packet generator to generate icn request traffic. + */ +static uword +hicnpg_client_interest_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame) +{ + u32 n_left_from, *from, *to_next; + hicnpg_interest_next_t next_index; + u32 pkts_processed = 0, pkts_dropped = 0; + u32 interest_msgs_generated = 0; + u32 bi0, bi1; + vlib_buffer_t *b0, *b1; + u8 pkt_type0 = 0, pkt_type1 = 0; + u16 msg_type0 = 0, msg_type1 = 0; + hicnpg_main_t *hpgm = &hicnpg_main; + int iface = 0; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 next0 = HICNPG_INTEREST_NEXT_DROP; + u32 next1 = HICNPG_INTEREST_NEXT_DROP; + u32 sw_if_index0 = ~0, sw_if_index1 = ~0; + u8 isv6_0; + u8 isv6_1; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p2, *p3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + + CLIB_PREFETCH (p2->data, (2 * CLIB_CACHE_LINE_BYTES), STORE); + CLIB_PREFETCH (p3->data, (2 * CLIB_CACHE_LINE_BYTES), STORE); + } + + /* + * speculatively enqueue b0 and b1 to the current + * next frame + */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + hicn_buffer_set_flags (b0, HICN_BUFFER_FLAGS_FROM_PG); + hicn_buffer_set_flags (b1, HICN_BUFFER_FLAGS_FROM_PG); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + vnet_buffer (b0)->sw_if_index[VLIB_RX] = hpgm->sw_if; + vnet_buffer (b1)->sw_if_index[VLIB_RX] = hpgm->sw_if; + + /* Check icn packets, locate names */ + if (hicn_interest_parse_pkt (b0) == HICN_ERROR_NONE) + { + /* this node grabs only interests */ + isv6_0 = hicn_buffer_is_v6 (b0); + + /* Increment the appropriate message counter */ + interest_msgs_generated++; + + iface = (hpgm->index_ifaces % hpgm->n_ifaces); + /* Rewrite and send */ + isv6_0 ? + hicn_rewrite_interestv6 ( + vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number, + hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, + iface) : + hicn_rewrite_interestv4 ( + vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number, + hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, iface); + + hpgm->index_ifaces++; + if (iface == (hpgm->n_ifaces - 1)) + hpgm->index++; + + next0 = isv6_0 ? HICNPG_INTEREST_NEXT_V6_LOOKUP : + HICNPG_INTEREST_NEXT_V4_LOOKUP; + } + if (hicn_interest_parse_pkt (b1) == HICN_ERROR_NONE) + { + /* this node grabs only interests */ + isv6_1 = hicn_buffer_is_v6 (b1); + + /* Increment the appropriate message counter */ + interest_msgs_generated++; + + iface = (hpgm->index_ifaces % hpgm->n_ifaces); + /* Rewrite and send */ + isv6_1 ? + hicn_rewrite_interestv6 ( + vm, b1, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number, + hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, + iface) : + hicn_rewrite_interestv4 ( + vm, b1, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number, + hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, iface); + + hpgm->index_ifaces++; + if (iface == (hpgm->n_ifaces - 1)) + hpgm->index++; + + next1 = isv6_1 ? HICNPG_INTEREST_NEXT_V6_LOOKUP : + HICNPG_INTEREST_NEXT_V4_LOOKUP; + } + /* Send pkt to next node */ + vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0; + vnet_buffer (b1)->sw_if_index[VLIB_TX] = ~0; + + pkts_processed += 2; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + hicnpg_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->pkt_type = pkt_type0; + t->msg_type = msg_type0; + t->sw_if_index = sw_if_index0; + t->next_index = next0; + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + hicnpg_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->pkt_type = pkt_type1; + t->msg_type = msg_type1; + t->sw_if_index = sw_if_index1; + t->next_index = next1; + } + } + if (next0 == HICNPG_INTEREST_NEXT_DROP) + { + pkts_dropped++; + } + if (next1 == HICNPG_INTEREST_NEXT_DROP) + { + pkts_dropped++; + } + /* + * verify speculative enqueues, maybe switch current + * next frame + */ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, + n_left_to_next, bi0, bi1, next0, + next1); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 next0 = HICNPG_INTEREST_NEXT_DROP; + u32 sw_if_index0; + u8 isv6_0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + hicn_buffer_set_flags (b0, HICN_BUFFER_FLAGS_FROM_PG); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + vnet_buffer (b0)->sw_if_index[VLIB_RX] = hpgm->sw_if; + + /* Check icn packets, locate names */ + if (hicn_interest_parse_pkt (b0) == HICN_ERROR_NONE) + { + /* this node grabs only interests */ + isv6_0 = hicn_buffer_is_v6 (b0); + + /* Increment the appropriate message counter */ + interest_msgs_generated++; + + iface = (hpgm->index_ifaces % hpgm->n_ifaces); + + /* Rewrite and send */ + isv6_0 ? + hicn_rewrite_interestv6 ( + vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number, + hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, + iface) : + hicn_rewrite_interestv4 ( + vm, b0, (hpgm->index / hpgm->n_flows) % hpgm->max_seq_number, + hpgm->interest_lifetime, hpgm->index % hpgm->n_flows, iface); + + hpgm->index_ifaces++; + if (iface == (hpgm->n_ifaces - 1)) + hpgm->index++; + + next0 = isv6_0 ? HICNPG_INTEREST_NEXT_V6_LOOKUP : + HICNPG_INTEREST_NEXT_V4_LOOKUP; + } + /* Send pkt to ip lookup */ + vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && + (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + hicnpg_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->pkt_type = pkt_type0; + t->msg_type = msg_type0; + t->sw_if_index = sw_if_index0; + t->next_index = next0; + } + pkts_processed += 1; + + if (next0 == HICNPG_INTEREST_NEXT_DROP) + { + pkts_dropped++; + } + /* + * verify speculative enqueue, maybe switch current + * next frame + */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, hicn_pg_interest_node.index, + HICNPG_ERROR_PROCESSED, pkts_processed); + vlib_node_increment_counter (vm, hicn_pg_interest_node.index, + HICNPG_ERROR_DROPPED, pkts_dropped); + vlib_node_increment_counter (vm, hicn_pg_interest_node.index, + HICNPG_ERROR_INTEREST_MSGS_GENERATED, + interest_msgs_generated); + + return (frame->n_vectors); +} + +void +hicn_rewrite_interestv4 (vlib_main_t *vm, vlib_buffer_t *b0, u32 seq_number, + u16 interest_lifetime, u32 next_flow, u32 iface) +{ + hicn_header_t *h0 = vlib_buffer_get_current (b0); + + /* Generate the right src and dst corresponding to flow and iface */ + ip46_address_t src_addr = { + .ip4 = hicnpg_main.pgen_clt_src_addr.ip4, + }; + hicn_name_t dst_name = { + .prefix.ip4 = hicnpg_main.pgen_clt_hicn_name->fp_addr.ip4, + .suffix = seq_number, + }; + + src_addr.ip4.as_u32 += clib_host_to_net_u32 (iface); + dst_name.prefix.ip4.as_u32 += clib_net_to_host_u32 (next_flow); + + /* Update locator and name */ + hicn_type_t type = hicn_get_buffer (b0)->type; + HICN_OPS4->set_interest_locator (type, &h0->protocol, &src_addr); + HICN_OPS4->set_interest_name (type, &h0->protocol, &dst_name); + + /* Update lifetime (currently L4 checksum is not updated) */ + HICN_OPS4->set_lifetime (type, &h0->protocol, interest_lifetime); + + /* Update checksums */ + HICN_OPS4->update_checksums (type, &h0->protocol, 0, 0); +} + +/** + * @brief Rewrite the IPv6 header as the next generated packet + * + * Set up a name prefix + * - etiher generate interest in which the name varies only after the prefix + * (inc : seq_number), then the flow acts on the prefix (CHECK) + * seq_number => TCP, FLOW => + * + * SRC : pgen_clt_src_addr.ip6 DST = generate name (pgen_clt_hicn_name.ip6) + * ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff + * \__/ \__/ + * +iface + flow + * Source is used to emulate different consumers. + * FIXME iface is ill-named, better name it consumer id + * Destination is used to iterate on the content. + */ +void +hicn_rewrite_interestv6 (vlib_main_t *vm, vlib_buffer_t *b0, u32 seq_number, + u16 interest_lifetime, u32 next_flow, u32 iface) +{ + hicn_header_t *h0 = vlib_buffer_get_current (b0); + + /* Generate the right src and dst corresponding to flow and iface */ + ip46_address_t src_addr = { + .ip6 = hicnpg_main.pgen_clt_src_addr.ip6, + }; + hicn_name_t dst_name = { + .prefix.ip6 = hicnpg_main.pgen_clt_hicn_name->fp_addr.ip6, + .suffix = seq_number, + }; + src_addr.ip6.as_u32[3] += clib_host_to_net_u32 (iface); + dst_name.prefix.ip6.as_u32[3] += clib_net_to_host_u32 (next_flow); + + /* Update locator and name */ + hicn_type_t type = hicn_get_buffer (b0)->type; + HICN_OPS6->set_interest_locator (type, &h0->protocol, &src_addr); + HICN_OPS6->set_interest_name (type, &h0->protocol, &dst_name); + + /* Update lifetime */ + HICN_OPS6->set_lifetime (type, &h0->protocol, interest_lifetime); + + /* Update checksums */ + calculate_tcp_checksum_v6 (vm, b0); +} + +void +calculate_tcp_checksum_v4 (vlib_main_t *vm, vlib_buffer_t *b0) +{ + ip4_header_t *ip0; + tcp_header_t *tcp0; + ip_csum_t sum0; + u32 tcp_len0; + + ip0 = (ip4_header_t *) (vlib_buffer_get_current (b0)); + tcp0 = + (tcp_header_t *) (vlib_buffer_get_current (b0) + sizeof (ip4_header_t)); + tcp_len0 = clib_net_to_host_u16 (ip0->length) - sizeof (ip4_header_t); + + /* Initialize checksum with header. */ + if (BITS (sum0) == 32) + { + sum0 = clib_mem_unaligned (&ip0->src_address, u32); + sum0 = + ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->dst_address, u32)); + } + else + sum0 = clib_mem_unaligned (&ip0->src_address, u64); + + sum0 = ip_csum_with_carry ( + sum0, clib_host_to_net_u32 (tcp_len0 + (ip0->protocol << 16))); + + /* Invalidate possibly old checksum. */ + tcp0->checksum = 0; + + u32 tcp_offset = sizeof (ip4_header_t); + sum0 = ip_incremental_checksum_buffer (vm, b0, tcp_offset, tcp_len0, sum0); + + tcp0->checksum = ~ip_csum_fold (sum0); +} + +void +calculate_tcp_checksum_v6 (vlib_main_t *vm, vlib_buffer_t *b0) +{ + ip6_header_t *ip0; + tcp_header_t *tcp0; + ip_csum_t sum0; + u32 tcp_len0; + + ip0 = (ip6_header_t *) (vlib_buffer_get_current (b0)); + tcp0 = + (tcp_header_t *) (vlib_buffer_get_current (b0) + sizeof (ip6_header_t)); + tcp_len0 = clib_net_to_host_u16 (ip0->payload_length); + + /* Initialize checksum with header. */ + if (BITS (sum0) == 32) + { + sum0 = clib_mem_unaligned (&ip0->src_address, u32); + sum0 = + ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->dst_address, u32)); + } + else + sum0 = clib_mem_unaligned (&ip0->src_address, u64); + + sum0 = ip_csum_with_carry ( + sum0, clib_host_to_net_u32 (tcp_len0 + (ip0->protocol << 16))); + + /* Invalidate possibly old checksum. */ + tcp0->checksum = 0; + + u32 tcp_offset = sizeof (ip6_header_t); + sum0 = ip_incremental_checksum_buffer (vm, b0, tcp_offset, tcp_len0, sum0); + + tcp0->checksum = ~ip_csum_fold (sum0); +} + +VLIB_REGISTER_NODE (hicn_pg_interest_node) = { + .function = hicnpg_client_interest_node_fn, + .name = "hicnpg-interest", + .vector_size = sizeof (u32), + .format_trace = format_hicnpg_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (hicnpg_error_strings), + .error_strings = hicnpg_error_strings, + .n_next_nodes = HICNPG_N_NEXT, + .next_nodes = { [HICNPG_INTEREST_NEXT_V4_LOOKUP] = "ip4-lookup", + [HICNPG_INTEREST_NEXT_V6_LOOKUP] = "ip6-lookup", + [HICNPG_INTEREST_NEXT_DROP] = "error-drop" }, +}; + +/* + * Next graph nodes, which reference the list in the actual registration + * block below + */ +typedef enum +{ + HICNPG_DATA_NEXT_DROP, + HICNPG_DATA_NEXT_LOOKUP4, + HICNPG_DATA_NEXT_LOOKUP6, + HICNPG_DATA_N_NEXT, +} hicnpg_data_next_t; + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; + u16 msg_type; +} icnpg_data_trace_t; + +/* packet trace format function */ +static u8 * +format_hicnpg_data_trace (u8 *s, va_list *args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + hicnpg_trace_t *t = va_arg (*args, hicnpg_trace_t *); + + s = format (s, "HICNPG: pkt: %d, msg %d, sw_if_index %d, next index %d", + (int) t->pkt_type, (int) t->msg_type, t->sw_if_index, + t->next_index); + return (s); +} + +/* + * Node function for the icn packet-generator client. The goal here is to + * manipulate/tweak a stream of packets that have been injected by the vpp + * packet generator to generate icn request traffic. + */ +static uword +hicnpg_client_data_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame) +{ + u32 n_left_from, *from, *to_next; + hicnpg_data_next_t next_index; + u32 pkts_processed = 0; + u32 content_msgs_received = 0; + u32 bi0, bi1; + vlib_buffer_t *b0, *b1; + u8 pkt_type0 = 0, pkt_type1 = 0; + u16 msg_type0 = 1, msg_type1 = 1; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 next0 = HICNPG_DATA_NEXT_DROP; + u32 next1 = HICNPG_DATA_NEXT_DROP; + u32 sw_if_index0, sw_if_index1; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p2, *p3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + + CLIB_PREFETCH (p2->data, (2 * CLIB_CACHE_LINE_BYTES), STORE); + CLIB_PREFETCH (p3->data, (2 * CLIB_CACHE_LINE_BYTES), STORE); + } + + /* + * speculatively enqueue b0 and b1 to the current + * next frame + */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + + next0 = HICNPG_DATA_NEXT_DROP; + next1 = HICNPG_DATA_NEXT_DROP; + + // Increment counter + content_msgs_received += 2; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + icnpg_data_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->pkt_type = pkt_type0; + t->msg_type = msg_type0; + t->sw_if_index = sw_if_index0; + t->next_index = next0; + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + icnpg_data_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->pkt_type = pkt_type1; + t->msg_type = msg_type1; + t->sw_if_index = sw_if_index1; + t->next_index = next1; + } + } + + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, + n_left_to_next, bi0, bi1, next0, + next1); + pkts_processed += 2; + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 next0 = HICNPG_DATA_NEXT_DROP; + u32 sw_if_index0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + + next0 = HICNPG_DATA_NEXT_DROP; + + // Increment a counter + content_msgs_received += 1; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && + (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + icnpg_data_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->pkt_type = pkt_type0; + t->msg_type = msg_type0; + t->sw_if_index = sw_if_index0; + t->next_index = next0; + } + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + + pkts_processed++; + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, hicn_pg_data_node.index, + HICNPG_ERROR_PROCESSED, pkts_processed); + vlib_node_increment_counter (vm, hicn_pg_data_node.index, + HICNPG_ERROR_CONTENT_MSGS_RECEIVED, + content_msgs_received); + return (frame->n_vectors); +} + +VLIB_REGISTER_NODE(hicn_pg_data_node) = +{ + .function = hicnpg_client_data_node_fn, + .name = "hicnpg-data", + .vector_size = sizeof(u32), + .format_trace = format_hicnpg_data_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(hicnpg_error_strings), + .error_strings = hicnpg_error_strings, + .n_next_nodes = HICNPG_DATA_N_NEXT, + .next_nodes = + { + [HICNPG_DATA_NEXT_DROP] = "error-drop", + [HICNPG_DATA_NEXT_LOOKUP4] = "ip4-lookup", + [HICNPG_DATA_NEXT_LOOKUP6] = "ip6-lookup", + }, +}; + +VNET_FEATURE_INIT (hicn_data_input_ip4_arc, static) = { + .arc_name = "ip4-unicast", + .node_name = "hicnpg-data", + .runs_before = VNET_FEATURES ("ip4-inacl"), +}; + +VNET_FEATURE_INIT (hicn_data_input_ip6_arc, static) = { + .arc_name = "ip6-unicast", + .node_name = "hicnpg-data", + .runs_before = VNET_FEATURES ("ip6-inacl"), +}; + +/* + * End of packet-generator client node + */ + +/* + * Beginning of packet-generation server node + */ + +/* Registration struct for a graph node */ +vlib_node_registration_t hicn_pg_server_node; + +/* Stats, which end up called "error" even though they aren't... */ +#define foreach_icnpg_server_error \ + _ (PROCESSED, "hICN PG Server packets processed") \ + _ (DROPPED, "hICN PG Server packets dropped") + +typedef enum +{ +#define _(sym, str) HICNPG_SERVER_ERROR_##sym, + foreach_icnpg_server_error +#undef _ + HICNPG_SERVER_N_ERROR, +} icnpg_server_error_t; + +static char *icnpg_server_error_strings[] = { +#define _(sym, string) string, + foreach_icnpg_server_error +#undef _ +}; + +/* + * Next graph nodes, which reference the list in the actual registration + * block below + */ +typedef enum +{ + HICNPG_SERVER_NEXT_V4_LOOKUP, + HICNPG_SERVER_NEXT_V6_LOOKUP, + HICNPG_SERVER_NEXT_DROP, + HICNPG_SERVER_N_NEXT, +} icnpg_server_next_t; + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; + u16 msg_type; +} hicnpg_server_trace_t; + +/* packet trace format function */ +static u8 * +format_icnpg_server_trace (u8 *s, va_list *args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + hicnpg_server_trace_t *t = va_arg (*args, hicnpg_server_trace_t *); + + s = format ( + s, "HICNPG SERVER: pkt: %d, msg %d, sw_if_index %d, next index %d", + (int) t->pkt_type, (int) t->msg_type, t->sw_if_index, t->next_index); + return (s); +} + +/* + * Node function for the icn packet-generator server. + */ +static uword +hicnpg_node_server_fn (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame, int isv6) +{ + u32 n_left_from, *from, *to_next; + icnpg_server_next_t next_index; + u32 pkts_processed = 0, pkts_dropped = 0; + u32 bi0, bi1; + vlib_buffer_t *b0, *b1; + u8 pkt_type0 = 0, pkt_type1 = 0; + u16 msg_type0 = 0, msg_type1 = 0; + + from = vlib_frame_vector_args (frame); + + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 next0 = HICNPG_SERVER_NEXT_DROP; + u32 next1 = HICNPG_SERVER_NEXT_DROP; + u32 sw_if_index0, sw_if_index1; + u32 hpgi0, hpgi1; + hicnpg_server_t *hpg0, *hpg1; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p2, *p3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + + CLIB_PREFETCH (p2->data, (2 * CLIB_CACHE_LINE_BYTES), STORE); + CLIB_PREFETCH (p3->data, (2 * CLIB_CACHE_LINE_BYTES), STORE); + } + + /* + * speculatively enqueue b0 and b1 to the current + * next frame + */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + + vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0; + vnet_buffer (b1)->sw_if_index[VLIB_TX] = ~0; + + hpgi0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX]; + hpgi1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX]; + + hpg0 = hicnpg_server_get (hpgi0); + hpg1 = hicnpg_server_get (hpgi1); + + if (hicn_interest_parse_pkt (b0) == HICN_ERROR_NONE) + { + vlib_buffer_t *rb = NULL; + rb = vlib_get_buffer (vm, hpg0->buffer_index); + + isv6 ? convert_interest_to_data_v6 (vm, b0, rb, bi0) : + convert_interest_to_data_v4 (vm, b0, rb, bi0); + + next0 = isv6 ? HICNPG_SERVER_NEXT_V6_LOOKUP : + HICNPG_SERVER_NEXT_V4_LOOKUP; + } + + if (hicn_interest_parse_pkt (b1) == HICN_ERROR_NONE) + { + vlib_buffer_t *rb = NULL; + rb = vlib_get_buffer (vm, hpg1->buffer_index); + + isv6 ? convert_interest_to_data_v6 (vm, b1, rb, bi1) : + convert_interest_to_data_v4 (vm, b1, rb, bi1); + + next1 = isv6 ? HICNPG_SERVER_NEXT_V6_LOOKUP : + HICNPG_SERVER_NEXT_V4_LOOKUP; + } + pkts_processed += 2; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + hicnpg_server_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->pkt_type = pkt_type0; + t->msg_type = msg_type0; + t->sw_if_index = sw_if_index0; + t->next_index = next0; + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + hicnpg_server_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->pkt_type = pkt_type1; + t->msg_type = msg_type1; + t->sw_if_index = sw_if_index1; + t->next_index = next1; + } + } + if (next0 == HICNPG_SERVER_NEXT_DROP) + { + pkts_dropped++; + } + if (next1 == HICNPG_SERVER_NEXT_DROP) + { + pkts_dropped++; + } + /* + * verify speculative enqueues, maybe switch current + * next frame + */ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, + n_left_to_next, bi0, bi1, next0, + next1); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 next0 = HICNPG_SERVER_NEXT_DROP; + u32 sw_if_index0 = ~0; + u32 hpgi0; + hicnpg_server_t *hpg0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0; + + hpgi0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX]; + hpg0 = hicnpg_server_get (hpgi0); + + if (hicn_interest_parse_pkt (b0) == HICN_ERROR_NONE) + { + /* this node grabs only interests */ + vlib_buffer_t *rb = NULL; + rb = vlib_get_buffer (vm, hpg0->buffer_index); + + isv6 ? convert_interest_to_data_v6 (vm, b0, rb, bi0) : + convert_interest_to_data_v4 (vm, b0, rb, bi0); + + next0 = isv6 ? HICNPG_SERVER_NEXT_V6_LOOKUP : + HICNPG_SERVER_NEXT_V4_LOOKUP; + } + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && + (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + hicnpg_server_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->pkt_type = pkt_type0; + t->msg_type = msg_type0; + t->sw_if_index = sw_if_index0; + t->next_index = next0; + } + pkts_processed += 1; + + if (next0 == HICNPG_SERVER_NEXT_DROP) + { + pkts_dropped++; + } + /* + * verify speculative enqueue, maybe switch current + * next frame + */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, hicn_pg_server_node.index, + HICNPG_SERVER_ERROR_PROCESSED, pkts_processed); + vlib_node_increment_counter (vm, hicn_pg_server_node.index, + HICNPG_SERVER_ERROR_DROPPED, pkts_dropped); + + return (frame->n_vectors); +} + +void +convert_interest_to_data_v4 (vlib_main_t *vm, vlib_buffer_t *b0, + vlib_buffer_t *rb, u32 bi0) +{ + hicn_header_t *h0 = vlib_buffer_get_current (b0); + + /* Get the packet length */ + u16 pkt_len = clib_net_to_host_u16 (h0->v4.ip.len); + + /* + * Rule of thumb: We want the size of the IP packet to be <= 1500 bytes + */ + u16 bytes_to_copy = rb->current_length; + if ((bytes_to_copy + pkt_len) > 1500) + { + bytes_to_copy = 1500 - pkt_len; + } + /* Add content to the data packet */ + vlib_buffer_add_data (vm, &bi0, rb->data, bytes_to_copy); + + b0 = vlib_get_buffer (vm, bi0); + + h0 = vlib_buffer_get_current (b0); + + ip4_address_t src_addr = h0->v4.ip.saddr; + h0->v4.ip.saddr = h0->v4.ip.daddr; + h0->v4.ip.daddr = src_addr; + + h0->v4.ip.len = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)); + h0->v4.ip.csum = ip4_header_checksum ((ip4_header_t *) &(h0->v4.ip)); + calculate_tcp_checksum_v4 (vm, b0); +} + +void +convert_interest_to_data_v6 (vlib_main_t *vm, vlib_buffer_t *b0, + vlib_buffer_t *rb, u32 bi0) +{ + hicn_header_t *h0 = vlib_buffer_get_current (b0); + + /* Get the packet length */ + uint16_t pkt_len = + clib_net_to_host_u16 (h0->v6.ip.len) + sizeof (ip6_header_t); + + /* + * Figure out how many bytes we can add to the content + * + * Rule of thumb: We want the size of the IP packet to be <= 1400 bytes + */ + u16 bytes_to_copy = rb->current_length; + if ((bytes_to_copy + pkt_len) > 1500) + { + bytes_to_copy = 1500 - pkt_len; + } + /* Add content to the data packet */ + vlib_buffer_add_data (vm, &bi0, rb->data, bytes_to_copy); + + b0 = vlib_get_buffer (vm, bi0); + + h0 = vlib_buffer_get_current (b0); + ip6_address_t src_addr = h0->v6.ip.saddr; + h0->v6.ip.saddr = h0->v6.ip.daddr; + h0->v6.ip.daddr = src_addr; + + h0->v6.ip.len = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) - + sizeof (ip6_header_t)); + h0->v6.tcp.data_offset_and_reserved |= 0x0f; + h0->v6.tcp.urg_ptr = htons (0xffff); + + calculate_tcp_checksum_v6 (vm, b0); +} + +VLIB_NODE_FN (hicn_pg_server6_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return hicnpg_node_server_fn (vm, node, frame, 1 /* is_v6 */); +} + +VLIB_NODE_FN (hicn_pg_server4_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return hicnpg_node_server_fn (vm, node, frame, 0 /* is_v6 */); +} + +VLIB_REGISTER_NODE(hicn_pg_server6_node) = +{ + .name = "hicnpg-server-6", + .vector_size = sizeof(u32), + .format_trace = format_icnpg_server_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(icnpg_server_error_strings), + .error_strings = icnpg_server_error_strings, + .n_next_nodes = HICNPG_SERVER_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = + { + [HICNPG_SERVER_NEXT_V4_LOOKUP] = "ip4-lookup", + [HICNPG_SERVER_NEXT_V6_LOOKUP] = "ip6-lookup", + [HICNPG_SERVER_NEXT_DROP] = "error-drop", + }, +}; + +VLIB_REGISTER_NODE(hicn_pg_server4_node) = +{ + .name = "hicnpg-server-4", + .vector_size = sizeof(u32), + .format_trace = format_icnpg_server_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(icnpg_server_error_strings), + .error_strings = icnpg_server_error_strings, + .n_next_nodes = HICNPG_SERVER_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = + { + [HICNPG_SERVER_NEXT_V4_LOOKUP] = "ip4-lookup", + [HICNPG_SERVER_NEXT_V6_LOOKUP] = "ip6-lookup", + [HICNPG_SERVER_NEXT_DROP] = "error-drop", + }, +}; + +/* + * End of packet-generator server node + */
\ No newline at end of file diff --git a/hicn-plugin/src/route.c b/hicn-plugin/src/route.c index a84891b9a..0c96e1412 100644 --- a/hicn-plugin/src/route.c +++ b/hicn-plugin/src/route.c @@ -34,6 +34,7 @@ #include "infra.h" #include "udp_tunnels/udp_tunnel.h" #include "mapme.h" +#include "pg.h" #define FIB_SOURCE_HICN 0x04 // Right after the FIB_SOURCE_INTERFACE priority @@ -234,7 +235,7 @@ sync_hicn_fib_entry (hicn_dpo_ctx_t *fib_entry, hicn_face_id_t **pvec_faces) do \ { \ /* Careful, this adds a lock on the face if it exists */ \ - hicn_face_add (dpo, nh, sw_if, &face_id, 0); \ + hicn_face_add (dpo, nh, sw_if, &face_id); \ vec_validate (vec_faces, index); \ vec_faces[index] = face_id; \ (index)++; \ @@ -294,10 +295,15 @@ sync_hicn_fib_entry (hicn_dpo_ctx_t *fib_entry, hicn_face_id_t **pvec_faces) default: continue; } - HICN_DEBUG ("Added new UDP face: %d because of route prefix %s", + HICN_DEBUG ("Added new UDP face: %d because of route prefix %U", face_id, format_ip_prefix, &_fib_entry->fe_prefix); udp_tunnel_add_existing (dpo->dpoi_index, proto); } + else if (dpo_is_pgserver (dpo)) + { + hicnpg_server_t *pg_server = hicnpg_server_get (dpo->dpoi_index); + ADD_FACE (&pg_server->hicn_locator); + } } const hicn_dpo_vft_t *strategy_vft = hicn_dpo_get_vft (fib_entry->dpo_type); diff --git a/hicn-plugin/src/strategy_node.c b/hicn-plugin/src/strategy_node.c index 66d9c2dbb..3ff2d0209 100644 --- a/hicn-plugin/src/strategy_node.c +++ b/hicn-plugin/src/strategy_node.c @@ -66,7 +66,7 @@ hicn_new_interest (hicn_strategy_runtime_t *rt, vlib_buffer_t *b0, u32 *next, f64 tnow, u8 *nameptr, u16 namelen, hicn_face_id_t outface, int nh_idx, index_t dpo_ctx_id0, const hicn_strategy_vft_t *strategy, dpo_type_t dpo_type, - u8 isv6, vl_api_hicn_api_node_stats_get_reply_t *stats, + vl_api_hicn_api_node_stats_get_reply_t *stats, u8 is_replication) { int ret; @@ -81,6 +81,7 @@ hicn_new_interest (hicn_strategy_runtime_t *rt, vlib_buffer_t *b0, u32 *next, u8 hash_entry_id = 0; u8 bucket_is_overflow = 0; u32 bucket_id = ~0; + u8 isv6 = hicn_buffer_is_v6 (b0); if (is_replication) { @@ -202,27 +203,22 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); while (n_left_from > 0 && n_left_to_next > 0) { - u8 isv6; u8 *nameptr; u16 namelen; - hicn_name_t name; - hicn_header_t *hicn0; vlib_buffer_t *b0; u32 bi0; hicn_face_id_t outfaces[MAX_OUT_FACES]; u32 outfaces_len; int nh_idx; u32 next0 = next_index; - int ret; /* Prefetch for next iteration. */ if (n_left_from > 1) { vlib_buffer_t *b1; b1 = vlib_get_buffer (vm, from[1]); - CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, LOAD); - CLIB_PREFETCH (&b1->trace_handle, 2 * CLIB_CACHE_LINE_BYTES, - STORE); + CLIB_PREFETCH (b1, 2 * CLIB_CACHE_LINE_BYTES, LOAD); + CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, LOAD); } /* Dequeue a packet buffer */ bi0 = from[0]; @@ -248,7 +244,8 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node, const hicn_strategy_vft_t *strategy = hicn_dpo_get_strategy_vft (dpo_ctx->dpo_type); - ret = hicn_interest_parse_pkt (b0, &name, &namelen, &hicn0, &isv6); + hicn_buffer_get_name_and_namelen (b0, &nameptr, &namelen); + stats.pkts_processed++; /* Select next hop */ /* @@ -256,8 +253,7 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node, * the interest-pcslookup node due to misconfiguration in * the punting rules. */ - if (PREDICT_TRUE (ret == HICN_ERROR_NONE && - HICN_IS_NAMEHASH_CACHED (b0) && + if (PREDICT_TRUE (HICN_IS_NAMEHASH_CACHED (b0) && strategy->hicn_select_next_hop ( vnet_buffer (b0)->ip.adj_index[VLIB_TX], &nh_idx, outfaces, &outfaces_len) == HICN_ERROR_NONE)) @@ -267,7 +263,6 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node, * here. Already checked in the interest_pcslookup * node */ - nameptr = (u8 *) (&name); u32 clones[outfaces_len]; if (outfaces_len > 1) { @@ -295,7 +290,7 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node, rt, local_b0, &next0, tnow, nameptr, namelen, outfaces[nh], nh_idx, vnet_buffer (local_b0)->ip.adj_index[VLIB_TX], - strategy, dpo_ctx->dpo_type, isv6, &stats, 0); + strategy, dpo_ctx->dpo_type, &stats, 0); } else { @@ -304,7 +299,7 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node, rt, local_b0, &next0, tnow, nameptr, namelen, outfaces[nh], nh_idx, vnet_buffer (local_b0)->ip.adj_index[VLIB_TX], - strategy, dpo_ctx->dpo_type, isv6, &stats, 1); + strategy, dpo_ctx->dpo_type, &stats, 1); } /* Maybe trace */ @@ -314,7 +309,7 @@ hicn_strategy_fn (vlib_main_t *vm, vlib_node_runtime_t *node, { hicn_strategy_trace_t *t = vlib_add_trace (vm, node, local_b0, sizeof (*t)); - t->pkt_type = HICN_PKT_TYPE_CONTENT; + t->pkt_type = HICN_PACKET_TYPE_DATA; t->sw_if_index = vnet_buffer (local_b0)->sw_if_index[VLIB_RX]; t->next_index = next0; @@ -376,4 +371,4 @@ VLIB_REGISTER_NODE (hicn_strategy_node) = * fd.io coding-style-patch-verification: ON * * Local Variables: eval: (c-set-style "gnu") End: - */ + */
\ No newline at end of file diff --git a/lib/includes/CMakeLists.txt b/lib/includes/CMakeLists.txt index 821feb2bb..392c2c94e 100644 --- a/lib/includes/CMakeLists.txt +++ b/lib/includes/CMakeLists.txt @@ -48,12 +48,18 @@ set(LIBHICN_HEADER_FILES_PROTOCOL ${CMAKE_CURRENT_SOURCE_DIR}/hicn/protocol/udp.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/protocol/new.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/array.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/bitmap.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/hash.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/ip_address.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/khash.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/log.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/map.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/pool.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/ring.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/set.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/sstrncpy.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/token.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/types.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/vector.h PARENT_SCOPE ) diff --git a/lib/includes/hicn/base.h b/lib/includes/hicn/base.h index 844814d57..b825619b7 100644 --- a/lib/includes/hicn/base.h +++ b/lib/includes/hicn/base.h @@ -21,6 +21,8 @@ #ifndef HICN_BASE_H #define HICN_BASE_H +#include <stdio.h> +#include <stdbool.h> #include "common.h" #ifdef _WIN32 #include <Winsock2.h> @@ -148,6 +150,16 @@ hicn_type_is_none (hicn_type_t type) } /** + * @brief hICN Packet type + */ +typedef enum +{ + HICN_PACKET_TYPE_INTEREST, + HICN_PACKET_TYPE_DATA, + HICN_PACKET_N_TYPE, +} hicn_packet_type_t; + +/** * @brief hICN Payload type * * This type distinguishes several types of data packet, which can either carry @@ -160,6 +172,61 @@ typedef enum HPT_UNSPEC = 999 } hicn_payload_type_t; +/*************************************************************** + * Interest Manifest + ***************************************************************/ + +#define MAX_SUFFIXES_IN_MANIFEST 255 +#define WORD_WIDTH (sizeof (uint32_t) * 8) +#define BITMAP_SIZE ((MAX_SUFFIXES_IN_MANIFEST + 1) / WORD_WIDTH) + +typedef struct +{ + /* This can be 16 bits, but we use 32 bits for alignment */ + uint32_t n_suffixes; + + uint32_t request_bitmap[BITMAP_SIZE]; + + /* Followed by the list of prefixes to ask */ + /* ... */ +} interest_manifest_header_t; + +// Bitmap operations + +static inline void +set_bit (uint32_t *bitmap, int i) +{ + size_t offset = i / WORD_WIDTH; + size_t pos = i % WORD_WIDTH; + bitmap[offset] |= ((uint32_t) 1 << pos); +} + +static inline void +unset_bit (uint32_t *bitmap, int i) +{ + size_t offset = i / WORD_WIDTH; + size_t pos = i % WORD_WIDTH; + bitmap[offset] &= ~((uint32_t) 1 << pos); +} + +static inline bool +is_bit_set (const uint32_t *bitmap, int i) +{ + size_t offset = i / WORD_WIDTH; + size_t pos = i % WORD_WIDTH; + return bitmap[offset] & ((uint32_t) 1 << pos); +} + +static inline void +bitmap_print (u32 *bitmap, size_t n_words) +{ + for (size_t word = 0; word < n_words; word++) + { + for (int bit = 31; bit >= 0; bit--) + (is_bit_set (&bitmap[word], bit)) ? printf ("1") : printf ("0"); + } +} + /** * @brief Path label computations * @@ -194,6 +261,79 @@ update_pathlabel (hicn_pathlabel_t current_label, hicn_faceid_t face_id, pl_face_id; } +/*************************************************************** + * Statistics + ***************************************************************/ + +typedef struct +{ + // Packets processed + uint32_t countReceived; // Interest and data only + uint32_t countInterestsReceived; + uint32_t countObjectsReceived; + + // Packets Dropped + uint32_t countDropped; + uint32_t countInterestsDropped; + uint32_t countObjectsDropped; + uint32_t countOtherDropped; + + // Forwarding + uint32_t countInterestForwarded; + uint32_t countObjectsForwarded; + + // Errors while forwarding + uint32_t countDroppedConnectionNotFound; + uint32_t countSendFailures; + uint32_t countDroppedNoRoute; + + // Interest processing + uint32_t countInterestsAggregated; + uint32_t countInterestsRetransmitted; + uint32_t countInterestsSatisfiedFromStore; + uint32_t countInterestsExpired; + + // Data processing + uint32_t countDroppedNoReversePath; + uint32_t countDataExpired; + + // TODO(eloparco): Currently not used + // uint32_t countDroppedNoHopLimit; + // uint32_t countDroppedZeroHopLimitFromRemote; + // uint32_t countDroppedZeroHopLimitToRemote; +} forwarder_stats_t; + +typedef struct +{ + uint32_t n_pit_entries; + uint32_t n_cs_entries; + uint32_t n_lru_evictions; +} pkt_cache_stats_t; + +typedef struct +{ + forwarder_stats_t forwarder; + pkt_cache_stats_t pkt_cache; +} hicn_light_stats_t; + +typedef struct +{ + struct + { + uint32_t rx_pkts; + uint32_t rx_bytes; + uint32_t tx_pkts; + uint32_t tx_bytes; + } interests; + struct + { + uint32_t rx_pkts; + uint32_t rx_bytes; + uint32_t tx_pkts; + uint32_t tx_bytes; + } data; +} connection_stats_t; + #endif /* HICN_BASE_H */ /* diff --git a/lib/includes/hicn/common.h b/lib/includes/hicn/common.h index b0898ce1f..1998099db 100644 --- a/lib/includes/hicn/common.h +++ b/lib/includes/hicn/common.h @@ -224,8 +224,6 @@ ip_csum_sub_even (ip_csum_t c, ip_csum_t x) u32 cumulative_hash32 (const void *data, size_t len, u32 lastValue); u32 hash32 (const void *data, size_t len); -u64 cumulative_hash64 (const void *data, size_t len, u64 lastValue); -u64 hash64 (const void *data, size_t len); void hicn_packet_dump (const uint8_t *buffer, size_t len); /** @@ -270,23 +268,75 @@ csum (const void *addr, size_t size, u16 init) #define HICN_IP_VERSION(packet) \ ((hicn_header_t *) packet)->protocol.ipv4.version -/* - * ntohll / htonll allows byte swapping for 64 bits integers - */ -#ifndef htonll -#define htonll(x) \ - ((1 == htonl (1)) ? \ - (x) : \ - ((uint64_t) htonl ((x) &0xFFFFFFFF) << 32) | htonl ((x) >> 32)) +#ifndef ntohll +static inline uint64_t +ntohll (uint64_t input) +{ + uint64_t return_val = input; +#if (__BYTE_ORDER__) == (__ORDER_LITTLE_ENDIAN__) + uint8_t *tmp = (uint8_t *) &return_val; + + tmp[0] = (uint8_t) (input >> 56); + tmp[1] = (uint8_t) (input >> 48); + tmp[2] = (uint8_t) (input >> 40); + tmp[3] = (uint8_t) (input >> 32); + tmp[4] = (uint8_t) (input >> 24); + tmp[5] = (uint8_t) (input >> 16); + tmp[6] = (uint8_t) (input >> 8); + tmp[7] = (uint8_t) (input >> 0); #endif -#ifndef ntohll -#define ntohll(x) \ - ((1 == ntohl (1)) ? \ - (x) : \ - ((uint64_t) ntohl ((x) &0xFFFFFFFF) << 32) | ntohl ((x) >> 32)) + return return_val; +} + +static inline uint64_t +htonll (uint64_t input) +{ + return (ntohll (input)); +} +#endif + +#define round_pow2(x, pow2) (((x) + (pow2) -1) & ~((pow2) -1)) + +#define _SIZEOF_ALIGNED(x, size) round_pow2 (sizeof (x), size) +#define SIZEOF_ALIGNED(x) _SIZEOF_ALIGNED (x, sizeof (void *)) + +/* Definitions for builtins unavailable on MSVC */ +#if defined(_MSC_VER) && !defined(__clang__) +#include <intrin.h> + +uint32_t __inline __builtin_ctz (uint32_t value) +{ + uint32_t trailing_zero = 0; + if (_BitScanForward (&trailing_zero, value)) + return trailing_zero; + else + return 32; +} + +uint32_t __inline __builtin_clz (uint32_t value) +{ + uint32_t leading_zero = 0; + if (_BitScanReverse (&leading_zero, value)) + return 31 - leading_zero; + else + return 32; +} + +uint32_t __inline __builtin_clzl2 (uint64_t value) +{ + uint32_t leading_zero = 0; + if (_BitScanReverse64 (&leading_zero, value)) + return 63 - leading_zero; + else + return 64; +} + +#define __builtin_clzl __builtin_clzll #endif +#define next_pow2(x) (x <= 1 ? 1 : 1ul << (64 - __builtin_clzl (x - 1))) + #endif /* HICN_COMMON_H */ /* diff --git a/lib/includes/hicn/compat.h b/lib/includes/hicn/compat.h index 8de3f9d7e..98c035b57 100644 --- a/lib/includes/hicn/compat.h +++ b/lib/includes/hicn/compat.h @@ -93,6 +93,8 @@ hicn_get_ah_format (hicn_format_t format) // HICN_V6_MIN_HDR_LEN : HICN_V4_MIN_HDR_LEN) #define HICN_MIN_HDR_LEN HICN_V6_MIN_HDR_LEN +hicn_type_t hicn_header_to_type (const hicn_header_t *h); + /** * @brief Parse packet headers and return hICN format * @param [in] format - hICN Format diff --git a/lib/includes/hicn/header.h b/lib/includes/hicn/header.h index 8af9170f8..208e35d68 100644 --- a/lib/includes/hicn/header.h +++ b/lib/includes/hicn/header.h @@ -135,6 +135,8 @@ typedef union #define HICN_V4_TCP_AH_HDRLEN (HICN_V4_TCP_HDRLEN + AH_HDRLEN) #define HICN_V4_ICMP_AH_HDRLEN (HICN_V4_ICMP_HDRLEN + AH_HDRLEN) +#define HICN_DEFAULT_PORT 9695 + #endif /* HICN_HEADER_H */ /* diff --git a/lib/includes/hicn/ops.h b/lib/includes/hicn/ops.h index e9eebc76c..4efef6523 100644 --- a/lib/includes/hicn/ops.h +++ b/lib/includes/hicn/ops.h @@ -257,6 +257,45 @@ typedef struct hicn_ops_s const hicn_lifetime_t lifetime); /** + * @brief Get the source port of the hicn packet. + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Interest or Data packet + * @param [out] source_port - Retrieved source port + * @return hICN error code + */ + int (*get_source_port) (hicn_type_t type, const hicn_protocol_t *h, + u16 *source_port); + + /** + * @brief Get the destination port of the hicn packet. + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Interest or Data packet + * @param [out] source_port - Retrieved destination port + * @return hICN error code + */ + int (*get_dest_port) (hicn_type_t type, const hicn_protocol_t *h, + u16 *dest_port); + + /** + * @brief Set the source port of the hicn packet. + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Interest or Data packet + * @param [out] source_port - Source port to set + * @return hICN error code + */ + int (*set_source_port) (hicn_type_t type, hicn_protocol_t *h, + u16 source_port); + + /** + * @brief Set the destination port of the hicn packet. + * @param [in] type - hICN packet type + * @param [in] h - Buffer holding the Interest or Data packet + * @param [out] source_port - Destination port to set + * @return hICN error code + */ + int (*set_dest_port) (hicn_type_t type, hicn_protocol_t *h, u16 dest_port); + + /** * @brief Update all checksums in packet headers * @param [in] type - hICN packet type * @param [in,out] h - Buffer holding the packet @@ -540,6 +579,10 @@ typedef struct hicn_ops_s ATTR_INIT (reset_data_for_hash, protocol##_reset_data_for_hash), \ ATTR_INIT (get_lifetime, protocol##_get_lifetime), \ ATTR_INIT (set_lifetime, protocol##_set_lifetime), \ + ATTR_INIT (get_source_port, protocol##_get_source_port), \ + ATTR_INIT (get_dest_port, protocol##_get_dest_port), \ + ATTR_INIT (set_source_port, protocol##_set_source_port), \ + ATTR_INIT (set_dest_port, protocol##_set_dest_port), \ ATTR_INIT (update_checksums, protocol##_update_checksums), \ ATTR_INIT (verify_checksums, protocol##_verify_checksums), \ ATTR_INIT (rewrite_interest, protocol##_rewrite_interest), \ @@ -775,6 +818,34 @@ PAYLOAD (hicn_type_t type, const hicn_protocol_t *h) return HICN_LIB_ERROR_##error; \ } +#define DECLARE_get_source_port(protocol, error) \ + int protocol##_get_source_port (hicn_type_t type, const hicn_protocol_t *h, \ + u16 *source_port) \ + { \ + return HICN_LIB_ERROR_##error; \ + } + +#define DECLARE_get_dest_port(protocol, error) \ + int protocol##_get_dest_port (hicn_type_t type, const hicn_protocol_t *h, \ + u16 *dest_port) \ + { \ + return HICN_LIB_ERROR_##error; \ + } + +#define DECLARE_set_source_port(protocol, error) \ + int protocol##_set_source_port (hicn_type_t type, hicn_protocol_t *h, \ + u16 source_port) \ + { \ + return HICN_LIB_ERROR_##error; \ + } + +#define DECLARE_set_dest_port(protocol, error) \ + int protocol##_set_dest_port (hicn_type_t type, hicn_protocol_t *h, \ + u16 dest_port) \ + { \ + return HICN_LIB_ERROR_##error; \ + } + #define DECLARE_update_checksums(protocol, error) \ int protocol##_update_checksums (hicn_type_t type, hicn_protocol_t *h, \ u16 partial_csum, size_t payload_length) \ diff --git a/lib/includes/hicn/util/array.h b/lib/includes/hicn/util/array.h index 46d60976e..f56c13140 100644 --- a/lib/includes/hicn/util/array.h +++ b/lib/includes/hicn/util/array.h @@ -28,8 +28,6 @@ #define BUFSIZE 1024 -typedef int (*cmp_t) (const void *x, const void *y); - #define TYPEDEF_ARRAY_H(NAME, T) \ \ typedef struct \ @@ -151,7 +149,7 @@ typedef int (*cmp_t) (const void *x, const void *y); for (unsigned i = 0; i < array->size; i++) \ { \ if (CMP (search, array->elements[i]) == 0) \ - return facelet_array_remove_index (array, i, element); \ + return NAME##_remove_index (array, i, element); \ } \ /* Not found */ \ if (element) \ diff --git a/lib/includes/hicn/util/bitmap.h b/lib/includes/hicn/util/bitmap.h new file mode 100644 index 000000000..11eb7870b --- /dev/null +++ b/lib/includes/hicn/util/bitmap.h @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file bitmap.h + * \brief Bitmap + * + * A bitmap is implemented as a wrapper over a vector made of bit elements + */ + +#ifndef UTIL_BITMAP_H +#define UTIL_BITMAP_H + +#include <assert.h> +#include <string.h> +#include <sys/param.h> // MIN, MAX + +#include <hicn/util/log.h> + +#include <hicn/common.h> +#include <hicn/util/vector.h> + +typedef uint_fast32_t bitmap_t; + +#define BITMAP_WIDTH(bitmap) (sizeof ((bitmap)[0]) * 8) + +/** + * @brief Allocate and initialize a bitmap + * + * @param[in,out] bitmap Bitmap to allocate and initialize + * @param[in] max_size Bitmap max_size + */ +#define bitmap_init(bitmap, init_size, max_size) \ + vector_init ( \ + bitmap, next_pow2 ((init_size) / BITMAP_WIDTH (bitmap)), \ + max_size == 0 ? 0 : next_pow2 ((max_size) / BITMAP_WIDTH (bitmap))) + +/* + * @brief Ensures a bitmap is sufficiently large to hold an element at the + * given position. + * + * @param[in] bitmap The bitmap for which to validate the position. + * @param[in] pos The position to validate. + * + * NOTE: + * - This function should always be called before writing to a bitmap element + * to eventually make room for it (the bitmap will eventually be resized). + */ +static inline int +bitmap_ensure_pos (bitmap_t **bitmap, off_t pos) +{ + size_t offset = pos / BITMAP_WIDTH (*bitmap); + return vector_ensure_pos (*bitmap, offset); +} + +/** + * @brief Returns the allocated size of a bitmap. + * + * @see listener_table_get_by_id + */ +#define bitmap_get_alloc_size(bitmap) vector_get_alloc_size (bitmap) + +/** + * @brief Retrieve the state of the i-th bit in the bitmap. + * + * @param[in] bitmap The bitmap to access. + * @param[in] i The bit position. + */ +static inline int +bitmap_get (const bitmap_t *bitmap, off_t i) +{ + size_t offset = i / BITMAP_WIDTH (bitmap); + assert (offset < bitmap_get_alloc_size (bitmap)); + size_t pos = i % BITMAP_WIDTH (bitmap); + size_t shift = BITMAP_WIDTH (bitmap) - pos - 1; + return (bitmap[offset] >> shift) & 1; +} + +/* + * @brief Returns whether the i-th bit is set (equal to 1) in a bitmap. + * + * @param[in] bitmap The bitmap to access. + * @param[in] i The bit position. + * + * @return bool + */ +#define bitmap_is_set(bitmap, i) (bitmap_get ((bitmap), (i)) == 1) +#define bitmap_is_unset(bitmap, i) (bitmap_get ((bitmap), (i)) == 0) + +/* + * @brief Returns whether the i-th bit is unset (equal to 0) in a bitmap. + * + * @param[in] bitmap The bitmap to access. + * @param[in] i The bit position. + * + * @return bool + */ +#define bitmap_set(bitmap, i) _bitmap_set ((bitmap_t **) &bitmap, i) + +/* + * @brief Returns whether the i-th bit is unset (equal to 0) in a bitmap + * (helper). + * + * @param[in] bitmap The bitmap to access. + * @param[in] i The bit position. + * + * @return bool + */ +static inline int +_bitmap_set (bitmap_t **bitmap_ptr, off_t i) +{ + if (bitmap_ensure_pos (bitmap_ptr, i) < 0) + return -1; + + bitmap_t *bitmap = *bitmap_ptr; + size_t offset = i / BITMAP_WIDTH (bitmap); + size_t pos = i % BITMAP_WIDTH (bitmap); + size_t shift = BITMAP_WIDTH (bitmap) - pos - 1; + + bitmap[offset] |= (bitmap_t) 1 << shift; + return 0; +} + +static inline int +bitmap_unset (bitmap_t *bitmap, off_t i) +{ + if (bitmap_ensure_pos (&bitmap, i) < 0) + return -1; + size_t offset = i / BITMAP_WIDTH (bitmap); + size_t pos = i % BITMAP_WIDTH (bitmap); + size_t shift = BITMAP_WIDTH (bitmap) - pos - 1; + bitmap[offset] &= ~(1ul << shift); + return 0; +} + +static inline int +bitmap_set_range (bitmap_t *bitmap, off_t from, off_t to) +{ + assert (from <= to); + ssize_t offset_from = from / BITMAP_WIDTH (bitmap); + ssize_t offset_to = to / BITMAP_WIDTH (bitmap); + size_t pos_from = from % BITMAP_WIDTH (bitmap); + size_t pos_to = to % BITMAP_WIDTH (bitmap); + + /* + * First block initialization is needed if <from> is not aligned with the + * bitmap element size or if to is within the same one. + */ + if ((pos_from != 0) || + ((offset_to == offset_from) && (pos_to != BITMAP_WIDTH (bitmap) - 1))) + { + size_t from_end = MIN (to, (offset_from + 1) * BITMAP_WIDTH (bitmap)); + for (size_t k = from; k < from_end; k++) + { + if (bitmap_set (bitmap, k) < 0) + goto END; + } + } + + /* + * Second block is needed if <to> is not aligned with the bitmap element + * size + */ + if ((pos_to != BITMAP_WIDTH (bitmap) - 1) && (offset_to != offset_from)) + { + size_t to_start = MAX (from, offset_to * BITMAP_WIDTH (bitmap)); + for (size_t k = to_start; k < (size_t) to; k++) + { + if (bitmap_set (bitmap, k) < 0) + goto END; + } + } + + if (pos_from != 0) + offset_from += 1; + if (pos_to != BITMAP_WIDTH (bitmap) - 1) + offset_to -= 1; + + /* + * We need to cover both elements at position offset_from and offset_to + * provided that offset_from is not bigger + */ + if (offset_to >= offset_from) + { + memset (&bitmap[offset_from], 0xFF, + (offset_to - offset_from + 1) * sizeof (bitmap[0])); + } + + return 0; + +END: + ERROR ("Error setting bitmap range\n"); + return -1; +} + +#define bitmap_set_to(bitmap, to) bitmap_set_range ((bitmap), 0, (to)) + +#define bitmap_free(bitmap) vector_free (bitmap) + +#endif /* UTIL_BITMAP_H */ diff --git a/lib/includes/hicn/util/hash.h b/lib/includes/hicn/util/hash.h new file mode 100644 index 000000000..ded8fc370 --- /dev/null +++ b/lib/includes/hicn/util/hash.h @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * \file hash.h + * \brief Simple non-cryptographic hash implementation. + * + * Two helpers are provided : + * hash(buf, len) : hash a buffer <buf> of length <len> + * hash_struct(buf) : hash a buffer corresponding to an allocated struct + * + * This file consists in excerpts from Jenkins hash (public domain). + * http://www.burtleburtle.net/bob/c/lookup3.c + */ +#ifndef UTIL_HASH_H +#define UTIL_HASH_H + +#include <stdint.h> + +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) +#define HASH_LITTLE_ENDIAN 1 +#define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +#define HASH_LITTLE_ENDIAN 0 +#define HASH_BIG_ENDIAN 1 +#else +#define HASH_LITTLE_ENDIAN 0 +#define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t) 1 << (n)) +#define hashmask(n) (hashsize (n) - 1) +#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) + +#define mix(a, b, c) \ + { \ + a -= c; \ + a ^= rot (c, 4); \ + c += b; \ + b -= a; \ + b ^= rot (a, 6); \ + a += c; \ + c -= b; \ + c ^= rot (b, 8); \ + b += a; \ + a -= c; \ + a ^= rot (c, 16); \ + c += b; \ + b -= a; \ + b ^= rot (a, 19); \ + a += c; \ + c -= b; \ + c ^= rot (b, 4); \ + b += a; \ + } + +#define final(a, b, c) \ + { \ + c ^= b; \ + c -= rot (b, 14); \ + a ^= c; \ + a -= rot (c, 11); \ + b ^= a; \ + b -= rot (a, 25); \ + c ^= b; \ + c -= rot (b, 16); \ + a ^= c; \ + a -= rot (c, 4); \ + b ^= a; \ + b -= rot (a, 14); \ + c ^= b; \ + c -= rot (b, 24); \ + } + +static inline uint32_t +hashlittle (const void *key, size_t length, uint32_t initval) +{ + uint32_t a, b, c; /* internal state */ + union + { + const void *ptr; + size_t i; + } u; /* needed for Mac Powerbook G4 */ + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t) length) + initval; + + u.ptr = key; + if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) + { + const uint32_t *k = (const uint32_t *) key; /* read 32-bit chunks */ + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) + */ + while (length > 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix (a, b, c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) + * block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch (length) + { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += k[2] & 0xffffff; + b += k[1]; + a += k[0]; + break; + case 10: + c += k[2] & 0xffff; + b += k[1]; + a += k[0]; + break; + case 9: + c += k[2] & 0xff; + b += k[1]; + a += k[0]; + break; + case 8: + b += k[1]; + a += k[0]; + break; + case 7: + b += k[1] & 0xffffff; + a += k[0]; + break; + case 6: + b += k[1] & 0xffff; + a += k[0]; + break; + case 5: + b += k[1] & 0xff; + a += k[0]; + break; + case 4: + a += k[0]; + break; + case 3: + a += k[0] & 0xffffff; + break; + case 2: + a += k[0] & 0xffff; + break; + case 1: + a += k[0] & 0xff; + break; + case 0: + return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *) k; + switch (length) + { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += ((uint32_t) k8[10]) << 16; /* fall through */ + case 10: + c += ((uint32_t) k8[9]) << 8; /* fall through */ + case 9: + c += k8[8]; /* fall through */ + case 8: + b += k[1]; + a += k[0]; + break; + case 7: + b += ((uint32_t) k8[6]) << 16; /* fall through */ + case 6: + b += ((uint32_t) k8[5]) << 8; /* fall through */ + case 5: + b += k8[4]; /* fall through */ + case 4: + a += k[0]; + break; + case 3: + a += ((uint32_t) k8[2]) << 16; /* fall through */ + case 2: + a += ((uint32_t) k8[1]) << 8; /* fall through */ + case 1: + a += k8[0]; + break; + case 0: + return c; + } + +#endif /* !valgrind */ + } + else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) + { + const uint16_t *k = (const uint16_t *) key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing + */ + while (length > 12) + { + a += k[0] + (((uint32_t) k[1]) << 16); + b += k[2] + (((uint32_t) k[3]) << 16); + c += k[4] + (((uint32_t) k[5]) << 16); + mix (a, b, c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block + */ + k8 = (const uint8_t *) k; + switch (length) + { + case 12: + c += k[4] + (((uint32_t) k[5]) << 16); + b += k[2] + (((uint32_t) k[3]) << 16); + a += k[0] + (((uint32_t) k[1]) << 16); + break; + case 11: + c += ((uint32_t) k8[10]) << 16; /* fall through */ + case 10: + c += k[4]; + b += k[2] + (((uint32_t) k[3]) << 16); + a += k[0] + (((uint32_t) k[1]) << 16); + break; + case 9: + c += k8[8]; /* fall through */ + case 8: + b += k[2] + (((uint32_t) k[3]) << 16); + a += k[0] + (((uint32_t) k[1]) << 16); + break; + case 7: + b += ((uint32_t) k8[6]) << 16; /* fall through */ + case 6: + b += k[2]; + a += k[0] + (((uint32_t) k[1]) << 16); + break; + case 5: + b += k8[4]; /* fall through */ + case 4: + a += k[0] + (((uint32_t) k[1]) << 16); + break; + case 3: + a += ((uint32_t) k8[2]) << 16; /* fall through */ + case 2: + a += k[0]; + break; + case 1: + a += k8[0]; + break; + case 0: + return c; /* zero length requires no mixing */ + } + } + else + { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *) key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) + */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t) k[1]) << 8; + a += ((uint32_t) k[2]) << 16; + a += ((uint32_t) k[3]) << 24; + b += k[4]; + b += ((uint32_t) k[5]) << 8; + b += ((uint32_t) k[6]) << 16; + b += ((uint32_t) k[7]) << 24; + c += k[8]; + c += ((uint32_t) k[9]) << 8; + c += ((uint32_t) k[10]) << 16; + c += ((uint32_t) k[11]) << 24; + mix (a, b, c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) + */ + switch (length) /* all the case statements fall through */ + { + case 12: + c += ((uint32_t) k[11]) << 24; + case 11: + c += ((uint32_t) k[10]) << 16; + case 10: + c += ((uint32_t) k[9]) << 8; + case 9: + c += k[8]; + case 8: + b += ((uint32_t) k[7]) << 24; + case 7: + b += ((uint32_t) k[6]) << 16; + case 6: + b += ((uint32_t) k[5]) << 8; + case 5: + b += k[4]; + case 4: + a += ((uint32_t) k[3]) << 24; + case 3: + a += ((uint32_t) k[2]) << 16; + case 2: + a += ((uint32_t) k[1]) << 8; + case 1: + a += k[0]; + break; + case 0: + return c; + } + } + + final (a, b, c); + return c; +} + +/* Helpers */ + +#define HASH_INITVAL 1 +//#define hash(buf, len) (hash_t)hashlittle(buf, len, HASH_INITVAL) +#define hash(buf, len) hashlittle (buf, len, HASH_INITVAL) +#define hash_struct(buf) hash (buf, sizeof (*buf)) + +#define str_hash(str) (hash (str, strlen (str))) +#define str_hash_eq(a, b) (str_hash (b) - str_hash (a)) + +#endif /* UTIL_JENKINS_HASH_H */ diff --git a/lib/includes/hicn/util/khash.h b/lib/includes/hicn/util/khash.h new file mode 100644 index 000000000..17401091f --- /dev/null +++ b/lib/includes/hicn/util/khash.h @@ -0,0 +1,826 @@ +/* The MIT License + + Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +/* + An example: + +#include "khash.h" +KHASH_MAP_INIT_INT(32, char) +int main() { + int ret, is_missing; + khiter_t k; + khash_t(32) *h = kh_init(32); + k = kh_put(32, h, 5, &ret); + kh_value(h, k) = 10; + k = kh_get(32, h, 10); + is_missing = (k == kh_end(h)); + k = kh_get(32, h, 5); + kh_del(32, h, k); + for (k = kh_begin(h); k != kh_end(h); ++k) + if (kh_exist(h, k)) kh_value(h, k) = 1; + kh_destroy(32, h); + return 0; +} +*/ + +/* + 2013-05-02 (0.2.8): + + * Use quadratic probing. When the capacity is power of 2, stepping + function i*(i+1)/2 guarantees to traverse each bucket. It is better than + double hashing on cache performance and is more robust than linear probing. + + In theory, double hashing should be more robust than quadratic + probing. However, my implementation is probably not for large hash tables, + because the second hash function is closely tied to the first hash function, + which reduce the effectiveness of double hashing. + + Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php + + 2011-12-29 (0.2.7): + + * Minor code clean up; no actual effect. + + 2011-09-16 (0.2.6): + + * The capacity is a power of 2. This seems to dramatically improve the + speed for simple keys. Thank Zilong Tan for the suggestion. + Reference: + + - http://code.google.com/p/ulib/ + - http://nothings.org/computer/judy/ + + * Allow to optionally use linear probing which usually has better + performance for random input. Double hashing is still the default as + it is more robust to certain non-random input. + + * Added Wang's integer hash function (not used by default). This hash + function is more robust to certain non-random input. + + 2011-02-14 (0.2.5): + + * Allow to declare global functions. + + 2009-09-26 (0.2.4): + + * Improve portability + + 2008-09-19 (0.2.3): + + * Corrected the example + * Improved interfaces + + 2008-09-11 (0.2.2): + + * Improved speed a little in kh_put() + + 2008-09-10 (0.2.1): + + * Added kh_clear() + * Fixed a compiling error + + 2008-09-02 (0.2.0): + + * Changed to token concatenation which increases flexibility. + + 2008-08-31 (0.1.2): + + * Fixed a bug in kh_get(), which has not been tested previously. + + 2008-08-31 (0.1.1): + + * Added destructor +*/ + +#ifndef __AC_KHASH_H +#define __AC_KHASH_H + +/*! + @header + + Generic hash table library. + */ + +#define AC_VERSION_KHASH_H "0.2.8" + +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +/* compiler specific configuration */ + +#if UINT_MAX == 0xffffffffu +typedef unsigned int khint32_t; +#elif ULONG_MAX == 0xffffffffu +typedef unsigned long khint32_t; +#endif + +#if ULONG_MAX == ULLONG_MAX +typedef unsigned long khint64_t; +#else +typedef unsigned long long khint64_t; +#endif + +#ifndef kh_inline +#ifdef _MSC_VER +#define kh_inline __inline +#else +#define kh_inline inline +#endif +#endif /* kh_inline */ + +#ifndef klib_unused +#if (defined __clang__ && __clang_major__ >= 3) || \ + (defined __GNUC__ && __GNUC__ >= 3) +#define klib_unused __attribute__ ((__unused__)) +#else +#define klib_unused +#endif +#endif /* klib_unused */ + +typedef khint32_t khint_t; +typedef khint_t khiter_t; + +#define __ac_isempty(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 2) +#define __ac_isdel(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 1) +#define __ac_iseither(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 3) +#define __ac_set_isdel_false(flag, i) \ + (flag[i >> 4] &= ~(1ul << ((i & 0xfU) << 1))) +#define __ac_set_isempty_false(flag, i) \ + (flag[i >> 4] &= ~(2ul << ((i & 0xfU) << 1))) +#define __ac_set_isboth_false(flag, i) \ + (flag[i >> 4] &= ~(3ul << ((i & 0xfU) << 1))) +#define __ac_set_isdel_true(flag, i) (flag[i >> 4] |= 1ul << ((i & 0xfU) << 1)) + +#define __ac_fsize(m) ((m) < 16 ? 1 : (m) >> 4) + +#ifndef kroundup32 +#define kroundup32(x) \ + (--(x), (x) |= (x) >> 1, (x) |= (x) >> 2, (x) |= (x) >> 4, (x) |= (x) >> 8, \ + (x) |= (x) >> 16, ++(x)) +#endif + +#ifndef kcalloc +#define kcalloc(N, Z) calloc (N, Z) +#endif +#ifndef kmalloc +#define kmalloc(Z) malloc (Z) +#endif +#ifndef krealloc +#define krealloc(P, Z) realloc (P, Z) +#endif +#ifndef kfree +#define kfree(P) free (P) +#endif + +static const double __ac_HASH_UPPER = 0.77; + +#define __KHASH_TYPE(name, khkey_t, khval_t) \ + typedef struct kh_##name##_s \ + { \ + khint_t n_buckets, size, n_occupied, upper_bound; \ + khint32_t *flags; \ + khkey_t *keys; \ + khval_t *vals; \ + } kh_##name##_t; + +#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \ + extern kh_##name##_t *kh_init_##name (void); \ + extern void kh_destroy_##name (kh_##name##_t *h); \ + extern void kh_clear_##name (kh_##name##_t *h); \ + extern khint_t kh_get_##name (const kh_##name##_t *h, khkey_t key); \ + extern int kh_resize_##name (kh_##name##_t *h, khint_t new_n_buckets); \ + extern khint_t kh_put_##name (kh_##name##_t *h, khkey_t key, int *ret); \ + extern void kh_del_##name (kh_##name##_t *h, khint_t x); + +#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, \ + __hash_equal) \ + SCOPE kh_##name##_t *kh_init_##name (void) \ + { \ + return (kh_##name##_t *) kcalloc (1, sizeof (kh_##name##_t)); \ + } \ + SCOPE void kh_destroy_##name (kh_##name##_t *h) \ + { \ + if (h) \ + { \ + kfree ((void *) h->keys); \ + kfree (h->flags); \ + kfree ((void *) h->vals); \ + kfree (h); \ + } \ + } \ + SCOPE void kh_clear_##name (kh_##name##_t *h) \ + { \ + if (h && h->flags) \ + { \ + memset (h->flags, 0xaa, \ + __ac_fsize (h->n_buckets) * sizeof (khint32_t)); \ + h->size = h->n_occupied = 0; \ + } \ + } \ + SCOPE khint_t kh_get_##name (const kh_##name##_t *h, khkey_t key) \ + { \ + if (h->n_buckets) \ + { \ + khint_t k, i, last, mask, step = 0; \ + mask = h->n_buckets - 1; \ + k = __hash_func (key); \ + i = k & mask; \ + last = i; \ + while (!__ac_isempty (h->flags, i) && \ + (__ac_isdel (h->flags, i) || !__hash_equal (h->keys[i], key))) \ + { \ + i = (i + (++step)) & mask; \ + if (i == last) \ + return h->n_buckets; \ + } \ + return __ac_iseither (h->flags, i) ? h->n_buckets : i; \ + } \ + else \ + return 0; \ + } \ + SCOPE int kh_resize_##name (kh_##name##_t *h, khint_t new_n_buckets) \ + { /* This function uses 0.25*n_buckets bytes of \ + working space instead of \ + [sizeof(key_t+val_t)+.25]*n_buckets. */ \ + khint32_t *new_flags = 0; \ + khint_t j = 1; \ + { \ + kroundup32 (new_n_buckets); \ + if (new_n_buckets < 4) \ + new_n_buckets = 4; \ + if (h->size >= (khint_t) (new_n_buckets * __ac_HASH_UPPER + 0.5)) \ + j = 0; /* requested size is too small */ \ + else \ + { /* hash table size to be changed (shrink or expand); rehash */ \ + new_flags = (khint32_t *) kmalloc (__ac_fsize (new_n_buckets) * \ + sizeof (khint32_t)); \ + if (!new_flags) \ + return -1; \ + memset (new_flags, 0xaa, \ + __ac_fsize (new_n_buckets) * sizeof (khint32_t)); \ + if (h->n_buckets < new_n_buckets) \ + { /* expand */ \ + khkey_t *new_keys = (khkey_t *) krealloc ( \ + (void *) h->keys, new_n_buckets * sizeof (khkey_t)); \ + if (!new_keys) \ + { \ + kfree (new_flags); \ + return -1; \ + } \ + h->keys = new_keys; \ + if (kh_is_map) \ + { \ + khval_t *new_vals = (khval_t *) krealloc ( \ + (void *) h->vals, new_n_buckets * sizeof (khval_t)); \ + if (!new_vals) \ + { \ + kfree (new_flags); \ + return -1; \ + } \ + h->vals = new_vals; \ + } \ + } /* otherwise shrink */ \ + } \ + } \ + if (j) \ + { /* rehashing is needed */ \ + for (j = 0; j != h->n_buckets; ++j) \ + { \ + if (__ac_iseither (h->flags, j) == 0) \ + { \ + khkey_t key = h->keys[j]; \ + khval_t val; \ + khint_t new_mask; \ + new_mask = new_n_buckets - 1; \ + if (kh_is_map) \ + val = h->vals[j]; \ + __ac_set_isdel_true (h->flags, j); \ + while (1) \ + { /* kick-out process; sort of like in Cuckoo hashing */ \ + khint_t k, i, step = 0; \ + k = __hash_func (key); \ + i = k & new_mask; \ + while (!__ac_isempty (new_flags, i)) \ + i = (i + (++step)) & new_mask; \ + __ac_set_isempty_false (new_flags, i); \ + if (i < h->n_buckets && __ac_iseither (h->flags, i) == 0) \ + { /* kick out the existing element */ \ + { \ + khkey_t tmp = h->keys[i]; \ + h->keys[i] = key; \ + key = tmp; \ + } \ + if (kh_is_map) \ + { \ + khval_t tmp = h->vals[i]; \ + h->vals[i] = val; \ + val = tmp; \ + } \ + __ac_set_isdel_true ( \ + h->flags, \ + i); /* mark it as deleted in the old hash table */ \ + } \ + else \ + { /* write the element and jump out of the loop */ \ + h->keys[i] = key; \ + if (kh_is_map) \ + h->vals[i] = val; \ + break; \ + } \ + } \ + } \ + } \ + if (h->n_buckets > new_n_buckets) \ + { /* shrink the hash table */ \ + h->keys = (khkey_t *) krealloc ( \ + (void *) h->keys, new_n_buckets * sizeof (khkey_t)); \ + if (kh_is_map) \ + h->vals = (khval_t *) krealloc ( \ + (void *) h->vals, new_n_buckets * sizeof (khval_t)); \ + } \ + kfree (h->flags); /* free the working space */ \ + h->flags = new_flags; \ + h->n_buckets = new_n_buckets; \ + h->n_occupied = h->size; \ + h->upper_bound = (khint_t) (h->n_buckets * __ac_HASH_UPPER + 0.5); \ + } \ + return 0; \ + } \ + SCOPE khint_t kh_put_##name (kh_##name##_t *h, khkey_t key, int *ret) \ + { \ + khint_t x; \ + if (h->n_occupied >= h->upper_bound) \ + { /* update the hash table */ \ + if (h->n_buckets > (h->size << 1)) \ + { \ + if (kh_resize_##name (h, h->n_buckets - 1) < 0) \ + { /* clear "deleted" elements */ \ + *ret = -1; \ + return h->n_buckets; \ + } \ + } \ + else if (kh_resize_##name (h, h->n_buckets + 1) < 0) \ + { /* expand the hash table */ \ + *ret = -1; \ + return h->n_buckets; \ + } \ + } /* TODO: to implement automatically shrinking; resize() already \ + support shrinking */ \ + { \ + khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \ + x = site = h->n_buckets; \ + k = __hash_func (key); \ + i = k & mask; \ + if (__ac_isempty (h->flags, i)) \ + x = i; /* for speed up */ \ + else \ + { \ + last = i; \ + while ( \ + !__ac_isempty (h->flags, i) && \ + (__ac_isdel (h->flags, i) || !__hash_equal (h->keys[i], key))) \ + { \ + if (__ac_isdel (h->flags, i)) \ + site = i; \ + i = (i + (++step)) & mask; \ + if (i == last) \ + { \ + x = site; \ + break; \ + } \ + } \ + if (x == h->n_buckets) \ + { \ + if (__ac_isempty (h->flags, i) && site != h->n_buckets) \ + x = site; \ + else \ + x = i; \ + } \ + } \ + } \ + if (__ac_isempty (h->flags, x)) \ + { /* not present at all */ \ + h->keys[x] = key; \ + __ac_set_isboth_false (h->flags, x); \ + ++h->size; \ + ++h->n_occupied; \ + *ret = 1; \ + } \ + else if (__ac_isdel (h->flags, x)) \ + { /* deleted */ \ + h->keys[x] = key; \ + __ac_set_isboth_false (h->flags, x); \ + ++h->size; \ + *ret = 2; \ + } \ + else \ + *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \ + return x; \ + } \ + SCOPE void kh_del_##name (kh_##name##_t *h, khint_t x) \ + { \ + if (x != h->n_buckets && !__ac_iseither (h->flags, x)) \ + { \ + __ac_set_isdel_true (h->flags, x); \ + --h->size; \ + } \ + } + +#define KHASH_DECLARE(name, khkey_t, khval_t) \ + __KHASH_TYPE (name, khkey_t, khval_t) \ + __KHASH_PROTOTYPES (name, khkey_t, khval_t) + +#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, \ + __hash_equal) \ + __KHASH_TYPE (name, khkey_t, khval_t) \ + __KHASH_IMPL (name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, \ + __hash_equal) + +#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, \ + __hash_equal) \ + KHASH_INIT2 (name, static kh_inline klib_unused, khkey_t, khval_t, \ + kh_is_map, __hash_func, __hash_equal) + +/* --- BEGIN OF HASH FUNCTIONS --- */ + +/*! @function + @abstract Integer hash function + @param key The integer [khint32_t] + @return The hash value [khint_t] + */ +#define kh_int_hash_func(key) (khint32_t) (key) +/*! @function + @abstract Integer comparison function + */ +#define kh_int_hash_equal(a, b) ((a) == (b)) +/*! @function + @abstract 64-bit integer hash function + @param key The integer [khint64_t] + @return The hash value [khint_t] + */ +#define kh_int64_hash_func(key) (khint32_t) ((key) >> 33 ^ (key) ^ (key) << 11) +/*! @function + @abstract 64-bit integer comparison function + */ +#define kh_int64_hash_equal(a, b) ((a) == (b)) +/*! @function + @abstract const char* hash function + @param s Pointer to a null terminated string + @return The hash value + */ +static kh_inline khint_t +__ac_X31_hash_string (const char *s) +{ + khint_t h = (khint_t) *s; + if (h) + for (++s; *s; ++s) + h = (h << 5) - h + (khint_t) *s; + return h; +} +/*! @function + @abstract Another interface to const char* hash function + @param key Pointer to a null terminated string [const char*] + @return The hash value [khint_t] + */ +#define kh_str_hash_func(key) __ac_X31_hash_string (key) +/*! @function + @abstract Const char* comparison function + */ +#define kh_str_hash_equal(a, b) (strcmp (a, b) == 0) + +static kh_inline khint_t +__ac_Wang_hash (khint_t key) +{ + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + return key; +} +#define kh_int_hash_func2(key) __ac_Wang_hash ((khint_t) key) + +/* --- END OF HASH FUNCTIONS --- */ + +/* Other convenient macros... */ + +/*! + @abstract Type of the hash table. + @param name Name of the hash table [symbol] + */ +#define khash_t(name) kh_##name##_t + +/*! @function + @abstract Initiate a hash table. + @param name Name of the hash table [symbol] + @return Pointer to the hash table [khash_t(name)*] + */ +#define kh_init(name) kh_init_##name () + +/*! @function + @abstract Destroy a hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + */ +#define kh_destroy(name, h) kh_destroy_##name (h) + +/*! @function + @abstract Reset a hash table without deallocating memory. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + */ +#define kh_clear(name, h) kh_clear_##name (h) + +/*! @function + @abstract Resize a hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + @param s New size [khint_t] + */ +#define kh_resize(name, h, s) kh_resize_##name (h, s) + +/*! @function + @abstract Insert a key to the hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + @param k Key [type of keys] + @param r Extra return code: -1 if the operation failed; + 0 if the key is present in the hash table; + 1 if the bucket is empty (never used); 2 if the element in + the bucket has been deleted [int*] + @return Iterator to the inserted element [khint_t] + */ +#define kh_put(name, h, k, r) kh_put_##name (h, k, r) + +/*! @function + @abstract Retrieve a key from the hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + @param k Key [type of keys] + @return Iterator to the found element, or kh_end(h) if the element is + absent [khint_t] + */ +#define kh_get(name, h, k) kh_get_##name (h, k) + +/*! @function + @abstract Remove a key from the hash table. + @param name Name of the hash table [symbol] + @param h Pointer to the hash table [khash_t(name)*] + @param k Iterator to the element to be deleted [khint_t] + */ +#define kh_del(name, h, k) kh_del_##name (h, k) + +/*! @function + @abstract Test whether a bucket contains data. + @param h Pointer to the hash table [khash_t(name)*] + @param x Iterator to the bucket [khint_t] + @return 1 if containing data; 0 otherwise [int] + */ +#define kh_exist(h, x) (!__ac_iseither ((h)->flags, (x))) + +/*! @function + @abstract Get key given an iterator + @param h Pointer to the hash table [khash_t(name)*] + @param x Iterator to the bucket [khint_t] + @return Key [type of keys] + */ +#define kh_key(h, x) ((h)->keys[x]) + +/*! @function + @abstract Get value given an iterator + @param h Pointer to the hash table [khash_t(name)*] + @param x Iterator to the bucket [khint_t] + @return Value [type of values] + @discussion For hash sets, calling this results in segfault. + */ +#define kh_val(h, x) ((h)->vals[x]) + +/*! @function + @abstract Alias of kh_val() + */ +#define kh_value(h, x) ((h)->vals[x]) + +/*! @function + @abstract Get the start iterator + @param h Pointer to the hash table [khash_t(name)*] + @return The start iterator [khint_t] + */ +#define kh_begin(h) (khint_t) (0) + +/*! @function + @abstract Get the end iterator + @param h Pointer to the hash table [khash_t(name)*] + @return The end iterator [khint_t] + */ +#define kh_end(h) ((h)->n_buckets) + +/*! @function + @abstract Get the number of elements in the hash table + @param h Pointer to the hash table [khash_t(name)*] + @return Number of elements in the hash table [khint_t] + */ +#define kh_size(h) ((h)->size) + +/*! @function + @abstract Get the number of buckets in the hash table + @param h Pointer to the hash table [khash_t(name)*] + @return Number of buckets in the hash table [khint_t] + */ +#define kh_n_buckets(h) ((h)->n_buckets) + +/*! @function + @abstract Iterate over the entries in the hash table + @param h Pointer to the hash table [khash_t(name)*] + @param kvar Variable to which key will be assigned + @param vvar Variable to which value will be assigned + @param code Block of code to execute + */ +#define kh_foreach(h, kvar, vvar, code) \ + { \ + khint_t __i; \ + for (__i = kh_begin (h); __i != kh_end (h); ++__i) \ + { \ + if (!kh_exist (h, __i)) \ + continue; \ + (kvar) = kh_key (h, __i); \ + (vvar) = kh_val (h, __i); \ + code; \ + } \ + } + +/*! @function + @abstract Iterate over the values in the hash table + @param h Pointer to the hash table [khash_t(name)*] + @param vvar Variable to which value will be assigned + @param code Block of code to execute + */ +#define kh_foreach_value(h, vvar, code) \ + { \ + khint_t __i; \ + for (__i = kh_begin (h); __i != kh_end (h); ++__i) \ + { \ + if (!kh_exist (h, __i)) \ + continue; \ + (vvar) = kh_val (h, __i); \ + code; \ + } \ + } + +/* More convenient interfaces */ + +/*! @function + @abstract Instantiate a hash set containing integer keys + @param name Name of the hash table [symbol] + */ +#define KHASH_SET_INIT_INT(name) \ + KHASH_INIT (name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal) + +/*! @function + @abstract Instantiate a hash map containing integer keys + @param name Name of the hash table [symbol] + @param khval_t Type of values [type] + */ +#define KHASH_MAP_INIT_INT(name, khval_t) \ + KHASH_INIT (name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal) + +/*! @function + @abstract Instantiate a hash set containing 64-bit integer keys + @param name Name of the hash table [symbol] + */ +#define KHASH_SET_INIT_INT64(name) \ + KHASH_INIT (name, khint64_t, char, 0, kh_int64_hash_func, \ + kh_int64_hash_equal) + +/*! @function + @abstract Instantiate a hash map containing 64-bit integer keys + @param name Name of the hash table [symbol] + @param khval_t Type of values [type] + */ +#define KHASH_MAP_INIT_INT64(name, khval_t) \ + KHASH_INIT (name, khint64_t, khval_t, 1, kh_int64_hash_func, \ + kh_int64_hash_equal) + +typedef const char *kh_cstr_t; +/*! @function + @abstract Instantiate a hash map containing const char* keys + @param name Name of the hash table [symbol] + */ +#define KHASH_SET_INIT_STR(name) \ + KHASH_INIT (name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal) + +/*! @function + @abstract Instantiate a hash map containing const char* keys + @param name Name of the hash table [symbol] + @param khval_t Type of values [type] + */ +#define KHASH_MAP_INIT_STR(name, khval_t) \ + KHASH_INIT (name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal) + +/****************************************************************************** + * Custom return codes + ******************************************************************************/ + +// RESET: same as added, but the key was already added in the past +#define foreach_kh_rc \ + _ (REPLACED) \ + _ (ADDED) \ + _ (RESET) \ + _ (NOT_FOUND) \ + _ (FOUND) \ + _ (FAIL) + +typedef enum +{ +#define _(x) KH_##x, + foreach_kh_rc +#undef _ +} kh_rc; + +/****************************************************************************** + * Custom + *high-level interface + ******************************************************************************/ + +#define _kh_var(x) _kh_var_##x + +/** + * @brief Return the value corresponding to a key in the hashtable. + * @return The value associated with the key or null if not found + */ +#define kh_get_val(kname, hashtable, key, default_val) \ + ({ \ + khiter_t _kh_var (k) = kh_get (kname, hashtable, key); \ + (_kh_var (k) != kh_end (hashtable) ? kh_val (hashtable, _kh_var (k)) : \ + default_val); \ + }) + +/** + * @brief Add key/value pair in the hashtable. + * @return 0 if an existing value (corresponding to the provided key) + * has been replaced; 1 if a new key/value pair has been added + * (the key was not already present in the hash table); + * 2 if a new key/value pair has been added in correspondence + * of a key previously deleted key + */ +#define kh_put_val(kname, hashtable, key, val) \ + ({ \ + int _kh_var (ret); \ + khiter_t _kh_var (k) = kh_put (kname, hashtable, key, &_kh_var (ret)); \ + kh_value (hashtable, _kh_var (k)) = val; \ + _kh_var (ret); \ + }) + +/** + * @brief Remove a key/value pair from the hashtable. + * @return void + */ +#define kh_remove_val(kname, hashtable, key) \ + ({ \ + khiter_t _kh_var (k) = kh_get (kname, hashtable, key); \ + if (_kh_var (k) != kh_end (hashtable)) \ + { \ + free ((void *) kh_key (hashtable, _kh_var (k))); \ + kh_del (kname, hashtable, _kh_var (k)); \ + } \ + }) + +/** + * @brief Free the hashtable. + * @return void + */ +#define kh_free(kname, hashtable) \ + ({ \ + const void *_kh_var (key); \ + unsigned _kh_var (val); \ + (void) _kh_var (val); \ + \ + kh_foreach (hashtable, _kh_var (key), _kh_var (val), { \ + free ((void *) _kh_var (key)); \ + }) kh_destroy (kname, hashtable); \ + }) + +#endif /* __AC_KHASH_H */ diff --git a/hicn-light/src/hicn/base/pool.h b/lib/includes/hicn/util/pool.h index b6573195c..7488e08fd 100644 --- a/hicn-light/src/hicn/base/pool.h +++ b/lib/includes/hicn/util/pool.h @@ -47,22 +47,24 @@ #include <stdbool.h> #include "bitmap.h" -#include "vector.h" +#include <hicn/util/vector.h> +#include "../common.h" /* Pool header */ -typedef struct { +typedef struct +{ size_t elt_size; size_t alloc_size; size_t max_size; bitmap_t *free_bitmap; /* bitmap of free indices */ - off_t *free_indices; /* vector of free indices */ + off_t *free_indices; /* vector of free indices */ } pool_hdr_t; -#define POOL_HDRLEN SIZEOF_ALIGNED(pool_hdr_t) +#define POOL_HDRLEN SIZEOF_ALIGNED (pool_hdr_t) /* This header actually prepends the actual content of the pool. */ -#define pool_hdr(pool) ((pool_hdr_t *)((uint8_t *)(pool)-POOL_HDRLEN)) +#define pool_hdr(pool) ((pool_hdr_t *) ((uint8_t *) (pool) -POOL_HDRLEN)) /******************************************************************************/ /* Helpers */ @@ -79,15 +81,15 @@ typedef struct { * * NOTE: that an empty pool might be equal to NULL. */ -void _pool_init(void **pool_ptr, size_t elt_size, size_t init_size, - size_t max_size); +void _pool_init (void **pool_ptr, size_t elt_size, size_t init_size, + size_t max_size); /** * @brief Free a pool data structure (helper). * * @param[in] pool_ptr Pointer to the pool data structure. */ -void _pool_free(void **pool_ptr); +void _pool_free (void **pool_ptr); /** * @brief Resize a pool data structure (helper). @@ -97,7 +99,7 @@ void _pool_free(void **pool_ptr); * This function should only be called internally, as the resize is implicitly * done (if allowed by the maximum size) when the user tries to get a new slot. */ -void _pool_resize(void **pool_ptr, size_t elt_size); +void _pool_resize (void **pool_ptr, size_t elt_size); /** * @brief Get a free element from the pool data structure (helper). @@ -109,7 +111,7 @@ void _pool_resize(void **pool_ptr, size_t elt_size); * NOTES: * - The memory chunk is cleared upon attribution */ -off_t _pool_get(void **pool, void **elt, size_t elt_size); +off_t _pool_get (void **pool, void **elt, size_t elt_size); /** * @brief Put an element back into the pool data structure (helper). @@ -117,7 +119,7 @@ off_t _pool_get(void **pool, void **elt, size_t elt_size); * @param[in] pool_ptr Pointer to the pool data structure to use. * @param[in] elt Pointer to the pool element to put back. */ -void _pool_put(void **pool, void **elt, size_t elt_size); +void _pool_put (void **pool, void **elt, size_t elt_size); /** * @brief Validate a pool element by index (helper). @@ -127,7 +129,7 @@ void _pool_put(void **pool, void **elt, size_t elt_size); * * @return bool A flag indicating whether the index is valid or not. */ -bool _pool_validate_id(void **pool_ptr, off_t id); +bool _pool_validate_id (void **pool_ptr, off_t id); /******************************************************************************/ /* Public API */ @@ -140,15 +142,15 @@ bool _pool_validate_id(void **pool_ptr, off_t id); * * NOTE: that an empty pool might be equal to NULL. */ -#define pool_init(pool, init_size, max_size) \ - _pool_init((void **)&pool, sizeof(pool[0]), init_size, max_size); +#define pool_init(pool, init_size, max_size) \ + _pool_init ((void **) &pool, sizeof (pool[0]), init_size, max_size); /** * @brief Free a pool data structure. * * @param[in] pool The pool data structure to free. */ -#define pool_free(pool) _pool_free((void **)&pool); +#define pool_free(pool) _pool_free ((void **) &pool); /** * @brief Get a free element from the pool data structure. @@ -160,8 +162,8 @@ bool _pool_validate_id(void **pool_ptr, off_t id); * NOTES: * - The memory chunk is cleared upon attribution */ -#define pool_get(pool, elt) \ - _pool_get((void **)&pool, (void **)&elt, sizeof(*elt)) +#define pool_get(pool, elt) \ + _pool_get ((void **) &pool, (void **) &elt, sizeof (*elt)) /** * @brief Put an element back into the pool data structure. @@ -169,8 +171,8 @@ bool _pool_validate_id(void **pool_ptr, off_t id); * @param[in] pool The pool data structure to use. * @param[in] elt The pool element to put back. */ -#define pool_put(pool, elt) \ - _pool_put((void **)&pool, (void **)&elt, sizeof(*elt)) +#define pool_put(pool, elt) \ + _pool_put ((void **) &pool, (void **) &elt, sizeof (*elt)) /** * @brief Validate a pool element by index. @@ -180,10 +182,10 @@ bool _pool_validate_id(void **pool_ptr, off_t id); * * @return bool A flag indicating whether the index is valid or not. */ -#define pool_validate_id(pool, id) _pool_validate_id((void **)&pool, (id)) +#define pool_validate_id(pool, id) _pool_validate_id ((void **) &pool, (id)) -#define pool_get_free_indices_size(pool) \ - vector_len(pool_hdr(pool)->free_indices) +#define pool_get_free_indices_size(pool) \ + vector_len (pool_hdr (pool)->free_indices) /** * @brief Returns the current length of the pool. @@ -196,8 +198,8 @@ bool _pool_validate_id(void **pool_ptr, off_t id); * - The pool length corresponds to the number of allocated elements, not the * size of the pool. */ -#define pool_len(pool) \ - (pool_hdr(pool)->alloc_size - pool_get_free_indices_size(pool)) +#define pool_len(pool) \ + (pool_hdr (pool)->alloc_size - pool_get_free_indices_size (pool)) /** * @brief Enumerate elements from a pool. @@ -213,18 +215,24 @@ bool _pool_validate_id(void **pool_ptr, off_t id); * * NOTE: i stars at 0. */ -#define pool_enumerate(pool, i, eltp, BODY) \ - do { \ - pool_hdr_t *_pool_var(ph) = pool_hdr(pool); \ - bitmap_t *_pool_var(fb) = _pool_var(ph)->free_bitmap; \ - for ((i) = 0; (i) < _pool_var(ph)->alloc_size; (i)++) { \ - if (bitmap_is_set(_pool_var(fb), (i))) continue; \ - eltp = (pool) + (i); \ - do { \ - BODY; \ - } while (0); \ - } \ - } while (0) +#define pool_enumerate(pool, i, eltp, BODY) \ + do \ + { \ + pool_hdr_t *_pool_var (ph) = pool_hdr (pool); \ + bitmap_t *_pool_var (fb) = _pool_var (ph)->free_bitmap; \ + for ((i) = 0; (i) < _pool_var (ph)->alloc_size; (i)++) \ + { \ + if (bitmap_is_set (_pool_var (fb), (i))) \ + continue; \ + eltp = (pool) + (i); \ + do \ + { \ + BODY; \ + } \ + while (0); \ + } \ + } \ + while (0) /** * @brief Iterate over elements in a pool. @@ -238,17 +246,19 @@ bool _pool_validate_id(void **pool_ptr, off_t id); * elements found in the pool. It is implemented using the more generic * enumeration function. */ -#define pool_foreach(pool, eltp, BODY) \ - do { \ - unsigned _pool_var(i); \ - pool_enumerate((pool), _pool_var(i), (eltp), BODY); \ - } while (0) +#define pool_foreach(pool, eltp, BODY) \ + do \ + { \ + unsigned _pool_var (i); \ + pool_enumerate ((pool), _pool_var (i), (eltp), BODY); \ + } \ + while (0) -#define pool_get_alloc_size(pool) pool_hdr(pool)->alloc_size +#define pool_get_alloc_size(pool) pool_hdr (pool)->alloc_size #ifdef WITH_TESTS -#define pool_get_free_indices(pool) pool_hdr(pool)->free_indices -#define pool_get_free_bitmap(pool) pool_hdr(pool)->free_bitmap +#define pool_get_free_indices(pool) pool_hdr (pool)->free_indices +#define pool_get_free_bitmap(pool) pool_hdr (pool)->free_bitmap #endif /* WITH_TESTS */ #endif /* UTIL_POOL_H */ diff --git a/lib/includes/hicn/util/ring.h b/lib/includes/hicn/util/ring.h new file mode 100644 index 000000000..9510672b3 --- /dev/null +++ b/lib/includes/hicn/util/ring.h @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file ring.h + * \brief Fixed-size pool allocator. + */ + +#ifndef UTIL_RING_H +#define UTIL_RING_H + +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include <sys/param.h> // MIN +#include <sys/types.h> + +#include <stdio.h> // XXX debug + +#include "../common.h" + +/******************************************************************************/ +/* Ring header */ + +typedef struct +{ + size_t roff; + size_t woff; + size_t size; + size_t max_size; +} ring_hdr_t; + +/* Make sure elements following the header are aligned */ +#define RING_HDRLEN SIZEOF_ALIGNED (ring_hdr_t) + +/* This header actually prepends the actual content of the vector */ +#define ring_hdr(ring) ((ring_hdr_t *) ((uint8_t *) ring - RING_HDRLEN)) + +/******************************************************************************/ +/* Helpers */ + +/** Local variable naming macro. */ +#define _ring_var(v) _ring_##v + +/** + * @brief Allocate and initialize a ring data structure (helper function). + * + * @param[in,out] ring_ptr Ring buffer to allocate and initialize. + * @param[in] elt_size Size of a ring element. + * @param[in] max_size Maximum vector size (O = unlimited). + */ +void _ring_init (void **ring_ptr, size_t elt_size, size_t max_size); + +/** + * @brief Free a ring data structure. + * + * @param ring_ptr[in] Pointer to the ring data structure to free. + */ +void _ring_free (void **ring_ptr); + +static inline int +_ring_add (void **ring_ptr, size_t elt_size, void *eltp) +{ + assert (*ring_ptr); + ring_hdr_t *rh = ring_hdr (*ring_ptr); + + /* We always write ! */ + memcpy ((uint8_t *) *ring_ptr + rh->woff * elt_size, eltp, elt_size); + rh->woff++; + if (rh->woff == rh->max_size) + rh->woff = 0; + if (rh->size < rh->max_size) + { + rh->size++; + } + else + { + /* One packet was dropped */ + rh->roff++; + if (rh->roff == rh->max_size) + rh->roff = 0; + } + return 0; +} + +static inline unsigned +_ring_get_fullness (void **ring_ptr) +{ + assert (*ring_ptr); + ring_hdr_t *rh = ring_hdr (*ring_ptr); + return (unsigned int) (rh->size * 100 / rh->max_size); +} + +static inline unsigned +_ring_is_full (void **ring_ptr) +{ + assert (*ring_ptr); + ring_hdr_t *rh = ring_hdr (*ring_ptr); + return rh->size == rh->max_size; +} + +static inline size_t +_ring_get_size (void **ring_ptr) +{ + assert (*ring_ptr); + ring_hdr_t *rh = ring_hdr (*ring_ptr); + return rh->size; +} + +static inline int +_ring_advance (void **ring_ptr, unsigned n) +{ + assert (*ring_ptr); + ring_hdr_t *rh = ring_hdr (*ring_ptr); + assert (n <= rh->size); + + rh->roff += n; + rh->size -= n; + while (rh->roff >= rh->max_size) + rh->roff -= rh->max_size; + return 0; +} + +static inline int +_ring_get (void **ring_ptr, size_t elt_size, unsigned i, void *eltp) +{ + assert (*ring_ptr); + ring_hdr_t *rh = ring_hdr (*ring_ptr); + assert (i <= rh->size); + size_t pos = rh->roff + i; + if (pos >= rh->max_size) + pos -= rh->max_size; + memcpy (eltp, (uint8_t *) *ring_ptr + pos * elt_size, elt_size); + return 0; +} + +/******************************************************************************/ +/* Public API */ + +/** + * @brief Allocate and initialize a ring data structure. + * + * @param[in,out] ring Ring to allocate and initialize. + * @param[in] max_size Maximum ring size (nonzero). + * + * NOTE: + * - Allocated memory is set to 0 (used by bitmap) + */ + +#define ring_init(RING, MAX_SIZE) \ + _ring_init ((void **) &(RING), sizeof ((RING)[0]), (MAX_SIZE)) + +#define ring_free(RING) _ring_free ((void **) &(RING)) + +#define ring_get_fullness(RING) _ring_get_fullness ((void **) &(RING)) + +#define ring_is_full(RING) _ring_is_full ((void **) &(RING)) + +#define ring_get_size(RING) _ring_get_size ((void **) &(RING)) + +#define ring_add(RING, ELT) \ + _ring_add ((void **) &(RING), sizeof (RING[0]), ELT) + +#define ring_add_value(RING, VALUE) \ + do \ + { \ + typeof (VALUE) _ring_var (v) = VALUE; \ + _ring_add ((void **) &(RING), sizeof (RING[0]), &_ring_var (v)); \ + } \ + while (0) + +#define ring_advance(RING, N) _ring_advance ((void **) &(RING), (N)) + +#define ring_get(RING, I, ELTP) \ + _ring_get ((void **) &RING, sizeof (RING[0]), (I), (ELTP)) + +/** + * @brief Helper function used by ring_foreach(). + */ +#define ring_enumerate_n(RING, I, ELTP, COUNT, BODY) \ + ({ \ + for ((I) = 0; (I) < MIN (ring_get_size (RING), (COUNT)); (I)++) \ + { \ + ring_get ((RING), (I), (ELTP)); \ + { \ + BODY; \ + } \ + } \ + }) + +#define ring_enumerate(ring, i, eltp, BODY) \ + ring_enumerate_n ((ring), (i), (eltp), 1, (BODY)) + +/** + * @brief Iterate over elements in a ring. + * + * @param[in] pool The ring data structure to iterate over + * @param[in, out] eltp A pointer to the element that will be used for + * iteration + * @param[in] BODY Block to execute during iteration + * + * @note Iteration will execute BODY with eltp corresponding successively to + * all elements found in the ring. It is implemented using the more generic + * enumeration function. + */ +#define ring_foreach_n(ring, eltp, count, BODY) \ + ({ \ + unsigned _ring_var (i); \ + ring_enumerate_n ((ring), _ring_var (i), (eltp), (count), BODY); \ + }) + +#define ring_foreach(ring, eltp, BODY) \ + ring_foreach_n ((ring), (eltp), 1, (BODY)) + +#endif /* UTIL_RING_H */ diff --git a/hicn-light/src/hicn/base/vector.h b/lib/includes/hicn/util/vector.h index 0b7a74aeb..46f195c6d 100644 --- a/hicn-light/src/hicn/base/vector.h +++ b/lib/includes/hicn/util/vector.h @@ -50,24 +50,27 @@ #include <stdint.h> #include <string.h> #include <sys/types.h> +#include <stdbool.h> -#include "common.h" +#include "../common.h" /******************************************************************************/ /* Vector header */ -typedef struct { +typedef struct +{ size_t cur_size; /** Vector current size (corresponding to the highest used - element). */ + element). */ size_t alloc_size; /** The currently allocated size. */ size_t max_size; /** The maximum allowed size (0 = no limit) */ } vector_hdr_t; /* Make sure elements following the header are aligned */ -#define VECTOR_HDRLEN SIZEOF_ALIGNED(vector_hdr_t) +#define VECTOR_HDRLEN SIZEOF_ALIGNED (vector_hdr_t) /* This header actually prepends the actual content of the vector */ -#define vector_hdr(vector) ((vector_hdr_t *)((uint8_t *)vector - VECTOR_HDRLEN)) +#define vector_hdr(vector) \ + ((vector_hdr_t *) ((uint8_t *) vector - VECTOR_HDRLEN)) /******************************************************************************/ /* Helpers */ @@ -82,16 +85,17 @@ typedef struct { * @param[in] elt_size Size of a vector element. * @param[in] init_size Initial vector size. * @param[in] max_size Maximum vector size (O = unlimited). + * @return int 0 if successful, -1 otherwise */ -void _vector_init(void **vector_ptr, size_t elt_size, size_t init_size, - size_t max_size); +int _vector_init (void **vector_ptr, size_t elt_size, size_t init_size, + size_t max_size); /** * @brief Free a vector data structure. * * @param vector_ptr[in] Pointer to the vector data structure to free. */ -void _vector_free(void **vector_ptr); +void _vector_free (void **vector_ptr); /** * @brief Resize a vector data structure. @@ -109,7 +113,7 @@ void _vector_free(void **vector_ptr); * position. This allows the caller not to care about doing successive calls to * this API while the vector is growing in size. */ -int _vector_resize(void **vector_ptr, size_t elt_size, off_t pos); +int _vector_resize (void **vector_ptr, size_t elt_size, off_t pos); /** * @brief Ensures a vector is sufficiently large to hold an element at the @@ -127,11 +131,12 @@ int _vector_resize(void **vector_ptr, size_t elt_size, off_t pos); * - This function can fail if the vector is full and for any reason it cannot * be resized. */ -static inline int _vector_ensure_pos(void **vector_ptr, size_t elt_size, - off_t pos) { - vector_hdr_t *vh = vector_hdr(*vector_ptr); - if (pos >= (off_t)vh->alloc_size) - return _vector_resize(vector_ptr, elt_size, pos + 1); +static inline int +_vector_ensure_pos (void **vector_ptr, size_t elt_size, off_t pos) +{ + vector_hdr_t *vh = vector_hdr (*vector_ptr); + if (pos >= (off_t) vh->alloc_size) + return _vector_resize (vector_ptr, elt_size, pos + 1); return 0; } @@ -147,14 +152,17 @@ static inline int _vector_ensure_pos(void **vector_ptr, size_t elt_size, * and evenutually resizes the vector to make room for it (if allowed by * maximum size). */ -static inline int _vector_push(void **vector_ptr, size_t elt_size, void *elt) { - vector_hdr_t *vh = vector_hdr(*vector_ptr); - if (_vector_ensure_pos(vector_ptr, elt_size, vh->cur_size) < 0) return -1; +static inline int +_vector_push (void **vector_ptr, size_t elt_size, void *elt) +{ + vector_hdr_t *vh = vector_hdr (*vector_ptr); + if (_vector_ensure_pos (vector_ptr, elt_size, vh->cur_size) < 0) + return -1; /* Always get header after a potential resize */ - vh = vector_hdr(*vector_ptr); - memcpy((uint8_t *)*vector_ptr + vh->cur_size * elt_size, elt, elt_size); - vh = vector_hdr(*vector_ptr); + vh = vector_hdr (*vector_ptr); + memcpy ((uint8_t *) *vector_ptr + vh->cur_size * elt_size, elt, elt_size); + vh = vector_hdr (*vector_ptr); vh->cur_size++; return 0; } @@ -168,19 +176,91 @@ static inline int _vector_push(void **vector_ptr, size_t elt_size, void *elt) { * @param[in] elt The element to remove * @return int Number of elemets (equal to 'elt') removed from the vector */ -static inline int _vector_remove_unordered(void *vector, size_t elt_size, - void *elt) { +static inline int +_vector_remove_unordered (void *vector, size_t elt_size, void *elt) +{ size_t num_removed = 0; - vector_hdr_t *vh = vector_hdr(vector); - for (size_t i = 0; i < vector_hdr(vector)->cur_size; i++) { - if (memcmp((uint8_t *)vector + i * elt_size, elt, elt_size) == 0) { - vh->cur_size--; - memcpy((uint8_t *)vector + i * elt_size, - (uint8_t *)vector + vh->cur_size * elt_size, elt_size); - num_removed++; + vector_hdr_t *vh = vector_hdr (vector); + for (size_t i = 0; i < vector_hdr (vector)->cur_size; i++) + { + if (memcmp ((uint8_t *) vector + i * elt_size, elt, elt_size) == 0) + { + vh->cur_size--; + // Copy last element to current position (hence order is not + // maintained) + memcpy ((uint8_t *) vector + i * elt_size, + (uint8_t *) vector + vh->cur_size * elt_size, elt_size); + num_removed++; + } } - } - return num_removed; + return (int) num_removed; +} + +/** + * @brief Get the element at the specified position and store in 'elt'. + * + * @param[in] vector Pointer to the vector data structure to use + * @param[in] pos Position of the element to retrieve + * @param[in] elt_size The size of a vector element + * @param[in] elt The element where the result is stored + * @return int 0 if successful, -1 otherwise + */ +static inline int +_vector_get (void *vector, off_t pos, size_t elt_size, void *elt) +{ + vector_hdr_t *vh = vector_hdr (vector); + if (pos >= vh->alloc_size) + return -1; + + memcpy (elt, (uint8_t *) vector + pos * elt_size, elt_size); + return 0; +} + +/** + * @brief Check if specified element is present in vector. + * + * @param[in] vector Pointer to the vector data structure to use + * @param[in] elt_size The size of a vector element + * @param[in] elt The element to search for + * @return true If specified element is contained in the vector + * @return false + */ +static inline bool +_vector_contains (void *vector, size_t elt_size, void *elt) +{ + for (int i = 0; i < vector_hdr (vector)->cur_size; i++) + { + if (memcmp ((uint8_t *) vector + i * elt_size, elt, elt_size) == 0) + return true; + } + + return false; +} + +/** + * @brief Remove the element at the specified position from the vector. + * Relative element order is preserved by shifting left the elements after the + * target. + * + * @param[in, out] vector Pointer to the vector data structure to use + * @param[in] elt_size The size of a vector element + * @param[in] pos Position of the element to remove + * @return int 0 if successful, -1 otherwise + */ +static inline int +_vector_remove_at (void **vector_ptr, size_t elt_size, off_t pos) +{ + vector_hdr_t *vh = vector_hdr (*vector_ptr); + if (pos >= vh->cur_size) + return -1; + + // Shift backward by one position all the elements after the one specified + memmove ((uint8_t *) (*vector_ptr) + pos * elt_size, + (uint8_t *) (*vector_ptr) + (pos + 1) * elt_size, + (vh->cur_size - 1 - pos) * elt_size); + vh->cur_size--; + + return 0; } /******************************************************************************/ @@ -197,15 +277,15 @@ static inline int _vector_remove_unordered(void *vector, size_t elt_size, * - Allocated memory is set to 0 (used by bitmap) */ -#define vector_init(vector, init_size, max_size) \ - _vector_init((void **)&vector, sizeof(vector[0]), init_size, max_size) +#define vector_init(vector, init_size, max_size) \ + _vector_init ((void **) &vector, sizeof (vector[0]), init_size, max_size) /** * @brief Free a vector data structure. * * @param[in] vector The vector data structure to free. */ -#define vector_free(vector) _vector_free((void **)&vector) +#define vector_free(vector) _vector_free ((void **) &vector) /** * @brief Resize a vector data structure. @@ -225,8 +305,8 @@ static inline int _vector_remove_unordered(void *vector, size_t elt_size, * vector will be truncated. * - Newly allocated memory is set to 0 (used by bitmap) */ -#define vector_resize(vector) \ - _vector_resize((void **)&(vector), sizeof((vector)[0]), 0) +#define vector_resize(vector) \ + _vector_resize ((void **) &(vector), sizeof ((vector)[0]), 0) /** * @brief Ensures a vector is sufficiently large to hold an element at the @@ -239,8 +319,8 @@ static inline int _vector_remove_unordered(void *vector, size_t elt_size, * - This function should always be called before writing to a vector element * to eventually make room for it (the vector will eventually be resized). */ -#define vector_ensure_pos(vector, pos) \ - _vector_ensure_pos((void **)&(vector), sizeof((vector)[0]), pos); +#define vector_ensure_pos(vector, pos) \ + _vector_ensure_pos ((void **) &(vector), sizeof ((vector)[0]), pos); /** * @brief Push an element at the end of a vector. @@ -253,13 +333,73 @@ static inline int _vector_remove_unordered(void *vector, size_t elt_size, * and evenutually resizes the vector to make room for it (if allowed by * maximum size). */ -#define vector_push(vector, elt) \ - ({ \ - typeof(elt) x = elt; \ - _vector_push((void **)&(vector), sizeof((vector)[0]), (void *)(&x)); \ +#define vector_push(vector, elt) \ + ({ \ + typeof (elt) _vector_var (x) = elt; \ + _vector_push ((void **) &(vector), sizeof ((vector)[0]), \ + (void *) (&_vector_var (x))); \ + }) + +#define vector_at(vector, pos) \ + ({ \ + assert (pos < vector_hdr (vector)->cur_size); \ + (vector)[(pos)]; \ + }) + +#define vector_set(vector, pos, elt) \ + ({ \ + assert (pos < vector_hdr (vector)->cur_size); \ + (vector)[(pos)] = elt; \ }) /** + * @brief Clear the vector content, i.e. new pushes will insert starting from + * position 0. + * + * @param[in, out] vector The vector to reset + */ +#define vector_reset(vector) (vector_len (vector) = 0) + +/** + * @brief Get the element at the specified position and store in 'elt'. + * + * @param[in] vector The vector data structure to use + * @param[in] pos Position of the element to retrieve + * @param[in] elt The element where the result is stored + * @return int 0 if successful, -1 otherwise + */ +#define vector_get(vector, pos, elt) \ + _vector_get ((void *) (vector), (pos), sizeof ((vector)[0]), \ + (void *) (&elt)); + +/** + * @brief Check if specified element is present in vector. + * + * @param[in] vector The vector data structure to use + * @param[in] elt The element to search for + * @return true If specified element is contained in the vector + * @return false + */ +#define vector_contains(vector, elt) \ + ({ \ + typeof (elt) _vector_var (x) = elt; \ + _vector_contains ((void *) (vector), sizeof ((vector)[0]), \ + (void *) (&_vector_var (x))); \ + }) + +/** + * @brief Remove the element at the specified position from the vector. + * Relative element order is preserved by shifting left the elements after the + * target. + * + * @param[in, out] vector The vector data structure to use + * @param[in] pos Position of the element to remove + * @return int 0 if successful, -1 otherwise + */ +#define vector_remove_at(vector, pos) \ + _vector_remove_at ((void **) &(vector), sizeof ((vector)[0]), (pos)) + +/** * @brief Remove all the occurrencies of an element from the vector. * The order of the elements is NOT maintained. * @@ -267,11 +407,11 @@ static inline int _vector_remove_unordered(void *vector, size_t elt_size, * @param[in] elt The element to remove * @return int Number of elemets (equal to 'elt') removed from the vector */ -#define vector_remove_unordered(vector, elt) \ - ({ \ - typeof(elt) x = elt; \ - _vector_remove_unordered((void *)(vector), sizeof((vector)[0]), \ - (void *)(&x)); \ +#define vector_remove_unordered(vector, elt) \ + ({ \ + typeof (elt) x = elt; \ + _vector_remove_unordered ((void *) (vector), sizeof ((vector)[0]), \ + (void *) (&x)); \ }) /** @@ -288,12 +428,12 @@ static inline int _vector_remove_unordered(void *vector, size_t elt_size, * - A user should always call vector_ensure_pos to ensure the vector is * sufficiently large to hold an element at the specified position. */ -#define vector_len(vector) vector_hdr(vector)->cur_size +#define vector_len(vector) vector_hdr (vector)->cur_size /** * @brief Returns the allocated size of a vector. */ -#define vector_get_alloc_size(vector) vector_hdr(vector)->alloc_size +#define vector_get_alloc_size(vector) vector_hdr (vector)->alloc_size /** * @brief Iterate over elements in a vector. @@ -303,25 +443,28 @@ static inline int _vector_remove_unordered(void *vector, size_t elt_size, * iteration * @param[in] BODY Block to execute during iteration * - * @note Iteration will execute BODY with eltp corresponding successively to all - * elements found in the vector. It is implemented using the more generic + * @note Iteration will execute BODY with eltp corresponding successively to + * all elements found in the vector. It is implemented using the more generic * enumeration function. */ -#define vector_foreach(vector, eltp, BODY) \ - ({ \ - unsigned _vector_var(i); \ - vector_enumerate((vector), _vector_var(i), (eltp), BODY); \ +#define vector_foreach(vector, eltp, BODY) \ + ({ \ + unsigned _vector_var (i); \ + vector_enumerate ((vector), _vector_var (i), (eltp), BODY); \ }) /** * @brief Helper function used by vector_foreach(). */ -#define vector_enumerate(vector, i, eltp, BODY) \ - ({ \ - for ((i) = 0; (i) < vector_len(vector); (i)++) { \ - eltp = (vector) + (i); \ - { BODY; } \ - } \ +#define vector_enumerate(vector, i, eltp, BODY) \ + ({ \ + for ((i) = 0; (i) < vector_len (vector); (i)++) \ + { \ + eltp = (vector) + (i); \ + { \ + BODY; \ + } \ + } \ }) #endif /* UTIL_VECTOR_H */ diff --git a/lib/src/CMakeLists.txt b/lib/src/CMakeLists.txt index ef74127cc..8e81aa442 100644 --- a/lib/src/CMakeLists.txt +++ b/lib/src/CMakeLists.txt @@ -33,6 +33,9 @@ list(APPEND LIBHICN_SOURCE_FILES protocol/new.c util/ip_address.c util/log.c + util/pool.c + util/ring.c + util/vector.c ) if (WIN32) diff --git a/lib/src/common.c b/lib/src/common.c index c4cb8bc3e..362034942 100644 --- a/lib/src/common.c +++ b/lib/src/common.c @@ -54,61 +54,44 @@ get_addr_family (const char *ip_address) /* hashes */ -u32 -cumulative_hash32 (const void *data, size_t len, u32 lastValue) +// FNV-1a 32-bit http://www.isthe.com/chongo/tech/comp/fnv/ +typedef u_int32_t Fnv32_t; +#define FNV_32_PRIME ((Fnv32_t) 0x01000193) +#define FNV1_32_INIT ((Fnv32_t) 0x811c9dc5) +#define FNV1_32A_INIT FNV1_32_INIT + +Fnv32_t +cumulative_hash32 (const void *buf, size_t len, Fnv32_t hval) { - // Standard FNV 32-bit prime: see - // http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param - const u32 fnv1a_prime = 0x01000193; - u32 hash = lastValue; - size_t i; - - const char *chardata = data; + unsigned char *bp = (unsigned char *) buf; /* start of buffer */ + unsigned char *be = bp + len; /* beyond end of buffer */ - for (i = 0; i < len; i++) + /* + * FNV-1a hash each octet in the buffer + */ + while (bp < be) { - hash = hash ^ chardata[i]; - hash = hash * fnv1a_prime; - } - return hash; -} + /* xor the bottom with the current octet */ + hval ^= (Fnv32_t) *bp++; -u32 -hash32 (const void *data, size_t len) -{ - // Standard FNV 32-bit offset: see - // http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param - const u32 fnv1a_offset = 0x811C9DC5; - return cumulative_hash32 (data, len, fnv1a_offset); -} - -u64 -cumulative_hash64 (const void *data, size_t len, u64 lastValue) -{ - // Standard FNV 64-bit prime: see - // http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param - const u64 fnv1a_prime = 0x00000100000001B3ULL; - u64 hash = lastValue; - const char *chardata = data; - size_t i; - - for (i = 0; i < len; i++) - { - hash = hash ^ chardata[i]; - hash = hash * fnv1a_prime; + /* multiply by the 32 bit FNV magic prime mod 2^32 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_32_PRIME; +#else + hval += + (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); +#endif } - return hash; + /* return our new hash value */ + return hval; } -u64 -hash64 (const void *data, size_t len) +u32 +hash32 (const void *data, size_t len) { - // Standard FNV 64-bit offset: see - // http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param - const u64 fnv1a_offset = 0xCBF29CE484222325ULL; - return cumulative_hash64 (data, len, fnv1a_offset); + return cumulative_hash32 (data, len, FNV1_32A_INIT); } void diff --git a/lib/src/ops.c b/lib/src/ops.c index 80ffcf3c5..20362d69d 100644 --- a/lib/src/ops.c +++ b/lib/src/ops.c @@ -57,6 +57,10 @@ DECLARE_update_data_pathlabel (none, NONE); DECLARE_reset_data_for_hash (none, NONE); DECLARE_get_lifetime (none, NONE); DECLARE_set_lifetime (none, NONE); +DECLARE_get_source_port (none, NONE); +DECLARE_get_dest_port (none, NONE); +DECLARE_set_source_port (none, NONE); +DECLARE_set_dest_port (none, NONE); DECLARE_update_checksums (none, NONE); DECLARE_verify_checksums (none, NONE); DECLARE_rewrite_interest (none, NONE); diff --git a/lib/src/protocol/ah.c b/lib/src/protocol/ah.c index b3d24161d..c9ed40179 100644 --- a/lib/src/protocol/ah.c +++ b/lib/src/protocol/ah.c @@ -45,6 +45,10 @@ DECLARE_set_data_pathlabel (ah, UNEXPECTED); DECLARE_update_data_pathlabel (ah, UNEXPECTED); DECLARE_get_lifetime (ah, UNEXPECTED); DECLARE_set_lifetime (ah, UNEXPECTED); +DECLARE_get_source_port (ah, UNEXPECTED); +DECLARE_get_dest_port (ah, UNEXPECTED); +DECLARE_set_source_port (ah, UNEXPECTED); +DECLARE_set_dest_port (ah, UNEXPECTED); DECLARE_get_payload_length (ah, UNEXPECTED); DECLARE_set_payload_length (ah, UNEXPECTED); DECLARE_get_payload_type (ah, UNEXPECTED); diff --git a/lib/src/protocol/icmp.c b/lib/src/protocol/icmp.c index 0452e4fbb..1fc6c7d2f 100644 --- a/lib/src/protocol/icmp.c +++ b/lib/src/protocol/icmp.c @@ -38,6 +38,10 @@ DECLARE_set_data_pathlabel (icmp, UNEXPECTED); DECLARE_update_data_pathlabel (icmp, UNEXPECTED); DECLARE_get_lifetime (icmp, UNEXPECTED); DECLARE_set_lifetime (icmp, UNEXPECTED); +DECLARE_get_source_port (icmp, UNEXPECTED); +DECLARE_get_dest_port (icmp, UNEXPECTED); +DECLARE_set_source_port (icmp, UNEXPECTED); +DECLARE_set_dest_port (icmp, UNEXPECTED); DECLARE_get_length (icmp, UNEXPECTED); DECLARE_get_payload_length (icmp, UNEXPECTED); DECLARE_set_payload_length (icmp, UNEXPECTED); diff --git a/lib/src/protocol/ipv4.c b/lib/src/protocol/ipv4.c index 5d445f018..840fbe34b 100644 --- a/lib/src/protocol/ipv4.c +++ b/lib/src/protocol/ipv4.c @@ -228,6 +228,31 @@ ipv4_set_lifetime (hicn_type_t type, hicn_protocol_t *h, } int +ipv4_get_source_port (hicn_type_t type, const hicn_protocol_t *h, + u16 *source_port) +{ + return CHILD_OPS (get_source_port, type, h, source_port); +} + +int +ipv4_get_dest_port (hicn_type_t type, const hicn_protocol_t *h, u16 *dest_port) +{ + return CHILD_OPS (get_dest_port, type, h, dest_port); +} + +int +ipv4_set_source_port (hicn_type_t type, hicn_protocol_t *h, u16 source_port) +{ + return CHILD_OPS (set_source_port, type, h, source_port); +} + +int +ipv4_set_dest_port (hicn_type_t type, hicn_protocol_t *h, u16 dest_port) +{ + return CHILD_OPS (set_dest_port, type, h, dest_port); +} + +int ipv4_update_checksums (hicn_type_t type, hicn_protocol_t *h, u16 partial_csum, size_t payload_length) { diff --git a/lib/src/protocol/ipv6.c b/lib/src/protocol/ipv6.c index b3a107a13..b3c543249 100644 --- a/lib/src/protocol/ipv6.c +++ b/lib/src/protocol/ipv6.c @@ -212,6 +212,31 @@ ipv6_set_lifetime (hicn_type_t type, hicn_protocol_t *h, } int +ipv6_get_source_port (hicn_type_t type, const hicn_protocol_t *h, + u16 *source_port) +{ + return CHILD_OPS (get_source_port, type, h, source_port); +} + +int +ipv6_get_dest_port (hicn_type_t type, const hicn_protocol_t *h, u16 *dest_port) +{ + return CHILD_OPS (get_dest_port, type, h, dest_port); +} + +int +ipv6_set_source_port (hicn_type_t type, hicn_protocol_t *h, u16 source_port) +{ + return CHILD_OPS (set_source_port, type, h, source_port); +} + +int +ipv6_set_dest_port (hicn_type_t type, hicn_protocol_t *h, u16 dest_port) +{ + return CHILD_OPS (set_dest_port, type, h, dest_port); +} + +int ipv6_update_checksums (hicn_type_t type, hicn_protocol_t *h, u16 partial_csum, size_t payload_length) { diff --git a/lib/src/protocol/new.c b/lib/src/protocol/new.c index 8c79963ad..07c1d0d76 100644 --- a/lib/src/protocol/new.c +++ b/lib/src/protocol/new.c @@ -22,6 +22,11 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" +DECLARE_get_source_port (new, UNEXPECTED); +DECLARE_get_dest_port (new, UNEXPECTED); +DECLARE_set_source_port (new, UNEXPECTED); +DECLARE_set_dest_port (new, UNEXPECTED); + static int is_interest (u8 flags) { diff --git a/lib/src/protocol/tcp.c b/lib/src/protocol/tcp.c index 8097cfd12..82fc461ea 100644 --- a/lib/src/protocol/tcp.c +++ b/lib/src/protocol/tcp.c @@ -251,6 +251,35 @@ tcp_set_lifetime (hicn_type_t type, hicn_protocol_t *h, } int +tcp_get_source_port (hicn_type_t type, const hicn_protocol_t *h, + u16 *source_port) +{ + *source_port = ntohs (h->tcp.sport); + return HICN_LIB_ERROR_NONE; +} + +int +tcp_get_dest_port (hicn_type_t type, const hicn_protocol_t *h, u16 *dest_port) +{ + *dest_port = ntohs (h->tcp.dport); + return HICN_LIB_ERROR_NONE; +} + +int +tcp_set_source_port (hicn_type_t type, hicn_protocol_t *h, u16 source_port) +{ + h->tcp.sport = htons (source_port); + return HICN_LIB_ERROR_NONE; +} + +int +tcp_set_dest_port (hicn_type_t type, hicn_protocol_t *h, u16 dest_port) +{ + h->tcp.dport = htons (dest_port); + return HICN_LIB_ERROR_NONE; +} + +int tcp_update_checksums (hicn_type_t type, hicn_protocol_t *h, u16 partial_csum, size_t payload_length) { diff --git a/lib/src/protocol/udp.c b/lib/src/protocol/udp.c index ee46b8e9d..7a14b09c2 100644 --- a/lib/src/protocol/udp.c +++ b/lib/src/protocol/udp.c @@ -143,6 +143,35 @@ udp_set_lifetime (hicn_type_t type, hicn_protocol_t *h, } int +udp_get_source_port (hicn_type_t type, const hicn_protocol_t *h, + u16 *source_port) +{ + *source_port = ntohs (h->udp.src_port); + return HICN_LIB_ERROR_NONE; +} + +int +udp_get_dest_port (hicn_type_t type, const hicn_protocol_t *h, u16 *dest_port) +{ + *dest_port = ntohs (h->udp.dst_port); + return HICN_LIB_ERROR_NONE; +} + +int +udp_set_source_port (hicn_type_t type, hicn_protocol_t *h, u16 source_port) +{ + h->udp.src_port = htons (source_port); + return HICN_LIB_ERROR_NONE; +} + +int +udp_set_dest_port (hicn_type_t type, hicn_protocol_t *h, u16 dest_port) +{ + h->udp.dst_port = htons (dest_port); + return HICN_LIB_ERROR_NONE; +} + +int udp_update_checksums (hicn_type_t type, hicn_protocol_t *h, u16 partial_csum, size_t payload_length) { diff --git a/lib/src/util/log.c b/lib/src/util/log.c index 975762603..91a87e848 100644 --- a/lib/src/util/log.c +++ b/lib/src/util/log.c @@ -30,6 +30,10 @@ log_conf_t log_conf = DEFAULT_LOG_CONF; #define FMT_DATETIME_LEN 20 #define snprintf_nowarn(...) (snprintf (__VA_ARGS__) < 0 ? abort () : (void) 0) +#define COLOR_RED "\033[31m" +#define COLOR_YELLOW "\033[33m" +#define COLOR_RESET "\033[0m" + static char ts[FMT_DATETIME_LEN]; static char * @@ -104,7 +108,7 @@ _log_va (int level, const char *fmt, va_list ap) } else { - __android_log_vprint (ANDROID_LOG_INFO, "HICN FACEMGR", fmt, ap); + __android_log_vprint (prio, "HICN FACEMGR", fmt, ap); } #else @@ -112,6 +116,7 @@ _log_va (int level, const char *fmt, va_list ap) if (level > log_conf.log_level) return; + char *color = COLOR_RESET; switch (level) { case LOG_FATAL: @@ -119,9 +124,11 @@ _log_va (int level, const char *fmt, va_list ap) break; case LOG_ERROR: prefix = "ERROR: "; + color = COLOR_RED; break; case LOG_WARN: prefix = "WARNING: "; + color = COLOR_YELLOW; break; case LOG_INFO: prefix = ""; @@ -137,9 +144,9 @@ _log_va (int level, const char *fmt, va_list ap) break; } FILE *f = log_conf.log_file ? log_conf.log_file : stdout; - fprintf (f, "%s %s", timestamp (), prefix); + fprintf (f, "%s%s %s", color, timestamp (), prefix); vfprintf (f, fmt, ap); - fprintf (f, "\n"); + fprintf (f, "%s\n", COLOR_RESET); #ifdef DEBUG fflush (f); #endif diff --git a/lib/src/util/pool.c b/lib/src/util/pool.c new file mode 100644 index 000000000..c6be92ce8 --- /dev/null +++ b/lib/src/util/pool.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file pool.c + * \brief Implementation of fixed-size pool allocator. + * + * NOTE: + * - Ideally, we should have a single realloc per resize, that would encompass + * both the free indices vector and bitmap, by nesting data structures. + * Because of the added complexity, and by lack of evidence of the need for + * this, we currently rely on a simpler implementation. + */ + +#include <assert.h> +#include <stdlib.h> // calloc + +#include <hicn/util/pool.h> + +#include <stdio.h> // XXX + +void +_pool_init (void **pool_ptr, size_t elt_size, size_t init_size, + size_t max_size) +{ + assert (pool_ptr); + assert (elt_size); + + init_size = next_pow2 (init_size); + + if (max_size && init_size > max_size) + goto ERR_MAX_SIZE; + + /* The initial pool size is rounded to the next power of two */ + size_t alloc_size = next_pow2 (init_size); + + pool_hdr_t *ph = calloc (POOL_HDRLEN + alloc_size * elt_size, 1); + if (!ph) + goto ERR_MALLOC; + + ph->elt_size = elt_size; + ph->alloc_size = alloc_size; + ph->max_size = max_size; + + /* Free indices */ + off_t *free_indices; + vector_init (free_indices, init_size, max_size); + for (unsigned i = 0; i < init_size; i++) + free_indices[i] = (init_size - 1) - i; + vector_len (free_indices) = init_size; + ph->free_indices = free_indices; + + /* Free bitmap */ + bitmap_t *fb = ph->free_bitmap; + bitmap_init (fb, init_size, max_size); + bitmap_set_to (fb, init_size); + ph->free_bitmap = fb; + + *pool_ptr = (uint8_t *) ph + POOL_HDRLEN; + + return; + +ERR_MALLOC: +ERR_MAX_SIZE: + *pool_ptr = NULL; + return; +} + +void +_pool_free (void **pool_ptr) +{ + pool_hdr_t *ph = pool_hdr (*pool_ptr); + vector_free (ph->free_indices); + bitmap_free (ph->free_bitmap); + + free (pool_hdr (*pool_ptr)); + *pool_ptr = NULL; +} + +bool +_pool_validate_id (void **pool_ptr, off_t id) +{ + pool_hdr_t *ph = pool_hdr (*pool_ptr); + size_t pool_size = pool_get_alloc_size (*pool_ptr); + if (id >= pool_size || !bitmap_is_unset (ph->free_bitmap, id)) + return false; + + return true; +} + +void +_pool_resize (void **pool_ptr, size_t elt_size) +{ + pool_hdr_t *ph = pool_hdr (*pool_ptr); + size_t old_size = ph->alloc_size; + size_t new_size = old_size * 2; + + WARN ("pool_resize to %lu", new_size); + + if (ph->max_size && new_size > ph->max_size) + goto ERR_MAX_SIZE; + + /* Double pool storage */ + ph = realloc (ph, POOL_HDRLEN + new_size * elt_size); + if (!ph) + goto ERR_REALLOC; + ph->elt_size = elt_size; + ph->alloc_size = new_size; + + /* + * After resize, the pool will have new free indices, ranging from + * old_size to (new_size - 1) + */ + vector_ensure_pos (ph->free_indices, old_size); + for (unsigned i = 0; i < old_size; i++) + ph->free_indices[i] = new_size - 1 - i; + vector_len (ph->free_indices) = old_size; + + /* We also need to update the bitmap */ + bitmap_ensure_pos (&(ph->free_bitmap), new_size - 1); + bitmap_set_range (ph->free_bitmap, old_size, new_size - 1); + + /* Reassign pool pointer */ + *pool_ptr = (uint8_t *) ph + POOL_HDRLEN; + + return; + +ERR_REALLOC: +ERR_MAX_SIZE: + *pool_ptr = NULL; + return; +} + +off_t +_pool_get (void **pool_ptr, void **elt, size_t elt_size) +{ + pool_hdr_t *ph = pool_hdr (*pool_ptr); + uint64_t l = vector_len (ph->free_indices); + if (l == 0) + { + _pool_resize (pool_ptr, elt_size); + ph = pool_hdr (*pool_ptr); + l = vector_len (ph->free_indices); + } + off_t free_id = ph->free_indices[l - 1]; + vector_len (ph->free_indices)--; + bitmap_unset (ph->free_bitmap, free_id); + *elt = *pool_ptr + free_id * elt_size; + return free_id; +} + +void +_pool_put (void **pool_ptr, void **elt, size_t elt_size) +{ + pool_hdr_t *ph = pool_hdr (*pool_ptr); + uint64_t l = vector_len (ph->free_indices); + vector_ensure_pos (ph->free_indices, l); + off_t freed_id = (*elt - *pool_ptr) / elt_size; + ph->free_indices[l] = freed_id; + vector_len (ph->free_indices)++; + bitmap_set (ph->free_bitmap, freed_id); +} diff --git a/hicn-light/src/hicn/base/ring.c b/lib/src/util/ring.c index 29727886a..2c722a842 100644 --- a/hicn-light/src/hicn/base/ring.c +++ b/lib/src/util/ring.c @@ -21,25 +21,29 @@ #include <stdlib.h> -#include "ring.h" +#include <hicn/util/ring.h> -void _ring_init(void** ring_ptr, size_t elt_size, size_t max_size) { - assert(ring_ptr); - assert(elt_size > 0); +void +_ring_init (void **ring_ptr, size_t elt_size, size_t max_size) +{ + assert (ring_ptr); + assert (elt_size > 0); // we use a static array, not a vector (for now) - assert(max_size != 0); + assert (max_size != 0); - ring_hdr_t* rh = malloc(RING_HDRLEN + max_size * elt_size); + ring_hdr_t *rh = malloc (RING_HDRLEN + max_size * elt_size); rh->roff = 0; rh->woff = 0; rh->size = 0; rh->max_size = max_size; - *ring_ptr = (uint8_t*)rh + RING_HDRLEN; + *ring_ptr = (uint8_t *) rh + RING_HDRLEN; } -void _ring_free(void** ring_ptr) { - free(ring_hdr(*ring_ptr)); +void +_ring_free (void **ring_ptr) +{ + free (ring_hdr (*ring_ptr)); *ring_ptr = NULL; } diff --git a/hicn-light/src/hicn/base/vector.c b/lib/src/util/vector.c index 36d808932..1f5cd0269 100644 --- a/hicn-light/src/hicn/base/vector.c +++ b/lib/src/util/vector.c @@ -19,67 +19,83 @@ */ #include <assert.h> -#include <stddef.h> // size_t -#include <stdlib.h> // calloc +#include <stddef.h> // size_t +#include <stdlib.h> // calloc #include <stdio.h> -#include "vector.h" +#include <hicn/util/vector.h> #define DEFAULT_VECTOR_SIZE 64 -void _vector_init(void** vector_ptr, size_t elt_size, size_t init_size, - size_t max_size) { - assert(vector_ptr); - assert(max_size == 0 || init_size < max_size); +int +_vector_init (void **vector_ptr, size_t elt_size, size_t init_size, + size_t max_size) +{ + assert (vector_ptr); + assert (max_size == 0 || init_size < max_size); - if (init_size == 0) init_size = DEFAULT_VECTOR_SIZE; + if (init_size == 0) + init_size = DEFAULT_VECTOR_SIZE; *vector_ptr = NULL; - _vector_resize(vector_ptr, elt_size, init_size); + int rc = _vector_resize (vector_ptr, elt_size, init_size); + if (rc < 0) + return -1; - vector_hdr_t* vh = vector_hdr(*vector_ptr); + vector_hdr_t *vh = vector_hdr (*vector_ptr); vh->cur_size = 0; vh->max_size = max_size; + + return 0; } -void _vector_free(void** vector_ptr) { - free(vector_hdr(*vector_ptr)); +void +_vector_free (void **vector_ptr) +{ + free (vector_hdr (*vector_ptr)); *vector_ptr = NULL; } -int _vector_resize(void** vector_ptr, size_t elt_size, off_t pos) { - vector_hdr_t* vh; - +int +_vector_resize (void **vector_ptr, size_t elt_size, off_t pos) +{ + vector_hdr_t *vh; size_t old_size; - if (*vector_ptr) { - vh = vector_hdr(*vector_ptr); - old_size = vh->alloc_size; - } else { - vh = NULL; - old_size = 0; - } + if (*vector_ptr) + { + vh = vector_hdr (*vector_ptr); + old_size = vh->alloc_size; + } + else + { + vh = NULL; + old_size = 0; + } /* Round the allocated size to the next power of 2 of the requested position */ - size_t new_size = next_pow2(pos); + size_t new_size = next_pow2 (pos); /* Don't grow the vector back */ - if (new_size < old_size) return 0; + if (new_size < old_size) + return 0; /* Don't exceed maximum size (for init, check is done beforehand) */ - if (vh && vh->max_size && new_size > vh->max_size) return -1; + if (vh && vh->max_size && new_size > vh->max_size) + return -1; - vh = realloc(vh, VECTOR_HDRLEN + new_size * elt_size); - if (!vh) return -1; + vh = realloc (vh, VECTOR_HDRLEN + new_size * elt_size); + if (!vh) + return -1; vh->alloc_size = new_size; /* Zero out the newly allocated memory (except headers) */ - memset((uint8_t*)vh + VECTOR_HDRLEN + old_size * elt_size, 0, - (new_size - old_size) * elt_size); + memset ((uint8_t *) vh + VECTOR_HDRLEN + old_size * elt_size, 0, + (new_size - old_size) * elt_size); /* Reassign vector pointer */ - *vector_ptr = (uint8_t*)vh + VECTOR_HDRLEN; + *vector_ptr = (uint8_t *) vh + VECTOR_HDRLEN; return 0; } diff --git a/libtransport/includes/hicn/transport/core/asio_wrapper.h b/libtransport/includes/hicn/transport/core/asio_wrapper.h index 78cad35dc..41b660587 100644 --- a/libtransport/includes/hicn/transport/core/asio_wrapper.h +++ b/libtransport/includes/hicn/transport/core/asio_wrapper.h @@ -23,6 +23,9 @@ TRANSPORT_CLANG_DISABLE_WARNING("-Wdeprecated-declarations") #ifndef ASIO_STANDALONE #define ASIO_STANDALONE #endif +#ifdef __APPLE__ +TRANSPORT_CLANG_DISABLE_WARNING("-Wshorten-64-to-32") +#endif #include <asio.hpp> TRANSPORT_POP_WARNING diff --git a/libtransport/includes/hicn/transport/core/connector.h b/libtransport/includes/hicn/transport/core/connector.h index b671a7d89..ad0d4f09d 100644 --- a/libtransport/includes/hicn/transport/core/connector.h +++ b/libtransport/includes/hicn/transport/core/connector.h @@ -30,6 +30,7 @@ #include <deque> #include <functional> +#include <system_error> namespace transport { @@ -57,10 +58,10 @@ class Connector : public std::enable_shared_from_this<Connector> { static constexpr std::uint16_t max_burst = 256; using Ptr = std::shared_ptr<Connector>; + using ReceptionBuffer = std::vector<utils::MemBuf::Ptr>; using PacketQueue = std::deque<utils::MemBuf::Ptr>; - using PacketReceivedCallback = - std::function<void(Connector *, const std::vector<utils::MemBuf::Ptr> &, - const std::error_code &)>; + using PacketReceivedCallback = std::function<void( + Connector *, const ReceptionBuffer &, const std::error_code &)>; using PacketSentCallback = std::function<void(Connector *, const std::error_code &)>; using OnCloseCallback = std::function<void(Connector *)>; @@ -118,6 +119,14 @@ class Connector : public std::enable_shared_from_this<Connector> { virtual void send(const utils::MemBuf::Ptr &buffer) = 0; + virtual void receive(const std::vector<utils::MemBuf::Ptr> &buffers) { + receive_callback_(this, buffers, std::make_error_code(std::errc())); + } + + virtual void reconnect() { + on_reconnect_callback_(this, std::make_error_code(std::errc())); + } + virtual void close() = 0; virtual State state() { return state_; }; @@ -134,6 +143,11 @@ class Connector : public std::enable_shared_from_this<Connector> { std::string getConnectorName() { return connector_name_; } + template <typename EP> + void setLocalEndpoint(EP &&endpoint) { + local_endpoint_ = std::forward<EP>(endpoint); + } + Endpoint getLocalEndpoint() { return local_endpoint_; } Endpoint getRemoteEndpoint() { return remote_endpoint_; } diff --git a/libtransport/includes/hicn/transport/core/content_object.h b/libtransport/includes/hicn/transport/core/content_object.h index a8df1e8e3..f8d95846e 100644 --- a/libtransport/includes/hicn/transport/core/content_object.h +++ b/libtransport/includes/hicn/transport/core/content_object.h @@ -43,8 +43,8 @@ class ContentObject : public Packet { template <typename... Args> ContentObject(CopyBufferOp op, Args &&...args) : Packet(op, std::forward<Args>(args)...) { - if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < - 0) { + if (hicn_data_get_name(format_, packet_start_, + &name_.getStructReference()) < 0) { throw errors::MalformedPacketException(); } } @@ -52,8 +52,8 @@ class ContentObject : public Packet { template <typename... Args> ContentObject(WrapBufferOp op, Args &&...args) : Packet(op, std::forward<Args>(args)...) { - if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < - 0) { + if (hicn_data_get_name(format_, packet_start_, + &name_.getStructReference()) < 0) { throw errors::MalformedPacketException(); } } @@ -65,8 +65,8 @@ class ContentObject : public Packet { throw errors::MalformedPacketException(); } - if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < - 0) { + if (hicn_data_get_name(format_, packet_start_, + &name_.getStructReference()) < 0) { throw errors::MalformedPacketException(); } } diff --git a/libtransport/includes/hicn/transport/core/interest.h b/libtransport/includes/hicn/transport/core/interest.h index b7ce3c3a0..9e6cdccb9 100644 --- a/libtransport/includes/hicn/transport/core/interest.h +++ b/libtransport/includes/hicn/transport/core/interest.h @@ -29,14 +29,6 @@ const uint32_t MAX_AGGREGATED_INTEREST = 128; class Interest : public Packet /*, public std::enable_shared_from_this<Interest>*/ { - private: - struct InterestManifestHeader { - /* This can be 16 bits, but we use 32 bits for alignment */ - uint32_t n_suffixes; - /* Followed by the list of prefixes to ask */ - /* ... */ - }; - public: using Ptr = std::shared_ptr<Interest>; @@ -51,7 +43,7 @@ class Interest Interest(CopyBufferOp op, Args &&...args) : Packet(op, std::forward<Args>(args)...) { if (hicn_interest_get_name(format_, packet_start_, - name_.getStructReference()) < 0) { + &name_.getStructReference()) < 0) { throw errors::MalformedPacketException(); } } @@ -60,7 +52,7 @@ class Interest Interest(WrapBufferOp op, Args &&...args) : Packet(op, std::forward<Args>(args)...) { if (hicn_interest_get_name(format_, packet_start_, - name_.getStructReference()) < 0) { + &name_.getStructReference()) < 0) { throw errors::MalformedPacketException(); } } @@ -108,6 +100,12 @@ class Interest uint32_t numberOfSuffixes(); + uint32_t *getRequestBitmap(); + + void setRequestBitmap(const uint32_t *request_bitmap); + + bool isValid(); + auto shared_from_this() { return utils::shared_from(this); } private: diff --git a/libtransport/includes/hicn/transport/core/io_module.h b/libtransport/includes/hicn/transport/core/io_module.h index 817d96d00..31da0b882 100644 --- a/libtransport/includes/hicn/transport/core/io_module.h +++ b/libtransport/includes/hicn/transport/core/io_module.h @@ -19,6 +19,7 @@ #include <hicn/transport/core/connector.h> #include <hicn/transport/core/packet.h> #include <hicn/transport/core/prefix.h> +#include <hicn/transport/portability/endianess.h> #include <hicn/transport/portability/portability.h> #include <hicn/transport/utils/chrono_typedefs.h> #include <hicn/transport/utils/membuf.h> @@ -48,13 +49,12 @@ class IoModule : utils::NonCopyable { mtu_(1500), output_interface_(""), content_store_reserved_(5000) { - inet_address_.v4.as_u32 = htonl(0x7f00001); + inet_address_.v4.as_u32 = portability::host_to_net(0x7f00001); inet6_address_.v6.as_u8[15] = 0x01; } public: static IoModule *load(const char *); - static bool unload(IoModule *); public: virtual ~IoModule(); @@ -65,6 +65,7 @@ class IoModule : utils::NonCopyable { virtual void init(Connector::PacketReceivedCallback &&receive_callback, Connector::PacketSentCallback &&sent_callback, + Connector::OnCloseCallback &&close_callback, Connector::OnReconnectCallback &&reconnect_callback, asio::io_service &io_service, const std::string &app_name = "Libtransport") = 0; @@ -108,11 +109,6 @@ class IoModule : utils::NonCopyable { const std::string &getOutputInterface() { return output_interface_; } -#ifndef ANDROID - private: - void *handle_; -#endif - protected: ip_address_t inet_address_; ip_address_t inet6_address_; diff --git a/libtransport/includes/hicn/transport/core/name.h b/libtransport/includes/hicn/transport/core/name.h index 5cb4efd10..cf6d3097c 100644 --- a/libtransport/includes/hicn/transport/core/name.h +++ b/libtransport/includes/hicn/transport/core/name.h @@ -46,6 +46,7 @@ class Name { friend class Packet; friend class ContentObject; friend class Interest; + friend class Prefix; static const uint32_t standard_name_string_length = 100; @@ -102,11 +103,11 @@ class Name { int getAddressFamily() const; private: - TRANSPORT_ALWAYS_INLINE const NameStruct *getConstStructReference() const { - return &name_; + TRANSPORT_ALWAYS_INLINE const NameStruct &getConstStructReference() const { + return name_; } - TRANSPORT_ALWAYS_INLINE NameStruct *getStructReference() { return &name_; } + TRANSPORT_ALWAYS_INLINE NameStruct &getStructReference() { return name_; } NameStruct name_; }; diff --git a/libtransport/includes/hicn/transport/core/prefix.h b/libtransport/includes/hicn/transport/core/prefix.h index 13401e1a8..778491a31 100644 --- a/libtransport/includes/hicn/transport/core/prefix.h +++ b/libtransport/includes/hicn/transport/core/prefix.h @@ -25,13 +25,9 @@ class Prefix { public: Prefix(); - Prefix(const char *prefix); - Prefix(const std::string &prefix); - Prefix(std::string &&prefix); - - Prefix(std::string &prefix, uint16_t prefix_length); + Prefix(const std::string &prefix, uint16_t prefix_length); Prefix(const core::Name &content_name, uint16_t prefix_length); @@ -39,6 +35,8 @@ class Prefix { bool operator==(const Prefix &prefix) const; + bool operator!=(const Prefix &prefix) const { return !operator==(prefix); } + std::unique_ptr<Sockaddr> toSockaddr() const; uint16_t getPrefixLength() const; @@ -47,26 +45,22 @@ class Prefix { std::string getNetwork() const; - int contains(const ip_address_t &content_name) const; + Prefix &setNetwork(const std::string &network); - int contains(const core::Name &content_name) const; + int getAddressFamily() const; - Name getName() const; + bool contains(const ip_address_t &content_name) const; - Name getRandomName() const; + bool contains(const core::Name &content_name) const; Name getName(const core::Name &mask, const core::Name &components, const core::Name &content_name) const; Name mapName(const core::Name &content_name) const; - Prefix &setNetwork(std::string &network); - - int getAddressFamily() const; - - Prefix &setAddressFamily(int address_family); - + Name makeName() const; Name makeRandomName() const; + Name makeNameWithIndex(std::uint64_t index) const; const ip_prefix_t &toIpPrefixStruct() const; @@ -74,8 +68,10 @@ class Prefix { static bool checkPrefixLengthAndAddressFamily(uint16_t prefix_length, int family); - void buildPrefix(std::string &prefix, uint16_t prefix_length, int family); + void buildPrefix(const std::string &prefix, uint16_t prefix_length, + int family); + private: ip_prefix_t ip_prefix_; }; diff --git a/libtransport/includes/hicn/transport/interfaces/CMakeLists.txt b/libtransport/includes/hicn/transport/interfaces/CMakeLists.txt index 1acaadcf0..43f95a466 100644 --- a/libtransport/includes/hicn/transport/interfaces/CMakeLists.txt +++ b/libtransport/includes/hicn/transport/interfaces/CMakeLists.txt @@ -24,11 +24,4 @@ list(APPEND HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/notification.h ) -if (${OPENSSL_VERSION} VERSION_EQUAL "1.1.1a" OR ${OPENSSL_VERSION} VERSION_GREATER "1.1.1a") - list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.h - ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.h - ) -endif() - set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) diff --git a/libtransport/includes/hicn/transport/interfaces/global_conf_interface.h b/libtransport/includes/hicn/transport/interfaces/global_conf_interface.h index a9fe6fac6..e1465d375 100644 --- a/libtransport/includes/hicn/transport/interfaces/global_conf_interface.h +++ b/libtransport/includes/hicn/transport/interfaces/global_conf_interface.h @@ -26,8 +26,16 @@ namespace transport { namespace interface { namespace global_config { -static const constexpr char io_module_section[] = "io_module"; -void parseConfigurationFile(const std::string& path = ""); +class GlobalConfigInterface { + public: + GlobalConfigInterface(); + ~GlobalConfigInterface(); + void parseConfigurationFile(const std::string& path = "") const; + + private: + void libtransportConfigInit() const; + void libtransportConfigTerminate() const; +}; class ConfigurationObject { public: @@ -49,7 +57,9 @@ class ConfigurationObject { class IoModuleConfiguration : public ConfigurationObject { public: - std::string getKey() const override { return io_module_section; } + static inline char section[] = "io_module"; + + std::string getKey() const override { return section; } std::string name; std::vector<std::string> search_path; diff --git a/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h deleted file mode 100644 index a67634c1e..000000000 --- a/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_consumer.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <hicn/transport/interfaces/socket_consumer.h> - -namespace transport { - -namespace interface { - -class P2PSecureConsumerSocket : public ConsumerSocket { - public: - P2PSecureConsumerSocket(int handshake_protocol, int transport_protocol); - ~P2PSecureConsumerSocket() = default; - void registerPrefix(const Prefix &producer_namespace); -}; - -} // namespace interface -} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h b/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h deleted file mode 100644 index e197a3658..000000000 --- a/libtransport/includes/hicn/transport/interfaces/p2psecure_socket_producer.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <hicn/transport/interfaces/socket_producer.h> - -namespace transport { - -namespace interface { - -class P2PSecureProducerSocket : public ProducerSocket { - public: - P2PSecureProducerSocket(); - P2PSecureProducerSocket(bool rtc, std::string &keystore_path, - std::string &keystore_pwd); - ~P2PSecureProducerSocket() = default; -}; - -} // namespace interface - -} // end namespace transport diff --git a/libtransport/includes/hicn/transport/interfaces/portal.h b/libtransport/includes/hicn/transport/interfaces/portal.h index 1a22b1f1d..bca78cb3b 100644 --- a/libtransport/includes/hicn/transport/interfaces/portal.h +++ b/libtransport/includes/hicn/transport/interfaces/portal.h @@ -95,7 +95,7 @@ class Portal : private utils::NonCopyable { * parameter. Otherwise ConsumerCallback::onTimeout will be used. */ void sendInterest( - core::Interest::Ptr &&interest, + core::Interest::Ptr &interest, uint32_t lifetime, OnContentObjectCallback &&on_content_object_callback = UNSET_CALLBACK, OnInterestTimeoutCallback &&on_interest_timeout_callback = UNSET_CALLBACK); diff --git a/libtransport/includes/hicn/transport/interfaces/socket_consumer.h b/libtransport/includes/hicn/transport/interfaces/socket_consumer.h index e26fe5a85..d997634da 100644 --- a/libtransport/includes/hicn/transport/interfaces/socket_consumer.h +++ b/libtransport/includes/hicn/transport/interfaces/socket_consumer.h @@ -250,6 +250,9 @@ class ConsumerSocket : private utils::NonCopyable { int setSocketOption(int socket_option_key, interface::IcnObserver *socket_option_value); + int setSocketOption(int socket_option_key, + const std::shared_ptr<auth::Signer> &socket_option_value); + int setSocketOption( int socket_option_key, const std::shared_ptr<auth::Verifier> &socket_option_value); @@ -283,6 +286,9 @@ class ConsumerSocket : private utils::NonCopyable { int getSocketOption(int socket_option_key, IcnObserver **socket_option_value); int getSocketOption(int socket_option_key, + std::shared_ptr<auth::Signer> &socket_option_value); + + int getSocketOption(int socket_option_key, std::shared_ptr<auth::Verifier> &socket_option_value); int getSocketOption(int socket_option_key, std::string &socket_option_value); diff --git a/libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h b/libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h index 0e19ae629..da8eafcd9 100644 --- a/libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h +++ b/libtransport/includes/hicn/transport/interfaces/socket_options_default_values.h @@ -53,9 +53,9 @@ static constexpr uint32_t key_locator_size = 60; // bytes static constexpr uint32_t limit_guard = 80; // bytes static constexpr uint32_t digest_size = 34; // bytes static constexpr uint32_t max_out_of_order_segments = 3; // content object -static constexpr uint32_t unverified_interval = 60000; // milliseconds -static constexpr double unverified_ratio = 0.2; -static constexpr uint32_t manifest_capacity = 20; +static constexpr uint32_t manifest_max_capacity = 30; +static constexpr uint32_t manifest_factor_relevant = 100; +static constexpr uint32_t manifest_factor_alert = 20; // RAAQM static constexpr int sample_number = 30; diff --git a/libtransport/includes/hicn/transport/interfaces/socket_options_keys.h b/libtransport/includes/hicn/transport/interfaces/socket_options_keys.h index 6cba50d8b..a14c8414c 100644 --- a/libtransport/includes/hicn/transport/interfaces/socket_options_keys.h +++ b/libtransport/includes/hicn/transport/interfaces/socket_options_keys.h @@ -46,6 +46,9 @@ typedef enum { LOW_RATE_AND_BESTPATH = 25, LOW_RATE_AND_REPLICATION = 26, LOW_RATE_AND_ALL_FWD_STRATEGIES = 27, + FEC_ONLY_LOW_RES_LOSSES = 28, + DELAY_AND_BESTPATH = 29, + DELAY_AND_REPLICATION = 30, } RtcTransportRecoveryStrategies; typedef enum { @@ -58,23 +61,23 @@ typedef enum { INTEREST_LIFETIME = 107, CONTENT_OBJECT_EXPIRY_TIME = 108, MAX_SEGMENT_SIZE = 109, - MIN_WINDOW_SIZE = 111, - MAX_WINDOW_SIZE = 112, - CURRENT_WINDOW_SIZE = 113, - ASYNC_MODE = 114, - MAKE_MANIFEST = 115, - PORTAL = 116, - RUNNING = 117, - APPLICATION_BUFFER = 118, - HASH_ALGORITHM = 119, - SIGNER = 121, - VERIFIER = 122, - UNVERIFIED_INTERVAL = 123, - UNVERIFIED_RATIO = 124, - STATS_INTERVAL = 125, - SUFFIX_STRATEGY = 126, - PACKET_FORMAT = 127, - FEC_TYPE = 128, + MIN_WINDOW_SIZE = 110, + MAX_WINDOW_SIZE = 111, + CURRENT_WINDOW_SIZE = 112, + ASYNC_MODE = 113, + PORTAL = 114, + RUNNING = 115, + APPLICATION_BUFFER = 116, + HASH_ALGORITHM = 117, + SIGNER = 118, + VERIFIER = 119, + MANIFEST_MAX_CAPACITY = 120, + MANIFEST_FACTOR_RELEVANT = 121, + MANIFEST_FACTOR_ALERT = 122, + STATS_INTERVAL = 123, + SUFFIX_STRATEGY = 124, + PACKET_FORMAT = 125, + FEC_TYPE = 126, } GeneralTransportOptions; typedef enum { @@ -139,6 +142,8 @@ typedef enum { typedef enum { RECOVERY_STRATEGY = 901, AGGREGATED_DATA = 902, + CONTENT_SHARING_MODE = 903, + AGGREGATED_INTERESTS = 904, } RtcTransportOptions; } // namespace interface diff --git a/libtransport/includes/hicn/transport/interfaces/socket_producer.h b/libtransport/includes/hicn/transport/interfaces/socket_producer.h index 77b89742a..be08c9a0b 100644 --- a/libtransport/includes/hicn/transport/interfaces/socket_producer.h +++ b/libtransport/includes/hicn/transport/interfaces/socket_producer.h @@ -123,6 +123,10 @@ class ProducerSocket : private utils::NonCopyable { int setSocketOption(int socket_option_key, const std::shared_ptr<auth::Signer> &socket_option_value); + int setSocketOption( + int socket_option_key, + const std::shared_ptr<auth::Verifier> &socket_option_value); + int setSocketOption(int socket_option_key, const std::string &socket_option_value); @@ -154,6 +158,9 @@ class ProducerSocket : private utils::NonCopyable { int getSocketOption(int socket_option_key, std::shared_ptr<auth::Signer> &socket_option_value); + int getSocketOption(int socket_option_key, + std::shared_ptr<auth::Verifier> &socket_option_value); + int getSocketOption(int socket_option_key, std::string &socket_option_value); int getSocketOption(int socket_option_key, diff --git a/libtransport/includes/hicn/transport/interfaces/statistics.h b/libtransport/includes/hicn/transport/interfaces/statistics.h index 4d9e1bfe2..e83aa9a27 100644 --- a/libtransport/includes/hicn/transport/interfaces/statistics.h +++ b/libtransport/includes/hicn/transport/interfaces/statistics.h @@ -73,10 +73,10 @@ class TransportStatistics { } TRANSPORT_ALWAYS_INLINE void updateAverageRtt( - const utils::SteadyTime::Milliseconds &rtt) { - auto rtt_milliseconds = rtt.count(); - average_rtt_ = - (alpha_ * average_rtt_) + ((1. - alpha_) * double(rtt_milliseconds)); + const utils::SteadyTime::Microseconds &rtt) { + double rtt_milliseconds = double(rtt.count()) / 1000.0; + + average_rtt_ = (alpha_ * average_rtt_) + ((1. - alpha_) * rtt_milliseconds); } TRANSPORT_ALWAYS_INLINE void updateAverageWindowSize(double current_window) { diff --git a/libtransport/includes/hicn/transport/portability/CMakeLists.txt b/libtransport/includes/hicn/transport/portability/CMakeLists.txt index 7a688b1f1..d29ec737c 100644 --- a/libtransport/includes/hicn/transport/portability/CMakeLists.txt +++ b/libtransport/includes/hicn/transport/portability/CMakeLists.txt @@ -15,6 +15,8 @@ list(APPEND HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/c_portability.h ${CMAKE_CURRENT_SOURCE_DIR}/portability.h ${CMAKE_CURRENT_SOURCE_DIR}/cpu.h + ${CMAKE_CURRENT_SOURCE_DIR}/cache.h + ${CMAKE_CURRENT_SOURCE_DIR}/endianess.h ) list(APPEND SOURCE_FILES diff --git a/libtransport/includes/hicn/transport/portability/cache.h b/libtransport/includes/hicn/transport/portability/cache.h new file mode 100644 index 000000000..ae113c7d6 --- /dev/null +++ b/libtransport/includes/hicn/transport/portability/cache.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <hicn/transport/portability/platform.h> + +namespace transport { +namespace portability { +namespace cache { + +/** + * @Prefetch utilities + */ + +/* Default cache line size of 64 bytes. */ +#ifndef LOG2_CACHE_LINE_BYTES +static constexpr const std::size_t klog2_cache_line_bytes = 6; +#else +static constexpr const std::size_t klog2_cache_line_bytes = + LOG2_CACHE_LINE_BYTES; +#endif + +/* How much data prefetch instruction prefetches */ +#ifndef LOG2_CACHE_PREFETCH_BYTES +static constexpr const std::size_t klog2_cache_prefetch_bytes = + klog2_cache_line_bytes; +#else +static constexpr const std::size_t klog2_cache_prefetch_bytes = + LOG2_CACHE_PREFETCH_BYTES; +#endif + +/* Default cache line fill buffers. */ +#ifndef N_PREFETCHES +static constexpr const std::size_t kn_prefetches = 16; +#else +static constexpr const std::size_t kn_prefetches = N_PREFETCHES; +#endif + +static constexpr const std::size_t kcache_line_bytes = + (1 << klog2_cache_line_bytes); +static constexpr const std::size_t kcache_prefetch_bytes = + (1 << klog2_cache_prefetch_bytes); + +static constexpr const int READ = 0; +static constexpr const int LOAD = 0; /* alias for read */ +static constexpr const int WRITE = 1; +static constexpr const int STORE = 1; /* alias for write */ + +#if defined(__GNUC__) || defined(__clang__) +// Clang & GCC + +template <int type> +static inline void _prefetch(uint8_t *addr, std::size_t n, std::size_t size) { + if (size > n * kcache_prefetch_bytes) { + __builtin_prefetch(addr + n * kcache_prefetch_bytes, type, + /* locality */ 3); + } +} + +template <typename T, int type> +static inline void prefetch(T *addr, std::size_t size) { + uint8_t *_addr = reinterpret_cast<uint8_t *>(addr); + + _prefetch<type>(_addr, 0, size); + _prefetch<type>(_addr, 1, size); + _prefetch<type>(_addr, 2, size); + _prefetch<type>(_addr, 3, size); +} +#endif + +} // namespace cache +} // namespace portability +} // namespace transport
\ No newline at end of file diff --git a/libtransport/includes/hicn/transport/portability/endianess.h b/libtransport/includes/hicn/transport/portability/endianess.h new file mode 100644 index 000000000..c18ac82cf --- /dev/null +++ b/libtransport/includes/hicn/transport/portability/endianess.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <hicn/transport/errors/errors.h> + +namespace transport { +namespace portability { + +#if (__BYTE_ORDER__) == (__ORDER_LITTLE_ENDIAN__) +static constexpr const bool kIsBigEndian = false; +static constexpr const bool kIsLittleEndian = true; +#else +static constexpr const bool kIsBigEndian = true; +static constexpr const bool kIsLittleEndian = false; +#endif + +template <typename T> +inline T bswap(T value) { + throw errors::RuntimeException("Not implemented"); +} + +template <> +inline int16_t bswap(int16_t value) { + return __builtin_bswap16(value); +} + +template <> +inline int32_t bswap(int32_t value) { + return __builtin_bswap32(value); +} + +template <> +inline int64_t bswap(int64_t value) { + return __builtin_bswap64(value); +} + +template <> +inline uint16_t bswap(uint16_t value) { + return __builtin_bswap16(value); +} + +template <> +inline uint32_t bswap(uint32_t value) { + return __builtin_bswap32(value); +} + +template <> +inline uint64_t bswap(uint64_t value) { + return __builtin_bswap64(value); +} + +template <typename T> +inline T host_to_net(T value) { + if constexpr (kIsLittleEndian) { + return bswap(value); + } + + return value; +} + +template <typename T> +inline T net_to_host(T value) { + if constexpr (kIsLittleEndian) { + return bswap(value); + } + + return value; +} + +} // namespace portability +} // namespace transport
\ No newline at end of file diff --git a/libtransport/includes/hicn/transport/portability/portability.h b/libtransport/includes/hicn/transport/portability/portability.h index b093f8892..fd6eca4de 100644 --- a/libtransport/includes/hicn/transport/portability/portability.h +++ b/libtransport/includes/hicn/transport/portability/portability.h @@ -26,6 +26,7 @@ #include <cstddef> +namespace transport { namespace portability { // Generalize warning push/pop. @@ -66,3 +67,4 @@ namespace portability { #endif } // namespace portability +} // namespace transport
\ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/chrono_typedefs.h b/libtransport/includes/hicn/transport/utils/chrono_typedefs.h index ddfbd00cd..14234eaa1 100644 --- a/libtransport/includes/hicn/transport/utils/chrono_typedefs.h +++ b/libtransport/includes/hicn/transport/utils/chrono_typedefs.h @@ -79,7 +79,7 @@ class Time { public: using Clock = T; using TimePoint = typename Clock::time_point; - using Rep = double; + using Rep = uint64_t; using Seconds = std::chrono::duration<Rep>; using Milliseconds = std::chrono::duration<Rep, std::milli>; using Microseconds = std::chrono::duration<Rep, std::micro>; diff --git a/libtransport/includes/hicn/transport/utils/color.h b/libtransport/includes/hicn/transport/utils/color.h new file mode 100644 index 000000000..3e8d93e14 --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/color.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <array> +#include <ostream> +#include <random> +#include <sstream> + +namespace utils { + +#define foreach_modifier \ + _(RESET, 0) \ + _(BOLD, 1) \ + _(FG_DEFAULT, 39) \ + _(FG_BLACK, 30) \ + _(FG_RED, 31) \ + _(FG_GREEN, 32) \ + _(FG_YELLOW, 33) \ + _(FG_BLUE, 34) \ + _(FG_MAGENTA, 35) \ + _(FG_CYAN, 36) \ + _(FG_LIGHT_GRAY, 37) \ + _(FG_DARK_GRAY, 90) \ + _(FG_LIGHT_RED, 91) \ + _(FG_LIGHT_GREEN, 92) \ + _(FG_LIGHT_YELLOW, 93) \ + _(FG_LIGHT_BLUE, 94) \ + _(FG_LIGHT_MAGENTA, 95) \ + _(FG_LIGHT_CYAN, 96) \ + _(FG_WHITE, 97) \ + _(BG_RED, 41) \ + _(BG_GREEN, 42) \ + _(BG_BLUE, 44) \ + _(BG_DEFAULT, 49) + +class ColorModifier { + static inline const std::size_t n_modifiers = 23; + static inline const char format_string_start[] = "\033["; + static inline const char format_string_end[] = "m"; + + public: + enum class Code { +#define _(name, value) name = value, + foreach_modifier +#undef _ + }; + + static inline std::array<Code, n_modifiers> code_array = { +#define _(name, value) Code::name, + foreach_modifier +#undef _ + }; + + static Code getRandomModifier() { + static std::random_device rd; + static std::mt19937 gen(rd()); + static std::uniform_int_distribution<> distr(4, 17); + + return code_array[distr(gen)]; + } + + ColorModifier(Code code) : code_(code), color_string_() { + std::stringstream ss; + if (std::getenv("COLORTERM") != nullptr) { + ss << format_string_start << static_cast<int>(code_) << format_string_end; + color_string_ = ss.str(); + } + } + + ColorModifier() : ColorModifier(getRandomModifier()) {} + + friend std::ostream& operator<<(std::ostream& os, const ColorModifier& mod) { + return os << mod.color_string_; + } + + private: + Code code_; + std::string color_string_; +}; + +} // namespace utils
\ No newline at end of file diff --git a/libtransport/includes/hicn/transport/utils/event_thread.h b/libtransport/includes/hicn/transport/utils/event_thread.h index 2cd2f3aca..164c853a5 100644 --- a/libtransport/includes/hicn/transport/utils/event_thread.h +++ b/libtransport/includes/hicn/transport/utils/event_thread.h @@ -29,16 +29,16 @@ class EventThread { EventThread(asio::io_service& io_service, bool detached = false) : internal_io_service_(nullptr), io_service_(std::ref(io_service)), - work_(std::make_unique<asio::io_service::work>(io_service_)), + work_guard_(asio::make_work_guard(io_service_.get())), thread_(nullptr), detached_(detached) { run(); } - EventThread(bool detached = false) + explicit EventThread(bool detached = false) : internal_io_service_(std::make_unique<asio::io_service>()), io_service_(std::ref(*internal_io_service_)), - work_(std::make_unique<asio::io_service::work>(io_service_)), + work_guard_(asio::make_work_guard(io_service_.get())), thread_(nullptr), detached_(detached) { run(); @@ -47,22 +47,12 @@ class EventThread { EventThread(const EventThread&) = delete; EventThread& operator=(const EventThread&) = delete; - EventThread(EventThread&& other) + EventThread(EventThread&& other) noexcept : internal_io_service_(std::move(other.internal_io_service_)), io_service_(std::move(other.io_service_)), - work_(std::move(other.work_)), + work_guard_(std::move(other.work_guard_)), thread_(std::move(other.thread_)), - detached_(std::move(other.detached_)) {} - - EventThread& operator=(EventThread&& other) { - internal_io_service_ = std::move(other.internal_io_service_); - io_service_ = std::move(other.io_service_); - work_ = std::move(other.work_); - thread_ = std::move(other.thread_); - detached_ = other.detached_; - - return *this; - } + detached_(other.detached_) {} ~EventThread() { stop(); } @@ -89,16 +79,16 @@ class EventThread { template <typename Func> void add(Func&& f) { - io_service_.get().post(std::forward<Func&&>(f)); + io_service_.get().post(std::forward<Func>(f)); } template <typename Func> void tryRunHandlerNow(Func&& f) { - io_service_.get().dispatch(std::forward<Func&&>(f)); + io_service_.get().dispatch(std::forward<Func>(f)); } template <typename Func> - void addAndWaitForExecution(Func&& f) { + void addAndWaitForExecution(Func&& f) const { auto promise = std::promise<void>(); auto future = promise.get_future(); @@ -111,7 +101,7 @@ class EventThread { } void stop() { - work_.reset(); + add([this]() { work_guard_.reset(); }); if (thread_ && thread_->joinable()) { thread_->join(); @@ -120,14 +110,14 @@ class EventThread { thread_.reset(); } - bool stopped() { return io_service_.get().stopped(); } + bool stopped() const { return io_service_.get().stopped(); } asio::io_service& getIoService() { return io_service_; } private: std::unique_ptr<asio::io_service> internal_io_service_; std::reference_wrapper<asio::io_service> io_service_; - std::unique_ptr<asio::io_service::work> work_; + asio::executor_work_guard<asio::io_context::executor_type> work_guard_; std::unique_ptr<std::thread> thread_; bool detached_; }; diff --git a/libtransport/includes/hicn/transport/utils/linux.h b/libtransport/includes/hicn/transport/utils/linux.h index 03d29c1db..14ef179ac 100644 --- a/libtransport/includes/hicn/transport/utils/linux.h +++ b/libtransport/includes/hicn/transport/utils/linux.h @@ -44,7 +44,7 @@ static TRANSPORT_ALWAYS_INLINE int retrieveInterfaceAddress( uint16_t prefix = 0; memcpy(&prefix, tmp->sin6_addr.s6_addr, sizeof(uint16_t)); - if (htons(LINK_LOCAL_PREFIX) != prefix) { + if (portability::host_to_net(LINK_LOCAL_PREFIX) != prefix) { *address = *(struct sockaddr_in6 *)ifa->ifa_addr; getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), addr, sizeof(addr), NULL, 0, NI_NUMERICHOST); diff --git a/libtransport/includes/hicn/transport/utils/thread_pool.h b/libtransport/includes/hicn/transport/utils/thread_pool.h index e4e47209c..76218ff09 100644 --- a/libtransport/includes/hicn/transport/utils/thread_pool.h +++ b/libtransport/includes/hicn/transport/utils/thread_pool.h @@ -29,8 +29,11 @@ class ThreadPool : public NonCopyable { std::size_t n_threads = std::thread::hardware_concurrency()) : workers_(n_threads > 0 ? n_threads : 1) {} + ~ThreadPool() = default; + std::size_t getNThreads() const { return workers_.size(); } EventThread &getWorker(std::size_t i) { return workers_.at(i); } + std::vector<EventThread> &getWorkers() { return workers_; } private: std::vector<EventThread> workers_; diff --git a/libtransport/src/auth/signer.cc b/libtransport/src/auth/signer.cc index 918e271f5..f13df53eb 100644 --- a/libtransport/src/auth/signer.cc +++ b/libtransport/src/auth/signer.cc @@ -15,6 +15,7 @@ #include <glog/logging.h> #include <hicn/transport/auth/signer.h> +#include <hicn/transport/core/interest.h> #include <hicn/transport/utils/chrono_typedefs.h> #include "hicn/transport/core/global_object_pool.h" @@ -50,6 +51,15 @@ void Signer::signPacket(PacketPtr packet) { hicn_header_t header_copy; hicn_packet_copy_header(format, packet->packet_start_, &header_copy, false); + // Copy bitmap from interest manifest + uint32_t request_bitmap[BITMAP_SIZE] = {0}; + if (packet->isInterest()) { + core::Interest *interest = dynamic_cast<core::Interest *>(packet); + if (interest->hasManifest()) + memcpy(request_bitmap, interest->getRequestBitmap(), + BITMAP_SIZE * sizeof(uint32_t)); + } + // Fill in the hICN AH header auto now = utils::SteadyTime::nowMs().count(); packet->setSignatureTimestamp(now); @@ -69,6 +79,12 @@ void Signer::signPacket(PacketPtr packet) { // Restore header hicn_packet_copy_header(format, &header_copy, packet->packet_start_, false); + + // Restore bitmap in interest manifest + if (packet->isInterest()) { + core::Interest *interest = dynamic_cast<core::Interest *>(packet); + interest->setRequestBitmap(request_bitmap); + } } void Signer::signBuffer(const std::vector<uint8_t> &buffer) { @@ -241,16 +257,23 @@ void AsymmetricSigner::setKey(CryptoSuite suite, std::shared_ptr<EVP_PKEY> key, std::shared_ptr<EVP_PKEY> pub_key) { suite_ = suite; key_ = key; - signature_len_ = EVP_PKEY_size(key.get()); + + signature_len_ = EVP_PKEY_size(key_.get()); DCHECK(signature_len_ <= signature_->tailroom()); + signature_->setLength(signature_len_); - std::vector<uint8_t> pbk(i2d_PublicKey(pub_key.get(), nullptr)); - uint8_t *pbk_ptr = pbk.data(); - int len = i2d_PublicKey(pub_key.get(), &pbk_ptr); + size_t enc_pbk_len = i2d_PublicKey(pub_key.get(), nullptr); + DCHECK(enc_pbk_len >= 0); + + uint8_t *enc_pbkey_raw = nullptr; + i2d_PublicKey(pub_key.get(), &enc_pbkey_raw); + DCHECK(enc_pbkey_raw != nullptr); key_id_ = CryptoHash(getHashType()); - key_id_.computeDigest(pbk_ptr, len); + key_id_.computeDigest(enc_pbkey_raw, enc_pbk_len); + + OPENSSL_free(enc_pbkey_raw); } size_t AsymmetricSigner::getSignatureFieldSize() const { diff --git a/libtransport/src/auth/verifier.cc b/libtransport/src/auth/verifier.cc index 5d5f01711..e257582f6 100644 --- a/libtransport/src/auth/verifier.cc +++ b/libtransport/src/auth/verifier.cc @@ -15,6 +15,7 @@ #include <hicn/transport/auth/verifier.h> #include <hicn/transport/core/global_object_pool.h> +#include <hicn/transport/core/interest.h> #include <protocols/errors.h> #include "glog/logging.h" @@ -51,6 +52,14 @@ bool Verifier::verifyPacket(PacketPtr packet) { hicn_header_t header_copy; hicn_packet_copy_header(format, packet->packet_start_, &header_copy, false); + // Copy bitmap from interest manifest + uint32_t request_bitmap[BITMAP_SIZE] = {0}; + if (packet->isInterest()) { + core::Interest *interest = dynamic_cast<core::Interest *>(packet); + memcpy(request_bitmap, interest->getRequestBitmap(), + BITMAP_SIZE * sizeof(uint32_t)); + } + // Retrieve packet signature utils::MemBuf::Ptr signature_raw = packet->getSignature(); std::size_t signature_len = packet->getSignatureSize(); @@ -69,6 +78,12 @@ bool Verifier::verifyPacket(PacketPtr packet) { packet->setSignature(signature_raw); packet->setSignatureSize(signature_raw->length()); + // Restore bitmap in interest manifest + if (packet->isInterest()) { + core::Interest *interest = dynamic_cast<core::Interest *>(packet); + interest->setRequestBitmap(request_bitmap); + } + return valid_packet; } diff --git a/libtransport/src/core/CMakeLists.txt b/libtransport/src/core/CMakeLists.txt index b9b024d60..777772a04 100644 --- a/libtransport/src/core/CMakeLists.txt +++ b/libtransport/src/core/CMakeLists.txt @@ -14,17 +14,18 @@ list(APPEND HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/facade.h ${CMAKE_CURRENT_SOURCE_DIR}/manifest.h - ${CMAKE_CURRENT_SOURCE_DIR}/manifest_inline.h ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format_fixed.h ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format.h ${CMAKE_CURRENT_SOURCE_DIR}/pending_interest.h ${CMAKE_CURRENT_SOURCE_DIR}/portal.h ${CMAKE_CURRENT_SOURCE_DIR}/errors.h ${CMAKE_CURRENT_SOURCE_DIR}/global_configuration.h + ${CMAKE_CURRENT_SOURCE_DIR}/global_id_counter.h ${CMAKE_CURRENT_SOURCE_DIR}/local_connector.h ${CMAKE_CURRENT_SOURCE_DIR}/global_workers.h ${CMAKE_CURRENT_SOURCE_DIR}/udp_connector.h ${CMAKE_CURRENT_SOURCE_DIR}/udp_listener.h + ${CMAKE_CURRENT_SOURCE_DIR}/global_module_manager.h ) list(APPEND SOURCE_FILES @@ -38,9 +39,9 @@ list(APPEND SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/portal.cc ${CMAKE_CURRENT_SOURCE_DIR}/global_configuration.cc ${CMAKE_CURRENT_SOURCE_DIR}/io_module.cc - ${CMAKE_CURRENT_SOURCE_DIR}/local_connector.cc ${CMAKE_CURRENT_SOURCE_DIR}/udp_connector.cc ${CMAKE_CURRENT_SOURCE_DIR}/udp_listener.cc + ${CMAKE_CURRENT_SOURCE_DIR}/constructor.cc ) if (NOT ${CMAKE_SYSTEM_NAME} MATCHES Android) @@ -56,4 +57,4 @@ if (NOT ${CMAKE_SYSTEM_NAME} MATCHES Android) endif() set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) diff --git a/libtransport/src/core/constructor.cc b/libtransport/src/core/constructor.cc new file mode 100644 index 000000000..0c7f0dfa8 --- /dev/null +++ b/libtransport/src/core/constructor.cc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <core/global_configuration.h> +#include <core/global_module_manager.h> +#include <core/global_workers.h> +#include <hicn/transport/core/global_object_pool.h> + +namespace transport { +namespace core { + +void __attribute__((constructor)) libtransportInit() { + // First the global module manager is initialized + GlobalModuleManager::getInstance(); + // Then the packet allocator is initialized + PacketManager<>::getInstance(); + // Then the global configuration is initialized + GlobalConfiguration::getInstance(); + // Then the global workers are initialized + GlobalWorkers::getInstance(); +} + +} // namespace core +} // namespace transport
\ No newline at end of file diff --git a/libtransport/src/core/content_object.cc b/libtransport/src/core/content_object.cc index 643e0388e..e66b2a6cd 100644 --- a/libtransport/src/core/content_object.cc +++ b/libtransport/src/core/content_object.cc @@ -15,6 +15,7 @@ #include <hicn/transport/core/content_object.h> #include <hicn/transport/errors/errors.h> +#include <hicn/transport/portability/endianess.h> #include <hicn/transport/utils/branch_prediction.h> extern "C" { @@ -46,7 +47,7 @@ ContentObject::ContentObject(const Name &name, Packet::Format format, } if (TRANSPORT_EXPECT_FALSE(hicn_data_get_name(format_, packet_start_, - name_.getStructReference()) < + &name_.getStructReference()) < 0)) { throw errors::MalformedPacketException(); } @@ -91,7 +92,7 @@ ContentObject::~ContentObject() {} const Name &ContentObject::getName() const { if (!name_) { if (hicn_data_get_name(format_, packet_start_, - (hicn_name_t *)name_.getConstStructReference()) < + (hicn_name_t *)&name_.getConstStructReference()) < 0) { throw errors::MalformedPacketException(); } @@ -104,11 +105,11 @@ Name &ContentObject::getWritableName() { return const_cast<Name &>(getName()); } void ContentObject::setName(const Name &name) { if (hicn_data_set_name(format_, packet_start_, - name.getConstStructReference()) < 0) { + &name.getConstStructReference()) < 0) { throw errors::RuntimeException("Error setting content object name."); } - if (hicn_data_get_name(format_, packet_start_, name_.getStructReference()) < + if (hicn_data_get_name(format_, packet_start_, &name_.getStructReference()) < 0) { throw errors::MalformedPacketException(); } @@ -121,11 +122,11 @@ uint32_t ContentObject::getPathLabel() const { "Error retrieving the path label from content object"); } - return ntohl(path_label); + return portability::net_to_host(path_label); } ContentObject &ContentObject::setPathLabel(uint32_t path_label) { - path_label = htonl(path_label); + path_label = portability::host_to_net(path_label); if (hicn_data_set_path_label((hicn_header_t *)packet_start_, path_label) < 0) { throw errors::RuntimeException( diff --git a/libtransport/src/core/facade.h b/libtransport/src/core/facade.h index 1ad4437e2..77c1d16d2 100644 --- a/libtransport/src/core/facade.h +++ b/libtransport/src/core/facade.h @@ -15,16 +15,16 @@ #pragma once +#include <core/manifest.h> #include <core/manifest_format_fixed.h> -#include <core/manifest_inline.h> #include <core/portal.h> namespace transport { namespace core { -using ContentObjectManifest = core::ManifestInline<ContentObject, Fixed>; -using InterestManifest = core::ManifestInline<Interest, Fixed>; +using ContentObjectManifest = core::Manifest<Fixed>; +using InterestManifest = core::Manifest<Fixed>; } // namespace core diff --git a/libtransport/src/io_modules/forwarder/global_id_counter.h b/libtransport/src/core/global_id_counter.h index 0a67b76d5..0a67b76d5 100644 --- a/libtransport/src/io_modules/forwarder/global_id_counter.h +++ b/libtransport/src/core/global_id_counter.h diff --git a/libtransport/src/core/global_module_manager.h b/libtransport/src/core/global_module_manager.h new file mode 100644 index 000000000..c9d272cdb --- /dev/null +++ b/libtransport/src/core/global_module_manager.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <glog/logging.h> +#include <hicn/transport/utils/singleton.h> + +#ifndef _WIN32 +#include <dlfcn.h> +#endif + +#include <atomic> +#include <iostream> +#include <mutex> +#include <unordered_map> + +namespace transport { +namespace core { + +class GlobalModuleManager : public utils::Singleton<GlobalModuleManager> { + public: + friend class utils::Singleton<GlobalModuleManager>; + + ~GlobalModuleManager() { + for (const auto &[key, value] : modules_) { + unload(value); + } + } + + void *loadModule(const std::string &module_name) { + void *handle = nullptr; + const char *error = nullptr; + + // Lock + std::unique_lock lck(mtx_); + + auto it = modules_.find(module_name); + if (it != modules_.end()) { + return it->second; + } + + // open module + handle = dlopen(module_name.c_str(), RTLD_NOW); + if (!handle) { + if ((error = dlerror()) != nullptr) { + LOG(ERROR) << error; + } + return nullptr; + } + + auto ret = modules_.try_emplace(module_name, handle); + DCHECK(ret.second); + + return handle; + } + + void unload(void *handle) { + // destroy object and close module + dlclose(handle); + } + + bool unloadModule(const std::string &module_name) { + // Lock + std::unique_lock lck(mtx_); + auto it = modules_.find(module_name); + if (it != modules_.end()) { + unload(it->second); + return true; + } + + return false; + } + + private: + GlobalModuleManager() = default; + std::mutex mtx_; + std::unordered_map<std::string, void *> modules_; +}; + +} // namespace core +} // namespace transport
\ No newline at end of file diff --git a/libtransport/src/core/global_workers.h b/libtransport/src/core/global_workers.h index 1ac254188..c5d794ef2 100644 --- a/libtransport/src/core/global_workers.h +++ b/libtransport/src/core/global_workers.h @@ -32,6 +32,8 @@ class GlobalWorkers : public utils::Singleton<GlobalWorkers> { return thread_pool_.getWorker(counter_++ % thread_pool_.getNThreads()); } + auto& getWorkers() { return thread_pool_.getWorkers(); } + private: GlobalWorkers() : counter_(0), thread_pool_() {} diff --git a/libtransport/src/core/interest.cc b/libtransport/src/core/interest.cc index b7719b3ed..8b9dcf256 100644 --- a/libtransport/src/core/interest.cc +++ b/libtransport/src/core/interest.cc @@ -21,6 +21,7 @@ extern "C" { #ifndef _WIN32 TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat") #endif +#include <hicn/base.h> #include <hicn/hicn.h> } @@ -39,12 +40,12 @@ Interest::Interest(const Name &interest_name, Packet::Format format, } if (hicn_interest_set_name(format_, packet_start_, - interest_name.getConstStructReference()) < 0) { + &interest_name.getConstStructReference()) < 0) { throw errors::MalformedPacketException(); } if (hicn_interest_get_name(format_, packet_start_, - name_.getStructReference()) < 0) { + &name_.getStructReference()) < 0) { throw errors::MalformedPacketException(); } } @@ -64,7 +65,7 @@ Interest::Interest(hicn_format_t format, std::size_t additional_header_size) Interest::Interest(MemBuf &&buffer) : Packet(std::move(buffer)) { if (hicn_interest_get_name(format_, packet_start_, - name_.getStructReference()) < 0) { + &name_.getStructReference()) < 0) { throw errors::MalformedPacketException(); } } @@ -86,9 +87,9 @@ Interest::~Interest() {} const Name &Interest::getName() const { if (!name_) { - if (hicn_interest_get_name(format_, packet_start_, - (hicn_name_t *)name_.getConstStructReference()) < - 0) { + if (hicn_interest_get_name( + format_, packet_start_, + (hicn_name_t *)&name_.getConstStructReference()) < 0) { throw errors::MalformedPacketException(); } } @@ -100,12 +101,12 @@ Name &Interest::getWritableName() { return const_cast<Name &>(getName()); } void Interest::setName(const Name &name) { if (hicn_interest_set_name(format_, packet_start_, - name.getConstStructReference()) < 0) { + &name.getConstStructReference()) < 0) { throw errors::RuntimeException("Error setting interest name."); } if (hicn_interest_get_name(format_, packet_start_, - name_.getStructReference()) < 0) { + &name_.getStructReference()) < 0) { throw errors::MalformedPacketException(); } } @@ -150,6 +151,13 @@ void Interest::resetForHash() { throw errors::RuntimeException( "Error resetting interest fields for hash computation."); } + + // Reset request bitmap in manifest + if (hasManifest()) { + auto int_manifest_header = + (interest_manifest_header_t *)(writableData() + headerSize()); + memset(int_manifest_header->request_bitmap, 0, BITMAP_SIZE * sizeof(u32)); + } } bool Interest::hasManifest() { @@ -171,19 +179,21 @@ void Interest::encodeSuffixes() { // We assume interest does not hold signature for the moment. auto int_manifest_header = - (InterestManifestHeader *)(writableData() + headerSize()); - int_manifest_header->n_suffixes = suffix_set_.size(); - std::size_t additional_length = - sizeof(InterestManifestHeader) + - int_manifest_header->n_suffixes * sizeof(uint32_t); + (interest_manifest_header_t *)(writableData() + headerSize()); + int_manifest_header->n_suffixes = (uint32_t)suffix_set_.size(); + memset(int_manifest_header->request_bitmap, 0xFFFFFFFF, + BITMAP_SIZE * sizeof(u32)); uint32_t *suffix = (uint32_t *)(int_manifest_header + 1); for (auto it = suffix_set_.begin(); it != suffix_set_.end(); it++, suffix++) { *suffix = *it; } + std::size_t additional_length = + sizeof(interest_manifest_header_t) + + int_manifest_header->n_suffixes * sizeof(uint32_t); append(additional_length); - updateLength(additional_length); + updateLength(); } uint32_t *Interest::firstSuffix() { @@ -191,7 +201,7 @@ uint32_t *Interest::firstSuffix() { return nullptr; } - auto ret = (InterestManifestHeader *)(writableData() + headerSize()); + auto ret = (interest_manifest_header_t *)(writableData() + headerSize()); ret += 1; return (uint32_t *)ret; @@ -202,11 +212,48 @@ uint32_t Interest::numberOfSuffixes() { return 0; } - auto header = (InterestManifestHeader *)(writableData() + headerSize()); + auto header = (interest_manifest_header_t *)(writableData() + headerSize()); return header->n_suffixes; } +uint32_t *Interest::getRequestBitmap() { + if (!hasManifest()) return nullptr; + + auto header = (interest_manifest_header_t *)(writableData() + headerSize()); + return header->request_bitmap; +} + +void Interest::setRequestBitmap(const uint32_t *request_bitmap) { + if (!hasManifest()) return; + + auto header = (interest_manifest_header_t *)(writableData() + headerSize()); + memcpy(header->request_bitmap, request_bitmap, + BITMAP_SIZE * sizeof(uint32_t)); +} + +bool Interest::isValid() { + if (!hasManifest()) return true; + + auto header = (interest_manifest_header_t *)(writableData() + headerSize()); + + if (header->n_suffixes == 0 || + header->n_suffixes > MAX_SUFFIXES_IN_MANIFEST) { + std::cerr << "Manifest with invalid number of suffixes " + << header->n_suffixes; + return false; + } + + uint32_t empty_bitmap[BITMAP_SIZE]; + memset(empty_bitmap, 0, sizeof(empty_bitmap)); + if (memcmp(empty_bitmap, header->request_bitmap, sizeof(empty_bitmap)) == 0) { + std::cerr << "Manifest with empty bitmap"; + return false; + } + + return true; +} + } // end namespace core } // end namespace transport diff --git a/libtransport/src/core/io_module.cc b/libtransport/src/core/io_module.cc index 69e4e8bcf..0f92cc47c 100644 --- a/libtransport/src/core/io_module.cc +++ b/libtransport/src/core/io_module.cc @@ -16,6 +16,7 @@ #ifndef _WIN32 #include <dlfcn.h> #endif +#include <core/global_module_manager.h> #include <glog/logging.h> #include <hicn/transport/core/io_module.h> @@ -38,54 +39,28 @@ IoModule *IoModule::load(const char *module_name) { #ifdef ANDROID return new HicnForwarderModule(); #else - void *handle = 0; - IoModule *module = 0; - IoModule *(*creator)(void) = 0; - const char *error = 0; + IoModule *iomodule = nullptr; + IoModule *(*creator)(void) = nullptr; + const char *error = nullptr; - // open module - handle = dlopen(module_name, RTLD_NOW); - if (!handle) { - if ((error = dlerror()) != 0) { - LOG(ERROR) << error; - } - return 0; - } + auto handle = GlobalModuleManager::getInstance().loadModule(module_name); // get factory method creator = (IoModule * (*)(void)) dlsym(handle, "create_module"); if (!creator) { - if ((error = dlerror()) != 0) { + if ((error = dlerror()) != nullptr) { LOG(ERROR) << error; } - return 0; + return nullptr; } // create object and return it - module = (*creator)(); - module->handle_ = handle; + iomodule = (*creator)(); - return module; + return iomodule; #endif } -bool IoModule::unload(IoModule *module) { - if (!module) { - return false; - } - -#ifdef ANDROID - delete module; -#else - // destroy object and close module - void *handle = module->handle_; - delete module; - dlclose(handle); -#endif - - return true; -} - } // namespace core } // namespace transport diff --git a/libtransport/src/core/local_connector.cc b/libtransport/src/core/local_connector.cc deleted file mode 100644 index f27be2e5c..000000000 --- a/libtransport/src/core/local_connector.cc +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <core/local_connector.h> -#include <glog/logging.h> -#include <hicn/transport/core/asio_wrapper.h> -#include <hicn/transport/core/content_object.h> -#include <hicn/transport/core/interest.h> -#include <hicn/transport/errors/not_implemented_exception.h> - -namespace transport { -namespace core { - -LocalConnector::~LocalConnector() {} - -void LocalConnector::close() { state_ = State::CLOSED; } - -void LocalConnector::send(Packet &packet) { - if (!isConnected()) { - return; - } - - auto buffer = - std::static_pointer_cast<utils::MemBuf>(packet.shared_from_this()); - - DLOG_IF(INFO, VLOG_IS_ON(3)) << "Sending packet to local socket."; - io_service_.get().post([this, buffer]() mutable { - std::vector<utils::MemBuf::Ptr> v{std::move(buffer)}; - receive_callback_(this, v, std::make_error_code(std::errc(0))); - }); -} - -void LocalConnector::send(const utils::MemBuf::Ptr &buffer) { - throw errors::NotImplementedException(); -} - -} // namespace core -} // namespace transport
\ No newline at end of file diff --git a/libtransport/src/core/local_connector.h b/libtransport/src/core/local_connector.h index eede89e74..963f455e6 100644 --- a/libtransport/src/core/local_connector.h +++ b/libtransport/src/core/local_connector.h @@ -15,9 +15,11 @@ #pragma once +#include <core/errors.h> #include <hicn/transport/core/asio_wrapper.h> #include <hicn/transport/core/connector.h> #include <hicn/transport/core/global_object_pool.h> +#include <hicn/transport/errors/not_implemented_exception.h> #include <hicn/transport/utils/move_wrapper.h> #include <hicn/transport/utils/shared_ptr_utils.h> #include <io_modules/forwarder/errors.h> @@ -34,19 +36,48 @@ class LocalConnector : public Connector { OnClose &&close_callback, OnReconnect &&on_reconnect) : Connector(receive_callback, packet_sent, close_callback, on_reconnect), io_service_(io_service), - io_service_work_(io_service_.get()) { - state_ = State::CONNECTED; - } + io_service_work_(io_service_.get()) {} - ~LocalConnector() override; + ~LocalConnector() override = default; - void send(Packet &packet) override; + auto shared_from_this() { return utils::shared_from(this); } - void send(const utils::MemBuf::Ptr &buffer) override; + void send(Packet &packet) override { send(packet.shared_from_this()); } - void close() override; + void send(const utils::MemBuf::Ptr &buffer) override { + throw errors::NotImplementedException(); + } - auto shared_from_this() { return utils::shared_from(this); } + void receive(const std::vector<utils::MemBuf::Ptr> &buffers) override { + DLOG_IF(INFO, VLOG_IS_ON(3)) << "Sending packet to local socket."; + std::weak_ptr<LocalConnector> self = shared_from_this(); + io_service_.get().post([self, _buffers{std::move(buffers)}]() mutable { + if (auto ptr = self.lock()) { + ptr->receive_callback_(ptr.get(), _buffers, + make_error_code(core_error::success)); + } + }); + } + + void reconnect() override { + state_ = State::CONNECTED; + std::weak_ptr<LocalConnector> self = shared_from_this(); + io_service_.get().post([self]() { + if (auto ptr = self.lock()) { + ptr->on_reconnect_callback_(ptr.get(), + make_error_code(core_error::success)); + } + }); + } + + void close() override { + std::weak_ptr<LocalConnector> self = shared_from_this(); + io_service_.get().post([self]() mutable { + if (auto ptr = self.lock()) { + ptr->on_close_callback_(ptr.get()); + } + }); + } private: std::reference_wrapper<asio::io_service> io_service_; diff --git a/libtransport/src/core/manifest.cc b/libtransport/src/core/manifest.cc deleted file mode 100644 index da2689426..000000000 --- a/libtransport/src/core/manifest.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <hicn/transport/core/manifest.h> - -namespace transport { - -namespace core { - -std::string ManifestEncoding::manifest_type = std::string("manifest_type"); - -std::map<ManifestType, std::string> ManifestEncoding::manifest_types = { - {FINAL_CHUNK_NUMBER, "FinalChunkNumber"}, {NAME_LIST, "NameList"}}; - -std::string ManifestEncoding::final_chunk_number = - std::string("final_chunk_number"); -std::string ManifestEncoding::content_name = std::string("content_name"); - -} // end namespace core - -} // end namespace transport
\ No newline at end of file diff --git a/libtransport/src/core/manifest.h b/libtransport/src/core/manifest.h index 5bdbfc6ff..40832bb6b 100644 --- a/libtransport/src/core/manifest.h +++ b/libtransport/src/core/manifest.h @@ -17,165 +17,72 @@ #include <core/manifest_format.h> #include <glog/logging.h> -#include <hicn/transport/core/content_object.h> -#include <hicn/transport/core/name.h> - -#include <set> +#include <hicn/transport/auth/verifier.h> +#include <hicn/transport/core/global_object_pool.h> +#include <hicn/transport/core/packet.h> namespace transport { - namespace core { -using typename core::Name; -using typename core::Packet; -using typename core::PayloadType; - -template <typename Base, typename FormatTraits, typename ManifestImpl> -class Manifest : public Base { - static_assert(std::is_base_of<Packet, Base>::value, - "Base must inherit from packet!"); - +template <typename FormatTraits> +class Manifest : public FormatTraits::Encoder, public FormatTraits::Decoder { public: - // core::ContentObjectManifest::Ptr + using Ptr = std::shared_ptr<Manifest>; using Encoder = typename FormatTraits::Encoder; using Decoder = typename FormatTraits::Decoder; - Manifest(Packet::Format format, std::size_t signature_size = 0) - : Base(format, signature_size), - encoder_(*this, signature_size), - decoder_(*this) { - DCHECK(_is_ah(format)); - Base::setPayloadType(PayloadType::MANIFEST); - } + using Hash = typename FormatTraits::Hash; + using HashType = typename FormatTraits::HashType; + using Suffix = typename FormatTraits::Suffix; + using SuffixList = typename FormatTraits::SuffixList; + using HashEntry = std::pair<auth::CryptoHashType, std::vector<uint8_t>>; - Manifest(Packet::Format format, const core::Name &name, - std::size_t signature_size = 0) - : Base(name, format, signature_size), - encoder_(*this, signature_size), - decoder_(*this) { - DCHECK(_is_ah(format)); - Base::setPayloadType(PayloadType::MANIFEST); + Manifest(Packet::Ptr packet, bool clear = false) + : Encoder(packet, clear), Decoder(packet), packet_(packet) { + packet->setPayloadType(PayloadType::MANIFEST); } - template <typename T> - Manifest(T &&base) - : Base(std::forward<T &&>(base)), - encoder_(*this, 0, false), - decoder_(*this) { - Base::setPayloadType(PayloadType::MANIFEST); - } - - // Useful for decoding manifests while avoiding packet copy - template <typename T> - Manifest(T &base) - : Base(base.getFormat()), encoder_(base, 0, false), decoder_(base) {} - virtual ~Manifest() = default; - std::size_t estimateManifestSize(std::size_t additional_entries = 0) { - return static_cast<ManifestImpl &>(*this).estimateManifestSizeImpl( - additional_entries); - } - - /* - * After the call to encode, users MUST call clear before adding data - * to the manifest. - */ - Manifest &encode() { return static_cast<ManifestImpl &>(*this).encodeImpl(); } - - Manifest &decode() { - Manifest::decoder_.decode(); - - manifest_type_ = decoder_.getType(); - manifest_transport_type_ = decoder_.getTransportType(); - hash_algorithm_ = decoder_.getHashAlgorithm(); - is_last_ = decoder_.getIsLast(); + Packet::Ptr getPacket() const { return packet_; } - return static_cast<ManifestImpl &>(*this).decodeImpl(); + void setHeaders(ManifestType type, uint8_t max_capacity, HashType hash_algo, + bool is_last, const Name &base_name) { + Encoder::setType(type); + Encoder::setMaxCapacity(max_capacity); + Encoder::setHashAlgorithm(hash_algo); + Encoder::setIsLast(is_last); + Encoder::setBaseName(base_name); } - static std::size_t manifestHeaderSize( - interface::ProductionProtocolAlgorithms transport_type = - interface::ProductionProtocolAlgorithms::UNKNOWN) { - return Encoder::manifestHeaderSize(transport_type); - } + auth::Verifier::SuffixMap getSuffixMap() const { + auth::Verifier::SuffixMap suffix_map; - static std::size_t manifestEntrySize() { - return Encoder::manifestEntrySize(); - } + HashType hash_algo = Decoder::getHashAlgorithm(); + SuffixList suffix_list = Decoder::getEntries(); - Manifest &setType(ManifestType type) { - manifest_type_ = type; - encoder_.setType(manifest_type_); - return *this; - } + for (auto it = suffix_list.begin(); it != suffix_list.end(); ++it) { + Hash hash(it->second, Hash::getSize(hash_algo), hash_algo); + suffix_map[it->first] = hash; + } - Manifest &setHashAlgorithm(auth::CryptoHashType hash_algorithm) { - hash_algorithm_ = hash_algorithm; - encoder_.setHashAlgorithm(hash_algorithm_); - return *this; + return suffix_map; } - auth::CryptoHashType getHashAlgorithm() const { return hash_algorithm_; } - - ManifestType getType() const { return manifest_type_; } - - interface::ProductionProtocolAlgorithms getTransportType() const { - return manifest_transport_type_; - } - - bool getIsLast() const { return is_last_; } - - Manifest &setVersion(ManifestVersion version) { - encoder_.setVersion(version); - return *this; - } - - Manifest &setParamsBytestream(const ParamsBytestream ¶ms) { - manifest_transport_type_ = - interface::ProductionProtocolAlgorithms::BYTE_STREAM; - encoder_.setParamsBytestream(params); - return *this; - } - - Manifest &setParamsRTC(const ParamsRTC ¶ms) { - manifest_transport_type_ = - interface::ProductionProtocolAlgorithms::RTC_PROD; - encoder_.setParamsRTC(params); - return *this; - } - - ParamsBytestream getParamsBytestream() const { - return decoder_.getParamsBytestream(); - } - - ParamsRTC getParamsRTC() const { return decoder_.getParamsRTC(); } - - ManifestVersion getVersion() const { return decoder_.getVersion(); } - - Manifest &setIsLast(bool is_last) { - encoder_.setIsLast(is_last); - is_last_ = is_last; - return *this; - } - - Manifest &clear() { - encoder_.clear(); - decoder_.clear(); - return *this; - } + static Manifest::Ptr createContentManifest(Packet::Format format, + const core::Name &manifest_name, + std::size_t signature_size) { + ContentObject::Ptr content_object = + core::PacketManager<>::getInstance().getPacket<ContentObject>( + format, signature_size); + content_object->setName(manifest_name); + return std::make_shared<Manifest>(content_object, true); + }; protected: - ManifestType manifest_type_; - interface::ProductionProtocolAlgorithms manifest_transport_type_; - auth::CryptoHashType hash_algorithm_; - bool is_last_; - - Encoder encoder_; - Decoder decoder_; + Packet::Ptr packet_; }; } // end namespace core - } // end namespace transport diff --git a/libtransport/src/core/manifest_format.h b/libtransport/src/core/manifest_format.h index caee210cd..89412316a 100644 --- a/libtransport/src/core/manifest_format.h +++ b/libtransport/src/core/manifest_format.h @@ -25,13 +25,8 @@ #include <unordered_map> namespace transport { - namespace core { -enum class ManifestVersion : uint8_t { - VERSION_1 = 1, -}; - enum class ManifestType : uint8_t { INLINE_MANIFEST = 1, FINAL_CHUNK_NUMBER = 2, @@ -83,14 +78,27 @@ class ManifestEncoder { return static_cast<Implementation &>(*this).clearImpl(); } + bool isEncoded() const { + return static_cast<const Implementation &>(*this).isEncodedImpl(); + } + ManifestEncoder &setType(ManifestType type) { return static_cast<Implementation &>(*this).setTypeImpl(type); } + ManifestEncoder &setMaxCapacity(uint8_t max_capacity) { + return static_cast<Implementation &>(*this).setMaxCapacityImpl( + max_capacity); + } + ManifestEncoder &setHashAlgorithm(auth::CryptoHashType hash) { return static_cast<Implementation &>(*this).setHashAlgorithmImpl(hash); } + ManifestEncoder &setIsLast(bool is_last) { + return static_cast<Implementation &>(*this).setIsLastImpl(is_last); + } + template < typename T, typename = std::enable_if_t<std::is_same< @@ -99,45 +107,36 @@ class ManifestEncoder { return static_cast<Implementation &>(*this).setBaseNameImpl(name); } - template <typename Hash> - ManifestEncoder &addSuffixAndHash(uint32_t suffix, Hash &&hash) { - return static_cast<Implementation &>(*this).addSuffixAndHashImpl( - suffix, std::forward<Hash &&>(hash)); + ManifestEncoder &setParamsBytestream(const ParamsBytestream ¶ms) { + return static_cast<Implementation &>(*this).setParamsBytestreamImpl(params); } - ManifestEncoder &setIsLast(bool is_last) { - return static_cast<Implementation &>(*this).setIsLastImpl(is_last); + ManifestEncoder &setParamsRTC(const ParamsRTC ¶ms) { + return static_cast<Implementation &>(*this).setParamsRTCImpl(params); } - ManifestEncoder &setVersion(ManifestVersion version) { - return static_cast<Implementation &>(*this).setVersionImpl(version); + template <typename Hash> + ManifestEncoder &addEntry(uint32_t suffix, Hash &&hash) { + return static_cast<Implementation &>(*this).addEntryImpl( + suffix, std::forward<Hash>(hash)); } - std::size_t estimateSerializedLength(std::size_t number_of_entries) { - return static_cast<Implementation &>(*this).estimateSerializedLengthImpl( - number_of_entries); + ManifestEncoder &removeEntry(uint32_t suffix) { + return static_cast<Implementation &>(*this).removeEntryImpl(suffix); } - ManifestEncoder &update() { - return static_cast<Implementation &>(*this).updateImpl(); + std::size_t manifestHeaderSize() const { + return static_cast<const Implementation &>(*this).manifestHeaderSizeImpl(); } - ManifestEncoder &setParamsBytestream(const ParamsBytestream ¶ms) { - return static_cast<Implementation &>(*this).setParamsBytestreamImpl(params); + std::size_t manifestPayloadSize(size_t additional_entries = 0) const { + return static_cast<const Implementation &>(*this).manifestPayloadSizeImpl( + additional_entries); } - ManifestEncoder &setParamsRTC(const ParamsRTC ¶ms) { - return static_cast<Implementation &>(*this).setParamsRTCImpl(params); - } - - static std::size_t manifestHeaderSize( - interface::ProductionProtocolAlgorithms transport_type = - interface::ProductionProtocolAlgorithms::UNKNOWN) { - return Implementation::manifestHeaderSizeImpl(transport_type); - } - - static std::size_t manifestEntrySize() { - return Implementation::manifestEntrySizeImpl(); + std::size_t manifestSize(size_t additional_entries = 0) const { + return static_cast<const Implementation &>(*this).manifestSizeImpl( + additional_entries); } }; @@ -146,11 +145,17 @@ class ManifestDecoder { public: virtual ~ManifestDecoder() = default; + ManifestDecoder &decode() { + return static_cast<Implementation &>(*this).decodeImpl(); + } + ManifestDecoder &clear() { return static_cast<Implementation &>(*this).clearImpl(); } - void decode() { static_cast<Implementation &>(*this).decodeImpl(); } + bool isDecoded() const { + return static_cast<const Implementation &>(*this).isDecodedImpl(); + } ManifestType getType() const { return static_cast<const Implementation &>(*this).getTypeImpl(); @@ -160,40 +165,48 @@ class ManifestDecoder { return static_cast<const Implementation &>(*this).getTransportTypeImpl(); } + uint8_t getMaxCapacity() const { + return static_cast<const Implementation &>(*this).getMaxCapacityImpl(); + } + auth::CryptoHashType getHashAlgorithm() const { return static_cast<const Implementation &>(*this).getHashAlgorithmImpl(); } + bool getIsLast() const { + return static_cast<const Implementation &>(*this).getIsLastImpl(); + } + core::Name getBaseName() const { return static_cast<const Implementation &>(*this).getBaseNameImpl(); } - auto getSuffixHashList() { - return static_cast<Implementation &>(*this).getSuffixHashListImpl(); + ParamsBytestream getParamsBytestream() const { + return static_cast<const Implementation &>(*this).getParamsBytestreamImpl(); } - bool getIsLast() const { - return static_cast<const Implementation &>(*this).getIsLastImpl(); + ParamsRTC getParamsRTC() const { + return static_cast<const Implementation &>(*this).getParamsRTCImpl(); } - ManifestVersion getVersion() const { - return static_cast<const Implementation &>(*this).getVersionImpl(); + auto getEntries() const { + return static_cast<const Implementation &>(*this).getEntriesImpl(); } - std::size_t estimateSerializedLength(std::size_t number_of_entries) const { - return static_cast<const Implementation &>(*this) - .estimateSerializedLengthImpl(number_of_entries); + std::size_t manifestHeaderSize() const { + return static_cast<const Implementation &>(*this).manifestHeaderSizeImpl(); } - ParamsBytestream getParamsBytestream() const { - return static_cast<const Implementation &>(*this).getParamsBytestreamImpl(); + std::size_t manifestPayloadSize(size_t additional_entries = 0) const { + return static_cast<const Implementation &>(*this).manifestPayloadSizeImpl( + additional_entries); } - ParamsRTC getParamsRTC() const { - return static_cast<const Implementation &>(*this).getParamsRTCImpl(); + std::size_t manifestSize(size_t additional_entries = 0) const { + return static_cast<const Implementation &>(*this).manifestSizeImpl( + additional_entries); } }; } // namespace core - } // namespace transport diff --git a/libtransport/src/core/manifest_format_fixed.cc b/libtransport/src/core/manifest_format_fixed.cc index 428d6ad12..668169642 100644 --- a/libtransport/src/core/manifest_format_fixed.cc +++ b/libtransport/src/core/manifest_format_fixed.cc @@ -18,22 +18,42 @@ #include <hicn/transport/utils/literals.h> namespace transport { - namespace core { -// TODO use preallocated pool of membufs -FixedManifestEncoder::FixedManifestEncoder(Packet &packet, - std::size_t signature_size, - bool clear) +// --------------------------------------------------------- +// FixedManifest +// --------------------------------------------------------- +size_t FixedManifest::manifestHeaderSize( + interface::ProductionProtocolAlgorithms transport_type) { + uint32_t params_size = 0; + + switch (transport_type) { + case interface::ProductionProtocolAlgorithms::BYTE_STREAM: + params_size = MANIFEST_PARAMS_BYTESTREAM_SIZE; + break; + case interface::ProductionProtocolAlgorithms::RTC_PROD: + params_size = MANIFEST_PARAMS_RTC_SIZE; + break; + default: + break; + } + + return MANIFEST_META_SIZE + MANIFEST_ENTRY_META_SIZE + params_size; +} + +size_t FixedManifest::manifestPayloadSize(size_t nb_entries) { + return nb_entries * MANIFEST_ENTRY_SIZE; +} + +// --------------------------------------------------------- +// FixedManifestEncoder +// --------------------------------------------------------- +FixedManifestEncoder::FixedManifestEncoder(Packet::Ptr packet, bool clear) : packet_(packet), - max_size_(Packet::default_mtu - packet_.headerSize()), - signature_size_(signature_size), transport_type_(interface::ProductionProtocolAlgorithms::UNKNOWN), - encoded_(false), - params_bytestream_({0}), - params_rtc_({0}) { - manifest_meta_ = reinterpret_cast<ManifestMeta *>(packet_.writableData() + - packet_.headerSize()); + encoded_(false) { + manifest_meta_ = reinterpret_cast<ManifestMeta *>(packet_->writableData() + + packet_->headerSize()); manifest_entry_meta_ = reinterpret_cast<ManifestEntryMeta *>(manifest_meta_ + 1); @@ -50,32 +70,34 @@ FixedManifestEncoder &FixedManifestEncoder::encodeImpl() { return *this; } + // Copy manifest header manifest_meta_->transport_type = static_cast<uint8_t>(transport_type_); manifest_entry_meta_->nb_entries = manifest_entries_.size(); - packet_.append(FixedManifestEncoder::manifestHeaderSizeImpl()); - packet_.updateLength(); + packet_->append(manifestHeaderSizeImpl()); + packet_->updateLength(); + auto params = reinterpret_cast<uint8_t *>(manifest_entry_meta_ + 1); switch (transport_type_) { - case interface::ProductionProtocolAlgorithms::BYTE_STREAM: - packet_.appendPayload( - reinterpret_cast<const uint8_t *>(¶ms_bytestream_), - MANIFEST_PARAMS_BYTESTREAM_SIZE); + case interface::ProductionProtocolAlgorithms::BYTE_STREAM: { + auto bytestream = reinterpret_cast<const uint8_t *>(¶ms_bytestream_); + std::memcpy(params, bytestream, MANIFEST_PARAMS_BYTESTREAM_SIZE); break; - case interface::ProductionProtocolAlgorithms::RTC_PROD: - packet_.appendPayload(reinterpret_cast<const uint8_t *>(¶ms_rtc_), - MANIFEST_PARAMS_RTC_SIZE); + } + case interface::ProductionProtocolAlgorithms::RTC_PROD: { + auto rtc = reinterpret_cast<const uint8_t *>(¶ms_rtc_); + std::memcpy(params, rtc, MANIFEST_PARAMS_RTC_SIZE); break; + } default: break; } - packet_.appendPayload( - reinterpret_cast<const uint8_t *>(manifest_entries_.data()), - manifest_entries_.size() * FixedManifestEncoder::manifestEntrySizeImpl()); + // Copy manifest entries + auto payload = reinterpret_cast<const uint8_t *>(manifest_entries_.data()); + packet_->appendPayload(payload, manifestPayloadSizeImpl()); - if (TRANSPORT_EXPECT_FALSE(packet_.payloadSize() < - estimateSerializedLengthImpl())) { + if (TRANSPORT_EXPECT_FALSE(packet_->payloadSize() < manifestSizeImpl())) { throw errors::RuntimeException("Error encoding the manifest"); } @@ -85,32 +107,21 @@ FixedManifestEncoder &FixedManifestEncoder::encodeImpl() { FixedManifestEncoder &FixedManifestEncoder::clearImpl() { if (encoded_) { - packet_.trimEnd(FixedManifestEncoder::manifestHeaderSizeImpl() + - manifest_entries_.size() * - FixedManifestEncoder::manifestEntrySizeImpl()); + packet_->trimEnd(manifestSizeImpl()); } transport_type_ = interface::ProductionProtocolAlgorithms::UNKNOWN; encoded_ = false; - params_bytestream_ = {0}; - params_rtc_ = {0}; *manifest_meta_ = {0}; *manifest_entry_meta_ = {0}; + params_bytestream_ = {0}; + params_rtc_ = {0}; manifest_entries_.clear(); return *this; } -FixedManifestEncoder &FixedManifestEncoder::updateImpl() { - max_size_ = Packet::default_mtu - packet_.headerSize() - signature_size_; - return *this; -} - -FixedManifestEncoder &FixedManifestEncoder::setVersionImpl( - ManifestVersion version) { - manifest_meta_->version = static_cast<uint8_t>(version); - return *this; -} +bool FixedManifestEncoder::isEncodedImpl() const { return encoded_; } FixedManifestEncoder &FixedManifestEncoder::setTypeImpl( ManifestType manifest_type) { @@ -118,6 +129,12 @@ FixedManifestEncoder &FixedManifestEncoder::setTypeImpl( return *this; } +FixedManifestEncoder &FixedManifestEncoder::setMaxCapacityImpl( + uint8_t max_capacity) { + manifest_meta_->max_capacity = max_capacity; + return *this; +} + FixedManifestEncoder &FixedManifestEncoder::setHashAlgorithmImpl( auth::CryptoHashType algorithm) { manifest_meta_->hash_algorithm = static_cast<uint8_t>(algorithm); @@ -159,61 +176,68 @@ FixedManifestEncoder &FixedManifestEncoder::setParamsRTCImpl( return *this; } -FixedManifestEncoder &FixedManifestEncoder::addSuffixAndHashImpl( +FixedManifestEncoder &FixedManifestEncoder::addEntryImpl( uint32_t suffix, const auth::CryptoHash &hash) { - manifest_entries_.push_back(ManifestEntry{ - .suffix = htonl(suffix), + ManifestEntry last_entry = { + .suffix = portability::host_to_net(suffix), .hash = {0}, - }); + }; - std::memcpy(reinterpret_cast<uint8_t *>(manifest_entries_.back().hash), - hash.getDigest()->data(), hash.getSize()); - - if (TRANSPORT_EXPECT_FALSE(estimateSerializedLengthImpl() > max_size_)) { - throw errors::RuntimeException("Manifest size exceeded the packet MTU!"); - } + auto last_hash = reinterpret_cast<uint8_t *>(last_entry.hash); + std::memcpy(last_hash, hash.getDigest()->data(), hash.getSize()); + manifest_entries_.push_back(last_entry); return *this; } -std::size_t FixedManifestEncoder::estimateSerializedLengthImpl( - std::size_t additional_entries) { - return FixedManifestEncoder::manifestHeaderSizeImpl(transport_type_) + - (manifest_entries_.size() + additional_entries) * - FixedManifestEncoder::manifestEntrySizeImpl(); +FixedManifestEncoder &FixedManifestEncoder::removeEntryImpl(uint32_t suffix) { + for (auto it = manifest_entries_.begin(); it != manifest_entries_.end();) { + if (it->suffix == suffix) + it = manifest_entries_.erase(it); + else + ++it; + } + return *this; } -std::size_t FixedManifestEncoder::manifestHeaderSizeImpl( - interface::ProductionProtocolAlgorithms transport_type) { - uint32_t params_size = 0; - - switch (transport_type) { - case interface::ProductionProtocolAlgorithms::BYTE_STREAM: - params_size = MANIFEST_PARAMS_BYTESTREAM_SIZE; - break; - case interface::ProductionProtocolAlgorithms::RTC_PROD: - params_size = MANIFEST_PARAMS_RTC_SIZE; - break; - default: - break; - } +size_t FixedManifestEncoder::manifestHeaderSizeImpl() const { + return FixedManifest::manifestHeaderSize(transport_type_); +} - return MANIFEST_META_SIZE + MANIFEST_ENTRY_META_SIZE + params_size; +size_t FixedManifestEncoder::manifestPayloadSizeImpl( + size_t additional_entries) const { + return FixedManifest::manifestPayloadSize(manifest_entries_.size() + + additional_entries); } -std::size_t FixedManifestEncoder::manifestEntrySizeImpl() { - return MANIFEST_ENTRY_SIZE; +size_t FixedManifestEncoder::manifestSizeImpl(size_t additional_entries) const { + return manifestHeaderSizeImpl() + manifestPayloadSizeImpl(additional_entries); } -FixedManifestDecoder::FixedManifestDecoder(Packet &packet) +// --------------------------------------------------------- +// FixedManifestDecoder +// --------------------------------------------------------- +FixedManifestDecoder::FixedManifestDecoder(Packet::Ptr packet) : packet_(packet), decoded_(false) { manifest_meta_ = - reinterpret_cast<ManifestMeta *>(packet_.getPayload()->writableData()); + reinterpret_cast<ManifestMeta *>(packet_->getPayload()->writableData()); manifest_entry_meta_ = reinterpret_cast<ManifestEntryMeta *>(manifest_meta_ + 1); - transport_type_ = getTransportTypeImpl(); +} - switch (transport_type_) { +FixedManifestDecoder::~FixedManifestDecoder() {} + +FixedManifestDecoder &FixedManifestDecoder::decodeImpl() { + if (decoded_) { + return *this; + } + + if (packet_->payloadSize() < manifestSizeImpl()) { + throw errors::RuntimeException( + "The packet payload size does not match expected manifest size"); + } + + switch (getTransportTypeImpl()) { case interface::ProductionProtocolAlgorithms::BYTE_STREAM: params_bytestream_ = reinterpret_cast<TransportParamsBytestream *>( manifest_entry_meta_ + 1); @@ -230,25 +254,9 @@ FixedManifestDecoder::FixedManifestDecoder(Packet &packet) reinterpret_cast<ManifestEntry *>(manifest_entry_meta_ + 1); break; } -} - -FixedManifestDecoder::~FixedManifestDecoder() {} - -void FixedManifestDecoder::decodeImpl() { - if (decoded_) { - return; - } - - std::size_t packet_size = packet_.payloadSize(); - - if (packet_size < - FixedManifestEncoder::manifestHeaderSizeImpl(transport_type_) || - packet_size < estimateSerializedLengthImpl()) { - throw errors::RuntimeException( - "The packet does not match expected manifest size."); - } decoded_ = true; + return *this; } FixedManifestDecoder &FixedManifestDecoder::clearImpl() { @@ -256,20 +264,22 @@ FixedManifestDecoder &FixedManifestDecoder::clearImpl() { return *this; } +bool FixedManifestDecoder::isDecodedImpl() const { return decoded_; } + ManifestType FixedManifestDecoder::getTypeImpl() const { return static_cast<ManifestType>(manifest_meta_->type); } -ManifestVersion FixedManifestDecoder::getVersionImpl() const { - return static_cast<ManifestVersion>(manifest_meta_->version); -} - interface::ProductionProtocolAlgorithms FixedManifestDecoder::getTransportTypeImpl() const { return static_cast<interface::ProductionProtocolAlgorithms>( manifest_meta_->transport_type); } +uint8_t FixedManifestDecoder::getMaxCapacityImpl() const { + return manifest_meta_->max_capacity; +} + auth::CryptoHashType FixedManifestDecoder::getHashAlgorithmImpl() const { return static_cast<auth::CryptoHashType>(manifest_meta_->hash_algorithm); } @@ -303,26 +313,34 @@ ParamsRTC FixedManifestDecoder::getParamsRTCImpl() const { }; } -typename Fixed::SuffixList FixedManifestDecoder::getSuffixHashListImpl() { +typename Fixed::SuffixList FixedManifestDecoder::getEntriesImpl() const { typename Fixed::SuffixList hash_list; for (int i = 0; i < manifest_entry_meta_->nb_entries; i++) { - hash_list.insert(hash_list.end(), - std::make_pair(ntohl(manifest_entries_[i].suffix), - reinterpret_cast<uint8_t *>( - &manifest_entries_[i].hash[0]))); + hash_list.insert( + hash_list.end(), + std::make_pair( + portability::net_to_host(manifest_entries_[i].suffix), + reinterpret_cast<uint8_t *>(&manifest_entries_[i].hash[0]))); } return hash_list; } -std::size_t FixedManifestDecoder::estimateSerializedLengthImpl( - std::size_t additional_entries) const { - return FixedManifestEncoder::manifestHeaderSizeImpl(transport_type_) + - (manifest_entry_meta_->nb_entries + additional_entries) * - FixedManifestEncoder::manifestEntrySizeImpl(); +size_t FixedManifestDecoder::manifestHeaderSizeImpl() const { + interface::ProductionProtocolAlgorithms type = getTransportTypeImpl(); + return FixedManifest::manifestHeaderSize(type); } -} // end namespace core +size_t FixedManifestDecoder::manifestPayloadSizeImpl( + size_t additional_entries) const { + size_t nb_entries = manifest_entry_meta_->nb_entries + additional_entries; + return FixedManifest::manifestPayloadSize(nb_entries); +} +size_t FixedManifestDecoder::manifestSizeImpl(size_t additional_entries) const { + return manifestHeaderSizeImpl() + manifestPayloadSizeImpl(additional_entries); +} + +} // end namespace core } // end namespace transport diff --git a/libtransport/src/core/manifest_format_fixed.h b/libtransport/src/core/manifest_format_fixed.h index 5fd2a673d..7ab371974 100644 --- a/libtransport/src/core/manifest_format_fixed.h +++ b/libtransport/src/core/manifest_format_fixed.h @@ -28,7 +28,7 @@ namespace core { // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// |Version| Type | Transport Type| Hash Algorithm|L| Reserved | +// | Type | TTYpe | Max Capacity | Hash Algo |L| Reserved | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // Manifest Entry Metadata: @@ -106,9 +106,9 @@ struct Fixed { const size_t MANIFEST_META_SIZE = 4; struct __attribute__((__packed__)) ManifestMeta { - std::uint8_t version : 4; std::uint8_t type : 4; - std::uint8_t transport_type; + std::uint8_t transport_type : 4; + std::uint8_t max_capacity; std::uint8_t hash_algorithm; std::uint8_t is_last; }; @@ -146,22 +146,26 @@ struct __attribute__((__packed__)) ManifestEntry { }; static_assert(sizeof(ManifestEntry) == MANIFEST_ENTRY_SIZE); -static const constexpr std::uint8_t manifest_version = 1; +class FixedManifest { + public: + static size_t manifestHeaderSize( + interface::ProductionProtocolAlgorithms transport_type); + static size_t manifestPayloadSize(size_t nb_entries); +}; class FixedManifestEncoder : public ManifestEncoder<FixedManifestEncoder> { public: - FixedManifestEncoder(Packet &packet, std::size_t signature_size = 0, - bool clear = true); + FixedManifestEncoder(Packet::Ptr packet, bool clear = false); ~FixedManifestEncoder(); FixedManifestEncoder &encodeImpl(); FixedManifestEncoder &clearImpl(); - FixedManifestEncoder &updateImpl(); + bool isEncodedImpl() const; // ManifestMeta - FixedManifestEncoder &setVersionImpl(ManifestVersion version); FixedManifestEncoder &setTypeImpl(ManifestType manifest_type); + FixedManifestEncoder &setMaxCapacityImpl(uint8_t max_capacity); FixedManifestEncoder &setHashAlgorithmImpl(Fixed::HashType algorithm); FixedManifestEncoder &setIsLastImpl(bool is_last); @@ -173,20 +177,15 @@ class FixedManifestEncoder : public ManifestEncoder<FixedManifestEncoder> { FixedManifestEncoder &setParamsRTCImpl(const ParamsRTC ¶ms); // ManifestEntry - FixedManifestEncoder &addSuffixAndHashImpl(uint32_t suffix, - const Fixed::Hash &hash); + FixedManifestEncoder &addEntryImpl(uint32_t suffix, const Fixed::Hash &hash); + FixedManifestEncoder &removeEntryImpl(uint32_t suffix); - std::size_t estimateSerializedLengthImpl(std::size_t additional_entries = 0); - - static std::size_t manifestHeaderSizeImpl( - interface::ProductionProtocolAlgorithms transport_type = - interface::ProductionProtocolAlgorithms::UNKNOWN); - static std::size_t manifestEntrySizeImpl(); + size_t manifestHeaderSizeImpl() const; + size_t manifestPayloadSizeImpl(size_t additional_entries = 0) const; + size_t manifestSizeImpl(size_t additional_entries = 0) const; private: - Packet &packet_; - std::size_t max_size_; - std::size_t signature_size_; + Packet::Ptr packet_; interface::ProductionProtocolAlgorithms transport_type_; bool encoded_; @@ -202,17 +201,18 @@ class FixedManifestEncoder : public ManifestEncoder<FixedManifestEncoder> { class FixedManifestDecoder : public ManifestDecoder<FixedManifestDecoder> { public: - FixedManifestDecoder(Packet &packet); + FixedManifestDecoder(Packet::Ptr packet); ~FixedManifestDecoder(); - void decodeImpl(); + FixedManifestDecoder &decodeImpl(); FixedManifestDecoder &clearImpl(); + bool isDecodedImpl() const; // ManifestMeta - ManifestVersion getVersionImpl() const; ManifestType getTypeImpl() const; interface::ProductionProtocolAlgorithms getTransportTypeImpl() const; + uint8_t getMaxCapacityImpl() const; Fixed::HashType getHashAlgorithmImpl() const; bool getIsLastImpl() const; @@ -224,14 +224,14 @@ class FixedManifestDecoder : public ManifestDecoder<FixedManifestDecoder> { ParamsRTC getParamsRTCImpl() const; // ManifestEntry - typename Fixed::SuffixList getSuffixHashListImpl(); + typename Fixed::SuffixList getEntriesImpl() const; - std::size_t estimateSerializedLengthImpl( - std::size_t additional_entries = 0) const; + size_t manifestHeaderSizeImpl() const; + size_t manifestPayloadSizeImpl(size_t additional_entries = 0) const; + size_t manifestSizeImpl(size_t additional_entries = 0) const; private: - Packet &packet_; - interface::ProductionProtocolAlgorithms transport_type_; + Packet::Ptr packet_; bool decoded_; // Manifest Header diff --git a/libtransport/src/core/manifest_inline.h b/libtransport/src/core/manifest_inline.h deleted file mode 100644 index ca48a4a79..000000000 --- a/libtransport/src/core/manifest_inline.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <core/manifest.h> -#include <core/manifest_format.h> -#include <hicn/transport/portability/portability.h> - -#include <set> - -namespace transport { - -namespace core { - -template <typename Base, typename FormatTraits> -class ManifestInline - : public Manifest<Base, FormatTraits, ManifestInline<Base, FormatTraits>> { - using ManifestBase = - Manifest<Base, FormatTraits, ManifestInline<Base, FormatTraits>>; - - using Hash = typename FormatTraits::Hash; - using HashType = typename FormatTraits::HashType; - using Suffix = typename FormatTraits::Suffix; - using SuffixList = typename FormatTraits::SuffixList; - using HashEntry = std::pair<auth::CryptoHashType, std::vector<uint8_t>>; - - public: - ManifestInline() : ManifestBase() {} - - ManifestInline(Packet::Format format, const core::Name &name, - std::size_t signature_size = 0) - : ManifestBase(format, name, signature_size) {} - - template <typename T> - ManifestInline(T &&base) : ManifestBase(std::forward<T &&>(base)) {} - - template <typename T> - ManifestInline(T &base) : ManifestBase(base) {} - - static TRANSPORT_ALWAYS_INLINE ManifestInline *createManifest( - Packet::Format format, const core::Name &manifest_name, - ManifestVersion version, ManifestType type, bool is_last, - const Name &base_name, HashType hash_algo, std::size_t signature_size) { - auto manifest = new ManifestInline(format, manifest_name, signature_size); - manifest->setVersion(version); - manifest->setType(type); - manifest->setHashAlgorithm(hash_algo); - manifest->setIsLast(is_last); - manifest->setBaseName(base_name); - return manifest; - } - - ManifestInline &encodeImpl() { - ManifestBase::encoder_.encode(); - return *this; - } - - ManifestInline &decodeImpl() { - base_name_ = ManifestBase::decoder_.getBaseName(); - suffix_hash_map_ = ManifestBase::decoder_.getSuffixHashList(); - - return *this; - } - - std::size_t estimateManifestSizeImpl(std::size_t additional_entries = 0) { - return ManifestBase::encoder_.estimateSerializedLength(additional_entries); - } - - ManifestInline &setBaseName(const Name &name) { - base_name_ = name; - ManifestBase::encoder_.setBaseName(base_name_); - return *this; - } - - const Name &getBaseName() { return base_name_; } - - ManifestInline &addSuffixHash(Suffix suffix, const Hash &hash) { - ManifestBase::encoder_.addSuffixAndHash(suffix, hash); - return *this; - } - - // Call this function only after the decode function! - const SuffixList &getSuffixList() { return suffix_hash_map_; } - - // Convert several manifests into a single map from suffixes to packet hashes. - // All manifests must have been decoded beforehand. - static std::unordered_map<Suffix, Hash> getSuffixMap( - const std::vector<ManifestInline *> &manifests) { - std::unordered_map<Suffix, Hash> suffix_map; - - for (auto manifest_ptr : manifests) { - HashType hash_type = manifest_ptr->getHashAlgorithm(); - SuffixList suffix_list = manifest_ptr->getSuffixList(); - - for (auto it = suffix_list.begin(); it != suffix_list.end(); ++it) { - Hash hash(it->second, Hash::getSize(hash_type), hash_type); - suffix_map[it->first] = hash; - } - } - - return suffix_map; - } - - static std::unordered_map<Suffix, Hash> getSuffixMap( - ManifestInline *manifest) { - return getSuffixMap(std::vector<ManifestInline *>{manifest}); - } - - private: - core::Name base_name_; - SuffixList suffix_hash_map_; -}; - -} // namespace core -} // namespace transport diff --git a/libtransport/src/core/name.cc b/libtransport/src/core/name.cc index 98091eea5..960947cb9 100644 --- a/libtransport/src/core/name.cc +++ b/libtransport/src/core/name.cc @@ -24,7 +24,7 @@ namespace transport { namespace core { -Name::Name() { name_ = {}; } +Name::Name() { std::memset(&name_, 0, sizeof(name_)); } /** * XXX This function does not use the name API provided by libhicn @@ -47,6 +47,7 @@ Name::Name(int family, const uint8_t *ip_address, std::uint32_t suffix) std::memcpy(dst, ip_address, length); name_.suffix = suffix; } + Name::Name(const char *name, uint32_t segment) { if (hicn_name_create(name, segment, &name_) < 0) { throw errors::InvalidIpAddressException(); diff --git a/libtransport/src/core/pending_interest.h b/libtransport/src/core/pending_interest.h index f8a4ba10e..fb10405d3 100644 --- a/libtransport/src/core/pending_interest.h +++ b/libtransport/src/core/pending_interest.h @@ -42,17 +42,9 @@ class PendingInterest { public: using Ptr = utils::ObjectPool<PendingInterest>::Ptr; - // PendingInterest() - // : interest_(nullptr, nullptr), - // timer_(), - // on_content_object_callback_(), - // on_interest_timeout_callback_() {} PendingInterest(asio::io_service &io_service, const Interest::Ptr &interest) - : interest_(interest), - timer_(io_service), - on_content_object_callback_(), - on_interest_timeout_callback_() {} + : interest_(interest), timer_(io_service) {} PendingInterest(asio::io_service &io_service, const Interest::Ptr &interest, OnContentObjectCallback &&on_content_object, @@ -65,10 +57,9 @@ class PendingInterest { ~PendingInterest() = default; template <typename Handler> - TRANSPORT_ALWAYS_INLINE void startCountdown(Handler &&cb) { - timer_.expires_from_now( - std::chrono::milliseconds(interest_->getLifetime())); - timer_.async_wait(std::forward<Handler &&>(cb)); + TRANSPORT_ALWAYS_INLINE void startCountdown(uint32_t lifetime, Handler &&cb) { + timer_.expires_from_now(std::chrono::milliseconds(lifetime)); + timer_.async_wait(std::forward<Handler>(cb)); } TRANSPORT_ALWAYS_INLINE void cancelTimer() { timer_.cancel(); } @@ -77,7 +68,7 @@ class PendingInterest { return std::move(interest_); } - TRANSPORT_ALWAYS_INLINE void setInterest(Interest::Ptr &interest) { + TRANSPORT_ALWAYS_INLINE void setInterest(const Interest::Ptr &interest) { interest_ = interest; } @@ -88,7 +79,7 @@ class PendingInterest { TRANSPORT_ALWAYS_INLINE void setOnContentObjectCallback( OnContentObjectCallback &&on_content_object) { - PendingInterest::on_content_object_callback_ = on_content_object; + PendingInterest::on_content_object_callback_ = std::move(on_content_object); } TRANSPORT_ALWAYS_INLINE const OnInterestTimeoutCallback & @@ -98,7 +89,8 @@ class PendingInterest { TRANSPORT_ALWAYS_INLINE void setOnTimeoutCallback( OnInterestTimeoutCallback &&on_interest_timeout) { - PendingInterest::on_interest_timeout_callback_ = on_interest_timeout; + PendingInterest::on_interest_timeout_callback_ = + std::move(on_interest_timeout); } private: diff --git a/libtransport/src/core/portal.cc b/libtransport/src/core/portal.cc index d8e8d78ea..c06969f19 100644 --- a/libtransport/src/core/portal.cc +++ b/libtransport/src/core/portal.cc @@ -43,12 +43,14 @@ std::string Portal::io_module_path_ = defaultIoModule(); std::string Portal::defaultIoModule() { using namespace std::placeholders; GlobalConfiguration::getInstance().registerConfigurationParser( - io_module_section, + IoModuleConfiguration::section, std::bind(&Portal::parseIoModuleConfiguration, _1, _2)); GlobalConfiguration::getInstance().registerConfigurationGetter( - io_module_section, std::bind(&Portal::getModuleConfiguration, _1, _2)); + IoModuleConfiguration::section, + std::bind(&Portal::getModuleConfiguration, _1, _2)); GlobalConfiguration::getInstance().registerConfigurationSetter( - io_module_section, std::bind(&Portal::setModuleConfiguration, _1, _2)); + IoModuleConfiguration::section, + std::bind(&Portal::setModuleConfiguration, _1, _2)); // return default conf_.name = default_module; @@ -57,7 +59,7 @@ std::string Portal::defaultIoModule() { void Portal::getModuleConfiguration(ConfigurationObject& object, std::error_code& ec) { - DCHECK(object.getKey() == io_module_section); + DCHECK(object.getKey() == IoModuleConfiguration::section); auto conf = dynamic_cast<const IoModuleConfiguration&>(object); conf = conf_; @@ -103,7 +105,7 @@ std::string getIoModulePath(const std::string& name, void Portal::setModuleConfiguration(const ConfigurationObject& object, std::error_code& ec) { - DCHECK(object.getKey() == io_module_section); + DCHECK(object.getKey() == IoModuleConfiguration::section); const IoModuleConfiguration& conf = dynamic_cast<const IoModuleConfiguration&>(object); diff --git a/libtransport/src/core/portal.h b/libtransport/src/core/portal.h index aae4c573e..6f3a48e83 100644 --- a/libtransport/src/core/portal.h +++ b/libtransport/src/core/portal.h @@ -32,6 +32,10 @@ #include <hicn/transport/utils/event_thread.h> #include <hicn/transport/utils/fixed_block_allocator.h> +extern "C" { +#include <hicn/header.h> +} + #include <future> #include <memory> #include <queue> @@ -179,19 +183,11 @@ class Portal : public ::utils::NonCopyable, Portal() : Portal(GlobalWorkers::getInstance().getWorker()) {} Portal(::utils::EventThread &worker) - : io_module_(nullptr, [](IoModule *module) { IoModule::unload(module); }), + : io_module_(nullptr), worker_(worker), app_name_("libtransport_application"), transport_callback_(nullptr), - is_consumer_(false) { - /** - * This workaroung allows to initialize memory for packet buffers *before* - * any static variables that may be initialized in the io_modules. In this - * way static variables in modules will be destroyed before the packet - * memory. - */ - PacketManager<>::getInstance(); - } + is_consumer_(false) {} public: using TransportCallback = interface::Portal::TransportCallback; @@ -275,6 +271,7 @@ class Portal : public ::utils::NonCopyable, ptr->transport_callback_->onError(ec); } }, + [self]([[maybe_unused]] Connector *c) { /* Nothing to do here */ }, [self](Connector *c, const std::error_code &ec) { auto ptr = self.lock(); if (ptr) { @@ -315,76 +312,113 @@ class Portal : public ::utils::NonCopyable, } /** - * Send an interest through to the local forwarder. - * - * @param interest - The pointer to the interest. The ownership of the - * interest is transferred by the caller to portal. - * - * @param on_content_object_callback - If the caller wishes to use a - * different callback to be called for this interest, it can set this - * parameter. Otherwise ConsumerCallback::onContentObject will be used. + * @brief Add interest to PIT * - * @param on_interest_timeout_callback - If the caller wishes to use a - * different callback to be called for this interest, it can set this - * parameter. Otherwise ConsumerCallback::onTimeout will be used. */ - void sendInterest( - Interest::Ptr &&interest, + void addInterestToPIT( + const Interest::Ptr &interest, uint32_t lifetime, OnContentObjectCallback &&on_content_object_callback = UNSET_CALLBACK, OnInterestTimeoutCallback &&on_interest_timeout_callback = UNSET_CALLBACK) { - DCHECK(std::this_thread::get_id() == worker_.getThreadId()); - - // Send it - interest->encodeSuffixes(); - io_module_->send(*interest); - uint32_t initial_hash = interest->getName().getHash32(false); auto hash = initial_hash + interest->getName().getSuffix(); uint32_t seq = interest->getName().getSuffix(); - uint32_t *suffix = interest->firstSuffix(); + const uint32_t *suffix = interest->firstSuffix(); auto n_suffixes = interest->numberOfSuffixes(); uint32_t counter = 0; // Set timers do { + auto pend_int = pending_interest_hash_table_.try_emplace( + hash, worker_.getIoService(), interest); + PendingInterest &pending_interest = pend_int.first->second; + if (!pend_int.second) { + // element was already in map + pend_int.first->second.cancelTimer(); + pending_interest.setInterest(interest); + } + + pending_interest.setOnContentObjectCallback( + std::move(on_content_object_callback)); + pending_interest.setOnTimeoutCallback( + std::move(on_interest_timeout_callback)); + + if (is_consumer_) { + auto self = weak_from_this(); + pending_interest.startCountdown( + lifetime, portal_details::makeCustomAllocatorHandler( + async_callback_memory_, + [self, hash, seq](const std::error_code &ec) { + if (TRANSPORT_EXPECT_FALSE(ec.operator bool())) { + return; + } + + if (auto ptr = self.lock()) { + ptr->timerHandler(hash, seq); + } + })); + } + if (suffix) { hash = initial_hash + *suffix; seq = *suffix; suffix++; } + } while (counter++ < n_suffixes); + } - auto it = pending_interest_hash_table_.find(hash); - PendingInterest *pending_interest = nullptr; - if (it != pending_interest_hash_table_.end()) { - it->second.cancelTimer(); - pending_interest = &it->second; - pending_interest->setInterest(interest); - } else { - auto pend_int = pending_interest_hash_table_.try_emplace( - hash, worker_.getIoService(), interest); - pending_interest = &pend_int.first->second; - } + void matchContentObjectInPIT(ContentObject &content_object) { + uint32_t hash = getHash(content_object.getName()); + auto it = pending_interest_hash_table_.find(hash); + if (it != pending_interest_hash_table_.end()) { + DLOG_IF(INFO, VLOG_IS_ON(3)) << "Found pending interest."; - pending_interest->setOnContentObjectCallback( - std::move(on_content_object_callback)); - pending_interest->setOnTimeoutCallback( - std::move(on_interest_timeout_callback)); + PendingInterest &pend_interest = it->second; + pend_interest.cancelTimer(); + auto _int = pend_interest.getInterest(); + auto callback = pend_interest.getOnDataCallback(); + pending_interest_hash_table_.erase(it); - auto self = weak_from_this(); - pending_interest->startCountdown( - portal_details::makeCustomAllocatorHandler( - async_callback_memory_, - [self, hash, seq](const std::error_code &ec) { - if (TRANSPORT_EXPECT_FALSE(ec.operator bool())) { - return; - } + if (is_consumer_) { + // Send object is for the app + if (callback != UNSET_CALLBACK) { + callback(*_int, content_object); + } else if (transport_callback_) { + transport_callback_->onContentObject(*_int, content_object); + } + } else { + // Send content object to the network + io_module_->send(content_object); + } + } else if (is_consumer_) { + DLOG_IF(INFO, VLOG_IS_ON(3)) + << "No interest pending for received content object."; + } + } - if (auto ptr = self.lock()) { - ptr->timerHandler(hash, seq); - } - })); + /** + * Send an interest through to the local forwarder. + * + * @param interest - The pointer to the interest. The ownership of the + * interest is transferred by the caller to portal. + * + * @param on_content_object_callback - If the caller wishes to use a + * different callback to be called for this interest, it can set this + * parameter. Otherwise ConsumerCallback::onContentObject will be used. + * + * @param on_interest_timeout_callback - If the caller wishes to use a + * different callback to be called for this interest, it can set this + * parameter. Otherwise ConsumerCallback::onTimeout will be used. + */ + void sendInterest( + Interest::Ptr &interest, uint32_t lifetime, + OnContentObjectCallback &&on_content_object_callback = UNSET_CALLBACK, + OnInterestTimeoutCallback &&on_interest_timeout_callback = + UNSET_CALLBACK) { + DCHECK(std::this_thread::get_id() == worker_.getThreadId()); - } while (counter++ < n_suffixes); + io_module_->send(*interest); + addInterestToPIT(interest, lifetime, std::move(on_content_object_callback), + std::move(on_interest_timeout_callback)); } /** @@ -423,8 +457,7 @@ class Portal : public ::utils::NonCopyable, void sendContentObject(ContentObject &content_object) { DCHECK(io_module_); DCHECK(std::this_thread::get_id() == worker_.getThreadId()); - - io_module_->send(content_object); + matchContentObjectInPIT(content_object); } /** @@ -582,6 +615,9 @@ class Portal : public ::utils::NonCopyable, void processInterest(Interest &interest) { // Interest for a producer DLOG_IF(INFO, VLOG_IS_ON(3)) << "processInterest " << interest.getName(); + + // Save interest in PIT + addInterestToPIT(interest.shared_from_this(), interest.getLifetime()); if (TRANSPORT_EXPECT_TRUE(transport_callback_ != nullptr)) { transport_callback_->onInterest(interest); } @@ -598,27 +634,7 @@ class Portal : public ::utils::NonCopyable, void processContentObject(ContentObject &content_object) { DLOG_IF(INFO, VLOG_IS_ON(3)) << "processContentObject " << content_object.getName(); - uint32_t hash = getHash(content_object.getName()); - - auto it = pending_interest_hash_table_.find(hash); - if (it != pending_interest_hash_table_.end()) { - DLOG_IF(INFO, VLOG_IS_ON(3)) << "Found pending interest."; - - PendingInterest &pend_interest = it->second; - pend_interest.cancelTimer(); - auto _int = pend_interest.getInterest(); - auto callback = pend_interest.getOnDataCallback(); - pending_interest_hash_table_.erase(it); - - if (callback != UNSET_CALLBACK) { - callback(*_int, content_object); - } else if (transport_callback_) { - transport_callback_->onContentObject(*_int, content_object); - } - } else { - DLOG_IF(INFO, VLOG_IS_ON(3)) - << "No interest pending for received content object."; - } + matchContentObjectInPIT(content_object); } /** @@ -632,7 +648,7 @@ class Portal : public ::utils::NonCopyable, private: portal_details::HandlerMemory async_callback_memory_; - std::unique_ptr<IoModule, void (*)(IoModule *)> io_module_; + std::unique_ptr<IoModule> io_module_; ::utils::EventThread &worker_; diff --git a/libtransport/src/core/prefix.cc b/libtransport/src/core/prefix.cc index 4c1e191e9..00748148f 100644 --- a/libtransport/src/core/prefix.cc +++ b/libtransport/src/core/prefix.cc @@ -13,8 +13,10 @@ * limitations under the License. */ +#include <glog/logging.h> #include <hicn/transport/core/prefix.h> #include <hicn/transport/errors/errors.h> +#include <hicn/transport/portability/endianess.h> #include <hicn/transport/utils/string_tokenizer.h> #ifndef _WIN32 @@ -37,10 +39,6 @@ namespace core { Prefix::Prefix() { std::memset(&ip_prefix_, 0, sizeof(ip_prefix_t)); } -Prefix::Prefix(const char *prefix) : Prefix(std::string(prefix)) {} - -Prefix::Prefix(std::string &&prefix) : Prefix(prefix) {} - Prefix::Prefix(const std::string &prefix) { utils::StringTokenizer st(prefix, "/"); @@ -56,7 +54,7 @@ Prefix::Prefix(const std::string &prefix) { buildPrefix(ip_address, uint16_t(atoi(prefix_length.c_str())), family); } -Prefix::Prefix(std::string &prefix, uint16_t prefix_length) { +Prefix::Prefix(const std::string &prefix, uint16_t prefix_length) { int family = get_addr_family(prefix.c_str()); buildPrefix(prefix, prefix_length, family); } @@ -73,12 +71,14 @@ Prefix::Prefix(const core::Name &content_name, uint16_t prefix_length) { ip_prefix_.family = family; } -void Prefix::buildPrefix(std::string &prefix, uint16_t prefix_length, +void Prefix::buildPrefix(const std::string &prefix, uint16_t prefix_length, int family) { if (!checkPrefixLengthAndAddressFamily(prefix_length, family)) { throw errors::InvalidIpAddressException(); } + std::memset(&ip_prefix_, 0, sizeof(ip_prefix_t)); + int ret; switch (family) { case AF_INET: @@ -131,62 +131,67 @@ std::unique_ptr<Sockaddr> Prefix::toSockaddr() const { uint16_t Prefix::getPrefixLength() const { return ip_prefix_.len; } Prefix &Prefix::setPrefixLength(uint16_t prefix_length) { + if (!checkPrefixLengthAndAddressFamily(prefix_length, ip_prefix_.family)) { + throw errors::InvalidIpAddressException(); + } + ip_prefix_.len = (u8)prefix_length; return *this; } int Prefix::getAddressFamily() const { return ip_prefix_.family; } -Prefix &Prefix::setAddressFamily(int address_family) { - ip_prefix_.family = address_family; - return *this; -} - std::string Prefix::getNetwork() const { if (!checkPrefixLengthAndAddressFamily(ip_prefix_.len, ip_prefix_.family)) { throw errors::InvalidIpAddressException(); } - std::size_t size = - ip_prefix_.family == 4 + AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; - - std::string network(size, 0); + char buffer[INET6_ADDRSTRLEN]; - if (ip_prefix_ntop_short(&ip_prefix_, (char *)network.c_str(), size) < 0) { + if (ip_prefix_ntop_short(&ip_prefix_, buffer, INET6_ADDRSTRLEN) < 0) { throw errors::RuntimeException( "Impossible to retrieve network from ip address."); } - return network; + return buffer; } -int Prefix::contains(const ip_address_t &content_name) const { - int res = - ip_address_cmp(&content_name, &(ip_prefix_.address), ip_prefix_.family); +bool Prefix::contains(const ip_address_t &content_name) const { + uint64_t mask[2] = {0, 0}; + auto content_name_copy = content_name; + auto network_copy = ip_prefix_.address; - if (ip_prefix_.len != (ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN_BITS - : IPV4_ADDR_LEN_BITS)) { - const u8 *ip_prefix_buffer = - ip_address_get_buffer(&(ip_prefix_.address), ip_prefix_.family); - const u8 *content_name_buffer = - ip_address_get_buffer(&content_name, ip_prefix_.family); - uint8_t mask = 0xFF >> (ip_prefix_.len % 8); - mask = ~mask; + auto prefix_length = getPrefixLength(); + if (ip_prefix_.family == AF_INET) { + prefix_length += 3 * IPV4_ADDR_LEN_BITS; + } - res += (ip_prefix_buffer[ip_prefix_.len] & mask) == - (content_name_buffer[ip_prefix_.len] & mask); + if (prefix_length == 0) { + mask[0] = mask[1] = 0; + } else if (prefix_length <= 64) { + mask[0] = portability::host_to_net((uint64_t)(~0) << (64 - prefix_length)); + mask[1] = 0; + } else if (prefix_length == 128) { + mask[0] = mask[1] = 0xffffffffffffffff; + } else { + prefix_length -= 64; + mask[0] = 0xffffffffffffffff; + mask[1] = portability::host_to_net((uint64_t)(~0) << (64 - prefix_length)); } - return res; -} + // Apply mask + content_name_copy.v6.as_u64[0] &= mask[0]; + content_name_copy.v6.as_u64[1] &= mask[1]; -int Prefix::contains(const core::Name &content_name) const { - return contains(content_name.toIpAddress().address); + network_copy.v6.as_u64[0] &= mask[0]; + network_copy.v6.as_u64[1] &= mask[1]; + + return ip_address_cmp(&network_copy, &content_name_copy, ip_prefix_.family) == + 0; } -Name Prefix::getName() const { - std::string s(getNetwork()); - return Name(s); +bool Prefix::contains(const core::Name &content_name) const { + return contains(content_name.toIpAddress().address); } /* @@ -199,8 +204,8 @@ Name Prefix::getName(const core::Name &mask, const core::Name &components, ip_prefix_.family != components.getAddressFamily() || ip_prefix_.family != content_name.getAddressFamily()) throw errors::RuntimeException( - "Prefix, mask, components and content name are not of the same address " - "family"); + "Prefix, mask, components and content name are not of the same" + "address family"); ip_address_t mask_ip = mask.toIpAddress().address; ip_address_t component_ip = components.toIpAddress().address; @@ -222,32 +227,6 @@ Name Prefix::getName(const core::Name &mask, const core::Name &components, return Name(ip_prefix_.family, (uint8_t *)&name_ip); } -Name Prefix::getRandomName() const { - ip_address_t name_ip = ip_prefix_.address; - u8 *name_ip_buffer = - const_cast<u8 *>(ip_address_get_buffer(&name_ip, ip_prefix_.family)); - - int addr_len = - (ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN * 8 : IPV4_ADDR_LEN * 8) - - ip_prefix_.len; - - size_t size = (size_t)ceil((float)addr_len / 8.0); - uint8_t *buffer = (uint8_t *)malloc(sizeof(uint8_t) * size); - - RAND_bytes(buffer, (int)size); - - int j = 0; - for (uint8_t i = (uint8_t)ceil((float)ip_prefix_.len / 8.0); - i < (ip_prefix_.family == AF_INET6 ? IPV6_ADDR_LEN : IPV4_ADDR_LEN); - i++) { - name_ip_buffer[i] = buffer[j]; - j++; - } - free(buffer); - - return Name(ip_prefix_.family, (uint8_t *)&name_ip); -} - /* * Map a name in a different name prefix to this name prefix */ @@ -276,47 +255,66 @@ Name Prefix::mapName(const core::Name &content_name) const { return Name(ip_prefix_.family, (uint8_t *)&name_ip); } -Prefix &Prefix::setNetwork(std::string &network) { - if (!inet_pton(AF_INET6, network.c_str(), ip_prefix_.address.v6.buffer)) { +Prefix &Prefix::setNetwork(const std::string &network) { + if (!ip_address_pton(network.c_str(), &ip_prefix_.address)) { throw errors::RuntimeException("The network name is not valid."); } return *this; } +Name Prefix::makeName() const { return makeNameWithIndex(0); } + Name Prefix::makeRandomName() const { - if (ip_prefix_.family == AF_INET6) { - std::default_random_engine eng((std::random_device())()); - std::uniform_int_distribution<uint32_t> idis( - 0, std::numeric_limits<uint32_t>::max()); - uint64_t random_number = idis(eng); - - uint32_t hash_size_bits = IPV6_ADDR_LEN_BITS - ip_prefix_.len; - uint64_t ip_address[2]; - memcpy(ip_address, ip_prefix_.address.v6.buffer, sizeof(uint64_t)); - memcpy(ip_address + 1, ip_prefix_.address.v6.buffer + 8, sizeof(uint64_t)); - std::string network(IPV6_ADDR_LEN * 3, 0); - - // Let's do the magic ;) - int shift_size = hash_size_bits > sizeof(random_number) * 8 - ? sizeof(random_number) * 8 - : hash_size_bits; - - ip_address[1] >>= shift_size; - ip_address[1] <<= shift_size; - - ip_address[1] |= random_number >> (sizeof(uint64_t) * 8 - shift_size); - - if (!inet_ntop(ip_prefix_.family, ip_address, (char *)network.c_str(), - IPV6_ADDR_LEN * 3)) { - throw errors::RuntimeException( - "Impossible to retrieve network from ip address."); - } + std::default_random_engine eng((std::random_device())()); + std::uniform_int_distribution<uint32_t> idis( + 0, std::numeric_limits<uint32_t>::max()); + uint64_t random_number = idis(eng); + + return makeNameWithIndex(random_number); +} + +Name Prefix::makeNameWithIndex(std::uint64_t index) const { + uint16_t prefix_length = getPrefixLength(); - return Name(network); + Name ret; + + // Adjust prefix length depending on the address family + if (getAddressFamily() == AF_INET) { + // Sanity check + DCHECK(prefix_length <= 32); + // Convert prefix length to ip46_address_t prefix length + prefix_length += IPV4_ADDR_LEN_BITS * 3; + } + + std::memcpy(ret.getStructReference().prefix.v6.as_u8, + ip_prefix_.address.v6.as_u8, sizeof(ip_address_t)); + + // Convert index in network byte order + index = portability::host_to_net(index); + + // Apply mask + uint64_t mask; + if (prefix_length == 0) { + mask = 0; + } else if (prefix_length <= 64) { + mask = 0; + } else if (prefix_length == 128) { + mask = 0xffffffffffffffff; + } else { + prefix_length -= 64; + mask = portability::host_to_net((uint64_t)(~0) << (64 - prefix_length)); } - return Name(); + ret.getStructReference().prefix.v6.as_u64[1] &= mask; + // Eventually truncate index if too big + index &= ~mask; + + // Apply index + ret.getStructReference().prefix.v6.as_u64[1] |= index; + + // Done + return ret; } bool Prefix::checkPrefixLengthAndAddressFamily(uint16_t prefix_length, diff --git a/libtransport/src/core/udp_connector.cc b/libtransport/src/core/udp_connector.cc index ee0c7ea9c..5d8e76bb1 100644 --- a/libtransport/src/core/udp_connector.cc +++ b/libtransport/src/core/udp_connector.cc @@ -56,9 +56,9 @@ void UdpTunnelConnector::send(Packet &packet) { void UdpTunnelConnector::send(const utils::MemBuf::Ptr &buffer) { auto self = shared_from_this(); - io_service_.post([self, pkt{buffer}]() { + io_service_.post([self, buffer]() { bool write_in_progress = !self->output_buffer_.empty(); - self->output_buffer_.push_back(std::move(pkt)); + self->output_buffer_.push_back(std::move(buffer)); if (TRANSPORT_EXPECT_TRUE(self->state_ == State::CONNECTED)) { if (!write_in_progress) { self->doSendPacket(self); @@ -201,6 +201,8 @@ void UdpTunnelConnector::writeHandler() { ptr->writeHandler(); } }); + } else { + sent_callback_(this, make_error_code(core_error::success)); } } diff --git a/libtransport/src/core/udp_connector.h b/libtransport/src/core/udp_connector.h index 65821852d..002f4ca9f 100644 --- a/libtransport/src/core/udp_connector.h +++ b/libtransport/src/core/udp_connector.h @@ -62,7 +62,7 @@ class UdpTunnelConnector : public Connector { #endif socket_(socket), resolver_(io_service_), - remote_endpoint_send_(std::forward<EndpointType &&>(remote_endpoint)), + remote_endpoint_send_(std::forward<EndpointType>(remote_endpoint)), timer_(io_service_), #ifdef LINUX send_timer_(io_service_), diff --git a/libtransport/src/core/udp_listener.cc b/libtransport/src/core/udp_listener.cc index c67673392..caa97e0ee 100644 --- a/libtransport/src/core/udp_listener.cc +++ b/libtransport/src/core/udp_listener.cc @@ -5,6 +5,7 @@ #include <core/udp_connector.h> #include <core/udp_listener.h> #include <glog/logging.h> +#include <hicn/transport/portability/endianess.h> #include <hicn/transport/utils/hash.h> #ifndef LINUX @@ -16,7 +17,7 @@ size_t hash<asio::ip::udp::endpoint>::operator()( : utils::hash::fnv32_buf( endpoint.address().to_v6().to_bytes().data(), 16); uint16_t port = endpoint.port(); - return utils::hash::fnv32_buf(&port, 2, hash_ip); + return utils::hash::fnv32_buf(&port, 2, (unsigned int)hash_ip); } } // namespace std #endif @@ -83,7 +84,8 @@ void UdpTunnelListener::readHandler(const std::error_code &ec) { std::copy_n(reinterpret_cast<uint8_t *>(&addr->sin_addr), address_bytes.size(), address_bytes.begin()); address_v4 address(address_bytes); - remote_endpoint_ = udp::endpoint(address, ntohs(addr->sin_port)); + remote_endpoint_ = + udp::endpoint(address, portability::net_to_host(addr->sin_port)); } else { auto addr = reinterpret_cast<struct sockaddr_in6 *>( &remote_endpoints_[current_position_]); @@ -91,7 +93,8 @@ void UdpTunnelListener::readHandler(const std::error_code &ec) { std::copy_n(reinterpret_cast<uint8_t *>(&addr->sin6_addr), address_bytes.size(), address_bytes.begin()); address_v6 address(address_bytes); - remote_endpoint_ = udp::endpoint(address, ntohs(addr->sin6_port)); + remote_endpoint_ = + udp::endpoint(address, portability::net_to_host(addr->sin6_port)); } /** diff --git a/libtransport/src/core/udp_listener.h b/libtransport/src/core/udp_listener.h index 813520309..d8095a262 100644 --- a/libtransport/src/core/udp_listener.h +++ b/libtransport/src/core/udp_listener.h @@ -40,7 +40,7 @@ class UdpTunnelListener socket_(std::make_shared<asio::ip::udp::socket>(io_service_, endpoint.protocol())), local_endpoint_(endpoint), - receive_callback_(std::forward<ReceiveCallback &&>(receive_callback)), + receive_callback_(std::forward<ReceiveCallback>(receive_callback)), #ifndef LINUX read_msg_(nullptr, 0) #else @@ -63,12 +63,12 @@ class UdpTunnelListener void close(); int deleteConnector(Connector *connector) { - return connectors_.erase(connector->getConnectorId()); + return (int)connectors_.erase(connector->getConnectorId()); } template <typename ReceiveCallback> void setReceiveCallback(ReceiveCallback &&callback) { - receive_callback_ = std::forward<ReceiveCallback &&>(callback); + receive_callback_ = std::forward<ReceiveCallback>(callback); } Connector *findConnector(Connector::Id connId) { diff --git a/libtransport/src/implementation/CMakeLists.txt b/libtransport/src/implementation/CMakeLists.txt index 1f2a33a4c..c759dd964 100644 --- a/libtransport/src/implementation/CMakeLists.txt +++ b/libtransport/src/implementation/CMakeLists.txt @@ -19,21 +19,8 @@ list(APPEND HEADER_FILES if (${OPENSSL_VERSION} VERSION_EQUAL "1.1.1a" OR ${OPENSSL_VERSION} VERSION_GREATER "1.1.1a") list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.cc - # ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.cc ${CMAKE_CURRENT_SOURCE_DIR}/socket.cc ) - - list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.h - # ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.h - ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.h - ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.h - ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.h - ) endif() set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) diff --git a/libtransport/src/implementation/p2psecure_socket_consumer.cc b/libtransport/src/implementation/p2psecure_socket_consumer.cc deleted file mode 100644 index 6b67a5487..000000000 --- a/libtransport/src/implementation/p2psecure_socket_consumer.cc +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <implementation/p2psecure_socket_consumer.h> -#include <interfaces/tls_socket_consumer.h> -#include <openssl/bio.h> -#include <openssl/ssl.h> -#include <openssl/tls1.h> - -#include <random> - -namespace transport { -namespace implementation { - -void P2PSecureConsumerSocket::setInterestPayload( - interface::ConsumerSocket &c, const core::Interest &interest) { - Interest &int2 = const_cast<Interest &>(interest); - random_suffix_ = int2.getName().getSuffix(); - - if (payload_ != NULL) int2.appendPayload(std::move(payload_)); -} - -/* Return the number of read bytes in the return param */ -int readOld(BIO *b, char *buf, int size) { - if (size < 0) return size; - - P2PSecureConsumerSocket *socket; - socket = (P2PSecureConsumerSocket *)BIO_get_data(b); - - std::unique_lock<std::mutex> lck(socket->mtx_); - - if (!socket->something_to_read_) { - if (!socket->transport_protocol_->isRunning()) { - socket->network_name_.setSuffix(socket->random_suffix_); - socket->ConsumerSocket::consume(socket->network_name_); - } - - if (!socket->something_to_read_) socket->cv_.wait(lck); - } - - size_t size_to_read, read; - size_t chain_size = socket->head_->length(); - - if (socket->head_->isChained()) - chain_size = socket->head_->computeChainDataLength(); - - if (chain_size > (size_t)size) { - read = size_to_read = (size_t)size; - } else { - read = size_to_read = chain_size; - socket->something_to_read_ = false; - } - - while (size_to_read) { - if (socket->head_->length() < size_to_read) { - std::memcpy(buf, socket->head_->data(), socket->head_->length()); - size_to_read -= socket->head_->length(); - buf += socket->head_->length(); - socket->head_ = socket->head_->pop(); - } else { - std::memcpy(buf, socket->head_->data(), size_to_read); - socket->head_->trimStart(size_to_read); - size_to_read = 0; - } - } - - return (int)read; -} - -/* Return the number of read bytes in readbytes */ -int read(BIO *b, char *buf, size_t size, size_t *readbytes) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = readOld(b, buf, (int)size); - - if (ret <= 0) { - *readbytes = 0; - return ret; - } - - *readbytes = (size_t)ret; - - return 1; -} - -/* Return the number of written bytes in the return param */ -int writeOld(BIO *b, const char *buf, int num) { - P2PSecureConsumerSocket *socket; - socket = (P2PSecureConsumerSocket *)BIO_get_data(b); - - socket->payload_ = utils::MemBuf::copyBuffer(buf, num); - - socket->ConsumerSocket::setSocketOption( - ConsumerCallbacksOptions::INTEREST_OUTPUT, - (ConsumerInterestCallback)std::bind( - &P2PSecureConsumerSocket::setInterestPayload, socket, - std::placeholders::_1, std::placeholders::_2)); - - return num; -} - -/* Return the number of written bytes in written */ -int write(BIO *b, const char *buf, size_t size, size_t *written) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = writeOld(b, buf, (int)size); - - if (ret <= 0) { - *written = 0; - return ret; - } - - *written = (size_t)ret; - - return 1; -} - -long ctrl(BIO *b, int cmd, long num, void *ptr) { return 1; } - -int P2PSecureConsumerSocket::addHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, - const unsigned char **out, - size_t *outlen, X509 *x, - size_t chainidx, int *al, - void *add_arg) { - if (ext_type == 100) { - *out = (unsigned char *)malloc(4); - *(uint32_t *)*out = 10; - *outlen = 4; - } - return 1; -} - -void P2PSecureConsumerSocket::freeHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, - const unsigned char *out, - void *add_arg) { - free(const_cast<unsigned char *>(out)); -} - -int P2PSecureConsumerSocket::parseHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, - const unsigned char *in, - size_t inlen, X509 *x, - size_t chainidx, int *al, - void *add_arg) { - P2PSecureConsumerSocket *socket = - reinterpret_cast<P2PSecureConsumerSocket *>(add_arg); - if (ext_type == 100) { - memcpy(&socket->secure_prefix_, in, sizeof(ip_prefix_t)); - } - return 1; -} - -P2PSecureConsumerSocket::P2PSecureConsumerSocket( - interface::ConsumerSocket *consumer, int handshake_protocol, - int transport_protocol) - : ConsumerSocket(consumer, handshake_protocol), - name_(), - tls_consumer_(nullptr), - decrypted_content_(), - payload_(), - head_(), - something_to_read_(false), - content_downloaded_(false), - random_suffix_(), - secure_prefix_(), - producer_namespace_(), - read_callback_decrypted_(), - mtx_(), - cv_(), - protocol_(transport_protocol) { - /* Create the (d)TLS state */ - const SSL_METHOD *meth = TLS_client_method(); - ctx_ = SSL_CTX_new(meth); - - int result = - SSL_CTX_set_ciphersuites(ctx_, - "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_" - "SHA256:TLS_AES_128_GCM_SHA256"); - if (result != 1) { - throw errors::RuntimeException( - "Unable to set cipher list on TLS subsystem. Aborting."); - } - - SSL_CTX_set_min_proto_version(ctx_, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(ctx_, TLS1_3_VERSION); - SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, NULL); - SSL_CTX_set_ssl_version(ctx_, meth); - - result = SSL_CTX_add_custom_ext( - ctx_, 100, SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS, - P2PSecureConsumerSocket::addHicnKeyIdCb, - P2PSecureConsumerSocket::freeHicnKeyIdCb, NULL, - P2PSecureConsumerSocket::parseHicnKeyIdCb, this); - - ssl_ = SSL_new(ctx_); - - bio_meth_ = BIO_meth_new(BIO_TYPE_CONNECT, "secure consumer socket"); - BIO_meth_set_read(bio_meth_, readOld); - BIO_meth_set_write(bio_meth_, writeOld); - BIO_meth_set_ctrl(bio_meth_, ctrl); - BIO *bio = BIO_new(bio_meth_); - BIO_set_init(bio, 1); - BIO_set_data(bio, this); - SSL_set_bio(ssl_, bio, bio); - - std::default_random_engine generator; - std::uniform_int_distribution<int> distribution( - 1, std::numeric_limits<uint32_t>::max()); - random_suffix_ = 0; - - this->ConsumerSocket::setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, - this); -}; - -P2PSecureConsumerSocket::~P2PSecureConsumerSocket() { - BIO_meth_free(bio_meth_); - SSL_shutdown(ssl_); -} - -int P2PSecureConsumerSocket::handshake() { - int result = 1; - - if (!(SSL_in_before(this->ssl_) || SSL_in_init(this->ssl_))) { - return 1; - } - - ConsumerSocket::getSocketOption(MAX_WINDOW_SIZE, old_max_win_); - ConsumerSocket::getSocketOption(CURRENT_WINDOW_SIZE, old_current_win_); - - ConsumerSocket::setSocketOption(MAX_WINDOW_SIZE, (double)1.0); - ConsumerSocket::setSocketOption(CURRENT_WINDOW_SIZE, (double)1.0); - - network_name_ = producer_namespace_.getRandomName(); - network_name_.setSuffix(0); - - DLOG_IF(INFO, VLOG_IS_ON(2)) << "Start handshake at " << network_name_; - result = SSL_connect(this->ssl_); - - return result; -} - -void P2PSecureConsumerSocket::initSessionSocket() { - tls_consumer_ = - std::make_shared<TLSConsumerSocket>(nullptr, this->protocol_, this->ssl_); - tls_consumer_->setInterface( - new interface::TLSConsumerSocket(tls_consumer_.get())); - - ConsumerTimerCallback *stats_summary_callback = nullptr; - this->getSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY, - &stats_summary_callback); - - uint32_t lifetime; - this->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, lifetime); - - tls_consumer_->setSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, - lifetime); - tls_consumer_->setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, - read_callback_decrypted_); - tls_consumer_->setSocketOption(ConsumerCallbacksOptions::STATS_SUMMARY, - *stats_summary_callback); - tls_consumer_->setSocketOption(GeneralTransportOptions::STATS_INTERVAL, - this->timer_interval_milliseconds_); - tls_consumer_->setSocketOption(MAX_WINDOW_SIZE, old_max_win_); - tls_consumer_->setSocketOption(CURRENT_WINDOW_SIZE, old_current_win_); - tls_consumer_->connect(); -} - -int P2PSecureConsumerSocket::consume(const Name &name) { - if (transport_protocol_->isRunning()) { - return CONSUMER_BUSY; - } - - if (handshake() != 1) { - throw errors::RuntimeException("Unable to perform client handshake"); - } else { - DLOG_IF(INFO, VLOG_IS_ON(2)) << "Handshake performed!"; - } - - initSessionSocket(); - - if (tls_consumer_ == nullptr) { - throw errors::RuntimeException("TLS socket does not exist"); - } - - std::shared_ptr<Name> prefix_name = std::make_shared<Name>( - secure_prefix_.family, - ip_address_get_buffer(&(secure_prefix_.address), secure_prefix_.family)); - std::shared_ptr<Prefix> prefix = - std::make_shared<Prefix>(*prefix_name, secure_prefix_.len); - - if (payload_ != nullptr) - return tls_consumer_->consume((prefix->mapName(name)), std::move(payload_)); - else - return tls_consumer_->consume((prefix->mapName(name))); -} - -void P2PSecureConsumerSocket::registerPrefix(const Prefix &producer_namespace) { - producer_namespace_ = producer_namespace; -} - -int P2PSecureConsumerSocket::setSocketOption( - int socket_option_key, ReadCallback *socket_option_value) { - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, ReadCallback *socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::READ_CALLBACK: - read_callback_decrypted_ = socket_option_value; - break; - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -void P2PSecureConsumerSocket::getReadBuffer(uint8_t **application_buffer, - size_t *max_length){}; - -void P2PSecureConsumerSocket::readDataAvailable(size_t length) noexcept {}; - -size_t P2PSecureConsumerSocket::maxBufferSize() const { - return SSL3_RT_MAX_PLAIN_LENGTH; -} - -void P2PSecureConsumerSocket::readBufferAvailable( - std::unique_ptr<utils::MemBuf> &&buffer) noexcept { - std::unique_lock<std::mutex> lck(this->mtx_); - if (head_) { - head_->prependChain(std::move(buffer)); - } else { - head_ = std::move(buffer); - } - - something_to_read_ = true; - cv_.notify_one(); -} - -void P2PSecureConsumerSocket::readError(const std::error_code &ec) noexcept {}; - -void P2PSecureConsumerSocket::readSuccess(std::size_t total_size) noexcept { - std::unique_lock<std::mutex> lck(this->mtx_); - content_downloaded_ = true; - something_to_read_ = true; - cv_.notify_one(); -} - -bool P2PSecureConsumerSocket::isBufferMovable() noexcept { return true; } - -} // namespace implementation -} // namespace transport diff --git a/libtransport/src/implementation/p2psecure_socket_consumer.h b/libtransport/src/implementation/p2psecure_socket_consumer.h deleted file mode 100644 index a5e69f611..000000000 --- a/libtransport/src/implementation/p2psecure_socket_consumer.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <hicn/transport/interfaces/socket_consumer.h> -#include <implementation/tls_socket_consumer.h> -#include <openssl/bio.h> -#include <openssl/ssl.h> - -namespace transport { -namespace implementation { - -class P2PSecureConsumerSocket : public ConsumerSocket, - public interface::ConsumerSocket::ReadCallback { - /* Return the number of read bytes in readbytes */ - friend int read(BIO *b, char *buf, size_t size, size_t *readbytes); - - /* Return the number of read bytes in the return param */ - friend int readOld(BIO *h, char *buf, int size); - - /* Return the number of written bytes in written */ - friend int write(BIO *b, const char *buf, size_t size, size_t *written); - - /* Return the number of written bytes in the return param */ - friend int writeOld(BIO *h, const char *buf, int num); - - friend long ctrl(BIO *b, int cmd, long num, void *ptr); - - public: - explicit P2PSecureConsumerSocket(interface::ConsumerSocket *consumer, - int handshake_protocol, - int transport_protocol); - - ~P2PSecureConsumerSocket(); - - int consume(const Name &name) override; - - void registerPrefix(const Prefix &producer_namespace); - - int setSocketOption( - int socket_option_key, - interface::ConsumerSocket::ReadCallback *socket_option_value) override; - - using ConsumerSocket::getSocketOption; - using ConsumerSocket::setSocketOption; - - protected: - /* Callback invoked once an interest has been received and its payload - * decrypted */ - ConsumerInterestCallback on_interest_input_decrypted_; - ConsumerInterestCallback on_interest_process_decrypted_; - - private: - Name name_; - std::shared_ptr<TLSConsumerSocket> tls_consumer_; - /* SSL handle */ - SSL *ssl_; - SSL_CTX *ctx_; - BIO_METHOD *bio_meth_; - /* Chain of MemBuf to be used as a temporary buffer to pass descypted data - * from the underlying layer to the application */ - std::unique_ptr<utils::MemBuf> decrypted_content_; - /* Chain of MemBuf holding the payload to be written into interest or data */ - std::unique_ptr<utils::MemBuf> payload_; - /* Chain of MemBuf holding the data retrieved from the underlying layer */ - std::unique_ptr<utils::MemBuf> head_; - bool something_to_read_; - bool content_downloaded_; - double old_max_win_; - double old_current_win_; - uint32_t random_suffix_; - ip_prefix_t secure_prefix_; - Prefix producer_namespace_; - interface::ConsumerSocket::ReadCallback *read_callback_decrypted_; - std::mutex mtx_; - - /* Condition variable for the wait */ - std::condition_variable cv_; - - int protocol_; - - void setInterestPayload(interface::ConsumerSocket &c, - const core::Interest &interest); - - static int addHicnKeyIdCb(SSL *s, unsigned int ext_type, unsigned int context, - const unsigned char **out, size_t *outlen, X509 *x, - size_t chainidx, int *al, void *add_arg); - - static void freeHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, const unsigned char *out, - void *add_arg); - - static int parseHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, const unsigned char *in, - size_t inlen, X509 *x, size_t chainidx, int *al, - void *add_arg); - - virtual void getReadBuffer(uint8_t **application_buffer, - size_t *max_length) override; - - virtual void readDataAvailable(size_t length) noexcept override; - - virtual size_t maxBufferSize() const override; - - virtual void readBufferAvailable( - std::unique_ptr<utils::MemBuf> &&buffer) noexcept override; - - virtual void readError(const std::error_code &ec) noexcept override; - - virtual void readSuccess(std::size_t total_size) noexcept override; - - virtual bool isBufferMovable() noexcept override; - - int handshake(); - - void initSessionSocket(); -}; - -} // namespace implementation - -} // end namespace transport diff --git a/libtransport/src/implementation/p2psecure_socket_producer.cc b/libtransport/src/implementation/p2psecure_socket_producer.cc deleted file mode 100644 index ee78ea53b..000000000 --- a/libtransport/src/implementation/p2psecure_socket_producer.cc +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <hicn/transport/core/interest.h> -#include <implementation/p2psecure_socket_producer.h> -// #include <implementation/tls_rtc_socket_producer.h> -#include <implementation/tls_socket_producer.h> -#include <interfaces/tls_rtc_socket_producer.h> -#include <interfaces/tls_socket_producer.h> -#include <openssl/bio.h> -#include <openssl/pkcs12.h> -#include <openssl/rand.h> -#include <openssl/ssl.h> - -namespace transport { -namespace implementation { - -/* Workaround to prevent content with expiry time equal to 0 to be lost when - * pushed in the forwarder */ -#define HICN_HANDSHAKE_CONTENT_EXPIRY_TIME 100; - -P2PSecureProducerSocket::P2PSecureProducerSocket( - interface::ProducerSocket *producer_socket) - : ProducerSocket(producer_socket, - ProductionProtocolAlgorithms::BYTE_STREAM), - mtx_(), - cv_(), - map_producers(), - list_producers() {} - -P2PSecureProducerSocket::P2PSecureProducerSocket( - interface::ProducerSocket *producer_socket, bool rtc, - std::string &keystore_path, std::string &keystore_pwd) - : ProducerSocket(producer_socket, - ProductionProtocolAlgorithms::BYTE_STREAM), - rtc_(rtc), - mtx_(), - cv_(), - map_producers(), - list_producers() { - /* Setup SSL context (identity and parameter to use TLS 1.3) */ - FILE *p12file = fopen(keystore_path.c_str(), "r"); - if (p12file == NULL) - throw errors::RuntimeException("impossible open keystore"); - std::unique_ptr<PKCS12, decltype(&::PKCS12_free)> p12( - d2i_PKCS12_fp(p12file, NULL), ::PKCS12_free); - // now we parse the file to get the first key and certificate - if (1 != PKCS12_parse(p12.get(), keystore_pwd.c_str(), &pkey_rsa_, &cert_509_, - NULL)) - throw errors::RuntimeException("impossible to get the private key"); - fclose(p12file); - - /* Set the callback so that when an interest is received we catch it and we - * decrypt the payload before passing it to the application. */ - ProducerSocket::setSocketOption( - ProducerCallbacksOptions::INTEREST_INPUT, - (ProducerInterestCallback)std::bind( - &P2PSecureProducerSocket::onInterestCallback, this, - std::placeholders::_1, std::placeholders::_2)); -} - -P2PSecureProducerSocket::~P2PSecureProducerSocket() {} - -void P2PSecureProducerSocket::initSessionSocket( - std::unique_ptr<TLSProducerSocket> &producer) { - producer->on_content_produced_application_ = - this->on_content_produced_application_; - producer->setSocketOption(CONTENT_OBJECT_EXPIRY_TIME, - this->content_object_expiry_time_); - producer->setSocketOption(SIGNER, this->signer_); - producer->setSocketOption(MAKE_MANIFEST, this->making_manifest_); - producer->setSocketOption(DATA_PACKET_SIZE, - (uint32_t)(this->data_packet_size_)); - uint32_t output_buffer_size = 0; - this->getSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE, - output_buffer_size); - producer->setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE, - output_buffer_size); - - if (!rtc_) { - producer->setInterface(new interface::TLSProducerSocket(producer.get())); - } else { - // TODO - // TLSRTCProducerSocket *rtc_producer = - // dynamic_cast<TLSRTCProducerSocket *>(producer.get()); - // rtc_producer->setInterface( - // new interface::TLSRTCProducerSocket(rtc_producer)); - } -} - -void P2PSecureProducerSocket::onInterestCallback(interface::ProducerSocket &p, - Interest &interest) { - std::unique_lock<std::mutex> lck(mtx_); - std::unique_ptr<TLSProducerSocket> tls_producer; - auto it = map_producers.find(interest.getName()); - - if (it != map_producers.end()) { - return; - } - - if (!rtc_) { - tls_producer = - std::make_unique<TLSProducerSocket>(nullptr, this, interest.getName()); - } else { - // TODO - // tls_producer = std::make_unique<TLSRTCProducerSocket>(nullptr, this, - // interest.getName()); - } - - initSessionSocket(tls_producer); - TLSProducerSocket *tls_producer_ptr = tls_producer.get(); - map_producers.insert({interest.getName(), move(tls_producer)}); - - DLOG_IF(INFO, VLOG_IS_ON(3)) << "Start handshake at " << interest.getName(); - - if (!rtc_) { - tls_producer_ptr->onInterest(*tls_producer_ptr, interest); - tls_producer_ptr->async_accept(); - } else { - // TODO - // TLSRTCProducerSocket *rtc_producer_ptr = - // dynamic_cast<TLSRTCProducerSocket *>(tls_producer_ptr); - // rtc_producer_ptr->onInterest(*rtc_producer_ptr, interest); - // rtc_producer_ptr->async_accept(); - } -} - -uint32_t P2PSecureProducerSocket::produceDatagram( - const Name &content_name, std::unique_ptr<utils::MemBuf> &&buffer) { - // TODO - throw errors::NotImplementedException(); - - // if (!rtc_) { - // throw errors::RuntimeException( - // "RTC must be the transport protocol to start the production of - // current " "data. Aborting."); - // } - - // std::unique_lock<std::mutex> lck(mtx_); - - // if (list_producers.empty()) cv_.wait(lck); - - // TODO - // for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++) - // { - // TLSRTCProducerSocket *rtc_producer = - // dynamic_cast<TLSRTCProducerSocket *>(it->get()); - // rtc_producer->produce(utils::MemBuf::copyBuffer(buffer, buffer_size)); - // } - - // return 0; -} - -uint32_t P2PSecureProducerSocket::produceStream( - const Name &content_name, std::unique_ptr<utils::MemBuf> &&buffer, - bool is_last, uint32_t start_offset) { - if (rtc_) { - throw errors::RuntimeException( - "RTC transport protocol is not compatible with the production of " - "current data. Aborting."); - } - - std::unique_lock<std::mutex> lck(mtx_); - uint32_t segments = 0; - - if (list_producers.empty()) cv_.wait(lck); - - for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++) - segments += (*it)->produceStream(content_name, buffer->clone(), is_last, - start_offset); - - return segments; -} - -uint32_t P2PSecureProducerSocket::produceStream(const Name &content_name, - const uint8_t *buffer, - size_t buffer_size, - bool is_last, - uint32_t start_offset) { - if (rtc_) { - throw errors::RuntimeException( - "RTC transport protocol is not compatible with the production of " - "current data. Aborting."); - } - - std::unique_lock<std::mutex> lck(mtx_); - uint32_t segments = 0; - if (list_producers.empty()) cv_.wait(lck); - - for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++) - segments += (*it)->produceStream(content_name, buffer, buffer_size, is_last, - start_offset); - - return segments; -} - -/* Redefinition of socket options to avoid name hiding */ -int P2PSecureProducerSocket::setSocketOption( - int socket_option_key, ProducerInterestCallback socket_option_value) { - if (!list_producers.empty()) { - for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - } - - switch (socket_option_key) { - case ProducerCallbacksOptions::INTEREST_INPUT: - on_interest_input_decrypted_ = socket_option_value; - return SOCKET_OPTION_SET; - - case ProducerCallbacksOptions::INTEREST_DROP: - on_interest_dropped_input_buffer_ = socket_option_value; - return SOCKET_OPTION_SET; - - case ProducerCallbacksOptions::INTEREST_PASS: - on_interest_inserted_input_buffer_ = socket_option_value; - return SOCKET_OPTION_SET; - - case ProducerCallbacksOptions::CACHE_HIT: - on_interest_satisfied_output_buffer_ = socket_option_value; - return SOCKET_OPTION_SET; - - case ProducerCallbacksOptions::CACHE_MISS: - on_interest_process_decrypted_ = socket_option_value; - return SOCKET_OPTION_SET; - - default: - return SOCKET_OPTION_NOT_SET; - } -} - -int P2PSecureProducerSocket::setSocketOption( - int socket_option_key, - const std::shared_ptr<auth::Signer> &socket_option_value) { - if (!list_producers.empty()) - for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - switch (socket_option_key) { - case GeneralTransportOptions::SIGNER: { - signer_.reset(); - signer_ = socket_option_value; - - return SOCKET_OPTION_SET; - } - default: - return SOCKET_OPTION_NOT_SET; - } -} - -int P2PSecureProducerSocket::setSocketOption(int socket_option_key, - uint32_t socket_option_value) { - if (!list_producers.empty()) { - for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - } - switch (socket_option_key) { - case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME: - content_object_expiry_time_ = - socket_option_value; // HICN_HANDSHAKE_CONTENT_EXPIRY_TIME; - return SOCKET_OPTION_SET; - } - return ProducerSocket::setSocketOption(socket_option_key, - socket_option_value); -} - -int P2PSecureProducerSocket::setSocketOption(int socket_option_key, - bool socket_option_value) { - if (!list_producers.empty()) - for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - return ProducerSocket::setSocketOption(socket_option_key, - socket_option_value); -} - -int P2PSecureProducerSocket::setSocketOption(int socket_option_key, - Name *socket_option_value) { - if (!list_producers.empty()) - for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - return ProducerSocket::setSocketOption(socket_option_key, - socket_option_value); -} - -int P2PSecureProducerSocket::setSocketOption( - int socket_option_key, ProducerContentObjectCallback socket_option_value) { - if (!list_producers.empty()) - for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - return ProducerSocket::setSocketOption(socket_option_key, - socket_option_value); -} - -int P2PSecureProducerSocket::setSocketOption( - int socket_option_key, ProducerContentCallback socket_option_value) { - if (!list_producers.empty()) - for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - switch (socket_option_key) { - case ProducerCallbacksOptions::CONTENT_PRODUCED: - on_content_produced_application_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; -} - -int P2PSecureProducerSocket::setSocketOption( - int socket_option_key, auth::CryptoHashType socket_option_value) { - if (!list_producers.empty()) - for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - return ProducerSocket::setSocketOption(socket_option_key, - socket_option_value); -} - -int P2PSecureProducerSocket::setSocketOption( - int socket_option_key, const std::string &socket_option_value) { - if (!list_producers.empty()) - for (auto it = list_producers.cbegin(); it != list_producers.cend(); it++) - (*it)->setSocketOption(socket_option_key, socket_option_value); - - return ProducerSocket::setSocketOption(socket_option_key, - socket_option_value); -} - -} // namespace implementation -} // namespace transport diff --git a/libtransport/src/implementation/p2psecure_socket_producer.h b/libtransport/src/implementation/p2psecure_socket_producer.h deleted file mode 100644 index 00f407a75..000000000 --- a/libtransport/src/implementation/p2psecure_socket_producer.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <hicn/transport/auth/signer.h> -#include <implementation/socket_producer.h> -// #include <implementation/tls_rtc_socket_producer.h> -#include <implementation/tls_socket_producer.h> -#include <openssl/ssl.h> -#include <utils/content_store.h> - -#include <condition_variable> -#include <forward_list> -#include <mutex> - -namespace transport { -namespace implementation { - -class P2PSecureProducerSocket : public ProducerSocket { - friend class TLSProducerSocket; - // TODO - // friend class TLSRTCProducerSocket; - - public: - explicit P2PSecureProducerSocket(interface::ProducerSocket *producer_socket); - - explicit P2PSecureProducerSocket(interface::ProducerSocket *producer_socket, - bool rtc, std::string &keystore_path, - std::string &keystore_pwd); - - ~P2PSecureProducerSocket(); - - uint32_t produceDatagram(const Name &content_name, - std::unique_ptr<utils::MemBuf> &&buffer) override; - - uint32_t produceStream(const Name &content_name, const uint8_t *buffer, - size_t buffer_size, bool is_last = true, - uint32_t start_offset = 0) override; - - uint32_t produceStream(const Name &content_name, - std::unique_ptr<utils::MemBuf> &&buffer, - bool is_last = true, - uint32_t start_offset = 0) override; - - int setSocketOption(int socket_option_key, - ProducerInterestCallback socket_option_value) override; - - int setSocketOption( - int socket_option_key, - const std::shared_ptr<auth::Signer> &socket_option_value) override; - - int setSocketOption(int socket_option_key, - uint32_t socket_option_value) override; - - int setSocketOption(int socket_option_key, bool socket_option_value) override; - - int setSocketOption(int socket_option_key, - Name *socket_option_value) override; - - int setSocketOption( - int socket_option_key, - ProducerContentObjectCallback socket_option_value) override; - - int setSocketOption(int socket_option_key, - ProducerContentCallback socket_option_value) override; - - int setSocketOption(int socket_option_key, - auth::CryptoHashType socket_option_value) override; - - int setSocketOption(int socket_option_key, - const std::string &socket_option_value) override; - - using ProducerSocket::getSocketOption; - // using ProducerSocket::onInterest; - - protected: - /* Callback invoked once an interest has been received and its payload - * decrypted */ - ProducerInterestCallback on_interest_input_decrypted_; - ProducerInterestCallback on_interest_process_decrypted_; - ProducerContentCallback on_content_produced_application_; - - private: - bool rtc_; - std::mutex mtx_; - /* Condition variable for the wait */ - std::condition_variable cv_; - X509 *cert_509_; - EVP_PKEY *pkey_rsa_; - std::unordered_map<core::Name, std::unique_ptr<TLSProducerSocket>, - core::hash<core::Name>, core::compare2<core::Name>> - map_producers; - std::list<std::unique_ptr<TLSProducerSocket>> list_producers; - - void onInterestCallback(interface::ProducerSocket &p, Interest &interest); - - void initSessionSocket(std::unique_ptr<TLSProducerSocket> &producer); -}; - -} // namespace implementation -} // namespace transport diff --git a/libtransport/src/implementation/socket.cc b/libtransport/src/implementation/socket.cc index 95941da07..b80fbb58c 100644 --- a/libtransport/src/implementation/socket.cc +++ b/libtransport/src/implementation/socket.cc @@ -23,7 +23,9 @@ namespace implementation { Socket::Socket(std::shared_ptr<core::Portal> &&portal) : portal_(std::move(portal)), is_async_(false), - packet_format_(interface::default_values::packet_format) {} + packet_format_(interface::default_values::packet_format), + signer_(std::make_shared<auth::VoidSigner>()), + verifier_(std::make_shared<auth::VoidVerifier>()) {} int Socket::setSocketOption(int socket_option_key, hicn_format_t packet_format) { diff --git a/libtransport/src/implementation/socket.h b/libtransport/src/implementation/socket.h index 11c9a704d..3eb93cff6 100644 --- a/libtransport/src/implementation/socket.h +++ b/libtransport/src/implementation/socket.h @@ -16,6 +16,8 @@ #pragma once #include <core/facade.h> +#include <hicn/transport/auth/signer.h> +#include <hicn/transport/auth/verifier.h> #include <hicn/transport/config.h> #include <hicn/transport/interfaces/callbacks.h> #include <hicn/transport/interfaces/socket_options_default_values.h> @@ -68,6 +70,8 @@ class Socket { std::shared_ptr<core::Portal> portal_; bool is_async_; hicn_format_t packet_format_; + std::shared_ptr<auth::Signer> signer_; + std::shared_ptr<auth::Verifier> verifier_; }; } // namespace implementation diff --git a/libtransport/src/implementation/socket_consumer.h b/libtransport/src/implementation/socket_consumer.h index 33e70888f..4721f426c 100644 --- a/libtransport/src/implementation/socket_consumer.h +++ b/libtransport/src/implementation/socket_consumer.h @@ -56,8 +56,8 @@ class ConsumerSocket : public Socket { rate_estimation_observer_(nullptr), rate_estimation_batching_parameter_(default_values::batch), rate_estimation_choice_(0), - unverified_interval_(default_values::unverified_interval), - unverified_ratio_(default_values::unverified_ratio), + manifest_factor_relevant_(default_values::manifest_factor_relevant), + manifest_factor_alert_(default_values::manifest_factor_alert), verifier_(std::make_shared<auth::VoidVerifier>()), verify_signature_(false), reset_window_(false), @@ -72,6 +72,8 @@ class ConsumerSocket : public Socket { timer_interval_milliseconds_(0), recovery_strategy_(RtcTransportRecoveryStrategies::RTX_ONLY), aggregated_data_(false), + content_sharing_mode_(false), + aggregated_interests_(false), guard_raaqm_params_() { switch (protocol) { case TransportProtocolAlgorithms::CBR: @@ -197,10 +199,6 @@ class ConsumerSocket : public Socket { current_window_size_ = socket_option_value; break; - case UNVERIFIED_RATIO: - unverified_ratio_ = socket_option_value; - break; - case GAMMA_VALUE: gamma_ = socket_option_value; break; @@ -242,10 +240,6 @@ class ConsumerSocket : public Socket { interest_lifetime_ = socket_option_value; break; - case GeneralTransportOptions::UNVERIFIED_INTERVAL: - unverified_interval_ = socket_option_value; - break; - case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER: if (socket_option_value > 0) { rate_estimation_batching_parameter_ = socket_option_value; @@ -271,6 +265,14 @@ class ConsumerSocket : public Socket { (RtcTransportRecoveryStrategies)socket_option_value; break; + case MANIFEST_FACTOR_RELEVANT: + manifest_factor_relevant_ = socket_option_value; + break; + + case MANIFEST_FACTOR_ALERT: + manifest_factor_alert_ = socket_option_value; + break; + default: return SOCKET_OPTION_NOT_SET; } @@ -339,6 +341,16 @@ class ConsumerSocket : public Socket { result = SOCKET_OPTION_SET; break; + case RtcTransportOptions::CONTENT_SHARING_MODE: + content_sharing_mode_ = socket_option_value; + result = SOCKET_OPTION_SET; + break; + + case RtcTransportOptions::AGGREGATED_INTERESTS: + aggregated_interests_ = socket_option_value; + result = SOCKET_OPTION_SET; + break; + default: return result; } @@ -416,6 +428,22 @@ class ConsumerSocket : public Socket { int setSocketOption( int socket_option_key, + const std::shared_ptr<auth::Signer> &socket_option_value) { + if (!transport_protocol_->isRunning()) { + switch (socket_option_key) { + case GeneralTransportOptions::SIGNER: + signer_.reset(); + signer_ = socket_option_value; + break; + default: + return SOCKET_OPTION_NOT_SET; + } + } + return SOCKET_OPTION_SET; + } + + int setSocketOption( + int socket_option_key, const std::shared_ptr<auth::Verifier> &socket_option_value) { if (!transport_protocol_->isRunning()) { switch (socket_option_key) { @@ -506,10 +534,6 @@ class ConsumerSocket : public Socket { socket_option_value = current_window_size_; break; - case GeneralTransportOptions::UNVERIFIED_RATIO: - socket_option_value = unverified_ratio_; - break; - // RAAQM parameters case RaaqmTransportOptions::GAMMA_VALUE: @@ -550,10 +574,6 @@ class ConsumerSocket : public Socket { socket_option_value = interest_lifetime_; break; - case GeneralTransportOptions::UNVERIFIED_INTERVAL: - socket_option_value = unverified_interval_; - break; - case RaaqmTransportOptions::SAMPLE_NUMBER: socket_option_value = sample_number_; break; @@ -574,6 +594,14 @@ class ConsumerSocket : public Socket { socket_option_value = recovery_strategy_; break; + case GeneralTransportOptions::MANIFEST_FACTOR_RELEVANT: + socket_option_value = manifest_factor_relevant_; + break; + + case GeneralTransportOptions::MANIFEST_FACTOR_ALERT: + socket_option_value = manifest_factor_alert_; + break; + default: return SOCKET_OPTION_NOT_GET; } @@ -599,6 +627,14 @@ class ConsumerSocket : public Socket { socket_option_value = aggregated_data_; break; + case RtcTransportOptions::CONTENT_SHARING_MODE: + socket_option_value = content_sharing_mode_; + break; + + case RtcTransportOptions::AGGREGATED_INTERESTS: + socket_option_value = aggregated_interests_; + break; + default: return SOCKET_OPTION_NOT_GET; } @@ -689,6 +725,18 @@ class ConsumerSocket : public Socket { } int getSocketOption(int socket_option_key, + std::shared_ptr<auth::Signer> &socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::SIGNER: + socket_option_value = signer_; + return SOCKET_OPTION_GET; + + default: + return SOCKET_OPTION_NOT_GET; + } + } + + int getSocketOption(int socket_option_key, std::shared_ptr<auth::Verifier> &socket_option_value) { switch (socket_option_key) { case GeneralTransportOptions::VERIFIER: @@ -827,8 +875,8 @@ class ConsumerSocket : public Socket { int rate_estimation_choice_; // Verification parameters - uint32_t unverified_interval_; - double unverified_ratio_; + uint32_t manifest_factor_relevant_; + uint32_t manifest_factor_alert_; std::shared_ptr<auth::Verifier> verifier_; transport::auth::KeyId *key_id_; std::atomic_bool verify_signature_; @@ -856,6 +904,8 @@ class ConsumerSocket : public Socket { // RTC protocol RtcTransportRecoveryStrategies recovery_strategy_; bool aggregated_data_; + bool content_sharing_mode_; + bool aggregated_interests_; utils::SpinLock guard_raaqm_params_; std::string output_interface_; diff --git a/libtransport/src/implementation/socket_producer.h b/libtransport/src/implementation/socket_producer.h index 37151d497..53ce28766 100644 --- a/libtransport/src/implementation/socket_producer.h +++ b/libtransport/src/implementation/socket_producer.h @@ -51,9 +51,8 @@ class ProducerSocket : public Socket { data_packet_size_(default_values::content_object_packet_size), max_segment_size_(default_values::content_object_packet_size), content_object_expiry_time_(default_values::content_object_expiry_time), - making_manifest_(default_values::manifest_capacity), + manifest_max_capacity_(default_values::manifest_max_capacity), hash_algorithm_(auth::CryptoHashType::SHA256), - signer_(std::make_shared<auth::VoidSigner>()), suffix_strategy_(std::make_shared<utils::IncrementalSuffixStrategy>(0)), aggregated_data_(false), fec_setting_(""), @@ -181,8 +180,8 @@ class ProducerSocket : public Socket { } break; - case GeneralTransportOptions::MAKE_MANIFEST: - making_manifest_ = socket_option_value; + case GeneralTransportOptions::MANIFEST_MAX_CAPACITY: + manifest_max_capacity_ = socket_option_value; break; case GeneralTransportOptions::MAX_SEGMENT_SIZE: @@ -433,6 +432,20 @@ class ProducerSocket : public Socket { return SOCKET_OPTION_SET; } + virtual int setSocketOption( + int socket_option_key, + const std::shared_ptr<auth::Verifier> &socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::VERIFIER: + verifier_.reset(); + verifier_ = socket_option_value; + return SOCKET_OPTION_SET; + + default: + return SOCKET_OPTION_NOT_SET; + } + } + int getSocketOption(int socket_option_key, ProducerCallback **socket_option_value) { // Reschedule the function on the io_service to avoid race condition in @@ -456,12 +469,13 @@ class ProducerSocket : public Socket { virtual int getSocketOption(int socket_option_key, uint32_t &socket_option_value) { switch (socket_option_key) { - case GeneralTransportOptions::MAKE_MANIFEST: - socket_option_value = making_manifest_; + case GeneralTransportOptions::MANIFEST_MAX_CAPACITY: + socket_option_value = (uint32_t)manifest_max_capacity_; break; case GeneralTransportOptions::OUTPUT_BUFFER_SIZE: - socket_option_value = production_protocol_->getOutputBufferSize(); + socket_option_value = + (uint32_t)production_protocol_->getOutputBufferSize(); break; case GeneralTransportOptions::DATA_PACKET_SIZE: @@ -636,6 +650,18 @@ class ProducerSocket : public Socket { return SOCKET_OPTION_GET; } + int getSocketOption(int socket_option_key, + std::shared_ptr<auth::Verifier> &socket_option_value) { + switch (socket_option_key) { + case GeneralTransportOptions::VERIFIER: + socket_option_value = verifier_; + return SOCKET_OPTION_GET; + + default: + return SOCKET_OPTION_NOT_GET; + } + } + int getSocketOption(int socket_option_key, std::string &socket_option_value) { switch (socket_option_key) { case GeneralTransportOptions::FEC_TYPE: @@ -736,11 +762,10 @@ class ProducerSocket : public Socket { std::atomic<size_t> max_segment_size_; std::atomic<uint32_t> content_object_expiry_time_; - std::atomic<uint32_t> making_manifest_; + std::atomic<uint32_t> manifest_max_capacity_; std::atomic<auth::CryptoHashType> hash_algorithm_; std::atomic<auth::CryptoSuite> crypto_suite_; utils::SpinLock signer_lock_; - std::shared_ptr<auth::Signer> signer_; std::shared_ptr<utils::SuffixStrategy> suffix_strategy_; std::shared_ptr<protocol::ProductionProtocol> production_protocol_; diff --git a/libtransport/src/implementation/tls_rtc_socket_producer.cc b/libtransport/src/implementation/tls_rtc_socket_producer.cc deleted file mode 100644 index 06d613ef0..000000000 --- a/libtransport/src/implementation/tls_rtc_socket_producer.cc +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <hicn/transport/core/interest.h> -#include <hicn/transport/interfaces/p2psecure_socket_producer.h> -#include <implementation/p2psecure_socket_producer.h> -#include <implementation/tls_rtc_socket_producer.h> -#include <openssl/bio.h> -#include <openssl/rand.h> -#include <openssl/ssl.h> - -namespace transport { -namespace implementation { - -int TLSRTCProducerSocket::read(BIO *b, char *buf, size_t size, - size_t *readbytes) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = TLSRTCProducerSocket::readOld(b, buf, (int)size); - - if (ret <= 0) { - *readbytes = 0; - return ret; - } - - *readbytes = (size_t)ret; - - return 1; -} - -int TLSRTCProducerSocket::readOld(BIO *b, char *buf, int size) { - TLSRTCProducerSocket *socket; - socket = (TLSRTCProducerSocket *)BIO_get_data(b); - - std::unique_lock<std::mutex> lck(socket->mtx_); - if (!socket->something_to_read_) { - (socket->cv_).wait(lck); - } - - utils::MemBuf *membuf = socket->handshake_packet_->next(); - int size_to_read; - - if ((int)membuf->length() > size) { - size_to_read = size; - } else { - size_to_read = membuf->length(); - socket->something_to_read_ = false; - } - - std::memcpy(buf, membuf->data(), size_to_read); - membuf->trimStart(size_to_read); - - return size_to_read; -} - -int TLSRTCProducerSocket::write(BIO *b, const char *buf, size_t size, - size_t *written) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = TLSRTCProducerSocket::writeOld(b, buf, (int)size); - - if (ret <= 0) { - *written = 0; - return ret; - } - - *written = (size_t)ret; - - return 1; -} - -int TLSRTCProducerSocket::writeOld(BIO *b, const char *buf, int num) { - TLSRTCProducerSocket *socket; - socket = (TLSRTCProducerSocket *)BIO_get_data(b); - - if (socket->getHandshakeState() != SERVER_FINISHED && socket->first_) { - uint32_t making_manifest = socket->parent_->making_manifest_; - - socket->tls_chunks_--; - socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, - 0U); - socket->parent_->ProducerSocket::produce( - socket->name_, (const uint8_t *)buf, num, socket->tls_chunks_ == 0, 0); - socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, - making_manifest); - socket->first_ = false; - - } else { - std::unique_ptr<utils::MemBuf> mbuf = - utils::MemBuf::copyBuffer(buf, (std::size_t)num, 0, 0); - auto a = mbuf.release(); - - socket->async_thread_.add([socket = socket, a]() { - socket->to_call_oncontentproduced_--; - auto mbuf = std::unique_ptr<utils::MemBuf>(a); - - socket->RTCProducerSocket::produce(std::move(mbuf)); - - ProducerContentCallback on_content_produced_application; - socket->getSocketOption(ProducerCallbacksOptions::CONTENT_PRODUCED, - on_content_produced_application); - - if (socket->to_call_oncontentproduced_ == 0 && - on_content_produced_application) { - on_content_produced_application( - (transport::interface::ProducerSocket &)(*socket->getInterface()), - std::error_code(), 0); - } - }); - } - - return num; -} - -TLSRTCProducerSocket::TLSRTCProducerSocket( - interface::ProducerSocket *producer_socket, P2PSecureProducerSocket *parent, - const Name &handshake_name) - : ProducerSocket(producer_socket), - RTCProducerSocket(producer_socket), - TLSProducerSocket(producer_socket, parent, handshake_name) { - BIO_METHOD *bio_meth = - BIO_meth_new(BIO_TYPE_ACCEPT, "secure rtc producer socket"); - BIO_meth_set_read(bio_meth, TLSRTCProducerSocket::readOld); - BIO_meth_set_write(bio_meth, TLSRTCProducerSocket::writeOld); - BIO_meth_set_ctrl(bio_meth, TLSProducerSocket::ctrl); - BIO *bio = BIO_new(bio_meth); - BIO_set_init(bio, 1); - BIO_set_data(bio, this); - SSL_set_bio(ssl_, bio, bio); -} - -void TLSRTCProducerSocket::accept() { - HandshakeState handshake_state = getHandshakeState(); - - if (handshake_state == UNINITIATED || handshake_state == CLIENT_HELLO) { - tls_chunks_ = 1; - int result = SSL_accept(ssl_); - - if (result != 1) - throw errors::RuntimeException("Unable to perform client handshake"); - } - - DLOG_IF(INFO, VLOG_IS_ON(2)) << "Handshake performed!"; - - parent_->list_producers.push_front( - std::move(parent_->map_producers[handshake_name_])); - parent_->map_producers.erase(handshake_name_); - - ProducerInterestCallback on_interest_process_decrypted; - getSocketOption(ProducerCallbacksOptions::CACHE_MISS, - on_interest_process_decrypted); - - if (on_interest_process_decrypted) { - Interest inter(std::move(handshake_packet_)); - on_interest_process_decrypted( - (transport::interface::ProducerSocket &)(*getInterface()), inter); - } - - parent_->cv_.notify_one(); -} - -int TLSRTCProducerSocket::async_accept() { - if (!async_thread_.stopped()) { - async_thread_.add([this]() { this->TLSRTCProducerSocket::accept(); }); - } else { - throw errors::RuntimeException( - "Async thread not running, impossible to perform handshake"); - } - - return 1; -} - -void TLSRTCProducerSocket::produce(std::unique_ptr<utils::MemBuf> &&buffer) { - HandshakeState handshake_state = getHandshakeState(); - - if (handshake_state != SERVER_FINISHED) { - throw errors::RuntimeException( - "New handshake on the same P2P secure producer socket not supported"); - } - - size_t buf_size = buffer->length(); - tls_chunks_ = ceil((float)buf_size / (float)SSL3_RT_MAX_PLAIN_LENGTH); - to_call_oncontentproduced_ = tls_chunks_; - - SSL_write(ssl_, buffer->data(), buf_size); - BIO *wbio = SSL_get_wbio(ssl_); - int i = BIO_flush(wbio); - (void)i; // To shut up gcc 5 -} - -} // namespace implementation -} // namespace transport diff --git a/libtransport/src/implementation/tls_rtc_socket_producer.h b/libtransport/src/implementation/tls_rtc_socket_producer.h deleted file mode 100644 index f6dc425e4..000000000 --- a/libtransport/src/implementation/tls_rtc_socket_producer.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <implementation/tls_socket_producer.h> - -namespace transport { -namespace implementation { - -class P2PSecureProducerSocket; - -class TLSRTCProducerSocket : public TLSProducerSocket { - friend class P2PSecureProducerSocket; - - public: - explicit TLSRTCProducerSocket(interface::ProducerSocket *producer_socket, - P2PSecureProducerSocket *parent, - const Name &handshake_name); - - ~TLSRTCProducerSocket() = default; - - uint32_t produceDatagram(const Name &content_name, - std::unique_ptr<utils::MemBuf> &&buffer) override; - - void accept() override; - - int async_accept() override; - - using TLSProducerSocket::onInterest; - using TLSProducerSocket::produce; - - protected: - static int read(BIO *b, char *buf, size_t size, size_t *readbytes); - - static int readOld(BIO *h, char *buf, int size); - - static int write(BIO *b, const char *buf, size_t size, size_t *written); - - static int writeOld(BIO *h, const char *buf, int num); -}; - -} // namespace implementation - -} // end namespace transport diff --git a/libtransport/src/implementation/tls_socket_consumer.cc b/libtransport/src/implementation/tls_socket_consumer.cc deleted file mode 100644 index b368c4b88..000000000 --- a/libtransport/src/implementation/tls_socket_consumer.cc +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <implementation/tls_socket_consumer.h> -#include <openssl/bio.h> -#include <openssl/ssl.h> -#include <openssl/tls1.h> - -#include <random> - -namespace transport { -namespace implementation { - -void TLSConsumerSocket::setInterestPayload(interface::ConsumerSocket &c, - const core::Interest &interest) { - Interest &int2 = const_cast<Interest &>(interest); - random_suffix_ = int2.getName().getSuffix(); - - if (payload_ != NULL) int2.appendPayload(std::move(payload_)); -} - -/* Return the number of read bytes in the return param */ -int readOldTLS(BIO *b, char *buf, int size) { - if (size < 0) return size; - - TLSConsumerSocket *socket; - socket = (TLSConsumerSocket *)BIO_get_data(b); - - std::unique_lock<std::mutex> lck(socket->mtx_); - - if (!socket->something_to_read_) { - if (!socket->transport_protocol_->isRunning()) { - socket->network_name_.setSuffix(socket->random_suffix_); - socket->ConsumerSocket::consume(socket->network_name_); - } - - if (!socket->something_to_read_) socket->cv_.wait(lck); - } - - size_t size_to_read, read; - size_t chain_size = socket->head_->length(); - - if (socket->head_->isChained()) - chain_size = socket->head_->computeChainDataLength(); - - if (chain_size > (size_t)size) { - read = size_to_read = (size_t)size; - } else { - read = size_to_read = chain_size; - socket->something_to_read_ = false; - } - - while (size_to_read) { - if (socket->head_->length() < size_to_read) { - std::memcpy(buf, socket->head_->data(), socket->head_->length()); - size_to_read -= socket->head_->length(); - buf += socket->head_->length(); - socket->head_ = socket->head_->pop(); - } else { - std::memcpy(buf, socket->head_->data(), size_to_read); - socket->head_->trimStart(size_to_read); - size_to_read = 0; - } - } - - return (int)read; -} - -/* Return the number of read bytes in readbytes */ -int readTLS(BIO *b, char *buf, size_t size, size_t *readbytes) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = readOldTLS(b, buf, (int)size); - - if (ret <= 0) { - *readbytes = 0; - return ret; - } - - *readbytes = (size_t)ret; - - return 1; -} - -/* Return the number of written bytes in the return param */ -int writeOldTLS(BIO *b, const char *buf, int num) { - TLSConsumerSocket *socket; - socket = (TLSConsumerSocket *)BIO_get_data(b); - - socket->payload_ = utils::MemBuf::copyBuffer(buf, num); - - socket->ConsumerSocket::setSocketOption( - ConsumerCallbacksOptions::INTEREST_OUTPUT, - (ConsumerInterestCallback)std::bind( - &TLSConsumerSocket::setInterestPayload, socket, std::placeholders::_1, - std::placeholders::_2)); - - return num; -} - -/* Return the number of written bytes in written */ -int writeTLS(BIO *b, const char *buf, size_t size, size_t *written) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = writeOldTLS(b, buf, (int)size); - - if (ret <= 0) { - *written = 0; - return ret; - } - - *written = (size_t)ret; - - return 1; -} - -long ctrlTLS(BIO *b, int cmd, long num, void *ptr) { return 1; } - -TLSConsumerSocket::TLSConsumerSocket(interface::ConsumerSocket *consumer_socket, - int protocol, SSL *ssl) - : ConsumerSocket(consumer_socket, protocol), - name_(), - decrypted_content_(), - payload_(), - head_(), - something_to_read_(false), - content_downloaded_(false), - random_suffix_(), - producer_namespace_(), - read_callback_decrypted_(), - mtx_(), - cv_(), - async_downloader_tls_() { - /* Create the (d)TLS state */ - const SSL_METHOD *meth = TLS_client_method(); - ctx_ = SSL_CTX_new(meth); - - int result = - SSL_CTX_set_ciphersuites(ctx_, - "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_" - "SHA256:TLS_AES_128_GCM_SHA256"); - if (result != 1) { - throw errors::RuntimeException( - "Unable to set cipher list on TLS subsystem. Aborting."); - } - - SSL_CTX_set_min_proto_version(ctx_, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(ctx_, TLS1_3_VERSION); - SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, NULL); - SSL_CTX_set_ssl_version(ctx_, meth); - - ssl_ = ssl; - - BIO_METHOD *bio_meth = - BIO_meth_new(BIO_TYPE_CONNECT, "secure consumer socket"); - BIO_meth_set_read(bio_meth, readOldTLS); - BIO_meth_set_write(bio_meth, writeOldTLS); - BIO_meth_set_ctrl(bio_meth, ctrlTLS); - BIO *bio = BIO_new(bio_meth); - BIO_set_init(bio, 1); - BIO_set_data(bio, this); - SSL_set_bio(ssl_, bio, bio); - - std::default_random_engine generator; - std::uniform_int_distribution<int> distribution( - 1, std::numeric_limits<uint32_t>::max()); - random_suffix_ = 0; - - this->ConsumerSocket::setSocketOption(ConsumerCallbacksOptions::READ_CALLBACK, - this); -}; - -/* The producer interface is not owned by the application, so is TLSSocket task - * to deallocate the memory */ -TLSConsumerSocket::~TLSConsumerSocket() { delete consumer_interface_; } - -int TLSConsumerSocket::consume(const Name &name, - std::unique_ptr<utils::MemBuf> &&buffer) { - this->payload_ = std::move(buffer); - - this->ConsumerSocket::setSocketOption( - ConsumerCallbacksOptions::INTEREST_OUTPUT, - (ConsumerInterestCallback)std::bind( - &TLSConsumerSocket::setInterestPayload, this, std::placeholders::_1, - std::placeholders::_2)); - - return consume(name); -} - -int TLSConsumerSocket::consume(const Name &name) { - if (transport_protocol_->isRunning()) { - return CONSUMER_BUSY; - } - - if ((SSL_in_before(this->ssl_) || SSL_in_init(this->ssl_))) { - throw errors::RuntimeException("Handshake not performed"); - } - - return download_content(name); -} - -int TLSConsumerSocket::download_content(const Name &name) { - network_name_ = name; - network_name_.setSuffix(0); - something_to_read_ = false; - content_downloaded_ = false; - - std::size_t max_buffer_size = read_callback_decrypted_->maxBufferSize(); - std::size_t buffer_size = - read_callback_decrypted_->maxBufferSize() + SSL3_RT_MAX_PLAIN_LENGTH; - decrypted_content_ = utils::MemBuf::createCombined(buffer_size); - int result = -1; - std::size_t size = 0; - - while (!content_downloaded_ || something_to_read_) { - result = SSL_read(this->ssl_, decrypted_content_->writableTail(), - SSL3_RT_MAX_PLAIN_LENGTH); - - /* SSL_read returns the data only if there were SSL3_RT_MAX_PLAIN_LENGTH of - * the data has been fully downloaded */ - - /* ASSERT((result < SSL3_RT_MAX_PLAIN_LENGTH && content_downloaded_) || */ - /* result == SSL3_RT_MAX_PLAIN_LENGTH); */ - - if (result >= 0) { - size += result; - decrypted_content_->append(result); - } else { - throw errors::RuntimeException("Unable to download content"); - } - - if (decrypted_content_->length() >= max_buffer_size) { - if (read_callback_decrypted_->isBufferMovable()) { - /* No need to perform an additional copy. The whole buffer will be - * tranferred to the application. */ - read_callback_decrypted_->readBufferAvailable( - std::move(decrypted_content_)); - decrypted_content_ = utils::MemBuf::create(buffer_size); - } else { - /* The buffer will be copied into the application-provided buffer */ - uint8_t *buffer; - std::size_t length; - std::size_t total_length = decrypted_content_->length(); - - while (decrypted_content_->length()) { - buffer = nullptr; - length = 0; - read_callback_decrypted_->getReadBuffer(&buffer, &length); - - if (!buffer || !length) { - throw errors::RuntimeException( - "Invalid buffer provided by the application."); - } - - auto to_copy = std::min(decrypted_content_->length(), length); - std::memcpy(buffer, decrypted_content_->data(), to_copy); - decrypted_content_->trimStart(to_copy); - } - - read_callback_decrypted_->readDataAvailable(total_length); - decrypted_content_->clear(); - } - } - } - - read_callback_decrypted_->readSuccess(size); - - return CONSUMER_FINISHED; -} - -void TLSConsumerSocket::registerPrefix(const Prefix &producer_namespace) { - producer_namespace_ = producer_namespace; -} - -int TLSConsumerSocket::setSocketOption(int socket_option_key, - ReadCallback *socket_option_value) { - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, ReadCallback *socket_option_value) -> int { - switch (socket_option_key) { - case ConsumerCallbacksOptions::READ_CALLBACK: - read_callback_decrypted_ = socket_option_value; - break; - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -void TLSConsumerSocket::getReadBuffer(uint8_t **application_buffer, - size_t *max_length) {} - -void TLSConsumerSocket::readDataAvailable(size_t length) noexcept {} - -size_t TLSConsumerSocket::maxBufferSize() const { - return SSL3_RT_MAX_PLAIN_LENGTH; -} - -void TLSConsumerSocket::readBufferAvailable( - std::unique_ptr<utils::MemBuf> &&buffer) noexcept { - std::unique_lock<std::mutex> lck(this->mtx_); - - if (head_) { - head_->prependChain(std::move(buffer)); - } else { - head_ = std::move(buffer); - } - - something_to_read_ = true; - cv_.notify_one(); -} - -void TLSConsumerSocket::readError(const std::error_code &ec) noexcept {} - -void TLSConsumerSocket::readSuccess(std::size_t total_size) noexcept { - std::unique_lock<std::mutex> lck(this->mtx_); - content_downloaded_ = true; - something_to_read_ = true; - cv_.notify_one(); -} - -bool TLSConsumerSocket::isBufferMovable() noexcept { return true; } - -} // namespace implementation -} // namespace transport diff --git a/libtransport/src/implementation/tls_socket_consumer.h b/libtransport/src/implementation/tls_socket_consumer.h deleted file mode 100644 index a74f1ee10..000000000 --- a/libtransport/src/implementation/tls_socket_consumer.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <hicn/transport/interfaces/socket_consumer.h> -#include <implementation/socket_consumer.h> -#include <openssl/ssl.h> - -namespace transport { -namespace implementation { - -class TLSConsumerSocket : public ConsumerSocket, - public interface::ConsumerSocket::ReadCallback { - /* Return the number of read bytes in readbytes */ - friend int readTLS(BIO *b, char *buf, size_t size, size_t *readbytes); - - /* Return the number of read bytes in the return param */ - friend int readOldTLS(BIO *h, char *buf, int size); - - /* Return the number of written bytes in written */ - friend int writeTLS(BIO *b, const char *buf, size_t size, size_t *written); - - /* Return the number of written bytes in the return param */ - friend int writeOldTLS(BIO *h, const char *buf, int num); - - friend long ctrlTLS(BIO *b, int cmd, long num, void *ptr); - - public: - explicit TLSConsumerSocket(interface::ConsumerSocket *consumer_socket, - int protocol, SSL *ssl_); - - ~TLSConsumerSocket(); - - int consume(const Name &name, std::unique_ptr<utils::MemBuf> &&buffer); - int consume(const Name &name) override; - - void registerPrefix(const Prefix &producer_namespace); - - int setSocketOption( - int socket_option_key, - interface::ConsumerSocket::ReadCallback *socket_option_value) override; - - using ConsumerSocket::getSocketOption; - using ConsumerSocket::setSocketOption; - - protected: - /* Callback invoked once an interest has been received and its payload - * decrypted */ - ConsumerInterestCallback on_interest_input_decrypted_; - ConsumerInterestCallback on_interest_process_decrypted_; - - private: - Name name_; - /* SSL handle */ - SSL *ssl_; - SSL_CTX *ctx_; - /* Chain of MemBuf to be used as a temporary buffer to pass descypted data - * from the underlying layer to the application */ - std::unique_ptr<utils::MemBuf> decrypted_content_; - /* Chain of MemBuf holding the payload to be written into interest or data */ - std::unique_ptr<utils::MemBuf> payload_; - /* Chain of MemBuf holding the data retrieved from the underlying layer */ - std::unique_ptr<utils::MemBuf> head_; - bool something_to_read_; - bool content_downloaded_; - uint32_t random_suffix_; - Prefix producer_namespace_; - interface::ConsumerSocket::ReadCallback *read_callback_decrypted_; - std::mutex mtx_; - /* Condition variable for the wait */ - std::condition_variable cv_; - utils::EventThread async_downloader_tls_; - - void setInterestPayload(interface::ConsumerSocket &c, - const core::Interest &interest); - - virtual void getReadBuffer(uint8_t **application_buffer, - size_t *max_length) override; - - virtual void readDataAvailable(size_t length) noexcept override; - - virtual size_t maxBufferSize() const override; - - virtual void readBufferAvailable( - std::unique_ptr<utils::MemBuf> &&buffer) noexcept override; - - virtual void readError(const std::error_code &ec) noexcept override; - - virtual void readSuccess(std::size_t total_size) noexcept override; - - virtual bool isBufferMovable() noexcept override; - - int download_content(const Name &name); -}; - -} // namespace implementation -} // end namespace transport diff --git a/libtransport/src/implementation/tls_socket_producer.cc b/libtransport/src/implementation/tls_socket_producer.cc deleted file mode 100644 index 47f3b43a6..000000000 --- a/libtransport/src/implementation/tls_socket_producer.cc +++ /dev/null @@ -1,550 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <hicn/transport/interfaces/socket_producer.h> -#include <implementation/p2psecure_socket_producer.h> -#include <implementation/tls_socket_producer.h> -#include <openssl/bio.h> -#include <openssl/rand.h> -#include <openssl/ssl.h> - -namespace transport { -namespace implementation { - -/* Return the number of read bytes in readbytes */ -int TLSProducerSocket::read(BIO *b, char *buf, size_t size, size_t *readbytes) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = TLSProducerSocket::readOld(b, buf, (int)size); - - if (ret <= 0) { - *readbytes = 0; - return ret; - } - - *readbytes = (size_t)ret; - - return 1; -} - -/* Return the number of read bytes in the return param */ -int TLSProducerSocket::readOld(BIO *b, char *buf, int size) { - TLSProducerSocket *socket; - socket = (TLSProducerSocket *)BIO_get_data(b); - - std::unique_lock<std::mutex> lck(socket->mtx_); - - DLOG_IF(INFO, VLOG_IS_ON(4)) << "Start wait on the CV."; - - if (!socket->something_to_read_) { - (socket->cv_).wait(lck); - } - - DLOG_IF(INFO, VLOG_IS_ON(4)) << "CV unlocked."; - - /* Either there already is something to read, or the thread has been waken up. - * We must return the payload in the interest anyway */ - utils::MemBuf *membuf = socket->handshake_packet_->next(); - int size_to_read; - - if ((int)membuf->length() > size) { - size_to_read = size; - } else { - size_to_read = (int)membuf->length(); - socket->something_to_read_ = false; - } - - std::memcpy(buf, membuf->data(), size_to_read); - membuf->trimStart(size_to_read); - - return size_to_read; -} - -/* Return the number of written bytes in written */ -int TLSProducerSocket::write(BIO *b, const char *buf, size_t size, - size_t *written) { - int ret; - - if (size > INT_MAX) size = INT_MAX; - - ret = TLSProducerSocket::writeOld(b, buf, (int)size); - - if (ret <= 0) { - *written = 0; - return ret; - } - - *written = (size_t)ret; - - return 1; -} - -/* Return the number of written bytes in the return param */ -int TLSProducerSocket::writeOld(BIO *b, const char *buf, int num) { - TLSProducerSocket *socket; - socket = (TLSProducerSocket *)BIO_get_data(b); - - if (socket->getHandshakeState() != SERVER_FINISHED && socket->first_) { - uint32_t making_manifest = socket->parent_->making_manifest_; - - //! socket->tls_chunks_ corresponds to is_last - socket->tls_chunks_--; - socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, - 0U); - socket->parent_->ProducerSocket::produceStream( - socket->name_, (const uint8_t *)buf, num, socket->tls_chunks_ == 0, - socket->last_segment_); - socket->parent_->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, - making_manifest); - socket->first_ = false; - } else { - socket->still_writing_ = true; - - std::unique_ptr<utils::MemBuf> mbuf = - utils::MemBuf::copyBuffer(buf, (std::size_t)num, 0, 0); - auto a = mbuf.release(); - - socket->async_thread_.add([socket = socket, a]() { - auto mbuf = std::unique_ptr<utils::MemBuf>(a); - - socket->tls_chunks_--; - socket->to_call_oncontentproduced_--; - - socket->last_segment_ += socket->ProducerSocket::produceStream( - socket->name_, std::move(mbuf), socket->tls_chunks_ == 0, - socket->last_segment_); - - ProducerContentCallback *on_content_produced_application; - socket->getSocketOption(ProducerCallbacksOptions::CONTENT_PRODUCED, - &on_content_produced_application); - - if (socket->to_call_oncontentproduced_ == 0 && - on_content_produced_application) { - on_content_produced_application->operator()(*socket->getInterface(), - std::error_code(), 0); - } - }); - } - - return num; -} - -TLSProducerSocket::TLSProducerSocket(interface::ProducerSocket *producer_socket, - P2PSecureProducerSocket *parent, - const Name &handshake_name) - : ProducerSocket(producer_socket, - ProductionProtocolAlgorithms::BYTE_STREAM), - on_content_produced_application_(), - mtx_(), - cv_(), - something_to_read_(false), - handshake_state_(UNINITIATED), - name_(), - handshake_packet_(), - last_segment_(0), - parent_(parent), - first_(true), - handshake_name_(handshake_name), - tls_chunks_(0), - to_call_oncontentproduced_(0), - still_writing_(false), - encryption_thread_() { - const SSL_METHOD *meth = TLS_server_method(); - ctx_ = SSL_CTX_new(meth); - - /* Setup SSL context (identity and parameter to use TLS 1.3) */ - SSL_CTX_use_certificate(ctx_, parent->cert_509_); - SSL_CTX_use_PrivateKey(ctx_, parent->pkey_rsa_); - - int result = - SSL_CTX_set_ciphersuites(ctx_, - "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_" - "SHA256:TLS_AES_128_GCM_SHA256"); - - if (result != 1) { - throw errors::RuntimeException( - "Unable to set cipher list on TLS subsystem. Aborting."); - } - - // We force it to be TLS 1.3 - SSL_CTX_set_min_proto_version(ctx_, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(ctx_, TLS1_3_VERSION); - SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, NULL); - SSL_CTX_set_num_tickets(ctx_, 0); - - result = SSL_CTX_add_custom_ext( - ctx_, 100, SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS, - TLSProducerSocket::addHicnKeyIdCb, TLSProducerSocket::freeHicnKeyIdCb, - this, TLSProducerSocket::parseHicnKeyIdCb, NULL); - - ssl_ = SSL_new(ctx_); - - /* Setup this producer socker as the bio that TLS will use to write and read - * data (in stream mode) */ - BIO_METHOD *bio_meth = - BIO_meth_new(BIO_TYPE_ACCEPT, "secure producer socket"); - BIO_meth_set_read(bio_meth, TLSProducerSocket::readOld); - BIO_meth_set_write(bio_meth, TLSProducerSocket::writeOld); - BIO_meth_set_ctrl(bio_meth, TLSProducerSocket::ctrl); - BIO *bio = BIO_new(bio_meth); - BIO_set_init(bio, 1); - BIO_set_data(bio, this); - SSL_set_bio(ssl_, bio, bio); - - /* Set the callback so that when an interest is received we catch it and we - * decrypt the payload before passing it to the application. */ - this->ProducerSocket::setSocketOption( - ProducerCallbacksOptions::CACHE_MISS, - (ProducerInterestCallback)std::bind(&TLSProducerSocket::cacheMiss, this, - std::placeholders::_1, - std::placeholders::_2)); - - this->ProducerSocket::setSocketOption( - ProducerCallbacksOptions::CONTENT_PRODUCED, - (ProducerContentCallback)bind( - &TLSProducerSocket::onContentProduced, this, std::placeholders::_1, - std::placeholders::_2, std::placeholders::_3)); -} - -/* The producer interface is not owned by the application, so is TLSSocket task - * to deallocate the memory */ -TLSProducerSocket::~TLSProducerSocket() { delete producer_interface_; } - -void TLSProducerSocket::accept() { - HandshakeState handshake_state = getHandshakeState(); - - if (handshake_state == UNINITIATED || handshake_state == CLIENT_HELLO) { - tls_chunks_ = 1; - int result = SSL_accept(ssl_); - - if (result != 1) - throw errors::RuntimeException("Unable to perform client handshake"); - } - - parent_->list_producers.push_front( - std::move(parent_->map_producers[handshake_name_])); - parent_->map_producers.erase(handshake_name_); - - ProducerInterestCallback *on_interest_process_decrypted; - getSocketOption(ProducerCallbacksOptions::CACHE_MISS, - &on_interest_process_decrypted); - - if (*on_interest_process_decrypted) { - Interest inter(std::move(*handshake_packet_)); - handshake_packet_.reset(); - on_interest_process_decrypted->operator()(*getInterface(), inter); - } else { - throw errors::RuntimeException( - "On interest process unset: unable to perform handshake"); - } - - handshake_state_ = SERVER_FINISHED; - DLOG_IF(INFO, VLOG_IS_ON(2)) << "Handshake performed!"; -} - -int TLSProducerSocket::async_accept() { - if (!async_thread_.stopped()) { - async_thread_.add([this]() { this->accept(); }); - } else { - throw errors::RuntimeException( - "Async thread not running: unable to perform handshake"); - } - - return 1; -} - -void TLSProducerSocket::onInterest(ProducerSocket &p, Interest &interest) { - HandshakeState handshake_state = getHandshakeState(); - - if (handshake_state == UNINITIATED || handshake_state == CLIENT_HELLO) { - std::unique_lock<std::mutex> lck(mtx_); - - name_ = interest.getName(); - // interest.separateHeaderPayload(); - handshake_packet_ = interest.acquireMemBufReference(); - something_to_read_ = true; - - cv_.notify_one(); - return; - } else if (handshake_state == SERVER_FINISHED) { - // interest.separateHeaderPayload(); - handshake_packet_ = interest.acquireMemBufReference(); - something_to_read_ = true; - - if (interest.getPayload()->length() > 0) { - SSL_read( - ssl_, - const_cast<unsigned char *>(interest.getPayload()->writableData()), - (int)interest.getPayload()->length()); - } - - ProducerInterestCallback *on_interest_input_decrypted; - getSocketOption(ProducerCallbacksOptions::INTEREST_INPUT, - &on_interest_input_decrypted); - - if (*on_interest_input_decrypted) - (*on_interest_input_decrypted)(*getInterface(), interest); - } -} - -void TLSProducerSocket::cacheMiss(interface::ProducerSocket &p, - Interest &interest) { - HandshakeState handshake_state = getHandshakeState(); - - DLOG_IF(INFO, VLOG_IS_ON(3)) << "On cache miss in TLS socket producer."; - - if (handshake_state == CLIENT_HELLO) { - std::unique_lock<std::mutex> lck(mtx_); - - // interest.separateHeaderPayload(); - handshake_packet_ = interest.acquireMemBufReference(); - something_to_read_ = true; - handshake_state_ = CLIENT_FINISHED; - - cv_.notify_one(); - } else if (handshake_state == SERVER_FINISHED) { - // interest.separateHeaderPayload(); - handshake_packet_ = interest.acquireMemBufReference(); - something_to_read_ = true; - - if (interest.getPayload()->length() > 0) { - SSL_read( - ssl_, - const_cast<unsigned char *>(interest.getPayload()->writableData()), - (int)interest.getPayload()->length()); - } - - if (on_interest_process_decrypted_ != VOID_HANDLER) - on_interest_process_decrypted_(*getInterface(), interest); - } -} - -TLSProducerSocket::HandshakeState TLSProducerSocket::getHandshakeState() { - if (SSL_in_before(ssl_)) { - handshake_state_ = UNINITIATED; - } - - if (SSL_in_init(ssl_) && handshake_state_ == UNINITIATED) { - handshake_state_ = CLIENT_HELLO; - } - - return handshake_state_; -} - -void TLSProducerSocket::onContentProduced(interface::ProducerSocket &p, - const std::error_code &err, - uint64_t bytes_written) {} - -uint32_t TLSProducerSocket::produceStream( - const Name &content_name, std::unique_ptr<utils::MemBuf> &&buffer, - bool is_last, uint32_t start_offset) { - if (getHandshakeState() != SERVER_FINISHED) { - throw errors::RuntimeException( - "New handshake on the same P2P secure producer socket not supported"); - } - - size_t buf_size = buffer->length(); - name_ = portal_->getServedNamespaces().begin()->mapName(content_name); - tls_chunks_ = to_call_oncontentproduced_ = - (int)ceil((float)buf_size / (float)SSL3_RT_MAX_PLAIN_LENGTH); - - if (!is_last) { - tls_chunks_++; - } - - last_segment_ = start_offset; - - SSL_write(ssl_, buffer->data(), (int)buf_size); - BIO *wbio = SSL_get_wbio(ssl_); - int i = BIO_flush(wbio); - (void)i; // To shut up gcc 5 - - return 0; -} - -long TLSProducerSocket::ctrl(BIO *b, int cmd, long num, void *ptr) { - if (cmd == BIO_CTRL_FLUSH) { - } - - return 1; -} - -int TLSProducerSocket::addHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, - const unsigned char **out, size_t *outlen, - X509 *x, size_t chainidx, int *al, - void *add_arg) { - TLSProducerSocket *socket = reinterpret_cast<TLSProducerSocket *>(add_arg); - - DLOG_IF(INFO, VLOG_IS_ON(3)) - << "On addHicnKeyIdCb, for the prefix registration."; - - if (ext_type == 100) { - auto &prefix = *socket->parent_->portal_->getServedNamespaces().begin(); - const ip_prefix_t &ip_prefix = prefix.toIpPrefixStruct(); - int inet_family = prefix.getAddressFamily(); - uint16_t prefix_len_bits = prefix.getPrefixLength(); - uint8_t prefix_len_bytes = prefix_len_bits / 8; - uint8_t prefix_len_u32 = prefix_len_bits / 32; - - ip_prefix_t *out_ip = (ip_prefix_t *)malloc(sizeof(ip_prefix_t)); - out_ip->family = inet_family; - out_ip->len = prefix_len_bits + 32; - u8 *out_ip_buf = const_cast<u8 *>( - ip_address_get_buffer(&(out_ip->address), inet_family)); - *out = reinterpret_cast<unsigned char *>(out_ip); - - RAND_bytes((unsigned char *)&socket->key_id_, 4); - - memcpy(out_ip_buf, ip_address_get_buffer(&(ip_prefix.address), inet_family), - prefix_len_bytes); - memcpy((out_ip_buf + prefix_len_bytes), &socket->key_id_, 4); - *outlen = sizeof(ip_prefix_t); - - ip_address_t mask = {}; - ip_address_t keyId_component = {}; - u32 *mask_buf; - u32 *keyId_component_buf; - - switch (inet_family) { - case AF_INET: - mask_buf = &(mask.v4.as_u32); - keyId_component_buf = &(keyId_component.v4.as_u32); - break; - case AF_INET6: - mask_buf = mask.v6.as_u32; - keyId_component_buf = keyId_component.v6.as_u32; - break; - default: - throw errors::RuntimeException("Unknown protocol"); - } - - if (prefix_len_bits > (inet_family == AF_INET6 ? IPV6_ADDR_LEN_BITS - 32 - : IPV4_ADDR_LEN_BITS - 32)) - throw errors::RuntimeException( - "Not enough space in the content name to add key_id"); - - mask_buf[prefix_len_u32] = 0xffffffff; - keyId_component_buf[prefix_len_u32] = socket->key_id_; - socket->last_segment_ = 0; - - socket->on_interest_process_decrypted_ = - socket->parent_->on_interest_process_decrypted_; - - socket->registerPrefix( - Prefix(prefix.getName(Name(inet_family, (uint8_t *)&mask), - Name(inet_family, (uint8_t *)&keyId_component), - prefix.getName()), - out_ip->len)); - socket->connect(); - } - return 1; -} - -void TLSProducerSocket::freeHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, - const unsigned char *out, - void *add_arg) { - free(const_cast<unsigned char *>(out)); -} - -int TLSProducerSocket::parseHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, - const unsigned char *in, size_t inlen, - X509 *x, size_t chainidx, int *al, - void *add_arg) { - return 1; -} - -int TLSProducerSocket::setSocketOption( - int socket_option_key, ProducerInterestCallback socket_option_value) { - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerInterestCallback socket_option_value) -> int { - int result = SOCKET_OPTION_SET; - - switch (socket_option_key) { - case ProducerCallbacksOptions::INTEREST_INPUT: - on_interest_input_decrypted_ = socket_option_value; - break; - - case ProducerCallbacksOptions::INTEREST_DROP: - on_interest_dropped_input_buffer_ = socket_option_value; - break; - - case ProducerCallbacksOptions::INTEREST_PASS: - on_interest_inserted_input_buffer_ = socket_option_value; - break; - - case ProducerCallbacksOptions::CACHE_HIT: - on_interest_satisfied_output_buffer_ = socket_option_value; - break; - - case ProducerCallbacksOptions::CACHE_MISS: - on_interest_process_decrypted_ = socket_option_value; - break; - - default: - result = SOCKET_OPTION_NOT_SET; - break; - } - - return result; - }); -} - -int TLSProducerSocket::setSocketOption( - int socket_option_key, ProducerContentCallback socket_option_value) { - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerContentCallback socket_option_value) -> int { - switch (socket_option_key) { - case ProducerCallbacksOptions::CONTENT_PRODUCED: - on_content_produced_application_ = socket_option_value; - break; - - default: - return SOCKET_OPTION_NOT_SET; - } - - return SOCKET_OPTION_SET; - }); -} - -int TLSProducerSocket::getSocketOption( - int socket_option_key, ProducerContentCallback **socket_option_value) { - return rescheduleOnIOService( - socket_option_key, socket_option_value, - [this](int socket_option_key, - ProducerContentCallback **socket_option_value) -> int { - switch (socket_option_key) { - case ProducerCallbacksOptions::CONTENT_PRODUCED: - *socket_option_value = &on_content_produced_application_; - break; - - default: - return SOCKET_OPTION_NOT_GET; - } - - return SOCKET_OPTION_GET; - }); -} - -} // namespace implementation -} // namespace transport diff --git a/libtransport/src/implementation/tls_socket_producer.h b/libtransport/src/implementation/tls_socket_producer.h deleted file mode 100644 index 0e958b321..000000000 --- a/libtransport/src/implementation/tls_socket_producer.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <implementation/socket_producer.h> -#include <openssl/ssl.h> - -#include <condition_variable> -#include <mutex> - -namespace transport { -namespace implementation { - -class P2PSecureProducerSocket; - -class TLSProducerSocket : virtual public ProducerSocket { - friend class P2PSecureProducerSocket; - - public: - explicit TLSProducerSocket(interface::ProducerSocket *producer_socket, - P2PSecureProducerSocket *parent, - const Name &handshake_name); - - ~TLSProducerSocket(); - - uint32_t produceStream(const Name &content_name, const uint8_t *buffer, - size_t buffer_size, bool is_last = true, - uint32_t start_offset = 0) override { - return produceStream(content_name, - utils::MemBuf::copyBuffer(buffer, buffer_size), - is_last, start_offset); - } - - uint32_t produceStream(const Name &content_name, - std::unique_ptr<utils::MemBuf> &&buffer, - bool is_last = true, - uint32_t start_offset = 0) override; - - virtual void accept(); - - virtual int async_accept(); - - virtual int setSocketOption( - int socket_option_key, - ProducerInterestCallback socket_option_value) override; - - virtual int setSocketOption( - int socket_option_key, - ProducerContentCallback socket_option_value) override; - - virtual int getSocketOption( - int socket_option_key, - ProducerContentCallback **socket_option_value) override; - - int getSocketOption(int socket_option_key, - ProducerContentCallback &socket_option_value); - - int getSocketOption(int socket_option_key, - ProducerInterestCallback &socket_option_value); - - using ProducerSocket::getSocketOption; - // using ProducerSocket::onInterest; - using ProducerSocket::setSocketOption; - - protected: - enum HandshakeState { - UNINITIATED, - CLIENT_HELLO, // when CLIENT_HELLO interest has been received - CLIENT_FINISHED, // when CLIENT_FINISHED interest has been received - SERVER_FINISHED, // when handshake is done - }; - /* Callback invoked once an interest has been received and its payload - * decrypted */ - ProducerInterestCallback on_interest_input_decrypted_; - ProducerInterestCallback on_interest_process_decrypted_; - ProducerContentCallback on_content_produced_application_; - std::mutex mtx_; - /* Condition variable for the wait */ - std::condition_variable cv_; - /* Bool variable, true if there is something to read (an interest arrived) */ - bool something_to_read_; - /* Bool variable, true if CLIENT_FINISHED interest has been received */ - HandshakeState handshake_state_; - /* First interest that open a secure connection */ - transport::core::Name name_; - /* SSL handle */ - SSL *ssl_; - SSL_CTX *ctx_; - Packet::MemBufPtr handshake_packet_; - std::unique_ptr<utils::MemBuf> head_; - std::uint32_t last_segment_; - std::uint32_t key_id_; - std::thread *handshake; - P2PSecureProducerSocket *parent_; - bool first_; - Name handshake_name_; - int tls_chunks_; - int to_call_oncontentproduced_; - bool still_writing_; - utils::EventThread encryption_thread_; - utils::EventThread async_thread_; - - void onInterest(ProducerSocket &p, Interest &interest); - - void cacheMiss(interface::ProducerSocket &p, Interest &interest); - - /* Return the number of read bytes in readbytes */ - static int read(BIO *b, char *buf, size_t size, size_t *readbytes); - - /* Return the number of read bytes in the return param */ - static int readOld(BIO *h, char *buf, int size); - - /* Return the number of written bytes in written */ - static int write(BIO *b, const char *buf, size_t size, size_t *written); - - /* Return the number of written bytes in the return param */ - static int writeOld(BIO *h, const char *buf, int num); - - static long ctrl(BIO *b, int cmd, long num, void *ptr); - - static int addHicnKeyIdCb(SSL *s, unsigned int ext_type, unsigned int context, - const unsigned char **out, size_t *outlen, X509 *x, - size_t chainidx, int *al, void *add_arg); - - static void freeHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, const unsigned char *out, - void *add_arg); - - static int parseHicnKeyIdCb(SSL *s, unsigned int ext_type, - unsigned int context, const unsigned char *in, - size_t inlen, X509 *x, size_t chainidx, int *al, - void *add_arg); - - void onContentProduced(interface::ProducerSocket &p, - const std::error_code &err, uint64_t bytes_written); - - HandshakeState getHandshakeState(); -}; - -} // namespace implementation -} // end namespace transport diff --git a/libtransport/src/interfaces/CMakeLists.txt b/libtransport/src/interfaces/CMakeLists.txt index 0a0603ac8..bf8f8dcf8 100644 --- a/libtransport/src/interfaces/CMakeLists.txt +++ b/libtransport/src/interfaces/CMakeLists.txt @@ -19,20 +19,4 @@ list(APPEND SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/global_configuration.cc ) -if (${OPENSSL_VERSION} VERSION_EQUAL "1.1.1a" OR ${OPENSSL_VERSION} VERSION_GREATER "1.1.1a") - list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_producer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/p2psecure_socket_consumer.cc - # ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.cc - ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.cc - ) - - list(APPEND HEADER_FILES - # ${CMAKE_CURRENT_SOURCE_DIR}/tls_rtc_socket_producer.h - ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_producer.h - ${CMAKE_CURRENT_SOURCE_DIR}/tls_socket_consumer.h - ) -endif() - set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) diff --git a/libtransport/src/interfaces/global_configuration.cc b/libtransport/src/interfaces/global_configuration.cc index cecdacc07..f8e7a90c3 100644 --- a/libtransport/src/interfaces/global_configuration.cc +++ b/libtransport/src/interfaces/global_configuration.cc @@ -14,6 +14,7 @@ */ #include <core/global_configuration.h> +#include <core/global_workers.h> #include <glog/logging.h> #include <hicn/transport/interfaces/global_conf_interface.h> @@ -23,10 +24,29 @@ namespace transport { namespace interface { namespace global_config { -void parseConfigurationFile(const std::string& path) { +GlobalConfigInterface::GlobalConfigInterface() { libtransportConfigInit(); } + +GlobalConfigInterface::~GlobalConfigInterface() { + libtransportConfigTerminate(); +} + +void GlobalConfigInterface::parseConfigurationFile( + const std::string &path) const { core::GlobalConfiguration::getInstance().parseConfiguration(path); } +void GlobalConfigInterface::libtransportConfigInit() const { + // nothing to do +} + +void GlobalConfigInterface::libtransportConfigTerminate() const { + // cleanup workers + auto &workers = core::GlobalWorkers::getInstance().getWorkers(); + for (auto &worker : workers) { + worker.stop(); + } +} + void ConfigurationObject::get() { std::error_code ec; core::GlobalConfiguration::getInstance().getConfiguration(*this, ec); diff --git a/libtransport/src/interfaces/p2psecure_socket_consumer.cc b/libtransport/src/interfaces/p2psecure_socket_consumer.cc deleted file mode 100644 index e329a50f1..000000000 --- a/libtransport/src/interfaces/p2psecure_socket_consumer.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <hicn/transport/interfaces/p2psecure_socket_consumer.h> -#include <implementation/p2psecure_socket_consumer.h> - -namespace transport { -namespace interface { - -P2PSecureConsumerSocket::P2PSecureConsumerSocket(int handshake_protocol, - int transport_protocol) - : ConsumerSocket() { - socket_ = std::unique_ptr<implementation::ConsumerSocket>( - new implementation::P2PSecureConsumerSocket(this, handshake_protocol, - transport_protocol)); -} - -void P2PSecureConsumerSocket::registerPrefix(const Prefix &producer_namespace) { - implementation::P2PSecureConsumerSocket &secure_consumer_socket = - *(static_cast<implementation::P2PSecureConsumerSocket *>(socket_.get())); - secure_consumer_socket.registerPrefix(producer_namespace); -} - -} // namespace interface -} // namespace transport diff --git a/libtransport/src/interfaces/p2psecure_socket_producer.cc b/libtransport/src/interfaces/p2psecure_socket_producer.cc deleted file mode 100644 index 5f98302d0..000000000 --- a/libtransport/src/interfaces/p2psecure_socket_producer.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <hicn/transport/interfaces/p2psecure_socket_producer.h> -#include <implementation/p2psecure_socket_producer.h> - -namespace transport { -namespace interface { - -P2PSecureProducerSocket::P2PSecureProducerSocket() { - socket_ = std::make_unique<implementation::P2PSecureProducerSocket>(this); -} - -P2PSecureProducerSocket::P2PSecureProducerSocket(bool rtc, - std::string &keystore_path, - std::string &keystore_pwd) { - socket_ = std::make_unique<implementation::P2PSecureProducerSocket>( - this, rtc, keystore_path, keystore_pwd); -} - -} // namespace interface -} // namespace transport diff --git a/libtransport/src/interfaces/portal.cc b/libtransport/src/interfaces/portal.cc index 84634a282..898766c50 100644 --- a/libtransport/src/interfaces/portal.cc +++ b/libtransport/src/interfaces/portal.cc @@ -35,10 +35,10 @@ class Portal::Impl { return portal_->interestIsPending(name); } - void sendInterest(core::Interest::Ptr &&interest, + void sendInterest(core::Interest::Ptr &interest, uint32_t lifetime, OnContentObjectCallback &&on_content_object_callback, OnInterestTimeoutCallback &&on_interest_timeout_callback) { - portal_->sendInterest(std::move(interest), + portal_->sendInterest(interest, lifetime, std::move(on_content_object_callback), std::move(on_interest_timeout_callback)); } @@ -86,10 +86,10 @@ bool Portal::interestIsPending(const core::Name &name) { } void Portal::sendInterest( - core::Interest::Ptr &&interest, + core::Interest::Ptr &interest, uint32_t lifetime, OnContentObjectCallback &&on_content_object_callback, OnInterestTimeoutCallback &&on_interest_timeout_callback) { - implementation_->sendInterest(std::move(interest), + implementation_->sendInterest(interest, lifetime, std::move(on_content_object_callback), std::move(on_interest_timeout_callback)); } diff --git a/libtransport/src/interfaces/socket_consumer.cc b/libtransport/src/interfaces/socket_consumer.cc index 747dc0974..cc496c8a5 100644 --- a/libtransport/src/interfaces/socket_consumer.cc +++ b/libtransport/src/interfaces/socket_consumer.cc @@ -102,6 +102,12 @@ int ConsumerSocket::setSocketOption(int socket_option_key, int ConsumerSocket::setSocketOption( int socket_option_key, + const std::shared_ptr<auth::Signer> &socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::setSocketOption( + int socket_option_key, const std::shared_ptr<auth::Verifier> &socket_option_value) { return socket_->setSocketOption(socket_option_key, socket_option_value); } @@ -163,6 +169,11 @@ int ConsumerSocket::getSocketOption(int socket_option_key, } int ConsumerSocket::getSocketOption( + int socket_option_key, std::shared_ptr<auth::Signer> &socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + +int ConsumerSocket::getSocketOption( int socket_option_key, std::shared_ptr<auth::Verifier> &socket_option_value) { return socket_->getSocketOption(socket_option_key, socket_option_value); diff --git a/libtransport/src/interfaces/socket_producer.cc b/libtransport/src/interfaces/socket_producer.cc index 10613c0e1..2155ebd78 100644 --- a/libtransport/src/interfaces/socket_producer.cc +++ b/libtransport/src/interfaces/socket_producer.cc @@ -148,6 +148,12 @@ int ProducerSocket::setSocketOption( return socket_->setSocketOption(socket_option_key, socket_option_value); } +int ProducerSocket::setSocketOption( + int socket_option_key, + const std::shared_ptr<auth::Verifier> &socket_option_value) { + return socket_->setSocketOption(socket_option_key, socket_option_value); +} + int ProducerSocket::setSocketOption(int socket_option_key, Packet::Format socket_option_value) { return socket_->setSocketOption(socket_option_key, socket_option_value); @@ -194,6 +200,12 @@ int ProducerSocket::getSocketOption( return socket_->getSocketOption(socket_option_key, socket_option_value); } +int ProducerSocket::getSocketOption( + int socket_option_key, + std::shared_ptr<auth::Verifier> &socket_option_value) { + return socket_->getSocketOption(socket_option_key, socket_option_value); +} + int ProducerSocket::getSocketOption(int socket_option_key, Packet::Format &socket_option_value) { return socket_->getSocketOption(socket_option_key, socket_option_value); diff --git a/libtransport/src/interfaces/tls_rtc_socket_producer.cc b/libtransport/src/interfaces/tls_rtc_socket_producer.cc deleted file mode 100644 index 6bf1b011c..000000000 --- a/libtransport/src/interfaces/tls_rtc_socket_producer.cc +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <implementation/tls_rtc_socket_producer.h> -#include <interfaces/tls_rtc_socket_producer.h> - -namespace transport { -namespace interface { - -TLSRTCProducerSocket::TLSRTCProducerSocket( - implementation::TLSRTCProducerSocket *implementation) { - socket_ = - std::unique_ptr<implementation::TLSRTCProducerSocket>(implementation); -} - -TLSRTCProducerSocket::~TLSRTCProducerSocket() { socket_.release(); } - -} // namespace interface -} // namespace transport diff --git a/libtransport/src/interfaces/tls_rtc_socket_producer.h b/libtransport/src/interfaces/tls_rtc_socket_producer.h deleted file mode 100644 index b8b6ec298..000000000 --- a/libtransport/src/interfaces/tls_rtc_socket_producer.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <hicn/transport/interfaces/socket_producer.h> - -namespace transport { - -namespace implementation { -class TLSRTCProducerSocket; -} - -namespace interface { - -class TLSRTCProducerSocket : public ProducerSocket { - public: - TLSRTCProducerSocket(implementation::TLSRTCProducerSocket *implementation); - - ~TLSRTCProducerSocket(); -}; - -} // namespace interface -} // end namespace transport diff --git a/libtransport/src/interfaces/tls_socket_consumer.cc b/libtransport/src/interfaces/tls_socket_consumer.cc deleted file mode 100644 index 24060d1d8..000000000 --- a/libtransport/src/interfaces/tls_socket_consumer.cc +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <implementation/tls_socket_consumer.h> -#include <interfaces/tls_socket_consumer.h> - -namespace transport { -namespace interface { - -TLSConsumerSocket::TLSConsumerSocket( - implementation::TLSConsumerSocket *implementation) { - socket_ = std::unique_ptr<implementation::TLSConsumerSocket>(implementation); -} - -TLSConsumerSocket::~TLSConsumerSocket() { socket_.release(); } - -} // namespace interface -} // namespace transport diff --git a/libtransport/src/interfaces/tls_socket_consumer.h b/libtransport/src/interfaces/tls_socket_consumer.h deleted file mode 100644 index 242dc91a5..000000000 --- a/libtransport/src/interfaces/tls_socket_consumer.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <hicn/transport/interfaces/socket_consumer.h> - -namespace transport { - -namespace implementation { -class TLSConsumerSocket; -} - -namespace interface { - -class TLSConsumerSocket : public ConsumerSocket { - public: - TLSConsumerSocket(implementation::TLSConsumerSocket *implementation); - ~TLSConsumerSocket(); -}; - -} // namespace interface - -} // end namespace transport diff --git a/libtransport/src/interfaces/tls_socket_producer.cc b/libtransport/src/interfaces/tls_socket_producer.cc deleted file mode 100644 index b2b9e723a..000000000 --- a/libtransport/src/interfaces/tls_socket_producer.cc +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <implementation/tls_socket_producer.h> -#include <interfaces/tls_socket_producer.h> - -namespace transport { -namespace interface { - -TLSProducerSocket::TLSProducerSocket( - implementation::TLSProducerSocket *implementation) { - socket_ = std::unique_ptr<implementation::TLSProducerSocket>(implementation); -} - -TLSProducerSocket::~TLSProducerSocket() { socket_.release(); } - -} // namespace interface -} // namespace transport diff --git a/libtransport/src/interfaces/tls_socket_producer.h b/libtransport/src/interfaces/tls_socket_producer.h deleted file mode 100644 index 9b31cb483..000000000 --- a/libtransport/src/interfaces/tls_socket_producer.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <hicn/transport/interfaces/socket_producer.h> - -namespace transport { - -namespace implementation { -class TLSProducerSocket; -} - -namespace interface { - -class TLSProducerSocket : public ProducerSocket { - public: - TLSProducerSocket(implementation::TLSProducerSocket *implementation); - ~TLSProducerSocket(); -}; - -} // namespace interface - -} // end namespace transport diff --git a/libtransport/src/io_modules/CMakeLists.txt b/libtransport/src/io_modules/CMakeLists.txt index f4143de04..f1a27d3cb 100644 --- a/libtransport/src/io_modules/CMakeLists.txt +++ b/libtransport/src/io_modules/CMakeLists.txt @@ -15,7 +15,7 @@ ############################################################## # Android case: no submodules ############################################################## -if (${CMAKE_SYSTEM_NAME} MATCHES Android) +if (${CMAKE_SYSTEM_NAME} MATCHES Android OR ${CMAKE_SYSTEM_NAME} MATCHES iOS) list(APPEND SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/hicn-light-ng/hicn_forwarder_module.cc ) diff --git a/libtransport/src/io_modules/forwarder/CMakeLists.txt b/libtransport/src/io_modules/forwarder/CMakeLists.txt index 3922316d3..2235d842e 100644 --- a/libtransport/src/io_modules/forwarder/CMakeLists.txt +++ b/libtransport/src/io_modules/forwarder/CMakeLists.txt @@ -17,7 +17,6 @@ list(APPEND MODULE_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/errors.h ${CMAKE_CURRENT_SOURCE_DIR}/forwarder_module.h ${CMAKE_CURRENT_SOURCE_DIR}/forwarder.h - ${CMAKE_CURRENT_SOURCE_DIR}/global_counter.h ) list(APPEND MODULE_SOURCE_FILES diff --git a/libtransport/src/io_modules/forwarder/forwarder.cc b/libtransport/src/io_modules/forwarder/forwarder.cc index 3ae5bf397..bfe4dd5de 100644 --- a/libtransport/src/io_modules/forwarder/forwarder.cc +++ b/libtransport/src/io_modules/forwarder/forwarder.cc @@ -14,12 +14,12 @@ */ #include <core/global_configuration.h> +#include <core/global_id_counter.h> #include <core/local_connector.h> #include <core/udp_connector.h> #include <core/udp_listener.h> #include <glog/logging.h> #include <io_modules/forwarder/forwarder.h> -#include <io_modules/forwarder/global_id_counter.h> namespace transport { @@ -90,11 +90,13 @@ Connector::Id Forwarder::registerLocalConnector( asio::io_service &io_service, Connector::PacketReceivedCallback &&receive_callback, Connector::PacketSentCallback &&sent_callback, + Connector::OnCloseCallback &&close_callback, Connector::OnReconnectCallback &&reconnect_callback) { utils::SpinLock::Acquire locked(connector_lock_); auto id = GlobalCounter<Connector::Id>::getInstance().getNext(); auto connector = std::make_shared<LocalConnector>( - io_service, receive_callback, sent_callback, nullptr, reconnect_callback); + io_service, std::move(receive_callback), std::move(sent_callback), + std::move(close_callback), std::move(reconnect_callback)); connector->setConnectorId(id); local_connectors_.emplace(id, std::move(connector)); return id; @@ -150,34 +152,13 @@ void Forwarder::onPacketReceived(Connector *connector, return; } - for (auto &packet_buffer_ptr : packets) { - auto &packet_buffer = *packet_buffer_ptr; - - // Figure out the type of packet we received - bool is_interest = Packet::isInterest(packet_buffer.data()); - - Packet *packet = nullptr; - if (is_interest) { - packet = static_cast<Interest *>(&packet_buffer); - } else { - packet = static_cast<ContentObject *>(&packet_buffer); - } - - for (auto &c : local_connectors_) { - auto role = c.second->getRole(); - auto is_producer = role == Connector::Role::PRODUCER; - if ((is_producer && is_interest) || (!is_producer && !is_interest)) { - c.second->send(*packet); - } else { - LOG(ERROR) << "Error sending packet to local connector. is_interest = " - << is_interest << " - is_producer = " << is_producer; - } - } + for (auto &c : local_connectors_) { + c.second->receive(packets); + } - // PCS Lookup + FIB lookup. Skip for now + // PCS Lookup + FIB lookup. Skip for now - // Forward packet to local connectors - } + // Forward packet to local connectors } void Forwarder::send(Packet &packet) { @@ -304,4 +285,4 @@ void Forwarder::parseForwarderConfiguration( } } // namespace core -} // namespace transport
\ No newline at end of file +} // namespace transport diff --git a/libtransport/src/io_modules/forwarder/forwarder.h b/libtransport/src/io_modules/forwarder/forwarder.h index 38b4260b3..9ad989fcd 100644 --- a/libtransport/src/io_modules/forwarder/forwarder.h +++ b/libtransport/src/io_modules/forwarder/forwarder.h @@ -47,6 +47,7 @@ class Forwarder { asio::io_service &io_service, Connector::PacketReceivedCallback &&receive_callback, Connector::PacketSentCallback &&sent_callback, + Connector::OnCloseCallback &&close_callback, Connector::OnReconnectCallback &&reconnect_callback); Forwarder &deleteConnector(Connector::Id id); diff --git a/libtransport/src/io_modules/forwarder/forwarder_module.cc b/libtransport/src/io_modules/forwarder/forwarder_module.cc index 0ced84ab4..77d2b5e6a 100644 --- a/libtransport/src/io_modules/forwarder/forwarder_module.cc +++ b/libtransport/src/io_modules/forwarder/forwarder_module.cc @@ -37,8 +37,6 @@ void ForwarderModule::send(Packet &packet) { forwarder_.send(packet); DLOG_IF(INFO, VLOG_IS_ON(3)) << "Sending from " << connector_id_ << " to " << 1 - connector_id_; - - // local_faces_.at(1 - local_id_).onPacket(packet); } void ForwarderModule::send(const utils::MemBuf::Ptr &buffer) { @@ -58,12 +56,13 @@ void ForwarderModule::closeConnection() { void ForwarderModule::init(Connector::PacketReceivedCallback &&receive_callback, Connector::PacketSentCallback &&sent_callback, + Connector::OnCloseCallback &&close_callback, Connector::OnReconnectCallback &&reconnect_callback, asio::io_service &io_service, const std::string &app_name) { connector_id_ = forwarder_.registerLocalConnector( io_service, std::move(receive_callback), std::move(sent_callback), - std::move(reconnect_callback)); + std::move(close_callback), std::move(reconnect_callback)); name_ = app_name; } diff --git a/libtransport/src/io_modules/forwarder/forwarder_module.h b/libtransport/src/io_modules/forwarder/forwarder_module.h index 52a12b67e..a48701161 100644 --- a/libtransport/src/io_modules/forwarder/forwarder_module.h +++ b/libtransport/src/io_modules/forwarder/forwarder_module.h @@ -44,6 +44,7 @@ class ForwarderModule : public IoModule { void init(Connector::PacketReceivedCallback &&receive_callback, Connector::PacketSentCallback &&sent_callback, + Connector::OnCloseCallback &&close_callback, Connector::OnReconnectCallback &&reconnect_callback, asio::io_service &io_service, const std::string &app_name = "Libtransport") override; diff --git a/libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.cc b/libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.cc index f67bd9447..95f04822f 100644 --- a/libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.cc +++ b/libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.cc @@ -100,12 +100,13 @@ void HicnForwarderModule::closeConnection() { void HicnForwarderModule::init( Connector::PacketReceivedCallback &&receive_callback, Connector::PacketSentCallback &&sent_callback, + Connector::OnCloseCallback &&close_callback, Connector::OnReconnectCallback &&reconnect_callback, asio::io_service &io_service, const std::string &app_name) { if (!connector_) { connector_.reset(new UdpTunnelConnector( io_service, std::move(receive_callback), std::move(sent_callback), - nullptr, std::move(reconnect_callback))); + std::move(close_callback), std::move(reconnect_callback))); } } @@ -130,7 +131,7 @@ bool HicnForwarderModule::isControlMessage(utils::MemBuf &packet_buffer) { */ utils::MemBuf::Ptr HicnForwarderModule::createCommandRoute( std::unique_ptr<sockaddr> &&addr, uint8_t prefix_length) { - utils::MemBuf::Ptr ret = utils::MemBuf::create(sizeof(msg_route_add_t)); + auto ret = PacketManager<>::getInstance().getMemBuf(); auto command = reinterpret_cast<msg_route_add_t *>(ret->writableData()); ret->append(sizeof(msg_route_add_t)); std::memset(command, 0, sizeof(*command)); @@ -170,8 +171,7 @@ utils::MemBuf::Ptr HicnForwarderModule::createCommandRoute( } utils::MemBuf::Ptr HicnForwarderModule::createCommandDeleteConnection() { - utils::MemBuf::Ptr ret = - utils::MemBuf::create(sizeof(msg_connection_remove_t)); + auto ret = PacketManager<>::getInstance().getMemBuf(); auto command = reinterpret_cast<msg_connection_remove_t *>(ret->writableData()); ret->append(sizeof(msg_connection_remove_t)); @@ -194,8 +194,7 @@ utils::MemBuf::Ptr HicnForwarderModule::createCommandDeleteConnection() { } utils::MemBuf::Ptr HicnForwarderModule::createCommandMapmeSendUpdate() { - utils::MemBuf::Ptr ret = - utils::MemBuf::create(sizeof(msg_mapme_send_update_t)); + auto ret = PacketManager<>::getInstance().getMemBuf(); auto command = reinterpret_cast<msg_mapme_send_update_t *>(ret->writableData()); ret->append(sizeof(msg_mapme_send_update_t)); @@ -217,7 +216,7 @@ utils::MemBuf::Ptr HicnForwarderModule::createCommandMapmeSendUpdate() { utils::MemBuf::Ptr HicnForwarderModule::createCommandSetForwardingStrategy( std::unique_ptr<sockaddr> &&addr, uint32_t prefix_len, std::string strategy) { - utils::MemBuf::Ptr ret = utils::MemBuf::create(sizeof(msg_strategy_set_t)); + auto ret = PacketManager<>::getInstance().getMemBuf(); auto command = reinterpret_cast<msg_strategy_set_t *>(ret->writableData()); ret->append(sizeof(msg_strategy_set_t)); std::memset(command, 0, sizeof(*command)); diff --git a/libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.h b/libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.h index 0bf82757d..7f0e7aca8 100644 --- a/libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.h +++ b/libtransport/src/io_modules/hicn-light-ng/hicn_forwarder_module.h @@ -64,6 +64,7 @@ class HicnForwarderModule : public IoModule { void init(Connector::PacketReceivedCallback &&receive_callback, Connector::PacketSentCallback &&sent_callback, + Connector::OnCloseCallback &&close_callback, Connector::OnReconnectCallback &&reconnect_callback, asio::io_service &io_service, const std::string &app_name = "Libtransport") override; diff --git a/libtransport/src/io_modules/loopback/loopback_module.cc b/libtransport/src/io_modules/loopback/loopback_module.cc index 5b7ed5f61..a7f30eb26 100644 --- a/libtransport/src/io_modules/loopback/loopback_module.cc +++ b/libtransport/src/io_modules/loopback/loopback_module.cc @@ -58,6 +58,7 @@ void LoopbackModule::closeConnection() { void LoopbackModule::init(Connector::PacketReceivedCallback &&receive_callback, Connector::PacketSentCallback &&sent_callback, + Connector::OnCloseCallback &&close_callback, Connector::OnReconnectCallback &&reconnect_callback, asio::io_service &io_service, const std::string &app_name) { @@ -66,7 +67,7 @@ void LoopbackModule::init(Connector::PacketReceivedCallback &&receive_callback, local_faces_.emplace( local_faces_.begin() + local_id_, new LocalConnector(io_service, std::move(receive_callback), - std::move(sent_callback), nullptr, + std::move(sent_callback), std::move(close_callback), std::move(reconnect_callback))); } } diff --git a/libtransport/src/io_modules/loopback/loopback_module.h b/libtransport/src/io_modules/loopback/loopback_module.h index 2779ae7e3..d51f237f4 100644 --- a/libtransport/src/io_modules/loopback/loopback_module.h +++ b/libtransport/src/io_modules/loopback/loopback_module.h @@ -42,6 +42,7 @@ class LoopbackModule : public IoModule { void init(Connector::PacketReceivedCallback &&receive_callback, Connector::PacketSentCallback &&sent_callback, + Connector::OnCloseCallback &&close_callback, Connector::OnReconnectCallback &&reconnect_callback, asio::io_service &io_service, const std::string &app_name = "Libtransport") override; diff --git a/libtransport/src/io_modules/memif/vpp_forwarder_module.cc b/libtransport/src/io_modules/memif/vpp_forwarder_module.cc index 65260077a..c096a71b8 100644 --- a/libtransport/src/io_modules/memif/vpp_forwarder_module.cc +++ b/libtransport/src/io_modules/memif/vpp_forwarder_module.cc @@ -50,13 +50,14 @@ VPPForwarderModule::~VPPForwarderModule() {} void VPPForwarderModule::init( Connector::PacketReceivedCallback &&receive_callback, Connector::PacketSentCallback &&sent_callback, + Connector::OnCloseCallback &&close_callback, Connector::OnReconnectCallback &&reconnect_callback, asio::io_service &io_service, const std::string &app_name) { if (!connector_) { connector_ = std::make_unique<MemifConnector>( std::move(receive_callback), std::move(sent_callback), - Connector::OnCloseCallback(0), std::move(reconnect_callback), - io_service, app_name); + std::move(close_callback), std::move(reconnect_callback), io_service, + app_name); } } diff --git a/libtransport/src/io_modules/memif/vpp_forwarder_module.h b/libtransport/src/io_modules/memif/vpp_forwarder_module.h index 162ee0ca5..5a5358078 100644 --- a/libtransport/src/io_modules/memif/vpp_forwarder_module.h +++ b/libtransport/src/io_modules/memif/vpp_forwarder_module.h @@ -48,6 +48,7 @@ class VPPForwarderModule : public IoModule { void init(Connector::PacketReceivedCallback &&receive_callback, Connector::PacketSentCallback &&sent_callback, + Connector::OnCloseCallback &&close_callback, Connector::OnReconnectCallback &&reconnect_callback, asio::io_service &io_service, const std::string &app_name = "Libtransport") override; diff --git a/libtransport/src/protocols/byte_stream_reassembly.cc b/libtransport/src/protocols/byte_stream_reassembly.cc index 3278595b7..b9eaf3bec 100644 --- a/libtransport/src/protocols/byte_stream_reassembly.cc +++ b/libtransport/src/protocols/byte_stream_reassembly.cc @@ -36,15 +36,6 @@ ByteStreamReassembly::ByteStreamReassembly( index_(Indexer::invalid_index), download_complete_(false) {} -void ByteStreamReassembly::reassemble( - std::unique_ptr<ContentObjectManifest> &&manifest) { - if (TRANSPORT_EXPECT_TRUE(manifest != nullptr) && read_buffer_->capacity()) { - received_packets_.emplace( - std::make_pair(manifest->getName().getSuffix(), nullptr)); - assembleContent(); - } -} - void ByteStreamReassembly::reassemble(ContentObject &content_object) { if (TRANSPORT_EXPECT_TRUE(read_buffer_->capacity())) { received_packets_.emplace( diff --git a/libtransport/src/protocols/byte_stream_reassembly.h b/libtransport/src/protocols/byte_stream_reassembly.h index bfcac3181..a1f965d5c 100644 --- a/libtransport/src/protocols/byte_stream_reassembly.h +++ b/libtransport/src/protocols/byte_stream_reassembly.h @@ -29,9 +29,6 @@ class ByteStreamReassembly : public Reassembly { protected: void reassemble(core::ContentObject &content_object) override; - void reassemble( - std::unique_ptr<core::ContentObjectManifest> &&manifest) override; - void reassemble(utils::MemBuf &buffer, uint32_t suffix) override; bool copyContent(core::ContentObject &content_object); diff --git a/libtransport/src/protocols/cbr.cc b/libtransport/src/protocols/cbr.cc index 446ea8b99..e3f0f1336 100644 --- a/libtransport/src/protocols/cbr.cc +++ b/libtransport/src/protocols/cbr.cc @@ -38,7 +38,7 @@ void CbrTransportProtocol::afterContentReception( const Interest &interest, const ContentObject &content_object) { auto segment = content_object.getName().getSuffix(); auto now = utils::SteadyTime::Clock::now(); - auto rtt = utils::SteadyTime::getDurationMs( + auto rtt = utils::SteadyTime::getDurationUs( interest_timepoints_[segment & mask], now); // Update stats updateStats(segment, rtt, now); diff --git a/libtransport/src/protocols/datagram_reassembly.cc b/libtransport/src/protocols/datagram_reassembly.cc index 3a32c81f5..a04b0eecf 100644 --- a/libtransport/src/protocols/datagram_reassembly.cc +++ b/libtransport/src/protocols/datagram_reassembly.cc @@ -29,8 +29,9 @@ void DatagramReassembly::reassemble(core::ContentObject& content_object) { auto read_buffer = content_object.getPayload(); DLOG_IF(INFO, VLOG_IS_ON(4)) << "Size of payload: " << read_buffer->length() << ". Trimming " - << transport_protocol_->transportHeaderLength(); - read_buffer->trimStart(transport_protocol_->transportHeaderLength()); + << transport_protocol_->transportHeaderLength(false); + // here we have only src data packet + read_buffer->trimStart(transport_protocol_->transportHeaderLength(false)); Reassembly::read_buffer_ = std::move(read_buffer); Reassembly::notifyApplication(); } diff --git a/libtransport/src/protocols/datagram_reassembly.h b/libtransport/src/protocols/datagram_reassembly.h index 0def32dd2..cefdca93b 100644 --- a/libtransport/src/protocols/datagram_reassembly.h +++ b/libtransport/src/protocols/datagram_reassembly.h @@ -29,10 +29,6 @@ class DatagramReassembly : public Reassembly { virtual void reassemble(core::ContentObject &content_object) override; void reassemble(utils::MemBuf &buffer, uint32_t suffix) override; virtual void reInitialize() override; - virtual void reassemble( - std::unique_ptr<core::ContentObjectManifest> &&manifest) override { - return; - } bool reassembleUnverified() override { return true; } }; diff --git a/libtransport/src/protocols/fec/rely.cc b/libtransport/src/protocols/fec/rely.cc index d4d98a90b..9e0a06dd8 100644 --- a/libtransport/src/protocols/fec/rely.cc +++ b/libtransport/src/protocols/fec/rely.cc @@ -79,7 +79,7 @@ void RelyEncoder::onPacketProduced(core::ContentObject &content_object, // Check new payload size and make sure it fits in packet buffer auto new_payload_size = produce_bytes(); - int difference = new_payload_size - length; + int difference = (int)(new_payload_size - length); DCHECK(difference > 0); DCHECK(content_object.ensureCapacity(difference)); diff --git a/libtransport/src/protocols/fec/rely.h b/libtransport/src/protocols/fec/rely.h index 001a26002..cc81222b2 100644 --- a/libtransport/src/protocols/fec/rely.h +++ b/libtransport/src/protocols/fec/rely.h @@ -15,6 +15,7 @@ #pragma once +#include <hicn/transport/portability/endianess.h> #include <hicn/transport/utils/chrono_typedefs.h> #include <hicn/transport/utils/membuf.h> #include <protocols/fec/fec_info.h> @@ -80,11 +81,19 @@ class RelyBase : public virtual FECBase { */ class fec_metadata { public: - void setSeqNumberBase(uint32_t suffix) { seq_number = htonl(suffix); } - uint32_t getSeqNumberBase() const { return ntohl(seq_number); } - - void setMetadataBase(uint32_t value) { metadata = htonl(value); } - uint32_t getMetadataBase() const { return ntohl(metadata); } + void setSeqNumberBase(uint32_t suffix) { + seq_number = portability::host_to_net(suffix); + } + uint32_t getSeqNumberBase() const { + return portability::net_to_host(seq_number); + } + + void setMetadataBase(uint32_t value) { + metadata = portability::host_to_net(value); + } + uint32_t getMetadataBase() const { + return portability::net_to_host(metadata); + } private: uint32_t seq_number; @@ -162,8 +171,9 @@ class RelyEncoder : RelyBase, rely::encoder, public ProducerFEC { /** * @brief Get the fec header size, if added to source packets + * there is not need to distinguish between source and FEC packets here */ - std::size_t getFecHeaderSize() override { + std::size_t getFecHeaderSize(bool isFEC) override { return header_bytes() + sizeof(fec_metadata) + 4; } @@ -184,8 +194,9 @@ class RelyDecoder : RelyBase, rely::decoder, public ConsumerFEC { /** * @brief Get the fec header size, if added to source packets + * there is not need to distinguish between source and FEC packets here */ - std::size_t getFecHeaderSize() override { + std::size_t getFecHeaderSize(bool isFEC) override { return header_bytes() + sizeof(fec_metadata); } diff --git a/libtransport/src/protocols/fec/rs.cc b/libtransport/src/protocols/fec/rs.cc index 9c0a3d4fb..d42740c32 100644 --- a/libtransport/src/protocols/fec/rs.cc +++ b/libtransport/src/protocols/fec/rs.cc @@ -146,7 +146,8 @@ void BlockCode::encode() { DLOG_IF(INFO, VLOG_IS_ON(4)) << "Calling encode with max_buffer_size_ = " << max_buffer_size_; for (uint32_t i = k_; i < n_; i++) { - fec_encode(code_, data, data[i], i, max_buffer_size_ + METADATA_BYTES); + fec_encode(code_, data, data[i], i, + (int)(max_buffer_size_ + METADATA_BYTES)); } // Re-include header in repair packets @@ -213,7 +214,8 @@ void BlockCode::decode() { DLOG_IF(INFO, VLOG_IS_ON(4)) << "Calling decode with max_buffer_size_ = " << max_buffer_size_; - fec_decode(code_, data, reinterpret_cast<int *>(index), max_buffer_size_); + fec_decode(code_, data, reinterpret_cast<int *>(index), + (int)max_buffer_size_); // Find the index in the block for recovered packets for (uint32_t i = 0, j = 0; i < k_; i++) { @@ -228,6 +230,7 @@ void BlockCode::decode() { auto &packet = operator[](i).getBuffer(); fec_metadata *metadata = reinterpret_cast<fec_metadata *>( packet->writableData() + max_buffer_size_ - METADATA_BYTES); + DCHECK(metadata->getPacketLength() <= packet->capacity()); // Adjust buffer length packet->setLength(metadata->getPacketLength()); // Adjust metadata diff --git a/libtransport/src/protocols/fec/rs.h b/libtransport/src/protocols/fec/rs.h index 034c32bdc..6672eaa6b 100644 --- a/libtransport/src/protocols/fec/rs.h +++ b/libtransport/src/protocols/fec/rs.h @@ -18,6 +18,7 @@ #include <arpa/inet.h> #include <hicn/transport/portability/c_portability.h> +#include <hicn/transport/portability/endianess.h> #include <hicn/transport/utils/membuf.h> #include <protocols/fec/fec_info.h> #include <protocols/fec_base.h> @@ -153,8 +154,10 @@ struct fec_header { */ uint8_t padding; - void setSeqNumberBase(uint32_t suffix) { seq_number = htonl(suffix); } - uint32_t getSeqNumberBase() { return ntohl(seq_number); } + void setSeqNumberBase(uint32_t suffix) { + seq_number = portability::host_to_net(suffix); + } + uint32_t getSeqNumberBase() { return portability::net_to_host(seq_number); } void setEncodedSymbolId(uint8_t esi) { encoded_symbol_id = esi; } uint8_t getEncodedSymbolId() { return encoded_symbol_id; } void setSourceBlockLen(uint8_t k) { source_block_len = k; } @@ -163,6 +166,8 @@ struct fec_header { uint8_t getNFecSymbols() { return n_fec_symbols; } }; +static_assert(sizeof(fec_header) <= 8, "fec_header is too large"); + class rs; /** @@ -177,11 +182,17 @@ class BlockCode : public Packets { */ class __attribute__((__packed__)) fec_metadata { public: - void setPacketLength(uint16_t length) { packet_length = htons(length); } - uint32_t getPacketLength() { return ntohs(packet_length); } + void setPacketLength(uint16_t length) { + packet_length = portability::host_to_net(length); + } + uint32_t getPacketLength() { + return portability::net_to_host(packet_length); + } - void setMetadataBase(uint32_t value) { metadata = htonl(value); } - uint32_t getMetadataBase() { return ntohl(metadata); } + void setMetadataBase(uint32_t value) { + metadata = portability::host_to_net(value); + } + uint32_t getMetadataBase() { return portability::net_to_host(metadata); } private: uint16_t packet_length; /* Used to get the real size of the packet after we @@ -388,8 +399,11 @@ class RSEncoder : public rs, public ProducerFEC { /** * @brief Get the fec header size, if added to source packets + * in RS the source packets do not transport any FEC header */ - std::size_t getFecHeaderSize() override { return 0; } + std::size_t getFecHeaderSize(bool isFEC) override { + return isFEC ? sizeof(fec_header) : 0; + } void clear() override { rs::clear(); @@ -435,8 +449,11 @@ class RSDecoder : public rs, public ConsumerFEC { /** * @brief Get the fec header size, if added to source packets + * in RS the source packets do not transport any FEC header */ - std::size_t getFecHeaderSize() override { return 0; } + std::size_t getFecHeaderSize(bool isFEC) override { + return isFEC ? sizeof(fec_header) : 0; + } /** * Clear decoder to reuse diff --git a/libtransport/src/protocols/fec_base.h b/libtransport/src/protocols/fec_base.h index bda3ee756..28f6a820a 100644 --- a/libtransport/src/protocols/fec_base.h +++ b/libtransport/src/protocols/fec_base.h @@ -101,8 +101,10 @@ class FECBase { /** * @brief Get size of FEC header. + * the fec header size may be different if a packet is a data packet or a FEC + * packet */ - virtual std::size_t getFecHeaderSize() = 0; + virtual std::size_t getFecHeaderSize(bool isFEC) = 0; /** * Set callback to call after packet encoding / decoding diff --git a/libtransport/src/protocols/manifest_incremental_indexer_bytestream.cc b/libtransport/src/protocols/manifest_incremental_indexer_bytestream.cc index b5ab8184f..0b15559a4 100644 --- a/libtransport/src/protocols/manifest_incremental_indexer_bytestream.cc +++ b/libtransport/src/protocols/manifest_incremental_indexer_bytestream.cc @@ -66,40 +66,33 @@ void ManifestIncrementalIndexer::onUntrustedManifest( return; } - auto manifest = - std::make_unique<ContentObjectManifest>(std::move(content_object)); - manifest->decode(); + core::ContentObjectManifest manifest(content_object.shared_from_this()); + manifest.decode(); - processTrustedManifest(interest, std::move(manifest), reassembly); + processTrustedManifest(interest, manifest, reassembly); } void ManifestIncrementalIndexer::processTrustedManifest( - core::Interest &interest, std::unique_ptr<ContentObjectManifest> manifest, + core::Interest &interest, core::ContentObjectManifest &manifest, bool reassembly) { - if (TRANSPORT_EXPECT_FALSE(manifest->getVersion() != - core::ManifestVersion::VERSION_1)) { - throw errors::RuntimeException("Received manifest with unknown version."); - } - - switch (manifest->getType()) { + switch (manifest.getType()) { case core::ManifestType::INLINE_MANIFEST: { suffix_strategy_->setFinalSuffix( - manifest->getParamsBytestream().final_segment); + manifest.getParamsBytestream().final_segment); // The packets to verify with the received manifest std::vector<auth::PacketPtr> packets; // Convert the received manifest to a map of packet suffixes to hashes - auth::Verifier::SuffixMap current_manifest = - core::ContentObjectManifest::getSuffixMap(manifest.get()); + auth::Verifier::SuffixMap suffix_map = manifest.getSuffixMap(); // Update 'suffix_map_' with new hashes from the received manifest and // build 'packets' - for (auto it = current_manifest.begin(); it != current_manifest.end();) { + for (auto it = suffix_map.begin(); it != suffix_map.end();) { if (unverified_segments_.find(it->first) == unverified_segments_.end()) { suffix_map_[it->first] = std::move(it->second); - current_manifest.erase(it++); + suffix_map.erase(it++); continue; } @@ -109,7 +102,7 @@ void ManifestIncrementalIndexer::processTrustedManifest( // Verify unverified segments using the received manifest auth::Verifier::PolicyMap policies = - verifier_->verifyPackets(packets, current_manifest); + verifier_->verifyPackets(packets, suffix_map); for (unsigned int i = 0; i < packets.size(); ++i) { auth::Suffix suffix = packets[i]->getName().getSuffix(); @@ -126,7 +119,9 @@ void ManifestIncrementalIndexer::processTrustedManifest( } if (reassembly) { - reassembly_->reassemble(std::move(manifest)); + auto manifest_co = + std::dynamic_pointer_cast<ContentObject>(manifest.getPacket()); + reassembly_->reassemble(*manifest_co); } break; } diff --git a/libtransport/src/protocols/manifest_incremental_indexer_bytestream.h b/libtransport/src/protocols/manifest_incremental_indexer_bytestream.h index 12876f35c..8527b55c1 100644 --- a/libtransport/src/protocols/manifest_incremental_indexer_bytestream.h +++ b/libtransport/src/protocols/manifest_incremental_indexer_bytestream.h @@ -76,7 +76,7 @@ class ManifestIncrementalIndexer : public IncrementalIndexer { core::ContentObject &content_object, bool reassembly); void processTrustedManifest(core::Interest &interest, - std::unique_ptr<ContentObjectManifest> manifest, + core::ContentObjectManifest &manifest, bool reassembly); void onUntrustedContentObject(core::Interest &interest, core::ContentObject &content_object, diff --git a/libtransport/src/protocols/prod_protocol_bytestream.cc b/libtransport/src/protocols/prod_protocol_bytestream.cc index 2a3ec07e1..7f103e12b 100644 --- a/libtransport/src/protocols/prod_protocol_bytestream.cc +++ b/libtransport/src/protocols/prod_protocol_bytestream.cc @@ -111,18 +111,18 @@ uint32_t ByteStreamProductionProtocol::produceStream( uint64_t manifest_free_space; uint32_t nb_manifests; std::shared_ptr<core::ContentObjectManifest> manifest; - uint32_t manifest_capacity = making_manifest_; + uint32_t manifest_capacity = manifest_max_capacity_; bool is_last_manifest = false; ParamsBytestream transport_params; manifest_format = Packet::toAHFormat(default_format); - content_format = - !making_manifest_ ? Packet::toAHFormat(default_format) : default_format; + content_format = !manifest_max_capacity_ ? Packet::toAHFormat(default_format) + : default_format; - content_header_size = - core::Packet::getHeaderSizeFromFormat(content_format, signature_length); - manifest_header_size = - core::Packet::getHeaderSizeFromFormat(manifest_format, signature_length); + content_header_size = (uint32_t)core::Packet::getHeaderSizeFromFormat( + content_format, signature_length); + manifest_header_size = (uint32_t)core::Packet::getHeaderSizeFromFormat( + manifest_format, signature_length); content_free_space = std::min(max_segment_size, data_packet_size - content_header_size); manifest_free_space = @@ -135,34 +135,39 @@ uint32_t ByteStreamProductionProtocol::produceStream( nb_segments++; } - if (making_manifest_) { + if (manifest_max_capacity_) { nb_manifests = static_cast<uint32_t>( std::ceil(float(nb_segments) / manifest_capacity)); final_block_number += nb_segments + nb_manifests - 1; transport_params.final_segment = is_last ? final_block_number : utils::SuffixStrategy::MAX_SUFFIX; - manifest.reset(ContentObjectManifest::createManifest( + manifest = ContentObjectManifest::createContentManifest( manifest_format, name.setSuffix(suffix_strategy->getNextManifestSuffix()), - core::ManifestVersion::VERSION_1, core::ManifestType::INLINE_MANIFEST, - is_last_manifest, name, hash_algo, signature_length)); - - manifest->setLifetime(content_object_expiry_time); + signature_length); + manifest->setHeaders(core::ManifestType::INLINE_MANIFEST, + manifest_max_capacity_, hash_algo, is_last_manifest, + name); manifest->setParamsBytestream(transport_params); + manifest->getPacket()->setLifetime(content_object_expiry_time); } auto self = shared_from_this(); for (unsigned int packaged_segments = 0; packaged_segments < nb_segments; packaged_segments++) { - if (making_manifest_) { - if (manifest->estimateManifestSize(1) > manifest_free_space) { + if (manifest_max_capacity_) { + if (manifest->Encoder::manifestSize(1) > manifest_free_space) { manifest->encode(); - signer_->signPacket(manifest.get()); + auto manifest_co = + std::dynamic_pointer_cast<ContentObject>(manifest->getPacket()); + + signer_->signPacket(manifest_co.get()); // Send the current manifest - passContentObjectToCallbacks(manifest, self); - DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send manifest " << manifest->getName(); + passContentObjectToCallbacks(manifest_co, self); + DLOG_IF(INFO, VLOG_IS_ON(3)) + << "Send manifest " << manifest_co->getName(); // Send content objects stored in the queue while (!content_queue_.empty()) { @@ -175,15 +180,15 @@ uint32_t ByteStreamProductionProtocol::produceStream( // Create new manifest. The reference to the last manifest has been // acquired in the passContentObjectToCallbacks function, so we can // safely release this reference. - manifest.reset(ContentObjectManifest::createManifest( + manifest = ContentObjectManifest::createContentManifest( manifest_format, name.setSuffix(suffix_strategy->getNextManifestSuffix()), - core::ManifestVersion::VERSION_1, - core::ManifestType::INLINE_MANIFEST, is_last_manifest, name, - hash_algo, signature_length)); - - manifest->setLifetime(content_object_expiry_time); + signature_length); + manifest->setHeaders(core::ManifestType::INLINE_MANIFEST, + manifest_max_capacity_, hash_algo, + is_last_manifest, name); manifest->setParamsBytestream(transport_params); + manifest->getPacket()->setLifetime(content_object_expiry_time); } } @@ -191,7 +196,7 @@ uint32_t ByteStreamProductionProtocol::produceStream( uint32_t content_suffix = suffix_strategy->getNextContentSuffix(); auto content_object = std::make_shared<ContentObject>( name.setSuffix(content_suffix), content_format, - !making_manifest_ ? signature_length : 0); + !manifest_max_capacity_ ? signature_length : 0); content_object->setLifetime(content_object_expiry_time); auto b = buffer->cloneOne(); @@ -203,7 +208,7 @@ uint32_t ByteStreamProductionProtocol::produceStream( b->append(buffer_size - bytes_segmented); bytes_segmented += (int)(buffer_size - bytes_segmented); - if (is_last && making_manifest_) { + if (is_last && manifest_max_capacity_) { is_last_manifest = true; } else if (is_last) { content_object->setLast(); @@ -219,9 +224,9 @@ uint32_t ByteStreamProductionProtocol::produceStream( // Either we sign the content object or we save its hash into the current // manifest - if (making_manifest_) { + if (manifest_max_capacity_) { auth::CryptoHash hash = content_object->computeDigest(hash_algo); - manifest->addSuffixHash(content_suffix, hash); + manifest->addEntry(content_suffix, hash); content_queue_.push(content_object); } else { signer_->signPacket(content_object.get()); @@ -232,16 +237,19 @@ uint32_t ByteStreamProductionProtocol::produceStream( } // We send the manifest that hasn't been fully filled yet - if (making_manifest_) { + if (manifest_max_capacity_) { if (is_last_manifest) { manifest->setIsLast(is_last_manifest); } manifest->encode(); - signer_->signPacket(manifest.get()); + auto manifest_co = + std::dynamic_pointer_cast<ContentObject>(manifest->getPacket()); + + signer_->signPacket(manifest_co.get()); - passContentObjectToCallbacks(manifest, self); - DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send manifest " << manifest->getName(); + passContentObjectToCallbacks(manifest_co, self); + DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send manifest " << manifest_co->getName(); while (!content_queue_.empty()) { passContentObjectToCallbacks(content_queue_.front(), self); diff --git a/libtransport/src/protocols/prod_protocol_rtc.cc b/libtransport/src/protocols/prod_protocol_rtc.cc index e49f58167..cb8dff6e4 100644 --- a/libtransport/src/protocols/prod_protocol_rtc.cc +++ b/libtransport/src/protocols/prod_protocol_rtc.cc @@ -43,9 +43,6 @@ RTCProductionProtocol::RTCProductionProtocol( last_produced_data_ts_(0), last_round_(utils::SteadyTime::nowMs().count()), allow_delayed_nacks_(false), - queue_timer_on_(false), - consumer_in_sync_(false), - on_consumer_in_sync_(nullptr), pending_fec_pace_(false), max_len_(0), queue_len_(0), @@ -54,8 +51,6 @@ RTCProductionProtocol::RTCProductionProtocol( std::uniform_int_distribution<> dis(0, 255); prod_label_ = dis(gen_); cache_label_ = (prod_label_ + 1) % 256; - interests_queue_timer_ = - std::make_unique<asio::steady_timer>(portal_->getThread().getIoService()); round_timer_ = std::make_unique<asio::steady_timer>(portal_->getThread().getIoService()); fec_pacing_timer_ = @@ -69,16 +64,7 @@ RTCProductionProtocol::~RTCProductionProtocol() {} void RTCProductionProtocol::setProducerParam() { // Flow name: here we assume there is only one prefix registered in the portal - flow_name_ = portal_->getServedNamespaces().begin()->getName(); - - // Manifest - uint32_t making_manifest; - socket_->getSocketOption(interface::GeneralTransportOptions::MAKE_MANIFEST, - making_manifest); - - // Signer - std::shared_ptr<auth::Signer> signer; - socket_->getSocketOption(interface::GeneralTransportOptions::SIGNER, signer); + flow_name_ = portal_->getServedNamespaces().begin()->makeName(); // Default format core::Packet::Format default_format; @@ -94,15 +80,22 @@ void RTCProductionProtocol::setProducerParam() { socket_->getSocketOption(interface::RtcTransportOptions::AGGREGATED_DATA, data_aggregation_); - size_t signature_size = signer->getSignatureFieldSize(); - data_header_format_ = { - !making_manifest ? Packet::toAHFormat(default_format) : default_format, - !making_manifest ? signature_size : 0}; + size_t signature_size = signer_->getSignatureFieldSize(); + data_header_format_ = {!manifest_max_capacity_ + ? Packet::toAHFormat(default_format) + : default_format, + !manifest_max_capacity_ ? signature_size : 0}; manifest_header_format_ = {Packet::toAHFormat(default_format), signature_size}; nack_header_format_ = {Packet::toAHFormat(default_format), signature_size}; fec_header_format_ = {Packet::toAHFormat(default_format), signature_size}; + // Initialize verifier for aggregated interests + std::shared_ptr<auth::Verifier> verifier; + socket_->getSocketOption(implementation::GeneralTransportOptions::VERIFIER, + verifier); + verifier_ = std::make_shared<rtc::RTCVerifier>(verifier, 0, 0); + // Schedule round timer scheduleRoundTimer(); } @@ -143,15 +136,17 @@ void RTCProductionProtocol::updateStats(bool new_round) { packets_production_rate_ = ceil((double)(produced_packets_ + prev_produced_packets_) * per_second); - // add fec packets looking at the fec code. we don't use directly the number - // of fec packets produced in 1 round because it may happen that different - // numbers of blocks are generated during the rounds and this creates - // inconsistencies in the estimation of the production rate - uint32_t k = fec::FECUtils::getSourceSymbols(fec_type_); - uint32_t n = fec::FECUtils::getBlockSymbols(fec_type_); + if (fec_encoder_ && fec_type_ != fec::FECType::UNKNOWN) { + // add fec packets looking at the fec code. we don't use directly the number + // of fec packets produced in 1 round because it may happen that different + // numbers of blocks are generated during the rounds and this creates + // inconsistencies in the estimation of the production rate + uint32_t k = fec::FECUtils::getSourceSymbols(fec_type_); + uint32_t n = fec::FECUtils::getBlockSymbols(fec_type_); - packets_production_rate_ += - ceil((double)packets_production_rate_ / (double)k) * (n - k); + packets_production_rate_ += + ceil((double)packets_production_rate_ / (double)k) * (n - k); + } // update the production rate as soon as it increases by 10% with respect to // the last round @@ -168,11 +163,6 @@ void RTCProductionProtocol::updateStats(bool new_round) { allow_delayed_nacks_ = false; } - // check if the production rate is decreased. if yes send nacks if needed - if (prev_packets_production_rate < packets_production_rate_) { - sendNacksForPendingInterests(); - } - if (new_round) { prev_produced_bytes_ = produced_bytes_; prev_produced_packets_ = produced_packets_; @@ -203,16 +193,25 @@ void RTCProductionProtocol::produce(ContentObject &content_object) { uint32_t RTCProductionProtocol::produceDatagram( const Name &content_name, std::unique_ptr<utils::MemBuf> &&buffer) { std::size_t buffer_size = buffer->length(); + DLOG_IF(INFO, VLOG_IS_ON(3)) + << "Maybe Sending content object: " << content_name; + if (TRANSPORT_EXPECT_FALSE(buffer_size == 0)) return 0; + DLOG_IF(INFO, VLOG_IS_ON(3)) << "Sending content object: " << content_name; + uint32_t data_packet_size; socket_->getSocketOption(interface::GeneralTransportOptions::DATA_PACKET_SIZE, data_packet_size); - - if (TRANSPORT_EXPECT_FALSE( - (Packet::getHeaderSizeFromFormat(data_header_format_.first, - data_header_format_.second) + - rtc::DATA_HEADER_SIZE + buffer_size) > data_packet_size)) { + // this is a source packet but we check the fec header size of FEC packet in + // order to leave room for the header when FEC packets will be generated + uint32_t fec_header = 0; + if (fec_encoder_) fec_encoder_->getFecHeaderSize(true); + uint32_t headers_size = + (uint32_t)Packet::getHeaderSizeFromFormat(data_header_format_.first, + data_header_format_.second) + + rtc::DATA_HEADER_SIZE + fec_header; + if (TRANSPORT_EXPECT_FALSE((headers_size + buffer_size) > data_packet_size)) { return 0; } @@ -338,47 +337,42 @@ void RTCProductionProtocol::emptyQueue() { } void RTCProductionProtocol::sendManifest(const Name &name) { - if (!making_manifest_) { + if (!manifest_max_capacity_) { return; } - Name manifest_name(name); - - uint32_t data_packet_size; - socket_->getSocketOption(interface::GeneralTransportOptions::DATA_PACKET_SIZE, - data_packet_size); - - // The maximum number of entries a manifest can hold - uint32_t manifest_capacity = making_manifest_; + Name manifest_name = name; // If there is not enough hashes to fill a manifest, return early - if (manifest_entries_.size() < manifest_capacity) { + if (manifest_entries_.size() < manifest_max_capacity_) { return; } // Create a new manifest std::shared_ptr<core::ContentObjectManifest> manifest = createManifest(manifest_name.setSuffix(current_seg_)); + auto manifest_co = + std::dynamic_pointer_cast<ContentObject>(manifest->getPacket()); // Fill the manifest with packet hashes that were previously saved uint32_t nb_entries; - for (nb_entries = 0; nb_entries < manifest_capacity; ++nb_entries) { + for (nb_entries = 0; nb_entries < manifest_max_capacity_; ++nb_entries) { if (manifest_entries_.empty()) { break; } std::pair<uint32_t, auth::CryptoHash> front = manifest_entries_.front(); - manifest->addSuffixHash(front.first, front.second); + manifest->addEntry(front.first, front.second); manifest_entries_.pop(); } DLOG_IF(INFO, VLOG_IS_ON(3)) - << "Sending manifest " << manifest->getName().getSuffix() << " of size " - << nb_entries; + << "Sending manifest " << manifest_co->getName().getSuffix() + << " of size " << nb_entries; // Encode and send the manifest manifest->encode(); portal_->getThread().tryRunHandlerNow( - [this, content_object{std::move(manifest)}, manifest_name]() mutable { + [this, content_object{std::move(manifest_co)}, manifest_name]() mutable { produceInternal(std::move(content_object), manifest_name); }); } @@ -394,11 +388,12 @@ RTCProductionProtocol::createManifest(const Name &content_name) const { uint64_t now = utils::SteadyTime::nowMs().count(); // Create a new manifest - std::shared_ptr<core::ContentObjectManifest> manifest( - ContentObjectManifest::createManifest( - manifest_header_format_.first, name, core::ManifestVersion::VERSION_1, - core::ManifestType::INLINE_MANIFEST, false, name, hash_algo, - manifest_header_format_.second)); + std::shared_ptr<core::ContentObjectManifest> manifest = + ContentObjectManifest::createContentManifest( + manifest_header_format_.first, name, manifest_header_format_.second); + manifest->setHeaders(core::ManifestType::INLINE_MANIFEST, + manifest_max_capacity_, hash_algo, false /* is_last */, + name); // Set connection parameters manifest->setParamsRTC(ParamsRTC{ @@ -444,7 +439,15 @@ void RTCProductionProtocol::producePktInternal( // set hicn stuff Name n(content_name); content_object->setName(n.setSuffix(current_seg_)); - content_object->setLifetime(500); // XXX this should be set by the APP + + uint32_t expiry_time = 0; + socket_->getSocketOption( + interface::GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME, + expiry_time); + if (expiry_time == interface::default_values::content_object_expiry_time) + expiry_time = 500; // the data expiration time should be set by the App. if + // the App does not specify it the default is 500ms + content_object->setLifetime(expiry_time); content_object->setPathLabel(prod_label_); // update stats @@ -466,9 +469,9 @@ void RTCProductionProtocol::producePktInternal( // pass packet to FEC encoder if (fec_encoder_ && !fec) { - uint32_t offset = - is_manifest ? content_object->headerSize() - : content_object->headerSize() + rtc::DATA_HEADER_SIZE; + uint32_t offset = is_manifest ? (uint32_t)content_object->headerSize() + : (uint32_t)content_object->headerSize() + + rtc::DATA_HEADER_SIZE; uint32_t metadata = static_cast<uint32_t>(content_object->getPayloadType()); fec_encoder_->onPacketProduced(*content_object, offset, metadata); @@ -481,19 +484,14 @@ void RTCProductionProtocol::producePktInternal( *content_object); } - auto seq_it = seqs_map_.find(current_seg_); - if (seq_it != seqs_map_.end()) { - sendContentObject(content_object, false, fec); - } + // TODO we may want to send FEC only if an interest is pending in the pit in + sendContentObject(content_object, false, fec); if (*on_content_object_output_) { on_content_object_output_->operator()(*socket_->getInterface(), *content_object); } - // remove interests from the interest cache if it exists - removeFromInterestQueue(current_seg_); - if (!fec) last_produced_data_ts_ = now; // Update current segment @@ -563,59 +561,65 @@ void RTCProductionProtocol::onInterest(Interest &interest) { on_interest_input_->operator()(*socket_->getInterface(), interest); } - auto suffix = interest.firstSuffix(); - // numberOfSuffixes returns only the prefixes in the payalod - // we add + 1 to count also the seq in the name - auto n_suffixes = interest.numberOfSuffixes() + 1; - Name name = interest.getName(); - bool prev_consumer_state = consumer_in_sync_; - - for (uint32_t i = 0; i < n_suffixes; i++) { - if (i > 0) { - name.setSuffix(*(suffix + (i - 1))); - } + if (!interest.isValid()) throw std::runtime_error("Bad interest format"); + if (interest.hasManifest() && + verifier_->verify(interest) != auth::VerificationPolicy::ACCEPT) + throw std::runtime_error("Interset manifest verification failed"); - DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received interest " << name; + uint32_t *suffix = interest.firstSuffix(); + uint32_t n_suffixes_in_manifest = interest.numberOfSuffixes(); + uint32_t *request_bitmap = interest.getRequestBitmap(); - const std::shared_ptr<ContentObject> content_object = - output_buffer_.find(name); + Name name = interest.getName(); + uint32_t pos = 0; // Position of current suffix in manifest - if (content_object) { - if (*on_interest_satisfied_output_buffer_) { - on_interest_satisfied_output_buffer_->operator()( - *socket_->getInterface(), interest); - } + DLOG_IF(INFO, VLOG_IS_ON(3)) + << "Received interest " << name << " (" << n_suffixes_in_manifest + << " suffixes in manifest)"; + + // Process the suffix in the interest header + // (first loop iteration), then suffixes in the manifest + do { + if (!interest.hasManifest() || is_bit_set(request_bitmap, pos)) { + const std::shared_ptr<ContentObject> content_object = + output_buffer_.find(name); + + if (content_object) { + if (*on_interest_satisfied_output_buffer_) { + on_interest_satisfied_output_buffer_->operator()( + *socket_->getInterface(), interest); + } - if (*on_content_object_output_) { - on_content_object_output_->operator()(*socket_->getInterface(), - *content_object); - } + if (*on_content_object_output_) { + on_content_object_output_->operator()(*socket_->getInterface(), + *content_object); + } - DLOG_IF(INFO, VLOG_IS_ON(3)) - << "Send content %u (onInterest) " << content_object->getName(); - content_object->setPathLabel(cache_label_); - sendContentObject(content_object); - } else { - if (*on_interest_process_) { - on_interest_process_->operator()(*socket_->getInterface(), interest); + DLOG_IF(INFO, VLOG_IS_ON(3)) + << "Send content %u (onInterest) " << content_object->getName(); + content_object->setPathLabel(cache_label_); + sendContentObject(content_object); + } else { + if (*on_interest_process_) { + on_interest_process_->operator()(*socket_->getInterface(), interest); + } + processInterest(name.getSuffix(), interest.getLifetime()); } - processInterest(name.getSuffix(), interest.getLifetime()); } - } - if (prev_consumer_state != consumer_in_sync_ && consumer_in_sync_) - on_consumer_in_sync_(*socket_->getInterface(), interest); + // Retrieve next suffix in the manifest + if (interest.hasManifest()) { + uint32_t seq = *suffix; + suffix++; + + name.setSuffix(seq); + interest.setName(name); + } + } while (pos++ < n_suffixes_in_manifest); } void RTCProductionProtocol::processInterest(uint32_t interest_seg, uint32_t lifetime) { - if (interest_seg == 0) { - // first packet from the consumer, reset sync state - consumer_in_sync_ = false; - } - - uint64_t now = utils::SteadyTime::nowMs().count(); - switch (rtc::ProbeHandler::getProbeType(interest_seg)) { case rtc::ProbeType::INIT: DLOG_IF(INFO, VLOG_IS_ON(3)) << "Received init probe " << interest_seg; @@ -629,183 +633,7 @@ void RTCProductionProtocol::processInterest(uint32_t interest_seg, break; } - // if the production rate 0 use delayed nacks - if (allow_delayed_nacks_ && interest_seg >= current_seg_) { - uint64_t next_timer = UINT64_MAX; - if (!timers_map_.empty()) { - next_timer = timers_map_.begin()->first; - } - - uint64_t expiration = now + rtc::NACK_DELAY; - addToInterestQueue(interest_seg, expiration); - - // here we have at least one interest in the queue, we need to start or - // update the timer - if (!queue_timer_on_) { - // set timeout - queue_timer_on_ = true; - scheduleQueueTimer(timers_map_.begin()->first - now); - } else { - // re-schedule the timer because a new interest will expires sooner - if (next_timer > timers_map_.begin()->first) { - interests_queue_timer_->cancel(); - scheduleQueueTimer(timers_map_.begin()->first - now); - } - } - return; - } - - if (queue_timer_on_) { - // the producer is producing. Send nacks to packets that will expire - // before the data production and remove the timer - queue_timer_on_ = false; - interests_queue_timer_->cancel(); - sendNacksForPendingInterests(); - } - - uint32_t max_gap = (uint32_t)floor( - (double)((double)((double)lifetime * - rtc::INTEREST_LIFETIME_REDUCTION_FACTOR / - rtc::MILLI_IN_A_SEC) * - (double)(packets_production_rate_))); - - if (interest_seg < current_seg_ || interest_seg > (max_gap + current_seg_)) { - sendNack(interest_seg); - } else { - if (!consumer_in_sync_ && on_consumer_in_sync_) { - // we consider the remote consumer to be in sync as soon as it covers - // 70% of the production window with interests - uint32_t perc = ceil((double)max_gap * 0.7); - if (interest_seg > (perc + current_seg_)) { - consumer_in_sync_ = true; - // on_consumer_in_sync_(*socket_->getInterface(), interest); - } - } - uint64_t expiration = - now + floor((double)lifetime * rtc::INTEREST_LIFETIME_REDUCTION_FACTOR); - addToInterestQueue(interest_seg, expiration); - } -} - -void RTCProductionProtocol::scheduleQueueTimer(uint64_t wait) { - interests_queue_timer_->expires_from_now(std::chrono::milliseconds(wait)); - std::weak_ptr<RTCProductionProtocol> self = shared_from_this(); - interests_queue_timer_->async_wait([self](const std::error_code &ec) { - if (ec) { - return; - } - - auto sp = self.lock(); - if (sp && sp->isRunning()) { - sp->interestQueueTimer(); - } - }); -} - -void RTCProductionProtocol::addToInterestQueue(uint32_t interest_seg, - uint64_t expiration) { - // check if the seq number exists already - auto it_seqs = seqs_map_.find(interest_seg); - if (it_seqs != seqs_map_.end()) { - // the seq already exists - if (expiration < it_seqs->second) { - // we need to update the timer becasue we got a smaller one - // 1) remove the entry from the multimap - // 2) update this entry - auto range = timers_map_.equal_range(it_seqs->second); - for (auto it_timers = range.first; it_timers != range.second; - it_timers++) { - if (it_timers->second == it_seqs->first) { - timers_map_.erase(it_timers); - break; - } - } - timers_map_.insert( - std::pair<uint64_t, uint32_t>(expiration, interest_seg)); - it_seqs->second = expiration; - } else { - // nothing to do here - return; - } - } else { - // add the new seq - timers_map_.insert(std::pair<uint64_t, uint32_t>(expiration, interest_seg)); - seqs_map_.insert(std::pair<uint32_t, uint64_t>(interest_seg, expiration)); - } -} - -void RTCProductionProtocol::sendNacksForPendingInterests() { - std::unordered_set<uint32_t> to_remove; - - uint32_t pps = ceil((double)(packets_production_rate_)*rtc:: - INTEREST_LIFETIME_REDUCTION_FACTOR); - - uint64_t now = utils::SteadyTime::nowMs().count(); - for (auto it = seqs_map_.begin(); it != seqs_map_.end(); it++) { - if (it->first > current_seg_ && it->second > now) { - double exp_time_in_sec = - (double)(it->second - now) / (double)rtc::MILLI_IN_A_SEC; - uint32_t packets_prod_before_expire = ceil((double)pps * exp_time_in_sec); - - if (it->first > (current_seg_ + packets_prod_before_expire)) { - sendNack(it->first); - to_remove.insert(it->first); - } - } else if (TRANSPORT_EXPECT_FALSE(it->first < current_seg_ || - it->second <= now)) { - // this branch should never be execcuted - // first condition: the packet was already prdocued and we have and old - // interest pending. send a nack to notify the consumer if needed. the - // case it->first = current_seg_ is not handled because - // the interest will be satified by the next data packet. - // second condition: the interest is expired. - sendNack(it->first); - to_remove.insert(it->first); - } - } - - // delete nacked interests - for (auto it = to_remove.begin(); it != to_remove.end(); it++) { - removeFromInterestQueue(*it); - } -} - -void RTCProductionProtocol::removeFromInterestQueue(uint32_t interest_seg) { - auto seq_it = seqs_map_.find(interest_seg); - if (seq_it != seqs_map_.end()) { - auto range = timers_map_.equal_range(seq_it->second); - for (auto it_timers = range.first; it_timers != range.second; it_timers++) { - if (it_timers->second == seq_it->first) { - timers_map_.erase(it_timers); - break; - } - } - seqs_map_.erase(seq_it); - } -} - -void RTCProductionProtocol::interestQueueTimer() { - uint64_t now = utils::SteadyTime::nowMs().count(); - - for (auto it_timers = timers_map_.begin(); it_timers != timers_map_.end();) { - uint64_t expire = it_timers->first; - if (expire <= now) { - uint32_t seq = it_timers->second; - sendNack(seq); - // remove the interest from the other map - seqs_map_.erase(seq); - it_timers = timers_map_.erase(it_timers); - } else { - // stop, we are done! - break; - } - } - if (timers_map_.empty()) { - queue_timer_on_ = false; - } else { - queue_timer_on_ = true; - scheduleQueueTimer(timers_map_.begin()->first - now); - } + if (interest_seg < current_seg_) sendNack(interest_seg); } void RTCProductionProtocol::sendManifestProbe(uint32_t sequence) { @@ -814,18 +642,20 @@ void RTCProductionProtocol::sendManifestProbe(uint32_t sequence) { std::shared_ptr<core::ContentObjectManifest> manifest_probe = createManifest(manifest_name); + auto manifest_probe_co = + std::dynamic_pointer_cast<ContentObject>(manifest_probe->getPacket()); - manifest_probe->setLifetime(0); - manifest_probe->setPathLabel(prod_label_); + manifest_probe_co->setLifetime(0); + manifest_probe_co->setPathLabel(prod_label_); manifest_probe->encode(); if (*on_content_object_output_) { on_content_object_output_->operator()(*socket_->getInterface(), - *manifest_probe); + *manifest_probe_co); } DLOG_IF(INFO, VLOG_IS_ON(3)) << "Send init probe " << sequence; - sendContentObject(manifest_probe, true, false); + sendContentObject(manifest_probe_co, true, false); } void RTCProductionProtocol::sendNack(uint32_t sequence) { @@ -847,20 +677,6 @@ void RTCProductionProtocol::sendNack(uint32_t sequence) { nack->setLifetime(0); nack->setPathLabel(prod_label_); - if (!consumer_in_sync_ && on_consumer_in_sync_ && - rtc::ProbeHandler::getProbeType(sequence) == rtc::ProbeType::NOT_PROBE && - sequence > next_packet) { - consumer_in_sync_ = true; - Packet::Format format; - socket_->getSocketOption(interface::GeneralTransportOptions::PACKET_FORMAT, - format); - - auto interest = - core::PacketManager<>::getInstance().getPacket<Interest>(format); - interest->setName(n); - on_consumer_in_sync_(*socket_->getInterface(), *interest); - } - if (*on_content_object_output_) { on_content_object_output_->operator()(*socket_->getInterface(), *nack); } @@ -881,7 +697,7 @@ void RTCProductionProtocol::sendContentObject( portal_->sendContentObject(*content_object); // Compute and save data packet digest - if (making_manifest_ && !is_ah) { + if (manifest_max_capacity_ && !is_ah) { auth::CryptoHashType hash_algo; socket_->getSocketOption(interface::GeneralTransportOptions::HASH_ALGORITHM, hash_algo); diff --git a/libtransport/src/protocols/prod_protocol_rtc.h b/libtransport/src/protocols/prod_protocol_rtc.h index c0424a39c..285ccb646 100644 --- a/libtransport/src/protocols/prod_protocol_rtc.h +++ b/libtransport/src/protocols/prod_protocol_rtc.h @@ -17,6 +17,7 @@ #include <hicn/transport/core/name.h> #include <protocols/production_protocol.h> +#include <protocols/rtc/rtc_verifier.h> #include <atomic> #include <map> @@ -50,11 +51,6 @@ class RTCProductionProtocol : public ProductionProtocol { buffer, buffer_size, buffer_size)); } - void setConsumerInSyncCallback( - interface::ProducerInterestCallback &&callback) { - on_consumer_in_sync_ = std::move(callback); - } - auto shared_from_this() { return utils::shared_from(this); } private: @@ -80,13 +76,6 @@ class RTCProductionProtocol : public ProductionProtocol { void updateStats(bool new_round); void scheduleRoundTimer(); - // pending intersts functions - void addToInterestQueue(uint32_t interest_seg, uint64_t expiration); - void sendNacksForPendingInterests(); - void removeFromInterestQueue(uint32_t interest_seg); - void scheduleQueueTimer(uint64_t wait); - void interestQueueTimer(); - // FEC functions void onFecPackets(fec::BufferArray &packets); fec::buffer getBuffer(std::size_t size); @@ -111,14 +100,14 @@ class RTCProductionProtocol : public ProductionProtocol { uint32_t prev_produced_bytes_; // XXX clearly explain all these new vars uint32_t prev_produced_packets_; - uint32_t produced_bytes_; // bytes produced in the last round - uint32_t produced_packets_; // packet produed in the last round + uint32_t produced_bytes_; // bytes produced in the last round + uint32_t produced_packets_; // packet produed in the last round uint32_t max_packet_production_; // never exceed this number of packets // without update stats - uint32_t bytes_production_rate_; // bytes per sec - uint32_t packets_production_rate_; // pps + uint32_t bytes_production_rate_; // bytes per sec + uint32_t packets_production_rate_; // pps uint64_t last_produced_data_ts_; // ms @@ -134,27 +123,6 @@ class RTCProductionProtocol : public ProductionProtocol { // of the new rate. bool allow_delayed_nacks_; - // queue for the received interests - // this map maps the expiration time of an interest to - // its sequence number. the map is sorted by timeouts - // the same timeout may be used for multiple sequence numbers - // but for each sequence number we store only the smallest - // expiry time. In this way the mapping from seqs_map_ to - // timers_map_ is unique - std::multimap<uint64_t, uint32_t> timers_map_; - - // this map does the opposite, this map is not ordered - std::unordered_map<uint32_t, uint64_t> seqs_map_; - bool queue_timer_on_; - std::unique_ptr<asio::steady_timer> interests_queue_timer_; - - // this callback is called when the remote consumer is in sync with high - // probability. it is called only the first time that the switch happen. - // XXX this makes sense only in P2P mode, while in standard mode is - // impossible to know the state of the consumers so it should not be used. - bool consumer_in_sync_; - interface::ProducerInterestCallback on_consumer_in_sync_; - // Save FEC packets here before sending them std::queue<ContentObject::Ptr> pending_fec_packets_; std::queue<std::pair<uint64_t, ContentObject::Ptr>> paced_fec_packets_; @@ -172,6 +140,9 @@ class RTCProductionProtocol : public ProductionProtocol { // Manifest std::queue<std::pair<uint32_t, auth::CryptoHash>> manifest_entries_; // map a packet suffix to a packet hash + + // Verifier for aggregated interests + std::shared_ptr<rtc::RTCVerifier> verifier_; }; } // namespace protocol diff --git a/libtransport/src/protocols/production_protocol.cc b/libtransport/src/protocols/production_protocol.cc index 8b781e38a..039a6a55a 100644 --- a/libtransport/src/protocols/production_protocol.cc +++ b/libtransport/src/protocols/production_protocol.cc @@ -78,8 +78,8 @@ int ProductionProtocol::start() { socket_->getSocketOption(GeneralTransportOptions::ASYNC_MODE, is_async_); socket_->getSocketOption(GeneralTransportOptions::SIGNER, signer_); - socket_->getSocketOption(GeneralTransportOptions::MAKE_MANIFEST, - making_manifest_); + socket_->getSocketOption(GeneralTransportOptions::MANIFEST_MAX_CAPACITY, + manifest_max_capacity_); std::string fec_type_str = ""; socket_->getSocketOption(GeneralTransportOptions::FEC_TYPE, fec_type_str); diff --git a/libtransport/src/protocols/production_protocol.h b/libtransport/src/protocols/production_protocol.h index 8e10d2f40..09718631f 100644 --- a/libtransport/src/protocols/production_protocol.h +++ b/libtransport/src/protocols/production_protocol.h @@ -79,6 +79,7 @@ class ProductionProtocol if (fec_str && (fec_type_ == fec::FECType::UNKNOWN)) { LOG(INFO) << "Using FEC " << fec_str; fec_type_ = fec::FECUtils::fecTypeFromString(fec_str); + CHECK(fec_type_ != fec::FECType::UNKNOWN); } if (fec_type_ == fec::FECType::UNKNOWN) { @@ -123,7 +124,7 @@ class ProductionProtocol // Signature and manifest std::shared_ptr<auth::Signer> signer_; - uint32_t making_manifest_; + uint32_t manifest_max_capacity_; bool is_async_; fec::FECType fec_type_; diff --git a/libtransport/src/protocols/raaqm.cc b/libtransport/src/protocols/raaqm.cc index 131367d78..bcbc15aef 100644 --- a/libtransport/src/protocols/raaqm.cc +++ b/libtransport/src/protocols/raaqm.cc @@ -371,7 +371,7 @@ void RaaqmTransportProtocol::onPacketDropped(Interest &interest, } interest_retransmissions_[segment & mask]++; - interest_to_retransmit_.push(segment); + interest_to_retransmit_.push((unsigned int)segment); } else { LOG(ERROR) << "Stop: received not trusted packet " << interest_retransmissions_[segment & mask] << " times"; @@ -429,7 +429,7 @@ void RaaqmTransportProtocol::onInterestTimeout(Interest::Ptr &interest, return; } - interest_to_retransmit_.push(segment); + interest_to_retransmit_.push((unsigned int)segment); scheduleNextInterests(); } else { LOG(ERROR) << "Stop: reached max retx limit."; @@ -491,7 +491,7 @@ void RaaqmTransportProtocol::updateRtt(uint64_t segment) { throw std::runtime_error("RAAQM ERROR: no current path found, exit"); } else { auto now = utils::SteadyTime::Clock::now(); - utils::SteadyTime::Milliseconds rtt = utils::SteadyTime::getDurationMs( + auto rtt = utils::SteadyTime::getDurationUs( interest_timepoints_[segment & mask], now); // Update stats @@ -525,7 +525,7 @@ void RaaqmTransportProtocol::RAAQM() { } void RaaqmTransportProtocol::updateStats( - uint32_t suffix, const utils::SteadyTime::Milliseconds &rtt, + uint32_t suffix, const utils::SteadyTime::Microseconds &rtt, utils::SteadyTime::TimePoint &now) { // Update RTT statistics stats_->updateAverageRtt(rtt); diff --git a/libtransport/src/protocols/raaqm.h b/libtransport/src/protocols/raaqm.h index ec344c23a..a7ef23b68 100644 --- a/libtransport/src/protocols/raaqm.h +++ b/libtransport/src/protocols/raaqm.h @@ -57,7 +57,7 @@ class RaaqmTransportProtocol : public TransportProtocol, virtual void afterDataUnsatisfied(uint64_t segment); virtual void updateStats(uint32_t suffix, - const utils::SteadyTime::Milliseconds &rtt, + const utils::SteadyTime::Microseconds &rtt, utils::SteadyTime::TimePoint &now); private: diff --git a/libtransport/src/protocols/raaqm_data_path.cc b/libtransport/src/protocols/raaqm_data_path.cc index d06fee918..b8e6e6285 100644 --- a/libtransport/src/protocols/raaqm_data_path.cc +++ b/libtransport/src/protocols/raaqm_data_path.cc @@ -50,9 +50,9 @@ RaaqmDataPath::RaaqmDataPath(double drop_factor, alpha_(ALPHA) {} RaaqmDataPath &RaaqmDataPath::insertNewRtt( - const utils::SteadyTime::Milliseconds &new_rtt, + const utils::SteadyTime::Microseconds &new_rtt, const utils::SteadyTime::TimePoint &now) { - rtt_ = new_rtt.count(); + rtt_ = new_rtt.count() / 1000; rtt_samples_.pushBack(rtt_); rtt_max_ = rtt_samples_.rBegin(); diff --git a/libtransport/src/protocols/raaqm_data_path.h b/libtransport/src/protocols/raaqm_data_path.h index b6f7c5ac1..dd24dad51 100644 --- a/libtransport/src/protocols/raaqm_data_path.h +++ b/libtransport/src/protocols/raaqm_data_path.h @@ -49,7 +49,7 @@ class RaaqmDataPath { * max of RTT. * @param new_rtt is the value of the new RTT */ - RaaqmDataPath &insertNewRtt(const utils::SteadyTime::Milliseconds &new_rtt, + RaaqmDataPath &insertNewRtt(const utils::SteadyTime::Microseconds &new_rtt, const utils::SteadyTime::TimePoint &now); /** diff --git a/libtransport/src/protocols/rate_estimation.cc b/libtransport/src/protocols/rate_estimation.cc index d834b53e6..01c18c6cb 100644 --- a/libtransport/src/protocols/rate_estimation.cc +++ b/libtransport/src/protocols/rate_estimation.cc @@ -107,9 +107,9 @@ InterRttEstimator::~InterRttEstimator() { } void InterRttEstimator::onRttUpdate( - const utils::SteadyTime::Milliseconds &rtt) { + const utils::SteadyTime::Microseconds &rtt) { pthread_mutex_lock(&(this->mutex_)); - this->rtt_ = rtt.count(); + this->rtt_ = rtt.count() / 1000.0; this->number_of_packets_++; this->avg_rtt_ += this->rtt_; pthread_mutex_unlock(&(this->mutex_)); @@ -256,7 +256,7 @@ void SimpleEstimator::onDataReceived(int packet_size) { this->total_size_ += packet_size; } -void SimpleEstimator::onRttUpdate(const utils::SteadyTime::Milliseconds &rtt) { +void SimpleEstimator::onRttUpdate(const utils::SteadyTime::Microseconds &rtt) { this->number_of_packets_++; if (this->number_of_packets_ == this->batching_param_) { @@ -300,9 +300,9 @@ BatchingPacketsEstimator::BatchingPacketsEstimator(double alpha_arg, } void BatchingPacketsEstimator::onRttUpdate( - const utils::SteadyTime::Milliseconds &rtt) { + const utils::SteadyTime::Microseconds &rtt) { this->number_of_packets_++; - this->avg_rtt_ += rtt.count(); + this->avg_rtt_ += rtt.count() / 1000.0; if (number_of_packets_ == this->batching_param_) { if (estimation_ == 0) { diff --git a/libtransport/src/protocols/rate_estimation.h b/libtransport/src/protocols/rate_estimation.h index b71de12e4..d809b2b7c 100644 --- a/libtransport/src/protocols/rate_estimation.h +++ b/libtransport/src/protocols/rate_estimation.h @@ -31,7 +31,7 @@ class IcnRateEstimator : utils::NonCopyable { virtual ~IcnRateEstimator(){}; - virtual void onRttUpdate(const utils::SteadyTime::Milliseconds &rtt){}; + virtual void onRttUpdate(const utils::SteadyTime::Microseconds &rtt){}; virtual void onDataReceived(int packetSize){}; @@ -66,7 +66,7 @@ class InterRttEstimator : public IcnRateEstimator { ~InterRttEstimator(); - void onRttUpdate(const utils::SteadyTime::Milliseconds &rtt); + void onRttUpdate(const utils::SteadyTime::Microseconds &rtt); void onDataReceived(int packet_size) { if (packet_size > this->max_packet_size_) { @@ -101,7 +101,7 @@ class BatchingPacketsEstimator : public IcnRateEstimator { public: BatchingPacketsEstimator(double alpha_arg, int batchingParam); - void onRttUpdate(const utils::SteadyTime::Milliseconds &rtt); + void onRttUpdate(const utils::SteadyTime::Microseconds &rtt); void onDataReceived(int packet_size) { if (packet_size > this->max_packet_size_) { @@ -148,7 +148,7 @@ class SimpleEstimator : public IcnRateEstimator { public: SimpleEstimator(double alpha, int batching_param); - void onRttUpdate(const utils::SteadyTime::Milliseconds &rtt); + void onRttUpdate(const utils::SteadyTime::Microseconds &rtt); void onDataReceived(int packet_size); diff --git a/libtransport/src/protocols/reassembly.h b/libtransport/src/protocols/reassembly.h index b0879201d..c0c4de3d8 100644 --- a/libtransport/src/protocols/reassembly.h +++ b/libtransport/src/protocols/reassembly.h @@ -57,12 +57,6 @@ class Reassembly { virtual void reassemble(utils::MemBuf &buffer, uint32_t suffix) = 0; /** - * Handle reassembly of manifest - */ - virtual void reassemble( - std::unique_ptr<core::ContentObjectManifest> &&manifest) = 0; - - /** * Reset reassembler for new round */ virtual void reInitialize() = 0; diff --git a/libtransport/src/protocols/rtc/probe_handler.cc b/libtransport/src/protocols/rtc/probe_handler.cc index 6a84914ab..60eceeb19 100644 --- a/libtransport/src/protocols/rtc/probe_handler.cc +++ b/libtransport/src/protocols/rtc/probe_handler.cc @@ -13,6 +13,7 @@ * limitations under the License. */ +#include <glog/logging.h> #include <hicn/transport/utils/chrono_typedefs.h> #include <protocols/rtc/probe_handler.h> #include <protocols/rtc/rtc_consts.h> @@ -64,7 +65,7 @@ double ProbeHandler::getProbeLossRate() { } void ProbeHandler::setSuffixRange(uint32_t min, uint32_t max) { - assert(min <= max && min >= MIN_PROBE_SEQ); + DCHECK(min <= max && min >= MIN_PROBE_SEQ); distr_ = std::uniform_int_distribution<uint32_t>(min, max); } diff --git a/libtransport/src/protocols/rtc/rtc.cc b/libtransport/src/protocols/rtc/rtc.cc index d2682edfa..9a56269f3 100644 --- a/libtransport/src/protocols/rtc/rtc.cc +++ b/libtransport/src/protocols/rtc/rtc.cc @@ -38,6 +38,7 @@ RTCTransportProtocol::RTCTransportProtocol( implementation::ConsumerSocket *icn_socket) : TransportProtocol(icn_socket, new RtcIndexer<>(icn_socket, this), new RtcReassembly(icn_socket, this)), + max_aggregated_interest_(1), number_(0) { icn_socket->getSocketOption(PORTAL, portal_); round_timer_ = @@ -55,9 +56,9 @@ void RTCTransportProtocol::resume() { TransportProtocol::resume(); } -std::size_t RTCTransportProtocol::transportHeaderLength() { +std::size_t RTCTransportProtocol::transportHeaderLength(bool isFEC) { return DATA_HEADER_SIZE + - (fec_decoder_ != nullptr ? fec_decoder_->getFecHeaderSize() : 0); + (fec_decoder_ != nullptr ? fec_decoder_->getFecHeaderSize(isFEC) : 0); } // private @@ -75,13 +76,13 @@ void RTCTransportProtocol::initParams() { std::shared_ptr<auth::Verifier> verifier; socket_->getSocketOption(GeneralTransportOptions::VERIFIER, verifier); - uint32_t unverified_interval; - socket_->getSocketOption(GeneralTransportOptions::UNVERIFIED_INTERVAL, - unverified_interval); + uint32_t factor_relevant; + socket_->getSocketOption(GeneralTransportOptions::MANIFEST_FACTOR_RELEVANT, + factor_relevant); - double unverified_ratio; - socket_->getSocketOption(GeneralTransportOptions::UNVERIFIED_RATIO, - unverified_ratio); + uint32_t factor_alert; + socket_->getSocketOption(GeneralTransportOptions::MANIFEST_FACTOR_ALERT, + factor_alert); rc_ = std::make_shared<RTCRateControlCongestionDetection>(); ldr_ = std::make_shared<RTCLossDetectionAndRecovery>( @@ -100,8 +101,8 @@ void RTCTransportProtocol::initParams() { } }); - verifier_ = std::make_shared<RTCVerifier>(verifier, unverified_interval, - unverified_ratio); + verifier_ = + std::make_shared<RTCVerifier>(verifier, factor_relevant, factor_alert); state_ = std::make_shared<RTCState>( indexer_verifier_.get(), @@ -138,19 +139,20 @@ void RTCTransportProtocol::initParams() { last_interest_sent_time_ = 0; last_interest_sent_seq_ = 0; -#if 0 - if(portal_->isConnectedToFwd()){ - max_aggregated_interest_ = 1; - }else{ - max_aggregated_interest_ = MAX_INTERESTS_IN_BATCH; - } -#else - max_aggregated_interest_ = 1; - if (const char *max_aggr = std::getenv("MAX_AGGREGATED_INTERESTS")) { - LOG(INFO) << "Max Aggregated: " << max_aggr; - max_aggregated_interest_ = std::stoul(std::string(max_aggr)); + // Aggregated interests setup + bool aggregated_interests_on; + socket_->getSocketOption(RtcTransportOptions::AGGREGATED_INTERESTS, + aggregated_interests_on); + if (aggregated_interests_on) { + if (const char *max_aggr = std::getenv("MAX_AGGREGATED_INTERESTS")) + max_aggregated_interest_ = (uint32_t)std::stoul(std::string(max_aggr)); + else + max_aggregated_interest_ = MAX_INTERESTS_IN_BATCH; + + max_aggregated_interest_ = std::min<uint32_t>(max_aggregated_interest_, + 1 + MAX_SUFFIXES_IN_MANIFEST); } -#endif + LOG(INFO) << "Max Aggregated: " << max_aggregated_interest_; max_sent_int_ = std::ceil((double)MAX_PACING_BATCH / (double)max_aggregated_interest_); @@ -263,6 +265,11 @@ void RTCTransportProtocol::discoveredRtt() { socket_->getSocketOption(RtcTransportOptions::RECOVERY_STRATEGY, strategy); ldr_->changeRecoveryStrategy( (interface::RtcTransportRecoveryStrategies)strategy); + + bool content_sharing_mode; + socket_->getSocketOption(RtcTransportOptions::CONTENT_SHARING_MODE, + content_sharing_mode); + if (content_sharing_mode) ldr_->setContentSharingMode(); ldr_->turnOnRecovery(); ldr_->onNewRound(false); @@ -270,22 +277,9 @@ void RTCTransportProtocol::discoveredRtt() { Name *name = nullptr; socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, &name); Prefix prefix(*name, 128); - if ((interface::RtcTransportRecoveryStrategies)strategy == - interface::RtcTransportRecoveryStrategies::LOW_RATE_AND_BESTPATH) { - fwd_strategy_.initFwdStrategy(portal_, prefix, state_.get(), - RTCForwardingStrategy::BEST_PATH); - } else if ((interface::RtcTransportRecoveryStrategies)strategy == - interface::RtcTransportRecoveryStrategies:: - LOW_RATE_AND_REPLICATION) { - fwd_strategy_.initFwdStrategy(portal_, prefix, state_.get(), - RTCForwardingStrategy::REPLICATION); - } else if ((interface::RtcTransportRecoveryStrategies)strategy == - interface::RtcTransportRecoveryStrategies:: - LOW_RATE_AND_ALL_FWD_STRATEGIES) { - fwd_strategy_.initFwdStrategy(portal_, prefix, state_.get(), - RTCForwardingStrategy::BOTH); - } - + fwd_strategy_.initFwdStrategy( + portal_, prefix, state_.get(), + (interface::RtcTransportRecoveryStrategies)strategy); updateSyncWindow(); } @@ -302,6 +296,12 @@ void RTCTransportProtocol::computeMaxSyncWindow() { return; } + bool content_sharing_mode; + socket_->getSocketOption(RtcTransportOptions::CONTENT_SHARING_MODE, + content_sharing_mode); + if (content_sharing_mode && (production_rate < MIN_PROD_RATE_SHARING_MODE)) + production_rate = MIN_PROD_RATE_SHARING_MODE; + production_rate += (production_rate * indexer_verifier_->getMaxFecOverhead()); uint32_t lifetime = default_values::interest_lifetime; @@ -330,6 +330,11 @@ void RTCTransportProtocol::updateSyncWindow() { double prod_rate = state_->getProducerRate(); double rtt = (double)state_->getMinRTT() / MILLI_IN_A_SEC; double packet_size = state_->getAveragePacketSize(); + bool content_sharing_mode; + socket_->getSocketOption(RtcTransportOptions::CONTENT_SHARING_MODE, + content_sharing_mode); + if (content_sharing_mode && (prod_rate < MIN_PROD_RATE_SHARING_MODE)) + prod_rate = MIN_PROD_RATE_SHARING_MODE; // if some of the info are not available do not update the current win if (prod_rate != 0.0 && rtt != 0.0 && packet_size != 0.0) { @@ -385,6 +390,19 @@ void RTCTransportProtocol::sendProbeInterest(uint32_t seq) { sendInterest(*interest_name); } +void RTCTransportProtocol::sendInterestForTimeout(uint32_t seq) { + if (!isRunning() && !is_first_) return; + + Name *interest_name = nullptr; + socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME, + &interest_name); + + // we got a timeout for this packet so it is not pending anymore + interest_name->setSuffix(seq); + state_->onSendNewInterest(interest_name); + sendInterest(*interest_name); +} + void RTCTransportProtocol::scheduleNextInterests() { DLOG_IF(INFO, VLOG_IS_ON(3)) << "Schedule next interests"; @@ -475,9 +493,9 @@ void RTCTransportProtocol::scheduleNextInterests() { } // skip received packets - if (indexer_verifier_->checkNextSuffix() <= - state_->getHighestSeqReceivedInOrder()) { - indexer_verifier_->jumpToIndex(state_->getHighestSeqReceivedInOrder() + 1); + uint32_t max_received = state_->getHighestSeqReceivedInOrder(); + if (indexer_verifier_->checkNextSuffix() <= max_received) { + indexer_verifier_->jumpToIndex(max_received + 1); } uint32_t sent_interests = 0; @@ -495,7 +513,6 @@ void RTCTransportProtocol::scheduleNextInterests() { << "In while loop. Window size: " << current_sync_win_; uint32_t next_seg = indexer_verifier_->getNextSuffix(); - name->setSuffix(next_seg); // send the packet only if: @@ -586,7 +603,6 @@ void RTCTransportProtocol::onInterestTimeout(Interest::Ptr &interest, } timeouts_or_nacks_.insert(segment_number); - if (TRANSPORT_EXPECT_TRUE(state_->isProducerActive()) && segment_number <= state_->getHighestSeqReceived()) { // we retransmit packets only if the producer is active, otherwise we @@ -627,11 +643,11 @@ void RTCTransportProtocol::onInterestTimeout(Interest::Ptr &interest, << "On timeout next seg = " << indexer_verifier_->checkNextSuffix() << ", jump to " << segment_number; // add an extra space in the window - current_sync_win_++; indexer_verifier_->jumpToIndex(segment_number); } state_->onTimeout(segment_number, false); + sendInterestForTimeout(segment_number); scheduleNextInterests(); } @@ -672,7 +688,6 @@ void RTCTransportProtocol::onNack(const ContentObject &content_object) { if (tn_it != timeouts_or_nacks_.end()) timeouts_or_nacks_.erase(tn_it); state_->onJumpForward(production_seg); - verifier_->onJumpForward(production_seg); // the client is asking for content in the past // switch to catch up state and increase the window // this is true only if the packet is not an RTX @@ -821,7 +836,8 @@ void RTCTransportProtocol::onContentObjectReceived( // Check if the packet is a retransmission if (ldr_->isRtx(segment_number) && state != PacketState::RECEIVED) { if (is_data || is_manifest) { - state_->onPacketRecoveredRtx(segment_number); + uint64_t rtt = ldr_->getRtxRtt(segment_number); + state_->onPacketRecoveredRtx(content_object, rtt); if (*on_content_object_input_) { (*on_content_object_input_)(*socket_->getInterface(), content_object); @@ -842,7 +858,7 @@ void RTCTransportProtocol::onContentObjectReceived( } if (is_fec) { - state_->onFecPacketRecoveredRtx(segment_number); + state_->onFecPacketRecoveredRtx(content_object); } } @@ -920,7 +936,7 @@ void RTCTransportProtocol::sendStatsToApp( stats_->updateAverageWindowSize(state_->getPendingInterestNumber()); stats_->updateLossRatio(state_->getPerSecondLossRate()); uint64_t rtt = state_->getAvgRTT(); - stats_->updateAverageRtt(utils::SteadyTime::Milliseconds(rtt)); + stats_->updateAverageRtt(utils::SteadyTime::Microseconds(rtt * 1000)); stats_->updateQueuingDelay(state_->getQueuing()); stats_->updateLostData(lost_data); @@ -960,9 +976,10 @@ void RTCTransportProtocol::decodePacket(ContentObject &content_object, DLOG_IF(INFO, VLOG_IS_ON(4)) << "Send packet " << content_object.getName() << " to FEC decoder"; - uint32_t offset = is_manifest - ? content_object.headerSize() - : content_object.headerSize() + rtc::DATA_HEADER_SIZE; + uint32_t offset = + is_manifest + ? (uint32_t)content_object.headerSize() + : (uint32_t)(content_object.headerSize() + rtc::DATA_HEADER_SIZE); uint32_t metadata = static_cast<uint32_t>(content_object.getPayloadType()); fec_decoder_->onDataPacket(content_object, offset, metadata); @@ -1016,7 +1033,7 @@ void RTCTransportProtocol::onFecPackets(fec::BufferArray &packets) { processManifest(*interest, *content_object); } - state_->onPacketRecoveredFec(seq_number, buffer->length()); + state_->onPacketRecoveredFec(seq_number, (uint32_t)buffer->length()); ldr_->onPacketRecoveredFec(seq_number); if (payload_type == PayloadType::DATA) { @@ -1038,11 +1055,11 @@ void RTCTransportProtocol::processManifest(Interest &interest, ContentObject::Ptr RTCTransportProtocol::removeFecHeader( const ContentObject &content_object) { - if (!fec_decoder_ || !fec_decoder_->getFecHeaderSize()) { + if (!fec_decoder_ || !fec_decoder_->getFecHeaderSize(false)) { return nullptr; } - size_t fec_header_size = fec_decoder_->getFecHeaderSize(); + size_t fec_header_size = fec_decoder_->getFecHeaderSize(false); const uint8_t *payload = content_object.data() + content_object.headerSize() + fec_header_size; size_t payload_size = content_object.payloadSize() - fec_header_size; diff --git a/libtransport/src/protocols/rtc/rtc.h b/libtransport/src/protocols/rtc/rtc.h index 3763f33c7..a8a474216 100644 --- a/libtransport/src/protocols/rtc/rtc.h +++ b/libtransport/src/protocols/rtc/rtc.h @@ -44,7 +44,7 @@ class RTCTransportProtocol : public TransportProtocol { void resume() override; - std::size_t transportHeaderLength() override; + std::size_t transportHeaderLength(bool isFEC) override; auto shared_from_this() { return utils::shared_from(this); } @@ -69,6 +69,7 @@ class RTCTransportProtocol : public TransportProtocol { // packet functions void sendRtxInterest(uint32_t seq); void sendProbeInterest(uint32_t seq); + void sendInterestForTimeout(uint32_t seq); void scheduleNextInterests() override; void onInterestTimeout(Interest::Ptr &interest, const Name &name) override; void onNack(const ContentObject &content_object); diff --git a/libtransport/src/protocols/rtc/rtc_consts.h b/libtransport/src/protocols/rtc/rtc_consts.h index 96e39d07e..29b5a3a12 100644 --- a/libtransport/src/protocols/rtc/rtc_consts.h +++ b/libtransport/src/protocols/rtc/rtc_consts.h @@ -54,7 +54,7 @@ const uint32_t PACING_WAIT = 1000; // usec to wait betwing two pacing batch. As const uint32_t MAX_RTX_IN_BATCH = 10; // max rtx to send in loop // packet const -const uint32_t RTC_INTEREST_LIFETIME = 2000; +const uint32_t RTC_INTEREST_LIFETIME = 4000; // probes sequence range const uint32_t MIN_PROBE_SEQ = 0xefffffff; @@ -93,6 +93,7 @@ const double CATCH_UP_WIN_INCREMENT = 1.2; // used in rate control const double WIN_DECREASE_FACTOR = 0.5; const double WIN_INCREASE_FACTOR = 1.5; +const uint32_t MIN_PROD_RATE_SHARING_MODE = 125000; // 1Mbps in bytes // round in congestion const double ROUNDS_BEFORE_TAKE_ACTION = 5; @@ -120,14 +121,14 @@ const uint64_t MAX_TIMER_RTX = ~0; const uint32_t SENTINEL_TIMER_INTERVAL = 100; // ms const uint32_t MAX_RTX_WITH_SENTINEL = 10; // packets const double CATCH_UP_RTT_INCREMENT = 1.2; -const double MAX_RESIDUAL_LOSS_RATE = 2.0; // % -const uint32_t WAIT_BEFORE_FEC_UPDATE = ROUNDS_PER_SEC * 5; +const double MAX_RESIDUAL_LOSS_RATE = 1.0; // % +const uint32_t WAIT_BEFORE_FEC_UPDATE = ROUNDS_PER_SEC; +const uint32_t MAX_RTT_BEFORE_FEC = 60; // ms // used by producer const uint32_t PRODUCER_STATS_INTERVAL = 200; // ms const uint32_t MIN_PRODUCTION_RATE = 25; // pps, equal to min window * // rounds in a second -const uint32_t NACK_DELAY = 1500; // ms const uint32_t FEC_PACING_TIME = 5; // ms // aggregated data consts @@ -139,6 +140,73 @@ const uint32_t AGGREGATED_PACKETS_TIMER = 2; // ms const uint32_t MAX_RTT = 200; // ms const double MAX_RESIDUAL_LOSSES = 0.05; // % +const uint8_t FEC_MATRIX[64][10] = { + {1, 2, 2, 2, 3, 3, 4, 5, 5, 6}, // k = 1 + {1, 2, 3, 3, 4, 5, 5, 6, 7, 9}, + {2, 2, 3, 4, 5, 6, 7, 8, 9, 11}, + {2, 3, 4, 5, 5, 7, 8, 9, 11, 13}, + {2, 3, 4, 5, 6, 7, 9, 10, 12, 14}, // k = 5 + {2, 3, 4, 6, 7, 8, 10, 12, 14, 16}, + {2, 4, 5, 6, 8, 9, 11, 13, 15, 18}, + {3, 4, 5, 7, 8, 10, 12, 14, 16, 19}, + {3, 4, 6, 7, 9, 11, 13, 15, 18, 21}, + {3, 4, 6, 8, 9, 11, 14, 16, 19, 23}, // k = 10 + {3, 5, 6, 8, 10, 12, 14, 17, 20, 24}, + {3, 5, 7, 8, 10, 13, 15, 18, 21, 26}, + {3, 5, 7, 9, 11, 13, 16, 19, 23, 27}, + {3, 5, 7, 9, 12, 14, 17, 20, 24, 28}, + {4, 6, 8, 10, 12, 15, 18, 21, 25, 30}, // k = 15 + {4, 6, 8, 10, 13, 15, 19, 22, 26, 31}, + {4, 6, 8, 11, 13, 16, 19, 23, 27, 33}, + {4, 6, 9, 11, 14, 17, 20, 24, 29, 34}, + {4, 6, 9, 11, 14, 17, 21, 25, 30, 35}, + {4, 7, 9, 12, 15, 18, 22, 26, 31, 37}, // k = 20 + {4, 7, 9, 12, 15, 19, 22, 27, 32, 38}, + {4, 7, 10, 13, 16, 19, 23, 28, 33, 40}, + {5, 7, 10, 13, 16, 20, 24, 29, 34, 41}, + {5, 7, 10, 13, 17, 20, 25, 30, 35, 42}, + {5, 8, 11, 14, 17, 21, 26, 31, 37, 44}, // k = 25 + {5, 8, 11, 14, 18, 22, 26, 31, 38, 45}, + {5, 8, 11, 15, 18, 22, 27, 32, 39, 46}, + {5, 8, 11, 15, 19, 23, 28, 33, 40, 48}, + {5, 8, 12, 15, 19, 24, 28, 34, 41, 49}, + {5, 9, 12, 16, 20, 24, 29, 35, 42, 50}, // k = 30 + {5, 9, 12, 16, 20, 25, 30, 36, 43, 51}, + {5, 9, 13, 16, 21, 25, 31, 37, 44, 53}, + {6, 9, 13, 17, 21, 26, 31, 38, 45, 54}, + {6, 9, 13, 17, 22, 26, 32, 39, 46, 55}, + {6, 10, 13, 17, 22, 27, 33, 40, 47, 57}, // k = 35 + {6, 10, 14, 18, 22, 28, 34, 40, 48, 58}, + {6, 10, 14, 18, 23, 28, 34, 41, 49, 59}, + {6, 10, 14, 19, 23, 29, 35, 42, 50, 60}, + {6, 10, 14, 19, 24, 29, 36, 43, 52, 62}, + {6, 10, 15, 19, 24, 30, 36, 44, 53, 63}, // k = 40 + {6, 11, 15, 20, 25, 31, 37, 45, 54, 64}, + {6, 11, 15, 20, 25, 31, 38, 46, 55, 65}, + {7, 11, 15, 20, 26, 32, 39, 46, 56, 67}, + {7, 11, 16, 21, 26, 32, 39, 47, 57, 68}, + {7, 11, 16, 21, 27, 33, 40, 48, 58, 69}, // k = 45 + {7, 11, 16, 21, 27, 33, 41, 49, 59, 70}, + {7, 12, 16, 22, 27, 34, 41, 50, 60, 72}, + {7, 12, 17, 22, 28, 34, 42, 51, 61, 73}, + {7, 12, 17, 22, 28, 35, 43, 52, 62, 74}, + {7, 12, 17, 23, 29, 36, 43, 52, 63, 75}, // k = 50 + {7, 12, 17, 23, 29, 36, 44, 53, 64, 77}, + {7, 12, 18, 23, 30, 37, 45, 54, 65, 78}, + {7, 13, 18, 24, 30, 37, 45, 55, 66, 79}, + {8, 13, 18, 24, 31, 38, 46, 56, 67, 80}, + {8, 13, 18, 24, 31, 38, 47, 57, 68, 82}, // k = 55 + {8, 13, 19, 25, 31, 39, 47, 57, 69, 83}, + {8, 13, 19, 25, 32, 39, 48, 58, 70, 84}, + {8, 13, 19, 25, 32, 40, 49, 59, 71, 85}, + {8, 14, 19, 26, 33, 41, 50, 60, 72, 86}, + {8, 14, 20, 26, 33, 41, 50, 61, 73, 88}, // k = 60 + {8, 14, 20, 26, 34, 42, 51, 61, 74, 89}, + {8, 14, 20, 27, 34, 42, 52, 62, 75, 90}, + {8, 14, 20, 27, 34, 43, 52, 63, 76, 91}, + {8, 14, 21, 27, 35, 43, 53, 64, 77, 92}, // k = 64 +}; + } // namespace rtc } // namespace protocol diff --git a/libtransport/src/protocols/rtc/rtc_data_path.cc b/libtransport/src/protocols/rtc/rtc_data_path.cc index b3abf5ea8..a421396b1 100644 --- a/libtransport/src/protocols/rtc/rtc_data_path.cc +++ b/libtransport/src/protocols/rtc/rtc_data_path.cc @@ -91,6 +91,8 @@ void RTCDataPath::insertRttSample( rtt_samples_ = 0; last_avg_rtt_compute_ = now; } + + received_packets_++; } void RTCDataPath::insertOwdSample(int64_t owd) { @@ -115,10 +117,6 @@ void RTCDataPath::insertOwdSample(int64_t owd) { int64_t diff = std::abs(owd - last_owd_); last_owd_ = owd; jitter_ += (1.0 / 16.0) * ((double)diff - jitter_); - - // owd is computed only for valid data packets so we count only - // this for decide if we recevie traffic or not - received_packets_++; } void RTCDataPath::computeInterArrivalGap(uint32_t segment_number) { @@ -150,12 +148,17 @@ double RTCDataPath::getInterArrivalGap() { return avg_inter_arrival_; } -bool RTCDataPath::isActive() { +bool RTCDataPath::isValidProducer() { if (received_nacks_ && rounds_without_packets_ < MAX_ROUNDS_WITHOUT_PKTS) return true; return false; } +bool RTCDataPath::isActive() { + if (rounds_without_packets_ < MAX_ROUNDS_WITHOUT_PKTS) return true; + return false; +} + bool RTCDataPath::pathToProducer() { if (received_nacks_) return true; return false; diff --git a/libtransport/src/protocols/rtc/rtc_data_path.h b/libtransport/src/protocols/rtc/rtc_data_path.h index 5afbbb87f..ba5201fe8 100644 --- a/libtransport/src/protocols/rtc/rtc_data_path.h +++ b/libtransport/src/protocols/rtc/rtc_data_path.h @@ -49,8 +49,9 @@ class RTCDataPath { double getQueuingDealy(); double getInterArrivalGap(); double getJitter(); - bool isActive(); - bool pathToProducer(); + bool isActive(); // pakets recevied from this path in the last rounds + bool pathToProducer(); // path from a producer + bool isValidProducer(); // path from a producer that is also active uint64_t getLastPacketTS(); uint32_t getPacketsLastRound(); diff --git a/libtransport/src/protocols/rtc/rtc_forwarding_strategy.cc b/libtransport/src/protocols/rtc/rtc_forwarding_strategy.cc index c6bc751e6..4bbd7eac0 100644 --- a/libtransport/src/protocols/rtc/rtc_forwarding_strategy.cc +++ b/libtransport/src/protocols/rtc/rtc_forwarding_strategy.cc @@ -14,6 +14,7 @@ */ #include <hicn/transport/interfaces/notification.h> +#include <protocols/rtc/rtc_consts.h> #include <protocols/rtc/rtc_forwarding_strategy.h> namespace transport { @@ -24,8 +25,13 @@ namespace rtc { using namespace transport::interface; +const double FWD_MAX_QUEUE = 30.0; // ms +const double FWD_MAX_RTT = MAX_RTT_BEFORE_FEC; // ms +const double FWD_MAX_LOSS_RATE = 0.1; + RTCForwardingStrategy::RTCForwardingStrategy() - : init_(false), + : low_rate_app_(false), + init_(false), forwarder_set_(false), selected_strategy_(NONE), current_strategy_(NONE), @@ -42,17 +48,56 @@ void RTCForwardingStrategy::setCallback( void RTCForwardingStrategy::initFwdStrategy( std::shared_ptr<core::Portal> portal, core::Prefix& prefix, RTCState* state, - strategy_t strategy) { - init_ = true; - selected_strategy_ = strategy; - if (strategy == BOTH) - current_strategy_ = BEST_PATH; - else - current_strategy_ = strategy; - rounds_since_last_set_ = 0; - prefix_ = prefix; - portal_ = portal; - state_ = state; + interface::RtcTransportRecoveryStrategies strategy) { + switch (strategy) { + case interface::RtcTransportRecoveryStrategies::LOW_RATE_AND_BESTPATH: + init_ = true; + low_rate_app_ = true; + selected_strategy_ = BEST_PATH; + current_strategy_ = BEST_PATH; + break; + case interface::RtcTransportRecoveryStrategies::LOW_RATE_AND_REPLICATION: + init_ = true; + low_rate_app_ = true; + selected_strategy_ = REPLICATION; + current_strategy_ = REPLICATION; + break; + case interface::RtcTransportRecoveryStrategies:: + LOW_RATE_AND_ALL_FWD_STRATEGIES: + init_ = true; + low_rate_app_ = true; + selected_strategy_ = BEST_PATH; + current_strategy_ = BEST_PATH; + break; + case interface::RtcTransportRecoveryStrategies::DELAY_AND_BESTPATH: + init_ = true; + low_rate_app_ = false; + selected_strategy_ = BEST_PATH; + current_strategy_ = BEST_PATH; + break; + case interface::RtcTransportRecoveryStrategies::DELAY_AND_REPLICATION: + init_ = true; + low_rate_app_ = false; + selected_strategy_ = REPLICATION; + current_strategy_ = REPLICATION; + break; + case interface::RtcTransportRecoveryStrategies::RECOVERY_OFF: + case interface::RtcTransportRecoveryStrategies::RTX_ONLY: + case interface::RtcTransportRecoveryStrategies::FEC_ONLY: + case interface::RtcTransportRecoveryStrategies::DELAY_BASED: + case interface::RtcTransportRecoveryStrategies::LOW_RATE: + case interface::RtcTransportRecoveryStrategies::FEC_ONLY_LOW_RES_LOSSES: + default: + // fwd strategies are not used + init_ = false; + } + + if (init_) { + rounds_since_last_set_ = 0; + prefix_ = prefix; + portal_ = portal; + state_ = state; + } } void RTCForwardingStrategy::checkStrategy() { @@ -99,16 +144,35 @@ void RTCForwardingStrategy::checkStrategyBestPath() { return; } - uint8_t qs = state_->getQualityScore(); + if (low_rate_app_) { + // this is used for gaming + uint8_t qs = state_->getQualityScore(); - if (qs >= 4 || rounds_since_last_set_ < 25) { // wait a least 5 sec - // between each switch - rounds_since_last_set_++; - return; - } + if (qs >= 4 || rounds_since_last_set_ < 25) { // wait a least 5 sec + // between each switch + rounds_since_last_set_++; + return; + } - // try to switch path - setStrategy(BEST_PATH); + // try to switch path + setStrategy(BEST_PATH); + } else { + if (rounds_since_last_set_ < 25) { // wait a least 5 sec + // between each switch + rounds_since_last_set_++; + return; + } + + double queue = state_->getQueuing(); + double rtt = state_->getAvgRTT(); + double loss_rate = state_->getPerSecondLossRate(); + + if (queue >= FWD_MAX_QUEUE || rtt >= FWD_MAX_RTT || + loss_rate > FWD_MAX_LOSS_RATE) { + // try to switch path + setStrategy(BEST_PATH); + } + } } void RTCForwardingStrategy::checkStrategyReplication() { @@ -133,7 +197,7 @@ void RTCForwardingStrategy::checkStrategyBoth() { // TODO // for the moment we use only best path. - // but later: + // for later: // 1. if both paths are bad use replication // 2. while using replication compute the effectiveness. if the majority of // the packets are coming from a single path, try to use bestpath diff --git a/libtransport/src/protocols/rtc/rtc_forwarding_strategy.h b/libtransport/src/protocols/rtc/rtc_forwarding_strategy.h index 9825877fd..c2227e09f 100644 --- a/libtransport/src/protocols/rtc/rtc_forwarding_strategy.h +++ b/libtransport/src/protocols/rtc/rtc_forwarding_strategy.h @@ -41,7 +41,7 @@ class RTCForwardingStrategy { void initFwdStrategy(std::shared_ptr<core::Portal> portal, core::Prefix& prefix, RTCState* state, - strategy_t strategy); + interface::RtcTransportRecoveryStrategies strategy); void checkStrategy(); void setCallback(interface::StrategyCallback&& callback); @@ -56,6 +56,10 @@ class RTCForwardingStrategy { std::array<std::string, 4> string_strategies_ = {"bestpath", "replication", "both", "none"}; + bool low_rate_app_; // if set to true the best path strategy will + // trigger a path switch based on the quality + // score, otherwise it will use the RTT, + // queuing delay and loss rate bool init_; // true if all val are initializes bool forwarder_set_; // true if the strategy is been set at least // once diff --git a/libtransport/src/protocols/rtc/rtc_ldr.cc b/libtransport/src/protocols/rtc/rtc_ldr.cc index abf6cda2c..6e88a8636 100644 --- a/libtransport/src/protocols/rtc/rtc_ldr.cc +++ b/libtransport/src/protocols/rtc/rtc_ldr.cc @@ -37,16 +37,24 @@ RTCLossDetectionAndRecovery::RTCLossDetectionAndRecovery( interface::RtcTransportRecoveryStrategies type, RecoveryStrategy::SendRtxCallback &&callback, interface::StrategyCallback &&external_callback) { - rs_type_ = type; if (type == interface::RtcTransportRecoveryStrategies::RECOVERY_OFF) { rs_ = std::make_shared<RecoveryStrategyRecoveryOff>( - indexer, std::move(callback), io_service, std::move(external_callback)); - } else if (type == interface::RtcTransportRecoveryStrategies::DELAY_BASED) { + indexer, std::move(callback), io_service, type, + std::move(external_callback)); + } else if (type == interface::RtcTransportRecoveryStrategies::DELAY_BASED || + type == interface::RtcTransportRecoveryStrategies:: + DELAY_AND_BESTPATH || + type == interface::RtcTransportRecoveryStrategies:: + DELAY_AND_REPLICATION) { rs_ = std::make_shared<RecoveryStrategyDelayBased>( - indexer, std::move(callback), io_service, std::move(external_callback)); - } else if (type == interface::RtcTransportRecoveryStrategies::FEC_ONLY) { + indexer, std::move(callback), io_service, type, + std::move(external_callback)); + } else if (type == interface::RtcTransportRecoveryStrategies::FEC_ONLY || + type == interface::RtcTransportRecoveryStrategies:: + FEC_ONLY_LOW_RES_LOSSES) { rs_ = std::make_shared<RecoveryStrategyFecOnly>( - indexer, std::move(callback), io_service, std::move(external_callback)); + indexer, std::move(callback), io_service, type, + std::move(external_callback)); } else if (type == interface::RtcTransportRecoveryStrategies::LOW_RATE || type == interface::RtcTransportRecoveryStrategies:: LOW_RATE_AND_BESTPATH || @@ -55,12 +63,14 @@ RTCLossDetectionAndRecovery::RTCLossDetectionAndRecovery( type == interface::RtcTransportRecoveryStrategies:: LOW_RATE_AND_ALL_FWD_STRATEGIES) { rs_ = std::make_shared<RecoveryStrategyLowRate>( - indexer, std::move(callback), io_service, std::move(external_callback)); + indexer, std::move(callback), io_service, type, + std::move(external_callback)); } else { // default - rs_type_ = interface::RtcTransportRecoveryStrategies::RTX_ONLY; + type = interface::RtcTransportRecoveryStrategies::RTX_ONLY; rs_ = std::make_shared<RecoveryStrategyRtxOnly>( - indexer, std::move(callback), io_service, std::move(external_callback)); + indexer, std::move(callback), io_service, type, + std::move(external_callback)); } } @@ -68,15 +78,21 @@ RTCLossDetectionAndRecovery::~RTCLossDetectionAndRecovery() {} void RTCLossDetectionAndRecovery::changeRecoveryStrategy( interface::RtcTransportRecoveryStrategies type) { - if (type == rs_type_) return; + if (type == rs_->getType()) return; - rs_type_ = type; + rs_->updateType(type); if (type == interface::RtcTransportRecoveryStrategies::RECOVERY_OFF) { rs_ = std::make_shared<RecoveryStrategyRecoveryOff>(std::move(*(rs_.get()))); - } else if (type == interface::RtcTransportRecoveryStrategies::DELAY_BASED) { + } else if (type == interface::RtcTransportRecoveryStrategies::DELAY_BASED || + type == interface::RtcTransportRecoveryStrategies:: + DELAY_AND_BESTPATH || + type == interface::RtcTransportRecoveryStrategies:: + DELAY_AND_REPLICATION) { rs_ = std::make_shared<RecoveryStrategyDelayBased>(std::move(*(rs_.get()))); - } else if (type == interface::RtcTransportRecoveryStrategies::FEC_ONLY) { + } else if (type == interface::RtcTransportRecoveryStrategies::FEC_ONLY || + type == interface::RtcTransportRecoveryStrategies:: + FEC_ONLY_LOW_RES_LOSSES) { rs_ = std::make_shared<RecoveryStrategyFecOnly>(std::move(*(rs_.get()))); } else if (type == interface::RtcTransportRecoveryStrategies::LOW_RATE || type == interface::RtcTransportRecoveryStrategies:: @@ -116,14 +132,15 @@ bool RTCLossDetectionAndRecovery::onDataPacketReceived( uint32_t seq = content_object.getName().getSuffix(); bool is_rtx = rs_->isRtx(seq); rs_->receivedPacket(seq); + bool ret = false; DLOG_IF(INFO, VLOG_IS_ON(3)) << "received data. add from " - << rs_->getState()->getHighestSeqReceivedInOrder() + 1 << " to " << seq; + << rs_->getState()->getHighestSeqReceived() + 1 << " to " << seq; if (!is_rtx) - return detectLoss(rs_->getState()->getHighestSeqReceivedInOrder() + 1, seq, - false); + ret = detectLoss(rs_->getState()->getHighestSeqReceived() + 1, seq, false); - return false; + rs_->getState()->updateHighestSeqReceived(seq); + return ret; } bool RTCLossDetectionAndRecovery::onNackPacketReceived( @@ -141,10 +158,9 @@ bool RTCLossDetectionAndRecovery::onNackPacketReceived( // may got lost and we should ask them rs_->receivedPacket(seq); - DLOG_IF(INFO, VLOG_IS_ON(3)) - << "received nack. add from " - << rs_->getState()->getHighestSeqReceivedInOrder() + 1 << " to " - << production_seq; + DLOG_IF(INFO, VLOG_IS_ON(3)) << "received nack. add from " + << rs_->getState()->getHighestSeqReceived() + 1 + << " to " << production_seq; // if it is a future nack store it in the list set of nacked seq if (production_seq <= seq) rs_->receivedFutureNack(seq); @@ -152,7 +168,7 @@ bool RTCLossDetectionAndRecovery::onNackPacketReceived( // call the detectLoss function using the probe flag = true. in fact the // losses detected using nacks are the same as the one detected using probes, // we should not increase the loss counter - return detectLoss(rs_->getState()->getHighestSeqReceivedInOrder() + 1, + return detectLoss(rs_->getState()->getHighestSeqReceived() + 1, production_seq, true); } @@ -164,12 +180,11 @@ bool RTCLossDetectionAndRecovery::onProbePacketReceived( uint32_t production_seq = RTCState::getProbeParams(probe).prod_seg; - DLOG_IF(INFO, VLOG_IS_ON(3)) - << "received probe. add from " - << rs_->getState()->getHighestSeqReceivedInOrder() + 1 << " to " - << production_seq; + DLOG_IF(INFO, VLOG_IS_ON(3)) << "received probe. add from " + << rs_->getState()->getHighestSeqReceived() + 1 + << " to " << production_seq; - return detectLoss(rs_->getState()->getHighestSeqReceivedInOrder() + 1, + return detectLoss(rs_->getState()->getHighestSeqReceived() + 1, production_seq, true); } @@ -183,8 +198,8 @@ bool RTCLossDetectionAndRecovery::detectLoss(uint32_t start, uint32_t stop, } // skip received or lost packets - if (start <= rs_->getState()->getHighestSeqReceivedInOrder()) { - start = rs_->getState()->getHighestSeqReceivedInOrder() + 1; + if (start <= rs_->getState()->getHighestSeqReceived()) { + start = rs_->getState()->getHighestSeqReceived() + 1; } bool loss_detected = false; diff --git a/libtransport/src/protocols/rtc/rtc_ldr.h b/libtransport/src/protocols/rtc/rtc_ldr.h index 7f683eaa6..24f22ffed 100644 --- a/libtransport/src/protocols/rtc/rtc_ldr.h +++ b/libtransport/src/protocols/rtc/rtc_ldr.h @@ -47,6 +47,7 @@ class RTCLossDetectionAndRecovery void setFecParams(uint32_t n, uint32_t k) { rs_->setFecParams(n, k); } + void setContentSharingMode() { rs_->setContentSharingMode(); } void turnOnRecovery() { rs_->turnOnRecovery(); } bool isRtxOn() { return rs_->isRtxOn(); } @@ -68,11 +69,12 @@ class RTCLossDetectionAndRecovery return rs_->isPossibleLossWithNoRtx(seq); } + uint64_t getRtxRtt(uint32_t seq) { return rs_->getRtxRtt(seq); } + private: // returns true if a loss is detected, false otherwise bool detectLoss(uint32_t start, uint32_t stop, bool recv_probe); - interface::RtcTransportRecoveryStrategies rs_type_; std::shared_ptr<RecoveryStrategy> rs_; }; diff --git a/libtransport/src/protocols/rtc/rtc_packet.h b/libtransport/src/protocols/rtc/rtc_packet.h index 391aedfc6..ffbbd78fd 100644 --- a/libtransport/src/protocols/rtc/rtc_packet.h +++ b/libtransport/src/protocols/rtc/rtc_packet.h @@ -52,6 +52,8 @@ #include <hicn/transport/portability/win_portability.h> #endif +#include <hicn/transport/portability/endianess.h> + #include <cstring> namespace transport { @@ -60,24 +62,6 @@ namespace protocol { namespace rtc { -inline uint64_t _ntohll(const uint64_t *input) { - uint64_t return_val; - uint8_t *tmp = (uint8_t *)&return_val; - - tmp[0] = (uint8_t)(*input >> 56); - tmp[1] = (uint8_t)(*input >> 48); - tmp[2] = (uint8_t)(*input >> 40); - tmp[3] = (uint8_t)(*input >> 32); - tmp[4] = (uint8_t)(*input >> 24); - tmp[5] = (uint8_t)(*input >> 16); - tmp[6] = (uint8_t)(*input >> 8); - tmp[7] = (uint8_t)(*input >> 0); - - return return_val; -} - -inline uint64_t _htonll(const uint64_t *input) { return (_ntohll(input)); } - const uint32_t DATA_HEADER_SIZE = 12; // bytes // XXX: sizeof(data_packet_t) is 16 // beacuse of padding @@ -87,11 +71,19 @@ struct data_packet_t { uint64_t timestamp; uint32_t prod_rate; - inline uint64_t getTimestamp() const { return _ntohll(×tamp); } - inline void setTimestamp(uint64_t time) { timestamp = _htonll(&time); } + inline uint64_t getTimestamp() const { + return portability::net_to_host(timestamp); + } + inline void setTimestamp(uint64_t time) { + timestamp = portability::host_to_net(time); + } - inline uint32_t getProductionRate() const { return ntohl(prod_rate); } - inline void setProductionRate(uint32_t rate) { prod_rate = htonl(rate); } + inline uint32_t getProductionRate() const { + return portability::net_to_host(prod_rate); + } + inline void setProductionRate(uint32_t rate) { + prod_rate = portability::host_to_net(rate); + } }; struct nack_packet_t { @@ -99,14 +91,26 @@ struct nack_packet_t { uint32_t prod_rate; uint32_t prod_seg; - inline uint64_t getTimestamp() const { return _ntohll(×tamp); } - inline void setTimestamp(uint64_t time) { timestamp = _htonll(&time); } + inline uint64_t getTimestamp() const { + return portability::net_to_host(timestamp); + } + inline void setTimestamp(uint64_t time) { + timestamp = portability::host_to_net(time); + } - inline uint32_t getProductionRate() const { return ntohl(prod_rate); } - inline void setProductionRate(uint32_t rate) { prod_rate = htonl(rate); } + inline uint32_t getProductionRate() const { + return portability::net_to_host(prod_rate); + } + inline void setProductionRate(uint32_t rate) { + prod_rate = portability::host_to_net(rate); + } - inline uint32_t getProductionSegment() const { return ntohl(prod_seg); } - inline void setProductionSegment(uint32_t seg) { prod_seg = htonl(seg); } + inline uint32_t getProductionSegment() const { + return portability::net_to_host(prod_seg); + } + inline void setProductionSegment(uint32_t seg) { + prod_seg = portability::host_to_net(seg); + } }; class AggrPktHeader { @@ -225,7 +229,7 @@ class AggrPktHeader { return (uint16_t) * (buf_ + pkt_index); } else { // 16 bits uint16_t *buf_16 = (uint16_t *)buf_; - return ntohs(*(buf_16 + pkt_index)); + return portability::net_to_host(*(buf_16 + pkt_index)); } } @@ -235,7 +239,7 @@ class AggrPktHeader { *(buf_ + pkt_index) = (uint8_t)len; } else { // 16 bits uint16_t *buf_16 = (uint16_t *)buf_; - *(buf_16 + pkt_index) = htons(len); + *(buf_16 + pkt_index) = portability::host_to_net(len); } } diff --git a/libtransport/src/protocols/rtc/rtc_reassembly.cc b/libtransport/src/protocols/rtc/rtc_reassembly.cc index 992bab50e..b1b0fcaba 100644 --- a/libtransport/src/protocols/rtc/rtc_reassembly.cc +++ b/libtransport/src/protocols/rtc/rtc_reassembly.cc @@ -40,7 +40,7 @@ void RtcReassembly::reassemble(core::ContentObject& content_object) { auto read_buffer = content_object.getPayload(); DLOG_IF(INFO, VLOG_IS_ON(3)) << "Size of payload: " << read_buffer->length(); - read_buffer->trimStart(transport_protocol_->transportHeaderLength()); + read_buffer->trimStart(transport_protocol_->transportHeaderLength(false)); if (data_aggregation_) { rtc::AggrPktHeader hdr((uint8_t*)read_buffer->data()); diff --git a/libtransport/src/protocols/rtc/rtc_recovery_strategy.cc b/libtransport/src/protocols/rtc/rtc_recovery_strategy.cc index 66ae5086c..257fdd09b 100644 --- a/libtransport/src/protocols/rtc/rtc_recovery_strategy.cc +++ b/libtransport/src/protocols/rtc/rtc_recovery_strategy.cc @@ -29,8 +29,12 @@ using namespace transport::interface; RecoveryStrategy::RecoveryStrategy( Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service, - bool use_rtx, bool use_fec, interface::StrategyCallback &&external_callback) - : recovery_on_(false), + bool use_rtx, bool use_fec, + interface::RtcTransportRecoveryStrategies rs_type, + interface::StrategyCallback &&external_callback) + : rs_type_(rs_type), + recovery_on_(false), + content_sharing_mode_(false), rtx_during_fec_(0), next_rtx_timer_(MAX_TIMER_RTX), send_rtx_callback_(std::move(callback)), @@ -43,7 +47,9 @@ RecoveryStrategy::RecoveryStrategy( } RecoveryStrategy::RecoveryStrategy(RecoveryStrategy &&rs) - : rtx_during_fec_(0), + : rs_type_(rs.rs_type_), + content_sharing_mode_(rs.content_sharing_mode_), + rtx_during_fec_(0), rtx_state_(std::move(rs.rtx_state_)), rtx_timers_(std::move(rs.rtx_timers_)), recover_with_fec_(std::move(rs.recover_with_fec_)), @@ -64,25 +70,52 @@ RecoveryStrategy::RecoveryStrategy(RecoveryStrategy &&rs) RecoveryStrategy::~RecoveryStrategy() {} void RecoveryStrategy::setFecParams(uint32_t n, uint32_t k) { + // if rs_type == FEC_ONLY_LOW_RES_LOSSES max k == 64 n_ = n; k_ = k; // XXX for the moment we go in steps of 5% loss rate. - // max loss rate = 95% + uint32_t i = 0; for (uint32_t loss_rate = 5; loss_rate < 100; loss_rate += 5) { - double dec_loss_rate = (double)(loss_rate + 5) / 100.0; - double exp_losses = (double)k_ * dec_loss_rate; - uint32_t fec_to_ask = ceil(exp_losses / (1 - dec_loss_rate)); - - fec_state_ f; - f.fec_to_ask = std::min(fec_to_ask, (n_ - k_)); - f.last_update = round_id_; - f.avg_residual_losses = 0.0; - f.consecutive_use = 0; - fec_per_loss_rate_.push_back(f); + uint32_t fec_to_ask = 0; + if (n_ != 0 && k_ != 0) { + if (rs_type_ == + interface::RtcTransportRecoveryStrategies::FEC_ONLY_LOW_RES_LOSSES) { + // the max loss rate in the matrix is 50% + uint32_t index = i; + if (i > 9) index = 9; + fec_to_ask = FEC_MATRIX[k_ - 1][index]; + } else { + double dec_loss_rate = (double)(loss_rate + 5); + if (dec_loss_rate == 100.0) dec_loss_rate = 95.0; + dec_loss_rate = dec_loss_rate / 100.0; + double exp_losses = ceil((double)k_ * dec_loss_rate); + fec_to_ask = ceil((exp_losses / (1 - dec_loss_rate)) * 1.25); + } + } + fec_to_ask = std::min(fec_to_ask, (n_ - k_)); + fec_per_loss_rate_.push_back(fec_to_ask); + + i++; } } +uint64_t RecoveryStrategy::getRtxRtt(uint32_t seq) { + auto it = rtx_state_.find(seq); + + if (it == rtx_state_.end()) return 0; + + // we can compute the RTT of an RTX only if it was send once. Infact if the + // RTX was sent twice or more the data may be alredy in flight and the RTT + // will be underestimated. This may happen also for packets that we + // retransmitted too soon. in that case the RTT will be filtered out by + // checking the path label + if (it->second.rtx_count_ != 1) return 0; + + // this a potentialy valid packet, compute the RTT + return (utils::SteadyTime::nowMs().count() - it->second.last_send_); +} + bool RecoveryStrategy::lossDetected(uint32_t seq) { if (isRtx(seq)) { // this packet is already in the list of rtx @@ -141,8 +174,10 @@ void RecoveryStrategy::addNewRtx(uint32_t seq, bool force) { state.first_send_ = state_->getInterestSentTime(seq); if (state.first_send_ == 0) // this interest was never sent before state.first_send_ = getNow(); - state.next_send_ = computeNextSend(seq, true); + state.last_send_ = state.first_send_; // we didn't send an RTX for this + // packet yet state.rtx_count_ = 0; + state.next_send_ = computeNextSend(seq, state.rtx_count_); DLOG_IF(INFO, VLOG_IS_ON(4)) << "Add " << seq << " to retransmissions. next rtx is in " << state.next_send_ - getNow() << " ms"; @@ -158,66 +193,50 @@ void RecoveryStrategy::addNewRtx(uint32_t seq, bool force) { } } -uint64_t RecoveryStrategy::computeNextSend(uint32_t seq, bool new_rtx) { +uint64_t RecoveryStrategy::computeNextSend(uint32_t seq, uint32_t rtx_counter) { uint64_t now = getNow(); - if (new_rtx) { - // for the new rtx we wait one estimated IAT after the loss detection. this - // is bacause, assuming that packets arrive with a constant IAT, we should - // get a new packet every IAT - double prod_rate = state_->getProducerRate(); - uint32_t estimated_iat = SENTINEL_TIMER_INTERVAL; - uint32_t jitter = 0; + if (rtx_counter == 0) { + uint32_t wait = 1; + if (content_sharing_mode_) return now + wait; - if (prod_rate != 0) { - double packet_size = state_->getAveragePacketSize(); - estimated_iat = ceil(1000.0 / (prod_rate / packet_size)); - jitter = ceil(state_->getJitter()); - } + uint32_t jitter = SENTINEL_TIMER_INTERVAL; + double prod_rate = state_->getProducerRate(); + if (prod_rate != 0) jitter = ceil(state_->getJitter()); - uint32_t wait = 1; - if (estimated_iat < 18) { - // for low rate app we do not wait to send a RTX - // we consider low rate stream with less than 50pps (iat >= 20ms) - // (e.g. audio in videoconf, mobile games). - // in the check we use 18ms to accomodate for measurements errors - // for flows with higher rate wait 1 ait + jitter - wait = estimated_iat + jitter; - } + wait += jitter; - DLOG_IF(INFO, VLOG_IS_ON(3)) - << "first rtx for " << seq << " in " << wait - << " ms, rtt = " << state_->getMinRTT() << " ait = " << estimated_iat - << " jttr = " << jitter; + DLOG_IF(INFO, VLOG_IS_ON(3)) << "first rtx for " << seq << " in " << wait + << " ms, jitter = " << jitter; return now + wait; } else { - // wait one RTT - uint32_t wait = SENTINEL_TIMER_INTERVAL; - + // wait one RTT. if an edge is known use the edge RTT for the first 5 rtx double prod_rate = state_->getProducerRate(); if (prod_rate == 0) { return now + SENTINEL_TIMER_INTERVAL; } - double packet_size = state_->getAveragePacketSize(); - uint32_t estimated_iat = ceil(1000.0 / (prod_rate / packet_size)); + uint64_t rtt = 0; + // if the transport detects an edge we try first to get the RTX from the + // edge. if no interest get a reply we move to the full RTT + if (rtx_counter < 5 && (state_->getEdgeRtt() != 0)) { + rtt = state_->getEdgeRtt(); + } else { + rtt = state_->getAvgRTT(); + } - uint64_t rtt = state_->getMinRTT(); if (rtt == 0) rtt = SENTINEL_TIMER_INTERVAL; - wait = rtt; + + if (content_sharing_mode_) return now + rtt; + + uint32_t wait = (uint32_t)rtt; uint32_t jitter = ceil(state_->getJitter()); wait += jitter; - // it may happen that the channel is congested and we have some additional - // queuing delay to take into account - uint32_t queue = ceil(state_->getQueuing()); - wait += queue; - DLOG_IF(INFO, VLOG_IS_ON(3)) - << "next rtx for " << seq << " in " << wait - << " ms, rtt = " << state_->getMinRTT() << " ait = " << estimated_iat - << " jttr = " << jitter << " queue = " << queue; + << "next rtx for " << seq << " in " << wait << " ms, rtt = " << rtt + << " jtter = " << jitter; return now + wait; } @@ -252,7 +271,9 @@ void RecoveryStrategy::retransmit() { state_->onRetransmission(seq); double prod_rate = state_->getProducerRate(); if (prod_rate != 0) rtx_it->second.rtx_count_++; - rtx_it->second.next_send_ = computeNextSend(seq, false); + rtx_it->second.last_send_ = now; + rtx_it->second.next_send_ = + computeNextSend(seq, rtx_it->second.rtx_count_); it = rtx_timers_.erase(it); rtx_timers_.insert( std::pair<uint64_t, uint32_t>(rtx_it->second.next_send_, seq)); @@ -327,6 +348,7 @@ void RecoveryStrategy::deleteRtx(uint32_t seq) { } it_timers++; } + // remove rtx rtx_state_.erase(it_rtx); } @@ -339,53 +361,13 @@ uint32_t RecoveryStrategy::computeFecPacketsToAsk() { if (loss_rate == 0) return 0; - // once per minute try to reduce the fec rate. it may happen that for some bin - // we ask too many fec packet. here we try to reduce this values gently - if (round_id_ % ROUNDS_PER_MIN == 0) { - reduceFec(); - } - // keep track of the last used fec. if we use a new bin on this round reset // consecutive use and avg loss in the prev bin uint32_t bin = ceil(loss_rate / 5.0) - 1; - if (bin > fec_per_loss_rate_.size() - 1) bin = fec_per_loss_rate_.size() - 1; + if (bin > fec_per_loss_rate_.size() - 1) + bin = (uint32_t)fec_per_loss_rate_.size() - 1; - if (bin != last_fec_used_) { - fec_per_loss_rate_[last_fec_used_].consecutive_use = 0; - fec_per_loss_rate_[last_fec_used_].avg_residual_losses = 0.0; - } - last_fec_used_ = bin; - fec_per_loss_rate_[last_fec_used_].consecutive_use++; - - // we update the stats only once very 5 rounds (1sec) that is the rate at - // which we compute residual losses - if (round_id_ % ROUNDS_PER_SEC == 0) { - double residual_losses = state_->getResidualLossRate() * 100; - // update residual loss rate - fec_per_loss_rate_[bin].avg_residual_losses = - (fec_per_loss_rate_[bin].avg_residual_losses * MOVING_AVG_ALPHA) + - (1 - MOVING_AVG_ALPHA) * residual_losses; - - if ((fec_per_loss_rate_[bin].last_update - round_id_) < - WAIT_BEFORE_FEC_UPDATE) { - // this bin is been updated recently so don't modify it and - // return the current state - return fec_per_loss_rate_[bin].fec_to_ask; - } - - // if the residual loss rate is too high and we can ask more fec packets and - // we are using this configuration since at least 5 sec update fec - if (fec_per_loss_rate_[bin].avg_residual_losses > MAX_RESIDUAL_LOSS_RATE && - fec_per_loss_rate_[bin].fec_to_ask < (n_ - k_) && - fec_per_loss_rate_[bin].consecutive_use > WAIT_BEFORE_FEC_UPDATE) { - // so increase the number of fec packets to ask - fec_per_loss_rate_[bin].fec_to_ask++; - fec_per_loss_rate_[bin].last_update = round_id_; - fec_per_loss_rate_[bin].avg_residual_losses = 0.0; - } - } - - return fec_per_loss_rate_[bin].fec_to_ask; + return fec_per_loss_rate_[bin]; } void RecoveryStrategy::setRtxFec(std::optional<bool> rtx_on, @@ -431,21 +413,6 @@ void RecoveryStrategy::removePacketState(uint32_t seq) { deleteRtx(seq); } -// private methods - -void RecoveryStrategy::reduceFec() { - for (uint32_t loss_rate = 5; loss_rate < 100; loss_rate += 5) { - double dec_loss_rate = (double)loss_rate / 100.0; - double exp_losses = (double)k_ * dec_loss_rate; - uint32_t fec_to_ask = ceil(exp_losses / (1 - dec_loss_rate)); - - uint32_t bin = ceil(loss_rate / 5.0) - 1; - if (fec_per_loss_rate_[bin].fec_to_ask > fec_to_ask) { - fec_per_loss_rate_[bin].fec_to_ask--; - } - } -} - } // end namespace rtc } // end namespace protocol diff --git a/libtransport/src/protocols/rtc/rtc_recovery_strategy.h b/libtransport/src/protocols/rtc/rtc_recovery_strategy.h index 482aedc9d..aceb85888 100644 --- a/libtransport/src/protocols/rtc/rtc_recovery_strategy.h +++ b/libtransport/src/protocols/rtc/rtc_recovery_strategy.h @@ -32,9 +32,10 @@ namespace rtc { class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> { protected: struct rtx_state_ { - uint64_t first_send_; - uint64_t next_send_; - uint32_t rtx_count_; + uint64_t first_send_; // first time this interest was sent + uint64_t last_send_; // last time this rtx was sent + uint64_t next_send_; // next retransmission time + uint32_t rtx_count_; // number or rtx }; using rtxState = struct rtx_state_; @@ -44,6 +45,7 @@ class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> { RecoveryStrategy(Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service, bool use_rtx, bool use_fec, + interface::RtcTransportRecoveryStrategies rs_type, interface::StrategyCallback &&external_callback); RecoveryStrategy(RecoveryStrategy &&rs); @@ -55,6 +57,7 @@ class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> { void setState(RTCState *state) { state_ = state; } void setRateControl(RTCRateControl *rateControl) { rc_ = rateControl; } void setFecParams(uint32_t n, uint32_t k); + void setContentSharingMode() { content_sharing_mode_ = true; } bool isRtx(uint32_t seq) { if (rtx_state_.find(seq) != rtx_state_.end()) return true; @@ -71,10 +74,20 @@ class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> { return false; } + interface::RtcTransportRecoveryStrategies getType() { + return rs_type_; + } + void updateType(interface::RtcTransportRecoveryStrategies type) { + rs_type_ = type; + } bool isRtxOn() { return rtx_on_; } bool isFecOn() { return fec_on_; } RTCState *getState() { return state_; } + + // if the function returns 0 it means that the packet is not an RTX or it is + // not a valid packet to safely compute the RTT + uint64_t getRtxRtt(uint32_t seq); bool lossDetected(uint32_t seq); void notifyNewLossDetedcted(uint32_t seq); void requestPossibleLostPacket(uint32_t seq); @@ -98,7 +111,7 @@ class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> { protected: // rtx functions void addNewRtx(uint32_t seq, bool force); - uint64_t computeNextSend(uint32_t seq, bool new_rtx); + uint64_t computeNextSend(uint32_t seq, uint32_t rtx_counter); void retransmit(); void scheduleNextRtx(); void deleteRtx(uint32_t seq); @@ -109,9 +122,11 @@ class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> { // common functons void removePacketState(uint32_t seq); + interface::RtcTransportRecoveryStrategies rs_type_; bool recovery_on_; bool rtx_on_; bool fec_on_; + bool content_sharing_mode_; // number of RTX sent after fec turned on // this is used to take into account jitter and out of order packets @@ -152,19 +167,9 @@ class RecoveryStrategy : public std::enable_shared_from_this<RecoveryStrategy> { RTCRateControl *rc_; private: - struct fec_state_ { - uint32_t fec_to_ask; - uint32_t last_update; // round id of the last update - // (wait 10 ruonds (2sec) between updates) - uint32_t consecutive_use; // consecutive ruonds where this fec was used - double avg_residual_losses; - }; - - void reduceFec(); - uint32_t round_id_; // number of rounds uint32_t last_fec_used_; - std::vector<fec_state_> fec_per_loss_rate_; + std::vector<uint32_t> fec_per_loss_rate_; interface::StrategyCallback callback_; }; diff --git a/libtransport/src/protocols/rtc/rtc_rs_delay.cc b/libtransport/src/protocols/rtc/rtc_rs_delay.cc index 4be751ec9..7d7a01133 100644 --- a/libtransport/src/protocols/rtc/rtc_rs_delay.cc +++ b/libtransport/src/protocols/rtc/rtc_rs_delay.cc @@ -25,8 +25,10 @@ namespace rtc { RecoveryStrategyDelayBased::RecoveryStrategyDelayBased( Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service, + interface::RtcTransportRecoveryStrategies rs_type, interface::StrategyCallback &&external_callback) : RecoveryStrategy(indexer, std::move(callback), io_service, true, false, + rs_type, std::move(external_callback)), // start with rtx congestion_state_(false), probing_state_(false), @@ -48,7 +50,7 @@ void RecoveryStrategyDelayBased::turnOnRecovery() { recovery_on_ = true; uint64_t rtt = state_->getMinRTT(); uint32_t fec_to_ask = computeFecPacketsToAsk(); - if (rtt > 80 && fec_to_ask != 0) { + if (rtt > MAX_RTT_BEFORE_FEC && fec_to_ask > 0) { // we need to start FEC (see fec only strategy for more details) setRtxFec(true, true); rtx_during_fec_ = 1; // avoid to stop fec @@ -84,16 +86,16 @@ void RecoveryStrategyDelayBased::onNewRound(bool in_sync) { return; } - uint64_t rtt = state_->getMinRTT(); + uint64_t rtt = state_->getAvgRTT(); - bool congestion = false; // XXX at the moment we are not looking at congestion events - // congestion = rc_->inCongestionState(); + // bool congestion = rc_->inCongestionState(); - if ((!fec_on_ && rtt >= 100) || (fec_on_ && rtt > 80) || congestion) { + if ((!fec_on_ && rtt >= MAX_RTT_BEFORE_FEC) || + (fec_on_ && rtt > (MAX_RTT_BEFORE_FEC - 10))) { // switch from rtx to fec or keep use fec. Notice that if some rtx are // waiting to be scheduled, they will be sent normally, but no new rtx will - // be created If the loss rate is 0 keep to use RTX. + // be created if the loss rate is 0 keep to use RTX. uint32_t fec_to_ask = computeFecPacketsToAsk(); softSwitchToFec(fec_to_ask); if (rtx_during_fec_ == 0) // if we do not send any RTX the losses @@ -104,7 +106,8 @@ void RecoveryStrategyDelayBased::onNewRound(bool in_sync) { return; } - if ((fec_on_ && rtt <= 80) || (!rtx_on_ && rtt <= 100)) { + if ((fec_on_ && rtt <= (MAX_RTT_BEFORE_FEC - 10)) || + (!rtx_on_ && rtt <= MAX_RTT_BEFORE_FEC)) { // turn on rtx softSwitchToFec(0); indexer_->setNFec(0); diff --git a/libtransport/src/protocols/rtc/rtc_rs_delay.h b/libtransport/src/protocols/rtc/rtc_rs_delay.h index 5ca90f4cb..9e1c41388 100644 --- a/libtransport/src/protocols/rtc/rtc_rs_delay.h +++ b/libtransport/src/protocols/rtc/rtc_rs_delay.h @@ -26,6 +26,7 @@ class RecoveryStrategyDelayBased : public RecoveryStrategy { public: RecoveryStrategyDelayBased(Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service, + interface::RtcTransportRecoveryStrategies rs_type, interface::StrategyCallback &&external_callback); RecoveryStrategyDelayBased(RecoveryStrategy &&rs); diff --git a/libtransport/src/protocols/rtc/rtc_rs_fec_only.cc b/libtransport/src/protocols/rtc/rtc_rs_fec_only.cc index c44212bda..5b10823ec 100644 --- a/libtransport/src/protocols/rtc/rtc_rs_fec_only.cc +++ b/libtransport/src/protocols/rtc/rtc_rs_fec_only.cc @@ -25,9 +25,10 @@ namespace rtc { RecoveryStrategyFecOnly::RecoveryStrategyFecOnly( Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service, + interface::RtcTransportRecoveryStrategies rs_type, interface::StrategyCallback &&external_callback) : RecoveryStrategy(indexer, std::move(callback), io_service, true, false, - std::move(external_callback)), + rs_type, std::move(external_callback)), congestion_state_(false), probing_state_(false), switch_rounds_(0) {} diff --git a/libtransport/src/protocols/rtc/rtc_rs_fec_only.h b/libtransport/src/protocols/rtc/rtc_rs_fec_only.h index 1ab78b842..42df25bd9 100644 --- a/libtransport/src/protocols/rtc/rtc_rs_fec_only.h +++ b/libtransport/src/protocols/rtc/rtc_rs_fec_only.h @@ -26,6 +26,7 @@ class RecoveryStrategyFecOnly : public RecoveryStrategy { public: RecoveryStrategyFecOnly(Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service, + interface::RtcTransportRecoveryStrategies rs_type, interface::StrategyCallback &&external_callback); RecoveryStrategyFecOnly(RecoveryStrategy &&rs); diff --git a/libtransport/src/protocols/rtc/rtc_rs_low_rate.cc b/libtransport/src/protocols/rtc/rtc_rs_low_rate.cc index 48dd3e34f..dbad563cd 100644 --- a/libtransport/src/protocols/rtc/rtc_rs_low_rate.cc +++ b/libtransport/src/protocols/rtc/rtc_rs_low_rate.cc @@ -25,8 +25,10 @@ namespace rtc { RecoveryStrategyLowRate::RecoveryStrategyLowRate( Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service, + interface::RtcTransportRecoveryStrategies rs_type, interface::StrategyCallback &&external_callback) : RecoveryStrategy(indexer, std::move(callback), io_service, false, true, + rs_type, std::move(external_callback)), // start with fec fec_consecutive_rounds_((MILLI_IN_A_SEC / ROUND_LEN) * 5), // 5 sec rtx_allowed_consecutive_rounds_(0) { @@ -75,7 +77,7 @@ void RecoveryStrategyLowRate::selectRecoveryStrategy(bool in_sync) { } uint32_t loss_rate = std::round(state_->getPerSecondLossRate() * 100); - uint32_t rtt = state_->getAvgRTT(); + uint32_t rtt = (uint32_t)state_->getAvgRTT(); bool use_rtx = false; for (size_t i = 0; i < switch_vector.size(); i++) { diff --git a/libtransport/src/protocols/rtc/rtc_rs_low_rate.h b/libtransport/src/protocols/rtc/rtc_rs_low_rate.h index d66b197e2..0e76efaca 100644 --- a/libtransport/src/protocols/rtc/rtc_rs_low_rate.h +++ b/libtransport/src/protocols/rtc/rtc_rs_low_rate.h @@ -34,6 +34,7 @@ class RecoveryStrategyLowRate : public RecoveryStrategy { public: RecoveryStrategyLowRate(Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service, + interface::RtcTransportRecoveryStrategies rs_type, interface::StrategyCallback &&external_callback); RecoveryStrategyLowRate(RecoveryStrategy &&rs); diff --git a/libtransport/src/protocols/rtc/rtc_rs_recovery_off.cc b/libtransport/src/protocols/rtc/rtc_rs_recovery_off.cc index 16b14eff6..00c6a0504 100644 --- a/libtransport/src/protocols/rtc/rtc_rs_recovery_off.cc +++ b/libtransport/src/protocols/rtc/rtc_rs_recovery_off.cc @@ -25,9 +25,10 @@ namespace rtc { RecoveryStrategyRecoveryOff::RecoveryStrategyRecoveryOff( Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service, + interface::RtcTransportRecoveryStrategies rs_type, interface::StrategyCallback &&external_callback) : RecoveryStrategy(indexer, std::move(callback), io_service, false, false, - std::move(external_callback)) {} + rs_type, std::move(external_callback)) {} RecoveryStrategyRecoveryOff::RecoveryStrategyRecoveryOff(RecoveryStrategy &&rs) : RecoveryStrategy(std::move(rs)) { diff --git a/libtransport/src/protocols/rtc/rtc_rs_recovery_off.h b/libtransport/src/protocols/rtc/rtc_rs_recovery_off.h index 3a9e71e7d..3d59cc473 100644 --- a/libtransport/src/protocols/rtc/rtc_rs_recovery_off.h +++ b/libtransport/src/protocols/rtc/rtc_rs_recovery_off.h @@ -26,6 +26,7 @@ class RecoveryStrategyRecoveryOff : public RecoveryStrategy { public: RecoveryStrategyRecoveryOff(Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service, + interface::RtcTransportRecoveryStrategies rs_type, interface::StrategyCallback &&external_callback); RecoveryStrategyRecoveryOff(RecoveryStrategy &&rs); diff --git a/libtransport/src/protocols/rtc/rtc_rs_rtx_only.cc b/libtransport/src/protocols/rtc/rtc_rs_rtx_only.cc index 8e5db5439..4d7cf7a82 100644 --- a/libtransport/src/protocols/rtc/rtc_rs_rtx_only.cc +++ b/libtransport/src/protocols/rtc/rtc_rs_rtx_only.cc @@ -25,9 +25,10 @@ namespace rtc { RecoveryStrategyRtxOnly::RecoveryStrategyRtxOnly( Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service, + interface::RtcTransportRecoveryStrategies rs_type, interface::StrategyCallback &&external_callback) : RecoveryStrategy(indexer, std::move(callback), io_service, true, false, - std::move(external_callback)) {} + rs_type, std::move(external_callback)) {} RecoveryStrategyRtxOnly::RecoveryStrategyRtxOnly(RecoveryStrategy &&rs) : RecoveryStrategy(std::move(rs)) { diff --git a/libtransport/src/protocols/rtc/rtc_rs_rtx_only.h b/libtransport/src/protocols/rtc/rtc_rs_rtx_only.h index e90e5ba13..03dbed1c7 100644 --- a/libtransport/src/protocols/rtc/rtc_rs_rtx_only.h +++ b/libtransport/src/protocols/rtc/rtc_rs_rtx_only.h @@ -26,6 +26,7 @@ class RecoveryStrategyRtxOnly : public RecoveryStrategy { public: RecoveryStrategyRtxOnly(Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service, + interface::RtcTransportRecoveryStrategies rs_type, interface::StrategyCallback &&external_callback); RecoveryStrategyRtxOnly(RecoveryStrategy &&rs); diff --git a/libtransport/src/protocols/rtc/rtc_state.cc b/libtransport/src/protocols/rtc/rtc_state.cc index 5b3b5e4c3..82ac0b9c1 100644 --- a/libtransport/src/protocols/rtc/rtc_state.cc +++ b/libtransport/src/protocols/rtc/rtc_state.cc @@ -106,6 +106,7 @@ void RTCState::initParams() { // paths stats path_table_.clear(); main_path_ = nullptr; + edge_path_ = nullptr; // packet cache (not pending anymore) packet_cache_.clear(); @@ -231,11 +232,9 @@ void RTCState::onDataPacketReceived(const core::ContentObject &content_object, } updatePacketSize(content_object); - updateReceivedBytes(content_object); + updateReceivedBytes(content_object, false); addRecvOrLost(seq, PacketState::RECEIVED); - if (seq > highest_seq_received_) highest_seq_received_ = seq; - // the producer is responding // it is generating valid data packets so we consider it active producer_is_active_ = true; @@ -245,11 +244,7 @@ void RTCState::onDataPacketReceived(const core::ContentObject &content_object, void RTCState::onFecPacketReceived(const core::ContentObject &content_object) { uint32_t seq = content_object.getName().getSuffix(); - // updateReceivedBytes(content_object); - received_fec_bytes_ += - (uint32_t)(content_object.headerSize() + content_object.payloadSize()); - - if (seq > highest_seq_received_) highest_seq_received_ = seq; + updateReceivedBytes(content_object, true); PacketState state = getPacketState(seq); if (state != PacketState::LOST) { @@ -328,12 +323,14 @@ void RTCState::onPacketLost(uint32_t seq) { DLOG_IF(INFO, VLOG_IS_ON(4)) << "packet " << seq << " is lost"; } } + addRecvOrLost(seq, PacketState::DEFINITELY_LOST); } -void RTCState::onPacketRecoveredRtx(uint32_t seq) { +void RTCState::onPacketRecoveredRtx(const core::ContentObject &content_object, + uint64_t rtt) { + uint32_t seq = content_object.getName().getSuffix(); packets_sent_to_app_++; - if (seq > highest_seq_received_) highest_seq_received_ = seq; // increase the recovered packet counter only if the packet was marked as LOST // before. @@ -341,13 +338,37 @@ void RTCState::onPacketRecoveredRtx(uint32_t seq) { if (state == PacketState::LOST) losses_recovered_++; addRecvOrLost(seq, PacketState::RECEIVED); + updateReceivedBytes(content_object, false); + + if (rtt == 0) return; // nothing to do + + uint32_t path_label = content_object.getPathLabel(); + auto path_it = path_table_.find(path_label); + if (path_it == path_table_.end()) { + // this is a new path and it must be a cache + std::shared_ptr<RTCDataPath> newPath = + std::make_shared<RTCDataPath>(path_label); + auto ret = path_table_.insert( + std::pair<uint32_t, std::shared_ptr<RTCDataPath>>(path_label, newPath)); + path_it = ret.first; + } + + auto path = path_it->second; + if (path->pathToProducer()) + return; // this packet is coming from a producer + // even if we sent an RTX. this may happen + // for RTX that are sent too fast or in + // case of multipath + + path->insertRttSample(utils::SteadyTime::Milliseconds(rtt), true); } -void RTCState::onFecPacketRecoveredRtx(uint32_t seq) { +void RTCState::onFecPacketRecoveredRtx( + const core::ContentObject &content_object) { // This is the same as onPacketRecoveredRtx, but in this is case the // pkt is also a FEC pkt, the addRecvOrLost will be called afterwards - if (seq > highest_seq_received_) highest_seq_received_ = seq; losses_recovered_++; + updateReceivedBytes(content_object, true); } void RTCState::onPacketRecoveredFec(uint32_t seq, uint32_t size) { @@ -355,8 +376,6 @@ void RTCState::onPacketRecoveredFec(uint32_t seq, uint32_t size) { packets_sent_to_app_++; recovered_bytes_with_fec_ += size; - if (seq > highest_seq_received_) highest_seq_received_ = seq; - // adding header to the count recovered_bytes_with_fec_ += 60; // XXX get header size some where @@ -487,21 +506,32 @@ void RTCState::onNewRound(double round_len, bool in_sync) { // channel losses uint32_t last_round_packets = 0; + uint64_t min_edge_rtt = UINT_MAX; std::shared_ptr<RTCDataPath> old_main_path = main_path_; main_path_ = nullptr; + edge_path_ = nullptr; for (auto it = path_table_.begin(); it != path_table_.end(); it++) { - if (it->second->isActive()) { + if (it->second->isValidProducer()) { uint32_t pkt = it->second->getPacketsLastRound(); if (pkt > last_round_packets) { last_round_packets = pkt; main_path_ = it->second; } + } else if (it->second->isActive() && !it->second->pathToProducer()) { + // this is a path to a cache from where we are receiving content + if (it->second->getMinRtt() < min_edge_rtt) { + min_edge_rtt = it->second->getMinRtt(); + edge_path_ = it->second; + } } it->second->roundEnd(); } if (main_path_ == nullptr) main_path_ = old_main_path; + if (edge_path_ == nullptr) edge_path_ = main_path_; + if (edge_path_->getMinRtt() >= main_path_->getMinRtt()) + edge_path_ = main_path_; // in case we get a new main path we reset the stats of the old one. this is // beacuse, in case we need to switch back we don't what to take decisions on @@ -551,9 +581,15 @@ void RTCState::onNewRound(double round_len, bool in_sync) { rounds_++; } -void RTCState::updateReceivedBytes(const core::ContentObject &content_object) { - received_bytes_ += - (uint32_t)(content_object.headerSize() + content_object.payloadSize()); +void RTCState::updateReceivedBytes(const core::ContentObject &content_object, + bool isFec) { + if (isFec) { + received_fec_bytes_ += + (uint32_t)(content_object.headerSize() + content_object.payloadSize()); + } else { + received_bytes_ += + (uint32_t)(content_object.headerSize() + content_object.payloadSize()); + } } void RTCState::updatePacketSize(const core::ContentObject &content_object) { @@ -703,6 +739,10 @@ void RTCState::dataToBeReceived(uint32_t seq) { addToPacketCache(seq, PacketState::TO_BE_RECEIVED); } +void RTCState::updateHighestSeqReceived(uint32_t seq) { + if (seq > highest_seq_received_) highest_seq_received_ = seq; +} + void RTCState::addRecvOrLost(uint32_t seq, PacketState state) { auto it = pending_interests_.find(seq); if (it != pending_interests_.end()) { @@ -803,7 +843,7 @@ core::ParamsRTC RTCState::getProbeParams(const core::ContentObject &probe) { switch (ProbeHandler::getProbeType(seq)) { case ProbeType::INIT: { core::ContentObjectManifest manifest( - const_cast<core::ContentObject &>(probe)); + const_cast<core::ContentObject &>(probe).shared_from_this()); manifest.decode(); params = manifest.getParamsRTC(); break; @@ -841,7 +881,7 @@ core::ParamsRTC RTCState::getDataParams(const core::ContentObject &data) { } case core::PayloadType::MANIFEST: { core::ContentObjectManifest manifest( - const_cast<core::ContentObject &>(data)); + const_cast<core::ContentObject &>(data).shared_from_this()); manifest.decode(); params = manifest.getParamsRTC(); break; diff --git a/libtransport/src/protocols/rtc/rtc_state.h b/libtransport/src/protocols/rtc/rtc_state.h index 4bd2f76a0..ac3cc621f 100644 --- a/libtransport/src/protocols/rtc/rtc_state.h +++ b/libtransport/src/protocols/rtc/rtc_state.h @@ -84,8 +84,9 @@ class RTCState : public std::enable_shared_from_this<RTCState> { void onNackPacketReceived(const core::ContentObject &nack, bool compute_stats); void onPacketLost(uint32_t seq); - void onPacketRecoveredRtx(uint32_t seq); - void onFecPacketRecoveredRtx(uint32_t seq); + void onPacketRecoveredRtx(const core::ContentObject &content_object, + uint64_t rtt); + void onFecPacketRecoveredRtx(const core::ContentObject &content_object); void onPacketRecoveredFec(uint32_t seq, uint32_t size); bool onProbePacketReceived(const core::ContentObject &probe); void onJumpForward(uint32_t next_seq); @@ -117,6 +118,11 @@ class RTCState : public std::enable_shared_from_this<RTCState> { return 0; } + uint64_t getEdgeRtt() const { + if (edge_path_ != nullptr) return edge_path_->getMinRtt(); + return 0; + } + void resetRttStats() { if (mainPathIsValid()) main_path_->clearRtt(); } @@ -149,7 +155,7 @@ class RTCState : public std::enable_shared_from_this<RTCState> { } uint32_t getPendingInterestNumber() const { - return pending_interests_.size(); + return (uint32_t)pending_interests_.size(); } PacketState getPacketState(uint32_t seq) { @@ -242,6 +248,8 @@ class RTCState : public std::enable_shared_from_this<RTCState> { // set it as TO_BE_RECEIVED. void dataToBeReceived(uint32_t seq); + void updateHighestSeqReceived(uint32_t seq); + // Extract RTC parameters from probes (init or RTT probes) and data packets. static core::ParamsRTC getProbeParams(const core::ContentObject &probe); static core::ParamsRTC getDataParams(const core::ContentObject &data); @@ -259,7 +267,8 @@ class RTCState : public std::enable_shared_from_this<RTCState> { // update stats void updateState(); - void updateReceivedBytes(const core::ContentObject &content_object); + void updateReceivedBytes(const core::ContentObject &content_object, + bool isFec); void updatePacketSize(const core::ContentObject &content_object); void updatePathStats(const core::ContentObject &content_object, bool is_nack); void updateLossRate(bool in_sycn); @@ -360,7 +369,12 @@ class RTCState : public std::enable_shared_from_this<RTCState> { // paths stats std::unordered_map<uint32_t, std::shared_ptr<RTCDataPath>> path_table_; - std::shared_ptr<RTCDataPath> main_path_; + std::shared_ptr<RTCDataPath> main_path_; // this is the path that connects + // the consumer to the producer. in + // case of multipath the trasnport + // uses the most active path + std::shared_ptr<RTCDataPath> edge_path_; // path to the closest cache if it + // exists // packet received // cache where to store info about the last MAX_CACHED_PACKETS diff --git a/libtransport/src/protocols/rtc/rtc_verifier.cc b/libtransport/src/protocols/rtc/rtc_verifier.cc index 7b6330a1f..861ceee89 100644 --- a/libtransport/src/protocols/rtc/rtc_verifier.cc +++ b/libtransport/src/protocols/rtc/rtc_verifier.cc @@ -22,11 +22,11 @@ namespace protocol { namespace rtc { RTCVerifier::RTCVerifier(std::shared_ptr<auth::Verifier> verifier, - uint32_t max_unverified_interval, - double max_unverified_ratio) + uint32_t factor_relevant, uint32_t factor_alert) : verifier_(verifier), - max_unverified_interval_(max_unverified_interval), - max_unverified_ratio_(max_unverified_ratio) {} + factor_relevant_(factor_relevant), + factor_alert_(factor_alert), + manifest_max_capacity_(std::numeric_limits<uint8_t>::max()) {} void RTCVerifier::setState(std::shared_ptr<RTCState> rtc_state) { rtc_state_ = rtc_state; @@ -36,12 +36,16 @@ void RTCVerifier::setVerifier(std::shared_ptr<auth::Verifier> verifier) { verifier_ = verifier; } -void RTCVerifier::setMaxUnverifiedInterval(uint32_t max_unverified_interval) { - max_unverified_interval_ = max_unverified_interval; +void RTCVerifier::setFactorRelevant(uint32_t factor_relevant) { + factor_relevant_ = factor_relevant; } -void RTCVerifier::setMaxUnverifiedRatio(double max_unverified_ratio) { - max_unverified_ratio_ = max_unverified_ratio; +void RTCVerifier::setFactorAlert(uint32_t factor_alert) { + factor_alert_ = factor_alert; +} + +auth::VerificationPolicy RTCVerifier::verify(core::Interest &interest) { + return verifier_->verifyPackets(&interest); } auth::VerificationPolicy RTCVerifier::verify( @@ -108,19 +112,27 @@ auth::VerificationPolicy RTCVerifier::verifyData( auth::Suffix suffix = content_object.getName().getSuffix(); auth::VerificationPolicy policy = auth::VerificationPolicy::ABORT; - Timestamp now = utils::SteadyTime::nowMs().count(); - // Flush old packets - Timestamp oldest = flush_packets(now); + uint32_t threshold_relevant = factor_relevant_ * manifest_max_capacity_; + uint32_t threshold_alert = factor_alert_ * manifest_max_capacity_; - // Add packet to map of unverified packets - packets_unverif_.add( - {.suffix = suffix, .timestamp = now, .size = content_object.length()}, - content_object.computeDigest(manifest_hash_algo_)); + // Flush packets outside relevance window + for (auto it = packets_unverif_.set().begin(); + it != packets_unverif_.set().end();) { + if (it->first > current_index_ - threshold_relevant) { + break; + } + packets_unverif_erased_.insert((unsigned int)it->first); + it = packets_unverif_.remove(it); + } + + // Add packet to set of unverified packets + packets_unverif_.add({current_index_, suffix}, + content_object.computeDigest(manifest_hash_algo_)); + current_index_++; - // Check that the ratio of unverified packets stays below the limit - if (now - oldest < max_unverified_interval_ || - getBufferRatio() < max_unverified_ratio_) { + // Check that the number of unverified packets is below the alert threshold + if (packets_unverif_.set().size() <= threshold_alert) { policy = auth::VerificationPolicy::ACCEPT; } @@ -139,18 +151,13 @@ auth::VerificationPolicy RTCVerifier::processManifest( auth::VerificationPolicy accept_policy = auth::VerificationPolicy::ACCEPT; // Decode manifest - core::ContentObjectManifest manifest(content_object); + core::ContentObjectManifest manifest(content_object.shared_from_this()); manifest.decode(); - // Update last manifest - if (suffix > last_manifest_) { - last_manifest_ = suffix; - } - - // Extract hash algorithm and hashes + // Extract manifest data + manifest_max_capacity_ = manifest.getMaxCapacity(); manifest_hash_algo_ = manifest.getHashAlgorithm(); - auth::Verifier::SuffixMap suffix_map = - core::ContentObjectManifest::getSuffixMap(&manifest); + auth::Verifier::SuffixMap suffix_map = manifest.getSuffixMap(); // Return early if the manifest is empty if (suffix_map.empty()) { @@ -186,10 +193,7 @@ auth::VerificationPolicy RTCVerifier::processManifest( for (const auto &p : policies) { switch (p.second) { case auth::VerificationPolicy::ACCEPT: { - auto packet_unverif_it = packets_unverif_.packetIt(p.first); - Packet packet_verif = *packet_unverif_it; - packets_unverif_.remove(packet_unverif_it); - packets_verif_.add(packet_verif); + packets_unverif_.remove(packets_unverif_.packet(p.first)); manifest_digests_.erase(p.first); break; } @@ -209,69 +213,20 @@ void RTCVerifier::onDataRecoveredFec(uint32_t suffix) { manifest_digests_.erase(suffix); } -void RTCVerifier::onJumpForward(uint32_t next_suffix) { - if (next_suffix <= last_manifest_ + 1) { - return; - } - - // When we jump forward in the suffix sequence, we remove packets that won't - // be verified. Those packets have a suffix in the range [last_manifest_ + 1, - // next_suffix[. - for (auth::Suffix suffix = last_manifest_ + 1; suffix < next_suffix; - ++suffix) { - auto packet_it = packets_unverif_.packetIt(suffix); - if (packet_it != packets_unverif_.set().end()) { - packets_unverif_.remove(packet_it); - } - } -} - -double RTCVerifier::getBufferRatio() const { - size_t total = packets_verif_.size() + packets_unverif_.size(); - double total_unverified = static_cast<double>(packets_unverif_.size()); - return total ? total_unverified / total : 0.0; -} - -RTCVerifier::Timestamp RTCVerifier::flush_packets(Timestamp now) { - Timestamp oldest_verified = packets_verif_.set().empty() - ? now - : packets_verif_.set().begin()->timestamp; - Timestamp oldest_unverified = packets_unverif_.set().empty() - ? now - : packets_unverif_.set().begin()->timestamp; - - // Prune verified packets older than the unverified interval - for (auto it = packets_verif_.set().begin(); - it != packets_verif_.set().end();) { - if (now - it->timestamp < max_unverified_interval_) { - break; - } - it = packets_verif_.remove(it); - } - - // Prune unverified packets older than the unverified interval - for (auto it = packets_unverif_.set().begin(); - it != packets_unverif_.set().end();) { - if (now - it->timestamp < max_unverified_interval_) { - break; - } - packets_unverif_erased_.insert(it->suffix); - it = packets_unverif_.remove(it); - } - - return std::min(oldest_verified, oldest_unverified); -} - std::pair<RTCVerifier::PacketSet::iterator, bool> RTCVerifier::Packets::add( - const Packet &packet) { + const Packet &packet, const auth::CryptoHash &digest) { auto inserted = packets_.insert(packet); - size_ += inserted.second ? packet.size : 0; + if (inserted.second) { + packets_map_[packet.second] = inserted.first; + suffix_map_[packet.second] = digest; + } return inserted; } RTCVerifier::PacketSet::iterator RTCVerifier::Packets::remove( PacketSet::iterator packet_it) { - size_ -= packet_it->size; + packets_map_.erase(packet_it->second); + suffix_map_.erase(packet_it->second); return packets_.erase(packet_it); } @@ -279,35 +234,13 @@ const std::set<RTCVerifier::Packet> &RTCVerifier::Packets::set() const { return packets_; }; -size_t RTCVerifier::Packets::size() const { return size_; }; - -std::pair<RTCVerifier::PacketSet::iterator, bool> -RTCVerifier::PacketsUnverif::add(const Packet &packet, - const auth::CryptoHash &digest) { - auto inserted = add(packet); - if (inserted.second) { - packets_map_[packet.suffix] = inserted.first; - digests_map_[packet.suffix] = digest; - } - return inserted; -} - -RTCVerifier::PacketSet::iterator RTCVerifier::PacketsUnverif::remove( - PacketSet::iterator packet_it) { - size_ -= packet_it->size; - packets_map_.erase(packet_it->suffix); - digests_map_.erase(packet_it->suffix); - return packets_.erase(packet_it); -} - -RTCVerifier::PacketSet::iterator RTCVerifier::PacketsUnverif::packetIt( +RTCVerifier::PacketSet::iterator RTCVerifier::Packets::packet( auth::Suffix suffix) { return packets_map_.at(suffix); }; -const auth::Verifier::SuffixMap &RTCVerifier::PacketsUnverif::suffixMap() - const { - return digests_map_; +const auth::Verifier::SuffixMap &RTCVerifier::Packets::suffixMap() const { + return suffix_map_; } } // end namespace rtc diff --git a/libtransport/src/protocols/rtc/rtc_verifier.h b/libtransport/src/protocols/rtc/rtc_verifier.h index 098984057..c83faf08a 100644 --- a/libtransport/src/protocols/rtc/rtc_verifier.h +++ b/libtransport/src/protocols/rtc/rtc_verifier.h @@ -27,19 +27,16 @@ namespace rtc { class RTCVerifier { public: explicit RTCVerifier(std::shared_ptr<auth::Verifier> verifier, - uint32_t max_unverified_interval, - double max_unverified_ratio); + uint32_t factor_relevant, uint32_t factor_alert); virtual ~RTCVerifier() = default; void setState(std::shared_ptr<RTCState> rtc_state); - void setVerifier(std::shared_ptr<auth::Verifier> verifier); + void setFactorRelevant(uint32_t factor_relevant); + void setFactorAlert(uint32_t factor_alert); - void setMaxUnverifiedInterval(uint32_t max_unverified_interval); - - void setMaxUnverifiedRatio(double max_unverified_ratio); - + auth::VerificationPolicy verify(core::Interest &interest); auth::VerificationPolicy verify(core::ContentObject &content_object, bool is_fec = false); auth::VerificationPolicy verifyProbe(core::ContentObject &content_object); @@ -51,81 +48,47 @@ class RTCVerifier { auth::VerificationPolicy processManifest(core::ContentObject &content_object); void onDataRecoveredFec(uint32_t suffix); - void onJumpForward(uint32_t next_suffix); - - double getBufferRatio() const; protected: - struct Packet; - using Timestamp = uint64_t; + using Index = uint64_t; + using Packet = std::pair<Index, auth::Suffix>; using PacketSet = std::set<Packet>; - struct Packet { - auth::Suffix suffix; - Timestamp timestamp; - size_t size; - - bool operator==(const Packet &b) const { - return timestamp == b.timestamp && suffix == b.suffix; - } - bool operator<(const Packet &b) const { - return timestamp == b.timestamp ? suffix < b.suffix - : timestamp < b.timestamp; - } - }; - class Packets { public: - virtual std::pair<PacketSet::iterator, bool> add(const Packet &packet); - virtual PacketSet::iterator remove(PacketSet::iterator packet_it); - const PacketSet &set() const; - size_t size() const; - - protected: - PacketSet packets_; - size_t size_; - }; - - class PacketsVerif : public Packets {}; - - class PacketsUnverif : public Packets { - public: - using Packets::add; std::pair<PacketSet::iterator, bool> add(const Packet &packet, const auth::CryptoHash &digest); - PacketSet::iterator remove(PacketSet::iterator packet_it) override; - PacketSet::iterator packetIt(auth::Suffix suffix); + PacketSet::iterator remove(PacketSet::iterator packet_it); + const PacketSet &set() const; + PacketSet::iterator packet(auth::Suffix suffix); const auth::Verifier::SuffixMap &suffixMap() const; private: + PacketSet packets_; std::unordered_map<auth::Suffix, PacketSet::iterator> packets_map_; - auth::Verifier::SuffixMap digests_map_; + auth::Verifier::SuffixMap suffix_map_; }; // The RTC state. std::shared_ptr<RTCState> rtc_state_; // The verifier instance. std::shared_ptr<auth::Verifier> verifier_; - // Window to consider when verifying packets. - uint32_t max_unverified_interval_; - // Ratio of unverified packets over which an alert is triggered. - double max_unverified_ratio_; - // The suffix of the last processed manifest. - auth::Suffix last_manifest_; + // Used to compute the relevance windows size (in packets). + uint32_t factor_relevant_; + // Used to compute the alert threshold (in packets). + uint32_t factor_alert_; + // The maximum number of entries a manifest can contain. + uint8_t manifest_max_capacity_; // Hash algorithm used by manifests. auth::CryptoHashType manifest_hash_algo_; // Digests extracted from all manifests received. auth::Verifier::SuffixMap manifest_digests_; - // Verified packets with timestamp >= now - max_unverified_interval_. - PacketsVerif packets_verif_; - // Unverified packets with timestamp >= now - max_unverified_interval_. - PacketsUnverif packets_unverif_; - // Unverified erased packets with timestamp < now - max_unverified_interval_. + // The number of data packets processed. + Index current_index_; + // Unverified packets with index in relevance window. + Packets packets_unverif_; + // Unverified erased packets with index outside relevance window. std::unordered_set<auth::Suffix> packets_unverif_erased_; - - // Flushes all packets with timestamp < now - max_unverified_interval_. - // Returns the timestamp of the oldest packet, verified or not. - Timestamp flush_packets(Timestamp now); }; } // namespace rtc diff --git a/libtransport/src/protocols/transport_protocol.cc b/libtransport/src/protocols/transport_protocol.cc index a73b9fb7b..b1803709b 100644 --- a/libtransport/src/protocols/transport_protocol.cc +++ b/libtransport/src/protocols/transport_protocol.cc @@ -79,6 +79,7 @@ int TransportProtocol::start() { &on_payload_); socket_->getSocketOption(GeneralTransportOptions::ASYNC_MODE, is_async_); + socket_->getSocketOption(GeneralTransportOptions::SIGNER, signer_); // Set it is the first time we schedule an interest is_first_ = true; @@ -143,14 +144,22 @@ void TransportProtocol::sendInterest( Packet::Format format; socket_->getSocketOption(interface::GeneralTransportOptions::PACKET_FORMAT, format); + size_t signature_size = 0; - auto interest = - core::PacketManager<>::getInstance().getPacket<Interest>(format); + // If aggregated interest, add spapce for signature + if (len > 0) { + format = Packet::toAHFormat(format); + signature_size = signer_->getSignatureFieldSize(); + } + + auto interest = core::PacketManager<>::getInstance().getPacket<Interest>( + format, signature_size); interest->setName(interest_name); for (uint32_t i = 0; i < len; i++) { interest->appendSuffix(additional_suffixes->at(i)); } + interest->encodeSuffixes(); uint32_t lifetime = default_values::interest_lifetime; socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, @@ -165,7 +174,16 @@ void TransportProtocol::sendInterest( return; } - portal_->sendInterest(std::move(interest)); + bool content_sharing_mode; + socket_->getSocketOption(RtcTransportOptions::CONTENT_SHARING_MODE, + content_sharing_mode); + if (content_sharing_mode) lifetime = ceil((double)lifetime * 0.9); + + // Compute signature + bool is_ah = _is_ah(interest->getFormat()); + if (is_ah) signer_->signPacket(interest.get()); + + portal_->sendInterest(interest, lifetime); } void TransportProtocol::onError(const std::error_code &ec) { diff --git a/libtransport/src/protocols/transport_protocol.h b/libtransport/src/protocols/transport_protocol.h index ad8cf0346..e71992561 100644 --- a/libtransport/src/protocols/transport_protocol.h +++ b/libtransport/src/protocols/transport_protocol.h @@ -64,7 +64,7 @@ class TransportProtocol * * @return The header length in bytes. */ - virtual std::size_t transportHeaderLength() { return 0; } + virtual std::size_t transportHeaderLength(bool isFEC) { return 0; } virtual void scheduleNextInterests() = 0; @@ -141,6 +141,9 @@ class TransportProtocol bool is_async_; fec::FECType fec_type_; + + // Signer for aggregated interests + std::shared_ptr<auth::Signer> signer_; }; } // end namespace protocol diff --git a/libtransport/src/test/CMakeLists.txt b/libtransport/src/test/CMakeLists.txt index e7018ceed..b7f14766e 100644 --- a/libtransport/src/test/CMakeLists.txt +++ b/libtransport/src/test/CMakeLists.txt @@ -31,6 +31,8 @@ list(APPEND TESTS_SRC test_quality_score.cc test_sessions.cc test_thread_pool.cc + test_quadloop.cc + test_prefix.cc ) if (ENABLE_RELY) diff --git a/libtransport/src/test/test_core_manifest.cc b/libtransport/src/test/test_core_manifest.cc index b998ce96b..e3d66c1cd 100644 --- a/libtransport/src/test/test_core_manifest.cc +++ b/libtransport/src/test/test_core_manifest.cc @@ -13,8 +13,8 @@ * limitations under the License. */ +#include <core/manifest.h> #include <core/manifest_format_fixed.h> -#include <core/manifest_inline.h> #include <gtest/gtest.h> #include <hicn/transport/auth/crypto_hash.h> #include <hicn/transport/auth/signer.h> @@ -33,10 +33,12 @@ namespace { // The fixture for testing class Foo. class ManifestTest : public ::testing::Test { protected: - using ContentObjectManifest = ManifestInline<ContentObject, Fixed>; + using ContentObjectManifest = Manifest<Fixed>; - ManifestTest() : name_("b001::123|321"), manifest1_(HF_INET6_TCP_AH, name_) { - // You can do set-up work for each test here. + ManifestTest() + : format_(HF_INET6_TCP_AH), name_("b001::123|321"), signature_size_(0) { + manifest_ = ContentObjectManifest::createContentManifest(format_, name_, + signature_size_); } virtual ~ManifestTest() { @@ -56,10 +58,11 @@ class ManifestTest : public ::testing::Test { // before the destructor). } + Packet::Format format_; Name name_; - ContentObjectManifest manifest1_; - - std::vector<uint8_t> manifest_payload = { + std::size_t signature_size_; + std::shared_ptr<ContentObjectManifest> manifest_; + std::vector<uint8_t> manifest_payload_ = { 0x11, 0x11, 0x01, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad // , 0x00, 0x00, // 0x00, 0x45, 0xa3, @@ -75,169 +78,200 @@ class ManifestTest : public ::testing::Test { } // namespace -TEST_F(ManifestTest, MoveConstructor) { +TEST_F(ManifestTest, ManifestConstructor) { // Create content object with manifest in payload - ContentObject co(HF_INET6_TCP_AH, 128); - co.appendPayload(&manifest_payload[0], manifest_payload.size()); - uint8_t buffer[256]; - co.appendPayload(buffer, 256); + ContentObject::Ptr co = + core::PacketManager<>::getInstance().getPacket<ContentObject>( + format_, signature_size_); + co->setName(name_); + co->appendPayload(manifest_payload_.data(), manifest_payload_.size()); + + uint8_t buffer[256] = {0}; + co->appendPayload(buffer, 256); // Copy packet payload uint8_t packet[1500]; - auto length = co.getPayload()->length(); - std::memcpy(packet, co.getPayload()->data(), length); + auto length = co->getPayload()->length(); + std::memcpy(packet, co->getPayload()->data(), length); // Create manifest - ContentObjectManifest m(std::move(co)); + ContentObjectManifest manifest(co); // Check manifest payload is exactly the same of content object - ASSERT_EQ(length, m.getPayload()->length()); - auto ret = std::memcmp(packet, m.getPayload()->data(), length); + ASSERT_EQ(length, manifest.getPacket()->getPayload()->length()); + auto ret = + std::memcmp(packet, manifest.getPacket()->getPayload()->data(), length); ASSERT_EQ(ret, 0); } -TEST_F(ManifestTest, SetLastManifest) { - manifest1_.clear(); - - manifest1_.setIsLast(true); - bool fcn = manifest1_.getIsLast(); - - ASSERT_TRUE(fcn == true); -} - TEST_F(ManifestTest, SetManifestType) { - manifest1_.clear(); + manifest_->Encoder::clear(); ManifestType type1 = ManifestType::INLINE_MANIFEST; ManifestType type2 = ManifestType::FLIC_MANIFEST; - manifest1_.setType(type1); - ManifestType type_returned1 = manifest1_.getType(); + manifest_->setType(type1); + ManifestType type_returned1 = manifest_->getType(); - manifest1_.clear(); + manifest_->Encoder::clear(); - manifest1_.setType(type2); - ManifestType type_returned2 = manifest1_.getType(); + manifest_->setType(type2); + ManifestType type_returned2 = manifest_->getType(); ASSERT_EQ(type1, type_returned1); ASSERT_EQ(type2, type_returned2); } +TEST_F(ManifestTest, SetMaxCapacity) { + manifest_->Encoder::clear(); + + uint8_t max_capacity1 = 0; + uint8_t max_capacity2 = 20; + + manifest_->setMaxCapacity(max_capacity1); + uint8_t max_capacity_returned1 = manifest_->getMaxCapacity(); + + manifest_->Encoder::clear(); + + manifest_->setMaxCapacity(max_capacity2); + uint8_t max_capacity_returned2 = manifest_->getMaxCapacity(); + + ASSERT_EQ(max_capacity1, max_capacity_returned1); + ASSERT_EQ(max_capacity2, max_capacity_returned2); +} + TEST_F(ManifestTest, SetHashAlgorithm) { - manifest1_.clear(); + manifest_->Encoder::clear(); - auth::CryptoHashType hash1 = auth::CryptoHashType::SHA512; - auth::CryptoHashType hash2 = auth::CryptoHashType::BLAKE2B512; - auth::CryptoHashType hash3 = auth::CryptoHashType::SHA256; + auth::CryptoHashType hash1 = auth::CryptoHashType::SHA256; + auth::CryptoHashType hash2 = auth::CryptoHashType::SHA512; + auth::CryptoHashType hash3 = auth::CryptoHashType::BLAKE2B512; - manifest1_.setHashAlgorithm(hash1); - auto type_returned1 = manifest1_.getHashAlgorithm(); + manifest_->setHashAlgorithm(hash1); + auto type_returned1 = manifest_->getHashAlgorithm(); - manifest1_.clear(); + manifest_->Encoder::clear(); - manifest1_.setHashAlgorithm(hash2); - auto type_returned2 = manifest1_.getHashAlgorithm(); + manifest_->setHashAlgorithm(hash2); + auto type_returned2 = manifest_->getHashAlgorithm(); - manifest1_.clear(); + manifest_->Encoder::clear(); - manifest1_.setHashAlgorithm(hash3); - auto type_returned3 = manifest1_.getHashAlgorithm(); + manifest_->setHashAlgorithm(hash3); + auto type_returned3 = manifest_->getHashAlgorithm(); ASSERT_EQ(hash1, type_returned1); ASSERT_EQ(hash2, type_returned2); ASSERT_EQ(hash3, type_returned3); } +TEST_F(ManifestTest, SetLastManifest) { + manifest_->Encoder::clear(); + + manifest_->setIsLast(true); + bool is_last = manifest_->getIsLast(); + + ASSERT_TRUE(is_last); +} + +TEST_F(ManifestTest, SetBaseName) { + manifest_->Encoder::clear(); + + core::Name base_name("b001::dead"); + + manifest_->setBaseName(base_name); + core::Name ret_name = manifest_->getBaseName(); + + ASSERT_EQ(base_name, ret_name); +} + TEST_F(ManifestTest, setParamsBytestream) { - manifest1_.clear(); + manifest_->Encoder::clear(); ParamsBytestream params{ - .final_segment = 1, + .final_segment = 0x0a, }; - manifest1_.setParamsBytestream(params); - manifest1_.encode(); + manifest_->setParamsBytestream(params); + auth::CryptoHash hash(auth::CryptoHashType::SHA256); + hash.computeDigest({0x01, 0x02, 0x03, 0x04}); + manifest_->addEntry(1, hash); + + manifest_->encode(); + manifest_->decode(); - ContentObjectManifest manifest(manifest1_); - manifest.decode(); + auto transport_type_returned = manifest_->getTransportType(); + auto params_returned = manifest_->getParamsBytestream(); ASSERT_EQ(interface::ProductionProtocolAlgorithms::BYTE_STREAM, - manifest.getTransportType()); - ASSERT_EQ(params, manifest.getParamsBytestream()); + transport_type_returned); + ASSERT_EQ(params, params_returned); } TEST_F(ManifestTest, SetParamsRTC) { - manifest1_.clear(); + manifest_->Encoder::clear(); ParamsRTC params{ - .timestamp = 1, - .prod_rate = 2, - .prod_seg = 3, + .timestamp = 0x0a, + .prod_rate = 0x0b, + .prod_seg = 0x0c, .fec_type = protocol::fec::FECType::UNKNOWN, }; - manifest1_.setParamsRTC(params); - manifest1_.encode(); + manifest_->setParamsRTC(params); + auth::CryptoHash hash(auth::CryptoHashType::SHA256); + hash.computeDigest({0x01, 0x02, 0x03, 0x04}); + manifest_->addEntry(1, hash); - ContentObjectManifest manifest(manifest1_); - manifest.decode(); + manifest_->encode(); + manifest_->decode(); + + auto transport_type_returned = manifest_->getTransportType(); + auto params_returned = manifest_->getParamsRTC(); ASSERT_EQ(interface::ProductionProtocolAlgorithms::RTC_PROD, - manifest.getTransportType()); - ASSERT_EQ(params, manifest.getParamsRTC()); + transport_type_returned); + ASSERT_EQ(params, params_returned); } TEST_F(ManifestTest, SignManifest) { - Name name("b001::", 0); auto signer = std::make_shared<auth::SymmetricSigner>( auth::CryptoSuite::HMAC_SHA256, "hunter2"); auto verifier = std::make_shared<auth::SymmetricVerifier>("hunter2"); - std::shared_ptr<ContentObjectManifest> manifest; - // Instantiate Manifest - manifest.reset(ContentObjectManifest::createManifest( - HF_INET6_TCP_AH, name, ManifestVersion::VERSION_1, - ManifestType::INLINE_MANIFEST, false, name, signer->getHashType(), - signer->getSignatureFieldSize())); + // Instantiate manifest + uint8_t max_capacity = 30; + std::shared_ptr<ContentObjectManifest> manifest = + ContentObjectManifest::createContentManifest( + format_, name_, signer->getSignatureFieldSize()); + manifest->setHeaders(ManifestType::INLINE_MANIFEST, max_capacity, + signer->getHashType(), false /* is_last */, name_); - // Add Manifest entry + // Add manifest entry auth::CryptoHash hash(signer->getHashType()); - hash.computeDigest(std::vector<uint8_t>{0x01, 0x02, 0x03, 0x04}); - manifest->addSuffixHash(1, hash); + hash.computeDigest({0x01, 0x02, 0x03, 0x04}); + manifest->addEntry(1, hash); // Encode manifest manifest->encode(); + auto manifest_co = + std::dynamic_pointer_cast<ContentObject>(manifest->getPacket()); // Sign manifest - signer->signPacket(manifest.get()); + signer->signPacket(manifest_co.get()); // Check size - ASSERT_EQ(manifest->payloadSize(), manifest->estimateManifestSize()); - ASSERT_EQ(manifest->length(), - manifest->headerSize() + manifest->payloadSize()); - ASSERT_EQ(ContentObjectManifest::manifestHeaderSize( - interface::ProductionProtocolAlgorithms::UNKNOWN), - manifest->manifestHeaderSize()); + ASSERT_EQ(manifest_co->payloadSize(), manifest->Encoder::manifestSize()); + ASSERT_EQ(manifest_co->length(), + manifest_co->headerSize() + manifest_co->payloadSize()); // Verify manifest - auth::VerificationPolicy policy = verifier->verifyPackets(manifest.get()); + auth::VerificationPolicy policy = verifier->verifyPackets(manifest_co.get()); ASSERT_EQ(auth::VerificationPolicy::ACCEPT, policy); } -TEST_F(ManifestTest, SetBaseName) { - manifest1_.clear(); - - core::Name base_name("b001::dead"); - manifest1_.setBaseName(base_name); - core::Name ret_name = manifest1_.getBaseName(); - - ASSERT_EQ(base_name, ret_name); -} - TEST_F(ManifestTest, SetSuffixList) { - manifest1_.clear(); - - core::Name base_name("b001::dead"); + manifest_->Encoder::clear(); using random_bytes_engine = std::independent_bits_engine<std::default_random_engine, CHAR_BIT, @@ -259,12 +293,13 @@ TEST_F(ManifestTest, SetSuffixList) { entries[i] = std::make_pair(suffixes[i], auth::CryptoHash(data[i].data(), data[i].size(), auth::CryptoHashType::SHA256)); - manifest1_.addSuffixHash(entries[i].first, entries[i].second); + manifest_->addEntry(entries[i].first, entries[i].second); } - manifest1_.setBaseName(base_name); - core::Name ret_name = manifest1_.getBaseName(); + core::Name base_name("b001::dead"); + manifest_->setBaseName(base_name); + core::Name ret_name = manifest_->getBaseName(); ASSERT_EQ(base_name, ret_name); delete[] entries; diff --git a/libtransport/src/test/test_interest.cc b/libtransport/src/test/test_interest.cc index d9c535881..e36ca0f93 100644 --- a/libtransport/src/test/test_interest.cc +++ b/libtransport/src/test/test_interest.cc @@ -258,5 +258,44 @@ TEST_F(InterestTest, AppendSuffixesEncodeAndIterate) { } } +TEST_F(InterestTest, AppendSuffixesWithGaps) { + // Create interest from buffer + Interest interest(HF_INET6_TCP); + + // Appenad some suffixes, out of order and with gaps + interest.appendSuffix(6); + interest.appendSuffix(2); + interest.appendSuffix(5); + interest.appendSuffix(1); + + // Encode them in wire format + interest.encodeSuffixes(); + EXPECT_TRUE(interest.hasManifest()); + + // Check first suffix correctness + auto suffix = interest.firstSuffix(); + EXPECT_NE(suffix, nullptr); + EXPECT_EQ(*suffix, 1U); + + // Iterate over them. They should be in order and without repetitions + std::vector<uint32_t> expected = {1, 2, 5, 6}; + EXPECT_EQ(interest.numberOfSuffixes(), expected.size()); + + for (uint32_t seq : expected) { + EXPECT_EQ(*suffix, seq); + suffix++; + } +} + +TEST_F(InterestTest, InterestWithoutManifest) { + // Create interest without manifest + Interest interest(HF_INET6_TCP); + auto suffix = interest.firstSuffix(); + + EXPECT_FALSE(interest.hasManifest()); + EXPECT_EQ(interest.numberOfSuffixes(), 0U); + EXPECT_EQ(suffix, nullptr); +} + } // namespace core } // namespace transport diff --git a/libtransport/src/test/test_memif_connector.cc b/libtransport/src/test/test_memif_connector.cc index 562a12c88..40f4df927 100644 --- a/libtransport/src/test/test_memif_connector.cc +++ b/libtransport/src/test/test_memif_connector.cc @@ -83,8 +83,8 @@ class Memif { recv_counter_ += buffers.size(); if (recv_counter_ == total_packets) { auto t1 = utils::SteadyTime::now(); - auto delta = utils::SteadyTime::getDurationS(t0_, t1); - auto rate = recv_counter_ / delta.count(); + auto delta = utils::SteadyTime::getDurationUs(t0_, t1); + double rate = double(recv_counter_) * 1.0e6 / double(delta.count()); LOG(INFO) << "rate: " << rate << " packets/s"; io_service_.stop(); } diff --git a/libtransport/src/test/test_packet_allocator.cc b/libtransport/src/test/test_packet_allocator.cc index b63ddde8d..744f1bd24 100644 --- a/libtransport/src/test/test_packet_allocator.cc +++ b/libtransport/src/test/test_packet_allocator.cc @@ -21,6 +21,7 @@ #define ALLOCATION_CHECKS #include <hicn/transport/core/global_object_pool.h> #undef ALLOCATION_CHECKS +#include <hicn/transport/utils/chrono_typedefs.h> #include <hicn/transport/utils/event_thread.h> namespace transport { @@ -30,6 +31,8 @@ class PacketAllocatorTest : public ::testing::Test { protected: static inline const std::size_t default_size = 2048; static inline const std::size_t default_n_buffer = 1024; + static inline const std::size_t counter = 1024; + static inline const std::size_t total_packets = 1024 * counter; // Get fixed block allocator_ of 1024 buffers of size 2048 bytes PacketAllocatorTest() : allocator_(PacketManager<>::getInstance()) { @@ -102,5 +105,27 @@ TEST_F(PacketAllocatorTest, CheckAllocationIsCorrect) { PacketManager<>::PacketStorage::packet_and_shared_ptr))); } +TEST_F(PacketAllocatorTest, CheckAllocationSpeed) { + // Check time needed to allocate 1 million packeauto &packet_manager = + auto &packet_manager = core::PacketManager<>::getInstance(); + + // Send 1 million packets + std::array<utils::MemBuf::Ptr, counter> packets; + auto t0 = utils::SteadyTime::now(); + std::size_t sum = 0; + for (std::size_t j = 0; j < counter; j++) { + for (std::size_t i = 0; i < counter; i++) { + packets[i] = packet_manager.getMemBuf(); + sum++; + } + } + auto t1 = utils::SteadyTime::now(); + + auto delta = utils::SteadyTime::getDurationUs(t0, t1); + auto rate = double(sum) * 1000000.0 / double(delta.count()); + + LOG(INFO) << "rate: " << rate << " packets/s"; +} + } // namespace core } // namespace transport
\ No newline at end of file diff --git a/libtransport/src/test/test_prefix.cc b/libtransport/src/test/test_prefix.cc new file mode 100644 index 000000000..5de737566 --- /dev/null +++ b/libtransport/src/test/test_prefix.cc @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <glog/logging.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <hicn/transport/core/prefix.h> +#include <hicn/transport/errors/invalid_ip_address_exception.h> +#include <hicn/transport/portability/endianess.h> + +#include <cstring> +#include <memory> +#include <vector> + +namespace transport { +namespace core { + +namespace { +class PrefixTest : public ::testing::Test { + protected: + static inline const char prefix_str0[] = "2001:db8:1::/64"; + static inline const char prefix_str1[] = "10.11.12.0/24"; + static inline const char prefix_str2[] = "2001:db8:1::abcd/64"; + static inline const char prefix_str3[] = "10.11.12.245/27"; + static inline const char wrong_prefix_str0[] = "10.11.12.245/45"; + static inline const char wrong_prefix_str1[] = "10.400.12.13/8"; + static inline const char wrong_prefix_str2[] = "2001:db8:1::/640"; + static inline const char wrong_prefix_str3[] = "20011::db8:1::/16"; + static inline const char wrong_prefix_str4[] = "2001::db8:1::fffff/96"; + + PrefixTest() = default; + + ~PrefixTest() override = default; + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + void SetUp() override { + // Code here will be called immediately after the constructor (right + // before each test). + } + + void TearDown() override { + // Code here will be called immediately after each test (right + // before the destructor). + } +}; + +TEST_F(PrefixTest, ConstructorRightString) { + // Create empty prefix + Prefix p; + + // Create prefix from string + Prefix p0(prefix_str0); + // Reconstruct string and check it is equal to original address + std::string network = p0.getNetwork(); + std::uint16_t prefix_length = p0.getPrefixLength(); + EXPECT_THAT(network + "/" + std::to_string(prefix_length), + ::testing::StrEq(prefix_str0)); + + // Create prefix from string + Prefix p1(prefix_str1); + // Reconstruct string and check it is equal to original address + network = p1.getNetwork(); + prefix_length = p1.getPrefixLength(); + EXPECT_THAT(network + "/" + std::to_string(prefix_length), + ::testing::StrEq(prefix_str1)); + + // Create prefix from string + Prefix p2(prefix_str2); + // Reconstruct string and check it is equal to original address + network = p2.getNetwork(); + prefix_length = p2.getPrefixLength(); + EXPECT_THAT(network + "/" + std::to_string(prefix_length), + ::testing::StrEq(prefix_str2)); + + // Create prefix from string + Prefix p3(prefix_str3); + // Reconstruct string and check it is equal to original address + network = p3.getNetwork(); + prefix_length = p3.getPrefixLength(); + EXPECT_THAT(network + "/" + std::to_string(prefix_length), + ::testing::StrEq(prefix_str3)); + + // Create prefix from string and prefix length + Prefix p4("2001::1234", 66); + // Reconstruct string and check it is equal to original address + network = p4.getNetwork(); + prefix_length = p4.getPrefixLength(); + auto af = p4.getAddressFamily(); + EXPECT_THAT(network, ::testing::StrEq("2001::1234")); + EXPECT_THAT(prefix_length, ::testing::Eq(66)); + EXPECT_THAT(af, ::testing::Eq(AF_INET6)); +} + +TEST_F(PrefixTest, ConstructorWrongString) { + try { + Prefix p0(wrong_prefix_str0); + FAIL() << "Expected exception"; + } catch (const errors::InvalidIpAddressException &) { + // Expected exception + } + + try { + Prefix p1(wrong_prefix_str1); + FAIL() << "Expected exception"; + } catch (const errors::InvalidIpAddressException &) { + // Expected exception + } + + try { + Prefix p2(wrong_prefix_str2); + FAIL() << "Expected exception"; + } catch (const errors::InvalidIpAddressException &) { + // Expected exception + } + + try { + Prefix p3(wrong_prefix_str3); + FAIL() << "Expected exception"; + } catch (const errors::InvalidIpAddressException &) { + // Expected exception + } + + try { + Prefix p4(wrong_prefix_str4); + FAIL() << "Expected exception"; + } catch (const errors::InvalidIpAddressException &) { + // Expected exception + } +} + +TEST_F(PrefixTest, Comparison) { + Prefix p0(prefix_str0); + Prefix p1(prefix_str1); + + // Expect they are different + EXPECT_THAT(p0, ::testing::Ne(p1)); + + auto p2 = p1; + // Expect they are equal + EXPECT_THAT(p1, ::testing::Eq(p2)); +} + +TEST_F(PrefixTest, ToSockAddress) { + Prefix p0(prefix_str3); + + auto ret = p0.toSockaddr(); + auto sockaddr = reinterpret_cast<sockaddr_in *>(ret.get()); + + EXPECT_THAT(sockaddr->sin_family, ::testing::Eq(AF_INET)); + EXPECT_THAT(sockaddr->sin_addr.s_addr, portability::host_to_net(0x0a0b0cf5)); +} + +TEST_F(PrefixTest, GetPrefixLength) { + Prefix p0(prefix_str3); + EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(27)); +} + +TEST_F(PrefixTest, SetPrefixLength) { + Prefix p0(prefix_str3); + EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(27)); + p0.setPrefixLength(20); + EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(20)); + + try { + p0.setPrefixLength(33); + FAIL() << "Expected exception"; + } catch ([[maybe_unused]] const errors::InvalidIpAddressException &) { + // Expected exception + } +} + +TEST_F(PrefixTest, SetGetNetwork) { + Prefix p0(prefix_str0); + EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(64)); + p0.setNetwork("b001::1234"); + EXPECT_THAT(p0.getNetwork(), ::testing::StrEq("b001::1234")); + EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(64)); +} + +TEST_F(PrefixTest, Contains) { + // IPv6 prefix + Prefix p0(prefix_str0); + ip_address_t ip0, ip1; + + ip_address_pton("2001:db8:1::1234", &ip0); + ip_address_pton("2001:db9:1::1234", &ip1); + + EXPECT_TRUE(p0.contains(ip0)); + EXPECT_FALSE(p0.contains(ip1)); + + Prefix p1(prefix_str1); + ip_address_pton("10.11.12.12", &ip0); + ip_address_pton("10.12.12.13", &ip1); + + EXPECT_TRUE(p1.contains(ip0)); + EXPECT_FALSE(p1.contains(ip1)); + + Prefix p2(prefix_str2); + ip_address_pton("2001:db8:1::dbca", &ip0); + ip_address_pton("10.12.12.12", &ip1); + + EXPECT_TRUE(p2.contains(ip0)); + EXPECT_FALSE(p2.contains(ip1)); + + Prefix p3(prefix_str3); + ip_address_pton("10.11.12.245", &ip0); + ip_address_pton("10.11.12.1", &ip1); + + EXPECT_TRUE(p3.contains(ip0)); + EXPECT_FALSE(p3.contains(ip1)); + + // Corner cases + Prefix p4("::/0"); + ip_address_pton("7001:db8:1::1234", &ip0); + ip_address_pton("8001:db8:1::1234", &ip1); + + EXPECT_TRUE(p4.contains(ip0)); + EXPECT_TRUE(p4.contains(ip1)); + + // Corner cases + Prefix p5("b001:a:b:c:d:e:f:1/128"); + ip_address_pton("b001:a:b:c:d:e:f:1", &ip0); + ip_address_pton("b001:a:b:c:d:e:f:2", &ip1); + + EXPECT_TRUE(p5.contains(ip0)); + EXPECT_FALSE(p5.contains(ip1)); +} + +TEST_F(PrefixTest, GetAddressFamily) { + Prefix p0(prefix_str0); + auto af = p0.getAddressFamily(); + EXPECT_THAT(af, ::testing::Eq(AF_INET6)); + + Prefix p1(prefix_str1); + af = p1.getAddressFamily(); + EXPECT_THAT(af, ::testing::Eq(AF_INET)); +} + +TEST_F(PrefixTest, MakeName) { + Prefix p0(prefix_str0); + auto name0 = p0.makeName(); + EXPECT_THAT(name0.toString(), ::testing::StrEq("2001:db8:1::|0")); + + Prefix p1(prefix_str1); + auto name1 = p1.makeName(); + EXPECT_THAT(name1.toString(), ::testing::StrEq("10.11.12.0|0")); + + Prefix p2(prefix_str2); + auto name2 = p2.makeName(); + EXPECT_THAT(name2.toString(), ::testing::StrEq("2001:db8:1::|0")); + + Prefix p3(prefix_str3); + auto name3 = p3.makeName(); + EXPECT_THAT(name3.toString(), ::testing::StrEq("10.11.12.224|0")); + + Prefix p4("b001:a:b:c:d:e:f:1/128"); + auto name4 = p4.makeName(); + EXPECT_THAT(name4.toString(), ::testing::StrEq("b001:a:b:c:d:e:f:1|0")); +} + +TEST_F(PrefixTest, MakeRandomName) { + Prefix p0(prefix_str0); + auto name0 = p0.makeRandomName(); + auto name1 = p0.makeRandomName(); + auto name2 = p0.makeRandomName(); + auto name3 = p0.makeRandomName(); + + EXPECT_THAT(name0, ::testing::Not(::testing::Eq(name1))); + EXPECT_THAT(name0, ::testing::Not(::testing::Eq(name2))); + EXPECT_THAT(name0, ::testing::Not(::testing::Eq(name3))); + EXPECT_THAT(name1, ::testing::Not(::testing::Eq(name2))); + EXPECT_THAT(name1, ::testing::Not(::testing::Eq(name3))); + EXPECT_THAT(name2, ::testing::Not(::testing::Eq(name3))); + + // Corner case + Prefix p2("b001:a:b:c:d:e:f:1/128"); + name0 = p2.makeRandomName(); + name1 = p2.makeRandomName(); + name2 = p2.makeRandomName(); + name3 = p2.makeRandomName(); + + EXPECT_THAT(name0, ::testing::Eq(name1)); + EXPECT_THAT(name0, ::testing::Eq(name2)); + EXPECT_THAT(name0, ::testing::Eq(name3)); + EXPECT_THAT(name1, ::testing::Eq(name2)); + EXPECT_THAT(name1, ::testing::Eq(name3)); + EXPECT_THAT(name2, ::testing::Eq(name3)); +} + +TEST_F(PrefixTest, MakeNameWithIndex) { + Prefix p0(prefix_str0); + auto name0 = p0.makeNameWithIndex(0); + EXPECT_THAT(name0.toString(), ::testing::StrEq("2001:db8:1::|0")); + auto name1 = p0.makeNameWithIndex(1); + EXPECT_THAT(name1.toString(), ::testing::StrEq("2001:db8:1::1|0")); + auto name2 = p0.makeNameWithIndex(2); + EXPECT_THAT(name2.toString(), ::testing::StrEq("2001:db8:1::2|0")); + auto name3 = p0.makeNameWithIndex(3); + EXPECT_THAT(name3.toString(), ::testing::StrEq("2001:db8:1::3|0")); + + Prefix p1(prefix_str1); + name0 = p1.makeNameWithIndex(0); + EXPECT_THAT(name0.toString(), ::testing::StrEq("10.11.12.0|0")); + name1 = p1.makeNameWithIndex(1); + EXPECT_THAT(name1.toString(), ::testing::StrEq("10.11.12.1|0")); + name2 = p1.makeNameWithIndex(2); + EXPECT_THAT(name2.toString(), ::testing::StrEq("10.11.12.2|0")); + name3 = p1.makeNameWithIndex(3); + EXPECT_THAT(name3.toString(), ::testing::StrEq("10.11.12.3|0")); + + // Test truncation + Prefix p2("b001::/96"); + name0 = p2.makeNameWithIndex(0xffffffffffffffff); + EXPECT_THAT(name0.toString(), ::testing::StrEq("b001::ffff:ffff|0")); +} + +} // namespace + +} // namespace core +} // namespace transport
\ No newline at end of file diff --git a/libtransport/src/test/test_quadloop.cc b/libtransport/src/test/test_quadloop.cc new file mode 100644 index 000000000..6a08033aa --- /dev/null +++ b/libtransport/src/test/test_quadloop.cc @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <glog/logging.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <hicn/transport/portability/cache.h> + +#include <array> +#include <cstring> +#include <memory> +#include <vector> + +namespace utils { + +class LoopTest : public ::testing::Test { + protected: + static inline const std::size_t size = 256; + + LoopTest() = default; + + ~LoopTest() override = default; + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + void SetUp() override { + // Code here will be called immediately after the constructor (right + // before each test). + } + + void TearDown() override { + // Code here will be called immediately after each test (right + // before the destructor). + } +}; + +// 1 cache line struct (64 bytes) +struct Data { + std::array<uint64_t, 8> data; +}; + +TEST_F(LoopTest, QuadLoopTest) { + // Create 2 arrays of 256 elements + std::vector<std::unique_ptr<Data>> _from; + std::vector<std::unique_ptr<Data>> _to_next; + _from.reserve(size); + _to_next.reserve(size); + + int n_left_from = size; + int n_left_to_next = size; + + // Initialize the arrays + for (std::size_t i = 0; i < size; i++) { + _from.push_back(std::make_unique<Data>()); + _to_next.push_back(std::make_unique<Data>()); + + for (int j = 0; j < 8; j++) { + _from[i]->data[j] = j; + _to_next[i]->data[j] = 0; + } + } + + const std::unique_ptr<Data> *from = &_from[0]; + const std::unique_ptr<Data> *to_next = &_to_next[0]; + + clock_t start; + clock_t end; + double clocks; + + start = clock(); + // Create a quad loop + while (n_left_from > 0) { + while (n_left_from >= 4 && n_left_to_next >= 4) { + { + using namespace transport::portability::cache; + Data *d2; + Data *d3; + + d2 = from[2].get(); + d3 = from[3].get(); + + prefetch<Data, READ>(d2, sizeof(Data)); + prefetch<Data, READ>(d3, sizeof(Data)); + + d2 = to_next[2].get(); + d3 = to_next[3].get(); + + prefetch<Data, WRITE>(d2, sizeof(Data)); + prefetch<Data, WRITE>(d3, sizeof(Data)); + } + + // Do 4 iterations + std::memcpy(to_next[0].get()->data.data(), from[0].get()->data.data(), + sizeof(Data)); + std::memcpy(to_next[1].get()->data.data(), from[1].get()->data.data(), + sizeof(Data)); + n_left_from -= 2; + n_left_to_next -= 2; + from += 2; + to_next += 2; + } + + while (n_left_from > 0 && n_left_to_next > 0) { + std::memcpy(to_next[0].get()->data.data(), from[0].get()->data.data(), + sizeof(Data)); + n_left_from -= 1; + n_left_to_next -= 1; + from += 1; + to_next += 1; + } + } + end = clock(); + clocks = (double)(end - start); + + LOG(INFO) << "Time with quad loop: " << clocks << std::endl; +} + +TEST_F(LoopTest, NormalLoopTest) { + // Create 2 arrays of 256 elements + std::vector<std::unique_ptr<Data>> _from; + std::vector<std::unique_ptr<Data>> _to_next; + _from.reserve(size); + _to_next.reserve(size); + + int n_left_from = size; + int n_left_to_next = size; + + // Initialize the arrays + for (std::size_t i = 0; i < size; i++) { + _from.push_back(std::make_unique<Data>()); + _to_next.push_back(std::make_unique<Data>()); + + for (int j = 0; j < 8; j++) { + _from[i]->data[j] = j; + _to_next[i]->data[j] = 0; + } + } + + const std::unique_ptr<Data> *from = &_from[0]; + const std::unique_ptr<Data> *to_next = &_to_next[0]; + + clock_t start; + clock_t end; + double clocks; + + start = clock(); + while (n_left_from > 0) { + while (n_left_from > 0 && n_left_to_next > 0) { + std::memcpy(to_next[0].get()->data.data(), from[0].get()->data.data(), + sizeof(Data)); + n_left_from -= 1; + n_left_to_next -= 1; + from += 1; + to_next += 1; + } + } + end = clock(); + clocks = ((double)(end - start)); + + LOG(INFO) << "Time with normal loop: " << clocks << std::endl; +} + +} // namespace utils
\ No newline at end of file diff --git a/libtransport/src/utils/epoll_event_reactor.h b/libtransport/src/utils/epoll_event_reactor.h index 8e7681c20..32d99c837 100644 --- a/libtransport/src/utils/epoll_event_reactor.h +++ b/libtransport/src/utils/epoll_event_reactor.h @@ -49,7 +49,7 @@ class EpollEventReactor : public EventReactor { if (it == event_callback_map_.end()) { { utils::SpinLock::Acquire locked(event_callback_map_lock_); - event_callback_map_[fd] = std::forward<EventHandler &&>(callback); + event_callback_map_[fd] = std::forward<EventHandler>(callback); } ret = addFileDescriptor(fd, events); diff --git a/libtransport/src/utils/fd_deadline_timer.h b/libtransport/src/utils/fd_deadline_timer.h index e15cd4d2a..cf0cde112 100644 --- a/libtransport/src/utils/fd_deadline_timer.h +++ b/libtransport/src/utils/fd_deadline_timer.h @@ -57,8 +57,8 @@ class FdDeadlineTimer : public DeadlineTimer<FdDeadlineTimer> { reactor_.addFileDescriptor( timer_fd_, events, - [callback = std::forward<WaitHandler &&>(callback)]( - const Event &event) -> int { + [callback = + std::forward<WaitHandler>(callback)](const Event &event) -> int { uint64_t s = 0; std::error_code ec; diff --git a/libtransport/src/utils/suffix_strategy.h b/libtransport/src/utils/suffix_strategy.h index 96eaed662..4b3ddbc74 100644 --- a/libtransport/src/utils/suffix_strategy.h +++ b/libtransport/src/utils/suffix_strategy.h @@ -36,11 +36,11 @@ enum class NextSuffixStrategy : uint8_t { class SuffixStrategy { public: static constexpr uint32_t MAX_SUFFIX = std::numeric_limits<uint32_t>::max(); - static constexpr uint8_t MAX_MANIFEST_CAPACITY = + static constexpr uint8_t MANIFEST_MAX_CAPACITY = std::numeric_limits<uint8_t>::max(); SuffixStrategy(NextSuffixStrategy strategy, uint32_t offset = 0, - uint32_t manifest_capacity = MAX_MANIFEST_CAPACITY) + uint32_t manifest_capacity = MANIFEST_MAX_CAPACITY) : suffix_stragegy_(strategy), next_suffix_(offset), manifest_capacity_(manifest_capacity), @@ -130,7 +130,7 @@ class SuffixStrategyFactory { public: static std::unique_ptr<SuffixStrategy> getSuffixStrategy( NextSuffixStrategy strategy, uint32_t start_offset = 0, - uint32_t manifest_capacity = SuffixStrategy::MAX_MANIFEST_CAPACITY) { + uint32_t manifest_capacity = SuffixStrategy::MANIFEST_MAX_CAPACITY) { switch (strategy) { case NextSuffixStrategy::INCREMENTAL: return std::make_unique<IncrementalSuffixStrategy>(start_offset); diff --git a/telemetry/.clang-format b/telemetry/.clang-format new file mode 100644 index 000000000..0043ea3d0 --- /dev/null +++ b/telemetry/.clang-format @@ -0,0 +1,3 @@ +# Copyright (c) 2022 Cisco and/or its affiliates. + +BasedOnStyle: Google
\ No newline at end of file diff --git a/telemetry/CMakeLists.txt b/telemetry/CMakeLists.txt index eff855646..181e726f1 100644 --- a/telemetry/CMakeLists.txt +++ b/telemetry/CMakeLists.txt @@ -11,19 +11,68 @@ # See the License for the specific language governing permissions and # limitations under the License. - +############################################################## +# Project and cmake version +############################################################## cmake_minimum_required(VERSION 3.10 FATAL_ERROR) +project(telemetry) + + +############################################################## +# C Standard +############################################################## +set(CMAKE_C_STANDARD 11) + + +############################################################## +# Cmake modules +############################################################## +include("${CMAKE_CURRENT_SOURCE_DIR}/../versions.cmake") +set(CMAKE_MODULE_PATH + ${CMAKE_MODULE_PATH} + ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules +) + + +############################################################## +# Libs and Bins names +############################################################## +set(COLLECTD_PLUGINS hicn-collectd-plugins CACHE INTERNAL "" FORCE) +set(HICN_LIGHT_TELEMETRY hicn_light) +set(KAFKA_TELEMETRY write_kafka_line_protocol) +set(VPP_TELEMETRY vpp) +set(VPP_HICN_TELEMETRY vpp_hicn) + ############################################################## -# Packaging and versioning +# Dependencies and third party libs ############################################################## +find_package(Collectd ${COLLECTD_DEFAULT_VERSION} REQUIRED) +add_subdirectory(third-party) + + +############################################################## +# Check if building as subproject or as root project +############################################################## +if(NOT (CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) AND + NOT (BUILD_HICNPLUGIN AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")) + return() +endif() +include(CommonSetup) + +# Include config.h in all collectd plugins +set(COLLECTD_COMPILER_OPTIONS -include config.h) + +# ############################################################## +# # Packaging and versioning +# ############################################################## include(${CMAKE_CURRENT_SOURCE_DIR}/../versions.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/packaging.cmake) ############################################################## # Subdirectories ############################################################## -if ((CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) OR - (BUILD_HICNPLUGIN AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")) - add_subdirectory(vpp-collectd) -endif () +add_subdirectory(hicn-light-collectd) +add_subdirectory(kafka-collectd) +add_subdirectory(vpp-collectd)
\ No newline at end of file diff --git a/telemetry/vpp-collectd/cmake/packaging.cmake b/telemetry/cmake/packaging.cmake index 49a617342..d5d2264ce 100644 --- a/telemetry/vpp-collectd/cmake/packaging.cmake +++ b/telemetry/cmake/packaging.cmake @@ -21,11 +21,11 @@ set(${COLLECTD_PLUGINS}_DESCRIPTION ) set(${COLLECTD_PLUGINS}_DEB_DEPENDENCIES - "collectd, hicn-plugin-dev (= stable_version)" + "collectd, hicn-plugin-dev (= stable_version) libhicnctrl (= stable_version) libyajl-dev" CACHE STRING "Dependencies for deb/rpm package." ) set(${COLLECTD_PLUGINS}_RPM_DEPENDENCIES - "collectd, hicn-plugin-dev = stable_version" + "collectd, hicn-plugin-dev (= stable_version) libhicnctrl (= stable_version) libyajl-dev" CACHE STRING "Dependencies for deb/rpm package." )
\ No newline at end of file diff --git a/telemetry/collectd.conf b/telemetry/collectd.conf new file mode 100644 index 000000000..225c161c6 --- /dev/null +++ b/telemetry/collectd.conf @@ -0,0 +1,54 @@ +############################################################################## +# Global # +############################################################################## +FQDNLookup true +#Interval 10 + +# Limit the size of the write queue. Default is no limit. Setting up a limit +# is recommended for servers handling a high volume of traffic. +#WriteQueueLimitHigh 1000000 +#WriteQueueLimitLow 800000 + +############################################################################## +# Logging # +############################################################################## +LoadPlugin logfile + +<Plugin logfile> + LogLevel "info" + File STDOUT + Timestamp true + PrintSeverity true +</Plugin> + +############################################################################## +# LoadPlugin section # +############################################################################## +LoadPlugin write_log + +<LoadPlugin hicn_light> + Globals true # Required to find libhicnctrl symbols + Interval 5 +</LoadPlugin> + +<LoadPlugin write_kafka_line_protocol> + Interval 10 +</LoadPlugin> + +############################################################################## +# Plugin configuration # +############################################################################## +<Plugin write_kafka_line_protocol> + Property "bootstrap.servers" "localhost:8081" + Property "security.protocol" "sasl_plaintext" + Property "sasl.mechanism" "SCRAM-SHA-256" + Property "sasl.username" "eloparco" + Property "sasl.password" "password" + + <Topic "stream"> + Format InfluxDB + </Topic> + # <Topic "metadata"> + # Format hicnJSON + # </Topic> +</Plugin> diff --git a/telemetry/data_model.h b/telemetry/data_model.h new file mode 100644 index 000000000..b1c4ae7e5 --- /dev/null +++ b/telemetry/data_model.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + */ + +#include "utils/common/common.h" + +#define KAFKA_TOPIC_KEY "_TOPIC" +#define KAFKA_STREAM_TOPIC "stream" +#define KAFKA_METADATA_TOPIC "metadata" + +/************** DATA SOURCES ******************************/ +data_source_t packets_dsrc[1] = { + {"packets", DS_TYPE_GAUGE, 0, NAN}, +}; + +data_source_t interests_dsrc[1] = { + {"interests", DS_TYPE_GAUGE, 0, NAN}, +}; + +data_source_t data_dsrc[1] = { + {"data", DS_TYPE_GAUGE, 0, NAN}, +}; + +data_source_t combined_dsrc[2] = { + {"packets", DS_TYPE_DERIVE, 0, NAN}, + {"bytes", DS_TYPE_DERIVE, 0, NAN}, +}; + +/************** DATA SETS NODE ****************************/ +data_set_t pkts_processed_ds = { + "pkts_processed", + STATIC_ARRAY_SIZE(packets_dsrc), + packets_dsrc, +}; + +data_set_t pkts_interest_count_ds = { + "pkts_interest_count", + STATIC_ARRAY_SIZE(packets_dsrc), + packets_dsrc, +}; + +data_set_t pkts_data_count_ds = { + "pkts_data_count", + STATIC_ARRAY_SIZE(packets_dsrc), + packets_dsrc, +}; + +data_set_t pkts_from_cache_count_ds = { + "pkts_from_cache_count", + STATIC_ARRAY_SIZE(packets_dsrc), + packets_dsrc, +}; + +data_set_t pkts_no_pit_count_ds = { + "pkts_no_pit_count", + STATIC_ARRAY_SIZE(packets_dsrc), + packets_dsrc, +}; + +data_set_t pit_expired_count_ds = { + "pit_expired_count", + STATIC_ARRAY_SIZE(interests_dsrc), + interests_dsrc, +}; + +data_set_t cs_expired_count_ds = { + "cs_expired_count", + STATIC_ARRAY_SIZE(data_dsrc), + data_dsrc, +}; + +data_set_t cs_lru_count_ds = { + "cs_lru_count", + STATIC_ARRAY_SIZE(data_dsrc), + data_dsrc, +}; + +data_set_t pkts_drop_no_buf_ds = { + "pkts_drop_no_buf", + STATIC_ARRAY_SIZE(packets_dsrc), + packets_dsrc, +}; + +data_set_t interests_aggregated_ds = { + "interests_aggregated", + STATIC_ARRAY_SIZE(interests_dsrc), + interests_dsrc, +}; + +data_set_t interests_retx_ds = { + "interests_retx", + STATIC_ARRAY_SIZE(interests_dsrc), + interests_dsrc, +}; + +data_set_t interests_hash_collision_ds = { + "interests_hash_collision", + STATIC_ARRAY_SIZE(interests_dsrc), + interests_dsrc, +}; + +data_set_t pit_entries_count_ds = { + "pit_entries_count", + STATIC_ARRAY_SIZE(interests_dsrc), + interests_dsrc, +}; + +data_set_t cs_entries_count_ds = { + "cs_entries_count", + STATIC_ARRAY_SIZE(data_dsrc), + data_dsrc, +}; + +data_set_t cs_entries_ntw_count_ds = { + "cs_entries_ntw_count", + STATIC_ARRAY_SIZE(data_dsrc), + data_dsrc, +}; + +/************** DATA SETS FACE ****************************/ +data_set_t irx_ds = { + "irx", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; + +data_set_t itx_ds = { + "itx", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; + +data_set_t drx_ds = { + "drx", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; + +data_set_t dtx_ds = { + "dtx", + STATIC_ARRAY_SIZE(combined_dsrc), + combined_dsrc, +}; diff --git a/telemetry/hicn-light-collectd/CMakeLists.txt b/telemetry/hicn-light-collectd/CMakeLists.txt new file mode 100644 index 000000000..984d7076c --- /dev/null +++ b/telemetry/hicn-light-collectd/CMakeLists.txt @@ -0,0 +1,65 @@ +# Copyright (c) 2022 Cisco and/or its affiliates. + +############################################################## +# Source files +############################################################## +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light.c +) + + +############################################################## +# Include dirs +############################################################## +list(APPEND INCLUDE_DIRS + ${COLLECTD_INCLUDE_DIRS} + ${THIRD_PARTY_INCLUDE_DIRS} +) + + +############################################################## +# Libraries +############################################################## +find_package(Libhicn ${CURRENT_VERSION} REQUIRED NO_MODULE) +find_package(Libhicnctrl ${CURRENT_VERSION} REQUIRED NO_MODULE) + +if (DISABLE_SHARED_LIBRARIES) + set(LIBTYPE static) +else() + set(LIBTYPE shared) +endif() + +list(APPEND LIBHICN_LIBRARIES hicn::hicn.${LIBTYPE}) +list(APPEND LIBHICNCTRL_LIBRARIES hicn::hicnctrl.${LIBTYPE}) + +list (APPEND LIBRARIES + PRIVATE ${LIBHICNCTRL_LIBRARIES} + PRIVATE ${LIBHICN_LIBRARIES} +) + + +############################################################## +# Compiler options +############################################################## +list(APPEND COMPILER_OPTIONS + ${DEFAULT_COMPILER_OPTIONS} + ${COLLECTD_COMPILER_OPTIONS} +) + + +############################################################## +# Build library +############################################################## +build_library(${HICN_LIGHT_TELEMETRY} + SHARED + EMPTY_PREFIX + SOURCES ${SOURCE_FILES} + LINK_LIBRARIES ${LIBRARIES} + INCLUDE_DIRS + PRIVATE ${INCLUDE_DIRS} + INSTALL_FULL_PATH_DIR ${COLLECTD_PLUGIN_DIR} + COMPONENT ${COLLECTD_PLUGINS} + DEPENDS ${DEPENDENCIES} + LINK_FLAGS ${LINK_FLAGS} + COMPILE_OPTIONS ${COMPILER_OPTIONS} +)
\ No newline at end of file diff --git a/telemetry/hicn-light-collectd/hicn_light.c b/telemetry/hicn-light-collectd/hicn_light.c new file mode 100644 index 000000000..bb4eb571c --- /dev/null +++ b/telemetry/hicn-light-collectd/hicn_light.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + */ + +#define ntohll hicn_ntohll // Rename to avoid collision +#include <hicn/ctrl/api.h> +#include <hicn/ctrl/hicn-light-ng.h> +#include <hicn/util/sstrncpy.h> +#undef ntohll + +#include "../data_model.h" +#include "collectd.h" +#include "plugin.h" +#include "utils/common/common.h" + +#define PLUGIN_NAME "hicn_light" + +static hc_sock_t *s = NULL; + +static void submit(const char *type, value_t *values, size_t values_len, + meta_data_t *meta) { + assert(type != NULL && values != NULL && values_len != 0); + + value_list_t vl = {.values = values, .values_len = values_len}; + if (meta) vl.meta = meta; + + int rc = strcpy_s(vl.plugin, sizeof(vl.plugin), PLUGIN_NAME); + _ASSERT(rc == EOK); + rc = strcpy_s(vl.type, sizeof(vl.type), type); + _ASSERT(rc == EOK); + rc = strcpy_s(vl.host, sizeof(vl.host), hostname_g); + _ASSERT(rc == EOK); + + plugin_dispatch_values(&vl); +} + +static int read_forwarder_global_stats(hc_data_t **pdata, meta_data_t *meta) { + // Retrieve global stats from forwarder + int rc = hc_stats_get(s, pdata); + if (rc < 0) { + plugin_log(LOG_ERR, "Could not read global stats from forwarder"); + return -1; + } + hicn_light_stats_t stats = *((hicn_light_stats_t *)(*pdata)->buffer); + + // Submit values + value_t values[1]; + values[0] = (value_t){.gauge = stats.forwarder.countReceived}; + submit(pkts_processed_ds.type, values, 1, meta); + values[0] = (value_t){.gauge = stats.forwarder.countInterestsReceived}; + submit(pkts_interest_count_ds.type, values, 1, meta); + values[0] = (value_t){.gauge = stats.forwarder.countObjectsReceived}; + submit(pkts_data_count_ds.type, values, 1, meta); + values[0] = + (value_t){.gauge = stats.forwarder.countInterestsSatisfiedFromStore}; + submit(pkts_from_cache_count_ds.type, values, 1, meta); + values[0] = (value_t){.gauge = stats.forwarder.countDroppedNoReversePath}; + submit(pkts_no_pit_count_ds.type, values, 1, meta); + values[0] = (value_t){.gauge = stats.forwarder.countInterestsExpired}; + submit(pit_expired_count_ds.type, values, 1, meta); + values[0] = (value_t){.gauge = stats.forwarder.countDataExpired}; + submit(cs_expired_count_ds.type, values, 1, meta); + values[0] = (value_t){.gauge = stats.pkt_cache.n_lru_evictions}; + submit(cs_lru_count_ds.type, values, 1, meta); + values[0] = (value_t){.gauge = stats.forwarder.countDropped}; + submit(pkts_drop_no_buf_ds.type, values, 1, meta); + values[0] = (value_t){.gauge = stats.forwarder.countInterestsAggregated}; + submit(interests_aggregated_ds.type, values, 1, meta); + values[0] = (value_t){.gauge = stats.forwarder.countInterestsRetransmitted}; + submit(interests_retx_ds.type, values, 1, meta); + values[0] = (value_t){.gauge = stats.pkt_cache.n_pit_entries}; + submit(pit_entries_count_ds.type, values, 1, meta); + values[0] = (value_t){.gauge = stats.pkt_cache.n_cs_entries}; + submit(cs_entries_count_ds.type, values, 1, meta); + + return 0; +} + +static int read_forwarder_per_face_stats(hc_data_t **pdata, meta_data_t *meta) { + // Retrieve per-face stats from forwarder + int rc = hc_stats_list(s, pdata); + if (rc < 0) { + plugin_log(LOG_ERR, "Could not read face stats from forwarder"); + return -1; + } + hc_data_t *data = *pdata; + cmd_stats_list_item_t *conn_stats = (cmd_stats_list_item_t *)data->buffer; + cmd_stats_list_item_t *end = + (cmd_stats_list_item_t *)(data->buffer + + data->size * data->out_element_size); + + // Submit values + while (conn_stats < end) { + rc = meta_data_add_unsigned_int(meta, "face_id", conn_stats->id); + assert(rc == 0); + + value_t values[2]; + values[0] = (value_t){.derive = conn_stats->stats.interests.rx_pkts}; + values[1] = (value_t){.derive = conn_stats->stats.interests.rx_bytes}; + submit(irx_ds.type, values, 2, meta); + values[0] = (value_t){.derive = conn_stats->stats.interests.tx_pkts}; + values[1] = (value_t){.derive = conn_stats->stats.interests.tx_bytes}; + submit(itx_ds.type, values, 2, meta); + values[0] = (value_t){.derive = conn_stats->stats.data.rx_pkts}; + values[1] = (value_t){.derive = conn_stats->stats.data.rx_bytes}; + submit(drx_ds.type, values, 2, meta); + values[0] = (value_t){.derive = conn_stats->stats.data.tx_pkts}; + values[1] = (value_t){.derive = conn_stats->stats.data.tx_bytes}; + submit(dtx_ds.type, values, 2, meta); + + conn_stats++; + } + + return 0; +} + +static int read_forwarder_stats() { + // Create metadata + meta_data_t *meta = meta_data_create(); + int rc = meta_data_add_string(meta, KAFKA_TOPIC_KEY, KAFKA_STREAM_TOPIC); + assert(rc == 0); + + hc_data_t *data = NULL; + rc = read_forwarder_global_stats(&data, meta); + if (rc < 0) goto READ_ERROR; + rc = read_forwarder_per_face_stats(&data, meta); + +READ_ERROR: + meta_data_destroy(meta); + hc_data_free(data); + return rc; +} + +static int connect_to_forwarder() { + plugin_log(LOG_INFO, "Connecting to forwarder"); + s = hc_sock_create_forwarder(HICNLIGHT_NG); + if (!s) { + plugin_log(LOG_ERR, "Could not create socket"); + return -1; + } + + int rc = hc_sock_connect(s); + if (rc < 0) { + plugin_log(LOG_ERR, "Could not establish connection to forwarder"); + hc_sock_free(s); + s = NULL; + return -1; + } + + return 0; +} + +static int disconnect_from_forwarder() { + plugin_log(LOG_INFO, "Disconnecting from forwarder"); + + if (s == NULL) { + plugin_log(LOG_ERR, "Forwarder not connected"); + return -1; + } + + hc_command_t command = {0}; + command.object.connection.id = 0; + int rc = strcpy_s(command.object.connection.name, + sizeof(command.object.connection.name), "SELF"); + if (rc != EOK || hc_connection_delete(s, &command.object.connection) < 0) { + rc = -1; + plugin_log(LOG_ERR, "Error removing local connection to forwarder"); + } + + hc_sock_free(s); + return rc; +} + +void module_register() { + // Data sets + plugin_register_data_set(&pkts_processed_ds); + plugin_register_data_set(&pkts_interest_count_ds); + plugin_register_data_set(&pkts_data_count_ds); + plugin_register_data_set(&pkts_from_cache_count_ds); + plugin_register_data_set(&pkts_no_pit_count_ds); + plugin_register_data_set(&pit_expired_count_ds); + plugin_register_data_set(&cs_expired_count_ds); + plugin_register_data_set(&cs_lru_count_ds); + plugin_register_data_set(&pkts_drop_no_buf_ds); + plugin_register_data_set(&interests_aggregated_ds); + plugin_register_data_set(&interests_retx_ds); + plugin_register_data_set(&interests_hash_collision_ds); + plugin_register_data_set(&pit_entries_count_ds); + plugin_register_data_set(&cs_entries_count_ds); + plugin_register_data_set(&cs_entries_ntw_count_ds); + plugin_register_data_set(&irx_ds); + plugin_register_data_set(&itx_ds); + plugin_register_data_set(&drx_ds); + plugin_register_data_set(&dtx_ds); + + // Callbacks + plugin_register_init(PLUGIN_NAME, connect_to_forwarder); + plugin_register_read(PLUGIN_NAME, read_forwarder_stats); + plugin_register_shutdown(PLUGIN_NAME, disconnect_from_forwarder); +}
\ No newline at end of file diff --git a/telemetry/kafka-collectd/CMakeLists.txt b/telemetry/kafka-collectd/CMakeLists.txt new file mode 100644 index 000000000..f1ff81117 --- /dev/null +++ b/telemetry/kafka-collectd/CMakeLists.txt @@ -0,0 +1,62 @@ +# Copyright (c) 2022 Cisco and/or its affiliates. + +############################################################## +# Source files +############################################################## +file(GLOB_RECURSE COLLECTD_UTILS_SOURCES "${THIRD_PARTY_INCLUDE_DIRS}/utils/cmds/*.c") + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/write_kafka_line_protocol.c + ${THIRD_PARTY_INCLUDE_DIRS}/utils/format_json/format_json.c + ${THIRD_PARTY_INCLUDE_DIRS}/utils/format_graphite/format_graphite.c + ${CMAKE_CURRENT_SOURCE_DIR}/format_influxdb.c + ${COLLECTD_UTILS_SOURCES} +) + + +############################################################## +# Include dirs +############################################################## +list(APPEND INCLUDE_DIRS + PRIVATE ${COLLECTD_INCLUDE_DIRS} + PRIVATE ${THIRD_PARTY_INCLUDE_DIRS} +) + + +############################################################## +# Libraries +############################################################## +find_package(RdKafka ${RDKAFKA_DEFAULT_VERSION} REQUIRED) +find_library(YAJL_LIB libyajl.so REQUIRED) + +list (APPEND LIBRARIES + ${YAJL_LIB} + ${RdKafka_LIBRARY_PATH} +) + + +############################################################## +# Compiler options +############################################################## +list(APPEND COMPILER_OPTIONS + ${DEFAULT_COMPILER_OPTIONS} + ${COLLECTD_COMPILER_OPTIONS} +) + + +############################################################## +# Build library +############################################################## +build_library(${KAFKA_TELEMETRY} + SHARED + EMPTY_PREFIX + SOURCES ${SOURCE_FILES} + LINK_LIBRARIES ${LIBRARIES} + INCLUDE_DIRS + PRIVATE ${INCLUDE_DIRS} + INSTALL_FULL_PATH_DIR ${COLLECTD_PLUGIN_DIR} + COMPONENT ${COLLECTD_PLUGINS} + DEPENDS ${DEPENDENCIES} + LINK_FLAGS ${LINK_FLAGS} + COMPILE_OPTIONS ${COMPILER_OPTIONS} +) diff --git a/telemetry/kafka-collectd/format_influxdb.c b/telemetry/kafka-collectd/format_influxdb.c new file mode 100644 index 000000000..f7ff29501 --- /dev/null +++ b/telemetry/kafka-collectd/format_influxdb.c @@ -0,0 +1,190 @@ +/** + * collectd - src/utils_format_influxdb.c + * Copyright (C) 2007-2009 Florian octo Forster + * Copyright (C) 2009 Aman Gupta + * Copyright (C) 2019 Carlos Peon Costa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; only version 2 of the License is applicable. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster <octo at collectd.org> + * Aman Gupta <aman at tmm1.net> + * Carlos Peon Costa <carlospeon at gmail.com> + * multiple Server directives by: + * Paul (systemcrash) <newtwen thatfunny_at_symbol gmail.com> + **/ + +#include "format_influxdb.h" + +#include "collectd.h" +#include "plugin.h" +#include "utils/common/common.h" +#include "utils/metadata/meta_data.h" +#include "utils_cache.h" + +static int format_influxdb_escape_string(char *buffer, size_t buffer_size, + const char *string) { + if ((buffer == NULL) || (string == NULL)) return -EINVAL; + + if (buffer_size < 3) return -ENOMEM; + + int dst_pos = 0; + +#define BUFFER_ADD(c) \ + do { \ + if (dst_pos >= (buffer_size - 1)) { \ + buffer[buffer_size - 1] = '\0'; \ + return -ENOMEM; \ + } \ + buffer[dst_pos] = (c); \ + dst_pos++; \ + } while (0) + + /* Escape special characters */ + for (int src_pos = 0; string[src_pos] != 0; src_pos++) { + if ((string[src_pos] == '\\') || (string[src_pos] == ' ') || + (string[src_pos] == ',') || (string[src_pos] == '=') || + (string[src_pos] == '"')) { + BUFFER_ADD('\\'); + BUFFER_ADD(string[src_pos]); + } else + BUFFER_ADD(string[src_pos]); + } /* for */ + buffer[dst_pos] = 0; + +#undef BUFFER_ADD + + return dst_pos; +} /* int format_influxdb_escape_string */ + +int format_influxdb_value_list( + char *buffer, int buffer_len, const data_set_t *ds, const value_list_t *vl, + bool store_rates, format_influxdb_time_precision_t time_precision) { + int status; + int offset = 0; + gauge_t *rates = NULL; + bool have_values = false; + + assert(0 == strcmp(ds->type, vl->type)); + +#define BUFFER_ADD_ESCAPE(...) \ + do { \ + status = format_influxdb_escape_string(buffer + offset, \ + buffer_len - offset, __VA_ARGS__); \ + if (status < 0) return status; \ + offset += status; \ + } while (0) + +#define BUFFER_ADD(...) \ + do { \ + status = snprintf(buffer + offset, buffer_len - offset, __VA_ARGS__); \ + if ((status < 0) || (status >= (buffer_len - offset))) { \ + sfree(rates); \ + return -ENOMEM; \ + } \ + offset += status; \ + } while (0) + + assert(vl->type); + BUFFER_ADD_ESCAPE(vl->type); + BUFFER_ADD(",host="); + BUFFER_ADD_ESCAPE(vl->host); + if (vl->meta) { + char **toc; + int n = meta_data_toc(vl->meta, &toc); + + for (int i = 0; i < n; i++) { + char *key = toc[i]; + char *value; + + if (meta_data_as_string(vl->meta, key, &value) == 0) { + BUFFER_ADD(","); + BUFFER_ADD_ESCAPE(key); + BUFFER_ADD("="); + BUFFER_ADD_ESCAPE(value); + free(value); + } + free(toc[i]); + } + + if (n != 0) free(toc); + } + + BUFFER_ADD(" "); + for (size_t i = 0; i < ds->ds_num; i++) { + if ((ds->ds[i].type != DS_TYPE_COUNTER) && + (ds->ds[i].type != DS_TYPE_GAUGE) && + (ds->ds[i].type != DS_TYPE_DERIVE) && + (ds->ds[i].type != DS_TYPE_ABSOLUTE)) { + sfree(rates); + return -EINVAL; + } + + if (ds->ds[i].type == DS_TYPE_GAUGE) { + if (isnan(vl->values[i].gauge)) continue; + if (have_values) BUFFER_ADD(","); + BUFFER_ADD("%s=%lf", ds->ds[i].name, vl->values[i].gauge); + have_values = true; + } else if (store_rates) { + if (rates == NULL) rates = uc_get_rate(ds, vl); + if (rates == NULL) { + WARNING( + "format_influxdb: " + "uc_get_rate failed."); + return -EINVAL; + } + if (isnan(rates[i])) continue; + if (have_values) BUFFER_ADD(","); + BUFFER_ADD("%s=%lf", ds->ds[i].name, rates[i]); + have_values = true; + } else if (ds->ds[i].type == DS_TYPE_COUNTER) { + if (have_values) BUFFER_ADD(","); + BUFFER_ADD("%s=%" PRIu64 "i", ds->ds[i].name, + (uint64_t)vl->values[i].counter); + have_values = true; + } else if (ds->ds[i].type == DS_TYPE_DERIVE) { + if (have_values) BUFFER_ADD(","); + BUFFER_ADD("%s=%" PRIi64 "i", ds->ds[i].name, vl->values[i].derive); + have_values = true; + } else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) { + if (have_values) BUFFER_ADD(","); + BUFFER_ADD("%s=%" PRIu64 "i", ds->ds[i].name, vl->values[i].absolute); + have_values = true; + } + + } /* for ds->ds_num */ + sfree(rates); + + if (!have_values) return 0; + + uint64_t influxdb_time = 0; + switch (time_precision) { + case NS: + influxdb_time = CDTIME_T_TO_NS(vl->time); + break; + case US: + influxdb_time = CDTIME_T_TO_US(vl->time); + break; + case MS: + influxdb_time = CDTIME_T_TO_MS(vl->time); + break; + } + + BUFFER_ADD(" %" PRIu64 "\n", influxdb_time); + +#undef BUFFER_ADD_ESCAPE +#undef BUFFER_ADD + + return offset; +} /* int format_influxdb_value_list */ diff --git a/telemetry/kafka-collectd/format_influxdb.h b/telemetry/kafka-collectd/format_influxdb.h new file mode 100644 index 000000000..fd298f11b --- /dev/null +++ b/telemetry/kafka-collectd/format_influxdb.h @@ -0,0 +1,45 @@ +/** + * collectd - src/utils_format_influxdb.h + * Copyright (C) 2007-2009 Florian octo Forster + * Copyright (C) 2009 Aman Gupta + * Copyright (C) 2019 Carlos Peon Costa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; only version 2 of the License is applicable. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster <octo at collectd.org> + * Aman Gupta <aman at tmm1.net> + * Carlos Peon Costa <carlospeon at gmail.com> + * multiple Server directives by: + * Paul (systemcrash) <newtwen thatfunny_at_symbol gmail.com> + **/ + +#ifndef UTILS_FORMAT_INFLUXDB_H +#define UTILS_FORMAT_INFLUXDB_H 1 + +#include "collectd.h" +#include "plugin.h" + +typedef enum { + NS, + US, + MS, +} format_influxdb_time_precision_t; + +int format_influxdb_value_list(char *buffer, int buffer_len, + const data_set_t *ds, const value_list_t *vl, + bool store_rates, + format_influxdb_time_precision_t time_precision); + +#endif /* UTILS_FORMAT_INFLUXDB_H */ diff --git a/telemetry/kafka-collectd/write_kafka_line_protocol.c b/telemetry/kafka-collectd/write_kafka_line_protocol.c new file mode 100644 index 000000000..5eb7b520d --- /dev/null +++ b/telemetry/kafka-collectd/write_kafka_line_protocol.c @@ -0,0 +1,526 @@ +/** + * collectd - src/write_kafka.c + * Copyright (C) 2014 Pierre-Yves Ritschard + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Pierre-Yves Ritschard <pyr at spootnik.org> + */ + +#include <errno.h> +#include <librdkafka/rdkafka.h> +#include <stdint.h> + +#include "../data_model.h" +#include "collectd.h" +#include "format_influxdb.h" +#include "plugin.h" +#include "utils/cmds/putval.h" +#include "utils/common/common.h" +#include "utils/format_graphite/format_graphite.h" +#include "utils/format_json/format_json.h" +#include "utils_random.h" + +struct kafka_topic_context { +#define KAFKA_FORMAT_JSON 0 +#define KAFKA_FORMAT_COMMAND 1 +#define KAFKA_FORMAT_GRAPHITE 2 +#define KAFKA_FORMAT_INFLUXDB 3 + uint8_t format; + unsigned int graphite_flags; + bool store_rates; + rd_kafka_topic_conf_t *conf; + rd_kafka_topic_t *topic; + rd_kafka_conf_t *kafka_conf; + rd_kafka_t *kafka; + char *key; + char *prefix; + char *postfix; + char escape_char; + char *topic_name; + pthread_mutex_t lock; +}; + +static int kafka_handle(struct kafka_topic_context *); +static int kafka_write(const data_set_t *, const value_list_t *, user_data_t *); +static int32_t kafka_partition(const rd_kafka_topic_t *, const void *, size_t, + int32_t, void *, void *); + +/* Version 0.9.0 of librdkafka deprecates rd_kafka_set_logger() in favor of + * rd_kafka_conf_set_log_cb(). This is to make sure we're not using the + * deprecated function. */ +#ifdef HAVE_LIBRDKAFKA_LOG_CB +#undef HAVE_LIBRDKAFKA_LOGGER +#endif + +#if defined(HAVE_LIBRDKAFKA_LOGGER) || defined(HAVE_LIBRDKAFKA_LOG_CB) +static void kafka_log(const rd_kafka_t *, int, const char *, const char *); + +static void kafka_log(const rd_kafka_t *rkt, int level, const char *fac, + const char *msg) { + plugin_log(level, "%s", msg); +} +#endif + +static rd_kafka_resp_err_t kafka_error() { +#if RD_KAFKA_VERSION >= 0x000b00ff + return rd_kafka_last_error(); +#else + return rd_kafka_errno2err(errno); +#endif +} + +static uint32_t kafka_hash(const char *keydata, size_t keylen) { + uint32_t hash = 5381; + for (; keylen > 0; keylen--) + hash = ((hash << 5) + hash) + keydata[keylen - 1]; + return hash; +} + +/* 31 bit -> 4 byte -> 8 byte hex string + null byte */ +#define KAFKA_RANDOM_KEY_SIZE 9 +#define KAFKA_RANDOM_KEY_BUFFER \ + (char[KAFKA_RANDOM_KEY_SIZE]) { "" } +static char *kafka_random_key(char buffer[static KAFKA_RANDOM_KEY_SIZE]) { + ssnprintf(buffer, KAFKA_RANDOM_KEY_SIZE, "%08" PRIX32, cdrand_u()); + return buffer; +} + +static int32_t kafka_partition(const rd_kafka_topic_t *rkt, const void *keydata, + size_t keylen, int32_t partition_cnt, void *p, + void *m) { + uint32_t key = kafka_hash(keydata, keylen); + uint32_t target = key % partition_cnt; + int32_t i = partition_cnt; + + while (--i > 0 && !rd_kafka_topic_partition_available(rkt, target)) { + target = (target + 1) % partition_cnt; + } + return target; +} + +static int kafka_handle(struct kafka_topic_context *ctx) /* {{{ */ +{ + char errbuf[1024]; + rd_kafka_conf_t *conf; + rd_kafka_topic_conf_t *topic_conf; + + if (ctx->kafka != NULL && ctx->topic != NULL) return 0; + + if (ctx->kafka == NULL) { + if ((conf = rd_kafka_conf_dup(ctx->kafka_conf)) == NULL) { + ERROR("write_kafka plugin: cannot duplicate kafka config"); + return 1; + } + + if ((ctx->kafka = rd_kafka_new(RD_KAFKA_PRODUCER, conf, errbuf, + sizeof(errbuf))) == NULL) { + ERROR("write_kafka plugin: cannot create kafka handle."); + return 1; + } + + rd_kafka_conf_destroy(ctx->kafka_conf); + ctx->kafka_conf = NULL; + + INFO("write_kafka plugin: created KAFKA handle : %s", + rd_kafka_name(ctx->kafka)); + +#if defined(HAVE_LIBRDKAFKA_LOGGER) && !defined(HAVE_LIBRDKAFKA_LOG_CB) + rd_kafka_set_logger(ctx->kafka, kafka_log); +#endif + } + + if (ctx->topic == NULL) { + if ((topic_conf = rd_kafka_topic_conf_dup(ctx->conf)) == NULL) { + ERROR("write_kafka plugin: cannot duplicate kafka topic config"); + return 1; + } + + if ((ctx->topic = rd_kafka_topic_new(ctx->kafka, ctx->topic_name, + topic_conf)) == NULL) { + ERROR("write_kafka plugin: cannot create topic : %s\n", + rd_kafka_err2str(kafka_error())); + return errno; + } + + rd_kafka_topic_conf_destroy(ctx->conf); + ctx->conf = NULL; + + INFO("write_kafka plugin: handle created for topic : %s", + rd_kafka_topic_name(ctx->topic)); + } + + return 0; + +} /* }}} int kafka_handle */ + +static int kafka_write(const data_set_t *ds, /* {{{ */ + const value_list_t *vl, user_data_t *ud) { + int status = 0; + void *key; + size_t keylen = 0; + char buffer[8192]; + size_t bfree = sizeof(buffer); + size_t bfill = 0; + size_t blen = 0; + struct kafka_topic_context *ctx = ud->data; + + if ((ds == NULL) || (vl == NULL) || (ctx == NULL)) return EINVAL; + + pthread_mutex_lock(&ctx->lock); + status = kafka_handle(ctx); + pthread_mutex_unlock(&ctx->lock); + if (status != 0) return status; + + bzero(buffer, sizeof(buffer)); + + switch (ctx->format) { + case KAFKA_FORMAT_COMMAND: + status = cmd_create_putval(buffer, sizeof(buffer), ds, vl); + if (status != 0) { + ERROR("write_kafka plugin: cmd_create_putval failed with status %i.", + status); + return status; + } + blen = strlen(buffer); + break; + case KAFKA_FORMAT_JSON: + format_json_initialize(buffer, &bfill, &bfree); + format_json_value_list(buffer, &bfill, &bfree, ds, vl, ctx->store_rates); + format_json_finalize(buffer, &bfill, &bfree); + blen = strlen(buffer); + break; + case KAFKA_FORMAT_GRAPHITE: + status = + format_graphite(buffer, sizeof(buffer), ds, vl, ctx->prefix, + ctx->postfix, ctx->escape_char, ctx->graphite_flags); + if (status != 0) { + ERROR("write_kafka plugin: format_graphite failed with status %i.", + status); + return status; + } + blen = strlen(buffer); + break; + case KAFKA_FORMAT_INFLUXDB: { + // Decide format depending on the topic + // (to handle multilple topics w/ different formats); + // Comment this part to use the stream topic as default for other + // collectd plugins (e.g. cpu, mem) + char *topic = NULL; + int rc = meta_data_get_string(vl->meta, KAFKA_TOPIC_KEY, &topic); + if (rc != 0 || topic == NULL) return 0; + if (strcasecmp(KAFKA_STREAM_TOPIC, topic) != 0) { + free(topic); + return 0; + } + meta_data_delete(vl->meta, KAFKA_TOPIC_KEY); + + status = + format_influxdb_value_list(buffer, sizeof(buffer), ds, vl, false, NS); + if (status <= 0) { + ERROR("write_kafka plugin: format_influxdb failed with status %i.", + status); + return status; + } + blen = strlen(buffer); + + // Print without newline + buffer[blen - 1] = 0; + INFO("%s", buffer); + buffer[blen - 1] = '\n'; + + break; + } + default: + ERROR("write_kafka plugin: invalid format %i.", ctx->format); + return -1; + } + + key = + (ctx->key != NULL) ? ctx->key : kafka_random_key(KAFKA_RANDOM_KEY_BUFFER); + keylen = strlen(key); + + rd_kafka_produce(ctx->topic, RD_KAFKA_PARTITION_UA, RD_KAFKA_MSG_F_COPY, + buffer, blen, key, keylen, NULL); + + return status; +} /* }}} int kafka_write */ + +static void kafka_topic_context_free(void *p) /* {{{ */ +{ + struct kafka_topic_context *ctx = p; + + if (ctx == NULL) return; + + if (ctx->topic_name != NULL) sfree(ctx->topic_name); + if (ctx->topic != NULL) rd_kafka_topic_destroy(ctx->topic); + if (ctx->conf != NULL) rd_kafka_topic_conf_destroy(ctx->conf); + if (ctx->kafka_conf != NULL) rd_kafka_conf_destroy(ctx->kafka_conf); + if (ctx->kafka != NULL) rd_kafka_destroy(ctx->kafka); + + sfree(ctx); +} /* }}} void kafka_topic_context_free */ + +static void kafka_config_topic(rd_kafka_conf_t *conf, + oconfig_item_t *ci) /* {{{ */ +{ + int status; + struct kafka_topic_context *tctx; + char *key = NULL; + char *val; + char callback_name[DATA_MAX_NAME_LEN]; + char errbuf[1024]; + oconfig_item_t *child; + rd_kafka_conf_res_t ret; + + if ((tctx = calloc(1, sizeof(*tctx))) == NULL) { + ERROR("write_kafka plugin: calloc failed."); + return; + } + + tctx->escape_char = '.'; + tctx->store_rates = true; + tctx->format = KAFKA_FORMAT_JSON; + tctx->key = NULL; + + if ((tctx->kafka_conf = rd_kafka_conf_dup(conf)) == NULL) { + sfree(tctx); + ERROR("write_kafka plugin: cannot allocate memory for kafka config"); + return; + } + +#ifdef HAVE_LIBRDKAFKA_LOG_CB + rd_kafka_conf_set_log_cb(tctx->kafka_conf, kafka_log); +#endif + + if ((tctx->conf = rd_kafka_topic_conf_new()) == NULL) { + rd_kafka_conf_destroy(tctx->kafka_conf); + sfree(tctx); + ERROR("write_kafka plugin: cannot create topic configuration."); + return; + } + + if (ci->values_num != 1) { + WARNING("kafka topic name needed."); + goto errout; + } + + if (ci->values[0].type != OCONFIG_TYPE_STRING) { + WARNING("kafka topic needs a string argument."); + goto errout; + } + + if ((tctx->topic_name = strdup(ci->values[0].value.string)) == NULL) { + ERROR("write_kafka plugin: cannot copy topic name."); + goto errout; + } + + for (int i = 0; i < ci->children_num; i++) { + /* + * The code here could be simplified but makes room + * for easy adding of new options later on. + */ + child = &ci->children[i]; + status = 0; + + if (strcasecmp("Property", child->key) == 0) { + if (child->values_num != 2) { + WARNING("kafka properties need both a key and a value."); + goto errout; + } + if (child->values[0].type != OCONFIG_TYPE_STRING || + child->values[1].type != OCONFIG_TYPE_STRING) { + WARNING("kafka properties needs string arguments."); + goto errout; + } + key = child->values[0].value.string; + val = child->values[1].value.string; + ret = + rd_kafka_topic_conf_set(tctx->conf, key, val, errbuf, sizeof(errbuf)); + if (ret != RD_KAFKA_CONF_OK) { + WARNING("cannot set kafka topic property %s to %s: %s.", key, val, + errbuf); + goto errout; + } + + } else if (strcasecmp("Key", child->key) == 0) { + if (cf_util_get_string(child, &tctx->key) != 0) continue; + if (strcasecmp("Random", tctx->key) == 0) { + sfree(tctx->key); + tctx->key = strdup(kafka_random_key(KAFKA_RANDOM_KEY_BUFFER)); + } + } else if (strcasecmp("Format", child->key) == 0) { + status = cf_util_get_string(child, &key); + if (status != 0) goto errout; + + assert(key != NULL); + + if (strcasecmp(key, "Command") == 0) { + tctx->format = KAFKA_FORMAT_COMMAND; + + } else if (strcasecmp(key, "Graphite") == 0) { + tctx->format = KAFKA_FORMAT_GRAPHITE; + + } else if (strcasecmp(key, "Json") == 0) { + tctx->format = KAFKA_FORMAT_JSON; + + } else if (strcasecmp(key, "InfluxDB") == 0) { + tctx->format = KAFKA_FORMAT_INFLUXDB; + + } else { + WARNING("write_kafka plugin: Invalid format string: %s", key); + } + + sfree(key); + + } else if (strcasecmp("StoreRates", child->key) == 0) { + status = cf_util_get_boolean(child, &tctx->store_rates); + (void)cf_util_get_flag(child, &tctx->graphite_flags, + GRAPHITE_STORE_RATES); + + } else if (strcasecmp("GraphiteSeparateInstances", child->key) == 0) { + status = cf_util_get_flag(child, &tctx->graphite_flags, + GRAPHITE_SEPARATE_INSTANCES); + + } else if (strcasecmp("GraphiteAlwaysAppendDS", child->key) == 0) { + status = cf_util_get_flag(child, &tctx->graphite_flags, + GRAPHITE_ALWAYS_APPEND_DS); + + } else if (strcasecmp("GraphitePreserveSeparator", child->key) == 0) { + status = cf_util_get_flag(child, &tctx->graphite_flags, + GRAPHITE_PRESERVE_SEPARATOR); + + } else if (strcasecmp("GraphiteUseTags", child->key) == 0) { + status = + cf_util_get_flag(child, &tctx->graphite_flags, GRAPHITE_USE_TAGS); + + } else if (strcasecmp("GraphitePrefix", child->key) == 0) { + status = cf_util_get_string(child, &tctx->prefix); + } else if (strcasecmp("GraphitePostfix", child->key) == 0) { + status = cf_util_get_string(child, &tctx->postfix); + } else if (strcasecmp("GraphiteEscapeChar", child->key) == 0) { + char *tmp_buff = NULL; + status = cf_util_get_string(child, &tmp_buff); + if (strlen(tmp_buff) > 1) + WARNING( + "write_kafka plugin: The option \"GraphiteEscapeChar\" handles " + "only one character. Others will be ignored."); + tctx->escape_char = tmp_buff[0]; + sfree(tmp_buff); + } else { + WARNING("write_kafka plugin: Invalid directive: %s.", child->key); + } + + if (status != 0) break; + } + + rd_kafka_topic_conf_set_partitioner_cb(tctx->conf, kafka_partition); + rd_kafka_topic_conf_set_opaque(tctx->conf, tctx); + + ssnprintf(callback_name, sizeof(callback_name), "write_kafka/%s", + tctx->topic_name); + + status = plugin_register_write(callback_name, kafka_write, + &(user_data_t){ + .data = tctx, + .free_func = kafka_topic_context_free, + }); + if (status != 0) { + WARNING( + "write_kafka plugin: plugin_register_write (\"%s\") " + "failed with status %i.", + callback_name, status); + goto errout; + } + + pthread_mutex_init(&tctx->lock, /* attr = */ NULL); + + return; +errout: + if (tctx->topic_name != NULL) free(tctx->topic_name); + if (tctx->conf != NULL) rd_kafka_topic_conf_destroy(tctx->conf); + if (tctx->kafka_conf != NULL) rd_kafka_conf_destroy(tctx->kafka_conf); + sfree(tctx); +} /* }}} int kafka_config_topic */ + +static int kafka_config(oconfig_item_t *ci) /* {{{ */ +{ + oconfig_item_t *child; + rd_kafka_conf_t *conf; + rd_kafka_conf_res_t ret; + char errbuf[1024]; + + if ((conf = rd_kafka_conf_new()) == NULL) { + WARNING("cannot allocate kafka configuration."); + return -1; + } + for (int i = 0; i < ci->children_num; i++) { + child = &ci->children[i]; + + if (strcasecmp("Topic", child->key) == 0) { + kafka_config_topic(conf, child); + } else if (strcasecmp(child->key, "Property") == 0) { + char *key = NULL; + char *val = NULL; + + if (child->values_num != 2) { + WARNING("kafka properties need both a key and a value."); + goto errout; + } + if (child->values[0].type != OCONFIG_TYPE_STRING || + child->values[1].type != OCONFIG_TYPE_STRING) { + WARNING("kafka properties needs string arguments."); + goto errout; + } + if ((key = strdup(child->values[0].value.string)) == NULL) { + WARNING("cannot allocate memory for attribute key."); + goto errout; + } + if ((val = strdup(child->values[1].value.string)) == NULL) { + WARNING("cannot allocate memory for attribute value."); + sfree(key); + goto errout; + } + ret = rd_kafka_conf_set(conf, key, val, errbuf, sizeof(errbuf)); + if (ret != RD_KAFKA_CONF_OK) { + WARNING("cannot set kafka property %s to %s: %s", key, val, errbuf); + sfree(key); + sfree(val); + goto errout; + } + sfree(key); + sfree(val); + } else { + WARNING( + "write_kafka plugin: Ignoring unknown " + "configuration option \"%s\" at top level.", + child->key); + } + } + if (conf != NULL) rd_kafka_conf_destroy(conf); + return 0; +errout: + if (conf != NULL) rd_kafka_conf_destroy(conf); + return -1; +} /* }}} int kafka_config */ + +void module_register(void) { + plugin_register_complex_config("write_kafka_line_protocol", kafka_config); +} diff --git a/telemetry/third-party/CMakeLists.txt b/telemetry/third-party/CMakeLists.txt new file mode 100644 index 000000000..26d305d62 --- /dev/null +++ b/telemetry/third-party/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright (c) 2022 Cisco and/or its affiliates. + +set(THIRD_PARTY_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}) + +include(FetchContent) +set(FETCHCONTENT_QUIET off) +FetchContent_Declare(collectd + URL https://github.com/collectd/collectd/archive/refs/tags/collectd-${COLLECTD_VERSION}.zip + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" +) +FetchContent_Populate(collectd) + +list(APPEND THIRD_PARTY_INCLUDE_DIRS + ${collectd_SOURCE_DIR}/src +) +set(THIRD_PARTY_INCLUDE_DIRS ${THIRD_PARTY_INCLUDE_DIRS} PARENT_SCOPE) diff --git a/telemetry/vpp-collectd/CMakeLists.txt b/telemetry/vpp-collectd/CMakeLists.txt index 54a1a4b76..4ce357f63 100644 --- a/telemetry/vpp-collectd/CMakeLists.txt +++ b/telemetry/vpp-collectd/CMakeLists.txt @@ -11,34 +11,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -project(hicn-collectd-plugins) - - -############################################################## -# CMake Modules -############################################################## -set(CMAKE_MODULE_PATH - ${CMAKE_MODULE_PATH} - ${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/Modules/) - - ############################################################## # Dependencies ############################################################## find_package(Vpp ${VPP_DEFAULT_VERSION} REQUIRED) -find_package(Collectd ${COLLECTD_DEFAULT_VERSION} REQUIRED) - - -############################################################## -# Libs and bins names -############################################################## -set(COLLECTD_PLUGINS hicn-collectd-plugins) - - -############################################################## -# Packaging -############################################################## -include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/packaging.cmake) ############################################################## diff --git a/telemetry/vpp-collectd/common/README.md b/telemetry/vpp-collectd/common/README.md deleted file mode 100644 index e3b9c74f6..000000000 --- a/telemetry/vpp-collectd/common/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Headers for collectd plugins - -These headers are required for plugin development but are not shipped with the -`collectd` Ubuntu 20.04 package (as of May 2021): - -* [common.h](https://github.com/collectd/collectd/blob/main/src/utils/common/common.h) -* [plugin.h](https://github.com/collectd/collectd/blob/main/src/daemon/plugin.h) -* [meta_data.h](https://github.com/collectd/collectd/blob/main/src/utils/metadata/meta_data.h) - -Related issues: -* [GitHub](https://github.com/collectd/collectd/issues/3881) -* [Ubuntu](https://bugs.launchpad.net/ubuntu/+source/collectd/+bug/1929079) diff --git a/telemetry/vpp-collectd/common/common.h b/telemetry/vpp-collectd/common/common.h deleted file mode 100644 index fce2d12bb..000000000 --- a/telemetry/vpp-collectd/common/common.h +++ /dev/null @@ -1,405 +0,0 @@ -/** - * collectd - src/common.h - * Copyright (C) 2005-2014 Florian octo Forster - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * Florian octo Forster <octo at collectd.org> - * Niki W. Waibel <niki.waibel@gmx.net> - **/ - -#ifndef COMMON_H -#define COMMON_H - -#include "collectd.h" - -#include "plugin.h" - -#if HAVE_PWD_H -#include <pwd.h> -#endif - -#define sfree(ptr) \ - do { \ - free(ptr); \ - (ptr) = NULL; \ - } while (0) - -#define STATIC_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) - -#define IS_TRUE(s) \ - ((strcasecmp("true", (s)) == 0) || (strcasecmp("yes", (s)) == 0) || \ - (strcasecmp("on", (s)) == 0)) -#define IS_FALSE(s) \ - ((strcasecmp("false", (s)) == 0) || (strcasecmp("no", (s)) == 0) || \ - (strcasecmp("off", (s)) == 0)) - -struct rate_to_value_state_s { - value_t last_value; - cdtime_t last_time; - gauge_t residual; -}; -typedef struct rate_to_value_state_s rate_to_value_state_t; - -struct value_to_rate_state_s { - value_t last_value; - cdtime_t last_time; -}; -typedef struct value_to_rate_state_s value_to_rate_state_t; - -char *sstrncpy(char *dest, const char *src, size_t n); - -__attribute__((format(printf, 3, 4))) int ssnprintf(char *str, size_t size, - char const *format, ...); - -__attribute__((format(printf, 1, 2))) char *ssnprintf_alloc(char const *format, - ...); - -char *sstrdup(const char *s); -size_t sstrnlen(const char *s, size_t n); -char *sstrndup(const char *s, size_t n); -void *smalloc(size_t size); -char *sstrerror(int errnum, char *buf, size_t buflen); - -#ifndef ERRBUF_SIZE -#define ERRBUF_SIZE 256 -#endif - -#define STRERROR(e) sstrerror((e), (char[ERRBUF_SIZE]){0}, ERRBUF_SIZE) -#define STRERRNO STRERROR(errno) - -/* - * NAME - * sread - * - * DESCRIPTION - * Reads exactly `n' bytes or fails. Syntax and other behavior is analogous - * to `read(2)'. - * - * PARAMETERS - * `fd' File descriptor to write to. - * `buf' Buffer that is to be written. - * `count' Number of bytes in the buffer. - * - * RETURN VALUE - * Zero upon success or non-zero if an error occurred. `errno' is set in this - * case. - */ -int sread(int fd, void *buf, size_t count); - -/* - * NAME - * swrite - * - * DESCRIPTION - * Writes exactly `n' bytes or fails. Syntax and other behavior is analogous - * to `write(2)'. - * - * PARAMETERS - * `fd' File descriptor to write to. - * `buf' Buffer that is to be written. - * `count' Number of bytes in the buffer. - * - * RETURN VALUE - * Zero upon success or non-zero if an error occurred. `errno' is set in this - * case. - */ -int swrite(int fd, const void *buf, size_t count); - -/* - * NAME - * strsplit - * - * DESCRIPTION - * Splits a string into parts and stores pointers to the parts in `fields'. - * The characters split at are: " ", "\t", "\r", and "\n". - * - * PARAMETERS - * `string' String to split. This string will be modified. `fields' will - * contain pointers to parts of this string, so free'ing it - * will destroy `fields' as well. - * `fields' Array of strings where pointers to the parts will be stored. - * `size' Number of elements in the array. No more than `size' - * pointers will be stored in `fields'. - * - * RETURN VALUE - * Returns the number of parts stored in `fields'. - */ -int strsplit(char *string, char **fields, size_t size); - -/* - * NAME - * strjoin - * - * DESCRIPTION - * Joins together several parts of a string using `sep' as a separator. This - * is equivalent to the Perl built-in `join'. - * - * PARAMETERS - * `dst' Buffer where the result is stored. Can be NULL if you need to - * determine the required buffer size only. - * `dst_len' Length of the destination buffer. No more than this many - * bytes will be written to the memory pointed to by `dst', - * including the trailing null-byte. Must be zero if dst is - * NULL. - * `fields' Array of strings to be joined. - * `fields_num' Number of elements in the `fields' array. - * `sep' String to be inserted between any two elements of `fields'. - * This string is neither prepended nor appended to the result. - * Instead of passing "" (empty string) one can pass NULL. - * - * RETURN VALUE - * Returns the number of characters in the resulting string, excluding a - * tailing null byte. If this value is greater than or equal to "dst_len", the - * result in "dst" is truncated (but still null terminated). On error a - * negative value is returned. - */ -int strjoin(char *dst, size_t dst_len, char **fields, size_t fields_num, - const char *sep); - -/* - * NAME - * escape_slashes - * - * DESCRIPTION - * Removes slashes ("/") from "buffer". If buffer contains a single slash, - * the result will be "root". Leading slashes are removed. All other slashes - * are replaced with underscores ("_"). - * This function is used by plugin_dispatch_values() to escape all parts of - * the identifier. - * - * PARAMETERS - * `buffer' String to be escaped. - * `buffer_size' Size of the buffer. No more then this many bytes will be - * written to `buffer', including the trailing null-byte. - * - * RETURN VALUE - * Returns zero upon success and a value smaller than zero upon failure. - */ -int escape_slashes(char *buffer, size_t buffer_size); - -/** - * NAME - * escape_string - * - * DESCRIPTION - * escape_string quotes and escapes a string to be usable with collectd's - * plain text protocol. "simple" strings are left as they are, for example if - * buffer is 'simple' before the call, it will remain 'simple'. However, if - * buffer contains 'more "complex"' before the call, the returned buffer will - * contain '"more \"complex\""'. - * - * If the buffer is too small to contain the escaped string, the string will - * be truncated. However, leading and trailing double quotes, as well as an - * ending null byte are guaranteed. - * - * RETURN VALUE - * Returns zero on success, even if the string was truncated. Non-zero on - * failure. - */ -int escape_string(char *buffer, size_t buffer_size); - -/* - * NAME - * replace_special - * - * DESCRIPTION - * Replaces any special characters (anything that's not alpha-numeric or a - * dash) with an underscore. - * - * E.g. "foo$bar&" would become "foo_bar_". - * - * PARAMETERS - * `buffer' String to be handled. - * `buffer_size' Length of the string. The function returns after - * encountering a null-byte or reading this many bytes. - */ -void replace_special(char *buffer, size_t buffer_size); - -/* - * NAME - * strunescape - * - * DESCRIPTION - * Replaces any escaped characters in a string with the appropriate special - * characters. The following escaped characters are recognized: - * - * \t -> <tab> - * \n -> <newline> - * \r -> <carriage return> - * - * For all other escacped characters only the backslash will be removed. - * - * PARAMETERS - * `buf' String to be unescaped. - * `buf_len' Length of the string, including the terminating null-byte. - * - * RETURN VALUE - * Returns zero upon success, a value less than zero else. - */ -int strunescape(char *buf, size_t buf_len); - -/** - * Removed trailing newline characters (CR and LF) from buffer, which must be - * null terminated. Returns the length of the resulting string. - */ -__attribute__((nonnull(1))) size_t strstripnewline(char *buffer); - -/* - * NAME - * timeval_cmp - * - * DESCRIPTION - * Compare the two time values `tv0' and `tv1' and store the absolut value - * of the difference in the time value pointed to by `delta' if it does not - * equal NULL. - * - * RETURN VALUE - * Returns an integer less than, equal to, or greater than zero if `tv0' is - * less than, equal to, or greater than `tv1' respectively. - */ -int timeval_cmp(struct timeval tv0, struct timeval tv1, struct timeval *delta); - -/* make sure tv_usec stores less than a second */ -#define NORMALIZE_TIMEVAL(tv) \ - do { \ - (tv).tv_sec += (tv).tv_usec / 1000000; \ - (tv).tv_usec = (tv).tv_usec % 1000000; \ - } while (0) - -/* make sure tv_sec stores less than a second */ -#define NORMALIZE_TIMESPEC(tv) \ - do { \ - (tv).tv_sec += (tv).tv_nsec / 1000000000; \ - (tv).tv_nsec = (tv).tv_nsec % 1000000000; \ - } while (0) - -int check_create_dir(const char *file_orig); - -#ifdef HAVE_LIBKSTAT -#if HAVE_KSTAT_H -#include <kstat.h> -#endif -int get_kstat(kstat_t **ksp_ptr, char *module, int instance, char *name); -long long get_kstat_value(kstat_t *ksp, char *name); -#endif - -#ifndef HAVE_HTONLL -unsigned long long ntohll(unsigned long long n); -unsigned long long htonll(unsigned long long n); -#endif - -#if FP_LAYOUT_NEED_NOTHING -#define ntohd(d) (d) -#define htond(d) (d) -#elif FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP -double ntohd(double d); -double htond(double d); -#else -#error \ - "Don't know how to convert between host and network representation of doubles." -#endif - -int format_name(char *ret, int ret_len, const char *hostname, - const char *plugin, const char *plugin_instance, - const char *type, const char *type_instance); -#define FORMAT_VL(ret, ret_len, vl) \ - format_name(ret, ret_len, (vl)->host, (vl)->plugin, (vl)->plugin_instance, \ - (vl)->type, (vl)->type_instance) -int format_values(char *ret, size_t ret_len, const data_set_t *ds, - const value_list_t *vl, bool store_rates); - -int parse_identifier(char *str, char **ret_host, char **ret_plugin, - char **ret_plugin_instance, char **ret_type, - char **ret_type_instance, char *default_host); -int parse_identifier_vl(const char *str, value_list_t *vl); -int parse_value(const char *value, value_t *ret_value, int ds_type); -int parse_values(char *buffer, value_list_t *vl, const data_set_t *ds); - -/* parse_value_file reads "path" and parses its content as an integer or - * floating point, depending on "ds_type". On success, the value is stored in - * "ret_value" and zero is returned. On failure, a non-zero value is returned. - */ -int parse_value_file(char const *path, value_t *ret_value, int ds_type); - -#if !HAVE_GETPWNAM_R -struct passwd; -int getpwnam_r(const char *name, struct passwd *pwbuf, char *buf, size_t buflen, - struct passwd **pwbufp); -#endif - -int notification_init(notification_t *n, int severity, const char *message, - const char *host, const char *plugin, - const char *plugin_instance, const char *type, - const char *type_instance); -#define NOTIFICATION_INIT_VL(n, vl) \ - notification_init(n, NOTIF_FAILURE, NULL, (vl)->host, (vl)->plugin, \ - (vl)->plugin_instance, (vl)->type, (vl)->type_instance) - -typedef int (*dirwalk_callback_f)(const char *dirname, const char *filename, - void *user_data); -int walk_directory(const char *dir, dirwalk_callback_f callback, - void *user_data, int hidden); -/* Returns the number of bytes read or negative on error. */ -ssize_t read_file_contents(char const *filename, void *buf, size_t bufsize); -/* Writes the contents of the file into the buffer with a trailing NUL. - * Returns the number of bytes written to the buffer or negative on error. */ -ssize_t read_text_file_contents(char const *filename, char *buf, - size_t bufsize); - -counter_t counter_diff(counter_t old_value, counter_t new_value); - -/* Convert a rate back to a value_t. When converting to a derive_t, counter_t - * or absolute_t, take fractional residuals into account. This is important - * when scaling counters, for example. - * Returns zero on success. Returns EAGAIN when called for the first time; in - * this case the value_t is invalid and the next call should succeed. Other - * return values indicate an error. */ -int rate_to_value(value_t *ret_value, gauge_t rate, - rate_to_value_state_t *state, int ds_type, cdtime_t t); - -int value_to_rate(gauge_t *ret_rate, value_t value, int ds_type, cdtime_t t, - value_to_rate_state_t *state); - -/* Converts a service name (a string) to a port number - * (in the range [1-65535]). Returns less than zero on error. */ -int service_name_to_port_number(const char *service_name); - -/* Sets various, non-default, socket options */ -void set_sock_opts(int sockfd); - -/** Parse a string to a derive_t value. Returns zero on success or non-zero on - * failure. If failure is returned, ret_value is not touched. */ -int strtoderive(const char *string, derive_t *ret_value); - -/** Parse a string to a gauge_t value. Returns zero on success or non-zero on - * failure. If failure is returned, ret_value is not touched. */ -int strtogauge(const char *string, gauge_t *ret_value); - -int strarray_add(char ***ret_array, size_t *ret_array_len, char const *str); -void strarray_free(char **array, size_t array_len); - -/** Check if the current process benefits from the capability passed in - * argument. Returns zero if it does, less than zero if it doesn't or on error. - * See capabilities(7) for the list of possible capabilities. - * */ -int check_capability(int arg); - -#endif /* COMMON_H */ diff --git a/telemetry/vpp-collectd/common/meta_data.h b/telemetry/vpp-collectd/common/meta_data.h deleted file mode 100644 index 203b14607..000000000 --- a/telemetry/vpp-collectd/common/meta_data.h +++ /dev/null @@ -1,71 +0,0 @@ -/** - * collectd - src/meta_data.h - * Copyright (C) 2008-2011 Florian octo Forster - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * Florian octo Forster <octo at collectd.org> - **/ - -#ifndef META_DATA_H -#define META_DATA_H - -#include "collectd.h" - -/* - * Defines - */ -#define MD_TYPE_STRING 1 -#define MD_TYPE_SIGNED_INT 2 -#define MD_TYPE_UNSIGNED_INT 3 -#define MD_TYPE_DOUBLE 4 -#define MD_TYPE_BOOLEAN 5 - -struct meta_data_s; -typedef struct meta_data_s meta_data_t; - -meta_data_t *meta_data_create(void); -meta_data_t *meta_data_clone(meta_data_t *orig); -int meta_data_clone_merge(meta_data_t **dest, meta_data_t *orig); -void meta_data_destroy(meta_data_t *md); - -int meta_data_exists(meta_data_t *md, const char *key); -int meta_data_type(meta_data_t *md, const char *key); -int meta_data_toc(meta_data_t *md, char ***toc); -int meta_data_delete(meta_data_t *md, const char *key); - -int meta_data_add_string(meta_data_t *md, const char *key, const char *value); -int meta_data_add_signed_int(meta_data_t *md, const char *key, int64_t value); -int meta_data_add_unsigned_int(meta_data_t *md, const char *key, - uint64_t value); -int meta_data_add_double(meta_data_t *md, const char *key, double value); -int meta_data_add_boolean(meta_data_t *md, const char *key, bool value); - -int meta_data_get_string(meta_data_t *md, const char *key, char **value); -int meta_data_get_signed_int(meta_data_t *md, const char *key, int64_t *value); -int meta_data_get_unsigned_int(meta_data_t *md, const char *key, - uint64_t *value); -int meta_data_get_double(meta_data_t *md, const char *key, double *value); -int meta_data_get_boolean(meta_data_t *md, const char *key, bool *value); - -/* Returns the value as a string, regardless of the type. */ -int meta_data_as_string(meta_data_t *md, const char *key, char **value); - -#endif /* META_DATA_H */ diff --git a/telemetry/vpp-collectd/common/plugin.h b/telemetry/vpp-collectd/common/plugin.h deleted file mode 100644 index bbd69e003..000000000 --- a/telemetry/vpp-collectd/common/plugin.h +++ /dev/null @@ -1,483 +0,0 @@ -/** - * collectd - src/daemon/plugin.h - * Copyright (C) 2005-2014 Florian octo Forster - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * Florian octo Forster <octo at collectd.org> - * Sebastian Harl <sh at tokkee.org> - **/ - -#ifndef PLUGIN_H -#define PLUGIN_H - -#include "collectd.h" - -#include "configfile.h" -#include "meta_data.h" -#include "utils_time.h" - -#include <inttypes.h> -#include <pthread.h> - -#define DS_TYPE_COUNTER 0 -#define DS_TYPE_GAUGE 1 -#define DS_TYPE_DERIVE 2 -#define DS_TYPE_ABSOLUTE 3 - -#define DS_TYPE_TO_STRING(t) \ - (t == DS_TYPE_COUNTER) ? "counter" \ - : (t == DS_TYPE_GAUGE) ? "gauge" \ - : (t == DS_TYPE_DERIVE) ? "derive" \ - : (t == DS_TYPE_ABSOLUTE) ? "absolute" \ - : "unknown" - -#ifndef LOG_ERR -#define LOG_ERR 3 -#endif -#ifndef LOG_WARNING -#define LOG_WARNING 4 -#endif -#ifndef LOG_NOTICE -#define LOG_NOTICE 5 -#endif -#ifndef LOG_INFO -#define LOG_INFO 6 -#endif -#ifndef LOG_DEBUG -#define LOG_DEBUG 7 -#endif - -#define NOTIF_MAX_MSG_LEN 256 - -#define NOTIF_FAILURE 1 -#define NOTIF_WARNING 2 -#define NOTIF_OKAY 4 - -#define plugin_interval (plugin_get_ctx().interval) - -/* - * Public data types - */ -struct identifier_s { - char *host; - char *plugin; - char *plugin_instance; - char *type; - char *type_instance; -}; -typedef struct identifier_s identifier_t; - -typedef unsigned long long counter_t; -typedef double gauge_t; -typedef int64_t derive_t; -typedef uint64_t absolute_t; - -union value_u { - counter_t counter; - gauge_t gauge; - derive_t derive; - absolute_t absolute; -}; -typedef union value_u value_t; - -struct value_list_s { - value_t *values; - size_t values_len; - cdtime_t time; - cdtime_t interval; - char host[DATA_MAX_NAME_LEN]; - char plugin[DATA_MAX_NAME_LEN]; - char plugin_instance[DATA_MAX_NAME_LEN]; - char type[DATA_MAX_NAME_LEN]; - char type_instance[DATA_MAX_NAME_LEN]; - meta_data_t *meta; -}; -typedef struct value_list_s value_list_t; - -#define VALUE_LIST_INIT \ - { .values = NULL, .meta = NULL } - -struct data_source_s { - char name[DATA_MAX_NAME_LEN]; - int type; - double min; - double max; -}; -typedef struct data_source_s data_source_t; - -struct data_set_s { - char type[DATA_MAX_NAME_LEN]; - size_t ds_num; - data_source_t *ds; -}; -typedef struct data_set_s data_set_t; - -enum notification_meta_type_e { - NM_TYPE_STRING, - NM_TYPE_SIGNED_INT, - NM_TYPE_UNSIGNED_INT, - NM_TYPE_DOUBLE, - NM_TYPE_BOOLEAN -}; - -typedef struct notification_meta_s { - char name[DATA_MAX_NAME_LEN]; - enum notification_meta_type_e type; - union { - const char *nm_string; - int64_t nm_signed_int; - uint64_t nm_unsigned_int; - double nm_double; - bool nm_boolean; - } nm_value; - struct notification_meta_s *next; -} notification_meta_t; - -typedef struct notification_s { - int severity; - cdtime_t time; - char message[NOTIF_MAX_MSG_LEN]; - char host[DATA_MAX_NAME_LEN]; - char plugin[DATA_MAX_NAME_LEN]; - char plugin_instance[DATA_MAX_NAME_LEN]; - char type[DATA_MAX_NAME_LEN]; - char type_instance[DATA_MAX_NAME_LEN]; - notification_meta_t *meta; -} notification_t; - -struct user_data_s { - void *data; - void (*free_func)(void *); -}; -typedef struct user_data_s user_data_t; - -enum cache_event_type_e { CE_VALUE_NEW, CE_VALUE_UPDATE, CE_VALUE_EXPIRED }; - -typedef struct cache_event_s { - enum cache_event_type_e type; - const value_list_t *value_list; - const char *value_list_name; - int ret; -} cache_event_t; - -struct plugin_ctx_s { - char *name; - cdtime_t interval; - cdtime_t flush_interval; - cdtime_t flush_timeout; -}; -typedef struct plugin_ctx_s plugin_ctx_t; - -/* - * Callback types - */ -typedef int (*plugin_init_cb)(void); -typedef int (*plugin_read_cb)(user_data_t *); -typedef int (*plugin_write_cb)(const data_set_t *, const value_list_t *, - user_data_t *); -typedef int (*plugin_flush_cb)(cdtime_t timeout, const char *identifier, - user_data_t *); -/* "missing" callback. Returns less than zero on failure, zero if other - * callbacks should be called, greater than zero if no more callbacks should be - * called. */ -typedef int (*plugin_missing_cb)(const value_list_t *, user_data_t *); -/* "cache event" callback. CE_VALUE_NEW events are sent to all registered - * callbacks. Callback should check if it interested in further CE_VALUE_UPDATE - * and CE_VALUE_EXPIRED events for metric and set event->ret = 1 if so. - */ -typedef int (*plugin_cache_event_cb)(cache_event_t *, user_data_t *); -typedef void (*plugin_log_cb)(int severity, const char *message, user_data_t *); -typedef int (*plugin_shutdown_cb)(void); -typedef int (*plugin_notification_cb)(const notification_t *, user_data_t *); -/* - * NAME - * plugin_set_dir - * - * DESCRIPTION - * Sets the current `plugindir' - * - * ARGUMENTS - * `dir' Path to the plugin directory - * - * NOTES - * If `dir' is NULL the compiled in default `PLUGINDIR' is used. - */ -void plugin_set_dir(const char *dir); - -/* - * NAME - * plugin_load - * - * DESCRIPTION - * Searches the current `plugindir' (see `plugin_set_dir') for the plugin - * named $type and loads it. Afterwards the plugin's `module_register' - * function is called, which then calls `plugin_register' to register callback - * functions. - * - * ARGUMENTS - * `name' Name of the plugin to load. - * `global' Make this plugins symbols available for other shared libraries. - * - * RETURN VALUE - * Returns zero upon success, a value greater than zero if no plugin was found - * and a value below zero if an error occurs. - * - * NOTES - * Re-loading an already loaded module is detected and zero is returned in - * this case. - */ -int plugin_load(const char *name, bool global); -bool plugin_is_loaded(char const *name); - -int plugin_init_all(void); -void plugin_read_all(void); -int plugin_read_all_once(void); -int plugin_shutdown_all(void); - -/* - * NAME - * plugin_write - * - * DESCRIPTION - * Calls the write function of the given plugin with the provided data set and - * value list. It differs from `plugin_dispatch_values' in that it does not - * update the cache, does not do threshold checking, call the chain subsystem - * and so on. It looks up the requested plugin and invokes the function, end - * of story. - * - * ARGUMENTS - * plugin Name of the plugin. If NULL, the value is sent to all registered - * write functions. - * ds Pointer to the data_set_t structure. If NULL, the data set is - * looked up according to the `type' member in the `vl' argument. - * vl The actual value to be processed. Must not be NULL. - * - * RETURN VALUE - * Returns zero upon success or non-zero if an error occurred. If `plugin' is - * NULL and more than one plugin is called, an error is only returned if *all* - * plugins fail. - * - * NOTES - * This is the function used by the `write' built-in target. May be used by - * other target plugins. - */ -int plugin_write(const char *plugin, const data_set_t *ds, - const value_list_t *vl); - -int plugin_flush(const char *plugin, cdtime_t timeout, const char *identifier); - -/* - * The `plugin_register_*' functions are used to make `config', `init', - * `read', `write' and `shutdown' functions known to the plugin - * infrastructure. Also, the data-formats are made public like this. - */ -int plugin_register_config(const char *name, - int (*callback)(const char *key, const char *val), - const char **keys, int keys_num); -int plugin_register_complex_config(const char *type, - int (*callback)(oconfig_item_t *)); -int plugin_register_init(const char *name, plugin_init_cb callback); -int plugin_register_read(const char *name, int (*callback)(void)); -/* "user_data" will be freed automatically, unless - * "plugin_register_complex_read" returns an error (non-zero). */ -int plugin_register_complex_read(const char *group, const char *name, - plugin_read_cb callback, cdtime_t interval, - user_data_t const *user_data); -int plugin_register_write(const char *name, plugin_write_cb callback, - user_data_t const *user_data); -int plugin_register_flush(const char *name, plugin_flush_cb callback, - user_data_t const *user_data); -int plugin_register_missing(const char *name, plugin_missing_cb callback, - user_data_t const *user_data); -int plugin_register_cache_event(const char *name, - plugin_cache_event_cb callback, - user_data_t const *ud); -int plugin_register_shutdown(const char *name, plugin_shutdown_cb callback); -int plugin_register_data_set(const data_set_t *ds); -int plugin_register_log(const char *name, plugin_log_cb callback, - user_data_t const *user_data); -int plugin_register_notification(const char *name, - plugin_notification_cb callback, - user_data_t const *user_data); - -int plugin_unregister_config(const char *name); -int plugin_unregister_complex_config(const char *name); -int plugin_unregister_init(const char *name); -int plugin_unregister_read(const char *name); -int plugin_unregister_read_group(const char *group); -int plugin_unregister_write(const char *name); -int plugin_unregister_flush(const char *name); -int plugin_unregister_missing(const char *name); -int plugin_unregister_cache_event(const char *name); -int plugin_unregister_shutdown(const char *name); -int plugin_unregister_data_set(const char *name); -int plugin_unregister_log(const char *name); -int plugin_unregister_notification(const char *name); - -/* - * NAME - * plugin_log_available_writers - * - * DESCRIPTION - * This function can be called to output a list of _all_ registered - * writers to the logfacility. - * Since some writers dynamically build their name it can be hard for - * the configuring person to know it. This function will fill this gap. - */ -void plugin_log_available_writers(void); - -/* - * NAME - * plugin_dispatch_values - * - * DESCRIPTION - * This function is called by reading processes with the values they've - * aquired. The function fetches the data-set definition (that has been - * registered using `plugin_register_data_set') and calls _all_ registered - * write-functions. - * - * ARGUMENTS - * `vl' Value list of the values that have been read by a `read' - * function. - */ -int plugin_dispatch_values(value_list_t const *vl); - -/* - * NAME - * plugin_dispatch_multivalue - * - * SYNOPSIS - * plugin_dispatch_multivalue (vl, true, DS_TYPE_GAUGE, - * "free", 42.0, - * "used", 58.0, - * NULL); - * - * DESCRIPTION - * Takes a list of type instances and values and dispatches that in a batch, - * making sure that all values have the same time stamp. If "store_percentage" - * is set to true, the "type" is set to "percent" and a percentage is - * calculated and dispatched, rather than the absolute values. Values that are - * NaN are dispatched as NaN and will not influence the total. - * - * The variadic arguments is a list of type_instance / type pairs, that are - * interpreted as type "char const *" and type, encoded by their corresponding - * "store_type": - * - * - "gauge_t" when "DS_TYPE_GAUGE" - * - "absolute_t" when "DS_TYPE_ABSOLUTE" - * - "derive_t" when "DS_TYPE_DERIVE" - * - "counter_t" when "DS_TYPE_COUNTER" - * - * The last argument must be - * a NULL pointer to signal end-of-list. - * - * RETURNS - * The number of values it failed to dispatch (zero on success). - */ -__attribute__((sentinel)) int plugin_dispatch_multivalue(value_list_t const *vl, - bool store_percentage, - int store_type, ...); - -int plugin_dispatch_missing(const value_list_t *vl); -void plugin_dispatch_cache_event(enum cache_event_type_e event_type, - unsigned long callbacks_mask, const char *name, - const value_list_t *vl); - -int plugin_dispatch_notification(const notification_t *notif); - -void plugin_log(int level, const char *format, ...) - __attribute__((format(printf, 2, 3))); - -/* These functions return the parsed severity or less than zero on failure. */ -int parse_log_severity(const char *severity); -int parse_notif_severity(const char *severity); - -#define ERROR(...) plugin_log(LOG_ERR, __VA_ARGS__) -#define WARNING(...) plugin_log(LOG_WARNING, __VA_ARGS__) -#define NOTICE(...) plugin_log(LOG_NOTICE, __VA_ARGS__) -#define INFO(...) plugin_log(LOG_INFO, __VA_ARGS__) -#if COLLECT_DEBUG -#define DEBUG(...) plugin_log(LOG_DEBUG, __VA_ARGS__) -#else /* COLLECT_DEBUG */ -#define DEBUG(...) /* noop */ -#endif /* ! COLLECT_DEBUG */ - -/* This will log messages, prefixed by plugin name */ -void daemon_log(int level, const char *format, ...) - __attribute__((format(printf, 2, 3))); - -#define P_ERROR(...) daemon_log(LOG_ERR, __VA_ARGS__) -#define P_WARNING(...) daemon_log(LOG_WARNING, __VA_ARGS__) -#define P_NOTICE(...) daemon_log(LOG_NOTICE, __VA_ARGS__) -#define P_INFO(...) daemon_log(LOG_INFO, __VA_ARGS__) - -const data_set_t *plugin_get_ds(const char *name); - -int plugin_notification_meta_add_string(notification_t *n, const char *name, - const char *value); -int plugin_notification_meta_add_signed_int(notification_t *n, const char *name, - int64_t value); -int plugin_notification_meta_add_unsigned_int(notification_t *n, - const char *name, uint64_t value); -int plugin_notification_meta_add_double(notification_t *n, const char *name, - double value); -int plugin_notification_meta_add_boolean(notification_t *n, const char *name, - bool value); - -int plugin_notification_meta_copy(notification_t *dst, - const notification_t *src); - -int plugin_notification_meta_free(notification_meta_t *n); - -/* - * Plugin context management. - */ - -void plugin_init_ctx(void); - -plugin_ctx_t plugin_get_ctx(void); -plugin_ctx_t plugin_set_ctx(plugin_ctx_t ctx); - -/* - * NAME - * plugin_get_interval - * - * DESCRIPTION - * This function returns the current value of the plugin's interval. The - * return value will be strictly greater than zero in all cases. If - * everything else fails, it will fall back to 10 seconds. - */ -cdtime_t plugin_get_interval(void); - -/* - * Context-aware thread management. - */ - -int plugin_thread_create(pthread_t *thread, void *(*start_routine)(void *), - void *arg, char const *name); - -/* - * Plugins need to implement this - */ - -void module_register(void); - -#endif /* PLUGIN_H */ diff --git a/telemetry/vpp-collectd/vpp-hicn/CMakeLists.txt b/telemetry/vpp-collectd/vpp-hicn/CMakeLists.txt index d55aede80..85dd51577 100644 --- a/telemetry/vpp-collectd/vpp-hicn/CMakeLists.txt +++ b/telemetry/vpp-collectd/vpp-hicn/CMakeLists.txt @@ -12,55 +12,62 @@ # limitations under the License. ############################################################## -# Check if building as subproject or as root project +# Dependencies ############################################################## -if(${CMAKE_SOURCE_DIR}/vpp-collectd STREQUAL ${PROJECT_SOURCE_DIR}) - message (STATUS "not compiling in the same folder") - find_package(HicnPlugin ${CURRENT_VERSION} REQUIRED) - find_package(Vapisafe ${CURRENT_VERSION} REQUIRED) -else() - message (STATUS "compiling in the same folder") - list(APPEND DEPENDENCIES - ${HICNPLUGIN_SHARED} - ) -endif() +find_package(HicnPlugin ${CURRENT_VERSION} REQUIRED) +find_package(Libsafevapi ${CURRENT_VERSION} REQUIRED NO_MODULE) ############################################################## -# Sources +# Source files ############################################################## list(APPEND SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/vpp_hicn.c ) + +############################################################## +# Include dirs +############################################################## list(APPEND INCLUDE_DIRS ${COLLECTD_INCLUDE_DIRS} + ${THIRD_PARTY_INCLUDE_DIRS} ${HICNPLUGIN_INCLUDE_DIRS} - ${SAFE_VAPI_INCLUDE_DIRS} + ${Libsafe_vapi_INCLUDE_DIRS} ${VPP_INCLUDE_DIRS} - ${CMAKE_CURRENT_SOURCE_DIR} - "${CMAKE_CURRENT_SOURCE_DIR}/../common" ) ############################################################## -# Libs +# Libraries ############################################################## list(APPEND LIBRARIES ${VPP_LIBRARY_VAPICLIENT} - ${SAFE_VAPI_LIBRARIES} + hicn::safevapi.shared +) + + +############################################################## +# Compiler options +############################################################## +list(APPEND COMPILER_OPTIONS + ${DEFAULT_COMPILER_OPTIONS} + ${COLLECTD_COMPILER_OPTIONS} ) ############################################################## # Build library ############################################################## -build_library(vpp_hicn +build_library(${VPP_HICN_TELEMETRY} + SHARED + EMPTY_PREFIX SOURCES ${SOURCE_FILES} LINK_LIBRARIES ${LIBRARIES} - INCLUDE_DIRS ${INCLUDE_DIRS} - INSTALL_FULL_PATH_DIR ${CMAKE_INSTALL_PREFIX}/lib/collectd - COMPONENT "${COLLECTD_PLUGINS}" + INCLUDE_DIRS + PRIVATE ${INCLUDE_DIRS} + INSTALL_FULL_PATH_DIR ${COLLECTD_PLUGIN_DIR} + COMPONENT ${COLLECTD_PLUGINS} DEPENDS ${DEPENDENCIES} COMPILE_OPTIONS ${COMPILER_OPTIONS} ) diff --git a/telemetry/vpp-collectd/vpp-hicn/vpp_hicn.c b/telemetry/vpp-collectd/vpp-hicn/vpp_hicn.c index a724c1124..a20bcbcd0 100644 --- a/telemetry/vpp-collectd/vpp-hicn/vpp_hicn.c +++ b/telemetry/vpp-collectd/vpp-hicn/vpp_hicn.c @@ -13,13 +13,14 @@ * limitations under the License. */ -/* Keep order as it is */ -#include "common.h" -#include <config.h> +#include "../../data_model.h" +#include "collectd.h" +#include "plugin.h" +#include "utils/common/common.h" #define counter_t vpp_counter_t +#include <hicn/vapi/vapi_safe.h> #include <vapi/hicn.api.vapi.h> -#include <vapi/vapi_safe.h> #undef counter_t DEFINE_VAPI_MSG_IDS_HICN_API_JSON @@ -34,140 +35,6 @@ static int config_keys_num = STATIC_ARRAY_SIZE(config_keys); static bool verbose = false; static char *tag = NULL; -/************** DATA SOURCES ******************************/ -static data_source_t packets_dsrc[1] = { - {"packets", DS_TYPE_GAUGE, 0, NAN}, -}; - -static data_source_t interests_dsrc[1] = { - {"interests", DS_TYPE_GAUGE, 0, NAN}, -}; - -static data_source_t data_dsrc[1] = { - {"data", DS_TYPE_GAUGE, 0, NAN}, -}; - -static data_source_t combined_dsrc[2] = { - {"packets", DS_TYPE_DERIVE, 0, NAN}, - {"bytes", DS_TYPE_DERIVE, 0, NAN}, -}; - -/************** DATA SETS NODE ****************************/ -static data_set_t pkts_processed_ds = { - "pkts_processed", - STATIC_ARRAY_SIZE(packets_dsrc), - packets_dsrc, -}; - -static data_set_t pkts_interest_count_ds = { - "pkts_interest_count", - STATIC_ARRAY_SIZE(packets_dsrc), - packets_dsrc, -}; - -static data_set_t pkts_data_count_ds = { - "pkts_data_count", - STATIC_ARRAY_SIZE(packets_dsrc), - packets_dsrc, -}; - -static data_set_t pkts_from_cache_count_ds = { - "pkts_from_cache_count", - STATIC_ARRAY_SIZE(packets_dsrc), - packets_dsrc, -}; - -static data_set_t pkts_no_pit_count_ds = { - "pkts_no_pit_count", - STATIC_ARRAY_SIZE(packets_dsrc), - packets_dsrc, -}; - -static data_set_t pit_expired_count_ds = { - "pit_expired_count", - STATIC_ARRAY_SIZE(interests_dsrc), - interests_dsrc, -}; - -static data_set_t cs_expired_count_ds = { - "cs_expired_count", - STATIC_ARRAY_SIZE(data_dsrc), - data_dsrc, -}; - -static data_set_t cs_lru_count_ds = { - "cs_lru_count", - STATIC_ARRAY_SIZE(data_dsrc), - data_dsrc, -}; - -static data_set_t pkts_drop_no_buf_ds = { - "pkts_drop_no_buf", - STATIC_ARRAY_SIZE(packets_dsrc), - packets_dsrc, -}; - -static data_set_t interests_aggregated_ds = { - "interests_aggregated", - STATIC_ARRAY_SIZE(interests_dsrc), - interests_dsrc, -}; - -static data_set_t interests_retx_ds = { - "interests_retx", - STATIC_ARRAY_SIZE(interests_dsrc), - interests_dsrc, -}; - -static data_set_t interests_hash_collision_ds = { - "interests_hash_collision", - STATIC_ARRAY_SIZE(interests_dsrc), - interests_dsrc, -}; - -static data_set_t pit_entries_count_ds = { - "pit_entries_count", - STATIC_ARRAY_SIZE(interests_dsrc), - interests_dsrc, -}; - -static data_set_t cs_entries_count_ds = { - "cs_entries_count", - STATIC_ARRAY_SIZE(data_dsrc), - data_dsrc, -}; - -static data_set_t cs_entries_ntw_count_ds = { - "cs_entries_ntw_count", - STATIC_ARRAY_SIZE(data_dsrc), - data_dsrc, -}; - -/************** DATA SETS FACE ****************************/ -static data_set_t irx_ds = { - "irx", - STATIC_ARRAY_SIZE(combined_dsrc), - combined_dsrc, -}; - -static data_set_t itx_ds = { - "itx", - STATIC_ARRAY_SIZE(combined_dsrc), - combined_dsrc, -}; - -static data_set_t drx_ds = { - "drx", - STATIC_ARRAY_SIZE(combined_dsrc), - combined_dsrc, -}; - -static data_set_t dtx_ds = { - "dtx", - STATIC_ARRAY_SIZE(combined_dsrc), - combined_dsrc, -}; - /**********************************************************/ /********** UTILITY FUNCTIONS *****************************/ /**********************************************************/ @@ -189,8 +56,7 @@ static int submit(const char *plugin_instance, const char *type, sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance)); sstrncpy(vl.type, type, sizeof(vl.type)); - if (tag != NULL) - sstrncpy(vl.type_instance, tag, sizeof(vl.type_instance)); + if (tag != NULL) sstrncpy(vl.type_instance, tag, sizeof(vl.type_instance)); return plugin_dispatch_values(&vl); } @@ -223,15 +89,12 @@ static int vpp_hicn_config(const char *key, const char *value) { /* * Callback called by the hICN plugin API when node stats are ready. */ -static vapi_error_e -parse_node_stats(vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, - bool is_last, - vapi_payload_hicn_api_node_stats_get_reply *reply) { - if (reply == NULL || rv != VAPI_OK) - return rv; +static vapi_error_e parse_node_stats( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_hicn_api_node_stats_get_reply *reply) { + if (reply == NULL || rv != VAPI_OK) return rv; - if (reply->retval != VAPI_OK) - return reply->retval; + if (reply->retval != VAPI_OK) return reply->retval; char *node_name = "node"; value_t values[1]; @@ -277,15 +140,12 @@ parse_node_stats(vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, /* * Callback called by the hICN plugin API when face stats are ready. */ -static vapi_error_e -parse_face_stats(vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, - bool is_last, - vapi_payload_hicn_api_face_stats_details *reply) { - if (reply == NULL || rv != VAPI_OK) - return rv; +static vapi_error_e parse_face_stats( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_hicn_api_face_stats_details *reply) { + if (reply == NULL || rv != VAPI_OK) return rv; - if (reply->retval != VAPI_OK) - return reply->retval; + if (reply->retval != VAPI_OK) return reply->retval; char face_name[10]; snprintf(face_name, 10, "face%u", reply->faceid); @@ -314,8 +174,7 @@ parse_face_stats(vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, static int vpp_hicn_init(void) { int ret = vapi_connect_safe(&vapi_ctx, 0); - if (ret) - plugin_log(LOG_ERR, "vpp_hicn plugin: vapi_connect_safe failed"); + if (ret) plugin_log(LOG_ERR, "vpp_hicn plugin: vapi_connect_safe failed"); return ret; } diff --git a/telemetry/vpp-collectd/vpp/CMakeLists.txt b/telemetry/vpp-collectd/vpp/CMakeLists.txt index 41c19208a..e1cf55553 100644 --- a/telemetry/vpp-collectd/vpp/CMakeLists.txt +++ b/telemetry/vpp-collectd/vpp/CMakeLists.txt @@ -20,13 +20,12 @@ list(APPEND SOURCE_FILES ############################################################## -# Include directories +# Include dirs ############################################################## list(APPEND INCLUDE_DIRS ${COLLECTD_INCLUDE_DIRS} + ${THIRD_PARTY_INCLUDE_DIRS} ${VPP_INCLUDE_DIRS} - ${CMAKE_CURRENT_SOURCE_DIR} - "${CMAKE_CURRENT_SOURCE_DIR}/../common" ) @@ -39,11 +38,26 @@ list(APPEND LIBRARIES ) -build_module(vpp +############################################################## +# Compiler options +############################################################## +list(APPEND COMPILER_OPTIONS + ${DEFAULT_COMPILER_OPTIONS} + ${COLLECTD_COMPILER_OPTIONS} +) + + +############################################################## +# Build library +############################################################## +build_library(${VPP_TELEMETRY} + SHARED + EMPTY_PREFIX SOURCES ${SOURCE_FILES} LINK_LIBRARIES ${LIBRARIES} - INCLUDE_DIRS ${INCLUDE_DIRS} - INSTALL_FULL_PATH_DIR ${CMAKE_INSTALL_PREFIX}/lib/collectd + INCLUDE_DIRS + PRIVATE ${INCLUDE_DIRS} + INSTALL_FULL_PATH_DIR ${COLLECTD_PLUGIN_DIR} COMPONENT ${COLLECTD_PLUGINS} COMPILE_OPTIONS ${COMPILER_OPTIONS} ) diff --git a/telemetry/vpp-collectd/vpp/vpp.c b/telemetry/vpp-collectd/vpp/vpp.c index 85d0971d0..ff70f3503 100644 --- a/telemetry/vpp-collectd/vpp/vpp.c +++ b/telemetry/vpp-collectd/vpp/vpp.c @@ -13,9 +13,9 @@ * limitations under the License. */ -/* Keep order as it is */ -#include "common.h" -#include <config.h> +#include "collectd.h" +#include "plugin.h" +#include "utils/common/common.h" #define counter_t vpp_counter_t #include <vpp-api/client/stat_client.h> @@ -165,8 +165,7 @@ static int submit(const char *plugin_instance, const char *type, sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance)); sstrncpy(vl.type, type, sizeof(vl.type)); - if (tag != NULL) - sstrncpy(vl.type_instance, tag, sizeof(vl.type_instance)); + if (tag != NULL) sstrncpy(vl.type_instance, tag, sizeof(vl.type_instance)); return plugin_dispatch_values(&vl); } @@ -261,8 +260,7 @@ static int vpp_init(void) { u8 *stat_segment_name = (u8 *)STAT_SEGMENT_SOCKET_FILE; int ret = stat_segment_connect((char *)stat_segment_name); - if (ret) - plugin_log(LOG_ERR, "vpp plugin: connecting to segment failed"); + if (ret) plugin_log(LOG_ERR, "vpp plugin: connecting to segment failed"); return ret; } @@ -296,66 +294,65 @@ static int vpp_read(void) { /* Collect results for each interface and submit them */ for (int i = 0; i < vec_len(res); i++) { switch (res[i].type) { - case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE: - for (int k = 0; k < vec_len(res[i].simple_counter_vec); k++) { - for (int j = 0; j < vec_len(res[i].simple_counter_vec[k]); j++) { - if (!interfaces[j]) { - continue; - } + case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE: + for (int k = 0; k < vec_len(res[i].simple_counter_vec); k++) { + for (int j = 0; j < vec_len(res[i].simple_counter_vec[k]); j++) { + if (!interfaces[j]) { + continue; + } - if (get_data_set(res[i].name, &data_set)) { - continue; - } + if (get_data_set(res[i].name, &data_set)) { + continue; + } - value_t values[1] = { - (value_t){.derive = res[i].simple_counter_vec[k][j]}}; + value_t values[1] = { + (value_t){.derive = res[i].simple_counter_vec[k][j]}}; - err = submit(interfaces[j], data_set.type, values, 1, ×tamp); + err = submit(interfaces[j], data_set.type, values, 1, ×tamp); - if (err) - goto END; + if (err) goto END; + } } - } - break; + break; - case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED: - for (int k = 0; k < vec_len(res[i].combined_counter_vec); k++) { - for (int j = 0; j < vec_len(res[i].combined_counter_vec[k]); j++) { - if (!interfaces[j]) { - continue; - } + case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED: + for (int k = 0; k < vec_len(res[i].combined_counter_vec); k++) { + for (int j = 0; j < vec_len(res[i].combined_counter_vec[k]); j++) { + if (!interfaces[j]) { + continue; + } - if (get_data_set(res[i].name, &data_set)) { - continue; - } + if (get_data_set(res[i].name, &data_set)) { + continue; + } - value_t values[2] = { - (value_t){.derive = res[i].combined_counter_vec[k][j].packets}, - (value_t){.derive = res[i].combined_counter_vec[k][j].bytes}, - }; + value_t values[2] = { + (value_t){.derive = res[i].combined_counter_vec[k][j].packets}, + (value_t){.derive = res[i].combined_counter_vec[k][j].bytes}, + }; - err = submit(interfaces[j], data_set.type, values, 2, ×tamp); + err = submit(interfaces[j], data_set.type, values, 2, ×tamp); - if (err) - goto END; + if (err) goto END; + } } - } - break; + break; - case STAT_DIR_TYPE_SCALAR_INDEX: - plugin_log(LOG_INFO, "vpp plugin: %.2f %s", res[i].scalar_value, - res[i].name); - break; + case STAT_DIR_TYPE_SCALAR_INDEX: + plugin_log(LOG_INFO, "vpp plugin: %.2f %s", res[i].scalar_value, + res[i].name); + break; - case STAT_DIR_TYPE_NAME_VECTOR: - break; + case STAT_DIR_TYPE_NAME_VECTOR: + break; - case STAT_DIR_TYPE_ERROR_INDEX: - break; + case STAT_DIR_TYPE_ERROR_INDEX: + break; - default: - plugin_log(LOG_WARNING, "vpp plugin: unknown stat type %d", res[i].type); - break; + default: + plugin_log(LOG_WARNING, "vpp plugin: unknown stat type %d", + res[i].type); + break; } } diff --git a/tests/.env b/tests/.env index 1d40e4dea..f36c66785 100644 --- a/tests/.env +++ b/tests/.env @@ -9,6 +9,6 @@ TEST_VPP_MEMIF=vpp-memif TEST_VPP_MEMIF_REPLICATION=vpp-memif-replication # names -RTC_PRODUCER=b002::1 +RTC_PRODUCER=b002:0:0:0:abcd::/80 RAAQM_PRODUCER=b002::2 PING_PRODUCER=b002::3 diff --git a/tests/2-nodes-hicn-light.yml b/tests/2-nodes-hicn-light.yml index 318a5ccbd..0aee8cf5e 100644 --- a/tests/2-nodes-hicn-light.yml +++ b/tests/2-nodes-hicn-light.yml @@ -58,8 +58,8 @@ services: sleep 4 - hiperf -z hicnlightng_module -D -S -R -B 4000kbps ${RTC_PRODUCER}/128 - hiperf -z hicnlightng_module -D -S ${RAAQM_PRODUCER}/128 - hicn-ping-server -z hicnlightng_module -d -s 0 -n ${PING_PRODUCER}/128 + hiperf -q -z hicnlightng_module -S -R -B 4000kbps ${RTC_PRODUCER} -P 2 & + hiperf -q -z hicnlightng_module -S ${RAAQM_PRODUCER}/128 & + hicn-ping-server -q -z hicnlightng_module -s 0 -n ${PING_PRODUCER}/128 & tail -f /dev/null diff --git a/tests/2-nodes-vpp-bridge.yml b/tests/2-nodes-vpp-bridge.yml index d9426844f..db1fa6fdc 100644 --- a/tests/2-nodes-vpp-bridge.yml +++ b/tests/2-nodes-vpp-bridge.yml @@ -98,10 +98,10 @@ services: sudo vpp -c /etc/vpp/startup.conf sleep 5 - sudo hiperf -D -S -R -B 4000kbps -z memif_module ${RTC_PRODUCER}/128 + sudo hiperf -q -S -R -B 4000kbps -z memif_module ${RTC_PRODUCER} -P 2 & sleep 1 - sudo hiperf -D -S -z memif_module ${RAAQM_PRODUCER}/128 + sudo hiperf -q -S -z memif_module ${RAAQM_PRODUCER}/128 & sleep 1 - sudo hicn-ping-server -d -s 0 -n ${PING_PRODUCER}/128 -z memif_module + sudo hicn-ping-server -q -s 0 -n ${PING_PRODUCER}/128 -z memif_module & tail -f /dev/null diff --git a/tests/2-nodes-vpp-memif-replication.yml b/tests/2-nodes-vpp-memif-replication.yml index 37f028dac..45de82400 100644 --- a/tests/2-nodes-vpp-memif-replication.yml +++ b/tests/2-nodes-vpp-memif-replication.yml @@ -134,10 +134,10 @@ services: sudo vpp -c /etc/vpp/startup.conf sleep 10 - sudo hiperf -D -S -R -B 4000kbps -z memif_module ${RTC_PRODUCER}/128 + sudo hiperf -q -S -R -B 4000kbps -z memif_module ${RTC_PRODUCER} -P 2 & sleep 5 - sudo hiperf -D -S -z memif_module ${RAAQM_PRODUCER}/128 + sudo hiperf -q -S -z memif_module ${RAAQM_PRODUCER}/128 & sleep 5 - sudo hicn-ping-server -d -s 0 -n ${PING_PRODUCER}/128 -z memif_module + sudo hicn-ping-server -q -s 0 -n ${PING_PRODUCER}/128 -z memif_module & tail -f /dev/null diff --git a/tests/2-nodes-vpp-memif.yml b/tests/2-nodes-vpp-memif.yml index 034437dbc..48b4a1c1d 100644 --- a/tests/2-nodes-vpp-memif.yml +++ b/tests/2-nodes-vpp-memif.yml @@ -107,10 +107,10 @@ services: sudo vpp -c /etc/vpp/startup.conf sleep 10 - sudo hiperf -D -S -R -B 4000kbps -z memif_module ${RTC_PRODUCER}/128 + sudo hiperf -q -S -R -B 4000kbps -z memif_module ${RTC_PRODUCER} -P 2 & sleep 5 - sudo hiperf -D -S -z memif_module ${RAAQM_PRODUCER}/128 + sudo hiperf -q -S -z memif_module ${RAAQM_PRODUCER}/128 & sleep 5 - sudo hicn-ping-server -d -s 0 -n ${PING_PRODUCER}/128 -z memif_module + sudo hicn-ping-server -q -s 0 -n ${PING_PRODUCER}/128 -z memif_module & tail -f /dev/null diff --git a/tests/Makefile b/tests/Makefile index 6e85a717e..0f30d6a42 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -30,6 +30,6 @@ down: functional: sleep 1 # Wait for the forwarder to be ready - bash config.sh test_listeners - bash config.sh test_connections - bash config.sh test_routes
\ No newline at end of file + bash config.sh ctrl listeners + bash config.sh ctrl connections + bash config.sh ctrl routes
\ No newline at end of file diff --git a/tests/config.sh b/tests/config.sh index d504b1c97..654bad518 100755 --- a/tests/config.sh +++ b/tests/config.sh @@ -16,7 +16,7 @@ BASE_IMAGE=${BASE_IMAGE:-hicn} BUILD_SOFTWARE=${BUILD_SOFTWARE:-1} set +a -HIPERF_CMD_RTC="hiperf -n 50 -C -H -R ${RTC_PRODUCER}" +HIPERF_CMD_RTC="hiperf -q -n 50 -C -H -R ${RTC_PRODUCER} -P 2" HIPERF_CMD_MEMIF_RTC="${HIPERF_CMD_RTC} -z memif_module" POSTPROCESS_COMMAND_RAAQM_RTC='tail -n +3 | \ tr -s " " | \ @@ -34,7 +34,7 @@ POSTPROCESS_COMMAND_RAAQM_RTC='tail -n +3 | \ print int(a[0]), int(a[n-1]), int(s/n) \ }"' -HIPERF_CMD_RAAQM="hiperf -n 50 -i 200 -C -H ${RAAQM_PRODUCER}" +HIPERF_CMD_RAAQM="hiperf -q -n 50 -i 200 -C -H ${RAAQM_PRODUCER}" HIPERF_CMD_CBR="${HIPERF_CMD_RAAQM} -W 350 -M 0" HIPERF_CMD_MEMIF_RAAQM="${HIPERF_CMD_RAAQM} -z memif_module" HIPERF_CMD_MEMIF_CBR="${HIPERF_CMD_CBR} -z memif_module" diff --git a/tests/forwarder.robot b/tests/forwarder.robot deleted file mode 100644 index 60345dbb0..000000000 --- a/tests/forwarder.robot +++ /dev/null @@ -1,45 +0,0 @@ -*** Settings *** -Library Process -Test Template Run Test -Test Setup Setup -Test Teardown Teardown -Test Timeout 5 seconds - -*** Variables *** -${cmd} bash test_forwarder.sh - -*** Test Cases *** -# Commands -Add listener test_add_listener -Remove listener test_remove_listener -Remove non-existing listener test_remove_non_existing_listener -Add duplicated listener test_add_duplicated_listener -List listeners test_list_listeners -Commands from config file test_commands_from_config - -# Ping -Ping one packet test_ping_one_packet -Ping two packets test_ping_two_packets -Ping using CS test_ping_using_cs -Ping using CS different order test_ping_using_cs_different_order -Ping timeout test_ping_timeout -Ping aggregation test_ping_aggregation -Ping with CS store disabled test_ping_with_cs_store_disabled -Ping with CS serve disabled test_ping_with_cs_serve_disabled -Ping with eviction test_ping_with_eviction -Ping with zero data lifetime test_ping_with_zero_data_lifetime - -*** Keywords *** -Setup - ${result}= Run Process ${cmd} set_up shell=True - Log Many stdout: ${result.stdout} stderr: ${result.stderr} - -Teardown - ${result}= Run Process ${cmd} tear_down shell=True - Log Many stdout: ${result.stdout} stderr: ${result.stderr} - -Run Test - [Arguments] ${test_name} - ${result}= Run Process ${cmd} ${test_name} shell=True - Log Many stdout: ${result.stdout} stderr: ${result.stderr} - Should Be Equal As Integers ${result.rc} 0
\ No newline at end of file diff --git a/tests/hiperf-local.sh b/tests/hiperf-local.sh new file mode 100644 index 000000000..1ef11eb72 --- /dev/null +++ b/tests/hiperf-local.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -eo pipefail + +if [[ "$(basename $(pwd))" != build* ]]; then + echo "Error: launch script from build dir" + exit 1 +fi + +# Stop forwarder and hiperf if already running +sudo killall -9 hicn-light-daemon hiperf 2>/dev/null || true + +# Start forwarder and hiperf server in background +ninja && sudo ./build-root/bin/hicn-light-daemon --daemon --log-file /tmp/lite_client.log >/dev/null +./build-root/bin/hiperf -z hicnlightng_module -S b001::/16 & + +# Run hiperf client for 20 seconds +sleep 1 +./build-root/bin/hiperf -z hicnlightng_module -C b001:: -W 50 -n 20 + +# Clean up +sudo killall -9 hicn-light-daemon hiperf diff --git a/tests/test_forwarder.sh b/tests/test_forwarder.sh deleted file mode 100644 index aba85d8d8..000000000 --- a/tests/test_forwarder.sh +++ /dev/null @@ -1,437 +0,0 @@ -#!/bin/bash - -############################################################################ -# CONSTANTS -############################################################################ -INTERFACE_CMD="ip route get 1 | grep -Po '(?<=(dev )).*(?= src| proto)'" -ADDRESS_CMD="ip route get 1 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'" -CTRL_CMD="docker exec test-hicn \ - /hicn-build/build/build-root/bin/hicn-light-control" -PING_SERVER_CMD="docker exec -d test-hicn \ - /hicn-build/build/build-root/bin/hicn-ping-server \ - -z hicnlightng_module" -PING_CLIENT_CMD="docker exec test-hicn \ - /hicn-build/build/build-root/bin/hicn-ping-client \ - -z hicnlightng_module" -PING_CLIENT_DETACHED_CMD="docker exec -d test-hicn \ - /hicn-build/build/build-root/bin/hicn-ping-client \ - -z hicnlightng_module" -LISTENER_NAME="udp0" -CONN_NAME="conn0" -PREFIX="c001::/64" -COST=1 -FIVE_SECONDS=5000 - -############################################################################ -# UTILS -############################################################################ -set_up() { - docker build -t hicn-dev . - run_forwarder -} - -tear_down() { - docker stop --time 0 test-hicn -} - -get_address() { - echo $(docker exec test-hicn sh -c "${ADDRESS_CMD}") -} - -get_interface() { - echo $(docker exec test-hicn sh -c "${INTERFACE_CMD}") -} - -#--------------------------------------------------------------------------- -# Exec -#--------------------------------------------------------------------------- -run_forwarder() { - capacity=${1:-"100000"} - loglevel=${2:-"trace"} - config=${3:-""} - - config_file_arg="" - if [[ $config != "" ]]; then - config_file_arg="--config ${config}" - fi - - docker run --rm -d --name test-hicn \ - -v $(pwd)/..:/hicn-build \ - -e LD_LIBRARY_PATH=/hicn-build/build/build-root/lib \ - hicn-dev \ - /hicn-build/build/build-root/bin/hicn-light-daemon \ - --log ${loglevel} --capacity ${capacity} $config_file_arg -} - -exec_controller() { - command=$1 - - # Redirect stderr to stdout - output=$(${CTRL_CMD} ${command} 2>&1) - assert_exit_code - echo ${output} -} - -exec_ping_server() { - data_lifetime=${1:-""} - - lifetime_arg="" - if [[ $data_lifetime != "" ]]; then - lifetime_arg="-l ${data_lifetime}" - fi - - ${PING_SERVER_CMD} ${lifetime_arg} -} - -exec_ping_client() { - num_packets=$1 - - output=$(${PING_CLIENT_CMD} -m ${num_packets}) - assert_exit_code - echo ${output} -} - -exec_ping_client_detached() { - num_packets=$1 - interest_lifetime=$2 - - ${PING_CLIENT_DETACHED_CMD} -m ${num_packets} -l ${interest_lifetime} -} - -#--------------------------------------------------------------------------- -# Asserts -#--------------------------------------------------------------------------- -assert_exit_code() { - if [[ $? -ne 0 ]]; then - exit_with_failure - fi -} - -assert_forwarder() { - # Print forwarder logs for debug info - echo "******** Forwarder Logs ********" - docker logs test-hicn - echo "********************************" - - output=$(docker logs test-hicn) - if [[ $output == "" ]]; then - exit_with_failure - fi - - if [[ "${output}" == *"ERROR"* ]]; then - exit_with_failure - fi - - if [[ "${output}" == *"Aborted (core dumped)"* ]]; then - exit_with_failure - fi -} - -assert_ack() { - # Print controller logs for debug info - echo "******** Controller Logs ********" - echo $1 - echo "********************************" - - output=$1 - - if [[ "$output" == *"Error"* ]]; then - exit_with_failure - fi -} - -assert_nack() { - # Print controller logs for debug info - echo "******** Controller Logs ********" - echo $1 - echo "********************************" - - output=$1 - - if [[ "$output" != *"Error"* ]]; then - exit_with_failure - fi -} - -assert_ping_client() { - # Print ping client logs for debug info - echo "******** Ping Client Logs ********" - echo $1 - echo "********************************" - - ping_client_output=$1 - pkts_sent=$2 - pkts_recv=$3 - pkts_timeout=$4 - - match_str="Sent: ${pkts_sent} Received: ${pkts_recv} Timeouts: ${pkts_timeout}" - if [[ ! ${ping_client_output} == *"${match_str}"* ]]; then - exit_with_failure - fi -} - -assert_forwarder_stats() { - satisfied_from_cs=${1:-""} - no_route_in_fib=${2:-""} - aggregated=${3:-""} - - fwder_stats=$(docker logs test-hicn | grep "Forwarder: received" | tail -n 1) - - if [[ $satisfied_from_cs != "" && - "${fwder_stats}" != *"satisfied_from_cs = ${satisfied_from_cs}"* ]]; then - exit_with_failure - fi - - if [[ $no_route_in_fib != "" && - "${fwder_stats}" != *"no_route_in_fib = ${no_route_in_fib}"* ]]; then - exit_with_failure - fi - - if [[ $aggregated != "" && - "${fwder_stats}" != *"aggregated = ${aggregated}"* ]]; then - exit_with_failure - fi -} - -assert_pkt_cache_stats() { - total_size=${1:-""} - pit_size=${2:-""} - cs_size=${3:-""} - - pkt_cache_stats=$(docker logs test-hicn | grep "Packet cache:" | tail -n 1) - - if [[ $total_size != "" && - "${pkt_cache_stats}" != *"total size = ${total_size}"* ]]; then - exit_with_failure - fi - - if [[ $pit_size != "" && - "${pkt_cache_stats}" != *"PIT size = ${pit_size}"* ]]; then - exit_with_failure - fi - - if [[ $cs_size != "" && - "${pkt_cache_stats}" != *"CS size = ${cs_size}"* ]]; then - exit_with_failure - fi -} - -assert_cs_stats() { - evictions=${1:-""} - - cs_stats=$(docker logs test-hicn | grep "Content store:" | tail -n 1) - - if [[ $evictions != "" && - "${cs_stats}" != *"evictions = ${evictions}"* ]]; then - exit_with_failure - fi -} - -############################################################################ -# TEST SUITE -############################################################################ - -#--------------------------------------------------------------------------- -# Commands -#--------------------------------------------------------------------------- -test_add_listener() { - # Exec hicn-light-control command and capture its output - INTERFACE=$(get_interface) - ADDRESS=$(get_address) - command="add listener udp ${LISTENER_NAME} ${ADDRESS} 9695 ${INTERFACE}" - ctrl_output=$(exec_controller "${command}") - - # Check hicn-light-control and hicn-light-daemon outputs - assert_ack "$ctrl_output" - assert_forwarder -} - -test_remove_listener() { - INTERFACE=$(get_interface) - ADDRESS=$(get_address) - command="add listener udp ${LISTENER_NAME} ${ADDRESS} 9695 ${INTERFACE}" - ctrl_output=$(exec_controller "${command}") - assert_ack "$ctrl_output" - - command="remove listener udp0" - ctrl_output=$(exec_controller "${command}") - - assert_ack "$ctrl_output" - assert_forwarder -} - -test_remove_non_existing_listener() { - command="remove listener udp0" - ctrl_output=$(exec_controller "${command}") - - assert_nack "$ctrl_output" - assert_forwarder -} - -test_add_duplicated_listener() { - # Exec hicn-light-control command and capture its output - INTERFACE=$(get_interface) - ADDRESS=$(get_address) - command="add listener udp ${LISTENER_NAME} ${ADDRESS} 9695 ${INTERFACE}" - exec_controller "${command}" - ctrl_output=$(exec_controller "${command}") - - # Check hicn-light-control and hicn-light-daemon outputs - assert_nack "$ctrl_output" - assert_forwarder -} - -test_list_listeners() { - # Exec hicn-light-control command and capture its output - command="list listener" - ctrl_output=$(exec_controller "${command}") - - # Check hicn-light-control and hicn-light-daemon outputs - assert_forwarder - # Only the local listener should be present - [[ "${ctrl_output}" =~ "inet4://127.0.0.1:9695" ]] && return 0 || exit_with_failure -} - -test_commands_from_config() { - # Create config file - INTERFACE=$(get_interface) - ADDRESS=$(get_address) - echo "# Teset config file - add listener udp $LISTENER_NAME $ADDRESS 9695 ${INTERFACE} - add connection udp $CONN_NAME $ADDRESS 12345 $ADDRESS 9695 ${INTERFACE} - add route $CONN_NAME $PREFIX $COST - set strategy c001::/64 random - " >forwarder.conf - - # Restart the forwarder specifying the config file - tear_down - run_forwarder "" "" "/hicn-build/tests/forwarder.conf" - rm forwarder.conf - - # Check for errors in the output - assert_forwarder -} - -#--------------------------------------------------------------------------- -# Ping -#--------------------------------------------------------------------------- -test_ping_one_packet() { - # Exec hicn-ping-server - exec_ping_server - # Exec hicn-ping-client (w/ 1 packet) and capture its output - output=$(exec_ping_client 1) - - # Check hicn-ping-client (1 pkt sent, 1 pkt received, 0 timeouts) - # and hicn-light-daemon outputs - assert_ping_client "${output}" 1 1 0 - assert_forwarder -} - -test_ping_two_packets() { - exec_ping_server - output=$(exec_ping_client 2) - - assert_ping_client "${output}" 2 2 0 - assert_forwarder -} - -test_ping_using_cs() { - exec_ping_server - exec_ping_client 2 - output=$(exec_ping_client 1) - - assert_ping_client "${output}" 1 1 0 - assert_forwarder - assert_forwarder_stats 1 -} - -test_ping_using_cs_different_order() { - exec_ping_server - exec_ping_client 1 - output=$(exec_ping_client 2) - - assert_ping_client "${output}" 2 2 0 - assert_forwarder - assert_forwarder_stats 1 -} - -test_ping_timeout() { - # Send ping without the ping server being run - output=$(exec_ping_client 1) - - assert_ping_client "${output}" 1 0 1 - assert_forwarder - assert_forwarder_stats 0 1 -} - -test_ping_aggregation() { - # Send ping without server, waiting for a reply - exec_ping_client_detached 1 ${FIVE_SECONDS} - exec_ping_server - # This new ping interest will be aggregated with the previous one - # and the forwarder will reply to both ping clients - output=$(exec_ping_client 1) - - assert_ping_client "${output}" 1 1 0 - assert_forwarder - assert_forwarder_stats "" "" 1 -} - -test_ping_with_cs_store_disabled() { - command="store cache off" - exec_controller "${command}" - - exec_ping_server - exec_ping_client 1 - output=$(exec_ping_client 1) - - assert_ping_client "${output}" 1 1 0 - assert_forwarder - assert_forwarder_stats 0 "" "" - # The packet is not stored in the CS - assert_pkt_cache_stats "" "" 0 -} - -test_ping_with_cs_serve_disabled() { - command="serve cache off" - exec_controller "${command}" - - exec_ping_server - exec_ping_client 1 - output=$(exec_ping_client 1) - - assert_ping_client "${output}" 1 1 0 - assert_forwarder - assert_forwarder_stats 0 "" "" - # The packet is stored in the CS, but CS is not used - assert_pkt_cache_stats "" "" 1 -} - -test_ping_with_eviction() { - # Restart the forwarder with CS capacity = 1 - tear_down - run_forwarder 1 - - exec_ping_server - exec_ping_client 1 - output=$(exec_ping_client 2) - - assert_ping_client "${output}" 2 2 0 - assert_forwarder - # Check if eviction happened - assert_cs_stats 1 - assert_pkt_cache_stats "" "" 1 -} - -test_ping_with_zero_data_lifetime() { - exec_ping_server 0 - exec_ping_client 1 - output=$(exec_ping_client 1) - - assert_ping_client "${output}" 1 1 0 - assert_forwarder - # The data is not taken from the CS because expired - assert_forwarder_stats 0 "" "" -} - -"$@" diff --git a/versions.cmake b/versions.cmake index 3bce94504..97e843298 100644 --- a/versions.cmake +++ b/versions.cmake @@ -5,4 +5,6 @@ set(VPP_DEFAULT_VERSION "22.02.0" "EXACT") set(LIBMEMIF_DEFAULT_VERSION "22.02" "EXACT") set(LIBCONFIG_DEFAULT_VERSION "1.5.0") set(COLLECTD_DEFAULT_VERSION "5.9.2" "EXACT") +set(RDKAFKA_DEFAULT_VERSION "1.8.2" "EXACT") set(ANDORID_SDK_DEP_DEFAULT_VERSION "2.1.1" "EXACT") +set(IOS_TOOLCHAIN_DEP_DEFAULT_VERSION "1.0.1" "EXACT") |