summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dev/net/Ethernet.py12
-rw-r--r--src/dev/net/SConscript1
-rw-r--r--src/dev/net/etherswitch.cc256
-rw-r--r--src/dev/net/etherswitch.hh123
4 files changed, 392 insertions, 0 deletions
diff --git a/src/dev/net/Ethernet.py b/src/dev/net/Ethernet.py
index 5f878ea10..981a19223 100644
--- a/src/dev/net/Ethernet.py
+++ b/src/dev/net/Ethernet.py
@@ -82,6 +82,18 @@ class EtherBus(EtherObject):
dump = Param.EtherDump(NULL, "dump object")
speed = Param.NetworkBandwidth('100Mbps', "bus speed in bits per second")
+class EtherSwitch(EtherObject):
+ type = 'EtherSwitch'
+ cxx_header = "dev/net/etherswitch.hh"
+ dump = Param.EtherDump(NULL, "dump object")
+ fabric_speed = Param.NetworkBandwidth('10Gbps', "switch fabric speed in bits "
+ "per second")
+ interface = VectorMasterPort("Ethernet Interface")
+ 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")
+ time_to_live = Param.Latency('10ms', "time to live of MAC address maping")
+
class EtherTap(EtherObject):
type = 'EtherTap'
cxx_header = "dev/net/ethertap.hh"
diff --git a/src/dev/net/SConscript b/src/dev/net/SConscript
index 9ad8eec92..e39df9d1c 100644
--- a/src/dev/net/SConscript
+++ b/src/dev/net/SConscript
@@ -51,6 +51,7 @@ SimObject('Ethernet.py')
# Basic Ethernet infrastructure
Source('etherbus.cc')
+Source('etherswitch.cc')
Source('etherdevice.cc')
Source('etherdump.cc')
Source('etherint.cc')
diff --git a/src/dev/net/etherswitch.cc b/src/dev/net/etherswitch.cc
new file mode 100644
index 000000000..02bbff65d
--- /dev/null
+++ b/src/dev/net/etherswitch.cc
@@ -0,0 +1,256 @@
+/*
+ * 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/net/etherswitch.hh"
+
+#include "base/random.hh"
+#include "debug/EthernetAll.hh"
+
+using namespace std;
+
+EtherSwitch::EtherSwitch(const Params *p)
+ : EtherObject(p), ttl(p->time_to_live)
+{
+ for (int i = 0; i < p->port_interface_connection_count; ++i) {
+ 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);
+ interfaces.push_back(interface);
+ }
+}
+
+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 nullptr;
+
+ Interface *interface = interfaces.at(idx);
+ panic_if(interface->getPeer(), "interface already connected\n");
+
+ return interface;
+}
+
+EtherSwitch::Interface::Interface(const std::string &name,
+ EtherSwitch *etherSwitch,
+ uint64_t outputBufferSize, Tick delay,
+ Tick delay_var, double rate)
+ : EtherInt(name), ticksPerByte(rate), switchDelay(delay),
+ delayVar(delay_var), parent(etherSwitch),
+ outputFifo(outputBufferSize), txEvent(this)
+{
+}
+
+bool
+EtherSwitch::Interface::recvPacket(EthPacketPtr packet)
+{
+ Net::EthAddr destMacAddr(packet->data);
+ Net::EthAddr srcMacAddr(&packet->data[6]);
+
+ learnSenderAddr(srcMacAddr, this);
+ Interface *receiver = lookupDestPort(destMacAddr);
+
+ if (!receiver || destMacAddr.multicast() || destMacAddr.broadcast()) {
+ for (auto it : parent->interfaces)
+ if (it != this)
+ it->enqueue(packet);
+ } 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);
+ }
+ // At the output port, we either have buffer space (no drop) or
+ // don't (drop packet); in both cases packet is received on
+ // the interface successfully and there is no notion of busy
+ // interface here (as we don't have inputFifo)
+ return true;
+}
+
+void
+EtherSwitch::Interface::enqueue(EthPacketPtr packet)
+{
+ 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
+ // otherwise, there is already a txEvent scheduled
+ if (!txEvent.scheduled()) {
+ parent->schedule(txEvent, curTick() + switchingDelay());
+ }
+}
+
+void
+EtherSwitch::Interface::transmit()
+{
+ // there should be something in the output queue
+ assert(!outputFifo.empty());
+
+ if (!sendPacket(outputFifo.front())) {
+ DPRINTF(Ethernet, "output port busy...retry later\n");
+ if (!txEvent.scheduled())
+ parent->schedule(txEvent, curTick() + retryTime);
+ } else {
+ DPRINTF(Ethernet, "packet sent: len=%d\n", outputFifo.front()->length);
+ outputFifo.pop();
+ // schedule an event to send the pkt at
+ // the head of queue, if there is any
+ if (!outputFifo.empty()) {
+ parent->schedule(txEvent, curTick() + switchingDelay());
+ }
+ }
+}
+
+Tick
+EtherSwitch::Interface::switchingDelay()
+{
+ Tick delay = (Tick)ceil(((double)outputFifo.front()->length
+ * ticksPerByte) + 1.0);
+ if (delayVar != 0)
+ delay += random_mt.random<Tick>(0, delayVar);
+ delay += switchDelay;
+ return delay;
+}
+
+EtherSwitch::Interface*
+EtherSwitch::Interface::lookupDestPort(Net::EthAddr destMacAddr)
+{
+ auto it = parent->forwardingTable.find(uint64_t(destMacAddr));
+
+ if (it == parent->forwardingTable.end()) {
+ DPRINTF(Ethernet, "no entry in forwaring table for MAC: "
+ "%x\n", uint64_t(destMacAddr));
+ return nullptr;
+ }
+
+ // check if this entry is valid based on TTL and lastUseTime
+ if ((curTick() - it->second.lastUseTime) > parent->ttl) {
+ // TTL for this mapping has been expired, so this item is not
+ // valide anymore, let's remove it from the map
+ parent->forwardingTable.erase(it);
+ return nullptr;
+ }
+
+ DPRINTF(Ethernet, "found entry for MAC address %x on port %s\n",
+ uint64_t(destMacAddr), it->second.interface->name());
+ return it->second.interface;
+}
+
+void
+EtherSwitch::Interface::learnSenderAddr(Net::EthAddr srcMacAddr,
+ Interface *sender)
+{
+ // learn the port for the sending MAC address
+ auto it = parent->forwardingTable.find(uint64_t(srcMacAddr));
+
+ // if the port for sender's MAC address is not cached,
+ // cache it now, otherwise just update lastUseTime time
+ if (it == parent->forwardingTable.end()) {
+ DPRINTF(Ethernet, "adding forwarding table entry for MAC "
+ " address %x on port %s\n", uint64_t(srcMacAddr),
+ sender->name());
+ EtherSwitch::SwitchTableEntry forwardingTableEntry;
+ forwardingTableEntry.interface = sender;
+ forwardingTableEntry.lastUseTime = curTick();
+ parent->forwardingTable.insert(std::make_pair(uint64_t(srcMacAddr),
+ forwardingTableEntry));
+ } else {
+ it->second.lastUseTime = curTick();
+ }
+}
+
+void
+EtherSwitch::serialize(CheckpointOut &cp) const
+{
+ for (auto it : interfaces)
+ it->serialize(it->name(), cp);
+}
+
+void
+EtherSwitch::unserialize(CheckpointIn &cp)
+{
+ for (auto it : interfaces)
+ it->unserialize(it->name(), cp);
+}
+
+void
+EtherSwitch::Interface::serialize(const std::string &base, CheckpointOut &cp)
+const
+{
+ bool event_scheduled = txEvent.scheduled();
+ paramOut(cp, base + ".event_scheduled", event_scheduled);
+ if (event_scheduled) {
+ Tick event_time = txEvent.when();
+ paramOut(cp, base + ".event_time", event_time);
+ }
+
+ outputFifo.serialize(base + "outputFifo", cp);
+}
+
+void
+EtherSwitch::Interface::unserialize(const std::string &base, CheckpointIn &cp)
+{
+ bool event_scheduled;
+ paramIn(cp, base + ".event_scheduled", event_scheduled);
+ if (event_scheduled) {
+ Tick event_time;
+ paramIn(cp, base + ".event_time", event_time);
+ parent->schedule(txEvent, event_time);
+ }
+
+ outputFifo.unserialize(base + "outputFifo", cp);
+}
+
+EtherSwitch *
+EtherSwitchParams::create()
+{
+ return new EtherSwitch(this);
+}
diff --git a/src/dev/net/etherswitch.hh b/src/dev/net/etherswitch.hh
new file mode 100644
index 000000000..69a3f40fd
--- /dev/null
+++ b/src/dev/net/etherswitch.hh
@@ -0,0 +1,123 @@
+/*
+ * 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 <unordered_map>
+
+#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);
+
+ protected:
+ /**
+ * Model for an Ethernet switch port
+ */
+ class Interface : public EtherInt
+ {
+ public:
+ Interface(const std::string &name, EtherSwitch *_etherSwitch,
+ uint64_t outputBufferSize, Tick delay, Tick delay_var,
+ double rate);
+ /**
+ * 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);
+ 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);
+
+ private:
+ const double ticksPerByte;
+ const Tick switchDelay;
+ const Tick delayVar;
+ EtherSwitch *parent;
+ /**
+ * output fifo at each interface
+ */
+ PacketFifo 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__