| /* | 
 |  * 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 | 
 |  */ | 
 |  | 
 | #ifndef __DEV_ETHERSWITCH_HH__ | 
 | #define __DEV_ETHERSWITCH_HH__ | 
 |  | 
 | #include <map> | 
 | #include <set> | 
 |  | 
 | #include "base/inet.hh" | 
 | #include "dev/net/etherint.hh" | 
 | #include "dev/net/etherlink.hh" | 
 | #include "dev/net/etherobject.hh" | 
 | #include "dev/net/etherpkt.hh" | 
 | #include "dev/net/pktfifo.hh" | 
 | #include "params/EtherSwitch.hh" | 
 | #include "sim/eventq.hh" | 
 |  | 
 | class EtherSwitch : public EtherObject | 
 | { | 
 |   public: | 
 |     typedef EtherSwitchParams Params; | 
 |  | 
 |     EtherSwitch(const Params *p); | 
 |     ~EtherSwitch(); | 
 |  | 
 |     const Params * params() const | 
 |     { | 
 |         return dynamic_cast<const Params*>(_params); | 
 |     } | 
 |  | 
 |     EtherInt *getEthPort(const std::string &if_name, int idx) override; | 
 |  | 
 |   protected: | 
 |     /** | 
 |      * Model for an Ethernet switch port | 
 |      */ | 
 |     class Interface : public EtherInt, public Serializable | 
 |     { | 
 |       public: | 
 |         Interface(const std::string &name, EtherSwitch *_etherSwitch, | 
 |                   uint64_t outputBufferSize, Tick delay, Tick delay_var, | 
 |                   double rate, unsigned id); | 
 |         /** | 
 |          * When a packet is received from a device, route it | 
 |          * through an (several) output queue(s) | 
 |          */ | 
 |         bool recvPacket(EthPacketPtr packet); | 
 |         /** | 
 |          * enqueue packet to the outputFifo | 
 |          */ | 
 |         void enqueue(EthPacketPtr packet, unsigned senderId); | 
 |         void sendDone() {} | 
 |         Tick switchingDelay(); | 
 |  | 
 |         Interface* lookupDestPort(Net::EthAddr destAddr); | 
 |         void learnSenderAddr(Net::EthAddr srcMacAddr, Interface *sender); | 
 |  | 
 |         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<PortFifoEntry, EntryOrder> fifo; | 
 |  | 
 |             const std::string objName; | 
 |             const unsigned _maxsize; | 
 |             unsigned _size; | 
 |  | 
 |           public: | 
 |             PortFifo(const std::string &name, int max) | 
 |                 :objName(name), _maxsize(max), _size(0) {} | 
 |             ~PortFifo() {} | 
 |  | 
 |             const std::string name() { return objName; } | 
 |             // Returns the available capacity of the fifo. | 
 |             // It can return a negative value because in "push" function | 
 |             // we first push the received packet into the fifo and then | 
 |             // check if we exceed the available capacity (if avail() < 0) | 
 |             // and remove packets from the end of fifo | 
 |             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 | 
 |          */ | 
 |         PortFifo outputFifo; | 
 |         void transmit(); | 
 |         EventWrapper<Interface, &Interface::transmit> txEvent; | 
 |     }; | 
 |  | 
 |     struct SwitchTableEntry { | 
 |             Interface *interface; | 
 |             Tick lastUseTime; | 
 |         }; | 
 |  | 
 |   private: | 
 |     // time to live for MAC address mappings | 
 |     const double ttl; | 
 |     // all interfaces of the switch | 
 |     std::vector<Interface*> interfaces; | 
 |     // table that maps MAC address to interfaces | 
 |     std::map<uint64_t, SwitchTableEntry> forwardingTable; | 
 |  | 
 |     void serialize(CheckpointOut &cp) const override; | 
 |     void unserialize(CheckpointIn &cp) override; | 
 | }; | 
 |  | 
 | #endif // __DEV_ETHERSWITCH_HH__ |