summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xSConstruct13
-rw-r--r--src/dev/net/Ethernet.py9
-rw-r--r--src/dev/net/ethertap.cc74
-rw-r--r--src/dev/net/ethertap.hh31
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__