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