diff --git a/sim/scenarios/corrupt-rate/README.md b/sim/scenarios/corrupt-rate/README.md index 352cee3..cb3289e 100644 --- a/sim/scenarios/corrupt-rate/README.md +++ b/sim/scenarios/corrupt-rate/README.md @@ -3,7 +3,8 @@ This scenario uses a bottleneck link similar to the [simple-p2p](../simple-p2p) scenario and optionally allows configuring the link to corrupt packets in either direction. Packets to be corrupted are chosen randomly in both directions, based -on rates specified by the user. +on rates specified by the user, but no more than a given number of packets are +corrupted in a row. This scenario has the following configurable properties: @@ -21,9 +22,15 @@ This scenario has the following configurable properties: rate (in percentage) in the server to client direction. This is a required parameter. For example, `--rate_to_client=10`. +* `--burst_to_client`: The maximum number of packets that will be corrupted in a + row in the server to client direction. This is an optional parameter. For + example, `--burst_to_client=3`. + * `--rate_to_server`: Same as `rate_to_client` but in the other direction. +* `--burst_to_server`: Same as `burst_to_client` but in the other direction. + For example, ```bash -./run.sh "corrupt-rate --delay=15ms --bandwidth=10Mbps --queue=25 --rate_to_client=10 --rate_to_server=20" +./run.sh "corrupt-rate --delay=15ms --bandwidth=10Mbps --queue=25 --rate_to_client=10 --rate_to_server=20 --burst_to_client=3 --burst_to_server=3" ``` diff --git a/sim/scenarios/corrupt-rate/corrupt-rate-error-model.cc b/sim/scenarios/corrupt-rate/corrupt-rate-error-model.cc index e269f55..bd963e4 100644 --- a/sim/scenarios/corrupt-rate/corrupt-rate-error-model.cc +++ b/sim/scenarios/corrupt-rate/corrupt-rate-error-model.cc @@ -1,13 +1,10 @@ +#include + #include #include #include "corrupt-rate-error-model.h" #include "../helper/quic-packet.h" -#include "ns3/header.h" -#include "ns3/packet.h" -#include "ns3/ppp-header.h" -#include "ns3/ipv4-header.h" -#include "ns3/udp-header.h" using namespace std; @@ -20,48 +17,87 @@ TypeId CorruptRateErrorModel::GetTypeId(void) { ; return tid; } - + CorruptRateErrorModel::CorruptRateErrorModel() - : rate(0), distr(0, 99) { + : rate(0), distr(0, 99), burst(INT_MAX), corrupted_in_a_row(0), corrupted(0), forwarded(0) { std::random_device rd; rng = new std::mt19937(rd()); } -void CorruptRateErrorModel::DoReset(void) { } +void CorruptRateErrorModel::DoReset(void) { + corrupted_in_a_row = 0; + corrupted = 0; + forwarded = 0; +} bool CorruptRateErrorModel::DoCorrupt(Ptr p) { if(!IsUDPPacket(p)) return false; QuicPacket qp = QuicPacket(p); - if(distr(*rng) >= rate) { - cout << "Forwarding packet (" << qp.GetUdpPayload().size() << " bytes) from " << qp.GetIpv4Header().GetSource() << endl; - qp.ReassemblePacket(); - return false; + bool shouldCorrupt = false; + if (qp.IsVersionNegotiationPacket()) { + // Don't corrupt Version Negotiation packets. + // Version Negotiation packets are expected to be sent when the version + // field of the Initial was corrupted. Client are supposed to ignore + // Version Negotiation packets that contain the version that they + // offered. + corrupted_in_a_row = 0; + shouldCorrupt = false; + } else if (corrupted_in_a_row >= burst) { + corrupted_in_a_row = 0; + shouldCorrupt = false; + } else if (distr(*rng) < rate) { + corrupted_in_a_row++; + shouldCorrupt = true; + } else { + corrupted_in_a_row = 0; + shouldCorrupt = false; } - // Don't corrupt Version Negotiation packets. - // Version Negotiation packets are expected to be sent when the version field of the Initial was corrupted. - // Client are supposed to ignore Version Negotiation packets that contain the version that they offered. - if(qp.IsVersionNegotiationPacket()) { - qp.ReassemblePacket(); - return false; - } - // Corrupt a byte in the 50 bytes of the UDP payload. - // This way, we will frequenetly hit the QUIC header. - std::uniform_int_distribution<> d(0, min(uint32_t(50), p->GetSize() - 1)); - int pos = d(*rng); - vector& payload = qp.GetUdpPayload(); - // Replace the byte at position pos with a random value. - while(true) { - uint8_t n = std::uniform_int_distribution<>(0, 255)(*rng); - if(payload[pos] == n) continue; - cout << "Corrupted packet (" << qp.GetUdpPayload().size() << " bytes) from " << qp.GetIpv4Header().GetSource() << " at offset " << pos << " (0x" << std::hex << (unsigned int) payload[pos] << " -> 0x" << (unsigned int) n << ")" << std::dec << endl; - payload[pos] = n; - break; + int pos = 0; + uint8_t old_n = 0; + uint8_t new_n = 0; + if (shouldCorrupt) { + cout << "Corrupting "; + corrupted++; + + // Corrupt a byte in the 50 bytes of the UDP payload. + // This way, we will frequently hit the QUIC header. + std::uniform_int_distribution<> d(0, min(uint32_t(50), p->GetSize() - 1)); + pos = d(*rng); + vector & payload = qp.GetUdpPayload(); + // Replace the byte at position pos with a random value. + while (true) { + uint8_t n = std::uniform_int_distribution<>(0, 255)(*rng); + if (payload[pos] == n) + continue; + old_n = payload[pos]; + payload[pos] = n; + new_n = payload[pos]; + break; + } + } else { + cout << "Forwarding "; + forwarded++; } qp.ReassemblePacket(); - return false; + + cout << qp.GetUdpPayload().size() << " bytes " + << qp.GetIpv4Header().GetSource() << ":" + << qp.GetUdpHeader().GetSourcePort() << " -> " + << qp.GetIpv4Header().GetDestination() << ":" + << qp.GetUdpHeader().GetDestinationPort(); + if (pos != 0) + cout << " offset " << pos << " 0x" << std::hex + << (unsigned int)old_n << " -> 0x" << (unsigned int)new_n + << std::dec; + cout << ", corrupted " + << corrupted << "/" << corrupted + forwarded << " (" << fixed + << setprecision(1) << (double)corrupted / (corrupted + forwarded) * 100 + << "%)" << endl; + + return shouldCorrupt; } void CorruptRateErrorModel::SetCorruptRate(int rate_in) { diff --git a/sim/scenarios/corrupt-rate/corrupt-rate-error-model.h b/sim/scenarios/corrupt-rate/corrupt-rate-error-model.h index 474539b..7ee9583 100644 --- a/sim/scenarios/corrupt-rate/corrupt-rate-error-model.h +++ b/sim/scenarios/corrupt-rate/corrupt-rate-error-model.h @@ -8,16 +8,22 @@ using namespace ns3; // The CorruptRateErrorModel corrupts random packets, at a user-specified rate. +// But no more than a user-specified number of packets in a row. class CorruptRateErrorModel : public RateErrorModel { public: static TypeId GetTypeId(void); CorruptRateErrorModel(); void SetCorruptRate(int perc); + void SetMaxCorruptBurst(int burst); private: int rate; std::mt19937 *rng; std::uniform_int_distribution<> distr; + int burst; + int corrupted_in_a_row; + int corrupted; + int forwarded; bool DoCorrupt (Ptr p); void DoReset(void);