lte: (Fixes #2277) EpcTftClassifier::Classify blindly assumes that a packet has a L4 header
This commit is contained in:
@@ -35,6 +35,7 @@ New user-visible features
|
||||
Bugs fixed
|
||||
----------
|
||||
- Bug 1745 - There can be only one Ipv6AddressHelper in a script
|
||||
- Bug 2277 - lte: EpcTftClassifier::Classify blindly assumes that a packet has a L4 header
|
||||
- Bug 2505 - network: Avoid asserts in Header/Trailer deserialization
|
||||
- Bug 2656 - wifi: Minstrel and MinstrelHt provide different results for 802.11a/b/g
|
||||
- Bug 2653 - tcp: Avoid saving smaller TS in case of packet reordering
|
||||
|
||||
@@ -48,10 +48,9 @@ EpcTftClassifier::EpcTftClassifier ()
|
||||
void
|
||||
EpcTftClassifier::Add (Ptr<EpcTft> tft, uint32_t id)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << tft);
|
||||
|
||||
m_tftMap[id] = tft;
|
||||
|
||||
NS_LOG_FUNCTION (this << tft << id);
|
||||
m_tftMap[id] = tft;
|
||||
|
||||
// simple sanity check: there shouldn't be more than 16 bearers (hence TFTs) per UE
|
||||
NS_ASSERT (m_tftMap.size () <= 16);
|
||||
}
|
||||
@@ -67,7 +66,7 @@ EpcTftClassifier::Delete (uint32_t id)
|
||||
uint32_t
|
||||
EpcTftClassifier::Classify (Ptr<Packet> p, EpcTft::Direction direction)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << p << direction);
|
||||
NS_LOG_FUNCTION (this << p << p->GetSize () << direction);
|
||||
|
||||
Ptr<Packet> pCopy = p->Copy ();
|
||||
|
||||
@@ -105,8 +104,103 @@ EpcTftClassifier::Classify (Ptr<Packet> p, EpcTft::Direction direction)
|
||||
}
|
||||
NS_LOG_INFO ("local address: " << localAddressIpv4 << " remote address: " << remoteAddressIpv4);
|
||||
|
||||
uint16_t payloadSize = ipv4Header.GetPayloadSize ();
|
||||
uint16_t fragmentOffset = ipv4Header.GetFragmentOffset ();
|
||||
bool isLastFragment = ipv4Header.IsLastFragment ();
|
||||
|
||||
// NS_LOG_DEBUG ("PayloadSize = " << payloadSize);
|
||||
// NS_LOG_DEBUG ("fragmentOffset " << fragmentOffset << " isLastFragment " << isLastFragment);
|
||||
|
||||
protocol = ipv4Header.GetProtocol ();
|
||||
tos = ipv4Header.GetTos ();
|
||||
|
||||
// Port info only can be get if it is the first fragment and
|
||||
// there is enough data in the payload
|
||||
// We keep the port info for fragmented packets,
|
||||
// i.e. it is the first one but it is not the last one
|
||||
if (fragmentOffset == 0)
|
||||
{
|
||||
if (protocol == UdpL4Protocol::PROT_NUMBER && payloadSize >= 8)
|
||||
{
|
||||
UdpHeader udpHeader;
|
||||
pCopy->RemoveHeader (udpHeader);
|
||||
if (direction == EpcTft::UPLINK)
|
||||
{
|
||||
localPort = udpHeader.GetSourcePort ();
|
||||
remotePort = udpHeader.GetDestinationPort ();
|
||||
}
|
||||
else
|
||||
{
|
||||
remotePort = udpHeader.GetSourcePort ();
|
||||
localPort = udpHeader.GetDestinationPort ();
|
||||
}
|
||||
if (!isLastFragment)
|
||||
{
|
||||
std::tuple<uint32_t, uint32_t, uint8_t, uint16_t> fragmentKey =
|
||||
std::make_tuple (ipv4Header.GetSource ().Get (),
|
||||
ipv4Header.GetDestination ().Get (),
|
||||
protocol,
|
||||
ipv4Header.GetIdentification ());
|
||||
|
||||
m_classifiedIpv4Fragments[fragmentKey] = std::make_pair (localPort, remotePort);
|
||||
}
|
||||
}
|
||||
else if (protocol == TcpL4Protocol::PROT_NUMBER && payloadSize >= 20)
|
||||
{
|
||||
TcpHeader tcpHeader;
|
||||
pCopy->RemoveHeader (tcpHeader);
|
||||
if (direction == EpcTft::UPLINK)
|
||||
{
|
||||
localPort = tcpHeader.GetSourcePort ();
|
||||
remotePort = tcpHeader.GetDestinationPort ();
|
||||
}
|
||||
else
|
||||
{
|
||||
remotePort = tcpHeader.GetSourcePort ();
|
||||
localPort = tcpHeader.GetDestinationPort ();
|
||||
}
|
||||
|
||||
if (!isLastFragment)
|
||||
{
|
||||
std::tuple<uint32_t, uint32_t, uint8_t, uint16_t> fragmentKey =
|
||||
std::make_tuple (ipv4Header.GetSource ().Get (),
|
||||
ipv4Header.GetDestination ().Get (),
|
||||
protocol,
|
||||
ipv4Header.GetIdentification ());
|
||||
|
||||
m_classifiedIpv4Fragments[fragmentKey] = std::make_pair (localPort, remotePort);
|
||||
}
|
||||
}
|
||||
|
||||
// else
|
||||
// First fragment but not enough data for port info or not UDP/TCP protocol.
|
||||
// Nothing can be done, i.e. we cannot get port info from packet.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not first fragment, so port info is not available but
|
||||
// port info should already be known (if there is not fragment reordering)
|
||||
std::tuple<uint32_t, uint32_t, uint8_t, uint16_t> fragmentKey =
|
||||
std::make_tuple (ipv4Header.GetSource ().Get (),
|
||||
ipv4Header.GetDestination ().Get (),
|
||||
protocol,
|
||||
ipv4Header.GetIdentification ());
|
||||
|
||||
std::map< std::tuple<uint32_t, uint32_t, uint8_t, uint16_t>,
|
||||
std::pair<uint32_t, uint32_t> >::iterator it =
|
||||
m_classifiedIpv4Fragments.find (fragmentKey);
|
||||
|
||||
if (it != m_classifiedIpv4Fragments.end ())
|
||||
{
|
||||
localPort = it->second.first;
|
||||
remotePort = it->second.second;
|
||||
|
||||
if (isLastFragment)
|
||||
{
|
||||
m_classifiedIpv4Fragments.erase (fragmentKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ipType == 0x06)
|
||||
{
|
||||
@@ -128,53 +222,44 @@ EpcTftClassifier::Classify (Ptr<Packet> p, EpcTft::Direction direction)
|
||||
|
||||
protocol = ipv6Header.GetNextHeader ();
|
||||
tos = ipv6Header.GetTrafficClass ();
|
||||
|
||||
if (protocol == UdpL4Protocol::PROT_NUMBER)
|
||||
{
|
||||
UdpHeader udpHeader;
|
||||
pCopy->RemoveHeader (udpHeader);
|
||||
|
||||
if (direction == EpcTft::UPLINK)
|
||||
{
|
||||
localPort = udpHeader.GetSourcePort ();
|
||||
remotePort = udpHeader.GetDestinationPort ();
|
||||
}
|
||||
else
|
||||
{
|
||||
remotePort = udpHeader.GetSourcePort ();
|
||||
localPort = udpHeader.GetDestinationPort ();
|
||||
}
|
||||
}
|
||||
else if (protocol == TcpL4Protocol::PROT_NUMBER)
|
||||
{
|
||||
TcpHeader tcpHeader;
|
||||
pCopy->RemoveHeader (tcpHeader);
|
||||
if (direction == EpcTft::UPLINK)
|
||||
{
|
||||
localPort = tcpHeader.GetSourcePort ();
|
||||
remotePort = tcpHeader.GetDestinationPort ();
|
||||
}
|
||||
else
|
||||
{
|
||||
remotePort = tcpHeader.GetSourcePort ();
|
||||
localPort = tcpHeader.GetDestinationPort ();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ABORT_MSG ("EpcTftClassifier::Classify - Unknown IP type...");
|
||||
}
|
||||
|
||||
if (protocol == UdpL4Protocol::PROT_NUMBER)
|
||||
{
|
||||
UdpHeader udpHeader;
|
||||
pCopy->RemoveHeader (udpHeader);
|
||||
|
||||
if (direction == EpcTft::UPLINK)
|
||||
{
|
||||
localPort = udpHeader.GetSourcePort ();
|
||||
remotePort = udpHeader.GetDestinationPort ();
|
||||
}
|
||||
else
|
||||
{
|
||||
remotePort = udpHeader.GetSourcePort ();
|
||||
localPort = udpHeader.GetDestinationPort ();
|
||||
}
|
||||
}
|
||||
else if (protocol == TcpL4Protocol::PROT_NUMBER)
|
||||
{
|
||||
TcpHeader tcpHeader;
|
||||
pCopy->RemoveHeader (tcpHeader);
|
||||
if (direction == EpcTft::UPLINK)
|
||||
{
|
||||
localPort = tcpHeader.GetSourcePort ();
|
||||
remotePort = tcpHeader.GetDestinationPort ();
|
||||
}
|
||||
else
|
||||
{
|
||||
remotePort = tcpHeader.GetSourcePort ();
|
||||
localPort = tcpHeader.GetDestinationPort ();
|
||||
}
|
||||
}
|
||||
else if (protocol == Icmpv6L4Protocol::PROT_NUMBER || protocol == Icmpv4L4Protocol::PROT_NUMBER)
|
||||
{
|
||||
remotePort = 0;
|
||||
localPort = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_INFO ("Unknown protocol: " << protocol);
|
||||
return 0; // no match
|
||||
}
|
||||
|
||||
if (ipType == 0x04)
|
||||
{
|
||||
|
||||
@@ -36,9 +36,20 @@ class EpcTft;
|
||||
class Packet;
|
||||
|
||||
/**
|
||||
* \brief classifies IP packets accoding to Traffic Flow Templates (TFTs)
|
||||
*
|
||||
* \note this implementation works with IPv4 only.
|
||||
* \brief classifies IP packets according to Traffic Flow Templates (TFTs)
|
||||
*
|
||||
* \note this implementation works with IPv4 and IPv6.
|
||||
* When there is fragmentation of IP packets, UDP/TCP ports maybe missing.
|
||||
*
|
||||
* The following actions are performed to use the port info present in the first segment with
|
||||
* the next fragments:
|
||||
* - Port info is stored if it is available, i.e. it is the first fragment with UDP/TCP protocol
|
||||
* and there is enough data in the payload of the IP packet for the port numbers.
|
||||
* - Port info is used for the next fragments.
|
||||
* - Port info is deleted, when the last fragment is processed.
|
||||
*
|
||||
* When we cannot cache the port info, the TFT of the default bearer is used. This may happen
|
||||
* if there is reordering or losses of IP packets.
|
||||
*/
|
||||
class EpcTftClassifier : public SimpleRefCount<EpcTftClassifier>
|
||||
{
|
||||
@@ -76,7 +87,16 @@ public:
|
||||
protected:
|
||||
|
||||
std::map <uint32_t, Ptr<EpcTft> > m_tftMap; ///< TFT map
|
||||
|
||||
|
||||
std::map < std::tuple<uint32_t, uint32_t, uint8_t, uint16_t>,
|
||||
std::pair<uint32_t, uint32_t> >
|
||||
m_classifiedIpv4Fragments; ///< Map with already classified IPv4 Fragments
|
||||
///< An entry is added when the port info is available, i.e.
|
||||
///< first fragment, UDP/TCP protocols and enough payload data
|
||||
///< An entry is used if port info is not available, i.e.
|
||||
///< not first fragment or not enough payload data for TCP/UDP
|
||||
///< An entry is removed when the last fragment is classified
|
||||
///< Note: If last fragment is lost, entry is not removed
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -116,14 +116,15 @@ EpcTftClassifierTestCase::EpcTftClassifierTestCase (Ptr<EpcTftClassifier> c,
|
||||
m_d (d),
|
||||
m_tftId (tftId)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_FUNCTION (this << c << d << sa << da << sp << dp << tos << tftId);
|
||||
|
||||
m_ipHeader.SetSource (sa);
|
||||
m_ipHeader.SetDestination (da);
|
||||
m_ipHeader.SetTos (tos);
|
||||
m_ipHeader.SetTos (tos);
|
||||
m_ipHeader.SetPayloadSize (8); // Full UDP header
|
||||
|
||||
m_udpHeader.SetSourcePort (sp);
|
||||
m_udpHeader.SetDestinationPort (dp);
|
||||
m_udpHeader.SetDestinationPort (dp);
|
||||
}
|
||||
|
||||
EpcTftClassifierTestCase::~EpcTftClassifierTestCase ()
|
||||
@@ -163,7 +164,7 @@ EpcTftClassifierTestCase::DoRun (void)
|
||||
udpPacket->AddHeader (m_ipHeader);
|
||||
NS_LOG_LOGIC (this << *udpPacket);
|
||||
uint32_t obtainedTftId = m_c ->Classify (udpPacket, m_d);
|
||||
NS_TEST_ASSERT_MSG_EQ (obtainedTftId, m_tftId, "bad classification of UDP packet");
|
||||
NS_TEST_ASSERT_MSG_EQ (obtainedTftId, (uint16_t) m_tftId, "bad classification of UDP packet");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user