TunChannel improvements:
authorClaudio-Daniel Freire <claudio-daniel.freire@inria.fr>
Tue, 9 Aug 2011 15:43:19 +0000 (17:43 +0200)
committerClaudio-Daniel Freire <claudio-daniel.freire@inria.fr>
Tue, 9 Aug 2011 15:43:19 +0000 (17:43 +0200)
 - Use python-iovec library for increased performance
 - In PlanetLab, support for GRE tunnels

src/nepi/testbeds/planetlab/metadata.py
src/nepi/testbeds/planetlab/scripts/tun_connect.py
src/nepi/testbeds/planetlab/tunproto.py
src/nepi/util/tunchannel.py
test/testbeds/planetlab/execute.py
test/testbeds/planetlab/integration_multi.py

index 92647b8..203b22d 100644 (file)
@@ -491,6 +491,12 @@ connector_types = dict({
                 "max": 1, 
                 "min": 0
             }),
+    "gre": dict({
+                "help": "IP or Ethernet tunneling using the GRE protocol", 
+                "name": "gre",
+                "max": 1, 
+                "min": 0
+            }),
     "fd->": dict({
                 "help": "TUN device file descriptor provider", 
                 "name": "fd->",
@@ -566,6 +572,12 @@ connections = [
         "init_code": functools.partial(connect_tun_iface_peer,"udp"),
         "can_cross": False
     }),
+    dict({
+        "from": (TESTBED_ID, TUNIFACE, "gre"),
+        "to":   (TESTBED_ID, TUNIFACE, "gre"),
+        "init_code": functools.partial(connect_tun_iface_peer,"gre"),
+        "can_cross": False
+    }),
     dict({
         "from": (TESTBED_ID, TAPIFACE, "tcp"),
         "to":   (TESTBED_ID, TAPIFACE, "tcp"),
@@ -578,6 +590,12 @@ connections = [
         "init_code": functools.partial(connect_tun_iface_peer,"udp"),
         "can_cross": False
     }),
+    dict({
+        "from": (TESTBED_ID, TAPIFACE, "gre"),
+        "to":   (TESTBED_ID, TAPIFACE, "gre"),
+        "init_code": functools.partial(connect_tun_iface_peer,"gre"),
+        "can_cross": False
+    }),
     dict({
         "from": (TESTBED_ID, TUNIFACE, "tcp"),
         "to":   (None, None, "tcp"),
@@ -598,6 +616,12 @@ connections = [
         "compl_code": functools.partial(crossconnect_tun_iface_peer_both,"fd"),
         "can_cross": True
     }),
+    dict({
+        "from": (TESTBED_ID, TUNIFACE, "gre"),
+        "to":   (None, None, "gre"),
+        "compl_code": functools.partial(crossconnect_tun_iface_peer_both,"gre"),
+        "can_cross": True
+    }),
     dict({
         "from": (TESTBED_ID, TAPIFACE, "tcp"),
         "to":   (None, None, "tcp"),
@@ -618,6 +642,14 @@ connections = [
         "compl_code": functools.partial(crossconnect_tun_iface_peer_both,"fd"),
         "can_cross": True
     }),
+    # EGRE is an extension of PlanetLab, so we can't connect externally
+    # if the other testbed isn't another PlanetLab
+    dict({
+        "from": (TESTBED_ID, TAPIFACE, "gre"),
+        "to":   (TESTBED_ID, None, "gre"),
+        "compl_code": functools.partial(crossconnect_tun_iface_peer_both,"gre"),
+        "can_cross": True
+    }),
 ]
 
 attributes = dict({
@@ -998,6 +1030,9 @@ configure_order = [ INTERNET, Parallel(NODE), NODEIFACE, Parallel(TAPIFACE), Par
 # Start (and prestart) node after ifaces, because the node needs the ifaces in order to set up routes
 start_order = [ INTERNET, NODEIFACE, Parallel(TAPIFACE), Parallel(TUNIFACE), Parallel(NODE), NETPIPE, Parallel(NEPIDEPENDENCY), Parallel(NS3DEPENDENCY), Parallel(DEPENDENCY), Parallel(APPLICATION) ]
 
+# cleanup order
+shutdown_order = [ Parallel(APPLICATION), Parallel(TAPIFACE), Parallel(TUNIFACE), Parallel(NETPIPE), Parallel(NEPIDEPENDENCY), Parallel(NS3DEPENDENCY), Parallel(DEPENDENCY), NODEIFACE, Parallel(NODE) ]
+
 factories_info = dict({
     NODE: dict({
             "help": "Virtualized Node (V-Server style)",
@@ -1044,7 +1079,7 @@ factories_info = dict({
                 "tun_proto", "tun_addr", "tun_port", "tun_key"
             ],
             "traces": ["packets", "pcap"],
-            "connector_types": ["node","udp","tcp","fd->"],
+            "connector_types": ["node","udp","tcp","fd->","gre"],
             "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
         }),
     TAPIFACE: dict({
@@ -1060,7 +1095,7 @@ factories_info = dict({
                 "tun_proto", "tun_addr", "tun_port", "tun_key"
             ],
             "traces": ["packets", "pcap"],
-            "connector_types": ["node","udp","tcp","fd->"],
+            "connector_types": ["node","udp","tcp","fd->","gre"],
             "tags": [tags.INTERFACE, tags.ALLOW_ADDRESSES],
         }),
     APPLICATION: dict({
@@ -1213,6 +1248,16 @@ testbed_attributes = dict({
             "range": (2000,30000),
             "validation_function": validation.is_integer_range(2000,30000)
         }),
+        "dedicated_slice": dict({
+            "name": "dedicatedSlice",
+            "help": "Set to True if the slice will be dedicated to this experiment. "
+                    "NEPI will perform node and slice cleanup, making sure slices are "
+                    "in a clean, repeatable state before running the experiment.",
+            "type": Attribute.BOOL,
+            "value": False,
+            "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
+            "validation_function": validation.is_bool
+        }),
     })
 
 supported_recovery_policies = [
index 8f79430..0eb46e3 100644 (file)
@@ -16,6 +16,7 @@ import re
 import functools
 import time
 import base64
+import traceback
 
 import tunchannel
 
@@ -51,7 +52,7 @@ parser.add_option(
     "-m", "--mode", dest="mode", metavar="MODE",
     default = "none",
     help = 
-        "Set mode. One of none, tun, tap, pl-tun, pl-tap. In any mode except none, a TUN/TAP will be created "
+        "Set mode. One of none, tun, tap, pl-tun, pl-tap, pl-gre-ip, pl-gre-eth. In any mode except none, a TUN/TAP will be created "
         "by using the proper interface (tunctl for tun/tap, /vsys/fd_tuntap.control for pl-tun/pl-tap), "
         "and it will be brought up (with ifconfig for tun/tap, with /vsys/vif_up for pl-tun/pl-tap). You have "
         "to specify an VIF_ADDRESS and VIF_MASK in any case (except for none).")
@@ -96,6 +97,11 @@ parser.add_option(
     help = 
         "Specify a symmetric encryption key with which to protect packets across "
         "the tunnel. python-crypto must be installed on the system." )
+parser.add_option(
+    "-K", "--gre-key", dest="gre_key", metavar="KEY", type="int",
+    default = None,
+    help = 
+        "Specify a demultiplexing 32-bit numeric key for GRE." )
 parser.add_option(
     "-N", "--no-capture", dest="no_capture", 
     action = "store_true",
@@ -144,7 +150,14 @@ class HostLock(object):
             processcond.release()
         
         self.lockfile = lockfile
-        fcntl.flock(self.lockfile, fcntl.LOCK_EX)
+        
+        while True:
+            try:
+                fcntl.flock(self.lockfile, fcntl.LOCK_EX)
+                break
+            except (OSError, IOError), e:
+                if e.args[0] != os.errno.EINTR:
+                    raise
     
     def __del__(self):
         processcond = self.__class__.processcond
@@ -196,6 +209,12 @@ def tunclose(tun_path, tun_name, tun):
         # close TUN object
         tun.close()
 
+def noopen(tun_path, tun_name):
+    print >>sys.stderr, "Using tun:", tun_name
+    return None
+def noclose(tun_path, tun_name, tun):
+    pass
+
 def tuntap_alloc(kind, tun_path, tun_name):
     args = ["tunctl"]
     if kind == "tun":
@@ -285,7 +304,39 @@ def pl_tuntap_alloc(kind, tun_path, tun_name):
     name = c_tun_name.value
     return str(fd), name
 
+_name_reservation = None
+def pl_tuntap_namealloc(kind, tun_path, tun_name):
+    global _name_reservation
+    # Serialize access
+    lockfile = open("/tmp/nepi-tun-connect.lock", "a")
+    _name_reservation = lock = HostLock(lockfile)
+    
+    # We need to do this, fd_tuntap is the only one who can
+    # tell us our slice id (this script runs as root, so no uid),
+    # and the pattern of device names accepted by vsys scripts
+    tunalloc_so = ctypes.cdll.LoadLibrary("./tunalloc.so")
+    c_tun_name = ctypes.c_char_p("\x00"*IFNAMSIZ) # the string will be mutated!
+    nkind= {"tun":IFF_TUN,
+            "tap":IFF_TAP}[kind]
+    fd = tunalloc_so.tun_alloc(nkind, c_tun_name)
+    name = c_tun_name.value
+    os.close(fd)
+
+    base = name[:name.index('-')+1]
+    existing = set(map(str.strip,os.popen("ip a | grep -o '%s[0-9]*'" % (base,)).read().strip().split('\n')))
+    
+    for i in xrange(9000,10000):
+        name = base + str(i)
+        if name not in existing:
+            break
+    else:
+        raise RuntimeError, "Could not assign interface name"
+    
+    return None, name
+
 def pl_vif_start(tun_path, tun_name):
+    global _name_reservation
+
     out = []
     def outreader():
         stdout = open("/vsys/vif_up.out","r")
@@ -295,8 +346,9 @@ def pl_vif_start(tun_path, tun_name):
 
     # Serialize access to vsys
     lockfile = open("/tmp/nepi-tun-connect.lock", "a")
-    lock = HostLock(lockfile)
-
+    lock = _name_reservation or HostLock(lockfile)
+    _name_reservation = None
+    
     stdin = open("/vsys/vif_up.in","w")
 
     t = threading.Thread(target=outreader)
@@ -311,6 +363,9 @@ def pl_vif_start(tun_path, tun_name):
         stdin.write("pointopoint=%s\n" % (options.vif_pointopoint,))
     if options.vif_txqueuelen is not None:
         stdin.write("txqueuelen=%d\n" % (options.vif_txqueuelen,))
+    if options.mode.startswith('pl-gre'):
+        stdin.write("gre=%d\n" % (options.gre_key,))
+        stdin.write("remote=%s\n" % (remaining_args[0],))
     stdin.close()
     
     t.join()
@@ -326,7 +381,13 @@ def pl_vif_stop(tun_path, tun_name):
         stdout = open("/vsys/vif_down.out","r")
         out.append(stdout.read())
         stdout.close()
-        time.sleep(1)
+        
+        while True:
+            ifaces = set(map(str.strip,os.popen("ip a | grep -o '%s'" % (tun_name,)).read().strip().split('\n')))
+            if tun_name in ifaces:
+                time.sleep(1)
+            else:
+                break
 
     # Serialize access to vsys
     lockfile = open("/tmp/nepi-tun-connect.lock", "a")
@@ -397,6 +458,16 @@ MODEINFO = {
                   dealloc=nop,
                   start=pl_vif_start,
                   stop=pl_vif_stop),
+    'pl-gre-ip' : dict(alloc=functools.partial(pl_tuntap_namealloc, "tun"),
+                  tunopen=noopen, tunclose=tunclose,
+                  dealloc=nop,
+                  start=pl_vif_start,
+                  stop=pl_vif_stop),
+    'pl-gre-eth': dict(alloc=functools.partial(pl_tuntap_namealloc, "tap"),
+                  tunopen=noopen, tunclose=noclose,
+                  dealloc=nop,
+                  start=pl_vif_start,
+                  stop=pl_vif_stop),
 }
     
 tun_path = options.tun_path
@@ -456,10 +527,16 @@ try:
         passfd.sendfd(sock, tun.fileno(), '0')
         
         # just wait forever
-        def tun_fwd(tun, remote):
+        def tun_fwd(tun, remote, **kw):
             while not TERMINATE:
                 time.sleep(1)
         remote = None
+    elif options.mode.startswith('pl-gre'):
+        # just wait forever
+        def tun_fwd(tun, remote, **kw):
+            while not TERMINATE:
+                time.sleep(1)
+        remote = remaining_args[0]
     elif options.udp:
         # connect to remote endpoint
         if remaining_args and not remaining_args[0].startswith('-'):
@@ -558,17 +635,17 @@ finally:
     try:
         modeinfo['stop'](tun_path, tun_name)
     except:
-        pass
+        traceback.print_exc()
 
     try:
         modeinfo['tunclose'](tun_path, tun_name, tun)
     except:
-        pass
+        traceback.print_exc()
         
     try:
         modeinfo['dealloc'](tun_path, tun_name)
     except:
-        pass
+        traceback.print_exc()
     
     print >>sys.stderr, "TERMINATED GRACEFULLY"
 
index 08a33ed..d3cf6b8 100644 (file)
@@ -107,7 +107,17 @@ class TunProtoBase(object):
         local.node.wait_dependencies()
 
         cmd = ( (
-            "cd %(home)s && gcc -fPIC -shared tunalloc.c -o tunalloc.so"
+            "cd %(home)s && "
+            "gcc -fPIC -shared tunalloc.c -o tunalloc.so && "
+            
+            "wget -q -c -O python-iovec-src.tar.gz %(iovec_url)s && "
+            "mkdir -p python-iovec && "
+            "cd python-iovec && "
+            "tar xzf ../python-iovec-src.tar.gz --strip-components=1 && "
+            "python setup.py build && "
+            "python setup.py install --install-lib .. && "
+            "cd .. "
+            
             + ( " && "
                 "wget -q -c -O python-passfd-src.tar.gz %(passfd_url)s && "
                 "mkdir -p python-passfd && "
@@ -117,10 +127,12 @@ class TunProtoBase(object):
                 "python setup.py install --install-lib .. "
                 
                 if local.tun_proto == "fd" else ""
-            ) )
+            ) 
+          )
         % {
             'home' : server.shell_escape(self.home_path),
             'passfd_url' : "http://yans.pl.sophia.inria.fr/code/hgwebdir.cgi/python-passfd/archive/2a6472c64c87.tar.gz",
+            'iovec_url' : "http://yans.pl.sophia.inria.fr/code/hgwebdir.cgi/python-iovec/archive/tip.tar.gz",
         } )
         (out,err),proc = server.popen_ssh_command(
             cmd,
@@ -186,6 +198,10 @@ class TunProtoBase(object):
             args.extend([
                 "--pass-fd", passfd_arg
             ])
+        elif check_proto == 'gre':
+            args.extend([
+                "-K", str(min(local_port, peer_port))
+            ])
         else:
             args.extend([
                 "-p", str(local_port if listen else peer_port),
@@ -312,9 +328,14 @@ class TunProtoBase(object):
                     
                     out = out.strip()
                     
-                    match = re.match(r"Using +tun: +([-a-zA-Z0-9]*) +.*",out)
+                    match = re.match(r"Using +tun: +([-a-zA-Z0-9]*).*",out)
                     if match:
                         self._if_name = match.group(1)
+                    elif out:
+                        self._logger.debug("if_name: %r does not match expected pattern", out)
+                        time.sleep(1)
+                else:
+                    pself._logger.warn("if_name: Could not get interface name")
         return self._if_name
     
     def async_launch(self, check_proto, listen, extra_args=[]):
@@ -540,6 +561,27 @@ class TunProtoFD(TunProtoBase):
     def launch(self, check_proto='fd', listen=False, extra_args=[]):
         super(TunProtoFD, self).launch(check_proto, listen, extra_args)
 
+class TunProtoGRE(TunProtoBase):
+    def __init__(self, local, peer, home_path, key, listening):
+        super(TunProtoGRE, self).__init__(local, peer, home_path, key)
+        self.listening = listening
+        self.mode = 'pl-gre-ip'
+    
+    def prepare(self):
+        pass
+    
+    def setup(self):
+        self.async_launch('gre', False)
+    
+    def shutdown(self):
+        self.kill()
+
+    def destroy(self):
+        self.waitkill()
+
+    def launch(self, check_proto='gre', listen=False, extra_args=[]):
+        super(TunProtoGRE, self).launch(check_proto, listen, extra_args)
+
 class TunProtoTCP(TunProtoBase):
     def __init__(self, local, peer, home_path, key, listening):
         super(TunProtoTCP, self).__init__(local, peer, home_path, key)
@@ -587,18 +629,25 @@ class TapProtoFD(TunProtoFD):
         super(TapProtoFD, self).__init__(local, peer, home_path, key, listening)
         self.mode = 'pl-tap'
 
+class TapProtoGRE(TunProtoGRE):
+    def __init__(self, local, peer, home_path, key, listening):
+        super(TapProtoGRE, self).__init__(local, peer, home_path, key, listening)
+        self.mode = 'pl-gre-eth'
+
 
 
 TUN_PROTO_MAP = {
     'tcp' : TunProtoTCP,
     'udp' : TunProtoUDP,
     'fd'  : TunProtoFD,
+    'gre' : TunProtoGRE,
 }
 
 TAP_PROTO_MAP = {
     'tcp' : TapProtoTCP,
     'udp' : TapProtoUDP,
     'fd'  : TapProtoFD,
+    'gre' : TapProtoGRE,
 }
 
 
index db0a6d9..9e34b45 100644 (file)
@@ -9,6 +9,8 @@ import fcntl
 import traceback
 import functools
 import collections
+import ctypes
+import time
 
 def ipfmt(ip):
     ipbytes = map(ord,ip.decode("hex"))
@@ -24,7 +26,7 @@ tagtype = {
 }
 def etherProto(packet, len=len):
     if len(packet) > 14:
-        if packet[12:14] == "\x81\x00":
+        if packet[12] == "\x81" and packet[13] == "\x00":
             # tagged
             return packet[16:18]
         else:
@@ -190,7 +192,8 @@ def nonblock(fd):
 
 def tun_fwd(tun, remote, with_pi, ether_mode, cipher_key, udp, TERMINATE, stderr=sys.stderr, reconnect=None, rwrite=None, rread=None, tunqueue=1000, tunkqueue=1000,
         cipher='AES',
-        len=len, max=max, OSError=OSError, select=select.select, selecterror=select.error, piWrap=piWrap, piStrip=piStrip, os=os, socket=socket):
+        len=len, max=max, OSError=OSError, select=select.select, selecterror=select.error, os=os, socket=socket,
+        retrycodes=(os.errno.EWOULDBLOCK, os.errno.EAGAIN, os.errno.EINTR) ):
     crypto_mode = False
     try:
         if cipher_key:
@@ -232,18 +235,48 @@ def tun_fwd(tun, remote, with_pi, ether_mode, cipher_key, udp, TERMINATE, stderr
     rnonblock = nonblock(remote)
     tnonblock = nonblock(tun)
     
+    # Pick up TUN/TAP writing method
+    if with_pi:
+        try:
+            import iovec
+            
+            # We have iovec, so we can skip PI injection
+            # and use iovec which does it natively
+            if ether_mode:
+                twrite = iovec.ethpiwrite
+                tread = iovec.piread2
+            else:
+                twrite = iovec.ippiwrite
+                tread = iovec.piread2
+        except ImportError:
+            # We have to inject PI headers pythonically
+            def twrite(fd, packet, oswrite=os.write, piWrap=piWrap, ether_mode=ether_mode):
+                return oswrite(fd, piWrap(packet, ether_mode))
+            
+            # For reading, we strip PI headers with buffer slicing and that's it
+            def tread(fd, maxlen, osread=os.read, piStrip=piStrip):
+                return piStrip(osread(fd, maxlen))
+    else:
+        # No need to inject PI headers
+        twrite = os.write
+        tread = os.read
+    
     # Limited frame parsing, to preserve packet boundaries.
     # Which is needed, since /dev/net/tun is unbuffered
     maxbkbuf = maxfwbuf = max(10,tunqueue-tunkqueue)
     tunhurry = max(0,maxbkbuf/2)
     fwbuf = collections.deque()
     bkbuf = collections.deque()
+    nfwbuf = 0
+    nbkbuf = 0
     if ether_mode:
         packetReady = bool
         pullPacket = collections.deque.popleft
+        reschedule = collections.deque.appendleft
     else:
         packetReady = _packetReady
         pullPacket = _pullPacket
+        reschedule = collections.deque.appendleft
     tunfd = tun.fileno()
     os_read = os.read
     os_write = os.write
@@ -290,16 +323,9 @@ def tun_fwd(tun, remote, with_pi, ether_mode, cipher_key, udp, TERMINATE, stderr
                         packet = pullPacket(fwbuf)
 
                         if crypto_mode:
-                            enpacket = encrypt_(packet, crypter)
-                        else:
-                            enpacket = packet
+                            packet = encrypt_(packet, crypter)
                         
-                        # try twice - sometimes it barks the first time,
-                        # due to ICMP Port Unreachable packets from previous writes
-                        try:
-                            rwrite(remote, enpacket)
-                        except socket.error:
-                            rwrite(remote, enpacket)
+                        rwrite(remote, packet)
                         #wr += 1
                         
                         if not rnonblock or not packetReady(fwbuf):
@@ -308,9 +334,9 @@ def tun_fwd(tun, remote, with_pi, ether_mode, cipher_key, udp, TERMINATE, stderr
                     # This except handles the entire While block on PURPOSE
                     # as an optimization (setting a try/except block is expensive)
                     # The only operation that can raise this exception is rwrite
-                    if e.errno == os.errno.EWOULDBLOCK:
+                    if e.errno in retrycodes:
                         # re-schedule packet
-                        fwbuf.insert(0, packet)
+                        reschedule(fwbuf, packet)
                     else:
                         raise
             except:
@@ -323,14 +349,12 @@ def tun_fwd(tun, remote, with_pi, ether_mode, cipher_key, udp, TERMINATE, stderr
                 elif not udp:
                     # in UDP mode, we ignore errors - packet loss man...
                     raise
-                traceback.print_exc(file=sys.stderr)
+                #traceback.print_exc(file=sys.stderr)
         if tun in wrdy:
             try:
-                while 1:
+                for x in xrange(50):
                     packet = pullPacket(bkbuf)
-                    if with_pi:
-                        packet = piWrap(packet, ether_mode)
-                    os_write(tunfd, packet)
+                    twrite(tunfd, packet)
                     #wt += 1
                     
                     # Do not inject packets into the TUN faster than they arrive, unless we're falling
@@ -339,13 +363,16 @@ def tun_fwd(tun, remote, with_pi, ether_mode, cipher_key, udp, TERMINATE, stderr
                     # we'll have high packet loss.
                     if not tnonblock or len(bkbuf) < tunhurry or not packetReady(bkbuf):
                         break
+                else:
+                    # Give some time for the kernel to process the packets
+                    time.sleep(0)
             except OSError,e:
                 # This except handles the entire While block on PURPOSE
                 # as an optimization (setting a try/except block is expensive)
                 # The only operation that can raise this exception is os_write
-                if e.errno == os.errno.EWOULDBLOCK:
+                if e.errno in retrycodes:
                     # re-schedule packet
-                    bkbuf.insert(0, packet)
+                    reschedule(bkbuf, packet)
                 else:
                     raise
         
@@ -353,10 +380,8 @@ def tun_fwd(tun, remote, with_pi, ether_mode, cipher_key, udp, TERMINATE, stderr
         if tun in rdrdy:
             try:
                 while 1:
-                    packet = os_read(tunfd,2000) # tun.read blocks until it gets 2k!
+                    packet = tread(tunfd,2000) # tun.read blocks until it gets 2k!
                     #rt += 1
-                    if with_pi:
-                        packet = piStrip(packet)
                     fwbuf.append(packet)
                     
                     if not tnonblock or len(fwbuf) >= maxfwbuf:
@@ -365,18 +390,13 @@ def tun_fwd(tun, remote, with_pi, ether_mode, cipher_key, udp, TERMINATE, stderr
                 # This except handles the entire While block on PURPOSE
                 # as an optimization (setting a try/except block is expensive)
                 # The only operation that can raise this exception is os_read
-                if e.errno != os.errno.EWOULDBLOCK:
+                if e.errno not in retrycodes:
                     raise
         if remote in rdrdy:
             try:
                 try:
                     while 1:
-                        # Try twice, sometimes it barks the first time, 
-                        # due to ICMP Port Unreachable packets from previous writes
-                        try:
-                            packet = rread(remote,2000)
-                        except socket.error:
-                            packet = rread(remote,2000)
+                        packet = rread(remote,2000)
                         #rr += 1
                         
                         if crypto_mode:
@@ -389,7 +409,7 @@ def tun_fwd(tun, remote, with_pi, ether_mode, cipher_key, udp, TERMINATE, stderr
                     # This except handles the entire While block on PURPOSE
                     # as an optimization (setting a try/except block is expensive)
                     # The only operation that can raise this exception is rread
-                    if e.errno != os.errno.EWOULDBLOCK:
+                    if e.errno not in retrycodes:
                         raise
             except Exception, e:
                 if reconnect is not None:
@@ -401,7 +421,7 @@ def tun_fwd(tun, remote, with_pi, ether_mode, cipher_key, udp, TERMINATE, stderr
                 elif not udp:
                     # in UDP mode, we ignore errors - packet loss man...
                     raise
-                traceback.print_exc(file=sys.stderr)
+                #traceback.print_exc(file=sys.stderr)
         
         #print >>sys.stderr, "rr:%d\twr:%d\trt:%d\twt:%d" % (rr,wr,rt,wt)
 
index 9768389..d21e430 100755 (executable)
@@ -392,6 +392,10 @@ echo 'OKIDOKI'
     def test_tun_ping_udp(self):
         self._pingtest("TunInterface", "udp")
 
+    @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
+    def test_tun_ping_gre(self):
+        self._pingtest("TunInterface", "gre")
+
     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
     def test_tap_ping(self):
         self._pingtest("TapInterface", "tcp")
@@ -400,6 +404,10 @@ echo 'OKIDOKI'
     def test_tap_ping_udp(self):
         self._pingtest("TapInterface", "udp")
 
+    @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
+    def test_tap_ping_gre(self):
+        self._pingtest("TapInterface", "gre")
+
     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
     def test_nepi_depends(self):
         instance = self.make_instance()
index ff8dc7b..2ec8df7 100755 (executable)
@@ -171,6 +171,11 @@ class PlanetLabMultiIntegrationTestCase(unittest.TestCase):
     def test_plpl_crossconnect_tcp(self):
         self._test_plpl_crossconnect("tcp")
 
+    @test_util.skipUnless(test_util.pl_auth() is not None, 
+        "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
+    def test_plpl_crossconnect_gre(self):
+        self._test_plpl_crossconnect("gre")
+
     @test_util.skipUnless(test_util.pl_auth() is not None, 
         "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
     def test_plpl_crossconnect_udp_recover(self):