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 
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:852
FlowId GetNewFlowId()
Returns a new, unique Flow Identifier.
DscpType
DiffServ codepoints.
Definition: ipv4-header.h:70
Ipv4Address destinationAddress
Destination address.
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 ...
uint16_t destinationPort
Destination port.
Ipv4Address GetSource(void) const
Definition: ipv4-header.cc:291
const uint8_t TCP_PROT_NUMBER
TCP Protocol number.
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
std::map< FlowId, FlowPacketId > m_flowPktIdMap
Map to FlowIds to FlowPacketId.
bool operator<(const EventId &a, const EventId &b)
Definition: event-id.h:160
uint8_t GetProtocol(void) const
Definition: ipv4-header.cc:272
def indent(source, debug, level)
Definition: check-style.py:439
Packet header for IPv4.
Definition: ipv4-header.h:33
uint8_t data[writeSize]
DscpType GetDscp(void) const
Definition: ipv4-header.cc:105
bool operator()(std::pair< Ipv4Header::DscpType, uint32_t > left, std::pair< Ipv4Header::DscpType, uint32_t > right)
Comparator function.
uint16_t GetFragmentOffset(void) const
Definition: ipv4-header.cc:246
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static Ipv4Address GetZero(void)
Structure to classify a packet.
Comparator used to sort the vector of DSCP values.
const uint8_t UDP_PROT_NUMBER
UDP Protocol number.
Ipv4Address GetDestination(void) const
Definition: ipv4-header.cc:304
void Indent(std::ostream &os, uint16_t level) const
Add a number of spaces for indentation purposes.
FiveTuple FindFlow(FlowId flowId) const
Searches for the FiveTuple corresponding to the given flowId.
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:378
bool operator==(const EventId &a, const EventId &b)
Definition: event-id.h:142
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
virtual void SerializeToXmlStream(std::ostream &os, uint16_t indent) const
Serializes the results to an std::ostream in XML format.
std::map< FiveTuple, FlowId > m_flowMap
Map to Flows Identifiers to FlowIds.
Ipv4Address sourceAddress
Source address.
uint32_t FlowId
Abstract identifier of a packet flow.
std::map< FlowId, std::map< Ipv4Header::DscpType, uint32_t > > m_flowDscpMap
Map FlowIds to (DSCP value, packet count) pairs.