Skip to content

Commit

Permalink
sim: add burst parameter to CorruptRateErrorModel (#137)
Browse files Browse the repository at this point in the history
* WIP

* Add burst parameter to CorruptRateErrorModel

Equivalent of #134

* Fix log output

* Update sim/scenarios/corrupt-rate/README.md

Co-authored-by: Max Inden <[email protected]>

* Suggestion from @mxinden

* Fix off-by-one

* Undo. Issue was something else.

---------

Co-authored-by: Max Inden <[email protected]>
  • Loading branch information
larseggert and mxinden authored Sep 11, 2024
1 parent e5f7217 commit f36915b
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 34 deletions.
11 changes: 9 additions & 2 deletions sim/scenarios/corrupt-rate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand All @@ -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"
```
100 changes: 68 additions & 32 deletions sim/scenarios/corrupt-rate/corrupt-rate-error-model.cc
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
#include <iomanip>

#include <cstdint>
#include <vector>

#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;

Expand All @@ -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<Packet> 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<uint8_t>& 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<uint8_t> & 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) {
Expand Down
6 changes: 6 additions & 0 deletions sim/scenarios/corrupt-rate/corrupt-rate-error-model.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<Packet> p);
void DoReset(void);
Expand Down

0 comments on commit f36915b

Please sign in to comment.