diff -r f35e317d2e1e -r 4e5fcc7544ad src/base/socket.hh --- a/src/base/socket.hh Fri Aug 07 17:43:21 2015 +0100 +++ b/src/base/socket.hh Mon Aug 10 22:38:28 2015 -0500 @@ -2,6 +2,18 @@ * Copyright (c) 2002-2005 The Regents of The University of Michigan * All rights reserved. * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 2015 The University of Wisconsin Madison + * All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright @@ -26,6 +38,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Nathan Binkert + * Mohammad Alian */ #ifndef __SOCKET_HH__ @@ -44,16 +57,55 @@ protected: bool listening; int fd; + /** + * Define an static fd variable. It will be used for all EtherTap devices + * instantiated in switch, then you don't need to occupy several ports in + * your system by creating so one socket per port + */ + static int fdStatic; public: ListenSocket(); virtual ~ListenSocket(); virtual int accept(bool nodelay = false); + /** + * acceptTap accept incoming connection on fdStatic. + */ + virtual int acceptTap(bool nodelay = false); virtual bool listen(int port, bool reuse = true); + /** + * listenTap is called by the first instant of EtherTap. + * It initializes "fdStatic" + */ + virtual bool listenTap(int port, bool reuse = true); int getfd() const { return fd; } + int getfdStatic() const { return fdStatic; } bool islistening() const { return listening; } + bool anyislistening() const { return anyListening; } }; +/** + * Client socket class. EtherTap of pd-gem5 nodes should act as a client and + * connect to a corresponding EtherTap port of the switch. + * ConnectSocket vs. ListenSocket: + * ListenSocket is like a server connection + * ConnectSocket is like a client connection + */ +class ConnectSocket +{ + protected: + int fd; + + public: + ConnectSocket(); + virtual ~ConnectSocket(); + + virtual int connect(int port, const char* ip, bool nodelay = false); + + int getfd() const { return fd; } +}; + + #endif //__SOCKET_HH__ diff -r f35e317d2e1e -r 4e5fcc7544ad src/base/socket.cc --- a/src/base/socket.cc Fri Aug 07 17:43:21 2015 +0100 +++ b/src/base/socket.cc Mon Aug 10 22:38:28 2015 -0500 @@ -2,6 +2,18 @@ * Copyright (c) 2002-2005 The Regents of The University of Michigan * All rights reserved. * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 2015 The University of Wisconsin Madison + * All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright @@ -26,6 +38,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Nathan Binkert + * Mohammad Alian */ #include @@ -33,6 +46,7 @@ #include #include #include +#include #include @@ -44,6 +58,7 @@ bool ListenSocket::listeningDisabled = false; bool ListenSocket::anyListening = false; +int ListenSocket::fdStatic; void ListenSocket::disableAll() @@ -116,6 +131,48 @@ return true; } +// Create a socket and configure it for listening in EtherTap +bool +ListenSocket::listenTap(int port, bool reuse) +{ + if (listening) + panic("Socket already listening!"); + + fdStatic = ::socket(PF_INET, SOCK_STREAM, 0); + if (fdStatic < 0) + panic("Can't create socket:%s !", strerror(errno)); + + if (reuse) { + int i = 1; + if (::setsockopt(fdStatic, SOL_SOCKET, SO_REUSEADDR, (char *)&i, + sizeof(i)) < 0) + panic("ListenSocket(listen): setsockopt() SO_REUSEADDR failed!"); + } + + struct sockaddr_in sockaddr; + sockaddr.sin_family = PF_INET; + sockaddr.sin_addr.s_addr = INADDR_ANY; + sockaddr.sin_port = htons(port); + // finally clear sin_zero + memset(&sockaddr.sin_zero, 0, sizeof(sockaddr.sin_zero)); + int ret = ::bind(fdStatic, (struct sockaddr *)&sockaddr, sizeof (sockaddr)); + if (ret != 0) { + if (ret == -1 && errno != EADDRINUSE) + panic("ListenSocket(listen): bind() failed!"); + return false; + } + // set number of allowed outstanding socket connections to 24 + if (::listen(fdStatic, 24) == -1) { + if (errno != EADDRINUSE) + panic("ListenSocket(listen): listen() failed!"); + + return false; + } + + listening = true; + anyListening = true; + return true; +} // Open a connection. Accept will block, so if you don't want it to, // make sure a connection is ready before you call accept. @@ -134,3 +191,67 @@ return sfd; } + + +// Open a connection on fdStatic. Accept will block, so if you don't want +// it to, make sure a connection is ready before you call accept +int +ListenSocket::acceptTap(bool nodelay) +{ + struct sockaddr_in sockaddr; + socklen_t slen = sizeof (sockaddr); + int sfd = ::accept(fdStatic, (struct sockaddr *)&sockaddr, &slen); + if (sfd != -1 && nodelay) { + int i = 1; + if (::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, + sizeof(i)) < 0) + warn("ListenSocket(accept): setsockopt() TCP_NODELAY failed!"); + } + + return sfd; +} + +// ConnectSocket +ConnectSocket::ConnectSocket() + : fd(-1) +{} + +ConnectSocket::~ConnectSocket() +{ + if (fd != -1) + close(fd); +} + +// Create a socket and connect to a connection +// which is listening on "port", "ip" +int +ConnectSocket::connect(int port, const char* ip, bool nodelay) +{ + + fd = ::socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) + panic("Can't create socket:%s !", strerror(errno)); + + if (nodelay) { + int i = 1; + if (::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, + sizeof(i)) < 0) + warn("ConnectSocket(connect): setsockopt() TCP_NODELAY failed!"); + } + + struct sockaddr_in sockaddr; + sockaddr.sin_family = PF_INET; + if(inet_pton(PF_INET, ip, &sockaddr.sin_addr)<=0) { + panic("\n inet_pton error occured\n"); + } + sockaddr.sin_port = htons(port); + // finally clear sin_zero + memset(&sockaddr.sin_zero, 0, sizeof(sockaddr.sin_zero)); + int ret = ::connect(fd, (struct sockaddr *)&sockaddr, sizeof (sockaddr)); + if (ret != 0) { + panic("ConnectSocket(connect): connect() failed!"); + } + + return fd; +} + diff -r f35e317d2e1e -r 4e5fcc7544ad src/dev/Ethernet.py --- a/src/dev/Ethernet.py Fri Aug 07 17:43:21 2015 +0100 +++ b/src/dev/Ethernet.py Mon Aug 10 22:38:28 2015 -0500 @@ -85,6 +85,11 @@ bufsz = Param.Int(10000, "tap buffer size") dump = Param.EtherDump(NULL, "dump object") port = Param.UInt16(3500, "tap port") + tap = MasterPort("EtherTap interface") + sync_quantum = Param.Latency('1us', "synchronization rate") + server = Param.Bool(False, "is this server or client tap") + server_ip = Param.String("127.0.0.1","server IP address") + num_nodes = Param.Int(4, "num of nodes in pd-gem5") class EtherDump(SimObject): type = 'EtherDump' diff -r f35e317d2e1e -r 4e5fcc7544ad src/dev/SConscript --- a/src/dev/SConscript Fri Aug 07 17:43:21 2015 +0100 +++ b/src/dev/SConscript Mon Aug 10 22:38:28 2015 -0500 @@ -105,6 +105,8 @@ DebugFlag('Intel8254Timer') DebugFlag('MC146818') DebugFlag('PCIDEV') +DebugFlag('Pdgem5') +DebugFlag('Pdgem5Sync') DebugFlag('PciConfigAll') DebugFlag('SimpleDisk') DebugFlag('SimpleDiskData') diff -r f35e317d2e1e -r 4e5fcc7544ad src/dev/ethertap.hh --- a/src/dev/ethertap.hh Fri Aug 07 17:43:21 2015 +0100 +++ b/src/dev/ethertap.hh Mon Aug 10 22:38:28 2015 -0500 @@ -2,6 +2,18 @@ * Copyright (c) 2003-2005 The Regents of The University of Michigan * All rights reserved. * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 2015 The University of Wisconsin Madison + * All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright @@ -26,6 +38,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Nathan Binkert + * Mohammad Alian */ /* @file @@ -46,22 +59,20 @@ #include "sim/eventq.hh" #include "sim/sim_object.hh" -class TapEvent; class TapListener; class EtherTapInt; - +class TapConnector; +extern std::vector pdgem5_ckpt_flag; /* * Interface to connect a simulated ethernet device to the real world */ class EtherTap : public EtherObject { protected: - friend class TapEvent; - TapEvent *event; - - protected: friend class TapListener; TapListener *listener; + friend class TapConnector; + TapConnector *connector; int socket; char *buffer; int buflen; @@ -77,8 +88,18 @@ std::string device; std::queue packetBuffer; EtherTapInt *interface; + uint64_t syncQuantum; + uint64_t pollQuantum; + bool inSwitchTap; + bool syncMsgReceived; + int syncState; + int tapId; + bool attached; - void process(int revent); + void process(); + void sendSync(); + void recvSync(); + void accept(); void enqueue(EthPacketData *packet); void retransmit(); @@ -98,6 +119,10 @@ friend class TxEvent; TxEvent txEvent; + EventWrapper tapInEvent; + EventWrapper recvSyncEvent; + EventWrapper sendSyncEvent; + EventWrapper acceptEvent; public: typedef EtherTapParams Params; @@ -114,6 +139,7 @@ virtual bool recvPacket(EthPacketPtr packet); virtual void sendDone(); + bool isattached() { return attached; } void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE; void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE; diff -r f35e317d2e1e -r 4e5fcc7544ad src/dev/ethertap.cc --- a/src/dev/ethertap.cc Fri Aug 07 17:43:21 2015 +0100 +++ b/src/dev/ethertap.cc Mon Aug 10 22:38:28 2015 -0500 @@ -2,6 +2,18 @@ * Copyright (c) 2003-2005 The Regents of The University of Michigan * All rights reserved. * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 2015 The University of Wisconsin Madison + * All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright @@ -26,6 +38,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Nathan Binkert + * Mohammad Alian */ /* @file @@ -47,108 +60,179 @@ #include "base/trace.hh" #include "debug/Ethernet.hh" #include "debug/EthernetData.hh" +#include "debug/Pdgem5Sync.hh" #include "dev/etherdump.hh" #include "dev/etherint.hh" #include "dev/etherpkt.hh" #include "dev/ethertap.hh" +#include "sim/sim_exit.hh" +#include +#include +#include +#include +#include using namespace std; - +#define SIM 0 +#define RECV 1 +#define SIM_MSG 1 +#define CKPT_MSG 2 +vector pdgem5_ckpt_flag; /** */ class TapListener { protected: - /** - */ - class Event : public PollEvent - { - protected: - TapListener *listener; - - public: - Event(TapListener *l, int fd, int e) - : PollEvent(fd, e), listener(l) {} - - virtual void process(int revent) { listener->accept(); } - }; - - friend class Event; - Event *event; - - protected: ListenSocket listener; EtherTap *tap; int port; public: TapListener(EtherTap *t, int p) - : event(NULL), tap(t), port(p) {} - ~TapListener() { if (event) delete event; } + : tap(t), port(p) {} + ~TapListener() {} void accept(); - void listen(); + void listen(bool flag); }; void -TapListener::listen() +TapListener::listen(bool flag) { - while (!listener.listen(port, true)) { - DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port); - port++; - } + // if this is the first instance of switch tap then we should create + // a socket, otherwise we don't need to create a new socket + if (flag) { + while (!listener.listenTap(port, true)) { + DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n" + , port); + port++; + } + struct ifaddrs * ifAddrStruct=NULL; + struct ifaddrs * ifa=NULL; + void * tmpAddrPtr=NULL; + getifaddrs(&ifAddrStruct); - ccprintf(cerr, "Listening for tap connection on port %d\n", port); - event = new Event(this, listener.getfd(), POLLIN|POLLERR); - pollQueue.schedule(event); + //print the port and ip information of EthrTap + for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) + continue; + //check if it is a valid IP4 Address + if (ifa->ifa_addr->sa_family == AF_INET) { + tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; + char addressBuffer[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); + if (!strcmp(ifa->ifa_name, "eth0")) { + setbuf(stdout, NULL); + ccprintf(cerr, "Listening for tap connection on %s %s %d\n", + ifa->ifa_name, addressBuffer, port); + fflush(stdout); + } + } + } + if (ifAddrStruct!=NULL) + freeifaddrs(ifAddrStruct); + } } void TapListener::accept() { + if (tap->isattached()) { + DPRINTF(Ethernet, "EtherTap already attached\n"); + return; + } // As a consequence of being called from the PollQueue, we might // have been called from a different thread. Migrate to "our" // thread. EventQueue::ScopedMigration migrate(tap->eventQueue()); - if (!listener.islistening()) + if (!listener.anyislistening()) panic("TapListener(accept): cannot accept if we're not listening!"); - int sfd = listener.accept(true); + int sfd = listener.acceptTap(true); + if (sfd != -1) + tap->attach(sfd); +} + +/** + */ +class TapConnector +{ + protected: + ConnectSocket connector; + EtherTap *tap; + int port; + const char *ip; + + public: + TapConnector(EtherTap *t, int p, const char *ip_) + : tap(t), port(p), ip(ip_) {} + ~TapConnector() { } + + void connect(); +}; + +void +TapConnector::connect() +{ + // connect to the switch tap device which is listening for connections + int sfd = connector.connect(port, ip, true); if (sfd != -1) tap->attach(sfd); } +void +EtherTap::accept() +{ + listener->accept(); +} + /** */ -class TapEvent : public PollEvent -{ - protected: - EtherTap *tap; - - public: - TapEvent(EtherTap *_tap, int fd, int e) - : PollEvent(fd, e), tap(_tap) {} - virtual void process(int revent) { tap->process(revent); } -}; - EtherTap::EtherTap(const Params *p) - : EtherObject(p), event(NULL), socket(-1), buflen(p->bufsz), dump(p->dump), - interface(NULL), txEvent(this) + : EtherObject(p), socket(-1), buflen(p->bufsz), dump(p->dump), + interface(NULL), syncQuantum(p->sync_quantum), inSwitchTap(p->server), + syncMsgReceived(false), attached(false), txEvent(this), + tapInEvent(this), recvSyncEvent(this), sendSyncEvent(this), + acceptEvent(this) { if (ListenSocket::allDisabled()) fatal("All listeners are disabled! EtherTap can't work!"); + static bool flag = true; buffer = new char[buflen]; - listener = new TapListener(this, p->port); - listener->listen(); interface = new EtherTapInt(name() + ".interface", this); + tapId = pdgem5_ckpt_flag.size(); + pdgem5_ckpt_flag.push_back(false); + + // if this is a tap interface of the switch, inistantiate TapListener + // object and schedule acceptEvent to accept an incomming connection + // from a node tap interface. Also initiate synchronized simulation by + // scheduling a sendSyncEvent + if (inSwitchTap) { + listener = new TapListener(this, p->port); + listener->listen(flag); + schedule(sendSyncEvent, curTick()); + schedule(acceptEvent, curTick()); + flag = false; + } else { + // if this is tap interface of a node, instantiate TapConnector + // which connects to the associated tap interface of the switch + // on p->port and p->server_ip. Also, initiate sychronized + // simulation by scheduling a recvSyncEvent + connector = new TapConnector(this, p->port, p->server_ip.c_str()); + connector->connect(); + schedule(recvSyncEvent, curTick()); + } + // set polling quantum for incoming packet to a value proportional to + // syncQuantum and not grater that 5us + pollQuantum = syncQuantum / 2; + if (syncQuantum > 10000000) + pollQuantum = 5000000; } EtherTap::~EtherTap() { - if (event) - delete event; if (buffer) delete [] buffer; @@ -166,20 +250,70 @@ data_len = 0; socket = fd; DPRINTF(Ethernet, "EtherTap attached\n"); - event = new TapEvent(this, socket, POLLIN|POLLERR); - pollQueue.schedule(event); + attached = true; + if (!tapInEvent.scheduled()) + schedule(tapInEvent, curTick() + pollQuantum); } void EtherTap::detach() { DPRINTF(Ethernet, "EtherTap detached\n"); - delete event; - event = 0; close(socket); socket = -1; } +/** + * send sync message to peer. + */ +void +EtherTap::sendSync() +{ + int msg = SIM_MSG; + // @node: if ckpt_m5Ops is executed during this quantum simulation + // send a CKPT_MSG to swtich + // @switch: send ckpt_msg to connected nodes + if (pdgem5_ckpt_flag[tapId]) { + msg = CKPT_MSG; + pdgem5_ckpt_flag[tapId] = false; + // switch should dump checkpoint when it sends CKPT_MSG to the + // last peer gem5 process + if (inSwitchTap) { + int remaining_taps = 0; + for (int i = 0; i < pdgem5_ckpt_flag.size(); i ++) { + if (pdgem5_ckpt_flag[i]) + remaining_taps ++; + } + if (remaining_taps == 0) + exitSimLoop("checkpoint"); + } + } + uint32_t sync_msg = htonl(msg); + ssize_t ret = write(socket, &sync_msg, sizeof(sync_msg)); + DPRINTF(Pdgem5Sync, "sent %d message to peer tap\n", msg); + assert(ret == sizeof(sync_msg)); + if (inSwitchTap) { + // schedule a recvSyncEvent for this tap interface + // at the end of current quantum + schedule(recvSyncEvent, curTick() + syncQuantum); + if (!tapInEvent.scheduled()) + schedule(tapInEvent, curTick() + pollQuantum); + } else { + // if this is a node tap interface, wait for sync message + // reception from switch + DPRINTF(Pdgem5Sync, "wait for sync message from peer \n"); + syncState = RECV; + process(); + } +} + +void +EtherTap::recvSync() +{ + DPRINTF(Pdgem5Sync, "wait for sync message from peer \n"); + syncState = RECV; + process(); +} bool EtherTap::recvPacket(EthPacketPtr packet) { @@ -206,31 +340,64 @@ {} void -EtherTap::process(int revent) +EtherTap::process() { - if (revent & POLLERR) { - detach(); - return; - } + char *data = buffer + sizeof(uint32_t); + if (buffer_offset < data_len + sizeof(uint32_t)) { + fd_set fds; + struct timeval timeout; + int rc; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + FD_ZERO(&fds); + FD_SET(socket, &fds); + rc = select(sizeof(fds), &fds, NULL, NULL, &timeout); + if (rc > 0 || (syncState == RECV && !syncMsgReceived)) { + int len = read(socket, buffer + buffer_offset, + buflen - buffer_offset); + if (len > 0) { - char *data = buffer + sizeof(uint32_t); - if (!(revent & POLLIN)) - return; + buffer_offset += len; + if (data_len == 0) + data_len = ntohl(*(uint32_t *)buffer); + // if it's a sync message + if (data_len == SIM_MSG) { + syncMsgReceived = true; + data_len = 0; + // clear buffer from sync message + buffer_offset -= sizeof(data_len); + memmove(buffer, buffer + sizeof(data_len), buffer_offset); - if (buffer_offset < data_len + sizeof(uint32_t)) { - int len = read(socket, buffer + buffer_offset, buflen - buffer_offset); - if (len == 0) { - detach(); - return; + // if the message in not the only data that we've read + if (buffer_offset != 0) { + data_len = ntohl(*(uint32_t *)buffer); + } + } else if (data_len == CKPT_MSG) { + DPRINTF(Pdgem5Sync, "ckpt message received from peer\n"); + syncMsgReceived = true; + data_len = 0; + // clear buffer from ckpt message + buffer_offset -= sizeof(data_len); + memmove(buffer, buffer + sizeof(data_len), buffer_offset); + + // if the message in not the only data that we've read + if (buffer_offset != 0) { + data_len = ntohl(*(uint32_t *)buffer); + } + + for (int i = 0; i < pdgem5_ckpt_flag.size(); i++) { + pdgem5_ckpt_flag[i] = true; + } + } + + DPRINTF(Ethernet, "Received data from peer: len=%d " + "buffer_offset=%d data_len=%d\n", len, buffer_offset, + data_len); + } else { + exitSimLoop("pd-gem5 exit"); + 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); } while (data_len != 0 && buffer_offset >= data_len + sizeof(uint32_t)) { @@ -244,6 +411,20 @@ if (buffer_offset > 0) { memmove(buffer, data + data_len, buffer_offset); data_len = ntohl(*(uint32_t *)buffer); + // if it's a sync message + if (data_len == 1) { + syncMsgReceived = true; + data_len = 0; + // clear buffer from sync message + buffer_offset -= sizeof(data_len); + memmove(buffer, buffer + sizeof(data_len), buffer_offset); + + // if the sync message in not the only data that we've read + if (buffer_offset != 0) { + data_len = ntohl(*(uint32_t *)buffer); + } + } + } else data_len = 0; @@ -258,6 +439,39 @@ dump->dump(packet); } } + if (!tapInEvent.scheduled()) + schedule(tapInEvent, curTick() + pollQuantum); + + switch (syncState) { + case SIM: + return; + case RECV: + if (syncMsgReceived) { + syncState = SIM; + syncMsgReceived = false; + if (inSwitchTap) { + DPRINTF(Ethernet, "sync message received, send back a " + "go-ahead or ckpt msg to peer\n"); + sendSync(); + } else { + if (pdgem5_ckpt_flag[tapId]) { + exitSimLoop("checkpoint"); + pdgem5_ckpt_flag[tapId] = false; + } + DPRINTF(Ethernet, "sync message received, start sim\n"); + // schedule a sendSyncEvent at the end of current quantum + // and return (let simulation goes on) + schedule(sendSyncEvent, curTick() + syncQuantum); + if (!tapInEvent.scheduled()) + schedule(tapInEvent, curTick() + pollQuantum); + } + return; + } + // poll peer connection for sync message reception + schedule(recvSyncEvent, curTick()); + default: + return; + } } void @@ -302,38 +516,71 @@ SERIALIZE_ARRAY(buffer, buflen); SERIALIZE_SCALAR(buffer_offset); SERIALIZE_SCALAR(data_len); + bool in_event_scheduled = tapInEvent.scheduled(); + paramOut(cp, "in_event_scheduled", in_event_scheduled); + if (in_event_scheduled) { + Tick event_time = tapInEvent.when(); + paramOut(cp, "in_event_time", event_time); + } - bool tapevent_present = false; - if (event) { - tapevent_present = true; - SERIALIZE_SCALAR(tapevent_present); - event->serialize(cp); + bool recv_event_scheduled = recvSyncEvent.scheduled(); + paramOut(cp, "recv_event_scheduled", recv_event_scheduled); + if (recv_event_scheduled) { + Tick event_time = recvSyncEvent.when(); + paramOut(cp, "recv_event_time", event_time); } - else { - SERIALIZE_SCALAR(tapevent_present); + + bool send_event_scheduled = sendSyncEvent.scheduled(); + paramOut(cp, "send_event_scheduled", send_event_scheduled); + if (send_event_scheduled) { + Tick event_time = sendSyncEvent.when(); + paramOut(cp, "send_event_time", event_time); } } void EtherTap::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); + if (inSwitchTap) { + if (acceptEvent.scheduled()) + deschedule(acceptEvent); + schedule(acceptEvent, curTick()); + } + if (tapInEvent.scheduled()) + deschedule(tapInEvent); + if (recvSyncEvent.scheduled()) + deschedule(recvSyncEvent); + if (sendSyncEvent.scheduled()) + deschedule(sendSyncEvent); - event->unserialize(cp); + bool in_event_scheduled; + paramIn(cp, "in_event_scheduled", in_event_scheduled); + if (in_event_scheduled) { + Tick event_time; + paramIn(cp, "in_event_time", event_time); + schedule(tapInEvent, event_time); + } - if (event->queued()) { - pollQueue.schedule(event); - } + bool recv_event_scheduled; + paramIn(cp, "recv_event_scheduled", recv_event_scheduled); + if (recv_event_scheduled) { + Tick event_time; + paramIn(cp, "recv_event_time", event_time); + schedule(recvSyncEvent, event_time); + } + + bool send_event_scheduled; + paramIn(cp, "send_event_scheduled", send_event_scheduled); + if (send_event_scheduled) { + Tick event_time; + paramIn(cp, "send_event_time", event_time); + schedule(sendSyncEvent, event_time); } } diff -r f35e317d2e1e -r 4e5fcc7544ad src/sim/pseudo_inst.cc --- a/src/sim/pseudo_inst.cc Fri Aug 07 17:43:21 2015 +0100 +++ b/src/sim/pseudo_inst.cc Mon Aug 10 22:38:28 2015 -0500 @@ -74,6 +74,7 @@ #include "sim/stats.hh" #include "sim/system.hh" #include "sim/vptr.hh" +#include "dev/ethertap.hh" using namespace std; @@ -504,7 +505,10 @@ Tick when = curTick() + delay * SimClock::Int::ns; Tick repeat = period * SimClock::Int::ns; - exitSimLoop("checkpoint", 0, when, repeat); + if (pdgem5_ckpt_flag.size()) + pdgem5_ckpt_flag[0] = true; + else + exitSimLoop("checkpoint", 0, when, repeat); } uint64_t