]>
Commit | Line | Data |
---|---|---|
35681c06 | 1 | #!/usr/bin/env python3 |
3e8ee54f | 2 | # |
d486dd0d | 3 | # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved. |
3e8ee54f | 4 | # Author: Roopa Prabhu, roopa@cumulusnetworks.com |
5 | # | |
6 | # ifaceScheduler -- | |
7 | # interface scheduler | |
8 | # | |
a6f80f0e | 9 | |
739f9c7e | 10 | import os |
69f58278 | 11 | import sys |
d486dd0d | 12 | |
d486dd0d JF |
13 | try: |
14 | from ifupdown2.ifupdown.graph import * | |
d486dd0d JF |
15 | from ifupdown2.ifupdown.iface import * |
16 | from ifupdown2.ifupdown.utils import utils | |
17 | from ifupdown2.ifupdown.statemanager import * | |
18 | ||
223ba5af | 19 | import ifupdown2.ifupdown.policymanager as policymanager |
d486dd0d | 20 | import ifupdown2.ifupdown.ifupdownflags as ifupdownflags |
bd441a51 | 21 | except (ImportError, ModuleNotFoundError): |
d486dd0d | 22 | from ifupdown.graph import * |
d486dd0d JF |
23 | from ifupdown.iface import * |
24 | from ifupdown.utils import utils | |
25 | from ifupdown.statemanager import * | |
26 | ||
27 | import ifupdown.ifupdownflags as ifupdownflags | |
223ba5af | 28 | import ifupdown.policymanager as policymanager |
d486dd0d JF |
29 | |
30 | ||
d08d5f54 | 31 | class ifaceSchedulerFlags(): |
904908bc RP |
32 | """ Enumerates scheduler flags """ |
33 | ||
c798b0f4 | 34 | INORDER = 0x1 |
35 | POSTORDER = 0x2 | |
d08d5f54 | 36 | |
be0b20f2 | 37 | class ifaceScheduler(): |
38 | """ scheduler functions to schedule configuration of interfaces. | |
a6f80f0e | 39 | |
a6f80f0e | 40 | supports scheduling of interfaces serially in plain interface list |
41 | or dependency graph format. | |
99b212b0 | 42 | |
a6f80f0e | 43 | """ |
44 | ||
c798b0f4 | 45 | _STATE_CHECK = True |
46 | ||
2009513f RP |
47 | _SCHED_STATUS = True |
48 | ||
223ba5af JF |
49 | VRF_MGMT_DEVNAME = policymanager.policymanager_api.get_module_globals( |
50 | module_name="vrf", | |
51 | attr="vrf-mgmt-devname" | |
52 | ) | |
53 | ||
d486dd0d JF |
54 | @classmethod |
55 | def reset(cls): | |
56 | cls._STATE_CHECK = True | |
57 | cls._SCHED_STATUS = True | |
58 | ||
2009513f RP |
59 | @classmethod |
60 | def get_sched_status(cls): | |
61 | return cls._SCHED_STATUS | |
5973036b | 62 | |
892c495e RP |
63 | @classmethod |
64 | def set_sched_status(cls, state): | |
65 | cls._SCHED_STATUS = state | |
66 | ||
be0b20f2 | 67 | @classmethod |
6e16e5ae | 68 | def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv=None): |
a6f80f0e | 69 | """ Runs sub operation on an interface """ |
62ddec8b | 70 | ifacename = ifaceobj.name |
a6f80f0e | 71 | |
3e6ea735 | 72 | if ifupdownobj.type and ifupdownobj.type != ifaceobj.type: |
2da58137 RP |
73 | return |
74 | ||
dbc018d3 | 75 | if not ifupdownobj.flags.ADDONS_ENABLE: return |
44a6ca06 RP |
76 | if op == 'query-checkcurr': |
77 | query_ifaceobj=ifupdownobj.create_n_save_ifaceobjcurr(ifaceobj) | |
16d854b4 RP |
78 | # If not type bridge vlan and the object does not exist, |
79 | # mark not found and return | |
80 | if (not ifupdownobj.link_exists(ifaceobj.name) and | |
81 | ifaceobj.type != ifaceType.BRIDGE_VLAN): | |
82 | query_ifaceobj.set_state_n_status(ifaceState.from_str(op), | |
83 | ifaceStatus.NOTFOUND) | |
84 | return | |
be0b20f2 | 85 | for mname in ifupdownobj.module_ops.get(op): |
37c0543d | 86 | m = ifupdownobj.modules.get(mname) |
a6f80f0e | 87 | err = 0 |
88 | try: | |
d08d5f54 | 89 | if hasattr(m, 'run'): |
a690dfae | 90 | msg = ('%s: %s : running module %s' %(ifacename, op, mname)) |
739f665b | 91 | if op == 'query-checkcurr': |
d486dd0d | 92 | # Dont check curr if the interface object was |
37c0543d | 93 | # auto generated |
dbc018d3 RP |
94 | if (ifaceobj.priv_flags and |
95 | ifaceobj.priv_flags.NOCONFIG): | |
37c0543d | 96 | continue |
a690dfae | 97 | ifupdownobj.logger.debug(msg) |
e1601369 | 98 | m.run(ifaceobj, op, query_ifaceobj, |
6e16e5ae | 99 | ifaceobj_getfunc=ifupdownobj.get_ifaceobjs) |
a6f80f0e | 100 | else: |
a690dfae | 101 | ifupdownobj.logger.debug(msg) |
3e6ea735 | 102 | m.run(ifaceobj, op, |
6e16e5ae | 103 | ifaceobj_getfunc=ifupdownobj.get_ifaceobjs) |
3b01ed76 | 104 | except Exception as e: |
3e6ea735 | 105 | if not ifupdownobj.ignore_error(str(e)): |
223ba5af | 106 | err = 1 |
166bc293 JF |
107 | #import traceback |
108 | #traceback.print_exc() | |
0e936c3f | 109 | |
223ba5af | 110 | ifupdownobj.logger.error(str(e)) |
3e6ea735 RP |
111 | # Continue with rest of the modules |
112 | pass | |
a6f80f0e | 113 | finally: |
ca105861 | 114 | if err or ifaceobj.status == ifaceStatus.ERROR: |
31a5f4c3 | 115 | ifaceobj.set_state_n_status(ifaceState.from_str(op), |
116 | ifaceStatus.ERROR) | |
2009513f | 117 | if 'up' in op or 'down' in op or 'query-checkcurr' in op: |
892c495e | 118 | cls.set_sched_status(False) |
d08d5f54 | 119 | else: |
3e6ea735 RP |
120 | # Mark success only if the interface was not already |
121 | # marked with error | |
122 | status = (ifaceobj.status | |
123 | if ifaceobj.status == ifaceStatus.ERROR | |
124 | else ifaceStatus.SUCCESS) | |
31a5f4c3 | 125 | ifaceobj.set_state_n_status(ifaceState.from_str(op), |
3e6ea735 | 126 | status) |
6bd7fc74 | 127 | |
ee3fcf44 | 128 | if ifupdownobj.config.get('addon_scripts_support', '0') == '1': |
d486dd0d | 129 | # execute /etc/network/ scripts |
a49b5d26 JF |
130 | command_env = (cenv or {}).copy() |
131 | command_env.update({ | |
132 | "IFACE": ifaceobj.name if ifaceobj.name else "", | |
133 | "LOGICAL": ifaceobj.name if ifaceobj.name else "", | |
134 | "METHOD": ifaceobj.addr_method if ifaceobj.addr_method else "", | |
135 | "ADDRFAM": ','.join(ifaceobj.addr_family) if ifaceobj.addr_family else "", | |
136 | }) | |
137 | ||
6bd7fc74 | 138 | for mname in ifupdownobj.script_ops.get(op, []): |
a49b5d26 | 139 | ifupdownobj.logger.debug("%s: %s : running script %s" % (ifacename, op, mname)) |
6bd7fc74 | 140 | try: |
a49b5d26 | 141 | utils.exec_command(mname, env=command_env) |
3b01ed76 | 142 | except Exception as e: |
739f9c7e JF |
143 | if "permission denied" in str(e).lower(): |
144 | ifupdownobj.logger.warning('%s: %s %s' % (ifacename, op, str(e))) | |
145 | else: | |
146 | ifupdownobj.log_error('%s: %s %s' % (ifacename, op, str(e))) | |
37c0543d | 147 | |
be0b20f2 | 148 | @classmethod |
6e16e5ae | 149 | def run_iface_list_ops(cls, ifupdownobj, ifaceobjs, ops): |
923290bd | 150 | """ Runs all operations on a list of interface |
151 | configurations for the same interface | |
152 | """ | |
a070c90e | 153 | |
a690dfae | 154 | # minor optimization. If operation is 'down', proceed only |
155 | # if interface exists in the system | |
923290bd | 156 | ifacename = ifaceobjs[0].name |
8c13865c | 157 | ifupdownobj.logger.info('%s: running ops ...' %ifacename) |
16d854b4 RP |
158 | if ('down' in ops[0] and |
159 | ifaceobjs[0].type != ifaceType.BRIDGE_VLAN and | |
77054f7f | 160 | ifaceobjs[0].addr_method != 'ppp' and |
923290bd | 161 | not ifupdownobj.link_exists(ifacename)): |
525f0a30 | 162 | ifupdownobj.logger.debug('%s: does not exist' %ifacename) |
923290bd | 163 | # run posthook before you get out of here, so that |
164 | # appropriate cleanup is done | |
165 | posthookfunc = ifupdownobj.sched_hooks.get('posthook') | |
166 | if posthookfunc: | |
167 | for ifaceobj in ifaceobjs: | |
168 | ifaceobj.status = ifaceStatus.SUCCESS | |
169 | posthookfunc(ifupdownobj, ifaceobj, 'down') | |
d486dd0d | 170 | return |
923290bd | 171 | for op in ops: |
172 | # first run ifupdownobj handlers. This is good enough | |
173 | # for the first object in the list | |
174 | handler = ifupdownobj.ops_handlers.get(op) | |
175 | if handler: | |
a070c90e RP |
176 | try: |
177 | handler(ifupdownobj, ifaceobjs[0]) | |
3b01ed76 | 178 | except Exception as e: |
61c4d724 | 179 | if not ifupdownobj.link_master_slave_ignore_error(str(e)): |
c46af1c9 | 180 | ifupdownobj.logger.warning('%s: %s' |
61c4d724 | 181 | %(ifaceobjs[0].name, str(e))) |
a070c90e | 182 | pass |
923290bd | 183 | for ifaceobj in ifaceobjs: |
6e16e5ae | 184 | cls.run_iface_op(ifupdownobj, ifaceobj, op, |
923290bd | 185 | cenv=ifupdownobj.generate_running_env(ifaceobj, op) |
ee3fcf44 RP |
186 | if ifupdownobj.config.get('addon_scripts_support', |
187 | '0') == '1' else None) | |
188 | posthookfunc = ifupdownobj.sched_hooks.get('posthook') | |
189 | if posthookfunc: | |
40ed8c4d RP |
190 | try: |
191 | [posthookfunc(ifupdownobj, ifaceobj, ops[0]) | |
192 | for ifaceobj in ifaceobjs] | |
3b01ed76 | 193 | except Exception as e: |
c46af1c9 | 194 | ifupdownobj.logger.warning('%s' %str(e)) |
40ed8c4d | 195 | pass |
21c7daa7 | 196 | |
197 | @classmethod | |
fa3da4be | 198 | def _check_upperifaces(cls, ifupdownobj, ifaceobj, ops, parent, |
199 | followdependents=False): | |
99b212b0 | 200 | """ Check if upperifaces are hanging off us and help caller decide |
201 | if he can proceed with the ops on this device | |
21c7daa7 | 202 | |
99b212b0 | 203 | Returns True or False indicating the caller to proceed with the |
204 | operation. | |
205 | """ | |
86fc62e2 | 206 | # proceed only for down operation |
207 | if 'down' not in ops[0]: | |
208 | return True | |
209 | ||
dbc018d3 RP |
210 | if (ifupdownobj.flags.SCHED_SKIP_CHECK_UPPERIFACES): |
211 | return True | |
212 | ||
fc5e1735 | 213 | if (ifupdownflags.flags.FORCE or |
dbc018d3 | 214 | not ifupdownobj.flags.ADDONS_ENABLE or |
86fc62e2 | 215 | (not ifupdownobj.is_ifaceobj_noconfig(ifaceobj) and |
33e106da | 216 | ifupdownobj.config.get('warn_on_ifdown', '0') == '0' and |
d2b35716 | 217 | not ifupdownflags.flags.ALL)): |
99b212b0 | 218 | return True |
65c48517 | 219 | |
62ddec8b | 220 | ulist = ifaceobj.upperifaces |
99b212b0 | 221 | if not ulist: |
222 | return True | |
33e106da | 223 | |
99b212b0 | 224 | # Get the list of upper ifaces other than the parent |
225 | tmpulist = ([u for u in ulist if u != parent] if parent | |
226 | else ulist) | |
227 | if not tmpulist: | |
228 | return True | |
229 | # XXX: This is expensive. Find a cheaper way to do this. | |
230 | # if any of the upperdevs are present, | |
231 | # return false to the caller to skip this interface | |
232 | for u in tmpulist: | |
233 | if ifupdownobj.link_exists(u): | |
d2b35716 | 234 | if not ifupdownflags.flags.ALL: |
86fc62e2 | 235 | if ifupdownobj.is_ifaceobj_noconfig(ifaceobj): |
236 | ifupdownobj.logger.info('%s: skipping interface down,' | |
237 | %ifaceobj.name + ' upperiface %s still around ' %u) | |
238 | else: | |
c46af1c9 | 239 | ifupdownobj.logger.warning('%s: skipping interface down,' |
86fc62e2 | 240 | %ifaceobj.name + ' upperiface %s still around ' %u) |
99b212b0 | 241 | return False |
21c7daa7 | 242 | return True |
243 | ||
be0b20f2 | 244 | @classmethod |
6e16e5ae N |
245 | def run_iface_graph(cls, ifupdownobj, ifacename, ops, parent=None, |
246 | order=ifaceSchedulerFlags.POSTORDER, | |
d08d5f54 | 247 | followdependents=True): |
6ef5bfa2 | 248 | """ runs interface by traversing all nodes rooted at itself """ |
249 | ||
d08d5f54 | 250 | # Each ifacename can have a list of iface objects |
31a5f4c3 | 251 | ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename) |
252 | if not ifaceobjs: | |
d08d5f54 | 253 | raise Exception('%s: not found' %ifacename) |
a6f80f0e | 254 | |
a070c90e RP |
255 | # Check state of the dependent. If it is already brought up, return |
256 | if (cls._STATE_CHECK and | |
257 | (ifaceobjs[0].state == ifaceState.from_str(ops[-1]))): | |
258 | ifupdownobj.logger.debug('%s: already processed' %ifacename) | |
259 | return | |
260 | ||
d08d5f54 | 261 | for ifaceobj in ifaceobjs: |
ca3f4fc7 | 262 | if not cls._check_upperifaces(ifupdownobj, ifaceobj, |
263 | ops, parent, followdependents): | |
a070c90e | 264 | return |
f3215127 | 265 | |
923290bd | 266 | # If inorder, run the iface first and then its dependents |
267 | if order == ifaceSchedulerFlags.INORDER: | |
6e16e5ae | 268 | cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops) |
923290bd | 269 | |
270 | for ifaceobj in ifaceobjs: | |
f3215127 | 271 | # Run lowerifaces or dependents |
62ddec8b | 272 | dlist = ifaceobj.lowerifaces |
f3215127 | 273 | if dlist: |
223ba5af JF |
274 | |
275 | if ifaceobj.link_kind == ifaceLinkKind.VRF: | |
276 | # remove non-auto lowerifaces from 'dlist' | |
277 | for lower_ifname in list(dlist): | |
278 | for lower_ifaceobj in ifupdownobj.get_ifaceobjs(lower_ifname) or []: | |
279 | if lower_ifaceobj and not lower_ifaceobj.auto and ifaceobj.name == cls.VRF_MGMT_DEVNAME: | |
280 | dlist.remove(lower_ifname) | |
281 | ||
fa3da4be | 282 | ifupdownobj.logger.debug('%s: found dependents %s' |
283 | %(ifacename, str(dlist))) | |
d08d5f54 | 284 | try: |
285 | if not followdependents: | |
286 | # XXX: this is yet another extra step, | |
287 | # but is needed for interfaces that are | |
f3215127 | 288 | # implicit dependents. even though we are asked to |
289 | # not follow dependents, we must follow the ones | |
290 | # that dont have user given config. Because we own them | |
d08d5f54 | 291 | new_dlist = [d for d in dlist |
923290bd | 292 | if ifupdownobj.is_iface_noconfig(d)] |
6ef5bfa2 | 293 | if new_dlist: |
be0b20f2 | 294 | cls.run_iface_list(ifupdownobj, new_dlist, ops, |
6e16e5ae | 295 | ifacename, order, followdependents, |
923290bd | 296 | continueonfailure=False) |
d08d5f54 | 297 | else: |
be0b20f2 | 298 | cls.run_iface_list(ifupdownobj, dlist, ops, |
6e16e5ae | 299 | ifacename, order, |
f3215127 | 300 | followdependents, |
6ef5bfa2 | 301 | continueonfailure=False) |
3b01ed76 | 302 | except Exception as e: |
be0b20f2 | 303 | if (ifupdownobj.ignore_error(str(e))): |
d08d5f54 | 304 | pass |
305 | else: | |
306 | # Dont bring the iface up if children did not come up | |
a690dfae | 307 | ifaceobj.set_state_n_status(ifaceState.NEW, |
923290bd | 308 | ifaceStatus.ERROR) |
d08d5f54 | 309 | raise |
923290bd | 310 | if order == ifaceSchedulerFlags.POSTORDER: |
6e16e5ae | 311 | cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops) |
a6f80f0e | 312 | |
be0b20f2 | 313 | @classmethod |
6e16e5ae N |
314 | def run_iface_list(cls, ifupdownobj, ifacenames, |
315 | ops, parent=None, order=ifaceSchedulerFlags.POSTORDER, | |
6ef5bfa2 | 316 | followdependents=True, continueonfailure=True): |
d08d5f54 | 317 | """ Runs interface list """ |
6e16e5ae | 318 | |
d08d5f54 | 319 | for ifacename in ifacenames: |
a6f80f0e | 320 | try: |
6e16e5ae N |
321 | cls.run_iface_graph(ifupdownobj, ifacename, ops, parent, |
322 | order, followdependents) | |
3b01ed76 | 323 | except Exception as e: |
6ef5bfa2 | 324 | if continueonfailure: |
69f58278 | 325 | if ifupdownobj.logger.isEnabledFor(logging.DEBUG): |
326 | traceback.print_tb(sys.exc_info()[2]) | |
be0b20f2 | 327 | ifupdownobj.logger.error('%s : %s' %(ifacename, str(e))) |
d08d5f54 | 328 | pass |
329 | else: | |
be0b20f2 | 330 | if (ifupdownobj.ignore_error(str(e))): |
6ef5bfa2 | 331 | pass |
332 | else: | |
9dce3561 | 333 | raise Exception('%s : (%s)' %(ifacename, str(e))) |
d08d5f54 | 334 | |
be0b20f2 | 335 | @classmethod |
c798b0f4 | 336 | def run_iface_graph_upper(cls, ifupdownobj, ifacename, ops, parent=None, |
337 | followdependents=True, skip_root=False): | |
338 | """ runs interface by traversing all nodes rooted at itself """ | |
339 | ||
340 | # Each ifacename can have a list of iface objects | |
341 | ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename) | |
342 | if not ifaceobjs: | |
343 | raise Exception('%s: not found' %ifacename) | |
344 | ||
a070c90e RP |
345 | if (cls._STATE_CHECK and |
346 | (ifaceobjs[0].state == ifaceState.from_str(ops[-1]))): | |
347 | ifupdownobj.logger.debug('%s: already processed' %ifacename) | |
348 | return | |
349 | ||
923290bd | 350 | if not skip_root: |
351 | # run the iface first and then its upperifaces | |
6e16e5ae | 352 | cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops) |
c798b0f4 | 353 | for ifaceobj in ifaceobjs: |
c798b0f4 | 354 | # Run upperifaces |
62ddec8b | 355 | ulist = ifaceobj.upperifaces |
c798b0f4 | 356 | if ulist: |
fa3da4be | 357 | ifupdownobj.logger.debug('%s: found upperifaces %s' |
358 | %(ifacename, str(ulist))) | |
c798b0f4 | 359 | try: |
360 | cls.run_iface_list_upper(ifupdownobj, ulist, ops, | |
361 | ifacename, | |
362 | followdependents, | |
363 | continueonfailure=True) | |
3b01ed76 | 364 | except Exception as e: |
c798b0f4 | 365 | if (ifupdownobj.ignore_error(str(e))): |
366 | pass | |
367 | else: | |
368 | raise | |
369 | ||
370 | @classmethod | |
371 | def run_iface_list_upper(cls, ifupdownobj, ifacenames, | |
372 | ops, parent=None, followdependents=True, | |
373 | continueonfailure=True, skip_root=False): | |
374 | """ Runs interface list """ | |
375 | ||
376 | for ifacename in ifacenames: | |
377 | try: | |
378 | cls.run_iface_graph_upper(ifupdownobj, ifacename, ops, parent, | |
379 | followdependents, skip_root) | |
3b01ed76 | 380 | except Exception as e: |
09a304ca RP |
381 | if ifupdownobj.logger.isEnabledFor(logging.DEBUG): |
382 | traceback.print_tb(sys.exc_info()[2]) | |
c46af1c9 | 383 | ifupdownobj.logger.warning('%s : %s' %(ifacename, str(e))) |
09a304ca | 384 | pass |
c798b0f4 | 385 | |
a9ab1b4f RP |
386 | @classmethod |
387 | def _get_valid_upperifaces(cls, ifupdownobj, ifacenames, | |
388 | allupperifacenames): | |
389 | """ Recursively find valid upperifaces | |
390 | ||
391 | valid upperifaces are: | |
392 | - An upperiface which had no user config (example builtin | |
393 | interfaces. usually vlan interfaces.) | |
394 | - or had config and previously up | |
395 | - and interface currently does not exist | |
396 | - or is a bridge (because if your upperiface was a bridge | |
397 | - u will have to execute up on the bridge | |
398 | to enslave the port and apply bridge attributes to the port) """ | |
399 | ||
400 | upperifacenames = [] | |
401 | for ifacename in ifacenames: | |
402 | # get upperifaces | |
403 | ifaceobj = ifupdownobj.get_ifaceobj_first(ifacename) | |
404 | if not ifaceobj: | |
405 | continue | |
6f89e489 | 406 | ulist = set(ifaceobj.upperifaces or []).difference(upperifacenames) |
a9ab1b4f RP |
407 | nulist = [] |
408 | for u in ulist: | |
409 | uifaceobj = ifupdownobj.get_ifaceobj_first(u) | |
410 | if not uifaceobj: | |
411 | continue | |
dbc018d3 RP |
412 | has_config = not (uifaceobj.priv_flags and |
413 | uifaceobj.priv_flags.NOCONFIG) | |
a9ab1b4f RP |
414 | if (((has_config and ifupdownobj.get_ifaceobjs_saved(u)) or |
415 | not has_config) and (not ifupdownobj.link_exists(u) | |
65e0c276 RP |
416 | # Do this always for a bridge. Note that this is |
417 | # not done for a vlan aware bridge because, | |
418 | # in the vlan aware bridge case, the bridge module | |
419 | # applies the bridge port configuration on the port | |
420 | # when up is scheduled on the port. | |
421 | or (uifaceobj.link_kind == ifaceLinkKind.BRIDGE))): | |
a9ab1b4f RP |
422 | nulist.append(u) |
423 | upperifacenames.extend(nulist) | |
424 | allupperifacenames.extend(upperifacenames) | |
425 | if upperifacenames: | |
426 | cls._get_valid_upperifaces(ifupdownobj, upperifacenames, | |
427 | allupperifacenames) | |
428 | return | |
429 | ||
430 | @classmethod | |
431 | def run_upperifaces(cls, ifupdownobj, ifacenames, ops, | |
432 | continueonfailure=True): | |
d486dd0d | 433 | """ Run through valid upperifaces """ |
a9ab1b4f RP |
434 | upperifaces = [] |
435 | ||
436 | cls._get_valid_upperifaces(ifupdownobj, ifacenames, upperifaces) | |
437 | if not upperifaces: | |
438 | return | |
439 | # dump valid upperifaces | |
440 | ifupdownobj.logger.debug(upperifaces) | |
441 | for u in upperifaces: | |
442 | try: | |
443 | ifaceobjs = ifupdownobj.get_ifaceobjs(u) | |
444 | if not ifaceobjs: | |
445 | continue | |
6e16e5ae | 446 | cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops) |
3b01ed76 | 447 | except Exception as e: |
a9ab1b4f | 448 | if continueonfailure: |
c46af1c9 | 449 | ifupdownobj.logger.warning('%s' %str(e)) |
a9ab1b4f | 450 | |
54ebaf3e RP |
451 | @classmethod |
452 | def _dump_dependency_info(cls, ifupdownobj, ifacenames, | |
453 | dependency_graph=None, indegrees=None): | |
454 | ifupdownobj.logger.info('{\n') | |
455 | ifupdownobj.logger.info('\nifaceobjs:') | |
456 | for iname in ifacenames: | |
3b01ed76 JF |
457 | iobjs = ifupdownobj.get_ifaceobjs(iname) |
458 | for iobj in iobjs: | |
459 | iobj.dump(ifupdownobj.logger) | |
54ebaf3e RP |
460 | if (dependency_graph): |
461 | ifupdownobj.logger.info('\nDependency Graph:') | |
462 | ifupdownobj.logger.info(dependency_graph) | |
3b01ed76 JF |
463 | if (indegrees): |
464 | ifupdownobj.logger.info('\nIndegrees:') | |
465 | ifupdownobj.logger.info(indegrees) | |
466 | ifupdownobj.logger.info('}\n') | |
54ebaf3e | 467 | |
5ee3e1a8 RP |
468 | @classmethod |
469 | def get_sorted_iface_list(cls, ifupdownobj, ifacenames, ops, | |
470 | dependency_graph, indegrees=None): | |
471 | if len(ifacenames) == 1: | |
472 | return ifacenames | |
473 | # Get a sorted list of all interfaces | |
474 | if not indegrees: | |
475 | indegrees = OrderedDict() | |
3b01ed76 | 476 | for ifacename in list(dependency_graph.keys()): |
5ee3e1a8 | 477 | indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename) |
54ebaf3e RP |
478 | |
479 | #cls._dump_dependency_info(ifupdownobj, ifacenames, | |
480 | # dependency_graph, indegrees) | |
481 | ||
5ee3e1a8 RP |
482 | ifacenames_all_sorted = graph.topological_sort_graphs_all( |
483 | dependency_graph, indegrees) | |
484 | # if ALL was set, return all interfaces | |
d2b35716 | 485 | if ifupdownflags.flags.ALL: |
5ee3e1a8 RP |
486 | return ifacenames_all_sorted |
487 | ||
488 | # else return ifacenames passed as argument in sorted order | |
489 | ifacenames_sorted = [] | |
490 | [ifacenames_sorted.append(ifacename) | |
491 | for ifacename in ifacenames_all_sorted | |
492 | if ifacename in ifacenames] | |
493 | return ifacenames_sorted | |
494 | ||
c798b0f4 | 495 | @classmethod |
6e16e5ae | 496 | def sched_ifaces(cls, ifupdownobj, ifacenames, ops, |
c798b0f4 | 497 | dependency_graph=None, indegrees=None, |
d08d5f54 | 498 | order=ifaceSchedulerFlags.POSTORDER, |
e308cb82 | 499 | followdependents=True, skipupperifaces=False, sort=False): |
2c0ad8b3 RP |
500 | """ runs interface configuration modules on interfaces passed as |
501 | argument. Runs topological sort on interface dependency graph. | |
502 | ||
503 | Args: | |
d486dd0d | 504 | **ifupdownobj** (object): ifupdownMain object |
904908bc RP |
505 | |
506 | **ifacenames** (list): list of interface names | |
507 | ||
508 | **ops** : list of operations to perform eg ['pre-up', 'up', 'post-up'] | |
509 | ||
510 | **dependency_graph** (dict): dependency graph in adjacency list format | |
2c0ad8b3 RP |
511 | |
512 | Kwargs: | |
904908bc RP |
513 | **indegrees** (dict): indegree array of the dependency graph |
514 | ||
515 | **order** (int): ifaceSchedulerFlags (POSTORDER, INORDER) | |
516 | ||
517 | **followdependents** (bool): follow dependent interfaces if true | |
2c0ad8b3 | 518 | |
e308cb82 RP |
519 | **sort** (bool): sort ifacelist in the case where ALL is not set |
520 | ||
d08d5f54 | 521 | """ |
5ee3e1a8 RP |
522 | # |
523 | # Algo: | |
524 | # if ALL/auto interfaces are specified, | |
525 | # - walk the dependency tree in postorder or inorder depending | |
526 | # on the operation. | |
527 | # (This is to run interfaces correctly in order) | |
528 | # else: | |
529 | # - sort iface list if the ifaces belong to a "class" | |
530 | # - else just run iface list in the order they were specified | |
531 | # | |
532 | # Run any upperifaces if available | |
533 | # | |
8c13865c | 534 | followupperifaces = False |
5ee3e1a8 RP |
535 | run_queue = [] |
536 | skip_ifacesort = int(ifupdownobj.config.get('skip_ifacesort', '0')) | |
537 | if not skip_ifacesort and not indegrees: | |
538 | indegrees = OrderedDict() | |
3b01ed76 | 539 | for ifacename in list(dependency_graph.keys()): |
5ee3e1a8 | 540 | indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename) |
c798b0f4 | 541 | |
d2b35716 | 542 | if not ifupdownflags.flags.ALL: |
e308cb82 RP |
543 | if 'up' in ops[0]: |
544 | # If there is any interface that does not exist, maybe it | |
545 | # is a logical interface and we have to followupperifaces | |
546 | # when it comes up, so lets get that list. | |
547 | if any([True for i in ifacenames | |
548 | if ifupdownobj.must_follow_upperifaces(i)]): | |
549 | followupperifaces = (True if | |
ca3f4fc7 | 550 | [i for i in ifacenames |
923290bd | 551 | if not ifupdownobj.link_exists(i)] |
552 | else False) | |
e308cb82 RP |
553 | # sort interfaces only if the caller asked to sort |
554 | # and skip_ifacesort is not on. | |
555 | if not skip_ifacesort and sort: | |
5ee3e1a8 RP |
556 | run_queue = cls.get_sorted_iface_list(ifupdownobj, ifacenames, |
557 | ops, dependency_graph, indegrees) | |
558 | if run_queue and 'up' in ops[0]: | |
559 | run_queue.reverse() | |
ba7b1d60 | 560 | else: |
e308cb82 RP |
561 | # if -a is set, we pick the interfaces |
562 | # that have no parents and use a sorted list of those | |
5ee3e1a8 RP |
563 | if not skip_ifacesort: |
564 | sorted_ifacenames = cls.get_sorted_iface_list(ifupdownobj, | |
565 | ifacenames, ops, dependency_graph, | |
566 | indegrees) | |
567 | if sorted_ifacenames: | |
568 | # pick interfaces that user asked | |
569 | # and those that dont have any dependents first | |
570 | [run_queue.append(ifacename) | |
571 | for ifacename in sorted_ifacenames | |
572 | if ifacename in ifacenames and | |
573 | not indegrees.get(ifacename)] | |
574 | ifupdownobj.logger.debug('graph roots (interfaces that ' + | |
575 | 'dont have dependents):' + ' %s' %str(run_queue)) | |
576 | else: | |
c46af1c9 | 577 | ifupdownobj.logger.warning('interface sort returned None') |
5ee3e1a8 | 578 | |
e308cb82 RP |
579 | # If queue not present, just run interfaces that were asked by the |
580 | # user | |
5ee3e1a8 RP |
581 | if not run_queue: |
582 | run_queue = list(ifacenames) | |
e308cb82 RP |
583 | # if we are taking the order of interfaces as specified |
584 | # in the interfaces file, we should reverse the list if we | |
585 | # want to down. This can happen if 'skip_ifacesort' | |
586 | # is been specified. | |
5ee3e1a8 RP |
587 | if 'down' in ops[0]: |
588 | run_queue.reverse() | |
589 | ||
590 | # run interface list | |
6e16e5ae | 591 | cls.run_iface_list(ifupdownobj, run_queue, ops, |
5ee3e1a8 RP |
592 | parent=None, order=order, |
593 | followdependents=followdependents) | |
892c495e | 594 | if not cls.get_sched_status(): |
2009513f | 595 | return |
09a304ca | 596 | |
ad25e7bb RP |
597 | if (not skipupperifaces and |
598 | ifupdownobj.config.get('skip_upperifaces', '0') == '0' and | |
d2b35716 | 599 | ((not ifupdownflags.flags.ALL and followdependents) or |
d486dd0d | 600 | followupperifaces) and |
5ee3e1a8 RP |
601 | 'up' in ops[0]): |
602 | # If user had given a set of interfaces to bring up | |
603 | # try and execute 'up' on the upperifaces | |
09a304ca RP |
604 | ifupdownobj.logger.info('running upperifaces (parent interfaces) ' + |
605 | 'if available ..') | |
892c495e | 606 | try: |
3fb52fa3 RP |
607 | # upperiface bring up is best effort. |
608 | # eg case: if we are bringing up a bridge port | |
609 | # this section does an 'ifup on the bridge' | |
610 | # so that the recently up'ed bridge port gets enslaved | |
611 | # to the bridge. But the up on the bridge may | |
612 | # throw out more errors if the bridge is not | |
613 | # in the correct state. Lets not surprise | |
614 | # the user with such errors when he has | |
615 | # only requested to bring up the bridge port. | |
892c495e | 616 | cls._STATE_CHECK = False |
3fb52fa3 | 617 | ifupdownflags.flags.IGNORE_ERRORS = True |
892c495e | 618 | cls.run_upperifaces(ifupdownobj, ifacenames, ops) |
892c495e | 619 | finally: |
3fb52fa3 RP |
620 | ifupdownflags.flags.IGNORE_ERRORS = False |
621 | cls._STATE_CHECK = True | |
892c495e RP |
622 | # upperiface bringup is best effort, so dont propagate errors |
623 | # reset scheduler status to True | |
624 | cls.set_sched_status(True) |