]> git.proxmox.com Git - ovs.git/blame - xenserver/opt_xensource_libexec_InterfaceReconfigureVswitch.py
bridge: Create new port_run() function.
[ovs.git] / xenserver / opt_xensource_libexec_InterfaceReconfigureVswitch.py
CommitLineData
b3080599 1# Copyright (c) 2008,2009 Citrix Systems, Inc.
34edeccf 2# Copyright (c) 2009,2010,2011 Nicira Networks.
b3080599
IC
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU Lesser General Public License as published
6# by the Free Software Foundation; version 2.1 only. with the special
7# exception on linking described in file LICENSE.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Lesser General Public License for more details.
13#
14from InterfaceReconfigure import *
ab32de00 15import os
47a3c536 16import re
b3080599
IC
17
18#
19# Bare Network Devices -- network devices without IP configuration
20#
21
22def netdev_down(netdev):
23 """Bring down a bare network device"""
24 if not netdev_exists(netdev):
25 log("netdev: down: device %s does not exist, ignoring" % netdev)
26 return
27 run_command(["/sbin/ifconfig", netdev, 'down'])
28
29def netdev_up(netdev, mtu=None):
30 """Bring up a bare network device"""
31 if not netdev_exists(netdev):
32 raise Error("netdev: up: device %s does not exist" % netdev)
33
34 if mtu:
35 mtu = ["mtu", mtu]
36 else:
37 mtu = []
38
39 run_command(["/sbin/ifconfig", netdev, 'up'] + mtu)
40
b3080599
IC
41#
42# PIF miscellanea
43#
44
45def pif_currently_in_use(pif):
46 """Determine if a PIF is currently in use.
47
48 A PIF is determined to be currently in use if
49 - PIF.currently-attached is true
50 - Any bond master is currently attached
51 - Any VLAN master is currently attached
52 """
53 rec = db().get_pif_record(pif)
54 if rec['currently_attached']:
55 log("configure_datapath: %s is currently attached" % (pif_netdev_name(pif)))
56 return True
57 for b in pif_get_bond_masters(pif):
58 if pif_currently_in_use(b):
59 log("configure_datapath: %s is in use by BOND master %s" % (pif_netdev_name(pif),pif_netdev_name(b)))
60 return True
61 for v in pif_get_vlan_masters(pif):
62 if pif_currently_in_use(v):
63 log("configure_datapath: %s is in use by VLAN master %s" % (pif_netdev_name(pif),pif_netdev_name(v)))
64 return True
65 return False
66
67#
68# Datapath Configuration
69#
70
71def pif_datapath(pif):
72 """Return the datapath PIF associated with PIF.
3b1acc99
BP
73A non-VLAN PIF is its own datapath PIF, except that a bridgeless PIF has
74no datapath PIF at all.
75A VLAN PIF's datapath PIF is its VLAN slave's datapath PIF.
b3080599
IC
76"""
77 if pif_is_vlan(pif):
78 return pif_datapath(pif_get_vlan_slave(pif))
79
80 pifrec = db().get_pif_record(pif)
81 nwrec = db().get_network_record(pifrec['network'])
82 if not nwrec['bridge']:
83 return None
84 else:
85 return pif
86
87def datapath_get_physical_pifs(pif):
88 """Return the PIFs for the physical network device(s) associated with a datapath PIF.
89For a bond master PIF, these are the bond slave PIFs.
90For a non-VLAN, non-bond master PIF, the PIF is its own physical device PIF.
91
92A VLAN PIF cannot be a datapath PIF.
93"""
92e906e4
IC
94 if pif_is_tunnel(pif):
95 return []
96 elif pif_is_vlan(pif):
b3080599
IC
97 # Seems like overkill...
98 raise Error("get-physical-pifs should not get passed a VLAN")
99 elif pif_is_bond(pif):
100 return pif_get_bond_slaves(pif)
101 else:
102 return [pif]
103
104def datapath_deconfigure_physical(netdev):
7c79588e 105 return ['--', '--with-iface', '--if-exists', 'del-port', netdev]
b3080599 106
47a3c536
BP
107def vsctl_escape(s):
108 if s.isalnum():
109 return s
110
111 def escape(match):
112 c = match.group(0)
113 if c == '\0':
114 raise Error("strings may not contain null bytes")
115 elif c == '\\':
116 return r'\\'
117 elif c == '\n':
118 return r'\n'
119 elif c == '\r':
120 return r'\r'
121 elif c == '\t':
122 return r'\t'
123 elif c == '\b':
124 return r'\b'
125 elif c == '\a':
126 return r'\a'
127 else:
128 return r'\x%02x' % ord(c)
129 return '"' + re.sub(r'["\\\000-\037]', escape, s) + '"'
130
92e906e4
IC
131def datapath_configure_tunnel(pif):
132 pass
133
b3080599 134def datapath_configure_bond(pif,slaves):
a4af0040 135 bridge = pif_bridge_name(pif)
e91087c7 136 pifrec = db().get_pif_record(pif)
b3080599
IC
137 interface = pif_netdev_name(pif)
138
a4af0040
JP
139 argv = ['--', '--fake-iface', 'add-bond', bridge, interface]
140 for slave in slaves:
141 argv += [pif_netdev_name(slave)]
b3080599 142
b3080599
IC
143 # Bonding options.
144 bond_options = {
145 "mode": "balance-slb",
146 "miimon": "100",
147 "downdelay": "200",
148 "updelay": "31000",
149 "use_carrier": "1",
2776e408 150 "hashing-algorithm": "src_mac",
b3080599
IC
151 }
152 # override defaults with values from other-config whose keys
153 # being with "bond-"
154 oc = pifrec['other_config']
155 overrides = filter(lambda (key,val):
156 key.startswith("bond-"), oc.items())
157 overrides = map(lambda (key,val): (key[5:], val), overrides)
158 bond_options.update(overrides)
2776e408
EJ
159 mode = None
160 halgo = None
47a3c536
BP
161
162 argv += ['--', 'set', 'Port', interface]
163 if pifrec['MAC'] != "":
164 argv += ['MAC=%s' % vsctl_escape(pifrec['MAC'])]
b3080599 165 for (name,val) in bond_options.items():
47a3c536
BP
166 if name in ['updelay', 'downdelay']:
167 # updelay and downdelay have dedicated schema columns.
168 # The value must be a nonnegative integer.
169 try:
170 value = int(val)
171 if value < 0:
172 raise ValueError
173
174 argv += ['bond_%s=%d' % (name, value)]
175 except ValueError:
176 log("bridge %s has invalid %s '%s'" % (bridge, name, value))
b9b627d5
EJ
177 elif name in ['miimon', 'use_carrier']:
178 try:
179 value = int(val)
180 if value < 0:
181 raise ValueError
182
183 if name == 'use_carrier':
184 if value:
185 value = "carrier"
186 else:
187 value = "miimon"
188 argv += ["other-config:bond-detect-mode=%s" % value]
189 else:
190 argv += ["other-config:bond-miimon-interval=%d" % value]
191 except ValueError:
192 log("bridge %s has invalid %s '%s'" % (bridge, name, value))
aa98d0cd 193 elif name == "mode":
2776e408
EJ
194 mode = val
195 elif name == "hashing-algorithm":
196 halgo = val
47a3c536
BP
197 else:
198 # Pass other bond options into other_config.
199 argv += ["other-config:%s=%s" % (vsctl_escape("bond-%s" % name),
200 vsctl_escape(val))]
2776e408
EJ
201
202 if mode == 'lacp':
203 argv += ['lacp=active']
204
205 if halgo == 'src_mac':
206 argv += ['bond_mode=balance-slb']
207 elif halgo == "tcpudp_ports":
208 argv += ['bond_mode=balance-tcp']
209 else:
210 log("bridge %s has invalid bond-hashing-algorithm '%s'" % (bridge, halgo))
211 argv += ['bond_mode=balance-slb']
212 elif mode in ['balance-slb', 'active-backup']:
213 argv += ['lacp=off', 'bond_mode=%s' % mode]
214 else:
215 log("bridge %s has invalid bond-mode '%s'" % (bridge, mode))
216 argv += ['lacp=off', 'bond_mode=balance-slb']
217
b3080599
IC
218 return argv
219
220def datapath_deconfigure_bond(netdev):
7c79588e 221 return ['--', '--with-iface', '--if-exists', 'del-port', netdev]
b3080599
IC
222
223def datapath_deconfigure_ipdev(interface):
7c79588e 224 return ['--', '--with-iface', '--if-exists', 'del-port', interface]
b3080599
IC
225
226def datapath_modify_config(commands):
13ffee26
JP
227 #log("modifying configuration:")
228 #for c in commands:
229 # log(" %s" % c)
a4af0040
JP
230
231 rc = run_command(['/usr/bin/ovs-vsctl'] + ['--timeout=20']
232 + [c for c in commands if not c.startswith('#')])
233 if not rc:
b3080599 234 raise Error("Failed to modify vswitch configuration")
b3080599
IC
235 return True
236
237#
238# Toplevel Datapath Configuration.
239#
240
d77ffabf
BP
241def configure_datapath(pif):
242 """Bring up the configuration for 'pif', which must not be a VLAN PIF, by:
243 - Tearing down other PIFs that use the same physical devices as 'pif'.
244 - Ensuring that 'pif' itself is set up.
245 - *Not* tearing down any PIFs that are stacked on top of 'pif' (i.e. VLANs
246 on top of 'pif'.
b3080599
IC
247
248 Returns a tuple containing
a4af0040 249 - A list containing the necessary vsctl command line arguments
b3080599
IC
250 - A list of additional devices which should be brought up after
251 the configuration is applied.
252 """
253
a4af0040 254 vsctl_argv = []
b3080599
IC
255 extra_up_ports = []
256
86e1bb44 257 assert not pif_is_vlan(pif)
b3080599
IC
258 bridge = pif_bridge_name(pif)
259
260 physical_devices = datapath_get_physical_pifs(pif)
261
86e1bb44
BP
262 vsctl_argv += ['## configuring datapath %s' % bridge]
263
b3080599
IC
264 # Determine additional devices to deconfigure.
265 #
266 # Given all physical devices which are part of this PIF we need to
267 # consider:
268 # - any additional bond which a physical device is part of.
269 # - any additional physical devices which are part of an additional bond.
270 #
271 # Any of these which are not currently in use should be brought
272 # down and deconfigured.
273 extra_down_bonds = []
274 extra_down_ports = []
275 for p in physical_devices:
276 for bond in pif_get_bond_masters(p):
277 if bond == pif:
278 log("configure_datapath: leaving bond %s up" % pif_netdev_name(bond))
279 continue
280 if bond in extra_down_bonds:
281 continue
282 if db().get_pif_record(bond)['currently_attached']:
283 log("configure_datapath: implicitly tearing down currently-attached bond %s" % pif_netdev_name(bond))
284
285 extra_down_bonds += [bond]
286
287 for s in pif_get_bond_slaves(bond):
288 if s in physical_devices:
289 continue
290 if s in extra_down_ports:
291 continue
292 if pif_currently_in_use(s):
293 continue
294 extra_down_ports += [s]
295
296 log("configure_datapath: bridge - %s" % bridge)
297 log("configure_datapath: physical - %s" % [pif_netdev_name(p) for p in physical_devices])
298 log("configure_datapath: extra ports - %s" % [pif_netdev_name(p) for p in extra_down_ports])
299 log("configure_datapath: extra bonds - %s" % [pif_netdev_name(p) for p in extra_down_bonds])
300
301 # Need to fully deconfigure any bridge which any of the:
302 # - physical devices
303 # - bond devices
304 # - sibling devices
305 # refers to
306 for brpif in physical_devices + extra_down_ports + extra_down_bonds:
307 if brpif == pif:
308 continue
309 b = pif_bridge_name(brpif)
310 #ifdown(b)
311 # XXX
312 netdev_down(b)
a4af0040
JP
313 vsctl_argv += ['# remove bridge %s' % b]
314 vsctl_argv += ['--', '--if-exists', 'del-br', b]
b3080599
IC
315
316 for n in extra_down_ports:
317 dev = pif_netdev_name(n)
a4af0040
JP
318 vsctl_argv += ['# deconfigure sibling physical device %s' % dev]
319 vsctl_argv += datapath_deconfigure_physical(dev)
b3080599
IC
320 netdev_down(dev)
321
322 for n in extra_down_bonds:
323 dev = pif_netdev_name(n)
a4af0040
JP
324 vsctl_argv += ['# deconfigure bond device %s' % dev]
325 vsctl_argv += datapath_deconfigure_bond(dev)
b3080599
IC
326 netdev_down(dev)
327
328 for p in physical_devices:
329 dev = pif_netdev_name(p)
a4af0040
JP
330 vsctl_argv += ['# deconfigure physical port %s' % dev]
331 vsctl_argv += datapath_deconfigure_physical(dev)
332
d77ffabf 333 vsctl_argv += ['--', '--may-exist', 'add-br', bridge]
13ffee26 334
b3080599 335 if len(physical_devices) > 1:
a4af0040
JP
336 vsctl_argv += ['# deconfigure bond %s' % pif_netdev_name(pif)]
337 vsctl_argv += datapath_deconfigure_bond(pif_netdev_name(pif))
338 vsctl_argv += ['# configure bond %s' % pif_netdev_name(pif)]
339 vsctl_argv += datapath_configure_bond(pif, physical_devices)
b3080599 340 extra_up_ports += [pif_netdev_name(pif)]
92e906e4 341 elif len(physical_devices) == 1:
b3080599 342 iface = pif_netdev_name(physical_devices[0])
a4af0040 343 vsctl_argv += ['# add physical device %s' % iface]
7b09e426 344 vsctl_argv += ['--', '--may-exist', 'add-port', bridge, iface]
92e906e4
IC
345 elif pif_is_tunnel(pif):
346 datapath_configure_tunnel(pif)
b3080599 347
16f2ae57
IC
348 vsctl_argv += ['# configure Bridge MAC']
349 vsctl_argv += ['--', 'set', 'Bridge', bridge,
350 'other-config:hwaddr=%s' % vsctl_escape(db().get_pif_record(pif)['MAC'])]
351
939e5a1b 352 pool = db().get_pool_record()
2dd26837 353 network = db().get_network_by_bridge(bridge)
da54975c 354 network_rec = None
2dd26837
EJ
355 fail_mode = None
356 valid_fail_modes = ['standalone', 'secure']
0671665d 357
2dd26837
EJ
358 if network:
359 network_rec = db().get_network_record(network)
360 fail_mode = network_rec['other_config'].get('vswitch-controller-fail-mode')
361
362 if (fail_mode not in valid_fail_modes) and pool:
c2875f43 363 fail_mode = pool['other_config'].get('vswitch-controller-fail-mode')
2dd26837
EJ
364
365 if fail_mode not in valid_fail_modes:
0671665d 366 fail_mode = 'standalone'
939e5a1b 367
2dd26837 368 vsctl_argv += ['--', 'set', 'Bridge', bridge, 'fail_mode=%s' % fail_mode]
939e5a1b 369
da54975c
AE
370 if network_rec:
371 dib = network_rec['other_config'].get('vswitch-disable-in-band')
372 if not dib:
373 vsctl_argv += ['--', 'remove', 'Bridge', bridge, 'other_config', 'disable-in-band']
374 elif dib in ['true', 'false']:
375 vsctl_argv += ['--', 'set', 'Bridge', bridge, 'other_config:disable-in-band=' + dib]
376 else:
377 log('"' + dib + '"' "isn't a valid setting for other_config:disable-in-band on " + bridge)
378
c0a50086 379 vsctl_argv += set_br_external_ids(pif)
86e1bb44
BP
380 vsctl_argv += ['## done configuring datapath %s' % bridge]
381
a4af0040 382 return vsctl_argv,extra_up_ports
b3080599 383
7966caf4 384def deconfigure_bridge(pif):
a4af0040 385 vsctl_argv = []
b3080599
IC
386
387 bridge = pif_bridge_name(pif)
388
2a75efe8 389 log("deconfigure_bridge: bridge - %s" % bridge)
b3080599 390
a4af0040
JP
391 vsctl_argv += ['# deconfigure bridge %s' % bridge]
392 vsctl_argv += ['--', '--if-exists', 'del-br', bridge]
b3080599 393
a4af0040 394 return vsctl_argv
b3080599 395
c0a50086 396def set_br_external_ids(pif):
47a3c536
BP
397 pifrec = db().get_pif_record(pif)
398 dp = pif_datapath(pif)
399 dprec = db().get_pif_record(dp)
400
c0a50086 401 xs_network_uuids = []
47a3c536 402 for nwpif in db().get_pifs_by_device(pifrec['device']):
c0a50086
BP
403 rec = db().get_pif_record(nwpif)
404
405 # When state is read from dbcache PIF.currently_attached
406 # is always assumed to be false... Err on the side of
407 # listing even detached networks for the time being.
408 #if nwpif != pif and not rec['currently_attached']:
409 # log("Network PIF %s not currently attached (%s)" % (rec['uuid'],pifrec['uuid']))
410 # continue
411 nwrec = db().get_network_record(rec['network'])
b13300c7
EJ
412
413 uuid = nwrec['uuid']
414 if pif_is_vlan(nwpif):
415 xs_network_uuids.append(uuid)
416 else:
417 xs_network_uuids.insert(0, uuid)
c0a50086
BP
418
419 vsctl_argv = []
c76fde78 420 vsctl_argv += ['# configure xs-network-uuids']
c0a50086 421 vsctl_argv += ['--', 'br-set-external-id', pif_bridge_name(pif),
c76fde78 422 'xs-network-uuids', ';'.join(xs_network_uuids)]
47a3c536 423
c0a50086
BP
424 return vsctl_argv
425
b3080599
IC
426#
427#
428#
429
430class DatapathVswitch(Datapath):
431 def __init__(self, pif):
432 Datapath.__init__(self, pif)
433 self._dp = pif_datapath(pif)
434 self._ipdev = pif_ipdev_name(pif)
435
436 if pif_is_vlan(pif) and not self._dp:
437 raise Error("Unbridged VLAN devices not implemented yet")
438
439 log("Configured for Vswitch datapath")
440
823c5699
IC
441 @classmethod
442 def rewrite(cls):
ab32de00
BP
443 if not os.path.exists("/var/run/openvswitch/db.sock"):
444 # ovsdb-server is not running, so we can't update the database.
445 # Probably we are being called as part of system shutdown. Just
446 # skip the update, since the external-ids will be updated on the
447 # next boot anyhow.
448 return
449
823c5699
IC
450 vsctl_argv = []
451 for pif in db().get_all_pifs():
452 pifrec = db().get_pif_record(pif)
453 if not pif_is_vlan(pif) and pifrec['currently_attached']:
454 vsctl_argv += set_br_external_ids(pif)
455
456 if vsctl_argv != []:
457 datapath_modify_config(vsctl_argv)
458
b3080599
IC
459 def configure_ipdev(self, cfg):
460 cfg.write("TYPE=Ethernet\n")
461
462 def preconfigure(self, parent):
a4af0040 463 vsctl_argv = []
b3080599
IC
464 extra_ports = []
465
466 pifrec = db().get_pif_record(self._pif)
66aeba23 467 dprec = db().get_pif_record(self._dp)
b3080599
IC
468
469 ipdev = self._ipdev
d77ffabf
BP
470 c,e = configure_datapath(self._dp)
471 bridge = pif_bridge_name(self._pif)
a4af0040 472 vsctl_argv += c
b3080599
IC
473 extra_ports += e
474
16f2ae57
IC
475 dpname = pif_bridge_name(self._dp)
476
d77ffabf 477 if pif_is_vlan(self._pif):
9ec4d255
EJ
478 # In some cases XAPI may misguidedly leave an instance of
479 # 'bridge' which should be deleted.
480 vsctl_argv += ['--', '--if-exists', 'del-br', bridge]
481
d77ffabf
BP
482 # configure_datapath() set up the underlying datapath bridge.
483 # Stack a VLAN bridge on top of it.
484 vsctl_argv += ['--', '--may-exist', 'add-br',
16f2ae57 485 bridge, dpname, pifrec['VLAN']]
c0a50086
BP
486
487 vsctl_argv += set_br_external_ids(self._pif)
a4af0040 488
13ffee26
JP
489 if ipdev != bridge:
490 vsctl_argv += ["# deconfigure ipdev %s" % ipdev]
491 vsctl_argv += datapath_deconfigure_ipdev(ipdev)
492 vsctl_argv += ["# reconfigure ipdev %s" % ipdev]
493 vsctl_argv += ['--', 'add-port', bridge, ipdev]
a4af0040 494
16f2ae57
IC
495 if ipdev != dpname:
496 vsctl_argv += ['# configure Interface MAC']
497 vsctl_argv += ['--', 'set', 'Interface', pif_ipdev_name(self._pif),
498 'MAC=%s' % vsctl_escape(dprec['MAC'])]
499
a4af0040 500 self._vsctl_argv = vsctl_argv
b3080599
IC
501 self._extra_ports = extra_ports
502
503 def bring_down_existing(self):
fe19e820
BP
504 # interface-reconfigure is never explicitly called to down a
505 # bond master. However, when we are called to up a slave it
f51c1d98
BP
506 # is implicit that we are destroying the master. Conversely,
507 # when we are called to up a bond is is implicit that we are
508 # taking down the slaves.
fe19e820 509 #
f51c1d98
BP
510 # This is (only) important in the case where the device being
511 # implicitly taken down uses DHCP. We need to kill the
512 # dhclient process, otherwise performing the inverse operation
513 # later later will fail because ifup will refuse to start a
514 # duplicate dhclient.
fe19e820
BP
515 bond_masters = pif_get_bond_masters(self._pif)
516 for master in bond_masters:
517 log("action_up: bring down bond master %s" % (pif_netdev_name(master)))
518 run_command(["/sbin/ifdown", pif_bridge_name(master)])
b3080599 519
f51c1d98
BP
520 bond_slaves = pif_get_bond_slaves(self._pif)
521 for slave in bond_slaves:
522 log("action_up: bring down bond slave %s" % (pif_netdev_name(slave)))
523 run_command(["/sbin/ifdown", pif_bridge_name(slave)])
524
b3080599
IC
525 def configure(self):
526 # Bring up physical devices. ovs-vswitchd initially enables or
527 # disables bond slaves based on whether carrier is detected
528 # when they are added, and a network device that is down
529 # always reports "no carrier".
530 physical_devices = datapath_get_physical_pifs(self._dp)
531
532 for p in physical_devices:
9a2b1175
IC
533 prec = db().get_pif_record(p)
534 oc = prec['other_config']
b3080599
IC
535
536 dev = pif_netdev_name(p)
537
9a2b1175 538 mtu = mtu_setting(prec['network'], "PIF", oc)
b3080599
IC
539
540 netdev_up(dev, mtu)
541
404c1692 542 settings, offload = ethtool_settings(oc, PIF_OTHERCONFIG_DEFAULTS)
b3080599
IC
543 if len(settings):
544 run_command(['/sbin/ethtool', '-s', dev] + settings)
545 if len(offload):
546 run_command(['/sbin/ethtool', '-K', dev] + offload)
547
a4af0040 548 datapath_modify_config(self._vsctl_argv)
b3080599
IC
549
550 def post(self):
551 for p in self._extra_ports:
552 log("action_up: bring up %s" % p)
553 netdev_up(p)
554
555 def bring_down(self):
a4af0040 556 vsctl_argv = []
b3080599
IC
557
558 dp = self._dp
559 ipdev = self._ipdev
560
561 bridge = pif_bridge_name(dp)
562
b3080599 563 log("deconfigure ipdev %s on %s" % (ipdev,bridge))
a4af0040
JP
564 vsctl_argv += ["# deconfigure ipdev %s" % ipdev]
565 vsctl_argv += datapath_deconfigure_ipdev(ipdev)
b3080599
IC
566
567 if pif_is_vlan(self._pif):
7966caf4
BP
568 # Delete the VLAN bridge.
569 vsctl_argv += deconfigure_bridge(self._pif)
570
b3080599
IC
571 # If the VLAN's slave is attached, leave datapath setup.
572 slave = pif_get_vlan_slave(self._pif)
573 if db().get_pif_record(slave)['currently_attached']:
574 log("action_down: vlan slave is currently attached")
575 dp = None
576
577 # If the VLAN's slave has other VLANs that are attached, leave datapath setup.
578 for master in pif_get_vlan_masters(slave):
579 if master != self._pif and db().get_pif_record(master)['currently_attached']:
580 log("action_down: vlan slave has other master: %s" % pif_netdev_name(master))
581 dp = None
582
583 # Otherwise, take down the datapath too (fall through)
584 if dp:
585 log("action_down: no more masters, bring down slave %s" % bridge)
586 else:
587 # Stop here if this PIF has attached VLAN masters.
588 masters = [db().get_pif_record(m)['VLAN'] for m in pif_get_vlan_masters(self._pif) if db().get_pif_record(m)['currently_attached']]
589 if len(masters) > 0:
590 log("Leaving datapath %s up due to currently attached VLAN masters %s" % (bridge, masters))
591 dp = None
592
593 if dp:
7966caf4 594 vsctl_argv += deconfigure_bridge(dp)
56cac225 595
df9a459a
IC
596 physical_devices = [pif_netdev_name(p) for p in datapath_get_physical_pifs(dp)]
597
598 log("action_down: bring down physical devices - %s" % physical_devices)
599
600 for p in physical_devices:
601 netdev_down(p)
602
56cac225 603 datapath_modify_config(vsctl_argv)