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
25#include "ns3/udp-header.h"
26#include "ns3/tcp-header.h"
27#include <algorithm>
28
29namespace ns3 {
30
31/* see http://www.iana.org/assignments/protocol-numbers */
32const uint8_t TCP_PROT_NUMBER = 6;
33const 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
77 {
78 return true;
79 }
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
104bool
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
202bool
203Ipv6FlowClassifier::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
209std::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
225void
226Ipv6FlowClassifier::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
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.