5 """network configuration"""
7 # system provided modules
8 import os, string, time, socket, modprobe
11 import sioc, bwlimit, logger, iptables
13 def GetSlivers(plc, data):
14 InitInterfaces(plc, data)
19 def InitNodeLimit(data):
20 if not 'networks' in data: return
22 # query running network interfaces
24 ips = dict(zip(devs.values(), devs.keys()))
27 macs[sioc.gifhwaddr(dev).lower()] = dev
29 # XXX Exempt Internet2 destinations from node bwlimits
30 # bwlimit.exempt_init('Internet2', internet2_ips)
31 for network in data['networks']:
32 # Get interface name preferably from MAC address, falling
35 if hwaddr <> None: hwaddr=hwaddr.lower()
37 dev = macs[network['mac']]
38 elif network['ip'] in ips:
39 dev = ips[network['ip']]
41 logger.log('%s: no such interface with address %s/%s' % (network['hostname'], network['ip'], network['mac']))
44 # Get current node cap
46 old_bwlimit = bwlimit.get_bwcap(dev)
50 # Get desired node cap
51 if network['bwlimit'] is None or network['bwlimit'] < 0:
52 new_bwlimit = bwlimit.bwmax
54 new_bwlimit = network['bwlimit']
56 if old_bwlimit != new_bwlimit:
57 # Reinitialize bandwidth limits
58 bwlimit.init(dev, new_bwlimit)
60 # XXX This should trigger an rspec refresh in case
61 # some previously invalid sliver bwlimit is now valid
62 # again, or vice-versa.
64 def InitI2(plc, data):
65 if not 'groups' in data: return
67 if "Internet2" in data['groups']:
68 logger.log("This is an Internet2 node. Setting rules.")
70 i2nodeids = plc.GetNodeGroups(["Internet2"])[0]['node_ids']
71 for node in plc.GetNodeNetworks({"node_id": i2nodeids}, ["ip"]):
73 i2nodes.append(node['ip'])
74 # this will create the set if it doesn't already exist
75 # and add IPs that don't exist in the set rather than
76 # just recreateing the set.
77 bwlimit.exempt_init('Internet2', i2nodes)
79 # set the iptables classification rule if it doesnt exist.
80 cmd = '-A POSTROUTING -m set --set Internet2 dst -j CLASSIFY --set-class 0001:2000 --add-mark'
82 ipt = os.popen("/sbin/iptables-save")
83 for line in ipt.readlines(): rules.append(line.strip(" \n"))
86 logger.verbose("net: Adding iptables rule for Internet2")
87 os.popen("/sbin/iptables -t mangle " + cmd)
89 def InitNAT(plc, data):
90 if not 'networks' in data: return
92 # query running network interfaces
94 ips = dict(zip(devs.values(), devs.keys()))
97 macs[sioc.gifhwaddr(dev).lower()] = dev
99 ipt = iptables.IPTables()
100 for network in data['networks']:
101 # Get interface name preferably from MAC address, falling
102 # back on IP address.
103 hwaddr=network['mac']
104 if hwaddr <> None: hwaddr=hwaddr.lower()
106 dev = macs[network['mac']]
107 elif network['ip'] in ips:
108 dev = ips[network['ip']]
110 logger.log('%s: no such interface with address %s/%s' % (network['hostname'], network['ip'], network['mac']))
114 settings = plc.GetNodeNetworkSettings({'nodenetwork_setting_id': network['nodenetwork_setting_ids']})
118 for setting in settings:
119 if setting['category'].upper() != 'FIREWALL':
121 if setting['name'].upper() == 'EXTERNAL':
122 # Enable NAT for this interface
124 elif setting['name'].upper() == 'INTERNAL':
126 elif setting['name'].upper() == 'PF': # XXX Uglier code is hard to find...
127 for pf in setting['value'].split("\n"):
129 for field in pf.split(","):
130 (key, val) = field.split("=", 2)
132 if 'new_dport' not in fields:
133 fields['new_dport'] = fields['dport']
134 if 'source' not in fields:
135 fields['source'] = "0.0.0.0/0"
139 def InitInterfaces(plc, data):
140 if not 'networks' in data: return
142 sysconfig = "/etc/sysconfig/network-scripts"
144 # query running network interfaces
145 devs = sioc.gifconf()
146 ips = dict(zip(devs.values(), devs.keys()))
149 macs[sioc.gifhwaddr(dev).lower()] = dev
151 # assume data['networks'] contains this node's NodeNetworks
154 hostname = data.get('hostname',socket.gethostname())
155 networks = data['networks']
156 failedToGetSettings = False
157 for network in networks:
158 logger.verbose('net:InitInterfaces interface %d: %s'%(interface,network))
159 logger.verbose('net:InitInterfaces macs = %s' % macs)
160 logger.verbose('net:InitInterfaces ips = %s' % ips)
161 # Get interface name preferably from MAC address, falling back
163 hwaddr=network['mac']
164 if hwaddr <> None: hwaddr=hwaddr.lower()
166 orig_ifname = macs[hwaddr]
167 elif network['ip'] in ips:
168 orig_ifname = ips[network['ip']]
173 logger.verbose('net:InitInterfaces orig_ifname = %s' % orig_ifname)
176 inter['ONBOOT']='yes'
177 inter['USERCTL']='no'
179 inter['HWADDR'] = network['mac']
181 if network['method'] == "static":
182 inter['BOOTPROTO'] = "static"
183 inter['IPADDR'] = network['ip']
184 inter['NETMASK'] = network['netmask']
186 elif network['method'] == "dhcp":
187 inter['BOOTPROTO'] = "dhcp"
188 if network['hostname']:
189 inter['DHCP_HOSTNAME'] = network['hostname']
191 inter['DHCP_HOSTNAME'] = hostname
192 if not network['is_primary']:
193 inter['DHCLIENTARGS'] = "-R subnet-mask"
195 if len(network['nodenetwork_setting_ids']) > 0:
197 settings = plc.GetNodeNetworkSettings({'nodenetwork_setting_id':
198 network['nodenetwork_setting_ids']})
200 logger.log("net:InitInterfaces FATAL: failed call GetNodeNetworkSettings({'nodenetwork_setting_id':{%s})"% \
201 network['nodenetwork_setting_ids'])
202 failedToGetSettings = True
203 continue # on to the next network
205 for setting in settings:
206 # to explicitly set interface name
207 settingname = setting['name'].upper()
208 if settingname in ('IFNAME','ALIAS','CFGOPTIONS','DRIVER'):
209 inter[settingname]=setting['value']
211 logger.log("net:InitInterfaces WARNING: ignored setting named %s"%setting['name'])
213 # support aliases to interfaces either by name or HWADDR
215 if 'HWADDR' in inter:
216 hwaddr = inter['HWADDR'].lower()
219 hwifname = macs[hwaddr]
220 if ('IFNAME' in inter) and inter['IFNAME'] <> hwifname:
221 logger.log("net:InitInterfaces WARNING: alias ifname (%s) and hwaddr ifname (%s) do not match"%\
222 (inter['IFNAME'],hwifname))
223 inter['IFNAME'] = hwifname
225 logger.log('net:InitInterfaces WARNING: mac addr %s for alias not found' %(hwaddr,alias))
227 if 'IFNAME' in inter:
228 # stupid RH /etc/sysconfig/network-scripts/ifup-aliases:new_interface()
229 # checks if the "$DEVNUM" only consists of '^[0-9A-Za-z_]*$'. Need to make
230 # our aliases compliant.
231 parts = inter['ALIAS'].split('_')
234 isValid=isValid and part.isalnum()
237 interfaces["%s:%s" % (inter['IFNAME'],inter['ALIAS'])] = inter
239 logger.log("net:InitInterfaces WARNING: interface alias (%s) not a valid string for RH ifup-aliases"% inter['ALIAS'])
241 logger.log("net:InitInterfaces WARNING: interface alias (%s) not matched to an interface"% inter['ALIAS'])
244 if ('IFNAME' not in inter) and not orig_ifname:
245 ifname="eth%d" % (interface-1)
246 # should check if $ifname is an eth already defines
247 if os.path.exists("%s/ifcfg-%s"%(sysconfig,ifname)):
248 logger.log("net:InitInterfaces WARNING: possibly blowing away %s configuration"%ifname)
250 if ('IFNAME' not in inter) and orig_ifname:
253 ifname = inter['IFNAME']
255 interfaces[ifname] = inter
257 m = modprobe.Modprobe()
258 m.input("/etc/modprobe.conf")
259 for (dev, inter) in interfaces.iteritems():
260 # get the driver string "moduleName option1=a option2=b"
261 driver=inter.get('DRIVER','')
263 driver=driver.split()
264 kernelmodule=driver[0]
265 m.aliasset(dev,kernelmodule)
266 options=" ".join(driver[1:])
268 m.optionsset(dev,options)
269 m.output("/etc/modprobe.conf")
271 # clean up after any ifcfg-$dev script that's no longer listed as
272 # part of the NodeNetworks associated with this node
274 # list all network-scripts
275 files = os.listdir(sysconfig)
277 # filter out the ifcfg-* files
280 if f.find("ifcfg-") == 0:
283 # remove loopback (lo) from ifcfgs list
285 if lo in ifcfgs: ifcfgs.remove(lo)
287 # remove known devices from icfgs list
288 for (dev, inter) in interfaces.iteritems():
290 if ifcfg in ifcfgs: ifcfgs.remove(ifcfg)
292 # delete the remaining ifcfgs from
293 deletedSomething = False
295 if not failedToGetSettings:
297 dev = ifcfg[len('ifcfg-'):]
298 path = "%s/ifcfg-%s" % (sysconfig,dev)
299 logger.verbose("net:InitInterfaces removing %s %s"%(dev,path))
300 ifdown = os.popen("/sbin/ifdown %s" % dev)
302 deletedSomething=True
305 # wait a bit for the one or more ifdowns to have taken effect
309 # Process ifcg-$dev changes / additions
311 for (dev, inter) in interfaces.iteritems():
313 f = file(tmpnam, "w")
314 f.write("# Autogenerated by NodeManager/net.py.... do not edit!\n")
315 if 'DRIVER' in inter:
316 f.write("# using %s driver for device %s\n" % (inter['DRIVER'],dev))
317 f.write('DEVICE="%s"\n' % dev)
319 # print the configuration values
320 for (key, val) in inter.iteritems():
321 if key not in ('IFNAME','ALIAS','CFGOPTIONS','DRIVER'):
322 f.write('%s="%s"\n' % (key, val))
324 # print the configuration specific option values (if any)
325 if 'CFGOPTIONS' in inter:
326 cfgoptions = inter['CFGOPTIONS']
327 f.write('#CFGOPTIONS are %s\n' % cfgoptions)
328 for cfgoption in cfgoptions.split():
329 key,val = cfgoption.split('=')
333 f.write('%s="%s"\n' % (key,val))
336 # compare whether two files are the same
337 def comparefiles(a,b):
339 logger.verbose("net:InitInterfaces comparing %s with %s" % (a,b))
340 if not os.path.exists(a): return False
345 if not os.path.exists(b): return False
350 return buf_a == buf_b
354 path = "%s/ifcfg-%s" % (sysconfig,dev)
355 if not os.path.exists(path):
356 logger.verbose('net:InitInterfaces adding configuration for %s' % dev)
357 # add ifcfg-$dev configuration file
358 os.rename(tmpnam,path)
362 elif not comparefiles(tmpnam,path):
363 logger.verbose('net:InitInterfaces Configuration change for %s' % dev)
364 logger.verbose('net:InitInterfaces ifdown %s' % dev)
365 # invoke ifdown for the old configuration
366 p = os.popen("/sbin/ifdown %s" % dev)
368 # wait a few secs for ifdown to complete
371 logger.log('replacing configuration for %s' % dev)
372 # replace ifcfg-$dev configuration file
373 os.rename(tmpnam,path)
377 # tmpnam & path are identical
382 fb = file("%s/ifcfg-%s"%(sysconfig,dev),"r")
383 for line in fb.readlines():
385 if parts[0][0]=="#":continue
386 if parts[0].find('='):
387 name,value = parts[0].split('=')
388 # clean up name & value
390 value = value.strip()
391 value = value.strip("'")
392 value = value.strip('"')
393 cfgvariables[name]=value
397 if name in cfgvariables:
398 value=cfgvariables[name]
399 value = value.lower()
403 # skip over device configs with ONBOOT=no
404 if getvar("ONBOOT") == 'no': continue
406 # don't bring up slave devices, the network scripts will
407 # handle those correctly
408 if getvar("SLAVE") == 'yes': continue
410 logger.verbose('net:InitInterfaces bringing up %s' % dev)
411 p = os.popen("/sbin/ifup %s" % dev)
415 def start(options, config):