# # NEPI, a framework to manage network experiments # Copyright (C) 2014 INRIA # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Author: Alina Quereilhac from nepi.execution.attribute import Attribute, Flags, Types from nepi.execution.resource import ResourceManager, ResourceState, \ clsinit_copy import os import socket import struct import fcntl @clsinit_copy class TapFdLink(ResourceManager): """ Interconnects a TAP or TUN Linux device to a FdNetDevice """ _rtype = "linux::ns3::TapFdLink" def __init__(self, ec, guid): super(TapFdLink, self).__init__(ec, guid) self._tap = None self._fdnetdevice = None self._fd = None @property def fdnetdevice(self): if not self._fdnetdevice: from nepi.resources.ns3.ns3fdnetdevice import NS3BaseFdNetDevice devices = self.get_connected(NS3BaseFdNetDevice.get_rtype()) if not devices or len(devices) != 1: msg = "TapFdLink must be connected to exactly one FdNetDevices" self.error(msg) raise RuntimeError, msg self._fdnetdevice = devices[0] return self._fdnetdevice @property def fdnode(self): return self.fdnetdevice.node @property def tap(self): if not self._tap: from nepi.resources.linux.tap import LinuxTap devices = self.get_connected(LinuxTap.get_rtype()) if not devices or len(devices) != 1: msg = "TapFdLink must be connected to exactly one LinuxTap" self.error(msg) raise RuntimeError, msg self._tap = devices[0] return self._tap @property def tapnode(self): return self.tap.node def do_provision(self): tap = self.tap fdnetdevice = self.fdnetdevice vif_name = self.ec.get(tap.guid, "deviceName") vif_type = tap.vif_type_flag pi = self.ec.get(tap.guid, "pi") self._fd = self.open_tap(vif_name, vif_type, pi) fdnetdevice.send_fd(self._fd) super(TapFdLink, self).do_provision() def do_deploy(self): if self.tap.state < ResourceState.READY or \ self.fdnetdevice.state < ResourceState.READY: self.ec.schedule(self.reschedule_delay, self.deploy) else: self.do_discover() self.do_provision() super(TapFdLink, self).do_deploy() def open_tap(self, vif_name, vif_type, pi): IFF_NO_PI = 0x1000 TUNSETIFF = 0x400454ca flags = 0 flags |= vif_type if not pi: flags |= IFF_NO_PI fd = os.open("/dev/net/tun", os.O_RDWR) err = fcntl.ioctl(fd, TUNSETIFF, struct.pack("16sH", vif_name, flags)) if err < 0: os.close(fd) raise RuntimeError("Could not configure device %s" % vif_name) return fd