This tutorial is dedicated to people who want to use TCP-Linux
to do NS-2 simulations. For information on how to install
TCP-Linux
into NS-2, see TCP-Linux
website. For general tutorials of NS-2, see the NS-2 website.
WARNING: You also need to set "window_" option in tcp agent to be large enough to see the performance difference. "window_" is the upperbound of congestion window in a TCP. It is 20 by default.
A
script for TCP-Sack1 |
A
script for TCP-Linux |
#Create a simulator object set ns [new Simulator] #Create two nodes and a link set bs [$ns node] set br [$ns node] $ns duplex-link $bs $br 100Mb 10ms DropTail #setup sender side set tcp [new Agent/TCP/Sack1] $tcp set timestamps_ true $tcp set windowOption_ 8 $ns attach-agent $bs $tcp #set up receiver side set sink [new Agent/TCPSink/Sack1] $sink set ts_echo_rfc1323_ true $ns attach-agent $br $sink #logical connection $ns connect $tcp $sink #Setup a FTP over TCP connection set ftp [new Application/FTP] $ftp attach-agent $tcp $ftp set type_ FTP #Schedule the life of the FTP $ns at 0 "$ftp start" $ns at 10 "$ftp stop" #Schedule the stop of the simulation $ns at 11 "exit 0" #Start the simulation $ns run |
#Create a simulator object set ns [new Simulator] #Create two nodes and a link set bs [$ns node] set br [$ns node] $ns duplex-link $bs $br 100Mb 10ms DropTail #setup sender side set tcp [new Agent/TCP/Linux] $tcp set timestamps_ true $ns at 0 "$tcp select_ca highspeed" $ns attach-agent $bs $tcp #set up receiver side set sink [new Agent/TCPSink/Sack1] $sink set ts_echo_rfc1323_ true $ns attach-agent $br $sink #logical connection $ns connect $tcp $sink #Setup a FTP over TCP connection set ftp [new Application/FTP] $ftp attach-agent $tcp $ftp set type_ FTP #Schedule the life of the FTP $ns at 0 "$ftp start" $ns at 10 "$ftp stop" #Schedule the stop of the simulation $ns at 11 "exit 0" #Start the simulation $ns run |
Naive Reno ( u32 in the codes are equivalent to unsigned int) |
/*
This is a very naive Reno implementation, shown as an example on how to
develop a new congestion control algorithm with TCP-Linux. */ /* This file itself should be copied to tcp/linux/ directory. */ /* To let the compiler compiles this file, an entry "tcp/linux/<NameOfThisFile>.o" should be added to Makefile */ /* This two header files link your implementation to TCP-Linux */ #include "ns-linux-c.h" #include "ns-linux-util.h" /* This equivalent to opencwnd in other implementation of NS-2. */ /* This function increase congestion window for each acknowledgment*/ void tcp_naive_reno_cong_avoid(struct tcp_sk *tp, u32 ack, u32 rtt, u32 in_flight, int flag) { if (tp->snd_cwnd < tp->snd_ssthresh) { tp->snd_cwnd++; } else { if (tp->snd_cwnd_cnt >= tp->snd_cwnd) { if (tp->snd_cwnd < tp->snd_cwnd_clamp) tp->snd_cwnd++; tp->snd_cwnd_cnt = 0; } else { tp->snd_cwnd_cnt++; } } } /* This function returns the slow-start threshold after a loss.*/ /* ssthreshold should be half of the congestion window after a loss */ u32 tcp_naive_reno_ssthresh(struct tcp_sk *tp) { return max(tp->snd_cwnd >> 1U, 2U); } /* This function returns the congestion window after a loss -- it is called AFTER the function ssthresh (above) */ /* Congestion window should be equal to the slow start threshold (after slow start threshold set to half of cwnd before loss). */ u32 tcp_naive_reno_min_cwnd(struct tcp_sk *tp) { return tp->snd_ssthresh; } /* a constant record for this congestion control algorithm */ /* The record should be hooked in tcp/linux/ns-linux-util.h and tcp/tcp-linux.cc */ struct tcp_congestion_ops naive_reno = { .name = "naive_reno", .ssthresh = tcp_naive_reno_ssthresh, .cong_avoid = tcp_naive_reno_cong_avoid, .min_cwnd = tcp_naive_reno_min_cwnd }; |
Variable Name |
type (32bit by default) |
Meanings |
equivalence in existing NS-2 TCP |
snd_nxt |
unsigned |
The sequence number of the
next byte that TCP is going to send. |
t_seqno_*size_ |
snd_una | unsigned | The sequence number of the
next byte that TCP is waiting for acknowledgment |
(highest_ack_+1)*size_ |
mss_cache |
unsigned | The size of a packet |
size_ |
srtt |
unsigned | 8 times of the smooth RTT |
t_srtt_ |
rx_opt.rcv_tsecr | unsigned | Value of timestamp echoed by the
last acknowledgment |
ts_echo_ |
rx_opt.saw_tstamp | bool |
Whether tiemstamp is seen in the last acknowledgment | !hdr_flags::access(pkt)->no_ts_ |
snd_ssthresh |
unsigned | Slow-Start
threshold |
ssthresh_ |
snd_cwnd |
unsigned | Congestion
window |
trunc(cwnd_) |
snd_cwnd_cnt |
unsigned (16 bit) |
Fraction
of congestion window which is not accumulated to 1 |
trunc(cwnd_*cwnd_)%cwnd_ |
snd_cwnd_clamp |
unsigned (16bit) |
upper bound of the congestion
window |
wnd_ |
snd_cwnd_stamp |
unsigned | the last
time that the congestion window is changed (to detect idling and other
situations) |
n/a |
bytes_acked |
unsigned |
the number of bytes that were
acknowledged in the last acknowledgment (for ABC) |
n/a |
icsk_ca_state |
unsigned (8bit) |
The current congestion control
state, which can be one of the followings: TCP_CA_Open: normal state TCP_CA_Recovery: Loss Recovery after a Fast Transmission TCP_CA_Loss: Loss Recovery after a Timeout (The following two states are not effective in TCP-Linux but is effective in Linux) TCP_CA_Disorder: duplicate packets detected, but haven't reach the threshold. So TCP shall assume that packet reordering is happening. TCP_CA_CWR: the state that congestion window is decreasing (after local congesiton in NIC, or ECN and etc). |
n/a |
icsk_ca_priv |
unsigned[16] |
private
data for individual congestion control algorithm for this flow |
n/a |
icsk_ca_ops |
struct tcp_congesiton_ops* |
a pointer to the congestion
control algorithm structure for this flow |
n/a |
function name |
explanation |
cong_avoid |
This function is called every
time an acknowledgment is received and the congestion window can be
increased. This is equivalent to opencwnd
in tcp.cc. ack is the number of bytes that are acknowledged in the latest acknowledgment; rtt is the the rtt measured by the latest acknowledgment; in_flight is the packet in flight before the latest acknowledgment; good_ack is an indicator whether the current situation is normal (no duplicate ack, no loss and no SACK). |
ssthresh |
This function is called when the
TCP flow detects a loss. It returns the slow start threshold of a flow, after a packet loss is detected. |
min_cwnd |
This function is called when the
TCP flow detects a loss. It returns the congestion window of a flow, after a packet loss is detected; (for many algorithms, this will be equal to ssthresh). When a loss is detected, min_cwnd is called after ssthresh. But some others algorithms might set min_cwnd to be smaller than ssthresh. If this is the case, there will be a slow start after loss recovery. |
undo_cwnd |
returns the congestion window of
a flow, after a false loss detection (due to false timeout or packet
reordering) is confirmed. This function is not effective in the
current version of TCP-Linux. |
rtt_sample |
This function is called when a
new RTT sample is obtained. It is mainly used by delay-based congestion
control algorithms which usually need accurate timestamps. usrtt is the RTT value in microsecond (us) unit. |
set_state | This function is called when the
congestion state of
the TCP is changed. newstate is the state code for the state that TCP is going to be in. The possible states are listed in the data structure interface table. It is to notify the congestion control algorithm and is used by some algorithms which turn off their special control during loss recovery. |
cwnd_event | This function is called when
there is an event that might be interested for congestion control
algorithm. ev is the congestion event code. The possible events are: CA_EVENT_FAST_ACK: An acknowledgment in sequence is received; CA_EVENT_SLOW_ACK: An acknowledgment not in sequence is received; CA_EVENT_TX_START: first transmission when no packet is in flight CA_EVENT_CWND_RESTART: congestion window is restarted CA_EVENT_COMPLETE_CWR: congestion window recovery is finished. CA_EVENT_FRTO: fast recovery timeout happens CA_EVENT_LOSS: retransmission timeout happens |
pkts_acked |
This function is called when
there is an acknowledgment that acknowledges some new packets. num_acked is the number of packets that are acknowledged by this acknowledgments. |
init |
This function is called after
the first acknowledgment is received and before the congestion control
algorithm will be called for the first time. If the congestion control algorithm has private data, it should initialize its private date here. |
release |
This function is called when the
flow finishes. If the congestion control algorithm has allocated
additional memory other than the 16 unsigned int of icsk_ca_priv,
it should delete the additional memory here to avoid memory leak. |
You might encounter one of the following problems in the last step:
Please check the known Linux bugs page to make sure it is really the problem of the algorithm, not a bug in Linux implementation.
Please check the known Linux bugs page to make sure it is really the problem of the algorithm, not a bug in Linux implementation.
This work is inspired and greatly helped by Prof. Pei Cao at Stanford and by Prof. Steven Low at Caltech. Many thanks to them!