TunnelController.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 "TunnelController.hh"
18 
19 // Custom includes
20 #include <senf/Utils/String.hh>
22 #include "TunnelHeaderPacket.hh"
23 #include "TunnelCtrlPacket.hh"
24 #include "TunnelInterface.hh"
25 
26 #define prefix_
27 //-/////////////////////////////////////////////////////////////////////////////////////////////////
28 
29 //-/////////////////////////////////////////////////////////////////////////////////////////////////
30 // senf::emu::TunnelIOStatistics
31 
33 {
34  reset();
35 }
36 
38 {
39  memset( this, 0, sizeof(*this));
41 }
42 
44  const
45 {
47 }
48 
50 {
51  TunnelIOStatistics tmp (*this);
52  reset();
53  return tmp;
54 }
55 
57  const
58 {
59  os << "(duration " << senf::ClockService::in_milliseconds(duration()) << " ms"
60  << ",rxRate " << (rxPackets*1000) / (senf::ClockService::in_milliseconds(duration())+1) << " pps" // +1 to avoid DIV_BY_ZERO
61  << ",txRate " << (txPackets*1000) / (senf::ClockService::in_milliseconds(duration())+1) << " pps"; // +1 to avoid DIV_BY_ZERO
62 
63  // add check for txStats here. But this is more tricky due to possible fragmentation
64  if ((rxControl + rxData + rxIgnored) != rxPackets)
65  os << ",stats bad";
66  else
67  os << ",stats good";
68 
69  os.setf(std::ios::fixed,std::ios::floatfield);
70  os.precision(1);
71 
72  os << ";rxPackets " << rxPackets
73  << ";rxData " << rxData << " (" << float(rxData) / float(rxPackets) * 100.0f << "%)"
74  << ",rxControl " << rxControl << " (" << float(rxControl) / float(rxPackets) * 100.0f << "%)"
75  << ",rxIgnored " << rxIgnored << " (" << float(rxIgnored) / float(rxPackets) * 100.0f << "%)"
76 
77  << ";txPackets " << txPackets
78  << ",txSent " << txSent << " (" << float(txSent) / float(txPackets) * 100.0f << "%)"
79  << ",txError " << txError << " (" << float(txError) / float(txPackets) * 100.0f << "%)"
80  << ",txOverrun " << txOverrun << " (" << float(txOverrun) / float(txPackets) * 100.0f << "%)"
81  << ",txDSQDropped "<< txDSQDropped<< " (" << float(txDSQDropped)/ float(txPackets) * 100.0f << "%)";
82 
83  os << ")";
84 }
85 
87  const
88 {
89  std::stringstream ss;
90  dump(ss);
91  return ss.str();
92 }
93 
94 //-/////////////////////////////////////////////////////////////////////////////////////////////////
95 // senf::emu::detail::TunnelControllerBase
96 
97 const signed reSyncTresh = 256;
98 
100  : timeout_(senf::ClockService::seconds(20)), interface_(interface), qAlgo_( new senf::ppi::NoneQueueingAlgorithm()),
101  seqNoDiff_(17)
102 {}
103 
105 {
106  return eth->type_length() == EthOUIExtensionPacketType::etherType && eth.find<TunnelCtrlPacket>(senf::nothrow);
107 }
108 
110 {
111  // use this as a trigger to flush our write queue
112  flushQueue(handle);
113 
115  INet6SocketAddress addr;
116 
117  handle.readfrom(thdr.data(), addr, SENF_EMU_MAXMTU);
118  if (SENF_UNLIKELY(thdr.data().size() == 0)) {
119  // ignore EGAIN, etc.
120  return senf::EthernetPacket();
121  }
122 
123  stats_.rxPackets++;
124 
125  try {
126  if (SENF_UNLIKELY((thdr.size() < (TunnelHeaderPacket::Parser::fixed_bytes + senf::EthernetPacketParser::fixed_bytes)) or
127  (thdr->reserved() != TunnelHeaderPacketType::reservedMagic))) {
128  stats_.rxIgnored++;
129  return EthernetPacket();
130  }
131 
133 
134  if (SENF_UNLIKELY(isTunnelCtrlPacket(eth))) {
135  v_handleCtrlPacket( eth, addr, handle);
136  stats_.rxControl++;
137  return EthernetPacket();
138  }
139 
140  stats_.rxData++;
141 
142  // Ctrl Frames do not have a valid seqNo, so perform this here where we only see Data frames
143  signed diff = v_processSequenceNumber(thdr, addr);
144 
145  eth.annotation<annotations::Interface>().value = interface_.id();
146  eth.annotation<annotations::Timestamp>().fromSocketProtocol(handle.protocol());
147  annotations::Quality & q (eth.annotation<annotations::Quality>());
148  q.rssi = 126; // one step below Ethernet to ensure native Ethernet Links yield a better SNR - this requires more thinking/integration
149  q.noise = -128;
150  q.snr = q.rssi - q.noise;
151  q.flags.frameLength = eth.size();
152 
153  if (SENF_LIKELY(diff == 1)) {
154  // all is fine
155  }
156  else if ( diff == 0) {
157  q.flags.frameDuplicate = true;
158  }
159  else if (diff > 1) {
160  q.setLoss(diff - 1);
161  } else {
162  q.flags.frameReordered = true;
163  }
164 
165  // fragmented frame ?
167  return eth;
168  }
169  auto extOUI (VLanId::payload<EthOUIExtensionPacket>(eth));
170  if (extOUI.next<EthernetFragmentPacket>(senf::nothrow)) {
171  if (reassembler_.processFrame(eth, extOUI.next<EthernetFragmentPacket>())) {
172  return reassembler_.reassembledPacket();
173  }
174  } else {
175  return eth;
176  }
177  } catch (TruncatedPacketException &) {
178  }
179 
180  // no output packet due to reassembling or exception caught
181  return EthernetPacket();
182 }
183 
184 
185 prefix_ void senf::emu::detail::TunnelControllerBase::do_sendPkt(Handle & handle, senf::EthernetPacket & pkt, std::pair<senf::INet6SocketAddress,unsigned> const & txInfo)
186 {
187  try{
188  v_prependTHdr(pkt);
189  handle.writeto(txInfo.first,pkt.prev().data());
190  stats_.txSent++;
191  }
192  catch(...) {
193  stats_.txError++;
194  };
195 }
196 
198 {
199  do_sendPkt( handle, pkt, v_getTxInfo(pkt));
200 }
201 
203 {
204  // first, flush any possibly pending packets
205  flushQueue(handle);
206 
207  stats_.txPackets++;
208 
209  pkt.annotation<annotations::Interface>().value = dstMAC;
210  auto txInfo (v_getTxInfo(pkt));
211 
212  // the following code is a bit tricky as we need to ensure that we either send/enqueue all fragments of a frame or drop the complete sequence of fragments!
213 
214  if (!qAlgo_->empty()) {
215  stats_.txOverrun++;
216  if (isTunnelCtrlPacket(pkt) or !fragmenter_.fragmentationRequired(pkt,txInfo.second + TunnelOverhead)) {
217  stats_.txDSQDropped += !qAlgo_->enqueue(pkt);
218  } else {
219  fragmenter_.fragmentFrame(pkt,txInfo.second + TunnelOverhead);
220  bool force (false); // if the first fragment has been enqueue()d, force all subsequent frags to be enqueue()d, as well
221  for (auto & frag : fragmenter_.fragments()) {
222  if (!force and !qAlgo_->enqueue(frag, force)) {
223  stats_.txDSQDropped += fragmenter_.fragments().size();
224  break;
225  }
226  force = true;
227  }
228  }
229  return true;
230  }
231 
232  if (isTunnelCtrlPacket(pkt) or !fragmenter_.fragmentationRequired(pkt,txInfo.second + TunnelOverhead)) {
233  if (handle.writeable()) {
234  do_sendPkt(handle, pkt, txInfo);
235  } else {
236  stats_.txOverrun++;
237  stats_.txDSQDropped += !qAlgo_->enqueue(pkt);
238  }
239  return true;
240  }
241 
242  fragmenter_.fragmentFrame(pkt,txInfo.second + TunnelOverhead);
243  bool force (false);
244  for (auto & frag : fragmenter_.fragments()) {
245  if (handle.writeable()) {
246  do_sendPkt(handle, frag, txInfo);
247  force = true; // one a seqment has been sent, force enqueue()ing for remaining frags (if required)
248  } else {
249  stats_.txOverrun++;
250  stats_.txDSQDropped += !qAlgo_->enqueue(frag, force); // if the first fragment has been enqueue()d, force all subsequent frags to be enqueue()d, as well
251  }
252  }
253 
254  return true;
255 }
256 
258 {
259  while (handle.writeable() and qAlgo_->peek()) {
260  // the below is not ideal as we create a new PktImpl. The whole mess here needs an overhaul
261  senf::EthernetPacket eth (qAlgo_->front().as<EthernetPacket>());
262  do_sendPkt(handle, eth);
263  qAlgo_->pop();
264  }
265 }
266 
268 {
269  return v_writePacket( handle, packet);
270 }
271 
273  Handle & handle, MACAddress const & dstMAC, boost::uint8_t code)
274 {
276  ctrlPacket->code() << code;
277  sendCtrlPacket(handle, dstMAC, ctrlPacket);
278 }
279 
281  Handle & handle, MACAddress const & dstMAC, TunnelCtrlPacket ctrlPacket)
282 {
283  EthernetPacket eth (EthernetPacket::create());
284  eth->source( interface_.id())
285  ->destination( dstMAC);
286  EthOUIExtensionPacket ethOUIExt (EthOUIExtensionPacket::createAfter(eth));
287  ethOUIExt.append(ctrlPacket);
288  eth.finalizeAll();
289  sendPkt( handle, dstMAC, eth);
290 }
291 
293  const
294 {
295  return timeout_;
296 }
297 
299 {
300  timeout_ = t;
301  v_timeoutChanged();
302 }
303 
305  const
306 {
307  return *qAlgo_;
308 }
309 
311 {
312  qAlgo_.reset(qAlgorithm.release());
313 }
314 
316 {
317  return fragmenter_.fragmentationCount();
318 }
319 
320 
322 {
323  os << "Id: " << interface_.id() << std::endl
324  << "Enabled: " << (interface_.enabled() ? "yes" : "no") << std::endl
325  << "Timeout: " << ClockService::in_seconds(timeout_) << " sec." << std::endl;
326  os << "IOStats: " << stats_.stats().dump() << std::endl;
327  os << "qAlgo.size: " << qAlgo_->size() << std::endl;
328  os << "Tunnel Overhead: " << TunnelOverhead << std::endl;
329  os << "FragmentationStats: out " << fragmenter_.fragmentationCount() << ", in " << reassembler_.packetsReassembled() << std::endl;
330 
331  v_dumpInfo(os);
332 }
333 
334 //-/////////////////////////////////////////////////////////////////////////////////////////////////
335 // senf::emu::detail::TunnelServerController
336 
338  : TunnelControllerBase(interface),
339  clients_by_lastSeen_(clients_.get<ByLastSeen>()),
340  clients_by_macAddr_(clients_.get<ByMACAddr>()),
341  clients_by_inetAddr_(clients_.get<ByINetAddr>()),
342  timer_( "senf::emu::TunnelServerController::timer", membind(&TunnelServerController::processTimeout, this))
343 {}
344 
345 prefix_ bool senf::emu::detail::TunnelServerController::v_writePacket(Handle & handle, EthernetPacket & eth)
346 {
347  MACAddress dst (eth->destination());
348  if (SENF_UNLIKELY(dst.multicast())) {
349  for (Clients_by_macAddr::iterator client = clients_by_macAddr_.begin(); client != clients_by_macAddr_.end(); client++) {
350  sendPkt(handle, client->macAddr, eth.clone());
351  }
352  return true;
353  } else {
354  Clients_by_macAddr::iterator client (clients_by_macAddr_.find(dst));
355  if (client != clients_by_macAddr_.end()) {
356  return sendPkt(handle, client->macAddr, eth);
357  }
358  }
359  return false;
360 }
361 
363 {
365 
366  if (SENF_LIKELY(!isTunnelCtrlPacket(eth))) {
367  Clients_by_macAddr::iterator client (clients_by_macAddr_.find(eth.annotation<annotations::Interface>().value));
368  if (client != clients_by_macAddr_.end()) {
369  thdr->sequenceNumber() = client->txSeqNo;
370  clients_by_macAddr_.modify( client, TunnelClient::incrTxSeqNo());
371  }
372  } else {
373  thdr->sequenceNumber() = 0;
374  }
375  thdr.finalizeThis();
376 }
377 
378 prefix_ std::pair<senf::INet6SocketAddress,unsigned> senf::emu::detail::TunnelServerController::v_getTxInfo(Packet const & eth)
379  const
380 {
381  Clients_by_macAddr::iterator client (clients_by_macAddr_.find(eth.annotation<annotations::Interface>().value));
382  if (SENF_LIKELY(client != clients_by_macAddr_.end())) {
383  return std::make_pair(client->inetAddr, client->fragmentationThreshold);
384  }
385 
386  return std::make_pair(INet6SocketAddress(INet6Address::None,0), 0);
387 }
388 
389 
390 prefix_ signed senf::emu::detail::TunnelServerController::v_processSequenceNumber(TunnelHeaderPacket const & thdr, INet6SocketAddress const & srcAddr)
391 {
392  Clients_by_inetAddr::iterator client (clients_by_inetAddr_.find(srcAddr));
393 
394  if (SENF_LIKELY(client != clients_by_inetAddr_.end())) {
395  signed diff;
396  if (SENF_UNLIKELY(client->rxSeqNo == 0xffffffff)) {
397  diff = 1;
398  } else {
399  diff = seqNoDiff_.difference(thdr->sequenceNumber(), client->rxSeqNo);
400  }
401  if ((diff > 0) or (diff < -reSyncTresh)) {
402  clients_by_inetAddr_.modify( client, TunnelClient::updateRxSeqNo(thdr->sequenceNumber()));
403  if (diff < -reSyncTresh) {
404  clients_by_inetAddr_.modify( client, TunnelClient::incReSyncs());
405  }
406  }
407  return diff;
408  }
409 
410  return 1;
411 }
412 
413 prefix_ void senf::emu::detail::TunnelServerController::v_handleCtrlPacket(
414  EthernetPacket const & ethPacket, INet6SocketAddress const & srcAddr, Handle & handle)
415 {
416  TunnelCtrlPacket ctrlPacket (ethPacket.find<TunnelCtrlPacket>());
417  Clients_by_macAddr::iterator clientByMAC (clients_by_macAddr_.find(ethPacket->source()));
418  Clients_by_inetAddr::iterator clientByINet (clients_by_inetAddr_.find(srcAddr));
419  unsigned responseCode (ctrlPacket->code() + 1); // ==0 => ignore; >0 => code
420  bool updateLastSeen (false);
421  bool updateINetAddr (false);
422 
423  switch (ctrlPacket->code()) {
425  if (! ctrlPacket->has_capacity()) {
426  // no capacity?! => reject
428  break;
429  }
430  if (clientByMAC == clients_by_macAddr_.end()) {
431  if (clientByINet == clients_by_inetAddr_.end()) {
432  // src mac and src ip/port not know => we have a new client
433  clientByMAC = clients_by_macAddr_.insert( TunnelClient(ethPacket->source(), srcAddr)).first;
434  updateLastSeen = true;
435  } else {
436  // unknown mac but known ip/port => maybe mac changed?! reject
438  }
439  } else {
440  if (clientByINet == clients_by_inetAddr_.end()) {
441  // known mac but unknown ip/port => update ip/port
442  updateINetAddr = true;
443  }
444  // else known mac and known ip/port => ok.
445  updateLastSeen = true;
446  }
447  clients_by_macAddr_.modify( clientByMAC, TunnelClient::updateCapacity(
448  tunnel::FromClientToServer, ctrlPacket->capacity().fromClientToServer()) );
449  clients_by_macAddr_.modify( clientByMAC, TunnelClient::updateCapacity(
450  tunnel::FromServerToClient, ctrlPacket->capacity().fromServerToClient()) );
451  break;
452 
454  if (clientByMAC == clients_by_macAddr_.end()) {
455  // unknown clients don't get a EchoReply
456  responseCode = 0; // ignore
457  } else {
458  if (clientByINet == clients_by_inetAddr_.end()) {
459  // known mac but unknown ip/port => update ip/port
460  updateINetAddr = true;
461  }
462  // else know mac and known ip/port => ok.
463  updateLastSeen = true;
464  }
465  break;
466 
468  if (clientByMAC != clients_by_macAddr_.end() && clientByINet != clients_by_inetAddr_.end())
469  // know mac an known ip/port => remove client
470  clients_by_macAddr_.erase( clientByMAC);
471  else
472  // unknown clients don't get an Ack
473  responseCode = 0; // ignore
474  break;
475 
477  break;
478 
482  SENF_LOG((senf::log::IMPORTANT)("invalid TunnelCtrlPacket received: " << unsigned(ctrlPacket->code())));
483  break;
484  }
485 
486  if (updateLastSeen) {
487  clients_by_macAddr_.modify( clientByMAC, TunnelClient::updateLastSeen());
488  resetTimer();
489  }
490  if (updateINetAddr)
491  clients_by_macAddr_.modify( clientByMAC, TunnelClient::updateInetAddr(srcAddr));
492 
493  if (responseCode != 0)
494  sendCtrlPacket( handle, ethPacket->source(), responseCode);
495 }
496 
497 prefix_ void senf::emu::detail::TunnelServerController::processTimeout()
498 {
499  SENF_ASSERT( !clients_.empty(), "empty client map in TunnelServerController::processTimeout");
500 
501  Clients_by_lastSeen::iterator client (clients_by_lastSeen_.begin());
502  SENF_LOG((senf::log::MESSAGE)("timeout for tunnel client ("
503  << client->macAddr << ", " << client->inetAddr << ") last seen " <<
504  ClockService::in_seconds(scheduler::now() - client->lastSeen) << " sec."));
505  clients_by_lastSeen_.erase( client);
506 
507  resetTimer();
508 }
509 
510 prefix_ void senf::emu::detail::TunnelServerController::resetTimer()
511 {
512  if (clients_.empty())
513  timer_.disable();
514  else
515  timer_.timeout(clients_by_lastSeen_.begin()->lastSeen + timeout());
516 }
517 
519 {
520  for (TunnelClient const & client : clients_) {
522  }
523 }
524 
525 namespace {
527  senf::emu::tunnel::Capacity::const_iterator i (capacity.find(direction));
528  return i != capacity.end() ? i->second : 0;
529  }
530 }
531 
533  const
534 {
535  Clients_by_macAddr::const_iterator client (clients_by_macAddr_.find(clientAddr));
536  return client != clients_by_macAddr_.end() ? get(client->capacity, direction) : 0;
537 }
538 
540 {
541  if (ft == 0)
542  ft = 1280u;
543 
544  Clients_by_macAddr::const_iterator client (clients_by_macAddr_.find(clientAddr));
545  if ( client != clients_by_macAddr_.end()) {
546  clients_by_macAddr_.modify( client, TunnelClient::updateFragmentationThreshold(ft));
547  } else {
548  for (auto it = clients_by_macAddr_.begin(); it != clients_by_macAddr_.end(); it++) {
549  clients_by_macAddr_.modify( it, TunnelClient::updateFragmentationThreshold(ft));
550  }
551  }
552 }
553 
555  const
556 {
557  Clients_by_macAddr::const_iterator client (clients_by_macAddr_.find(clientAddr));
558  return client != clients_by_macAddr_.end() ? (client->fragmentationThreshold) : 0;
559 }
560 
561 
562 prefix_ void senf::emu::detail::TunnelServerController::v_dumpInfo(std::ostream & os)
563  const
564 {
565  os << "Clients:";
566  if (clients_.empty()) {
567  os << " none" << std::endl;
568  return;
569  }
570  os << std::endl;
571  boost::format fmtClient ("%-30s %-17s %4d %9d %4s %18d %18d %5x %5x %7d");
572  os << fmtClient % "address" % "MAC address" % "FragThesh" % "last seen" %"" % "capacity_to_client" % "capacity_from_client" % "TxSeq" % "RxSeq" % "ReSyncs"<< std::endl;
573  for (TunnelClient const & client : clients_) {
574  os << fmtClient
575  % senf::str(client.inetAddr)
576  % senf::str(client.macAddr)
577  % senf::str(client.fragmentationThreshold)
578  % ClockService::in_seconds(scheduler::now() - client.lastSeen) % "sec."
579  % get(client.capacity, tunnel::FromServerToClient)
580  % get(client.capacity, tunnel::FromClientToServer)
581  % client.txSeqNo
582  % client.rxSeqNo
583  % client.reSyncs
584  << std::endl;
585  }
586 }
587 
588 
589 //-/////////////////////////////////////////////////////////////////////////////////////////////////
590 // senf::emu::detail::TunnelClientController
591 
593  : TunnelControllerBase(interface),
594  interface_(interface), established_(false),
595  timer_( "TunnelClientController::timer", membind(&TunnelClientController::processTimeout, this)),
596  serverLastSeen_(0),
597  txSeqNo_(0),
598  rxSeqNo_(0xffffffff),
599  setupRequests_(0),
600  reSyncs_(0),
601  reordered_(0),
602  duplicate_(0)
603 {
604  v_timeoutChanged();
606 }
607 
608 prefix_ signed senf::emu::detail::TunnelClientController::v_processSequenceNumber(TunnelHeaderPacket const & thdr, INet6SocketAddress const & srcAddr)
609 {
610  signed diff;
611  if (SENF_UNLIKELY(rxSeqNo_ == 0xffffffff)) {
612  diff = 1;
613  } else {
614  diff = seqNoDiff_.difference(thdr->sequenceNumber(), rxSeqNo_);
615  }
616  if ((diff > 0) or (diff < -reSyncTresh)) {
617  rxSeqNo_ = thdr->sequenceNumber();
618  if (diff < -reSyncTresh) {
619  reSyncs_++;
620  }
621  }
622  reordered_ += diff < 0;
623  duplicate_ += diff == 0;
624 
625  return diff;
626 }
627 
628 prefix_ void senf::emu::detail::TunnelClientController::v_handleCtrlPacket(
629  EthernetPacket const & ethPacket, INet6SocketAddress const & srcAddr, Handle & handle)
630 {
631  if (srcAddr != serverAddress()) {
632  SENF_LOG(("skipping control Packet from unknown server " << srcAddr));
633  return; // we only accept control packets from the configured tunnel server
634  }
635  serverLastSeen_ = senf::scheduler::now();
636  TunnelCtrlPacket ctrlPacket (ethPacket.find<TunnelCtrlPacket>());
637  switch (ctrlPacket->code()) {
639  established_ = true;
640  serverMAC_ = ethPacket->source();
641  break;
642 
644  SENF_LOG((senf::log::IMPORTANT)("Tunnel setup rejected."));
645  // fall through
648  SENF_LOG((senf::log::IMPORTANT)("Tunnel terminated."));
649  established_ = false;
650  serverMAC_ = MACAddress::None;
651  break;
652 
654  break;
655 
658  SENF_LOG((senf::log::IMPORTANT)("invalid TunnelCtrlPacket received: " << unsigned(ctrlPacket->code())));
659  break;
660  }
661 }
662 
663 
664 
665 prefix_ bool senf::emu::detail::TunnelClientController::v_writePacket(Handle & handle, EthernetPacket & eth)
666 {
667  if (SENF_LIKELY(established_)) {
668  return sendPkt( handle, serverMAC_, eth);
669  }
670 
671  return false;
672 }
673 
675 {
677  if (SENF_LIKELY(!isTunnelCtrlPacket(eth))) {
678  thdr->sequenceNumber() = txSeqNo_;
679  txSeqNo_ = (txSeqNo_ + 1) % 0x20000;
680  } else {
681  thdr->sequenceNumber() = 0;
682  }
683  thdr.finalizeThis();
684 }
685 
686 prefix_ std::pair<senf::INet6SocketAddress,unsigned> senf::emu::detail::TunnelClientController::v_getTxInfo(Packet const & eth)
687  const
688 {
689  return std::make_pair(serverINet_, fragmentationThreshold_);
690 }
691 
692 prefix_ void senf::emu::detail::TunnelClientController::processTimeout()
693 {
694  timer_.timeout( ClockService::now() + echoInterval_);
695  if (established_) {
696  if (scheduler::now() - serverLastSeen_ < timeout()) {
697  sendCtrlPacket( interface_.socket, serverMAC_, TunnelCtrlPacketParser::EchoRequest);
698  return;
699  }
700  // connection time out
701  established_ = false;
702  serverMAC_ = MACAddress::None;
703  setupRequests_ = 0;
704  txSeqNo_ = 0;
705  rxSeqNo_ = 0xFFFFFFFF;
706  reSyncs_ = 0;
707  reordered_ = 0;
708  duplicate_ = 0;
710  }
711  if (serverINet_ && interface_.enabled())
712  sendSetupRequest();
713 }
714 
715 prefix_ void senf::emu::detail::TunnelClientController::sendSetupRequest()
716 {
718  setupRequest->add_capacity();
719  setupRequest->capacity().fromClientToServer() << interface_.capacity(tunnel::FromClientToServer);
720  setupRequest->capacity().fromServerToClient() << interface_.capacity(tunnel::FromServerToClient);
721  sendCtrlPacket( interface_.socket, MACAddress::Broadcast, setupRequest);
722  setupRequests_++;
723 }
724 
726  const
727 {
728  return established_;
729 }
730 
732 {
733  if (interface_.enabled()) {
734  established_ = false;
735  processTimeout();
736  } else {
737  timer_.timeout( senf::ClockService::clock_type(0), false);
738  if (established_) {
739  established_ = false;
740  sendCtrlPacket( interface_.socket, serverMAC_, TunnelCtrlPacketParser::TerminateRequest);
741  }
742  }
743  serverMAC_ = MACAddress::None;
744  serverLastSeen_ = ClockService::clock_type(0);
745  setupRequests_ = 0;
746  txSeqNo_ = 0;
747  rxSeqNo_ = 0xFFFFFFFF;
748  reSyncs_ = 0;
750 }
751 
753 {
754  serverINet_ = address;
755  reset();
756 }
757 
759  const
760 {
761  return serverINet_;
762 }
763 
765 {
766  if (ft == 0)
767  ft = 1280u;
768 
769  fragmentationThreshold_ = ft;
770 }
771 
773  const
774 {
775  return fragmentationThreshold_;
776 }
777 
778 prefix_ void senf::emu::detail::TunnelClientController::v_timeoutChanged()
779 {
780  echoInterval_ = senf::ClockService::milliseconds(1000);
781 }
782 
783 prefix_ void senf::emu::detail::TunnelClientController::v_dumpInfo(std::ostream & os)
784  const
785 {
786  os << "Echo interval: " << ClockService::in_seconds(echoInterval_) << " sec." << std::endl
787  << "Connection established: " << (established_ ? "yes" : "no") << std::endl
788  << "Server address: " << serverINet_ << std::endl
789  << "Server MACAddress: " << serverMAC_ << std::endl
790  << "Server last seen: "
791  << (serverLastSeen_ ? senf::str(ClockService::in_seconds(scheduler::now() - serverLastSeen_)) : "none")
792  << " sec." << std::endl
793  << "fragThresh " << fragmentationThreshold() << std::endl
794  << "Tunnel Overhead: " << TunnelOverhead << std::endl
795  << "setupREQs sent " << setupRequests_ << std::endl
796  << "txSeqNo: 0x" << std::hex << txSeqNo_ << ", rxSeqno 0x" << rxSeqNo_ << std::dec << ", reSyncs " << reSyncs_ << std::endl
797  << "reordered: " << reordered_ << ", duplicate: " << duplicate_ << std::endl;
798 }
799 
800 //-/////////////////////////////////////////////////////////////////////////////////////////////////
801 #undef prefix_
802 
803 
804 // Local Variables:
805 // mode: c++
806 // fill-column: 100
807 // comment-column: 40
808 // c-file-style: "senf"
809 // indent-tabs-mode: nil
810 // ispell-local-dictionary: "american"
811 // compile-command: "scons -u test"
812 // End:
TunnelControlPacket public header.
unsigned capacity(tunnel::CapacityDirection direction) const
config::time_type clock_type
static MACAddress const None
bool processFrame(senf::EthernetPacket const &eth, EthernetFragmentPacket const &fragment)
bool sendPkt(Handle &handle, MACAddress const &dstMAC, senf::EthernetPacket pkt)
#define SENF_EMU_MAXMTU
Definition: config.hh:40
virtual std::pair< INet6SocketAddress, unsigned > v_getTxInfo(Packet const &eth) const =0
TunnelController internal header.
static SENF_CLOCKSERVICE_CONSTEXPR int64_type in_milliseconds(clock_type const &v)
static ConcretePacket createBefore(Packet const &packet)
std::map< CapacityDirection, unsigned > Capacity
Incoming or outgoing interface.
Definition: Annotations.hh:37
bool enabled() const
true, if interface enabled
ClockService::clock_type timeout() const
TunnelServerController(TunnelServerInterface &interface)
void id(MACAddress const &eui)
Change interface MAC.
Definition: InterfaceAPI.cc:82
#define SENF_LIKELY(x)
const signed reSyncTresh
boost::function< R(Args)> membind(R(T::*fn)(Args), T *ob)
noinit
void v_prependTHdr(EthernetPacket &eth) override
TunnelControllerBase(TunnelInterfaceBase &interface)
PacketData & data() const
std::unique_ptr< QueueingAlgorithm > ptr
void sendCtrlPacket(Handle &handle, MACAddress const &dstMAC, boost::uint8_t code)
void v_prependTHdr(EthernetPacket &eth) override
static SENF_CLOCKSERVICE_CONSTEXPR clock_type milliseconds(int64_type const &v)
senf::ClockService::clock_type tstamp
void timeout(ClockService::clock_type const &timeout, bool initiallyEnabled=true)
std::vector< senf::EthernetPacket > & fragments()
Incoming packet timestamp.
Definition: Annotations.hh:86
std::pair< INet6SocketAddress, unsigned > v_getTxInfo(Packet const &eth) const override
Tunnel Server Interface.
Packet next() const
static std::uint16_t payloadTypeLength(senf::EthernetPacket const &eth)
senf::Detail::DifferenceSigned seqNoDiff_
senf::EthernetPacket & reassembledPacket()
unsigned fragmentationThreshold(MACAddress const &clientAddr) const
void fragmentFrame(senf::EthernetPacket const &pkt, unsigned treshold)
bool writePacket(Handle &handle, PacketType packet)
static const EtherTypes::key_t etherType
Annotation & annotation()
std::pair< INet6SocketAddress, unsigned > v_getTxInfo(Packet const &eth) const override
void do_sendPkt(Handle &handle, senf::EthernetPacket &pkt, std::pair< senf::INet6SocketAddress, unsigned > const &txInfo)
nothrow
static ConcretePacket create()
static constexpr std::uint32_t reservedMagic
ConcretePacket< EthOUIExtensionPacketType > EthOUIExtensionPacket
TunnelClientController(TunnelClientInterface &interface)
#define SENF_ASSERT(x, comment)
unsigned capacity(MACAddress const &clientAddr, tunnel::CapacityDirection direction) const
size_type size() const
ppi::QueueingAlgorithm & qAlgorithm() const
#define prefix_
size_type size() const
static clock_type now()
static SENF_CLOCKSERVICE_CONSTEXPR int64_type in_seconds(clock_type const &v)
virtual void v_prependTHdr(EthernetPacket &eth)=0
void finalizeThis()
TunnelInterface public header.
ConcretePacket< EthernetPacketType > EthernetPacket
senf::ClockService::clock_type duration() const
static INet6Address const None
static bool isTunnelCtrlPacket(EthernetPacket const &eth)
#define SENF_LOG(args)
static MACAddress const Broadcast
std::int32_t difference(std::uint32_t current, std::uint32_t last)
#define SENF_UNLIKELY(x)
INet6SocketAddress const & serverAddress() const
void dump(std::ostream &os) const
static bool fragmentationRequired(senf::EthernetPacket const &pkt, unsigned threshold)