netdev-dpdk: fix mbuf leaks
[cascardo/ovs.git] / xenserver / opt_xensource_libexec_interface-reconfigure
1 #!/usr/bin/env python
2 #
3 # Copyright (c) 2008,2009 Citrix Systems, Inc.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as published
7 # by the Free Software Foundation; version 2.1 only. with the special
8 # exception on linking described in file LICENSE.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU Lesser General Public License for more details.
14 #
15 """Usage:
16
17     %(command-name)s <PIF> up
18     %(command-name)s <PIF> down
19     %(command-name)s rewrite
20     %(command-name)s --force <BRIDGE> up
21     %(command-name)s --force <BRIDGE> down
22     %(command-name)s --force <BRIDGE> rewrite --device=<INTERFACE> --mac=<MAC-ADDRESS> <CONFIG>
23
24     where <PIF> is one of:
25        --session <SESSION-REF> --pif <PIF-REF>
26        --pif-uuid <PIF-UUID>
27     and <CONFIG> is one of:
28        --mode=dhcp
29        --mode=static --ip=<IPADDR> --netmask=<NM> [--gateway=<GW>]
30
31   Options:
32     --session           A session reference to use to access the xapi DB
33     --pif               A PIF reference within the session.
34     --pif-uuid          The UUID of a PIF.
35     --force             An interface name.
36     --root-prefix=DIR   Use DIR as alternate root directory (for testing).
37     --no-syslog         Write log messages to stderr instead of system log.
38 """
39
40 # Notes:
41 # 1. Every pif belongs to exactly one network
42 # 2. Every network has zero or one pifs
43 # 3. A network may have an associated bridge, allowing vifs to be attached
44 # 4. A network may be bridgeless (there's no point having a bridge over a storage pif)
45
46 from InterfaceReconfigure import *
47
48 import os, sys, getopt
49 import syslog
50 import traceback
51 import re
52 import random
53 import syslog
54
55 management_pif = None
56
57 dbcache_file = "/var/xapi/network.dbcache"
58
59 #
60 # Logging.
61 #
62
63 def log_pif_action(action, pif):
64     pifrec = db().get_pif_record(pif)
65     rec = {}
66     rec['uuid'] = pifrec['uuid']
67     rec['ip_configuration_mode'] = pifrec['ip_configuration_mode']
68     rec['action'] = action
69     rec['pif_netdev_name'] = pif_netdev_name(pif)
70     rec['message'] = "Bring %(action)s PIF %(uuid)s" % rec
71     log("%(message)s: %(pif_netdev_name)s configured as %(ip_configuration_mode)s" % rec)
72
73 #
74 # Exceptions.
75 #
76
77 class Usage(Exception):
78     def __init__(self, msg):
79         Exception.__init__(self)
80         self.msg = msg
81
82 #
83 # Boot from Network filesystem or device.
84 #
85
86 def check_allowed(pif):
87     """Determine whether interface-reconfigure should be manipulating this PIF.
88
89     Used to prevent system PIFs (such as network root disk) from being interfered with.
90     """
91
92     pifrec = db().get_pif_record(pif)
93     try:
94         f = open(root_prefix() + "/proc/ardence")
95         macline = filter(lambda x: x.startswith("HWaddr:"), f.readlines())
96         f.close()
97         if len(macline) == 1:
98             p = re.compile(".*\s%(MAC)s\s.*" % pifrec, re.IGNORECASE)
99             if p.match(macline[0]):
100                 log("Skipping PVS device %(device)s (%(MAC)s)" % pifrec)
101                 return False
102     except IOError:
103         pass
104     return True
105
106 #
107 # Bare Network Devices -- network devices without IP configuration
108 #
109
110 def netdev_remap_name(pif, already_renamed=[]):
111     """Check whether 'pif' exists and has the correct MAC.
112     If not, try to find a device with the correct MAC and rename it.
113     'already_renamed' is used to avoid infinite recursion.
114     """
115
116     def read1(name):
117         file = None
118         try:
119             file = open(name, 'r')
120             return file.readline().rstrip('\n')
121         finally:
122             if file != None:
123                 file.close()
124
125     def get_netdev_mac(device):
126         try:
127             return read1("%s/sys/class/net/%s/address" % (root_prefix(), device))
128         except:
129             # Probably no such device.
130             return None
131
132     def get_netdev_tx_queue_len(device):
133         try:
134             return int(read1("%s/sys/class/net/%s/tx_queue_len" % (root_prefix(), device)))
135         except:
136             # Probably no such device.
137             return None
138
139     def get_netdev_by_mac(mac):
140         for device in os.listdir(root_prefix() + "/sys/class/net"):
141             dev_mac = get_netdev_mac(device)
142             if (dev_mac and mac.lower() == dev_mac.lower() and
143                 get_netdev_tx_queue_len(device)):
144                 return device
145         return None
146
147     def rename_netdev(old_name, new_name):
148         raise Error("Trying to rename %s to %s - This functionality has been removed" % (old_name, new_name))
149         # log("Changing the name of %s to %s" % (old_name, new_name))
150         # run_command(['/sbin/ifconfig', old_name, 'down'])
151         # if not run_command(['/sbin/ip', 'link', 'set', old_name, 'name', new_name]):
152         #     raise Error("Could not rename %s to %s" % (old_name, new_name))
153
154     pifrec = db().get_pif_record(pif)
155     device = pifrec['device']
156     mac = pifrec['MAC']
157
158     # Is there a network device named 'device' at all?
159     device_exists = netdev_exists(device)
160     if device_exists:
161         # Yes.  Does it have MAC 'mac'?
162         found_mac = get_netdev_mac(device)
163         if found_mac and mac.lower() == found_mac.lower():
164             # Yes, everything checks out the way we want.  Nothing to do.
165             return
166     else:
167         log("No network device %s" % device)
168
169     # What device has MAC 'mac'?
170     cur_device = get_netdev_by_mac(mac)
171     if not cur_device:
172         log("No network device has MAC %s" % mac)
173         return
174
175     # First rename 'device', if it exists, to get it out of the way
176     # for 'cur_device' to replace it.
177     if device_exists:
178         rename_netdev(device, "dev%d" % random.getrandbits(24))
179
180     # Rename 'cur_device' to 'device'.
181     rename_netdev(cur_device, device)
182
183 #
184 # IP Network Devices -- network devices with IP configuration
185 #
186
187 def ifdown(netdev):
188     """Bring down a network interface"""
189     if not netdev_exists(netdev):
190         log("ifdown: device %s does not exist, ignoring" % netdev)
191         return
192     if not os.path.exists("%s/etc/sysconfig/network-scripts/ifcfg-%s" % (root_prefix(), netdev)):
193         log("ifdown: device %s exists but ifcfg-%s does not" % (netdev,netdev))
194         run_command(["/sbin/ifconfig", netdev, 'down'])
195         return
196     run_command(["/sbin/ifdown", netdev])
197
198 def ifup(netdev):
199     """Bring up a network interface"""
200     if not os.path.exists(root_prefix() + "/etc/sysconfig/network-scripts/ifcfg-%s" % netdev):
201         raise Error("ifup: device %s exists but ifcfg-%s does not" % (netdev,netdev))
202     d = os.getenv("DHCLIENTARGS","")
203     if os.path.exists("/etc/firstboot.d/data/firstboot_in_progress"):
204         os.putenv("DHCLIENTARGS", d + " -T 240 " )
205     run_command(["/sbin/ifup", netdev])
206     os.putenv("DHCLIENTARGS", d )
207
208 #
209 #
210 #
211
212 def pif_rename_physical_devices(pif):
213     if pif_is_tunnel(pif):
214         return
215
216     if pif_is_vlan(pif):
217         pif = pif_get_vlan_slave(pif)
218
219     if pif_is_bond(pif):
220         pifs = pif_get_bond_slaves(pif)
221     else:
222         pifs = [pif]
223
224     for pif in pifs:
225         netdev_remap_name(pif)
226
227 #
228 # IP device configuration
229 #
230
231 def ipdev_configure_static_routes(interface, oc, f):
232     """Open a route-<interface> file for static routes.
233
234     Opens the static routes configuration file for interface and writes one
235     line for each route specified in the network's other config "static-routes" value.
236     E.g. if
237            interface ( RO): xenbr1
238            other-config (MRW): static-routes: 172.16.0.0/15/192.168.0.3,172.18.0.0/16/192.168.0.4;...
239
240     Then route-xenbr1 should be
241           172.16.0.0/15 via 192.168.0.3 dev xenbr1
242           172.18.0.0/16 via 192.168.0.4 dev xenbr1
243     """
244     if oc.has_key('static-routes'):
245         # The key is present - extract comma separates entries
246         lines = oc['static-routes'].split(',')
247     else:
248         # The key is not present, i.e. there are no static routes
249         lines = []
250
251     child = ConfigurationFile("%s/etc/sysconfig/network-scripts/route-%s" % (root_prefix(), interface))
252     child.write("# DO NOT EDIT: This file (%s) was autogenerated by %s\n" % \
253             (os.path.basename(child.path()), os.path.basename(sys.argv[0])))
254
255     try:
256         for l in lines:
257             network, masklen, gateway = l.split('/')
258             child.write("%s/%s via %s dev %s\n" % (network, masklen, gateway, interface))
259
260         f.attach_child(child)
261         child.close()
262
263     except ValueError, e:
264         log("Error in other-config['static-routes'] format for network %s: %s" % (interface, e))
265
266 def ipdev_open_ifcfg(pif):
267     ipdev = pif_ipdev_name(pif)
268
269     log("Writing network configuration for %s" % ipdev)
270
271     f = ConfigurationFile("%s/etc/sysconfig/network-scripts/ifcfg-%s" % (root_prefix(), ipdev))
272
273     f.write("# DO NOT EDIT: This file (%s) was autogenerated by %s\n" % \
274             (os.path.basename(f.path()), os.path.basename(sys.argv[0])))
275     f.write("XEMANAGED=yes\n")
276     f.write("DEVICE=%s\n" % ipdev)
277     f.write("ONBOOT=no\n")
278     f.write("NOZEROCONF=yes\n")
279
280     return f
281
282 def ipdev_configure_network(pif, dp):
283     """Write the configuration file for a network.
284
285     Writes configuration derived from the network object into the relevant
286     ifcfg file.  The configuration file is passed in, but if the network is
287     bridgeless it will be ifcfg-<interface>, otherwise it will be ifcfg-<bridge>.
288
289     This routine may also write ifcfg files of the networks corresponding to other PIFs
290     in order to maintain consistency.
291
292     params:
293         pif:  Opaque_ref of pif
294         dp:   Datapath object
295     """
296
297     pifrec = db().get_pif_record(pif)
298     nw = pifrec['network']
299     nwrec = db().get_network_record(nw)
300
301     ipdev = pif_ipdev_name(pif)
302
303     f = ipdev_open_ifcfg(pif)
304
305     mode = pifrec['ip_configuration_mode']
306     log("Configuring %s using %s configuration" % (ipdev, mode))
307
308     oc = None
309     if pifrec.has_key('other_config'):
310         oc = pifrec['other_config']
311
312     dp.configure_ipdev(f)
313
314     if pifrec['ip_configuration_mode'] == "DHCP":
315         f.write("BOOTPROTO=dhcp\n")
316         f.write("PERSISTENT_DHCLIENT=yes\n")
317     elif pifrec['ip_configuration_mode'] == "Static":
318         f.write("BOOTPROTO=none\n")
319         f.write("NETMASK=%(netmask)s\n" % pifrec)
320         f.write("IPADDR=%(IP)s\n" % pifrec)
321         f.write("GATEWAY=%(gateway)s\n" % pifrec)
322     elif pifrec['ip_configuration_mode'] == "None":
323         f.write("BOOTPROTO=none\n")
324     else:
325         raise Error("Unknown ip-configuration-mode %s" % pifrec['ip_configuration_mode'])
326
327     if nwrec.has_key('other_config'):
328         settings,offload = ethtool_settings(nwrec['other_config'])
329         if len(settings):
330             f.write("ETHTOOL_OPTS=\"%s\"\n" % str.join(" ", settings))
331         if len(offload):
332             f.write("ETHTOOL_OFFLOAD_OPTS=\"%s\"\n" % str.join(" ", offload))
333
334         ipdev_configure_static_routes(ipdev, nwrec['other_config'], f)
335
336     mtu = mtu_setting(nw, "Network", nwrec['other_config'])
337     if mtu:
338         f.write("MTU=%s\n" % mtu)
339
340
341     if pifrec.has_key('DNS') and pifrec['DNS'] != "":
342         ServerList = pifrec['DNS'].split(",")
343         for i in range(len(ServerList)): f.write("DNS%d=%s\n" % (i+1, ServerList[i]))
344     if oc and oc.has_key('domain'):
345         f.write("DOMAIN='%s'\n" % oc['domain'].replace(',', ' '))
346
347     # There can be only one DNSDEV and one GATEWAYDEV in /etc/sysconfig/network.
348     #
349     # The peerdns pif will be the one with
350     # pif::other-config:peerdns=true, or the mgmt pif if none have
351     # this set.
352     #
353     # The gateway pif will be the one with
354     # pif::other-config:defaultroute=true, or the mgmt pif if none
355     # have this set.
356
357     # Work out which pif on this host should be the DNSDEV and which
358     # should be the GATEWAYDEV
359     #
360     # Note: we prune out the bond master pif (if it exists). This is
361     # because when we are called to bring up an interface with a bond
362     # master, it is implicit that we should bring down that master.
363
364     pifs_on_host = [p for p in db().get_all_pifs() if not p in pif_get_bond_masters(pif)]
365
366     # now prune out bond slaves as they are not connected to the IP 
367     # stack and so cannot be used as gateway or DNS devices.
368     pifs_on_host = [ p for p in pifs_on_host if len(pif_get_bond_masters(p)) == 0]
369
370     # loop through all the pifs on this host looking for one with
371     #   other-config:peerdns = true, and one with
372     #   other-config:default-route=true
373     peerdns_pif = None
374     defaultroute_pif = None
375     for __pif in pifs_on_host:
376         __pifrec = db().get_pif_record(__pif)
377         __oc = __pifrec['other_config']
378         if __oc.has_key('peerdns') and __oc['peerdns'] == 'true':
379             if peerdns_pif == None:
380                 peerdns_pif = __pif
381             else:
382                 log('Warning: multiple pifs with "peerdns=true" - choosing %s and ignoring %s' % \
383                         (db().get_pif_record(peerdns_pif)['device'], __pifrec['device']))
384         if __oc.has_key('defaultroute') and __oc['defaultroute'] == 'true':
385             if defaultroute_pif == None:
386                 defaultroute_pif = __pif
387             else:
388                 log('Warning: multiple pifs with "defaultroute=true" - choosing %s and ignoring %s' % \
389                         (db().get_pif_record(defaultroute_pif)['device'], __pifrec['device']))
390
391     # If no pif is explicitly specified then use the mgmt pif for
392     # peerdns/defaultroute.
393     if peerdns_pif == None:
394         peerdns_pif = management_pif
395     if defaultroute_pif == None:
396         defaultroute_pif = management_pif
397
398     is_dnsdev = peerdns_pif == pif
399     is_gatewaydev = defaultroute_pif == pif
400
401     if is_dnsdev or is_gatewaydev:
402         fnetwork = ConfigurationFile(root_prefix() + "/etc/sysconfig/network")
403         for line in fnetwork.readlines():
404             if is_dnsdev and line.lstrip().startswith('DNSDEV='):
405                 fnetwork.write('DNSDEV=%s\n' % ipdev)
406                 is_dnsdev = False
407             elif is_gatewaydev and line.lstrip().startswith('GATEWAYDEV='):
408                 fnetwork.write('GATEWAYDEV=%s\n' % ipdev)
409                 is_gatewaydev = False
410             else:
411                 fnetwork.write(line)
412
413         if is_dnsdev:
414             fnetwork.write('DNSDEV=%s\n' % ipdev)
415         if is_gatewaydev:
416             fnetwork.write('GATEWAYDEV=%s\n' % ipdev)
417
418         fnetwork.close()
419         f.attach_child(fnetwork)
420
421     return f
422
423 #
424 # Toplevel actions
425 #
426
427 def action_up(pif, force):
428     pifrec = db().get_pif_record(pif)
429
430     ipdev = pif_ipdev_name(pif)
431     dp = DatapathFactory()(pif)
432
433     log("action_up: %s" % ipdev)
434
435     f = ipdev_configure_network(pif, dp)
436
437     dp.preconfigure(f)
438
439     f.close()
440
441     pif_rename_physical_devices(pif)
442
443     # if we are not forcing the interface up then attempt to tear down
444     # any existing devices which might interfere with brinign this one
445     # up.
446     if not force:
447         ifdown(ipdev)
448
449         dp.bring_down_existing()
450
451     try:
452         f.apply()
453
454         dp.configure()
455
456         ifup(ipdev)
457
458         dp.post()
459
460         # Update /etc/issue (which contains the IP address of the management interface)
461         os.system(root_prefix() + "/sbin/update-issue")
462
463         f.commit()
464     except Error, e:
465         log("failed to apply changes: %s" % e.msg)
466         f.revert()
467         raise
468
469 def action_down(pif):
470     ipdev = pif_ipdev_name(pif)
471     dp = DatapathFactory()(pif)
472
473     log("action_down: %s" % ipdev)
474
475     ifdown(ipdev)
476
477     dp.bring_down()
478
479 def action_rewrite():
480     DatapathFactory().rewrite()
481     
482 # This is useful for reconfiguring the mgmt interface after having lost connectivity to the pool master
483 def action_force_rewrite(bridge, config):
484     def getUUID():
485         import subprocess
486         uuid,_ = subprocess.Popen(['uuidgen'], stdout = subprocess.PIPE).communicate()
487         return uuid.strip()
488
489     # Notes:
490     # 1. that this assumes the interface is bridged
491     # 2. If --gateway is given it will make that the default gateway for the host
492
493     # extract the configuration
494     try:
495         mode = config['mode']
496         mac = config['mac']
497         interface = config['device']
498     except:
499         raise Usage("Please supply --mode, --mac and --device")
500
501     if mode == 'static':
502         try:
503             netmask = config['netmask']
504             ip = config['ip']
505         except:
506             raise Usage("Please supply --netmask and --ip")
507         try:
508             gateway = config['gateway']
509         except:
510             gateway = None
511     elif mode != 'dhcp':
512         raise Usage("--mode must be either static or dhcp")
513
514     if config.has_key('vlan'):
515         is_vlan = True
516         vlan_slave, vlan_vid = config['vlan'].split('.')
517     else:
518         is_vlan = False
519
520     if is_vlan:
521         raise Error("Force rewrite of VLAN not implemented")
522
523     log("Configuring %s using %s configuration" % (bridge, mode))
524
525     f = ConfigurationFile(root_prefix() + dbcache_file)
526
527     pif_uuid = getUUID()
528     network_uuid = getUUID()
529
530     f.write('<?xml version="1.0" ?>\n')
531     f.write('<xenserver-network-configuration>\n')
532     f.write('\t<pif ref="OpaqueRef:%s">\n' % pif_uuid)
533     f.write('\t\t<network>OpaqueRef:%s</network>\n' % network_uuid)
534     f.write('\t\t<management>True</management>\n')
535     f.write('\t\t<uuid>%sPif</uuid>\n' % interface)
536     f.write('\t\t<bond_slave_of>OpaqueRef:NULL</bond_slave_of>\n')
537     f.write('\t\t<bond_master_of/>\n')
538     f.write('\t\t<VLAN_slave_of/>\n')
539     f.write('\t\t<VLAN_master_of>OpaqueRef:NULL</VLAN_master_of>\n')
540     f.write('\t\t<VLAN>-1</VLAN>\n')
541     f.write('\t\t<tunnel_access_PIF_of/>\n')
542     f.write('\t\t<tunnel_transport_PIF_of/>\n')
543     f.write('\t\t<device>%s</device>\n' % interface)
544     f.write('\t\t<MAC>%s</MAC>\n' % mac)
545     f.write('\t\t<other_config/>\n')
546     if mode == 'dhcp':
547         f.write('\t\t<ip_configuration_mode>DHCP</ip_configuration_mode>\n')
548         f.write('\t\t<IP></IP>\n')
549         f.write('\t\t<netmask></netmask>\n')
550         f.write('\t\t<gateway></gateway>\n')
551         f.write('\t\t<DNS></DNS>\n')
552     elif mode == 'static':
553         f.write('\t\t<ip_configuration_mode>Static</ip_configuration_mode>\n')
554         f.write('\t\t<IP>%s</IP>\n' % ip)
555         f.write('\t\t<netmask>%s</netmask>\n' % netmask)
556         if gateway is not None:
557             f.write('\t\t<gateway>%s</gateway>\n' % gateway)
558         f.write('\t\t<DNS></DNS>\n')
559     else:
560         raise Error("Unknown mode %s" % mode)
561     f.write('\t</pif>\n')
562
563     f.write('\t<network ref="OpaqueRef:%s">\n' % network_uuid)
564     f.write('\t\t<uuid>InitialManagementNetwork</uuid>\n')
565     f.write('\t\t<PIFs>\n')
566     f.write('\t\t\t<PIF>OpaqueRef:%s</PIF>\n' % pif_uuid)
567     f.write('\t\t</PIFs>\n')
568     f.write('\t\t<bridge>%s</bridge>\n' % bridge)
569     f.write('\t\t<other_config/>\n')
570     f.write('\t</network>\n')
571     f.write('</xenserver-network-configuration>\n')
572
573     f.close()
574
575     try:
576         f.apply()
577         f.commit()
578     except Error, e:
579         log("failed to apply changes: %s" % e.msg)
580         f.revert()
581         raise
582
583 def main(argv=None):
584     global management_pif
585
586     session = None
587     pif_uuid = None
588     pif = None
589
590     force_interface = None
591     force_management = False
592
593     if argv is None:
594         argv = sys.argv
595
596     try:
597         try:
598             shortops = "h"
599             longops = [ "pif=", "pif-uuid=",
600                         "session=",
601                         "force=",
602                         "force-interface=",
603                         "management",
604                         "mac=", "device=", "mode=", "ip=", "netmask=", "gateway=",
605                         "root-prefix=",
606                         "no-syslog",
607                         "help" ]
608             arglist, args = getopt.gnu_getopt(argv[1:], shortops, longops)
609         except getopt.GetoptError, msg:
610             raise Usage(msg)
611
612         force_rewrite_config = {}
613
614         for o,a in arglist:
615             if o == "--pif":
616                 pif = a
617             elif o == "--pif-uuid":
618                 pif_uuid = a
619             elif o == "--session":
620                 session = a
621             elif o == "--force-interface" or o == "--force":
622                 force_interface = a
623             elif o == "--management":
624                 force_management = True
625             elif o in ["--mac", "--device", "--mode", "--ip", "--netmask", "--gateway"]:
626                 force_rewrite_config[o[2:]] = a
627             elif o == "--root-prefix":
628                 set_root_prefix(a)
629             elif o == "--no-syslog":
630                 set_log_destination("stderr")
631             elif o == "-h" or o == "--help":
632                 print __doc__ % {'command-name': os.path.basename(argv[0])}
633                 return 0
634
635         if get_log_destination() == "syslog":
636             syslog.openlog(os.path.basename(argv[0]))
637             log("Called as " + str.join(" ", argv))
638
639         if len(args) < 1:
640             raise Usage("Required option <action> not present")
641         if len(args) > 1:
642             raise Usage("Too many arguments")
643
644         action = args[0]
645
646         if not action in ["up", "down", "rewrite", "rewrite-configuration"]:
647             raise Usage("Unknown action \"%s\"" % action)
648
649         # backwards compatibility
650         if action == "rewrite-configuration": action = "rewrite"
651
652         if ( session or pif ) and pif_uuid:
653             raise Usage("--session/--pif and --pif-uuid are mutually exclusive.")
654         if ( session and not pif ) or ( not session and pif ):
655             raise Usage("--session and --pif must be used together.")
656         if force_interface and ( session or pif or pif_uuid ):
657             raise Usage("--force is mutually exclusive with --session, --pif and --pif-uuid")
658         if len(force_rewrite_config) and not (force_interface and action == "rewrite"):
659             raise Usage("\"--force rewrite\" needed for --device, --mode, --ip, --netmask, and --gateway")
660         if (action == "rewrite") and (pif or pif_uuid ):
661             raise Usage("rewrite action does not take --pif or --pif-uuid")
662         
663         global db
664         if force_interface:
665             log("Force interface %s %s" % (force_interface, action))
666
667             if action == "rewrite":
668                 action_force_rewrite(force_interface, force_rewrite_config)
669             elif action in ["up", "down"]:
670                 db_init_from_cache(dbcache_file)
671                 pif = db().get_pif_by_bridge(force_interface)
672                 management_pif = db().get_management_pif()
673
674                 if action == "up":
675                     action_up(pif, True)
676                 elif action == "down":
677                     action_down(pif)
678             else:
679                 raise Error("Unknown action %s"  % action)
680         else:
681             db_init_from_xenapi(session)
682
683             if pif_uuid:
684                 pif = db().get_pif_by_uuid(pif_uuid)
685
686             if action == "rewrite":
687                 action_rewrite()
688             else:
689                 if not pif:
690                     raise Usage("No PIF given")
691
692                 if force_management:
693                     # pif is going to be the management pif
694                     management_pif = pif
695                 else:
696                     # pif is not going to be the management pif.
697                     # Search DB cache for pif on same host with management=true
698                     pifrec = db().get_pif_record(pif)
699                     management_pif = db().get_management_pif()
700
701                 log_pif_action(action, pif)
702
703                 if not check_allowed(pif):
704                     return 0
705
706                 if action == "up":
707                     action_up(pif, False)
708                 elif action == "down":
709                     action_down(pif)
710                 else:
711                     raise Error("Unknown action %s"  % action)
712
713             # Save cache.
714             db().save(dbcache_file)
715
716     except Usage, err:
717         print >>sys.stderr, err.msg
718         print >>sys.stderr, "For help use --help."
719         return 2
720     except Error, err:
721         log(err.msg)
722         return 1
723
724     return 0
725
726 if __name__ == "__main__":
727     rc = 1
728     try:
729         rc = main()
730     except:
731         ex = sys.exc_info()
732         err = traceback.format_exception(*ex)
733         for exline in err:
734             log(exline)
735
736     syslog.closelog()
737
738     sys.exit(rc)