| /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
| /* |
| * Copyright (c) 2014-2020, Regents of the University of California, |
| * Arizona Board of Regents, |
| * Colorado State University, |
| * University Pierre & Marie Curie, Sorbonne University, |
| * Washington University in St. Louis, |
| * Beijing Institute of Technology, |
| * The University of Memphis. |
| * |
| * This file is part of NFD (Named Data Networking Forwarding Daemon). |
| * See AUTHORS.md for complete list of NFD authors and contributors. |
| * |
| * NFD 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, |
| * either version 3 of the License, or (at your option) any later version. |
| * |
| * NFD 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 |
| * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include "face/generic-link-service.hpp" |
| #include "face/face.hpp" |
| |
| #include "tests/test-common.hpp" |
| #include "tests/key-chain-fixture.hpp" |
| #include "tests/daemon/global-io-fixture.hpp" |
| #include "dummy-transport.hpp" |
| |
| #include <ndn-cxx/lp/empty-value.hpp> |
| #include <ndn-cxx/lp/prefix-announcement-header.hpp> |
| #include <ndn-cxx/lp/tags.hpp> |
| #include <ndn-cxx/security/signing-helpers.hpp> |
| |
| namespace nfd { |
| namespace face { |
| namespace tests { |
| |
| using namespace nfd::tests; |
| |
| BOOST_AUTO_TEST_SUITE(Face) |
| |
| using nfd::Face; |
| |
| class GenericLinkServiceFixture : public GlobalIoTimeFixture, public KeyChainFixture |
| { |
| protected: |
| GenericLinkServiceFixture() |
| { |
| // By default, GenericLinkService is created with default options. |
| // Test cases may invoke initialize() with alternate options. |
| initialize({}); |
| } |
| |
| void |
| initialize(const GenericLinkService::Options& options, |
| ssize_t mtu = MTU_UNLIMITED, |
| ssize_t sendQueueCapacity = QUEUE_UNSUPPORTED) |
| { |
| face = make_unique<Face>(make_unique<GenericLinkService>(options), |
| make_unique<DummyTransport>("dummy://", "dummy://", |
| ndn::nfd::FACE_SCOPE_NON_LOCAL, |
| ndn::nfd::FACE_PERSISTENCY_PERSISTENT, |
| ndn::nfd::LINK_TYPE_POINT_TO_POINT, |
| mtu, sendQueueCapacity)); |
| service = static_cast<GenericLinkService*>(face->getLinkService()); |
| transport = static_cast<DummyTransport*>(face->getTransport()); |
| |
| face->afterReceiveInterest.connect( |
| [this] (const Interest& interest, const EndpointId&) { receivedInterests.push_back(interest); }); |
| face->afterReceiveData.connect( |
| [this] (const Data& data, const EndpointId&) { receivedData.push_back(data); }); |
| face->afterReceiveNack.connect( |
| [this] (const lp::Nack& nack, const EndpointId&) { receivedNacks.push_back(nack); }); |
| } |
| |
| lp::PrefixAnnouncementHeader |
| makePrefixAnnHeader(const Name& announcedName) |
| { |
| return lp::PrefixAnnouncementHeader{signPrefixAnn(makePrefixAnn(announcedName, 1_h), |
| m_keyChain, ndn::signingWithSha256())}; |
| } |
| |
| protected: |
| unique_ptr<Face> face; |
| GenericLinkService* service = nullptr; |
| DummyTransport* transport = nullptr; |
| std::vector<Interest> receivedInterests; |
| std::vector<Data> receivedData; |
| std::vector<lp::Nack> receivedNacks; |
| }; |
| |
| BOOST_FIXTURE_TEST_SUITE(TestGenericLinkService, GenericLinkServiceFixture) |
| |
| BOOST_AUTO_TEST_SUITE(SimpleSendReceive) // send and receive without other fields |
| |
| BOOST_AUTO_TEST_CASE(SendInterest) |
| { |
| // Initialize with Options that disables all services |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| |
| auto interest1 = makeInterest("/localhost/test"); |
| face->sendInterest(*interest1); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nOutInterests, 1); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet interest1pkt(transport->sentPackets.back()); |
| BOOST_CHECK(interest1pkt.has<lp::FragmentField>()); |
| BOOST_CHECK(!interest1pkt.has<lp::SequenceField>()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendData) |
| { |
| // Initialize with Options that disables all services |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| |
| auto data1 = makeData("/localhost/test"); |
| face->sendData(*data1); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nOutData, 1); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet data1pkt(transport->sentPackets.back()); |
| BOOST_CHECK(data1pkt.has<lp::FragmentField>()); |
| BOOST_CHECK(!data1pkt.has<lp::SequenceField>()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendDataOverrideMtu) |
| { |
| // Initialize with Options that disables all services and does not override MTU |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| |
| BOOST_CHECK_EQUAL(transport->getMtu(), MTU_UNLIMITED); |
| BOOST_CHECK_EQUAL(service->getEffectiveMtu(), MTU_UNLIMITED); |
| BOOST_CHECK_EQUAL(face->getMtu(), MTU_UNLIMITED); |
| BOOST_CHECK_EQUAL(service->canOverrideMtuTo(MTU_UNLIMITED), false); |
| BOOST_CHECK_EQUAL(service->canOverrideMtuTo(MTU_INVALID), false); |
| // Attempts to override MTU will fail when transport MTU is unlimited |
| BOOST_CHECK_EQUAL(service->canOverrideMtuTo(4000), false); |
| |
| // Initialize with Options that disables all services and overrides MTU (Transport MTU 8800) |
| options.overrideMtu = MIN_MTU; |
| initialize(options, ndn::MAX_NDN_PACKET_SIZE); |
| |
| // Ensure effective MTU is override value |
| BOOST_CHECK_EQUAL(transport->getMtu(), ndn::MAX_NDN_PACKET_SIZE); |
| BOOST_CHECK_EQUAL(service->getEffectiveMtu(), MIN_MTU); |
| BOOST_CHECK_EQUAL(face->getMtu(), MIN_MTU); |
| |
| // Check MTU overrides with Transport MTU finite |
| BOOST_CHECK_EQUAL(service->canOverrideMtuTo(MTU_UNLIMITED), false); |
| BOOST_CHECK_EQUAL(service->canOverrideMtuTo(MTU_INVALID), false); |
| BOOST_CHECK_EQUAL(service->canOverrideMtuTo(MIN_MTU - 1), false); |
| BOOST_CHECK_EQUAL(service->canOverrideMtuTo(MIN_MTU), true); |
| BOOST_CHECK_EQUAL(service->canOverrideMtuTo(4000), true); |
| BOOST_CHECK_EQUAL(service->canOverrideMtuTo(20000), true); |
| |
| // Send Data with less than MIN_MTU octets |
| auto data1 = makeData("/localhost"); |
| BOOST_CHECK_LE(data1->wireEncode().size(), MIN_MTU); |
| face->sendData(*data1); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nOutData, 1); |
| BOOST_CHECK_EQUAL(service->getCounters().nOutOverMtu, 0); |
| |
| // Send Data with more than MIN_MTU octets |
| auto data2 = makeData("/localhost/test/1234567890/1234567890/1234567890/1234567890"); |
| BOOST_CHECK_GT(data2->wireEncode().size(), MIN_MTU); |
| face->sendData(*data2); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nOutData, 2); |
| BOOST_CHECK_EQUAL(service->getCounters().nOutOverMtu, 1); |
| |
| // Override MTU greater than the Transport's MTU will not be utilized |
| options.overrideMtu = 5000; |
| initialize(options, 4000); |
| BOOST_CHECK_EQUAL(service->getEffectiveMtu(), 4000); |
| BOOST_CHECK_EQUAL(face->getMtu(), 4000); |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendNack) |
| { |
| // Initialize with Options that disables all services |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| |
| auto nack1 = makeNack(*makeInterest("/localhost/test", false, nullopt, 323), |
| lp::NackReason::NO_ROUTE); |
| face->sendNack(nack1); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nOutNacks, 1); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet nack1pkt(transport->sentPackets.back()); |
| BOOST_CHECK(nack1pkt.has<lp::NackField>()); |
| BOOST_CHECK(nack1pkt.has<lp::FragmentField>()); |
| BOOST_CHECK(!nack1pkt.has<lp::SequenceField>()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveBareInterest) |
| { |
| // Initialize with Options that disables all services |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| |
| auto interest1 = makeInterest("/23Rd9hEiR"); |
| transport->receivePacket(interest1->wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInInterests, 1); |
| BOOST_REQUIRE_EQUAL(receivedInterests.size(), 1); |
| BOOST_CHECK_EQUAL(receivedInterests.back().wireEncode(), interest1->wireEncode()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveInterest) |
| { |
| // Initialize with Options that disables all services |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| |
| auto interest1 = makeInterest("/23Rd9hEiR"); |
| lp::Packet lpPacket; |
| lpPacket.set<lp::FragmentField>(std::make_pair( |
| interest1->wireEncode().begin(), interest1->wireEncode().end())); |
| lpPacket.set<lp::SequenceField>(0); // force LpPacket encoding |
| |
| transport->receivePacket(lpPacket.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInInterests, 1); |
| BOOST_REQUIRE_EQUAL(receivedInterests.size(), 1); |
| BOOST_CHECK_EQUAL(receivedInterests.back().wireEncode(), interest1->wireEncode()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveBareData) |
| { |
| // Initialize with Options that disables all services |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| |
| auto data1 = makeData("/12345678"); |
| transport->receivePacket(data1->wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInData, 1); |
| BOOST_REQUIRE_EQUAL(receivedData.size(), 1); |
| BOOST_CHECK_EQUAL(receivedData.back().wireEncode(), data1->wireEncode()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveData) |
| { |
| // Initialize with Options that disables all services |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| |
| auto data1 = makeData("/12345689"); |
| lp::Packet lpPacket; |
| lpPacket.set<lp::FragmentField>(std::make_pair( |
| data1->wireEncode().begin(), data1->wireEncode().end())); |
| lpPacket.set<lp::SequenceField>(0); // force LpPacket encoding |
| |
| transport->receivePacket(lpPacket.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInData, 1); |
| BOOST_REQUIRE_EQUAL(receivedData.size(), 1); |
| BOOST_CHECK_EQUAL(receivedData.back().wireEncode(), data1->wireEncode()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveNack) |
| { |
| // Initialize with Options that disables all services |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| |
| lp::Nack nack1 = makeNack(*makeInterest("/localhost/test", false, nullopt, 323), |
| lp::NackReason::NO_ROUTE); |
| lp::Packet lpPacket; |
| lpPacket.set<lp::FragmentField>(std::make_pair( |
| nack1.getInterest().wireEncode().begin(), nack1.getInterest().wireEncode().end())); |
| lpPacket.set<lp::NackField>(nack1.getHeader()); |
| |
| transport->receivePacket(lpPacket.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNacks, 1); |
| BOOST_REQUIRE_EQUAL(receivedNacks.size(), 1); |
| BOOST_CHECK_EQUAL(receivedNacks.back().getReason(), nack1.getReason()); |
| BOOST_CHECK_EQUAL(receivedNacks.back().getInterest().wireEncode(), nack1.getInterest().wireEncode()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveIdlePacket) |
| { |
| // Initialize with Options that disables all services |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| |
| lp::Packet lpPacket; |
| lpPacket.set<lp::SequenceField>(0); |
| |
| transport->receivePacket(lpPacket.wireEncode()); |
| |
| // IDLE packet should be ignored, but is not an error |
| BOOST_CHECK_EQUAL(service->getCounters().nInLpInvalid, 0); |
| BOOST_CHECK_EQUAL(receivedInterests.size(), 0); |
| BOOST_CHECK_EQUAL(receivedData.size(), 0); |
| BOOST_CHECK_EQUAL(receivedNacks.size(), 0); |
| } |
| |
| BOOST_AUTO_TEST_SUITE_END() // SimpleSendReceive |
| |
| BOOST_AUTO_TEST_SUITE(Fragmentation) |
| |
| BOOST_AUTO_TEST_CASE(FragmentationDisabledExceedMtuDrop) |
| { |
| // Initialize with Options that disable fragmentation |
| GenericLinkService::Options options; |
| options.allowFragmentation = false; |
| initialize(options); |
| |
| transport->setMtu(55); |
| |
| auto data = makeData("/test/data/123456789/987654321/123456789"); |
| face->sendData(*data); |
| |
| BOOST_CHECK_EQUAL(transport->sentPackets.size(), 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nOutOverMtu, 1); |
| } |
| |
| // It is possible for some interfaces (e.g., virtual Ethernet) to have their MTU set to zero |
| // This test case ensures that packets are dropped if the MTU is zero |
| BOOST_AUTO_TEST_CASE(FragmentationDisabledZeroMtuDrop) |
| { |
| // Initialize with Options that disable fragmentation |
| GenericLinkService::Options options; |
| options.allowFragmentation = false; |
| initialize(options); |
| |
| transport->setMtu(0); |
| |
| auto data = makeData("/test/data/123456789/987654321/123456789"); |
| face->sendData(*data); |
| |
| BOOST_CHECK_EQUAL(transport->sentPackets.size(), 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nOutOverMtu, 1); |
| } |
| |
| BOOST_AUTO_TEST_CASE(FragmentationUnlimitedMtu) |
| { |
| // Initialize with Options that enable fragmentation |
| GenericLinkService::Options options; |
| options.allowFragmentation = true; |
| initialize(options); |
| |
| transport->setMtu(MTU_UNLIMITED); |
| |
| auto data = makeData("/test/data/123456789/987654321/123456789"); |
| face->sendData(*data); |
| |
| BOOST_CHECK_EQUAL(transport->sentPackets.size(), 1); |
| } |
| |
| BOOST_AUTO_TEST_CASE(FragmentationUnderMtu) |
| { |
| // Initialize with Options that enable fragmentation |
| GenericLinkService::Options options; |
| options.allowFragmentation = true; |
| initialize(options); |
| |
| transport->setMtu(105); |
| |
| auto data = makeData("/test/data/123456789/987654321/123456789"); |
| face->sendData(*data); |
| |
| BOOST_CHECK_EQUAL(transport->sentPackets.size(), 1); |
| } |
| |
| BOOST_AUTO_TEST_CASE(FragmentationOverMtu) |
| { |
| // Initialize with Options that enable fragmentation |
| GenericLinkService::Options options; |
| options.allowFragmentation = true; |
| initialize(options); |
| |
| transport->setMtu(60); |
| |
| auto data = makeData("/test/data/123456789/987654321/123456789"); |
| face->sendData(*data); |
| |
| BOOST_CHECK_GT(transport->sentPackets.size(), 1); |
| } |
| |
| // It is possible for some interfaces (e.g., virtual Ethernet) to have their MTU set to zero |
| // This test case ensures that packets are dropped if the MTU is zero |
| BOOST_AUTO_TEST_CASE(FragmentationZeroMtuDrop) |
| { |
| // Initialize with Options that enable fragmentation |
| GenericLinkService::Options options; |
| options.allowFragmentation = true; |
| initialize(options); |
| |
| transport->setMtu(0); |
| |
| auto data = makeData("/test/data/123456789/987654321/123456789"); |
| face->sendData(*data); |
| |
| BOOST_CHECK_EQUAL(transport->sentPackets.size(), 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nFragmentationErrors, 1); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReassembleFragments) |
| { |
| // Initialize with Options that enables reassembly |
| GenericLinkService::Options options; |
| options.allowReassembly = true; |
| initialize(options); |
| |
| auto interest = makeInterest( |
| "/mt7P130BHXmtLm5dwaY5dpUM6SWYNN2B05g7y3UhsQuLvDdnTWdNnTeEiLuW3FAbJRSG3tzQ0UfaSEgG9rvYHmsKtgPMag1Hj4Tr"); |
| lp::Packet packet(interest->wireEncode()); |
| |
| // fragment the packet |
| LpFragmenter fragmenter({}); |
| size_t mtu = 100; |
| bool isOk = false; |
| std::vector<lp::Packet> frags; |
| std::tie(isOk, frags) = fragmenter.fragmentPacket(packet, mtu); |
| BOOST_REQUIRE(isOk); |
| BOOST_CHECK_GT(frags.size(), 1); |
| |
| // receive the fragments |
| for (ssize_t fragIndex = frags.size() - 1; fragIndex >= 0; --fragIndex) { |
| size_t sequence = 1000 + fragIndex; |
| frags[fragIndex].add<lp::SequenceField>(sequence); |
| |
| transport->receivePacket(frags[fragIndex].wireEncode()); |
| |
| if (fragIndex > 0) { |
| BOOST_CHECK(receivedInterests.empty()); |
| BOOST_CHECK_EQUAL(service->getCounters().nReassembling, 1); |
| } |
| else { |
| BOOST_CHECK_EQUAL(receivedInterests.size(), 1); |
| BOOST_CHECK_EQUAL(receivedInterests.back().wireEncode(), interest->wireEncode()); |
| BOOST_CHECK_EQUAL(service->getCounters().nReassembling, 0); |
| } |
| } |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReassemblyDisabledDropFragIndex) |
| { |
| // Initialize with Options that disables reassembly |
| GenericLinkService::Options options; |
| options.allowReassembly = false; |
| initialize(options); |
| |
| auto interest = makeInterest("/IgFe6NvH"); |
| lp::Packet packet(interest->wireEncode()); |
| packet.set<lp::FragIndexField>(140); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInLpInvalid, 0); // not an error |
| BOOST_CHECK(receivedInterests.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReassemblyDisabledDropFragCount) |
| { |
| // Initialize with Options that disables reassembly |
| GenericLinkService::Options options; |
| options.allowReassembly = false; |
| initialize(options); |
| |
| auto interest = makeInterest("/SeGmEjvIVX"); |
| lp::Packet packet(interest->wireEncode()); |
| packet.set<lp::FragCountField>(276); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInLpInvalid, 0); // not an error |
| BOOST_CHECK(receivedInterests.empty()); |
| } |
| |
| BOOST_AUTO_TEST_SUITE_END() // Fragmentation |
| |
| BOOST_AUTO_TEST_SUITE(Reliability) |
| |
| BOOST_AUTO_TEST_CASE(SendInterest) |
| { |
| // Initialize with Options that enables reliability |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| options.reliabilityOptions.isEnabled = true; |
| initialize(options); |
| |
| auto interest1 = makeInterest("/localhost/test"); |
| face->sendInterest(*interest1); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nOutInterests, 1); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet interest1pkt(transport->sentPackets.back()); |
| BOOST_CHECK(interest1pkt.has<lp::FragmentField>()); |
| BOOST_CHECK(interest1pkt.has<lp::TxSequenceField>()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendData) |
| { |
| // Initialize with Options that enables reliability |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| options.reliabilityOptions.isEnabled = true; |
| initialize(options); |
| |
| auto data1 = makeData("/localhost/test"); |
| face->sendData(*data1); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nOutData, 1); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet data1pkt(transport->sentPackets.back()); |
| BOOST_CHECK(data1pkt.has<lp::FragmentField>()); |
| BOOST_CHECK(data1pkt.has<lp::TxSequenceField>()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendNack) |
| { |
| // Initialize with Options that enables reliability |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| options.reliabilityOptions.isEnabled = true; |
| initialize(options); |
| |
| auto nack1 = makeNack(*makeInterest("/localhost/test", false, nullopt, 323), |
| lp::NackReason::NO_ROUTE); |
| face->sendNack(nack1); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nOutNacks, 1); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet nack1pkt(transport->sentPackets.back()); |
| BOOST_CHECK(nack1pkt.has<lp::NackField>()); |
| BOOST_CHECK(nack1pkt.has<lp::FragmentField>()); |
| BOOST_CHECK(nack1pkt.has<lp::TxSequenceField>()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(DropDuplicatePacket) |
| { |
| // Initialize with Options that enables reliability |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| options.reliabilityOptions.isEnabled = true; |
| initialize(options); |
| |
| Interest interest("/test/prefix"); |
| interest.setCanBePrefix(false); |
| lp::Packet pkt1; |
| pkt1.add<lp::FragmentField>({interest.wireEncode().begin(), interest.wireEncode().end()}); |
| pkt1.add<lp::SequenceField>(7); |
| pkt1.add<lp::TxSequenceField>(12); |
| transport->receivePacket(pkt1.wireEncode()); |
| BOOST_CHECK_EQUAL(service->getCounters().nInInterests, 1); |
| BOOST_CHECK_EQUAL(service->getCounters().nDuplicateSequence, 0); |
| |
| lp::Packet pkt2; |
| pkt2.add<lp::FragmentField>({interest.wireEncode().begin(), interest.wireEncode().end()}); |
| pkt2.add<lp::SequenceField>(7); |
| pkt2.add<lp::TxSequenceField>(13); |
| transport->receivePacket(pkt2.wireEncode()); |
| BOOST_CHECK_EQUAL(service->getCounters().nInInterests, 1); |
| BOOST_CHECK_EQUAL(service->getCounters().nDuplicateSequence, 1); |
| } |
| |
| BOOST_AUTO_TEST_SUITE_END() // Reliability |
| |
| // congestion detection and marking |
| BOOST_AUTO_TEST_SUITE(CongestionMark) |
| |
| BOOST_AUTO_TEST_CASE(NoCongestion) |
| { |
| GenericLinkService::Options options; |
| options.allowCongestionMarking = true; |
| options.baseCongestionMarkingInterval = 100_ms; |
| initialize(options, MTU_UNLIMITED, 65536); |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, time::steady_clock::TimePoint::max()); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 0); |
| |
| auto interest = makeInterest("/12345678"); |
| |
| // congestion threshold will be 32768 bytes, since min(65536, 65536 / 2) = 32768 bytes |
| |
| // no congestion |
| transport->setSendQueueLength(0); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet pkt1(transport->sentPackets.back()); |
| BOOST_CHECK_EQUAL(pkt1.count<lp::CongestionMarkField>(), 0); |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, time::steady_clock::TimePoint::max()); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 0); |
| |
| // no congestion |
| transport->setSendQueueLength(32768); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 2); |
| lp::Packet pkt2(transport->sentPackets.back()); |
| BOOST_CHECK_EQUAL(pkt2.count<lp::CongestionMarkField>(), 0); |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, time::steady_clock::TimePoint::max()); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 0); |
| } |
| |
| BOOST_AUTO_TEST_CASE(CongestionCoDel) |
| { |
| GenericLinkService::Options options; |
| options.allowCongestionMarking = true; |
| options.baseCongestionMarkingInterval = 100_ms; |
| initialize(options, MTU_UNLIMITED, 65536); |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, time::steady_clock::TimePoint::max()); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 0); |
| |
| auto interest = makeInterest("/12345678"); |
| |
| // first congested packet, will not be marked |
| transport->setSendQueueLength(65537); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet pkt0(transport->sentPackets.back()); |
| BOOST_REQUIRE_EQUAL(pkt0.count<lp::CongestionMarkField>(), 0); |
| time::steady_clock::TimePoint nextMarkTime = time::steady_clock::now() + 100_ms; |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, nextMarkTime); |
| |
| time::nanoseconds markingInterval( |
| static_cast<time::nanoseconds::rep>(options.baseCongestionMarkingInterval.count() / |
| std::sqrt(service->m_nMarkedSinceInMarkingState + 1))); |
| |
| advanceClocks(markingInterval + 1_ms); |
| face->sendInterest(*interest); |
| lp::Packet pkt1(transport->sentPackets.back()); |
| |
| // First congestion mark appears after one interval (100 ms) |
| BOOST_REQUIRE_EQUAL(pkt1.count<lp::CongestionMarkField>(), 1); |
| BOOST_CHECK_EQUAL(pkt1.get<lp::CongestionMarkField>(), 1); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 1); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 1); |
| |
| // advance clock to half of marking interval cycle |
| advanceClocks(markingInterval / 2); // 50ms |
| |
| // second congested packet, but within marking interval, will not be marked |
| transport->setSendQueueLength(66000); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 3); |
| lp::Packet pkt2(transport->sentPackets.back()); |
| BOOST_CHECK_EQUAL(pkt2.count<lp::CongestionMarkField>(), 0); |
| |
| markingInterval = time::nanoseconds( |
| static_cast<time::nanoseconds::rep>(options.baseCongestionMarkingInterval.count() / |
| std::sqrt(service->m_nMarkedSinceInMarkingState + 1))); |
| nextMarkTime += markingInterval; |
| |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, nextMarkTime); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 1); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 1); |
| |
| // advance clocks past end of initial interval cycle |
| this->advanceClocks((markingInterval / 2) + 1_ms); |
| |
| // first congested packet after waiting marking interval, will be marked |
| transport->setSendQueueLength(66000); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 4); |
| lp::Packet pkt3(transport->sentPackets.back()); |
| BOOST_REQUIRE_EQUAL(pkt3.count<lp::CongestionMarkField>(), 1); |
| BOOST_CHECK_EQUAL(pkt3.get<lp::CongestionMarkField>(), 1); |
| markingInterval = time::nanoseconds( |
| static_cast<time::nanoseconds::rep>(options.baseCongestionMarkingInterval.count() / |
| std::sqrt(service->m_nMarkedSinceInMarkingState + 1))); |
| nextMarkTime += markingInterval; |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, nextMarkTime); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 2); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 2); |
| |
| // advance clock partway through current marking interval |
| this->advanceClocks(markingInterval - 20_ms); |
| |
| // still congested, but within marking interval cycle |
| transport->setSendQueueLength(66000); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 5); |
| lp::Packet pkt4(transport->sentPackets.back()); |
| BOOST_CHECK_EQUAL(pkt4.count<lp::CongestionMarkField>(), 0); |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, nextMarkTime); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 2); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 2); |
| |
| // advance clocks past end of current marking interval cycle |
| this->advanceClocks(21_ms); |
| |
| // still congested, after marking interval cycle |
| transport->setSendQueueLength(66000); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 6); |
| lp::Packet pkt5(transport->sentPackets.back()); |
| BOOST_REQUIRE_EQUAL(pkt5.count<lp::CongestionMarkField>(), 1); |
| BOOST_CHECK_EQUAL(pkt5.get<lp::CongestionMarkField>(), 1); |
| markingInterval = time::nanoseconds( |
| static_cast<time::nanoseconds::rep>(options.baseCongestionMarkingInterval.count() / |
| std::sqrt(service->m_nMarkedSinceInMarkingState + 1))); |
| nextMarkTime += markingInterval; |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, nextMarkTime); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 3); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 3); |
| |
| this->advanceClocks(1_ms); |
| |
| // still congested, but within marking interval cycle |
| transport->setSendQueueLength(66000); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 7); |
| lp::Packet pkt6(transport->sentPackets.back()); |
| BOOST_CHECK_EQUAL(pkt6.count<lp::CongestionMarkField>(), 0); |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, nextMarkTime); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 3); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 3); |
| |
| this->advanceClocks(markingInterval); |
| |
| // still congested, after marking interval cycle |
| transport->setSendQueueLength(66000); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 8); |
| lp::Packet pkt7(transport->sentPackets.back()); |
| BOOST_REQUIRE_EQUAL(pkt7.count<lp::CongestionMarkField>(), 1); |
| BOOST_CHECK_EQUAL(pkt7.get<lp::CongestionMarkField>(), 1); |
| markingInterval = time::nanoseconds( |
| static_cast<time::nanoseconds::rep>(options.baseCongestionMarkingInterval.count() / |
| std::sqrt(service->m_nMarkedSinceInMarkingState + 1))); |
| nextMarkTime += markingInterval; |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, nextMarkTime); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 4); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 4); |
| |
| // no more congestion |
| transport->setSendQueueLength(30000); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 9); |
| lp::Packet pkt8(transport->sentPackets.back()); |
| BOOST_CHECK_EQUAL(pkt8.count<lp::CongestionMarkField>(), 0); |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, time::steady_clock::TimePoint::max()); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 4); |
| |
| this->advanceClocks(50_ms); |
| |
| // send queue congested again, but can't mark packet because within one full interval of last mark |
| transport->setSendQueueLength(66000); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 10); |
| lp::Packet pkt9(transport->sentPackets.back()); |
| BOOST_CHECK_EQUAL(pkt9.count<lp::CongestionMarkField>(), 0); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 0); |
| markingInterval = time::nanoseconds( |
| static_cast<time::nanoseconds::rep>(options.baseCongestionMarkingInterval.count() / |
| std::sqrt(service->m_nMarkedSinceInMarkingState + 1))); |
| nextMarkTime = time::steady_clock::now() + markingInterval; |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, nextMarkTime); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 4); |
| |
| // advance clock past full 100ms interval since last mark |
| this->advanceClocks(markingInterval + 2_ms); |
| BOOST_CHECK_GT(time::steady_clock::now(), nextMarkTime); |
| |
| transport->setSendQueueLength(66000); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 11); |
| lp::Packet pkt10(transport->sentPackets.back()); |
| BOOST_REQUIRE_EQUAL(pkt10.count<lp::CongestionMarkField>(), 1); |
| BOOST_CHECK_EQUAL(pkt10.get<lp::CongestionMarkField>(), 1); |
| markingInterval = time::nanoseconds( |
| static_cast<time::nanoseconds::rep>(options.baseCongestionMarkingInterval.count() / |
| std::sqrt(service->m_nMarkedSinceInMarkingState + 1))); |
| nextMarkTime += markingInterval; |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, nextMarkTime); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 1); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 5); |
| |
| // advance clock partway through 100ms marking interval |
| this->advanceClocks(50_ms); |
| |
| // not marked since within 100ms window before can mark again |
| transport->setSendQueueLength(66000); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 12); |
| lp::Packet pkt11(transport->sentPackets.back()); |
| BOOST_CHECK_EQUAL(pkt11.count<lp::CongestionMarkField>(), 0); |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, nextMarkTime); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 1); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 5); |
| |
| // advance clocks past m_nextMarkTime |
| this->advanceClocks(51_ms); |
| |
| // markable packet, queue length still above threshold |
| transport->setSendQueueLength(66000); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 13); |
| lp::Packet pkt12(transport->sentPackets.back()); |
| BOOST_REQUIRE_EQUAL(pkt12.count<lp::CongestionMarkField>(), 1); |
| BOOST_CHECK_EQUAL(pkt12.get<lp::CongestionMarkField>(), 1); |
| markingInterval = time::nanoseconds( |
| static_cast<time::nanoseconds::rep>(options.baseCongestionMarkingInterval.count() / |
| std::sqrt(service->m_nMarkedSinceInMarkingState + 1))); |
| nextMarkTime += markingInterval; |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, nextMarkTime); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 2); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 6); |
| |
| // no more congestion |
| transport->setSendQueueLength(10000); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 14); |
| lp::Packet pkt13(transport->sentPackets.back()); |
| BOOST_CHECK_EQUAL(pkt13.count<lp::CongestionMarkField>(), 0); |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, time::steady_clock::TimePoint::max()); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 6); |
| |
| // advance clocks past one full interval since last mark |
| this->advanceClocks(102_ms); |
| |
| // start congestion again |
| transport->setSendQueueLength(66000); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 15); |
| lp::Packet pkt14(transport->sentPackets.back()); |
| BOOST_REQUIRE_EQUAL(pkt14.count<lp::CongestionMarkField>(), 0); |
| nextMarkTime = time::steady_clock::now() + 100_ms; |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, nextMarkTime); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 6); |
| |
| // no more congestion, cancel marking interval |
| transport->setSendQueueLength(5000); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 16); |
| lp::Packet pkt15(transport->sentPackets.back()); |
| BOOST_CHECK_EQUAL(pkt15.count<lp::CongestionMarkField>(), 0); |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, time::steady_clock::TimePoint::max()); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 6); |
| } |
| |
| BOOST_AUTO_TEST_CASE(DefaultThreshold) |
| { |
| GenericLinkService::Options options; |
| options.allowCongestionMarking = true; |
| options.baseCongestionMarkingInterval = 100_ms; |
| initialize(options, MTU_UNLIMITED, QUEUE_UNSUPPORTED); |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, time::steady_clock::TimePoint::max()); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 0); |
| |
| auto interest = makeInterest("/12345678"); |
| |
| // congestion threshold will be 65536 bytes, since the transport reports that it cannot measure |
| // the queue capacity |
| |
| // no congestion |
| transport->setSendQueueLength(0); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet pkt1(transport->sentPackets.back()); |
| BOOST_CHECK_EQUAL(pkt1.count<lp::CongestionMarkField>(), 0); |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, time::steady_clock::TimePoint::max()); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 0); |
| |
| // no congestion |
| transport->setSendQueueLength(65536); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 2); |
| lp::Packet pkt2(transport->sentPackets.back()); |
| BOOST_CHECK_EQUAL(pkt2.count<lp::CongestionMarkField>(), 0); |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, time::steady_clock::TimePoint::max()); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 0); |
| |
| // first congested (not marked yet) packet |
| transport->setSendQueueLength(65537); |
| face->sendInterest(*interest); |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 3); |
| lp::Packet pkt3(transport->sentPackets.back()); |
| BOOST_REQUIRE_EQUAL(pkt3.count<lp::CongestionMarkField>(), 0); |
| time::steady_clock::TimePoint nextMarkTime = time::steady_clock::now() + 100_ms; |
| BOOST_CHECK_EQUAL(service->m_nextMarkTime, nextMarkTime); |
| BOOST_CHECK_EQUAL(service->m_nMarkedSinceInMarkingState, 0); |
| BOOST_CHECK_EQUAL(service->getCounters().nCongestionMarked, 0); |
| } |
| |
| BOOST_AUTO_TEST_SUITE_END() // CongestionMark |
| |
| BOOST_AUTO_TEST_SUITE(LpFields) |
| |
| BOOST_AUTO_TEST_CASE(ReceiveNextHopFaceId) |
| { |
| // Initialize with Options that enables local fields |
| GenericLinkService::Options options; |
| options.allowLocalFields = true; |
| initialize(options); |
| |
| auto interest = makeInterest("/12345678"); |
| lp::Packet packet(interest->wireEncode()); |
| packet.set<lp::NextHopFaceIdField>(1000); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_REQUIRE_EQUAL(receivedInterests.size(), 1); |
| auto tag = receivedInterests.back().getTag<lp::NextHopFaceIdTag>(); |
| BOOST_REQUIRE(tag != nullptr); |
| BOOST_CHECK_EQUAL(*tag, 1000); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveNextHopFaceIdDisabled) |
| { |
| // Initialize with Options that disables local fields |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| |
| auto interest = makeInterest("/12345678"); |
| lp::Packet packet(interest->wireEncode()); |
| packet.set<lp::NextHopFaceIdField>(1000); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 0); // not an error |
| BOOST_CHECK(receivedInterests.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveNextHopFaceIdDropData) |
| { |
| // Initialize with Options that enables local fields |
| GenericLinkService::Options options; |
| options.allowLocalFields = true; |
| initialize(options); |
| |
| auto data = makeData("/12345678"); |
| lp::Packet packet(data->wireEncode()); |
| packet.set<lp::NextHopFaceIdField>(1000); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 1); |
| BOOST_CHECK(receivedData.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveNextHopFaceIdDropNack) |
| { |
| // Initialize with Options that enables local fields |
| GenericLinkService::Options options; |
| options.allowLocalFields = true; |
| initialize(options); |
| |
| lp::Nack nack = makeNack(*makeInterest("/localhost/test", false, nullopt, 123), |
| lp::NackReason::NO_ROUTE); |
| lp::Packet packet; |
| packet.set<lp::FragmentField>(std::make_pair( |
| nack.getInterest().wireEncode().begin(), nack.getInterest().wireEncode().end())); |
| packet.set<lp::NackField>(nack.getHeader()); |
| packet.set<lp::NextHopFaceIdField>(1000); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 1); |
| BOOST_CHECK(receivedNacks.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveCachePolicy) |
| { |
| // Initialize with Options that disables local fields |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| // CachePolicy is unprivileged and does not require allowLocalFields option. |
| |
| auto data = makeData("/12345678"); |
| lp::Packet packet(data->wireEncode()); |
| packet.set<lp::CachePolicyField>(lp::CachePolicy().setPolicy(lp::CachePolicyType::NO_CACHE)); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_REQUIRE_EQUAL(receivedData.size(), 1); |
| auto tag = receivedData.back().getTag<lp::CachePolicyTag>(); |
| BOOST_REQUIRE(tag != nullptr); |
| BOOST_CHECK_EQUAL(tag->get().getPolicy(), lp::CachePolicyType::NO_CACHE); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveCachePolicyDropInterest) |
| { |
| // Initialize with Options that enables local fields |
| GenericLinkService::Options options; |
| options.allowLocalFields = true; |
| initialize(options); |
| |
| auto interest = makeInterest("/12345678"); |
| lp::Packet packet(interest->wireEncode()); |
| lp::CachePolicy policy; |
| policy.setPolicy(lp::CachePolicyType::NO_CACHE); |
| packet.set<lp::CachePolicyField>(policy); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 1); |
| BOOST_CHECK(receivedInterests.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveCachePolicyDropNack) |
| { |
| // Initialize with Options that enables local fields |
| GenericLinkService::Options options; |
| options.allowLocalFields = true; |
| initialize(options); |
| |
| lp::Nack nack = makeNack(*makeInterest("/localhost/test", false, nullopt, 123), |
| lp::NackReason::NO_ROUTE); |
| lp::Packet packet(nack.getInterest().wireEncode()); |
| packet.set<lp::NackField>(nack.getHeader()); |
| lp::CachePolicy policy; |
| policy.setPolicy(lp::CachePolicyType::NO_CACHE); |
| packet.set<lp::CachePolicyField>(policy); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 1); |
| BOOST_CHECK(receivedNacks.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendIncomingFaceId) |
| { |
| // Initialize with Options that enables local fields |
| GenericLinkService::Options options; |
| options.allowLocalFields = true; |
| initialize(options); |
| |
| auto interest = makeInterest("/12345678"); |
| interest->setTag(make_shared<lp::IncomingFaceIdTag>(1000)); |
| |
| face->sendInterest(*interest); |
| |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet sent(transport->sentPackets.back()); |
| BOOST_REQUIRE(sent.has<lp::IncomingFaceIdField>()); |
| BOOST_CHECK_EQUAL(sent.get<lp::IncomingFaceIdField>(), 1000); |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendIncomingFaceIdDisabled) |
| { |
| // Initialize with Options that disables local fields |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| |
| auto interest = makeInterest("/12345678"); |
| interest->setTag(make_shared<lp::IncomingFaceIdTag>(1000)); |
| |
| face->sendInterest(*interest); |
| |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet sent(transport->sentPackets.back()); |
| BOOST_CHECK(!sent.has<lp::IncomingFaceIdField>()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveIncomingFaceIdIgnoreInterest) |
| { |
| // Initialize with Options that enables local fields |
| GenericLinkService::Options options; |
| options.allowLocalFields = true; |
| initialize(options); |
| |
| auto interest = makeInterest("/12345678"); |
| lp::Packet packet(interest->wireEncode()); |
| packet.set<lp::IncomingFaceIdField>(1000); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 0); // not an error |
| BOOST_REQUIRE_EQUAL(receivedInterests.size(), 1); |
| BOOST_CHECK(receivedInterests.back().getTag<lp::IncomingFaceIdTag>() == nullptr); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveIncomingFaceIdIgnoreData) |
| { |
| // Initialize with Options that enables local fields |
| GenericLinkService::Options options; |
| options.allowLocalFields = true; |
| initialize(options); |
| |
| auto data = makeData("/z1megUh9Bj"); |
| lp::Packet packet(data->wireEncode()); |
| packet.set<lp::IncomingFaceIdField>(1000); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 0); // not an error |
| BOOST_REQUIRE_EQUAL(receivedData.size(), 1); |
| BOOST_CHECK(receivedData.back().getTag<lp::IncomingFaceIdTag>() == nullptr); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveIncomingFaceIdIgnoreNack) |
| { |
| // Initialize with Options that enables local fields |
| GenericLinkService::Options options; |
| options.allowLocalFields = true; |
| initialize(options); |
| |
| lp::Nack nack = makeNack(*makeInterest("/TPAhdiHz", false, nullopt, 278), |
| lp::NackReason::CONGESTION); |
| lp::Packet packet(nack.getInterest().wireEncode()); |
| packet.set<lp::NackField>(nack.getHeader()); |
| packet.set<lp::IncomingFaceIdField>(1000); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 0); // not an error |
| BOOST_REQUIRE_EQUAL(receivedNacks.size(), 1); |
| BOOST_CHECK(receivedNacks.back().getTag<lp::IncomingFaceIdTag>() == nullptr); |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendCongestionMarkInterest) |
| { |
| auto interest = makeInterest("/12345678"); |
| interest->setTag(make_shared<lp::CongestionMarkTag>(1)); |
| |
| face->sendInterest(*interest); |
| |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet sent(transport->sentPackets.back()); |
| BOOST_REQUIRE(sent.has<lp::CongestionMarkField>()); |
| BOOST_CHECK_EQUAL(sent.get<lp::CongestionMarkField>(), 1); |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendCongestionMarkData) |
| { |
| auto data = makeData("/12345678"); |
| data->setTag(make_shared<lp::CongestionMarkTag>(0)); |
| |
| face->sendData(*data); |
| |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet sent(transport->sentPackets.back()); |
| BOOST_REQUIRE(sent.has<lp::CongestionMarkField>()); |
| BOOST_CHECK_EQUAL(sent.get<lp::CongestionMarkField>(), 0); |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendCongestionMarkNack) |
| { |
| lp::Nack nack = makeNack(*makeInterest("/localhost/test", false, nullopt, 123), |
| lp::NackReason::NO_ROUTE); |
| nack.setTag(make_shared<lp::CongestionMarkTag>(std::numeric_limits<uint64_t>::max())); |
| |
| face->sendNack(nack); |
| |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet sent(transport->sentPackets.back()); |
| BOOST_REQUIRE(sent.has<lp::CongestionMarkField>()); |
| BOOST_CHECK_EQUAL(sent.get<lp::CongestionMarkField>(), std::numeric_limits<uint64_t>::max()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveCongestionMarkInterest) |
| { |
| auto interest = makeInterest("/12345678"); |
| lp::Packet packet(interest->wireEncode()); |
| packet.set<lp::CongestionMarkField>(1); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_REQUIRE_EQUAL(receivedInterests.size(), 1); |
| auto tag = receivedInterests.back().getTag<lp::CongestionMarkTag>(); |
| BOOST_REQUIRE(tag != nullptr); |
| BOOST_CHECK_EQUAL(*tag, 1); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveCongestionMarkData) |
| { |
| auto data = makeData("/12345678"); |
| lp::Packet packet(data->wireEncode()); |
| packet.set<lp::CongestionMarkField>(1); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_REQUIRE_EQUAL(receivedData.size(), 1); |
| auto tag = receivedData.back().getTag<lp::CongestionMarkTag>(); |
| BOOST_REQUIRE(tag != nullptr); |
| BOOST_CHECK_EQUAL(*tag, 1); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveCongestionMarkNack) |
| { |
| lp::Nack nack = makeNack(*makeInterest("/localhost/test", false, nullopt, 123), |
| lp::NackReason::NO_ROUTE); |
| lp::Packet packet; |
| packet.set<lp::FragmentField>(std::make_pair( |
| nack.getInterest().wireEncode().begin(), nack.getInterest().wireEncode().end())); |
| packet.set<lp::NackField>(nack.getHeader()); |
| packet.set<lp::CongestionMarkField>(1); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_REQUIRE_EQUAL(receivedNacks.size(), 1); |
| auto tag = receivedNacks.back().getTag<lp::CongestionMarkTag>(); |
| BOOST_REQUIRE(tag != nullptr); |
| BOOST_CHECK_EQUAL(*tag, 1); |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendNonDiscovery) |
| { |
| GenericLinkService::Options options; |
| options.allowSelfLearning = true; |
| initialize(options); |
| |
| auto interest = makeInterest("/12345678"); |
| interest->setTag(make_shared<lp::NonDiscoveryTag>(lp::EmptyValue{})); |
| |
| face->sendInterest(*interest); |
| |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet sent(transport->sentPackets.back()); |
| BOOST_CHECK(sent.has<lp::NonDiscoveryField>()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendNonDiscoveryDisabled) |
| { |
| GenericLinkService::Options options; |
| options.allowSelfLearning = false; |
| initialize(options); |
| |
| auto interest = makeInterest("/12345678"); |
| interest->setTag(make_shared<lp::NonDiscoveryTag>(lp::EmptyValue{})); |
| |
| face->sendInterest(*interest); |
| |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet sent(transport->sentPackets.back()); |
| BOOST_CHECK(!sent.has<lp::NonDiscoveryField>()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveNonDiscovery) |
| { |
| GenericLinkService::Options options; |
| options.allowSelfLearning = true; |
| initialize(options); |
| |
| auto interest = makeInterest("/12345678"); |
| lp::Packet packet(interest->wireEncode()); |
| packet.set<lp::NonDiscoveryField>(lp::EmptyValue{}); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_REQUIRE_EQUAL(receivedInterests.size(), 1); |
| auto tag = receivedInterests.back().getTag<lp::NonDiscoveryTag>(); |
| BOOST_CHECK(tag != nullptr); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveNonDiscoveryDisabled) |
| { |
| GenericLinkService::Options options; |
| options.allowSelfLearning = false; |
| initialize(options); |
| |
| auto interest = makeInterest("/12345678"); |
| lp::Packet packet(interest->wireEncode()); |
| packet.set<lp::NonDiscoveryField>(lp::EmptyValue{}); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 0); // not an error |
| BOOST_CHECK_EQUAL(receivedInterests.size(), 1); |
| auto tag = receivedInterests.back().getTag<lp::NonDiscoveryTag>(); |
| BOOST_CHECK(tag == nullptr); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveNonDiscoveryDropData) |
| { |
| GenericLinkService::Options options; |
| options.allowSelfLearning = true; |
| initialize(options); |
| |
| auto data = makeData("/12345678"); |
| lp::Packet packet(data->wireEncode()); |
| packet.set<lp::NonDiscoveryField>(lp::EmptyValue{}); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 1); |
| BOOST_CHECK(receivedData.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceiveNonDiscoveryDropNack) |
| { |
| GenericLinkService::Options options; |
| options.allowSelfLearning = true; |
| initialize(options); |
| |
| lp::Nack nack = makeNack(*makeInterest("/localhost/test", false, nullopt, 123), |
| lp::NackReason::NO_ROUTE); |
| lp::Packet packet; |
| packet.set<lp::FragmentField>(std::make_pair( |
| nack.getInterest().wireEncode().begin(), nack.getInterest().wireEncode().end())); |
| packet.set<lp::NackField>(nack.getHeader()); |
| packet.set<lp::NonDiscoveryField>(lp::EmptyValue{}); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 1); |
| BOOST_CHECK(receivedNacks.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendPrefixAnnouncement) |
| { |
| GenericLinkService::Options options; |
| options.allowSelfLearning = true; |
| initialize(options); |
| |
| auto data = makeData("/12345678"); |
| auto pah = makePrefixAnnHeader("/local/ndn/prefix"); |
| data->setTag(make_shared<lp::PrefixAnnouncementTag>(pah)); |
| |
| face->sendData(*data); |
| |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet sent(transport->sentPackets.back()); |
| BOOST_CHECK(sent.has<lp::PrefixAnnouncementField>()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendPrefixAnnouncementDisabled) |
| { |
| GenericLinkService::Options options; |
| options.allowSelfLearning = false; |
| initialize(options); |
| |
| auto data = makeData("/12345678"); |
| auto pah = makePrefixAnnHeader("/local/ndn/prefix"); |
| data->setTag(make_shared<lp::PrefixAnnouncementTag>(pah)); |
| |
| face->sendData(*data); |
| |
| BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1); |
| lp::Packet sent(transport->sentPackets.back()); |
| BOOST_CHECK(!sent.has<lp::PrefixAnnouncementField>()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceivePrefixAnnouncement) |
| { |
| GenericLinkService::Options options; |
| options.allowSelfLearning = true; |
| initialize(options); |
| |
| auto data = makeData("/12345678"); |
| lp::Packet packet(data->wireEncode()); |
| auto pah = makePrefixAnnHeader("/local/ndn/prefix"); |
| packet.set<lp::PrefixAnnouncementField>(pah); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_REQUIRE_EQUAL(receivedData.size(), 1); |
| auto tag = receivedData.back().getTag<lp::PrefixAnnouncementTag>(); |
| BOOST_CHECK_EQUAL(tag->get().getPrefixAnn()->getAnnouncedName(), "/local/ndn/prefix"); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceivePrefixAnnouncementDisabled) |
| { |
| GenericLinkService::Options options; |
| options.allowSelfLearning = false; |
| initialize(options); |
| |
| auto data = makeData("/12345678"); |
| lp::Packet packet(data->wireEncode()); |
| auto pah = makePrefixAnnHeader("/local/ndn/prefix"); |
| packet.set<lp::PrefixAnnouncementField>(pah); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 0); // not an error |
| BOOST_CHECK_EQUAL(receivedData.size(), 1); |
| auto tag = receivedData.back().getTag<lp::PrefixAnnouncementTag>(); |
| BOOST_CHECK(tag == nullptr); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceivePrefixAnnouncementDropInterest) |
| { |
| GenericLinkService::Options options; |
| options.allowSelfLearning = true; |
| initialize(options); |
| |
| auto interest = makeInterest("/12345678"); |
| lp::Packet packet(interest->wireEncode()); |
| auto pah = makePrefixAnnHeader("/local/ndn/prefix"); |
| packet.set<lp::PrefixAnnouncementField>(pah); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 1); |
| BOOST_CHECK(receivedInterests.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ReceivePrefixAnnouncementDropNack) |
| { |
| GenericLinkService::Options options; |
| options.allowSelfLearning = true; |
| initialize(options); |
| |
| lp::Nack nack = makeNack(*makeInterest("/localhost/test", false, nullopt, 123), |
| lp::NackReason::NO_ROUTE); |
| lp::Packet packet; |
| packet.set<lp::FragmentField>(std::make_pair( |
| nack.getInterest().wireEncode().begin(), nack.getInterest().wireEncode().end())); |
| packet.set<lp::NackField>(nack.getHeader()); |
| auto pah = makePrefixAnnHeader("/local/ndn/prefix"); |
| packet.set<lp::PrefixAnnouncementField>(pah); |
| |
| transport->receivePacket(packet.wireEncode()); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 1); |
| BOOST_CHECK(receivedNacks.empty()); |
| } |
| |
| BOOST_AUTO_TEST_SUITE_END() // LpFields |
| |
| BOOST_AUTO_TEST_SUITE(Malformed) // receive malformed packets |
| |
| BOOST_AUTO_TEST_CASE(WrongTlvType) |
| { |
| // Initialize with Options that disables all services |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| |
| auto packet = ndn::encoding::makeEmptyBlock(tlv::Name); |
| transport->receivePacket(packet); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInLpInvalid, 1); |
| BOOST_CHECK_EQUAL(receivedInterests.size(), 0); |
| BOOST_CHECK_EQUAL(receivedData.size(), 0); |
| BOOST_CHECK_EQUAL(receivedNacks.size(), 0); |
| } |
| |
| BOOST_AUTO_TEST_CASE(Unparsable) |
| { |
| // Initialize with Options that disables all services |
| GenericLinkService::Options options; |
| options.allowLocalFields = false; |
| initialize(options); |
| |
| auto packet = ndn::encoding::makeStringBlock(lp::tlv::LpPacket, "x"); |
| BOOST_CHECK_THROW(packet.parse(), tlv::Error); |
| transport->receivePacket(packet); |
| |
| BOOST_CHECK_EQUAL(service->getCounters().nInLpInvalid, 1); |
| BOOST_CHECK_EQUAL(receivedInterests.size(), 0); |
| BOOST_CHECK_EQUAL(receivedData.size(), 0); |
| BOOST_CHECK_EQUAL(receivedNacks.size(), 0); |
| } |
| |
| BOOST_AUTO_TEST_SUITE_END() // Malformed |
| |
| BOOST_AUTO_TEST_SUITE_END() // TestGenericLinkService |
| BOOST_AUTO_TEST_SUITE_END() // Face |
| |
| } // namespace tests |
| } // namespace face |
| } // namespace nfd |