dev: Add a version of EtherTap which uses the tap driver.
authorGabe Black <gabeblack@google.com>
Sat, 3 Jun 2017 14:23:05 +0000 (07:23 -0700)
committerGabe Black <gabeblack@google.com>
Sat, 3 Jun 2017 15:24:02 +0000 (15:24 +0000)
The object is called EtherTap (as opposed to EtherTapStub, what the former
EtherTap was renamed to), and its existance is gated on the linux/if_tun.h
header file existing. That's probably overly strict, but it will hopefully
be minimally likely to break the build for other systems.

Change-Id: Ie03507fadf0d843a4d4d52f283c44a416c6f2a74
Reviewed-on: https://gem5-review.googlesource.com/3646
Reviewed-by: Nathan Binkert <nate@binkert.org>
Maintainer: Nathan Binkert <nate@binkert.org>

SConstruct
src/dev/net/Ethernet.py
src/dev/net/ethertap.cc
src/dev/net/ethertap.hh

index 65179f10a051f1cd6e8da5c4f8ea8e7b9a4b08f1..ef7af0f26856cf121b559de32b261506288351e7 100755 (executable)
@@ -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'])
 
index 68867c00f613bc1b1a4f8ecb9fa9b0c045d7edfc..71665c56493bd7fb18ac5db377053106fd0b180e 100644 (file)
@@ -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"
index f08de0ebf7f50358d6a1b5cca15771b9b2d3e08c..0c027b621f72ef11e8c47f3a613e797e04dfd8a8 100644 (file)
 #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()
 {
index 718af18086ef859db19e92cceeed7dac34fbc143..96cc4710cc95482b1b71cdfb077678e621510b11 100644 (file)
 #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__