FrameAnalyzer.cc
Go to the documentation of this file.
1 //
2 // Copyright (c) 2020 Fraunhofer Institute for Applied Information Technology (FIT)
3 // Network Research Group (NET)
4 // Schloss Birlinghoven, 53754 Sankt Augustin, GERMANY
5 // Contact: support@wiback.org
6 //
7 // This file is part of the SENF code tree.
8 // It is licensed under the 3-clause BSD License (aka New BSD License).
9 // See LICENSE.txt in the top level directory for details or visit
10 // https://opensource.org/licenses/BSD-3-Clause
11 //
12 
13 
14 #include "FrameAnalyzer.hh"
15 
16 // Custom includes
19 #include "80211Analyzer.hh"
20 
21 #define prefix_
22 //-/////////////////////////////////////////////////////////////////////////////////////////////////
23 
25  : configuration_(configuration),
26  timer_("reportingTimer", senf::membind( &FrameAnalyzer::timerEvent, this)),
27  initWait_("maxWaitTimer", senf::membind( &FrameAnalyzer::initWaitEvent, this)),
28  startTime_(senf::ClockService::milliseconds(0)),
29  nextTimeout_(senf::ClockService::milliseconds(0)),
30  numPackets_(0),
31  mplsDetected_(false)
32 {
33  noroute(input);
34  input.onRequest( &FrameAnalyzer::request);
36  if (configuration.maxWait != senf::ClockService::milliseconds(0))
37  initWait_.timeout( senf::scheduler::now() + configuration.maxWait);
38 }
39 
40 prefix_ void FrameAnalyzer::timerEvent()
41 {
42  // get current time
44  // call report with current time and the actual interval duration
45  if (startTime_ > senf::ClockService::clock_type(0)) {
46  report(current - startTime_, configuration_.reportingInterval + (current - nextTimeout_));
47  }
48  // restart timer fixing any potential scheduling issues
49  nextTimeout_ += configuration_.reportingInterval;
50  timer_.timeout( nextTimeout_);
51 }
52 
53 prefix_ void FrameAnalyzer::initWaitEvent()
54 {
55  SENF_LOG((senf::log::IMPORTANT)("No packet received, terminating..."));
56  exitCode(1);
58 }
59 
61 {
62  SENF_LOG((senf::log::IMPORTANT)("Here we go..."));
63 
64  startTime_ = senf::ClockService::now();
65  nextTimeout_ = startTime_ + configuration_.reportingInterval;
66  timer_.timeout( nextTimeout_);
67  initWait_.disable();
68 }
69 
70 prefix_ void FrameAnalyzer::request()
71 {
73  // we've been started
74  if ((senf::scheduler::now() - startTime_) >= configuration_.duration) {
76  }
77  }
78 
79  // Look for the Annotation Packet. If we have one, we have receiving cooked 802.11 frames...
80  senf::EthernetPacket const & ethIn (input());
82  if (!ap) {
83  // If not, we receive plain data frames (Ethernet)
85  // let see, if we understand them
86  if (!handleDataFrame(ethIn, ap)) {
88  }
89  return;
90  }
91 
93 
94  if (ap->corrupt()) {
96  return;
97  }
98 
101  return;
102  }
103 
105  if (wlanm) {
106  flowStats(PacketStatistics::MNGT, 0)->analyze(ap, wlanm.size());
107  return;
108  }
109 
111  if (wlanc) {
112  flowStats(PacketStatistics::CTRL, 0)->analyze(ap, wlanc.size());
113  return;
114  }
115 
116  // nonQoSData WLAN frames
118  if (data) {
120  return;
121  }
122 
124  if (eth) {
125  if (handleDataFrame(eth, ap))
126  return;
127  }
128 
130 }
131 
133 
134 prefix_ bool FrameAnalyzer::handleDataFrame(senf::EthernetPacket const & eth, senf::AnnotationsPacket const & ap)
135 {
137 
138  senf::MPLSPacket const & mpls (eth.next<senf::MPLSPacket>(senf::nothrow));
139  if (mpls) {
140  senf::TIMPacket const & tim (mpls.next<senf::TIMPacket>(senf::nothrow));
141  if (tim) {
142  if (handleMPLSPacket(eth, ap, mpls, tim)) {
143  if (configuration_.numPackets > 0) {
144  if (++numPackets_ >= configuration_.numPackets) {
146  }
147  }
148  return true;
149  }
150  }
151  }
152 
153  senf::IPv4Packet const & ip4 (eth.next<senf::IPv4Packet>(senf::nothrow));
154  if (ip4) {
155  senf::UDPPacket const & udp (ip4.next<senf::UDPPacket>(senf::nothrow));
156  if (udp) {
157  if (handleUDPPacket( eth, ap, ip4, udp)) {
158  if (configuration_.numPackets > 0) {
159  if (++numPackets_ >= configuration_.numPackets) {
161  }
162  }
163  return true;
164  }
165  }
166  }
167 
168  return false;
169 }
170 
171 prefix_ bool FrameAnalyzer::handleMPLSPacket(senf::EthernetPacket const & eth, senf::AnnotationsPacket const & ap,
172  senf::MPLSPacket const& mpls, senf::TIMPacket const & tim)
173 {
174  mplsDetected_ = true;
175  return ((FlowStatisticsTIM*)flowStats(FlowStatistics::TIM, mpls->label()))->analyze(tim, ap);
176 }
177 
178 prefix_ bool FrameAnalyzer::handleUDPPacket(senf::EthernetPacket const & eth, senf::AnnotationsPacket const & ap,
179  senf::IPv4Packet const& ip4, senf::UDPPacket const & udp)
180 {
181  // check for matching source addr/port
182  if (((configuration_.source.address() != senf::INet4Address::None) && (configuration_.source.address() != ip4->destination().value())) ||
183  ((configuration_.source.port() != 0) && (configuration_.source.port() != udp->destination()))) {
184  return false;
185  }
186 
187  // check for matching destination addr/port
188  if (((configuration_.destination.address() != senf::INet4Address::None) && (configuration_.destination.address() != ip4->destination().value())) ||
189  ((configuration_.destination.port() != 0) && (configuration_.destination.port() != udp->destination()))) {
190  return false;
191  }
192 
193  if (configuration_.mgenMode) {
194  MGENPacket const & mgen (udp.parseNextAs<MGENPacket>());
195  if (mgen) {
196  return ((FlowStatisticsMGEN*)flowStats(FlowStatistics::MGEN, mgen->flowId()))->analyze(mgen, ap);
197  }
198  }
199  else if (configuration_.iperfMode) {
200  IperfUDPPacket const & iperf (udp.parseNextAs<IperfUDPPacket>());
201  if (iperf) {
202  return ((FlowStatisticsIPERF*)flowStats(FlowStatistics::IPERF, 0))->analyze(iperf, ap);
203  }
204  }
205 
206  return false;
207 }
208 
210 {
211  auto key (std::make_pair(type, flowId));
212 
213  auto it (packetStatsMap.find(key));
214  if (it != packetStatsMap.end()) {
215  return it->second;
216  }
217 
218  // first flow created (first frame seen)
219  if (packetStatsMap.empty()) {
220  resetStartTime();
221  }
222 
223  switch (type) {
230  packetStatsMap.insert(key, new PacketStatistics());
231  break;
233  packetStatsMap.insert(key, new FlowStatisticsIPERF());
234  break;
236  packetStatsMap.insert(key, new FlowStatisticsMGEN());
237  break;
239  packetStatsMap.insert(key, new FlowStatisticsTIM());
240  break;
241  }
242 
243  return packetStatsMap.find(key)->second;
244 }
245 
246 
248 {
249  for (auto const & ps : packetStatsMap) {
250  ps.second->clear();
251  }
252 }
253 
254 static std::string flowIdAsString(PacketStatistics::Type type, std::uint32_t flowId)
255 {
256  std::string label ("?!?UNKNOWN?!?");
257  switch (type) {
259  label = "RECEIVED " + senf::str(flowId);
260  break;
262  label = "CORRUPT " + senf::str(flowId);
263  break;
265  label = "DATA " + senf::str(flowId);
266  break;
268  label = "CTRL " + senf::str(flowId);
269  break;
271  label = "MNGT " + senf::str(flowId);
272  break;
274  label = "OTHER " + senf::str(flowId);
275  break;
277  label = "IPERF " + senf::str(flowId);
278  break;
280  label = "MGEN " + senf::str(flowId);
281  break;
282  case PacketStatistics::TIM:
283  label = "TIM " + senf::str(flowId);
284  break;
285  }
286 
287  label.resize(16, ' ');
288 
289  return label;
290 }
291 
292 prefix_ void FrameAnalyzer::report(senf::ClockService::clock_type const & timestamp, senf::ClockService::clock_type const & actualDuration)
293 {
294  for (auto const & ps : packetStatsMap) {
295  if (configuration_.csvMode) {
296  std::cout << flowIdAsString(ps.first.first, ps.first.second) << "," << senf::ClockService::in_milliseconds(timestamp);
297  ps.second->dump(std::cout, actualDuration, true);
298  } else {
299  std::cout << flowIdAsString(ps.first.first, ps.first.second) << " " << senf::ClockService::in_milliseconds(timestamp);
300  ps.second->dump(std::cout, actualDuration, false);
301  }
302  std::cout << std::endl;
303  }
304 
305  resetStats();
306 }
307 
308 //-/////////////////////////////////////////////////////////////////////////////////////////////////
309 #undef prefix_
senf::ClockService::clock_type duration
config::time_type clock_type
senf::INet4SocketAddress destination
senf::ClockService::clock_type maxWait
static SENF_CLOCKSERVICE_CONSTEXPR int64_type in_milliseconds(clock_type const &v)
PacketStatistics * flowStats(PacketStatistics::Type, std::uint32_t flowId)
u8 type
virtual void terminate() const
boost::function< R(Args)> membind(R(T::*fn)(Args), T *ob)
void exitCode(int code)
void noroute(connector::Connector &connector)
WLANPacket_DataFrameType::packet WLANPacket_DataFrame
WLANPacket_MgtFrameType::packet WLANPacket_MgtFrame
static INet4Address const None
static SENF_CLOCKSERVICE_CONSTEXPR clock_type milliseconds(int64_type const &v)
void timeout(ClockService::clock_type const &timeout, bool initiallyEnabled=true)
std::uint64_t numPackets
80211Analyzer public header
Packet next() const
senf::ClockService::clock_type reportingInterval
WLANPacket_CtrlFrameType::packet WLANPacket_CtrlFrame
Configuration const & configuration_
nothrow
#define prefix_
senf::INet4SocketAddress source
bool analyze(senf::AnnotationsPacket const &ap, std::uint16_t payloadSize)
WLANInterface public header.
WLANModulationParameter const & findModulationById(ModulationParameter::id_t id) const
static WLANModulationParameterRegistry & instance()
size_type size() const
static clock_type now()
senf::ppi::connector::PassiveInput< senf::EthernetPacket > input
FrameAnalyzer(Configuration const &configuration)
ConcretePacket< EthernetPacketType > EthernetPacket
unsigned port() const
#define SENF_LOG(args)
INet4Address address() const
void resetStartTime()
boost::ptr_map< std::pair< PacketStatistics::Type, std::uint32_t >, PacketStatistics > packetStatsMap
ConcretePacket< UDPPacketType > UDPPacket
void throttlingDisc(ThrottlingDisc const &disc)
ConcretePacket< IPv4PacketType > IPv4Packet