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