diff -r d914107ffbf1 -r 79181d97f42d src/dev/Ethernet.py --- a/src/dev/Ethernet.py Mon Aug 10 22:40:36 2015 -0500 +++ b/src/dev/Ethernet.py Mon Aug 10 22:41:08 2015 -0500 @@ -57,6 +57,9 @@ delay_var = Param.Latency('0ns', "packet transmit delay variability") speed = Param.NetworkBandwidth('1Gbps', "link speed") dump = Param.EtherDump(NULL, "dump object") + mode = Param.Int(0,"etherlink mode for operating in pd-gem5") + ni_speed = Param.NetworkBandwidth('1Gbps', "peer network device speed") + ni_delay = Param.Latency('0us', "peer network device delay") class MultiEtherLink(EtherObject): type = 'MultiEtherLink' diff -r d914107ffbf1 -r 79181d97f42d src/dev/etherdump.hh --- a/src/dev/etherdump.hh Mon Aug 10 22:40:36 2015 -0500 +++ b/src/dev/etherdump.hh Mon Aug 10 22:41:08 2015 -0500 @@ -50,6 +50,7 @@ std::ostream *stream; const unsigned maxlen; void dumpPacket(EthPacketPtr &packet); + void dumpPacket(EthPacketPtr &packet, Tick time_stamp); void init(); public: diff -r d914107ffbf1 -r 79181d97f42d src/dev/etherlink.hh --- a/src/dev/etherlink.hh Mon Aug 10 22:40:36 2015 -0500 +++ b/src/dev/etherlink.hh Mon Aug 10 22:41:08 2015 -0500 @@ -74,6 +74,11 @@ Tick linkDelay; Tick delayVar; EtherDump *dump; + Tick senderTick; + int mode; + Tick releaseTick; + double niTicksPerByte; + Tick niDelay; protected: /* @@ -90,13 +95,18 @@ public: Link(const std::string &name, EtherObject *p, int num, - double rate, Tick delay, Tick delay_var, EtherDump *dump); + double rate, Tick delay, Tick delay_var, EtherDump *dump, + int mode = 0, double ni_rate = 0, Tick ni_delay = 0); ~Link() {} const std::string name() const { return objName; } bool busy() const { return (bool)packet; } bool transmit(EthPacketPtr packet); + void attachTimeStamp(uint64_t time_stamp_int); + void detachTimeStamp(); + void setTimeStamp(uint64_t time_stamp); + uint64_t getTimeStamp(); void setTxInt(EtherInt *i) { assert(!txint); txint = i; } void setRxInt(EtherInt *i) { assert(!rxint); rxint = i; } diff -r d914107ffbf1 -r 79181d97f42d src/dev/etherlink.cc --- a/src/dev/etherlink.cc Mon Aug 10 22:40:36 2015 -0500 +++ b/src/dev/etherlink.cc Mon Aug 10 22:41:08 2015 -0500 @@ -2,6 +2,18 @@ * Copyright (c) 2002-2005 The Regents of The University of Michigan * All rights reserved. * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 2015 The University of Wisconsin Madison + * 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 @@ -27,6 +39,7 @@ * * Authors: Nathan Binkert * Ron Dreslinski + * Mohammad Alian */ /* @file @@ -42,6 +55,7 @@ #include "base/trace.hh" #include "debug/Ethernet.hh" #include "debug/EthernetData.hh" +#include "debug/Pdgem5.hh" #include "dev/etherdump.hh" #include "dev/etherint.hh" #include "dev/etherlink.hh" @@ -57,9 +71,11 @@ : EtherObject(p) { link[0] = new Link(name() + ".link0", this, 0, p->speed, - p->delay, p->delay_var, p->dump); + p->delay, p->delay_var, p->dump, + p->mode, p->ni_speed, p->ni_delay); link[1] = new Link(name() + ".link1", this, 1, p->speed, - p->delay, p->delay_var, p->dump); + p->delay, p->delay_var, p->dump, + p->mode, p->ni_speed, p->ni_delay); interface[0] = new Interface(name() + ".int0", link[0], link[1]); interface[1] = new Interface(name() + ".int1", link[1], link[0]); @@ -99,10 +115,12 @@ } EtherLink::Link::Link(const string &name, EtherObject *p, int num, - double rate, Tick delay, Tick delay_var, EtherDump *d) + double rate, Tick delay, Tick delay_var, EtherDump *d, + int mode_, double ni_rate, Tick ni_delay) : objName(name), parent(p), number(num), txint(NULL), rxint(NULL), ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d), - doneEvent(this) + mode(mode_), releaseTick(0), niTicksPerByte(ni_rate), + niDelay(ni_delay), doneEvent(this) { } void @@ -125,6 +143,9 @@ DPRINTF(Ethernet, "packet received: len=%d\n", packet->length); DDUMP(EthernetData, packet->data, packet->length); rxint->sendPacket(packet); + //dump packet here, if packets are comming from outside world! + if (dump && (mode == 1 && name().find(".link0") == std::string::npos)) + dump->dump(packet); } class LinkDelayEvent : public Event @@ -149,9 +170,81 @@ void EtherLink::Link::txDone() { - if (dump) + if (dump && !mode) dump->dump(packet); + // mode = 1 is 'pd-gem5 connector' mode + // We use etherlink in this mode to connect nic or switch port to ethertap + if (mode == 1) { + // We assume that int0 is connected to nic or switch + // We should timestamp packets that we recieve form int0 before + // sending them to peer (ethertap) + if (name().find(".link0") != std::string::npos) { + DPRINTF(Pdgem5, "receive packet from interface0, " + "start to add time stamp, len=%d, releaseTick=%lu\n", + packet->length, releaseTick); + uint64_t time_stamp; + + // network interface timing params. + // We have already applied ni transmission delay at transmit + // function, add ni propagation delay here + time_stamp = curTick() + niDelay; + + // link timing params. + // Add link transmission and propagation delay to time_stamp + // To make sure that we don't reorder packets after adding + // transmission latency (size/bw), we utilize "releaseTick" + // variable to serialize outgoing packets. + // We assume that link bw is not network bottleneck + Tick link_trans_delay = (Tick)ceil(((double)packet->length + * ticksPerByte) + 1.0); + if (releaseTick > time_stamp) { + time_stamp = releaseTick + link_trans_delay + linkDelay; + releaseTick += link_trans_delay; + } else { + releaseTick = time_stamp + link_trans_delay; + time_stamp += link_trans_delay + linkDelay; + } + DPRINTF(Pdgem5, "time_stamp=%lu, link_trans_delay=%lu\n", + time_stamp, link_trans_delay); + // attach time_stamp as well as curTick at the end of the packet + attachTimeStamp(time_stamp); + // send packet immediately to peer (ethertap) + txComplete(packet); + packet = 0; + assert(!busy()); + + txint->sendDone(); + return; + } else { + // Otherwise, we should extract time stamp form the incoming + // packet and send it to peer (nic or switch) at "time_stamp" + DPRINTF(Pdgem5, "receive packet from interface1, " + "startng to remove time stamp, len=%d\n", packet->length); + uint64_t time_stamp; + + time_stamp = getTimeStamp(); + detachTimeStamp(); + + if (time_stamp < curTick()) { + // print a warning message as data packet has received late! + // this may happen with relaxed synchronization + warn("VIOLATION, packet arrived late %lu\n", curTick() - + time_stamp); + // deliver packet instantly to peer + time_stamp = curTick(); + } + // deliver packet at time_stamp to peer (NIC or Switch) + Event *event = new LinkDelayEvent(this, packet); + parent->schedule(event, time_stamp); + packet = 0; + assert(!busy()); + + txint->sendDone(); + return; + } + } + // etherlink defualt functionality if (linkDelay > 0) { DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay); Event *event = new LinkDelayEvent(this, packet); @@ -178,6 +271,32 @@ DDUMP(EthernetData, pkt->data, pkt->length); packet = pkt; + // mode = 1 is 'pd-gem5 connector' mode + // We use etherlink in this mode to connect nic or switch port to ethertap + if (mode == 1) { + // We assume that int0 is connected to nic/switch and int1 to ethertap + // If we recieve packet form int1 (ethertap), then we should call + // txDone instantly + if (name().find(".link1") != std::string::npos) { + txDone(); + return true; + } + // dump packets before applying network interface (ni) timing + if (dump) + dump->dump(packet); + + // If we recieve packets form int0, we should apply ni's + // transmission delay, and keep link busy during that period + Tick trans_delay = (Tick)ceil(((double)pkt->length * niTicksPerByte) + + 1.0); + if (delayVar != 0) + trans_delay += random_mt.random(0, delayVar); + DPRINTF(Pdgem5, "scheduling packet: ni_delay=%d, (ni_rate=%f)\n", + trans_delay, niTicksPerByte); + parent->schedule(doneEvent, curTick() + trans_delay); + return true; + } + // etherlink defualt functionality Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0); if (delayVar != 0) delay += random_mt.random(0, delayVar); @@ -225,6 +344,72 @@ } } +// this function attaches curTick and a time_stamp to the packet +void +EtherLink::Link::attachTimeStamp(uint64_t time_stamp) +{ + char buff[10000]; + int data_len = packet->length; + + // copy packet data into buff + memcpy(buff, packet->data, data_len); + Tick cur_tick = curTick(); + + // add curTick and time_stamp at the end of buff + memmove(buff + data_len, &cur_tick, sizeof(uint64_t)); + memmove(buff + data_len + sizeof(uint64_t), &time_stamp, + sizeof(uint64_t)); + // create a new time stamped packet + packet = make_shared(data_len + 2 * sizeof(uint64_t)); + packet->length = data_len + 2 * sizeof(uint64_t); + // set packet->data + memcpy(packet->data, buff, data_len + 2 * sizeof(uint64_t)); + + DPRINTF(Pdgem5, "added %lu as time stamp, len=%d\n", + time_stamp, packet->length); +} + +// This function detaches the time stamp of the packet in the link +void +EtherLink::Link::detachTimeStamp() +{ + char buff[10000]; + int data_len = packet->length; + + // get a backup from packet data + memcpy(buff, packet->data, data_len); + // generate a new packet without timestamp + packet = make_shared(data_len - 2 * sizeof(uint64_t)); + packet->length = data_len - 2 * sizeof(uint64_t); + memcpy(packet->data, buff, data_len - 2 * sizeof(uint64_t)); +} + +void +EtherLink::Link::setTimeStamp(uint64_t time_stamp) +{ + int data_len = packet->length; + DPRINTF(Pdgem5, "set packet time stamp to %lu\n", time_stamp); + memmove(packet->data + data_len - sizeof(int64_t), &time_stamp, + sizeof(uint64_t)); +} + +// This function returns thetime stamp of the packet in the link +// it also sets senderTick member variable +uint64_t +EtherLink::Link::getTimeStamp() +{ + Tick time_stamp; + int data_len = packet->length; + memmove(&senderTick, packet->data + data_len - 2 * sizeof(uint64_t), + sizeof(uint64_t)); + memmove(&time_stamp, packet->data + data_len - sizeof(uint64_t), + sizeof(uint64_t)); + DPRINTF(Pdgem5, "removed time stamp %lu, senderTick %lu, len=%d\n", + time_stamp, senderTick, packet->length); + + return time_stamp; +} + LinkDelayEvent::LinkDelayEvent() : Event(Default_Pri, AutoSerialize | AutoDelete), link(NULL) {