manager: Check IPv6 addressses and routes

Start IPv6 route advertisement on a server, and ensure routes and
IPv6 addresses are created correctly.  Reconnect to a non-IPv6
service, and ensure routes and addresses have been deleted.

BUG=chromium-os:7605
TEST=Run test (also ensure revamped __get_ipaddr continues to
work for v4 addresses)

Change-Id: I1ef99814a1bd2e81f42b52e80d2d0f612002f707
Reviewed-on: http://gerrit.chromium.org/gerrit/8780
Reviewed-by: Erik Kline <ek@chromium.org>
Reviewed-by: Sam Leffler <sleffler@chromium.org>
Commit-Ready: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/server/site_linux_server.py b/server/site_linux_server.py
index 732aeb1..373e3b9 100644
--- a/server/site_linux_server.py
+++ b/server/site_linux_server.py
@@ -12,13 +12,15 @@
 
     """
 
-    def __init__(self, server, wifi_ip):
+    def __init__(self, server, config):
         site_linux_system.LinuxSystem.__init__(self, server, {}, "server")
 
         self.server                      = server    # Server host.
         self.vpn_kind                    = None
-        self.wifi_ip                     = wifi_ip
+        self.config                      = config
         self.openvpn_config              = {}
+        self.radvd_config                = {'file':'/tmp/radvd-test.conf',
+                                            'server':'/usr/sbin/radvd'}
 
     def vpn_server_config(self, params):
         """ Configure & launch the server side of the VPN.
@@ -175,3 +177,36 @@
                 raise error.TestFail('(internal error): No kill case '
                                      'for VPN kind (%s)' % self.vpn_kind)
             self.vpn_kind = None
+
+    def ipv6_server_config(self, params):
+        self.ipv6_server_kill({})
+        radvd_opts = { 'interface': self.config.get('server_dev', 'eth0'),
+                       'adv_send_advert': 'on',
+                       'min_adv_interval': '3',
+                       'max_adv_interval': '10',
+                       # NB: Address below is is within the 2001:0db8/32
+                       # "documentation only" prefix (RFC3849), which is
+                       # guaranteed never to be assigned to a real network.
+                       'prefix': '2001:0db8:0100:f101::/64',
+                       'adv_on_link': 'on',
+                       'adv_autonomous': 'on',
+                       'adv_router_addr': 'on' }
+        radvd_opts.update(params)
+
+        config = ('interface %(interface)s {\n'
+                  '  AdvSendAdvert %(adv_send_advert)s;\n'
+                  '  MinRtrAdvInterval %(min_adv_interval)s;\n'
+                  '  MaxRtrAdvInterval %(max_adv_interval)s;\n'
+                  '  prefix %(prefix)s {\n'
+                  '    AdvOnLink %(adv_on_link)s;\n'
+                  '    AdvAutonomous %(adv_autonomous)s;\n'
+                  '    AdvRouterAddr %(adv_router_addr)s;\n'
+                  '  };\n'
+                  '};\n') % radvd_opts
+        cfg_file = params.get('config_file', self.radvd_config['file'])
+        self.server.run('cat <<EOF >%s\n%s\nEOF\n' % (cfg_file, config))
+        self.server.run('%s -C %s\n' % (self.radvd_config['server'], cfg_file))
+
+    def ipv6_server_kill(self, params):
+        self.server.run('pkill %s >/dev/null 2>&1' %
+                        self.radvd_config['server'], ignore_status=True)