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.GetDestination ().IsMulticast ())
109  {
110  // we are not prepared to handle multicast yet
111  return false;
112  }
113 
114  FiveTuple tuple;
115  tuple.sourceAddress = ipHeader.GetSource ();
116  tuple.destinationAddress = ipHeader.GetDestination ();
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 
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 Ipv6Address GetZero()
Get the 0 (::) Ipv6Address.
bool IsMulticast() const
If the IPv6 address is multicast (ff00::/8).
Comparator used to sort the vector of DSCP values.
bool operator()(std::pair< Ipv6Header::DscpType, uint32_t > left, std::pair< Ipv6Header::DscpType, uint32_t > right)
Comparator function.
std::map< FiveTuple, FlowId > m_flowMap
Map to Flows Identifiers to FlowIds.
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 ...
FiveTuple FindFlow(FlowId flowId) const
Searches for the FiveTuple corresponding to the given flowId.
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
std::map< FlowId, FlowPacketId > m_flowPktIdMap
Map to FlowIds to FlowPacketId.
std::map< FlowId, std::map< Ipv6Header::DscpType, uint32_t > > m_flowDscpMap
Map FlowIds to (DSCP value, packet count) pairs.
virtual void SerializeToXmlStream(std::ostream &os, uint16_t indent) const
Serializes the results to an std::ostream in XML format.
Packet header for IPv6.
Definition: ipv6-header.h:36
Ipv6Address GetSource(void) const
Get the "Source address" field.
Definition: ipv6-header.cc:105
DscpType GetDscp(void) const
Definition: ipv6-header.cc:222
uint8_t GetNextHeader(void) const
Get the next header.
Definition: ipv6-header.cc:80
Ipv6Address GetDestination(void) const
Get the "Destination address" field.
Definition: ipv6-header.cc:125
DscpType
DiffServ Code Points Code Points defined in Assured Forwarding (AF) RFC 2597 Expedited Forwarding (EF...
Definition: ipv6-header.h:47
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.
Ipv6Address destinationAddress
Destination address.
Ipv6Address sourceAddress
Source address.