A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
ipv4-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//
19
21
22#include "ns3/packet.h"
23#include "ns3/tcp-header.h"
24#include "ns3/udp-header.h"
25
26#include <algorithm>
27
28namespace ns3
29{
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
35bool
37{
38 if (t1.sourceAddress < t2.sourceAddress)
39 {
40 return true;
41 }
42 if (t1.sourceAddress != t2.sourceAddress)
43 {
44 return false;
45 }
46
48 {
49 return true;
50 }
52 {
53 return false;
54 }
55
56 if (t1.protocol < t2.protocol)
57 {
58 return true;
59 }
60 if (t1.protocol != t2.protocol)
61 {
62 return false;
63 }
64
65 if (t1.sourcePort < t2.sourcePort)
66 {
67 return true;
68 }
69 if (t1.sourcePort != t2.sourcePort)
70 {
71 return false;
72 }
73
75 {
76 return true;
77 }
79 {
80 return false;
81 }
82
83 return false;
84}
85
86bool
88{
89 return (t1.sourceAddress == t2.sourceAddress &&
92}
93
95{
96}
97
98bool
100 Ptr<const Packet> ipPayload,
101 uint32_t* out_flowId,
102 uint32_t* out_packetId)
103{
104 if (ipHeader.GetFragmentOffset() > 0)
105 {
106 // Ignore fragments: they don't carry a valid L4 header
107 return false;
108 }
109
110 FiveTuple tuple;
111 tuple.sourceAddress = ipHeader.GetSource();
112 tuple.destinationAddress = ipHeader.GetDestination();
113 tuple.protocol = ipHeader.GetProtocol();
114
115 if ((tuple.protocol != UDP_PROT_NUMBER) && (tuple.protocol != TCP_PROT_NUMBER))
116 {
117 return false;
118 }
119
120 if (ipPayload->GetSize() < 4)
121 {
122 // the packet doesn't carry enough bytes
123 return false;
124 }
125
126 // we rely on the fact that for both TCP and UDP the ports are
127 // carried in the first 4 octets.
128 // This allows to read the ports even on fragmented packets
129 // not carrying a full TCP or UDP header.
130
131 uint8_t data[4];
132 ipPayload->CopyData(data, 4);
133
134 uint16_t srcPort = 0;
135 srcPort |= data[0];
136 srcPort <<= 8;
137 srcPort |= data[1];
138
139 uint16_t dstPort = 0;
140 dstPort |= data[2];
141 dstPort <<= 8;
142 dstPort |= data[3];
143
144 tuple.sourcePort = srcPort;
145 tuple.destinationPort = dstPort;
146
147 // try to insert the tuple, but check if it already exists
148 std::pair<std::map<FiveTuple, FlowId>::iterator, bool> insert =
149 m_flowMap.insert(std::pair<FiveTuple, FlowId>(tuple, 0));
150
151 // if the insertion succeeded, we need to assign this tuple a new flow identifier
152 if (insert.second)
153 {
154 FlowId newFlowId = GetNewFlowId();
155 insert.first->second = newFlowId;
156 m_flowPktIdMap[newFlowId] = 0;
157 m_flowDscpMap[newFlowId];
158 }
159 else
160 {
161 m_flowPktIdMap[insert.first->second]++;
162 }
163
164 // increment the counter of packets with the same DSCP value
165 Ipv4Header::DscpType dscp = ipHeader.GetDscp();
166 std::pair<std::map<Ipv4Header::DscpType, uint32_t>::iterator, bool> dscpInserter =
167 m_flowDscpMap[insert.first->second].insert(
168 std::pair<Ipv4Header::DscpType, uint32_t>(dscp, 1));
169
170 // if the insertion did not succeed, we need to increment the counter
171 if (!dscpInserter.second)
172 {
173 m_flowDscpMap[insert.first->second][dscp]++;
174 }
175
176 *out_flowId = insert.first->second;
177 *out_packetId = m_flowPktIdMap[*out_flowId];
178
179 return true;
180}
181
184{
185 for (std::map<FiveTuple, FlowId>::const_iterator iter = m_flowMap.begin();
186 iter != m_flowMap.end();
187 iter++)
188 {
189 if (iter->second == flowId)
190 {
191 return iter->first;
192 }
193 }
194 NS_FATAL_ERROR("Could not find the flow with ID " << flowId);
195 FiveTuple retval = {Ipv4Address::GetZero(), Ipv4Address::GetZero(), 0, 0, 0};
196 return retval;
197}
198
199bool
200Ipv4FlowClassifier::SortByCount::operator()(std::pair<Ipv4Header::DscpType, uint32_t> left,
201 std::pair<Ipv4Header::DscpType, uint32_t> right)
202{
203 return left.second > right.second;
204}
205
206std::vector<std::pair<Ipv4Header::DscpType, uint32_t>>
208{
209 std::map<FlowId, std::map<Ipv4Header::DscpType, uint32_t>>::const_iterator flow =
210 m_flowDscpMap.find(flowId);
211
212 if (flow == m_flowDscpMap.end())
213 {
214 NS_FATAL_ERROR("Could not find the flow with ID " << flowId);
215 }
216
217 std::vector<std::pair<Ipv4Header::DscpType, uint32_t>> v(flow->second.begin(),
218 flow->second.end());
219 std::sort(v.begin(), v.end(), SortByCount());
220 return v;
221}
222
223void
224Ipv4FlowClassifier::SerializeToXmlStream(std::ostream& os, uint16_t indent) const
225{
226 Indent(os, indent);
227 os << "<Ipv4FlowClassifier>\n";
228
229 indent += 2;
230 for (std::map<FiveTuple, FlowId>::const_iterator iter = m_flowMap.begin();
231 iter != m_flowMap.end();
232 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<Ipv4Header::DscpType, uint32_t>>::const_iterator flow =
244 m_flowDscpMap.find(iter->second);
245
246 if (flow != m_flowDscpMap.end())
247 {
248 for (std::map<Ipv4Header::DscpType, uint32_t>::const_iterator i = flow->second.begin();
249 i != flow->second.end();
250 i++)
251 {
252 Indent(os, indent);
253 os << "<Dscp value=\"0x" << std::hex << static_cast<uint32_t>(i->first) << "\""
254 << " packets=\"" << std::dec << i->second << "\" />\n";
255 }
256 }
257
258 indent -= 2;
259 Indent(os, indent);
260 os << "</Flow>\n";
261 }
262
263 indent -= 2;
264 Indent(os, indent);
265 os << "</Ipv4FlowClassifier>\n";
266}
267
268} // namespace ns3
FlowId GetNewFlowId()
Returns a new, unique Flow Identifier.
static Ipv4Address GetZero()
Comparator used to sort the vector of DSCP values.
bool operator()(std::pair< Ipv4Header::DscpType, uint32_t > left, std::pair< Ipv4Header::DscpType, uint32_t > right)
Comparator function.
std::map< FlowId, FlowPacketId > m_flowPktIdMap
Map to FlowIds to FlowPacketId.
void SerializeToXmlStream(std::ostream &os, uint16_t indent) const override
Serializes the results to an std::ostream in XML format.
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 ...
FiveTuple FindFlow(FlowId flowId) const
Searches for the FiveTuple corresponding to the given flowId.
std::map< FlowId, std::map< Ipv4Header::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 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
Packet header for IPv4.
Definition: ipv4-header.h:34
Ipv4Address GetSource() const
Definition: ipv4-header.cc:302
uint8_t GetProtocol() const
Definition: ipv4-header.cc:281
Ipv4Address GetDestination() const
Definition: ipv4-header.cc:316
DscpType GetDscp() const
Definition: ipv4-header.cc:108
DscpType
DiffServ codepoints.
Definition: ipv4-header.h:72
uint16_t GetFragmentOffset() const
Definition: ipv4-header.cc:254
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
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]
Helper to indent output a specified number of steps.
Definition: test.cc:648
Structure to classify a packet.
uint16_t destinationPort
Destination port.
Ipv4Address sourceAddress
Source address.
Ipv4Address destinationAddress
Destination address.