]> git.proxmox.com Git - mirror_ovs.git/blame - xenserver/opt_xensource_libexec_InterfaceReconfigureVswitch.py
ovsdb: Use column diffs for ovsdb and raft log entries.
[mirror_ovs.git] / xenserver / opt_xensource_libexec_InterfaceReconfigureVswitch.py
CommitLineData
431488e6 1# Copyright (c) 2008,2009,2011 Citrix Systems, Inc.
0b2c7e69 2# Copyright (c) 2009,2010,2011,2012,2013,2017 Nicira, Inc.
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
da7198b4 17import subprocess
b3080599
IC
18
19#
20# Bare Network Devices -- network devices without IP configuration
21#
22
23def netdev_down(netdev):
24 """Bring down a bare network device"""
25 if not netdev_exists(netdev):
26 log("netdev: down: device %s does not exist, ignoring" % netdev)
27 return
0b2c7e69 28 run_command(["/sbin/ip", "link", "set", netdev, 'down'])
b3080599
IC
29
30def netdev_up(netdev, mtu=None):
31 """Bring up a bare network device"""
32 if not netdev_exists(netdev):
33 raise Error("netdev: up: device %s does not exist" % netdev)
34
35 if mtu:
36 mtu = ["mtu", mtu]
37 else:
38 mtu = []
39
0b2c7e69 40 run_command(["/sbin/ip", "link", "set", netdev, 'up'] + mtu)
b3080599 41
431488e6
BP
42# This is a list of drivers that do support VLAN tx or rx acceleration, but
43# to which the VLAN bug workaround should not be applied. This could be
44# because these are known-good drivers (that is, they do not have any of
45# the bugs that the workaround avoids) or because the VLAN bug workaround
46# will not work for them and may cause other problems.
47#
48# This is a very short list because few drivers have been tested.
49NO_VLAN_WORKAROUND_DRIVERS = (
50 "bonding",
51)
52def netdev_get_driver_name(netdev):
53 """Returns the name of the driver for network device 'netdev'"""
54 symlink = '%s/sys/class/net/%s/device/driver' % (root_prefix(), netdev)
55 try:
56 target = os.readlink(symlink)
fc35b165 57 except OSError as e:
431488e6
BP
58 log("%s: could not read netdev's driver name (%s)" % (netdev, e))
59 return None
60
61 slash = target.rfind('/')
62 if slash < 0:
63 log("target %s of symbolic link %s does not contain slash"
64 % (target, symlink))
65 return None
66
67 return target[slash + 1:]
68
69def netdev_get_features(netdev):
70 """Returns the features bitmap for the driver for 'netdev'.
71 The features bitmap is a set of NETIF_F_ flags supported by its driver."""
72 try:
73 features = open("%s/sys/class/net/%s/features" % (root_prefix(), netdev)).read().strip()
74 return int(features, 0)
75 except:
76 return 0 # interface prolly doesn't exist
77
78def netdev_has_vlan_accel(netdev):
79 """Returns True if 'netdev' supports VLAN acceleration, False otherwise."""
80 NETIF_F_HW_VLAN_TX = 128
81 NETIF_F_HW_VLAN_RX = 256
82 NETIF_F_VLAN = NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX
83 return (netdev_get_features(netdev) & NETIF_F_VLAN) != 0
84
b3080599
IC
85#
86# PIF miscellanea
87#
88
89def pif_currently_in_use(pif):
90 """Determine if a PIF is currently in use.
91
92 A PIF is determined to be currently in use if
93 - PIF.currently-attached is true
94 - Any bond master is currently attached
95 - Any VLAN master is currently attached
96 """
97 rec = db().get_pif_record(pif)
98 if rec['currently_attached']:
99 log("configure_datapath: %s is currently attached" % (pif_netdev_name(pif)))
100 return True
101 for b in pif_get_bond_masters(pif):
102 if pif_currently_in_use(b):
103 log("configure_datapath: %s is in use by BOND master %s" % (pif_netdev_name(pif),pif_netdev_name(b)))
104 return True
105 for v in pif_get_vlan_masters(pif):
106 if pif_currently_in_use(v):
107 log("configure_datapath: %s is in use by VLAN master %s" % (pif_netdev_name(pif),pif_netdev_name(v)))
108 return True
109 return False
110
111#
112# Datapath Configuration
113#
114
115def pif_datapath(pif):
116 """Return the datapath PIF associated with PIF.
3b1acc99
BP
117A non-VLAN PIF is its own datapath PIF, except that a bridgeless PIF has
118no datapath PIF at all.
119A VLAN PIF's datapath PIF is its VLAN slave's datapath PIF.
b3080599
IC
120"""
121 if pif_is_vlan(pif):
122 return pif_datapath(pif_get_vlan_slave(pif))
123
124 pifrec = db().get_pif_record(pif)
125 nwrec = db().get_network_record(pifrec['network'])
126 if not nwrec['bridge']:
127 return None
128 else:
129 return pif
130
131def datapath_get_physical_pifs(pif):
132 """Return the PIFs for the physical network device(s) associated with a datapath PIF.
133For a bond master PIF, these are the bond slave PIFs.
134For a non-VLAN, non-bond master PIF, the PIF is its own physical device PIF.
135
136A VLAN PIF cannot be a datapath PIF.
137"""
92e906e4
IC
138 if pif_is_tunnel(pif):
139 return []
140 elif pif_is_vlan(pif):
b3080599
IC
141 # Seems like overkill...
142 raise Error("get-physical-pifs should not get passed a VLAN")
143 elif pif_is_bond(pif):
144 return pif_get_bond_slaves(pif)
145 else:
146 return [pif]
147
148def datapath_deconfigure_physical(netdev):
7c79588e 149 return ['--', '--with-iface', '--if-exists', 'del-port', netdev]
b3080599 150
47a3c536
BP
151def vsctl_escape(s):
152 if s.isalnum():
153 return s
154
155 def escape(match):
156 c = match.group(0)
157 if c == '\0':
158 raise Error("strings may not contain null bytes")
159 elif c == '\\':
160 return r'\\'
161 elif c == '\n':
162 return r'\n'
163 elif c == '\r':
164 return r'\r'
165 elif c == '\t':
166 return r'\t'
167 elif c == '\b':
168 return r'\b'
169 elif c == '\a':
170 return r'\a'
171 else:
172 return r'\x%02x' % ord(c)
173 return '"' + re.sub(r'["\\\000-\037]', escape, s) + '"'
174
92e906e4
IC
175def datapath_configure_tunnel(pif):
176 pass
177
b3080599 178def datapath_configure_bond(pif,slaves):
a4af0040 179 bridge = pif_bridge_name(pif)
e91087c7 180 pifrec = db().get_pif_record(pif)
b3080599
IC
181 interface = pif_netdev_name(pif)
182
a4af0040
JP
183 argv = ['--', '--fake-iface', 'add-bond', bridge, interface]
184 for slave in slaves:
185 argv += [pif_netdev_name(slave)]
b3080599 186
b3080599
IC
187 # Bonding options.
188 bond_options = {
189 "mode": "balance-slb",
190 "miimon": "100",
191 "downdelay": "200",
192 "updelay": "31000",
193 "use_carrier": "1",
2776e408 194 "hashing-algorithm": "src_mac",
b3080599
IC
195 }
196 # override defaults with values from other-config whose keys
197 # being with "bond-"
198 oc = pifrec['other_config']
cb1e1737
JS
199 overrides = filter(lambda key_val:
200 key_val[0].startswith("bond-"), oc.items())
201 overrides = map(lambda key_val: (key_val[0][5:], key_val[1]), overrides)
b3080599 202 bond_options.update(overrides)
2776e408
EJ
203 mode = None
204 halgo = None
47a3c536
BP
205
206 argv += ['--', 'set', 'Port', interface]
207 if pifrec['MAC'] != "":
208 argv += ['MAC=%s' % vsctl_escape(pifrec['MAC'])]
8b35f045 209 for (name,val) in sorted(bond_options.items()):
47a3c536
BP
210 if name in ['updelay', 'downdelay']:
211 # updelay and downdelay have dedicated schema columns.
212 # The value must be a nonnegative integer.
213 try:
214 value = int(val)
215 if value < 0:
216 raise ValueError
217
218 argv += ['bond_%s=%d' % (name, value)]
219 except ValueError:
220 log("bridge %s has invalid %s '%s'" % (bridge, name, value))
b9b627d5
EJ
221 elif name in ['miimon', 'use_carrier']:
222 try:
223 value = int(val)
224 if value < 0:
225 raise ValueError
226
227 if name == 'use_carrier':
228 if value:
229 value = "carrier"
230 else:
231 value = "miimon"
232 argv += ["other-config:bond-detect-mode=%s" % value]
233 else:
234 argv += ["other-config:bond-miimon-interval=%d" % value]
235 except ValueError:
236 log("bridge %s has invalid %s '%s'" % (bridge, name, value))
aa98d0cd 237 elif name == "mode":
2776e408
EJ
238 mode = val
239 elif name == "hashing-algorithm":
240 halgo = val
47a3c536
BP
241 else:
242 # Pass other bond options into other_config.
243 argv += ["other-config:%s=%s" % (vsctl_escape("bond-%s" % name),
244 vsctl_escape(val))]
2776e408
EJ
245
246 if mode == 'lacp':
247 argv += ['lacp=active']
248
249 if halgo == 'src_mac':
250 argv += ['bond_mode=balance-slb']
251 elif halgo == "tcpudp_ports":
252 argv += ['bond_mode=balance-tcp']
253 else:
254 log("bridge %s has invalid bond-hashing-algorithm '%s'" % (bridge, halgo))
255 argv += ['bond_mode=balance-slb']
256 elif mode in ['balance-slb', 'active-backup']:
257 argv += ['lacp=off', 'bond_mode=%s' % mode]
258 else:
259 log("bridge %s has invalid bond-mode '%s'" % (bridge, mode))
260 argv += ['lacp=off', 'bond_mode=balance-slb']
261
b3080599
IC
262 return argv
263
264def datapath_deconfigure_bond(netdev):
7c79588e 265 return ['--', '--with-iface', '--if-exists', 'del-port', netdev]
b3080599
IC
266
267def datapath_deconfigure_ipdev(interface):
7c79588e 268 return ['--', '--with-iface', '--if-exists', 'del-port', interface]
b3080599
IC
269
270def datapath_modify_config(commands):
13ffee26
JP
271 #log("modifying configuration:")
272 #for c in commands:
273 # log(" %s" % c)
a4af0040
JP
274
275 rc = run_command(['/usr/bin/ovs-vsctl'] + ['--timeout=20']
276 + [c for c in commands if not c.startswith('#')])
277 if not rc:
b3080599 278 raise Error("Failed to modify vswitch configuration")
b3080599
IC
279 return True
280
281#
282# Toplevel Datapath Configuration.
283#
284
d77ffabf
BP
285def configure_datapath(pif):
286 """Bring up the configuration for 'pif', which must not be a VLAN PIF, by:
287 - Tearing down other PIFs that use the same physical devices as 'pif'.
288 - Ensuring that 'pif' itself is set up.
289 - *Not* tearing down any PIFs that are stacked on top of 'pif' (i.e. VLANs
290 on top of 'pif'.
b3080599
IC
291
292 Returns a tuple containing
a4af0040 293 - A list containing the necessary vsctl command line arguments
b3080599
IC
294 - A list of additional devices which should be brought up after
295 the configuration is applied.
da7198b4
DT
296 - A list containing flows to apply to the pif bridge, note that
297 port numbers may need to be substituted once ofport is known
b3080599
IC
298 """
299
a4af0040 300 vsctl_argv = []
b3080599 301 extra_up_ports = []
da7198b4 302 bridge_flows = []
b3080599 303
86e1bb44 304 assert not pif_is_vlan(pif)
b3080599
IC
305 bridge = pif_bridge_name(pif)
306
307 physical_devices = datapath_get_physical_pifs(pif)
308
86e1bb44
BP
309 vsctl_argv += ['## configuring datapath %s' % bridge]
310
b3080599
IC
311 # Determine additional devices to deconfigure.
312 #
313 # Given all physical devices which are part of this PIF we need to
314 # consider:
315 # - any additional bond which a physical device is part of.
316 # - any additional physical devices which are part of an additional bond.
317 #
318 # Any of these which are not currently in use should be brought
319 # down and deconfigured.
320 extra_down_bonds = []
321 extra_down_ports = []
322 for p in physical_devices:
323 for bond in pif_get_bond_masters(p):
324 if bond == pif:
325 log("configure_datapath: leaving bond %s up" % pif_netdev_name(bond))
326 continue
327 if bond in extra_down_bonds:
328 continue
329 if db().get_pif_record(bond)['currently_attached']:
330 log("configure_datapath: implicitly tearing down currently-attached bond %s" % pif_netdev_name(bond))
331
332 extra_down_bonds += [bond]
333
334 for s in pif_get_bond_slaves(bond):
335 if s in physical_devices:
336 continue
337 if s in extra_down_ports:
338 continue
339 if pif_currently_in_use(s):
340 continue
341 extra_down_ports += [s]
342
343 log("configure_datapath: bridge - %s" % bridge)
344 log("configure_datapath: physical - %s" % [pif_netdev_name(p) for p in physical_devices])
345 log("configure_datapath: extra ports - %s" % [pif_netdev_name(p) for p in extra_down_ports])
346 log("configure_datapath: extra bonds - %s" % [pif_netdev_name(p) for p in extra_down_bonds])
347
348 # Need to fully deconfigure any bridge which any of the:
349 # - physical devices
350 # - bond devices
351 # - sibling devices
352 # refers to
353 for brpif in physical_devices + extra_down_ports + extra_down_bonds:
354 if brpif == pif:
355 continue
356 b = pif_bridge_name(brpif)
357 #ifdown(b)
358 # XXX
359 netdev_down(b)
a4af0040
JP
360 vsctl_argv += ['# remove bridge %s' % b]
361 vsctl_argv += ['--', '--if-exists', 'del-br', b]
b3080599
IC
362
363 for n in extra_down_ports:
364 dev = pif_netdev_name(n)
a4af0040
JP
365 vsctl_argv += ['# deconfigure sibling physical device %s' % dev]
366 vsctl_argv += datapath_deconfigure_physical(dev)
b3080599
IC
367 netdev_down(dev)
368
369 for n in extra_down_bonds:
370 dev = pif_netdev_name(n)
a4af0040
JP
371 vsctl_argv += ['# deconfigure bond device %s' % dev]
372 vsctl_argv += datapath_deconfigure_bond(dev)
b3080599
IC
373 netdev_down(dev)
374
375 for p in physical_devices:
376 dev = pif_netdev_name(p)
a4af0040
JP
377 vsctl_argv += ['# deconfigure physical port %s' % dev]
378 vsctl_argv += datapath_deconfigure_physical(dev)
379
d77ffabf 380 vsctl_argv += ['--', '--may-exist', 'add-br', bridge]
13ffee26 381
b3080599 382 if len(physical_devices) > 1:
a4af0040
JP
383 vsctl_argv += ['# deconfigure bond %s' % pif_netdev_name(pif)]
384 vsctl_argv += datapath_deconfigure_bond(pif_netdev_name(pif))
385 vsctl_argv += ['# configure bond %s' % pif_netdev_name(pif)]
386 vsctl_argv += datapath_configure_bond(pif, physical_devices)
b3080599 387 extra_up_ports += [pif_netdev_name(pif)]
92e906e4 388 elif len(physical_devices) == 1:
b3080599 389 iface = pif_netdev_name(physical_devices[0])
a4af0040 390 vsctl_argv += ['# add physical device %s' % iface]
7b09e426 391 vsctl_argv += ['--', '--may-exist', 'add-port', bridge, iface]
92e906e4
IC
392 elif pif_is_tunnel(pif):
393 datapath_configure_tunnel(pif)
b3080599 394
16f2ae57
IC
395 vsctl_argv += ['# configure Bridge MAC']
396 vsctl_argv += ['--', 'set', 'Bridge', bridge,
397 'other-config:hwaddr=%s' % vsctl_escape(db().get_pif_record(pif)['MAC'])]
398
939e5a1b 399 pool = db().get_pool_record()
2dd26837 400 network = db().get_network_by_bridge(bridge)
da54975c 401 network_rec = None
2dd26837
EJ
402 fail_mode = None
403 valid_fail_modes = ['standalone', 'secure']
0671665d 404
2dd26837
EJ
405 if network:
406 network_rec = db().get_network_record(network)
407 fail_mode = network_rec['other_config'].get('vswitch-controller-fail-mode')
408
409 if (fail_mode not in valid_fail_modes) and pool:
c2875f43 410 fail_mode = pool['other_config'].get('vswitch-controller-fail-mode')
da7198b4
DT
411 # Add default flows to allow management traffic if fail-mode
412 # transitions to secure based on pool fail-mode setting
413 if fail_mode == 'secure' and db().get_pif_record(pif).get('management', False):
414 prev_fail_mode = vswitchCfgQuery(['get-fail-mode', bridge])
415 if prev_fail_mode != 'secure':
416 tp = 'idle_timeout=0,priority=0'
417 host_mgmt_mac = db().get_pif_record(pif)['MAC']
418 # account for bond as management interface
419 if len(physical_devices) > 1:
420 bridge_flows += ['%s,in_port=local,arp,dl_src=%s,actions=NORMAL' % (tp, host_mgmt_mac)]
421 bridge_flows += ['%s,in_port=local,dl_src=%s,actions=NORMAL' % (tp, host_mgmt_mac)]
422 # we don't know slave ofports yet, substitute later
423 bridge_flows += ['%s,in_port=%%s,arp,nw_proto=1,actions=local' % (tp)]
424 bridge_flows += ['%s,in_port=%%s,dl_dst=%s,actions=local' % (tp, host_mgmt_mac)]
425 else:
426 bridge_flows += ['%s,in_port=%%s,arp,nw_proto=1,actions=local' % (tp)]
427 bridge_flows += ['%s,in_port=local,arp,dl_src=%s,actions=%%s' % (tp, host_mgmt_mac)]
428 bridge_flows += ['%s,in_port=%%s,dl_dst=%s,actions=local' % (tp, host_mgmt_mac)]
429 bridge_flows += ['%s,in_port=local,dl_src=%s,actions=%%s' % (tp, host_mgmt_mac)]
2dd26837
EJ
430
431 if fail_mode not in valid_fail_modes:
0671665d 432 fail_mode = 'standalone'
939e5a1b 433
2dd26837 434 vsctl_argv += ['--', 'set', 'Bridge', bridge, 'fail_mode=%s' % fail_mode]
939e5a1b 435
da54975c
AE
436 if network_rec:
437 dib = network_rec['other_config'].get('vswitch-disable-in-band')
438 if not dib:
439 vsctl_argv += ['--', 'remove', 'Bridge', bridge, 'other_config', 'disable-in-band']
440 elif dib in ['true', 'false']:
441 vsctl_argv += ['--', 'set', 'Bridge', bridge, 'other_config:disable-in-band=' + dib]
442 else:
443 log('"' + dib + '"' "isn't a valid setting for other_config:disable-in-band on " + bridge)
444
c0a50086 445 vsctl_argv += set_br_external_ids(pif)
86e1bb44
BP
446 vsctl_argv += ['## done configuring datapath %s' % bridge]
447
da7198b4 448 return vsctl_argv,extra_up_ports,bridge_flows
b3080599 449
7966caf4 450def deconfigure_bridge(pif):
a4af0040 451 vsctl_argv = []
b3080599
IC
452
453 bridge = pif_bridge_name(pif)
454
2a75efe8 455 log("deconfigure_bridge: bridge - %s" % bridge)
b3080599 456
a4af0040
JP
457 vsctl_argv += ['# deconfigure bridge %s' % bridge]
458 vsctl_argv += ['--', '--if-exists', 'del-br', bridge]
b3080599 459
a4af0040 460 return vsctl_argv
b3080599 461
c0a50086 462def set_br_external_ids(pif):
47a3c536
BP
463 pifrec = db().get_pif_record(pif)
464 dp = pif_datapath(pif)
465 dprec = db().get_pif_record(dp)
466
c0a50086 467 xs_network_uuids = []
47a3c536 468 for nwpif in db().get_pifs_by_device(pifrec['device']):
c0a50086
BP
469 rec = db().get_pif_record(nwpif)
470
471 # When state is read from dbcache PIF.currently_attached
472 # is always assumed to be false... Err on the side of
473 # listing even detached networks for the time being.
474 #if nwpif != pif and not rec['currently_attached']:
475 # log("Network PIF %s not currently attached (%s)" % (rec['uuid'],pifrec['uuid']))
476 # continue
477 nwrec = db().get_network_record(rec['network'])
b13300c7
EJ
478
479 uuid = nwrec['uuid']
480 if pif_is_vlan(nwpif):
481 xs_network_uuids.append(uuid)
482 else:
483 xs_network_uuids.insert(0, uuid)
c0a50086
BP
484
485 vsctl_argv = []
c76fde78 486 vsctl_argv += ['# configure xs-network-uuids']
c0a50086 487 vsctl_argv += ['--', 'br-set-external-id', pif_bridge_name(pif),
c76fde78 488 'xs-network-uuids', ';'.join(xs_network_uuids)]
47a3c536 489
c0a50086
BP
490 return vsctl_argv
491
b3080599
IC
492#
493#
494#
495
496class DatapathVswitch(Datapath):
497 def __init__(self, pif):
498 Datapath.__init__(self, pif)
499 self._dp = pif_datapath(pif)
500 self._ipdev = pif_ipdev_name(pif)
da7198b4 501 self._bridge_flows = []
b3080599
IC
502
503 if pif_is_vlan(pif) and not self._dp:
504 raise Error("Unbridged VLAN devices not implemented yet")
505
506 log("Configured for Vswitch datapath")
507
823c5699
IC
508 @classmethod
509 def rewrite(cls):
ab32de00
BP
510 if not os.path.exists("/var/run/openvswitch/db.sock"):
511 # ovsdb-server is not running, so we can't update the database.
512 # Probably we are being called as part of system shutdown. Just
513 # skip the update, since the external-ids will be updated on the
514 # next boot anyhow.
515 return
516
823c5699
IC
517 vsctl_argv = []
518 for pif in db().get_all_pifs():
519 pifrec = db().get_pif_record(pif)
520 if not pif_is_vlan(pif) and pifrec['currently_attached']:
521 vsctl_argv += set_br_external_ids(pif)
522
523 if vsctl_argv != []:
524 datapath_modify_config(vsctl_argv)
525
b3080599
IC
526 def configure_ipdev(self, cfg):
527 cfg.write("TYPE=Ethernet\n")
528
529 def preconfigure(self, parent):
a4af0040 530 vsctl_argv = []
b3080599 531 extra_ports = []
da7198b4 532 bridge_flows = []
b3080599
IC
533
534 pifrec = db().get_pif_record(self._pif)
66aeba23 535 dprec = db().get_pif_record(self._dp)
b3080599
IC
536
537 ipdev = self._ipdev
da7198b4 538 c,e,f = configure_datapath(self._dp)
d77ffabf 539 bridge = pif_bridge_name(self._pif)
a4af0040 540 vsctl_argv += c
b3080599 541 extra_ports += e
da7198b4 542 bridge_flows += f
b3080599 543
16f2ae57
IC
544 dpname = pif_bridge_name(self._dp)
545
d77ffabf 546 if pif_is_vlan(self._pif):
9ec4d255
EJ
547 # In some cases XAPI may misguidedly leave an instance of
548 # 'bridge' which should be deleted.
549 vsctl_argv += ['--', '--if-exists', 'del-br', bridge]
550
d77ffabf
BP
551 # configure_datapath() set up the underlying datapath bridge.
552 # Stack a VLAN bridge on top of it.
553 vsctl_argv += ['--', '--may-exist', 'add-br',
16f2ae57 554 bridge, dpname, pifrec['VLAN']]
c0a50086
BP
555
556 vsctl_argv += set_br_external_ids(self._pif)
a4af0040 557
13ffee26
JP
558 if ipdev != bridge:
559 vsctl_argv += ["# deconfigure ipdev %s" % ipdev]
560 vsctl_argv += datapath_deconfigure_ipdev(ipdev)
561 vsctl_argv += ["# reconfigure ipdev %s" % ipdev]
562 vsctl_argv += ['--', 'add-port', bridge, ipdev]
a4af0040 563
16f2ae57
IC
564 if ipdev != dpname:
565 vsctl_argv += ['# configure Interface MAC']
566 vsctl_argv += ['--', 'set', 'Interface', pif_ipdev_name(self._pif),
567 'MAC=%s' % vsctl_escape(dprec['MAC'])]
568
a4af0040 569 self._vsctl_argv = vsctl_argv
b3080599 570 self._extra_ports = extra_ports
da7198b4 571 self._bridge_flows = bridge_flows
b3080599
IC
572
573 def bring_down_existing(self):
fe19e820
BP
574 # interface-reconfigure is never explicitly called to down a
575 # bond master. However, when we are called to up a slave it
f51c1d98
BP
576 # is implicit that we are destroying the master. Conversely,
577 # when we are called to up a bond is is implicit that we are
578 # taking down the slaves.
fe19e820 579 #
f51c1d98
BP
580 # This is (only) important in the case where the device being
581 # implicitly taken down uses DHCP. We need to kill the
582 # dhclient process, otherwise performing the inverse operation
583 # later later will fail because ifup will refuse to start a
584 # duplicate dhclient.
fe19e820
BP
585 bond_masters = pif_get_bond_masters(self._pif)
586 for master in bond_masters:
587 log("action_up: bring down bond master %s" % (pif_netdev_name(master)))
588 run_command(["/sbin/ifdown", pif_bridge_name(master)])
b3080599 589
f51c1d98
BP
590 bond_slaves = pif_get_bond_slaves(self._pif)
591 for slave in bond_slaves:
592 log("action_up: bring down bond slave %s" % (pif_netdev_name(slave)))
593 run_command(["/sbin/ifdown", pif_bridge_name(slave)])
594
b3080599
IC
595 def configure(self):
596 # Bring up physical devices. ovs-vswitchd initially enables or
597 # disables bond slaves based on whether carrier is detected
598 # when they are added, and a network device that is down
599 # always reports "no carrier".
600 physical_devices = datapath_get_physical_pifs(self._dp)
c64540e3
EJ
601
602 if pif_is_bond(self._dp):
603 brec = db().get_pif_record(self._dp)
604 bond_mtu = mtu_setting(brec['network'], "PIF", brec['other_config'])
605 else:
606 bond_mtu = None
b3080599
IC
607
608 for p in physical_devices:
9a2b1175
IC
609 prec = db().get_pif_record(p)
610 oc = prec['other_config']
b3080599
IC
611
612 dev = pif_netdev_name(p)
613
c64540e3
EJ
614 if bond_mtu:
615 mtu = bond_mtu
616 else:
617 mtu = mtu_setting(prec['network'], "PIF", oc)
b3080599
IC
618
619 netdev_up(dev, mtu)
620
404c1692 621 settings, offload = ethtool_settings(oc, PIF_OTHERCONFIG_DEFAULTS)
b3080599
IC
622 if len(settings):
623 run_command(['/sbin/ethtool', '-s', dev] + settings)
624 if len(offload):
625 run_command(['/sbin/ethtool', '-K', dev] + offload)
626
431488e6
BP
627 driver = netdev_get_driver_name(dev)
628 if 'vlan-bug-workaround' in oc:
629 vlan_bug_workaround = oc['vlan-bug-workaround'] == 'true'
630 elif driver in NO_VLAN_WORKAROUND_DRIVERS:
631 vlan_bug_workaround = False
632 else:
633 vlan_bug_workaround = netdev_has_vlan_accel(dev)
634
a4af0040 635 datapath_modify_config(self._vsctl_argv)
da7198b4
DT
636 if self._bridge_flows:
637 ofports = []
638 physical_devices = datapath_get_physical_pifs(self._dp)
639 if len(physical_devices) > 1:
640 for slave in physical_devices:
641 name = pif_netdev_name(slave)
642 ofport = vswitchCfgQuery(['get', 'interface', name, 'ofport'])
643 ofports.append(ofport)
644 else:
645 name = pif_netdev_name(self._dp)
646 ofport = vswitchCfgQuery(['get', 'interface', name, 'ofport'])
647 ofports.append(ofport)
648 dpname = pif_bridge_name(self._dp)
649 for flow in self._bridge_flows:
650 if flow.find('in_port=%s') != -1 or flow.find('actions=%s') != -1:
651 for port in ofports:
1ea636ec 652 f = flow % (port.decode())
da7198b4
DT
653 run_command(['/usr/bin/ovs-ofctl', 'add-flow', dpname, f])
654 else:
655 run_command(['/usr/bin/ovs-ofctl', 'add-flow', dpname, flow])
b3080599
IC
656
657 def post(self):
658 for p in self._extra_ports:
659 log("action_up: bring up %s" % p)
660 netdev_up(p)
661
662 def bring_down(self):
a4af0040 663 vsctl_argv = []
b3080599
IC
664
665 dp = self._dp
666 ipdev = self._ipdev
667
668 bridge = pif_bridge_name(dp)
669
b3080599 670 log("deconfigure ipdev %s on %s" % (ipdev,bridge))
a4af0040
JP
671 vsctl_argv += ["# deconfigure ipdev %s" % ipdev]
672 vsctl_argv += datapath_deconfigure_ipdev(ipdev)
b3080599
IC
673
674 if pif_is_vlan(self._pif):
7966caf4
BP
675 # Delete the VLAN bridge.
676 vsctl_argv += deconfigure_bridge(self._pif)
677
b3080599
IC
678 # If the VLAN's slave is attached, leave datapath setup.
679 slave = pif_get_vlan_slave(self._pif)
680 if db().get_pif_record(slave)['currently_attached']:
681 log("action_down: vlan slave is currently attached")
682 dp = None
683
684 # If the VLAN's slave has other VLANs that are attached, leave datapath setup.
685 for master in pif_get_vlan_masters(slave):
686 if master != self._pif and db().get_pif_record(master)['currently_attached']:
687 log("action_down: vlan slave has other master: %s" % pif_netdev_name(master))
688 dp = None
689
690 # Otherwise, take down the datapath too (fall through)
691 if dp:
692 log("action_down: no more masters, bring down slave %s" % bridge)
693 else:
694 # Stop here if this PIF has attached VLAN masters.
695 masters = [db().get_pif_record(m)['VLAN'] for m in pif_get_vlan_masters(self._pif) if db().get_pif_record(m)['currently_attached']]
696 if len(masters) > 0:
697 log("Leaving datapath %s up due to currently attached VLAN masters %s" % (bridge, masters))
698 dp = None
699
700 if dp:
7966caf4 701 vsctl_argv += deconfigure_bridge(dp)
56cac225 702
df9a459a
IC
703 physical_devices = [pif_netdev_name(p) for p in datapath_get_physical_pifs(dp)]
704
705 log("action_down: bring down physical devices - %s" % physical_devices)
706
707 for p in physical_devices:
708 netdev_down(p)
709
56cac225 710 datapath_modify_config(vsctl_argv)
da7198b4
DT
711
712#
713# utility methods
714#
715
716def vswitchCfgQuery(action_args):
717 cmd = ['%s/usr/bin/ovs-vsctl' % root_prefix(),
fba6bd1d 718 '-vconsole:off'] + action_args
da7198b4
DT
719 output = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()
720 if len(output) == 0 or output[0] == None:
721 output = ""
722 else:
723 output = output[0].strip()
724 return output