TunnelInterface.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 "TunnelInterface.hh"
18 
19 // Custom includes
24 #include "TunnelCtrlPacket.hh"
25 #include "TunnelHeaderPacket.hh"
26 
27 #define prefix_
28 //-/////////////////////////////////////////////////////////////////////////////////////////////////
29 
31 // senf::emu::detail::TunnelIOHelper
32 
33 template <class Controller>
34 prefix_ senf::emu::detail::TunnelIOHelper<Controller>::TunnelIOHelper(TunnelControllerBase & ctrl, TunnelInterfaceNet<Controller> const & tif)
35  : ctrl_(ctrl), tunnelIface_(tif)
36 {}
37 
38 template <class Controller>
39 prefix_ typename senf::emu::detail::TunnelIOHelper<Controller>::PacketType senf::emu::detail::TunnelIOHelper<Controller>::operator()(Handle & handle)
40 {
41  auto pkt (ctrl_.readPacket(handle));
42  if (!pkt)
43  return pkt;
44 
45  if (SENF_UNLIKELY(tunnelIface_._annotationMode())) {
46  return prependAnnotationsPacket(pkt);
47  } else {
48  return pkt;
49  }
50 }
51 
52 template <class Controller>
53 prefix_ bool senf::emu::detail::TunnelIOHelper<Controller>::operator()(Handle & handle, PacketType const & packet)
54 {
55  if (SENF_LIKELY(packet.size() <= tunnelIface_.mtu() + 18))
56  return ctrl_.writePacket(handle, packet.as<EthernetPacket>());
57 
58  return true;
59 }
60 
61 
62 //-/////////////////////////////////////////////////////////////////////////////////////////////////
63 // senf::emu::detail::TunnelInterfaceNet
64 
65 template <class Controller>
66 prefix_ senf::emu::detail::TunnelInterfaceNet<Controller>::TunnelInterfaceNet(typename Controller::Interface & interface)
67  : socket(senf::noinit), tunnelCtrl(interface),
68  source(socket, TunnelIOHelper<Controller>(tunnelCtrl, *this)), sink(socket, TunnelIOHelper<Controller>(tunnelCtrl, *this)),
69  netOutput(source.output), netInput(sink.input), mtu_(1500u), maxBurst_(48), promisc_(false), annotationMode_(false)
70 {
71 }
72 
73 template <class Controller>
74 prefix_ void senf::emu::detail::TunnelInterfaceNet<Controller>::assignSocket(UDPv6ClientSocketHandle socket_)
75 {
76  socket = socket_;
77  source.handle(socket);
78  source.maxBurst(maxBurst_);
79  sink.handle(socket);
80 }
81 
82 template <class Controller>
83 prefix_ unsigned senf::emu::detail::TunnelInterfaceNet<Controller>::rcvBuf()
84 {
85  if (socket)
86  return socket.protocol().rcvbuf();
87  return 0;
88 }
89 
90 template <class Controller>
91 prefix_ void senf::emu::detail::TunnelInterfaceNet<Controller>::rcvBuf(unsigned rcvbuf)
92 {
93  if (socket)
94  socket.protocol().rcvbuf(rcvbuf);
95 }
96 
97 template <class Controller>
98 prefix_ unsigned senf::emu::detail::TunnelInterfaceNet<Controller>::sndBuf()
99 {
100  if (socket)
101  return socket.protocol().sndbuf();
102  return 0;
103 }
104 
105 template <class Controller>
106 prefix_ void senf::emu::detail::TunnelInterfaceNet<Controller>::sndBuf(unsigned sndbuf)
107 {
108  if (socket)
109  socket.protocol().sndbuf(sndbuf);
110 }
111 
112 template <class Controller>
113 prefix_ unsigned senf::emu::detail::TunnelInterfaceNet<Controller>::mtu()
114  const
115 {
116  return mtu_;
117 }
118 
119 template <class Controller>
120 prefix_ void senf::emu::detail::TunnelInterfaceNet<Controller>::mtu(unsigned v)
121 {
122  v = std::max(576u, v);
123  v = std::min(unsigned(SENF_EMU_MAXMTU - senf::EthernetPacketParser::fixed_bytes), v);
124  mtu_ = v;
125 }
126 
127 template <class Controller>
128 prefix_ unsigned senf::emu::detail::TunnelInterfaceNet<Controller>::maxBurst()
129  const
130 {
131  return source.maxBurst();
132 }
133 
134 template <class Controller>
135 prefix_ void senf::emu::detail::TunnelInterfaceNet<Controller>::maxBurst(unsigned v)
136 {
137  maxBurst_ = v;
138  source.maxBurst(maxBurst_);
139 }
140 
141 template <class Controller>
142 prefix_ void senf::emu::detail::TunnelInterfaceNet<Controller>::_promisc(bool p)
143 {
144  promisc_ = p;
145 }
146 
147 template <class Controller>
148 prefix_ bool senf::emu::detail::TunnelInterfaceNet<Controller>::_promisc()
149  const
150 {
151  return promisc_;
152 }
153 
154 template <class Controller>
155 prefix_ void senf::emu::detail::TunnelInterfaceNet<Controller>::_annotationMode(bool a)
156 {
157  annotationMode_ = a;
158 }
159 
160 template <class Controller>
161 prefix_ bool senf::emu::detail::TunnelInterfaceNet<Controller>::_annotationMode()
162  const
163 {
164  return annotationMode_;
165 }
166 
167 
168 //-/////////////////////////////////////////////////////////////////////////////////////////////////
169 // senf::emu::TunnelInterfaceBase
170 
171 namespace {
172  struct DisableInterfaceGuard
173  {
174  DisableInterfaceGuard(senf::emu::Interface & iface)
175  : iface_ (iface), enabled_ (iface_.enabled())
176  { if (enabled_) iface_.disable(); }
177 
178  ~DisableInterfaceGuard()
179  { if (enabled_) iface_.enable(); }
180 
181  senf::emu::Interface & iface_;
182  bool enabled_;
183  };
184 }
185 
186 namespace senf { namespace emu { namespace tunnel {
188 }}}
189 
190 template <class Output, class Input>
192  detail::TunnelControllerBase & ctrlBase, INet6SocketAddress const & address)
193  : BidirectionalWiredInterface(output, input),
194  ctrlBase_(ctrlBase), socketAddress_(address), ifaceIdFactory_( new SimpleInterfaceIdFactory()),
195  id_(ifaceIdFactory_->getId()), isUp_(false), dev_("NetEMU-P2PTunnel")
196 {
199 
200  namespace fty = console::factory;
201  consoleDir()
202  .add("timeout", fty::Command(
204  consoleDir()
205  .add("timeout", fty::Command(
207  consoleDir()
208  .add("info", fty::Command( &detail::TunnelControllerBase::dumpInfo, &ctrlBase_));
209  consoleDir()
210  .add("queue", qAlgorithm().consoleDir());
211  consoleDir()
212  .add("address", fty::Command(
213  SENF_MEMBINDFNP(senf::INet6SocketAddress const &, TunnelInterfaceBase, address, () const)) );
214  consoleDir()
215  .add("fragmentationCount", fty::Command(&detail::TunnelControllerBase::fragmentationCount, &ctrlBase_));
216 }
217 
219 {
220  ifaceIdFactory_->releaseId( id());
221 }
222 
224 {
225  return ctrlBase_;
226 }
227 
229  const
230 {
231  return ctrlBase_;
232 }
233 
235 {
236  ctrlBase_.qAlgorithm( std::move(qAlgo));
237  consoleDir().add("queue", qAlgorithm().consoleDir());
238 }
239 
241  const
242 {
243  return ctrlBase_.qAlgorithm();
244 }
245 
246 
248  const
249 {
250  return socketAddress_;
251 }
252 
254  const
255 {
256  return ctrlBase_.timeout();
257 }
258 
260 {
261  ctrlBase_.timeout( t);
262 }
263 
264 prefix_ boost::shared_ptr<senf::emu::InterfaceIdFactoryBase> senf::emu::TunnelInterfaceBase::ifaceIdFactory()
265 {
266  return ifaceIdFactory_;
267 }
268 
269 prefix_ void senf::emu::TunnelInterfaceBase::ifaceIdFactory(boost::shared_ptr<InterfaceIdFactoryBase> factory)
270 {
271  DisableInterfaceGuard guard (*this);
272  ifaceIdFactory_->releaseId( id_);
273  ifaceIdFactory_ = factory;
274  id_ = MACAddress::None;
275  id( ifaceIdFactory_->getId());
276 }
277 
279 {
280  isUp_ = up;
281 }
282 
283 prefix_ bool senf::emu::TunnelInterfaceBase::v_enabled()
284  const
285 {
286  return isUp_;
287 }
288 
289 prefix_ void senf::emu::TunnelInterfaceBase::v_id(MACAddress const & mac)
290 {
291  DisableInterfaceGuard guard (*this);
292  ifaceIdFactory_->releaseId( id_);
293  id_ = mac;
294 }
295 
296 prefix_ senf::MACAddress senf::emu::TunnelInterfaceBase::v_id()
297  const
298 {
299  return id_;
300 }
301 
302 prefix_ void senf::emu::TunnelInterfaceBase::v_mcAdd(MACAddress const & address)
303 {
304  throw senf::SystemException("multicast not supported on TunnelInterfaces", ENOSYS);
305 }
306 
307 prefix_ void senf::emu::TunnelInterfaceBase::v_mcDrop(MACAddress const & address)
308 {
309  throw senf::SystemException("multicast not supported on TunnelInterfaces", ENOSYS);
310 }
311 
312 prefix_ boost::uint8_t senf::emu::TunnelInterfaceBase::v_linkTypeId()
313  const
314 {
315  return 5; // RADIUS network access server (NAS)-Port-Type for "virtual" (see RFC 2865)
316 }
317 
318 prefix_ std::string const & senf::emu::TunnelInterfaceBase::v_device()
319  const
320 {
321  return dev_;
322 }
323 
324 
325 //-/////////////////////////////////////////////////////////////////////////////////////////////////
326 // senf::emu::TunnelServerInterface
327 
329  : TunnelServerInterface(INet6SocketAddress(INet6Address::from_inet4address(address.address()), address.port()))
330 {
331 }
332 
334  : detail::TunnelServerInterfaceNet( *this),
335  TunnelInterfaceBase(netOutput, netInput, tunnelCtrl, address),
336  sndBufSize_(96*1024), rcvBufSize_(384*1024)
337 {
338  namespace fty = console::factory;
339  consoleDir()
340  .add("sndBuf", fty::Command(
341  SENF_MEMBINDFNP(void, TunnelServerInterface, sndBuf, (unsigned)))
342  .doc( "set the send socket buffer size in bytes"));
343  consoleDir()
344  .add("sndBuf", fty::Command(
346  .doc( "get the send socket buffer size in bytes"));
347  consoleDir()
348  .add("rcvBuf", fty::Command(
349  SENF_MEMBINDFNP(void, TunnelServerInterface, rcvBuf, (unsigned)))
350  .doc( "set the receive socket buffer size in bytes"));
351  consoleDir()
352  .add("rcvBuf", fty::Command(
354  .doc( "get the receive socket buffer size in bytes"));
355  consoleDir()
356  .add("fragmentationThreshold", fty::Command(
358  .doc( "set the fragmentationThreshold for the specified client in bytes"));
359  consoleDir()
360  .add("fragmentationThreshold", fty::Command(
362  .doc( "get the fragmentationThreshold for the specified client in bytes"));
363  consoleDir()
364  .add("maxBurst", fty::Command(
365  SENF_MEMBINDFNP(void, TunnelServerInterface, maxBurst, (unsigned)))
366  .doc( "set the maxBurst limit when receiving packets"));
367  consoleDir()
368  .add("maxBurst", fty::Command(
369  SENF_MEMBINDFNP(unsigned, TunnelServerInterface, maxBurst, () const))
370  .doc( "get the maxBurst limit when receiving packets"));
371 }
372 
373 prefix_ void senf::emu::TunnelServerInterface::v_enable()
374 {
375  isUp(true);
376  UDPv6ClientSocketHandle socket (address());
377  socket.blocking(false); // make sure we operate in non-blocking mode to avoid queuing on kernel tx problems
378  socket.protocol().mtuDiscovery(IP_PMTUDISC_DONT);
379 // socket.protocol().sndLowat(SENF_EMU_MAXMTU);
380  assignSocket( socket);
381  sndBuf(sndBufSize_);
382  rcvBuf(rcvBufSize_);
383 }
384 
385 prefix_ void senf::emu::TunnelServerInterface::v_disable()
386 {
387  isUp(false);
388  tunnelCtrl.terminateAllClients( sink.handle());
389  assignSocket( UDPv6ClientSocketHandle(senf::noinit));
390 }
391 
393  const
394 {
395  return tunnelCtrl.capacity(client, direction);
396 }
397 
399  const
400 {
401  return ((detail::TunnelServerController&)tunnelCtrlBase()).fragmentationThreshold(client);
402 }
403 
405 {
407 }
408 
410 {
411  // need to cache sndBufSize_ so we can (re-)apply the value in v_enable()
412  sndBufSize_ = std::max(sndbuf, 2048u);
413  TunnelInterfaceNet::sndBuf( sndBufSize_);
414 }
415 
417 {
418  // need to cache sndBufSize_ so we can (re-)apply the value in v_enable()
419  return sndBufSize_ = TunnelInterfaceNet::sndBuf();
420 }
421 
423 {
424  // need to cache rcvBufSize_ so we can (re-)apply the value in v_enable()
425  rcvBufSize_ = std::max(rcvbuf, 4096u);
426  TunnelInterfaceNet::rcvBuf( rcvBufSize_);
427 }
428 
430 {
431  // need to cache rcvBufSize_ so we can (re-)apply the value in v_enable()
432  return rcvBufSize_ = TunnelInterfaceNet::rcvBuf();
433 }
434 
435 prefix_ unsigned senf::emu::TunnelServerInterface::v_mtu()
436  const
437 {
438  return TunnelInterfaceNet::mtu();
439 }
440 
441 prefix_ void senf::emu::TunnelServerInterface::v_mtu(unsigned v)
442 {
443  TunnelInterfaceNet::mtu(v);
444 }
445 
447  const
448 {
449  return TunnelInterfaceNet::maxBurst();
450 }
451 
453 {
454  TunnelInterfaceNet::maxBurst(v);
455 }
456 
457 prefix_ void senf::emu::TunnelServerInterface::v_promisc(bool p)
458 {
459  TunnelInterfaceNet::_promisc(p);
460 }
461 
462 prefix_ bool senf::emu::TunnelServerInterface::v_promisc()
463  const
464 {
465  return TunnelInterfaceNet::_promisc();
466 }
467 
468 prefix_ void senf::emu::TunnelServerInterface::v_annotationMode(bool a)
469 {
470  TunnelInterfaceNet::_annotationMode(a);
471 }
472 
473 prefix_ bool senf::emu::TunnelServerInterface::v_annotationMode()
474  const
475 {
476  return TunnelInterfaceNet::_annotationMode();
477 }
478 
479 
480 //-/////////////////////////////////////////////////////////////////////////////////////////////////
481 // senf::emu::TunnelClientInterface
482 
484  : TunnelClientInterface(INet6SocketAddress(INet6Address::from_inet4address(address.address()), address.port()))
485 {
486 }
487 
489  : detail::TunnelClientInterfaceNet( *this),
490  TunnelInterfaceBase(netOutput, netInput, tunnelCtrl, address),
491  sndBufSize_(96*1024), rcvBufSize_(384*1024)
492 {
493  namespace fty = console::factory;
494  consoleDir()
495  .add("established", fty::Command( &TunnelClientInterface::established, this));
496  consoleDir()
497  .add("serverAddress", fty::Command(
499  consoleDir()
500  .add("serverAddress", fty::Command(
502  consoleDir()
503  .add("serverAddress", fty::Command(
505  consoleDir()
506  .add("capacity", fty::Variable(capacity_));
507 
508  consoleDir()
509  .add("sndBuf", fty::Command(
510  SENF_MEMBINDFNP(void, TunnelClientInterface, sndBuf, (unsigned)))
511  .doc( "set the send socket buffer size in bytes"));
512  consoleDir()
513  .add("sndBuf", fty::Command(
515  .doc( "get the send socket buffer size in bytes"));
516  consoleDir()
517  .add("rcvBuf", fty::Command(
518  SENF_MEMBINDFNP(void, TunnelClientInterface, rcvBuf, (unsigned)))
519  .doc( "set the receive socket buffer size in bytes"));
520  consoleDir()
521  .add("rcvBuf", fty::Command(
523  .doc( "get the receive socket buffer size in bytes"));
524  consoleDir()
525  .add("fragmentationThreshold", fty::Command(
527  .doc( "set the fragmentationThreshold for this tunnel in bytes"));
528  consoleDir()
529  .add("fragmentationThreshold", fty::Command(
531  .doc( "get the fragmentationThreshold for this tunnel in bytes"));
532  consoleDir()
533  .add("maxBurst", fty::Command(
534  SENF_MEMBINDFNP(void, TunnelClientInterface, maxBurst, (unsigned)))
535  .doc( "set the maxBurst limit when receiving packets"));
536  consoleDir()
537  .add("maxBurst", fty::Command(
538  SENF_MEMBINDFNP(unsigned, TunnelClientInterface, maxBurst, () const))
539  .doc( "get the maxBurst limit when receiving packets"));
540 
541  capacity_[tunnel::FromClientToServer] = 100000u;
542  capacity_[tunnel::FromServerToClient] = 100000u;
543 }
544 
545 prefix_ void senf::emu::TunnelClientInterface::v_enable()
546 {
547  isUp(true);
548  UDPv6ClientSocketHandle socket (address());
549 // socket.connect(serverAddress()); // as a client: Only accept packets from our server
550  socket.blocking(false); // make sure we operate in non-blocking mode to avoid queuing on kernel tx problems
551  socket.protocol().mtuDiscovery(IP_PMTUDISC_DONT);
552 // socket.protocol().sndLowat(SENF_EMU_MAXMTU);
553  assignSocket(socket);
554  sndBuf(sndBufSize_);
555  rcvBuf(rcvBufSize_);
556  tunnelCtrl.reset();
557 }
558 
559 prefix_ void senf::emu::TunnelClientInterface::v_disable()
560 {
561  isUp(false);
562  assignSocket( UDPv6ClientSocketHandle(senf::noinit));
563  tunnelCtrl.reset();
564 }
565 
567 {
569 }
570 
572 {
573  tunnelCtrl.serverAddress( address);
574 }
575 
577  const
578 {
579  return tunnelCtrl.serverAddress();
580 }
581 
583  const
584 {
585  return tunnelCtrl.established();
586 }
587 
589  const
590 {
591  tunnel::Capacity::const_iterator i (capacity_.find(direction));
592  return i != capacity_.end() ? i->second : 0u;
593 }
594 
596 {
597  capacity_[direction] = cap;
598 }
599 
601  const
602 {
603  return ((detail::TunnelClientController&)tunnelCtrlBase()).fragmentationThreshold();
604 }
605 
607 {
609 }
610 
611 
613 {
614  // need to cache sndBufSize_ so we can (re-)apply the value in v_enable()
615  sndBufSize_ = std::max(sndbuf, 2048u);
616  TunnelInterfaceNet::sndBuf( sndBufSize_);
617 }
618 
620 {
621  // need to cache sndBufSize_ so we can (re-)apply the value in v_enable()
622  return sndBufSize_ = TunnelInterfaceNet::sndBuf();
623 }
624 
626 {
627  // need to cache rcvBufSize_ so we can (re-)apply the value in v_enable()
628  rcvBufSize_ = std::max(rcvbuf, 4096u);
629  TunnelInterfaceNet::rcvBuf( rcvBufSize_);
630 }
631 
633 {
634  // need to cache rcvBufSize_ so we can (re-)apply the value in v_enable()
635  return rcvBufSize_ = TunnelInterfaceNet::rcvBuf();
636 }
637 
638 prefix_ unsigned senf::emu::TunnelClientInterface::v_mtu()
639  const
640 {
641  return TunnelInterfaceNet::mtu();
642 }
643 
644 prefix_ void senf::emu::TunnelClientInterface::v_mtu(unsigned v)
645 {
646  TunnelInterfaceNet::mtu(v);
647 }
648 
650  const
651 {
652  return TunnelInterfaceNet::maxBurst();
653 }
654 
656 {
657  TunnelInterfaceNet::maxBurst(v);
658 }
659 
660 prefix_ void senf::emu::TunnelClientInterface::v_promisc(bool p)
661 {
662  TunnelInterfaceNet::_promisc(p);
663 }
664 
665 prefix_ bool senf::emu::TunnelClientInterface::v_promisc()
666  const
667 {
668  return TunnelInterfaceNet::_promisc();
669 }
670 
671 prefix_ void senf::emu::TunnelClientInterface::v_annotationMode(bool a)
672 {
673  TunnelInterfaceNet::_annotationMode(a);
674 }
675 
676 prefix_ bool senf::emu::TunnelClientInterface::v_annotationMode()
677  const
678 {
679  return TunnelInterfaceNet::_annotationMode();
680 }
681 
682 
683 //-/////////////////////////////////////////////////////////////////////////////////////////////////
684 #undef prefix_
685 
686 
687 // Local Variables:
688 // mode: c++
689 // fill-column: 100
690 // comment-column: 40
691 // c-file-style: "senf"
692 // indent-tabs-mode: nil
693 // ispell-local-dictionary: "american"
694 // compile-command: "scons -u test"
695 // End:
TunnelControlPacket public header.
TunnelClientInterface(INet6SocketAddress const &address)
unsigned capacity(tunnel::CapacityDirection direction) const
config::time_type clock_type
static MACAddress const None
#define SENF_EMU_MAXMTU
Definition: config.hh:40
Interface API base class
senf::ppi::QueueingAlgorithm & qAlgorithm() const
unsigned capacity(MACAddress const &client, tunnel::CapacityDirection direction) const
#define SENF_MEMBINDFNP(ret, cls, fn, args)
std::uint8_t mac[6]
ClockService::clock_type timeout() const
INet6SocketAddress const & address() const
#define SENF_LIKELY(x)
std::int32_t min
noinit
ProtocolClientSocketHandle< UDPv6SocketProtocol > UDPv6ClientSocketHandle
std::int32_t max
EthernetPacket prependAnnotationsPacket(Packet const &pkt, MACAddress const &src_=senf::MACAddress::None, MACAddress const &dst_=senf::MACAddress::Broadcast)
TunnelServerInterface(INet6SocketAddress const &address)
std::unique_ptr< QueueingAlgorithm > ptr
console::DirectoryNode & consoleDir() const
Access interface console directory.
static INet6Address from_inet4address(INet4Address const &addr)
NodeType & add(std::string const &name, boost::shared_ptr< NodeType > node)
detail::TunnelControllerBase & tunnelCtrlBase()
Tunnel Server Interface.
MACAddress const & id() const
Get interface MAC Address.
#define prefix_
INet6SocketAddress const & serverAddress() const
ppi::QueueingAlgorithm & qAlgorithm() const
SENF_CONSOLE_REGISTER_ENUM(CapacityDirection,(FromClientToServer)(FromServerToClient))
ClockService::clock_type timeout() const
unsigned fragmentationThreshold(MACAddress const &client) const
boost::shared_ptr< InterfaceIdFactoryBase > ifaceIdFactory()
TunnelInterface public header.
TunnelInterfaceBase(Output &output, Input &input, detail::TunnelControllerBase &ctrlBase, INet6SocketAddress const &address)
ConcretePacket< EthernetPacketType > EthernetPacket
unsigned port() const
AnnotationsPacket public header.
INet4Address address() const
#define SENF_UNLIKELY(x)