A Discrete-Event Network Simulator
API
ipv6-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 // Modifications: Tommaso Pecorella <tommaso.pecorella@unifi.it>
19 //
20 
21 #include "ipv6-flow-classifier.h"
22 
23 #include "ns3/packet.h"
24 #include "ns3/tcp-header.h"
25 #include "ns3/udp-header.h"
26 
27 #include <algorithm>
28 
29 namespace ns3
30 {
31 
32 /* see http://www.iana.org/assignments/protocol-numbers */
33 const uint8_t TCP_PROT_NUMBER = 6;
34 const uint8_t UDP_PROT_NUMBER = 17;
35 
36 bool
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 
87 bool
89 {
90  return (t1.sourceAddress == t2.sourceAddress &&
93 }
94 
96 {
97 }
98 
99 bool
101  Ptr<const Packet> ipPayload,
102  uint32_t* out_flowId,
103  uint32_t* out_packetId)
104 {
105  if (ipHeader.GetDestination().IsMulticast())
106  {
107  // we are not prepared to handle multicast yet
108  return false;
109  }
110 
111  FiveTuple tuple;
112  tuple.sourceAddress = ipHeader.GetSource();
113  tuple.destinationAddress = ipHeader.GetDestination();
114  tuple.protocol = ipHeader.GetNextHeader();
115 
116  if ((tuple.protocol != UDP_PROT_NUMBER) && (tuple.protocol != TCP_PROT_NUMBER))
117  {
118  return false;
119  }
120 
121  if (ipPayload->GetSize() < 4)
122  {
123  // the packet doesn't carry enough bytes
124  return false;
125  }
126 
127  // we rely on the fact that for both TCP and UDP the ports are
128  // carried in the first 4 octets.
129  // This allows to read the ports even on fragmented packets
130  // not carrying a full TCP or UDP header.
131 
132  uint8_t data[4];
133  ipPayload->CopyData(data, 4);
134 
135  uint16_t srcPort = 0;
136  srcPort |= data[0];
137  srcPort <<= 8;
138  srcPort |= data[1];
139 
140  uint16_t dstPort = 0;
141  dstPort |= data[2];
142  dstPort <<= 8;
143  dstPort |= data[3];
144 
145  tuple.sourcePort = srcPort;
146  tuple.destinationPort = dstPort;
147 
148  // try to insert the tuple, but check if it already exists
149  std::pair<std::map<FiveTuple, FlowId>::iterator, bool> insert =
150  m_flowMap.insert(std::pair<FiveTuple, FlowId>(tuple, 0));
151 
152  // if the insertion succeeded, we need to assign this tuple a new flow identifier
153  if (insert.second)
154  {
155  FlowId newFlowId = GetNewFlowId();
156  insert.first->second = newFlowId;
157  m_flowPktIdMap[newFlowId] = 0;
158  m_flowDscpMap[newFlowId];
159  }
160  else
161  {
162  m_flowPktIdMap[insert.first->second]++;
163  }
164 
165  // increment the counter of packets with the same DSCP value
166  Ipv6Header::DscpType dscp = ipHeader.GetDscp();
167  std::pair<std::map<Ipv6Header::DscpType, uint32_t>::iterator, bool> dscpInserter =
168  m_flowDscpMap[insert.first->second].insert(
169  std::pair<Ipv6Header::DscpType, uint32_t>(dscp, 1));
170 
171  // if the insertion did not succeed, we need to increment the counter
172  if (!dscpInserter.second)
173  {
174  m_flowDscpMap[insert.first->second][dscp]++;
175  }
176 
177  *out_flowId = insert.first->second;
178  *out_packetId = m_flowPktIdMap[*out_flowId];
179 
180  return true;
181 }
182 
185 {
186  for (std::map<FiveTuple, FlowId>::const_iterator iter = m_flowMap.begin();
187  iter != m_flowMap.end();
188  iter++)
189  {
190  if (iter->second == flowId)
191  {
192  return iter->first;
193  }
194  }
195  NS_FATAL_ERROR("Could not find the flow with ID " << flowId);
196  FiveTuple retval = {Ipv6Address::GetZero(), Ipv6Address::GetZero(), 0, 0, 0};
197  return retval;
198 }
199 
200 bool
201 Ipv6FlowClassifier::SortByCount::operator()(std::pair<Ipv6Header::DscpType, uint32_t> left,
202  std::pair<Ipv6Header::DscpType, uint32_t> right)
203 {
204  return left.second > right.second;
205 }
206 
207 std::vector<std::pair<Ipv6Header::DscpType, uint32_t>>
209 {
210  std::map<FlowId, std::map<Ipv6Header::DscpType, uint32_t>>::const_iterator flow =
211  m_flowDscpMap.find(flowId);
212 
213  if (flow == m_flowDscpMap.end())
214  {
215  NS_FATAL_ERROR("Could not find the flow with ID " << flowId);
216  }
217 
218  std::vector<std::pair<Ipv6Header::DscpType, uint32_t>> v(flow->second.begin(),
219  flow->second.end());
220  std::sort(v.begin(), v.end(), SortByCount());
221  return v;
222 }
223 
224 void
225 Ipv6FlowClassifier::SerializeToXmlStream(std::ostream& os, uint16_t indent) const
226 {
227  Indent(os, indent);
228  os << "<Ipv6FlowClassifier>\n";
229 
230  indent += 2;
231  for (std::map<FiveTuple, FlowId>::const_iterator iter = m_flowMap.begin();
232  iter != m_flowMap.end();
233  iter++)
234  {
235  Indent(os, indent);
236  os << "<Flow flowId=\"" << iter->second << "\""
237  << " sourceAddress=\"" << iter->first.sourceAddress << "\""
238  << " destinationAddress=\"" << iter->first.destinationAddress << "\""
239  << " protocol=\"" << int(iter->first.protocol) << "\""
240  << " sourcePort=\"" << iter->first.sourcePort << "\""
241  << " destinationPort=\"" << iter->first.destinationPort << "\">\n";
242 
243  indent += 2;
244  std::map<FlowId, std::map<Ipv6Header::DscpType, uint32_t>>::const_iterator flow =
245  m_flowDscpMap.find(iter->second);
246 
247  if (flow != m_flowDscpMap.end())
248  {
249  for (std::map<Ipv6Header::DscpType, uint32_t>::const_iterator i = flow->second.begin();
250  i != flow->second.end();
251  i++)
252  {
253  Indent(os, indent);
254  os << "<Dscp value=\"0x" << std::hex << static_cast<uint32_t>(i->first) << "\""
255  << " packets=\"" << std::dec << i->second << "\" />\n";
256  }
257  }
258 
259  indent -= 2;
260  Indent(os, indent);
261  os << "</Flow>\n";
262  }
263 
264  indent -= 2;
265  Indent(os, indent);
266  os << "</Ipv6FlowClassifier>\n";
267 }
268 
269 } // 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 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.
void SerializeToXmlStream(std::ostream &os, uint16_t indent) const override
Serializes the results to an std::ostream in XML format.
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.
Packet header for IPv6.
Definition: ipv6-header.h:36
DscpType GetDscp() const
Definition: ipv6-header.cc:223
uint8_t GetNextHeader() const
Get the next header.
Definition: ipv6-header.cc:88
Ipv6Address GetDestination() const
Get the "Destination address" field.
Definition: ipv6-header.cc:124
Ipv6Address GetSource() const
Get the "Source address" field.
Definition: ipv6-header.cc:112
DscpType
DiffServ Code Points Code Points defined in Assured Forwarding (AF) RFC 2597 Expedited Forwarding (EF...
Definition: ipv6-header.h:47
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.
Ipv6Address destinationAddress
Destination address.
Ipv6Address sourceAddress
Source address.