EthernetAnnotator.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 // Custom includes
18 #include "EthernetAnnotator.hh"
19 
22 
23 #define prefix_
24 
26  : id_ (id),
27  pvid_(VLanId::None),
28  vlanMismatch_(0),
29  annotate_(false),
30  rxMode_(rxMode), mmapMode_(mmapMode)
31 {
32  route(input, output).autoThrottling( false);
34  if (rxMode_) {
35  if (mmapMode_) {
36  input.onRequest(&EthernetAnnotator::requestRxMMAP);
37  } else {
38  input.onRequest(&EthernetAnnotator::requestRx);
39  }
40  }
41  else {
42  input.onRequest(&EthernetAnnotator::requestTx);
43  }
44 
45  handle_pkt = std::bind(&senf::emu::EthernetAnnotator::handle_pkt_dummy, this, std::placeholders::_1);
46 }
47 
49 {
50  id_ = id;
51 }
52 
54  const
55 {
56  return id_;
57 }
58 
60 {
61  annotate_ = a;
62  if (rxMode_ and !pvid_) {
63  if (annotate_)
64  handle_pkt = std::bind(&senf::emu::EthernetAnnotator::handle_pkt_dummy_annotate, this, std::placeholders::_1);
65  else
66  handle_pkt = std::bind(&senf::emu::EthernetAnnotator::handle_pkt_dummy, this, std::placeholders::_1);
67  }
68 }
69 
71  const
72 {
73  return annotate_;
74 }
75 
77 {
78  if (rxMode_ and mmapMode_) {
79  if (p)
80  input.onRequest(&EthernetAnnotator::requestRxMMAPpromisc);
81  else
82  input.onRequest(&EthernetAnnotator::requestRxMMAP);
83  }
84 }
85 
87 {
88  std::uint32_t tmp (vlanMismatch_);
89  vlanMismatch_ = 0;
90  return tmp;
91 }
92 
93 prefix_ void senf::emu::EthernetAnnotator::netemu_annotations(senf::EthernetPacket const & eth)
94 {
95  eth.annotation<annotations::Interface>().value = id_;
96  {
97  emu::annotations::Quality const & q (eth.annotation<emu::annotations::Quality>());
98  q.rssi = 127; // for now, we report the maximum signal 'quality'
99  q.noise = -128; // this should be read out via ethtool commands (i.e. for fiber links)
100  q.snr = 255;
101  q.flags.frameLength = eth.size();
102  }
103 }
104 
105 prefix_ void senf::emu::EthernetAnnotator::requestRx()
106 {
107  senf::EthernetPacket const & eth (input());
108 
109  netemu_annotations(eth);
110  eth.annotation<annotations::Timestamp>().fromScheduler();
111 
112  handle_pkt(eth);
113 }
114 
115 prefix_ void senf::emu::EthernetAnnotator::requestRxMMAP()
116 {
117  senf::EthernetPacket const & eth (input());
118 
119  netemu_annotations(eth);
120  eth.annotation<annotations::Timestamp>().fromQueueBuffer(*(eth.annotation<senf::ppi::QueueBufferAnnotation>().value));
121 
122  handle_pkt(eth);
123 }
124 
125 prefix_ void senf::emu::EthernetAnnotator::requestRxMMAPpromisc()
126 {
127  senf::EthernetPacket const & eth (input());
128 
129  netemu_annotations(eth);
130  eth.annotation<annotations::Timestamp>().fromQueueBuffer(*(eth.annotation<senf::ppi::QueueBufferAnnotation>().value));
131 
132  // check, if the h/w has removed the VLAN tag...
133  // this might happen if VLAN offloading is not configured/working properly !!!
134  boost::optional<unsigned> vlanId (eth.annotation<senf::ppi::QueueBufferAnnotation>()->vlan());
135  if (SENF_UNLIKELY(vlanId)) {
136  // put the tag BACK in as outer TAG
138  EthVLanSPacket vlan (EthVLanSPacket::createInsertBefore(eth.next()));
139  vlan->vlanId() << *vlanId;
140  vlan->type_length() << eth->type_length();
141  EthernetPacket(eth).finalizeTo(vlan);
142  vlan.reparse();
143  } else {
144  EthVLanCPacket vlan (EthVLanCPacket::createInsertBefore(eth.next()));
145  vlan->vlanId() << *vlanId;
146  vlan->type_length() << eth->type_length();
147  EthernetPacket(eth).finalizeTo(vlan);
148  vlan.reparse();
149  }
150  }
151 
152  handle_pkt(eth);
153 }
154 
155 
156 prefix_ void senf::emu::EthernetAnnotator::requestTx()
157 {
158  senf::EthernetPacket const & eth (input());
159 
160  handle_pkt(eth);
161 }
162 
164 {
165  pvid_ = pvid;
166  handle_pkt = std::bind(&senf::emu::EthernetAnnotator::handle_pkt_insert_tag, this, std::placeholders::_1);
167 }
168 
170 {
171  pvid_ = pvid;
172  handle_pkt = std::bind(&senf::emu::EthernetAnnotator::handle_pkt_remove_tag, this, std::placeholders::_1);
173 }
174 
176 {
177  pvid_ = VLanId::None;
178  handle_pkt = std::bind(&senf::emu::EthernetAnnotator::handle_pkt_dummy, this, std::placeholders::_1);
179 }
180 
181 prefix_ void senf::emu::EthernetAnnotator::handle_pkt_dummy(senf::EthernetPacket const & eth)
182 {
183  output(eth);
184 }
185 
186 prefix_ void senf::emu::EthernetAnnotator::handle_pkt_dummy_annotate(senf::EthernetPacket const & eth)
187 {
189 }
190 
191 prefix_ void senf::emu::EthernetAnnotator::handle_pkt_remove_tag(senf::EthernetPacket const & eth)
192 {
193  if (eth->type_length() == EthVLanCPacketType::etherType) {
194  auto vlan (eth.next<EthVLanCPacket>(senf::nothrow));
195  if (SENF_UNLIKELY(!vlan or (vlan->vlanId() != pvid_.id()) or !pvid_.ctag())) {
196  vlanMismatch_++;
197  return;
198  }
199 
200  // remove outer VLAN C-TAG here
201  std::uint16_t tl (vlan->type_length());
202  ::memmove(
203  vlan.data().begin(),
204  vlan.data().begin() + senf::EthVLanPacketParser::fixed_bytes,
205  vlan.size() - senf::EthVLanPacketParser::fixed_bytes);
206 
207  EthernetPacket tmp(eth);
208  tmp.data().resize( tmp.size() - senf::EthVLanPacketParser::fixed_bytes);
209  tmp->type_length() = tl;
210  tmp.reparse();
211  } else if (eth->type_length() == EthVLanSPacketType::etherType) {
212  auto vlan (eth.next<EthVLanSPacket>(senf::nothrow));
213  if (SENF_UNLIKELY(!vlan or (vlan->vlanId() != pvid_.id()) or !pvid_.stag())) {
214  vlanMismatch_++;
215  return;
216  }
217 
218  // remove outer VLAN S-TAG here
219  std::uint16_t tl (vlan->type_length());
220  ::memmove(
221  vlan.data().begin(),
222  vlan.data().begin() + senf::EthVLanPacketParser::fixed_bytes,
223  vlan.size() - senf::EthVLanPacketParser::fixed_bytes);
224 
225  EthernetPacket tmp(eth);
226  tmp.data().resize( tmp.size() - senf::EthVLanPacketParser::fixed_bytes);
227  tmp->type_length() = tl;
228  tmp.reparse();
229  } else {
230  vlanMismatch_++;
231  return;
232  }
233 
234  if (SENF_UNLIKELY(annotate_))
236  else
237  output(eth);
238 }
239 
240 prefix_ void senf::emu::EthernetAnnotator::handle_pkt_insert_tag(senf::EthernetPacket const & eth)
241 {
242  // If a C-TAG PVID is configured, we only except untagged frames
243  if (pvid_.ctag()) {
244  senf::EthVLanCPacket const & vlanC (eth.next<senf::EthVLanCPacket>(senf::nothrow));
245  if (SENF_UNLIKELY(vlanC)) {
246  vlanMismatch_++;
247  return;
248  }
249  senf::EthVLanSPacket const & vlanS (eth.next<senf::EthVLanSPacket>(senf::nothrow));
250  if (SENF_UNLIKELY(vlanS)) {
251  vlanMismatch_++;
252  return;
253  }
254  } else {
255  // S-TAGs are always added
256  }
257 
258  std::uint16_t tl (eth->type_length());
259  senf::Packet const & pkt (eth.next(senf::nothrow));
260  if (SENF_LIKELY(pkt)) {
261  if (pvid_.ctag()) {
262  senf::EthVLanCPacket vtmp (senf::EthVLanCPacket::createInsertBefore(pkt));
263  vtmp->vlanId() = pvid_.id();
264  vtmp->type_length() = tl;
265  EthernetPacket(eth).finalizeTo(vtmp);
266  } else {
267  senf::EthVLanSPacket vtmp (senf::EthVLanSPacket::createInsertBefore(pkt));
268  vtmp->vlanId() = pvid_.id();
269  vtmp->type_length() = tl;
270  EthernetPacket(eth).finalizeTo(vtmp);
271  }
272  } else {
273  if (pvid_.ctag()) {
274  senf::EthVLanCPacket vtmp (senf::EthVLanCPacket::createAfter(eth));
275  vtmp->vlanId() = pvid_.id();
276  vtmp->type_length() = tl;
277  EthernetPacket(eth).finalizeTo(vtmp);
278  } else {
279  senf::EthVLanSPacket vtmp (senf::EthVLanSPacket::createAfter(eth));
280  vtmp->vlanId() = pvid_.id();
281  vtmp->type_length() = tl;
282  EthernetPacket(eth).finalizeTo(vtmp);
283  }
284  }
285 
286  if (SENF_UNLIKELY(annotate_))
288  else
289  output(eth);
290 }
291 
292 //-/////////////////////////////////////////////////////////////////////////////////////////////////
293 #undef prefix_
unsigned tpid() const
#define prefix_
EthernetAnnotator(bool rxMode, bool mmapMode, senf::MACAddress const &id_=senf::MACAddress::None)
Route< connector::InputConnector, connector::OutputConnector > & route(connector::InputConnector &input, connector::OutputConnector &output)
Incoming or outgoing interface.
Definition: Annotations.hh:37
ppi::connector::ActiveOutput< senf::EthernetPacket > output
QueueReadPolicy::Buffer const * value
ConcretePacket< EthVLanSPacketType > EthVLanSPacket
static const EtherTypes::key_t etherType
#define SENF_LIKELY(x)
static VLanId const None
Definition: VLanId.hh:35
Annotations public header.
std::uint16_t id() const
HardwareEthernetInterface internal header.
EthernetPacket prependAnnotationsPacket(Packet const &pkt, MACAddress const &src_=senf::MACAddress::None, MACAddress const &dst_=senf::MACAddress::Broadcast)
static const EtherTypes::key_t etherType
void insertTag(VLanId const &pvid)
bool stag() const
MACAddress const & id() const
ppi::connector::PassiveInput< senf::EthernetPacket > input
Incoming packet timestamp.
Definition: Annotations.hh:86
void removeTag(VLanId const &pvid)
ConcretePacket< EthVLanCPacketType > EthVLanCPacket
nothrow
boost::optional< unsigned > vlan() const
void finalizeTo()
ConcretePacket< EthernetPacketType > EthernetPacket
AnnotationsPacket public header.
#define SENF_UNLIKELY(x)
void throttlingDisc(ThrottlingDisc const &disc)
bool ctag() const