A Discrete-Event Network Simulator
API
ipv6-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 // Modifications: Tommaso Pecorella <tommaso.pecorella@unifi.it>
20 //
21 
22 #include "ns3/packet.h"
23 
24 #include "ipv6-flow-classifier.h"
25 #include "ns3/udp-header.h"
26 #include "ns3/tcp-header.h"
27 #include <algorithm>
28 
29 namespace ns3 {
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 
36 
39 {
40  if (t1.sourceAddress < t2.sourceAddress)
41  {
42  return true;
43  }
44  if (t1.sourceAddress != t2.sourceAddress)
45  {
46  return false;
47  }
48 
50  {
51  return true;
52  }
54  {
55  return false;
56  }
57 
58  if (t1.protocol < t2.protocol)
59  {
60  return true;
61  }
62  if (t1.protocol != t2.protocol)
63  {
64  return false;
65  }
66 
67  if (t1.sourcePort < t2.sourcePort)
68  {
69  return true;
70  }
71  if (t1.sourcePort != t2.sourcePort)
72  {
73  return false;
74  }
75 
76  if (t1.destinationPort < t2.destinationPort)
77  {
78  return true;
79  }
80  if (t1.destinationPort != t2.destinationPort)
81  {
82  return false;
83  }
84 
85  return false;
86 }
87 
90 {
91  return (t1.sourceAddress == t2.sourceAddress &&
93  t1.protocol == t2.protocol &&
94  t1.sourcePort == t2.sourcePort &&
96 }
97 
98 
99 
101 {
102 }
103 
104 bool
106  uint32_t *out_flowId, uint32_t *out_packetId)
107 {
108  if (ipHeader.GetDestinationAddress ().IsMulticast ())
109  {
110  // we are not prepared to handle multicast yet
111  return false;
112  }
113 
114  FiveTuple tuple;
115  tuple.sourceAddress = ipHeader.GetSourceAddress ();
116  tuple.destinationAddress = ipHeader.GetDestinationAddress ();
117  tuple.protocol = ipHeader.GetNextHeader ();
118 
119  if ((tuple.protocol != UDP_PROT_NUMBER) && (tuple.protocol != TCP_PROT_NUMBER))
120  {
121  return false;
122  }
123 
124  if (ipPayload->GetSize () < 4)
125  {
126  // the packet doesn't carry enough bytes
127  return false;
128  }
129 
130  // we rely on the fact that for both TCP and UDP the ports are
131  // carried in the first 4 octects.
132  // This allows to read the ports even on fragmented packets
133  // not carrying a full TCP or UDP header.
134 
135  uint8_t data[4];
136  ipPayload->CopyData (data, 4);
137 
138  uint16_t srcPort = 0;
139  srcPort |= data[0];
140  srcPort <<= 8;
141  srcPort |= data[1];
142 
143  uint16_t dstPort = 0;
144  dstPort |= data[2];
145  dstPort <<= 8;
146  dstPort |= data[3];
147 
148  tuple.sourcePort = srcPort;
149  tuple.destinationPort = dstPort;
150 
151  // try to insert the tuple, but check if it already exists
152  std::pair<std::map<FiveTuple, FlowId>::iterator, bool> insert
153  = m_flowMap.insert (std::pair<FiveTuple, FlowId> (tuple, 0));
154 
155  // if the insertion succeeded, we need to assign this tuple a new flow identifier
156  if (insert.second)
157  {
158  FlowId newFlowId = GetNewFlowId ();
159  insert.first->second = newFlowId;
160  m_flowPktIdMap[newFlowId] = 0;
161  m_flowDscpMap[newFlowId];
162  }
163  else
164  {
165  m_flowPktIdMap[insert.first->second] ++;
166  }
167 
168  // increment the counter of packets with the same DSCP value
169  Ipv6Header::DscpType dscp = ipHeader.GetDscp ();
170  std::pair<std::map<Ipv6Header::DscpType, uint32_t>::iterator, bool> dscpInserter
171  = m_flowDscpMap[insert.first->second].insert (std::pair<Ipv6Header::DscpType, uint32_t> (dscp, 1));
172 
173  // if the insertion did not succeed, we need to increment the counter
174  if (!dscpInserter.second)
175  {
176  m_flowDscpMap[insert.first->second][dscp] ++;
177  }
178 
179  *out_flowId = insert.first->second;
180  *out_packetId = m_flowPktIdMap[*out_flowId];
181 
182  return true;
183 }
184 
185 
188 {
189  for (std::map<FiveTuple, FlowId>::const_iterator
190  iter = m_flowMap.begin (); iter != m_flowMap.end (); iter++)
191  {
192  if (iter->second == flowId)
193  {
194  return iter->first;
195  }
196  }
197  NS_FATAL_ERROR ("Could not find the flow with ID " << flowId);
198  FiveTuple retval = { Ipv6Address::GetZero (), Ipv6Address::GetZero (), 0, 0, 0 };
199  return retval;
200 }
201 
202 bool
203 Ipv6FlowClassifier::SortByCount::operator() (std::pair<Ipv6Header::DscpType, uint32_t> left,
204  std::pair<Ipv6Header::DscpType, uint32_t> right)
205 {
206  return left.second > right.second;
207 }
208 
209 std::vector<std::pair<Ipv6Header::DscpType, uint32_t> >
211 {
212  std::map<FlowId, std::map<Ipv6Header::DscpType, uint32_t> >::const_iterator flow
213  = m_flowDscpMap.find (flowId);
214 
215  if (flow == m_flowDscpMap.end ())
216  {
217  NS_FATAL_ERROR ("Could not find the flow with ID " << flowId);
218  }
219 
220  std::vector<std::pair<Ipv6Header::DscpType, uint32_t> > v (flow->second.begin (), flow->second.end ());
221  std::sort (v.begin (), v.end (), SortByCount ());
222  return v;
223 }
224 
225 void
226 Ipv6FlowClassifier::SerializeToXmlStream (std::ostream &os, uint16_t indent) const
227 {
228  Indent (os, indent); os << "<Ipv6FlowClassifier>\n";
229 
230  indent += 2;
231  for (std::map<FiveTuple, FlowId>::const_iterator
232  iter = m_flowMap.begin (); iter != m_flowMap.end (); 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<Ipv6Header::DscpType, uint32_t> >::const_iterator flow
244  = m_flowDscpMap.find (iter->second);
245 
246  if (flow != m_flowDscpMap.end ())
247  {
248  for (std::map<Ipv6Header::DscpType, uint32_t>::const_iterator i = flow->second.begin (); i != flow->second.end (); i++)
249  {
250  Indent (os, indent);
251  os << "<Dscp value=\"0x" << std::hex << static_cast<uint32_t> (i->first) << "\""
252  << " packets=\"" << std::dec << i->second << "\" />\n";
253  }
254  }
255 
256  indent -= 2;
257  Indent (os, indent); os << "</Flow>\n";
258  }
259 
260  indent -= 2;
261  Indent (os, indent); os << "</Ipv6FlowClassifier>\n";
262 
263 }
264 
265 
266 } // namespace ns3
267 
uint8_t GetNextHeader(void) const
Get the next header.
Definition: ipv6-header.cc:80
Packet header for IPv6.
Definition: ipv6-header.h:34
FiveTuple FindFlow(FlowId flowId) const
Searches for the FiveTuple corresponding to the given flowId.
FlowId GetNewFlowId()
Returns a new, unique Flow Identifier.
DscpType
DiffServ Code Points Code Points defined in Assured Forwarding (AF) RFC 2597 Expedited Forwarding (EF...
Definition: ipv6-header.h:45
Ipv6Address destinationAddress
Destination address.
const uint8_t TCP_PROT_NUMBER
TCP Protocol number.
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:796
std::vector< std::pair< Ipv6Header::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 ...
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:162
void Indent(std::ostream &os, uint16_t level) const
Add a number of spaces for indentation purposes.
bool Classify(const Ipv6Header &ipHeader, Ptr< const Packet > ipPayload, uint32_t *out_flowId, uint32_t *out_packetId)
try to classify the packet into flow-id and packet-id
DscpType GetDscp(void) const
Definition: ipv6-header.cc:202
bool operator<(const EventId &a, const EventId &b)
Definition: event-id.h:153
def indent(source, debug, level)
Definition: check-style.py:424
static Ipv6Address GetZero()
Get the 0 (::) Ipv6Address.
uint8_t data[writeSize]
std::map< FlowId, std::map< Ipv6Header::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 operator()(std::pair< Ipv6Header::DscpType, uint32_t > left, std::pair< Ipv6Header::DscpType, uint32_t > right)
Comparator function.
Ipv6Address sourceAddress
Source address.
std::map< FlowId, FlowPacketId > m_flowPktIdMap
Map to FlowIds to FlowPacketId.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
bool IsMulticast() const
If the IPv6 address is multicast (ff00::/8).
const uint8_t UDP_PROT_NUMBER
UDP Protocol number.
Ipv6Address GetSourceAddress(void) const
Get the "Source address" field.
Definition: ipv6-header.cc:100
bool operator==(const EventId &a, const EventId &b)
Definition: event-id.h:135
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:355
virtual void SerializeToXmlStream(std::ostream &os, uint16_t indent) const
Serializes the results to an std::ostream in XML format.
Comparator used to sort the vector of DSCP values.
uint16_t destinationPort
Destination port.
Structure to classify a packet.
Ipv6Address GetDestinationAddress(void) const
Get the "Destination address" field.
Definition: ipv6-header.cc:110
uint32_t FlowId
Abstract identifier of a packet flow.