A Discrete-Event Network Simulator
API
ipv4-flow-classifier.cc
Go to the documentation of this file.
1 //
2 // Copyright (c) 2009 INESC Porto
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License version 2 as
6 // published by the Free Software Foundation;
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 //
17 // Author: Gustavo J. A. M. Carneiro <gjc@inescporto.pt> <gjcarneiro@gmail.com>
18 //
19 
20 #include "ipv4-flow-classifier.h"
21 
22 #include "ns3/packet.h"
23 #include "ns3/tcp-header.h"
24 #include "ns3/udp-header.h"
25 
26 #include <algorithm>
27 
28 namespace ns3
29 {
30 
31 /* see http://www.iana.org/assignments/protocol-numbers */
32 const uint8_t TCP_PROT_NUMBER = 6;
33 const uint8_t UDP_PROT_NUMBER = 17;
34 
35 bool
37 {
38  if (t1.sourceAddress < t2.sourceAddress)
39  {
40  return true;
41  }
42  if (t1.sourceAddress != t2.sourceAddress)
43  {
44  return false;
45  }
46 
48  {
49  return true;
50  }
52  {
53  return false;
54  }
55 
56  if (t1.protocol < t2.protocol)
57  {
58  return true;
59  }
60  if (t1.protocol != t2.protocol)
61  {
62  return false;
63  }
64 
65  if (t1.sourcePort < t2.sourcePort)
66  {
67  return true;
68  }
69  if (t1.sourcePort != t2.sourcePort)
70  {
71  return false;
72  }
73 
74  if (t1.destinationPort < t2.destinationPort)
75  {
76  return true;
77  }
78  if (t1.destinationPort != t2.destinationPort)
79  {
80  return false;
81  }
82 
83  return false;
84 }
85 
86 bool
88 {
89  return (t1.sourceAddress == t2.sourceAddress &&
92 }
93 
95 {
96 }
97 
98 bool
100  Ptr<const Packet> ipPayload,
101  uint32_t* out_flowId,
102  uint32_t* out_packetId)
103 {
104  if (ipHeader.GetFragmentOffset() > 0)
105  {
106  // Ignore fragments: they don't carry a valid L4 header
107  return false;
108  }
109 
110  FiveTuple tuple;
111  tuple.sourceAddress = ipHeader.GetSource();
112  tuple.destinationAddress = ipHeader.GetDestination();
113  tuple.protocol = ipHeader.GetProtocol();
114 
115  if ((tuple.protocol != UDP_PROT_NUMBER) && (tuple.protocol != TCP_PROT_NUMBER))
116  {
117  return false;
118  }
119 
120  if (ipPayload->GetSize() < 4)
121  {
122  // the packet doesn't carry enough bytes
123  return false;
124  }
125 
126  // we rely on the fact that for both TCP and UDP the ports are
127  // carried in the first 4 octets.
128  // This allows to read the ports even on fragmented packets
129  // not carrying a full TCP or UDP header.
130 
131  uint8_t data[4];
132  ipPayload->CopyData(data, 4);
133 
134  uint16_t srcPort = 0;
135  srcPort |= data[0];
136  srcPort <<= 8;
137  srcPort |= data[1];
138 
139  uint16_t dstPort = 0;
140  dstPort |= data[2];
141  dstPort <<= 8;
142  dstPort |= data[3];
143 
144  tuple.sourcePort = srcPort;
145  tuple.destinationPort = dstPort;
146 
147  // try to insert the tuple, but check if it already exists
148  std::pair<std::map<FiveTuple, FlowId>::iterator, bool> insert =
149  m_flowMap.insert(std::pair<FiveTuple, FlowId>(tuple, 0));
150 
151  // if the insertion succeeded, we need to assign this tuple a new flow identifier
152  if (insert.second)
153  {
154  FlowId newFlowId = GetNewFlowId();
155  insert.first->second = newFlowId;
156  m_flowPktIdMap[newFlowId] = 0;
157  m_flowDscpMap[newFlowId];
158  }
159  else
160  {
161  m_flowPktIdMap[insert.first->second]++;
162  }
163 
164  // increment the counter of packets with the same DSCP value
165  Ipv4Header::DscpType dscp = ipHeader.GetDscp();
166  std::pair<std::map<Ipv4Header::DscpType, uint32_t>::iterator, bool> dscpInserter =
167  m_flowDscpMap[insert.first->second].insert(
168  std::pair<Ipv4Header::DscpType, uint32_t>(dscp, 1));
169 
170  // if the insertion did not succeed, we need to increment the counter
171  if (!dscpInserter.second)
172  {
173  m_flowDscpMap[insert.first->second][dscp]++;
174  }
175 
176  *out_flowId = insert.first->second;
177  *out_packetId = m_flowPktIdMap[*out_flowId];
178 
179  return true;
180 }
181 
184 {
185  for (std::map<FiveTuple, FlowId>::const_iterator iter = m_flowMap.begin();
186  iter != m_flowMap.end();
187  iter++)
188  {
189  if (iter->second == flowId)
190  {
191  return iter->first;
192  }
193  }
194  NS_FATAL_ERROR("Could not find the flow with ID " << flowId);
195  FiveTuple retval = {Ipv4Address::GetZero(), Ipv4Address::GetZero(), 0, 0, 0};
196  return retval;
197 }
198 
199 bool
200 Ipv4FlowClassifier::SortByCount::operator()(std::pair<Ipv4Header::DscpType, uint32_t> left,
201  std::pair<Ipv4Header::DscpType, uint32_t> right)
202 {
203  return left.second > right.second;
204 }
205 
206 std::vector<std::pair<Ipv4Header::DscpType, uint32_t>>
208 {
209  std::map<FlowId, std::map<Ipv4Header::DscpType, uint32_t>>::const_iterator flow =
210  m_flowDscpMap.find(flowId);
211 
212  if (flow == m_flowDscpMap.end())
213  {
214  NS_FATAL_ERROR("Could not find the flow with ID " << flowId);
215  }
216 
217  std::vector<std::pair<Ipv4Header::DscpType, uint32_t>> v(flow->second.begin(),
218  flow->second.end());
219  std::sort(v.begin(), v.end(), SortByCount());
220  return v;
221 }
222 
223 void
224 Ipv4FlowClassifier::SerializeToXmlStream(std::ostream& os, uint16_t indent) const
225 {
226  Indent(os, indent);
227  os << "<Ipv4FlowClassifier>\n";
228 
229  indent += 2;
230  for (std::map<FiveTuple, FlowId>::const_iterator iter = m_flowMap.begin();
231  iter != m_flowMap.end();
232  iter++)
233  {
234  Indent(os, indent);
235  os << "<Flow flowId=\"" << iter->second << "\""
236  << " sourceAddress=\"" << iter->first.sourceAddress << "\""
237  << " destinationAddress=\"" << iter->first.destinationAddress << "\""
238  << " protocol=\"" << int(iter->first.protocol) << "\""
239  << " sourcePort=\"" << iter->first.sourcePort << "\""
240  << " destinationPort=\"" << iter->first.destinationPort << "\">\n";
241 
242  indent += 2;
243  std::map<FlowId, std::map<Ipv4Header::DscpType, uint32_t>>::const_iterator flow =
244  m_flowDscpMap.find(iter->second);
245 
246  if (flow != m_flowDscpMap.end())
247  {
248  for (std::map<Ipv4Header::DscpType, uint32_t>::const_iterator i = flow->second.begin();
249  i != flow->second.end();
250  i++)
251  {
252  Indent(os, indent);
253  os << "<Dscp value=\"0x" << std::hex << static_cast<uint32_t>(i->first) << "\""
254  << " packets=\"" << std::dec << i->second << "\" />\n";
255  }
256  }
257 
258  indent -= 2;
259  Indent(os, indent);
260  os << "</Flow>\n";
261  }
262 
263  indent -= 2;
264  Indent(os, indent);
265  os << "</Ipv4FlowClassifier>\n";
266 }
267 
268 } // namespace ns3
void Indent(std::ostream &os, uint16_t level) const
Add a number of spaces for indentation purposes.
FlowId GetNewFlowId()
Returns a new, unique Flow Identifier.
static Ipv4Address GetZero()
Comparator used to sort the vector of DSCP values.
bool operator()(std::pair< Ipv4Header::DscpType, uint32_t > left, std::pair< Ipv4Header::DscpType, uint32_t > right)
Comparator function.
std::map< FlowId, FlowPacketId > m_flowPktIdMap
Map to FlowIds to FlowPacketId.
void SerializeToXmlStream(std::ostream &os, uint16_t indent) const override
Serializes the results to an std::ostream in XML format.
std::vector< std::pair< Ipv4Header::DscpType, uint32_t > > GetDscpCounts(FlowId flowId) const
get the DSCP values of the packets belonging to the flow with the given FlowId, sorted in decreasing ...
FiveTuple FindFlow(FlowId flowId) const
Searches for the FiveTuple corresponding to the given flowId.
std::map< FlowId, std::map< Ipv4Header::DscpType, uint32_t > > m_flowDscpMap
Map FlowIds to (DSCP value, packet count) pairs.
std::map< FiveTuple, FlowId > m_flowMap
Map to Flows Identifiers to FlowIds.
bool Classify(const Ipv4Header &ipHeader, Ptr< const Packet > ipPayload, uint32_t *out_flowId, uint32_t *out_packetId)
try to classify the packet into flow-id and packet-id
Packet header for IPv4.
Definition: ipv4-header.h:34
Ipv4Address GetSource() const
Definition: ipv4-header.cc:302
uint8_t GetProtocol() const
Definition: ipv4-header.cc:281
Ipv4Address GetDestination() const
Definition: ipv4-header.cc:316
DscpType GetDscp() const
Definition: ipv4-header.cc:108
DscpType
DiffServ codepoints.
Definition: ipv4-header.h:72
uint16_t GetFragmentOffset() const
Definition: ipv4-header.cc:254
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:863
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:400
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
uint32_t FlowId
Abstract identifier of a packet flow.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
const uint8_t TCP_PROT_NUMBER
TCP Protocol number.
bool operator==(const EventId &a, const EventId &b)
Definition: event-id.h:157
bool operator<(const EventId &a, const EventId &b)
Definition: event-id.h:170
const uint8_t UDP_PROT_NUMBER
UDP Protocol number.
uint8_t data[writeSize]
Structure to classify a packet.
uint16_t destinationPort
Destination port.
Ipv4Address sourceAddress
Source address.
Ipv4Address destinationAddress
Destination address.