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