Simple module for toggling network namespaces based on slice attributes
[nodemanager.git] / net.py
1 #
2 # $Id$
3 #
4
5 """network configuration"""
6
7 import sioc
8 import bwlimit
9 import logger
10 import string
11 import iptables
12 import os
13
14 def GetSlivers(plc, data):
15     InitNodeLimit(data)
16     InitI2(plc, data)
17     InitNAT(plc, data)
18
19 def InitNodeLimit(data):
20     # query running network interfaces
21     devs = sioc.gifconf()
22     ips = dict(zip(devs.values(), devs.keys()))
23     macs = {}
24     for dev in devs:
25         macs[sioc.gifhwaddr(dev).lower()] = dev
26
27     # XXX Exempt Internet2 destinations from node bwlimits
28     # bwlimit.exempt_init('Internet2', internet2_ips)
29     for network in data['networks']:
30         # Get interface name preferably from MAC address, falling
31         # back on IP address.
32         if macs.has_key(network['mac']):
33             dev = macs[network['mac'].lower()]
34         elif ips.has_key(network['ip']):
35             dev = ips[network['ip']]
36         else:
37             logger.log('%s: no such interface with address %s/%s' % (network['hostname'], network['ip'], network['mac']))
38             continue
39
40         # Get current node cap
41         try:
42             old_bwlimit = bwlimit.get_bwcap(dev)
43         except:
44             old_bwlimit = None
45
46         # Get desired node cap
47         if network['bwlimit'] is None or network['bwlimit'] < 0:
48             new_bwlimit = bwlimit.bwmax
49         else:
50             new_bwlimit = network['bwlimit']
51
52         if old_bwlimit != new_bwlimit:
53             # Reinitialize bandwidth limits
54             bwlimit.init(dev, new_bwlimit)
55
56             # XXX This should trigger an rspec refresh in case
57             # some previously invalid sliver bwlimit is now valid
58             # again, or vice-versa.
59
60 def InitI2(plc, data):
61     if "Internet2" in data['groups']:
62         logger.log("This is an Internet2 node.  Setting rules.")
63         i2nodes = []
64         i2nodeids = plc.GetNodeGroups(["Internet2"])[0]['node_ids']
65         for node in plc.GetNodeNetworks({"node_id": i2nodeids}, ["ip"]):
66             # Get the IPs
67             i2nodes.append(node['ip'])
68         # this will create the set if it doesn't already exist
69         # and add IPs that don't exist in the set rather than
70         # just recreateing the set.
71         bwlimit.exempt_init('Internet2', i2nodes)
72         
73         # set the iptables classification rule if it doesnt exist.
74         cmd = '-A POSTROUTING -m set --set Internet2 dst -j CLASSIFY --set-class 0001:2000 --add-mark'
75         rules = []
76         ipt = os.popen("/sbin/iptables-save")
77         for line in ipt.readlines(): rules.append(line.strip(" \n"))
78         ipt.close()
79         if cmd not in rules:
80             logger.verbose("net:  Adding iptables rule for Internet2")
81             os.popen("/sbin/iptables -t mangle " + cmd)
82
83 def InitNAT(plc, data):
84     # query running network interfaces
85     devs = sioc.gifconf()
86     ips = dict(zip(devs.values(), devs.keys()))
87     macs = {}
88     for dev in devs:
89         macs[sioc.gifhwaddr(dev).lower()] = dev
90
91     ipt = iptables.IPTables()
92     for network in data['networks']:
93         # Get interface name preferably from MAC address, falling
94         # back on IP address.
95         if macs.has_key(network['mac']):
96             dev = macs[network['mac'].lower()]
97         elif ips.has_key(network['ip']):
98             dev = ips[network['ip']]
99         else:
100             logger.log('%s: no such interface with address %s/%s' % (network['hostname'], network['ip'], network['mac']))
101             continue
102
103         try:
104             settings = plc.GetNodeNetworkSettings({'nodenetwork_setting_id': network['nodenetwork_setting_ids']})
105         except:
106             continue
107         # XXX arbitrary names
108         for setting in settings:
109             if setting['category'].upper() != 'FIREWALL':
110                 continue
111             if setting['name'].upper() == 'EXTERNAL':
112                 # Enable NAT for this interface
113                 ipt.add_ext(dev)
114             elif setting['name'].upper() == 'INTERNAL':
115                 ipt.add_int(dev)
116             elif setting['name'].upper() == 'PF': # XXX Uglier code is hard to find...
117                 for pf in setting['value'].split("\n"):
118                     fields = {}
119                     for field in pf.split(","):
120                         (key, val) = field.split("=", 2)
121                         fields[key] = val
122                     if 'new_dport' not in fields:
123                         fields['new_dport'] = fields['dport']
124                     if 'source' not in fields:
125                         fields['source'] = "0.0.0.0/0"
126                     ipt.add_pf(fields)
127     ipt.commit()
128
129 def start(options, config):
130     pass