Setup and teardown NAT interfaces automatically
[nodemanager-topo.git] / topo.py
diff --git a/topo.py b/topo.py
index 4d4e4a9..502b605 100755 (executable)
--- a/topo.py
+++ b/topo.py
@@ -10,11 +10,17 @@ import logger
 import subprocess
 import sioc
 import re
 import subprocess
 import sioc
 import re
-
-dryrun=0
-setup_link_cmd="/usr/share/vini/setup-egre-link"
-teardown_link_cmd="/usr/share/vini/teardown-egre-link"
+import vserver
+import os
+
+dryrun = 0
+vinidir = "/usr/share/vini/"
+setup_link_cmd = vinidir + "setup-egre-link"
+teardown_link_cmd = vinidir + "teardown-egre-link"
+setup_nat_cmd = vinidir + "setup-nat"
+teardown_nat_cmd = vinidir + "teardown-nat"
 ifaces = {}
 ifaces = {}
+old_ifaces = {}
 
 def run(cmd):
     if dryrun:
 
 def run(cmd):
     if dryrun:
@@ -29,7 +35,6 @@ Check for existence of interface d<key>x<nodeid>
 """
 def virtual_link(key, nodeid):
     name = "d%sx%s" % (key, nodeid)
 """
 def virtual_link(key, nodeid):
     name = "d%sx%s" % (key, nodeid)
-    # logger.log("Looking for iface %s" % name)
     if name in ifaces:
         return True
     else:
     if name in ifaces:
         return True
     else:
@@ -41,7 +46,7 @@ Create a "virtual link" for slice between here and nodeid.
 The key is used to create the EGRE tunnel.
 """
 def setup_virtual_link(slice, key, rate, myid, nodeid, ipaddr):
 The key is used to create the EGRE tunnel.
 """
 def setup_virtual_link(slice, key, rate, myid, nodeid, ipaddr):
-    logger.log("Set up virtual link to node %d" % nodeid)
+    logger.log("%s: Set up virtual link to node %d" % (slice, nodeid))
     if myid < nodeid:
         virtip = "10.%d.%d.2" % (myid, nodeid)
     else:
     if myid < nodeid:
         virtip = "10.%d.%d.2" % (myid, nodeid)
     else:
@@ -55,9 +60,58 @@ def setup_virtual_link(slice, key, rate, myid, nodeid, ipaddr):
 """
 Tear down the "virtual link" for slice between here and nodeid.
 """
 """
 Tear down the "virtual link" for slice between here and nodeid.
 """
-def teardown_virtual_link(slice, key, nodeid):
-    logger.log("Tear down virtual link to node %s" % nodeid)
-    run(teardown_link_cmd + " %s %s %s" % (slice, nodeid, key))
+def teardown_virtual_link(key, nodeid):
+    logger.log("topo: Tear down virtual link %sx%s" % (key, nodeid))
+    run(teardown_link_cmd + " %s %s" % (nodeid, key))
+    return
+
+
+"""
+Called for all active virtual link interfaces, so they won't be cleaned up.
+"""
+def refresh_virtual_link(nodeid, key):
+    name = "d%sx%s" % (key, nodeid)
+    if name in old_ifaces:
+        del old_ifaces[name]
+    return
+
+
+"""
+Check for existence of interface natx<key>
+"""
+def nat_exists(key):
+    name = "natx%s" % key
+    if name in ifaces:
+        return True
+    else:
+        return False
+
+
+"""
+Create a NAT interface inside the sliver.  
+"""
+def setup_nat(slice, myid, key):
+    logger.log("%s: Set up NAT" % slice)
+    run(setup_nat_cmd + " %s %s %s" % (slice, myid, key))
+    return
+
+
+"""
+Tear down the NAT interface identified by key
+"""
+def teardown_nat(key):
+    logger.log("topo: Tear down NAT %s" % key)
+    run(teardown_nat_cmd + " %s" % key)
+    return
+
+
+"""
+Called for all active NAT interfaces, so they won't be cleaned up.
+"""
+def refresh_nat(key):
+    name = "natx%s" % (key)
+    if name in old_ifaces:
+        del old_ifaces[name]
     return
 
 
     return
 
 
@@ -65,15 +119,21 @@ def teardown_virtual_link(slice, key, nodeid):
 Clean up old virtual links (e.g., to nodes that have been deleted 
 from the slice).
 """
 Clean up old virtual links (e.g., to nodes that have been deleted 
 from the slice).
 """
-def clean_up_old_virtual_links(slice, key, nodelist):
-    pattern = "d%sx(.*)" % key
-    for iface in ifaces:
-        m = re.match(pattern, iface)
+def clean_up_old_virtual_links():
+    pattern1 = "d(.*)x(.*)"
+    pattern2 = "natx(.*)"
+    for iface in old_ifaces:
+        m = re.match(pattern1, iface)
         if m:
         if m:
-            node = int(m.group(1))
-            if not node in nodelist:
-                logger.log("%s" % nodelist)
-                teardown_virtual_link(slice, key, node)
+            key = int(m.group(1))
+            node = int(m.group(2))
+            teardown_virtual_link(key, node)
+
+        m = re.match(pattern2, iface)
+        if m:
+            key = int(m.group(1))
+            teardown_nat(key)
+    return
 
 
 """
 
 
 """
@@ -86,17 +146,43 @@ def convert_topospec_to_list(rspec):
 """
 Update virtual links for the slice
 """
 """
 Update virtual links for the slice
 """
-def update(slice, myid, topospec, key):
+def update(slice, myid, topospec, key, netns):
     topolist = convert_topospec_to_list(topospec)
     topolist = convert_topospec_to_list(topospec)
-    nodelist=[]
     for (nodeid,ipaddr,rate) in topolist:
     for (nodeid,ipaddr,rate) in topolist:
-        nodelist.append(nodeid)
         if not virtual_link(key, nodeid):
         if not virtual_link(key, nodeid):
-            setup_virtual_link(slice, key, rate, myid, nodeid, ipaddr)
+            if netns:
+                setup_virtual_link(slice, key, rate, myid, nodeid, ipaddr)
         else:
         else:
-            logger.log("Virtual link to node %s exists" % nodeid)
+            logger.log("%s: virtual link to node %s exists" % (slice, nodeid))
+            refresh_virtual_link(nodeid, key)
 
 
-    clean_up_old_virtual_links(slice, key, nodelist)
+    if not nat_exists(key):
+        setup_nat(slice, myid, key)
+    else:
+        logger.log("%s: NAT exists" % slice)
+        refresh_nat(key)
+
+
+"""
+Write /etc/vservers/<slicename>/spaces/net
+"""
+def writeConf(slicename, value):
+    SLICEDIR="/etc/vservers/%s/" % slicename
+    SPACESDIR="%s/spaces/" % SLICEDIR
+    if os.path.exists(SLICEDIR):
+        if not os.path.exists(SPACESDIR):
+            try:
+                os.mkdir(SPACESDIR)
+            except os.error:
+                logger.log("netns: could not create %s\n" % SPACESDIR)
+                return
+        f = open("%s/net" % SPACESDIR, "w")
+        f.write("%s\n" % value)
+        f.close()
+        STATUS="OFF"
+        if value:
+            STATUS="ON"
+        logger.log("%s: network namespace %s\n" % (slicename, STATUS))
 
 
 def start(options, config):
 
 
 def start(options, config):
@@ -106,18 +192,35 @@ def start(options, config):
 """
 Update the virtual links for a sliver if it has a 'netns' attribute,
 an 'egre_key' attribute, and a 'topo_rspec' attribute.
 """
 Update the virtual links for a sliver if it has a 'netns' attribute,
 an 'egre_key' attribute, and a 'topo_rspec' attribute.
+
+Creating the virtual link depends on the contents of 
+/etc/vservers/<slice>/spaces/net.  Update this first.
 """
 def GetSlivers(data):
 """
 def GetSlivers(data):
-    global ifaces
-    ifaces = sioc.gifconf()
+    global ifaces, old_ifaces
+    ifaces = old_ifaces = sioc.gifconf()
 
     for sliver in data['slivers']:
         attrs = {}
         for attribute in sliver['attributes']:
             attrs[attribute['name']] = attribute['value']
 
     for sliver in data['slivers']:
         attrs = {}
         for attribute in sliver['attributes']:
             attrs[attribute['name']] = attribute['value']
-        if 'netns' in attrs and 'egre_key' in attrs and 'topo_rspec' in attrs:
-            if attrs['netns'] > 0:
-                logger.log("Update topology for slice %s" % sliver['name'])
-                update(sliver['name'], data['node_id'], 
-                       attrs['topo_rspec'], attrs['egre_key'])
+        if 'netns' in attrs:
+            netns = int(attrs['netns'])
+            writeConf(sliver['name'], netns)
+        else:
+            netns = 0
+
+        try:
+            if vserver.VServer(sliver['name']).is_running():
+                if 'egre_key' in attrs and 'topo_rspec' in attrs:
+                    logger.log("topo: Update topology for slice %s" % \
+                                   sliver['name'])
+                    update(sliver['name'], data['node_id'], 
+                           attrs['topo_rspec'], attrs['egre_key'], netns)
+        except:
+            logger.log("topo: sliver %s not running yet. Deferring." % \
+                           sliver['name'])
+
+    clean_up_old_virtual_links()
+