3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
18 import ifupdown
.statemanager
as statemanager
19 import ifupdown
.ifupdownconfig
as ifupdownConfig
20 import ifupdown
.ifupdownflags
as ifupdownflags
21 from networkinterfaces
import *
23 from scheduler
import *
24 from collections
import deque
25 from collections
import OrderedDict
30 .. module:: ifupdownmain
31 :synopsis: main module for ifupdown package
33 .. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
38 _crossmark
= u
'\u2717'
39 _success_sym
= '(%s)' %_tickmark
40 _error_sym
= '(%s)' %_crossmark
42 class ifupdownMainFlags():
46 COMPAT_EXEC_SCRIPTS
= False
47 STATEMANAGER_ENABLE
= True
48 STATEMANAGER_UPDATE
= True
50 DELETE_DEPENDENT_IFACES_WITH_NOCONFIG
= False
51 SCHED_SKIP_CHECK_UPPERIFACES
= False
52 CHECK_SHARED_DEPENDENTS
= True
54 class ifacePrivFlags():
55 # priv flags to mark iface objects
59 def __init__(self
, builtin
=False, noconfig
=False):
60 self
.BUILTIN
= builtin
61 self
.NOCONFIG
= noconfig
63 class ifupdownMain(ifupdownBase
):
64 """ ifupdown2 main class """
66 scripts_dir
='/etc/network'
67 addon_modules_dir
='/usr/share/ifupdown2/addons'
68 addon_modules_configfile
='/etc/network/ifupdown2/addons.conf'
70 # iface dictionary in the below format:
71 # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
73 # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
75 # Each ifaceobject corresponds to a configuration block for
77 # The value in the dictionary is a list because the network
78 # interface configuration file supports more than one iface section
79 # in the interfaces file
80 ifaceobjdict
= OrderedDict()
82 # iface dictionary representing the curr running state of an iface
83 # in the below format:
84 # {'<ifacename>' : <ifaceobject>}
85 ifaceobjcurrdict
= OrderedDict()
87 # Dictionary representing operation and modules
89 module_ops
= OrderedDict([('pre-up', []),
92 ('query-checkcurr', []),
93 ('query-running', []),
94 ('query-dependency', []),
101 # For old style /etc/network/ bash scripts
102 script_ops
= OrderedDict([('pre-up', []),
109 # Handlers for ops that ifupdown2 owns
110 def run_up(self
, ifaceobj
):
111 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs).
112 # there is no real interface behind it
113 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
115 if ifaceobj
.link_kind
& ifaceLinkKind
.VRF
:
117 if (ifaceobj
.addr_method
and
118 ifaceobj
.addr_method
== 'manual'):
120 if self
._delay
_admin
_state
:
121 self
._delay
_admin
_state
_iface
_queue
.append(ifaceobj
.name
)
123 # If this object is a link slave, ie its link is controlled
124 # by its link master interface, then dont set the link state.
125 # But do allow user to change state of the link if the interface
126 # is already with its link master (hence the master check).
127 if ifaceobj
.link_type
== ifaceLinkType
.LINK_SLAVE
:
129 if not self
.link_exists(ifaceobj
.name
):
131 self
.link_up(ifaceobj
.name
)
133 def run_down(self
, ifaceobj
):
134 if ifaceobj
.link_kind
& ifaceLinkKind
.VRF
:
136 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs)
137 # there is no real interface behind it
138 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
140 if (ifaceobj
.addr_method
and
141 ifaceobj
.addr_method
== 'manual'):
143 if self
._delay
_admin
_state
:
144 self
._delay
_admin
_state
_iface
_queue
.append(ifaceobj
.name
)
146 # If this object is a link slave, ie its link is controlled
147 # by its link master interface, then dont set the link state.
148 # But do allow user to change state of the link if the interface
149 # is already with its link master (hence the master check).
150 if ifaceobj
.link_type
== ifaceLinkType
.LINK_SLAVE
:
152 if not self
.link_exists(ifaceobj
.name
):
154 self
.link_down(ifaceobj
.name
)
156 # ifupdown object interface operation handlers
157 ops_handlers
= OrderedDict([('up', run_up
),
160 def run_sched_ifaceobj_posthook(self
, ifaceobj
, op
):
161 if (ifaceobj
.priv_flags
and (ifaceobj
.priv_flags
.BUILTIN
or
162 ifaceobj
.priv_flags
.NOCONFIG
)):
164 if self
.flags
.STATEMANAGER_UPDATE
:
165 self
.statemanager
.ifaceobj_sync(ifaceobj
, op
)
167 # ifupdown object interface scheduler pre and posthooks
168 sched_hooks
= {'posthook' : run_sched_ifaceobj_posthook
}
170 def __init__(self
, config
={},
171 force
=False, dryrun
=False, nowait
=False,
172 perfmode
=False, withdepends
=False, njobs
=1,
173 cache
=False, addons_enable
=True, statemanager_enable
=True,
174 interfacesfile
='/etc/network/interfaces',
175 interfacesfileiobuf
=None,
176 interfacesfileformat
='native',
178 """This member function initializes the ifupdownmain object.
181 config (dict): config dict from /etc/network/ifupdown2/ifupdown2.conf
182 force (bool): force interface configuration
183 dryrun (bool): dryrun interface configuration
184 withdepends (bool): apply interface configuration on all depends
185 interfacesfile (str): interfaces file. default is /etc/network/interfaces
186 interfacesfileformat (str): default is 'native'. Other choices are 'json'
189 AttributeError, KeyError """
191 self
.logger
= logging
.getLogger('ifupdown')
192 ifupdownflags
.flags
.FORCE
= force
193 ifupdownflags
.flags
.DRYRUN
= dryrun
194 ifupdownflags
.flags
.WITHDEFAULTS
= withdefaults
195 ifupdownflags
.flags
.NOWAIT
= nowait
196 ifupdownflags
.flags
.PERFMODE
= perfmode
197 ifupdownflags
.flags
.CACHE
= cache
199 # Can be used to provide hints for caching
200 ifupdownflags
.flags
.CACHE_FLAGS
= 0x0
202 self
.flags
= ifupdownMainFlags()
204 self
.flags
.WITH_DEPENDS
= withdepends
205 self
.flags
.STATEMANAGER_ENABLE
= statemanager_enable
206 self
.interfacesfile
= interfacesfile
207 self
.interfacesfileiobuf
= interfacesfileiobuf
208 self
.interfacesfileformat
= interfacesfileformat
210 self
.logger
.debug(self
.config
)
211 self
.blacklisted_ifaces_present
= False
213 self
.type = ifaceType
.UNKNOWN
215 self
.flags
.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG
= False
216 self
.flags
.ADDONS_ENABLE
= addons_enable
218 self
.ifaces
= OrderedDict()
220 self
.pp
= pprint
.PrettyPrinter(indent
=4)
221 self
.modules
= OrderedDict({})
222 self
.module_attrs
= {}
224 self
.load_addon_modules(self
.addon_modules_dir
)
225 if self
.flags
.COMPAT_EXEC_SCRIPTS
:
226 self
.load_scripts(self
.scripts_dir
)
227 self
.dependency_graph
= OrderedDict({})
229 self
._cache
_no
_repeats
= {}
231 if self
.flags
.STATEMANAGER_ENABLE
:
233 self
.statemanager
= statemanager
.statemanager_api
234 self
.statemanager
.read_saved_state()
236 # XXX Maybe we should continue by ignoring old state
237 self
.logger
.warning('error reading state (%s)' %str
(e
))
240 self
.flags
.STATEMANAGER_UPDATE
= False
241 self
._delay
_admin
_state
= True if self
.config
.get(
242 'delay_admin_state_change', '0') == '1' else False
243 self
._delay
_admin
_state
_iface
_queue
= []
244 if self
._delay
_admin
_state
:
245 self
.logger
.info('\'delay_admin_state_change\' is set. admin ' +
246 'state changes will be delayed till the end.')
248 self
._link
_master
_slave
= True if self
.config
.get(
249 'link_master_slave', '0') == '1' else False
250 if self
._link
_master
_slave
:
251 self
.logger
.info('\'link_master_slave\' is set. slave admin ' +
252 'state changes will be delayed till the ' +
253 'masters admin state change.')
255 # squash iface objects for same interface both internal and
256 # external representation. It is off by default.
257 self
._ifaceobj
_squash
= True if self
.config
.get(
258 'ifaceobj_squash', '0') == '1' else False
260 # squash iface objects for same interface internal
261 # representation only. External representation as seen by ifquery
262 # will continue to see multiple iface stanzas if it was specified
263 # that way by the user. It is on by default.
264 self
._ifaceobj
_squash
_internal
= True if self
.config
.get(
265 'ifaceobj_squash_internal', '1') == '1' else False
267 # initialize global config object with config passed by the user
268 # This makes config available to addon modules
269 ifupdownConfig
.config
= self
.config
271 def link_master_slave_ignore_error(self
, errorstr
):
272 # If link master slave flag is set,
273 # there may be cases where the lowerdev may not be
274 # up resulting in 'Network is down' error
275 # This can happen if the lowerdev is a LINK_SLAVE
276 # of another interface which is not up yet
277 # example of such a case:
278 # bringing up a vlan on a bond interface and the bond
279 # is a LINK_SLAVE of a bridge (in other words the bond is
280 # part of a bridge) which is not up yet
281 if self
._link
_master
_slave
:
282 if 'Network is down':
286 def get_ifaceobjs(self
, ifacename
):
287 return self
.ifaceobjdict
.get(ifacename
)
289 def get_ifaceobjs_saved(self
, ifacename
):
290 """ Return ifaceobjects from statemanager """
291 if self
.flags
.STATEMANAGER_ENABLE
:
292 return self
.statemanager
.get_ifaceobjs(ifacename
)
296 def get_ifaceobj_first(self
, ifacename
):
297 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
302 def get_ifacenames(self
):
303 return self
.ifaceobjdict
.keys()
305 def get_iface_obj_last(self
, ifacename
):
306 return self
.ifaceobjdict
.get(ifacename
)[-1]
309 def must_follow_upperifaces(self
, ifacename
):
311 # XXX: This bleeds the knowledge of iface
312 # types in the infrastructure module.
313 # Cant think of a better fix at the moment.
314 # In future maybe the module can set a flag
315 # to indicate if we should follow upperifaces
317 ifaceobj
= self
.get_ifaceobj_first(ifacename
)
318 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
322 def create_n_save_ifaceobj(self
, ifacename
, priv_flags
=None,
324 """ creates a iface object and adds it to the iface dictionary """
326 ifaceobj
.name
= ifacename
327 ifaceobj
.priv_flags
= priv_flags
329 if not self
._link
_master
_slave
:
330 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
332 ifaceobj
.inc_refcnt()
333 self
.ifaceobjdict
[ifacename
] = [ifaceobj
]
336 def create_n_save_ifaceobjcurr(self
, ifaceobj
):
337 """ creates a copy of iface object and adds it to the iface
338 dict containing current iface objects
340 ifaceobjcurr
= iface()
341 ifaceobjcurr
.name
= ifaceobj
.name
342 ifaceobjcurr
.type = ifaceobj
.type
343 ifaceobjcurr
.lowerifaces
= ifaceobj
.lowerifaces
344 ifaceobjcurr
.priv_flags
= copy
.deepcopy(ifaceobj
.priv_flags
)
345 ifaceobjcurr
.auto
= ifaceobj
.auto
346 self
.ifaceobjcurrdict
.setdefault(ifaceobj
.name
,
347 []).append(ifaceobjcurr
)
350 def get_ifaceobjcurr(self
, ifacename
, idx
=0):
351 ifaceobjlist
= self
.ifaceobjcurrdict
.get(ifacename
)
357 return ifaceobjlist
[idx
]
359 def get_ifaceobjrunning(self
, ifacename
):
360 return self
.ifaceobjrunningdict
.get(ifacename
)
362 def get_iface_refcnt(self
, ifacename
):
363 """ Return iface ref count """
365 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
373 def is_iface_builtin_byname(self
, ifacename
):
374 """ Returns true if iface name is a builtin interface.
376 A builtin interface is an interface which ifupdown understands.
377 The following are currently considered builtin ifaces:
378 - vlan interfaces in the format <ifacename>.<vlanid>
380 return '.' in ifacename
382 def is_ifaceobj_builtin(self
, ifaceobj
):
383 """ Returns true if iface name is a builtin interface.
385 A builtin interface is an interface which ifupdown understands.
386 The following are currently considered builtin ifaces:
387 - vlan interfaces in the format <ifacename>.<vlanid>
390 return (ifaceobj
.priv_flags
and ifaceobj
.priv_flags
.BUILTIN
)
392 def is_ifaceobj_noconfig(self
, ifaceobj
):
393 """ Returns true if iface object did not have a user defined config.
395 These interfaces appear only when they are dependents of interfaces
396 which have user defined config
398 return (ifaceobj
.priv_flags
and ifaceobj
.priv_flags
.NOCONFIG
)
400 def is_iface_noconfig(self
, ifacename
):
401 """ Returns true if iface has no config """
403 ifaceobj
= self
.get_ifaceobj_first(ifacename
)
404 if not ifaceobj
: return True
405 return self
.is_ifaceobj_noconfig(ifaceobj
)
407 def check_shared_dependents(self
, ifaceobj
, dlist
):
408 """ ABSOLETE: Check if dlist intersects with any other
409 interface with slave dependents.
410 example: bond and bridges.
411 This function logs such errors """
412 setdlist
= Set(dlist
)
413 for ifacename
, ifacedlist
in self
.dependency_graph
.items():
416 check_depends
= False
417 iobjs
= self
.get_ifaceobjs(ifacename
)
421 if (i
.dependency_type
== ifaceDependencyType
.MASTER_SLAVE
):
424 common
= Set(ifacedlist
).intersection(setdlist
)
426 self
.logger
.error('misconfig..?. iface %s and %s '
427 %(ifaceobj
.name
, ifacename
) +
428 'seem to share dependents/ports %s' %str
(list(common
)))
430 def _set_iface_role(self
, ifaceobj
, role
, upperifaceobj
):
431 if (self
.flags
.CHECK_SHARED_DEPENDENTS
and
432 (ifaceobj
.role
& ifaceRole
.SLAVE
) and
433 (role
== ifaceRole
.SLAVE
) and (upperifaceobj
.role
== ifaceRole
.MASTER
)):
434 self
.logger
.error("misconfig..? %s %s is enslaved to multiple interfaces %s"
436 ifaceLinkPrivFlags
.get_all_str(ifaceobj
.link_privflags
), str(ifaceobj
.upperifaces
)))
437 ifaceobj
.set_status(ifaceStatus
.ERROR
)
441 def _set_iface_role_n_kind(self
, ifaceobj
, upperifaceobj
):
443 if (upperifaceobj
.link_kind
& ifaceLinkKind
.BOND
):
444 self
._set
_iface
_role
(ifaceobj
, ifaceRole
.SLAVE
, upperifaceobj
)
445 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BOND_SLAVE
447 if (upperifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
):
448 self
._set
_iface
_role
(ifaceobj
, ifaceRole
.SLAVE
, upperifaceobj
)
449 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_PORT
451 if (ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
) \
452 and (upperifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
):
453 upperifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_VXLAN
455 # vrf masters get processed after slaves, which means
456 # check both link_kind vrf and vrf slave
457 if ((upperifaceobj
.link_kind
& ifaceLinkKind
.VRF
) or
458 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
)):
459 self
._set
_iface
_role
(ifaceobj
, ifaceRole
.SLAVE
, upperifaceobj
)
460 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.VRF_SLAVE
461 if self
._link
_master
_slave
:
462 if upperifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
463 ifaceobj
.link_type
= ifaceLinkType
.LINK_SLAVE
465 upperifaceobj
.link_type
= ifaceLinkType
.LINK_NA
466 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
468 def dump_iface_dependency_info(self
):
469 """ debug funtion to print raw dependency
470 info - lower and upper devices"""
472 for ifacename
, ifaceobjs
in self
.ifaceobjdict
.iteritems():
474 self
.logger
.info("%s: refcnt: %d, lower: %s, upper: %s" %(ifacename
,
475 self
.get_iface_refcnt(ifacename
),
476 str(iobj
.lowerifaces
) if iobj
.lowerifaces
else [],
477 str(iobj
.upperifaces
) if iobj
.upperifaces
else []))
480 def preprocess_dependency_list(self
, upperifaceobj
, dlist
, ops
):
481 """ We go through the dependency list and
482 delete or add interfaces from the interfaces dict by
483 applying the following rules:
484 if flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
485 we only consider devices whose configuration was
486 specified in the network interfaces file. We delete
487 any interface whose config was not specified except
488 for vlan devices. vlan devices get special treatment.
489 Even if they are not present they are created and added
491 elif flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
492 we create objects for all dependent devices that are not
493 present in the ifacesdict
498 dilist
= self
.get_ifaceobjs(d
)
501 if self
.is_iface_builtin_byname(d
):
502 ni
= self
.create_n_save_ifaceobj(d
,
503 ifacePrivFlags(True, True), True)
504 elif not self
.flags
.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG
:
505 ni
= self
.create_n_save_ifaceobj(d
,
506 ifacePrivFlags(False, True), True)
510 ni
.add_to_upperifaces(upperifaceobj
.name
)
511 self
._set
_iface
_role
_n
_kind
(ni
, upperifaceobj
)
515 di
.add_to_upperifaces(upperifaceobj
.name
)
516 self
._set
_iface
_role
_n
_kind
(di
, upperifaceobj
)
520 def preprocess_upperiface(self
, lowerifaceobj
, ulist
, ops
):
522 if (lowerifaceobj
.upperifaces
and
523 u
in lowerifaceobj
.upperifaces
):
525 lowerifaceobj
.add_to_upperifaces(u
)
526 uifacelist
= self
.get_ifaceobjs(u
)
528 for ui
in uifacelist
:
529 lowerifaceobj
.inc_refcnt()
530 self
._set
_iface
_role
_n
_kind
(lowerifaceobj
, ui
)
531 ui
.add_to_lowerifaces(lowerifaceobj
.name
)
533 def query_lowerifaces(self
, ifaceobj
, ops
, ifacenames
, type=None):
534 """ Gets iface dependents by calling into respective modules """
537 # Get dependents for interface by querying respective modules
538 for module
in self
.modules
.values():
540 if ops
[0] == 'query-running':
541 if (not hasattr(module
,
542 'get_dependent_ifacenames_running')):
544 dlist
= module
.get_dependent_ifacenames_running(ifaceobj
)
546 if (not hasattr(module
, 'get_dependent_ifacenames')):
548 dlist
= module
.get_dependent_ifacenames(ifaceobj
,
551 self
.logger
.warn('%s: error getting dependent interfaces (%s)'
552 %(ifaceobj
.name
, str(e
)))
555 if dlist
: ret_dlist
.extend(dlist
)
556 return list(set(ret_dlist
))
558 def query_upperifaces(self
, ifaceobj
, ops
, ifacenames
, type=None):
559 """ Gets iface upperifaces by calling into respective modules """
562 # Get upperifaces for interface by querying respective modules
563 for module
in self
.modules
.values():
565 if ops
[0] == 'query-running':
566 if (not hasattr(module
,
567 'get_upper_ifacenames_running')):
569 ulist
= module
.get_upper_ifacenames_running(ifaceobj
)
571 if (not hasattr(module
, 'get_upper_ifacenames')):
573 ulist
= module
.get_upper_ifacenames(ifaceobj
, ifacenames
)
575 self
.logger
.warn('%s: error getting upper interfaces (%s)'
576 %(ifaceobj
.name
, str(e
)))
579 if ulist
: ret_ulist
.extend(ulist
)
580 return list(set(ret_ulist
))
582 def populate_dependency_info(self
, ops
, ifacenames
=None):
583 """ recursive function to generate iface dependency info """
586 ifacenames
= self
.ifaceobjdict
.keys()
588 iqueue
= deque(ifacenames
)
591 # Go through all modules and find dependent ifaces
594 ifaceobjs
= self
.get_ifaceobjs(i
)
597 dependents_processed
= False
599 # Store all dependency info in the first ifaceobj
600 # but get dependency info from all ifaceobjs
601 ifaceobj
= ifaceobjs
[0]
602 for iobj
in ifaceobjs
:
603 ulist
= self
.query_upperifaces(iobj
, ops
, ifacenames
)
605 dependents_processed
= True
607 dlist
= self
.query_lowerifaces(iobj
, ops
, ifacenames
)
611 self
.preprocess_upperiface(ifaceobj
, ulist
, ops
)
612 if dependents_processed
:
615 self
.preprocess_dependency_list(ifaceobj
,
617 ifaceobj
.lowerifaces
= dlist
618 [iqueue
.append(d
) for d
in dlist
]
619 #if not self.dependency_graph.get(i):
620 # self.dependency_graph[i] = dlist
622 for i
in self
.ifaceobjdict
.keys():
623 iobj
= self
.get_ifaceobj_first(i
)
625 self
.dependency_graph
[i
] = iobj
.lowerifaces
627 self
.dependency_graph
[i
] = []
629 if not self
.blacklisted_ifaces_present
:
632 # Walk through the dependency graph and remove blacklisted
633 # interfaces that were picked up as dependents
634 for i
in self
.dependency_graph
.keys():
635 ifaceobj
= self
.get_ifaceobj_first(i
)
639 if ifaceobj
.blacklisted
and not ifaceobj
.upperifaces
:
640 # if blacklisted and was not picked up as a
641 # dependent of a upper interface, delete the
642 # interface from the dependency graph
643 dlist
= ifaceobj
.lowerifaces
646 difaceobjs
= self
.get_ifaceobjs(d
)
652 d
.upperifaces
.remove(i
)
654 self
.logger
.debug('error removing %s from %s upperifaces' %(i
, d
))
656 self
.logger
.debug("populate_dependency_info: deleting blacklisted interface %s" %i)
657 del self
.dependency_graph
[i
]
660 def _check_config_no_repeats(self
, ifaceobj
):
661 """ check if object has an attribute that is
662 restricted to a single object in the system.
663 if yes, warn and return """
664 for k
,v
in self
._cache
_no
_repeats
.items():
665 iv
= ifaceobj
.config
.get(k
)
666 if iv
and iv
[0] == v
:
667 self
.logger
.error('ignoring interface %s. ' %ifaceobj
.name
+
668 'Only one object with attribute ' +
669 '\'%s %s\' allowed.' %(k
, v
))
671 for k
, v
in self
.config
.get('no_repeats', {}).items():
672 iv
= ifaceobj
.config
.get(k
)
673 if iv
and iv
[0] == v
:
674 self
._cache
_no
_repeats
[k
] = v
677 def _save_iface_squash(self
, ifaceobj
):
678 """ squash ifaceobjects belonging to same iface
679 into a single object """
680 if self
._check
_config
_no
_repeats
(ifaceobj
):
682 ifaceobj
.priv_flags
= ifacePrivFlags()
683 if not self
._link
_master
_slave
:
684 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
685 currentifaceobjlist
= self
.ifaceobjdict
.get(ifaceobj
.name
)
686 if not currentifaceobjlist
:
687 self
.ifaceobjdict
[ifaceobj
.name
] = [ifaceobj
]
689 if ifaceobj
.compare(currentifaceobjlist
[0]):
690 self
.logger
.warn('duplicate interface %s found' %ifaceobj
.name
)
692 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
693 self
.ifaceobjdict
[ifaceobj
.name
].append(ifaceobj
)
695 currentifaceobjlist
[0].squash(ifaceobj
)
697 def _save_iface(self
, ifaceobj
):
698 if self
._check
_config
_no
_repeats
(ifaceobj
):
700 ifaceobj
.priv_flags
= ifacePrivFlags()
701 if not self
._link
_master
_slave
:
702 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
703 currentifaceobjlist
= self
.ifaceobjdict
.get(ifaceobj
.name
)
704 if not currentifaceobjlist
:
705 self
.ifaceobjdict
[ifaceobj
.name
]= [ifaceobj
]
706 if not self
._ifaceobj
_squash
:
707 ifaceobj
.flags |
= ifaceobj
.YOUNGEST_SIBLING
709 if ifaceobj
.compare(currentifaceobjlist
[0]):
710 self
.logger
.warn('duplicate interface %s found' %ifaceobj
.name
)
712 if currentifaceobjlist
[0].type == ifaceobj
.type:
713 currentifaceobjlist
[0].flags |
= ifaceobj
.HAS_SIBLINGS
714 ifaceobj
.flags |
= ifaceobj
.HAS_SIBLINGS
715 # clear the OLDEST_SIBLING from all the siblings
716 for iface
in self
.ifaceobjdict
[ifaceobj
.name
]:
717 iface
.flags
&= ~ifaceobj
.OLDEST_SIBLING
718 # current sibling is the oldest
719 ifaceobj
.flags |
= ifaceobj
.OLDEST_SIBLING
720 self
.ifaceobjdict
[ifaceobj
.name
].append(ifaceobj
)
722 def _iface_configattr_syntax_checker(self
, attrname
, attrval
):
723 for m
, mdict
in self
.module_attrs
.items():
726 attrsdict
= mdict
.get('attrs')
728 a
= attrsdict
.get(attrname
)
730 if a
.get('deprecated'):
731 newa
= a
.get('new-attribute')
733 self
.logger
.warn('attribute %s is deprecated. Use %s instead' %(attrname
, newa
))
735 self
.logger
.warn('attribute %s is deprecated'
738 except AttributeError:
742 def _ifaceobj_syntax_checker(self
, ifaceobj
):
744 for attrname
, attrvalue
in ifaceobj
.config
.items():
746 for k
, v
in self
.module_attrs
.items():
747 if v
and v
.get('attrs', {}).get(attrname
):
752 self
.logger
.warn('%s: unsupported attribute \'%s\'' \
753 % (ifaceobj
.name
, attrname
))
757 def read_iface_config(self
):
758 """ Reads default network interface config /etc/network/interfaces. """
760 nifaces
= networkInterfaces(self
.interfacesfile
,
761 self
.interfacesfileiobuf
,
762 self
.interfacesfileformat
,
763 template_engine
=self
.config
.get('template_engine'),
764 template_lookuppath
=self
.config
.get('template_lookuppath'))
765 if self
._ifaceobj
_squash
or self
._ifaceobj
_squash
_internal
:
766 nifaces
.subscribe('iface_found', self
._save
_iface
_squash
)
768 nifaces
.subscribe('iface_found', self
._save
_iface
)
769 nifaces
.subscribe('validateifaceattr',
770 self
._iface
_configattr
_syntax
_checker
)
771 nifaces
.subscribe('validateifaceobj', self
._ifaceobj
_syntax
_checker
)
773 if nifaces
.errors
or nifaces
.warns
:
777 def read_old_iface_config(self
):
778 """ Reads the saved iface config instead of default iface config.
779 And saved iface config is already read by the statemanager """
780 self
.ifaceobjdict
= copy
.deepcopy(self
.statemanager
.ifaceobjdict
)
782 def _load_addon_modules_config(self
):
783 """ Load addon modules config file """
785 with
open(self
.addon_modules_configfile
, 'r') as f
:
786 lines
= f
.readlines()
789 litems
= l
.strip(' \n\t\r').split(',')
790 if not litems
or len(litems
) < 2:
792 operation
= litems
[0]
794 self
.module_ops
[operation
].append(mname
)
796 self
.logger
.warn('error reading line \'%s\'' %(l
, str(e
)))
799 def load_addon_modules(self
, modules_dir
):
800 """ load python modules from modules_dir
802 Default modules_dir is /usr/share/ifupdownmodules
805 self
.logger
.info('loading builtin modules from %s' %modules_dir
)
806 self
._load
_addon
_modules
_config
()
807 if not modules_dir
in sys
.path
:
808 sys
.path
.append(modules_dir
)
810 for op
, mlist
in self
.module_ops
.items():
812 if self
.modules
.get(mname
):
814 mpath
= modules_dir
+ '/' + mname
+ '.py'
815 if os
.path
.exists(mpath
):
817 m
= __import__(mname
)
818 mclass
= getattr(m
, mname
)
822 self
.modules
[mname
] = minstance
824 self
.module_attrs
[mname
] = minstance
.get_modinfo()
830 # Assign all modules to query operations
831 self
.module_ops
['query-checkcurr'] = self
.modules
.keys()
832 self
.module_ops
['query-running'] = self
.modules
.keys()
833 self
.module_ops
['query-dependency'] = self
.modules
.keys()
834 self
.module_ops
['query'] = self
.modules
.keys()
835 self
.module_ops
['query-raw'] = self
.modules
.keys()
838 def _modules_help(self
):
839 """ Prints addon modules supported syntax """
842 for m
, mdict
in self
.module_attrs
.items():
845 print('%s: %s' %(m
, mdict
.get('mhelp')))
846 attrdict
= mdict
.get('attrs')
850 for attrname
, attrvaldict
in attrdict
.items():
851 if attrvaldict
.get('compat', False):
853 print('%s%s' %(indent
, attrname
))
854 print('%shelp: %s' %(indent
+ ' ',
855 attrvaldict
.get('help', '')))
856 print ('%srequired: %s' %(indent
+ ' ',
857 attrvaldict
.get('required', False)))
858 default
= attrvaldict
.get('default')
860 print('%sdefault: %s' %(indent
+ ' ', default
))
862 validrange
= attrvaldict
.get('validrange')
864 print('%svalidrange: %s-%s'
865 %(indent
+ ' ', validrange
[0], validrange
[1]))
867 validvals
= attrvaldict
.get('validvals')
869 print('%svalidvals: %s'
870 %(indent
+ ' ', ','.join(validvals
)))
872 examples
= attrvaldict
.get('example')
876 print '%sexample:' %(indent
+ ' ')
878 print '%s%s' %(indent
+ ' ', e
)
883 def load_scripts(self
, modules_dir
):
884 """ loading user modules from /etc/network/.
886 Note that previously loaded python modules override modules found
887 under /etc/network if any
891 self
.logger
.info('looking for user scripts under %s' %modules_dir
)
892 for op
, mlist
in self
.script_ops
.items():
893 msubdir
= modules_dir
+ '/if-%s.d' %op
894 self
.logger
.info('loading scripts under %s ...' %msubdir
)
896 module_list
= os
.listdir(msubdir
)
897 for module
in module_list
:
898 if self
.modules
.get(module
) is not None:
900 self
.script_ops
[op
].append(
901 msubdir
+ '/' + module
)
906 def _sched_ifaces(self
, ifacenames
, ops
, skipupperifaces
=False,
907 followdependents
=True, sort
=False):
908 self
.logger
.debug('scheduling \'%s\' for %s'
909 %(str(ops
), str(ifacenames
)))
910 self
._pretty
_print
_ordered
_dict
('dependency graph',
911 self
.dependency_graph
)
912 ifaceScheduler
.sched_ifaces(self
, ifacenames
, ops
,
913 dependency_graph
=self
.dependency_graph
,
914 order
=ifaceSchedulerFlags
.INORDER
916 else ifaceSchedulerFlags
.POSTORDER
,
917 followdependents
=followdependents
,
918 skipupperifaces
=skipupperifaces
,
919 sort
=True if (sort
or self
.flags
.IFACE_CLASS
) else False)
920 return ifaceScheduler
.get_sched_status()
922 def _render_ifacename(self
, ifacename
):
924 vlan_match
= re
.match("^([\d]+)-([\d]+)", ifacename
)
926 vlan_groups
= vlan_match
.groups()
927 if vlan_groups
[0] and vlan_groups
[1]:
928 [new_ifacenames
.append('%d' %v
)
929 for v
in range(int(vlan_groups
[0]),
930 int(vlan_groups
[1])+1)]
931 return new_ifacenames
933 def _preprocess_ifacenames(self
, ifacenames
):
934 """ validates interface list for config existance.
936 returns -1 if one or more interface not found. else, returns 0
942 ifaceobjs
= self
.get_ifaceobjs(i
)
944 # if name not available, render interface name and check again
945 rendered_ifacenames
= utils
.expand_iface_range(i
)
946 if rendered_ifacenames
:
947 for ri
in rendered_ifacenames
:
948 ifaceobjs
= self
.get_ifaceobjs(ri
)
950 err_iface
+= ' ' + ri
952 new_ifacenames
.append(ri
)
956 new_ifacenames
.append(i
)
958 raise Exception('cannot find interfaces:%s' %err_iface
)
959 return new_ifacenames
961 def _iface_whitelisted(self
, auto
, allow_classes
, excludepats
, ifacename
):
962 """ Checks if interface is whitelisted depending on set of parameters.
964 interfaces are checked against the allow_classes and auto lists.
970 # Check if interface matches the exclude patter
972 for e
in excludepats
:
973 if re
.search(e
, ifacename
):
975 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
978 self
.logger
.debug('iface %s' %ifacename
+ ' not found')
980 # If matched exclude pattern, return false
984 self
.blacklisted_ifaces_present
= True
986 # Check if interface belongs to the class
987 # the user is interested in, if not return false
992 common
= Set([allow_classes
]).intersection(
997 # If a class was requested and interface does not belong
998 # to the class, only then mark the ifaceobjs as blacklisted
999 self
.blacklisted_ifaces_present
= True
1001 i
.blacklisted
= True
1003 # If the user has requested auto class, check if the interface
1011 # If auto was requested and interface was not marked auto,
1012 # only then mark all of them as blacklisted
1013 self
.blacklisted_ifaces_present
= True
1015 i
.blacklisted
= True
1018 def _compat_conv_op_to_mode(self
, op
):
1019 """ Returns old op name to work with existing scripts """
1022 elif op
== 'pre-down':
1027 def generate_running_env(self
, ifaceobj
, op
):
1028 """ Generates a dictionary with env variables required for
1029 an interface. Used to support script execution for interfaces.
1033 iface_env
= ifaceobj
.env
1037 cenv
.update(iface_env
)
1040 cenv
['MODE'] = self
._compat
_conv
_op
_to
_mode
(op
)
1043 def _save_state(self
):
1044 if (not self
.flags
.STATEMANAGER_ENABLE
or
1045 not self
.flags
.STATEMANAGER_UPDATE
):
1048 # Update persistant iface states
1049 self
.statemanager
.save_state()
1050 except Exception, e
:
1051 if self
.logger
.isEnabledFor(logging
.DEBUG
):
1052 t
= sys
.exc_info()[2]
1053 traceback
.print_tb(t
)
1054 self
.logger
.warning('error saving state (%s)' %str
(e
))
1056 def set_type(self
, type):
1058 self
.type = ifaceType
.IFACE
1059 elif type == 'vlan':
1060 self
.type = ifaceType
.BRIDGE_VLAN
1062 self
.type = ifaceType
.UNKNOWN
1064 def _process_delay_admin_state_queue(self
, op
):
1065 if not self
._delay
_admin
_state
_iface
_queue
:
1070 func
= self
.link_down
1073 for i
in self
._delay
_admin
_state
_iface
_queue
:
1075 if self
.link_exists(i
):
1077 except Exception, e
:
1078 self
.logger
.warn(str(e
))
1081 def up(self
, ops
, auto
=False, allow_classes
=None, ifacenames
=None,
1082 excludepats
=None, printdependency
=None, syntaxcheck
=False,
1083 type=None, skipupperifaces
=False):
1084 """This brings the interface(s) up
1087 ops (list): list of ops to perform on the interface(s).
1088 Eg: ['pre-up', 'up', 'post-up'
1091 auto (bool): act on interfaces marked auto
1092 allow_classes (list): act on interfaces belonging to classes in the list
1093 ifacenames (list): act on interfaces specified in this list
1094 excludepats (list): list of patterns of interfaces to exclude
1095 syntaxcheck (bool): only perform syntax check
1101 self
.flags
.IFACE_CLASS
= True
1102 if not self
.flags
.ADDONS_ENABLE
:
1103 self
.flags
.STATEMANAGER_UPDATE
= False
1105 self
.flags
.ALL
= True
1106 self
.flags
.WITH_DEPENDS
= True
1108 iface_read_ret
= self
.read_iface_config()
1113 ifacenames
= self
._preprocess
_ifacenames
(ifacenames
)
1115 # if iface list not given by user, assume all from config file
1116 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1118 # filter interfaces based on auto and allow classes
1119 filtered_ifacenames
= [i
for i
in ifacenames
1120 if self
._iface
_whitelisted
(auto
, allow_classes
,
1122 if not filtered_ifacenames
:
1123 raise Exception('no ifaces found matching given allow lists')
1126 self
.populate_dependency_info(ops
, filtered_ifacenames
)
1127 self
.print_dependency(filtered_ifacenames
, printdependency
)
1130 self
.populate_dependency_info(ops
)
1132 # If only syntax check was requested, return here.
1133 # return here because we want to make sure most
1134 # errors above are caught and reported.
1136 if not iface_read_ret
:
1141 ret
= self
._sched
_ifaces
(filtered_ifacenames
, ops
,
1142 skipupperifaces
=skipupperifaces
,
1143 followdependents
=True
1144 if self
.flags
.WITH_DEPENDS
else False)
1146 self
._process
_delay
_admin
_state
_queue
('up')
1147 if not ifupdownflags
.flags
.DRYRUN
and self
.flags
.ADDONS_ENABLE
:
1150 if not iface_read_ret
or not ret
:
1153 def down(self
, ops
, auto
=False, allow_classes
=None, ifacenames
=None,
1154 excludepats
=None, printdependency
=None, usecurrentconfig
=False,
1156 """ down an interface """
1161 self
.flags
.IFACE_CLASS
= True
1162 if not self
.flags
.ADDONS_ENABLE
:
1163 self
.flags
.STATEMANAGER_UPDATE
= False
1165 self
.flags
.ALL
= True
1166 self
.flags
.WITH_DEPENDS
= True
1167 # For down we need to look at old state, unless usecurrentconfig
1169 if (not usecurrentconfig
and self
.flags
.STATEMANAGER_ENABLE
and
1170 self
.statemanager
.ifaceobjdict
):
1171 # Since we are using state manager objects,
1172 # skip the updating of state manager objects
1173 self
.logger
.debug('Looking at old state ..')
1174 self
.read_old_iface_config()
1176 # If no old state available
1178 self
.read_iface_config()
1179 except Exception, e
:
1180 raise Exception('error reading iface config (%s)' %str
(e
))
1182 # If iface list is given by the caller, always check if iface
1185 ifacenames
= self
._preprocess
_ifacenames
(ifacenames
)
1186 except Exception, e
:
1187 raise Exception('%s' %str
(e
) +
1188 ' (interface was probably never up ?)')
1190 # if iface list not given by user, assume all from config file
1191 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1193 # filter interfaces based on auto and allow classes
1194 filtered_ifacenames
= [i
for i
in ifacenames
1195 if self
._iface
_whitelisted
(auto
, allow_classes
,
1197 if not filtered_ifacenames
:
1198 raise Exception('no ifaces found matching given allow lists ' +
1199 '(or interfaces were probably never up ?)')
1202 self
.populate_dependency_info(ops
, filtered_ifacenames
)
1203 self
.print_dependency(filtered_ifacenames
, printdependency
)
1206 self
.populate_dependency_info(ops
)
1209 self
._sched
_ifaces
(filtered_ifacenames
, ops
,
1210 followdependents
=True
1211 if self
.flags
.WITH_DEPENDS
else False)
1213 self
._process
_delay
_admin
_state
_queue
('down')
1214 if not ifupdownflags
.flags
.DRYRUN
and self
.flags
.ADDONS_ENABLE
:
1217 def query(self
, ops
, auto
=False, format_list
=False, allow_classes
=None,
1219 excludepats
=None, printdependency
=None,
1220 format
='native', type=None):
1221 """ query an interface """
1225 # Let us forget internal squashing when it comes to
1226 # ifquery. It can surprise people relying of ifquery
1228 self
._ifaceobj
_squash
_internal
= False
1231 self
.flags
.IFACE_CLASS
= True
1232 if self
.flags
.STATEMANAGER_ENABLE
and ops
[0] == 'query-savedstate':
1233 return self
.statemanager
.dump_pretty(ifacenames
)
1234 self
.flags
.STATEMANAGER_UPDATE
= False
1236 self
.logger
.debug('setting flag ALL')
1237 self
.flags
.ALL
= True
1238 self
.flags
.WITH_DEPENDS
= True
1240 if ops
[0] == 'query-syntax':
1241 self
._modules
_help
()
1243 elif ops
[0] == 'query-running':
1244 # create fake devices to all dependents that dont have config
1245 map(lambda i
: self
.create_n_save_ifaceobj(i
,
1246 ifacePrivFlags(False, True)), ifacenames
)
1249 self
.read_iface_config()
1253 if ifacenames
and ops
[0] != 'query-running':
1254 # If iface list is given, always check if iface is present
1255 ifacenames
= self
._preprocess
_ifacenames
(ifacenames
)
1257 # if iface list not given by user, assume all from config file
1258 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1260 # filter interfaces based on auto and allow classes
1261 if ops
[0] == 'query-running':
1262 filtered_ifacenames
= ifacenames
1264 filtered_ifacenames
= [i
for i
in ifacenames
1265 if self
._iface
_whitelisted
(auto
, allow_classes
,
1267 if not filtered_ifacenames
:
1268 raise Exception('no ifaces found matching ' +
1269 'given allow lists')
1271 self
.populate_dependency_info(ops
)
1272 if ops
[0] == 'query-dependency' and printdependency
:
1273 self
.print_dependency(filtered_ifacenames
, printdependency
)
1276 if format_list
and (ops
[0] == 'query' or ops
[0] == 'query-raw'):
1277 return self
.print_ifaceobjs_list(filtered_ifacenames
)
1279 if ops
[0] == 'query':
1280 return self
.print_ifaceobjs_pretty(filtered_ifacenames
, format
)
1281 elif ops
[0] == 'query-raw':
1282 return self
.print_ifaceobjs_raw(filtered_ifacenames
)
1284 ret
= self
._sched
_ifaces
(filtered_ifacenames
, ops
,
1285 followdependents
=True
1286 if self
.flags
.WITH_DEPENDS
else False)
1288 if ops
[0] == 'query-checkcurr':
1289 ret
= self
.print_ifaceobjscurr_pretty(filtered_ifacenames
, format
)
1291 # if any of the object has an error, signal that silently
1293 elif ops
[0] == 'query-running':
1294 self
.print_ifaceobjsrunning_pretty(filtered_ifacenames
, format
)
1297 def _reload_currentlyup(self
, upops
, downops
, auto
=True, allow
=None,
1298 ifacenames
=None, excludepats
=None, usecurrentconfig
=False,
1299 syntaxcheck
=False, **extra_args
):
1300 """ reload currently up interfaces """
1301 new_ifaceobjdict
= {}
1303 # Override auto to true
1306 iface_read_ret
= self
.read_iface_config()
1309 if not self
.ifaceobjdict
:
1310 self
.logger
.warn("nothing to reload ..exiting.")
1312 already_up_ifacenames
= []
1313 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1314 filtered_ifacenames
= [i
for i
in ifacenames
1315 if self
._iface
_whitelisted
(auto
, allow
,
1318 # generate dependency graph of interfaces
1319 self
.populate_dependency_info(upops
)
1321 # If only syntax check was requested, return here.
1322 # return here because we want to make sure most
1323 # errors above are caught and reported.
1325 if not iface_read_ret
:
1329 if (not usecurrentconfig
and self
.flags
.STATEMANAGER_ENABLE
1330 and self
.statemanager
.ifaceobjdict
):
1331 already_up_ifacenames
= self
.statemanager
.ifaceobjdict
.keys()
1333 # Get already up interfaces that still exist in the interfaces file
1334 already_up_ifacenames_not_present
= Set(
1335 already_up_ifacenames
).difference(ifacenames
)
1336 already_up_ifacenames_still_present
= Set(
1337 already_up_ifacenames
).difference(
1338 already_up_ifacenames_not_present
)
1339 interfaces_to_up
= Set(already_up_ifacenames_still_present
).union(
1340 filtered_ifacenames
)
1342 if (already_up_ifacenames_not_present
and
1343 self
.config
.get('ifreload_currentlyup_down_notpresent') == '1'):
1344 self
.logger
.info('reload: schedule down on interfaces: %s'
1345 %str
(already_up_ifacenames_not_present
))
1347 # Save a copy of new iface objects and dependency_graph
1348 new_ifaceobjdict
= dict(self
.ifaceobjdict
)
1349 new_dependency_graph
= dict(self
.dependency_graph
)
1351 # old interface config is read into self.ifaceobjdict
1352 self
.read_old_iface_config()
1354 # reinitialize dependency graph
1355 self
.dependency_graph
= OrderedDict({})
1356 falready_up_ifacenames_not_present
= [i
for i
in
1357 already_up_ifacenames_not_present
1358 if self
._iface
_whitelisted
(auto
, allow
,
1360 self
.populate_dependency_info(downops
,
1361 falready_up_ifacenames_not_present
)
1362 self
._sched
_ifaces
(falready_up_ifacenames_not_present
, downops
,
1363 followdependents
=False, sort
=True)
1365 self
.logger
.debug('no interfaces to down ..')
1367 # Now, run 'up' with new config dict
1368 # reset statemanager update flag to default
1370 self
.flags
.ALL
= True
1371 self
.flags
.WITH_DEPENDS
= True
1372 if new_ifaceobjdict
:
1373 # and now, ifaceobjdict is back to current config
1374 self
.ifaceobjdict
= new_ifaceobjdict
1375 self
.dependency_graph
= new_dependency_graph
1377 if not self
.ifaceobjdict
:
1379 self
.logger
.info('reload: scheduling up on interfaces: %s'
1380 %str
(interfaces_to_up
))
1381 ret
= self
._sched
_ifaces
(interfaces_to_up
, upops
,
1382 followdependents
=True
1383 if self
.flags
.WITH_DEPENDS
else False)
1384 if ifupdownflags
.flags
.DRYRUN
:
1388 if not iface_read_ret
or not ret
:
1391 def _reload_default(self
, upops
, downops
, auto
=False, allow
=None,
1392 ifacenames
=None, excludepats
=None, usecurrentconfig
=False,
1393 syntaxcheck
=False, **extra_args
):
1394 """ reload interface config """
1395 new_ifaceobjdict
= {}
1398 iface_read_ret
= self
.read_iface_config()
1402 if not self
.ifaceobjdict
:
1403 self
.logger
.warn("nothing to reload ..exiting.")
1406 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1407 new_filtered_ifacenames
= [i
for i
in ifacenames
1408 if self
._iface
_whitelisted
(auto
, allow
,
1410 # generate dependency graph of interfaces
1411 self
.populate_dependency_info(upops
)
1413 # If only syntax check was requested, return here.
1414 # return here because we want to make sure most
1415 # errors above are caught and reported.
1417 if not iface_read_ret
:
1421 if (not usecurrentconfig
and self
.flags
.STATEMANAGER_ENABLE
1422 and self
.statemanager
.ifaceobjdict
):
1423 # Save a copy of new iface objects and dependency_graph
1424 new_ifaceobjdict
= dict(self
.ifaceobjdict
)
1425 new_dependency_graph
= dict(self
.dependency_graph
)
1427 self
.ifaceobjdict
= OrderedDict({})
1428 self
.dependency_graph
= OrderedDict({})
1430 # if old state is present, read old state and mark op for 'down'
1431 # followed by 'up' aka: reload
1432 # old interface config is read into self.ifaceobjdict
1433 self
.read_old_iface_config()
1436 # oldconfig not available, continue with 'up' with new config
1438 new_ifaceobjdict
= self
.ifaceobjdict
1439 new_dependency_graph
= self
.dependency_graph
1441 if op
== 'reload' and ifacenames
:
1442 ifacenames
= self
.ifaceobjdict
.keys()
1443 old_filtered_ifacenames
= [i
for i
in ifacenames
1444 if self
._iface
_whitelisted
(auto
, allow
,
1447 # generate dependency graph of old interfaces,
1448 # This should make sure built in interfaces are
1449 # populated. disable check shared dependents as an optimization.
1450 # these are saved interfaces and dependency for these
1451 # have been checked before they became part of saved state.
1453 self
.flags
.CHECK_SHARED_DEPENDENTS
= False
1454 self
.populate_dependency_info(upops
)
1455 self
.flags
.CHECK_SHARED_DEPENDENTS
= True
1456 except Exception, e
:
1457 self
.logger
.info("error generating dependency graph for "
1458 "saved interfaces (%s)" %str
(e
))
1461 # make sure we pick up built-in interfaces
1462 # if config file had 'ifreload_down_changed' variable
1463 # set, also look for interfaces that changed to down them
1464 down_changed
= int(self
.config
.get('ifreload_down_changed', '1'))
1466 # Generate the interface down list
1467 # Interfaces that go into the down list:
1468 # - interfaces that were present in last config and are not
1469 # present in the new config
1470 # - interfaces that were changed between the last and current
1473 for ifname
in self
.ifaceobjdict
.keys():
1474 lastifaceobjlist
= self
.ifaceobjdict
.get(ifname
)
1475 if not self
.is_ifaceobj_builtin(lastifaceobjlist
[0]):
1476 # if interface is not built-in and is not in
1477 # old filtered ifacenames
1478 if ifname
not in old_filtered_ifacenames
:
1481 # If interface is not present in the new file
1482 # append it to the down list
1483 newifaceobjlist
= new_ifaceobjdict
.get(ifname
)
1484 if not newifaceobjlist
:
1485 ifacedownlist
.append(ifname
)
1487 # If ifaceobj was present in the old interfaces file,
1488 # and does not have a config in the new interfaces file
1489 # but has been picked up as a dependent of another
1490 # interface, catch it here. This catches a common error
1491 # for example: remove a bond section from the interfaces
1492 # file, but leave it around as a bridge port
1493 # XXX: Ideally its better to just add it to the
1494 # ifacedownlist. But we will be cautious here
1495 # and just print a warning
1496 if (self
.is_ifaceobj_noconfig(newifaceobjlist
[0]) and
1497 not self
.is_ifaceobj_builtin(newifaceobjlist
[0]) and
1498 lastifaceobjlist
[0].is_config_present()):
1499 self
.logger
.warn('%s: misconfig ? removed but still exists as a dependency of %s' %(newifaceobjlist
[objidx
].name
,
1500 str(newifaceobjlist
[objidx
].upperifaces
)))
1501 if not down_changed
:
1503 if len(newifaceobjlist
) != len(lastifaceobjlist
):
1504 ifacedownlist
.append(ifname
)
1507 # If interface has changed between the current file
1508 # and the last installed append it to the down list
1509 # compare object list
1510 for objidx
in range(0, len(lastifaceobjlist
)):
1511 oldobj
= lastifaceobjlist
[objidx
]
1512 newobj
= newifaceobjlist
[objidx
]
1513 if not newobj
.compare(oldobj
):
1514 ifacedownlist
.append(ifname
)
1518 self
.logger
.info('reload: scheduling down on interfaces: %s'
1519 %str
(ifacedownlist
))
1520 # reinitialize dependency graph
1521 self
.dependency_graph
= OrderedDict({})
1523 # Generate dependency info for old config
1524 self
.flags
.CHECK_SHARED_DEPENDENTS
= False
1525 self
.populate_dependency_info(downops
, ifacedownlist
)
1526 self
.flags
.CHECK_SHARED_DEPENDENTS
= True
1529 # XXX: Hack to skip checking upperifaces during down.
1530 # the dependency list is not complete here
1531 # and we dont want to down the upperiface.
1532 # Hence during reload, set this to true.
1533 # This is being added to avoid a failure in
1534 # scheduler._check_upperifaces when we are dowing
1535 # a builtin bridge port
1536 self
.flags
.SCHED_SKIP_CHECK_UPPERIFACES
= True
1537 self
._sched
_ifaces
(ifacedownlist
, downops
,
1538 followdependents
=False,
1540 except Exception, e
:
1541 self
.logger
.error(str(e
))
1544 self
.flags
.SCHED_SKIP_CHECK_UPPERIFACES
= False
1545 self
._process
_delay
_admin
_state
_queue
('down')
1547 self
.logger
.debug('no interfaces to down ..')
1549 # Now, run 'up' with new config dict
1550 # reset statemanager update flag to default
1551 if not new_ifaceobjdict
:
1552 self
.logger
.debug('no interfaces to up')
1556 self
.flags
.ALL
= True
1557 self
.flags
.WITH_DEPENDS
= True
1558 # and now, we are back to the current config in ifaceobjdict
1559 self
.ifaceobjdict
= new_ifaceobjdict
1560 self
.dependency_graph
= new_dependency_graph
1562 self
.logger
.info('reload: scheduling up on interfaces: %s'
1563 %str
(new_filtered_ifacenames
))
1565 ret
= self
._sched
_ifaces
(new_filtered_ifacenames
, upops
,
1566 followdependents
=True
1567 if self
.flags
.WITH_DEPENDS
else False)
1568 except Exception, e
:
1569 self
.logger
.error(str(e
))
1572 self
._process
_delay
_admin
_state
_queue
('up')
1573 if ifupdownflags
.flags
.DRYRUN
:
1577 if not iface_read_ret
or not ret
:
1580 def reload(self
, *args
, **kargs
):
1581 """ reload interface config """
1582 self
.logger
.debug('reloading interface config ..')
1583 if kargs
.get('currentlyup', False):
1584 self
._reload
_currentlyup
(*args
, **kargs
)
1586 self
._reload
_default
(*args
, **kargs
)
1588 def _pretty_print_ordered_dict(self
, prefix
, argdict
):
1589 outbuf
= prefix
+ ' {\n'
1590 for k
, vlist
in argdict
.items():
1591 outbuf
+= '\t%s : %s\n' %(k
, str(vlist
))
1592 self
.logger
.debug(outbuf
+ '}')
1594 def print_dependency(self
, ifacenames
, format
):
1595 """ prints iface dependency information """
1598 ifacenames
= self
.ifaceobjdict
.keys()
1599 if format
== 'list':
1600 for k
,v
in self
.dependency_graph
.items():
1601 print '%s : %s' %(k
, str(v
))
1602 elif format
== 'dot':
1604 map(lambda i
: indegrees
.update({i
:
1605 self
.get_iface_refcnt(i
)}),
1606 self
.dependency_graph
.keys())
1607 graph
.generate_dots(self
.dependency_graph
, indegrees
)
1609 def print_ifaceobjs_list(self
, ifacenames
):
1610 for i
in ifacenames
:
1613 def print_ifaceobjs_raw(self
, ifacenames
):
1614 """ prints raw lines for ifaces from config file """
1616 for i
in ifacenames
:
1617 for ifaceobj
in self
.get_ifaceobjs(i
):
1618 if (self
.is_ifaceobj_builtin(ifaceobj
) or
1619 not ifaceobj
.is_config_present()):
1621 ifaceobj
.dump_raw(self
.logger
)
1623 if self
.flags
.WITH_DEPENDS
and not self
.flags
.ALL
:
1624 dlist
= ifaceobj
.lowerifaces
1625 if not dlist
: continue
1626 self
.print_ifaceobjs_raw(dlist
)
1628 def _get_ifaceobjs_pretty(self
, ifacenames
, ifaceobjs
, running
=False):
1629 """ returns iface obj list """
1631 for i
in ifacenames
:
1632 for ifaceobj
in self
.get_ifaceobjs(i
):
1633 if ((not running
and self
.is_ifaceobj_noconfig(ifaceobj
)) or
1634 (running
and not ifaceobj
.is_config_present())):
1636 ifaceobjs
.append(ifaceobj
)
1637 if self
.flags
.WITH_DEPENDS
and not self
.flags
.ALL
:
1638 dlist
= ifaceobj
.lowerifaces
1639 if not dlist
: continue
1640 self
._get
_ifaceobjs
_pretty
(dlist
, ifaceobjs
, running
)
1642 def print_ifaceobjs_pretty(self
, ifacenames
, format
='native'):
1643 """ pretty prints iface in format given by keyword arg format """
1646 self
._get
_ifaceobjs
_pretty
(ifacenames
, ifaceobjs
)
1647 if not ifaceobjs
: return
1648 if format
== 'json':
1649 print json
.dumps(ifaceobjs
, cls
=ifaceJsonEncoder
,
1650 indent
=4, separators
=(',', ': '))
1652 expand
= int(self
.config
.get('ifquery_ifacename_expand_range', '0'))
1654 if not expand
and (i
.flags
& iface
.IFACERANGE_ENTRY
):
1655 # print only the first one
1656 if i
.flags
& iface
.IFACERANGE_START
:
1657 i
.dump_pretty(use_realname
=True)
1661 def _get_ifaceobjscurr_pretty(self
, ifacenames
, ifaceobjs
):
1663 for i
in ifacenames
:
1664 ifaceobjscurr
= self
.get_ifaceobjcurr(i
)
1665 if not ifaceobjscurr
: continue
1666 for ifaceobj
in ifaceobjscurr
:
1667 if (ifaceobj
.status
== ifaceStatus
.NOTFOUND
or
1668 ifaceobj
.status
== ifaceStatus
.ERROR
):
1670 if self
.is_ifaceobj_noconfig(ifaceobj
):
1672 ifaceobjs
.append(ifaceobj
)
1673 if self
.flags
.WITH_DEPENDS
and not self
.flags
.ALL
:
1674 dlist
= ifaceobj
.lowerifaces
1675 if not dlist
: continue
1676 dret
= self
._get
_ifaceobjscurr
_pretty
(dlist
, ifaceobjs
)
1680 def print_ifaceobjscurr_pretty(self
, ifacenames
, format
='native'):
1681 """ pretty prints current running state of interfaces with status.
1683 returns 1 if any of the interface has an error,
1688 ret
= self
._get
_ifaceobjscurr
_pretty
(ifacenames
, ifaceobjs
)
1689 if not ifaceobjs
: return
1691 # override ifaceStatusUserStrs
1692 ifaceStatusUserStrs
.SUCCESS
= self
.config
.get('ifquery_check_success_str', _success_sym
)
1693 ifaceStatusUserStrs
.ERROR
= self
.config
.get('ifquery_check_error_str', _error_sym
)
1694 ifaceStatusUserStrs
.UNKNOWN
= self
.config
.get('ifquery_check_unknown_str', '')
1695 if format
== 'json':
1696 print json
.dumps(ifaceobjs
, cls
=ifaceJsonEncoderWithStatus
,
1697 indent
=2, separators
=(',', ': '))
1699 map(lambda i
: i
.dump_pretty(with_status
=True), ifaceobjs
)
1702 def print_ifaceobjsrunning_pretty(self
, ifacenames
, format
='native'):
1703 """ pretty prints iface running state """
1706 self
._get
_ifaceobjs
_pretty
(ifacenames
, ifaceobjs
, running
=True)
1707 if not ifaceobjs
: return
1708 if format
== 'json':
1709 print json
.dumps(ifaceobjs
, cls
=ifaceJsonEncoder
, indent
=2,
1710 separators
=(',', ': '))
1712 map(lambda i
: i
.dump_pretty(), ifaceobjs
)
1715 print 'ifupdown main object dump'
1716 print self
.pp
.pprint(self
.modules
)
1717 print self
.pp
.pprint(self
.ifaceobjdict
)
1719 def _dump_ifaceobjs(self
, ifacenames
):
1720 for i
in ifacenames
:
1721 ifaceobjs
= self
.get_ifaceobjs(i
)