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