]>
Commit | Line | Data |
---|---|---|
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 | # | |
14 | from InterfaceReconfigure import * | |
ab32de00 | 15 | import os |
47a3c536 | 16 | import re |
b3080599 IC |
17 | |
18 | # | |
19 | # Bare Network Devices -- network devices without IP configuration | |
20 | # | |
21 | ||
22 | def 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 | ||
29 | def 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 | ||
45 | def 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 | ||
71 | def pif_datapath(pif): | |
72 | """Return the datapath PIF associated with PIF. | |
3b1acc99 BP |
73 | A non-VLAN PIF is its own datapath PIF, except that a bridgeless PIF has |
74 | no datapath PIF at all. | |
75 | A 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 | ||
87 | def datapath_get_physical_pifs(pif): | |
88 | """Return the PIFs for the physical network device(s) associated with a datapath PIF. | |
89 | For a bond master PIF, these are the bond slave PIFs. | |
90 | For a non-VLAN, non-bond master PIF, the PIF is its own physical device PIF. | |
91 | ||
92 | A 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 | ||
104 | def datapath_deconfigure_physical(netdev): | |
7c79588e | 105 | return ['--', '--with-iface', '--if-exists', 'del-port', netdev] |
b3080599 | 106 | |
47a3c536 BP |
107 | def 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 |
131 | def datapath_configure_tunnel(pif): |
132 | pass | |
133 | ||
b3080599 | 134 | def 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 | ||
220 | def datapath_deconfigure_bond(netdev): | |
7c79588e | 221 | return ['--', '--with-iface', '--if-exists', 'del-port', netdev] |
b3080599 IC |
222 | |
223 | def datapath_deconfigure_ipdev(interface): | |
7c79588e | 224 | return ['--', '--with-iface', '--if-exists', 'del-port', interface] |
b3080599 IC |
225 | |
226 | def 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 |
241 | def 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 | 384 | def 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 | 396 | def 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 | ||
430 | class 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) |