etherlink.cc revision 633
112863Sgabeblack@google.com/*
212863Sgabeblack@google.com * Copyright (c) 2003 The Regents of The University of Michigan
312863Sgabeblack@google.com * All rights reserved.
412863Sgabeblack@google.com *
512863Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
612863Sgabeblack@google.com * modification, are permitted provided that the following conditions are
712863Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
812863Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
912863Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
1012863Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
1112863Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
1212863Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
1312863Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
1412863Sgabeblack@google.com * this software without specific prior written permission.
1512863Sgabeblack@google.com *
1612863Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1712863Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1812863Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1912863Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2012863Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2112863Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2212863Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2312863Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2412863Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2512863Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2612863Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2712863Sgabeblack@google.com */
2812863Sgabeblack@google.com
2912863Sgabeblack@google.com/* @file
3012863Sgabeblack@google.com * Device module for modelling a fixed bandwidth full duplex ethernet link
3112863Sgabeblack@google.com */
3212950Sgabeblack@google.com
3312863Sgabeblack@google.com#include <cmath>
3412863Sgabeblack@google.com#include <deque>
3513317Sgabeblack@google.com#include <string>
3613191Sgabeblack@google.com#include <vector>
3713091Sgabeblack@google.com
3813079Sgabeblack@google.com#include "base/trace.hh"
3912863Sgabeblack@google.com#include "dev/etherdump.hh"
4012950Sgabeblack@google.com#include "dev/etherint.hh"
4112863Sgabeblack@google.com#include "dev/etherlink.hh"
4212863Sgabeblack@google.com#include "dev/etherpkt.hh"
4312863Sgabeblack@google.com#include "sim/builder.hh"
4412863Sgabeblack@google.com#include "sim/universe.hh"
4512863Sgabeblack@google.com#include "sim/system.hh"
4612863Sgabeblack@google.com
4712950Sgabeblack@google.comusing namespace std;
4812863Sgabeblack@google.com
4912863Sgabeblack@google.comEtherLink::EtherLink(const string &name, EtherInt *i1, EtherInt *i2,
5012863Sgabeblack@google.com                     Tick speed, Tick dly, EtherDump *dump)
5113303Sgabeblack@google.com    : SimObject(name)
5213303Sgabeblack@google.com{
5313191Sgabeblack@google.com    double rate = ((double)ticksPerSecond * 8.0) / (double)speed;
5413191Sgabeblack@google.com    Tick delay = US2Ticks(dly);
5513291Sgabeblack@google.com
5612950Sgabeblack@google.com    link1 = new Link(name + ".link1", rate, delay, dump);
5712950Sgabeblack@google.com    link2 = new Link(name + ".link2", rate, delay, dump);
5812950Sgabeblack@google.com
5912950Sgabeblack@google.com    int1 = new Interface(name + ".int1", link1, link2);
6012950Sgabeblack@google.com    int2 = new Interface(name + ".int2", link2, link1);
6113079Sgabeblack@google.com
6213079Sgabeblack@google.com    int1->setPeer(i1);
6313268Sgabeblack@google.com    i1->setPeer(int1);
6413268Sgabeblack@google.com    int2->setPeer(i2);
6513079Sgabeblack@google.com    i2->setPeer(int2);
6613268Sgabeblack@google.com}
6713268Sgabeblack@google.com
6813268Sgabeblack@google.comEtherLink::~EtherLink()
6913268Sgabeblack@google.com{
7013268Sgabeblack@google.com    delete link1;
7113268Sgabeblack@google.com    delete link2;
7213079Sgabeblack@google.com
7313079Sgabeblack@google.com    delete int1;
7412982Sgabeblack@google.com    delete int2;
7512863Sgabeblack@google.com}
7612950Sgabeblack@google.com
7712863Sgabeblack@google.comEtherLink::Interface::Interface(const string &name, Link *tx, Link *rx)
7812950Sgabeblack@google.com    : EtherInt(name), txlink(tx)
7912950Sgabeblack@google.com{
8012863Sgabeblack@google.com    tx->setTxInt(this);
8113268Sgabeblack@google.com    rx->setRxInt(this);
8213268Sgabeblack@google.com}
8313268Sgabeblack@google.com
8413268Sgabeblack@google.comEtherLink::Link::Link(const string &name, double rate, Tick delay,
8513268Sgabeblack@google.com                      EtherDump *d)
8613268Sgabeblack@google.com    : objName(name), txint(NULL), rxint(NULL), ticksPerByte(rate),
8713268Sgabeblack@google.com      linkDelay(delay), dump(d), doneEvent(this)
8813268Sgabeblack@google.com{}
8913268Sgabeblack@google.com
9013268Sgabeblack@google.comvoid
9113268Sgabeblack@google.comEtherLink::serialize(ostream &os)
9212863Sgabeblack@google.com{
9312863Sgabeblack@google.com    nameOut(os, name() + ".link1");
9412863Sgabeblack@google.com    link1->serialize(os);
9512863Sgabeblack@google.com    nameOut(os, name() + ".link2");
9612863Sgabeblack@google.com    link2->serialize(os);
9713268Sgabeblack@google.com}
9813268Sgabeblack@google.com
9913268Sgabeblack@google.comvoid
10012950Sgabeblack@google.comEtherLink::unserialize(Checkpoint *cp, const string &section)
10113268Sgabeblack@google.com{
10212950Sgabeblack@google.com    link1->unserialize(cp, section + ".link1");
10313268Sgabeblack@google.com    link2->unserialize(cp, section + ".link2");
10412863Sgabeblack@google.com}
10512863Sgabeblack@google.com
10613091Sgabeblack@google.comvoid
10713091Sgabeblack@google.comEtherLink::Link::txComplete(PacketPtr &packet)
10813091Sgabeblack@google.com{
10913091Sgabeblack@google.com    DPRINTF(Ethernet, "packet received: len=%d\n", packet->length);
11013091Sgabeblack@google.com    DDUMP(EthernetData, packet->data, packet->length);
11113091Sgabeblack@google.com    rxint->sendPacket(packet);
11213091Sgabeblack@google.com}
11313091Sgabeblack@google.com
11413091Sgabeblack@google.comclass LinkDelayEvent : public Event
11513291Sgabeblack@google.com{
11613091Sgabeblack@google.com  protected:
11713091Sgabeblack@google.com    EtherLink::Link *link;
11813091Sgabeblack@google.com    PacketPtr packet;
11913091Sgabeblack@google.com
12013091Sgabeblack@google.com    // non-scheduling version for createForUnserialize()
12113091Sgabeblack@google.com    LinkDelayEvent(EtherLink::Link *link);
12213091Sgabeblack@google.com
12313091Sgabeblack@google.com  public:
12413291Sgabeblack@google.com    LinkDelayEvent(EtherLink::Link *link, PacketPtr &pkt, Tick when);
12513091Sgabeblack@google.com
12613091Sgabeblack@google.com    void process();
12713191Sgabeblack@google.com
12813191Sgabeblack@google.com    virtual void serialize(ostream &os);
12913191Sgabeblack@google.com    virtual void unserialize(Checkpoint *cp, const string &section);
13013268Sgabeblack@google.com    static Serializable *createForUnserialize(Checkpoint *cp,
13113268Sgabeblack@google.com                                              const string &section);
13213268Sgabeblack@google.com};
13313268Sgabeblack@google.com
13413268Sgabeblack@google.com
13513268Sgabeblack@google.comvoid
13613268Sgabeblack@google.comEtherLink::Link::txDone()
13713268Sgabeblack@google.com{
13813268Sgabeblack@google.com    if (dump)
13913268Sgabeblack@google.com        dump->dump(packet);
14013191Sgabeblack@google.com
14113191Sgabeblack@google.com    if (linkDelay > 0) {
14213191Sgabeblack@google.com        DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay);
14313191Sgabeblack@google.com        new LinkDelayEvent(this, packet, curTick + linkDelay);
14413191Sgabeblack@google.com    } else {
14513191Sgabeblack@google.com        txComplete(packet);
14613191Sgabeblack@google.com    }
14713317Sgabeblack@google.com
14813191Sgabeblack@google.com    packet = 0;
14913268Sgabeblack@google.com    assert(!busy());
15013268Sgabeblack@google.com
15113268Sgabeblack@google.com    txint->sendDone();
15213268Sgabeblack@google.com}
15313268Sgabeblack@google.com
15413268Sgabeblack@google.combool
15513268Sgabeblack@google.comEtherLink::Link::transmit(PacketPtr &pkt)
15613268Sgabeblack@google.com{
15713268Sgabeblack@google.com    if (busy()) {
15813268Sgabeblack@google.com        DPRINTF(Ethernet, "packet not sent, link busy\n");
15913191Sgabeblack@google.com        return false;
16013191Sgabeblack@google.com    }
16113191Sgabeblack@google.com
16213191Sgabeblack@google.com    DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length);
16313191Sgabeblack@google.com    DDUMP(EthernetData, pkt->data, pkt->length);
16413268Sgabeblack@google.com
16513268Sgabeblack@google.com    packet = pkt;
16613268Sgabeblack@google.com    Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0);
16713268Sgabeblack@google.com    DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
16813268Sgabeblack@google.com            delay, ticksPerByte);
16913268Sgabeblack@google.com    doneEvent.schedule(curTick + delay);
17013268Sgabeblack@google.com
17113268Sgabeblack@google.com    return true;
17213268Sgabeblack@google.com}
17313268Sgabeblack@google.com
17413191Sgabeblack@google.comvoid
17513191Sgabeblack@google.comEtherLink::Link::serialize(ostream &os)
17613191Sgabeblack@google.com{
17713191Sgabeblack@google.com    bool packet_exists = packet;
17813191Sgabeblack@google.com    SERIALIZE_SCALAR(packet_exists);
17913268Sgabeblack@google.com
18013268Sgabeblack@google.com    bool event_scheduled = doneEvent.scheduled();
18113268Sgabeblack@google.com    SERIALIZE_SCALAR(event_scheduled);
18213268Sgabeblack@google.com    if (event_scheduled) {
18313268Sgabeblack@google.com        Tick event_time = doneEvent.when();
18413268Sgabeblack@google.com        SERIALIZE_SCALAR(event_time);
18513268Sgabeblack@google.com    }
18613268Sgabeblack@google.com
18713268Sgabeblack@google.com    if (packet_exists) {
18813268Sgabeblack@google.com        nameOut(os, csprintf("%s.packet", name()));
18913191Sgabeblack@google.com        packet->serialize(os);
19013191Sgabeblack@google.com    }
19112863Sgabeblack@google.com}
19212950Sgabeblack@google.com
19312863Sgabeblack@google.comvoid
19412950Sgabeblack@google.comEtherLink::Link::unserialize(Checkpoint *cp, const string &section)
19512950Sgabeblack@google.com{
19612950Sgabeblack@google.com    bool packet_exists;
19712863Sgabeblack@google.com    UNSERIALIZE_SCALAR(packet_exists);
19812863Sgabeblack@google.com    if (packet_exists) {
19912950Sgabeblack@google.com        packet = new EtherPacket;
20013079Sgabeblack@google.com        packet->unserialize(cp, csprintf("%s.packet", section));
20113079Sgabeblack@google.com    }
20213317Sgabeblack@google.com
20313317Sgabeblack@google.com    bool event_scheduled;
20413079Sgabeblack@google.com    UNSERIALIZE_SCALAR(event_scheduled);
20513079Sgabeblack@google.com    if (event_scheduled) {
20613079Sgabeblack@google.com        Tick event_time;
20713079Sgabeblack@google.com        UNSERIALIZE_SCALAR(event_time);
20812950Sgabeblack@google.com        doneEvent.schedule(event_time);
20912950Sgabeblack@google.com    }
21012950Sgabeblack@google.com}
21112950Sgabeblack@google.com
21212950Sgabeblack@google.comLinkDelayEvent::LinkDelayEvent(EtherLink::Link *l)
21313046Sgabeblack@google.com    : Event(&mainEventQueue), link(l)
21412982Sgabeblack@google.com{
21512950Sgabeblack@google.com    setFlags(AutoSerialize);
216    setFlags(AutoDelete);
217}
218
219LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, PacketPtr &p, Tick when)
220    : Event(&mainEventQueue), link(l), packet(p)
221{
222    setFlags(AutoSerialize);
223    setFlags(AutoDelete);
224    schedule(when);
225}
226
227void
228LinkDelayEvent::process()
229{
230    link->txComplete(packet);
231}
232
233void
234LinkDelayEvent::serialize(ostream &os)
235{
236    paramOut(os, "type", string("LinkDelayEvent"));
237    Event::serialize(os);
238    SERIALIZE_OBJPTR(link);
239
240    nameOut(os, csprintf("%s.packet", name()));
241    packet->serialize(os);
242}
243
244
245void
246LinkDelayEvent::unserialize(Checkpoint *cp, const string &section)
247{
248    Event::unserialize(cp, section);
249    packet = new EtherPacket;
250    packet->unserialize(cp, csprintf("%s.packet", section));
251}
252
253
254Serializable *
255LinkDelayEvent::createForUnserialize(Checkpoint *cp, const string &section)
256{
257    EtherLink::Link *link;
258    UNSERIALIZE_OBJPTR(link);
259    return new LinkDelayEvent(link);
260}
261
262REGISTER_SERIALIZEABLE("LinkDelayEvent", LinkDelayEvent)
263
264BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherLink)
265
266    SimObjectParam<EtherInt *> interface1;
267    SimObjectParam<EtherInt *> interface2;
268    Param<Tick> link_speed;
269    Param<Tick> link_delay;
270    SimObjectParam<EtherDump *> packet_dump;
271
272END_DECLARE_SIM_OBJECT_PARAMS(EtherLink)
273
274BEGIN_INIT_SIM_OBJECT_PARAMS(EtherLink)
275
276    INIT_PARAM(interface1, "interface 1"),
277    INIT_PARAM(interface2, "interface 2"),
278    INIT_PARAM_DFLT(link_speed, "link speed in bits per second", 100000000),
279    INIT_PARAM_DFLT(link_delay, "transmit delay of packets in us", 0),
280    INIT_PARAM_DFLT(packet_dump, "object to dump network packets to", NULL)
281
282END_INIT_SIM_OBJECT_PARAMS(EtherLink)
283
284CREATE_SIM_OBJECT(EtherLink)
285{
286    return new EtherLink(getInstanceName(), interface1, interface2, link_speed,
287                         link_delay, packet_dump);
288}
289
290REGISTER_SIM_OBJECT("EtherLink", EtherLink)
291