face: piggyback Ack field with fixed-width encoding
refs #4403 Change-Id: I4b0123d20aea058581774d467452553724fddc61
This commit is contained in:
1 parent
e34a2825f1
commit
21e0193e5c
2 files changed
+54
-158
No files matched your search
@@ -168,11 +168,10 @@ LpReliability::piggyback(lp::Packet& pkt, ssize_t mtu)
|
||||
|
||||
while (!m_ackQueue.empty()) {
|
||||
lp::Sequence ackSeq = m_ackQueue.front();
|
||||
// Ack Size = Ack Type (3 octets) + Ack Length (1 octet) + Value (1, 2, 4, or 8 octets)
|
||||
ssize_t ackSize = tlv::sizeOfVarNumber(lp::tlv::Ack) +
|
||||
tlv::sizeOfVarNumber(
|
||||
tlv::sizeOfNonNegativeInteger(std::numeric_limits<lp::Sequence>::max())) +
|
||||
tlv::sizeOfNonNegativeInteger(ackSeq);
|
||||
// Ack size = Ack TLV-TYPE (3 octets) + TLV-LENGTH (1 octet) + uint64_t (8 octets)
|
||||
const ssize_t ackSize = tlv::sizeOfVarNumber(lp::tlv::Ack) +
|
||||
tlv::sizeOfVarNumber(sizeof(lp::Sequence)) +
|
||||
sizeof(lp::Sequence);
|
||||
|
||||
if (ackSize > remainingSpace) {
|
||||
break;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "dummy-transport.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
@@ -763,33 +764,41 @@ BOOST_AUTO_TEST_CASE(PiggybackAcks)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(PiggybackAcksMtu)
|
||||
{
|
||||
// This test case tests for piggybacking Acks when there is an MTU on the link.
|
||||
// MTU is 1500, payload has 60 octets plus 6 octets for LpPacket and Fragment TL and 10 octets for
|
||||
// TxSequence, leaving 1426 octets for piggybacking. Each Ack header is 12 octets, so each
|
||||
// LpPacket can carry 118 Acks, and it takes 9 LpPackets for 1000 Acks.
|
||||
|
||||
transport->setMtu(1500);
|
||||
|
||||
std::unordered_set<lp::Sequence> expectedAcks;
|
||||
for (lp::Sequence i = 1000; i < 2000; i++) {
|
||||
reliability->m_ackQueue.push(i);
|
||||
expectedAcks.insert(i);
|
||||
}
|
||||
|
||||
BOOST_CHECK(!reliability->m_ackQueue.empty());
|
||||
|
||||
for (uint32_t i = 0; i < 5; i++) {
|
||||
for (uint32_t i = 1; i <= 9; i++) {
|
||||
lp::Packet pkt = makeFrag(i, 60);
|
||||
linkService->sendLpPackets({pkt});
|
||||
|
||||
BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), i + 1);
|
||||
BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), i);
|
||||
lp::Packet sentPkt(transport->sentPackets.back().packet);
|
||||
BOOST_CHECK_EQUAL(getPktNo(sentPkt), i);
|
||||
BOOST_CHECK(sentPkt.has<lp::AckField>());
|
||||
|
||||
for (lp::Sequence ack : sentPkt.list<lp::AckField>()) {
|
||||
BOOST_CHECK_EQUAL(expectedAcks.erase(ack), 1);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_CHECK(reliability->m_ackQueue.empty());
|
||||
BOOST_CHECK(expectedAcks.empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(PiggybackAcksMtuNoSpace)
|
||||
{
|
||||
// This test case tests for piggybacking Acks when there is an MTU on the link, resulting in no
|
||||
// space for Acks (and negative remainingSpace in the piggyback function).
|
||||
// MTU is 250, payload has 230 octets plus 4 octets for LpPacket and Fragment TL and 10 octets for
|
||||
// TxSequence, leaving 6 octets for piggybacking. Each Ack header is 12 octets, so there's no room
|
||||
// to piggyback any Ack in LpPacket.
|
||||
|
||||
transport->setMtu(250);
|
||||
|
||||
@@ -797,17 +806,15 @@ BOOST_AUTO_TEST_CASE(PiggybackAcksMtuNoSpace)
|
||||
reliability->m_ackQueue.push(i);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 100);
|
||||
|
||||
lp::Packet pkt = makeFrag(1, 240);
|
||||
lp::Packet pkt = makeFrag(1, 230);
|
||||
linkService->sendLpPackets({pkt});
|
||||
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 100);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1);
|
||||
lp::Packet sentPkt(transport->sentPackets.back().packet);
|
||||
BOOST_CHECK_EQUAL(getPktNo(sentPkt), 1);
|
||||
BOOST_CHECK(!sentPkt.has<lp::AckField>());
|
||||
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 100);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(StartIdleAckTimer)
|
||||
@@ -848,188 +855,78 @@ BOOST_AUTO_TEST_CASE(StartIdleAckTimer)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(IdleAckTimer)
|
||||
{
|
||||
// T+1ms
|
||||
advanceClocks(time::milliseconds(1), 1);
|
||||
|
||||
for (lp::Sequence i = 1000; i < 2000; i++) {
|
||||
// T+0ms: populate ack queue and start idle ack timer
|
||||
std::unordered_set<lp::Sequence> expectedAcks;
|
||||
for (lp::Sequence i = 1000; i < 1500; i++) {
|
||||
reliability->m_ackQueue.push(i);
|
||||
expectedAcks.insert(i);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 1000);
|
||||
BOOST_CHECK(!reliability->m_isIdleAckTimerRunning);
|
||||
reliability->startIdleAckTimer();
|
||||
BOOST_CHECK(reliability->m_isIdleAckTimerRunning);
|
||||
|
||||
// T+5ms
|
||||
// T+4ms: idle ack timer has not yet expired, no IDLE packet generated
|
||||
advanceClocks(time::milliseconds(1), 4);
|
||||
BOOST_CHECK(reliability->m_isIdleAckTimerRunning);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 1000);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 500);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.front(), 1000);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.back(), 1999);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.back(), 1499);
|
||||
BOOST_CHECK_EQUAL(transport->sentPackets.size(), 0);
|
||||
|
||||
// T+6ms
|
||||
// T+5ms: idle ack timer expires, IDLE packet generated
|
||||
advanceClocks(time::milliseconds(1), 1);
|
||||
|
||||
BOOST_CHECK(!reliability->m_isIdleAckTimerRunning);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 0);
|
||||
BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1);
|
||||
lp::Packet sentPkt1(transport->sentPackets.back().packet);
|
||||
|
||||
BOOST_CHECK(!sentPkt1.has<lp::TxSequenceField>());
|
||||
BOOST_CHECK_EQUAL(sentPkt1.count<lp::AckField>(), 1000);
|
||||
|
||||
for (lp::Sequence i = 10000; i < 11000; i++) {
|
||||
reliability->m_ackQueue.push(i);
|
||||
lp::Packet sentPkt(transport->sentPackets.back().packet);
|
||||
BOOST_CHECK(!sentPkt.has<lp::TxSequenceField>());
|
||||
for (lp::Sequence ack : sentPkt.list<lp::AckField>()) {
|
||||
BOOST_CHECK_EQUAL(expectedAcks.erase(ack), 1);
|
||||
}
|
||||
|
||||
reliability->startIdleAckTimer();
|
||||
BOOST_CHECK(reliability->m_isIdleAckTimerRunning);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 1000);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.front(), 10000);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.back(), 10999);
|
||||
|
||||
// T+10ms
|
||||
advanceClocks(time::milliseconds(1), 4);
|
||||
BOOST_CHECK(reliability->m_isIdleAckTimerRunning);
|
||||
BOOST_CHECK_EQUAL(transport->sentPackets.size(), 1);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 1000);
|
||||
|
||||
// T+11ms
|
||||
advanceClocks(time::milliseconds(1), 1);
|
||||
|
||||
BOOST_CHECK(!reliability->m_isIdleAckTimerRunning);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 0);
|
||||
BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 2);
|
||||
lp::Packet sentPkt2(transport->sentPackets.back().packet);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(sentPkt2.count<lp::AckField>(), 1000);
|
||||
BOOST_CHECK(!sentPkt2.has<lp::TxSequenceField>());
|
||||
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 0);
|
||||
reliability->startIdleAckTimer();
|
||||
|
||||
// T+16ms
|
||||
advanceClocks(time::milliseconds(1), 5);
|
||||
|
||||
BOOST_CHECK(!reliability->m_isIdleAckTimerRunning);
|
||||
BOOST_CHECK_EQUAL(transport->sentPackets.size(), 2);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 0);
|
||||
BOOST_CHECK(expectedAcks.empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(IdleAckTimerMtu)
|
||||
{
|
||||
transport->setMtu(1500);
|
||||
|
||||
// T+1ms
|
||||
advanceClocks(time::milliseconds(1), 1);
|
||||
|
||||
for (lp::Sequence i = 1000; i < 2000; i++) {
|
||||
// T+0ms: populate ack queue and start idle ack timer
|
||||
std::unordered_set<lp::Sequence> expectedAcks;
|
||||
for (lp::Sequence i = 1000; i < 1500; i++) {
|
||||
reliability->m_ackQueue.push(i);
|
||||
expectedAcks.insert(i);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 1000);
|
||||
BOOST_CHECK(!reliability->m_isIdleAckTimerRunning);
|
||||
reliability->startIdleAckTimer();
|
||||
BOOST_CHECK(reliability->m_isIdleAckTimerRunning);
|
||||
|
||||
// T+5ms
|
||||
// T+4ms: idle ack timer has not yet expired, no IDLE packet generated
|
||||
advanceClocks(time::milliseconds(1), 4);
|
||||
BOOST_CHECK(reliability->m_isIdleAckTimerRunning);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 1000);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 500);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.front(), 1000);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.back(), 1499);
|
||||
BOOST_CHECK_EQUAL(transport->sentPackets.size(), 0);
|
||||
|
||||
// T+6ms
|
||||
// T+5ms: idle ack timer expires, IDLE packets generated
|
||||
advanceClocks(time::milliseconds(1), 1);
|
||||
|
||||
BOOST_CHECK(!reliability->m_isIdleAckTimerRunning);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 0);
|
||||
|
||||
for (lp::Sequence i = 5000; i < 6000; i++) {
|
||||
reliability->m_ackQueue.push(i);
|
||||
}
|
||||
|
||||
reliability->startIdleAckTimer();
|
||||
BOOST_CHECK(reliability->m_isIdleAckTimerRunning);
|
||||
|
||||
// given Ack of size 6 and MTU of 1500, 249 Acks/IDLE packet
|
||||
// MTU is 1500. LpPacket TL occupies 4 octets. Each Ack header is 12 octets. There are room for
|
||||
// 124 Acks per LpPacket, and it takes 5 LpPackets to carry 500 Acks.
|
||||
BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 5);
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
lp::Packet sentPkt(transport->sentPackets[i].packet);
|
||||
BOOST_CHECK(!sentPkt.has<lp::TxSequenceField>());
|
||||
BOOST_CHECK_EQUAL(sentPkt.count<lp::AckField>(), 249);
|
||||
}
|
||||
lp::Packet sentPkt(transport->sentPackets[4].packet);
|
||||
BOOST_CHECK(!sentPkt.has<lp::TxSequenceField>());
|
||||
BOOST_CHECK_LE(sentPkt.count<lp::AckField>(), 249);
|
||||
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 1000);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.front(), 5000);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.back(), 5999);
|
||||
|
||||
// T+10ms
|
||||
advanceClocks(time::milliseconds(1), 4);
|
||||
BOOST_CHECK(reliability->m_isIdleAckTimerRunning);
|
||||
BOOST_CHECK_EQUAL(transport->sentPackets.size(), 5);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 1000);
|
||||
|
||||
// T+11ms
|
||||
advanceClocks(time::milliseconds(1), 1);
|
||||
|
||||
BOOST_CHECK(!reliability->m_isIdleAckTimerRunning);
|
||||
|
||||
for (lp::Sequence i = 100000; i < 101000; i++) {
|
||||
reliability->m_ackQueue.push(i);
|
||||
BOOST_CHECK_EQUAL(sentPkt.count<lp::AckField>(), i == 4 ? 4 : 124);
|
||||
for (lp::Sequence ack : sentPkt.list<lp::AckField>()) {
|
||||
BOOST_CHECK_EQUAL(expectedAcks.erase(ack), 1);
|
||||
}
|
||||
}
|
||||
|
||||
reliability->startIdleAckTimer();
|
||||
BOOST_CHECK(reliability->m_isIdleAckTimerRunning);
|
||||
|
||||
// given Ack of size 6 and MTU of 1500, 249 Acks/IDLE packet
|
||||
BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 10);
|
||||
for (size_t i = 5; i < 9; i++) {
|
||||
lp::Packet sentPkt(transport->sentPackets[i].packet);
|
||||
BOOST_CHECK(!sentPkt.has<lp::TxSequenceField>());
|
||||
BOOST_CHECK_EQUAL(sentPkt.count<lp::AckField>(), 249);
|
||||
}
|
||||
sentPkt.wireDecode(transport->sentPackets[9].packet);
|
||||
BOOST_CHECK(!sentPkt.has<lp::TxSequenceField>());
|
||||
BOOST_CHECK_LE(sentPkt.count<lp::AckField>(), 249);
|
||||
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 1000);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.front(), 100000);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.back(), 100999);
|
||||
BOOST_CHECK(reliability->m_isIdleAckTimerRunning);
|
||||
|
||||
// T+15ms
|
||||
advanceClocks(time::milliseconds(1), 4);
|
||||
BOOST_CHECK(reliability->m_isIdleAckTimerRunning);
|
||||
BOOST_CHECK_EQUAL(transport->sentPackets.size(), 10);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 1000);
|
||||
|
||||
// T+16ms
|
||||
advanceClocks(time::milliseconds(1), 1);
|
||||
|
||||
// given Ack of size 8 and MTU of 1500, approx 187 Acks/IDLE packet
|
||||
BOOST_CHECK(!reliability->m_isIdleAckTimerRunning);
|
||||
BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 16);
|
||||
for (size_t i = 10; i < 15; i++) {
|
||||
lp::Packet sentPkt(transport->sentPackets[i].packet);
|
||||
BOOST_CHECK(!sentPkt.has<lp::TxSequenceField>());
|
||||
BOOST_CHECK_EQUAL(sentPkt.count<lp::AckField>(), 187);
|
||||
}
|
||||
sentPkt.wireDecode(transport->sentPackets[15].packet);
|
||||
BOOST_CHECK(!sentPkt.has<lp::TxSequenceField>());
|
||||
BOOST_CHECK_LE(sentPkt.count<lp::AckField>(), 187);
|
||||
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 0);
|
||||
reliability->startIdleAckTimer();
|
||||
|
||||
// T+21ms
|
||||
advanceClocks(time::milliseconds(1), 5);
|
||||
|
||||
BOOST_CHECK(!reliability->m_isIdleAckTimerRunning);
|
||||
BOOST_CHECK_EQUAL(transport->sentPackets.size(), 16);
|
||||
BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 0);
|
||||
BOOST_CHECK(expectedAcks.empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestLpReliability
|
||||
|
||||
Reference in new issue
Block a user