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