]>
git.proxmox.com Git - mirror_ovs.git/blob - xenserver/opt_xensource_libexec_interface-reconfigure
3 # Copyright (c) Citrix Systems 2008. All rights reserved.
4 # Copyright (c) 2009 Nicira Networks.
8 %(command-name)s --session <SESSION-REF> --pif <PIF-REF> [up|down|rewrite]
9 %(command-name)s --force <BRIDGE> [up|down|rewrite <CONFIG>]
10 %(command-name)s --force all down
13 <CONFIG> = --device=<INTERFACE> --mode=dhcp
14 <CONFIG> = --device=<INTERFACE> --mode=static --ip=<IPADDR> --netmask=<NM> [--gateway=<GW>]
17 --session A session reference to use to access the xapi DB
18 --pif A PIF reference.
19 --force-interface An interface name. Mutually exclusive with --session/--pif.
21 Either both --session and --pif or just --pif-uuid.
23 <ACTION> is either "up" or "down" or "rewrite"
27 # Undocumented parameters for test & dev:
29 # --output-directory=<DIR> Write configuration to <DIR>. Also disables actually
30 # raising/lowering the interfaces
31 # --pif-uuid A PIF UUID, use instead of --session/--pif.
36 # 1. Every pif belongs to exactly one network
37 # 2. Every network has zero or one pifs
38 # 3. A network may have an associated bridge, allowing vifs to be attached
39 # 4. A network may be bridgeless (there's no point having a bridge over a storage pif)
41 # XXX: --force-interface=all down
43 # XXX: --force-interface rewrite
45 # XXX: Sometimes this leaves "orphaned" datapaths, e.g. a datapath whose
46 # only port is the local port. Should delete those.
48 # XXX: This can leave crud in ovs-vswitchd.conf in this scenario:
49 # - Create bond in XenCenter.
50 # - Create VLAN on bond in XenCenter.
51 # - Attempt to delete bond in XenCenter (this will fail because there
52 # is a VLAN on the bond, although the error may not be reported
53 # until the next step)
54 # - Delete VLAN in XenCenter.
55 # - Delete bond in XenCenter.
56 # At this point there will still be some configuration data for the bond
57 # or the VLAN in ovs-vswitchd.conf.
60 import os
, sys
, getopt
, time
, signal
67 output_directory
= None
72 dbcache_file
= "/etc/ovs-vswitch.dbcache"
73 vswitch_config_dir
= "/etc/openvswitch"
75 class Usage(Exception):
76 def __init__(self
, msg
):
77 Exception.__init
__(self
)
80 class Error(Exception):
81 def __init__(self
, msg
):
82 Exception.__init
__(self
)
85 class ConfigurationFile(object):
86 """Write a file, tracking old and new versions.
88 Supports writing a new version of a file and applying and
89 reverting those changes.
92 __STATE
= {"OPEN":"OPEN",
93 "NOT-APPLIED":"NOT-APPLIED", "APPLIED":"APPLIED",
94 "REVERTED":"REVERTED", "COMMITTED": "COMMITTED"}
96 def __init__(self
, fname
, path
="/etc/sysconfig/network-scripts"):
98 self
.__state
= self
.__STATE
['OPEN']
103 dirname
= output_directory
107 self
.__path
= os
.path
.join(dirname
, fname
)
108 self
.__oldpath
= os
.path
.join(dirname
, "." + fname
+ ".xapi-old")
109 self
.__newpath
= os
.path
.join(dirname
, "." + fname
+ ".xapi-new")
110 self
.__unlink
= False
112 self
.__f
= open(self
.__newpath
, "w")
114 def attach_child(self
, child
):
115 self
.__children
.append(child
)
122 return open(self
.path()).readlines()
126 def write(self
, args
):
127 if self
.__state
!= self
.__STATE
['OPEN']:
128 raise Error("Attempt to write to file in state %s" % self
.__state
)
132 if self
.__state
!= self
.__STATE
['OPEN']:
133 raise Error("Attempt to unlink file in state %s" % self
.__state
)
136 self
.__state
= self
.__STATE
['NOT-APPLIED']
139 if self
.__state
!= self
.__STATE
['OPEN']:
140 raise Error("Attempt to close file in state %s" % self
.__state
)
143 self
.__state
= self
.__STATE
['NOT-APPLIED']
146 if self
.__state
!= self
.__STATE
['NOT-APPLIED']:
147 raise Error("Attempt to compare file in state %s" % self
.__state
)
152 if self
.__state
!= self
.__STATE
['NOT-APPLIED']:
153 raise Error("Attempt to apply configuration from state %s" % self
.__state
)
155 for child
in self
.__children
:
158 log("Applying changes to %s configuration" % self
.__fname
)
160 # Remove previous backup.
161 if os
.access(self
.__oldpath
, os
.F_OK
):
162 os
.unlink(self
.__oldpath
)
164 # Save current configuration.
165 if os
.access(self
.__path
, os
.F_OK
):
166 os
.link(self
.__path
, self
.__oldpath
)
167 os
.unlink(self
.__path
)
169 # Apply new configuration.
170 assert(os
.path
.exists(self
.__newpath
))
171 if not self
.__unlink
:
172 os
.link(self
.__newpath
, self
.__path
)
174 pass # implicit unlink of original file
176 # Remove temporary file.
177 os
.unlink(self
.__newpath
)
179 self
.__state
= self
.__STATE
['APPLIED']
182 if self
.__state
!= self
.__STATE
['APPLIED']:
183 raise Error("Attempt to revert configuration from state %s" % self
.__state
)
185 for child
in self
.__children
:
188 log("Reverting changes to %s configuration" % self
.__fname
)
190 # Remove existing new configuration
191 if os
.access(self
.__newpath
, os
.F_OK
):
192 os
.unlink(self
.__newpath
)
194 # Revert new configuration.
195 if os
.access(self
.__path
, os
.F_OK
):
196 os
.link(self
.__path
, self
.__newpath
)
197 os
.unlink(self
.__path
)
199 # Revert to old configuration.
200 if os
.access(self
.__oldpath
, os
.F_OK
):
201 os
.link(self
.__oldpath
, self
.__path
)
202 os
.unlink(self
.__oldpath
)
204 # Leave .*.xapi-new as an aid to debugging.
206 self
.__state
= self
.__STATE
['REVERTED']
209 if self
.__state
!= self
.__STATE
['APPLIED']:
210 raise Error("Attempt to commit configuration from state %s" % self
.__state
)
212 for child
in self
.__children
:
215 log("Committing changes to %s configuration" % self
.__fname
)
217 if os
.access(self
.__oldpath
, os
.F_OK
):
218 os
.unlink(self
.__oldpath
)
219 if os
.access(self
.__newpath
, os
.F_OK
):
220 os
.unlink(self
.__newpath
)
222 self
.__state
= self
.__STATE
['COMMITTED']
225 return output_directory
is not None
229 print >>sys
.stderr
, s
233 def check_allowed(pif
):
234 pifrec
= db
.get_pif_record(pif
)
236 f
= open("/proc/ardence")
237 macline
= filter(lambda x
: x
.startswith("HWaddr:"), f
.readlines())
239 if len(macline
) == 1:
240 p
= re
.compile(".*\s%(MAC)s\s.*" % pifrec
, re
.IGNORECASE
)
241 if p
.match(macline
[0]):
242 log("Skipping PVS device %(device)s (%(MAC)s)" % pifrec
)
248 def interface_exists(i
):
249 return os
.path
.exists("/sys/class/net/" + i
)
251 class DatabaseCache(object):
252 def __init__(self
, session_ref
=None, cache_file
=None):
253 if session_ref
and cache_file
:
254 raise Error("can't specify session reference and cache file")
256 if cache_file
== None:
257 session
= XenAPI
.xapi_local()
260 log("No session ref given on command line, logging in.")
261 session
.xenapi
.login_with_password("root", "")
263 session
._session
= session_ref
266 self
.__vlans
= session
.xenapi
.VLAN
.get_all_records()
267 self
.__bonds
= session
.xenapi
.Bond
.get_all_records()
268 self
.__pifs
= session
.xenapi
.PIF
.get_all_records()
269 self
.__networks
= session
.xenapi
.network
.get_all_records()
272 session
.xenapi
.session
.logout()
274 log("Loading xapi database cache from %s" % cache_file
)
275 f
= open(cache_file
, 'r')
276 members
= pickle
.load(f
)
277 self
.extras
= pickle
.load(f
)
280 self
.__vlans
= members
['vlans']
281 self
.__bonds
= members
['bonds']
282 self
.__pifs
= members
['pifs']
283 self
.__networks
= members
['networks']
285 def save(self
, cache_file
, extras
):
286 f
= open(cache_file
, 'w')
287 pickle
.dump({'vlans': self
.__vlans
,
288 'bonds': self
.__bonds
,
290 'networks': self
.__networks
}, f
)
291 pickle
.dump(extras
, f
)
294 def get_pif_by_uuid(self
, uuid
):
295 pifs
= map(lambda (ref
,rec
): ref
,
296 filter(lambda (ref
,rec
): uuid
== rec
['uuid'],
297 self
.__pifs
.items()))
299 raise Error("Unknown PIF \"%s\"" % uuid
)
301 raise Error("Non-unique PIF \"%s\"" % uuid
)
305 def get_pifs_by_record(self
, record
):
306 """record is partial pif record.
307 Get the pif(s) whose record matches.
311 if record
[key
] != pifrec
[key
]:
315 return map(lambda (ref
,rec
): ref
,
316 filter(lambda (ref
,rec
): match(rec
),
317 self
.__pifs
.items()))
319 def get_pif_by_record(self
, record
):
320 """record is partial pif record.
321 Get the pif whose record matches.
323 pifs
= self
.get_pifs_by_record(record
)
325 raise Error("No matching PIF \"%s\"" % str(record
))
327 raise Error("Multiple matching PIFs \"%s\"" % str(record
))
331 def get_pif_by_bridge(self
, host
, bridge
):
332 networks
= map(lambda (ref
,rec
): ref
,
333 filter(lambda (ref
,rec
): rec
['bridge'] == bridge
,
334 self
.__networks
.items()))
335 if len(networks
) == 0:
336 raise Error("No matching network \"%s\"")
339 for network
in networks
:
340 nwrec
= self
.get_network_record(network
)
341 for pif
in nwrec
['PIFs']:
342 pifrec
= self
.get_pif_record(pif
)
343 if pifrec
['host'] != host
:
346 raise Error("Multiple PIFs on %s for network %s" % (host
, bridge
))
349 raise Error("No PIF on %s for network %s" % (host
, bridge
))
352 def get_pif_record(self
, pif
):
353 if self
.__pifs
.has_key(pif
):
354 return self
.__pifs
[pif
]
355 raise Error("Unknown PIF \"%s\"" % pif
)
356 def get_all_pifs(self
):
358 def pif_exists(self
, pif
):
359 return self
.__pifs
.has_key(pif
)
361 def get_management_pif(self
, host
):
362 """ Returns the management pif on host
364 all
= self
.get_all_pifs()
366 pifrec
= self
.get_pif_record(pif
)
367 if pifrec
['management'] and pifrec
['host'] == host
:
371 def get_network_record(self
, network
):
372 if self
.__networks
.has_key(network
):
373 return self
.__networks
[network
]
374 raise Error("Unknown network \"%s\"" % network
)
375 def get_all_networks(self
):
376 return self
.__networks
378 def get_bond_record(self
, bond
):
379 if self
.__bonds
.has_key(bond
):
380 return self
.__bonds
[bond
]
384 def get_vlan_record(self
, vlan
):
385 if self
.__vlans
.has_key(vlan
):
386 return self
.__vlans
[vlan
]
390 def bridge_name(pif
):
391 """Return the bridge name associated with pif, or None if network is bridgeless"""
392 pifrec
= db
.get_pif_record(pif
)
393 nwrec
= db
.get_network_record(pifrec
['network'])
396 # TODO: sanity check that nwrec['bridgeless'] != 'true'
397 return nwrec
['bridge']
399 # TODO: sanity check that nwrec['bridgeless'] == 'true'
402 def interface_name(pif
):
403 """Construct an interface name from the given PIF record."""
405 pifrec
= db
.get_pif_record(pif
)
407 if pifrec
['VLAN'] == '-1':
408 return pifrec
['device']
410 return "%(device)s.%(VLAN)s" % pifrec
412 def datapath_name(pif
):
413 """Return the OpenFlow datapath name associated with pif.
414 For a non-VLAN PIF, the datapath name is the bridge name.
415 For a VLAN PIF, the datapath name is the bridge name for the PIF's VLAN slave.
416 (xapi will create a datapath named with the bridge name even though we won't
420 pifrec
= db
.get_pif_record(pif
)
422 if pifrec
['VLAN'] == '-1':
423 return bridge_name(pif
)
425 return bridge_name(get_vlan_slave_of_pif(pif
))
428 """Return the the name of the network device that carries the
429 IP configuration (if any) associated with pif.
430 The ipdev name is the same as the bridge name.
433 pifrec
= db
.get_pif_record(pif
)
434 return bridge_name(pif
)
436 def physdev_names(pif
):
437 """Return the name(s) of the physical network device(s) associated with pif.
438 For a VLAN PIF, the physical devices are the VLAN slave's physical devices.
439 For a bond master PIF, the physical devices are the bond slaves.
440 For a non-VLAN, non-bond master PIF, the physical device is the PIF itself.
443 pifrec
= db
.get_pif_record(pif
)
445 if pifrec
['VLAN'] != '-1':
446 return physdev_names(get_vlan_slave_of_pif(pif
))
447 elif len(pifrec
['bond_master_of']) != 0:
449 for slave
in get_bond_slaves_of_pif(pif
):
450 physdevs
+= physdev_names(slave
)
453 return [pifrec
['device']]
455 def log_pif_action(action
, pif
):
456 pifrec
= db
.get_pif_record(pif
)
457 pifrec
['action'] = action
458 pifrec
['interface-name'] = interface_name(pif
)
459 if action
== "rewrite":
460 pifrec
['message'] = "Rewrite PIF %(uuid)s configuration" % pifrec
462 pifrec
['message'] = "Bring %(action)s PIF %(uuid)s" % pifrec
463 log("%(message)s: %(interface-name)s configured as %(ip_configuration_mode)s" % pifrec
)
465 def get_bond_masters_of_pif(pif
):
466 """Returns a list of PIFs which are bond masters of this PIF"""
468 pifrec
= db
.get_pif_record(pif
)
470 bso
= pifrec
['bond_slave_of']
472 # bond-slave-of is currently a single reference but in principle a
473 # PIF could be a member of several bonds which are not
474 # concurrently attached. Be robust to this possibility.
475 if not bso
or bso
== "OpaqueRef:NULL":
477 elif not type(bso
) == list:
480 bondrecs
= [db
.get_bond_record(bond
) for bond
in bso
]
481 bondrecs
= [rec
for rec
in bondrecs
if rec
]
483 return [bond
['master'] for bond
in bondrecs
]
485 def get_bond_slaves_of_pif(pif
):
486 """Returns a list of PIFs which make up the given bonded pif."""
488 pifrec
= db
.get_pif_record(pif
)
489 host
= pifrec
['host']
491 bmo
= pifrec
['bond_master_of']
493 raise Error("Bond-master-of contains too many elements")
498 bondrec
= db
.get_bond_record(bmo
[0])
500 raise Error("No bond record for bond master PIF")
502 return bondrec
['slaves']
504 def get_vlan_slave_of_pif(pif
):
505 """Find the PIF which is the VLAN slave of pif.
507 Returns the 'physical' PIF underneath the a VLAN PIF @pif."""
509 pifrec
= db
.get_pif_record(pif
)
511 vlan
= pifrec
['VLAN_master_of']
512 if not vlan
or vlan
== "OpaqueRef:NULL":
513 raise Error("PIF is not a VLAN master")
515 vlanrec
= db
.get_vlan_record(vlan
)
517 raise Error("No VLAN record found for PIF")
519 return vlanrec
['tagged_PIF']
521 def get_vlan_masters_of_pif(pif
):
522 """Returns a list of PIFs which are VLANs on top of the given pif."""
524 pifrec
= db
.get_pif_record(pif
)
525 vlans
= [db
.get_vlan_record(v
) for v
in pifrec
['VLAN_slave_of']]
526 return [v
['untagged_PIF'] for v
in vlans
if v
and db
.pif_exists(v
['untagged_PIF'])]
528 def interface_deconfigure_commands(interface
):
529 # The use of [!0-9] keeps an interface of 'eth0' from matching
530 # VLANs attached to eth0 (such as 'eth0.123'), which are distinct
532 return ['--del-match=bridge.*.port=%s' % interface
,
533 '--del-match=bonding.%s.[!0-9]*' % interface
,
534 '--del-match=bonding.*.slave=%s' % interface
,
535 '--del-match=vlan.%s.[!0-9]*' % interface
,
536 '--del-match=port.%s.[!0-9]*' % interface
,
537 '--del-match=iface.%s.[!0-9]*' % interface
]
539 def run_command(command
):
540 log("Running command: " + ' '.join(command
))
541 if os
.spawnl(os
.P_WAIT
, command
[0], *command
) != 0:
542 log("Command failed: " + ' '.join(command
))
546 def down_netdev(interface
, deconfigure
=True):
547 if not interface_exists(interface
):
548 log("down_netdev: interface %s does not exist, ignoring" % interface
)
550 argv
= ["/sbin/ifconfig", interface
, 'down']
555 pidfile_name
= '/var/run/dhclient-%s.pid' % interface
558 pidfile
= open(pidfile_name
, 'r')
559 os
.kill(int(pidfile
.readline()), signal
.SIGTERM
)
565 # Remove dhclient pidfile.
567 os
.remove(pidfile_name
)
572 def up_netdev(interface
):
573 run_command(["/sbin/ifconfig", interface
, 'up'])
575 def find_distinguished_pifs(pif
):
576 """Returns the PIFs on host that own DNS and the default route.
577 The peerdns pif will be the one with pif::other-config:peerdns=true, or the mgmt pif if none have this set.
578 The gateway pif will be the one with pif::other-config:defaultroute=true, or the mgmt pif if none have this set.
580 Note: we prune out the bond master pif (if it exists).
581 This is because when we are called to bring up an interface with a bond master, it is implicit that
582 we should bring down that master."""
584 pifrec
= db
.get_pif_record(pif
)
585 host
= pifrec
['host']
587 pifs_on_host
= [ __pif
for __pif
in db
.get_all_pifs() if
588 db
.get_pif_record(__pif
)['host'] == host
and
589 (not __pif
in get_bond_masters_of_pif(pif
)) ]
592 defaultroute_pif
= None
594 # loop through all the pifs on this host looking for one with
595 # other-config:peerdns = true, and one with
596 # other-config:default-route=true
597 for __pif
in pifs_on_host
:
598 __pifrec
= db
.get_pif_record(__pif
)
599 __oc
= __pifrec
['other_config']
600 if __oc
.has_key('peerdns') and __oc
['peerdns'] == 'true':
601 if peerdns_pif
== None:
604 log('Warning: multiple pifs with "peerdns=true" - choosing %s and ignoring %s' % \
605 (db
.get_pif_record(peerdns_pif
)['device'], __pifrec
['device']))
606 if __oc
.has_key('defaultroute') and __oc
['defaultroute'] == 'true':
607 if defaultroute_pif
== None:
608 defaultroute_pif
= __pif
610 log('Warning: multiple pifs with "defaultroute=true" - choosing %s and ignoring %s' % \
611 (db
.get_pif_record(defaultroute_pif
)['device'], __pifrec
['device']))
613 # If no pif is explicitly specified then use the mgmt pif for peerdns/defaultroute
614 if peerdns_pif
== None:
615 peerdns_pif
= management_pif
616 if defaultroute_pif
== None:
617 defaultroute_pif
= management_pif
619 return peerdns_pif
, defaultroute_pif
621 def ethtool_settings(oc
):
622 # Options for "ethtool -s"
624 if oc
.has_key('ethtool-speed'):
625 val
= oc
['ethtool-speed']
626 if val
in ["10", "100", "1000"]:
627 settings
+= ['speed', val
]
629 log("Invalid value for ethtool-speed = %s. Must be 10|100|1000." % val
)
630 if oc
.has_key('ethtool-duplex'):
631 val
= oc
['ethtool-duplex']
632 if val
in ["10", "100", "1000"]:
633 settings
+= ['duplex', 'val']
635 log("Invalid value for ethtool-duplex = %s. Must be half|full." % val
)
636 if oc
.has_key('ethtool-autoneg'):
637 val
= oc
['ethtool-autoneg']
638 if val
in ["true", "on"]:
639 settings
+= ['autoneg', 'on']
640 elif val
in ["false", "off"]:
641 settings
+= ['autoneg', 'off']
643 log("Invalid value for ethtool-autoneg = %s. Must be on|true|off|false." % val
)
645 # Options for "ethtool -K"
647 for opt
in ("rx", "tx", "sg", "tso", "ufo", "gso"):
648 if oc
.has_key("ethtool-" + opt
):
649 val
= oc
["ethtool-" + opt
]
650 if val
in ["true", "on"]:
651 offload
+= [opt
, 'on']
652 elif val
in ["false", "off"]:
653 offload
+= [opt
, 'off']
655 log("Invalid value for ethtool-%s = %s. Must be on|true|off|false." % (opt
, val
))
657 return settings
, offload
659 def configure_netdev(pif
):
660 pifrec
= db
.get_pif_record(pif
)
661 datapath
= datapath_name(pif
)
662 ipdev
= ipdev_name(pif
)
664 host
= pifrec
['host']
665 nw
= pifrec
['network']
666 nwrec
= db
.get_network_record(nw
)
668 ifconfig_argv
= ['/sbin/ifconfig', ipdev
, 'up']
670 if pifrec
['ip_configuration_mode'] == "DHCP":
672 elif pifrec
['ip_configuration_mode'] == "Static":
673 ifconfig_argv
+= [pifrec
['IP']]
674 ifconfig_argv
+= ['netmask', pifrec
['netmask']]
675 gateway
= pifrec
['gateway']
676 elif pifrec
['ip_configuration_mode'] == "None":
680 raise Error("Unknown IP-configuration-mode %s" % pifrec
['ip_configuration_mode'])
683 if pifrec
.has_key('other_config'):
684 oc
= pifrec
['other_config']
685 if oc
.has_key('mtu'):
686 int(oc
['mtu']) # Check that the value is an integer
687 ifconfig_argv
+= ['mtu', oc
['mtu']]
689 run_command(ifconfig_argv
)
691 (peerdns_pif
, defaultroute_pif
) = find_distinguished_pifs(pif
)
693 if peerdns_pif
== pif
:
694 f
= ConfigurationFile('resolv.conf', "/etc")
695 if oc
.has_key('domain'):
696 f
.write("search %s\n" % oc
['domain'])
697 for dns
in pifrec
['DNS'].split(","):
698 f
.write("nameserver %s\n" % dns
)
703 if defaultroute_pif
== pif
and gateway
!= '':
704 run_command(['/sbin/ip', 'route', 'replace', 'default',
705 'via', gateway
, 'dev', ipdev
])
707 if oc
.has_key('static-routes'):
708 for line
in oc
['static-routes'].split(','):
709 network
, masklen
, gateway
= line
.split('/')
710 run_command(['/sbin/ip', 'route', 'add',
711 '%s/%s' % (netmask
, masklen
), 'via', gateway
,
714 settings
, offload
= ethtool_settings(oc
)
716 run_command(['/sbin/ethtool', '-s', ipdev
] + settings
)
718 run_command(['/sbin/ethtool', '-K', ipdev
] + offload
)
720 if pifrec
['ip_configuration_mode'] == "DHCP":
722 print "Determining IP information for %s..." % ipdev
,
723 argv
= ['/sbin/dhclient', '-q',
724 '-lf', '/var/lib/dhclient/dhclient-%s.leases' % ipdev
,
725 '-pf', '/var/run/dhclient-%s.pid' % ipdev
,
727 if run_command(argv
):
732 def modify_config(commands
):
733 run_command(['/root/vswitch/bin/ovs-cfg-mod', '-vANY:console:emer',
734 '-F', '/etc/ovs-vswitchd.conf']
736 run_command(['/sbin/service', 'vswitch', 'reload'])
738 def is_bond_pif(pif
):
739 pifrec
= db
.get_pif_record(pif
)
740 return len(pifrec
['bond_master_of']) != 0
742 def configure_bond(pif
):
743 pifrec
= db
.get_pif_record(pif
)
744 interface
= interface_name(pif
)
745 ipdev
= ipdev_name(pif
)
746 datapath
= datapath_name(pif
)
747 physdevs
= physdev_names(pif
)
749 argv
= ['--del-match=bonding.%s.[!0-9]*' % interface
]
750 argv
+= ["--add=bonding.%s.slave=%s" % (interface
, slave
)
751 for slave
in physdevs
]
755 "mode": "balance-slb",
761 # override defaults with values from other-config whose keys
763 oc
= pifrec
['other_config']
764 overrides
= filter(lambda (key
,val
):
765 key
.startswith("bond-"), oc
.items())
766 overrides
= map(lambda (key
,val
): (key
[5:], val
), overrides
)
767 bond_options
.update(overrides
)
768 for (name
,val
) in bond_options
.items():
769 argv
+= ["--add=bonding.%s.%s=%s" % (interface
, name
, val
)]
773 pifrec
= db
.get_pif_record(pif
)
775 bridge
= bridge_name(pif
)
776 interface
= interface_name(pif
)
777 ipdev
= ipdev_name(pif
)
778 datapath
= datapath_name(pif
)
779 physdevs
= physdev_names(pif
)
781 if pifrec
['VLAN'] != '-1':
782 vlan_slave
= get_vlan_slave_of_pif(pif
)
783 if vlan_slave
and is_bond_pif(vlan_slave
):
784 bond_master
= vlan_slave
785 elif is_bond_pif(pif
):
790 bond_slaves
= get_bond_slaves_of_pif(bond_master
)
793 bond_masters
= get_bond_masters_of_pif(pif
)
795 # Support "rpm -e vswitch" gracefully by keeping Centos configuration
796 # files up-to-date, even though we don't use them or need them.
797 f
= configure_pif(pif
)
798 mode
= pifrec
['ip_configuration_mode']
800 log("Configuring %s using %s configuration" % (bridge
, mode
))
801 br
= open_network_ifcfg(pif
)
802 configure_network(pif
, br
)
806 log("Configuring %s using %s configuration" % (interface
, mode
))
807 configure_network(pif
, f
)
809 for master
in bond_masters
:
810 master_bridge
= bridge_name(master
)
811 removed
= unconfigure_pif(master
)
812 f
.attach_child(removed
)
814 removed
= open_network_ifcfg(master
)
815 log("Unlinking stale file %s" % removed
.path())
817 f
.attach_child(removed
)
819 # /etc/xensource/scripts/vif needs to know where to add VIFs.
821 if not os
.path
.exists(vswitch_config_dir
):
822 os
.mkdir(vswitch_config_dir
)
823 br
= ConfigurationFile("br-%s" % bridge
, vswitch_config_dir
)
824 br
.write("VLAN_SLAVE=%s\n" % datapath
)
825 br
.write("VLAN_VID=%s\n" % pifrec
['VLAN'])
829 # Update all configuration files (both ours and Centos's).
833 # "ifconfig down" the network device and delete its IP address, etc.
835 for physdev
in physdevs
:
838 # Remove all keys related to pif and any bond masters linked to PIF.
839 del_ports
= [ipdev
] + physdevs
+ bond_masters
840 if vlan_slave
and bond_master
:
841 del_ports
+= [interface_name(bond_master
)]
843 # What ports do we need to add to the datapath?
845 # We definitely need the ipdev, and ordinarily we want the
846 # physical devices too, but for bonds we need the bond as bridge
848 add_ports
= [ipdev
, datapath
]
850 add_ports
+= physdevs
852 add_ports
+= [interface_name(bond_master
)]
854 # What ports do we need to delete?
856 # - All the ports that we add, to avoid duplication and to drop
857 # them from another datapath in case they're misassigned.
859 # - The physical devices, since they will either be in add_ports
860 # or added to the bonding device (see below).
862 # - The bond masters for pif. (Ordinarily pif shouldn't have any
863 # bond masters. If it does then interface-reconfigure is
864 # implicitly being asked to take them down.)
865 del_ports
= add_ports
+ physdevs
+ bond_masters
867 # What networks does this datapath carry?
869 # - The network corresponding to the datapath's PIF.
871 # - The networks corresponding to any VLANs attached to the
874 for nwpif
in db
.get_pifs_by_record({'device': pifrec
['device'],
875 'host': pifrec
['host']}):
876 net
= db
.get_pif_record(nwpif
)['network']
877 network_uuids
+= [db
.get_network_record(net
)['uuid']]
879 # Bring up bond slaves early, because ovs-vswitchd initially
880 # enables or disables bond slaves based on whether carrier is
881 # detected when they are added, and a network device that is down
882 # always reports "no carrier".
883 bond_slave_physdevs
= []
884 for slave
in bond_slaves
:
885 bond_slave_physdevs
+= physdev_names(slave
)
886 for slave_physdev
in bond_slave_physdevs
:
887 up_netdev(slave_physdev
)
889 # Now modify the ovs-vswitchd config file.
891 for port
in set(del_ports
):
892 argv
+= interface_deconfigure_commands(port
)
893 for port
in set(add_ports
):
894 argv
+= ['--add=bridge.%s.port=%s' % (datapath
, port
)]
896 argv
+= ['--add=vlan.%s.tag=%s' % (ipdev
, pifrec
['VLAN'])]
897 argv
+= ['--add=iface.%s.internal=true' % (ipdev
)]
899 # xapi creates a bridge by the name of the ipdev and requires
900 # that the IP address will be on it. We need to delete this
901 # bridge because we need that device to be a member of our
903 argv
+= ['--del-match=bridge.%s.[!0-9]*' % ipdev
]
905 # xapi insists that its attempts to create the bridge succeed,
906 # so force that to happen.
907 argv
+= ['--add=iface.%s.fake-bridge=true' % (ipdev
)]
910 os
.unlink("%s/br-%s" % (vswitch_config_dir
, bridge
))
913 argv
+= ['--del-match=bridge.%s.xs-network-uuids=*' % datapath
]
914 argv
+= ['--add=bridge.%s.xs-network-uuids=%s' % (datapath
, uuid
)
915 for uuid
in set(network_uuids
)]
917 argv
+= configure_bond(bond_master
)
920 # Configure network devices.
921 configure_netdev(pif
)
923 # Bring up VLAN slave, plus physical devices other than bond
924 # slaves (which we brought up earlier).
926 up_netdev(ipdev_name(vlan_slave
))
927 for physdev
in set(physdevs
) - set(bond_slave_physdevs
):
930 # Update /etc/issue (which contains the IP address of the management interface)
931 os
.system("/sbin/update-issue")
933 def action_down(pif
):
934 rec
= db
.get_pif_record(pif
)
935 interface
= interface_name(pif
)
936 bridge
= bridge_name(pif
)
937 ipdev
= ipdev_name(pif
)
939 # Support "rpm -e vswitch" gracefully by keeping Centos configuration
940 # files up-to-date, even though we don't use them or need them.
941 f
= unconfigure_pif(pif
)
943 br
= open_network_ifcfg(pif
)
944 log("Unlinking stale file %s" % br
.path())
951 log("action_down failed to apply changes: %s" % e
.msg
)
956 if rec
['VLAN'] != '-1':
957 # Get rid of the VLAN device itself.
959 argv
+= interface_deconfigure_commands(ipdev
)
961 # If the VLAN's slave is attached, stop here.
962 slave
= get_vlan_slave_of_pif(pif
)
963 if db
.get_pif_record(slave
)['currently_attached']:
964 log("VLAN slave is currently attached")
968 # If the VLAN's slave has other VLANs that are attached, stop here.
969 masters
= get_vlan_masters_of_pif(slave
)
971 if m
!= pif
and db
.get_pif_record(m
)['currently_attached']:
972 log("VLAN slave has other master %s" % interface_naem(m
))
976 # Otherwise, take down the VLAN's slave too.
977 log("No more masters, bring down vlan slave %s" % interface_name(slave
))
980 # Stop here if this PIF has attached VLAN masters.
981 vlan_masters
= get_vlan_masters_of_pif(pif
)
982 log("VLAN masters of %s - %s" % (rec
['device'], [interface_name(m
) for m
in vlan_masters
]))
983 for m
in vlan_masters
:
984 if db
.get_pif_record(m
)['currently_attached']:
985 log("Leaving %s up due to currently attached VLAN master %s" % (interface
, interface_name(m
)))
988 # pif is now either a bond or a physical device which needs to be
989 # brought down. pif might have changed so re-check all its attributes.
990 rec
= db
.get_pif_record(pif
)
991 interface
= interface_name(pif
)
992 bridge
= bridge_name(pif
)
993 ipdev
= ipdev_name(pif
)
996 bond_slaves
= get_bond_slaves_of_pif(pif
)
997 log("bond slaves of %s - %s" % (rec
['device'], [interface_name(s
) for s
in bond_slaves
]))
998 for slave
in bond_slaves
:
999 slave_interface
= interface_name(slave
)
1000 log("bring down bond slave %s" % slave_interface
)
1001 argv
+= interface_deconfigure_commands(slave_interface
)
1002 down_netdev(slave_interface
)
1004 argv
+= interface_deconfigure_commands(ipdev
)
1007 argv
+= ['--del-match', 'bridge.%s.*' % datapath_name(pif
)]
1008 argv
+= ['--del-match', 'bonding.%s.[!0-9]*' % interface
]
1011 def action_rewrite(pif
):
1012 # Support "rpm -e vswitch" gracefully by keeping Centos configuration
1013 # files up-to-date, even though we don't use them or need them.
1014 pifrec
= db
.get_pif_record(pif
)
1015 f
= configure_pif(pif
)
1016 interface
= interface_name(pif
)
1017 bridge
= bridge_name(pif
)
1018 mode
= pifrec
['ip_configuration_mode']
1020 log("Configuring %s using %s configuration" % (bridge
, mode
))
1021 br
= open_network_ifcfg(pif
)
1022 configure_network(pif
, br
)
1026 log("Configuring %s using %s configuration" % (interface
, mode
))
1027 configure_network(pif
, f
)
1033 log("failed to apply changes: %s" % e
.msg
)
1037 # We have no code of our own to run here.
1040 def main(argv
=None):
1041 global output_directory
, management_pif
1047 force_interface
= None
1048 force_management
= False
1056 longops
= [ "output-directory=",
1057 "pif=", "pif-uuid=",
1063 "device=", "mode=", "ip=", "netmask=", "gateway=",
1065 arglist
, args
= getopt
.gnu_getopt(argv
[1:], shortops
, longops
)
1066 except getopt
.GetoptError
, msg
:
1069 force_rewrite_config
= {}
1072 if o
== "--output-directory":
1073 output_directory
= a
1076 elif o
== "--pif-uuid":
1078 elif o
== "--session":
1080 elif o
== "--force-interface" or o
== "--force":
1082 elif o
== "--management":
1083 force_management
= True
1084 elif o
in ["--device", "--mode", "--ip", "--netmask", "--gateway"]:
1085 force_rewrite_config
[o
[2:]] = a
1086 elif o
== "-h" or o
== "--help":
1087 print __doc__
% {'command-name': os
.path
.basename(argv
[0])}
1090 if not debug_mode():
1091 syslog
.openlog(os
.path
.basename(argv
[0]))
1092 log("Called as " + str.join(" ", argv
))
1094 raise Usage("Required option <action> not present")
1096 raise Usage("Too many arguments")
1099 # backwards compatibility
1100 if action
== "rewrite-configuration": action
= "rewrite"
1102 if output_directory
and ( session
or pif
):
1103 raise Usage("--session/--pif cannot be used with --output-directory")
1104 if ( session
or pif
) and pif_uuid
:
1105 raise Usage("--session/--pif and --pif-uuid are mutually exclusive.")
1106 if ( session
and not pif
) or ( not session
and pif
):
1107 raise Usage("--session and --pif must be used together.")
1108 if force_interface
and ( session
or pif
or pif_uuid
):
1109 raise Usage("--force is mutually exclusive with --session, --pif and --pif-uuid")
1110 if len(force_rewrite_config
) and not (force_interface
and action
== "rewrite"):
1111 raise Usage("\"--force rewrite\" needed for --device, --mode, --ip, --netmask, and --gateway")
1115 log("Force interface %s %s" % (force_interface
, action
))
1117 if action
== "rewrite":
1118 action_force_rewrite(force_interface
, force_rewrite_config
)
1120 db
= DatabaseCache(cache_file
=dbcache_file
)
1121 host
= db
.extras
['host']
1122 pif
= db
.get_pif_by_bridge(host
, force_interface
)
1123 management_pif
= db
.get_management_pif(host
)
1127 elif action
== "down":
1130 raise Usage("Unknown action %s" % action
)
1132 db
= DatabaseCache(session_ref
=session
)
1135 pif
= db
.get_pif_by_uuid(pif_uuid
)
1138 raise Usage("No PIF given")
1140 if force_management
:
1141 # pif is going to be the management pif
1142 management_pif
= pif
1144 # pif is not going to be the management pif.
1145 # Search DB cache for pif on same host with management=true
1146 pifrec
= db
.get_pif_record(pif
)
1147 host
= pifrec
['host']
1148 management_pif
= db
.get_management_pif(host
)
1150 log_pif_action(action
, pif
)
1152 if not check_allowed(pif
):
1157 elif action
== "down":
1159 elif action
== "rewrite":
1162 raise Usage("Unknown action %s" % action
)
1165 pifrec
= db
.get_pif_record(pif
)
1166 db
.save(dbcache_file
, {'host': pifrec
['host']})
1169 print >>sys
.stderr
, err
.msg
1170 print >>sys
.stderr
, "For help use --help."
1178 # The following code allows interface-reconfigure to keep Centos
1179 # network configuration files up-to-date, even though the vswitch
1180 # never uses them. In turn, that means that "rpm -e vswitch" does not
1181 # have to update any configuration files.
1183 def configure_ethtool(oc
, f
):
1184 # Options for "ethtool -s"
1186 setting_opts
= ["autoneg", "speed", "duplex"]
1187 # Options for "ethtool -K"
1189 offload_opts
= ["rx", "tx", "sg", "tso", "ufo", "gso"]
1191 for opt
in [opt
for opt
in setting_opts
+ offload_opts
if oc
.has_key("ethtool-" + opt
)]:
1192 val
= oc
["ethtool-" + opt
]
1194 if opt
in ["speed"]:
1195 if val
in ["10", "100", "1000"]:
1196 val
= "speed " + val
1198 log("Invalid value for ethtool-speed = %s. Must be 10|100|1000." % val
)
1200 elif opt
in ["duplex"]:
1201 if val
in ["half", "full"]:
1202 val
= "duplex " + val
1204 log("Invalid value for ethtool-duplex = %s. Must be half|full." % val
)
1206 elif opt
in ["autoneg"] + offload_opts
:
1207 if val
in ["true", "on"]:
1209 elif val
in ["false", "off"]:
1212 log("Invalid value for ethtool-%s = %s. Must be on|true|off|false." % (opt
, val
))
1215 if opt
in setting_opts
:
1216 if val
and settings
:
1217 settings
= settings
+ " " + val
1220 elif opt
in offload_opts
:
1222 offload
= offload
+ " " + val
1227 f
.write("ETHTOOL_OPTS=\"%s\"\n" % settings
)
1229 f
.write("ETHTOOL_OFFLOAD_OPTS=\"%s\"\n" % offload
)
1231 def configure_mtu(oc
, f
):
1232 if not oc
.has_key('mtu'):
1236 mtu
= int(oc
['mtu'])
1237 f
.write("MTU=%d\n" % mtu
)
1238 except ValueError, x
:
1239 log("Invalid value for mtu = %s" % mtu
)
1241 def configure_static_routes(interface
, oc
, f
):
1242 """Open a route-<interface> file for static routes.
1244 Opens the static routes configuration file for interface and writes one
1245 line for each route specified in the network's other config "static-routes" value.
1247 interface ( RO): xenbr1
1248 other-config (MRW): static-routes: 172.16.0.0/15/192.168.0.3,172.18.0.0/16/192.168.0.4;...
1250 Then route-xenbr1 should be
1251 172.16.0.0/15 via 192.168.0.3 dev xenbr1
1252 172.18.0.0/16 via 192.168.0.4 dev xenbr1
1254 fname
= "route-%s" % interface
1255 if oc
.has_key('static-routes'):
1256 # The key is present - extract comma seperates entries
1257 lines
= oc
['static-routes'].split(',')
1259 # The key is not present, i.e. there are no static routes
1262 child
= ConfigurationFile(fname
)
1263 child
.write("# DO NOT EDIT: This file (%s) was autogenerated by %s\n" % \
1264 (os
.path
.basename(child
.path()), os
.path
.basename(sys
.argv
[0])))
1268 network
, masklen
, gateway
= l
.split('/')
1269 child
.write("%s/%s via %s dev %s\n" % (network
, masklen
, gateway
, interface
))
1271 f
.attach_child(child
)
1274 except ValueError, e
:
1275 log("Error in other-config['static-routes'] format for network %s: %s" % (interface
, e
))
1277 def __open_ifcfg(interface
):
1278 """Open a network interface configuration file.
1280 Opens the configuration file for interface, writes a header and
1281 common options and returns the file object.
1283 fname
= "ifcfg-%s" % interface
1284 f
= ConfigurationFile(fname
)
1286 f
.write("# DO NOT EDIT: This file (%s) was autogenerated by %s\n" % \
1287 (os
.path
.basename(f
.path()), os
.path
.basename(sys
.argv
[0])))
1288 f
.write("XEMANAGED=yes\n")
1289 f
.write("DEVICE=%s\n" % interface
)
1290 f
.write("ONBOOT=no\n")
1294 def open_network_ifcfg(pif
):
1295 bridge
= bridge_name(pif
)
1296 interface
= interface_name(pif
)
1298 return __open_ifcfg(bridge
)
1300 return __open_ifcfg(interface
)
1303 def open_pif_ifcfg(pif
):
1304 pifrec
= db
.get_pif_record(pif
)
1306 log("Configuring %s (%s)" % (interface_name(pif
), pifrec
['MAC']))
1308 f
= __open_ifcfg(interface_name(pif
))
1310 if pifrec
.has_key('other_config'):
1311 configure_ethtool(pifrec
['other_config'], f
)
1312 configure_mtu(pifrec
['other_config'], f
)
1316 def configure_network(pif
, f
):
1317 """Write the configuration file for a network.
1319 Writes configuration derived from the network object into the relevant
1320 ifcfg file. The configuration file is passed in, but if the network is
1321 bridgeless it will be ifcfg-<interface>, otherwise it will be ifcfg-<bridge>.
1323 This routine may also write ifcfg files of the networks corresponding to other PIFs
1324 in order to maintain consistency.
1327 pif: Opaque_ref of pif
1328 f : ConfigurationFile(/path/to/ifcfg) to which we append network configuration
1331 pifrec
= db
.get_pif_record(pif
)
1332 host
= pifrec
['host']
1333 nw
= pifrec
['network']
1334 nwrec
= db
.get_network_record(nw
)
1336 bridge
= bridge_name(pif
)
1337 interface
= interface_name(pif
)
1343 if nwrec
.has_key('other_config'):
1344 configure_ethtool(nwrec
['other_config'], f
)
1345 configure_mtu(nwrec
['other_config'], f
)
1346 configure_static_routes(device
, nwrec
['other_config'], f
)
1349 if pifrec
.has_key('other_config'):
1350 oc
= pifrec
['other_config']
1352 if device
== bridge
:
1353 f
.write("TYPE=Bridge\n")
1354 f
.write("DELAY=0\n")
1355 f
.write("STP=off\n")
1356 f
.write("PIFDEV=%s\n" % interface_name(pif
))
1358 if pifrec
['ip_configuration_mode'] == "DHCP":
1359 f
.write("BOOTPROTO=dhcp\n")
1360 f
.write("PERSISTENT_DHCLIENT=yes\n")
1361 elif pifrec
['ip_configuration_mode'] == "Static":
1362 f
.write("BOOTPROTO=none\n")
1363 f
.write("NETMASK=%(netmask)s\n" % pifrec
)
1364 f
.write("IPADDR=%(IP)s\n" % pifrec
)
1365 f
.write("GATEWAY=%(gateway)s\n" % pifrec
)
1366 elif pifrec
['ip_configuration_mode'] == "None":
1367 f
.write("BOOTPROTO=none\n")
1369 raise Error("Unknown ip-configuration-mode %s" % pifrec
['ip_configuration_mode'])
1371 if pifrec
.has_key('DNS') and pifrec
['DNS'] != "":
1372 ServerList
= pifrec
['DNS'].split(",")
1373 for i
in range(len(ServerList
)): f
.write("DNS%d=%s\n" % (i
+1, ServerList
[i
]))
1374 if oc
and oc
.has_key('domain'):
1375 f
.write("DOMAIN='%s'\n" % oc
['domain'].replace(',', ' '))
1377 # We only allow one ifcfg-xenbr* to have PEERDNS=yes and there can be only one GATEWAYDEV in /etc/sysconfig/network.
1378 # The peerdns pif will be the one with pif::other-config:peerdns=true, or the mgmt pif if none have this set.
1379 # The gateway pif will be the one with pif::other-config:defaultroute=true, or the mgmt pif if none have this set.
1381 # Work out which pif on this host should be the one with PEERDNS=yes and which should be the GATEWAYDEV
1383 # Note: we prune out the bond master pif (if it exists).
1384 # This is because when we are called to bring up an interface with a bond master, it is implicit that
1385 # we should bring down that master.
1386 pifs_on_host
= [ __pif
for __pif
in db
.get_all_pifs() if
1387 db
.get_pif_record(__pif
)['host'] == host
and
1388 (not __pif
in get_bond_masters_of_pif(pif
)) ]
1389 other_pifs_on_host
= [ __pif
for __pif
in pifs_on_host
if __pif
!= pif
]
1392 defaultroute_pif
= None
1394 # loop through all the pifs on this host looking for one with
1395 # other-config:peerdns = true, and one with
1396 # other-config:default-route=true
1397 for __pif
in pifs_on_host
:
1398 __pifrec
= db
.get_pif_record(__pif
)
1399 __oc
= __pifrec
['other_config']
1400 if __oc
.has_key('peerdns') and __oc
['peerdns'] == 'true':
1401 if peerdns_pif
== None:
1404 log('Warning: multiple pifs with "peerdns=true" - choosing %s and ignoring %s' % \
1405 (db
.get_pif_record(peerdns_pif
)['device'], __pifrec
['device']))
1406 if __oc
.has_key('defaultroute') and __oc
['defaultroute'] == 'true':
1407 if defaultroute_pif
== None:
1408 defaultroute_pif
= __pif
1410 log('Warning: multiple pifs with "defaultroute=true" - choosing %s and ignoring %s' % \
1411 (db
.get_pif_record(defaultroute_pif
)['device'], __pifrec
['device']))
1413 # If no pif is explicitly specified then use the mgmt pif for peerdns/defaultroute
1414 if peerdns_pif
== None:
1415 peerdns_pif
= management_pif
1416 if defaultroute_pif
== None:
1417 defaultroute_pif
= management_pif
1419 # Update all the other network's ifcfg files and ensure consistency
1420 for __pif
in other_pifs_on_host
:
1421 __f
= open_network_ifcfg(__pif
)
1422 peerdns_line_wanted
= 'PEERDNS=%s\n' % ((__pif
== peerdns_pif
) and 'yes' or 'no')
1423 lines
= __f
.readlines()
1425 if not peerdns_line_wanted
in lines
:
1426 # the PIF selected for DNS has changed and as a result this ifcfg file needs rewriting
1428 if not line
.lstrip().startswith('PEERDNS'):
1430 log("Setting %s in %s" % (peerdns_line_wanted
.strip(), __f
.path()))
1431 __f
.write(peerdns_line_wanted
)
1436 # There is no need to change this ifcfg file. So don't attach_child.
1439 # ... and for this pif too
1440 f
.write('PEERDNS=%s\n' % ((pif
== peerdns_pif
) and 'yes' or 'no'))
1443 fnetwork
= ConfigurationFile("network", "/etc/sysconfig")
1444 for line
in fnetwork
.readlines():
1445 if line
.lstrip().startswith('GATEWAY') :
1447 fnetwork
.write(line
)
1448 if defaultroute_pif
:
1449 gatewaydev
= bridge_name(defaultroute_pif
)
1451 gatewaydev
= interface_name(defaultroute_pif
)
1452 fnetwork
.write('GATEWAYDEV=%s\n' % gatewaydev
)
1454 f
.attach_child(fnetwork
)
1459 def configure_physical_interface(pif
):
1460 """Write the configuration for a physical interface.
1462 Writes the configuration file for the physical interface described by
1465 Returns the open file handle for the interface configuration file.
1468 pifrec
= db
.get_pif_record(pif
)
1470 f
= open_pif_ifcfg(pif
)
1472 f
.write("TYPE=Ethernet\n")
1473 f
.write("HWADDR=%(MAC)s\n" % pifrec
)
1477 def configure_bond_interface(pif
):
1478 """Write the configuration for a bond interface.
1480 Writes the configuration file for the bond interface described by
1481 the pif object. Handles writing the configuration for the slave
1484 Returns the open file handle for the bond interface configuration
1488 pifrec
= db
.get_pif_record(pif
)
1489 oc
= pifrec
['other_config']
1490 f
= open_pif_ifcfg(pif
)
1492 if pifrec
['MAC'] != "":
1493 f
.write("MACADDR=%s\n" % pifrec
['MAC'])
1495 for slave
in get_bond_slaves_of_pif(pif
):
1496 s
= configure_physical_interface(slave
)
1497 s
.write("MASTER=%(device)s\n" % pifrec
)
1498 s
.write("SLAVE=yes\n")
1502 # The bond option defaults
1504 "mode": "balance-slb",
1511 # override defaults with values from other-config whose keys being with "bond-"
1512 overrides
= filter(lambda (key
,val
): key
.startswith("bond-"), oc
.items())
1513 overrides
= map(lambda (key
,val
): (key
[5:], val
), overrides
)
1514 bond_options
.update(overrides
)
1516 # write the bond options to ifcfg-bondX
1517 f
.write('BONDING_OPTS="')
1518 for (name
,val
) in bond_options
.items():
1519 f
.write("%s=%s " % (name
,val
))
1523 def configure_vlan_interface(pif
):
1524 """Write the configuration for a VLAN interface.
1526 Writes the configuration file for the VLAN interface described by
1527 the pif object. Handles writing the configuration for the master
1528 interface if necessary.
1530 Returns the open file handle for the VLAN interface configuration
1534 slave
= configure_pif(get_vlan_slave_of_pif(pif
))
1537 f
= open_pif_ifcfg(pif
)
1538 f
.write("VLAN=yes\n")
1539 f
.attach_child(slave
)
1543 def configure_pif(pif
):
1544 """Write the configuration for a PIF object.
1546 Writes the configuration file the PIF and all dependent
1547 interfaces (bond slaves and VLAN masters etc).
1549 Returns the open file handle for the interface configuration file.
1552 pifrec
= db
.get_pif_record(pif
)
1554 if pifrec
['VLAN'] != '-1':
1555 f
= configure_vlan_interface(pif
)
1556 elif len(pifrec
['bond_master_of']) != 0:
1557 f
= configure_bond_interface(pif
)
1559 f
= configure_physical_interface(pif
)
1561 bridge
= bridge_name(pif
)
1563 f
.write("BRIDGE=%s\n" % bridge
)
1567 def unconfigure_pif(pif
):
1568 """Clear up the files created by configure_pif"""
1569 f
= open_pif_ifcfg(pif
)
1570 log("Unlinking stale file %s" % f
.path())
1574 if __name__
== "__main__":
1580 err
= traceback
.format_exception(*ex
)
1584 if not debug_mode():