12SN/A/* 21762SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan 32SN/A * All rights reserved. 42SN/A * 52SN/A * Redistribution and use in source and binary forms, with or without 62SN/A * modification, are permitted provided that the following conditions are 72SN/A * met: redistributions of source code must retain the above copyright 82SN/A * notice, this list of conditions and the following disclaimer; 92SN/A * redistributions in binary form must reproduce the above copyright 102SN/A * notice, this list of conditions and the following disclaimer in the 112SN/A * documentation and/or other materials provided with the distribution; 122SN/A * neither the name of the copyright holders nor the names of its 132SN/A * contributors may be used to endorse or promote products derived from 142SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665SN/A * 282665SN/A * Authors: Nathan Binkert 292SN/A */ 302SN/A 312SN/A/* @file 322SN/A * Interface to connect a simulated ethernet device to the real world 332SN/A */ 342SN/A 3511263Sandreas.sandberg@arm.com#include "dev/net/ethertap.hh" 3611263Sandreas.sandberg@arm.com 37873SN/A#if defined(__OpenBSD__) || defined(__APPLE__) 382SN/A#include <sys/param.h> 3911263Sandreas.sandberg@arm.com 402SN/A#endif 4112056Sgabeblack@google.com 4212056Sgabeblack@google.com#if USE_TUNTAP && defined(__linux__) 4312056Sgabeblack@google.com#if 1 // Hide from the style checker since these have to be out of order. 4412056Sgabeblack@google.com#include <sys/socket.h> // Has to be included before if.h for some reason. 4512056Sgabeblack@google.com 4612056Sgabeblack@google.com#endif 4712056Sgabeblack@google.com 4812056Sgabeblack@google.com#include <linux/if.h> 4912056Sgabeblack@google.com#include <linux/if_tun.h> 5012056Sgabeblack@google.com 5112056Sgabeblack@google.com#endif 5212056Sgabeblack@google.com 5312056Sgabeblack@google.com#include <fcntl.h> 542SN/A#include <netinet/in.h> 5512056Sgabeblack@google.com#include <sys/ioctl.h> 562SN/A#include <unistd.h> 572SN/A 5812056Sgabeblack@google.com#include <cstring> 592SN/A#include <deque> 602SN/A#include <string> 612SN/A 6212334Sgabeblack@google.com#include "base/logging.hh" 63146SN/A#include "base/pollevent.hh" 64146SN/A#include "base/socket.hh" 65146SN/A#include "base/trace.hh" 668232SN/A#include "debug/Ethernet.hh" 678232SN/A#include "debug/EthernetData.hh" 6811263Sandreas.sandberg@arm.com#include "dev/net/etherdump.hh" 6911263Sandreas.sandberg@arm.com#include "dev/net/etherint.hh" 7011263Sandreas.sandberg@arm.com#include "dev/net/etherpkt.hh" 712SN/A 722SN/Ausing namespace std; 732SN/A 7412055Sgabeblack@google.comclass TapEvent : public PollEvent 7512055Sgabeblack@google.com{ 7612055Sgabeblack@google.com protected: 7712055Sgabeblack@google.com EtherTapBase *tap; 7812055Sgabeblack@google.com 7912055Sgabeblack@google.com public: 8012055Sgabeblack@google.com TapEvent(EtherTapBase *_tap, int fd, int e) 8112055Sgabeblack@google.com : PollEvent(fd, e), tap(_tap) {} 8212632Sgabeblack@google.com 8312632Sgabeblack@google.com void 8412632Sgabeblack@google.com process(int revent) override 8512632Sgabeblack@google.com { 8612632Sgabeblack@google.com // Ensure that our event queue is active. It may not be since we get 8712632Sgabeblack@google.com // here from the PollQueue whenever a real packet happens to arrive. 8812632Sgabeblack@google.com EventQueue::ScopedMigration migrate(tap->eventQueue()); 8912632Sgabeblack@google.com 9012632Sgabeblack@google.com tap->recvReal(revent); 9112632Sgabeblack@google.com } 9212055Sgabeblack@google.com}; 9312055Sgabeblack@google.com 9412055Sgabeblack@google.comEtherTapBase::EtherTapBase(const Params *p) 9513766Sgabeblack@google.com : SimObject(p), buflen(p->bufsz), dump(p->dump), event(NULL), 9612130Sspwilson2@wisc.edu interface(NULL), 9712130Sspwilson2@wisc.edu txEvent([this]{ retransmit(); }, "EtherTapBase retransmit") 9812055Sgabeblack@google.com{ 9912055Sgabeblack@google.com buffer = new uint8_t[buflen]; 10012055Sgabeblack@google.com interface = new EtherTapInt(name() + ".interface", this); 10112055Sgabeblack@google.com} 10212055Sgabeblack@google.com 10312055Sgabeblack@google.comEtherTapBase::~EtherTapBase() 10412055Sgabeblack@google.com{ 10512055Sgabeblack@google.com delete buffer; 10612055Sgabeblack@google.com delete event; 10712055Sgabeblack@google.com delete interface; 10812055Sgabeblack@google.com} 10912055Sgabeblack@google.com 11012055Sgabeblack@google.comvoid 11112055Sgabeblack@google.comEtherTapBase::serialize(CheckpointOut &cp) const 11212055Sgabeblack@google.com{ 11312055Sgabeblack@google.com SERIALIZE_SCALAR(buflen); 11412055Sgabeblack@google.com uint8_t *buffer = (uint8_t *)this->buffer; 11512055Sgabeblack@google.com SERIALIZE_ARRAY(buffer, buflen); 11612055Sgabeblack@google.com 11712055Sgabeblack@google.com bool tapevent_present = false; 11812055Sgabeblack@google.com if (event) { 11912055Sgabeblack@google.com tapevent_present = true; 12012055Sgabeblack@google.com SERIALIZE_SCALAR(tapevent_present); 12112055Sgabeblack@google.com event->serialize(cp); 12212055Sgabeblack@google.com } else { 12312055Sgabeblack@google.com SERIALIZE_SCALAR(tapevent_present); 12412055Sgabeblack@google.com } 12512055Sgabeblack@google.com} 12612055Sgabeblack@google.com 12712055Sgabeblack@google.comvoid 12812055Sgabeblack@google.comEtherTapBase::unserialize(CheckpointIn &cp) 12912055Sgabeblack@google.com{ 13012055Sgabeblack@google.com UNSERIALIZE_SCALAR(buflen); 13112055Sgabeblack@google.com uint8_t *buffer = (uint8_t *)this->buffer; 13212055Sgabeblack@google.com UNSERIALIZE_ARRAY(buffer, buflen); 13312055Sgabeblack@google.com 13412055Sgabeblack@google.com bool tapevent_present; 13512055Sgabeblack@google.com UNSERIALIZE_SCALAR(tapevent_present); 13612055Sgabeblack@google.com if (tapevent_present) { 13712055Sgabeblack@google.com event = new TapEvent(this, 0, 0); 13812055Sgabeblack@google.com event->unserialize(cp); 13912055Sgabeblack@google.com if (event->queued()) 14012055Sgabeblack@google.com pollQueue.schedule(event); 14112055Sgabeblack@google.com } 14212055Sgabeblack@google.com} 14312055Sgabeblack@google.com 14412055Sgabeblack@google.com 14512055Sgabeblack@google.comvoid 14612055Sgabeblack@google.comEtherTapBase::pollFd(int fd) 14712055Sgabeblack@google.com{ 14812055Sgabeblack@google.com assert(!event); 14912055Sgabeblack@google.com event = new TapEvent(this, fd, POLLIN|POLLERR); 15012055Sgabeblack@google.com pollQueue.schedule(event); 15112055Sgabeblack@google.com} 15212055Sgabeblack@google.com 15312055Sgabeblack@google.comvoid 15412055Sgabeblack@google.comEtherTapBase::stopPolling() 15512055Sgabeblack@google.com{ 15612055Sgabeblack@google.com assert(event); 15712055Sgabeblack@google.com delete event; 15812055Sgabeblack@google.com event = NULL; 15912055Sgabeblack@google.com} 16012055Sgabeblack@google.com 16112055Sgabeblack@google.com 16213784Sgabeblack@google.comPort & 16313784Sgabeblack@google.comEtherTapBase::getPort(const std::string &if_name, PortID idx) 16412055Sgabeblack@google.com{ 16513784Sgabeblack@google.com if (if_name == "tap") 16613784Sgabeblack@google.com return *interface; 16713784Sgabeblack@google.com return SimObject::getPort(if_name, idx); 16812055Sgabeblack@google.com} 16912055Sgabeblack@google.com 17012055Sgabeblack@google.combool 17112055Sgabeblack@google.comEtherTapBase::recvSimulated(EthPacketPtr packet) 17212055Sgabeblack@google.com{ 17312055Sgabeblack@google.com if (dump) 17412055Sgabeblack@google.com dump->dump(packet); 17512055Sgabeblack@google.com 17612055Sgabeblack@google.com DPRINTF(Ethernet, "EtherTap sim->real len=%d\n", packet->length); 17712055Sgabeblack@google.com DDUMP(EthernetData, packet->data, packet->length); 17812055Sgabeblack@google.com 17912055Sgabeblack@google.com bool success = sendReal(packet->data, packet->length); 18012055Sgabeblack@google.com 18112055Sgabeblack@google.com interface->recvDone(); 18212055Sgabeblack@google.com 18312055Sgabeblack@google.com return success; 18412055Sgabeblack@google.com} 18512055Sgabeblack@google.com 18612055Sgabeblack@google.comvoid 18712055Sgabeblack@google.comEtherTapBase::sendSimulated(void *data, size_t len) 18812055Sgabeblack@google.com{ 18912055Sgabeblack@google.com EthPacketPtr packet; 19012055Sgabeblack@google.com packet = make_shared<EthPacketData>(len); 19112055Sgabeblack@google.com packet->length = len; 19212055Sgabeblack@google.com packet->simLength = len; 19312055Sgabeblack@google.com memcpy(packet->data, data, len); 19412055Sgabeblack@google.com 19512055Sgabeblack@google.com DPRINTF(Ethernet, "EtherTap real->sim len=%d\n", packet->length); 19612055Sgabeblack@google.com DDUMP(EthernetData, packet->data, packet->length); 19712055Sgabeblack@google.com if (!packetBuffer.empty() || !interface->sendPacket(packet)) { 19812055Sgabeblack@google.com DPRINTF(Ethernet, "bus busy...buffer for retransmission\n"); 19912055Sgabeblack@google.com packetBuffer.push(packet); 20012055Sgabeblack@google.com if (!txEvent.scheduled()) 20112055Sgabeblack@google.com schedule(txEvent, curTick() + retryTime); 20212055Sgabeblack@google.com } else if (dump) { 20312055Sgabeblack@google.com dump->dump(packet); 20412055Sgabeblack@google.com } 20512055Sgabeblack@google.com} 20612055Sgabeblack@google.com 20712055Sgabeblack@google.comvoid 20812055Sgabeblack@google.comEtherTapBase::retransmit() 20912055Sgabeblack@google.com{ 21012055Sgabeblack@google.com if (packetBuffer.empty()) 21112055Sgabeblack@google.com return; 21212055Sgabeblack@google.com 21312055Sgabeblack@google.com EthPacketPtr packet = packetBuffer.front(); 21412055Sgabeblack@google.com if (interface->sendPacket(packet)) { 21512055Sgabeblack@google.com if (dump) 21612055Sgabeblack@google.com dump->dump(packet); 21712055Sgabeblack@google.com DPRINTF(Ethernet, "EtherTap retransmit\n"); 21812055Sgabeblack@google.com packetBuffer.front() = NULL; 21912055Sgabeblack@google.com packetBuffer.pop(); 22012055Sgabeblack@google.com } 22112055Sgabeblack@google.com 22212055Sgabeblack@google.com if (!packetBuffer.empty() && !txEvent.scheduled()) 22312055Sgabeblack@google.com schedule(txEvent, curTick() + retryTime); 22412055Sgabeblack@google.com} 22512055Sgabeblack@google.com 22612055Sgabeblack@google.com 2272SN/Aclass TapListener 2282SN/A{ 2292SN/A protected: 2302SN/A class Event : public PollEvent 2312SN/A { 2322SN/A protected: 2332SN/A TapListener *listener; 2342SN/A 2352SN/A public: 23612055Sgabeblack@google.com Event(TapListener *l, int fd, int e) : PollEvent(fd, e), listener(l) {} 2372SN/A 23812055Sgabeblack@google.com void process(int revent) override { listener->accept(); } 2392SN/A }; 2402SN/A 2412SN/A friend class Event; 2422SN/A Event *event; 2432SN/A 24412055Sgabeblack@google.com void accept(); 24512055Sgabeblack@google.com 2462SN/A protected: 2472SN/A ListenSocket listener; 24812054Sgabeblack@google.com EtherTapStub *tap; 2492SN/A int port; 2502SN/A 2512SN/A public: 25212055Sgabeblack@google.com TapListener(EtherTapStub *t, int p) : event(NULL), tap(t), port(p) {} 25312055Sgabeblack@google.com ~TapListener() { delete event; } 2542SN/A 2552SN/A void listen(); 2562SN/A}; 2572SN/A 2582SN/Avoid 2592SN/ATapListener::listen() 2602SN/A{ 2612SN/A while (!listener.listen(port, true)) { 2622SN/A DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port); 2632SN/A port++; 2642SN/A } 2652SN/A 2662SN/A ccprintf(cerr, "Listening for tap connection on port %d\n", port); 2672SN/A event = new Event(this, listener.getfd(), POLLIN|POLLERR); 2682SN/A pollQueue.schedule(event); 2692SN/A} 2702SN/A 2712SN/Avoid 2722SN/ATapListener::accept() 2732SN/A{ 27410156SN/A // As a consequence of being called from the PollQueue, we might 27510156SN/A // have been called from a different thread. Migrate to "our" 27610156SN/A // thread. 27710156SN/A EventQueue::ScopedMigration migrate(tap->eventQueue()); 27810156SN/A 2792SN/A if (!listener.islistening()) 2802SN/A panic("TapListener(accept): cannot accept if we're not listening!"); 2812SN/A 2822SN/A int sfd = listener.accept(true); 2832SN/A if (sfd != -1) 2842SN/A tap->attach(sfd); 2852SN/A} 2862SN/A 2872SN/A 28812055Sgabeblack@google.comEtherTapStub::EtherTapStub(const Params *p) : EtherTapBase(p), socket(-1) 2892SN/A{ 2905523SN/A if (ListenSocket::allDisabled()) 29112054Sgabeblack@google.com fatal("All listeners are disabled! EtherTapStub can't work!"); 2925523SN/A 2934981SN/A listener = new TapListener(this, p->port); 2942SN/A listener->listen(); 2952SN/A} 2962SN/A 29712054Sgabeblack@google.comEtherTapStub::~EtherTapStub() 2982SN/A{ 2992SN/A delete listener; 3002SN/A} 3012SN/A 3022SN/Avoid 30312055Sgabeblack@google.comEtherTapStub::serialize(CheckpointOut &cp) const 30412055Sgabeblack@google.com{ 30512055Sgabeblack@google.com EtherTapBase::serialize(cp); 30612055Sgabeblack@google.com 30712055Sgabeblack@google.com SERIALIZE_SCALAR(socket); 30812055Sgabeblack@google.com SERIALIZE_SCALAR(buffer_used); 30912055Sgabeblack@google.com SERIALIZE_SCALAR(frame_len); 31012055Sgabeblack@google.com} 31112055Sgabeblack@google.com 31212055Sgabeblack@google.comvoid 31312055Sgabeblack@google.comEtherTapStub::unserialize(CheckpointIn &cp) 31412055Sgabeblack@google.com{ 31512055Sgabeblack@google.com EtherTapBase::unserialize(cp); 31612055Sgabeblack@google.com 31712055Sgabeblack@google.com UNSERIALIZE_SCALAR(socket); 31812055Sgabeblack@google.com UNSERIALIZE_SCALAR(buffer_used); 31912055Sgabeblack@google.com UNSERIALIZE_SCALAR(frame_len); 32012055Sgabeblack@google.com} 32112055Sgabeblack@google.com 32212055Sgabeblack@google.com 32312055Sgabeblack@google.comvoid 32412054Sgabeblack@google.comEtherTapStub::attach(int fd) 3252SN/A{ 3262SN/A if (socket != -1) 3272SN/A close(fd); 3282SN/A 32912055Sgabeblack@google.com buffer_used = 0; 33012055Sgabeblack@google.com frame_len = 0; 3312SN/A socket = fd; 33212054Sgabeblack@google.com DPRINTF(Ethernet, "EtherTapStub attached\n"); 33312055Sgabeblack@google.com pollFd(socket); 3342SN/A} 3352SN/A 3362SN/Avoid 33712054Sgabeblack@google.comEtherTapStub::detach() 3382SN/A{ 33912054Sgabeblack@google.com DPRINTF(Ethernet, "EtherTapStub detached\n"); 34012055Sgabeblack@google.com stopPolling(); 3412SN/A close(socket); 3422SN/A socket = -1; 3432SN/A} 3442SN/A 3452SN/Avoid 34612055Sgabeblack@google.comEtherTapStub::recvReal(int revent) 3472SN/A{ 3482SN/A if (revent & POLLERR) { 3492SN/A detach(); 3502SN/A return; 3512SN/A } 3522SN/A 3532SN/A if (!(revent & POLLIN)) 3542SN/A return; 3552SN/A 35612055Sgabeblack@google.com // Read in as much of the new data as we can. 35712055Sgabeblack@google.com int len = read(socket, buffer + buffer_used, buflen - buffer_used); 35812055Sgabeblack@google.com if (len == 0) { 35912055Sgabeblack@google.com detach(); 36012055Sgabeblack@google.com return; 36112055Sgabeblack@google.com } 36212055Sgabeblack@google.com buffer_used += len; 36312055Sgabeblack@google.com 36412055Sgabeblack@google.com // If there's not enough data for the frame length, wait for more. 36512055Sgabeblack@google.com if (buffer_used < sizeof(uint32_t)) 36612055Sgabeblack@google.com return; 36712055Sgabeblack@google.com 36812055Sgabeblack@google.com if (frame_len == 0) 36912055Sgabeblack@google.com frame_len = ntohl(*(uint32_t *)buffer); 37012055Sgabeblack@google.com 37112055Sgabeblack@google.com DPRINTF(Ethernet, "Received data from peer: len=%d buffer_used=%d " 37212055Sgabeblack@google.com "frame_len=%d\n", len, buffer_used, frame_len); 37312055Sgabeblack@google.com 37412055Sgabeblack@google.com uint8_t *frame_start = &buffer[sizeof(uint32_t)]; 37512055Sgabeblack@google.com while (frame_len != 0 && buffer_used >= frame_len + sizeof(uint32_t)) { 37612055Sgabeblack@google.com sendSimulated(frame_start, frame_len); 37712055Sgabeblack@google.com 37812055Sgabeblack@google.com // Bookkeeping. 37912055Sgabeblack@google.com buffer_used -= frame_len + sizeof(uint32_t); 38012055Sgabeblack@google.com if (buffer_used > 0) { 38112055Sgabeblack@google.com // If there's still any data left, move it into position. 38212055Sgabeblack@google.com memmove(buffer, frame_start + frame_len, buffer_used); 3832SN/A } 38412055Sgabeblack@google.com frame_len = 0; 3852SN/A 38612055Sgabeblack@google.com if (buffer_used >= sizeof(uint32_t)) 38712055Sgabeblack@google.com frame_len = ntohl(*(uint32_t *)buffer); 3882SN/A } 3892SN/A} 3902SN/A 39112055Sgabeblack@google.combool 39212055Sgabeblack@google.comEtherTapStub::sendReal(const void *data, size_t len) 3932SN/A{ 39412055Sgabeblack@google.com uint32_t frame_len = htonl(len); 39512055Sgabeblack@google.com ssize_t ret = write(socket, &frame_len, sizeof(frame_len)); 39612055Sgabeblack@google.com if (ret != sizeof(frame_len)) 39712055Sgabeblack@google.com return false; 39812055Sgabeblack@google.com return write(socket, data, len) == len; 3992SN/A} 4002SN/A 401253SN/A 40212056Sgabeblack@google.com#if USE_TUNTAP 40312056Sgabeblack@google.com 40412056Sgabeblack@google.comEtherTap::EtherTap(const Params *p) : EtherTapBase(p) 40512056Sgabeblack@google.com{ 40612978Streapking@google.com int fd = open(p->tun_clone_device.c_str(), O_RDWR | O_NONBLOCK); 40712056Sgabeblack@google.com if (fd < 0) 40812056Sgabeblack@google.com panic("Couldn't open %s.\n", p->tun_clone_device); 40912056Sgabeblack@google.com 41012056Sgabeblack@google.com struct ifreq ifr; 41112056Sgabeblack@google.com memset(&ifr, 0, sizeof(ifr)); 41212056Sgabeblack@google.com ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 41312559Ssiddhesh.poyarekar@gmail.com strncpy(ifr.ifr_name, p->tap_device_name.c_str(), IFNAMSIZ - 1); 41412056Sgabeblack@google.com 41512056Sgabeblack@google.com if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) 41612056Sgabeblack@google.com panic("Failed to access tap device %s.\n", ifr.ifr_name); 41712056Sgabeblack@google.com // fd now refers to the tap device. 41812056Sgabeblack@google.com tap = fd; 41912056Sgabeblack@google.com pollFd(tap); 42012056Sgabeblack@google.com} 42112056Sgabeblack@google.com 42212056Sgabeblack@google.comEtherTap::~EtherTap() 42312056Sgabeblack@google.com{ 42412056Sgabeblack@google.com stopPolling(); 42512056Sgabeblack@google.com close(tap); 42612056Sgabeblack@google.com tap = -1; 42712056Sgabeblack@google.com} 42812056Sgabeblack@google.com 42912056Sgabeblack@google.comvoid 43012056Sgabeblack@google.comEtherTap::recvReal(int revent) 43112056Sgabeblack@google.com{ 43212056Sgabeblack@google.com if (revent & POLLERR) 43312056Sgabeblack@google.com panic("Error polling for tap data.\n"); 43412056Sgabeblack@google.com 43512056Sgabeblack@google.com if (!(revent & POLLIN)) 43612056Sgabeblack@google.com return; 43712056Sgabeblack@google.com 43812978Streapking@google.com ssize_t ret; 43912978Streapking@google.com while ((ret = read(tap, buffer, buflen))) { 44012978Streapking@google.com if (ret < 0) { 44112978Streapking@google.com if (errno == EAGAIN) 44212978Streapking@google.com break; 44312978Streapking@google.com panic("Failed to read from tap device.\n"); 44412978Streapking@google.com } 44512056Sgabeblack@google.com 44612978Streapking@google.com sendSimulated(buffer, ret); 44712978Streapking@google.com } 44812056Sgabeblack@google.com} 44912056Sgabeblack@google.com 45012056Sgabeblack@google.combool 45112056Sgabeblack@google.comEtherTap::sendReal(const void *data, size_t len) 45212056Sgabeblack@google.com{ 45312978Streapking@google.com int n; 45412978Streapking@google.com pollfd pfd[1]; 45512978Streapking@google.com pfd->fd = tap; 45612978Streapking@google.com pfd->events = POLLOUT; 45712978Streapking@google.com 45812978Streapking@google.com // `tap` is a nonblock fd. Here we try to write until success, and use 45912978Streapking@google.com // poll to make a blocking wait. 46012978Streapking@google.com while ((n = write(tap, data, len)) != len) { 46112978Streapking@google.com if (errno != EAGAIN) 46212978Streapking@google.com panic("Failed to write data to tap device.\n"); 46312978Streapking@google.com pfd->revents = 0; 46412978Streapking@google.com int ret = poll(pfd, 1, -1); 46512978Streapking@google.com // timeout is set to inf, we shouldn't get 0 in any case. 46612978Streapking@google.com assert(ret != 0); 46712978Streapking@google.com if (ret == -1 || (ret == 1 && (pfd->revents & POLLERR))) { 46812978Streapking@google.com panic("Failed when polling to write data to tap device.\n"); 46912978Streapking@google.com } 47012978Streapking@google.com } 47112056Sgabeblack@google.com return true; 47212056Sgabeblack@google.com} 47312056Sgabeblack@google.com 47412056Sgabeblack@google.comEtherTap * 47512056Sgabeblack@google.comEtherTapParams::create() 47612056Sgabeblack@google.com{ 47712056Sgabeblack@google.com return new EtherTap(this); 47812056Sgabeblack@google.com} 47912056Sgabeblack@google.com 48012056Sgabeblack@google.com#endif 48112056Sgabeblack@google.com 48212054Sgabeblack@google.comEtherTapStub * 48312054Sgabeblack@google.comEtherTapStubParams::create() 4842SN/A{ 48512054Sgabeblack@google.com return new EtherTapStub(this); 4862SN/A} 487