From 4612c76189c3964395ca8f62b2bfea5cd78dc641 Mon Sep 17 00:00:00 2001 From: sedrubal Date: Mon, 30 Aug 2021 10:21:21 +0200 Subject: [PATCH 1/8] Add asymmetric-p2p scenario --- .../asymmetric-p2p/asymmetric-p2p.cc | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc diff --git a/sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc b/sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc new file mode 100644 index 0000000..3c16006 --- /dev/null +++ b/sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc @@ -0,0 +1,82 @@ +#include "ns3/core-module.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" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE("ns3 simulator"); + +int main(int argc, char *argv[]) { + + std::string channelDelay; + std::string forwardDataRate; + std::string forwardQueueSize; + std::string returnDataRate; + std::string returnQueueSize; + + 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.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; + + // Stick in the point-to-point line between the sides. + // QuicPointToPointHelper p2pLeft, p2pRight; + // p2pLeft.SetDeviceAttribute("DataRate", StringValue(returnDataRate)); + // p2pLeft.SetChannelAttribute("Delay", StringValue(returnDelay)); + // p2pLeft.SetQueueSize(StringValue(returnQueue + "p")); + // p2pRight.SetDeviceAttribute("DataRate", StringValue(forwardDataRate)); + // p2pRight.SetChannelAttribute("Delay", StringValue(forwardDelay)); + // p2pRight.SetQueueSize(StringValue(forwardQueue + "p")); + // + // NetDeviceContainer devices; + // devices.Add(p2pLeft.Install(sim.GetLeftNode(), p2pRight)); + // devices.Add(p2pRight.Install(p2pLeft, sim.GetRightNode())); + + QuicPointToPointHelper p2p; + p2p.SetChannelAttribute("Delay", StringValue(channelDelay)); + // p2p.SetDeviceAttribute("DataRate", StringValue(forwardDataRate)); + // p2p.SetQueueSize(StringValue(forwardQueue + "p")); + + 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)); + + auto returnQueue = leftP2PNetDev->GetQueue(); + auto forwardQueue = rightP2PNetDev->GetQueue(); + returnQueue->SetMaxSize(QueueSize(returnQueueSize + "p")); + forwardQueue->SetMaxSize(QueueSize(forwardQueueSize + "p")); + + // auto leftNode = sim.GetLeftNode(); + // auto leftDevice = leftNode->GetDevice(0); + // leftDevice->SetDataRate(StringValue(returnDataRate)) + // leftDevice->SetQueue(StringValue(returnQueue)) + // auto leftPtr = devices.Get(0); + // leftPtr->SetDataRate(StringValue(returnDataRate)) + // leftPtr->SetQueue(StringValue(returnQueue)) + // + // auto rightPtr = devices.Get(1); + // rightPtr->SetDataRate(StringValue(forwardDataRate)) + // rightPtr->SetQueue(StringValue(forwardQueue)) + + sim.Run(Seconds(36000)); +} From ee068594ca059babd83501b9720819a52f821cfc Mon Sep 17 00:00:00 2001 From: sedrubal Date: Fri, 10 Sep 2021 09:24:29 +0200 Subject: [PATCH 2/8] Add loss features to asymmetric scenario --- .../asymmetric-p2p/asymmetric-p2p.cc | 65 ++++++++++--------- .../asymmetric-p2p/drop-rate-error-model.cc | 1 + .../asymmetric-p2p/drop-rate-error-model.h | 1 + 3 files changed, 36 insertions(+), 31 deletions(-) create mode 120000 sim/scenarios/asymmetric-p2p/drop-rate-error-model.cc create mode 120000 sim/scenarios/asymmetric-p2p/drop-rate-error-model.h diff --git a/sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc b/sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc index 3c16006..19e9cd6 100644 --- a/sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc +++ b/sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc @@ -1,4 +1,5 @@ #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" @@ -6,18 +7,28 @@ #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" using namespace ns3; +using namespace std; NS_LOG_COMPONENT_DEFINE("ns3 simulator"); int main(int argc, char *argv[]) { - std::string channelDelay; - std::string forwardDataRate; - std::string forwardQueueSize; - std::string returnDataRate; - std::string returnQueueSize; + string channelDelay; + string forwardDataRate; + string forwardQueueSize; + string returnDataRate; + string returnQueueSize; + string drop_rate_to_client; + string drop_rate_to_server; + + // for dropping packets: + random_device rand_dev; + mt19937 generator(rand_dev()); // Seed random number generator first + Ptr drops_to_client = CreateObject(); + Ptr drops_to_server = CreateObject(); CommandLine cmd; cmd.AddValue("delay", "delay of the channel in both directions (RTT = 2 * delay)", channelDelay); @@ -25,6 +36,8 @@ int main(int argc, char *argv[]) { 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("drop-rate-to-client", "packet drop rate (towards client)", drop_rate_to_client); + cmd.AddValue("drop-rate-to-server", "packet drop rate (towards server)", drop_rate_to_server); cmd.Parse(argc, argv); NS_ABORT_MSG_IF(channelDelay.length() == 0, "Missing parameter: delay"); @@ -35,23 +48,8 @@ int main(int argc, char *argv[]) { QuicNetworkSimulatorHelper sim; - // Stick in the point-to-point line between the sides. - // QuicPointToPointHelper p2pLeft, p2pRight; - // p2pLeft.SetDeviceAttribute("DataRate", StringValue(returnDataRate)); - // p2pLeft.SetChannelAttribute("Delay", StringValue(returnDelay)); - // p2pLeft.SetQueueSize(StringValue(returnQueue + "p")); - // p2pRight.SetDeviceAttribute("DataRate", StringValue(forwardDataRate)); - // p2pRight.SetChannelAttribute("Delay", StringValue(forwardDelay)); - // p2pRight.SetQueueSize(StringValue(forwardQueue + "p")); - // - // NetDeviceContainer devices; - // devices.Add(p2pLeft.Install(sim.GetLeftNode(), p2pRight)); - // devices.Add(p2pRight.Install(p2pLeft, sim.GetRightNode())); - QuicPointToPointHelper p2p; p2p.SetChannelAttribute("Delay", StringValue(channelDelay)); - // p2p.SetDeviceAttribute("DataRate", StringValue(forwardDataRate)); - // p2p.SetQueueSize(StringValue(forwardQueue + "p")); NetDeviceContainer devices = p2p.Install(sim.GetLeftNode(), sim.GetRightNode()); @@ -66,17 +64,22 @@ int main(int argc, char *argv[]) { returnQueue->SetMaxSize(QueueSize(returnQueueSize + "p")); forwardQueue->SetMaxSize(QueueSize(forwardQueueSize + "p")); - // auto leftNode = sim.GetLeftNode(); - // auto leftDevice = leftNode->GetDevice(0); - // leftDevice->SetDataRate(StringValue(returnDataRate)) - // leftDevice->SetQueue(StringValue(returnQueue)) - // auto leftPtr = devices.Get(0); - // leftPtr->SetDataRate(StringValue(returnDataRate)) - // leftPtr->SetQueue(StringValue(returnQueue)) - // - // auto rightPtr = devices.Get(1); - // rightPtr->SetDataRate(StringValue(forwardDataRate)) - // rightPtr->SetQueue(StringValue(forwardQueue)) + // Set client and server drop rates. + if (drop_rate_to_client.length() == 0) { + drops_to_client->SetDropRate(0); + cout << "Using drop rate to client: 0 %. (Use --drop-rate-to-client to change)" << endl; + } else { + drops_to_client->SetDropRate(stoi(drop_rate_to_client)); + } + if (drop_rate_to_server.length() == 0) { + drops_to_server->SetDropRate(0); + cout << "Using drop rate to server: 0 %. (Use --drop-rate-to-server to change)" << endl; + } else { + drops_to_server->SetDropRate(stoi(drop_rate_to_server)); + } + + devices.Get(0)->SetAttribute("ReceiveErrorModel", PointerValue(drops_to_client)); + devices.Get(1)->SetAttribute("ReceiveErrorModel", PointerValue(drops_to_server)); 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 From 043f0ac84c416288608239571114534a0b2d60ae Mon Sep 17 00:00:00 2001 From: sedrubal Date: Mon, 25 Oct 2021 17:04:15 +0200 Subject: [PATCH 3/8] Add support for nftables --- sim/Dockerfile | 9 ++++++--- sim/run.sh | 31 +++++++++++++++++++++---------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/sim/Dockerfile b/sim/Dockerfile index 91a7e5e..aee0183 100644 --- a/sim/Dockerfile +++ b/sim/Dockerfile @@ -37,9 +37,12 @@ RUN cd /wait-for-it-quic && 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 \ + net-tools \ + iptables \ + nftables \ + && apt-get clean WORKDIR /ns3 COPY --from=builder /ns3/out/src/fd-net-device/* /ns3/src/fd-net-device/ diff --git a/sim/run.sh b/sim/run.sh index 9be56e6..4bb7505 100644 --- a/sim/run.sh +++ b/sim/run.sh @@ -11,21 +11,32 @@ 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 +if iptables -L 2> /dev/null | grep FORWARD > /dev/null; then + echo "Using iptables" + 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 +elif grep nf_tables /proc/modules > /dev/null ; then + echo "Using 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 +else + echo "Neither ip_tables nor nf_tables module is loaded. Skipping firewall configuration." +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 From a7e8729025dab0725debacbe6e916173dc80ccfa Mon Sep 17 00:00:00 2001 From: sedrubal Date: Wed, 3 Nov 2021 16:02:31 +0100 Subject: [PATCH 4/8] Fix configuring firewall --- sim/run.sh | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/sim/run.sh b/sim/run.sh index 4bb7505..3497996 100644 --- a/sim/run.sh +++ b/sim/run.sh @@ -11,20 +11,30 @@ 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. +FIREWALL_CONFIGURED=0 if iptables -L 2> /dev/null | grep FORWARD > /dev/null; then - echo "Using iptables" + 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 -elif grep nf_tables /proc/modules > /dev/null ; then - echo "Using nftables" + 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 -else - echo "Neither ip_tables nor nf_tables module is loaded. Skipping firewall configuration." + FIREWALL_CONFIGURED=1 +fi +if [[ $FIREWALL_CONFIGURED != 1 ]]; then + echo "Could not configure firewall!" + exit 1 fi if [[ -n "$WAITFORSERVER" ]]; then From 64acc9f3071da59878773ba5641f1e9ff75345a4 Mon Sep 17 00:00:00 2001 From: sedrubal Date: Thu, 4 Nov 2021 18:12:54 +0100 Subject: [PATCH 5/8] Enhance logging --- .../drop-rate/drop-rate-error-model.cc | 46 ++++++++++++++++--- .../drop-rate/drop-rate-error-model.h | 9 +++- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/sim/scenarios/drop-rate/drop-rate-error-model.cc b/sim/scenarios/drop-rate/drop-rate-error-model.cc index 62c561c..4234e4d 100644 --- a/sim/scenarios/drop-rate/drop-rate-error-model.cc +++ b/sim/scenarios/drop-rate/drop-rate-error-model.cc @@ -12,27 +12,61 @@ 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." << 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..74a8fbf 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; + 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 */ From 96b038080aa378db918b007edd9ab57120317e8f Mon Sep 17 00:00:00 2001 From: sedrubal Date: Thu, 11 Nov 2021 19:29:47 +0100 Subject: [PATCH 6/8] Improve Dockerfile --- sim/Dockerfile | 85 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 27 deletions(-) diff --git a/sim/Dockerfile b/sim/Dockerfile index aee0183..5b7ddc1 100644 --- a/sim/Dockerfile +++ b/sim/Dockerfile @@ -1,61 +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 \ + && 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" ] From 11f0bc573d6f797cbc86a88d13a5d225feae764a Mon Sep 17 00:00:00 2001 From: sedrubal Date: Thu, 11 Nov 2021 19:42:27 +0100 Subject: [PATCH 7/8] Remove NS_FATAL_ERROR and stop properly? --- sim/scenarios/helper/quic-network-simulator-helper.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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) { From c1977f485f64d728bc11c5f79d1b7a57d85e6af3 Mon Sep 17 00:00:00 2001 From: sedrubal Date: Thu, 28 Apr 2022 15:24:42 +0200 Subject: [PATCH 8/8] Add support for a Gilbert-Elliot-Loss Model --- .../asymmetric-p2p/asymmetric-p2p.cc | 149 +++++++++++++++--- .../gilbert-elliott-drop-model.cc | 86 ++++++++++ .../gilbert-elliott-drop-model.h | 42 +++++ .../drop-rate/drop-rate-error-model.cc | 7 +- .../drop-rate/drop-rate-error-model.h | 2 +- 5 files changed, 263 insertions(+), 23 deletions(-) create mode 100644 sim/scenarios/asymmetric-p2p/gilbert-elliott-drop-model.cc create mode 100644 sim/scenarios/asymmetric-p2p/gilbert-elliott-drop-model.h diff --git a/sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc b/sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc index 19e9cd6..6ce1a61 100644 --- a/sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc +++ b/sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc @@ -8,12 +8,51 @@ #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; @@ -21,14 +60,17 @@ int main(int argc, char *argv[]) { string forwardQueueSize; string returnDataRate; string returnQueueSize; - string drop_rate_to_client; - string drop_rate_to_server; + 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 - Ptr drops_to_client = CreateObject(); - Ptr drops_to_server = CreateObject(); CommandLine cmd; cmd.AddValue("delay", "delay of the channel in both directions (RTT = 2 * delay)", channelDelay); @@ -36,8 +78,13 @@ int main(int argc, char *argv[]) { 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("drop-rate-to-client", "packet drop rate (towards client)", drop_rate_to_client); - cmd.AddValue("drop-rate-to-server", "packet drop rate (towards server)", drop_rate_to_server); + 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"); @@ -59,27 +106,87 @@ int main(int argc, char *argv[]) { leftP2PNetDev->SetDataRate(DataRate(returnDataRate)); rightP2PNetDev->SetDataRate(DataRate(forwardDataRate)); - auto returnQueue = leftP2PNetDev->GetQueue(); - auto forwardQueue = rightP2PNetDev->GetQueue(); + 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 (drop_rate_to_client.length() == 0) { - drops_to_client->SetDropRate(0); - cout << "Using drop rate to client: 0 %. (Use --drop-rate-to-client to change)" << endl; + 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 { - drops_to_client->SetDropRate(stoi(drop_rate_to_client)); - } - if (drop_rate_to_server.length() == 0) { - drops_to_server->SetDropRate(0); - cout << "Using drop rate to server: 0 %. (Use --drop-rate-to-server to change)" << endl; - } else { - drops_to_server->SetDropRate(stoi(drop_rate_to_server)); - } - devices.Get(0)->SetAttribute("ReceiveErrorModel", PointerValue(drops_to_client)); - devices.Get(1)->SetAttribute("ReceiveErrorModel", PointerValue(drops_to_server)); + 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/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 4234e4d..45982ef 100644 --- a/sim/scenarios/drop-rate/drop-rate-error-model.cc +++ b/sim/scenarios/drop-rate/drop-rate-error-model.cc @@ -39,7 +39,12 @@ void DropRateErrorModel::log(void) { 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." << endl; + 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; } diff --git a/sim/scenarios/drop-rate/drop-rate-error-model.h b/sim/scenarios/drop-rate/drop-rate-error-model.h index 74a8fbf..0720824 100644 --- a/sim/scenarios/drop-rate/drop-rate-error-model.h +++ b/sim/scenarios/drop-rate/drop-rate-error-model.h @@ -24,7 +24,7 @@ class DropRateErrorModel : public ErrorModel { bool first_packet_logged; static constexpr unsigned int LOG_AFTER_PACKETS = 1000; - bool DoCorrupt (Ptr p); + bool DoCorrupt(Ptr p); void DoReset(void); void log(void);