diff -r d50bc51b82ab -r 51af672c9841 src/dev/Ethernet.py --- a/src/dev/Ethernet.py Tue Jun 23 16:37:53 2015 -0500 +++ b/src/dev/Ethernet.py Tue Jun 23 16:58:14 2015 -0500 @@ -53,6 +53,19 @@ dump = Param.EtherDump(NULL, "dump object") speed = Param.NetworkBandwidth('100Mbps', "bus speed in bits per second") +class EtherSwitch(EtherObject): + type = 'EtherSwitch' + cxx_header = "dev/etherswitch.hh" + dump = Param.EtherDump(NULL, "dump object") + speed = Param.NetworkBandwidth('1Gbps', "switch speed in bits per second") + interface = VectorMasterPort("Ethernet Interface") + input_buffer_size = Param.MemorySize('1MB', "size of input port buffers") + output_buffer_size = Param.MemorySize('1MB', "size of output port buffers") + delay = Param.Latency('0us', "packet transmit delay") + delay_var = Param.Latency('0ns', "packet transmit delay variability") + queue_size = Param.Int(100,"output queue size on each interface") + port_count = Param.Int(3,"number of ports") + class EtherTap(EtherObject): type = 'EtherTap' cxx_header = "dev/ethertap.hh" diff -r d50bc51b82ab -r 51af672c9841 src/dev/SConscript --- a/src/dev/SConscript Tue Jun 23 16:37:53 2015 -0500 +++ b/src/dev/SConscript Tue Jun 23 16:58:14 2015 -0500 @@ -56,6 +56,7 @@ Source('disk_image.cc') Source('dma_device.cc') Source('etherbus.cc') +Source('etherswitch.cc') Source('etherdevice.cc') Source('etherdump.cc') Source('etherint.cc') diff -r d50bc51b82ab -r 51af672c9841 src/dev/etherint.hh --- a/src/dev/etherint.hh Tue Jun 23 16:37:53 2015 -0500 +++ b/src/dev/etherint.hh Tue Jun 23 16:58:14 2015 -0500 @@ -65,12 +65,12 @@ void recvDone() { peer->sendDone(); } virtual void sendDone() = 0; - bool sendPacket(EthPacketPtr packet) + virtual bool sendPacket(EthPacketPtr packet) { return peer ? peer->recvPacket(packet) : true; } virtual bool recvPacket(EthPacketPtr packet) = 0; bool askBusy() {return peer->isBusy(); } - virtual bool isBusy() { return false; } + virtual bool isBusy() const { return false; } }; #endif // __DEV_ETHERINT_HH__ diff -r d50bc51b82ab -r 51af672c9841 src/dev/etherlink.hh --- a/src/dev/etherlink.hh Tue Jun 23 16:37:53 2015 -0500 +++ b/src/dev/etherlink.hh Tue Jun 23 16:58:14 2015 -0500 @@ -54,6 +54,8 @@ class Interface; friend class LinkDelayEvent; + + public: /* * Model for a single uni-directional link */ @@ -62,11 +64,11 @@ protected: std::string objName; - EtherLink *parent; + EtherObject *parent; int number; - Interface *txint; - Interface *rxint; + EtherInt *txint; + EtherInt *rxint; double ticksPerByte; Tick linkDelay; @@ -87,7 +89,7 @@ void txComplete(EthPacketPtr packet); public: - Link(const std::string &name, EtherLink *p, int num, + Link(const std::string &name, EtherObject *p, int num, double rate, Tick delay, Tick delay_var, EtherDump *dump); ~Link() {} @@ -96,14 +98,15 @@ bool busy() const { return (bool)packet; } bool transmit(EthPacketPtr packet); - void setTxInt(Interface *i) { assert(!txint); txint = i; } - void setRxInt(Interface *i) { assert(!rxint); rxint = i; } + void setTxInt(EtherInt *i) { assert(!txint); txint = i; } + void setRxInt(EtherInt *i) { assert(!rxint); rxint = i; } void serialize(const std::string &base, std::ostream &os); void unserialize(const std::string &base, Checkpoint *cp, const std::string §ion); }; + protected: /* * Interface at each end of the link */ @@ -116,7 +119,7 @@ Interface(const std::string &name, Link *txlink, Link *rxlink); bool recvPacket(EthPacketPtr packet) { return txlink->transmit(packet); } void sendDone() { peer->sendDone(); } - bool isBusy() { return txlink->busy(); } + bool isBusy() const { return txlink->busy(); } }; Link *link[2]; diff -r d50bc51b82ab -r 51af672c9841 src/dev/etherlink.cc --- a/src/dev/etherlink.cc Tue Jun 23 16:37:53 2015 -0500 +++ b/src/dev/etherlink.cc Tue Jun 23 16:58:14 2015 -0500 @@ -85,8 +85,7 @@ i = interface[1]; else return NULL; - if (i->getPeer()) - panic("interface already connected to\n"); + fatal_if(i->getPeer(), "interface already connected to\n"); return i; } @@ -99,7 +98,7 @@ rx->setRxInt(this); } -EtherLink::Link::Link(const string &name, EtherLink *p, int num, +EtherLink::Link::Link(const string &name, EtherObject *p, int num, double rate, Tick delay, Tick delay_var, EtherDump *d) : objName(name), parent(p), number(num), txint(NULL), rxint(NULL), ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d), @@ -251,7 +250,7 @@ paramOut(os, "type", string("LinkDelayEvent")); Event::serialize(os); - EtherLink *parent = link->parent; + EtherLink *parent = static_cast(link->parent); bool number = link->number; SERIALIZE_OBJPTR(parent); SERIALIZE_SCALAR(number); @@ -271,7 +270,7 @@ UNSERIALIZE_OBJPTR(parent); UNSERIALIZE_SCALAR(number); - link = parent->link[number]; + link = static_cast(parent)->link[number]; packet = make_shared(16384); packet->unserialize("packet", cp, section); diff -r d50bc51b82ab -r 51af672c9841 src/dev/etherswitch.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dev/etherswitch.hh Tue Jun 23 16:58:14 2015 -0500 @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2014 The Regents of The University of Michigan + * 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 + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Anthony Gutierrez + */ + +/* @file + * Device model for an ethernet switch + */ + +#ifndef __DEV_ETHERSWITCH_HH__ +#define __DEV_ETHERSWITCH_HH__ + +#include "base/inet.hh" +#include "dev/etherint.hh" +#include "dev/etherlink.hh" +#include "dev/etherobject.hh" +#include "dev/etherpkt.hh" +#include "dev/pktfifo.hh" +#include "params/EtherSwitch.hh" +#include "sim/eventq.hh" + +class EtherSwitch : public EtherObject +{ + public: + typedef EtherSwitchParams Params; + + EtherSwitch(const Params *p); + virtual ~EtherSwitch(); + + const Params * params() const + { + return dynamic_cast(_params); + } + + virtual EtherInt *getEthPort(const std::string &if_name, int idx); + + protected: + friend class OrderingEvent; + friend class QueuedPacketsDecEvent; + class Interface : public EtherInt + { + public: + Interface(const std::string &name, EtherObject *p, int number, + int inputBufferSize, int outputBufferSize, double rate, + Tick delay, Tick delay_var, int output_q_size); + bool recvPacket(EthPacketPtr packet); + bool sendPacket(EthPacketPtr Packet); + EthPacketPtr getInputPacket(); + void popInputPacket() { inputFifo.pop(); } + void sendDone() {} + bool isBusy() const { return inputFifo.full(); } + bool inputFifoEmpty() const { return inputFifo.empty(); } + uint64_t getTimeStamp(EthPacketPtr packet); + void setTimeStamp(uint64_t time_stamp, EthPacketPtr packet); + void txDone(EthPacketPtr packet); + + private: + friend class OrderingEvent; + friend class QueuedPacketsDecEvent; + EtherObject *parent; + int number; + PacketFifo inputFifo; + // switch speed + double ticksPerByte; + Tick intDelay; + Tick delayVar; + // when interface gets idle + Tick releaseTick; + int outputQSize; + int queuedPackets; + }; + + class EtherFabric + { + public: + EtherFabric(const std::string &name, EtherSwitch &_etherSwitch); + ~EtherFabric(); + const std::string &name() const { return fabricName; } + void connectAllLinks(std::vector &_interfaces); + void forwardingEngine(Interface *); + Interface* lookupDestPort(Net::EthAddr destAddr); + void learnSenderAddr(Net::EthAddr srcAddr, Interface* sender); + void broadcast(EthPacketPtr packet, Interface *sender); + + protected: + struct SwitchTableEntry { + Interface *interface; + Tick arrivalTime; + }; + + private: + std::string fabricName; + EtherSwitch ðerSwitch; + // table that maps MAC address to interfaces + std::map forwardingTable; + // the actual fabric, i.e., this holds all the + // point-to-point links + std::map, + EtherLink::Link*> fabricLinks; + std::vector *interfaces; + }; + + void scheduleForwarding(Interface *); + void scheduleTransmit(); + private: + // actual switching fabric + EtherFabric switchFabric; + // all interfaces of the switch + std::vector interfaces; +}; + +#endif // __DEV_ETHERSWITCH_HH__ diff -r d50bc51b82ab -r 51af672c9841 src/dev/etherswitch.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dev/etherswitch.cc Tue Jun 23 16:58:14 2015 -0500 @@ -0,0 +1,486 @@ +/* + * Copyright (c) 2014 The Regents of The University of Michigan + * 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 + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Anthony Gutierrez + * Mohammad Alian + */ + +/* @file + * Device model for an ethernet switch + */ + +#include "dev/etherswitch.hh" + +#include + +#include "base/random.hh" +#include "debug/EthernetAll.hh" + +using namespace std; + +class OrderingEvent : public Event +{ + protected: + EtherSwitch::Interface *interface; + EthPacketPtr packet; + + public: + OrderingEvent(EtherSwitch::Interface *interface, EthPacketPtr pkt); + + void process(); + + virtual void serialize(ostream &os); + void unserialize(Checkpoint *cp, const string §ion) {} + void unserialize(Checkpoint *cp, const string §ion, + EventQueue *eventq); +}; + +class QueuedPacketsDecEvent : public Event +{ + protected: + EtherSwitch::Interface *interface; + + public: + QueuedPacketsDecEvent(EtherSwitch::Interface *i): + Event(Default_Pri, AutoSerialize | AutoDelete), interface(i) {} + + void process() { + DPRINTF(Ethernet, "decrement queuedPackets variable, %d\n", + interface->queuedPackets); + interface->queuedPackets --; + } + + virtual void serialize(ostream &os); + void unserialize(Checkpoint *cp, const string §ion) {} + void unserialize(Checkpoint *cp, const string §ion, + EventQueue *eventq); +}; + +EtherSwitch::EtherSwitch(const Params *p) + : EtherObject(p), switchFabric(name() + ".switchFabric", + *this) +{ + for (int i = 0; i < p->port_count; ++i) { + std::string interfaceName = csprintf("%s.interface%d", name(), i); + Interface *interface = new Interface(interfaceName, this, + i, + p->input_buffer_size, + p->output_buffer_size, + p->speed, + p->delay, + p->delay_var, + p->queue_size); + interfaces.push_back(interface); + } + switchFabric.connectAllLinks(interfaces); +} + +EtherSwitch::~EtherSwitch() +{ + for (auto it : interfaces) + delete it; + + interfaces.clear(); +} + +EtherInt* +EtherSwitch::getEthPort(const std::string &if_name, int idx) +{ + if (idx < 0 || idx >= interfaces.size()) + return NULL; + + Interface *interface = interfaces.at(idx); + panic_if(interface->getPeer(), "interface already connected\n"); + + return interface; +} + +// schedule the forwarding engine, which is responsible +// for figuring out which port to forward the packet to, +// or broadcasting the packet +void +EtherSwitch::scheduleForwarding(Interface *sender) +{ + DPRINTF(Ethernet, "scheduling forwarding engine\n"); + // forward packet from the interface input queue + switchFabric.forwardingEngine(sender); +} + +EtherSwitch::Interface::Interface(const std::string &name, EtherObject *p, + int num, int inputBufferSize, int outputBufferSize, double rate, + Tick delay, Tick delay_var, int output_q_size): EtherInt(name), + parent(p), inputFifo(inputBufferSize), ticksPerByte(rate), + intDelay(delay), delayVar(delay_var), releaseTick(0), + outputQSize(output_q_size), queuedPackets(0) +{ +} + +// when a packet is received from a device just store +// it in an input queue until it can be forwarded +bool +EtherSwitch::Interface::recvPacket(EthPacketPtr packet) +{ + DPRINTF(Ethernet, "received packet\n"); + if (inputFifo.push(packet)) { + DPRINTF(Ethernet, "adding packet to input queue\n"); + ((EtherSwitch*)parent)->scheduleForwarding(this); + return true; + } else { + DPRINTF(Ethernet, "input fifo for interface %s full, " + "dropping packet.\n", name()); + return false; + } +} + +// don't actually send a packet here. once a packet +// makes it through a fabric link, put it in +// an output queue +bool +EtherSwitch::Interface::sendPacket(EthPacketPtr packet) +{ + uint64_t time_stamp; + time_stamp = getTimeStamp(packet); + DPRINTF(Ethernet, "ordering point of packet with time stamp %lu\n", + time_stamp); + if (curTick() > time_stamp){ + ccprintf(cerr, "VIOLATION, packet arrived late %lu\n", + curTick() - time_stamp); + txDone(packet); + } + else { + Event *event = new OrderingEvent(this, packet); + parent->schedule(event, time_stamp); + } + return true; +} + +// this is where we actually send a packet to the +// receiving device +void +EtherSwitch::Interface::txDone(EthPacketPtr packet) +{ + // update packet time stamp and send it instantly to peer + Tick trans_delay = (Tick)ceil(((double)packet->length * ticksPerByte) + 1.0); + if (delayVar != 0) + trans_delay += random_mt.random(0, delayVar); + if (releaseTick > curTick()) { + releaseTick += trans_delay; + queuedPackets ++; + // schedule an event to decrement "queuedPackets" @ releaseTick + Event *event = new QueuedPacketsDecEvent(this); + parent->schedule(event, releaseTick); + } + else + releaseTick = curTick() + trans_delay; + + DPRINTF(Ethernet, "deliver packet with updated time stamp %lu\n", + releaseTick + intDelay); + //set packet time stamp and send it instantly to the peer + setTimeStamp( releaseTick + intDelay, packet); + assert(peer->recvPacket(packet)); +} + +EthPacketPtr +EtherSwitch::Interface::getInputPacket() +{ + if (inputFifo.empty()) + return NULL; + EthPacketPtr pkt; + pkt = inputFifo.front(); + //we don't need the packet in the fifo, as we deliver it immediately + popInputPacket(); + return pkt; +} + +EtherSwitch::EtherFabric::EtherFabric(const std::string &name, + EtherSwitch &_etherSwitch): fabricName(name), + etherSwitch(_etherSwitch), interfaces(NULL) +{ +} + +EtherSwitch::EtherFabric::~EtherFabric() +{ + for (auto it : fabricLinks) + delete it.second; + + fabricLinks.clear(); +} + +// connect rx and tx links in a point-to-point fashion for +// each port on the switch. there will always be n*(n-1) "no delay" links. +// this essentially creates the switch fabric +void +EtherSwitch::EtherFabric::connectAllLinks(std::vector &_interfaces) +{ + interfaces = &_interfaces; + int linkNum = 0; + + for (auto itr1 : *interfaces) { + for (auto itr2 : *interfaces) { + if (itr1 == itr2) + continue; + std::string linkName = csprintf("%s.link%d", name(), linkNum); + //instantiate "no delay" etherlinks + EtherLink::Link *link = new EtherLink::Link(linkName, ðerSwitch, + linkNum, 0, 0, 0, etherSwitch.params()->dump); + link->setTxInt(itr1); + link->setRxInt(itr2); + std::pair intPair + = std::make_pair(itr1, itr2); + + DPRINTF(Ethernet, "connecting port %s and port %s " + "over link %x\n", itr1->name(), itr2->name(), + link->name()); + fabricLinks.insert(std::pair, + EtherLink::Link*>(intPair, link)); + ++linkNum; + } + } +} + +// forward along or broadcast the packet that is received in "sender" interface +void +EtherSwitch::EtherFabric::forwardingEngine(Interface *sender) +{ + Interface *receiver; + + //send packet immediately over the fabric + DPRINTF(Ethernet, "forwarding packet over fabric\n"); + + EthPacketPtr packet = sender->getInputPacket(); + + //we should have a packet in the input queue for this interface + assert(packet); + + uint8_t srcAddr[ETH_ADDR_LEN]; + uint8_t destAddr[ETH_ADDR_LEN]; + memcpy(srcAddr, &packet->data[6], ETH_ADDR_LEN); + memcpy(destAddr, packet->data, ETH_ADDR_LEN); + Net::EthAddr destMacAddr(destAddr); + Net::EthAddr srcMacAddr(srcAddr); + + learnSenderAddr(srcMacAddr, sender); + receiver = lookupDestPort(destMacAddr); + + if (!receiver || destMacAddr.multicast() || destMacAddr.broadcast()) { + broadcast(packet, sender); + } else { + DPRINTF(Ethernet, "sending packet from MAC %x on port " + "%s to MAC %x on port %s\n", uint64_t(srcMacAddr), + sender->name(), uint64_t(destMacAddr), receiver->name()); + auto linkItr = fabricLinks.find(std::make_pair(sender, receiver)); + assert(linkItr != fabricLinks.end()); + linkItr->second->transmit(packet); + } +} + +// try to find which port a device (MAC) is associated with +EtherSwitch::Interface* +EtherSwitch::EtherFabric::lookupDestPort(Net::EthAddr destMacAddr) +{ + auto it = forwardingTable.find(uint64_t(destMacAddr)); + + if (it == forwardingTable.end()) { + DPRINTF(Ethernet, "no entry in forwaring table for MAC: " + "%x\n", uint64_t(destMacAddr)); + return NULL; + } + + DPRINTF(Ethernet, "found entry for MAC address %x on port %s\n", + uint64_t(destMacAddr), it->second.interface->name()); + return it->second.interface; +} + +// cache the MAC address for the device connected to a given port +void +EtherSwitch::EtherFabric::learnSenderAddr(Net::EthAddr srcMacAddr, + Interface *sender) +{ + // learn the port for the sending MAC address + auto it = forwardingTable.find(uint64_t(srcMacAddr)); + + // if the port for sender's MAC address is not cached, + // cache it now, otherwise just update arrival time + if (it == forwardingTable.end()) { + DPRINTF(Ethernet, "adding forwarding table entry for MAC " + " address %x on port %s\n", uint64_t(srcMacAddr), + sender->name()); + SwitchTableEntry forwardingTableEntry; + forwardingTableEntry.interface = sender; + forwardingTableEntry.arrivalTime = curTick(); + forwardingTable.insert(std::pair( + uint64_t(srcMacAddr), forwardingTableEntry)); + } else { + it->second.arrivalTime = curTick(); + } + // should also schedule the removal of an entry after it's TTL expires +} + +// broadcast a packet to all ports without allowing any loopback +void +EtherSwitch::EtherFabric::broadcast(EthPacketPtr packet, Interface *sender) +{ + //broadcast packets on all ports + for (auto it : *interfaces) { + if (it == sender) + continue; + + auto linkItr = fabricLinks.find(std::make_pair(sender, it)); + assert(linkItr != fabricLinks.end()); + EtherLink::Link *link = linkItr->second; + DPRINTF(Ethernet, "broadcasting from port %s to port %s " + "over link %s\n", sender->name(), it->name(), link->name()); + //we have to be able to send the packet through the fabric + if (!link->transmit(packet)) { + DPRINTF(Ethernet, "we have to be able to send the packet" + " through the fabric\n"); + assert(link->transmit(packet)); + } + } +} + +EtherSwitch * +EtherSwitchParams::create() +{ + return new EtherSwitch(this); +} + +uint64_t +EtherSwitch::Interface::getTimeStamp(EthPacketPtr packet) +{ + DPRINTF(Ethernet, "get packet time stamp, length = %d\n",packet->length); + + char time_stamp_cstr[13]; + uint64_t time_stamp_int; + int i = 0; + memmove(time_stamp_cstr, packet->data + packet->length - 12, 12); + //find the first non-zero digit, i = position of the first non zero digit + for (i = 0; i < 12; i++) + if(time_stamp_cstr[i] != '0') + break; + memmove(time_stamp_cstr, time_stamp_cstr + i, 12 - i); + time_stamp_cstr[12 - i] = '\0'; + time_stamp_int = atol(time_stamp_cstr) + curTick() - + curTick() % 1000000000000; + /* + Sanity check + If we had a transition to next second of simulation while packet was in + flight. We assume that the flight time is not more than 0.5 second in + simulted time + */ + if (time_stamp_int > curTick() + 500000000000) + time_stamp_int = time_stamp_int - 1000000000000; + if (time_stamp_int < curTick() - 500000000000) + time_stamp_int = time_stamp_int + 1000000000000; + return time_stamp_int; +} + +void +EtherSwitch::Interface::setTimeStamp(uint64_t time_stamp, EthPacketPtr packet) +{ + DPRINTF(Ethernet, "set packet time stamp to %lu\n", time_stamp); + + char time_stamp_cstr[13]; + char zero_pad[13] = "000000000000"; + //convert tick to c_string + sprintf(time_stamp_cstr, "%lu", time_stamp % 1000000000000); + //put new tick into the zero-padded string + memmove(zero_pad + strlen(zero_pad) - strlen(time_stamp_cstr), + time_stamp_cstr, strlen(time_stamp_cstr)); + //replace zero padded string with the current time stamp + memmove(packet->data + packet->length - 12, zero_pad, 12); +} + + +OrderingEvent::OrderingEvent(EtherSwitch::Interface *i, EthPacketPtr p) + : Event(Default_Pri, AutoSerialize | AutoDelete), interface(i), packet(p) +{ +} + +void +OrderingEvent::process() +{ + interface->txDone(packet); +} + +void +OrderingEvent::serialize(ostream &os) +{ + paramOut(os, "type", string("OrderingEvent")); + Event::serialize(os); + + EtherSwitch *parent = static_cast(interface->parent); + int number = interface->number; + SERIALIZE_OBJPTR(parent); + SERIALIZE_SCALAR(number); + + packet->serialize("packet", os); +} + +void +OrderingEvent::unserialize(Checkpoint *cp, const string §ion, + EventQueue *eventq) +{ + Event::unserialize(cp, section, eventq); + + EtherSwitch *parent; + int number; + UNSERIALIZE_OBJPTR(parent); + UNSERIALIZE_SCALAR(number); + + interface = static_cast(parent)->interfaces[number]; + + packet = make_shared(16384); + packet->unserialize("packet", cp, section); +} + +void +QueuedPacketsDecEvent::serialize(ostream &os) +{ + paramOut(os, "type", string("QueuedPacketsDecEvent")); + Event::serialize(os); + + EtherSwitch *parent = static_cast(interface->parent); + int number = interface->number; + SERIALIZE_OBJPTR(parent); + SERIALIZE_SCALAR(number); +} + + +void +QueuedPacketsDecEvent::unserialize(Checkpoint *cp, const string §ion, + EventQueue *eventq) +{ + Event::unserialize(cp, section, eventq); + + EtherSwitch *parent; + int number; + UNSERIALIZE_OBJPTR(parent); + UNSERIALIZE_SCALAR(number); + + interface = static_cast(parent)->interfaces[number]; +}