A Discrete-Event Network Simulator
API
epc-tft-classifier.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 CTTC
3  * Copyright (c) 2010 TELEMATICS LAB, DEE - Politecnico di Bari
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  * Authors:
19  * Nicola Baldo <nbaldo@cttc.es> (the EpcTftClassifier class)
20  * Giuseppe Piro <g.piro@poliba.it> (part of the code in EpcTftClassifier::Classify ()
21  * which comes from RrcEntity::Classify of the GSoC 2010 LTE module)
22  *
23  */
24 
25 #include "epc-tft-classifier.h"
26 
27 #include "epc-tft.h"
28 
29 #include "ns3/icmpv4-l4-protocol.h"
30 #include "ns3/icmpv6-l4-protocol.h"
31 #include "ns3/ipv4-header.h"
32 #include "ns3/ipv4-l3-protocol.h"
33 #include "ns3/ipv6-header.h"
34 #include "ns3/ipv6-l3-protocol.h"
35 #include "ns3/log.h"
36 #include "ns3/packet.h"
37 #include "ns3/tcp-header.h"
38 #include "ns3/tcp-l4-protocol.h"
39 #include "ns3/udp-header.h"
40 #include "ns3/udp-l4-protocol.h"
41 
42 namespace ns3
43 {
44 
45 NS_LOG_COMPONENT_DEFINE("EpcTftClassifier");
46 
48 {
49  NS_LOG_FUNCTION(this);
50 }
51 
52 void
54 {
55  NS_LOG_FUNCTION(this << tft << id);
56  m_tftMap[id] = tft;
57 
58  // simple sanity check: there shouldn't be more than 16 bearers (hence TFTs) per UE
59  NS_ASSERT(m_tftMap.size() <= 16);
60 }
61 
62 void
64 {
65  NS_LOG_FUNCTION(this << id);
66  m_tftMap.erase(id);
67 }
68 
69 uint32_t
70 EpcTftClassifier::Classify(Ptr<Packet> p, EpcTft::Direction direction, uint16_t protocolNumber)
71 {
72  NS_LOG_FUNCTION(this << p << p->GetSize() << direction);
73 
74  Ptr<Packet> pCopy = p->Copy();
75 
76  Ipv4Address localAddressIpv4;
77  Ipv4Address remoteAddressIpv4;
78 
79  Ipv6Address localAddressIpv6;
80  Ipv6Address remoteAddressIpv6;
81 
82  uint8_t protocol;
83  uint8_t tos;
84 
85  uint16_t localPort = 0;
86  uint16_t remotePort = 0;
87 
88  if (protocolNumber == Ipv4L3Protocol::PROT_NUMBER)
89  {
90  Ipv4Header ipv4Header;
91  pCopy->RemoveHeader(ipv4Header);
92 
93  if (direction == EpcTft::UPLINK)
94  {
95  localAddressIpv4 = ipv4Header.GetSource();
96  remoteAddressIpv4 = ipv4Header.GetDestination();
97  }
98  else
99  {
100  NS_ASSERT(direction == EpcTft::DOWNLINK);
101  remoteAddressIpv4 = ipv4Header.GetSource();
102  localAddressIpv4 = ipv4Header.GetDestination();
103  }
104  NS_LOG_INFO("local address: " << localAddressIpv4
105  << " remote address: " << remoteAddressIpv4);
106 
107  uint16_t payloadSize = ipv4Header.GetPayloadSize();
108  uint16_t fragmentOffset = ipv4Header.GetFragmentOffset();
109  bool isLastFragment = ipv4Header.IsLastFragment();
110 
111  // NS_LOG_DEBUG ("PayloadSize = " << payloadSize);
112  // NS_LOG_DEBUG ("fragmentOffset " << fragmentOffset << " isLastFragment " <<
113  // isLastFragment);
114 
115  protocol = ipv4Header.GetProtocol();
116  tos = ipv4Header.GetTos();
117 
118  // Port info only can be get if it is the first fragment and
119  // there is enough data in the payload
120  // We keep the port info for fragmented packets,
121  // i.e. it is the first one but it is not the last one
122  if (fragmentOffset == 0)
123  {
124  if (protocol == UdpL4Protocol::PROT_NUMBER && payloadSize >= 8)
125  {
126  UdpHeader udpHeader;
127  pCopy->RemoveHeader(udpHeader);
128  if (direction == EpcTft::UPLINK)
129  {
130  localPort = udpHeader.GetSourcePort();
131  remotePort = udpHeader.GetDestinationPort();
132  }
133  else
134  {
135  remotePort = udpHeader.GetSourcePort();
136  localPort = udpHeader.GetDestinationPort();
137  }
138  if (!isLastFragment)
139  {
140  std::tuple<uint32_t, uint32_t, uint8_t, uint16_t> fragmentKey =
141  std::make_tuple(ipv4Header.GetSource().Get(),
142  ipv4Header.GetDestination().Get(),
143  protocol,
144  ipv4Header.GetIdentification());
145 
146  m_classifiedIpv4Fragments[fragmentKey] = std::make_pair(localPort, remotePort);
147  }
148  }
149  else if (protocol == TcpL4Protocol::PROT_NUMBER && payloadSize >= 20)
150  {
151  TcpHeader tcpHeader;
152  pCopy->RemoveHeader(tcpHeader);
153  if (direction == EpcTft::UPLINK)
154  {
155  localPort = tcpHeader.GetSourcePort();
156  remotePort = tcpHeader.GetDestinationPort();
157  }
158  else
159  {
160  remotePort = tcpHeader.GetSourcePort();
161  localPort = tcpHeader.GetDestinationPort();
162  }
163 
164  if (!isLastFragment)
165  {
166  std::tuple<uint32_t, uint32_t, uint8_t, uint16_t> fragmentKey =
167  std::make_tuple(ipv4Header.GetSource().Get(),
168  ipv4Header.GetDestination().Get(),
169  protocol,
170  ipv4Header.GetIdentification());
171 
172  m_classifiedIpv4Fragments[fragmentKey] = std::make_pair(localPort, remotePort);
173  }
174  }
175 
176  // else
177  // First fragment but not enough data for port info or not UDP/TCP protocol.
178  // Nothing can be done, i.e. we cannot get port info from packet.
179  }
180  else
181  {
182  // Not first fragment, so port info is not available but
183  // port info should already be known (if there is not fragment reordering)
184  std::tuple<uint32_t, uint32_t, uint8_t, uint16_t> fragmentKey =
185  std::make_tuple(ipv4Header.GetSource().Get(),
186  ipv4Header.GetDestination().Get(),
187  protocol,
188  ipv4Header.GetIdentification());
189 
190  auto it = m_classifiedIpv4Fragments.find(fragmentKey);
191 
192  if (it != m_classifiedIpv4Fragments.end())
193  {
194  localPort = it->second.first;
195  remotePort = it->second.second;
196 
197  if (isLastFragment)
198  {
199  m_classifiedIpv4Fragments.erase(fragmentKey);
200  }
201  }
202  }
203  }
204  else if (protocolNumber == Ipv6L3Protocol::PROT_NUMBER)
205  {
206  Ipv6Header ipv6Header;
207  pCopy->RemoveHeader(ipv6Header);
208 
209  if (direction == EpcTft::UPLINK)
210  {
211  localAddressIpv6 = ipv6Header.GetSource();
212  remoteAddressIpv6 = ipv6Header.GetDestination();
213  }
214  else
215  {
216  NS_ASSERT(direction == EpcTft::DOWNLINK);
217  remoteAddressIpv6 = ipv6Header.GetSource();
218  localAddressIpv6 = ipv6Header.GetDestination();
219  }
220  NS_LOG_INFO("local address: " << localAddressIpv6
221  << " remote address: " << remoteAddressIpv6);
222 
223  protocol = ipv6Header.GetNextHeader();
224  tos = ipv6Header.GetTrafficClass();
225 
226  if (protocol == UdpL4Protocol::PROT_NUMBER)
227  {
228  UdpHeader udpHeader;
229  pCopy->RemoveHeader(udpHeader);
230 
231  if (direction == EpcTft::UPLINK)
232  {
233  localPort = udpHeader.GetSourcePort();
234  remotePort = udpHeader.GetDestinationPort();
235  }
236  else
237  {
238  remotePort = udpHeader.GetSourcePort();
239  localPort = udpHeader.GetDestinationPort();
240  }
241  }
242  else if (protocol == TcpL4Protocol::PROT_NUMBER)
243  {
244  TcpHeader tcpHeader;
245  pCopy->RemoveHeader(tcpHeader);
246  if (direction == EpcTft::UPLINK)
247  {
248  localPort = tcpHeader.GetSourcePort();
249  remotePort = tcpHeader.GetDestinationPort();
250  }
251  else
252  {
253  remotePort = tcpHeader.GetSourcePort();
254  localPort = tcpHeader.GetDestinationPort();
255  }
256  }
257  }
258  else
259  {
260  NS_ABORT_MSG("EpcTftClassifier::Classify - Unknown IP type...");
261  }
262 
263  if (protocolNumber == Ipv4L3Protocol::PROT_NUMBER)
264  {
265  NS_LOG_INFO("Classifying packet:"
266  << " localAddr=" << localAddressIpv4 << " remoteAddr=" << remoteAddressIpv4
267  << " localPort=" << localPort << " remotePort=" << remotePort << " tos=0x"
268  << (uint16_t)tos);
269 
270  // now it is possible to classify the packet!
271  // we use a reverse iterator since filter priority is not implemented properly.
272  // This way, since the default bearer is expected to be added first, it will be evaluated
273  // last.
274  std::map<uint32_t, Ptr<EpcTft>>::const_reverse_iterator it;
275  NS_LOG_LOGIC("TFT MAP size: " << m_tftMap.size());
276 
277  for (it = m_tftMap.rbegin(); it != m_tftMap.rend(); ++it)
278  {
279  NS_LOG_LOGIC("TFT id: " << it->first);
280  NS_LOG_LOGIC(" Ptr<EpcTft>: " << it->second);
281  Ptr<EpcTft> tft = it->second;
282  if (tft->Matches(direction,
283  remoteAddressIpv4,
284  localAddressIpv4,
285  remotePort,
286  localPort,
287  tos))
288  {
289  NS_LOG_LOGIC("matches with TFT ID = " << it->first);
290  return it->first; // the id of the matching TFT
291  }
292  }
293  }
294  else if (protocolNumber == Ipv6L3Protocol::PROT_NUMBER)
295  {
296  NS_LOG_INFO("Classifying packet:"
297  << " localAddr=" << localAddressIpv6 << " remoteAddr=" << remoteAddressIpv6
298  << " localPort=" << localPort << " remotePort=" << remotePort << " tos=0x"
299  << (uint16_t)tos);
300 
301  // now it is possible to classify the packet!
302  // we use a reverse iterator since filter priority is not implemented properly.
303  // This way, since the default bearer is expected to be added first, it will be evaluated
304  // last.
305  std::map<uint32_t, Ptr<EpcTft>>::const_reverse_iterator it;
306  NS_LOG_LOGIC("TFT MAP size: " << m_tftMap.size());
307 
308  for (it = m_tftMap.rbegin(); it != m_tftMap.rend(); ++it)
309  {
310  NS_LOG_LOGIC("TFT id: " << it->first);
311  NS_LOG_LOGIC(" Ptr<EpcTft>: " << it->second);
312  Ptr<EpcTft> tft = it->second;
313  if (tft->Matches(direction,
314  remoteAddressIpv6,
315  localAddressIpv6,
316  remotePort,
317  localPort,
318  tos))
319  {
320  NS_LOG_LOGIC("matches with TFT ID = " << it->first);
321  return it->first; // the id of the matching TFT
322  }
323  }
324  }
325  NS_LOG_LOGIC("no match");
326  return 0; // no match
327 }
328 
329 } // namespace ns3
std::map< std::tuple< uint32_t, uint32_t, uint8_t, uint16_t >, std::pair< uint32_t, uint32_t > > m_classifiedIpv4Fragments
Map with already classified IPv4 Fragments An entry is added when the port info is available,...
uint32_t Classify(Ptr< Packet > p, EpcTft::Direction direction, uint16_t protocolNumber)
classify an IP packet
void Add(Ptr< EpcTft > tft, uint32_t id)
add a TFT to the Classifier
std::map< uint32_t, Ptr< EpcTft > > m_tftMap
TFT map.
void Delete(uint32_t id)
delete an existing TFT from the classifier
Direction
Indicates the direction of the traffic that is to be classified.
Definition: epc-tft.h:51
@ DOWNLINK
Definition: epc-tft.h:52
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:42
uint32_t Get() const
Get the host-order 32-bit IP address.
Packet header for IPv4.
Definition: ipv4-header.h:34
Ipv4Address GetSource() const
Definition: ipv4-header.cc:302
uint8_t GetTos() const
Definition: ipv4-header.cc:196
uint16_t GetIdentification() const
Definition: ipv4-header.cc:71
uint8_t GetProtocol() const
Definition: ipv4-header.cc:281
bool IsLastFragment() const
Definition: ipv4-header.cc:217
Ipv4Address GetDestination() const
Definition: ipv4-header.cc:316
uint16_t GetPayloadSize() const
Definition: ipv4-header.cc:64
uint16_t GetFragmentOffset() const
Definition: ipv4-header.cc:254
static const uint16_t PROT_NUMBER
Protocol number (0x0800)
Describes an IPv6 address.
Definition: ipv6-address.h:49
Packet header for IPv6.
Definition: ipv6-header.h:35
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
uint8_t GetTrafficClass() const
Get the "Traffic class" field.
Definition: ipv6-header.cc:52
Ipv6Address GetSource() const
Get the "Source address" field.
Definition: ipv6-header.cc:112
static const uint16_t PROT_NUMBER
The protocol number for IPv6 (0x86DD).
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:294
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:861
Ptr< Packet > Copy() const
performs a COW copy of the packet.
Definition: packet.cc:131
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
Header for the Transmission Control Protocol.
Definition: tcp-header.h:47
uint16_t GetDestinationPort() const
Get the destination port.
Definition: tcp-header.cc:112
uint16_t GetSourcePort() const
Get the source port.
Definition: tcp-header.cc:106
static const uint8_t PROT_NUMBER
protocol number (0x6)
Packet header for UDP packets.
Definition: udp-header.h:41
uint16_t GetDestinationPort() const
Definition: udp-header.cc:54
uint16_t GetSourcePort() const
Definition: udp-header.cc:48
static const uint8_t PROT_NUMBER
protocol number (0x11)
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
Every class exported by the ns3 library is enclosed in the ns3 namespace.