3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
12 from collections
import OrderedDict
14 from ipaddr
import IPNetwork
, IPv4Network
, IPv6Network
, IPAddress
, IPv4Address
, IPv6Address
17 import ifupdown2
.ifupdownaddons
.cache
18 import ifupdown2
.ifupdownaddons
.LinkUtils
19 import ifupdown2
.ifupdownaddons
.mstpctlutil
21 import ifupdown2
.ifupdown
.policymanager
22 import ifupdown2
.ifupdown
.ifupdownflags
23 import ifupdown2
.ifupdown
.statemanager
as statemanager
24 import ifupdown2
.ifupdown
.ifupdownflags
as ifupdownflags
25 import ifupdown2
.ifupdown
.ifupdownconfig
as ifupdownConfig
27 from ifupdown2
.ifupdown
.graph
import *
28 from ifupdown2
.ifupdown
.iface
import *
29 from ifupdown2
.ifupdown
.scheduler
import *
30 from ifupdown2
.ifupdown
.exceptions
import *
31 from ifupdown2
.ifupdown
.networkinterfaces
import *
32 from ifupdown2
.ifupdown
.config
import ADDON_MODULES_DIR
, ADDONS_CONF_PATH
, IFUPDOWN2_ADDON_DROPIN_FOLDER
34 import ifupdownaddons
.cache
35 import ifupdownaddons
.LinkUtils
36 import ifupdownaddons
.mstpctlutil
38 import ifupdown
.ifupdownflags
39 import ifupdown
.policymanager
40 import ifupdown
.statemanager
as statemanager
41 import ifupdown
.ifupdownflags
as ifupdownflags
42 import ifupdown
.ifupdownconfig
as ifupdownConfig
44 from ifupdown
.graph
import *
45 from ifupdown
.iface
import *
46 from ifupdown
.scheduler
import *
47 from ifupdown
.exceptions
import *
48 from ifupdown
.networkinterfaces
import *
49 from ifupdown
.config
import ADDON_MODULES_DIR
, ADDONS_CONF_PATH
, IFUPDOWN2_ADDON_DROPIN_FOLDER
53 .. module:: ifupdownmain
54 :synopsis: main module for ifupdown package
56 .. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
61 _crossmark
= u
'\u2717'
62 _success_sym
= '(%s)' %_tickmark
63 _error_sym
= '(%s)' %_crossmark
65 class ifupdownMainFlags():
66 COMPAT_EXEC_SCRIPTS
= False
67 STATEMANAGER_ENABLE
= True
68 STATEMANAGER_UPDATE
= True
70 DELETE_DEPENDENT_IFACES_WITH_NOCONFIG
= False
71 SCHED_SKIP_CHECK_UPPERIFACES
= False
72 CHECK_SHARED_DEPENDENTS
= True
74 class ifacePrivFlags():
75 # priv flags to mark iface objects
79 def __init__(self
, builtin
=False, noconfig
=False):
80 self
.BUILTIN
= builtin
81 self
.NOCONFIG
= noconfig
83 class ifupdownMain(ifupdownBase
):
84 """ ifupdown2 main class """
86 scripts_dir
= '/etc/network'
87 addon_modules_dir
= ADDON_MODULES_DIR
88 addon_modules_configfile
= ADDONS_CONF_PATH
90 # Handlers for ops that ifupdown2 owns
91 def run_up(self
, ifaceobj
):
92 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs).
93 # there is no real interface behind it
94 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
96 if ((ifaceobj
.link_kind
& ifaceLinkKind
.VRF
) or
97 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
)):
98 self
._keep
_link
_down
(ifaceobj
)
100 if self
._delay
_admin
_state
:
101 self
._delay
_admin
_state
_iface
_queue
.append(ifaceobj
.name
)
103 # If this object is a link slave, ie its link is controlled
104 # by its link master interface, then dont set the link state.
105 # But do allow user to change state of the link if the interface
106 # is already with its link master (hence the master check).
107 if ifaceobj
.link_type
== ifaceLinkType
.LINK_SLAVE
:
109 if not self
.link_exists(ifaceobj
.name
):
111 if self
._keep
_link
_down
(ifaceobj
):
114 self
.link_up(ifaceobj
.name
)
116 if ifaceobj
.addr_method
== 'manual':
121 def _keep_link_down(self
, ifaceobj
):
122 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.KEEP_LINK_DOWN
:
123 # user has asked to explicitly keep the link down,
124 # so, force link down
125 self
.logger
.info('%s: keeping link down due to user config' %ifaceobj
.name
)
126 self
.link_down(ifaceobj
.name
)
130 def run_down(self
, ifaceobj
):
131 if ((ifaceobj
.link_kind
& ifaceLinkKind
.VRF
) or
132 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
)):
134 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs)
135 # there is no real interface behind it
136 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
138 if self
._delay
_admin
_state
:
139 self
._delay
_admin
_state
_iface
_queue
.append(ifaceobj
.name
)
141 # If this object is a link slave, ie its link is controlled
142 # by its link master interface, then dont set the link state.
143 # But do allow user to change state of the link if the interface
144 # is already with its link master (hence the master check).
145 if ifaceobj
.link_type
== ifaceLinkType
.LINK_SLAVE
:
147 if not self
.link_exists(ifaceobj
.name
):
150 self
.link_down(ifaceobj
.name
)
152 if ifaceobj
.addr_method
== 'manual':
157 # ifupdown object interface operation handlers
158 ops_handlers
= OrderedDict([('up', run_up
),
161 def run_sched_ifaceobj_posthook(self
, ifaceobj
, op
):
162 if (ifaceobj
.priv_flags
and (ifaceobj
.priv_flags
.BUILTIN
or
163 ifaceobj
.priv_flags
.NOCONFIG
)):
165 if self
.flags
.STATEMANAGER_UPDATE
:
166 self
.statemanager
.ifaceobj_sync(ifaceobj
, op
)
168 # ifupdown object interface scheduler pre and posthooks
169 sched_hooks
= {'posthook' : run_sched_ifaceobj_posthook
}
171 def reset_ifupdown2(self
):
172 ifaceScheduler
.reset()
174 ifupdown2
.ifupdown
.statemanager
.reset()
175 ifupdown2
.ifupdown
.policymanager
.reset()
176 ifupdown2
.ifupdown
.ifupdownflags
.reset()
177 ifupdownConfig
.reset()
178 ifupdown2
.ifupdownaddons
.mstpctlutil
.mstpctlutil
.reset()
179 ifupdown2
.ifupdownaddons
.LinkUtils
.LinkUtils
.reset()
181 ifupdown2
.ifupdownaddons
.cache
.linkCache
.reset()
182 ifupdown2
.ifupdownaddons
.cache
.MSTPAttrsCache
.invalidate()
184 def __init__(self
, config
={},
185 daemon
=False, force
=False, dryrun
=False, nowait
=False,
186 perfmode
=False, withdepends
=False, njobs
=1,
187 cache
=False, addons_enable
=True, statemanager_enable
=True,
188 interfacesfile
='/etc/network/interfaces',
189 interfacesfileiobuf
=None,
190 interfacesfileformat
='native',
192 """This member function initializes the ifupdownmain object.
195 config (dict): config dict from /etc/network/ifupdown2/ifupdown2.conf
196 force (bool): force interface configuration
197 dryrun (bool): dryrun interface configuration
198 withdepends (bool): apply interface configuration on all depends
199 interfacesfile (str): interfaces file. default is /etc/network/interfaces
200 interfacesfileformat (str): default is 'native'. Other choices are 'json'
203 AttributeError, KeyError """
206 self
.reset_ifupdown2()
208 # iface dictionary in the below format:
209 # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
211 # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
213 # Each ifaceobject corresponds to a configuration block for
215 # The value in the dictionary is a list because the network
216 # interface configuration file supports more than one iface section
217 # in the interfaces file
218 self
.ifaceobjdict
= OrderedDict()
220 # iface dictionary representing the curr running state of an iface
221 # in the below format:
222 # {'<ifacename>' : <ifaceobject>}
223 self
.ifaceobjcurrdict
= OrderedDict()
225 # Dictionary representing operation and modules
226 # for every operation
227 self
.module_ops
= OrderedDict([('pre-up', []),
230 ('query-checkcurr', []),
231 ('query-running', []),
232 ('query-dependency', []),
239 # For old style /etc/network/ bash scripts
240 self
.script_ops
= OrderedDict([('pre-up', []),
248 self
.logger
= logging
.getLogger('ifupdown')
249 ifupdownflags
.flags
.FORCE
= force
250 ifupdownflags
.flags
.DRYRUN
= dryrun
251 ifupdownflags
.flags
.WITHDEFAULTS
= withdefaults
252 ifupdownflags
.flags
.NOWAIT
= nowait
253 ifupdownflags
.flags
.PERFMODE
= perfmode
254 ifupdownflags
.flags
.CACHE
= cache
255 ifupdownflags
.flags
.WITH_DEPENDS
= withdepends
257 # Can be used to provide hints for caching
258 ifupdownflags
.flags
.CACHE_FLAGS
= 0x0
260 self
.flags
= ifupdownMainFlags()
262 self
.flags
.STATEMANAGER_ENABLE
= statemanager_enable
263 self
.interfacesfile
= interfacesfile
264 self
.interfacesfileiobuf
= interfacesfileiobuf
265 self
.interfacesfileformat
= interfacesfileformat
267 self
.logger
.debug(self
.config
)
268 self
.blacklisted_ifaces_present
= False
270 self
.type = ifaceType
.UNKNOWN
272 self
.flags
.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG
= False
273 self
.flags
.ADDONS_ENABLE
= addons_enable
275 self
.ifaces
= OrderedDict()
277 self
.pp
= pprint
.PrettyPrinter(indent
=4)
278 self
.modules
= OrderedDict({})
279 self
.module_attrs
= {}
280 self
.overridden_ifupdown_scripts
= []
282 if self
.config
.get('addon_python_modules_support', '1') == '1':
283 self
.load_addon_modules(self
.addon_modules_dir
)
284 if self
.config
.get('addon_scripts_support', '0') == '1':
285 self
.load_scripts(self
.scripts_dir
)
286 self
.dependency_graph
= OrderedDict({})
288 self
._cache
_no
_repeats
= {}
290 # initialize global config object with config passed by the user
291 # This makes config available to addon modules
292 ifupdownConfig
.config
= self
.config
293 statemanager
.statemanager_api
.init()
295 if self
.flags
.STATEMANAGER_ENABLE
:
296 self
.statemanager
= statemanager
.statemanager_api
298 self
.statemanager
.read_saved_state()
300 # if read_saved_state fails, state file might be corrupt.
301 # Ignore old state and continue
302 self
.logger
.warning('error reading state (%s)' %str
(e
))
304 self
.flags
.STATEMANAGER_UPDATE
= False
305 self
._delay
_admin
_state
= True if self
.config
.get(
306 'delay_admin_state_change', '0') == '1' else False
307 self
._delay
_admin
_state
_iface
_queue
= []
308 if self
._delay
_admin
_state
:
309 self
.logger
.info('\'delay_admin_state_change\' is set. admin ' +
310 'state changes will be delayed till the end.')
312 self
._link
_master
_slave
= True if self
.config
.get(
313 'link_master_slave', '0') == '1' else False
314 if self
._link
_master
_slave
:
315 self
.logger
.info('\'link_master_slave\' is set. slave admin ' +
316 'state changes will be delayed till the ' +
317 'masters admin state change.')
319 # squash iface objects for same interface both internal and
320 # external representation. It is off by default.
321 self
._ifaceobj
_squash
= True if self
.config
.get(
322 'ifaceobj_squash', '0') == '1' else False
324 # squash iface objects for same interface internal
325 # representation only. External representation as seen by ifquery
326 # will continue to see multiple iface stanzas if it was specified
327 # that way by the user. It is on by default.
328 self
._ifaceobj
_squash
_internal
= True if self
.config
.get(
329 'ifaceobj_squash_internal', '1') == '1' else False
331 self
.validate_keywords
= {
332 '<mac>': self
._keyword
_mac
,
333 '<text>': self
._keyword
_text
,
334 '<ipv4>': self
._keyword
_ipv
4,
335 '<ipv6>': self
._keyword
_ipv
6,
336 '<ip>': self
._keyword
_ip
,
337 '<number>': self
._keyword
_number
,
338 '<interface>': self
._keyword
_interface
,
339 '<ipv4-vrf-text>': self
._keyword
_ipv
4_vrf
_text
,
340 '<number-ipv4-list>': self
._keyword
_number
_ipv
4_list
,
341 '<interface-list>': self
._keyword
_interface
_list
,
342 '<ipv4/prefixlen>': self
._keyword
_ipv
4_prefixlen
,
343 '<ipv6/prefixlen>': self
._keyword
_ipv
6_prefixlen
,
344 '<ip/prefixlen>': self
._keyword
_ip
_prefixlen
,
345 '<number-range-list>': self
._keyword
_number
_range
_list
,
346 '<number-comma-range-list>': self
._keyword
_number
_comma
_range
_list
,
347 '<interface-range-list>': self
._keyword
_interface
_range
_list
,
348 '<interface-range-list-multiple-of-16>': self
._keyword
_interface
_range
_list
_multiple
_of
_16,
349 '<mac-ip/prefixlen-list>': self
._keyword
_mac
_ip
_prefixlen
_list
,
350 '<number-interface-list>': self
._keyword
_number
_interface
_list
,
351 '<interface-yes-no-list>': self
._keyword
_interface
_yes
_no
_list
,
352 '<interface-on-off-list>': self
._keyword
_interface
_on
_off
_list
,
353 '<interface-yes-no-0-1-list>': self
._keyword
_interface
_yes
_no
_0_1_list
,
354 '<interface-disabled-automatic-enabled>': self
._keyword
_interface
_disabled
_automatic
_enabled
_list
,
355 '<interface-yes-no-auto-list>': self
._keyword
_interface
_yes
_no
_auto
_list
,
356 '<interface-l2protocol-tunnel-list>': self
._keyword
_interface
_l2protocol
_tunnel
_list
359 def link_master_slave_ignore_error(self
, errorstr
):
360 # If link master slave flag is set,
361 # there may be cases where the lowerdev may not be
362 # up resulting in 'Network is down' error
363 # This can happen if the lowerdev is a LINK_SLAVE
364 # of another interface which is not up yet
365 # example of such a case:
366 # bringing up a vlan on a bond interface and the bond
367 # is a LINK_SLAVE of a bridge (in other words the bond is
368 # part of a bridge) which is not up yet
369 if self
._link
_master
_slave
:
370 if 'Network is down' in errorstr
:
374 def get_ifaceobjs(self
, ifacename
):
375 return self
.ifaceobjdict
.get(ifacename
)
377 def get_ifaceobjs_saved(self
, ifacename
):
378 """ Return ifaceobjects from statemanager """
379 if self
.flags
.STATEMANAGER_ENABLE
:
380 return self
.statemanager
.get_ifaceobjs(ifacename
)
384 def get_ifaceobj_first(self
, ifacename
):
385 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
390 def get_ifacenames(self
):
391 return self
.ifaceobjdict
.keys()
393 def get_iface_obj_last(self
, ifacename
):
394 return self
.ifaceobjdict
.get(ifacename
)[-1]
397 def must_follow_upperifaces(self
, ifacename
):
399 # XXX: This bleeds the knowledge of iface
400 # types in the infrastructure module.
401 # Cant think of a better fix at the moment.
402 # In future maybe the module can set a flag
403 # to indicate if we should follow upperifaces
405 ifaceobj
= self
.get_ifaceobj_first(ifacename
)
406 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
410 def create_n_save_ifaceobj(self
, ifacename
, priv_flags
=None,
412 """ creates a iface object and adds it to the iface dictionary """
414 ifaceobj
.name
= ifacename
415 ifaceobj
.priv_flags
= priv_flags
417 if not self
._link
_master
_slave
:
418 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
420 ifaceobj
.inc_refcnt()
421 self
.ifaceobjdict
[ifacename
] = [ifaceobj
]
424 def create_n_save_ifaceobjcurr(self
, ifaceobj
):
425 """ creates a copy of iface object and adds it to the iface
426 dict containing current iface objects
428 ifaceobjcurr
= iface()
429 ifaceobjcurr
.name
= ifaceobj
.name
430 ifaceobjcurr
.type = ifaceobj
.type
431 ifaceobjcurr
.lowerifaces
= ifaceobj
.lowerifaces
432 ifaceobjcurr
.priv_flags
= copy
.deepcopy(ifaceobj
.priv_flags
)
433 ifaceobjcurr
.auto
= ifaceobj
.auto
434 self
.ifaceobjcurrdict
.setdefault(ifaceobj
.name
,
435 []).append(ifaceobjcurr
)
438 def get_ifaceobjcurr(self
, ifacename
, idx
=0):
439 ifaceobjlist
= self
.ifaceobjcurrdict
.get(ifacename
)
445 return ifaceobjlist
[idx
]
447 def get_ifaceobjrunning(self
, ifacename
):
448 return self
.ifaceobjrunningdict
.get(ifacename
)
450 def get_iface_refcnt(self
, ifacename
):
451 """ Return iface ref count """
453 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
461 def is_iface_builtin_byname(self
, ifacename
):
462 """ Returns true if iface name is a builtin interface.
464 A builtin interface is an interface which ifupdown understands.
465 The following are currently considered builtin ifaces:
466 - vlan interfaces in the format <ifacename>.<vlanid>
468 return '.' in ifacename
470 def is_ifaceobj_builtin(self
, ifaceobj
):
471 """ Returns true if iface name is a builtin interface.
473 A builtin interface is an interface which ifupdown understands.
474 The following are currently considered builtin ifaces:
475 - vlan interfaces in the format <ifacename>.<vlanid>
477 if (ifaceobj
.priv_flags
and ifaceobj
.priv_flags
.BUILTIN
):
481 def is_ifaceobj_noconfig(self
, ifaceobj
):
482 """ Returns true if iface object did not have a user defined config.
484 These interfaces appear only when they are dependents of interfaces
485 which have user defined config
487 return (ifaceobj
.priv_flags
and ifaceobj
.priv_flags
.NOCONFIG
)
489 def is_iface_noconfig(self
, ifacename
):
490 """ Returns true if iface has no config """
492 ifaceobj
= self
.get_ifaceobj_first(ifacename
)
493 if not ifaceobj
: return True
494 return self
.is_ifaceobj_noconfig(ifaceobj
)
496 def check_shared_dependents(self
, ifaceobj
, dlist
):
497 """ ABSOLETE: Check if dlist intersects with any other
498 interface with slave dependents.
499 example: bond and bridges.
500 This function logs such errors """
501 setdlist
= Set(dlist
)
502 for ifacename
, ifacedlist
in self
.dependency_graph
.items():
505 check_depends
= False
506 iobjs
= self
.get_ifaceobjs(ifacename
)
510 if (i
.dependency_type
== ifaceDependencyType
.MASTER_SLAVE
):
513 common
= Set(ifacedlist
).intersection(setdlist
)
515 self
.logger
.error('misconfig..?. iface %s and %s '
516 %(ifaceobj
.name
, ifacename
) +
517 'seem to share dependents/ports %s' %str
(list(common
)))
519 def _set_iface_role(self
, ifaceobj
, role
, upperifaceobj
):
520 if (self
.flags
.CHECK_SHARED_DEPENDENTS
and
521 (ifaceobj
.role
& ifaceRole
.SLAVE
) and
522 (role
== ifaceRole
.SLAVE
) and (upperifaceobj
.role
& ifaceRole
.MASTER
)):
523 self
.logger
.error("misconfig..? %s %s is enslaved to multiple interfaces %s"
525 ifaceLinkPrivFlags
.get_all_str(ifaceobj
.link_privflags
), str(ifaceobj
.upperifaces
)))
526 ifaceobj
.set_status(ifaceStatus
.ERROR
)
530 def _set_iface_role_n_kind(self
, ifaceobj
, upperifaceobj
):
531 if (upperifaceobj
.link_kind
& ifaceLinkKind
.BOND
):
532 self
._set
_iface
_role
(ifaceobj
, ifaceRole
.SLAVE
, upperifaceobj
)
533 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BOND_SLAVE
535 if (upperifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
):
536 self
._set
_iface
_role
(ifaceobj
, ifaceRole
.SLAVE
, upperifaceobj
)
537 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_PORT
539 if (ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
) \
540 and (upperifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
):
541 upperifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_VXLAN
543 # vrf masters get processed after slaves, which means
544 # check both link_kind vrf and vrf slave
545 if ((upperifaceobj
.link_kind
& ifaceLinkKind
.VRF
) or
546 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
)):
547 self
._set
_iface
_role
(ifaceobj
, ifaceRole
.SLAVE
, upperifaceobj
)
548 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.VRF_SLAVE
549 if self
._link
_master
_slave
:
550 if upperifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
551 ifaceobj
.link_type
= ifaceLinkType
.LINK_SLAVE
553 upperifaceobj
.link_type
= ifaceLinkType
.LINK_NA
554 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
556 def dump_iface_dependency_info(self
):
557 """ debug funtion to print raw dependency
558 info - lower and upper devices"""
560 for ifacename
, ifaceobjs
in self
.ifaceobjdict
.iteritems():
562 self
.logger
.info("%s: refcnt: %d, lower: %s, upper: %s" %(ifacename
,
563 self
.get_iface_refcnt(ifacename
),
564 str(iobj
.lowerifaces
) if iobj
.lowerifaces
else [],
565 str(iobj
.upperifaces
) if iobj
.upperifaces
else []))
568 def preprocess_dependency_list(self
, upperifaceobj
, dlist
, ops
):
569 """ We go through the dependency list and
570 delete or add interfaces from the interfaces dict by
571 applying the following rules:
572 if flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
573 we only consider devices whose configuration was
574 specified in the network interfaces file. We delete
575 any interface whose config was not specified except
576 for vlan devices. vlan devices get special treatment.
577 Even if they are not present they are created and added
579 elif flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
580 we create objects for all dependent devices that are not
581 present in the ifacesdict
586 dilist
= self
.get_ifaceobjs(d
)
589 if self
.is_iface_builtin_byname(d
):
590 ni
= self
.create_n_save_ifaceobj(d
,
591 ifacePrivFlags(True, True), True)
592 elif not self
.flags
.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG
:
593 ni
= self
.create_n_save_ifaceobj(d
,
594 ifacePrivFlags(False, True), True)
598 ni
.add_to_upperifaces(upperifaceobj
.name
)
599 self
._set
_iface
_role
_n
_kind
(ni
, upperifaceobj
)
603 di
.add_to_upperifaces(upperifaceobj
.name
)
604 self
._set
_iface
_role
_n
_kind
(di
, upperifaceobj
)
608 def preprocess_upperiface(self
, lowerifaceobj
, ulist
, ops
):
610 if (lowerifaceobj
.upperifaces
and
611 u
in lowerifaceobj
.upperifaces
):
613 lowerifaceobj
.add_to_upperifaces(u
)
614 uifacelist
= self
.get_ifaceobjs(u
)
616 for ui
in uifacelist
:
617 lowerifaceobj
.inc_refcnt()
618 self
._set
_iface
_role
_n
_kind
(lowerifaceobj
, ui
)
619 ui
.add_to_lowerifaces(lowerifaceobj
.name
)
621 def query_lowerifaces(self
, ifaceobj
, ops
, ifacenames
, type=None):
622 """ Gets iface dependents by calling into respective modules """
625 # Get dependents for interface by querying respective modules
626 for module
in self
.modules
.values():
628 if ops
[0] == 'query-running':
629 if (not hasattr(module
,
630 'get_dependent_ifacenames_running')):
632 dlist
= module
.get_dependent_ifacenames_running(ifaceobj
)
634 if (not hasattr(module
, 'get_dependent_ifacenames')):
636 dlist
= module
.get_dependent_ifacenames(ifaceobj
,
639 self
.logger
.warn('%s: error getting dependent interfaces (%s)'
640 %(ifaceobj
.name
, str(e
)))
643 if dlist
: ret_dlist
.extend(dlist
)
644 return list(set(ret_dlist
))
646 def query_upperifaces(self
, ifaceobj
, ops
, ifacenames
, type=None):
647 """ Gets iface upperifaces by calling into respective modules """
650 # Get upperifaces for interface by querying respective modules
651 for module
in self
.modules
.values():
653 if ops
[0] == 'query-running':
654 if (not hasattr(module
,
655 'get_upper_ifacenames_running')):
657 ulist
= module
.get_upper_ifacenames_running(ifaceobj
)
659 if (not hasattr(module
, 'get_upper_ifacenames')):
661 ulist
= module
.get_upper_ifacenames(ifaceobj
, ifacenames
)
663 self
.logger
.warn('%s: error getting upper interfaces (%s)'
664 %(ifaceobj
.name
, str(e
)))
667 if ulist
: ret_ulist
.extend(ulist
)
668 return list(set(ret_ulist
))
670 def populate_dependency_info(self
, ops
, ifacenames
=None):
671 """ recursive function to generate iface dependency info """
674 ifacenames
= self
.ifaceobjdict
.keys()
676 iqueue
= deque(ifacenames
)
679 # Go through all modules and find dependent ifaces
682 ifaceobjs
= self
.get_ifaceobjs(i
)
685 dependents_processed
= False
687 # Store all dependency info in the first ifaceobj
688 # but get dependency info from all ifaceobjs
689 ifaceobj
= ifaceobjs
[0]
690 for iobj
in ifaceobjs
:
691 ulist
= self
.query_upperifaces(iobj
, ops
, ifacenames
)
693 dependents_processed
= True
695 dlist
= self
.query_lowerifaces(iobj
, ops
, ifacenames
)
699 self
.preprocess_upperiface(ifaceobj
, ulist
, ops
)
700 if dependents_processed
:
703 self
.preprocess_dependency_list(ifaceobj
,
705 ifaceobj
.lowerifaces
= dlist
706 [iqueue
.append(d
) for d
in dlist
]
707 #if not self.dependency_graph.get(i):
708 # self.dependency_graph[i] = dlist
710 for i
in self
.ifaceobjdict
.keys():
711 iobj
= self
.get_ifaceobj_first(i
)
712 if (not iobj
.link_kind
and
713 not (iobj
.link_privflags
& ifaceLinkPrivFlags
.LOOPBACK
) and
715 iobj
.link_privflags |
= ifaceLinkPrivFlags
.LOOPBACK
717 self
.dependency_graph
[i
] = iobj
.lowerifaces
719 self
.dependency_graph
[i
] = []
721 if not self
.blacklisted_ifaces_present
:
724 # Walk through the dependency graph and remove blacklisted
725 # interfaces that were picked up as dependents
726 for i
in self
.dependency_graph
.keys():
727 ifaceobj
= self
.get_ifaceobj_first(i
)
731 if ifaceobj
.blacklisted
and not ifaceobj
.upperifaces
:
732 # if blacklisted and was not picked up as a
733 # dependent of a upper interface, delete the
734 # interface from the dependency graph
735 dlist
= ifaceobj
.lowerifaces
738 difaceobjs
= self
.get_ifaceobjs(d
)
744 d
.upperifaces
.remove(i
)
746 self
.logger
.debug('error removing %s from %s upperifaces' %(i
, d
))
748 self
.logger
.debug("populate_dependency_info: deleting blacklisted interface %s" %i)
749 del self
.dependency_graph
[i
]
752 def _check_config_no_repeats(self
, ifaceobj
):
753 """ check if object has an attribute that is
754 restricted to a single object in the system.
755 if yes, warn and return """
756 for k
,v
in self
._cache
_no
_repeats
.items():
757 iv
= ifaceobj
.config
.get(k
)
758 if iv
and iv
[0] == v
:
759 self
.logger
.error('ignoring interface %s. ' %ifaceobj
.name
+
760 'Only one object with attribute ' +
761 '\'%s %s\' allowed.' %(k
, v
))
763 for k
, v
in self
.config
.get('no_repeats', {}).items():
764 iv
= ifaceobj
.config
.get(k
)
765 if iv
and iv
[0] == v
:
766 self
._cache
_no
_repeats
[k
] = v
769 def _save_iface_squash(self
, ifaceobj
):
770 """ squash ifaceobjects belonging to same iface
771 into a single object """
772 if self
._check
_config
_no
_repeats
(ifaceobj
):
774 ifaceobj
.priv_flags
= ifacePrivFlags()
775 if not self
._link
_master
_slave
:
776 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
777 currentifaceobjlist
= self
.ifaceobjdict
.get(ifaceobj
.name
)
778 if not currentifaceobjlist
:
779 self
.ifaceobjdict
[ifaceobj
.name
] = [ifaceobj
]
781 if ifaceobj
.compare(currentifaceobjlist
[0]):
782 self
.logger
.warn('duplicate interface %s found' %ifaceobj
.name
)
784 for obj
in self
.ifaceobjdict
[ifaceobj
.name
]:
785 if obj
.type == ifaceobj
.type:
788 self
.ifaceobjdict
[ifaceobj
.name
].append(ifaceobj
)
790 def _save_iface(self
, ifaceobj
):
791 if self
._check
_config
_no
_repeats
(ifaceobj
):
793 ifaceobj
.priv_flags
= ifacePrivFlags()
794 if not self
._link
_master
_slave
:
795 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
796 currentifaceobjlist
= self
.ifaceobjdict
.get(ifaceobj
.name
)
797 if not currentifaceobjlist
:
798 self
.ifaceobjdict
[ifaceobj
.name
]= [ifaceobj
]
799 if not self
._ifaceobj
_squash
:
800 ifaceobj
.flags |
= ifaceobj
.YOUNGEST_SIBLING
802 if ifaceobj
.compare(currentifaceobjlist
[0]):
803 self
.logger
.warn('duplicate interface %s found' %ifaceobj
.name
)
805 if currentifaceobjlist
[0].type == ifaceobj
.type:
806 currentifaceobjlist
[0].flags |
= ifaceobj
.HAS_SIBLINGS
807 ifaceobj
.flags |
= ifaceobj
.HAS_SIBLINGS
808 # clear the OLDEST_SIBLING from all the siblings
809 for iface
in self
.ifaceobjdict
[ifaceobj
.name
]:
810 iface
.flags
&= ~ifaceobj
.OLDEST_SIBLING
811 # current sibling is the oldest
812 ifaceobj
.flags |
= ifaceobj
.OLDEST_SIBLING
813 self
.ifaceobjdict
[ifaceobj
.name
].append(ifaceobj
)
815 def _keyword_text(self
, value
, validrange
=None):
816 return isinstance(value
, str) and len(value
) > 0
818 def _keyword_mac(self
, value
, validrange
=None):
819 if value
.strip().startswith('ether'):
820 value
= value
.strip()[6:]
821 return re
.match('[0-9a-f]{1,2}([-:])[0-9a-f]{1,2}(\\1[0-9a-f]{1,2}){4}$',
824 def _keyword_check_list(self
, _list
, obj
, limit
=None):
826 if limit
and limit
> 0:
827 for i
in xrange(0, limit
):
829 return len(_list
) == limit
834 except Exception as e
:
835 self
.logger
.debug('keyword: check list: %s' % str(e
))
838 def _keyword_ipv4(self
, value
, validrange
=None):
839 return self
._keyword
_check
_list
(value
.split(), IPv4Address
, limit
=1)
841 def _keyword_ipv4_prefixlen(self
, value
, validrange
=None):
842 return self
._keyword
_check
_list
(value
.split(), IPv4Network
, limit
=1)
844 def _keyword_ipv6(self
, value
, validrange
=None):
845 return self
._keyword
_check
_list
(value
.split(), IPv6Address
, limit
=1)
847 def _keyword_ipv6_prefixlen(self
, value
, validrange
=None):
848 return self
._keyword
_check
_list
(value
.split(), IPv6Network
, limit
=1)
850 def _keyword_ip(self
, value
, validrange
=None):
851 return self
._keyword
_check
_list
(value
.split(), IPAddress
, limit
=1)
853 def _keyword_ip_prefixlen(self
, value
, validrange
=None):
854 return self
._keyword
_check
_list
(value
.split(), IPNetwork
, limit
=1)
856 def _keyword_mac_ip_prefixlen_list(self
, value
, validrange
=None):
858 <mac> <ip> [<ip> ...]
859 ex: address-virtual 00:11:22:33:44:01 11.0.1.1/24 11.0.1.2/24
865 if not self
._keyword
_mac
(res
[0]):
868 if not self
._keyword
_ip
_prefixlen
(ip
):
871 except Exception as e
:
872 self
.logger
.debug('keyword: mac ipaddr prefixlen: %s' % str(e
))
875 def _keyword_number_ipv4_list(self
, value
, validrange
=None):
877 <number>=<ipv4> [<number>=<ipv4> ...]
878 ex: bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1
881 elements
= value
.split(' ')
884 for elem
in elements
:
889 except Exception as e
:
890 self
.logger
.debug('keyword: number ipv4: %s' % str(e
))
893 def _keyword_interface(self
, ifacename
, validrange
=None):
894 return self
.get_ifaceobjs(ifacename
)
896 def _keyword_ipv4_vrf_text(self
, value
, validrange
=None):
899 ex: clagd-backup-ip 10.10.10.42 vrf blue
901 values
= value
.split()
904 if size
> 3 or size
< 1:
907 IPv4Address(values
[0])
909 if values
[1] != 'vrf':
912 if not self
._keyword
_text
(values
[2]):
915 except Exception as e
:
916 self
.logger
.debug('keyword: ipv4 vrf text: %s' % str(e
))
919 def _keyword_interface_list_with_value(self
, value
, validvals
):
920 values
= value
.split()
923 if values
[0] in validvals
:
926 iface_value
= v
.split('=')
927 size
= len(iface_value
)
929 if iface_value
[0] == 'glob' or iface_value
[0] == 'regex':
932 if not iface_value
[1] in validvals
:
935 except Exception as e
:
936 self
.logger
.debug('keyword: interface list with value: %s' % str(e
))
939 def _keyword_interface_on_off_list(self
, value
, validrange
=None):
941 <yes|no> | ( <interface>=<on|off> [<interface>=<on|off> ...] )
942 ex: bridge-learning swp1=on swp2=off
944 return self
._keyword
_interface
_list
_with
_value
(value
, ['on', 'off'])
946 def _keyword_interface_yes_no_list(self
, value
, validrange
=None):
948 <yes|no> | ( <interface>=<yes|no> [<interface>=<yes|no> ...] )
949 ex: mstpctl-portrestrrole swp1=yes swp2=no
951 return self
._keyword
_interface
_list
_with
_value
(value
, ['yes', 'no'])
953 def _keyword_interface_yes_no_auto_list(self
, value
, validrange
=None):
956 ( <interface>=<yes|no|auto> [<interface>=<yes|no|auto> ...] )
957 ex: mstpctl-portp2p swp1=yes swp2=no swp3=auto
959 return self
._keyword
_interface
_list
_with
_value
(value
,
960 ['yes', 'no', 'auto'])
962 def _keyword_interface_l2protocol_tunnel_list(self
, value
, validrange
=None):
964 bridge-l2protocol-tunnel swpX=lacp,stp swpY=cdp swpZ=all
965 bridge-l2protocol-tunnel lacp stp,lldp,cdp
966 bridge-l2protocol-tunnel stp lacp cdp
967 bridge-l2protocol-tunnel lldp pvst
968 bridge-l2protocol-tunnel stp
969 bridge-l2protocol-tunnel all
973 for intf_arg
in value
.split():
974 intf_arg_split
= intf_arg
.split('=')
975 for arg
in re
.split(',|\s*', intf_arg_split
[1]):
976 if arg
not in ['all', 'stp', 'lldp', 'lacp', 'cdp', 'pvst']:
979 for arg
in re
.split(',|\s*', value
):
980 if arg
not in ['all', 'stp', 'lldp', 'lacp', 'cdp', 'pvst']:
986 def _keyword_interface_yes_no_0_1_list(self
, value
, validrange
=None):
989 ( <interface>=<yes|no|0|1> [<interface>=<yes|no|0|1> ...] )
990 ex: bridge-portmcrouter swp1=yes swp2=yes swp3=1
992 return self
._keyword
_interface
_list
_with
_value
(value
,
993 ['yes', 'no', '1', '0', '2'])
995 def _keyword_interface_disabled_automatic_enabled_list(self
, value
, validrange
=None):
996 return self
._keyword
_interface
_list
_with
_value
(value
, [
997 '0', 'disabled', 'no',
998 '1', 'automatic', 'yes',
1001 def _keyword_interface_range_list_multiple_of_16(self
, value
, validrange
):
1002 return self
._keyword
_interface
_range
_list
(value
, validrange
, multiple
=16)
1004 def _keyword_interface_range_list(self
, value
, validrange
, multiple
=None):
1006 <number> | ( <interface>=<number> [ <interface>=number> ...] )
1007 ex: mstpctl-portpathcost swp1=0 swp2=1
1009 values
= value
.split()
1011 if len(values
) == 1 and '=' not in values
[0]:
1014 if n
< int(validrange
[0]) or n
> int(
1016 raise invalidValueError('value of out range "%s":'
1017 ' valid attribute range: %s'
1019 '-'.join(validrange
)))
1021 if multiple
is not None:
1022 if not (n
% multiple
== 0):
1023 raise invalidValueError('invalid value %s: must be a multiple of %s' % (n
, multiple
))
1026 except invalidValueError
as e
:
1028 except Exception as e
:
1029 self
.logger
.debug('keyword: interface range list: %s'
1033 iface_value
= v
.split('=')
1034 size
= len(iface_value
)
1037 number
= int(iface_value
[1])
1038 if number
< int(validrange
[0]) or number
> int(
1040 raise invalidValueError(
1041 'value of out range "%s" for iface "%s":'
1042 ' valid attribute range: %s'
1045 '-'.join(validrange
)))
1047 if multiple
is not None:
1048 if not (number
% multiple
== 0):
1049 raise invalidValueError('invalid value %s: must be a multiple of %s' % (number
, multiple
))
1052 except invalidValueError
as e
:
1054 except Exception as e
:
1055 self
.logger
.debug('keyword: interface range list: %s' % str(e
))
1058 def _keyword_interface_list(self
, value
, validrange
=None):
1060 [glob|regex] <interface> [ [glob|regex] <interface> ...]
1061 ex: bridge-ports swp1 swp2 glob swp3-5.100 regex (swp[6|7|8].100)
1063 interface_list
= value
.split()
1064 size
= len(interface_list
)
1067 if interface_list
[i
] == 'glob' or interface_list
[i
] == 'regex':
1070 if not self
._keyword
_interface
(interface_list
[i
]):
1075 def _keyword_number_range_list(self
, value
, validrange
=None):
1077 <number> [<number>-<number>]
1078 ex: bridge-vids 42 100-200
1080 number_list
= value
.split()
1083 while i
< len(number_list
):
1084 if '-' in number_list
[i
]:
1085 range = number_list
[i
].split('-')
1094 except Exception as e
:
1095 self
.logger
.debug('keyword: number range list: %s' % str(e
))
1098 def _keyword_number_interface_list(self
, value
, validrange
=None):
1100 <number> <interface> [<interface>... [<number> <interface> ... ]]
1101 bridge-waitport 42 swp1 swp2 swp3 9 swp4
1103 interface_list
= value
.split()
1104 if not interface_list
:
1107 int(interface_list
[0])
1109 for elem
in interface_list
[1:]:
1118 except Exception as e
:
1119 self
.logger
.debug('keyword: number interface list: %s' % str(e
))
1122 def _keyword_number(self
, value
, validrange
=None):
1126 except Exception as e
:
1127 self
.logger
.debug('keyword: number: %s' % str(e
))
1130 def _is_keyword(self
, value
):
1131 if isinstance(value
, tuple):
1133 keyword_found
= value
in self
.validate_keywords
1134 if value
.startswith('<') and value
.endswith('>') and not keyword_found
:
1135 raise Exception('%s: invalid keyword, please make sure to use'
1136 ' a valid keyword see `ifquery -s`' % value
)
1137 return keyword_found
1139 def _check_validvals_value(self
, attrname
, value
, validvals
, validrange
):
1140 if validvals
and value
not in validvals
:
1142 for keyword
in validvals
:
1143 if self
._is
_keyword
(keyword
):
1145 if self
.validate_keywords
[keyword
](value
, validrange
):
1146 return {'result': True}
1148 if self
.validate_keywords
[keyword
](value
):
1149 return {'result': True}
1153 'message': 'invalid value "%s": valid attribute values: %s'
1154 % (value
, validvals
)
1156 elif validvals
and value
in validvals
:
1159 if len(validrange
) != 2:
1160 raise Exception('%s: invalid range in addon configuration'
1161 % '-'.join(validrange
))
1163 if _value
< int(validrange
[0]) or _value
> int(validrange
[1]):
1166 'message': 'value of out range "%s": '
1167 'valid attribute range: %s'
1168 % (value
, '-'.join(validrange
))
1170 return {'result': True}
1172 def _check_validvals(self
, ifacename
, module_name
, attrs
):
1173 ifaceobj
= self
.get_ifaceobjs(ifacename
)
1177 for attrname
, attrvalue
in ifaceobj
[0].config
.items():
1179 attrname_dict
= attrs
.get(attrname
, {})
1180 validvals
= attrname_dict
.get('validvals', [])
1181 validrange
= attrname_dict
.get('validrange', [])
1182 for value
in attrvalue
:
1183 res
= self
._check
_validvals
_value
(attrname
,
1187 if not res
['result']:
1188 self
.logger
.warn('%s: %s: %s' %
1189 (ifacename
, attrname
, res
['message']))
1191 except Exception as e
:
1192 self
.logger
.warn('addon \'%s\': %s: %s' % (module_name
,
1198 def _module_syntax_check(self
, filtered_ifacenames
):
1200 for ifacename
in filtered_ifacenames
:
1201 for module
in self
.modules
.values():
1203 if hasattr(module
, '_modinfo'):
1204 if not self
._check
_validvals
(ifacename
,
1205 module
.__class
__.__name
__,
1206 module
._modinfo
.get('attrs', {})):
1208 if hasattr(module
, 'syntax_check') and callable(module
.syntax_check
):
1209 if not module
.syntax_check(self
.get_ifaceobjs(ifacename
)[0],
1210 self
.get_ifaceobjs
):
1212 except Exception, e
:
1213 self
.logger
.warn('%s: %s' % (ifacename
, str(e
)))
1217 def _iface_configattr_syntax_checker(self
, attrname
, attrval
):
1218 for m
, mdict
in self
.module_attrs
.items():
1221 attrsdict
= mdict
.get('attrs')
1223 a
= attrsdict
.get(attrname
)
1225 if a
.get('deprecated'):
1226 newa
= a
.get('new-attribute')
1228 self
.logger
.warn('attribute %s is deprecated. use %s instead.' %(attrname
, newa
))
1230 self
.logger
.warn('attribute %s is deprecated.'
1234 for key
in attrsdict
:
1235 if 'aliases' in attrsdict
[key
]:
1236 if attrname
in attrsdict
[key
]['aliases']:
1238 except AttributeError:
1242 def _ifaceobj_syntax_checker(self
, ifaceobj
):
1244 for attrname
, attrvalue
in ifaceobj
.config
.items():
1246 for k
, v
in self
.module_attrs
.items():
1247 if v
and v
.get('attrs', {}).get(attrname
):
1252 self
.logger
.warn('%s: unsupported attribute \'%s\'' \
1253 % (ifaceobj
.name
, attrname
))
1257 def read_iface_config(self
):
1258 """ Reads default network interface config /etc/network/interfaces. """
1260 nifaces
= networkInterfaces(self
.interfacesfile
,
1261 self
.interfacesfileiobuf
,
1262 self
.interfacesfileformat
,
1263 template_enable
=self
.config
.get('template_enable', 0),
1264 template_engine
=self
.config
.get('template_engine'),
1265 template_lookuppath
=self
.config
.get('template_lookuppath'))
1266 if self
._ifaceobj
_squash
or self
._ifaceobj
_squash
_internal
:
1267 nifaces
.subscribe('iface_found', self
._save
_iface
_squash
)
1269 nifaces
.subscribe('iface_found', self
._save
_iface
)
1270 if self
.config
.get('addon_syntax_check', '1') == '1':
1271 nifaces
.subscribe('validateifaceattr',
1272 self
._iface
_configattr
_syntax
_checker
)
1273 nifaces
.subscribe('validateifaceobj', self
._ifaceobj
_syntax
_checker
)
1275 if nifaces
.errors
or nifaces
.warns
:
1279 def read_old_iface_config(self
):
1280 """ Reads the saved iface config instead of default iface config.
1281 And saved iface config is already read by the statemanager """
1282 self
.ifaceobjdict
= copy
.deepcopy(self
.statemanager
.ifaceobjdict
)
1284 def _load_addon_modules_config(self
):
1285 """ Load addon modules config file """
1287 with
open(self
.addon_modules_configfile
, 'r') as f
:
1288 lines
= f
.readlines()
1291 litems
= l
.strip(' \n\t\r').split(',')
1292 if not litems
or len(litems
) < 2:
1294 operation
= litems
[0]
1296 self
.module_ops
[operation
].append(mname
)
1297 except Exception, e
:
1298 self
.logger
.warn('error reading line \'%s\' %s:' %(l
, str(e
)))
1301 def load_addon_modules(self
, modules_dir_list
):
1302 """ load python modules from modules_dir
1304 Default modules_dir is /usr/share/ifupdownmodules
1307 failed_import
= list()
1309 self
.logger
.info('loading builtin modules from %s' % str(modules_dir_list
))
1310 self
._load
_addon
_modules
_config
()
1312 for modules_dir
in modules_dir_list
:
1313 if not modules_dir
in sys
.path
:
1314 sys
.path
.insert(1, modules_dir
)
1316 for op
, mlist
in self
.module_ops
.items():
1318 if self
.modules
.get(mname
):
1320 mpath
= modules_dir
+ '/' + mname
+ '.py'
1321 if os
.path
.exists(mpath
) and mpath
not in failed_import
:
1323 m
= __import__(mname
)
1324 mclass
= getattr(m
, mname
)
1325 except Exception as e
:
1326 self
.logger
.warning('cannot load "%s" module: %s' % (mname
, str(e
)))
1327 failed_import
.append(mpath
)
1330 minstance
= mclass()
1331 script_override
= minstance
.get_overrides_ifupdown_scripts()
1332 self
.overridden_ifupdown_scripts
.extend(script_override
)
1333 except moduleNotSupported
, e
:
1334 self
.logger
.info('module %s not loaded (%s)\n'
1339 self
.modules
[mname
] = minstance
1341 self
.module_attrs
[mname
] = minstance
.get_modinfo()
1347 # Assign all modules to query operations
1348 self
.module_ops
['query-checkcurr'] = self
.modules
.keys()
1349 self
.module_ops
['query-running'] = self
.modules
.keys()
1350 self
.module_ops
['query-dependency'] = self
.modules
.keys()
1351 self
.module_ops
['query'] = self
.modules
.keys()
1352 self
.module_ops
['query-raw'] = self
.modules
.keys()
1354 def _keyword_number_comma_range_list(self
, value
, validrange
=None):
1355 return self
._keyword
_number
_range
_list
(value
.replace(',', ' '), validrange
=validrange
)
1358 def _modules_help(self
, fmt
):
1359 """ Prints addon modules supported syntax """
1363 for key
, value
in self
.modules
.items():
1364 if hasattr(value
, '_modinfo'):
1366 'mhelp': value
._modinfo
['mhelp'],
1367 'attrs': value
.merge_modinfo_with_policy_files()
1369 print json
.dumps(modinfos
)
1372 for m
, mdict
in self
.module_attrs
.items():
1375 print('%s: %s' %(m
, mdict
.get('mhelp')))
1376 attrdict
= self
.modules
[m
].merge_modinfo_with_policy_files()
1380 for attrname
, attrvaldict
in attrdict
.items():
1381 if attrvaldict
.get('compat', False):
1383 print('%s%s' %(indent
, attrname
))
1384 print('%shelp: %s' %(indent
+ ' ',
1385 attrvaldict
.get('help', '')))
1386 print ('%srequired: %s' %(indent
+ ' ',
1387 attrvaldict
.get('required', False)))
1388 default
= attrvaldict
.get('default')
1390 print('%sdefault: %s' %(indent
+ ' ', default
))
1392 validrange
= attrvaldict
.get('validrange')
1394 print('%svalidrange: %s-%s'
1395 %(indent
+ ' ', validrange
[0], validrange
[1]))
1397 validvals
= attrvaldict
.get('validvals')
1399 print('%svalidvals: %s'
1400 %(indent
+ ' ', ','.join(validvals
)))
1402 examples
= attrvaldict
.get('example')
1406 print '%sexample:' %(indent
+ ' ')
1408 print '%s%s' %(indent
+ ' ', e
)
1413 def load_scripts(self
, modules_dir
):
1414 """ loading user modules from /etc/network/.
1416 Note that previously loaded python modules override modules found
1417 under /etc/network if any
1421 self
.logger
.info('looking for user scripts under %s' %modules_dir
)
1422 for op
, mlist
in self
.script_ops
.items():
1423 msubdir
= modules_dir
+ '/if-%s.d' %op
1424 self
.logger
.info('loading scripts under %s ...' %msubdir
)
1426 module_list
= os
.listdir(msubdir
)
1427 for module
in module_list
:
1428 if self
.modules
.get(module
) or module
in self
.overridden_ifupdown_scripts
:
1430 self
.script_ops
[op
].append(msubdir
+ '/' + module
)
1435 def _sched_ifaces(self
, ifacenames
, ops
, skipupperifaces
=False,
1436 followdependents
=True, sort
=False):
1437 self
.logger
.debug('scheduling \'%s\' for %s'
1438 %(str(ops
), str(ifacenames
)))
1439 self
._pretty
_print
_ordered
_dict
('dependency graph',
1440 self
.dependency_graph
)
1441 ifaceScheduler
.sched_ifaces(self
, ifacenames
, ops
,
1442 dependency_graph
=self
.dependency_graph
,
1443 order
=ifaceSchedulerFlags
.INORDER
1445 else ifaceSchedulerFlags
.POSTORDER
,
1446 followdependents
=followdependents
,
1447 skipupperifaces
=skipupperifaces
,
1448 sort
=True if (sort
or ifupdownflags
.flags
.CLASS
) else False)
1449 return ifaceScheduler
.get_sched_status()
1451 def _render_ifacename(self
, ifacename
):
1453 vlan_match
= re
.match("^([\d]+)-([\d]+)", ifacename
)
1455 vlan_groups
= vlan_match
.groups()
1456 if vlan_groups
[0] and vlan_groups
[1]:
1457 [new_ifacenames
.append('%d' %v
)
1458 for v
in range(int(vlan_groups
[0]),
1459 int(vlan_groups
[1])+1)]
1460 return new_ifacenames
1462 def _preprocess_ifacenames(self
, ifacenames
):
1463 """ validates interface list for config existance.
1465 returns -1 if one or more interface not found. else, returns 0
1470 for i
in ifacenames
:
1471 ifaceobjs
= self
.get_ifaceobjs(i
)
1473 # if name not available, render interface name and check again
1474 rendered_ifacenames
= utils
.expand_iface_range(i
)
1475 if rendered_ifacenames
:
1476 for ri
in rendered_ifacenames
:
1477 ifaceobjs
= self
.get_ifaceobjs(ri
)
1479 err_iface
+= ' ' + ri
1481 new_ifacenames
.append(ri
)
1483 err_iface
+= ' ' + i
1485 new_ifacenames
.append(i
)
1487 raise Exception('cannot find interfaces:%s' %err_iface
)
1488 return new_ifacenames
1490 def _iface_whitelisted(self
, auto
, allow_classes
, excludepats
, ifacename
):
1491 """ Checks if interface is whitelisted depending on set of parameters.
1493 interfaces are checked against the allow_classes and auto lists.
1499 # Check if interface matches the exclude patter
1501 for e
in excludepats
:
1502 if re
.search(e
, ifacename
):
1504 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
1507 self
.logger
.debug('iface %s' %ifacename
+ ' not found')
1509 # If matched exclude pattern, return false
1512 i
.blacklisted
= True
1513 self
.blacklisted_ifaces_present
= True
1515 # Check if interface belongs to the class
1516 # the user is interested in, if not return false
1521 common
= Set(allow_classes
).intersection(
1526 # If a class was requested and interface does not belong
1527 # to the class, only then mark the ifaceobjs as blacklisted
1528 self
.blacklisted_ifaces_present
= True
1530 i
.blacklisted
= True
1532 # If the user has requested auto class, check if the interface
1540 # If auto was requested and interface was not marked auto,
1541 # only then mark all of them as blacklisted
1542 self
.blacklisted_ifaces_present
= True
1544 i
.blacklisted
= True
1547 def _compat_conv_op_to_mode(self
, op
):
1548 """ Returns old op name to work with existing scripts """
1556 def generate_running_env(self
, ifaceobj
, op
):
1557 """ Generates a dictionary with env variables required for
1558 an interface. Used to support script execution for interfaces.
1562 iface_env
= ifaceobj
.get_env()
1564 cenv
= dict(os
.environ
)
1566 cenv
.update(iface_env
)
1571 cenv
['MODE'] = self
._compat
_conv
_op
_to
_mode
(op
)
1576 def _save_state(self
):
1577 if (not self
.flags
.STATEMANAGER_ENABLE
or
1578 not self
.flags
.STATEMANAGER_UPDATE
):
1581 # Update persistant iface states
1582 self
.statemanager
.save_state()
1583 except Exception, e
:
1584 if self
.logger
.isEnabledFor(logging
.DEBUG
):
1585 t
= sys
.exc_info()[2]
1586 traceback
.print_tb(t
)
1587 self
.logger
.warning('error saving state (%s)' %str
(e
))
1589 def set_type(self
, type):
1591 self
.type = ifaceType
.IFACE
1592 elif type == 'vlan':
1593 self
.type = ifaceType
.BRIDGE_VLAN
1595 self
.type = ifaceType
.UNKNOWN
1597 def _process_delay_admin_state_queue(self
, op
):
1598 if not self
._delay
_admin
_state
_iface
_queue
:
1603 func
= self
.link_down
1606 for i
in self
._delay
_admin
_state
_iface
_queue
:
1608 if self
.link_exists(i
):
1610 except Exception, e
:
1611 self
.logger
.warn(str(e
))
1614 def up(self
, ops
, auto
=False, allow_classes
=None, ifacenames
=None,
1615 excludepats
=None, printdependency
=None, syntaxcheck
=False,
1616 type=None, skipupperifaces
=False):
1617 """This brings the interface(s) up
1620 ops (list): list of ops to perform on the interface(s).
1621 Eg: ['pre-up', 'up', 'post-up'
1624 auto (bool): act on interfaces marked auto
1625 allow_classes (list): act on interfaces belonging to classes in the list
1626 ifacenames (list): act on interfaces specified in this list
1627 excludepats (list): list of patterns of interfaces to exclude
1628 syntaxcheck (bool): only perform syntax check
1634 ifupdownflags
.flags
.CLASS
= True
1635 if not self
.flags
.ADDONS_ENABLE
:
1636 self
.flags
.STATEMANAGER_UPDATE
= False
1638 ifupdownflags
.flags
.ALL
= True
1639 ifupdownflags
.flags
.WITH_DEPENDS
= True
1641 iface_read_ret
= self
.read_iface_config()
1645 filtered_ifacenames
= None
1647 ifacenames
= self
._preprocess
_ifacenames
(ifacenames
)
1650 filtered_ifacenames
= self
._get
_filtered
_ifacenames
_with
_classes
(auto
, allow_classes
, excludepats
, ifacenames
)
1652 # if iface list not given by user, assume all from config file
1653 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1655 if not filtered_ifacenames
:
1656 # filter interfaces based on auto and allow classes
1657 filtered_ifacenames
= [i
for i
in ifacenames
1658 if self
._iface
_whitelisted
(auto
, allow_classes
,
1661 if not filtered_ifacenames
:
1662 raise Exception('no ifaces found matching given allow lists')
1665 self
.populate_dependency_info(ops
, filtered_ifacenames
)
1666 self
.print_dependency(filtered_ifacenames
, printdependency
)
1669 self
.populate_dependency_info(ops
)
1671 # If only syntax check was requested, return here.
1672 # return here because we want to make sure most
1673 # errors above are caught and reported.
1675 if not self
._module
_syntax
_check
(filtered_ifacenames
):
1677 if not iface_read_ret
:
1679 elif self
._any
_iface
_errors
(filtered_ifacenames
):
1685 ret
= self
._sched
_ifaces
(filtered_ifacenames
, ops
,
1686 skipupperifaces
=skipupperifaces
,
1687 followdependents
=True
1688 if ifupdownflags
.flags
.WITH_DEPENDS
1691 self
._process
_delay
_admin
_state
_queue
('up')
1692 if not ifupdownflags
.flags
.DRYRUN
and self
.flags
.ADDONS_ENABLE
:
1695 if not iface_read_ret
or not ret
:
1698 def _get_filtered_ifacenames_with_classes(self
, auto
, allow_classes
, excludepats
, ifacenames
):
1699 # if user has specified ifacelist and allow_classes
1700 # append the allow_classes interfaces to user
1702 filtered_ifacenames
= [i
for i
in self
.ifaceobjdict
.keys()
1703 if self
._iface
_whitelisted
(auto
, allow_classes
,
1705 filtered_ifacenames
+= ifacenames
1707 for intf
in ifacenames
:
1708 for obj
in self
.get_ifaceobjs(intf
) or []:
1709 obj
.blacklisted
= False
1711 return filtered_ifacenames
1713 def down(self
, ops
, auto
=False, allow_classes
=None, ifacenames
=None,
1714 excludepats
=None, printdependency
=None, usecurrentconfig
=False,
1716 """ down an interface """
1721 ifupdownflags
.flags
.CLASS
= True
1722 if not self
.flags
.ADDONS_ENABLE
:
1723 self
.flags
.STATEMANAGER_UPDATE
= False
1725 ifupdownflags
.flags
.ALL
= True
1726 ifupdownflags
.flags
.WITH_DEPENDS
= True
1727 # For down we need to look at old state, unless usecurrentconfig
1729 if (not usecurrentconfig
and self
.flags
.STATEMANAGER_ENABLE
and
1730 self
.statemanager
.ifaceobjdict
):
1731 # Since we are using state manager objects,
1732 # skip the updating of state manager objects
1733 self
.logger
.debug('Looking at old state ..')
1734 self
.read_old_iface_config()
1736 # If no old state available
1738 self
.read_iface_config()
1739 except Exception, e
:
1740 raise Exception('error reading iface config (%s)' %str
(e
))
1741 filtered_ifacenames
= None
1743 # If iface list is given by the caller, always check if iface
1746 ifacenames
= self
._preprocess
_ifacenames
(ifacenames
)
1749 filtered_ifacenames
= self
._get
_filtered
_ifacenames
_with
_classes
(auto
, allow_classes
, excludepats
, ifacenames
)
1751 except Exception, e
:
1752 raise Exception('%s' %str
(e
) +
1753 ' (interface was probably never up ?)')
1756 # if iface list not given by user, assume all from config file
1757 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1759 if not filtered_ifacenames
:
1760 # filter interfaces based on auto and allow classes
1761 filtered_ifacenames
= [i
for i
in ifacenames
1762 if self
._iface
_whitelisted
(auto
, allow_classes
,
1765 if not filtered_ifacenames
:
1766 raise Exception('no ifaces found matching given allow lists ' +
1767 '(or interfaces were probably never up ?)')
1770 self
.populate_dependency_info(ops
, filtered_ifacenames
)
1771 self
.print_dependency(filtered_ifacenames
, printdependency
)
1774 self
.populate_dependency_info(ops
)
1777 self
._sched
_ifaces
(filtered_ifacenames
, ops
,
1778 followdependents
=True
1779 if ifupdownflags
.flags
.WITH_DEPENDS
else False)
1781 self
._process
_delay
_admin
_state
_queue
('down')
1782 if not ifupdownflags
.flags
.DRYRUN
and self
.flags
.ADDONS_ENABLE
:
1785 def query(self
, ops
, auto
=False, format_list
=False, allow_classes
=None,
1787 excludepats
=None, printdependency
=None,
1788 format
='native', type=None):
1789 """ query an interface """
1793 # Let us forget internal squashing when it comes to
1794 # ifquery. It can surprise people relying of ifquery
1796 self
._ifaceobj
_squash
_internal
= False
1799 ifupdownflags
.flags
.CLASS
= True
1800 if self
.flags
.STATEMANAGER_ENABLE
and ops
[0] == 'query-savedstate':
1801 return self
.statemanager
.dump_pretty(ifacenames
)
1802 self
.flags
.STATEMANAGER_UPDATE
= False
1804 iface_read_ret
= True
1807 self
.logger
.debug('setting flag ALL')
1808 ifupdownflags
.flags
.ALL
= True
1809 ifupdownflags
.flags
.WITH_DEPENDS
= True
1811 if ops
[0] == 'query-syntax':
1812 self
._modules
_help
(format
)
1814 elif ops
[0] == 'query-running':
1815 # create fake devices to all dependents that dont have config
1816 map(lambda i
: self
.create_n_save_ifaceobj(i
,
1817 ifacePrivFlags(False, True)), ifacenames
)
1820 iface_read_ret
= self
.read_iface_config()
1824 if ifacenames
and ops
[0] != 'query-running':
1825 # If iface list is given, always check if iface is present
1826 ifacenames
= self
._preprocess
_ifacenames
(ifacenames
)
1829 filtered_ifacenames
= self
._get
_filtered
_ifacenames
_with
_classes
(auto
, allow_classes
, excludepats
, ifacenames
)
1831 # if iface list not given by user, assume all from config file
1832 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1834 # filter interfaces based on auto and allow classes
1835 if ops
[0] == 'query-running':
1836 filtered_ifacenames
= ifacenames
1837 elif not allow_classes
:
1838 filtered_ifacenames
= [
1839 i
for i
in ifacenames
1840 if self
._iface
_whitelisted
(
1847 if not filtered_ifacenames
:
1848 raise Exception('no ifaces found matching ' +
1849 'given allow lists')
1851 self
.populate_dependency_info(ops
)
1852 if ops
[0] == 'query-dependency' and printdependency
:
1853 self
.print_dependency(filtered_ifacenames
, printdependency
)
1856 if format_list
and (ops
[0] == 'query' or ops
[0] == 'query-raw'):
1857 return self
.print_ifaceobjs_list(filtered_ifacenames
)
1859 if ops
[0] == 'query' and not ifupdownflags
.flags
.WITHDEFAULTS
:
1860 return self
.print_ifaceobjs_pretty(filtered_ifacenames
, format
)
1861 elif ops
[0] == 'query-raw':
1862 return self
.print_ifaceobjs_raw(filtered_ifacenames
)
1864 ret
= self
._sched
_ifaces
(filtered_ifacenames
, ops
,
1865 followdependents
=True
1866 if ifupdownflags
.flags
.WITH_DEPENDS
else False)
1868 if ops
[0] == 'query' and ifupdownflags
.flags
.WITHDEFAULTS
:
1869 return self
.print_ifaceobjs_pretty(filtered_ifacenames
, format
)
1870 elif ops
[0] == 'query-checkcurr':
1871 if self
.print_ifaceobjscurr_pretty(filtered_ifacenames
, format
):
1872 # if any of the object has an error, signal that silently
1874 elif ops
[0] == 'query-running':
1875 self
.print_ifaceobjsrunning_pretty(filtered_ifacenames
, format
)
1878 if not iface_read_ret
or not ret
:
1881 def _reload_currentlyup(self
, upops
, downops
, auto
=False, allow
=None,
1882 ifacenames
=None, excludepats
=None, usecurrentconfig
=False,
1883 syntaxcheck
=False, **extra_args
):
1884 """ reload currently up interfaces """
1885 new_ifaceobjdict
= {}
1887 self
.logger
.info('reloading interfaces that are currently up ..')
1890 iface_read_ret
= self
.read_iface_config()
1893 if not self
.ifaceobjdict
:
1894 self
.logger
.warn("nothing to reload ..exiting.")
1896 already_up_ifacenames
= []
1897 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1899 if (not usecurrentconfig
and self
.flags
.STATEMANAGER_ENABLE
1900 and self
.statemanager
.ifaceobjdict
):
1901 already_up_ifacenames
= self
.statemanager
.ifaceobjdict
.keys()
1903 # Get already up interfaces that still exist in the interfaces file
1904 already_up_ifacenames_not_present
= Set(
1905 already_up_ifacenames
).difference(ifacenames
)
1906 already_up_ifacenames_still_present
= Set(
1907 already_up_ifacenames
).difference(
1908 already_up_ifacenames_not_present
)
1910 interfaces_to_up
= already_up_ifacenames_still_present
1912 # generate dependency graph of interfaces
1913 self
.populate_dependency_info(upops
, interfaces_to_up
)
1915 # If only syntax check was requested, return here.
1916 # return here because we want to make sure most
1917 # errors above are caught and reported.
1919 if not self
._module
_syntax
_check
(interfaces_to_up
):
1921 if not iface_read_ret
:
1923 elif self
._any
_iface
_errors
(interfaces_to_up
):
1927 if (already_up_ifacenames_not_present
and
1928 self
.config
.get('ifreload_currentlyup_down_notpresent') == '1'):
1929 self
.logger
.info('reload: schedule down on interfaces: %s'
1930 %str
(already_up_ifacenames_not_present
))
1932 # Save a copy of new iface objects and dependency_graph
1933 new_ifaceobjdict
= dict(self
.ifaceobjdict
)
1934 new_dependency_graph
= dict(self
.dependency_graph
)
1936 # old interface config is read into self.ifaceobjdict
1937 self
.read_old_iface_config()
1939 # reinitialize dependency graph
1940 self
.dependency_graph
= OrderedDict({})
1941 falready_up_ifacenames_not_present
= [i
for i
in
1942 already_up_ifacenames_not_present
1943 if self
._iface
_whitelisted
(auto
, allow
,
1945 self
.populate_dependency_info(downops
,
1946 falready_up_ifacenames_not_present
)
1947 self
._sched
_ifaces
(falready_up_ifacenames_not_present
, downops
,
1948 followdependents
=False, sort
=True)
1950 self
.logger
.info('no interfaces to down ..')
1952 # Now, run 'up' with new config dict
1953 # reset statemanager update flag to default
1955 ifupdownflags
.flags
.ALL
= True
1956 ifupdownflags
.flags
.WITH_DEPENDS
= True
1957 if new_ifaceobjdict
:
1958 # and now, ifaceobjdict is back to current config
1959 self
.ifaceobjdict
= new_ifaceobjdict
1960 self
.dependency_graph
= new_dependency_graph
1962 if not self
.ifaceobjdict
:
1963 self
.logger
.info('no interfaces to up')
1965 self
.logger
.info('reload: scheduling up on interfaces: %s'
1966 %str
(interfaces_to_up
))
1967 ret
= self
._sched
_ifaces
(interfaces_to_up
, upops
,
1968 followdependents
=True
1969 if ifupdownflags
.flags
.WITH_DEPENDS
else False)
1970 if ifupdownflags
.flags
.DRYRUN
:
1974 if not iface_read_ret
or not ret
:
1977 def _reload_default(self
, upops
, downops
, auto
=False, allow
=None,
1978 ifacenames
=None, excludepats
=None, usecurrentconfig
=False,
1979 syntaxcheck
=False, **extra_args
):
1980 """ reload interface config """
1981 new_ifaceobjdict
= {}
1984 iface_read_ret
= self
.read_iface_config()
1988 if not self
.ifaceobjdict
:
1989 self
.logger
.warn("nothing to reload ..exiting.")
1992 if not ifacenames
: ifacenames
= self
.ifaceobjdict
.keys()
1993 new_filtered_ifacenames
= [i
for i
in ifacenames
1994 if self
._iface
_whitelisted
(auto
, allow
,
1996 # generate dependency graph of interfaces
1997 self
.populate_dependency_info(upops
)
1999 # If only syntax check was requested, return here.
2000 # return here because we want to make sure most
2001 # errors above are caught and reported.
2003 if not self
._module
_syntax
_check
(new_filtered_ifacenames
):
2005 if not iface_read_ret
:
2007 elif self
._any
_iface
_errors
(new_filtered_ifacenames
):
2011 if (not usecurrentconfig
and self
.flags
.STATEMANAGER_ENABLE
2012 and self
.statemanager
.ifaceobjdict
):
2013 # Save a copy of new iface objects and dependency_graph
2014 new_ifaceobjdict
= dict(self
.ifaceobjdict
)
2015 new_dependency_graph
= dict(self
.dependency_graph
)
2017 self
.ifaceobjdict
= OrderedDict({})
2018 self
.dependency_graph
= OrderedDict({})
2020 # if old state is present, read old state and mark op for 'down'
2021 # followed by 'up' aka: reload
2022 # old interface config is read into self.ifaceobjdict
2023 self
.read_old_iface_config()
2026 # oldconfig not available, continue with 'up' with new config
2028 new_ifaceobjdict
= self
.ifaceobjdict
2029 new_dependency_graph
= self
.dependency_graph
2031 if op
== 'reload' and ifacenames
:
2032 ifacenames
= self
.ifaceobjdict
.keys()
2033 old_filtered_ifacenames
= [i
for i
in ifacenames
2034 if self
._iface
_whitelisted
(auto
, allow
,
2037 # generate dependency graph of old interfaces,
2038 # This should make sure built in interfaces are
2039 # populated. disable check shared dependents as an optimization.
2040 # these are saved interfaces and dependency for these
2041 # have been checked before they became part of saved state.
2043 self
.flags
.CHECK_SHARED_DEPENDENTS
= False
2044 self
.populate_dependency_info(upops
)
2045 self
.flags
.CHECK_SHARED_DEPENDENTS
= True
2046 except Exception, e
:
2047 self
.logger
.info("error generating dependency graph for "
2048 "saved interfaces (%s)" %str
(e
))
2051 # make sure we pick up built-in interfaces
2052 # if config file had 'ifreload_down_changed' variable
2053 # set, also look for interfaces that changed to down them
2054 down_changed
= int(self
.config
.get('ifreload_down_changed', '1'))
2056 # Generate the interface down list
2057 # Interfaces that go into the down list:
2058 # - interfaces that were present in last config and are not
2059 # present in the new config
2060 # - interfaces that were changed between the last and current
2063 for ifname
in self
.ifaceobjdict
.keys():
2064 lastifaceobjlist
= self
.ifaceobjdict
.get(ifname
)
2065 if not self
.is_ifaceobj_builtin(lastifaceobjlist
[0]):
2066 # if interface is not built-in and is not in
2067 # old filtered ifacenames
2068 if ifname
not in old_filtered_ifacenames
:
2071 # If interface is not present in the new file
2072 # append it to the down list
2073 newifaceobjlist
= new_ifaceobjdict
.get(ifname
)
2074 if not newifaceobjlist
:
2075 ifacedownlist
.append(ifname
)
2077 # If ifaceobj was present in the old interfaces file,
2078 # and does not have a config in the new interfaces file
2079 # but has been picked up as a dependent of another
2080 # interface, catch it here. This catches a common error
2081 # for example: remove a bond section from the interfaces
2082 # file, but leave it around as a bridge port
2083 # XXX: Ideally its better to just add it to the
2084 # ifacedownlist. But we will be cautious here
2085 # and just print a warning
2086 if (self
.is_ifaceobj_noconfig(newifaceobjlist
[0]) and
2087 not self
.is_ifaceobj_builtin(newifaceobjlist
[0]) and
2088 lastifaceobjlist
[0].is_config_present() and
2089 lastifaceobjlist
[0].link_kind
):
2091 # Check if interface is picked up by a regex in the upperifaces.
2092 print_warning
= True
2094 for upper
in newifaceobjlist
[objidx
].upperifaces
or []:
2096 for upper_ifaceobj
in self
.ifaceobjdict
.get(upper
):
2097 slaves
.extend(upper_ifaceobj
.get_attr_value("bond-slaves") or [])
2098 slaves
.extend(upper_ifaceobj
.get_attr_value("bridge-ports") or [])
2099 slaves_string
= " ".join(slaves
)
2100 if newifaceobjlist
[objidx
].name
not in slaves_string
:
2101 print_warning
= "regex" not in slaves_string
2102 if not print_warning
:
2104 ###############################################################
2106 warning_no_config_regex
= (
2107 "%s: misconfig ? removed but still exists as a dependency of %s.\n"
2108 "Please remove the dependency manually `ifdown %s` if it is being "
2109 "picked up as part of a regex" % (
2110 newifaceobjlist
[objidx
].name
,
2111 str(newifaceobjlist
[objidx
].upperifaces
),
2112 newifaceobjlist
[objidx
].name
2117 self
.logger
.warn(warning_no_config_regex
)
2119 # The warning shouldn't be printed because we've detected that this
2120 # interface was pick up as part of a regex but the config doesn't
2121 # exist anymore. It was most likely removed from the config file itself
2122 # We should down this interface and remove it from the ifaceobjdict
2123 # and dependency graph used for the following ifreload.
2124 ifname_to_remove
= newifaceobjlist
[objidx
].name
2125 ifacedownlist
.append(ifname_to_remove
)
2128 if new_ifaceobjdict
:
2129 del new_ifaceobjdict
[ifname_to_remove
]
2131 for k
, v
in new_dependency_graph
.iteritems():
2132 if ifname_to_remove
in v
:
2133 v
.remove(ifname_to_remove
)
2134 del new_dependency_graph
[ifname_to_remove
]
2135 except Exception as e
:
2136 self
.logger
.warning(warning_no_config_regex
)
2137 self
.logger
.warning("while trying to fix this situation "
2138 "we ran into the following issues: %s" % str(e
))
2140 elif (lastifaceobjlist
[0].link_kind
and
2141 not newifaceobjlist
[0].link_kind
):
2142 self
.logger
.warn('%s: moved from being a %s to a'
2143 ' physical interface (non-logical interface).'
2144 'This interface will be downed.\n'
2145 ' If this was not intentional, please restore the'
2146 ' original interface definition and execute ifreload'
2147 % (newifaceobjlist
[objidx
].name
,
2148 ifaceLinkKind
.to_str(lastifaceobjlist
[0].link_kind
)))
2149 ifacedownlist
.append(newifaceobjlist
[objidx
].name
)
2150 if not down_changed
:
2152 if len(newifaceobjlist
) != len(lastifaceobjlist
):
2153 ifacedownlist
.append(ifname
)
2156 # If interface has changed between the current file
2157 # and the last installed append it to the down list
2158 # compare object list
2159 for objidx
in range(0, len(lastifaceobjlist
)):
2160 oldobj
= lastifaceobjlist
[objidx
]
2161 newobj
= newifaceobjlist
[objidx
]
2162 if not newobj
.compare(oldobj
):
2163 ifacedownlist
.append(ifname
)
2167 self
.logger
.info('reload: scheduling down on interfaces: %s'
2168 %str
(ifacedownlist
))
2169 # reinitialize dependency graph
2170 self
.dependency_graph
= OrderedDict({})
2172 # Generate dependency info for old config
2173 self
.flags
.CHECK_SHARED_DEPENDENTS
= False
2174 self
.populate_dependency_info(downops
, ifacedownlist
)
2175 self
.flags
.CHECK_SHARED_DEPENDENTS
= True
2178 # XXX: Hack to skip checking upperifaces during down.
2179 # the dependency list is not complete here
2180 # and we dont want to down the upperiface.
2181 # Hence during reload, set this to true.
2182 # This is being added to avoid a failure in
2183 # scheduler._check_upperifaces when we are dowing
2184 # a builtin bridge port
2185 self
.flags
.SCHED_SKIP_CHECK_UPPERIFACES
= True
2186 self
._sched
_ifaces
(ifacedownlist
, downops
,
2187 followdependents
=False,
2189 except Exception, e
:
2190 self
.logger
.error(str(e
))
2193 self
.flags
.SCHED_SKIP_CHECK_UPPERIFACES
= False
2194 self
._process
_delay
_admin
_state
_queue
('down')
2196 self
.logger
.info('no interfaces to down ..')
2198 # Now, run 'up' with new config dict
2199 # reset statemanager update flag to default
2200 if not new_ifaceobjdict
:
2201 self
.logger
.debug('no interfaces to up')
2205 ifupdownflags
.flags
.ALL
= True
2206 ifupdownflags
.flags
.WITH_DEPENDS
= True
2207 # and now, we are back to the current config in ifaceobjdict
2208 self
.ifaceobjdict
= new_ifaceobjdict
2209 self
.dependency_graph
= new_dependency_graph
2211 self
.logger
.info('reload: scheduling up on interfaces: %s'
2212 %str
(new_filtered_ifacenames
))
2213 ifupdownflags
.flags
.CACHE
= True
2215 ret
= self
._sched
_ifaces
(new_filtered_ifacenames
, upops
,
2216 followdependents
=True
2217 if ifupdownflags
.flags
.WITH_DEPENDS
2219 except Exception, e
:
2221 self
.logger
.error(str(e
))
2223 self
._process
_delay
_admin
_state
_queue
('up')
2224 if ifupdownflags
.flags
.DRYRUN
:
2228 if not iface_read_ret
or not ret
:
2231 def reload(self
, *args
, **kargs
):
2232 """ reload interface config """
2233 self
.logger
.debug('reloading interface config ..')
2234 if kargs
.get('currentlyup', False):
2235 self
._reload
_currentlyup
(*args
, **kargs
)
2237 self
._reload
_default
(*args
, **kargs
)
2239 def _any_iface_errors(self
, ifacenames
):
2240 for i
in ifacenames
:
2241 ifaceobjs
= self
.get_ifaceobjs(i
)
2242 if not ifaceobjs
: continue
2243 for ifaceobj
in ifaceobjs
:
2244 if (ifaceobj
.status
== ifaceStatus
.NOTFOUND
or
2245 ifaceobj
.status
== ifaceStatus
.ERROR
):
2249 def _pretty_print_ordered_dict(self
, prefix
, argdict
):
2250 outbuf
= prefix
+ ' {\n'
2251 for k
, vlist
in argdict
.items():
2252 outbuf
+= '\t%s : %s\n' %(k
, str(vlist
))
2253 self
.logger
.debug(outbuf
+ '}')
2255 def print_dependency(self
, ifacenames
, format
):
2256 """ prints iface dependency information """
2259 ifacenames
= self
.ifaceobjdict
.keys()
2260 if format
== 'list':
2261 for k
,v
in self
.dependency_graph
.items():
2262 print '%s : %s' %(k
, str(v
))
2263 elif format
== 'dot':
2265 map(lambda i
: indegrees
.update({i
:
2266 self
.get_iface_refcnt(i
)}),
2267 self
.dependency_graph
.keys())
2268 graph
.generate_dots(self
.dependency_graph
, indegrees
)
2270 def print_ifaceobjs_list(self
, ifacenames
):
2271 for i
in ifacenames
:
2274 def print_ifaceobjs_raw(self
, ifacenames
):
2275 """ prints raw lines for ifaces from config file """
2277 for i
in ifacenames
:
2278 for ifaceobj
in self
.get_ifaceobjs(i
):
2279 if self
.is_ifaceobj_builtin(ifaceobj
):
2281 ifaceobj
.dump_raw(self
.logger
)
2282 if (ifupdownflags
.flags
.WITH_DEPENDS
and
2283 not ifupdownflags
.flags
.ALL
):
2284 dlist
= ifaceobj
.lowerifaces
2285 if not dlist
: continue
2286 self
.print_ifaceobjs_raw(dlist
)
2288 def _get_ifaceobjs_pretty(self
, ifacenames
, ifaceobjs
, running
=False):
2289 """ returns iface obj list """
2291 for i
in ifacenames
:
2292 for ifaceobj
in self
.get_ifaceobjs(i
):
2293 if ((not running
and self
.is_ifaceobj_noconfig(ifaceobj
)) or
2294 (running
and not ifaceobj
.is_config_present() and
2295 not self
.is_iface_builtin_byname(i
) and
2296 not ifaceobj
.upperifaces
)):
2298 ifaceobjs
.append(ifaceobj
)
2299 if (ifupdownflags
.flags
.WITH_DEPENDS
and
2300 not ifupdownflags
.flags
.ALL
):
2301 dlist
= ifaceobj
.lowerifaces
2302 if not dlist
: continue
2303 self
._get
_ifaceobjs
_pretty
(dlist
, ifaceobjs
, running
)
2305 def print_ifaceobjs_pretty(self
, ifacenames
, format
='native'):
2306 """ pretty prints iface in format given by keyword arg format """
2309 self
._get
_ifaceobjs
_pretty
(ifacenames
, ifaceobjs
)
2310 if not ifaceobjs
: return
2311 if format
== 'json':
2312 print json
.dumps(ifaceobjs
, cls
=ifaceJsonEncoder
,
2313 indent
=4, separators
=(',', ': '))
2315 expand
= int(self
.config
.get('ifquery_ifacename_expand_range', '0'))
2317 if not expand
and (i
.flags
& iface
.IFACERANGE_ENTRY
):
2318 # print only the first one
2319 if i
.flags
& iface
.IFACERANGE_START
:
2320 i
.dump_pretty(use_realname
=True)
2324 def _get_ifaceobjscurr_pretty(self
, ifacenames
, ifaceobjs
):
2326 for i
in ifacenames
:
2327 ifaceobjscurr
= self
.get_ifaceobjcurr(i
)
2328 if not ifaceobjscurr
: continue
2329 for ifaceobj
in ifaceobjscurr
:
2330 if (ifaceobj
.status
== ifaceStatus
.NOTFOUND
or
2331 ifaceobj
.status
== ifaceStatus
.ERROR
):
2333 if self
.is_ifaceobj_noconfig(ifaceobj
):
2335 ifaceobjs
.append(ifaceobj
)
2336 if (ifupdownflags
.flags
.WITH_DEPENDS
and
2337 not ifupdownflags
.flags
.ALL
):
2338 dlist
= ifaceobj
.lowerifaces
2339 if not dlist
: continue
2340 dret
= self
._get
_ifaceobjscurr
_pretty
(dlist
, ifaceobjs
)
2344 def print_ifaceobjscurr_pretty(self
, ifacenames
, format
='native'):
2345 """ pretty prints current running state of interfaces with status.
2347 returns 1 if any of the interface has an error,
2352 ret
= self
._get
_ifaceobjscurr
_pretty
(ifacenames
, ifaceobjs
)
2353 if not ifaceobjs
: return
2355 # override ifaceStatusUserStrs
2356 ifaceStatusUserStrs
.SUCCESS
= self
.config
.get('ifquery_check_success_str', _success_sym
)
2357 ifaceStatusUserStrs
.ERROR
= self
.config
.get('ifquery_check_error_str', _error_sym
)
2358 ifaceStatusUserStrs
.UNKNOWN
= self
.config
.get('ifquery_check_unknown_str', '')
2359 if format
== 'json':
2360 print json
.dumps(ifaceobjs
, cls
=ifaceJsonEncoderWithStatus
,
2361 indent
=2, separators
=(',', ': '))
2363 map(lambda i
: i
.dump_pretty(with_status
=True), ifaceobjs
)
2366 def print_ifaceobjsrunning_pretty(self
, ifacenames
, format
='native'):
2367 """ pretty prints iface running state """
2370 self
._get
_ifaceobjs
_pretty
(ifacenames
, ifaceobjs
, running
=True)
2371 if not ifaceobjs
: return
2372 if format
== 'json':
2373 print json
.dumps(ifaceobjs
, cls
=ifaceJsonEncoder
, indent
=2,
2374 separators
=(',', ': '))
2376 map(lambda i
: i
.dump_pretty(), ifaceobjs
)
2379 print 'ifupdown main object dump'
2380 print self
.pp
.pprint(self
.modules
)
2381 print self
.pp
.pprint(self
.ifaceobjdict
)
2383 def _dump_ifaceobjs(self
, ifacenames
):
2384 for i
in ifacenames
:
2385 ifaceobjs
= self
.get_ifaceobjs(i
)