ethertap.cc revision 12054:ab04045965d1
16899SN/A/* 26899SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan 36899SN/A * All rights reserved. 46899SN/A * 56899SN/A * Redistribution and use in source and binary forms, with or without 66899SN/A * modification, are permitted provided that the following conditions are 76899SN/A * met: redistributions of source code must retain the above copyright 86899SN/A * notice, this list of conditions and the following disclaimer; 96899SN/A * redistributions in binary form must reproduce the above copyright 106899SN/A * notice, this list of conditions and the following disclaimer in the 116899SN/A * documentation and/or other materials provided with the distribution; 126899SN/A * neither the name of the copyright holders nor the names of its 136899SN/A * contributors may be used to endorse or promote products derived from 146899SN/A * this software without specific prior written permission. 156899SN/A * 166899SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176899SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186899SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196899SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206899SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216899SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226899SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236899SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246899SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256899SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266899SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276899SN/A * 286899SN/A * Authors: Nathan Binkert 296899SN/A */ 307632SBrad.Beckmann@amd.com 318232Snate@binkert.org/* @file 327053SN/A * Interface to connect a simulated ethernet device to the real world 336899SN/A */ 346899SN/A 356899SN/A#include "dev/net/ethertap.hh" 367053SN/A 377053SN/A#if defined(__OpenBSD__) || defined(__APPLE__) 387053SN/A#include <sys/param.h> 398932SBrad.Beckmann@amd.com 408932SBrad.Beckmann@amd.com#endif 418932SBrad.Beckmann@amd.com#include <netinet/in.h> 426899SN/A#include <unistd.h> 437053SN/A 446899SN/A#include <deque> 457053SN/A#include <string> 467053SN/A 477053SN/A#include "base/misc.hh" 487053SN/A#include "base/pollevent.hh" 498164Snilay@cs.wisc.edu#include "base/socket.hh" 507053SN/A#include "base/trace.hh" 516899SN/A#include "debug/Ethernet.hh" 526899SN/A#include "debug/EthernetData.hh" 537053SN/A#include "dev/net/etherdump.hh" 547053SN/A#include "dev/net/etherint.hh" 556899SN/A#include "dev/net/etherpkt.hh" 567053SN/A 577053SN/Ausing namespace std; 586899SN/A 597053SN/A/** 607053SN/A */ 617053SN/Aclass TapListener 627053SN/A{ 636899SN/A protected: 648184Ssomayeh@cs.wisc.edu /** 658184Ssomayeh@cs.wisc.edu */ 668184Ssomayeh@cs.wisc.edu class Event : public PollEvent 678184Ssomayeh@cs.wisc.edu { 687053SN/A protected: 697053SN/A TapListener *listener; 707053SN/A 717053SN/A public: 727053SN/A Event(TapListener *l, int fd, int e) 737053SN/A : PollEvent(fd, e), listener(l) {} 747053SN/A 757053SN/A virtual void process(int revent) { listener->accept(); } 767053SN/A }; 776899SN/A 786899SN/A friend class Event; 797053SN/A Event *event; 807053SN/A 816899SN/A protected: 827053SN/A ListenSocket listener; 836899SN/A EtherTapStub *tap; 848932SBrad.Beckmann@amd.com int port; 858950Sandreas.hansson@arm.com 866899SN/A public: 877053SN/A TapListener(EtherTapStub *t, int p) 887053SN/A : event(NULL), tap(t), port(p) {} 896899SN/A ~TapListener() { if (event) delete event; } 907053SN/A 916899SN/A void accept(); 927053SN/A void listen(); 937053SN/A}; 947053SN/A 957053SN/Avoid 968932SBrad.Beckmann@amd.comTapListener::listen() 978950Sandreas.hansson@arm.com{ 987053SN/A while (!listener.listen(port, true)) { 997053SN/A DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port); 1007053SN/A port++; 1017053SN/A } 1027053SN/A 1036899SN/A ccprintf(cerr, "Listening for tap connection on port %d\n", port); 1046899SN/A event = new Event(this, listener.getfd(), POLLIN|POLLERR); 1057568SN/A pollQueue.schedule(event); 1068832SAli.Saidi@ARM.com} 1078832SAli.Saidi@ARM.com 1088190SLisa.Hsu@amd.comvoid 1097568SN/ATapListener::accept() 1108949Sandreas.hansson@arm.com{ 1116899SN/A // As a consequence of being called from the PollQueue, we might 1127053SN/A // have been called from a different thread. Migrate to "our" 1137053SN/A // thread. 1147053SN/A EventQueue::ScopedMigration migrate(tap->eventQueue()); 1157053SN/A 1166899SN/A if (!listener.islistening()) 1178975Sandreas.hansson@arm.com panic("TapListener(accept): cannot accept if we're not listening!"); 1187053SN/A 1197053SN/A int sfd = listener.accept(true); 1207053SN/A if (sfd != -1) 1217053SN/A tap->attach(sfd); 1227053SN/A} 1237053SN/A 1247053SN/A/** 1257053SN/A */ 1266899SN/Aclass TapEvent : public PollEvent 1277053SN/A{ 1287053SN/A protected: 1297053SN/A EtherTapStub *tap; 1306899SN/A 1316899SN/A public: 1327053SN/A TapEvent(EtherTapStub *_tap, int fd, int e) 1338184Ssomayeh@cs.wisc.edu : PollEvent(fd, e), tap(_tap) {} 1348184Ssomayeh@cs.wisc.edu virtual void process(int revent) { tap->process(revent); } 1358184Ssomayeh@cs.wisc.edu}; 1368184Ssomayeh@cs.wisc.edu 1378184Ssomayeh@cs.wisc.eduEtherTapStub::EtherTapStub(const Params *p) 1388932SBrad.Beckmann@amd.com : EtherObject(p), event(NULL), socket(-1), buflen(p->bufsz), dump(p->dump), 1398950Sandreas.hansson@arm.com interface(NULL), txEvent(this) 1408184Ssomayeh@cs.wisc.edu{ 1418184Ssomayeh@cs.wisc.edu if (ListenSocket::allDisabled()) 1428184Ssomayeh@cs.wisc.edu fatal("All listeners are disabled! EtherTapStub can't work!"); 1438832SAli.Saidi@ARM.com 1448832SAli.Saidi@ARM.com buffer = new char[buflen]; 1458184Ssomayeh@cs.wisc.edu listener = new TapListener(this, p->port); 1468184Ssomayeh@cs.wisc.edu listener->listen(); 1478184Ssomayeh@cs.wisc.edu interface = new EtherTapInt(name() + ".interface", this); 1488184Ssomayeh@cs.wisc.edu} 1498184Ssomayeh@cs.wisc.edu 1508949Sandreas.hansson@arm.comEtherTapStub::~EtherTapStub() 1518184Ssomayeh@cs.wisc.edu{ 1528184Ssomayeh@cs.wisc.edu if (event) 1538184Ssomayeh@cs.wisc.edu delete event; 1548184Ssomayeh@cs.wisc.edu if (buffer) 1558184Ssomayeh@cs.wisc.edu delete [] buffer; 1568184Ssomayeh@cs.wisc.edu 1578975Sandreas.hansson@arm.com delete interface; 1588184Ssomayeh@cs.wisc.edu delete listener; 1598184Ssomayeh@cs.wisc.edu} 1608184Ssomayeh@cs.wisc.edu 1618184Ssomayeh@cs.wisc.eduvoid 1628184Ssomayeh@cs.wisc.eduEtherTapStub::attach(int fd) 1637053SN/A{ 1646899SN/A if (socket != -1) 1657053SN/A close(fd); 1667053SN/A 1676899SN/A buffer_offset = 0; 1688932SBrad.Beckmann@amd.com data_len = 0; 1698950Sandreas.hansson@arm.com socket = fd; 1706899SN/A DPRINTF(Ethernet, "EtherTapStub attached\n"); 1717053SN/A event = new TapEvent(this, socket, POLLIN|POLLERR); 1726899SN/A pollQueue.schedule(event); 1737053SN/A} 1747053SN/A 1756899SN/Avoid 1767053SN/AEtherTapStub::detach() 1778832SAli.Saidi@ARM.com{ 1788832SAli.Saidi@ARM.com DPRINTF(Ethernet, "EtherTapStub detached\n"); 1797053SN/A delete event; 1806899SN/A event = 0; 1818190SLisa.Hsu@amd.com close(socket); 1827053SN/A socket = -1; 1837053SN/A} 1847053SN/A 1857053SN/Abool 1867053SN/AEtherTapStub::recvPacket(EthPacketPtr packet) 1877053SN/A{ 1886899SN/A if (dump) 1897053SN/A dump->dump(packet); 1906899SN/A 1918949Sandreas.hansson@arm.com DPRINTF(Ethernet, "EtherTapStub output len=%d\n", packet->length); 1929208Snilay@cs.wisc.edu DDUMP(EthernetData, packet->data, packet->length); 1937053SN/A uint32_t len = htonl(packet->length); 1947053SN/A ssize_t ret = write(socket, &len, sizeof(len)); 1956899SN/A if (ret != sizeof(len)) 1967053SN/A return false; 1977053SN/A ret = write(socket, packet->data, packet->length); 1986899SN/A if (ret != packet->length) 1997053SN/A return false; 2007053SN/A 2017053SN/A interface->recvDone(); 2027053SN/A 2036899SN/A return true; 2048975Sandreas.hansson@arm.com} 2057053SN/A 2067053SN/Avoid 2077053SN/AEtherTapStub::sendDone() 2087053SN/A{} 2097053SN/A 2107053SN/Avoid 2117053SN/AEtherTapStub::process(int revent) 2127053SN/A{ 2137053SN/A if (revent & POLLERR) { 2147053SN/A detach(); 2157053SN/A return; 2167053SN/A } 2177053SN/A 2187053SN/A char *data = buffer + sizeof(uint32_t); 2197053SN/A if (!(revent & POLLIN)) 2207053SN/A return; 2217053SN/A 2227053SN/A if (buffer_offset < data_len + sizeof(uint32_t)) { 2236899SN/A int len = read(socket, buffer + buffer_offset, buflen - buffer_offset); 2246899SN/A if (len == 0) { 2256899SN/A detach(); 2267053SN/A return; 2277053SN/A } 2286899SN/A 2297053SN/A buffer_offset += len; 2307053SN/A 2316899SN/A if (data_len == 0) 2328932SBrad.Beckmann@amd.com data_len = ntohl(*(uint32_t *)buffer); 2338950Sandreas.hansson@arm.com 2346899SN/A DPRINTF(Ethernet, "Received data from peer: len=%d buffer_offset=%d " 2357053SN/A "data_len=%d\n", len, buffer_offset, data_len); 2366899SN/A } 2378932SBrad.Beckmann@amd.com 2388950Sandreas.hansson@arm.com while (data_len != 0 && buffer_offset >= data_len + sizeof(uint32_t)) { 2397053SN/A EthPacketPtr packet; 2407053SN/A packet = make_shared<EthPacketData>(data_len); 2416899SN/A packet->length = data_len; 2427568SN/A packet->simLength = data_len; 2437568SN/A memcpy(packet->data, data, data_len); 2448832SAli.Saidi@ARM.com 2457568SN/A assert(buffer_offset >= data_len + sizeof(uint32_t)); 2468190SLisa.Hsu@amd.com buffer_offset -= data_len + sizeof(uint32_t); 2478949Sandreas.hansson@arm.com if (buffer_offset > 0) { 2489208Snilay@cs.wisc.edu memmove(buffer, data + data_len, buffer_offset); 2497053SN/A data_len = ntohl(*(uint32_t *)buffer); 2506899SN/A } else 2517053SN/A data_len = 0; 2527053SN/A 2537053SN/A DPRINTF(Ethernet, "EtherTapStub input len=%d\n", packet->length); 2547053SN/A DDUMP(EthernetData, packet->data, packet->length); 2556899SN/A if (!interface->sendPacket(packet)) { 2568975Sandreas.hansson@arm.com DPRINTF(Ethernet, "bus busy...buffer for retransmission\n"); 2577053SN/A packetBuffer.push(packet); 2587053SN/A if (!txEvent.scheduled()) 2597053SN/A schedule(txEvent, curTick() + retryTime); 2607053SN/A } else if (dump) { 2617053SN/A dump->dump(packet); 2627053SN/A } 2637053SN/A } 2647053SN/A} 2657053SN/A 2667053SN/Avoid 2677053SN/AEtherTapStub::retransmit() 2687053SN/A{ 2697053SN/A if (packetBuffer.empty()) 2706899SN/A return; 2717053SN/A 2727053SN/A EthPacketPtr packet = packetBuffer.front(); 2737053SN/A if (interface->sendPacket(packet)) { 2747053SN/A if (dump) 2757053SN/A dump->dump(packet); 2766899SN/A DPRINTF(Ethernet, "EtherTapStub retransmit\n"); 2776899SN/A packetBuffer.front() = NULL; 2787053SN/A packetBuffer.pop(); 2799475Snilay@cs.wisc.edu } 2806899SN/A 2817053SN/A if (!packetBuffer.empty() && !txEvent.scheduled()) 2826899SN/A schedule(txEvent, curTick() + retryTime); 2837053SN/A} 2847053SN/A 2856899SN/AEtherInt* 2867053SN/AEtherTapStub::getEthPort(const std::string &if_name, int idx) 2877053SN/A{ 2887053SN/A if (if_name == "tap") { 2897053SN/A if (interface->getPeer()) 2906899SN/A panic("Interface already connected to\n"); 2916899SN/A return interface; 2927053SN/A } 2937053SN/A return NULL; 2947053SN/A} 2957053SN/A 2967053SN/A 2977053SN/A//===================================================================== 2987053SN/A 2997053SN/Avoid 3007053SN/AEtherTapStub::serialize(CheckpointOut &cp) const 3017053SN/A{ 3027053SN/A SERIALIZE_SCALAR(socket); 3037053SN/A SERIALIZE_SCALAR(buflen); 3047053SN/A uint8_t *buffer = (uint8_t *)this->buffer; 3057053SN/A SERIALIZE_ARRAY(buffer, buflen); 3067053SN/A SERIALIZE_SCALAR(buffer_offset); 3077053SN/A SERIALIZE_SCALAR(data_len); 3087053SN/A 3099208Snilay@cs.wisc.edu bool tapevent_present = false; 3107805Snilay@cs.wisc.edu if (event) { 3117805Snilay@cs.wisc.edu tapevent_present = true; 3127805Snilay@cs.wisc.edu SERIALIZE_SCALAR(tapevent_present); 3137805Snilay@cs.wisc.edu event->serialize(cp); 3147805Snilay@cs.wisc.edu } 3159475Snilay@cs.wisc.edu else { 3167053SN/A SERIALIZE_SCALAR(tapevent_present); 3177053SN/A } 3187053SN/A} 3197053SN/A 3206899SN/Avoid 3217053SN/AEtherTapStub::unserialize(CheckpointIn &cp) 3227053SN/A{ 3236899SN/A UNSERIALIZE_SCALAR(socket); 3247053SN/A UNSERIALIZE_SCALAR(buflen); 3257053SN/A uint8_t *buffer = (uint8_t *)this->buffer; 3267053SN/A UNSERIALIZE_ARRAY(buffer, buflen); 3277053SN/A UNSERIALIZE_SCALAR(buffer_offset); 3287805Snilay@cs.wisc.edu UNSERIALIZE_SCALAR(data_len); 3299475Snilay@cs.wisc.edu 3307053SN/A bool tapevent_present; 3317053SN/A UNSERIALIZE_SCALAR(tapevent_present); 3327053SN/A if (tapevent_present) { 3337053SN/A event = new TapEvent(this, socket, POLLIN|POLLERR); 3347053SN/A 3357053SN/A event->unserialize(cp); 3366899SN/A 3376899SN/A if (event->queued()) { 3387053SN/A pollQueue.schedule(event); 3397053SN/A } 3406899SN/A } 3417053SN/A} 3427053SN/A 3437053SN/A//===================================================================== 3447053SN/A 3456899SN/AEtherTapStub * 3466899SN/AEtherTapStubParams::create() 3477053SN/A{ 3487053SN/A return new EtherTapStub(this); 3496899SN/A} 3507053SN/A