diff --git a/devices/gl-ar750/default.nix b/devices/gl-ar750/default.nix
index a3acff3..72935f7 100644
--- a/devices/gl-ar750/default.nix
+++ b/devices/gl-ar750/default.nix
@@ -126,11 +126,13 @@
           in {
             lan = link.build {
               ifname = "lan";
-              devpath = "/devices/platform/ahb/19000000.eth";
+              #              devpath = "/devices/platform/ahb/19000000.eth";
+              devpath = "/devices/platform/ahb/1a000000.eth";
             };
             wan = link.build {
               ifname = "wan";
-              devpath = "/devices/platform/ahb/1a000000.eth";
+              devpath = "/devices/platform/ahb/19000000.eth";
+              # devpath = "/devices/platform/ahb/1a000000.eth";
             };
             wlan = link.build {
               ifname = "wlan0";
diff --git a/examples/l2tp.nix b/examples/l2tp.nix
index c01ca93..c13a989 100644
--- a/examples/l2tp.nix
+++ b/examples/l2tp.nix
@@ -26,7 +26,7 @@
 
   lns = { hostname = "l2tp.aaisp.net.uk"; address = "194.4.172.12"; };
 
-  inherit (pkgs.liminix.services) oneshot target;
+  inherit (pkgs.liminix.services) oneshot longrun target;
   inherit (pkgs.pseudofile) dir symlink;
   inherit (pkgs) serviceFns;
   svc = config.system.service;
@@ -57,21 +57,77 @@ in rec {
     authType = "chap";
   };
 
-  services.dhcpc = svc.network.dhcp.client.build {
-    interface = config.services.wwan;
-    dependencies = [ config.services.hostname ];
-  };
+  services.wan =
+    let
+      z = final : prev: {
+        controller = longrun rec {
+          name = "wan-switcher";
+          run = ''
+            (in_outputs ${name}
+             ${pkgs.s6-rc-round-robin}/bin/s6-rc-round-robin \
+               -p ${final.proxy.name} \
+               ${lib.concatStringsSep " "
+                 (builtins.map (f: f.name) [final.pppoe final.l2tp])}
+            )
+          '';
+        };
+        pppoe = (svc.pppoe.build {
+          interface = config.hardware.networkInterfaces.wan;
+
+          ppp-options = [
+            "debug" "+ipv6" "noauth"
+            "name" rsecrets.l2tp.name
+            "password" rsecrets.l2tp.password
+          ];
+        }).overrideAttrs(o: { inherit (final) controller; });
+
+        l2tp =
+          let
+            check-address = oneshot rec {
+              name = "check-lns-address";
+              up = "grep -Fx ${ lns.address} $(output_path ${services.lns-address} addresses)";
+              dependencies = [ services.lns-address ];
+            };
+            route = svc.network.route.build {
+              via = "$(output ${services.dhcpc} router)";
+              target = lns.address;
+              dependencies = [services.dhcpc check-address];
+            };
+          in (svc.l2tp.build {
+            lns = lns.address;
+            ppp-options = [
+              "debug" "+ipv6" "noauth"
+              "name" rsecrets.l2tp.name
+              "connect-delay" "5000"
+              "password" rsecrets.l2tp.password
+            ];
+            dependencies = [config.services.lns-address route check-address];
+          }).overrideAttrs(o: { inherit (final) controller; });
+        proxy = oneshot rec {
+          name = "wan-proxy";
+          inherit (final) controller;
+          buildInputs = with final; [ pppoe l2tp];
+          up = ''
+            echo start proxy ${name}
+            set -x
+            (in_outputs ${name}
+             cp -rv $(output_path ${final.controller} active)/* .
+            )
+          '';
+        };
+      };
+    in (lib.fix (lib.extends z (prev : { }))).proxy;
 
   services.sshd = svc.ssh.build { };
 
   services.resolvconf = oneshot rec {
-    dependencies = [ services.l2tp ];
+    dependencies = [ services.wan ];
     name = "resolvconf";
     up = ''
       . ${serviceFns}
        ( in_outputs ${name}
         for i in ns1 ns2 ; do
-          ns=$(output ${services.l2tp} $i)
+          ns=$(output ${services.wan} $i)
           echo "nameserver $ns" >> resolv.conf
         done
        )
@@ -83,6 +139,11 @@ in rec {
     };
   };
 
+  services.dhcpc = svc.network.dhcp.client.build {
+    interface = config.services.wwan;
+    dependencies = [ config.services.hostname ];
+  };
+
   services.lns-address = let
     ns = "$(output_word ${services.dhcpc} dns 1)";
     route-to-bootstrap-nameserver = svc.network.route.build {
@@ -101,35 +162,10 @@ in rec {
     '';
   };
 
-  services.l2tp =
-    let
-      check-address = oneshot rec {
-        name = "check-lns-address";
-        up = ''
-          grep -Fx ${lns.address} $(output_path ${services.lns-address} addresses)
-        '';
-        dependencies = [ services.lns-address ];
-      };
-      route = svc.network.route.build {
-        via = "$(output ${services.dhcpc} router)";
-        target = lns.address;
-        dependencies = [services.dhcpc check-address];
-      };
-    in svc.l2tp.build {
-      lns = lns.address;
-      ppp-options = [
-        "debug" "+ipv6" "noauth"
-        "name" rsecrets.l2tp.name
-        "connect-delay" "5000"
-        "password" rsecrets.l2tp.password
-      ];
-      dependencies = [config.services.lns-address route check-address];
-  };
-
   services.defaultroute4 = svc.network.route.build {
-    via = "$(output ${services.l2tp} peer-address)";
+    via = "$(output ${services.wan} peer-address)";
     target = "default";
-    dependencies = [services.l2tp];
+    dependencies = [services.wan];
   };
 
 #  defaultProfile.packages = [ pkgs.go-l2tp ];
diff --git a/modules/ppp/l2tp.nix b/modules/ppp/l2tp.nix
index 1ba0978..1f7ad05 100644
--- a/modules/ppp/l2tp.nix
+++ b/modules/ppp/l2tp.nix
@@ -44,7 +44,8 @@ let
     require authentication = no
     pppoptfile = ${writeText "ppp-options" ppp-options'}
     autodial = yes
-    redial = yes
+    redial = no
+    max redials = 1
   '';
   control = "/run/xl2tpd/control-${name}";
 in
@@ -56,4 +57,5 @@ longrun {
     exec ${xl2tpd}/bin/xl2tpd -D -p /run/xl2tpd/${name}.pid -c ${conf} -C ${control} 
   '';
   notification-fd = 10;
+  timeout-up = 40 * 1000;
 }
diff --git a/modules/ppp/pppoe.nix b/modules/ppp/pppoe.nix
index 848ddba..33462c9 100644
--- a/modules/ppp/pppoe.nix
+++ b/modules/ppp/pppoe.nix
@@ -9,6 +9,8 @@
 { interface, ppp-options }:
 let
   inherit (liminix.services) longrun;
+  lcp-echo-interval = 4;
+  lcp-echo-failure = 3;
   name = "${interface.name}.pppoe";
   ip-up = writeAshScript "ip-up" {} ''
     . ${serviceFns} 
@@ -37,15 +39,19 @@ let
     "ipparam" name
     "nodetach"
     "usepeerdns"
+    "lcp-echo-interval" (builtins.toString lcp-echo-interval)
+    "lcp-echo-failure" (builtins.toString lcp-echo-failure)
     "logfd" "2"
   ];
 in
 longrun {
   inherit name;
   run = ''
-    . ${serviceFns} 
-    ${ppp}/bin/pppd pty "${pppoe}/bin/pppoe -I $(output ${interface} ifname)" ${lib.concatStringsSep " " ppp-options'}
+    . ${serviceFns}
+    echo Starting pppoe, pppd pid is $$
+    exec ${ppp}/bin/pppd pty "${pppoe}/bin/pppoe -T ${builtins.toString (4 * lcp-echo-interval)}  -I $(output ${interface} ifname)" ${lib.concatStringsSep " " ppp-options'}
   '';
   notification-fd = 10;
+  timeout-up = (10 + lcp-echo-failure * lcp-echo-interval) * 1000;
   dependencies = [ interface ];
 }
diff --git a/pkgs/default.nix b/pkgs/default.nix
index cbbc211..0f505a4 100644
--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -95,6 +95,7 @@ in {
   run-liminix-vm = callPackage ./run-liminix-vm { };
   s6-init-bin = callPackage ./s6-init-bin { };
   s6-rc-database = callPackage ./s6-rc-database { };
+  s6-rc-round-robin = callPackage ./s6-rc-round-robin { };
   s6-rc-up-tree = callPackage ./s6-rc-up-tree { };
 
   # schnapps is written by Turris and provides a high-level interface
diff --git a/pkgs/s6-rc-round-robin/default.nix b/pkgs/s6-rc-round-robin/default.nix
new file mode 100644
index 0000000..c614496
--- /dev/null
+++ b/pkgs/s6-rc-round-robin/default.nix
@@ -0,0 +1,21 @@
+{
+  lualinux,
+  writeFennel,
+  anoia,
+  linotify,
+  fennel,
+  stdenv,
+  s6-rc-up-tree,
+}:
+stdenv.mkDerivation {
+  name = "s6-rc-round-robin";
+  src = ./.;
+  propagatedBuildInputs = [ s6-rc-up-tree ];
+  installPhase = ''
+    mkdir -p $out/bin
+    cp -p ${writeFennel "uevent-watch" {
+      packages = [fennel anoia linotify lualinux s6-rc-up-tree] ;
+      mainFunction = "run";
+    } ./robin.fnl} $out/bin/s6-rc-round-robin
+  '';
+}
diff --git a/pkgs/s6-rc-round-robin/robin.fnl b/pkgs/s6-rc-round-robin/robin.fnl
new file mode 100644
index 0000000..28c3a99
--- /dev/null
+++ b/pkgs/s6-rc-round-robin/robin.fnl
@@ -0,0 +1,58 @@
+(local { : directory? : symlink } (require :anoia.fs))
+(local { : assoc : system } (require :anoia))
+(local inotify (require :inotify))
+
+(fn parse-args [args]
+  (match args
+    ["-p" proxy & rest] (assoc (parse-args rest) :proxy proxy)
+    backends { : backends }
+    _  nil))
+
+(fn %% [fmt ...] (string.format fmt ...))
+
+(fn start-service [service]
+  (let [(ok msg) (pcall system (%% "s6-rc-up-tree %q" service))]
+    (when (not ok) (print msg))
+    ok))
+
+(fn stop-service [service]
+  (let [(ok msg) (%% "s6-rc -b -d change %q" service)]
+    (when (not ok) (print msg))
+    ok))
+
+(fn watch-fsevents [directory-name]
+  (doto (inotify.init)
+    (: :addwatch directory-name
+       inotify.IN_CREATE
+       inotify.IN_MOVE
+       inotify.IN_DELETE
+       inotify.IN_DELETE_SELF
+       inotify.IN_MOVED_FROM
+       inotify.IN_MOVED_TO
+       inotify.IN_CLOSE_WRITE)))
+
+(fn round-robin [els]
+  (var i -1)
+  (fn []
+    (set i (% (+ 1 i) (# els)))
+    (. els (+ 1 i))))
+
+(fn run []
+  (let [{ : proxy : backends } (parse-args arg)]
+    (each [s (round-robin backends)]
+      (print "ROBIN starting " s)
+      (when (start-service s)
+        (let [outputs-dir (.. "/run/services/outputs/" s)]
+          (print "ROBIN started " s "expecting outputs in " outputs-dir)
+          (with-open [watcher (watch-fsevents outputs-dir)]
+            (symlink outputs-dir "active")
+            (start-service proxy)
+            (while (directory? outputs-dir)
+              (print :ROBIN (watcher:read))))))
+      ;; service failed to start, or started and finished
+      (print "ROBIN finished " s "stopping proxy")
+      (stop-service proxy)
+      (os.remove "active")
+      )))
+
+{ : run }
diff --git a/pkgs/s6-rc-up-tree/s6-rc-up-tree.sh b/pkgs/s6-rc-up-tree/s6-rc-up-tree.sh
index 4146c3f..07c4871 100644
--- a/pkgs/s6-rc-up-tree/s6-rc-up-tree.sh
+++ b/pkgs/s6-rc-up-tree/s6-rc-up-tree.sh
@@ -3,22 +3,26 @@ service=$1
 blocks=""
 for controlled in $(cd /run/services/controlled/ && echo *); do
     down=$(s6-rc -b -un0 change $controlled)
-    echo $controlled $down
+    echo $controlled
     if test -n "$down"; then
 	blocks="$blocks $controlled "
     fi
 done
 
 for s in $(s6-rc-db -d all-dependencies $service); do
+    start=$s
     for dep in $(s6-rc-db all-dependencies $s); do
 	case "$blocks" in
 	    "* $dep *")
 		echo "not starting $s, blocked by $dep"
+		start=""
 		;;
 	    *)
-		echo "starting $s because $service"
-		s6-rc -b -u change $s
 		;;
 	esac
     done
+    if test -n "$start" ; then
+	echo "starting $s because $service"
+	s6-rc -b -u change $s
+    fi
 done
diff --git a/pkgs/write-fennel/default.nix b/pkgs/write-fennel/default.nix
index 2fc1f51..e27095d 100644
--- a/pkgs/write-fennel/default.nix
+++ b/pkgs/write-fennel/default.nix
@@ -28,6 +28,7 @@ stdenv.mkDerivation {
      echo "package.path = ${lib.strings.escapeShellArg (builtins.concatStringsSep "" luapath)} .. package.path"
      echo "package.cpath = ${lib.strings.escapeShellArg (builtins.concatStringsSep "" luacpath)} .. package.cpath"
      echo "local ok, stdlib = pcall(require,'posix.stdlib'); if ok then stdlib.setenv('PATH',${lib.escapeShellArg (lib.makeBinPath packages)} .. \":\" .. os.getenv('PATH')) end"
+     echo "local ok, ll = pcall(require,'lualinux'); if ok then ll.setenv('PATH',${lib.escapeShellArg (lib.makeBinPath packages)} .. \":\" .. os.getenv('PATH')) end"
      fennel ${if correlate then "--correlate" else ""} --compile ${source}
     ) >  ${name}.lua
   '';