Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1917)

Unified Diff: src/internet/model/tcp-socket-base.cc

Issue 314790043: Phase 2: ECN implementation for TCP (Closed)
Patch Set: Set 6: Removed iptos packet tag for rst Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/internet/model/tcp-socket-base.h ('k') | src/internet/test/tcp-ecn-test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/internet/model/tcp-socket-base.cc
===================================================================
--- a/src/internet/model/tcp-socket-base.cc
+++ b/src/internet/model/tcp-socket-base.cc
@@ -135,6 +135,10 @@
BooleanValue (true),
MakeBooleanAccessor (&TcpSocketBase::m_limitedTx),
MakeBooleanChecker ())
+ .AddAttribute ("UseEcn", "True to use ECN functionality",
+ BooleanValue (false),
+ MakeBooleanAccessor (&TcpSocketBase::m_ecn),
+ MakeBooleanChecker ())
.AddTraceSource ("RTO",
"Retransmission timeout",
MakeTraceSourceAccessor (&TcpSocketBase::m_rto),
@@ -159,6 +163,10 @@
"TCP Congestion machine state",
MakeTraceSourceAccessor (&TcpSocketBase::m_congStateTrace),
"ns3::TcpSocketState::TcpCongStatesTracedValueCallback")
+ .AddTraceSource ("EcnState",
+ "Current ECN State of TCP Socket",
+ MakeTraceSourceAccessor (&TcpSocketBase::m_ecnStateTrace),
+ "ns3::TcpSocketState::EcnStatesTracedValueCallback")
.AddTraceSource ("AdvWND",
"Advertised Window Size",
MakeTraceSourceAccessor (&TcpSocketBase::m_advWnd),
@@ -195,6 +203,18 @@
"Receive tcp packet from IP protocol",
MakeTraceSourceAccessor (&TcpSocketBase::m_rxTrace),
"ns3::TcpSocketBase::TcpTxRxTracedCallback")
+ .AddTraceSource ("EcnEchoSeq",
+ "Sequence of last received ECN Echo",
+ MakeTraceSourceAccessor (&TcpSocketBase::m_ecnEchoSeq),
+ "ns3::SequenceNumber32TracedValueCallback")
+ .AddTraceSource ("EcnCESeq",
+ "Sequence of last received CE ",
+ MakeTraceSourceAccessor (&TcpSocketBase::m_ecnCESeq),
+ "ns3::SequenceNumber32TracedValueCallback")
+ .AddTraceSource ("EcnCWRSeq",
+ "Sequence of last received CWR",
+ MakeTraceSourceAccessor (&TcpSocketBase::m_ecnCWRSeq),
+ "ns3::SequenceNumber32TracedValueCallback")
;
return tid;
}
@@ -225,6 +245,10 @@
"TCP Congestion machine state",
MakeTraceSourceAccessor (&TcpSocketState::m_congState),
"ns3::TracedValue::TcpCongStatesTracedValueCallback")
+ .AddTraceSource ("EcnState",
+ "Current ECN State of TCP Socket",
+ MakeTraceSourceAccessor (&TcpSocketState::m_ecnState),
+ "ns3::TracedValue::EcnStatesTracedValueCallback")
.AddTraceSource ("HighestSequence",
"Highest sequence number received from peer",
MakeTraceSourceAccessor (&TcpSocketState::m_highTxMark),
@@ -246,6 +270,7 @@
m_segmentSize (0),
m_lastAckedSeq (0),
m_congState (CA_OPEN),
+ m_ecnState (ECN_DISABLED),
m_highTxMark (0),
// Change m_nextTxSequence for non-zero initial sequence number
m_nextTxSequence (0),
@@ -263,6 +288,7 @@
m_segmentSize (other.m_segmentSize),
m_lastAckedSeq (other.m_lastAckedSeq),
m_congState (other.m_congState),
+ m_ecnState (other.m_ecnState),
m_highTxMark (other.m_highTxMark),
m_nextTxSequence (other.m_nextTxSequence),
m_rcvTimestampValue (other.m_rcvTimestampValue),
@@ -276,6 +302,13 @@
"CA_OPEN", "CA_DISORDER", "CA_CWR", "CA_RECOVERY", "CA_LOSS"
};
+const char* const
+TcpSocketState::EcnStateName[TcpSocketState::ECN_CWR_SENT+1] =
+{
+ "ECN_DISABLED", "ECN_IDLE", "ECN_CE_RCVD", "ECN_ECE_SENT", "ECN_ECE_RCVD", "ECN_CWR_SENT"
+};
+
+
TcpSocketBase::TcpSocketBase (void)
: TcpSocket (),
m_retxEvent (),
@@ -332,7 +365,11 @@
m_retxThresh (3),
m_limitedTx (false),
m_congestionControl (0),
- m_isFirstPartialAck (true)
+ m_isFirstPartialAck (true),
+ m_ecn(false),
+ m_ecnEchoSeq (0),
+ m_ecnCESeq (0),
+ m_ecnCWRSeq (0)
{
NS_LOG_FUNCTION (this);
m_rxBuffer = CreateObject<TcpRxBuffer> ();
@@ -353,6 +390,10 @@
MakeCallback (&TcpSocketBase::UpdateCongState, this));
NS_ASSERT (ok == true);
+ ok = m_tcb->TraceConnectWithoutContext ("EcnState",
+ MakeCallback (&TcpSocketBase::UpdateEcnState, this));
+ NS_ASSERT (ok == true);
+
ok = m_tcb->TraceConnectWithoutContext ("NextTxSequence",
MakeCallback (&TcpSocketBase::UpdateNextTxSequence, this));
NS_ASSERT (ok == true);
@@ -409,7 +450,10 @@
m_limitedTx (sock.m_limitedTx),
m_isFirstPartialAck (sock.m_isFirstPartialAck),
m_txTrace (sock.m_txTrace),
- m_rxTrace (sock.m_rxTrace)
+ m_rxTrace (sock.m_rxTrace),
+ m_ecn (sock.m_ecn),
+ m_ecnEchoSeq (sock.m_ecnEchoSeq),
+ m_ecnCWRSeq (sock.m_ecnCWRSeq)
{
NS_LOG_FUNCTION (this);
NS_LOG_LOGIC ("Invoked the copy constructor");
@@ -448,6 +492,10 @@
MakeCallback (&TcpSocketBase::UpdateCongState, this));
NS_ASSERT (ok == true);
+ ok = m_tcb->TraceConnectWithoutContext ("EcnState",
+ MakeCallback (&TcpSocketBase::UpdateEcnState, this));
+ NS_ASSERT (ok == true);
+
ok = m_tcb->TraceConnectWithoutContext ("NextTxSequence",
MakeCallback (&TcpSocketBase::UpdateNextTxSequence, this));
NS_ASSERT (ok == true);
@@ -1051,9 +1099,18 @@
// A new connection is allowed only if this socket does not have a connection
if (m_state == CLOSED || m_state == LISTEN || m_state == SYN_SENT || m_state == LAST_ACK || m_state == CLOSE_WAIT)
{ // send a SYN packet and change state into SYN_SENT
- SendEmptyPacket (TcpHeader::SYN);
+ // send a SYN packet with ECE and CWR flags set if sender is ECN capable
+ if (m_ecn)
+ {
+ SendEmptyPacket (TcpHeader::SYN | TcpHeader::ECE | TcpHeader::CWR);
+ }
+ else
+ {
+ SendEmptyPacket (TcpHeader::SYN);
+ }
NS_LOG_DEBUG (TcpStateName[m_state] << " -> SYN_SENT");
m_state = SYN_SENT;
+ m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED; // because sender is not yet aware about receiver's ECN capability
}
else if (m_state != TIME_WAIT)
{ // In states SYN_RCVD, ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, and CLOSING, an connection
@@ -1160,7 +1217,15 @@
Address fromAddress = InetSocketAddress (header.GetSource (), port);
Address toAddress = InetSocketAddress (header.GetDestination (),
m_endPoint->GetLocalPort ());
-
+ TcpHeader tcpHeader;
+ packet->PeekHeader (tcpHeader);
+ if (header.GetEcn() == Ipv4Header::ECN_CE && m_ecnCESeq < tcpHeader.GetAckNumber ())
+ {
+ NS_LOG_INFO ("Received CE flag is valid");
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CE_RCVD");
+ m_ecnCESeq = tcpHeader.GetAckNumber ();
+ m_tcb->m_ecnState = TcpSocketState::ECN_CE_RCVD;
+ }
DoForwardUp (packet, fromAddress, toAddress);
}
@@ -1178,6 +1243,15 @@
Address toAddress = Inet6SocketAddress (header.GetDestinationAddress (),
m_endPoint6->GetLocalPort ());
+ TcpHeader tcpHeader;
+ packet->PeekHeader (tcpHeader);
+ if (header.GetEcn() == Ipv6Header::ECN_CE && m_ecnCESeq < tcpHeader.GetAckNumber ())
+ {
+ NS_LOG_INFO ("Received CE flag is valid");
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CE_RCVD");
+ m_ecnCESeq = tcpHeader.GetAckNumber ();
+ m_tcb->m_ecnState = TcpSocketState::ECN_CE_RCVD;
+ }
DoForwardUp (packet, fromAddress, toAddress);
}
@@ -1235,7 +1309,29 @@
// Acknowledgement should be sent for all unacceptable packets (RFC793, p.69)
if (m_state == ESTABLISHED && !(tcpHeader.GetFlags () & TcpHeader::RST))
{
- SendEmptyPacket (TcpHeader::ACK);
+ // Check if the sender has responded to ECN echo by reducing the Congestion Window
+ if (tcpHeader.GetFlags () & TcpHeader::CWR )
+ {
+ // Check if a packet with CE bit set is received. If there is no CE bit set, then change the state to ECN_IDLE to
+ // stop sending ECN Echo messages. If there is CE bit set, the packet should continue sending ECN Echo messages
+ //
+ if (m_tcb->m_ecnState != TcpSocketState::ECN_CE_RCVD)
+ {
+ m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
+ }
+ }
+ if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD || m_tcb->m_ecnState == TcpSocketState::ECN_ECE_SENT)
+ {
+ // Receiver sets ECE flags when it receives a packet with CE bit on or sender hasn’t responded to ECN echo sent by receiver
+ SendEmptyPacket (TcpHeader::ACK | TcpHeader::ECE);
+ m_tcb->m_ecnState = TcpSocketState::ECN_ECE_SENT;
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_ECE_SENT");
+ }
+ else
+ {
+ SendEmptyPacket (TcpHeader::ACK);
+ }
}
return;
}
@@ -1416,8 +1512,8 @@
{
NS_LOG_FUNCTION (this << tcpHeader);
- // Extract the flags. PSH and URG are not honoured.
- uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG);
+ // Extract the flags. PSH, URG, CWR and ECE are not honoured.
+ uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG | TcpHeader::CWR | TcpHeader::ECE);
// Different flags are different events
if (tcpflags == TcpHeader::ACK)
@@ -1439,7 +1535,17 @@
NS_LOG_WARN ("Ignored ack of " << tcpHeader.GetAckNumber () <<
" HighTxMark = " << m_tcb->m_highTxMark);
+ // Receiver sets ECE flags when it receives a packet with CE bit on or sender hasn’t responded to ECN echo sent by receiver
+ if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD || m_tcb->m_ecnState == TcpSocketState::ECN_ECE_SENT)
+ {
+ SendEmptyPacket (TcpHeader::ACK | TcpHeader::ECE);
+ m_tcb->m_ecnState = TcpSocketState::ECN_ECE_SENT;
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_ECE_SENT");
+ }
+ else
+ {
SendEmptyPacket (TcpHeader::ACK);
+ }
}
else
{
@@ -1656,6 +1762,17 @@
SequenceNumber32 ackNumber = tcpHeader.GetAckNumber ();
+ if (ackNumber > m_txBuffer->HeadSequence () && (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED) && (tcpHeader.GetFlags () & TcpHeader::ECE))
+ {
+ if (m_ecnEchoSeq < tcpHeader.GetAckNumber ())
+ {
+ NS_LOG_INFO ("Received ECN Echo is valid");
+ m_ecnEchoSeq = tcpHeader.GetAckNumber ();
+ m_tcb->m_ecnState = TcpSocketState::ECN_ECE_RCVD;
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_ECE_RCVD");
+ }
+ }
+
// RFC 6675 Section 5: 2nd, 3rd paragraph and point (A), (B) implementation
// are inside the function ProcessAck
ProcessAck (ackNumber, scoreboardUpdated);
@@ -1888,8 +2005,8 @@
{
NS_LOG_FUNCTION (this << tcpHeader);
- // Extract the flags. PSH and URG are not honoured.
- uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG);
+ // Extract the flags. PSH, URG, CWR and ECE are not honoured.
+ uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG | TcpHeader::CWR | TcpHeader::ECE);
// Fork a socket if received a SYN. Do nothing otherwise.
// C.f.: the LISTEN part in tcp_v4_do_rcv() in tcp_ipv4.c in Linux kernel
@@ -1917,8 +2034,8 @@
{
NS_LOG_FUNCTION (this << tcpHeader);
- // Extract the flags. PSH and URG are not honoured.
- uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG);
+ // Extract the flags. PSH, URG, CWR and ECE are not honoured.
+ uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG | TcpHeader::CWR | TcpHeader::ECE);
if (tcpflags == 0)
{ // Bare data, accept it and move to ESTABLISHED state. This is not a normal behaviour. Remove this?
@@ -1940,7 +2057,22 @@
m_state = SYN_RCVD;
m_synCount = m_synRetries;
m_rxBuffer->SetNextRxSequence (tcpHeader.GetSequenceNumber () + SequenceNumber32 (1));
- SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
+
+ /* Check if we recieved an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if the traffic is ECN capable and
+ * sender has sent ECN SYN packet
+ */
+ if (m_ecn && (tcpHeader.GetFlags () & (TcpHeader::CWR | TcpHeader::ECE)) == (TcpHeader::CWR | TcpHeader::ECE))
+ {
+ NS_LOG_INFO ("Received ECN SYN packet");
+ SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK | TcpHeader::ECE);
+ m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
+ }
+ else
+ {
+ m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
+ SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
+ }
}
else if (tcpflags == (TcpHeader::SYN | TcpHeader::ACK)
&& m_tcb->m_nextTxSequence + SequenceNumber32 (1) == tcpHeader.GetAckNumber ())
@@ -1954,6 +2086,21 @@
m_tcb->m_highTxMark = ++m_tcb->m_nextTxSequence;
m_txBuffer->SetHeadSequence (m_tcb->m_nextTxSequence);
SendEmptyPacket (TcpHeader::ACK);
+
+ /* Check if we received an ECN SYN-ACK packet. Change the ECN state of sender to ECN_IDLE if receiver has sent an ECN SYN-ACK
+ * packet and the traffic is ECN Capable
+ */
+ if (m_ecn && (tcpHeader.GetFlags () & (TcpHeader::CWR | TcpHeader::ECE)) == (TcpHeader::ECE))
+ {
+ NS_LOG_INFO ("Received ECN SYN-ACK packet.");
+ m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
+ }
+ else
+ {
+ m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
+ }
+
SendPendingData (m_connected);
Simulator::ScheduleNow (&TcpSocketBase::ConnectionSucceeded, this);
// Always respond to first data packet to speed up the connection.
@@ -1979,8 +2126,8 @@
{
NS_LOG_FUNCTION (this << tcpHeader);
- // Extract the flags. PSH and URG are not honoured.
- uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG);
+ // Extract the flags. PSH, URG, CWR and ECE are not honoured.
+ uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG | TcpHeader::CWR | TcpHeader::ECE);
if (tcpflags == 0
|| (tcpflags == TcpHeader::ACK
@@ -2019,7 +2166,22 @@
else if (tcpflags == TcpHeader::SYN)
{ // Probably the peer lost my SYN+ACK
m_rxBuffer->SetNextRxSequence (tcpHeader.GetSequenceNumber () + SequenceNumber32 (1));
- SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
+
+ /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if sender has sent an ECN SYN
+ * packet and the traffic is ECN Capable
+ */
+ if (m_ecn && (tcpHeader.GetFlags () & (TcpHeader::CWR | TcpHeader::ECE)) == (TcpHeader::CWR | TcpHeader::ECE))
+ {
+ NS_LOG_INFO ("Received ECN SYN packet");
+ SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK |TcpHeader::ECE);
+ m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
+ }
+ else
+ {
+ m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
+ SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
+ }
}
else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
{
@@ -2070,8 +2232,8 @@
{
NS_LOG_FUNCTION (this << tcpHeader);
- // Extract the flags. PSH and URG are not honoured.
- uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG);
+ // Extract the flags. PSH, URG, CWR and ECE are not honoured.
+ uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG | TcpHeader::CWR | TcpHeader::ECE);
if (packet->GetSize () > 0 && tcpflags != TcpHeader::ACK)
{ // Bare data, accept it
@@ -2142,8 +2304,8 @@
{
NS_LOG_FUNCTION (this << tcpHeader);
- // Extract the flags. PSH and URG are not honoured.
- uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG);
+ // Extract the flags. PSH, URG, CWR and ECE are not honoured.
+ uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG | TcpHeader::CWR | TcpHeader::ECE);
if (tcpflags == TcpHeader::ACK)
{
@@ -2174,8 +2336,8 @@
{
NS_LOG_FUNCTION (this << tcpHeader);
- // Extract the flags. PSH and URG are not honoured.
- uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG);
+ // Extract the flags. PSH, URG, CWR and ECE are not honoured.
+ uint8_t tcpflags = tcpHeader.GetFlags () & ~(TcpHeader::PSH | TcpHeader::URG | TcpHeader::CWR | TcpHeader::ECE);
if (tcpflags == 0)
{
@@ -2602,7 +2764,20 @@
// Set the sequence number and send SYN+ACK
m_rxBuffer->SetNextRxSequence (h.GetSequenceNumber () + SequenceNumber32 (1));
- SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
+ /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if sender has sent an ECN SYN
+ * packet and the traffic is ECN Capable
+ */
+ if (m_ecn && (h.GetFlags () & (TcpHeader::CWR | TcpHeader::ECE)) == (TcpHeader::CWR | TcpHeader::ECE))
+ {
+ SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK | TcpHeader::ECE);
+ m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
+ }
+ else
+ {
+ SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
+ m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
+ }
}
void
@@ -2643,6 +2818,25 @@
m_delAckCount = 0;
}
+ // Sender should reduce the Congestion Window as a response to receiver's ECN Echo notification only once per window
+ if (m_tcb->m_ecnState == TcpSocketState::ECN_ECE_RCVD && m_ecnEchoSeq.Get() > m_ecnCWRSeq.Get() && !isRetransmission )
+ {
+ NS_LOG_INFO ("Backoff mechanism by reducing CWND by half because we've received ECN Echo");
+ m_tcb->m_ssThresh = m_congestionControl->GetSsThresh (m_tcb, BytesInFlight ());
+ m_tcb->m_cWnd = std::max ((uint32_t)m_tcb->m_cWnd/2, m_tcb->m_segmentSize);
+ flags |= TcpHeader::CWR;
+ m_ecnCWRSeq = seq;
+ m_tcb->m_ecnState = TcpSocketState::ECN_CWR_SENT;
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CWR_SENT");
+ NS_LOG_INFO ("CWR flags set");
+ NS_LOG_DEBUG (TcpSocketState::TcpCongStateName[m_tcb->m_congState] << " -> CA_CWR");
+ if (m_tcb->m_congState == TcpSocketState::CA_OPEN)
+ {
+ m_congestionControl->CongestionStateSet (m_tcb, TcpSocketState::CA_CWR);
+ m_tcb->m_congState = TcpSocketState::CA_CWR;
+ }
+ }
+
/*
* Add tags for each socket option.
* Note that currently the socket adds both IPv4 tag and IPv6 tag
@@ -2652,16 +2846,49 @@
if (GetIpTos ())
{
SocketIpTosTag ipTosTag;
- ipTosTag.SetTos (GetIpTos ());
+ NS_LOG_LOGIC (" ECT bits should not be set on retransmitted packets ");
+ if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && (GetIpTos () & 0x3) == 0 && !isRetransmission)
+ {
+ ipTosTag.SetTos (GetIpTos () | 0x2);
+ }
+ else
+ {
+ ipTosTag.SetTos (GetIpTos ());
+ }
p->AddPacketTag (ipTosTag);
}
+ else
+ {
+ if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && !isRetransmission)
+ {
+ SocketIpTosTag ipTosTag;
+ ipTosTag.SetTos (0x02);
+ p->AddPacketTag (ipTosTag);
+ }
+ }
if (IsManualIpv6Tclass ())
{
SocketIpv6TclassTag ipTclassTag;
- ipTclassTag.SetTclass (GetIpv6Tclass ());
+ if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && (GetIpv6Tclass () & 0x3) == 0 && !isRetransmission)
+ {
+ ipTclassTag.SetTclass (GetIpv6Tclass () | 0x2);
+ }
+ else
+ {
+ ipTclassTag.SetTclass (GetIpv6Tclass ());
+ }
p->AddPacketTag (ipTclassTag);
}
+ else
+ {
+ if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && !isRetransmission)
+ {
+ SocketIpv6TclassTag ipTclassTag;
+ ipTclassTag.SetTclass (0x02);
+ p->AddPacketTag (ipTclassTag);
+ }
+ }
if (IsManualIpTtl ())
{
@@ -2998,7 +3225,16 @@
SequenceNumber32 expectedSeq = m_rxBuffer->NextRxSequence ();
if (!m_rxBuffer->Add (p, tcpHeader))
{ // Insert failed: No data or RX buffer full
- SendEmptyPacket (TcpHeader::ACK);
+ if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD || m_tcb->m_ecnState == TcpSocketState::ECN_ECE_SENT)
+ {
+ SendEmptyPacket (TcpHeader::ACK | TcpHeader::ECE);
+ m_tcb->m_ecnState = TcpSocketState::ECN_ECE_SENT;
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_ECE_SENT");
+ }
+ else
+ {
+ SendEmptyPacket (TcpHeader::ACK);
+ }
return;
}
// Notify app to receive if necessary
@@ -3024,7 +3260,16 @@
// Now send a new ACK packet acknowledging all received and delivered data
if (m_rxBuffer->Size () > m_rxBuffer->Available () || m_rxBuffer->NextRxSequence () > expectedSeq + p->GetSize ())
{ // A gap exists in the buffer, or we filled a gap: Always ACK
- SendEmptyPacket (TcpHeader::ACK);
+ if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD || m_tcb->m_ecnState == TcpSocketState::ECN_ECE_SENT)
+ {
+ SendEmptyPacket (TcpHeader::ACK | TcpHeader::ECE);
+ m_tcb->m_ecnState = TcpSocketState::ECN_ECE_SENT;
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_ECE_SENT");
+ }
+ else
+ {
+ SendEmptyPacket (TcpHeader::ACK);
+ }
}
else
{ // In-sequence packet: ACK if delayed ack count allows
@@ -3032,7 +3277,16 @@
{
m_delAckEvent.Cancel ();
m_delAckCount = 0;
- SendEmptyPacket (TcpHeader::ACK);
+ if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD || m_tcb->m_ecnState == TcpSocketState::ECN_ECE_SENT)
+ {
+ SendEmptyPacket (TcpHeader::ACK | TcpHeader::ECE);
+ m_tcb->m_ecnState = TcpSocketState::ECN_ECE_SENT;
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_ECE_SENT");
+ }
+ else
+ {
+ SendEmptyPacket (TcpHeader::ACK);
+ }
}
else if (m_delAckEvent.IsExpired ())
{
@@ -3242,7 +3496,15 @@
TcpSocketBase::DelAckTimeout (void)
{
m_delAckCount = 0;
- SendEmptyPacket (TcpHeader::ACK);
+ if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD || m_tcb->m_ecnState == TcpSocketState::ECN_ECE_SENT)
+ {
+ SendEmptyPacket (TcpHeader::ACK | TcpHeader::ECE);
+ m_tcb->m_ecnState = TcpSocketState::ECN_ECE_SENT;
+ }
+ else
+ {
+ SendEmptyPacket (TcpHeader::ACK);
+ }
}
void
@@ -3286,7 +3548,17 @@
tcpHeader.SetDestinationPort (m_endPoint6->GetPeerPort ());
}
AddOptions (tcpHeader);
-
+ //Send a packet tag for setting ECT bits in IP header
+ if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED)
+ {
+ SocketIpTosTag ipTosTag;
+ ipTosTag.SetTos (0x02);
+ p->AddPacketTag (ipTosTag);
+
+ SocketIpv6TclassTag ipTclassTag;
+ ipTclassTag.SetTclass (0x02);
+ p->AddPacketTag (ipTclassTag);
+ }
m_txTrace (p, tcpHeader, this);
if (m_endPoint != 0)
@@ -3315,7 +3587,15 @@
{
if (m_synCount > 0)
{
- SendEmptyPacket (TcpHeader::SYN);
+ if (m_ecn)
+ {
+ SendEmptyPacket (TcpHeader::SYN | TcpHeader::ECE | TcpHeader::CWR);
+ }
+ else
+ {
+ SendEmptyPacket (TcpHeader::SYN);
+ }
+ m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
}
else
{
@@ -3416,7 +3696,16 @@
*/
if (oldSize < size && m_connected)
{
- SendEmptyPacket (TcpHeader::ACK);
+ if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD || m_tcb->m_ecnState == TcpSocketState::ECN_ECE_SENT)
+ {
+ SendEmptyPacket (TcpHeader::ACK | TcpHeader::ECE);
+ m_tcb->m_ecnState = TcpSocketState::ECN_ECE_SENT;
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_ECE_SENT");
+ }
+ else
+ {
+ SendEmptyPacket (TcpHeader::ACK);
+ }
}
}
@@ -3821,6 +4110,13 @@
}
void
+TcpSocketBase::UpdateEcnState (TcpSocketState::EcnState_t oldValue,
+ TcpSocketState::EcnState_t newValue)
+{
+ m_ecnStateTrace (oldValue, newValue);
+}
+
+void
TcpSocketBase::UpdateNextTxSequence (SequenceNumber32 oldValue,
SequenceNumber32 newValue)
@@ -3858,6 +4154,12 @@
return 0;
}
+void
+TcpSocketBase::SetEcn()
+{
+ m_ecn = true;
+}
+
//RttHistory methods
RttHistory::RttHistory (SequenceNumber32 s, uint32_t c, Time t)
: seq (s),
« no previous file with comments | « src/internet/model/tcp-socket-base.h ('k') | src/internet/test/tcp-ecn-test.cc » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b