gem5  v20.1.0.0
etherswitch.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 The Regents of The University of Michigan
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met: redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer;
9  * redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution;
12  * neither the name of the copyright holders nor the names of its
13  * contributors may be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /* @file
30  * Device model for an ethernet switch
31  */
32 
33 #include "dev/net/etherswitch.hh"
34 
35 #include "base/random.hh"
36 #include "base/trace.hh"
37 #include "debug/EthernetAll.hh"
38 #include "sim/core.hh"
39 
40 using namespace std;
41 
43  : SimObject(p), ttl(p->time_to_live)
44 {
45  for (int i = 0; i < p->port_interface_connection_count; ++i) {
46  std::string interfaceName = csprintf("%s.interface%d", name(), i);
47  Interface *interface = new Interface(interfaceName, this,
48  p->output_buffer_size, p->delay,
49  p->delay_var, p->fabric_speed, i);
50  interfaces.push_back(interface);
51  }
52 }
53 
55 {
56  for (auto it : interfaces)
57  delete it;
58 
59  interfaces.clear();
60 }
61 
62 Port &
63 EtherSwitch::getPort(const std::string &if_name, PortID idx)
64 {
65  if (if_name == "interface") {
66  panic_if(idx < 0 || idx >= interfaces.size(), "index out of bounds");
67  return *interfaces.at(idx);
68  }
69 
70  return SimObject::getPort(if_name, idx);
71 }
72 
73 bool
75 {
76  assert(ptr->length);
77 
78  _size += ptr->length;
79  fifo.emplace_hint(fifo.end(), ptr, curTick(), senderId);
80 
81  // Drop the extra pushed packets from end of the fifo
82  while (avail() < 0) {
83  DPRINTF(Ethernet, "Fifo is full. Drop packet: len=%d\n",
84  std::prev(fifo.end())->packet->length);
85 
86  _size -= std::prev(fifo.end())->packet->length;
87  fifo.erase(std::prev(fifo.end()));
88  }
89 
90  if (empty()) {
91  warn("EtherSwitch: Packet length (%d) exceeds the maximum storage "
92  "capacity of port fifo (%d)", ptr->length, _maxsize);
93  }
94 
95  // Return true if the newly pushed packet gets inserted
96  // at the head of the queue, otherwise return false
97  // We need this information to deschedule the event that has been
98  // scheduled for the old head of queue packet and schedule a new one
99  if (!empty() && fifo.begin()->packet == ptr) {
100  return true;
101  }
102  return false;
103 }
104 
105 void
107 {
108  if (empty())
109  return;
110 
111  assert(_size >= fifo.begin()->packet->length);
112  // Erase the packet at the head of the queue
113  _size -= fifo.begin()->packet->length;
114  fifo.erase(fifo.begin());
115 }
116 
117 void
119 {
120  fifo.clear();
121  _size = 0;
122 }
123 
125  EtherSwitch *etherSwitch,
126  uint64_t outputBufferSize, Tick delay,
127  Tick delay_var, double rate, unsigned id)
128  : EtherInt(name), ticksPerByte(rate), switchDelay(delay),
129  delayVar(delay_var), interfaceId(id), parent(etherSwitch),
130  outputFifo(name + ".outputFifo", outputBufferSize),
131  txEvent([this]{ transmit(); }, name)
132 {
133 }
134 
135 bool
137 {
138  Net::EthAddr destMacAddr(packet->data);
139  Net::EthAddr srcMacAddr(&packet->data[6]);
140 
141  learnSenderAddr(srcMacAddr, this);
142  Interface *receiver = lookupDestPort(destMacAddr);
143 
144  if (!receiver || destMacAddr.multicast() || destMacAddr.broadcast()) {
145  for (auto it : parent->interfaces)
146  if (it != this)
147  it->enqueue(packet, interfaceId);
148  } else {
149  DPRINTF(Ethernet, "sending packet from MAC %x on port "
150  "%s to MAC %x on port %s\n", uint64_t(srcMacAddr),
151  this->name(), uint64_t(destMacAddr), receiver->name());
152 
153  receiver->enqueue(packet, interfaceId);
154  }
155  // At the output port, we either have buffer space (no drop) or
156  // don't (drop packet); in both cases packet is received on
157  // the interface successfully and there is no notion of busy
158  // interface here (as we don't have inputFifo)
159  return true;
160 }
161 
162 void
164 {
165  // assuming per-interface transmission events,
166  // if the newly push packet gets inserted at the head of the queue
167  // (either there was nothing in the queue or the priority of the new
168  // packet was higher than the packets already in the fifo)
169  // then we need to schedule an event at
170  // "curTick" + "switchingDelay of the packet at the head of the fifo"
171  // to send this packet out the external link
172  // otherwise, there is already a txEvent scheduled
173  if (outputFifo.push(packet, senderId)) {
174  parent->reschedule(txEvent, curTick() + switchingDelay(), true);
175  }
176 }
177 
178 void
180 {
181  // there should be something in the output queue
182  assert(!outputFifo.empty());
183 
184  if (!sendPacket(outputFifo.front())) {
185  DPRINTF(Ethernet, "output port busy...retry later\n");
186  if (!txEvent.scheduled())
187  parent->schedule(txEvent, curTick() + SimClock::Int::ns);
188  } else {
189  DPRINTF(Ethernet, "packet sent: len=%d\n", outputFifo.front()->length);
190  outputFifo.pop();
191  // schedule an event to send the pkt at
192  // the head of queue, if there is any
193  if (!outputFifo.empty()) {
194  parent->schedule(txEvent, curTick() + switchingDelay());
195  }
196  }
197 }
198 
199 Tick
201 {
202  Tick delay = (Tick)ceil(((double)outputFifo.front()->simLength
203  * ticksPerByte) + 1.0);
204  if (delayVar != 0)
205  delay += random_mt.random<Tick>(0, delayVar);
206  delay += switchDelay;
207  return delay;
208 }
209 
212 {
213  auto it = parent->forwardingTable.find(uint64_t(destMacAddr));
214 
215  if (it == parent->forwardingTable.end()) {
216  DPRINTF(Ethernet, "no entry in forwaring table for MAC: "
217  "%x\n", uint64_t(destMacAddr));
218  return nullptr;
219  }
220 
221  // check if this entry is valid based on TTL and lastUseTime
222  if ((curTick() - it->second.lastUseTime) > parent->ttl) {
223  // TTL for this mapping has been expired, so this item is not
224  // valide anymore, let's remove it from the map
225  parent->forwardingTable.erase(it);
226  return nullptr;
227  }
228 
229  DPRINTF(Ethernet, "found entry for MAC address %x on port %s\n",
230  uint64_t(destMacAddr), it->second.interface->name());
231  return it->second.interface;
232 }
233 
234 void
236  Interface *sender)
237 {
238  // learn the port for the sending MAC address
239  auto it = parent->forwardingTable.find(uint64_t(srcMacAddr));
240 
241  // if the port for sender's MAC address is not cached,
242  // cache it now, otherwise just update lastUseTime time
243  if (it == parent->forwardingTable.end()) {
244  DPRINTF(Ethernet, "adding forwarding table entry for MAC "
245  " address %x on port %s\n", uint64_t(srcMacAddr),
246  sender->name());
247  EtherSwitch::SwitchTableEntry forwardingTableEntry;
248  forwardingTableEntry.interface = sender;
249  forwardingTableEntry.lastUseTime = curTick();
250  parent->forwardingTable.insert(std::make_pair(uint64_t(srcMacAddr),
251  forwardingTableEntry));
252  } else {
253  it->second.lastUseTime = curTick();
254  }
255 }
256 
257 void
259 {
260  for (auto it : interfaces)
261  it->serializeSection(cp, it->name());
262 
263 }
264 
265 void
267 {
268  for (auto it : interfaces)
269  it->unserializeSection(cp, it->name());
270 
271 }
272 
273 void
275 {
276  bool event_scheduled = txEvent.scheduled();
277  SERIALIZE_SCALAR(event_scheduled);
278 
279  if (event_scheduled) {
280  Tick event_time = txEvent.when();
281  SERIALIZE_SCALAR(event_time);
282  }
283  outputFifo.serializeSection(cp, "outputFifo");
284 }
285 
286 void
288 {
289  bool event_scheduled;
290  UNSERIALIZE_SCALAR(event_scheduled);
291 
292  if (event_scheduled) {
293  Tick event_time;
294  UNSERIALIZE_SCALAR(event_time);
295  parent->schedule(txEvent, event_time);
296  }
297  outputFifo.unserializeSection(cp, "outputFifo");
298 }
299 
300 void
302 {
303  packet->serialize("packet", cp);
304  SERIALIZE_SCALAR(recvTick);
305  SERIALIZE_SCALAR(srcId);
306 }
307 
308 void
310 {
311  packet = make_shared<EthPacketData>(16384);
312  packet->unserialize("packet", cp);
313  UNSERIALIZE_SCALAR(recvTick);
314  UNSERIALIZE_SCALAR(srcId);
315 }
316 
317 void
319 {
320  SERIALIZE_SCALAR(_size);
321  int fifosize = fifo.size();
322 
323  SERIALIZE_SCALAR(fifosize);
324 
325  int i = 0;
326  for (const auto &entry : fifo)
327  entry.serializeSection(cp, csprintf("entry%d", i++));
328 }
329 
330 void
332 {
333  UNSERIALIZE_SCALAR(_size);
334  int fifosize;
335 
336  UNSERIALIZE_SCALAR(fifosize);
337  fifo.clear();
338 
339  for (int i = 0; i < fifosize; ++i) {
340  PortFifoEntry entry(nullptr, 0, 0);
341 
342  entry.unserializeSection(cp, csprintf("entry%d", i));
343 
344  fifo.insert(entry);
345 
346  }
347 }
348 
349 EtherSwitch *
350 EtherSwitchParams::create()
351 {
352  return new EtherSwitch(this);
353 }
EtherSwitch::Interface::PortFifo::_size
unsigned _size
Definition: etherswitch.hh:136
Serializable::unserializeSection
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
Definition: serialize.cc:178
SimClock::Int::ns
Tick ns
nanosecond
Definition: core.cc:65
warn
#define warn(...)
Definition: logging.hh:239
EtherSwitch::Interface::PortFifoEntry::serialize
void serialize(CheckpointOut &cp) const
Serialize an object.
Definition: etherswitch.cc:301
EtherSwitch::Interface::PortFifo::fifo
std::set< PortFifoEntry, EntryOrder > fifo
Definition: etherswitch.hh:132
EtherSwitch::getPort
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Definition: etherswitch.cc:63
UNSERIALIZE_SCALAR
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:797
EtherSwitch::interfaces
std::vector< Interface * > interfaces
Definition: etherswitch.hh:185
EtherSwitch::Interface::serialize
void serialize(CheckpointOut &cp) const
Serialize an object.
Definition: etherswitch.cc:274
etherswitch.hh
EtherSwitch::Interface::parent
EtherSwitch * parent
Definition: etherswitch.hh:98
EtherSwitch::SwitchTableEntry
Definition: etherswitch.hh:176
ArmISA::i
Bitfield< 7 > i
Definition: miscregs_types.hh:63
EtherSwitch::Interface::ticksPerByte
const double ticksPerByte
Definition: etherswitch.hh:93
EtherInt
Definition: etherint.hh:47
EtherSwitch
Definition: etherswitch.hh:48
EtherSwitch::Interface::PortFifo::serialize
void serialize(CheckpointOut &cp) const
Serialization stuff.
Definition: etherswitch.cc:318
Net::EthAddr
Definition: inet.hh:72
EtherSwitch::Interface::PortFifo::_maxsize
const unsigned _maxsize
Definition: etherswitch.hh:135
random.hh
Tick
uint64_t Tick
Tick count type.
Definition: types.hh:63
EtherSwitch::Interface
Model for an Ethernet switch port.
Definition: etherswitch.hh:68
PortID
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition: types.hh:237
EtherSwitch::Interface::PortFifo::push
bool push(EthPacketPtr ptr, unsigned senderId)
Push a packet into the fifo and sort the packets with same recv tick by port id.
Definition: etherswitch.cc:74
EtherSwitch::Interface::transmit
void transmit()
Definition: etherswitch.cc:179
EtherSwitch::SwitchTableEntry::lastUseTime
Tick lastUseTime
Definition: etherswitch.hh:178
EtherSwitch::Interface::PortFifoEntry::unserialize
void unserialize(CheckpointIn &cp)
Unserialize an object.
Definition: etherswitch.cc:309
random_mt
Random random_mt
Definition: random.cc:96
EtherSwitch::unserialize
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: etherswitch.cc:266
cp
Definition: cprintf.cc:40
Net::EthAddr::broadcast
bool broadcast() const
Definition: inet.hh:111
EtherSwitch::Params
EtherSwitchParams Params
Definition: etherswitch.hh:51
EtherSwitch::SwitchTableEntry::interface
Interface * interface
Definition: etherswitch.hh:177
EtherSwitch::Interface::learnSenderAddr
void learnSenderAddr(Net::EthAddr srcMacAddr, Interface *sender)
Definition: etherswitch.cc:235
SimObject::getPort
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
Definition: sim_object.cc:123
EtherSwitch::Interface::PortFifo::pop
void pop()
Definition: etherswitch.cc:106
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:234
EtherSwitch::EtherSwitch
EtherSwitch(const Params *p)
Definition: etherswitch.cc:42
EtherSwitch::Interface::PortFifo::empty
bool empty() const
Definition: etherswitch.hh:152
Port
Ports are used to interface objects to each other.
Definition: port.hh:56
EtherSwitch::Interface::enqueue
void enqueue(EthPacketPtr packet, unsigned senderId)
enqueue packet to the outputFifo
Definition: etherswitch.cc:163
EtherSwitch::Interface::PortFifo::clear
void clear()
Definition: etherswitch.cc:118
Port::id
const PortID id
A numeric identifier to distinguish ports in a vector, and set to InvalidPortID in case this port is ...
Definition: port.hh:74
core.hh
SERIALIZE_SCALAR
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:790
EtherSwitch::Interface::outputFifo
PortFifo outputFifo
output fifo at each interface
Definition: etherswitch.hh:171
SimObject::name
virtual const std::string name() const
Definition: sim_object.hh:133
EthPacketPtr
std::shared_ptr< EthPacketData > EthPacketPtr
Definition: etherpkt.hh:87
EtherSwitch::Interface::Interface
Interface(const std::string &name, EtherSwitch *_etherSwitch, uint64_t outputBufferSize, Tick delay, Tick delay_var, double rate, unsigned id)
Definition: etherswitch.cc:124
panic_if
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:197
Net::EthAddr::multicast
bool multicast() const
Definition: inet.hh:110
EtherInt::name
const std::string & name() const
Return port name (for DPRINTF).
Definition: etherint.hh:59
EtherSwitch::~EtherSwitch
~EtherSwitch()
Definition: etherswitch.cc:54
EtherSwitch::Interface::PortFifo::avail
int avail() const
Definition: etherswitch.hh:149
std
Overload hash function for BasicBlockRange type.
Definition: vec_reg.hh:587
EtherSwitch::Interface::PortFifoEntry
Definition: etherswitch.hh:100
EtherSwitch::Interface::switchingDelay
Tick switchingDelay()
Definition: etherswitch.cc:200
EtherSwitch::Interface::lookupDestPort
Interface * lookupDestPort(Net::EthAddr destAddr)
Definition: etherswitch.cc:211
Random::random
std::enable_if< std::is_integral< T >::value, T >::type random()
Use the SFINAE idiom to choose an implementation based on whether the type is integral or floating po...
Definition: random.hh:86
EtherSwitch::Interface::recvPacket
bool recvPacket(EthPacketPtr packet)
When a packet is received from a device, route it through an (several) output queue(s)
Definition: etherswitch.cc:136
EtherSwitch::Interface::delayVar
const Tick delayVar
Definition: etherswitch.hh:95
CheckpointOut
std::ostream CheckpointOut
Definition: serialize.hh:63
EtherSwitch::Interface::txEvent
EventFunctionWrapper txEvent
Definition: etherswitch.hh:173
EtherSwitch::serialize
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: etherswitch.cc:258
trace.hh
EtherSwitch::Interface::PortFifo::unserialize
void unserialize(CheckpointIn &cp)
Unserialize an object.
Definition: etherswitch.cc:331
EtherSwitch::Interface::interfaceId
const unsigned interfaceId
Definition: etherswitch.hh:96
MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:323
CheckpointIn
Definition: serialize.hh:67
EtherSwitch::Interface::unserialize
void unserialize(CheckpointIn &cp)
Unserialize an object.
Definition: etherswitch.cc:287
ArmISA::ttl
Bitfield< 51, 48 > ttl
Definition: miscregs_types.hh:148
csprintf
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:158
EtherSwitch::Interface::switchDelay
const Tick switchDelay
Definition: etherswitch.hh:94
curTick
Tick curTick()
The current simulated tick.
Definition: core.hh:45
SimObject
Abstract superclass for simulation objects.
Definition: sim_object.hh:92

Generated on Wed Sep 30 2020 14:02:11 for gem5 by doxygen 1.8.17