gem5  v22.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 #include "sim/cur_tick.hh"
40 
41 namespace gem5
42 {
43 
45  : SimObject(p), ttl(p.time_to_live)
46 {
47  for (int i = 0; i < p.port_interface_connection_count; ++i) {
48  std::string interfaceName = csprintf("%s.interface%d", name(), i);
49  Interface *interface = new Interface(interfaceName, this,
50  p.output_buffer_size, p.delay,
51  p.delay_var, p.fabric_speed, i);
52  interfaces.push_back(interface);
53  }
54 }
55 
57 {
58  for (auto it : interfaces)
59  delete it;
60 
61  interfaces.clear();
62 }
63 
64 Port &
65 EtherSwitch::getPort(const std::string &if_name, PortID idx)
66 {
67  if (if_name == "interface") {
68  panic_if(idx < 0 || idx >= interfaces.size(), "index out of bounds");
69  return *interfaces.at(idx);
70  }
71 
72  return SimObject::getPort(if_name, idx);
73 }
74 
75 bool
77 {
78  assert(ptr->length);
79 
80  _size += ptr->length;
81  fifo.emplace_hint(fifo.end(), ptr, curTick(), senderId);
82 
83  // Drop the extra pushed packets from end of the fifo
84  while (avail() < 0) {
85  DPRINTF(Ethernet, "Fifo is full. Drop packet: len=%d\n",
86  std::prev(fifo.end())->packet->length);
87 
88  _size -= std::prev(fifo.end())->packet->length;
89  fifo.erase(std::prev(fifo.end()));
90  }
91 
92  if (empty()) {
93  warn("EtherSwitch: Packet length (%d) exceeds the maximum storage "
94  "capacity of port fifo (%d)", ptr->length, _maxsize);
95  }
96 
97  // Return true if the newly pushed packet gets inserted
98  // at the head of the queue, otherwise return false
99  // We need this information to deschedule the event that has been
100  // scheduled for the old head of queue packet and schedule a new one
101  if (!empty() && fifo.begin()->packet == ptr) {
102  return true;
103  }
104  return false;
105 }
106 
107 void
109 {
110  if (empty())
111  return;
112 
113  assert(_size >= fifo.begin()->packet->length);
114  // Erase the packet at the head of the queue
115  _size -= fifo.begin()->packet->length;
116  fifo.erase(fifo.begin());
117 }
118 
119 void
121 {
122  fifo.clear();
123  _size = 0;
124 }
125 
127  EtherSwitch *etherSwitch,
128  uint64_t outputBufferSize, Tick delay,
129  Tick delay_var, double rate, unsigned id)
130  : EtherInt(name), ticksPerByte(rate), switchDelay(delay),
131  delayVar(delay_var), interfaceId(id), parent(etherSwitch),
132  outputFifo(name + ".outputFifo", outputBufferSize),
133  txEvent([this]{ transmit(); }, name)
134 {
135 }
136 
137 bool
139 {
140  networking::EthAddr destMacAddr(packet->data);
141  networking::EthAddr srcMacAddr(&packet->data[6]);
142 
143  learnSenderAddr(srcMacAddr, this);
144  Interface *receiver = lookupDestPort(destMacAddr);
145 
146  if (!receiver || destMacAddr.multicast() || destMacAddr.broadcast()) {
147  for (auto it : parent->interfaces)
148  if (it != this)
149  it->enqueue(packet, interfaceId);
150  } else {
151  DPRINTF(Ethernet, "sending packet from MAC %x on port "
152  "%s to MAC %x on port %s\n", uint64_t(srcMacAddr),
153  this->name(), uint64_t(destMacAddr), receiver->name());
154 
155  receiver->enqueue(packet, interfaceId);
156  }
157  // At the output port, we either have buffer space (no drop) or
158  // don't (drop packet); in both cases packet is received on
159  // the interface successfully and there is no notion of busy
160  // interface here (as we don't have inputFifo)
161  return true;
162 }
163 
164 void
166 {
167  // assuming per-interface transmission events,
168  // if the newly push packet gets inserted at the head of the queue
169  // (either there was nothing in the queue or the priority of the new
170  // packet was higher than the packets already in the fifo)
171  // then we need to schedule an event at
172  // "curTick" + "switchingDelay of the packet at the head of the fifo"
173  // to send this packet out the external link
174  // otherwise, there is already a txEvent scheduled
175  if (outputFifo.push(packet, senderId)) {
176  parent->reschedule(txEvent, curTick() + switchingDelay(), true);
177  }
178 }
179 
180 void
182 {
183  // there should be something in the output queue
184  assert(!outputFifo.empty());
185 
186  if (!sendPacket(outputFifo.front())) {
187  DPRINTF(Ethernet, "output port busy...retry later\n");
188  if (!txEvent.scheduled())
189  parent->schedule(txEvent, curTick() + sim_clock::as_int::ns);
190  } else {
191  DPRINTF(Ethernet, "packet sent: len=%d\n", outputFifo.front()->length);
192  outputFifo.pop();
193  // schedule an event to send the pkt at
194  // the head of queue, if there is any
195  if (!outputFifo.empty()) {
196  parent->schedule(txEvent, curTick() + switchingDelay());
197  }
198  }
199 }
200 
201 Tick
203 {
204  Tick delay = (Tick)ceil(((double)outputFifo.front()->simLength
205  * ticksPerByte) + 1.0);
206  if (delayVar != 0)
207  delay += random_mt.random<Tick>(0, delayVar);
208  delay += switchDelay;
209  return delay;
210 }
211 
214 {
215  auto it = parent->forwardingTable.find(uint64_t(destMacAddr));
216 
217  if (it == parent->forwardingTable.end()) {
218  DPRINTF(Ethernet, "no entry in forwaring table for MAC: "
219  "%x\n", uint64_t(destMacAddr));
220  return nullptr;
221  }
222 
223  // check if this entry is valid based on TTL and lastUseTime
224  if ((curTick() - it->second.lastUseTime) > parent->ttl) {
225  // TTL for this mapping has been expired, so this item is not
226  // valide anymore, let's remove it from the map
227  parent->forwardingTable.erase(it);
228  return nullptr;
229  }
230 
231  DPRINTF(Ethernet, "found entry for MAC address %x on port %s\n",
232  uint64_t(destMacAddr), it->second.interface->name());
233  return it->second.interface;
234 }
235 
236 void
238  Interface *sender)
239 {
240  // learn the port for the sending MAC address
241  auto it = parent->forwardingTable.find(uint64_t(srcMacAddr));
242 
243  // if the port for sender's MAC address is not cached,
244  // cache it now, otherwise just update lastUseTime time
245  if (it == parent->forwardingTable.end()) {
246  DPRINTF(Ethernet, "adding forwarding table entry for MAC "
247  " address %x on port %s\n", uint64_t(srcMacAddr),
248  sender->name());
249  EtherSwitch::SwitchTableEntry forwardingTableEntry;
250  forwardingTableEntry.interface = sender;
251  forwardingTableEntry.lastUseTime = curTick();
252  parent->forwardingTable.insert(std::make_pair(uint64_t(srcMacAddr),
253  forwardingTableEntry));
254  } else {
255  it->second.lastUseTime = curTick();
256  }
257 }
258 
259 void
261 {
262  for (auto it : interfaces)
263  it->serializeSection(cp, it->name());
264 
265 }
266 
267 void
269 {
270  for (auto it : interfaces)
271  it->unserializeSection(cp, it->name());
272 
273 }
274 
275 void
277 {
278  bool event_scheduled = txEvent.scheduled();
279  SERIALIZE_SCALAR(event_scheduled);
280 
281  if (event_scheduled) {
282  Tick event_time = txEvent.when();
283  SERIALIZE_SCALAR(event_time);
284  }
285  outputFifo.serializeSection(cp, "outputFifo");
286 }
287 
288 void
290 {
291  bool event_scheduled;
292  UNSERIALIZE_SCALAR(event_scheduled);
293 
294  if (event_scheduled) {
295  Tick event_time;
296  UNSERIALIZE_SCALAR(event_time);
297  parent->schedule(txEvent, event_time);
298  }
299  outputFifo.unserializeSection(cp, "outputFifo");
300 }
301 
302 void
304 {
305  packet->serialize("packet", cp);
306  SERIALIZE_SCALAR(recvTick);
307  SERIALIZE_SCALAR(srcId);
308 }
309 
310 void
312 {
313  packet = std::make_shared<EthPacketData>(16384);
314  packet->unserialize("packet", cp);
315  UNSERIALIZE_SCALAR(recvTick);
316  UNSERIALIZE_SCALAR(srcId);
317 }
318 
319 void
321 {
322  SERIALIZE_SCALAR(_size);
323  int fifosize = fifo.size();
324 
325  SERIALIZE_SCALAR(fifosize);
326 
327  int i = 0;
328  for (const auto &entry : fifo)
329  entry.serializeSection(cp, csprintf("entry%d", i++));
330 }
331 
332 void
334 {
335  UNSERIALIZE_SCALAR(_size);
336  int fifosize;
337 
338  UNSERIALIZE_SCALAR(fifosize);
339  fifo.clear();
340 
341  for (int i = 0; i < fifosize; ++i) {
342  PortFifoEntry entry(nullptr, 0, 0);
343 
344  entry.unserializeSection(cp, csprintf("entry%d", i));
345 
346  fifo.insert(entry);
347 
348  }
349 }
350 
351 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
const std::string & name() const
Return port name (for DPRINTF).
Definition: etherint.hh:62
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:76
std::set< PortFifoEntry, EntryOrder > fifo
Definition: etherswitch.hh:134
void serialize(CheckpointOut &cp) const
Serialization stuff.
Definition: etherswitch.cc:320
void unserialize(CheckpointIn &cp)
Unserialize an object.
Definition: etherswitch.cc:333
Model for an Ethernet switch port.
Definition: etherswitch.hh:70
PortFifo outputFifo
output fifo at each interface
Definition: etherswitch.hh:173
void learnSenderAddr(networking::EthAddr srcMacAddr, Interface *sender)
Definition: etherswitch.cc:237
Interface * lookupDestPort(networking::EthAddr destAddr)
Definition: etherswitch.cc:213
void unserialize(CheckpointIn &cp)
Unserialize an object.
Definition: etherswitch.cc:289
void enqueue(EthPacketPtr packet, unsigned senderId)
enqueue packet to the outputFifo
Definition: etherswitch.cc:165
bool recvPacket(EthPacketPtr packet)
When a packet is received from a device, route it through an (several) output queue(s)
Definition: etherswitch.cc:138
EventFunctionWrapper txEvent
Definition: etherswitch.hh:175
Interface(const std::string &name, EtherSwitch *_etherSwitch, uint64_t outputBufferSize, Tick delay, Tick delay_var, double rate, unsigned id)
Definition: etherswitch.cc:126
void serialize(CheckpointOut &cp) const
Serialize an object.
Definition: etherswitch.cc:276
std::vector< Interface * > interfaces
Definition: etherswitch.hh:188
EtherSwitchParams Params
Definition: etherswitch.hh:57
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Definition: etherswitch.cc:65
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: etherswitch.cc:268
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: etherswitch.cc:260
EtherSwitch(const Params &p)
Definition: etherswitch.cc:44
virtual std::string name() const
Definition: named.hh:47
Ports are used to interface objects to each other.
Definition: port.hh:62
const PortID id
A numeric identifier to distinguish ports in a vector, and set to InvalidPortID in case this port is ...
Definition: port.hh:79
Abstract superclass for simulation objects.
Definition: sim_object.hh:148
Random random_mt
Definition: random.cc:99
std::enable_if_t< std::is_integral_v< T >, T > random()
Use the SFINAE idiom to choose an implementation based on whether the type is integral or floating po...
Definition: random.hh:90
bool broadcast() const
Definition: inet.hh:117
bool multicast() const
Definition: inet.hh:116
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:204
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
Definition: serialize.cc:81
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
Definition: sim_object.cc:126
#define warn(...)
Definition: logging.hh:246
Bitfield< 51, 48 > ttl
Definition: misc_types.hh:152
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 54 > p
Definition: pagetable.hh:70
Tick ns
nanosecond
Definition: core.cc:71
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
std::ostream CheckpointOut
Definition: serialize.hh:66
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition: types.hh:245
uint64_t Tick
Tick count type.
Definition: types.hh:58
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
std::shared_ptr< EthPacketData > EthPacketPtr
Definition: etherpkt.hh:90
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568
void unserialize(CheckpointIn &cp)
Unserialize an object.
Definition: etherswitch.cc:311
void serialize(CheckpointOut &cp) const
Serialize an object.
Definition: etherswitch.cc:303

Generated on Wed Dec 21 2022 10:22:34 for gem5 by doxygen 1.9.1