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 # query running network interfaces
22 ips = dict(zip(devs.values(), devs.keys()))
25 macs[sioc.gifhwaddr(dev).lower()] = dev
27 # XXX Exempt Internet2 destinations from node bwlimits
28 # bwlimit.exempt_init('Internet2', internet2_ips)
29 for network in data['networks']:
30 # Get interface name preferably from MAC address, falling
33 if hwaddr <> None: hwaddr=hwaddr.lower()
35 dev = macs[network['mac']]
36 elif network['ip'] in ips:
37 dev = ips[network['ip']]
39 logger.log('%s: no such interface with address %s/%s' % (network['hostname'], network['ip'], network['mac']))
42 # Get current node cap
44 old_bwlimit = bwlimit.get_bwcap(dev)
48 # Get desired node cap
49 if network['bwlimit'] is None or network['bwlimit'] < 0:
50 new_bwlimit = bwlimit.bwmax
52 new_bwlimit = network['bwlimit']
54 if old_bwlimit != new_bwlimit:
55 # Reinitialize bandwidth limits
56 bwlimit.init(dev, new_bwlimit)
58 # XXX This should trigger an rspec refresh in case
59 # some previously invalid sliver bwlimit is now valid
60 # again, or vice-versa.
62 def InitI2(plc, data):
63 if "Internet2" in data['groups']:
64 logger.log("This is an Internet2 node. Setting rules.")
66 i2nodeids = plc.GetNodeGroups(["Internet2"])[0]['node_ids']
67 for node in plc.GetNodeNetworks({"node_id": i2nodeids}, ["ip"]):
69 i2nodes.append(node['ip'])
70 # this will create the set if it doesn't already exist
71 # and add IPs that don't exist in the set rather than
72 # just recreateing the set.
73 bwlimit.exempt_init('Internet2', i2nodes)
75 # set the iptables classification rule if it doesnt exist.
76 cmd = '-A POSTROUTING -m set --set Internet2 dst -j CLASSIFY --set-class 0001:2000 --add-mark'
78 ipt = os.popen("/sbin/iptables-save")
79 for line in ipt.readlines(): rules.append(line.strip(" \n"))
82 logger.verbose("net: Adding iptables rule for Internet2")
83 os.popen("/sbin/iptables -t mangle " + cmd)
85 def InitNAT(plc, data):
86 # query running network interfaces
88 ips = dict(zip(devs.values(), devs.keys()))
91 macs[sioc.gifhwaddr(dev).lower()] = dev
93 ipt = iptables.IPTables()
94 for network in data['networks']:
95 # Get interface name preferably from MAC address, falling
98 if hwaddr <> None: hwaddr=hwaddr.lower()
100 dev = macs[network['mac']]
101 elif network['ip'] in ips:
102 dev = ips[network['ip']]
104 logger.log('%s: no such interface with address %s/%s' % (network['hostname'], network['ip'], network['mac']))
108 settings = plc.GetNodeNetworkSettings({'nodenetwork_setting_id': network['nodenetwork_setting_ids']})
112 for setting in settings:
113 if setting['category'].upper() != 'FIREWALL':
115 if setting['name'].upper() == 'EXTERNAL':
116 # Enable NAT for this interface
118 elif setting['name'].upper() == 'INTERNAL':
120 elif setting['name'].upper() == 'PF': # XXX Uglier code is hard to find...
121 for pf in setting['value'].split("\n"):
123 for field in pf.split(","):
124 (key, val) = field.split("=", 2)
126 if 'new_dport' not in fields:
127 fields['new_dport'] = fields['dport']
128 if 'source' not in fields:
129 fields['source'] = "0.0.0.0/0"
133 def InitInterfaces(plc, data):
134 sysconfig = "/etc/sysconfig/network-scripts"
136 # query running network interfaces
137 devs = sioc.gifconf()
138 ips = dict(zip(devs.values(), devs.keys()))
141 macs[sioc.gifhwaddr(dev).lower()] = dev
143 # assume data['networks'] contains this node's NodeNetworks
146 hostname = data.get('hostname',socket.gethostname())
147 networks = data.get('networks',())
148 failedToGetSettings = False
149 for network in networks:
150 logger.log('interface %d: %s'%(interface,network))
151 logger.log('macs = %s' % macs)
152 logger.log('ips = %s' % ips)
153 # Get interface name preferably from MAC address, falling back
155 hwaddr=network['mac']
156 if hwaddr <> None: hwaddr=hwaddr.lower()
158 orig_ifname = macs[hwaddr]
159 elif network['ip'] in ips:
160 orig_ifname = ips[network['ip']]
165 logger.log('orig_ifname = %s' % orig_ifname)
168 inter['ONBOOT']='yes'
169 inter['USERCTL']='no'
171 inter['HWADDR'] = network['mac']
173 if network['method'] == "static":
174 inter['BOOTPROTO'] = "static"
175 inter['IPADDR'] = network['ip']
176 inter['NETMASK'] = network['netmask']
178 elif network['method'] == "dhcp":
179 inter['BOOTPROTO'] = "dhcp"
180 if network['hostname']:
181 inter['DHCP_HOSTNAME'] = network['hostname']
183 inter['DHCP_HOSTNAME'] = hostname
184 if not network['is_primary']:
185 inter['DHCLIENTARGS'] = "-R subnet-mask"
187 if len(network['nodenetwork_setting_ids']) > 0:
189 settings = plc.GetNodeNetworkSettings({'nodenetwork_setting_id':
190 network['nodenetwork_setting_ids']})
192 logger.log("FATAL: failed call GetNodeNetworkSettings({'nodenetwork_setting_id':{%s})"% \
193 network['nodenetwork_setting_ids'])
194 failedToGetSettings = True
195 continue # on to the next network
197 for setting in settings:
198 # to explicitly set interface name
199 settingname = setting['name'].upper()
200 if settingname in ('IFNAME','ALIAS','CFGOPTIONS','DRIVER'):
201 inter[settingname]=setting['value']
203 logger.log("WARNING: ignored setting named %s"%setting['name'])
205 # support aliases to interfaces either by name or HWADDR
207 if 'HWADDR' in inter:
208 hwaddr = inter['HWADDR'].lower()
211 hwifname = macs[hwaddr]
212 if ('IFNAME' in inter) and inter['IFNAME'] <> hwifname:
213 logger.log("WARNING: alias ifname (%s) and hwaddr ifname (%s) do not match"%\
214 (inter['IFNAME'],hwifname))
215 inter['IFNAME'] = hwifname
217 logger.log('WARNING: mac addr %s for alias not found' %(hwaddr,alias))
219 if 'IFNAME' in inter:
220 # stupid RH /etc/sysconfig/network-scripts/ifup-aliases:new_interface()
221 # checks if the "$DEVNUM" only consists of '^[0-9A-Za-z_]*$'. Need to make
222 # our aliases compliant.
223 parts = inter['ALIAS'].split('_')
226 isValid=isValid and part.isalnum()
229 interfaces["%s:%s" % (inter['IFNAME'],inter['ALIAS'])] = inter
231 logger.log("WARNING: interface alias (%s) not a valid string for RH ifup-aliases"% inter['ALIAS'])
233 logger.log("WARNING: interface alias (%s) not matched to an interface"% inter['ALIAS'])
236 if ('IFNAME' not in inter) and not orig_ifname:
237 ifname="eth%d" % (interface-1)
238 # should check if $ifname is an eth already defines
239 if os.path.exists("%s/ifcfg-%s"%(sysconfig,ifname)):
240 logger.log("WARNING: possibly blowing away %s configuration"%ifname)
242 if ('IFNAME' not in inter) and orig_ifname:
245 ifname = inter['IFNAME']
247 interfaces[ifname] = inter
249 m = modprobe.Modprobe()
250 m.input("/etc/modprobe.conf")
251 for (dev, inter) in interfaces.iteritems():
252 # get the driver string "moduleName option1=a option2=b"
253 driver=inter.get('DRIVER','')
255 driver=driver.split()
256 kernelmodule=driver[0]
257 m.aliasset(dev,kernelmodule)
258 options=" ".join(driver[1:])
260 m.optionsset(dev,options)
261 m.output("/etc/modprobe.conf")
263 # clean up after any ifcfg-$dev script that's no longer listed as
264 # part of the NodeNetworks associated with this node
266 # list all network-scripts
267 files = os.listdir(sysconfig)
269 # filter out the ifcfg-* files
272 if f.find("ifcfg-") == 0:
275 # remove loopback (lo) from ifcfgs list
277 if lo in ifcfgs: ifcfgs.remove(lo)
279 # remove known devices from icfgs list
280 for (dev, inter) in interfaces.iteritems():
282 if ifcfg in ifcfgs: ifcfgs.remove(ifcfg)
284 # delete the remaining ifcfgs from
285 deletedSomething = False
287 if not failedToGetSettings:
289 dev = ifcfg[len('ifcfg-'):]
290 path = "%s/ifcfg-%s" % (sysconfig,dev)
291 logger.log("removing %s %s"%(dev,path))
292 ifdown = os.popen("/sbin/ifdown %s" % dev)
294 deletedSomething=True
297 # wait a bit for the one or more ifdowns to have taken effect
301 # Process ifcg-$dev changes / additions
303 for (dev, inter) in interfaces.iteritems():
305 f = file(tmpnam, "w")
306 f.write("# Autogenerated by NodeManager/net.py.... do not edit!\n")
307 if 'DRIVER' in inter:
308 f.write("# using %s driver for device %s\n" % (inter['DRIVER'],dev))
309 f.write('DEVICE="%s"\n' % dev)
311 # print the configuration values
312 for (key, val) in inter.iteritems():
313 if key not in ('IFNAME','ALIAS','CFGOPTIONS','DRIVER'):
314 f.write('%s="%s"\n' % (key, val))
316 # print the configuration specific option values (if any)
317 if 'CFGOPTIONS' in inter:
318 cfgoptions = inter['CFGOPTIONS']
319 f.write('#CFGOPTIONS are %s\n' % cfgoptions)
320 for cfgoption in cfgoptions.split():
321 key,val = cfgoption.split('=')
325 f.write('%s="%s"\n' % (key,val))
328 # compare whether two files are the same
329 def comparefiles(a,b):
331 logger.log("comparing %s with %s" % (a,b))
332 if not os.path.exists(a): return False
337 if not os.path.exists(b): return False
342 return buf_a == buf_b
346 path = "%s/ifcfg-%s" % (sysconfig,dev)
347 if not os.path.exists(path):
348 logger.log('adding configuration for %s' % dev)
349 # add ifcfg-$dev configuration file
350 os.rename(tmpnam,path)
354 elif not comparefiles(tmpnam,path):
355 logger.log('Configuration change for %s' % dev)
356 logger.log('ifdown %s' % dev)
357 # invoke ifdown for the old configuration
358 p = os.popen("/sbin/ifdown %s" % dev)
360 # wait a few secs for ifdown to complete
363 logger.log('replacing configuration for %s' % dev)
364 # replace ifcfg-$dev configuration file
365 os.rename(tmpnam,path)
369 # tmpnam & path are identical
374 fb = file("%s/ifcfg-%s"%(sysconfig,dev),"r")
375 for line in fb.readlines():
377 if parts[0][0]=="#":continue
378 if parts[0].find('='):
379 name,value = parts[0].split('=')
380 # clean up name & value
382 value = value.strip()
383 value = value.strip("'")
384 value = value.strip('"')
385 cfgvariables[name]=value
389 if name in cfgvariables:
390 value=cfgvariables[name]
391 value = value.lower()
395 # skip over device configs with ONBOOT=no
396 if getvar("ONBOOT") == 'no': continue
398 # don't bring up slave devices, the network scripts will
399 # handle those correctly
400 if getvar("SLAVE") == 'yes': continue
402 logger.log('bringing up %s' % dev)
403 p = os.popen("/sbin/ifup %s" % dev)
407 def start(options, config):