gem5  v20.1.0.0
ethertap.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2003-2005 The Regents of The University of Michigan
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met: redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer;
9  * redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution;
12  * neither the name of the copyright holders nor the names of its
13  * contributors may be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /* @file
30  * Interface to connect a simulated ethernet device to the real world
31  */
32 
33 #include "dev/net/ethertap.hh"
34 
35 #if defined(__OpenBSD__) || defined(__APPLE__)
36 #include <sys/param.h>
37 
38 #endif
39 
40 #if USE_TUNTAP && defined(__linux__)
41 #if 1 // Hide from the style checker since these have to be out of order.
42 #include <sys/socket.h> // Has to be included before if.h for some reason.
43 
44 #endif
45 
46 #include <linux/if.h>
47 #include <linux/if_tun.h>
48 
49 #endif
50 
51 #include <fcntl.h>
52 #include <netinet/in.h>
53 #include <sys/ioctl.h>
54 #include <unistd.h>
55 
56 #include <cstring>
57 #include <deque>
58 #include <string>
59 
60 #include "base/logging.hh"
61 #include "base/pollevent.hh"
62 #include "base/socket.hh"
63 #include "base/trace.hh"
64 #include "debug/Ethernet.hh"
65 #include "debug/EthernetData.hh"
66 #include "dev/net/etherdump.hh"
67 #include "dev/net/etherint.hh"
68 #include "dev/net/etherpkt.hh"
69 
70 using namespace std;
71 
72 class TapEvent : public PollEvent
73 {
74  protected:
76 
77  public:
78  TapEvent(EtherTapBase *_tap, int fd, int e)
79  : PollEvent(fd, e), tap(_tap) {}
80 
81  void
82  process(int revent) override
83  {
84  // Ensure that our event queue is active. It may not be since we get
85  // here from the PollQueue whenever a real packet happens to arrive.
87 
88  tap->recvReal(revent);
89  }
90 };
91 
93  : SimObject(p), buflen(p->bufsz), dump(p->dump), event(NULL),
94  interface(NULL),
95  txEvent([this]{ retransmit(); }, "EtherTapBase retransmit")
96 {
97  buffer = new uint8_t[buflen];
98  interface = new EtherTapInt(name() + ".interface", this);
99 }
100 
102 {
103  delete buffer;
104  delete event;
105  delete interface;
106 }
107 
108 void
110 {
112  uint8_t *buffer = (uint8_t *)this->buffer;
114 
115  bool tapevent_present = false;
116  if (event) {
117  tapevent_present = true;
118  SERIALIZE_SCALAR(tapevent_present);
119  event->serialize(cp);
120  } else {
121  SERIALIZE_SCALAR(tapevent_present);
122  }
123 }
124 
125 void
127 {
129  uint8_t *buffer = (uint8_t *)this->buffer;
131 
132  bool tapevent_present;
133  UNSERIALIZE_SCALAR(tapevent_present);
134  if (tapevent_present) {
135  event = new TapEvent(this, 0, 0);
136  event->unserialize(cp);
137  if (event->queued())
139  }
140 }
141 
142 
143 void
145 {
146  assert(!event);
147  event = new TapEvent(this, fd, POLLIN|POLLERR);
149 }
150 
151 void
153 {
154  assert(event);
155  delete event;
156  event = NULL;
157 }
158 
159 
160 Port &
161 EtherTapBase::getPort(const std::string &if_name, PortID idx)
162 {
163  if (if_name == "tap")
164  return *interface;
165  return SimObject::getPort(if_name, idx);
166 }
167 
168 bool
170 {
171  if (dump)
172  dump->dump(packet);
173 
174  DPRINTF(Ethernet, "EtherTap sim->real len=%d\n", packet->length);
175  DDUMP(EthernetData, packet->data, packet->length);
176 
177  bool success = sendReal(packet->data, packet->length);
178 
179  interface->recvDone();
180 
181  return success;
182 }
183 
184 void
186 {
187  EthPacketPtr packet;
188  packet = make_shared<EthPacketData>(len);
189  packet->length = len;
190  packet->simLength = len;
191  memcpy(packet->data, data, len);
192 
193  DPRINTF(Ethernet, "EtherTap real->sim len=%d\n", packet->length);
194  DDUMP(EthernetData, packet->data, packet->length);
195  if (!packetBuffer.empty() || !interface->sendPacket(packet)) {
196  DPRINTF(Ethernet, "bus busy...buffer for retransmission\n");
197  packetBuffer.push(packet);
198  if (!txEvent.scheduled())
200  } else if (dump) {
201  dump->dump(packet);
202  }
203 }
204 
205 void
207 {
208  if (packetBuffer.empty())
209  return;
210 
211  EthPacketPtr packet = packetBuffer.front();
212  if (interface->sendPacket(packet)) {
213  if (dump)
214  dump->dump(packet);
215  DPRINTF(Ethernet, "EtherTap retransmit\n");
216  packetBuffer.front() = NULL;
217  packetBuffer.pop();
218  }
219 
220  if (!packetBuffer.empty() && !txEvent.scheduled())
222 }
223 
224 
226 {
227  protected:
228  class Event : public PollEvent
229  {
230  protected:
232 
233  public:
234  Event(TapListener *l, int fd, int e) : PollEvent(fd, e), listener(l) {}
235 
236  void process(int revent) override { listener->accept(); }
237  };
238 
239  friend class Event;
241 
242  void accept();
243 
244  protected:
247  int port;
248 
249  public:
250  TapListener(EtherTapStub *t, int p) : event(NULL), tap(t), port(p) {}
251  ~TapListener() { delete event; }
252 
253  void listen();
254 };
255 
256 void
258 {
259  while (!listener.listen(port, true)) {
260  DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port);
261  port++;
262  }
263 
264  ccprintf(cerr, "Listening for tap connection on port %d\n", port);
265  event = new Event(this, listener.getfd(), POLLIN|POLLERR);
267 }
268 
269 void
271 {
272  // As a consequence of being called from the PollQueue, we might
273  // have been called from a different thread. Migrate to "our"
274  // thread.
276 
277  if (!listener.islistening())
278  panic("TapListener(accept): cannot accept if we're not listening!");
279 
280  int sfd = listener.accept(true);
281  if (sfd != -1)
282  tap->attach(sfd);
283 }
284 
285 
287 {
289  fatal("All listeners are disabled! EtherTapStub can't work!");
290 
291  listener = new TapListener(this, p->port);
292  listener->listen();
293 }
294 
296 {
297  delete listener;
298 }
299 
300 void
302 {
304 
308 }
309 
310 void
312 {
314 
318 }
319 
320 
321 void
323 {
324  if (socket != -1)
325  close(fd);
326 
327  buffer_used = 0;
328  frame_len = 0;
329  socket = fd;
330  DPRINTF(Ethernet, "EtherTapStub attached\n");
331  pollFd(socket);
332 }
333 
334 void
336 {
337  DPRINTF(Ethernet, "EtherTapStub detached\n");
338  stopPolling();
339  close(socket);
340  socket = -1;
341 }
342 
343 void
345 {
346  if (revent & POLLERR) {
347  detach();
348  return;
349  }
350 
351  if (!(revent & POLLIN))
352  return;
353 
354  // Read in as much of the new data as we can.
355  int len = read(socket, buffer + buffer_used, buflen - buffer_used);
356  if (len == 0) {
357  detach();
358  return;
359  }
360  buffer_used += len;
361 
362  // If there's not enough data for the frame length, wait for more.
363  if (buffer_used < sizeof(uint32_t))
364  return;
365 
366  if (frame_len == 0)
367  frame_len = ntohl(*(uint32_t *)buffer);
368 
369  DPRINTF(Ethernet, "Received data from peer: len=%d buffer_used=%d "
370  "frame_len=%d\n", len, buffer_used, frame_len);
371 
372  uint8_t *frame_start = &buffer[sizeof(uint32_t)];
373  while (frame_len != 0 && buffer_used >= frame_len + sizeof(uint32_t)) {
374  sendSimulated(frame_start, frame_len);
375 
376  // Bookkeeping.
377  buffer_used -= frame_len + sizeof(uint32_t);
378  if (buffer_used > 0) {
379  // If there's still any data left, move it into position.
380  memmove(buffer, frame_start + frame_len, buffer_used);
381  }
382  frame_len = 0;
383 
384  if (buffer_used >= sizeof(uint32_t))
385  frame_len = ntohl(*(uint32_t *)buffer);
386  }
387 }
388 
389 bool
390 EtherTapStub::sendReal(const void *data, size_t len)
391 {
392  uint32_t frame_len = htonl(len);
393  ssize_t ret = write(socket, &frame_len, sizeof(frame_len));
394  if (ret != sizeof(frame_len))
395  return false;
396  return write(socket, data, len) == len;
397 }
398 
399 
400 #if USE_TUNTAP
401 
402 EtherTap::EtherTap(const Params *p) : EtherTapBase(p)
403 {
404  int fd = open(p->tun_clone_device.c_str(), O_RDWR | O_NONBLOCK);
405  if (fd < 0)
406  panic("Couldn't open %s.\n", p->tun_clone_device);
407 
408  struct ifreq ifr;
409  memset(&ifr, 0, sizeof(ifr));
410  ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
411  strncpy(ifr.ifr_name, p->tap_device_name.c_str(), IFNAMSIZ - 1);
412 
413  if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0)
414  panic("Failed to access tap device %s.\n", ifr.ifr_name);
415  // fd now refers to the tap device.
416  tap = fd;
417  pollFd(tap);
418 }
419 
420 EtherTap::~EtherTap()
421 {
422  stopPolling();
423  close(tap);
424  tap = -1;
425 }
426 
427 void
428 EtherTap::recvReal(int revent)
429 {
430  if (revent & POLLERR)
431  panic("Error polling for tap data.\n");
432 
433  if (!(revent & POLLIN))
434  return;
435 
436  ssize_t ret;
437  while ((ret = read(tap, buffer, buflen))) {
438  if (ret < 0) {
439  if (errno == EAGAIN)
440  break;
441  panic("Failed to read from tap device.\n");
442  }
443 
444  sendSimulated(buffer, ret);
445  }
446 }
447 
448 bool
449 EtherTap::sendReal(const void *data, size_t len)
450 {
451  int n;
452  pollfd pfd[1];
453  pfd->fd = tap;
454  pfd->events = POLLOUT;
455 
456  // `tap` is a nonblock fd. Here we try to write until success, and use
457  // poll to make a blocking wait.
458  while ((n = write(tap, data, len)) != len) {
459  if (errno != EAGAIN)
460  panic("Failed to write data to tap device.\n");
461  pfd->revents = 0;
462  int ret = poll(pfd, 1, -1);
463  // timeout is set to inf, we shouldn't get 0 in any case.
464  assert(ret != 0);
465  if (ret == -1 || (ret == 1 && (pfd->revents & POLLERR))) {
466  panic("Failed when polling to write data to tap device.\n");
467  }
468  }
469  return true;
470 }
471 
472 EtherTap *
473 EtherTapParams::create()
474 {
475  return new EtherTap(this);
476 }
477 
478 #endif
479 
480 EtherTapStub *
481 EtherTapStubParams::create()
482 {
483  return new EtherTapStub(this);
484 }
fatal
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:183
Event::scheduled
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:460
socket.hh
SimClock::Int::ns
Tick ns
nanosecond
Definition: core.cc:65
ListenSocket
Definition: socket.hh:32
TapListener::listener
ListenSocket listener
Definition: ethertap.cc:245
EtherTapStub::recvReal
void recvReal(int revent) override
Definition: ethertap.cc:344
ListenSocket::listen
virtual bool listen(int port, bool reuse=true)
Definition: socket.cc:99
TapListener::TapListener
TapListener(EtherTapStub *t, int p)
Definition: ethertap.cc:250
data
const char data[]
Definition: circlebuf.test.cc:42
EtherTapBase::sendReal
virtual bool sendReal(const void *data, size_t len)=0
UNSERIALIZE_SCALAR
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:797
TapEvent::TapEvent
TapEvent(EtherTapBase *_tap, int fd, int e)
Definition: ethertap.cc:78
EtherTapBase::stopPolling
void stopPolling()
Definition: ethertap.cc:152
EtherTapBase::retransmit
void retransmit()
Definition: ethertap.cc:206
TapListener::port
int port
Definition: ethertap.cc:247
TapListener::Event::listener
TapListener * listener
Definition: ethertap.cc:231
TapListener::accept
void accept()
Definition: ethertap.cc:270
ArmISA::fd
Bitfield< 14, 12 > fd
Definition: types.hh:159
EtherTapStub::EtherTapStub
EtherTapStub(const Params *p)
Definition: ethertap.cc:286
etherint.hh
etherdump.hh
ListenSocket::accept
virtual int accept(bool nodelay=false)
Definition: socket.cc:148
EtherTapBase::sendSimulated
void sendSimulated(void *data, size_t len)
Definition: ethertap.cc:185
PortID
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition: types.hh:237
EtherTapStub
Definition: ethertap.hh:136
EtherTapBase::recvReal
virtual void recvReal(int revent)=0
EtherTapBase::buflen
int buflen
Definition: ethertap.hh:74
PollQueue::schedule
void schedule(PollEvent *event)
Definition: pollevent.cc:159
TapEvent
Definition: ethertap.cc:72
TapListener::listen
void listen()
Definition: ethertap.cc:257
EtherTapStub::unserialize
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: ethertap.cc:311
EtherTapBase::interface
EtherTapInt * interface
Definition: ethertap.hh:98
EtherTapStub::buffer_used
uint32_t buffer_used
Definition: ethertap.hh:162
EtherTapBase::TapEvent
friend class TapEvent
Definition: ethertap.hh:83
ArmISA::n
Bitfield< 31 > n
Definition: miscregs_types.hh:450
pollQueue
PollQueue pollQueue
Definition: pollevent.cc:55
EtherTapStub::socket
int socket
Definition: ethertap.hh:157
cp
Definition: cprintf.cc:40
EventManager::schedule
void schedule(Event &event, Tick when)
Definition: eventq.hh:1005
EtherTapStub::listener
TapListener * listener
Definition: ethertap.hh:155
SimObject::getPort
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
Definition: sim_object.cc:123
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:234
EtherTapInt
Definition: ethertap.hh:113
ListenSocket::getfd
int getfd() const
Definition: socket.hh:72
MipsISA::event
Bitfield< 10, 5 > event
Definition: pra_constants.hh:297
pollevent.hh
Port
Ports are used to interface objects to each other.
Definition: port.hh:56
ListenSocket::islistening
bool islistening() const
Definition: socket.hh:73
EtherTapBase::unserialize
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: ethertap.cc:126
TapListener::tap
EtherTapStub * tap
Definition: ethertap.cc:246
SERIALIZE_ARRAY
#define SERIALIZE_ARRAY(member, size)
Definition: serialize.hh:832
EtherTapBase::serialize
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: ethertap.cc:109
EventManager::eventQueue
EventQueue * eventQueue() const
Definition: eventq.hh:996
name
const std::string & name()
Definition: trace.cc:50
SERIALIZE_SCALAR
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:790
DDUMP
#define DDUMP(x, data, count)
DPRINTF is a debugging trace facility that allows one to selectively enable tracing statements.
Definition: trace.hh:233
ethertap.hh
EtherTapBase::event
TapEvent * event
Definition: ethertap.hh:84
EtherTapBase::getPort
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Definition: ethertap.cc:161
PollEvent::queued
bool queued()
Definition: pollevent.hh:70
TapListener
Definition: ethertap.cc:225
EtherTapStub::attach
void attach(int fd)
Definition: ethertap.cc:322
ArmISA::e
Bitfield< 9 > e
Definition: miscregs_types.hh:61
TapListener::Event::process
void process(int revent) override
Definition: ethertap.cc:236
EtherTapBase::EtherTapBase
EtherTapBase(const Params *p)
Definition: ethertap.cc:92
EthPacketPtr
std::shared_ptr< EthPacketData > EthPacketPtr
Definition: etherpkt.hh:87
ListenSocket::allDisabled
static bool allDisabled()
Definition: socket.cc:70
EventQueue::ScopedMigration
Definition: eventq.hh:665
TapEvent::process
void process(int revent) override
Definition: ethertap.cc:82
EtherInt::recvDone
void recvDone()
Definition: etherint.hh:67
UNSERIALIZE_ARRAY
#define UNSERIALIZE_ARRAY(member, size)
Definition: serialize.hh:840
std
Overload hash function for BasicBlockRange type.
Definition: vec_reg.hh:587
ArmISA::t
Bitfield< 5 > t
Definition: miscregs_types.hh:67
TapListener::Event
friend class Event
Definition: ethertap.cc:239
Stats::dump
void dump()
Dump all statistics data to the registered outputs.
Definition: statistics.cc:560
ArmISA::len
Bitfield< 18, 16 > len
Definition: miscregs_types.hh:439
ccprintf
void ccprintf(cp::Print &print)
Definition: cprintf.hh:127
EtherTapStub::frame_len
uint32_t frame_len
Definition: ethertap.hh:163
logging.hh
etherpkt.hh
TapEvent::tap
EtherTapBase * tap
Definition: ethertap.cc:75
EtherTapBase::Params
EtherTapBaseParams Params
Definition: ethertap.hh:59
CheckpointOut
std::ostream CheckpointOut
Definition: serialize.hh:63
EtherInt::sendPacket
bool sendPacket(EthPacketPtr packet)
Definition: etherint.hh:70
EtherTapBase::~EtherTapBase
virtual ~EtherTapBase()
Definition: ethertap.cc:101
EtherTapBase::pollFd
void pollFd(int fd)
Definition: ethertap.cc:144
trace.hh
EtherTapBase::buffer
uint8_t * buffer
Definition: ethertap.hh:73
EtherTapStub::detach
void detach()
Definition: ethertap.cc:335
PollEvent
Definition: pollevent.hh:41
MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:323
TapListener::event
Event * event
Definition: ethertap.cc:240
TapListener::Event::Event
Event(TapListener *l, int fd, int e)
Definition: ethertap.cc:234
CheckpointIn
Definition: serialize.hh:67
MipsISA::l
Bitfield< 5 > l
Definition: pra_constants.hh:320
EtherTapBase::txEvent
EventFunctionWrapper txEvent
Definition: ethertap.hh:110
EtherTapStub::~EtherTapStub
~EtherTapStub()
Definition: ethertap.cc:295
EtherTapStub::TapListener
friend class TapListener
Definition: ethertap.hh:154
TapListener::Event
Definition: ethertap.cc:228
EtherTapBase::packetBuffer
std::queue< EthPacketPtr > packetBuffer
Definition: ethertap.hh:108
EtherTapBase::recvSimulated
bool recvSimulated(EthPacketPtr packet)
Definition: ethertap.cc:169
EtherTapStub::serialize
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: ethertap.cc:301
EtherTapBase
Definition: ethertap.hh:56
TapListener::~TapListener
~TapListener()
Definition: ethertap.cc:251
EtherDump::dump
void dump(EthPacketPtr &pkt)
Definition: etherdump.hh:57
EtherTapBase::dump
EtherDump * dump
Definition: ethertap.hh:76
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:171
curTick
Tick curTick()
The current simulated tick.
Definition: core.hh:45
EtherTapStub::sendReal
bool sendReal(const void *data, size_t len) override
Definition: ethertap.cc:390
SimObject
Abstract superclass for simulation objects.
Definition: sim_object.hh:92

Generated on Wed Sep 30 2020 14:02:11 for gem5 by doxygen 1.8.17