ethertap.cc revision 146
112855Sgabeblack@google.com/* 212855Sgabeblack@google.com * Copyright (c) 2003 The Regents of The University of Michigan 312855Sgabeblack@google.com * All rights reserved. 412855Sgabeblack@google.com * 512855Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 612855Sgabeblack@google.com * modification, are permitted provided that the following conditions are 712855Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 812855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 912855Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 1012855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 1112855Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 1212855Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 1312855Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 1412855Sgabeblack@google.com * this software without specific prior written permission. 1512855Sgabeblack@google.com * 1612855Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1712855Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1812855Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1912855Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2012855Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2112855Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2212855Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2312855Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2412855Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2512855Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2612855Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2712855Sgabeblack@google.com */ 2812855Sgabeblack@google.com 2912855Sgabeblack@google.com/* @file 3012855Sgabeblack@google.com * Interface to connect a simulated ethernet device to the real world 3112855Sgabeblack@google.com */ 3212855Sgabeblack@google.com 3312855Sgabeblack@google.com#if defined(__OpenBSD__) 3412855Sgabeblack@google.com#include <sys/param.h> 3512855Sgabeblack@google.com#endif 3612855Sgabeblack@google.com#include <netinet/in.h> 3712855Sgabeblack@google.com 3812855Sgabeblack@google.com#include <unistd.h> 3912855Sgabeblack@google.com 4012855Sgabeblack@google.com#include <deque> 4112855Sgabeblack@google.com#include <string> 4212855Sgabeblack@google.com 4312855Sgabeblack@google.com#include "base/misc.hh" 4412855Sgabeblack@google.com#include "base/pollevent.hh" 4512855Sgabeblack@google.com#include "base/socket.hh" 4612855Sgabeblack@google.com#include "base/trace.hh" 4712855Sgabeblack@google.com#include "dev/etherdump.hh" 4812855Sgabeblack@google.com#include "dev/etherint.hh" 4912855Sgabeblack@google.com#include "dev/etherpkt.hh" 5012855Sgabeblack@google.com#include "dev/ethertap.hh" 5112855Sgabeblack@google.com#include "sim/builder.hh" 5212855Sgabeblack@google.com 5312855Sgabeblack@google.comusing namespace std; 5412855Sgabeblack@google.com 5512855Sgabeblack@google.com/** 5612855Sgabeblack@google.com */ 5712855Sgabeblack@google.comclass TapListener 5812855Sgabeblack@google.com{ 5912855Sgabeblack@google.com protected: 6012855Sgabeblack@google.com /** 6112855Sgabeblack@google.com */ 6212855Sgabeblack@google.com class Event : public PollEvent 6312855Sgabeblack@google.com { 6412855Sgabeblack@google.com protected: 6512855Sgabeblack@google.com TapListener *listener; 6612855Sgabeblack@google.com 6712855Sgabeblack@google.com public: 6812855Sgabeblack@google.com Event(TapListener *l, int fd, int e) 6912855Sgabeblack@google.com : PollEvent(fd, e), listener(l) {} 7012855Sgabeblack@google.com 7112855Sgabeblack@google.com virtual void process(int revent) { listener->accept(); } 7212855Sgabeblack@google.com }; 7312855Sgabeblack@google.com 7412855Sgabeblack@google.com friend class Event; 7512855Sgabeblack@google.com Event *event; 7612855Sgabeblack@google.com 7712855Sgabeblack@google.com protected: 7812855Sgabeblack@google.com ListenSocket listener; 7912855Sgabeblack@google.com EtherTap *tap; 8012855Sgabeblack@google.com int port; 8112855Sgabeblack@google.com 8212855Sgabeblack@google.com public: 8312855Sgabeblack@google.com TapListener(EtherTap *t, int p) 8412855Sgabeblack@google.com : event(NULL), tap(t), port(p) {} 8512855Sgabeblack@google.com ~TapListener() { if (event) delete event; } 8612855Sgabeblack@google.com 8712855Sgabeblack@google.com void accept(); 8812855Sgabeblack@google.com void listen(); 8912855Sgabeblack@google.com}; 9012855Sgabeblack@google.com 9112855Sgabeblack@google.comvoid 9212855Sgabeblack@google.comTapListener::listen() 9312855Sgabeblack@google.com{ 9412855Sgabeblack@google.com while (!listener.listen(port, true)) { 9512855Sgabeblack@google.com DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port); 9612855Sgabeblack@google.com port++; 9712855Sgabeblack@google.com } 9812855Sgabeblack@google.com 9912855Sgabeblack@google.com ccprintf(cerr, "Listening for tap connection on port %d\n", port); 10012855Sgabeblack@google.com event = new Event(this, listener.getfd(), POLLIN|POLLERR); 10112855Sgabeblack@google.com pollQueue.schedule(event); 10212855Sgabeblack@google.com} 10312855Sgabeblack@google.com 10412855Sgabeblack@google.comvoid 10512855Sgabeblack@google.comTapListener::accept() 10612855Sgabeblack@google.com{ 10712855Sgabeblack@google.com if (!listener.islistening()) 10812855Sgabeblack@google.com panic("TapListener(accept): cannot accept if we're not listening!"); 10912855Sgabeblack@google.com 11012855Sgabeblack@google.com int sfd = listener.accept(true); 11112855Sgabeblack@google.com if (sfd != -1) 11212855Sgabeblack@google.com tap->attach(sfd); 11312855Sgabeblack@google.com} 11412855Sgabeblack@google.com 11512855Sgabeblack@google.com/** 11612855Sgabeblack@google.com */ 11712855Sgabeblack@google.comclass TapEvent : public PollEvent 11812855Sgabeblack@google.com{ 11912855Sgabeblack@google.com protected: 12012855Sgabeblack@google.com EtherTap *tap; 12112855Sgabeblack@google.com 12212855Sgabeblack@google.com public: 12312855Sgabeblack@google.com TapEvent(EtherTap *_tap, int fd, int e) 12412855Sgabeblack@google.com : PollEvent(fd, e), tap(_tap) {} 12512855Sgabeblack@google.com virtual void process(int revent) { tap->process(revent); } 12612855Sgabeblack@google.com}; 12712855Sgabeblack@google.com 12812855Sgabeblack@google.comEtherTap::EtherTap(const string &name, EtherDump *d, int port, int bufsz) 12912855Sgabeblack@google.com : EtherInt(name), event(NULL), socket(-1), buflen(bufsz), dump(d), 13012855Sgabeblack@google.com txEvent(this) 13112855Sgabeblack@google.com{ 13212855Sgabeblack@google.com buffer = new char[buflen]; 13312855Sgabeblack@google.com listener = new TapListener(this, port); 13412855Sgabeblack@google.com listener->listen(); 13512855Sgabeblack@google.com} 13612855Sgabeblack@google.com 13712855Sgabeblack@google.comEtherTap::~EtherTap() 13812855Sgabeblack@google.com{ 13912855Sgabeblack@google.com if (event) 14012855Sgabeblack@google.com delete event; 14112855Sgabeblack@google.com if (buffer) 14212855Sgabeblack@google.com delete [] buffer; 14312855Sgabeblack@google.com 14412855Sgabeblack@google.com delete listener; 14512855Sgabeblack@google.com} 14612855Sgabeblack@google.com 14712855Sgabeblack@google.comvoid 14812855Sgabeblack@google.comEtherTap::attach(int fd) 14912855Sgabeblack@google.com{ 15012855Sgabeblack@google.com if (socket != -1) 15112855Sgabeblack@google.com close(fd); 15212855Sgabeblack@google.com 15312855Sgabeblack@google.com buffer_offset = 0; 15412855Sgabeblack@google.com data_len = 0; 15512855Sgabeblack@google.com socket = fd; 15612855Sgabeblack@google.com DPRINTF(Ethernet, "EtherTap attached\n"); 15712855Sgabeblack@google.com event = new TapEvent(this, socket, POLLIN|POLLERR); 15812855Sgabeblack@google.com pollQueue.schedule(event); 15912855Sgabeblack@google.com} 16012855Sgabeblack@google.com 16112855Sgabeblack@google.comvoid 16212855Sgabeblack@google.comEtherTap::detach() 16312855Sgabeblack@google.com{ 16412855Sgabeblack@google.com DPRINTF(Ethernet, "EtherTap detached\n"); 16512855Sgabeblack@google.com delete event; 16612855Sgabeblack@google.com close(socket); 16712855Sgabeblack@google.com socket = -1; 16812855Sgabeblack@google.com} 16912855Sgabeblack@google.com 17012855Sgabeblack@google.combool 17112855Sgabeblack@google.comEtherTap::recvPacket(PacketPtr packet) 17212855Sgabeblack@google.com{ 17312855Sgabeblack@google.com if (dump) 17412855Sgabeblack@google.com dump->dump(packet); 17512855Sgabeblack@google.com 17612855Sgabeblack@google.com DPRINTF(Ethernet, "EtherTap output len=%d\n", packet->length); 17712855Sgabeblack@google.com DDUMP(EthernetData, packet->data, packet->length); 17812855Sgabeblack@google.com u_int32_t len = htonl(packet->length); 17912855Sgabeblack@google.com write(socket, &len, sizeof(len)); 18012855Sgabeblack@google.com write(socket, packet->data, packet->length); 18112855Sgabeblack@google.com 18212855Sgabeblack@google.com recvDone(); 18312855Sgabeblack@google.com 18412855Sgabeblack@google.com return true; 18512855Sgabeblack@google.com} 18612855Sgabeblack@google.com 18712855Sgabeblack@google.comvoid 18812855Sgabeblack@google.comEtherTap::sendDone() 18912855Sgabeblack@google.com{} 19012855Sgabeblack@google.com 19112855Sgabeblack@google.comvoid 19212855Sgabeblack@google.comEtherTap::process(int revent) 19312855Sgabeblack@google.com{ 19412855Sgabeblack@google.com if (revent & POLLERR) { 19512855Sgabeblack@google.com detach(); 19612855Sgabeblack@google.com return; 19712855Sgabeblack@google.com } 19812855Sgabeblack@google.com 19912855Sgabeblack@google.com char *data = buffer + sizeof(u_int32_t); 20012855Sgabeblack@google.com if (!(revent & POLLIN)) 20112855Sgabeblack@google.com return; 20212855Sgabeblack@google.com 20312855Sgabeblack@google.com if (buffer_offset < data_len + sizeof(u_int32_t)) { 20412855Sgabeblack@google.com int len = read(socket, buffer + buffer_offset, buflen - buffer_offset); 20512855Sgabeblack@google.com if (len == 0) { 20612855Sgabeblack@google.com detach(); 20712855Sgabeblack@google.com return; 20812855Sgabeblack@google.com } 20912855Sgabeblack@google.com 21012855Sgabeblack@google.com buffer_offset += len; 21112855Sgabeblack@google.com 21212855Sgabeblack@google.com if (data_len == 0) 21312855Sgabeblack@google.com data_len = ntohl(*(u_int32_t *)buffer); 21412855Sgabeblack@google.com 21512855Sgabeblack@google.com DPRINTF(Ethernet, "Received data from peer: len=%d buffer_offset=%d " 21612855Sgabeblack@google.com "data_len=%d\n", len, buffer_offset, data_len); 21712855Sgabeblack@google.com } 21812855Sgabeblack@google.com 21912855Sgabeblack@google.com while (data_len != 0 && buffer_offset >= data_len + sizeof(u_int32_t)) { 22012855Sgabeblack@google.com PacketPtr packet; 22112855Sgabeblack@google.com packet = new EtherPacket; 22212855Sgabeblack@google.com packet->data = new uint8_t[data_len]; 22312855Sgabeblack@google.com packet->length = data_len; 22412855Sgabeblack@google.com memcpy(packet->data, data, data_len); 22512855Sgabeblack@google.com 22612855Sgabeblack@google.com buffer_offset -= data_len + sizeof(u_int32_t); 22712855Sgabeblack@google.com assert(buffer_offset >= 0); 22812855Sgabeblack@google.com if (buffer_offset > 0) { 22912855Sgabeblack@google.com memmove(buffer, data + data_len, buffer_offset); 23012855Sgabeblack@google.com data_len = ntohl(*(u_int32_t *)buffer); 23112855Sgabeblack@google.com } else 23212855Sgabeblack@google.com data_len = 0; 23312855Sgabeblack@google.com 23412855Sgabeblack@google.com DPRINTF(Ethernet, "EtherTap input len=%d\n", packet->length); 23512855Sgabeblack@google.com DDUMP(EthernetData, packet->data, packet->length); 23612855Sgabeblack@google.com if (!sendPacket(packet)) { 23712855Sgabeblack@google.com DPRINTF(Ethernet, "bus busy...buffer for retransmission\n"); 23812855Sgabeblack@google.com packetBuffer.push(packet); 23912855Sgabeblack@google.com if (!txEvent.scheduled()) 24012855Sgabeblack@google.com txEvent.schedule(curTick + 1000); 24112855Sgabeblack@google.com } else if (dump) 24212855Sgabeblack@google.com dump->dump(packet); 24312855Sgabeblack@google.com } 24412855Sgabeblack@google.com} 24512855Sgabeblack@google.com 24612855Sgabeblack@google.comvoid 24712855Sgabeblack@google.comEtherTap::retransmit() 24812855Sgabeblack@google.com{ 24912855Sgabeblack@google.com if (packetBuffer.empty()) 25012855Sgabeblack@google.com return; 25112855Sgabeblack@google.com 25212855Sgabeblack@google.com PacketPtr packet = packetBuffer.front(); 25312855Sgabeblack@google.com if (sendPacket(packet)) { 25412855Sgabeblack@google.com if (dump) 25512855Sgabeblack@google.com dump->dump(packet); 25612855Sgabeblack@google.com DPRINTF(Ethernet, "EtherTap retransmit\n"); 25712855Sgabeblack@google.com packetBuffer.front() = NULL; 25812855Sgabeblack@google.com packetBuffer.pop(); 25912855Sgabeblack@google.com } 26012855Sgabeblack@google.com 26112855Sgabeblack@google.com if (!packetBuffer.empty() && !txEvent.scheduled()) 26212855Sgabeblack@google.com txEvent.schedule(curTick + 1000); 26312855Sgabeblack@google.com} 26412855Sgabeblack@google.com 26512855Sgabeblack@google.comBEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherTap) 26612855Sgabeblack@google.com 26712855Sgabeblack@google.com SimObjectParam<EtherInt *> peer; 26812855Sgabeblack@google.com SimObjectParam<EtherDump *> packet_dump; 26912855Sgabeblack@google.com Param<uint16_t> port; 27012855Sgabeblack@google.com Param<uint16_t> bufsz; 27112855Sgabeblack@google.com 27212855Sgabeblack@google.comEND_DECLARE_SIM_OBJECT_PARAMS(EtherTap) 27312855Sgabeblack@google.com 27412855Sgabeblack@google.comBEGIN_INIT_SIM_OBJECT_PARAMS(EtherTap) 27512855Sgabeblack@google.com 27612855Sgabeblack@google.com INIT_PARAM_DFLT(peer, "peer interface", NULL), 27712855Sgabeblack@google.com INIT_PARAM_DFLT(packet_dump, "object to dump network packets to", NULL), 27812855Sgabeblack@google.com INIT_PARAM_DFLT(port, "tap port", 3500), 27912855Sgabeblack@google.com INIT_PARAM_DFLT(bufsz, "tap buffer size", 10000) 28012855Sgabeblack@google.com 28112855Sgabeblack@google.comEND_INIT_SIM_OBJECT_PARAMS(EtherTap) 28212855Sgabeblack@google.com 28312855Sgabeblack@google.com 28412855Sgabeblack@google.comCREATE_SIM_OBJECT(EtherTap) 28512855Sgabeblack@google.com{ 28612855Sgabeblack@google.com EtherTap *tap = new EtherTap(getInstanceName(), packet_dump, port, bufsz); 28712855Sgabeblack@google.com 28812855Sgabeblack@google.com if (peer) { 28912855Sgabeblack@google.com tap->setPeer(peer); 29012855Sgabeblack@google.com peer->setPeer(tap); 29112855Sgabeblack@google.com } 29212855Sgabeblack@google.com 29312855Sgabeblack@google.com return tap; 29412855Sgabeblack@google.com} 29512855Sgabeblack@google.com 29612855Sgabeblack@google.comREGISTER_SIM_OBJECT("EtherTap", EtherTap) 29712855Sgabeblack@google.com