diff --git a/sim/Dockerfile b/sim/Dockerfile index 91a7e5e..5b7ddc1 100644 --- a/sim/Dockerfile +++ b/sim/Dockerfile @@ -1,58 +1,92 @@ -FROM ubuntu:20.04 AS builder +FROM ubuntu:20.04 AS qns-builder -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y python3 build-essential cmake wget +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + ca-certificates \ + python3 \ + build-essential \ + cmake \ + wget \ + && apt-get clean ENV VERS 3.32 -RUN wget https://www.nsnam.org/release/ns-allinone-$VERS.tar.bz2 -RUN tar xjf ns-allinone-$VERS.tar.bz2 && rm ns-allinone-$VERS.tar.bz2 -RUN mv /ns-allinone-$VERS/ns-$VERS /ns3 +RUN wget --progress=dot:giga https://www.nsnam.org/release/ns-allinone-$VERS.tar.bz2 \ + && tar xjf ns-allinone-$VERS.tar.bz2 && rm ns-allinone-$VERS.tar.bz2 \ + && mv /ns-allinone-$VERS/ns-$VERS /ns3 WORKDIR /ns3 -RUN mkdir out/ -RUN ./waf configure --build-profile=release --out=out/ -RUN ./waf build - -RUN cd / && \ - wget https://dl.google.com/go/go1.15.linux-amd64.tar.gz && \ - tar xfz go1.15.linux-amd64.tar.gz && \ - rm go1.15.linux-amd64.tar.gz +RUN mkdir out/ \ + && ./waf configure \ + --build-profile=release \ + --out=out/ \ + && ./waf build # make including of the QuicNetworkSimulatorHelper class possible COPY wscript.patch . -RUN patch < wscript.patch +RUN patch < wscript.patch \ + && rm -r \ + scratch/subdir \ + scratch/scratch-simulator.cc -RUN rm -r scratch/subdir scratch/scratch-simulator.cc COPY scenarios scratch/ # compile all the scenarios -RUN ./waf build && \ - cd out/lib && du -sh . && strip -v * && du -sh . && cd ../.. && \ - cd out/scratch && rm -r subdir helper scratch-simulator* +RUN ./waf build \ + && cd out/lib \ + && du -sh . \ + && strip -v ./* \ + && du -sh . \ + && cd ../.. \ + && cd out/scratch \ + && rm -r \ + subdir \ + helper \ + scratch-simulator* + +# --- + +FROM ubuntu:20.04 AS wait-for-it-builder + +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + wget \ + ca-certificates \ + && apt-get clean + +WORKDIR / +RUN wget --progress=dot:giga https://dl.google.com/go/go1.15.linux-amd64.tar.gz \ + && tar xfz go1.15.linux-amd64.tar.gz \ + && rm go1.15.linux-amd64.tar.gz ENV PATH="/go/bin:${PATH}" COPY wait-for-it-quic /wait-for-it-quic -RUN cd /wait-for-it-quic && go build . +WORKDIR /wait-for-it-quic +RUN go build . + +# --- FROM ubuntu:20.04 -RUN apt-get update && \ - apt-get install -y net-tools iptables && \ - apt-get clean +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + net-tools \ + iptables \ + nftables \ + && apt-get clean WORKDIR /ns3 -COPY --from=builder /ns3/out/src/fd-net-device/* /ns3/src/fd-net-device/ -COPY --from=builder /ns3/out/scratch/*/* /ns3/scratch/ -COPY --from=builder /ns3/out/lib/ /ns3/lib -COPY --from=builder /wait-for-it-quic/wait-for-it-quic /usr/bin +COPY --from=qns-builder /ns3/out/src/fd-net-device/* /ns3/src/fd-net-device/ +COPY --from=qns-builder /ns3/out/scratch/*/* /ns3/scratch/ +COPY --from=qns-builder /ns3/out/lib/ /ns3/lib +COPY --from=wait-for-it-builder /wait-for-it-quic/wait-for-it-quic /usr/bin # see https://gitlab.com/nsnam/ns-3-dev/issues/97 ENV PATH="/ns3/src/fd-net-device/:${PATH}" ENV LD_LIBRARY_PATH="/ns3/lib" COPY run.sh . -RUN chmod +x run.sh -RUN mkdir /logs +RUN chmod +x run.sh \ + && mkdir /logs ENTRYPOINT [ "./run.sh" ] diff --git a/sim/run.sh b/sim/run.sh index 9be56e6..3497996 100644 --- a/sim/run.sh +++ b/sim/run.sh @@ -11,21 +11,42 @@ ifconfig eth1 promisc # and a packet arriving at eth1 destined to 10.0.0.0/16 directly to eth0. # This would allow packets to skip the ns3 simulator altogether. # Drop those to make sure they actually take the path through ns3. -iptables -A FORWARD -i eth0 -o eth1 -j DROP -iptables -A FORWARD -i eth1 -o eth0 -j DROP -ip6tables -A FORWARD -i eth0 -o eth1 -j DROP -ip6tables -A FORWARD -i eth1 -o eth0 -j DROP +FIREWALL_CONFIGURED=0 +if iptables -L 2> /dev/null | grep FORWARD > /dev/null; then + echo "Configuring iptables" + iptables -A FORWARD -i eth0 -o eth1 -j DROP + iptables -A FORWARD -i eth1 -o eth0 -j DROP + FIREWALL_CONFIGURED=1 +fi +if ip6tables -L 2> /dev/null | grep FORWARD > /dev/null; then + echo "Configuring ip6tables" + ip6tables -A FORWARD -i eth0 -o eth1 -j DROP + ip6tables -A FORWARD -i eth1 -o eth0 -j DROP + FIREWALL_CONFIGURED=1 +fi +if grep nf_tables /proc/modules > /dev/null ; then + echo "Configuring nftables" + nft add table ip filter + nft add chain ip filter FORWARD + nft add rule ip filter FORWARD iifname "eth0" oifname "eth1" counter drop + nft add rule ip filter FORWARD iifname "eth1" oifname "eth0" counter drop + FIREWALL_CONFIGURED=1 +fi +if [[ $FIREWALL_CONFIGURED != 1 ]]; then + echo "Could not configure firewall!" + exit 1 +fi if [[ -n "$WAITFORSERVER" ]]; then - wait-for-it-quic -t 10s $WAITFORSERVER + wait-for-it-quic -t 10s "${WAITFORSERVER}" fi -echo "Using scenario:" $SCENARIO +echo "Using scenario: ${SCENARIO}" eval ./scratch/"$SCENARIO &" -PID=`jobs -p` -trap "kill -SIGINT $PID" INT -trap "kill -SIGTERM $PID" TERM -trap "kill -SIGKILL $PID" KILL +PID=$(jobs -p) +trap "kill -SIGINT ${PID}" INT +trap "kill -SIGTERM ${PID}" TERM +trap "kill -SIGKILL ${PID}" KILL wait diff --git a/sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc b/sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc new file mode 100644 index 0000000..6ce1a61 --- /dev/null +++ b/sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc @@ -0,0 +1,192 @@ +#include "ns3/core-module.h" +#include "ns3/error-model.h" +#include "ns3/internet-module.h" +#include "ns3/point-to-point-module.h" +#include "ns3/queue.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/queue-size.h" +#include "../helper/quic-network-simulator-helper.h" +#include "../helper/quic-point-to-point-helper.h" +#include "drop-rate-error-model.h" +#include "gilbert-elliott-drop-model.h" +#include +#include +#include +#include + + +using namespace ns3; +using namespace std; + +NS_LOG_COMPONENT_DEFINE("ns3 simulator"); + +static Ptr> returnQueue; +static Ptr> forwardQueue; +static constexpr unsigned int QUEUE_LOG_INTERVAL_USEC = 200000; + +void timer_handler(int signum){ + cout << + "# return\t" << + returnQueue->GetNPackets() << "pkgs \t" << + returnQueue->GetNBytes() << "bytes \t" << + returnQueue->GetTotalReceivedPackets() << " pkgs\t" << + returnQueue->GetTotalReceivedBytes() << " bytes\t" << + returnQueue->GetTotalDroppedPackets() << " pkgs\t" << + returnQueue->GetTotalDroppedBytes() << " bytes\t" << + returnQueue->GetTotalDroppedPacketsBeforeEnqueue() << " pkgs\t" << + returnQueue->GetTotalDroppedBytesBeforeEnqueue() << " bytes\t" << + returnQueue->GetTotalDroppedPacketsAfterDequeue() << " pkgs\t" << + returnQueue->GetTotalDroppedBytesAfterDequeue() << " bytes" << + endl; + cout << + "# forward\t" << + forwardQueue->GetNPackets() << "pkgs \t" << + forwardQueue->GetNBytes() << "bytes \t" << + forwardQueue->GetTotalReceivedPackets() << " pkgs\t" << + forwardQueue->GetTotalReceivedBytes() << " bytes\t" << + forwardQueue->GetTotalDroppedPackets() << " pkgs\t" << + forwardQueue->GetTotalDroppedBytes() << " bytes\t" << + forwardQueue->GetTotalDroppedPacketsBeforeEnqueue() << " pkgs\t" << + forwardQueue->GetTotalDroppedBytesBeforeEnqueue() << " bytes\t" << + forwardQueue->GetTotalDroppedPacketsAfterDequeue() << " pkgs\t" << + forwardQueue->GetTotalDroppedBytesAfterDequeue() << " bytes" << + endl; +} + +int main(int argc, char *argv[]) { + + string channelDelay; + string forwardDataRate; + string forwardQueueSize; + string returnDataRate; + string returnQueueSize; + string goodBadProbToClient; + string badGoodProbToClient; + string goodBadProbToServer; + string badGoodProbToServer; + string dropRateToClient; + string dropRateToServer; + bool linkErrorModels = false; + + // for dropping packets: + random_device rand_dev; + mt19937 generator(rand_dev()); // Seed random number generator first + + CommandLine cmd; + cmd.AddValue("delay", "delay of the channel in both directions (RTT = 2 * delay)", channelDelay); + cmd.AddValue("forward-data-rate", "data rate of the forward link (right -> left)", forwardDataRate); + cmd.AddValue("forward-queue", "queue size of the forward link (right -> left) (in packets)", forwardQueueSize); + cmd.AddValue("return-data-rate", "data rate of the return link (left -> right)", returnDataRate); + cmd.AddValue("return-queue", "queue size of the return link (left -> right) (in packets)", returnQueueSize); + cmd.AddValue("good-bad-prob-to-client", "Gilber-Elliott Probability for Transition from Good to Bad (towards client)", goodBadProbToClient); + cmd.AddValue("bad-good-prob-to-client", "Gilber-Elliott Probability for Transition from Bad to Good (towards client)", badGoodProbToClient); + cmd.AddValue("good-bad-prob-to-server", "Gilber-Elliott Probability for Transition from Good to Bad (towards server)", goodBadProbToServer); + cmd.AddValue("bad-good-prob-to-server", "Gilber-Elliott Probability for Transition from Bad to Good (towards server)", badGoodProbToServer); + cmd.AddValue("link-error-models", "Use the same error model instance in both directions (-> produce errors during the same time)", linkErrorModels); + cmd.AddValue("drop-rate-to-client", "random packet drop rate (towards client)", dropRateToClient); + cmd.AddValue("drop-rate-to-server", "random packet drop rate (towards server)", dropRateToServer); + cmd.Parse(argc, argv); + + NS_ABORT_MSG_IF(channelDelay.length() == 0, "Missing parameter: delay"); + NS_ABORT_MSG_IF(forwardDataRate.length() == 0, "Missing parameter: forward-data-rate"); + NS_ABORT_MSG_IF(forwardQueueSize.length() == 0, "Missing parameter: forward-queue"); + NS_ABORT_MSG_IF(returnDataRate.length() == 0, "Missing parameter: return-data-rate"); + NS_ABORT_MSG_IF(returnQueueSize.length() == 0, "Missing parameter: return-queue"); + + QuicNetworkSimulatorHelper sim; + + QuicPointToPointHelper p2p; + p2p.SetChannelAttribute("Delay", StringValue(channelDelay)); + + NetDeviceContainer devices = p2p.Install(sim.GetLeftNode(), sim.GetRightNode()); + + auto leftP2PNetDev = devices.Get(0)->GetObject(); + auto rightP2PNetDev = devices.Get(1)->GetObject(); + + leftP2PNetDev->SetDataRate(DataRate(returnDataRate)); + rightP2PNetDev->SetDataRate(DataRate(forwardDataRate)); + + returnQueue = leftP2PNetDev->GetQueue(); + forwardQueue = rightP2PNetDev->GetQueue(); + returnQueue->SetMaxSize(QueueSize(returnQueueSize + "p")); + forwardQueue->SetMaxSize(QueueSize(forwardQueueSize + "p")); + + struct sigaction sa; + struct itimerval timer; + + /* Install timer_handler as the signal handler for SIGVTALRM. */ + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &timer_handler; + sigaction(SIGVTALRM, &sa, NULL); + cout << "# queue\t" << + "size pkgs\tsize bytes\t" << + "rx pkgs\trx bytes\t" << + "dropped pkgs\tdropped bytes\t" << + "dr b enq pkgs\tdr b enq bytes\t" << + "dr a deq pkgs\tdr a deq pkgs bytes" << + endl; + + /* Configure the timer to expire after x usec... */ + timer.it_value.tv_sec = 0; + timer.it_value.tv_usec = QUEUE_LOG_INTERVAL_USEC; + /* ... and every x usec after that. */ + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = QUEUE_LOG_INTERVAL_USEC; + /* Start a virtual timer. It counts down whenever this process is executing. */ + setitimer(ITIMER_VIRTUAL, &timer, NULL); + + // Set client and server drop rates. + if (linkErrorModels && (goodBadProbToClient.length() == 0 || badGoodProbToClient.length() == 0 || dropRateToClient.length() != 0 || goodBadProbToServer.length() != 0 || badGoodProbToServer.length() != 0 || dropRateToServer.length() != 0)) { + NS_ABORT_MSG_IF(true, "--link-error-models must be used with --good-bad-prob-to-client and --bad-good-prob-to-client only."); + } else if (linkErrorModels && goodBadProbToClient.length() != 0 && badGoodProbToClient.length() != 0) { + // link error models + auto probGB = stof(goodBadProbToClient); + auto probBG = stof(badGoodProbToClient); + cout << "Using Gilbert-Elliot-Loss-Model for both directions with P(b|g) = " << probGB << " \% and P(g|b) = " << probBG << " \%" << endl; + Ptr drops = CreateObject(); + drops->SetProbabilities(probGB, probBG); + devices.Get(0)->SetAttribute("ReceiveErrorModel", PointerValue(drops)); + devices.Get(1)->SetAttribute("ReceiveErrorModel", PointerValue(drops)); + } else { + + if (goodBadProbToClient.length() > 0 && badGoodProbToClient.length() > 0 && dropRateToClient.length() == 0) { + auto probGB = stof(goodBadProbToClient); + auto probBG = stof(badGoodProbToClient); + cout << "Using Gilbert-Elliot-Loss-Model for forward path with P(b|g) = " << probGB << " \% and P(g|b) = " << probBG << " \%" << endl; + Ptr dropsToClient = CreateObject(); + dropsToClient->SetProbabilities(probGB, probBG); + devices.Get(0)->SetAttribute("ReceiveErrorModel", PointerValue(dropsToClient)); + } else if (goodBadProbToClient.length() == 0 && badGoodProbToClient.length() == 0 && dropRateToClient.length() > 0) { + cout << "Using uniform random loss model in forward path with P('err') = " << dropRateToClient << " \%" << endl; + Ptr dropsToClient = CreateObject(); + dropsToClient->SetDropRate(stoi(dropRateToClient)); + devices.Get(0)->SetAttribute("ReceiveErrorModel", PointerValue(dropsToClient)); + } else if (goodBadProbToClient.length() == 0 && badGoodProbToClient.length() == 0 && dropRateToClient.length() == 0) { + cout << "Using drop rate to client: 0 %. (Use --drop-rate-to-client or --good-bad-prob-to-client and --bad-good-prob-to-client to change)" << endl; + } else { + cerr << "Cannot mix random loss model (--drop-rate-to-client) and Gilbert-Elliott-Loss-Model (--good-bad-prob-to-client and --bad-good-prob-to-client)" << endl; + NS_ABORT_MSG_IF(true, "Fix arguments!"); + } + + if (goodBadProbToServer.length() > 0 && badGoodProbToServer.length() > 0 && dropRateToServer.length() == 0) { + auto probGB = stof(goodBadProbToServer); + auto probBG = stof(badGoodProbToServer); + cout << "Using Gilbert-Elliot-Loss-Model for return path with P(b|g) = " << probGB << " \% and P(g|b) = " << probBG << " \%" << endl; + Ptr dropsToServer = CreateObject(); + dropsToServer->SetProbabilities(probGB, probBG); + devices.Get(1)->SetAttribute("ReceiveErrorModel", PointerValue(dropsToServer)); + } else if (goodBadProbToServer.length() == 0 && badGoodProbToServer.length() == 0 && dropRateToServer.length() > 0) { + cout << "Using uniform random loss model in return path with P('err') = " << dropRateToServer << " \%" << endl; + Ptr dropsToServer = CreateObject(); + dropsToServer->SetDropRate(stoi(dropRateToServer)); + devices.Get(1)->SetAttribute("ReceiveErrorModel", PointerValue(dropsToServer)); + } else if (goodBadProbToServer.length() == 0 && badGoodProbToServer.length() == 0 && dropRateToServer.length() == 0) { + cout << "Using drop rate to server: 0 %. (Use --drop-rate-to-server or --good-bad-prob-to-server and --bad-good-prob-to-server to change)" << endl; + } else { + cerr << "Cannot mix random loss model (--drop-rate-to-server) and Gilbert-Elliott-Loss-Model (--good-bad-prob-to-server and --bad-good-prob-to-server)" << endl; + NS_ABORT_MSG_IF(true, "Fix arguments!"); + } + } + + sim.Run(Seconds(36000)); +} diff --git a/sim/scenarios/asymmetric-p2p/drop-rate-error-model.cc b/sim/scenarios/asymmetric-p2p/drop-rate-error-model.cc new file mode 120000 index 0000000..3d8eef7 --- /dev/null +++ b/sim/scenarios/asymmetric-p2p/drop-rate-error-model.cc @@ -0,0 +1 @@ +../drop-rate/drop-rate-error-model.cc \ No newline at end of file diff --git a/sim/scenarios/asymmetric-p2p/drop-rate-error-model.h b/sim/scenarios/asymmetric-p2p/drop-rate-error-model.h new file mode 120000 index 0000000..ab14de7 --- /dev/null +++ b/sim/scenarios/asymmetric-p2p/drop-rate-error-model.h @@ -0,0 +1 @@ +../drop-rate/drop-rate-error-model.h \ No newline at end of file diff --git a/sim/scenarios/asymmetric-p2p/gilbert-elliott-drop-model.cc b/sim/scenarios/asymmetric-p2p/gilbert-elliott-drop-model.cc new file mode 100644 index 0000000..23e2fe9 --- /dev/null +++ b/sim/scenarios/asymmetric-p2p/gilbert-elliott-drop-model.cc @@ -0,0 +1,86 @@ +#include "../helper/quic-packet.h" +#include "gilbert-elliott-drop-model.h" + +using namespace std; + +NS_OBJECT_ENSURE_REGISTERED(GilbertElliottDropModel); + +TypeId GilbertElliottDropModel::GetTypeId(void) { + static TypeId tid = TypeId("GilbertElliottDropModel") + .SetParent() + .AddConstructor() + ; + return tid; +} + +GilbertElliottDropModel::GilbertElliottDropModel() + : + goodBadPerc(0), + badGoodPerc(0), + state(GilbertElliottState::GOOD), + distr(0.0, 1.0), + drop_counter(0), + pass_counter(0), + first_packet_logged(false) +{ + std::random_device rd; + rng = new std::mt19937(rd()); +} + +void GilbertElliottDropModel::DoReset(void) { } + +void GilbertElliottDropModel::log(void) { + if (!first_packet_logged) { + if (pass_counter > 0) { + cout << "First packet forwarded." << endl; + } else if (drop_counter > 0) { + cout << "First packet dropped." << endl; + } else { + cout << "WTF!" << endl; + } + first_packet_logged = true; + cout << "Will log stats after every " << LOG_AFTER_PACKETS << "th packet." << endl; + } else if (drop_counter + pass_counter >= LOG_AFTER_PACKETS) { + cout << "Among the last " << + LOG_AFTER_PACKETS << " packets, " << + drop_counter << " packets were dropped and " << + pass_counter << " were forwarded -> p_err = " << + drop_counter * 100.0 / LOG_AFTER_PACKETS << " %" << + endl; + drop_counter = 0; + pass_counter = 0; + } +} + +bool GilbertElliottDropModel::DoCorrupt(Ptr p) { + if (!IsUDPPacket(p)) { + return false; + } + + QuicPacket qp = QuicPacket(p); + + // check if we switch the state: + float rnd = distr(*rng); + if (this->state == GilbertElliottState::GOOD && rnd < this->goodBadPerc) { + state = GilbertElliottState::BAD; + } else if (this->state == GilbertElliottState::BAD && rnd < this->badGoodPerc) { + state = GilbertElliottState::GOOD; + } + + if (this->state == GilbertElliottState::GOOD) { + pass_counter += 1; + log(); + qp.ReassemblePacket(); + return false; + } else { + drop_counter += 1; + log(); + return true; + } + +} + +void GilbertElliottDropModel::SetProbabilities(float goodBadPerc, float badGoodPerc) { + this->goodBadPerc = goodBadPerc; + this->badGoodPerc = badGoodPerc; +} diff --git a/sim/scenarios/asymmetric-p2p/gilbert-elliott-drop-model.h b/sim/scenarios/asymmetric-p2p/gilbert-elliott-drop-model.h new file mode 100644 index 0000000..b991d14 --- /dev/null +++ b/sim/scenarios/asymmetric-p2p/gilbert-elliott-drop-model.h @@ -0,0 +1,42 @@ +#ifndef GILBERT_ELLIOTT_DROP_MODEL_H +#define GILBERT_ELLIOTT_DROP_MODEL_H + +#include +#include +#include "ns3/error-model.h" + +using namespace ns3; + +enum GilbertElliottState { + GOOD, + BAD, +}; + +// The model drops packets in the error state and passes packets in the normal state. +// The transition between both states is described by the transition probabilities. +class GilbertElliottDropModel : public ErrorModel { + public: + static TypeId GetTypeId(void); + GilbertElliottDropModel(); + void SetProbabilities(float goodBadPerc, float badGoodPerc); + + private: + float goodBadPerc; + float badGoodPerc; + GilbertElliottState state; + + std::mt19937 *rng; + std::uniform_real_distribution<> distr; + + unsigned int drop_counter; + unsigned int pass_counter; + bool first_packet_logged; + static constexpr unsigned int LOG_AFTER_PACKETS = 1000; + + bool DoCorrupt(Ptr p); + void DoReset(void); + + void log(void); +}; + +#endif /* GILBERT_ELLIOTT_DROP_MODEL_H */ diff --git a/sim/scenarios/drop-rate/drop-rate-error-model.cc b/sim/scenarios/drop-rate/drop-rate-error-model.cc index 62c561c..45982ef 100644 --- a/sim/scenarios/drop-rate/drop-rate-error-model.cc +++ b/sim/scenarios/drop-rate/drop-rate-error-model.cc @@ -12,27 +12,66 @@ TypeId DropRateErrorModel::GetTypeId(void) { ; return tid; } - + DropRateErrorModel::DropRateErrorModel() - : rate(0), distr(0, 99) { + : + rate(0), + distr(0, 99), + drop_counter(0), + pass_counter(0), + first_packet_logged(false) +{ std::random_device rd; rng = new std::mt19937(rd()); } void DropRateErrorModel::DoReset(void) { } - + +void DropRateErrorModel::log(void) { + if (!first_packet_logged) { + if (pass_counter > 0) { + cout << "First packet forwarded." << endl; + } else if (drop_counter > 0) { + cout << "First packet dropped." << endl; + } else { + cout << "WTF!" << endl; + } + first_packet_logged = true; + cout << "Will log stats after every " << LOG_AFTER_PACKETS << "th packet." << endl; + } else if (drop_counter + pass_counter >= LOG_AFTER_PACKETS) { + cout << "Among the last " << + LOG_AFTER_PACKETS << " packets, " << + drop_counter << " packets were dropped and " << + pass_counter << " were forwarded -> p_err = " << + drop_counter * 100.0 / LOG_AFTER_PACKETS << " %" << + endl; + drop_counter = 0; + pass_counter = 0; + } +} + bool DropRateErrorModel::DoCorrupt(Ptr p) { - if(!IsUDPPacket(p)) return false; + 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; + // cout << "Forwarding packet (" << qp.GetUdpPayload().size() << " bytes) from " << qp.GetIpv4Header().GetSource() << endl; + // if (rate > 0) { + pass_counter += 1; + log(); + // } qp.ReassemblePacket(); return false; } - cout << "Dropping packet (" << qp.GetUdpPayload().size() << " bytes) from " << qp.GetIpv4Header().GetSource() << endl; + // cout << "Dropping packet (" << qp.GetUdpPayload().size() << " bytes) from " << qp.GetIpv4Header().GetSource() << endl; + // if (rate > 0) { + drop_counter += 1; + log(); + // } return true; } diff --git a/sim/scenarios/drop-rate/drop-rate-error-model.h b/sim/scenarios/drop-rate/drop-rate-error-model.h index 91c2313..0720824 100644 --- a/sim/scenarios/drop-rate/drop-rate-error-model.h +++ b/sim/scenarios/drop-rate/drop-rate-error-model.h @@ -13,14 +13,21 @@ class DropRateErrorModel : public ErrorModel { static TypeId GetTypeId(void); DropRateErrorModel(); void SetDropRate(int perc); - + private: int rate; std::mt19937 *rng; std::uniform_int_distribution<> distr; - bool DoCorrupt (Ptr p); + unsigned int drop_counter; + unsigned int pass_counter; + bool first_packet_logged; + static constexpr unsigned int LOG_AFTER_PACKETS = 1000; + + bool DoCorrupt(Ptr p); void DoReset(void); + + void log(void); }; #endif /* DROPRATE_ERROR_MODEL_H */ diff --git a/sim/scenarios/helper/quic-network-simulator-helper.cc b/sim/scenarios/helper/quic-network-simulator-helper.cc index 81a09cd..e74ce8d 100644 --- a/sim/scenarios/helper/quic-network-simulator-helper.cc +++ b/sim/scenarios/helper/quic-network-simulator-helper.cc @@ -20,8 +20,11 @@ using namespace ns3; void onSignal(int signum) { std::cout << "Received signal: " << signum << std::endl; // see https://gitlab.com/nsnam/ns-3-dev/issues/102 - Simulator::Stop(); - NS_FATAL_ERROR(signum); + // schedule stop task in 60s. We will exit later, when no packets arrive until then. + Simulator::Stop(Time("60s")); + // Simulator::Stop(Time("1s")); + // Simulator::Stop(); + // NS_FATAL_ERROR(signum); } void installNetDevice(Ptr node, std::string deviceName, Mac48AddressValue macAddress, Ipv4InterfaceAddress ipv4Address, Ipv6InterfaceAddress ipv6Address) {