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