main.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 
17 //#include "main.hh"
18 //#include "main.ih"
19 
20 // Custom includes
21 #include <boost/lexical_cast.hpp>
22 #include <iostream>
23 #include <senf/PPI.hh>
34 #include <senf/Utils/Logger.hh>
35 #include <senf/Utils/Console.hh>
36 
37 //#include "main.mpp"
38 #define prefix_
39 
41 namespace module = senf::ppi::module;
43 namespace ppi = senf::ppi;
44 namespace emu = senf::emu;
45 
46 namespace {
47 
48  struct WMMParameter
49  {
50  std::uint8_t accessCategory;
51  std::uint16_t cwMin;
52  std::uint16_t cwMax;
53  std::uint8_t aifs;
54  std::uint16_t txOp;
55  };
56 
57  // TODO (2014-01-13 mtk): TxOp timings are considered in .11n mode in 3.13 (and hopefully above :)
58  static WMMParameter defaultHtWMM[] = {
59  // NC
60  { NL80211_TXQ_Q_VO, 3, 7, 0, 0 },
61  // VO
62  { NL80211_TXQ_Q_VI, 3, 7, 2, 10 },
63  // VI
64  { NL80211_TXQ_Q_BE, 7, 15, 3, 20 },
65  // BE
66  { NL80211_TXQ_Q_BK, 7, 15, 5, 40 },
67  };
68 
69  class ReceiveGroup : public module::Module
70  {
71  SENF_PPI_MODULE(ReceiveGroup);
72  public:
75  senf::MACAddress id_;
76 
77  ReceiveGroup(senf::emu::Interface const & interface) {
78  route( input, output); //autoThrottling( false);
79  // input.throttlingDisc( senf::ppi::ThrottlingDiscipline::NONE);
80  input.onRequest( &ReceiveGroup::request);
81 
82  id_ = interface.id();
83  }
84 
85  void request() {
86  senf::EthernetPacket const & eth (input());
87  senf::MACAddress dst (eth->destination());
88 
89  if (dst != id_ || dst.multicast()) {
90  if (! eth.annotation<senf::emu::annotations::Quality>().flags.frameDuplicate) {
91  output(eth);
92  }
93  }
94  }
95  };
96 
97  class TransmitGroup : public module::Module
98  {
99  SENF_PPI_MODULE(TransmitGroup);
100  public:
103 
104  TransmitGroup(senf::emu::Interface const & interface) {
105  route( input, output); // autoThrottling( false);
106  // input.throttlingDisc( senf::ppi::ThrottlingDiscipline::NONE);
107  input.onRequest( &TransmitGroup::request);
108  }
109 
110  void request() {
111  senf::Packet const & pkt (input());
112 
113  output(pkt);
114  }
115  };
116 
118 
119 
120  class Forwarder : public module::Module
121  {
122  SENF_PPI_MODULE(Forwarder);
123  public:
126 
127  Forwarder(senf::MACAddress const & src, senf::MACAddress const & dst)
128  : first_ (true), src_ (src), dst_ (dst), packetCount_(0), packetIgnored_(0), ttlMin_(255), ttlMax_(0)
129  {
130  route(input, output);
131  input.onRequest(&Forwarder::request);
132  }
133 
134  unsigned packetCount()
135  {
136  unsigned res (packetCount_);
137  packetCount_ = 0;
138  return res;
139  }
140 
141  unsigned packetIgnored()
142  {
143  unsigned res (packetIgnored_);
144  packetIgnored_ = 0;
145  return res;
146  }
147 
148  private:
149  void request()
150  {
151  if (first_) {
152  std::cerr << "first packet: " << ((void*) this) << std::endl;
153  first_ = false;
154  }
155 
156  senf::EthernetPacket const & eth (input());
157  std::uint8_t ttl (0);
158 
159  // look into the next header and do something
160  senf::IPv4Packet const & ipv4 (eth.next<senf::IPv4Packet>(senf::nothrow));
161  if (ipv4) {
162  ttl = std::uint8_t(ipv4->ttl());
163  ttlMin_ = std::min(ttl, ttlMin_);
164  ttlMax_ = std::max(ttl, ttlMax_);
165  }
166  senf::IPv6Packet const & ipv6 (eth.next<senf::IPv6Packet>(senf::nothrow));
167  if (ipv6) {
168  ttl = std::uint8_t(ipv6->hopLimit());
169  ttlMin_ = std::min(ttl, ttlMin_);
170  ttlMax_ = std::max(ttl, ttlMax_);
171  }
172 
173  // only forward EthernetII frames. If a ttl is known, it must be >2
174  if ((eth->type_length() > 1536) && ((ttl == 0) || (ttl > 2))) {
175  eth->destination() << dst_;
176  eth->source() << src_;
177  output(eth);
178  ++ packetCount_;
179  } else {
180  ++ packetIgnored_;
181  }
182  }
183 
184  bool first_;
185  senf::MACAddress src_;
186  senf::MACAddress dst_;
187  unsigned packetCount_;
188  unsigned packetIgnored_;
189  std::uint8_t ttlMin_, ttlMax_;
190  };
191 
192  class EthernetInterface
194  {
195  public:
196  EthernetInterface(std::string const & iface)
198  {}
199  };
200 
201  class WLANInterface
203  {
204  public:
205  WLANInterface(std::string const & phy)
206  : emu::HardwareWLANInterface(initInterfaces(phy))
207  {
208  monitorDevice( monInterfaceName(wnlc_.phyIndex()));
209 
210  /*
211  maxBurst(32);
212  qlen(384);
213  sndBuf(32768);
214  */
215  }
216 
217  ~WLANInterface()
218  {
219  try {
220  wnlc_.ibss_leave();
221  } catch (...) {}
222  }
223 
224  std::string initInterfaces(std::string const & dev)
225  {
227  // first, remove all existing interfaces of the phy device
228  for (std::string iface : wnlc.all_interfaces()) {
229  wnlc.del_interface( iface);
230  }
231 
232  // now, add the monitor interface...
233  wnlc.add_monInterface(monInterfaceName(wnlc.phyIndex()),
238 
239  // ... and then the adhoc interface
240  std::string ifname (adhocInterfaceName(wnlc.phyIndex()));
241  wnlc.add_adhocInterface(ifname);
242 
243  return ifname;
244  }
245 
246  std::string adhocInterfaceName(int phyIndex)
247  {
248  return (boost::format("wiback-wlan%d") % phyIndex).str();
249  }
250 
251  std::string monInterfaceName(int phyIndex)
252  {
253  return (boost::format("wiback-mon%d") % phyIndex).str();
254  }
255 
256  void join(unsigned freq, unsigned bwidth, unsigned netId)
257  {
258  std::string ssid;
260  ssid = "WiBACK-" + std::to_string(netId) + "-" + std::to_string(freq);
261  std::uint64_t tmp ((std::uint64_t(netId) << 32) + freq);
262  char buf[64];
263  sprintf( buf, "00:%x:%x:%x:%x:%x", std::uint32_t((tmp >> 32) & 0xff), std::uint32_t((tmp >> 24) & 0xff),
264  std::uint32_t((tmp >> 16) & 0xff), std::uint32_t((tmp >> 8) & 0xff),
265  std::uint32_t((tmp >> 0) & 0xff));
266  bssid = senf::MACAddress::from_string( buf);
267 
268  joinAdhocNetwork( ssid, freq*1000, bwidth*1000)
269  ->bssid( bssid)
270  ->beaconInterval(125)
271  ->ampduFactor(1); // WiBACK default. Should be configurable via policy.
272  // For more recent kernels 3.13++, we should set this to 3 and control the burst length via TxOp
273 
274  modulation(senf::emu::WLANModulationParameter::MCS, 7);
275  txPower(txPowers().back().upper);
276  coverageRange(450);
277  senf::emu::WirelessNLController wnlc(device());
278  // the PID rate controller counts the total number of transmissions not only the retries, hence +1
279  wnlc.set_retryLimit(2,2);
280 
281  // default WiBACK WMM settings
282  for (unsigned i = 0; i < 4; i++){
283  wnlc.set_txQueueParameters( defaultHtWMM[i].accessCategory, defaultHtWMM[i].cwMin, defaultHtWMM[i].cwMax, defaultHtWMM[i].aifs, defaultHtWMM[i].txOp);
284  }
285  }
286  };
287 
288  template <class Interface>
289  class App : public module::Module
290  {
291  SENF_PPI_MODULE(App);
292  public:
293  typedef typename OurDecoration::template apply<Interface>::type DecoInterface;
294  DecoInterface iface0;
295  DecoInterface iface1;
296  Forwarder forwarder0;
297  Forwarder forwarder1;
298 
299  ppi::IntervalTimer statsTimer;
300  struct ::timeval startTime;
301  unsigned long lastStats;
302 
305 
306  App(std::string const & iface0_,
307  unsigned freq0,
308  senf::MACAddress peer0,
309  std::string const & iface1_,
310  unsigned freq1,
311  senf::MACAddress peer1,
312  unsigned burst_,
313  unsigned ring_,
314  unsigned rxbuf_,
315  unsigned txbuf_)
316  : iface0 (iface0_),
317  iface1 (iface1_),
318  forwarder0 (iface1.id(), peer1),
319  forwarder1 (iface0.id(), peer0),
320  statsTimer (senf::ClockService::seconds(1)),
321  lastStats (0),
322  sigint (SIGINT, boost::bind(&App::terminate, this)),
323  sigterm (SIGTERM, boost::bind(&App::terminate, this))
324  {
325  iface0.interface().rcvBuf(rxbuf_);
326  iface0.interface().sndBuf(txbuf_);
327  iface0.interface().qlen(ring_);
328  iface0.interface().maxBurst(burst_);
329 
330  iface1.interface().rcvBuf(rxbuf_);
331  iface1.interface().sndBuf(txbuf_);
332  iface1.interface().qlen(ring_);
333  iface1.interface().maxBurst(burst_);
334 
335  iface0.interface().enable();
336  iface1.interface().enable();
337 
338  WLANInterface *wif;
339  if ((wif = dynamic_cast<WLANInterface*>(&iface0.interface())) != NULL) {
340  wif->join(freq0, 40, 4711u);
341  }
342  if ((wif = dynamic_cast<WLANInterface*>(&iface1.interface())) != NULL) {
343  wif->join(freq1, 40, 4711u);
344  }
345 
346  ppi::connect(iface0, forwarder0);
347  ppi::connect(forwarder0, iface1);
348 
349  ppi::connect(iface1, forwarder1);
350  ppi::connect(forwarder1, iface0);
351 
352  registerEvent(statsTimer, &App::stats);
353  ::gettimeofday(&startTime, 0);
354  }
355 
356  void stats()
357  {
358  struct ::timeval tv;
359  ::gettimeofday(&tv, 0);
360  unsigned long time (
361  (tv.tv_sec - startTime.tv_sec) * 1000000 + tv.tv_usec - startTime.tv_usec);
362  std::cout << tv.tv_sec << '.' << std::setw(6) << std::setfill('0') << tv.tv_usec
363  << " usecs " << time - lastStats
364  << " packets forwarded " << forwarder0.packetCount() + forwarder1.packetCount()
365  << " packets ignored " << forwarder0.packetIgnored() + forwarder1.packetIgnored()
366  << " queue0-drops " << iface0.interface().rxQueueDropped()
367  << " queue1-drops " << iface1.interface().rxQueueDropped()
368  << std::endl;
369  lastStats = time;
370  }
371 
372  void terminate()
373  {
374  std::cerr << "bye." << std::endl;
376  }
377  };
378 
379  template <class Application>
380  void run(std::string iface0, unsigned freq0, senf::MACAddress peer0,
381  std::string iface1, unsigned freq1, senf::MACAddress peer1,
382  unsigned burst, unsigned nrring, unsigned rxbuf, unsigned txbuf)
383  {
384  Application app (iface0, freq0, peer0, iface1, freq1, peer1, burst, nrring, rxbuf, txbuf);
385  ppi::run();
386  }
387 
388 }
389 
390 int main(int argc, char ** argv)
391 {
392 // senf::log::ConsoleTarget::logToStderr();
393 
394  if (argc < 9) {
395  std::cerr << "Usage:\n " << argv[0] << "\n"
396  << " <iface1> <freq0> <peermac1>\n"
397  << " <iface2> <freq1> <peermac2>\n"
398  << " <burst> <rxbuf> <txbuf> <nrring> [[NO]RT] [[NO]WLAN]\n"
399  << std::endl;
400  return 1;
401  }
402 
403  std::string iface0 (argv[1]);
404  unsigned freq0 (boost::lexical_cast<unsigned>(argv[2]));
406  std::string iface1 (argv[4]);
407  unsigned freq1 (boost::lexical_cast<unsigned>(argv[5]));
409 
410  unsigned burst (boost::lexical_cast<unsigned>(argv[7]));
411  unsigned rxbuf (boost::lexical_cast<unsigned>(argv[8]));
412  unsigned txbuf (boost::lexical_cast<unsigned>(argv[9]));
413  unsigned nrring (boost::lexical_cast<unsigned>(argv[10]));
414 
415  bool enableRT (true);
416  bool useWlan (false);
417 
418  for (int i (11); i < argc; ++ i) {
419  bool state (true);
420  char * arg (argv[i]);
421  if (*arg == 'N') {
422  state = false;
423  if (*(++ arg) == 'O')
424  ++ arg;
425  }
426  switch (*arg) {
427  case 'R': enableRT = state; break;
428  case 'W': useWlan = state; break;
429  default: std::cerr << "invalid flag " << argv[i] << std::endl; ::exit(1);
430  }
431  }
432 
433  if (enableRT) {
434  ::sched_param schedpm = {};
435  schedpm.sched_priority = 1;
436  if (::sched_setscheduler(::getpid(), SCHED_FIFO, &schedpm) >= 0)
437  std::cerr << "SCHED_FIFO realtime scheduling enabled" << std::endl;
438  }
439 
440  senf::scheduler::watchdogTimeout(0); // allow debugging using gdb
441 
443 
444  if (useWlan)
445  run< App<WLANInterface> >(iface0, freq0 , peer0,
446  iface1, freq1, peer1,
447  burst, nrring, rxbuf, txbuf);
448  run< App<EthernetInterface> >(iface0, freq0, peer0,
449  iface1, freq1, peer1,
450  burst, nrring, rxbuf, txbuf);
451 
452  return 0;
453 }
454 
456 #undef prefix_
457 //#include "main.mpp"
458 
459 
460 // Local Variables:
461 // mode: c++
462 // indent-tabs-mode: nil
463 // End:
static Server & start(senf::INet4SocketAddress const &address)
#define NL80211_TXQ_Q_BE
Definition: nl80211-new.h:3511
Interface API base class
void add_adhocInterface(std::string const &name)
WirelessExtController public header.
u8 type
virtual void terminate() const
void del_interface(std::string const &name)
void id(MACAddress const &eui)
Change interface MAC.
Definition: InterfaceAPI.cc:82
static SENF_CLOCKSERVICE_CONSTEXPR clock_type seconds(int64_type const &v)
static MACAddress from_string(std::string const &s)
char ssid[36]
std::int32_t min
std::int32_t max
void add_monInterface(std::string const &name, int flags=MonitorFlags::None)
static INet4Address const None
Apply additional modules to an interface.
ConcretePacket< IPv6PacketType > IPv6Packet
int run(int argc, char const *argv[])
Definition: dfstest.cc:83
std::uint8_t bssid[6]
#define NL80211_TXQ_Q_VO
Definition: nl80211-new.h:3509
void set_txQueueParameters(boost::uint8_t queue, boost::uint16_t cwMin, boost::uint16_t cwMax, boost::uint8_t aifs, boost::uint16_t txop)
#define SENF_PPI_MODULE(name)
nothrow
int main(int argc, char **argv)
Definition: main.cc:390
void set_retryLimit(boost::uint8_t shortLimit, boost::uint8_t longLimit)
__be16 freq1
#define NL80211_TXQ_Q_VI
Definition: nl80211-new.h:3510
bool multicast() const
ConcretePacket< EthernetPacketType > EthernetPacket
HardwareEthernetInterface public header.
HardwareWLANInterface public header.
__be16 freq
#define NL80211_TXQ_Q_BK
Definition: nl80211-new.h:3512
ConcretePacket< IPv4PacketType > IPv4Packet