gem5  v19.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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  * Authors: Nathan Binkert
29  */
30 
31 /* @file
32  * Interface to connect a simulated ethernet device to the real world
33  */
34 
35 #include "dev/net/ethertap.hh"
36 
37 #if defined(__OpenBSD__) || defined(__APPLE__)
38 #include <sys/param.h>
39 
40 #endif
41 
42 #if USE_TUNTAP && defined(__linux__)
43 #if 1 // Hide from the style checker since these have to be out of order.
44 #include <sys/socket.h> // Has to be included before if.h for some reason.
45 
46 #endif
47 
48 #include <linux/if.h>
49 #include <linux/if_tun.h>
50 
51 #endif
52 
53 #include <fcntl.h>
54 #include <netinet/in.h>
55 #include <sys/ioctl.h>
56 #include <unistd.h>
57 
58 #include <cstring>
59 #include <deque>
60 #include <string>
61 
62 #include "base/logging.hh"
63 #include "base/pollevent.hh"
64 #include "base/socket.hh"
65 #include "base/trace.hh"
66 #include "debug/Ethernet.hh"
67 #include "debug/EthernetData.hh"
68 #include "dev/net/etherdump.hh"
69 #include "dev/net/etherint.hh"
70 #include "dev/net/etherpkt.hh"
71 
72 using namespace std;
73 
74 class TapEvent : public PollEvent
75 {
76  protected:
78 
79  public:
80  TapEvent(EtherTapBase *_tap, int fd, int e)
81  : PollEvent(fd, e), tap(_tap) {}
82 
83  void
84  process(int revent) override
85  {
86  // Ensure that our event queue is active. It may not be since we get
87  // here from the PollQueue whenever a real packet happens to arrive.
89 
90  tap->recvReal(revent);
91  }
92 };
93 
95  : SimObject(p), buflen(p->bufsz), dump(p->dump), event(NULL),
96  interface(NULL),
97  txEvent([this]{ retransmit(); }, "EtherTapBase retransmit")
98 {
99  buffer = new uint8_t[buflen];
100  interface = new EtherTapInt(name() + ".interface", this);
101 }
102 
104 {
105  delete buffer;
106  delete event;
107  delete interface;
108 }
109 
110 void
112 {
114  uint8_t *buffer = (uint8_t *)this->buffer;
115  SERIALIZE_ARRAY(buffer, buflen);
116 
117  bool tapevent_present = false;
118  if (event) {
119  tapevent_present = true;
120  SERIALIZE_SCALAR(tapevent_present);
121  event->serialize(cp);
122  } else {
123  SERIALIZE_SCALAR(tapevent_present);
124  }
125 }
126 
127 void
129 {
131  uint8_t *buffer = (uint8_t *)this->buffer;
132  UNSERIALIZE_ARRAY(buffer, buflen);
133 
134  bool tapevent_present;
135  UNSERIALIZE_SCALAR(tapevent_present);
136  if (tapevent_present) {
137  event = new TapEvent(this, 0, 0);
138  event->unserialize(cp);
139  if (event->queued())
141  }
142 }
143 
144 
145 void
147 {
148  assert(!event);
149  event = new TapEvent(this, fd, POLLIN|POLLERR);
151 }
152 
153 void
155 {
156  assert(event);
157  delete event;
158  event = NULL;
159 }
160 
161 
162 Port &
163 EtherTapBase::getPort(const std::string &if_name, PortID idx)
164 {
165  if (if_name == "tap")
166  return *interface;
167  return SimObject::getPort(if_name, idx);
168 }
169 
170 bool
172 {
173  if (dump)
174  dump->dump(packet);
175 
176  DPRINTF(Ethernet, "EtherTap sim->real len=%d\n", packet->length);
177  DDUMP(EthernetData, packet->data, packet->length);
178 
179  bool success = sendReal(packet->data, packet->length);
180 
181  interface->recvDone();
182 
183  return success;
184 }
185 
186 void
188 {
189  EthPacketPtr packet;
190  packet = make_shared<EthPacketData>(len);
191  packet->length = len;
192  packet->simLength = len;
193  memcpy(packet->data, data, len);
194 
195  DPRINTF(Ethernet, "EtherTap real->sim len=%d\n", packet->length);
196  DDUMP(EthernetData, packet->data, packet->length);
197  if (!packetBuffer.empty() || !interface->sendPacket(packet)) {
198  DPRINTF(Ethernet, "bus busy...buffer for retransmission\n");
199  packetBuffer.push(packet);
200  if (!txEvent.scheduled())
202  } else if (dump) {
203  dump->dump(packet);
204  }
205 }
206 
207 void
209 {
210  if (packetBuffer.empty())
211  return;
212 
213  EthPacketPtr packet = packetBuffer.front();
214  if (interface->sendPacket(packet)) {
215  if (dump)
216  dump->dump(packet);
217  DPRINTF(Ethernet, "EtherTap retransmit\n");
218  packetBuffer.front() = NULL;
219  packetBuffer.pop();
220  }
221 
222  if (!packetBuffer.empty() && !txEvent.scheduled())
224 }
225 
226 
228 {
229  protected:
230  class Event : public PollEvent
231  {
232  protected:
234 
235  public:
236  Event(TapListener *l, int fd, int e) : PollEvent(fd, e), listener(l) {}
237 
238  void process(int revent) override { listener->accept(); }
239  };
240 
241  friend class Event;
243 
244  void accept();
245 
246  protected:
249  int port;
250 
251  public:
252  TapListener(EtherTapStub *t, int p) : event(NULL), tap(t), port(p) {}
253  ~TapListener() { delete event; }
254 
255  void listen();
256 };
257 
258 void
260 {
261  while (!listener.listen(port, true)) {
262  DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port);
263  port++;
264  }
265 
266  ccprintf(cerr, "Listening for tap connection on port %d\n", port);
267  event = new Event(this, listener.getfd(), POLLIN|POLLERR);
269 }
270 
271 void
273 {
274  // As a consequence of being called from the PollQueue, we might
275  // have been called from a different thread. Migrate to "our"
276  // thread.
277  EventQueue::ScopedMigration migrate(tap->eventQueue());
278 
279  if (!listener.islistening())
280  panic("TapListener(accept): cannot accept if we're not listening!");
281 
282  int sfd = listener.accept(true);
283  if (sfd != -1)
284  tap->attach(sfd);
285 }
286 
287 
289 {
291  fatal("All listeners are disabled! EtherTapStub can't work!");
292 
293  listener = new TapListener(this, p->port);
294  listener->listen();
295 }
296 
298 {
299  delete listener;
300 }
301 
302 void
304 {
306 
310 }
311 
312 void
314 {
316 
320 }
321 
322 
323 void
325 {
326  if (socket != -1)
327  close(fd);
328 
329  buffer_used = 0;
330  frame_len = 0;
331  socket = fd;
332  DPRINTF(Ethernet, "EtherTapStub attached\n");
333  pollFd(socket);
334 }
335 
336 void
338 {
339  DPRINTF(Ethernet, "EtherTapStub detached\n");
340  stopPolling();
341  close(socket);
342  socket = -1;
343 }
344 
345 void
347 {
348  if (revent & POLLERR) {
349  detach();
350  return;
351  }
352 
353  if (!(revent & POLLIN))
354  return;
355 
356  // Read in as much of the new data as we can.
357  int len = read(socket, buffer + buffer_used, buflen - buffer_used);
358  if (len == 0) {
359  detach();
360  return;
361  }
362  buffer_used += len;
363 
364  // If there's not enough data for the frame length, wait for more.
365  if (buffer_used < sizeof(uint32_t))
366  return;
367 
368  if (frame_len == 0)
369  frame_len = ntohl(*(uint32_t *)buffer);
370 
371  DPRINTF(Ethernet, "Received data from peer: len=%d buffer_used=%d "
372  "frame_len=%d\n", len, buffer_used, frame_len);
373 
374  uint8_t *frame_start = &buffer[sizeof(uint32_t)];
375  while (frame_len != 0 && buffer_used >= frame_len + sizeof(uint32_t)) {
376  sendSimulated(frame_start, frame_len);
377 
378  // Bookkeeping.
379  buffer_used -= frame_len + sizeof(uint32_t);
380  if (buffer_used > 0) {
381  // If there's still any data left, move it into position.
382  memmove(buffer, frame_start + frame_len, buffer_used);
383  }
384  frame_len = 0;
385 
386  if (buffer_used >= sizeof(uint32_t))
387  frame_len = ntohl(*(uint32_t *)buffer);
388  }
389 }
390 
391 bool
392 EtherTapStub::sendReal(const void *data, size_t len)
393 {
394  uint32_t frame_len = htonl(len);
395  ssize_t ret = write(socket, &frame_len, sizeof(frame_len));
396  if (ret != sizeof(frame_len))
397  return false;
398  return write(socket, data, len) == len;
399 }
400 
401 
402 #if USE_TUNTAP
403 
404 EtherTap::EtherTap(const Params *p) : EtherTapBase(p)
405 {
406  int fd = open(p->tun_clone_device.c_str(), O_RDWR | O_NONBLOCK);
407  if (fd < 0)
408  panic("Couldn't open %s.\n", p->tun_clone_device);
409 
410  struct ifreq ifr;
411  memset(&ifr, 0, sizeof(ifr));
412  ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
413  strncpy(ifr.ifr_name, p->tap_device_name.c_str(), IFNAMSIZ - 1);
414 
415  if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0)
416  panic("Failed to access tap device %s.\n", ifr.ifr_name);
417  // fd now refers to the tap device.
418  tap = fd;
419  pollFd(tap);
420 }
421 
422 EtherTap::~EtherTap()
423 {
424  stopPolling();
425  close(tap);
426  tap = -1;
427 }
428 
429 void
430 EtherTap::recvReal(int revent)
431 {
432  if (revent & POLLERR)
433  panic("Error polling for tap data.\n");
434 
435  if (!(revent & POLLIN))
436  return;
437 
438  ssize_t ret;
439  while ((ret = read(tap, buffer, buflen))) {
440  if (ret < 0) {
441  if (errno == EAGAIN)
442  break;
443  panic("Failed to read from tap device.\n");
444  }
445 
446  sendSimulated(buffer, ret);
447  }
448 }
449 
450 bool
451 EtherTap::sendReal(const void *data, size_t len)
452 {
453  int n;
454  pollfd pfd[1];
455  pfd->fd = tap;
456  pfd->events = POLLOUT;
457 
458  // `tap` is a nonblock fd. Here we try to write until success, and use
459  // poll to make a blocking wait.
460  while ((n = write(tap, data, len)) != len) {
461  if (errno != EAGAIN)
462  panic("Failed to write data to tap device.\n");
463  pfd->revents = 0;
464  int ret = poll(pfd, 1, -1);
465  // timeout is set to inf, we shouldn't get 0 in any case.
466  assert(ret != 0);
467  if (ret == -1 || (ret == 1 && (pfd->revents & POLLERR))) {
468  panic("Failed when polling to write data to tap device.\n");
469  }
470  }
471  return true;
472 }
473 
474 EtherTap *
475 EtherTapParams::create()
476 {
477  return new EtherTap(this);
478 }
479 
480 #endif
481 
482 EtherTapStub *
483 EtherTapStubParams::create()
484 {
485  return new EtherTapStub(this);
486 }
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:167
ListenSocket listener
Definition: ethertap.cc:247
void ccprintf(cp::Print &print)
Definition: cprintf.hh:131
#define DPRINTF(x,...)
Definition: trace.hh:229
void accept()
Definition: ethertap.cc:272
Ports are used to interface objects to each other.
Definition: port.hh:60
EtherTapStub(const Params *p)
Definition: ethertap.cc:288
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
Definition: sim_object.cc:126
bool queued()
Definition: pollevent.hh:61
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:175
PollQueue pollQueue
Definition: pollevent.cc:57
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: ethertap.cc:313
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: ethertap.cc:111
TapListener(EtherTapStub *t, int p)
Definition: ethertap.cc:252
uint32_t buffer_used
Definition: ethertap.hh:164
void sendSimulated(void *data, size_t len)
Definition: ethertap.cc:187
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Definition: ethertap.cc:163
#define DDUMP(x, data, count)
Definition: trace.hh:228
void retransmit()
Definition: ethertap.cc:208
TapEvent * event
Definition: ethertap.hh:86
Overload hash function for BasicBlockRange type.
Definition: vec_reg.hh:586
friend class TapEvent
Definition: ethertap.hh:85
Definition: cprintf.cc:42
void detach()
Definition: ethertap.cc:337
Bitfield< 31 > n
void schedule(PollEvent *event)
Definition: pollevent.cc:161
friend class TapListener
Definition: ethertap.hh:156
virtual ~EtherTapBase()
Definition: ethertap.cc:103
uint32_t frame_len
Definition: ethertap.hh:165
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:645
Tick curTick()
The current simulated tick.
Definition: core.hh:47
Temporarily migrate execution to a different event queue.
Definition: eventq.hh:552
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:385
EventFunctionWrapper txEvent
Definition: ethertap.hh:112
bool recvSimulated(EthPacketPtr packet)
Definition: ethertap.cc:171
static bool allDisabled()
Definition: socket.cc:73
EtherDump * dump
Definition: ethertap.hh:78
void listen()
Definition: ethertap.cc:259
void dump(EthPacketPtr &pkt)
Definition: etherdump.hh:59
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: ethertap.cc:303
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: ethertap.cc:128
virtual bool sendReal(const void *data, size_t len)=0
Bitfield< 18, 16 > len
#define SERIALIZE_ARRAY(member, size)
Definition: serialize.hh:658
std::shared_ptr< EthPacketData > EthPacketPtr
Definition: etherpkt.hh:90
bool sendReal(const void *data, size_t len) override
Definition: ethertap.cc:392
EtherTapBase(const Params *p)
Definition: ethertap.cc:94
Bitfield< 10, 5 > event
void stopPolling()
Definition: ethertap.cc:154
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:643
void process(int revent) override
Definition: ethertap.cc:238
#define UNSERIALIZE_ARRAY(member, size)
Definition: serialize.hh:661
bool sendPacket(EthPacketPtr packet)
Definition: etherint.hh:72
Event(TapListener *l, int fd, int e)
Definition: ethertap.cc:236
Bitfield< 9 > e
EventQueue * eventQueue() const
Definition: eventq.hh:738
EtherTapStub * tap
Definition: ethertap.cc:248
Event(Priority p=Default_Pri, Flags f=0)
Definition: eventq.hh:345
virtual void recvReal(int revent)=0
TapListener * listener
Definition: ethertap.cc:233
void recvDone()
Definition: etherint.hh:69
std::ostream CheckpointOut
Definition: serialize.hh:68
EtherTapBaseParams Params
Definition: ethertap.hh:61
TapEvent(EtherTapBase *_tap, int fd, int e)
Definition: ethertap.cc:80
EtherTapInt * interface
Definition: ethertap.hh:100
const Tick retryTime
Definition: core.hh:49
void schedule(Event &event, Tick when)
Definition: eventq.hh:744
void attach(int fd)
Definition: ethertap.cc:324
std::queue< EthPacketPtr > packetBuffer
Definition: ethertap.hh:110
EtherTapBase * tap
Definition: ethertap.cc:77
Event * event
Definition: ethertap.cc:242
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition: types.hh:237
void dump()
Dump all statistics data to the registered outputs.
Definition: statistics.cc:561
Bitfield< 5 > t
Bitfield< 14, 12 > fd
Definition: types.hh:160
void recvReal(int revent) override
Definition: ethertap.cc:346
Bitfield< 0 > p
uint8_t * buffer
Definition: ethertap.hh:75
const char data[]
Bitfield< 5 > l
Abstract superclass for simulation objects.
Definition: sim_object.hh:96
TapListener * listener
Definition: ethertap.hh:157
void pollFd(int fd)
Definition: ethertap.cc:146
void process(int revent) override
Definition: ethertap.cc:84

Generated on Fri Feb 28 2020 16:27:01 for gem5 by doxygen 1.8.13