gem5 v24.0.0.0
Loading...
Searching...
No Matches
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 HAVE_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#include "sim/core.hh"
70#include "sim/cur_tick.hh"
71
72namespace gem5
73{
74
75class TapEvent : public PollEvent
76{
77 protected:
79
80 public:
81 TapEvent(EtherTapBase *_tap, int fd, int e)
82 : PollEvent(fd, e), tap(_tap) {}
83
84 void
85 process(int revent) override
86 {
87 // Ensure that our event queue is active. It may not be since we get
88 // here from the PollQueue whenever a real packet happens to arrive.
90
91 tap->recvReal(revent);
92 }
93};
94
96 : SimObject(p), buflen(p.bufsz), dump(p.dump), event(NULL),
97 interface(NULL),
98 txEvent([this]{ retransmit(); }, "EtherTapBase retransmit")
99{
100 buffer = new uint8_t[buflen];
101 interface = new EtherTapInt(name() + ".interface", this);
102}
103
105{
106 delete buffer;
107 delete event;
108 delete interface;
109}
110
111void
113{
115 uint8_t *buffer = (uint8_t *)this->buffer;
117
118 bool tapevent_present = false;
119 if (event) {
120 tapevent_present = true;
121 SERIALIZE_SCALAR(tapevent_present);
122 event->serialize(cp);
123 } else {
124 SERIALIZE_SCALAR(tapevent_present);
125 }
126}
127
128void
130{
132 uint8_t *buffer = (uint8_t *)this->buffer;
134
135 bool tapevent_present;
136 UNSERIALIZE_SCALAR(tapevent_present);
137 if (tapevent_present) {
138 event = new TapEvent(this, 0, 0);
139 event->unserialize(cp);
140 if (event->queued())
142 }
143}
144
145
146void
148{
149 assert(!event);
150 event = new TapEvent(this, fd, POLLIN|POLLERR);
152}
153
154void
156{
157 assert(event);
158 delete event;
159 event = NULL;
160}
161
162
163Port &
164EtherTapBase::getPort(const std::string &if_name, PortID idx)
165{
166 if (if_name == "tap")
167 return *interface;
168 return SimObject::getPort(if_name, idx);
169}
170
171bool
173{
174 if (dump)
175 dump->dump(packet);
176
177 DPRINTF(Ethernet, "EtherTap sim->real len=%d\n", packet->length);
178 DDUMP(EthernetData, packet->data, packet->length);
179
180 bool success = sendReal(packet->data, packet->length);
181
183
184 return success;
185}
186
187void
189{
190 EthPacketPtr packet;
191 packet = std::make_shared<EthPacketData>(len);
192 packet->length = len;
193 packet->simLength = len;
194 memcpy(packet->data, data, len);
195
196 DPRINTF(Ethernet, "EtherTap real->sim len=%d\n", packet->length);
197 DDUMP(EthernetData, packet->data, packet->length);
198 if (!packetBuffer.empty() || !interface->sendPacket(packet)) {
199 DPRINTF(Ethernet, "bus busy...buffer for retransmission\n");
200 packetBuffer.push(packet);
201 if (!txEvent.scheduled())
203 } else if (dump) {
204 dump->dump(packet);
205 }
206}
207
208void
210{
211 if (packetBuffer.empty())
212 return;
213
214 EthPacketPtr packet = packetBuffer.front();
215 if (interface->sendPacket(packet)) {
216 if (dump)
217 dump->dump(packet);
218 DPRINTF(Ethernet, "EtherTap retransmit\n");
219 packetBuffer.front() = NULL;
220 packetBuffer.pop();
221 }
222
223 if (!packetBuffer.empty() && !txEvent.scheduled())
225}
226
227
229{
230 protected:
231 class Event : public PollEvent
232 {
233 protected:
235
236 public:
237 Event(TapListener *l, int fd, int e) : PollEvent(fd, e), listener(l) {}
238
239 void process(int revent) override { listener->accept(); }
240 };
241
242 friend class Event;
243 Event *event = nullptr;
244
245 void accept();
246
247 protected:
250
251 public:
253 listener(std::move(_listener)), tap(t) {}
254 ~TapListener() { delete event; }
255
256 void listen();
257};
258
259void
261{
262 listener->listen();
263
264 event = new Event(this, listener->getfd(), POLLIN|POLLERR);
266}
267
268void
270{
271 // As a consequence of being called from the PollQueue, we might
272 // have been called from a different thread. Migrate to "our"
273 // thread.
275
276 if (!listener->islistening())
277 panic("TapListener(accept): cannot accept if we're not listening!");
278
279 int sfd = listener->accept();
280 if (sfd != -1)
281 tap->attach(sfd);
282}
283
284
286{
288 fatal("All listeners are disabled! EtherTapStub can't work!");
289
290 listener = new TapListener(this, p.port.build(name()));
291 listener->listen();
292}
293
295{
296 delete listener;
297}
298
299void
308
309void
318
319
320void
322{
323 if (socket != -1)
324 close(fd);
325
326 buffer_used = 0;
327 frame_len = 0;
328 socket = fd;
329 DPRINTF(Ethernet, "EtherTapStub attached\n");
330 pollFd(socket);
331}
332
333void
335{
336 DPRINTF(Ethernet, "EtherTapStub detached\n");
337 stopPolling();
338 close(socket);
339 socket = -1;
340}
341
342void
344{
345 if (revent & POLLERR) {
346 detach();
347 return;
348 }
349
350 if (!(revent & POLLIN))
351 return;
352
353 // Read in as much of the new data as we can.
354 int len = read(socket, buffer + buffer_used, buflen - buffer_used);
355 if (len == 0) {
356 detach();
357 return;
358 }
359 buffer_used += len;
360
361 // If there's not enough data for the frame length, wait for more.
362 if (buffer_used < sizeof(uint32_t))
363 return;
364
365 if (frame_len == 0)
366 frame_len = ntohl(*(uint32_t *)buffer);
367
368 DPRINTF(Ethernet, "Received data from peer: len=%d buffer_used=%d "
369 "frame_len=%d\n", len, buffer_used, frame_len);
370
371 uint8_t *frame_start = &buffer[sizeof(uint32_t)];
372 while (frame_len != 0 && buffer_used >= frame_len + sizeof(uint32_t)) {
373 sendSimulated(frame_start, frame_len);
374
375 // Bookkeeping.
376 buffer_used -= frame_len + sizeof(uint32_t);
377 if (buffer_used > 0) {
378 // If there's still any data left, move it into position.
379 memmove(buffer, frame_start + frame_len, buffer_used);
380 }
381 frame_len = 0;
382
383 if (buffer_used >= sizeof(uint32_t))
384 frame_len = ntohl(*(uint32_t *)buffer);
385 }
386}
387
388bool
389EtherTapStub::sendReal(const void *data, size_t len)
390{
391 uint32_t frame_len = htonl(len);
392 ssize_t ret = write(socket, &frame_len, sizeof(frame_len));
393 if (ret != sizeof(frame_len))
394 return false;
395 return write(socket, data, len) == len;
396}
397
398
399#if HAVE_TUNTAP
400
401EtherTap::EtherTap(const Params &p) : EtherTapBase(p)
402{
403 int fd = open(p.tun_clone_device.c_str(), O_RDWR | O_NONBLOCK);
404 if (fd < 0)
405 panic("Couldn't open %s.\n", p.tun_clone_device);
406
407 struct ifreq ifr;
408 memset(&ifr, 0, sizeof(ifr));
409 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
410 strncpy(ifr.ifr_name, p.tap_device_name.c_str(), IFNAMSIZ - 1);
411
412 if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0)
413 panic("Failed to access tap device %s.\n", ifr.ifr_name);
414 // fd now refers to the tap device.
415 tap = fd;
416 pollFd(tap);
417}
418
419EtherTap::~EtherTap()
420{
421 stopPolling();
422 close(tap);
423 tap = -1;
424}
425
426void
427EtherTap::recvReal(int revent)
428{
429 if (revent & POLLERR)
430 panic("Error polling for tap data.\n");
431
432 if (!(revent & POLLIN))
433 return;
434
435 ssize_t ret;
436 while ((ret = read(tap, buffer, buflen))) {
437 if (ret < 0) {
438 if (errno == EAGAIN)
439 break;
440 panic("Failed to read from tap device.\n");
441 }
442
443 sendSimulated(buffer, ret);
444 }
445}
446
447bool
448EtherTap::sendReal(const void *data, size_t len)
449{
450 int n;
451 pollfd pfd[1];
452 pfd->fd = tap;
453 pfd->events = POLLOUT;
454
455 // `tap` is a nonblock fd. Here we try to write until success, and use
456 // poll to make a blocking wait.
457 while ((n = write(tap, data, len)) != len) {
458 if (errno != EAGAIN)
459 panic("Failed to write data to tap device.\n");
460 pfd->revents = 0;
461 int ret = poll(pfd, 1, -1);
462 // timeout is set to inf, we shouldn't get 0 in any case.
463 assert(ret != 0);
464 if (ret == -1 || (ret == 1 && (pfd->revents & POLLERR))) {
465 panic("Failed when polling to write data to tap device.\n");
466 }
467 }
468 return true;
469}
470
471#endif // HAVE_TUNTAP
472
473} // namespace gem5
#define DDUMP(x, data, count)
DPRINTF is a debugging trace facility that allows one to selectively enable tracing statements.
Definition trace.hh:204
#define DPRINTF(x,...)
Definition trace.hh:210
const char data[]
void dump(EthPacketPtr &pkt)
Definition etherdump.hh:60
bool sendPacket(EthPacketPtr packet)
Definition etherint.hh:73
void recvDone()
Definition etherint.hh:70
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Definition ethertap.cc:164
void sendSimulated(void *data, size_t len)
Definition ethertap.cc:188
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition ethertap.cc:129
TapEvent * event
Definition ethertap.hh:81
virtual ~EtherTapBase()
Definition ethertap.cc:104
EtherTapBaseParams Params
Definition ethertap.hh:62
virtual void recvReal(int revent)=0
void pollFd(int fd)
Definition ethertap.cc:147
EtherTapInt * interface
Definition ethertap.hh:95
uint8_t * buffer
Definition ethertap.hh:70
bool recvSimulated(EthPacketPtr packet)
Definition ethertap.cc:172
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition ethertap.cc:112
std::queue< EthPacketPtr > packetBuffer
Definition ethertap.hh:105
friend class TapEvent
Definition ethertap.hh:80
virtual bool sendReal(const void *data, size_t len)=0
EventFunctionWrapper txEvent
Definition ethertap.hh:107
EtherTapBase(const Params &p)
Definition ethertap.cc:95
EtherDump * dump
Definition ethertap.hh:73
EtherTapStub(const Params &p)
Definition ethertap.cc:285
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition ethertap.cc:300
friend class TapListener
Definition ethertap.hh:145
EtherTapStubParams Params
Definition ethertap.hh:136
void attach(int fd)
Definition ethertap.cc:321
void recvReal(int revent) override
Definition ethertap.cc:343
uint32_t buffer_used
Definition ethertap.hh:153
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition ethertap.cc:310
bool sendReal(const void *data, size_t len) override
Definition ethertap.cc:389
TapListener * listener
Definition ethertap.hh:146
static bool allDisabled()
Definition socket.cc:90
virtual std::string name() const
Definition named.hh:47
Ports are used to interface objects to each other.
Definition port.hh:62
Abstract superclass for simulation objects.
TapEvent(EtherTapBase *_tap, int fd, int e)
Definition ethertap.cc:81
void process(int revent) override
Definition ethertap.cc:85
EtherTapBase * tap
Definition ethertap.cc:78
void process(int revent) override
Definition ethertap.cc:239
Event(TapListener *l, int fd, int e)
Definition ethertap.cc:237
TapListener * listener
Definition ethertap.cc:234
friend class Event
Definition ethertap.cc:242
EtherTapStub * tap
Definition ethertap.cc:249
TapListener(EtherTapStub *t, ListenSocketPtr _listener)
Definition ethertap.cc:252
ListenSocketPtr listener
Definition ethertap.cc:248
bool scheduled() const
Determine if the current event is scheduled.
Definition eventq.hh:458
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
EventQueue * eventQueue() const
Definition eventq.hh:1003
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
PollQueue pollQueue
Definition pollevent.cc:55
void schedule(PollEvent *event)
Definition pollevent.cc:159
#define UNSERIALIZE_ARRAY(member, size)
Definition serialize.hh:618
#define SERIALIZE_ARRAY(member, size)
Definition serialize.hh:610
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
Bitfield< 14, 12 > fd
Definition types.hh:150
Bitfield< 31 > n
Bitfield< 18, 16 > len
Bitfield< 5 > t
Definition misc_types.hh:71
Bitfield< 9 > e
Definition misc_types.hh:65
Bitfield< 10, 5 > event
Bitfield< 5 > l
Bitfield< 0 > p
Tick ns
nanosecond
Definition core.cc:68
void dump()
Dump all statistics data to the registered outputs.
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
std::ostream CheckpointOut
Definition serialize.hh:66
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition types.hh:245
std::unique_ptr< ListenSocket > ListenSocketPtr
Definition socket.hh:112
std::shared_ptr< EthPacketData > EthPacketPtr
Definition etherpkt.hh:90
Overload hash function for BasicBlockRange type.
Definition binary32.hh:81
#define UNSERIALIZE_SCALAR(scalar)
Definition serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition serialize.hh:568
const std::string & name()
Definition trace.cc:48

Generated on Tue Jun 18 2024 16:24:03 for gem5 by doxygen 1.11.0