diff --git a/src/internet/model/ipv4-queue-disc-item.cc b/src/internet/model/ipv4-queue-disc-item.cc index 021beb217..97d54de71 100644 --- a/src/internet/model/ipv4-queue-disc-item.cc +++ b/src/internet/model/ipv4-queue-disc-item.cc @@ -18,6 +18,8 @@ #include "ns3/log.h" #include "ipv4-queue-disc-item.h" +#include "ns3/tcp-header.h" +#include "ns3/udp-header.h" namespace ns3 { @@ -109,4 +111,59 @@ Ipv4QueueDiscItem::GetUint8Value (QueueItem::Uint8Values field, uint8_t& value) return ret; } +uint32_t +Ipv4QueueDiscItem::Hash (uint32_t perturbation) const +{ + NS_LOG_FUNCTION (this << perturbation); + + Ipv4Address src = m_header.GetSource (); + Ipv4Address dest = m_header.GetDestination (); + uint8_t prot = m_header.GetProtocol (); + uint16_t fragOffset = m_header.GetFragmentOffset (); + + TcpHeader tcpHdr; + UdpHeader udpHdr; + uint16_t srcPort = 0; + uint16_t destPort = 0; + + if (prot == 6 && fragOffset == 0) // TCP + { + GetPacket ()->PeekHeader (tcpHdr); + srcPort = tcpHdr.GetSourcePort (); + destPort = tcpHdr.GetDestinationPort (); + } + else if (prot == 17 && fragOffset == 0) // UDP + { + GetPacket ()->PeekHeader (udpHdr); + srcPort = udpHdr.GetSourcePort (); + destPort = udpHdr.GetDestinationPort (); + } + if (prot != 6 && prot != 17) + { + NS_LOG_WARN ("Unknown transport protocol, no port number included in hash computation"); + } + + /* serialize the 5-tuple and the perturbation in buf */ + uint8_t buf[17]; + src.Serialize (buf); + dest.Serialize (buf + 4); + buf[8] = prot; + buf[9] = (srcPort >> 8) & 0xff; + buf[10] = srcPort & 0xff; + buf[11] = (destPort >> 8) & 0xff; + buf[12] = destPort & 0xff; + buf[13] = (perturbation >> 24) & 0xff; + buf[14] = (perturbation >> 16) & 0xff; + buf[15] = (perturbation >> 8) & 0xff; + buf[16] = perturbation & 0xff; + + // Linux calculates jhash2 (jenkins hash), we calculate murmur3 because it is + // already available in ns-3 + uint32_t hash = Hash32 ((char*) buf, 17); + + NS_LOG_DEBUG ("Hash value " << hash); + + return hash; +} + } // namespace ns3 diff --git a/src/internet/model/ipv4-queue-disc-item.h b/src/internet/model/ipv4-queue-disc-item.h index 76ab26fb2..52371a4b6 100644 --- a/src/internet/model/ipv4-queue-disc-item.h +++ b/src/internet/model/ipv4-queue-disc-item.h @@ -82,6 +82,18 @@ public: */ virtual bool Mark (void); + /** + * \brief Computes the hash of the packet's 5-tuple + * + * Computes the hash of the source and destination IP addresses, protocol + * number and, if the transport protocol is either UDP or TCP, the source + * and destination port + * + * \param perturbation hash perturbation value + * \return the hash of the packet's 5-tuple + */ + virtual uint32_t Hash (uint32_t perturbation) const; + private: /** * \brief Default constructor diff --git a/src/internet/model/ipv6-queue-disc-item.cc b/src/internet/model/ipv6-queue-disc-item.cc index b1e61aaf7..508fec462 100644 --- a/src/internet/model/ipv6-queue-disc-item.cc +++ b/src/internet/model/ipv6-queue-disc-item.cc @@ -18,6 +18,8 @@ #include "ns3/log.h" #include "ipv6-queue-disc-item.h" +#include "ns3/tcp-header.h" +#include "ns3/udp-header.h" namespace ns3 { @@ -108,4 +110,58 @@ Ipv6QueueDiscItem::GetUint8Value (QueueItem::Uint8Values field, uint8_t& value) return ret; } +uint32_t +Ipv6QueueDiscItem::Hash (uint32_t perturbation) const +{ + NS_LOG_FUNCTION (this << perturbation); + + Ipv6Address src = m_header.GetSourceAddress (); + Ipv6Address dest = m_header.GetDestinationAddress (); + uint8_t prot = m_header.GetNextHeader (); + + TcpHeader tcpHdr; + UdpHeader udpHdr; + uint16_t srcPort = 0; + uint16_t destPort = 0; + + if (prot == 6) // TCP + { + GetPacket ()->PeekHeader (tcpHdr); + srcPort = tcpHdr.GetSourcePort (); + destPort = tcpHdr.GetDestinationPort (); + } + else if (prot == 17) // UDP + { + GetPacket ()->PeekHeader (udpHdr); + srcPort = udpHdr.GetSourcePort (); + destPort = udpHdr.GetDestinationPort (); + } + if (prot != 6 && prot != 17) + { + NS_LOG_WARN ("Unknown transport protocol, no port number included in hash computation"); + } + + /* serialize the 5-tuple and the perturbation in buf */ + uint8_t buf[41]; + src.Serialize (buf); + dest.Serialize (buf + 16); + buf[32] = prot; + buf[33] = (srcPort >> 8) & 0xff; + buf[34] = srcPort & 0xff; + buf[35] = (destPort >> 8) & 0xff; + buf[36] = destPort & 0xff; + buf[37] = (perturbation >> 24) & 0xff; + buf[38] = (perturbation >> 16) & 0xff; + buf[39] = (perturbation >> 8) & 0xff; + buf[40] = perturbation & 0xff; + + // Linux calculates jhash2 (jenkins hash), we calculate murmur3 because it is + // already available in ns-3 + uint32_t hash = Hash32 ((char*) buf, 41); + + NS_LOG_DEBUG ("Found Ipv6 packet; hash of the five tuple " << hash); + + return hash; +} + } // namespace ns3 diff --git a/src/internet/model/ipv6-queue-disc-item.h b/src/internet/model/ipv6-queue-disc-item.h index 0a4be133f..4afe86c73 100644 --- a/src/internet/model/ipv6-queue-disc-item.h +++ b/src/internet/model/ipv6-queue-disc-item.h @@ -82,6 +82,18 @@ public: */ virtual bool Mark (void); + /** + * \brief Computes the hash of the packet's 5-tuple + * + * Computes the hash of the source and destination IP addresses, protocol + * number and, if the transport protocol is either UDP or TCP, the source + * and destination port + * + * \param perturbation hash perturbation value + * \return the hash of the packet's 5-tuple + */ + virtual uint32_t Hash (uint32_t perturbation) const; + private: /** * \brief Default constructor diff --git a/src/network/utils/queue-item.cc b/src/network/utils/queue-item.cc index aab3b330d..339c79d81 100644 --- a/src/network/utils/queue-item.cc +++ b/src/network/utils/queue-item.cc @@ -139,4 +139,11 @@ QueueDiscItem::Print (std::ostream& os) const ; } +uint32_t +QueueDiscItem::Hash (uint32_t perturbation) const +{ + NS_LOG_WARN ("The Hash method should be redefined by subclasses"); + return 0; +} + } // namespace ns3 diff --git a/src/network/utils/queue-item.h b/src/network/utils/queue-item.h index 18fb7c635..d22b03ba2 100644 --- a/src/network/utils/queue-item.h +++ b/src/network/utils/queue-item.h @@ -215,6 +215,17 @@ public: */ virtual bool Mark (void) = 0; + /** + * \brief Computes the hash of various fields of the packet header + * + * This method just returns 0. Subclasses should implement a reasonable hash + * for their protocol type, such as hashing on the TCP/IP 5-tuple. + * + * \param perturbation hash perturbation value + * \return the hash of various fields of the packet header + */ + virtual uint32_t Hash (uint32_t perturbation = 0) const; + private: /** * \brief Default constructor