Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add asymmetric-p2p scenario #99

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 63 additions & 29 deletions sim/Dockerfile
Original file line number Diff line number Diff line change
@@ -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" ]
41 changes: 31 additions & 10 deletions sim/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
192 changes: 192 additions & 0 deletions sim/scenarios/asymmetric-p2p/asymmetric-p2p.cc
Original file line number Diff line number Diff line change
@@ -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 <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>


using namespace ns3;
using namespace std;

NS_LOG_COMPONENT_DEFINE("ns3 simulator");

static Ptr<Queue<Packet>> returnQueue;
static Ptr<Queue<Packet>> 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<PointToPointNetDevice>();
auto rightP2PNetDev = devices.Get(1)->GetObject<PointToPointNetDevice>();

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<GilbertElliottDropModel> drops = CreateObject<GilbertElliottDropModel>();
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<GilbertElliottDropModel> dropsToClient = CreateObject<GilbertElliottDropModel>();
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<DropRateErrorModel> dropsToClient = CreateObject<DropRateErrorModel>();
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<GilbertElliottDropModel> dropsToServer = CreateObject<GilbertElliottDropModel>();
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<DropRateErrorModel> dropsToServer = CreateObject<DropRateErrorModel>();
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));
}
1 change: 1 addition & 0 deletions sim/scenarios/asymmetric-p2p/drop-rate-error-model.cc
1 change: 1 addition & 0 deletions sim/scenarios/asymmetric-p2p/drop-rate-error-model.h
Loading