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