Use pyplnet.
[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 import plnet
13
14 def GetSlivers(plc, data):
15     InitInterfaces(plc, data)
16     InitNodeLimit(data)
17     InitI2(plc, data)
18     InitNAT(plc, data)
19
20 def InitNodeLimit(data):
21     # query running network interfaces
22     devs = sioc.gifconf()
23     ips = dict(zip(devs.values(), devs.keys()))
24     macs = {}
25     for dev in devs:
26         macs[sioc.gifhwaddr(dev).lower()] = dev
27
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'].lower()):
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.GetInterfaceTags({'interface_tag_id': network['interface_tag_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 InitInterfaces(plc, data):
129     if not 'networks' in data:
130         return
131     plnet.InitInterfaces(logger, plc, data)
132
133 def start(options, config):
134     pass