gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups 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/misc.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  virtual void process(int revent) { tap->recvReal(revent); }
83 };
84 
86  : EtherObject(p), buflen(p->bufsz), dump(p->dump), event(NULL),
87  interface(NULL), txEvent(this)
88 {
89  buffer = new uint8_t[buflen];
90  interface = new EtherTapInt(name() + ".interface", this);
91 }
92 
94 {
95  delete buffer;
96  delete event;
97  delete interface;
98 }
99 
100 void
102 {
104  uint8_t *buffer = (uint8_t *)this->buffer;
105  SERIALIZE_ARRAY(buffer, buflen);
106 
107  bool tapevent_present = false;
108  if (event) {
109  tapevent_present = true;
110  SERIALIZE_SCALAR(tapevent_present);
111  event->serialize(cp);
112  } else {
113  SERIALIZE_SCALAR(tapevent_present);
114  }
115 }
116 
117 void
119 {
121  uint8_t *buffer = (uint8_t *)this->buffer;
122  UNSERIALIZE_ARRAY(buffer, buflen);
123 
124  bool tapevent_present;
125  UNSERIALIZE_SCALAR(tapevent_present);
126  if (tapevent_present) {
127  event = new TapEvent(this, 0, 0);
128  event->unserialize(cp);
129  if (event->queued())
131  }
132 }
133 
134 
135 void
137 {
138  assert(!event);
139  event = new TapEvent(this, fd, POLLIN|POLLERR);
141 }
142 
143 void
145 {
146  assert(event);
147  delete event;
148  event = NULL;
149 }
150 
151 
152 EtherInt*
153 EtherTapBase::getEthPort(const std::string &if_name, int idx)
154 {
155  if (if_name == "tap") {
156  if (interface->getPeer())
157  panic("Interface already connected to\n");
158  return interface;
159  }
160  return NULL;
161 }
162 
163 bool
165 {
166  if (dump)
167  dump->dump(packet);
168 
169  DPRINTF(Ethernet, "EtherTap sim->real len=%d\n", packet->length);
170  DDUMP(EthernetData, packet->data, packet->length);
171 
172  bool success = sendReal(packet->data, packet->length);
173 
174  interface->recvDone();
175 
176  return success;
177 }
178 
179 void
181 {
182  EthPacketPtr packet;
183  packet = make_shared<EthPacketData>(len);
184  packet->length = len;
185  packet->simLength = len;
186  memcpy(packet->data, data, len);
187 
188  DPRINTF(Ethernet, "EtherTap real->sim len=%d\n", packet->length);
189  DDUMP(EthernetData, packet->data, packet->length);
190  if (!packetBuffer.empty() || !interface->sendPacket(packet)) {
191  DPRINTF(Ethernet, "bus busy...buffer for retransmission\n");
192  packetBuffer.push(packet);
193  if (!txEvent.scheduled())
195  } else if (dump) {
196  dump->dump(packet);
197  }
198 }
199 
200 void
202 {
203  if (packetBuffer.empty())
204  return;
205 
206  EthPacketPtr packet = packetBuffer.front();
207  if (interface->sendPacket(packet)) {
208  if (dump)
209  dump->dump(packet);
210  DPRINTF(Ethernet, "EtherTap retransmit\n");
211  packetBuffer.front() = NULL;
212  packetBuffer.pop();
213  }
214 
215  if (!packetBuffer.empty() && !txEvent.scheduled())
217 }
218 
219 
221 {
222  protected:
223  class Event : public PollEvent
224  {
225  protected:
227 
228  public:
229  Event(TapListener *l, int fd, int e) : PollEvent(fd, e), listener(l) {}
230 
231  void process(int revent) override { listener->accept(); }
232  };
233 
234  friend class Event;
236 
237  void accept();
238 
239  protected:
242  int port;
243 
244  public:
245  TapListener(EtherTapStub *t, int p) : event(NULL), tap(t), port(p) {}
246  ~TapListener() { delete event; }
247 
248  void listen();
249 };
250 
251 void
253 {
254  while (!listener.listen(port, true)) {
255  DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port);
256  port++;
257  }
258 
259  ccprintf(cerr, "Listening for tap connection on port %d\n", port);
260  event = new Event(this, listener.getfd(), POLLIN|POLLERR);
262 }
263 
264 void
266 {
267  // As a consequence of being called from the PollQueue, we might
268  // have been called from a different thread. Migrate to "our"
269  // thread.
271 
272  if (!listener.islistening())
273  panic("TapListener(accept): cannot accept if we're not listening!");
274 
275  int sfd = listener.accept(true);
276  if (sfd != -1)
277  tap->attach(sfd);
278 }
279 
280 
282 {
284  fatal("All listeners are disabled! EtherTapStub can't work!");
285 
286  listener = new TapListener(this, p->port);
287  listener->listen();
288 }
289 
291 {
292  delete listener;
293 }
294 
295 void
297 {
299 
303 }
304 
305 void
307 {
309 
313 }
314 
315 
316 void
318 {
319  if (socket != -1)
320  close(fd);
321 
322  buffer_used = 0;
323  frame_len = 0;
324  socket = fd;
325  DPRINTF(Ethernet, "EtherTapStub attached\n");
326  pollFd(socket);
327 }
328 
329 void
331 {
332  DPRINTF(Ethernet, "EtherTapStub detached\n");
333  stopPolling();
334  close(socket);
335  socket = -1;
336 }
337 
338 void
340 {
341  if (revent & POLLERR) {
342  detach();
343  return;
344  }
345 
346  if (!(revent & POLLIN))
347  return;
348 
349  // Read in as much of the new data as we can.
350  int len = read(socket, buffer + buffer_used, buflen - buffer_used);
351  if (len == 0) {
352  detach();
353  return;
354  }
355  buffer_used += len;
356 
357  // If there's not enough data for the frame length, wait for more.
358  if (buffer_used < sizeof(uint32_t))
359  return;
360 
361  if (frame_len == 0)
362  frame_len = ntohl(*(uint32_t *)buffer);
363 
364  DPRINTF(Ethernet, "Received data from peer: len=%d buffer_used=%d "
365  "frame_len=%d\n", len, buffer_used, frame_len);
366 
367  uint8_t *frame_start = &buffer[sizeof(uint32_t)];
368  while (frame_len != 0 && buffer_used >= frame_len + sizeof(uint32_t)) {
369  sendSimulated(frame_start, frame_len);
370 
371  // Bookkeeping.
372  buffer_used -= frame_len + sizeof(uint32_t);
373  if (buffer_used > 0) {
374  // If there's still any data left, move it into position.
375  memmove(buffer, frame_start + frame_len, buffer_used);
376  }
377  frame_len = 0;
378 
379  if (buffer_used >= sizeof(uint32_t))
380  frame_len = ntohl(*(uint32_t *)buffer);
381  }
382 }
383 
384 bool
385 EtherTapStub::sendReal(const void *data, size_t len)
386 {
387  uint32_t frame_len = htonl(len);
388  ssize_t ret = write(socket, &frame_len, sizeof(frame_len));
389  if (ret != sizeof(frame_len))
390  return false;
391  return write(socket, data, len) == len;
392 }
393 
394 
395 #if USE_TUNTAP
396 
397 EtherTap::EtherTap(const Params *p) : EtherTapBase(p)
398 {
399  int fd = open(p->tun_clone_device.c_str(), O_RDWR);
400  if (fd < 0)
401  panic("Couldn't open %s.\n", p->tun_clone_device);
402 
403  struct ifreq ifr;
404  memset(&ifr, 0, sizeof(ifr));
405  ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
406  strncpy(ifr.ifr_name, p->tap_device_name.c_str(), IFNAMSIZ);
407 
408  if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0)
409  panic("Failed to access tap device %s.\n", ifr.ifr_name);
410  // fd now refers to the tap device.
411  tap = fd;
412  pollFd(tap);
413 }
414 
415 EtherTap::~EtherTap()
416 {
417  stopPolling();
418  close(tap);
419  tap = -1;
420 }
421 
422 void
423 EtherTap::recvReal(int revent)
424 {
425  if (revent & POLLERR)
426  panic("Error polling for tap data.\n");
427 
428  if (!(revent & POLLIN))
429  return;
430 
431  ssize_t ret = read(tap, buffer, buflen);
432  if (ret < 0)
433  panic("Failed to read from tap device.\n");
434 
435  sendSimulated(buffer, ret);
436 }
437 
438 bool
439 EtherTap::sendReal(const void *data, size_t len)
440 {
441  if (write(tap, data, len) != len)
442  panic("Failed to write data to tap device.\n");
443  return true;
444 }
445 
446 EtherTap *
447 EtherTapParams::create()
448 {
449  return new EtherTap(this);
450 }
451 
452 #endif
453 
454 EtherTapStub *
455 EtherTapStubParams::create()
456 {
457  return new EtherTapStub(this);
458 }
ListenSocket listener
Definition: ethertap.cc:240
void ccprintf(cp::Print &print)
Definition: cprintf.hh:130
#define DPRINTF(x,...)
Definition: trace.hh:212
void accept()
Definition: ethertap.cc:265
EtherTapStub(const Params *p)
Definition: ethertap.cc:281
bool queued()
Definition: pollevent.hh:61
virtual bool listen(int port, bool reuse=true)
Definition: socket.cc:90
PollQueue pollQueue
Definition: pollevent.cc:55
#define panic(...)
Definition: misc.hh:153
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: ethertap.cc:306
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: ethertap.cc:101
TapListener(EtherTapStub *t, int p)
Definition: ethertap.cc:245
uint32_t buffer_used
Definition: ethertap.hh:178
TxEvent txEvent
Definition: ethertap.hh:126
void sendSimulated(void *data, size_t len)
Definition: ethertap.cc:180
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:381
#define DDUMP(x, data, count)
Definition: trace.hh:211
void retransmit()
Definition: ethertap.cc:201
EtherInt * getPeer()
Definition: etherint.hh:63
TapEvent * event
Definition: ethertap.hh:87
friend class TapEvent
Definition: ethertap.hh:86
void detach()
Definition: ethertap.cc:330
const char data[]
Definition: circlebuf.cc:43
void schedule(PollEvent *event)
Definition: pollevent.cc:159
friend class TapListener
Definition: ethertap.hh:170
virtual ~EtherTapBase()
Definition: ethertap.cc:93
uint32_t frame_len
Definition: ethertap.hh:179
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:145
Tick curTick()
The current simulated tick.
Definition: core.hh:47
Temporarily migrate execution to a different event queue.
Definition: eventq.hh:546
bool recvSimulated(EthPacketPtr packet)
Definition: ethertap.cc:164
static bool allDisabled()
Definition: socket.cc:61
EtherDump * dump
Definition: ethertap.hh:79
void listen()
Definition: ethertap.cc:252
EtherObjectParams Params
Definition: etherobject.hh:51
void dump(EthPacketPtr &pkt)
Definition: etherdump.hh:59
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: ethertap.cc:296
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: ethertap.cc:118
virtual bool sendReal(const void *data, size_t len)=0
#define fatal(...)
Definition: misc.hh:163
#define SERIALIZE_ARRAY(member, size)
Definition: serialize.hh:158
std::shared_ptr< EthPacketData > EthPacketPtr
Definition: etherpkt.hh:90
virtual int accept(bool nodelay=false)
Definition: socket.cc:136
bool sendReal(const void *data, size_t len) override
Definition: ethertap.cc:385
EtherTapBase(const Params *p)
Definition: ethertap.cc:85
virtual void process(int revent)
Definition: ethertap.cc:82
EventQueue * eventQueue() const
Definition: eventq.hh:722
Bitfield< 10, 5 > event
void stopPolling()
Definition: ethertap.cc:144
The base EtherObject class, allows for an accesor function to a simobj that returns the Port...
Definition: etherobject.hh:48
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:143
void process(int revent) override
Definition: ethertap.cc:231
#define UNSERIALIZE_ARRAY(member, size)
Definition: serialize.hh:161
bool sendPacket(EthPacketPtr packet)
Definition: etherint.hh:68
Event(TapListener *l, int fd, int e)
Definition: ethertap.cc:229
Bitfield< 9 > e
Definition: miscregs.hh:1376
EtherTapStub * tap
Definition: ethertap.cc:241
friend class Event
Definition: ethertap.cc:234
TapListener * listener
Definition: ethertap.cc:226
void recvDone()
Definition: etherint.hh:65
std::ostream CheckpointOut
Definition: serialize.hh:67
TapEvent(EtherTapBase *_tap, int fd, int e)
Definition: ethertap.cc:80
Bitfield< 18, 16 > len
Definition: miscregs.hh:1626
EtherTapInt * interface
Definition: ethertap.hh:101
const Tick retryTime
Definition: core.hh:49
bool islistening() const
Definition: socket.hh:60
void schedule(Event &event, Tick when)
Definition: eventq.hh:728
EtherInt * getEthPort(const std::string &if_name, int idx) override
Additional function to return the Port of a memory object.
Definition: ethertap.cc:153
void attach(int fd)
Definition: ethertap.cc:317
std::queue< EthPacketPtr > packetBuffer
Definition: ethertap.hh:110
EtherTapBase * tap
Definition: ethertap.cc:77
Event * event
Definition: ethertap.cc:235
void dump()
Dump all statistics data to the registered outputs.
Definition: statistics.cc:517
Bitfield< 5 > t
Definition: miscregs.hh:1382
Bitfield< 14, 12 > fd
Definition: types.hh:155
void recvReal(int revent) override
Definition: ethertap.cc:339
Bitfield< 0 > p
uint8_t * buffer
Definition: ethertap.hh:76
Bitfield< 5 > l
int getfd() const
Definition: socket.hh:59
TapListener * listener
Definition: ethertap.hh:171
void pollFd(int fd)
Definition: ethertap.cc:136

Generated on Fri Jun 9 2017 13:03:46 for gem5 by doxygen 1.8.6