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