diff options
-rwxr-xr-x | SConstruct | 13 | ||||
-rw-r--r-- | src/dev/net/Ethernet.py | 9 | ||||
-rw-r--r-- | src/dev/net/ethertap.cc | 74 | ||||
-rw-r--r-- | src/dev/net/ethertap.hh | 31 |
4 files changed, 127 insertions, 0 deletions
diff --git a/SConstruct b/SConstruct index 65179f10a..ef7af0f26 100755 --- a/SConstruct +++ b/SConstruct @@ -1101,6 +1101,11 @@ if not have_kvm: print "Info: Compatible header file <linux/kvm.h> not found, " \ "disabling KVM support." +# Check if the TUN/TAP driver is available. +have_tuntap = conf.CheckHeader('linux/if_tun.h', '<>') +if not have_tuntap: + print "Info: Compatible header file <linux/if_tun.h> not found." + # x86 needs support for xsave. We test for the structure here since we # won't be able to run new tests by the time we know which ISA we're # targeting. @@ -1233,6 +1238,9 @@ sticky_vars.AddVariables( BoolVariable('USE_FENV', 'Use <fenv.h> IEEE mode control', have_fenv), BoolVariable('CP_ANNOTATE', 'Enable critical path annotation capability', False), BoolVariable('USE_KVM', 'Enable hardware virtualized (KVM) CPU models', have_kvm), + BoolVariable('USE_TUNTAP', + 'Enable using a tap device to bridge to the host network', + have_tuntap), BoolVariable('BUILD_GPU', 'Build the compute-GPU model', False), EnumVariable('PROTOCOL', 'Coherence protocol for Ruby', 'None', all_protocols), @@ -1477,6 +1485,11 @@ for variant_path in variant_paths: "target ISA combination" env['USE_KVM'] = False + if env['USE_TUNTAP']: + if not have_tuntap: + print "Warning: Can't connect EtherTap with a tap device." + env['USE_TUNTAP'] = False + if env['BUILD_GPU']: env.Append(CPPDEFINES=['BUILD_GPU']) diff --git a/src/dev/net/Ethernet.py b/src/dev/net/Ethernet.py index 68867c00f..71665c564 100644 --- a/src/dev/net/Ethernet.py +++ b/src/dev/net/Ethernet.py @@ -38,6 +38,7 @@ # # Authors: Nathan Binkert +from m5.defines import buildEnv from m5.SimObject import SimObject from m5.params import * from m5.proxy import * @@ -103,6 +104,14 @@ class EtherTapBase(EtherObject): dump = Param.EtherDump(NULL, "dump object") tap = SlavePort("Ethernet interface to connect to gem5's network") +if buildEnv['USE_TUNTAP']: + class EtherTap(EtherTapBase): + type = 'EtherTap' + cxx_header = "dev/net/ethertap.hh" + tun_clone_device = Param.String('/dev/net/tun', + "Path to the tun clone device node") + tap_device_name = Param.String('gem5-tap', "Tap device name") + class EtherTapStub(EtherTapBase): type = 'EtherTapStub' cxx_header = "dev/net/ethertap.hh" diff --git a/src/dev/net/ethertap.cc b/src/dev/net/ethertap.cc index f08de0ebf..0c027b621 100644 --- a/src/dev/net/ethertap.cc +++ b/src/dev/net/ethertap.cc @@ -38,9 +38,24 @@ #include <sys/param.h> #endif + +#if USE_TUNTAP && defined(__linux__) +#if 1 // Hide from the style checker since these have to be out of order. +#include <sys/socket.h> // Has to be included before if.h for some reason. + +#endif + +#include <linux/if.h> +#include <linux/if_tun.h> + +#endif + +#include <fcntl.h> #include <netinet/in.h> +#include <sys/ioctl.h> #include <unistd.h> +#include <cstring> #include <deque> #include <string> @@ -377,6 +392,65 @@ EtherTapStub::sendReal(const void *data, size_t len) } +#if USE_TUNTAP + +EtherTap::EtherTap(const Params *p) : EtherTapBase(p) +{ + int fd = open(p->tun_clone_device.c_str(), O_RDWR); + if (fd < 0) + panic("Couldn't open %s.\n", p->tun_clone_device); + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + strncpy(ifr.ifr_name, p->tap_device_name.c_str(), IFNAMSIZ); + + if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) + panic("Failed to access tap device %s.\n", ifr.ifr_name); + // fd now refers to the tap device. + tap = fd; + pollFd(tap); +} + +EtherTap::~EtherTap() +{ + stopPolling(); + close(tap); + tap = -1; +} + +void +EtherTap::recvReal(int revent) +{ + if (revent & POLLERR) + panic("Error polling for tap data.\n"); + + if (!(revent & POLLIN)) + return; + + ssize_t ret = read(tap, buffer, buflen); + if (ret < 0) + panic("Failed to read from tap device.\n"); + + sendSimulated(buffer, ret); +} + +bool +EtherTap::sendReal(const void *data, size_t len) +{ + if (write(tap, data, len) != len) + panic("Failed to write data to tap device.\n"); + return true; +} + +EtherTap * +EtherTapParams::create() +{ + return new EtherTap(this); +} + +#endif + EtherTapStub * EtherTapStubParams::create() { diff --git a/src/dev/net/ethertap.hh b/src/dev/net/ethertap.hh index 718af1808..96cc4710c 100644 --- a/src/dev/net/ethertap.hh +++ b/src/dev/net/ethertap.hh @@ -39,9 +39,16 @@ #include <string> #include "base/pollevent.hh" +#include "config/use_tuntap.hh" #include "dev/net/etherint.hh" #include "dev/net/etherobject.hh" #include "dev/net/etherpkt.hh" + +#if USE_TUNTAP +#include "params/EtherTap.hh" + +#endif + #include "params/EtherTapStub.hh" #include "sim/eventq.hh" #include "sim/sim_object.hh" @@ -176,4 +183,28 @@ class EtherTapStub : public EtherTapBase }; +#if USE_TUNTAP +class EtherTap : public EtherTapBase +{ + public: + typedef EtherTapParams Params; + EtherTap(const Params *p); + ~EtherTap(); + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + + protected: + int tap; + + void recvReal(int revent) override; + bool sendReal(const void *data, size_t len) override; +}; +#endif + + #endif // __DEV_NET_ETHERTAP_HH__ |