dev: Refactor the EtherTapStub to make room for using tap.
A lot of the implementation of EtherTapStub can be shared with a version which uses a tap device directly. This change factors out those parts to accommodate that. Change-Id: I9c2e31f1be139ca73859a83f05457cef90101006 Reviewed-on: https://gem5-review.googlesource.com/3645 Reviewed-by: Nathan Binkert <nate@binkert.org> Maintainer: Nathan Binkert <nate@binkert.org>
This commit is contained in:
@@ -95,13 +95,18 @@ class EtherSwitch(EtherObject):
|
||||
delay_var = Param.Latency('0ns', "packet transmit delay variability")
|
||||
time_to_live = Param.Latency('10ms', "time to live of MAC address maping")
|
||||
|
||||
class EtherTapStub(EtherObject):
|
||||
type = 'EtherTapStub'
|
||||
class EtherTapBase(EtherObject):
|
||||
type = 'EtherTapBase'
|
||||
abstract = True
|
||||
cxx_header = "dev/net/ethertap.hh"
|
||||
bufsz = Param.Int(10000, "tap buffer size")
|
||||
dump = Param.EtherDump(NULL, "dump object")
|
||||
tap = SlavePort("Ethernet interface to connect to gem5's network")
|
||||
|
||||
class EtherTapStub(EtherTapBase):
|
||||
type = 'EtherTapStub'
|
||||
cxx_header = "dev/net/ethertap.hh"
|
||||
port = Param.UInt16(3500, "Port helper should send packets to")
|
||||
tap = SlavePort("Ethernet interface to gem5's network")
|
||||
|
||||
class EtherDump(SimObject):
|
||||
type = 'EtherDump'
|
||||
|
||||
@@ -56,39 +56,180 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
*/
|
||||
class TapEvent : public PollEvent
|
||||
{
|
||||
protected:
|
||||
EtherTapBase *tap;
|
||||
|
||||
public:
|
||||
TapEvent(EtherTapBase *_tap, int fd, int e)
|
||||
: PollEvent(fd, e), tap(_tap) {}
|
||||
virtual void process(int revent) { tap->recvReal(revent); }
|
||||
};
|
||||
|
||||
EtherTapBase::EtherTapBase(const Params *p)
|
||||
: EtherObject(p), buflen(p->bufsz), dump(p->dump), event(NULL),
|
||||
interface(NULL), txEvent(this)
|
||||
{
|
||||
buffer = new uint8_t[buflen];
|
||||
interface = new EtherTapInt(name() + ".interface", this);
|
||||
}
|
||||
|
||||
EtherTapBase::~EtherTapBase()
|
||||
{
|
||||
delete buffer;
|
||||
delete event;
|
||||
delete interface;
|
||||
}
|
||||
|
||||
void
|
||||
EtherTapBase::serialize(CheckpointOut &cp) const
|
||||
{
|
||||
SERIALIZE_SCALAR(buflen);
|
||||
uint8_t *buffer = (uint8_t *)this->buffer;
|
||||
SERIALIZE_ARRAY(buffer, buflen);
|
||||
|
||||
bool tapevent_present = false;
|
||||
if (event) {
|
||||
tapevent_present = true;
|
||||
SERIALIZE_SCALAR(tapevent_present);
|
||||
event->serialize(cp);
|
||||
} else {
|
||||
SERIALIZE_SCALAR(tapevent_present);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EtherTapBase::unserialize(CheckpointIn &cp)
|
||||
{
|
||||
UNSERIALIZE_SCALAR(buflen);
|
||||
uint8_t *buffer = (uint8_t *)this->buffer;
|
||||
UNSERIALIZE_ARRAY(buffer, buflen);
|
||||
|
||||
bool tapevent_present;
|
||||
UNSERIALIZE_SCALAR(tapevent_present);
|
||||
if (tapevent_present) {
|
||||
event = new TapEvent(this, 0, 0);
|
||||
event->unserialize(cp);
|
||||
if (event->queued())
|
||||
pollQueue.schedule(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EtherTapBase::pollFd(int fd)
|
||||
{
|
||||
assert(!event);
|
||||
event = new TapEvent(this, fd, POLLIN|POLLERR);
|
||||
pollQueue.schedule(event);
|
||||
}
|
||||
|
||||
void
|
||||
EtherTapBase::stopPolling()
|
||||
{
|
||||
assert(event);
|
||||
delete event;
|
||||
event = NULL;
|
||||
}
|
||||
|
||||
|
||||
EtherInt*
|
||||
EtherTapBase::getEthPort(const std::string &if_name, int idx)
|
||||
{
|
||||
if (if_name == "tap") {
|
||||
if (interface->getPeer())
|
||||
panic("Interface already connected to\n");
|
||||
return interface;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
EtherTapBase::recvSimulated(EthPacketPtr packet)
|
||||
{
|
||||
if (dump)
|
||||
dump->dump(packet);
|
||||
|
||||
DPRINTF(Ethernet, "EtherTap sim->real len=%d\n", packet->length);
|
||||
DDUMP(EthernetData, packet->data, packet->length);
|
||||
|
||||
bool success = sendReal(packet->data, packet->length);
|
||||
|
||||
interface->recvDone();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void
|
||||
EtherTapBase::sendSimulated(void *data, size_t len)
|
||||
{
|
||||
EthPacketPtr packet;
|
||||
packet = make_shared<EthPacketData>(len);
|
||||
packet->length = len;
|
||||
packet->simLength = len;
|
||||
memcpy(packet->data, data, len);
|
||||
|
||||
DPRINTF(Ethernet, "EtherTap real->sim len=%d\n", packet->length);
|
||||
DDUMP(EthernetData, packet->data, packet->length);
|
||||
if (!packetBuffer.empty() || !interface->sendPacket(packet)) {
|
||||
DPRINTF(Ethernet, "bus busy...buffer for retransmission\n");
|
||||
packetBuffer.push(packet);
|
||||
if (!txEvent.scheduled())
|
||||
schedule(txEvent, curTick() + retryTime);
|
||||
} else if (dump) {
|
||||
dump->dump(packet);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EtherTapBase::retransmit()
|
||||
{
|
||||
if (packetBuffer.empty())
|
||||
return;
|
||||
|
||||
EthPacketPtr packet = packetBuffer.front();
|
||||
if (interface->sendPacket(packet)) {
|
||||
if (dump)
|
||||
dump->dump(packet);
|
||||
DPRINTF(Ethernet, "EtherTap retransmit\n");
|
||||
packetBuffer.front() = NULL;
|
||||
packetBuffer.pop();
|
||||
}
|
||||
|
||||
if (!packetBuffer.empty() && !txEvent.scheduled())
|
||||
schedule(txEvent, curTick() + retryTime);
|
||||
}
|
||||
|
||||
|
||||
class TapListener
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
*/
|
||||
class Event : public PollEvent
|
||||
{
|
||||
protected:
|
||||
TapListener *listener;
|
||||
|
||||
public:
|
||||
Event(TapListener *l, int fd, int e)
|
||||
: PollEvent(fd, e), listener(l) {}
|
||||
Event(TapListener *l, int fd, int e) : PollEvent(fd, e), listener(l) {}
|
||||
|
||||
virtual void process(int revent) { listener->accept(); }
|
||||
void process(int revent) override { listener->accept(); }
|
||||
};
|
||||
|
||||
friend class Event;
|
||||
Event *event;
|
||||
|
||||
void accept();
|
||||
|
||||
protected:
|
||||
ListenSocket listener;
|
||||
EtherTapStub *tap;
|
||||
int port;
|
||||
|
||||
public:
|
||||
TapListener(EtherTapStub *t, int p)
|
||||
: event(NULL), tap(t), port(p) {}
|
||||
~TapListener() { if (event) delete event; }
|
||||
TapListener(EtherTapStub *t, int p) : event(NULL), tap(t), port(p) {}
|
||||
~TapListener() { delete event; }
|
||||
|
||||
void accept();
|
||||
void listen();
|
||||
};
|
||||
|
||||
@@ -121,226 +262,120 @@ TapListener::accept()
|
||||
tap->attach(sfd);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
class TapEvent : public PollEvent
|
||||
{
|
||||
protected:
|
||||
EtherTapStub *tap;
|
||||
|
||||
public:
|
||||
TapEvent(EtherTapStub *_tap, int fd, int e)
|
||||
: PollEvent(fd, e), tap(_tap) {}
|
||||
virtual void process(int revent) { tap->process(revent); }
|
||||
};
|
||||
|
||||
EtherTapStub::EtherTapStub(const Params *p)
|
||||
: EtherObject(p), event(NULL), socket(-1), buflen(p->bufsz), dump(p->dump),
|
||||
interface(NULL), txEvent(this)
|
||||
EtherTapStub::EtherTapStub(const Params *p) : EtherTapBase(p), socket(-1)
|
||||
{
|
||||
if (ListenSocket::allDisabled())
|
||||
fatal("All listeners are disabled! EtherTapStub can't work!");
|
||||
|
||||
buffer = new char[buflen];
|
||||
listener = new TapListener(this, p->port);
|
||||
listener->listen();
|
||||
interface = new EtherTapInt(name() + ".interface", this);
|
||||
}
|
||||
|
||||
EtherTapStub::~EtherTapStub()
|
||||
{
|
||||
if (event)
|
||||
delete event;
|
||||
if (buffer)
|
||||
delete [] buffer;
|
||||
|
||||
delete interface;
|
||||
delete listener;
|
||||
}
|
||||
|
||||
void
|
||||
EtherTapStub::serialize(CheckpointOut &cp) const
|
||||
{
|
||||
EtherTapBase::serialize(cp);
|
||||
|
||||
SERIALIZE_SCALAR(socket);
|
||||
SERIALIZE_SCALAR(buffer_used);
|
||||
SERIALIZE_SCALAR(frame_len);
|
||||
}
|
||||
|
||||
void
|
||||
EtherTapStub::unserialize(CheckpointIn &cp)
|
||||
{
|
||||
EtherTapBase::unserialize(cp);
|
||||
|
||||
UNSERIALIZE_SCALAR(socket);
|
||||
UNSERIALIZE_SCALAR(buffer_used);
|
||||
UNSERIALIZE_SCALAR(frame_len);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EtherTapStub::attach(int fd)
|
||||
{
|
||||
if (socket != -1)
|
||||
close(fd);
|
||||
|
||||
buffer_offset = 0;
|
||||
data_len = 0;
|
||||
buffer_used = 0;
|
||||
frame_len = 0;
|
||||
socket = fd;
|
||||
DPRINTF(Ethernet, "EtherTapStub attached\n");
|
||||
event = new TapEvent(this, socket, POLLIN|POLLERR);
|
||||
pollQueue.schedule(event);
|
||||
pollFd(socket);
|
||||
}
|
||||
|
||||
void
|
||||
EtherTapStub::detach()
|
||||
{
|
||||
DPRINTF(Ethernet, "EtherTapStub detached\n");
|
||||
delete event;
|
||||
event = 0;
|
||||
stopPolling();
|
||||
close(socket);
|
||||
socket = -1;
|
||||
}
|
||||
|
||||
bool
|
||||
EtherTapStub::recvPacket(EthPacketPtr packet)
|
||||
{
|
||||
if (dump)
|
||||
dump->dump(packet);
|
||||
|
||||
DPRINTF(Ethernet, "EtherTapStub output len=%d\n", packet->length);
|
||||
DDUMP(EthernetData, packet->data, packet->length);
|
||||
uint32_t len = htonl(packet->length);
|
||||
ssize_t ret = write(socket, &len, sizeof(len));
|
||||
if (ret != sizeof(len))
|
||||
return false;
|
||||
ret = write(socket, packet->data, packet->length);
|
||||
if (ret != packet->length)
|
||||
return false;
|
||||
|
||||
interface->recvDone();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
EtherTapStub::sendDone()
|
||||
{}
|
||||
|
||||
void
|
||||
EtherTapStub::process(int revent)
|
||||
EtherTapStub::recvReal(int revent)
|
||||
{
|
||||
if (revent & POLLERR) {
|
||||
detach();
|
||||
return;
|
||||
}
|
||||
|
||||
char *data = buffer + sizeof(uint32_t);
|
||||
if (!(revent & POLLIN))
|
||||
return;
|
||||
|
||||
if (buffer_offset < data_len + sizeof(uint32_t)) {
|
||||
int len = read(socket, buffer + buffer_offset, buflen - buffer_offset);
|
||||
if (len == 0) {
|
||||
detach();
|
||||
return;
|
||||
}
|
||||
|
||||
buffer_offset += len;
|
||||
|
||||
if (data_len == 0)
|
||||
data_len = ntohl(*(uint32_t *)buffer);
|
||||
|
||||
DPRINTF(Ethernet, "Received data from peer: len=%d buffer_offset=%d "
|
||||
"data_len=%d\n", len, buffer_offset, data_len);
|
||||
// Read in as much of the new data as we can.
|
||||
int len = read(socket, buffer + buffer_used, buflen - buffer_used);
|
||||
if (len == 0) {
|
||||
detach();
|
||||
return;
|
||||
}
|
||||
buffer_used += len;
|
||||
|
||||
while (data_len != 0 && buffer_offset >= data_len + sizeof(uint32_t)) {
|
||||
EthPacketPtr packet;
|
||||
packet = make_shared<EthPacketData>(data_len);
|
||||
packet->length = data_len;
|
||||
packet->simLength = data_len;
|
||||
memcpy(packet->data, data, data_len);
|
||||
|
||||
assert(buffer_offset >= data_len + sizeof(uint32_t));
|
||||
buffer_offset -= data_len + sizeof(uint32_t);
|
||||
if (buffer_offset > 0) {
|
||||
memmove(buffer, data + data_len, buffer_offset);
|
||||
data_len = ntohl(*(uint32_t *)buffer);
|
||||
} else
|
||||
data_len = 0;
|
||||
|
||||
DPRINTF(Ethernet, "EtherTapStub input len=%d\n", packet->length);
|
||||
DDUMP(EthernetData, packet->data, packet->length);
|
||||
if (!interface->sendPacket(packet)) {
|
||||
DPRINTF(Ethernet, "bus busy...buffer for retransmission\n");
|
||||
packetBuffer.push(packet);
|
||||
if (!txEvent.scheduled())
|
||||
schedule(txEvent, curTick() + retryTime);
|
||||
} else if (dump) {
|
||||
dump->dump(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EtherTapStub::retransmit()
|
||||
{
|
||||
if (packetBuffer.empty())
|
||||
// If there's not enough data for the frame length, wait for more.
|
||||
if (buffer_used < sizeof(uint32_t))
|
||||
return;
|
||||
|
||||
EthPacketPtr packet = packetBuffer.front();
|
||||
if (interface->sendPacket(packet)) {
|
||||
if (dump)
|
||||
dump->dump(packet);
|
||||
DPRINTF(Ethernet, "EtherTapStub retransmit\n");
|
||||
packetBuffer.front() = NULL;
|
||||
packetBuffer.pop();
|
||||
}
|
||||
if (frame_len == 0)
|
||||
frame_len = ntohl(*(uint32_t *)buffer);
|
||||
|
||||
if (!packetBuffer.empty() && !txEvent.scheduled())
|
||||
schedule(txEvent, curTick() + retryTime);
|
||||
}
|
||||
DPRINTF(Ethernet, "Received data from peer: len=%d buffer_used=%d "
|
||||
"frame_len=%d\n", len, buffer_used, frame_len);
|
||||
|
||||
EtherInt*
|
||||
EtherTapStub::getEthPort(const std::string &if_name, int idx)
|
||||
{
|
||||
if (if_name == "tap") {
|
||||
if (interface->getPeer())
|
||||
panic("Interface already connected to\n");
|
||||
return interface;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
uint8_t *frame_start = &buffer[sizeof(uint32_t)];
|
||||
while (frame_len != 0 && buffer_used >= frame_len + sizeof(uint32_t)) {
|
||||
sendSimulated(frame_start, frame_len);
|
||||
|
||||
|
||||
//=====================================================================
|
||||
|
||||
void
|
||||
EtherTapStub::serialize(CheckpointOut &cp) const
|
||||
{
|
||||
SERIALIZE_SCALAR(socket);
|
||||
SERIALIZE_SCALAR(buflen);
|
||||
uint8_t *buffer = (uint8_t *)this->buffer;
|
||||
SERIALIZE_ARRAY(buffer, buflen);
|
||||
SERIALIZE_SCALAR(buffer_offset);
|
||||
SERIALIZE_SCALAR(data_len);
|
||||
|
||||
bool tapevent_present = false;
|
||||
if (event) {
|
||||
tapevent_present = true;
|
||||
SERIALIZE_SCALAR(tapevent_present);
|
||||
event->serialize(cp);
|
||||
}
|
||||
else {
|
||||
SERIALIZE_SCALAR(tapevent_present);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EtherTapStub::unserialize(CheckpointIn &cp)
|
||||
{
|
||||
UNSERIALIZE_SCALAR(socket);
|
||||
UNSERIALIZE_SCALAR(buflen);
|
||||
uint8_t *buffer = (uint8_t *)this->buffer;
|
||||
UNSERIALIZE_ARRAY(buffer, buflen);
|
||||
UNSERIALIZE_SCALAR(buffer_offset);
|
||||
UNSERIALIZE_SCALAR(data_len);
|
||||
|
||||
bool tapevent_present;
|
||||
UNSERIALIZE_SCALAR(tapevent_present);
|
||||
if (tapevent_present) {
|
||||
event = new TapEvent(this, socket, POLLIN|POLLERR);
|
||||
|
||||
event->unserialize(cp);
|
||||
|
||||
if (event->queued()) {
|
||||
pollQueue.schedule(event);
|
||||
// Bookkeeping.
|
||||
buffer_used -= frame_len + sizeof(uint32_t);
|
||||
if (buffer_used > 0) {
|
||||
// If there's still any data left, move it into position.
|
||||
memmove(buffer, frame_start + frame_len, buffer_used);
|
||||
}
|
||||
frame_len = 0;
|
||||
|
||||
if (buffer_used >= sizeof(uint32_t))
|
||||
frame_len = ntohl(*(uint32_t *)buffer);
|
||||
}
|
||||
}
|
||||
|
||||
//=====================================================================
|
||||
bool
|
||||
EtherTapStub::sendReal(const void *data, size_t len)
|
||||
{
|
||||
uint32_t frame_len = htonl(len);
|
||||
ssize_t ret = write(socket, &frame_len, sizeof(frame_len));
|
||||
if (ret != sizeof(frame_len))
|
||||
return false;
|
||||
return write(socket, data, len) == len;
|
||||
}
|
||||
|
||||
|
||||
EtherTapStub *
|
||||
EtherTapStubParams::create()
|
||||
|
||||
@@ -47,65 +47,14 @@
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
class TapEvent;
|
||||
class TapListener;
|
||||
class EtherTapInt;
|
||||
|
||||
/*
|
||||
* Interface to connect a simulated ethernet device to the real world. An
|
||||
* external helper program bridges between this object's TCP port and a
|
||||
* source/sink for Ethernet frames. Each frame going in either direction is
|
||||
* prepended with the frame's length in a 32 bit integer in network byte order.
|
||||
*/
|
||||
class EtherTapStub : public EtherObject
|
||||
class EtherTapBase : public EtherObject
|
||||
{
|
||||
protected:
|
||||
friend class TapEvent;
|
||||
TapEvent *event;
|
||||
|
||||
protected:
|
||||
friend class TapListener;
|
||||
TapListener *listener;
|
||||
int socket;
|
||||
char *buffer;
|
||||
int buflen;
|
||||
uint32_t buffer_offset;
|
||||
uint32_t data_len;
|
||||
|
||||
EtherDump *dump;
|
||||
|
||||
void attach(int fd);
|
||||
void detach();
|
||||
|
||||
protected:
|
||||
std::string device;
|
||||
std::queue<EthPacketPtr> packetBuffer;
|
||||
EtherTapInt *interface;
|
||||
|
||||
void process(int revent);
|
||||
void enqueue(EthPacketData *packet);
|
||||
void retransmit();
|
||||
|
||||
/*
|
||||
*/
|
||||
class TxEvent : public Event
|
||||
{
|
||||
protected:
|
||||
EtherTapStub *tap;
|
||||
|
||||
public:
|
||||
TxEvent(EtherTapStub *_tap) : tap(_tap) {}
|
||||
void process() { tap->retransmit(); }
|
||||
virtual const char *description() const
|
||||
{ return "EtherTapStub retransmit"; }
|
||||
};
|
||||
|
||||
friend class TxEvent;
|
||||
TxEvent txEvent;
|
||||
|
||||
public:
|
||||
typedef EtherTapStubParams Params;
|
||||
EtherTapStub(const Params *p);
|
||||
virtual ~EtherTapStub();
|
||||
typedef EtherTapBaseParams Params;
|
||||
EtherTapBase(const Params *p);
|
||||
virtual ~EtherTapBase();
|
||||
|
||||
const Params *
|
||||
params() const
|
||||
@@ -113,26 +62,117 @@ class EtherTapStub : public EtherObject
|
||||
return dynamic_cast<const Params *>(_params);
|
||||
}
|
||||
|
||||
EtherInt *getEthPort(const std::string &if_name, int idx) override;
|
||||
|
||||
virtual bool recvPacket(EthPacketPtr packet);
|
||||
virtual void sendDone();
|
||||
|
||||
void serialize(CheckpointOut &cp) const override;
|
||||
void unserialize(CheckpointIn &cp) override;
|
||||
|
||||
protected:
|
||||
uint8_t *buffer;
|
||||
int buflen;
|
||||
|
||||
EtherDump *dump;
|
||||
|
||||
|
||||
/*
|
||||
* Interface to the real network.
|
||||
*/
|
||||
protected:
|
||||
friend class TapEvent;
|
||||
TapEvent *event;
|
||||
void pollFd(int fd);
|
||||
void stopPolling();
|
||||
|
||||
// Receive data from the real network.
|
||||
virtual void recvReal(int revent) = 0;
|
||||
// Prepare and send data out to the real network.
|
||||
virtual bool sendReal(const void *data, size_t len) = 0;
|
||||
|
||||
|
||||
/*
|
||||
* Interface to the simulated network.
|
||||
*/
|
||||
protected:
|
||||
EtherTapInt *interface;
|
||||
|
||||
public:
|
||||
EtherInt *getEthPort(const std::string &if_name, int idx) override;
|
||||
|
||||
bool recvSimulated(EthPacketPtr packet);
|
||||
void sendSimulated(void *data, size_t len);
|
||||
|
||||
protected:
|
||||
std::queue<EthPacketPtr> packetBuffer;
|
||||
void retransmit();
|
||||
|
||||
class TxEvent : public Event
|
||||
{
|
||||
protected:
|
||||
EtherTapBase *tap;
|
||||
|
||||
public:
|
||||
TxEvent(EtherTapBase *_tap) : tap(_tap) {}
|
||||
void process() { tap->retransmit(); }
|
||||
virtual const char *description() const
|
||||
{ return "EtherTapBase retransmit"; }
|
||||
};
|
||||
|
||||
friend class TxEvent;
|
||||
TxEvent txEvent;
|
||||
};
|
||||
|
||||
class EtherTapInt : public EtherInt
|
||||
{
|
||||
private:
|
||||
EtherTapStub *tap;
|
||||
EtherTapBase *tap;
|
||||
public:
|
||||
EtherTapInt(const std::string &name, EtherTapStub *t)
|
||||
: EtherInt(name), tap(t)
|
||||
EtherTapInt(const std::string &name, EtherTapBase *t) :
|
||||
EtherInt(name), tap(t)
|
||||
{ }
|
||||
|
||||
virtual bool recvPacket(EthPacketPtr pkt) { return tap->recvPacket(pkt); }
|
||||
virtual void sendDone() { tap->sendDone(); }
|
||||
bool recvPacket(EthPacketPtr pkt) override
|
||||
{ return tap->recvSimulated(pkt); }
|
||||
void sendDone() override {}
|
||||
};
|
||||
|
||||
|
||||
class TapListener;
|
||||
|
||||
/*
|
||||
* Interface to connect a simulated ethernet device to the real world. An
|
||||
* external helper program bridges between this object's TCP port and a
|
||||
* source/sink for Ethernet frames. Each frame going in either direction is
|
||||
* prepended with the frame's length in a 32 bit integer in network byte order.
|
||||
*/
|
||||
class EtherTapStub : public EtherTapBase
|
||||
{
|
||||
public:
|
||||
typedef EtherTapStubParams Params;
|
||||
EtherTapStub(const Params *p);
|
||||
~EtherTapStub();
|
||||
|
||||
const Params *
|
||||
params() const
|
||||
{
|
||||
return dynamic_cast<const Params *>(_params);
|
||||
}
|
||||
|
||||
void serialize(CheckpointOut &cp) const override;
|
||||
void unserialize(CheckpointIn &cp) override;
|
||||
|
||||
|
||||
protected:
|
||||
friend class TapListener;
|
||||
TapListener *listener;
|
||||
|
||||
int socket;
|
||||
|
||||
void attach(int fd);
|
||||
void detach();
|
||||
|
||||
uint32_t buffer_used;
|
||||
uint32_t frame_len;
|
||||
|
||||
void recvReal(int revent) override;
|
||||
bool sendReal(const void *data, size_t len) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user