diff -r 954d3014f7f0 -r c7242a550140 src/dev/net/etherswitch.hh --- a/src/dev/net/etherswitch.hh Fri May 06 15:52:34 2016 +0100 +++ b/src/dev/net/etherswitch.hh Mon May 16 22:20:59 2016 -0500 @@ -36,6 +36,8 @@ #ifndef __DEV_ETHERSWITCH_HH__ #define __DEV_ETHERSWITCH_HH__ +#include +#include #include #include "base/inet.hh" @@ -66,12 +68,13 @@ /** * Model for an Ethernet switch port */ - class Interface : public EtherInt + class Interface : public EtherInt, public Serializable + { public: Interface(const std::string &name, EtherSwitch *_etherSwitch, uint64_t outputBufferSize, Tick delay, Tick delay_var, - double rate); + double rate, unsigned id); /** * When a packet is received from a device, route it * through an (several) output queue(s) @@ -80,25 +83,89 @@ /** * enqueue packet to the outputFifo */ - void enqueue(EthPacketPtr packet); + void enqueue(EthPacketPtr packet, unsigned senderId); void sendDone() {} Tick switchingDelay(); Interface* lookupDestPort(Net::EthAddr destAddr); void learnSenderAddr(Net::EthAddr srcMacAddr, Interface *sender); - void serialize(const std::string &base, CheckpointOut &cp) const; - void unserialize(const std::string &base, CheckpointIn &cp); + void serialize(CheckpointOut &cp) const; + void unserialize(CheckpointIn &cp); private: const double ticksPerByte; const Tick switchDelay; const Tick delayVar; + const unsigned interfaceId; + EtherSwitch *parent; + protected: + struct PortFifoEntry : public Serializable + + { + PortFifoEntry(EthPacketPtr pkt, Tick recv_tick, unsigned id) + : packet(pkt), recvTick(recv_tick), srcId(id) {} + + EthPacketPtr packet; + Tick recvTick; + // id of the port that the packet has been received from + unsigned srcId; + ~PortFifoEntry() + { + packet = nullptr; + recvTick = 0; + srcId = 0; + } + void serialize(CheckpointOut &cp) const; + void unserialize(CheckpointIn &cp); + }; + + class PortFifo : public Serializable + { + protected: + struct EntryOrder { + bool operator() (const PortFifoEntry& lhs, + const PortFifoEntry& rhs) const + { + if (lhs.recvTick == rhs.recvTick) + return lhs.srcId < rhs.srcId; + else + return lhs.recvTick < rhs.recvTick; + } + }; + std::set fifo; + const unsigned _maxsize; + unsigned _size; + + public: + PortFifo(int max) + :_maxsize(max), _size(0) {} + ~PortFifo() {} + int avail() const { return _maxsize - _size; } + + EthPacketPtr front() { return fifo.begin()->packet; } + bool empty() const { return _size <= 0; } + unsigned size() const { return _size; } + + /** + * Push a packet into the fifo + * and sort the packets with same recv tick by port id + */ + bool push(EthPacketPtr ptr, unsigned senderId); + void pop(); + void clear(); + /** + * Serialization stuff + */ + void serialize(CheckpointOut &cp) const; + void unserialize(CheckpointIn &cp); + + }; /** * output fifo at each interface */ - PacketFifo outputFifo; + PortFifo outputFifo; void transmit(); EventWrapper txEvent; }; diff -r 954d3014f7f0 -r c7242a550140 src/dev/net/etherswitch.cc --- a/src/dev/net/etherswitch.cc Fri May 06 15:52:34 2016 +0100 +++ b/src/dev/net/etherswitch.cc Mon May 16 22:20:59 2016 -0500 @@ -32,6 +32,7 @@ /* @file * Device model for an ethernet switch */ +#include #include "dev/net/etherswitch.hh" @@ -47,7 +48,7 @@ std::string interfaceName = csprintf("%s.interface%d", name(), i); Interface *interface = new Interface(interfaceName, this, p->output_buffer_size, p->delay, - p->delay_var, p->fabric_speed); + p->delay_var, p->fabric_speed, i); interfaces.push_back(interface); } } @@ -72,12 +73,55 @@ return interface; } +bool +EtherSwitch::Interface::PortFifo::push(EthPacketPtr ptr, unsigned senderId) +{ + assert(ptr->length); + + _size += ptr->length; + PortFifoEntry entry(ptr, curTick(), senderId); + fifo.insert(entry); + + // Drop the extra pushed packets from end of the fifo + while (avail() < 0) { + _size -= std::prev(fifo.end())->packet->length; + fifo.erase(std::prev(fifo.end())); + } + + // Retrun true if the newly pushed packet gets inserted + // at the head of the queue, otherwise reture false + // We need this information to deschedule the event that has been + // scheduled for the old head of queue packet and schedule a new one + if (fifo.begin()->recvTick == curTick() && + fifo.begin()->srcId == senderId) + return true; + return false; +} + +void +EtherSwitch::Interface::PortFifo::pop() +{ + if (empty()) + return; + + // Erase the packet at the head of the queue + _size -= fifo.begin()->packet->length; + fifo.erase(fifo.begin()); +} + +void +EtherSwitch::Interface::PortFifo::clear() +{ + fifo.clear(); + _size = 0; +} + EtherSwitch::Interface::Interface(const std::string &name, EtherSwitch *etherSwitch, uint64_t outputBufferSize, Tick delay, - Tick delay_var, double rate) + Tick delay_var, double rate, unsigned id) : EtherInt(name), ticksPerByte(rate), switchDelay(delay), - delayVar(delay_var), parent(etherSwitch), + delayVar(delay_var), interfaceId(id), parent(etherSwitch), outputFifo(outputBufferSize), txEvent(this) { } @@ -94,13 +138,13 @@ if (!receiver || destMacAddr.multicast() || destMacAddr.broadcast()) { for (auto it : parent->interfaces) if (it != this) - it->enqueue(packet); + it->enqueue(packet, interfaceId); } else { DPRINTF(Ethernet, "sending packet from MAC %x on port " "%s to MAC %x on port %s\n", uint64_t(srcMacAddr), this->name(), uint64_t(destMacAddr), receiver->name()); - receiver->enqueue(packet); + receiver->enqueue(packet, interfaceId); } // At the output port, we either have buffer space (no drop) or // don't (drop packet); in both cases packet is received on @@ -110,20 +154,19 @@ } void -EtherSwitch::Interface::enqueue(EthPacketPtr packet) +EtherSwitch::Interface::enqueue(EthPacketPtr packet, unsigned senderId) { - if (!outputFifo.push(packet)) { - // output buffer full, drop packet - DPRINTF(Ethernet, "output buffer full, drop packet\n"); - return; - } - // assuming per-interface transmission events, - // if there was nothing in the Fifo before push the - // current packet, then we need to schedule an event at - // curTick + switchingDelay to send this packet out the external link + // if the newly push packet gets inserted at the head of the queue + // (either there was nothing in the queue or the priority of the new + // packet was higher than the packets already in the fifo) + // then we need to schedule an event at + // "curTick" + "switchingDelay of the packet at the head of the fifo" + // to send this packet out the external link // otherwise, there is already a txEvent scheduled - if (!txEvent.scheduled()) { + if (outputFifo.push(packet, senderId)) { + if (txEvent.scheduled()) + parent->deschedule(txEvent); parent->schedule(txEvent, curTick() + switchingDelay()); } } @@ -211,42 +254,95 @@ EtherSwitch::serialize(CheckpointOut &cp) const { for (auto it : interfaces) - it->serialize(it->name(), cp); + it->serializeSection(cp, it->name()); + } void EtherSwitch::unserialize(CheckpointIn &cp) { for (auto it : interfaces) - it->unserialize(it->name(), cp); + it->unserializeSection(cp, it->name()); + } void -EtherSwitch::Interface::serialize(const std::string &base, CheckpointOut &cp) -const +EtherSwitch::Interface::serialize(CheckpointOut &cp) const { bool event_scheduled = txEvent.scheduled(); - paramOut(cp, base + ".event_scheduled", event_scheduled); + SERIALIZE_SCALAR(event_scheduled); + if (event_scheduled) { Tick event_time = txEvent.when(); - paramOut(cp, base + ".event_time", event_time); + SERIALIZE_SCALAR(event_time); } - - outputFifo.serialize(base + "outputFifo", cp); + outputFifo.serializeSection(cp, "outputFifo"); } void -EtherSwitch::Interface::unserialize(const std::string &base, CheckpointIn &cp) +EtherSwitch::Interface::unserialize(CheckpointIn &cp) { bool event_scheduled; - paramIn(cp, base + ".event_scheduled", event_scheduled); + UNSERIALIZE_SCALAR(event_scheduled); + if (event_scheduled) { Tick event_time; - paramIn(cp, base + ".event_time", event_time); + UNSERIALIZE_SCALAR(event_time); parent->schedule(txEvent, event_time); } + outputFifo.unserializeSection(cp, "outputFifo"); +} - outputFifo.unserialize(base + "outputFifo", cp); +void +EtherSwitch::Interface::PortFifoEntry::serialize(CheckpointOut &cp) const + +{ + packet->serialize("packet", cp); + SERIALIZE_SCALAR(recvTick); + SERIALIZE_SCALAR(srcId); +} + +void +EtherSwitch::Interface::PortFifoEntry::unserialize(CheckpointIn &cp) + +{ + packet = make_shared(16384); + packet->unserialize("packet", cp); + UNSERIALIZE_SCALAR(recvTick); + UNSERIALIZE_SCALAR(srcId); +} + +void +EtherSwitch::Interface::PortFifo::serialize(CheckpointOut &cp) const + +{ + SERIALIZE_SCALAR(_size); + SERIALIZE_SCALAR(_maxsize); + SERIALIZE_SCALAR(fifo.size()); + + int i = 0; + for (const auto &entry : fifo) + entry.serializeSection(cp, csprintf("entry%d", i++)); +} + +void +EtherSwitch::Interface::PortFifo::unserialize(CheckpointIn &cp) + +{ + UNSERIALIZE_SCALAR(_size); + int fifosize; + + UNSERIALIZE_SCALAR(fifosize); + fifo.clear(); + + for (int i = 0; i < fifosize; ++i) { + PortFifoEntry entry(nullptr, 0, 0); + + entry.unserializeSection(cp, csprintf("entry%d", i)); + + fifo.insert(entry); + + } } EtherSwitch *