The ECN implementation model for Linux TCP in ns-2 simulator∗ Naeem Khademi Networks and Distributed Systems Group Department of Informatics, University of Oslo Oslo, Norway naeemk@ifi.uio.no ABSTRACT unsigned char cong_action_; /* Congestion Action. Transport sender notifying transport receiver of responses to congestion.(CWR bit in TCP header) */ This technical report describes in details the implementation of ECN for Linux TCP in ns-2 simulator. /* these functions use the newer ECN names but leaves the actual field names above to maintain backward compat */ unsigned char& ect() { return ecn_capable_; } /* (ECT bit in IP header) */ unsigned char& ect1() { return eem_capable_; } /* (use ECT(1) bit in IP header instead of ECT(0)) e.g.used for early ecn marking (EEM) */ unsigned char& ecnecho() { return ecn_; } /* (ECN Echo bit in TCP header) */ unsigned char& ce() { return ecn_to_echo_; } /* (CE bit in IP header) */ unsigned char& cong_action() { return cong_action_; } /* (CWR bit in TCP header-old name) */ unsigned char& cwr() { return cong_action_; } /* (CWR bit in TCP header) */ ... Keywords TCP, ECN, Linux, ns-2; 1. INTRODUCTION A short story about ECN and citing relevant RFCs 2. OPERATION OF ECN How ECN protocol works; explain the sender-router-receiver interaction, header flags and bits e.g. ECT(0), CE, ECE, CWR, etc. 3. ECN IMPLEMENTATION FOR NS-2 LINUX TCP Some bits, flags and functions defined in TCP header files as well as TCP Agent class as in Listing 1 and Listing 2. Listing 1: ECN-related variables and functions in hdr_flags struct in common/flags.h. struct hdr_flags { unsigned char ecn_; /* transport receiver notifying transport sender of ECN (ECN Echo bit in TCP header) */ unsigned char ecn_to_echo_; /* ecn to be echoed back in the opposite direction (CE bit in IP header) */ unsigned char ecn_capable_; /* an ecn-capable tranport (ECT bit in IP header) */ unsigned char eem_capable_; /* an early ecn marking (EEM capable transport (ECT(1) bit in IP header) */ ∗PROPOSED DRAFT IN PROGRESS: Please do not redistribute! }; Listing 2: ECN-related variables in TcpAgent class in tcp/tcp.h. class TcpAgent : public Agent { ... protected: int ecn_; /* Explicit Congestion Notification */ int eem_; /* Early ECN Marking */ int eem_beta; /* Early ECN Marking beta factor */ int cong_action_; /* Congestion Action. True to indicate that the sender responded to congestion. */ int ecn_burst_; /* True when the previous ACK packet carried ECN-Echo. */ int ecn_backoff_; /* True when retransmit timer should begin to be backed off. */ int ect_; /* turn on ect bit now? */ int ect1_; /* ect(1) bit e.g. used for early ECN marking */ ... }; CE marking by AQM (here RED) at the router is in Listing 3 and Listing 4. Listing 3: ECN marking indicator in queue/red.h. next_pkts_in_flight_ = linux_.snd_cwnd; //we do rate halving if (linux_.icsk_ca_ops==NULL) { slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF); load_to_linux(); } else { //ok this is the linux part linux_.snd_ssthresh = icsk->icsk_ca_ops->ssthresh(&linux_); linux_.snd_cwnd_cnt = 0; linux_.bytes_acked = 0; if (icsk->icsk_ca_ops->min_cwnd) linux_.snd_cwnd = icsk->icsk_ca_ops->min_cwnd(&linux_); else linux_.snd_cwnd = linux_.snd_ssthresh; ncwndcuts_++; cong_action_ = TRUE; } if (flag & FLAG_ECE) ++necnresponses_; tcp_set_ca_state(TCP_CA_Recovery); struct edp { int setbit; /* true to set congestion indication bit */ ... }; class REDQueue : public Queue { ... protected: edp edp_; /* early-drop params */ ... } Listing 4: CE marking in RED queue as in queue/red.cc. int REDQueue::drop_early(Packet* pkt) { hdr_cmn* ch = hdr_cmn::access(pkt); ... if (u <= edv_.v_prob) { // DROP or MARK edv_.count = 0; edv_.count_bytes = 0; hdr_flags* hf = hdr_flags::access(pickPacketForECN(pkt)); if (edp_.setbit && hf->ect() && (!edp_.use_mark_p || edv_.v_prob1 < edp_.mark_p)) { hf->ce() = 1; /* mark Congestion Experienced bit */ /* Tell the queue monitor here - call emark(pkt) */ return (0); // no drop } else { return (1); // drop } } return (0); // no DROP/mark } TCP sender receives a packet with ECN-Echo (ECE) bit set and sets the ECE flag. It also reacts to ECE by halving the cwnd as shown in Listing 5. Listing 5: Rate halving due to loss or ECE signal in tcp/tcp-linux.cc. void LinuxTcpAgent::recv(Packet *pkt, Handler*) { //equivalence to tcp_ack ... if (hdr_flags::access(pkt)->ecnecho() && ecn_ && (ack>1)) { flag |= FLAG_ECE; //ECN } ... } void LinuxTcpAgent::tcp_fastretrans_alert(unsigned char flag) { struct inet_connection_sock *icsk = &linux_; ... switch (linux_.icsk_ca_state) { case TCP_CA_Recovery: break; case TCP_CA_Loss: //let it through default: //TCP_CA_Open and have loss or ECE if (flag&(FLAG_DATA_LOST | FLAG_ECE)) { recover_ = maxseq_; last_cwnd_action_ = CWND_ACTION_DUPACK; touch_cwnd(); } } } Once a packet is being sent at the sender, it sets ECT(0) bitorder if ECN is turned on. If cwnd reduction (rate-halving) has happened, it sets the CWR bit in outgoing packet’s header in Listing 6. Listing 6: ECT(0) and CWR marking at the TCP sender in tcp/tcp.cc. void TcpAgent::output(int seqno, int reason) { ... Packet* p = allocpkt(); hdr_flags* hf = hdr_flags::access(p); ... if (ecn_) { hf->ect() = 1; // ECN-capable transport } if (cong_action_ && (!is_retransmit || SetCWRonRetransmit_)) { hf->cong_action() = TRUE; /* Congestion action. */ cong_action_ = FALSE; } } 4. CONCLUSIONS In this paper, we provided in-depth knowledge over implementation of ECN for Linux TCP in ns-2 simulator.