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