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// SPDX-License-Identifier: GPL-2.0-only
5//
6// Author: Gustavo J. A. M. Carneiro <gjc@inescporto.pt> <gjcarneiro@gmail.com>
7//
8
10
11#include "ns3/packet.h"
12#include "ns3/tcp-header.h"
13#include "ns3/udp-header.h"
14
15#include <algorithm>
16
17namespace ns3
18{
19
20/* see http://www.iana.org/assignments/protocol-numbers */
21const uint8_t TCP_PROT_NUMBER = 6; //!< TCP Protocol number
22const uint8_t UDP_PROT_NUMBER = 17; //!< UDP Protocol number
23
24bool
26{
27 if (t1.sourceAddress < t2.sourceAddress)
28 {
29 return true;
30 }
31 if (t1.sourceAddress != t2.sourceAddress)
32 {
33 return false;
34 }
35
37 {
38 return true;
39 }
41 {
42 return false;
43 }
44
45 if (t1.protocol < t2.protocol)
46 {
47 return true;
48 }
49 if (t1.protocol != t2.protocol)
50 {
51 return false;
52 }
53
54 if (t1.sourcePort < t2.sourcePort)
55 {
56 return true;
57 }
58 if (t1.sourcePort != t2.sourcePort)
59 {
60 return false;
61 }
62
64 {
65 return true;
66 }
68 {
69 return false;
70 }
71
72 return false;
73}
74
75bool
82
86
87bool
89 Ptr<const Packet> ipPayload,
90 uint32_t* out_flowId,
91 uint32_t* out_packetId)
92{
93 if (ipHeader.GetFragmentOffset() > 0)
94 {
95 // Ignore fragments: they don't carry a valid L4 header
96 return false;
97 }
98
99 FiveTuple tuple;
100 tuple.sourceAddress = ipHeader.GetSource();
101 tuple.destinationAddress = ipHeader.GetDestination();
102 tuple.protocol = ipHeader.GetProtocol();
103
104 if ((tuple.protocol != UDP_PROT_NUMBER) && (tuple.protocol != TCP_PROT_NUMBER))
105 {
106 return false;
107 }
108
109 if (ipPayload->GetSize() < 4)
110 {
111 // the packet doesn't carry enough bytes
112 return false;
113 }
114
115 // we rely on the fact that for both TCP and UDP the ports are
116 // carried in the first 4 octets.
117 // This allows to read the ports even on fragmented packets
118 // not carrying a full TCP or UDP header.
119
120 uint8_t data[4];
121 ipPayload->CopyData(data, 4);
122
123 uint16_t srcPort = 0;
124 srcPort |= data[0];
125 srcPort <<= 8;
126 srcPort |= data[1];
127
128 uint16_t dstPort = 0;
129 dstPort |= data[2];
130 dstPort <<= 8;
131 dstPort |= data[3];
132
133 tuple.sourcePort = srcPort;
134 tuple.destinationPort = dstPort;
135
136 // try to insert the tuple, but check if it already exists
137 auto insert = m_flowMap.insert(std::pair<FiveTuple, FlowId>(tuple, 0));
138
139 // if the insertion succeeded, we need to assign this tuple a new flow identifier
140 if (insert.second)
141 {
142 FlowId newFlowId = GetNewFlowId();
143 insert.first->second = newFlowId;
144 m_flowPktIdMap[newFlowId] = 0;
145 m_flowDscpMap[newFlowId];
146 }
147 else
148 {
149 m_flowPktIdMap[insert.first->second]++;
150 }
151
152 // increment the counter of packets with the same DSCP value
153 Ipv4Header::DscpType dscp = ipHeader.GetDscp();
154 auto dscpInserter = m_flowDscpMap[insert.first->second].insert(
155 std::pair<Ipv4Header::DscpType, uint32_t>(dscp, 1));
156
157 // if the insertion did not succeed, we need to increment the counter
158 if (!dscpInserter.second)
159 {
160 m_flowDscpMap[insert.first->second][dscp]++;
161 }
162
163 *out_flowId = insert.first->second;
164 *out_packetId = m_flowPktIdMap[*out_flowId];
165
166 return true;
167}
168
171{
172 for (auto iter = m_flowMap.begin(); iter != m_flowMap.end(); iter++)
173 {
174 if (iter->second == flowId)
175 {
176 return iter->first;
177 }
178 }
179 NS_FATAL_ERROR("Could not find the flow with ID " << flowId);
180 FiveTuple retval = {Ipv4Address::GetZero(), Ipv4Address::GetZero(), 0, 0, 0};
181 return retval;
182}
183
184bool
185Ipv4FlowClassifier::SortByCount::operator()(std::pair<Ipv4Header::DscpType, uint32_t> left,
186 std::pair<Ipv4Header::DscpType, uint32_t> right)
187{
188 return left.second > right.second;
189}
190
191std::vector<std::pair<Ipv4Header::DscpType, uint32_t>>
193{
194 auto flow = m_flowDscpMap.find(flowId);
195
196 if (flow == m_flowDscpMap.end())
197 {
198 NS_FATAL_ERROR("Could not find the flow with ID " << flowId);
199 }
200
201 std::vector<std::pair<Ipv4Header::DscpType, uint32_t>> v(flow->second.begin(),
202 flow->second.end());
203 std::sort(v.begin(), v.end(), SortByCount());
204 return v;
205}
206
207void
208Ipv4FlowClassifier::SerializeToXmlStream(std::ostream& os, uint16_t indent) const
209{
210 Indent(os, indent);
211 os << "<Ipv4FlowClassifier>\n";
212
213 indent += 2;
214 for (auto iter = m_flowMap.begin(); iter != m_flowMap.end(); iter++)
215 {
216 Indent(os, indent);
217 os << "<Flow flowId=\"" << iter->second << "\""
218 << " sourceAddress=\"" << iter->first.sourceAddress << "\""
219 << " destinationAddress=\"" << iter->first.destinationAddress << "\""
220 << " protocol=\"" << int(iter->first.protocol) << "\""
221 << " sourcePort=\"" << iter->first.sourcePort << "\""
222 << " destinationPort=\"" << iter->first.destinationPort << "\">\n";
223
224 indent += 2;
225 auto flow = m_flowDscpMap.find(iter->second);
226
227 if (flow != m_flowDscpMap.end())
228 {
229 for (auto i = flow->second.begin(); i != flow->second.end(); i++)
230 {
231 Indent(os, indent);
232 os << "<Dscp value=\"0x" << std::hex << static_cast<uint32_t>(i->first) << "\""
233 << " packets=\"" << std::dec << i->second << "\" />\n";
234 }
235 }
236
237 indent -= 2;
238 Indent(os, indent);
239 os << "</Flow>\n";
240 }
241
242 indent -= 2;
243 Indent(os, indent);
244 os << "</Ipv4FlowClassifier>\n";
245}
246
247} // 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 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:23
Ipv4Address GetSource() const
uint8_t GetProtocol() const
Ipv4Address GetDestination() const
DscpType GetDscp() const
DscpType
DiffServ codepoints.
Definition ipv4-header.h:61
uint16_t GetFragmentOffset() const
Smart pointer class similar to boost::intrusive_ptr.
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
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:155
bool operator<(const EventId &a, const EventId &b)
Definition event-id.h:168
const uint8_t UDP_PROT_NUMBER
UDP Protocol number.
uint8_t data[writeSize]
Structure to classify a packet.
uint16_t destinationPort
Destination port.
Ipv4Address sourceAddress
Source address.
Ipv4Address destinationAddress
Destination address.