3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
17 from collections
import OrderedDict
20 import ifupdown2
.lib
.nlcache
as nlcache
22 import ifupdown2
.ifupdownaddons
.mstpctlutil
24 import ifupdown2
.nlmanager
.ipnetwork
as ipnetwork
26 import ifupdown2
.ifupdown
.policymanager
27 import ifupdown2
.ifupdown
.statemanager
as statemanager
28 import ifupdown2
.ifupdown
.ifupdownflags
as ifupdownflags
29 import ifupdown2
.ifupdown
.ifupdownconfig
as ifupdownConfig
31 from ifupdown2
.ifupdown
.graph
import *
32 from ifupdown2
.ifupdown
.iface
import *
33 from ifupdown2
.ifupdown
.scheduler
import *
34 from ifupdown2
.ifupdown
.exceptions
import *
35 from ifupdown2
.ifupdown
.networkinterfaces
import *
36 from ifupdown2
.ifupdown
.config
import ADDON_MODULES_DIR
, ADDONS_CONF_PATH
, IFUPDOWN2_ADDON_DROPIN_FOLDER
37 except (ImportError, ModuleNotFoundError
):
38 import lib
.nlcache
as nlcache
40 import ifupdownaddons
.mstpctlutil
42 import nlmanager
.ipnetwork
as ipnetwork
44 import ifupdown
.ifupdownflags
45 import ifupdown
.policymanager
46 import ifupdown
.statemanager
as statemanager
47 import ifupdown
.ifupdownflags
as ifupdownflags
48 import ifupdown
.ifupdownconfig
as ifupdownConfig
50 from ifupdown
.graph
import *
51 from ifupdown
.iface
import *
52 from ifupdown
.scheduler
import *
53 from ifupdown
.exceptions
import *
54 from ifupdown
.networkinterfaces
import *
55 from ifupdown
.config
import ADDON_MODULES_DIR
, ADDONS_CONF_PATH
, IFUPDOWN2_ADDON_DROPIN_FOLDER
59 .. module:: ifupdownmain
60 :synopsis: main module for ifupdown package
62 .. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
68 _success_sym
= '(%s)' %_tickmark
69 _error_sym
= '(%s)' %_crossmark
71 class ifupdownMainFlags():
72 COMPAT_EXEC_SCRIPTS
= False
73 STATEMANAGER_ENABLE
= True
74 STATEMANAGER_UPDATE
= True
76 DELETE_DEPENDENT_IFACES_WITH_NOCONFIG
= False
77 SCHED_SKIP_CHECK_UPPERIFACES
= False
78 CHECK_SHARED_DEPENDENTS
= True
80 class ifacePrivFlags():
81 # priv flags to mark iface objects
85 def __init__(self
, builtin
=False, noconfig
=False):
86 self
.BUILTIN
= builtin
87 self
.NOCONFIG
= noconfig
90 """ ifupdown2 main class """
92 scripts_dir
= '/etc/network'
93 addon_modules_dir
= ADDON_MODULES_DIR
94 addon_modules_configfile
= ADDONS_CONF_PATH
96 # Handlers for ops that ifupdown2 owns
97 def run_up(self
, ifaceobj
):
98 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs).
99 # there is no real interface behind it
100 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
102 if ((ifaceobj
.link_kind
& ifaceLinkKind
.VRF
) or
103 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
)):
104 self
._keep
_link
_down
(ifaceobj
)
106 if self
._delay
_admin
_state
:
107 self
._delay
_admin
_state
_iface
_queue
.append(ifaceobj
.name
)
109 # If this object is a link slave, ie its link is controlled
110 # by its link master interface, then dont set the link state.
111 # But do allow user to change state of the link if the interface
112 # is already with its link master (hence the master check).
113 if ifaceobj
.link_type
== ifaceLinkType
.LINK_SLAVE
:
115 if not self
.link_exists(ifaceobj
.name
):
117 if self
._keep
_link
_down
(ifaceobj
):
120 self
.netlink
.link_up(ifaceobj
.name
)
122 if ifaceobj
.addr_method
== 'manual':
127 def _keep_link_down(self
, ifaceobj
):
128 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.KEEP_LINK_DOWN
:
129 # user has asked to explicitly keep the link down,
130 # so, force link down
131 self
.logger
.info('%s: keeping link down due to user config' %ifaceobj
.name
)
132 self
.netlink
.link_down(ifaceobj
.name
)
136 def run_down(self
, ifaceobj
):
137 if ((ifaceobj
.link_kind
& ifaceLinkKind
.VRF
) or
138 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
)):
140 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs)
141 # there is no real interface behind it
142 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
144 if self
._delay
_admin
_state
:
145 self
._delay
_admin
_state
_iface
_queue
.append(ifaceobj
.name
)
147 # If this object is a link slave, ie its link is controlled
148 # by its link master interface, then dont set the link state.
149 # But do allow user to change state of the link if the interface
150 # is already with its link master (hence the master check).
151 if ifaceobj
.link_type
== ifaceLinkType
.LINK_SLAVE
:
153 if not self
.link_exists(ifaceobj
.name
):
156 if not ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.LOOPBACK
:
157 # set intf down (except loopback)
158 self
.netlink
.link_down(ifaceobj
.name
)
160 self
.logger
.info("%s: ifupdown2 cannot bring loopback interface down" % ifaceobj
.name
)
162 if ifaceobj
.addr_method
== 'manual':
167 # ifupdown object interface operation handlers
168 ops_handlers
= OrderedDict([('up', run_up
),
171 def run_sched_ifaceobj_posthook(self
, ifaceobj
, op
):
172 if (ifaceobj
.priv_flags
and (ifaceobj
.priv_flags
.BUILTIN
or
173 ifaceobj
.priv_flags
.NOCONFIG
)):
175 if self
.flags
.STATEMANAGER_UPDATE
:
176 self
.statemanager
.ifaceobj_sync(ifaceobj
, op
)
178 # ifupdown object interface scheduler pre and posthooks
179 sched_hooks
= {'posthook' : run_sched_ifaceobj_posthook
}
181 def reset_ifupdown2(self
):
182 self
.modules
= OrderedDict({})
183 self
.module_attrs
= {}
185 ifaceScheduler
.reset()
187 ifupdown2
.ifupdown
.statemanager
.reset()
188 ifupdown2
.ifupdown
.policymanager
.reset()
189 ifupdown2
.ifupdown
.ifupdownflags
.reset()
190 ifupdownConfig
.reset()
191 ifupdown2
.ifupdownaddons
.mstpctlutil
.mstpctlutil
.reset()
194 ifupdown
.statemanager
.reset()
195 ifupdown
.policymanager
.reset()
196 ifupdown
.ifupdownflags
.reset()
197 ifupdownConfig
.reset()
198 ifupdownaddons
.mstpctlutil
.mstpctlutil
.reset()
202 def ignore_error(self
, errmsg
):
203 if (ifupdownflags
.flags
.FORCE
== True or re
.search(r
'exists', errmsg
,
204 re
.IGNORECASE | re
.MULTILINE
) is not None):
208 def log_warn(self
, str):
209 if self
.ignore_error(str) == False:
210 if self
.logger
.getEffectiveLevel() == logging
.DEBUG
:
211 traceback
.print_stack()
212 traceback
.print_exc()
213 self
.logger
.warning(str)
216 def log_error(self
, str):
217 if self
.ignore_error(str) == False:
222 def link_exists(self
, ifacename
):
223 return os
.path
.exists('/sys/class/net/%s' %ifacename
)
225 def __init__(self
, config
={}, args
=None,
226 daemon
=False, force
=False, dryrun
=False, nowait
=False,
227 perfmode
=False, withdepends
=False, njobs
=1,
228 cache
=False, addons_enable
=True, statemanager_enable
=True,
229 interfacesfile
='/etc/network/interfaces',
230 interfacesfileiobuf
=None,
231 interfacesfileformat
='native',
233 """This member function initializes the ifupdownmain object.
236 config (dict): config dict from /etc/network/ifupdown2/ifupdown2.conf
237 force (bool): force interface configuration
238 dryrun (bool): dryrun interface configuration
239 withdepends (bool): apply interface configuration on all depends
240 interfacesfile (str): interfaces file. default is /etc/network/interfaces
241 interfacesfileformat (str): default is 'native'. Other choices are 'json'
244 AttributeError, KeyError """
246 modulename
= self
.__class
__.__name
__
247 self
.logger
= logging
.getLogger('ifupdown.' + modulename
)
250 self
.reset_ifupdown2()
252 # init nlcache with appropriate log level
253 nlcache
.NetlinkListenerWithCache
.init(logging
.DEBUG
if args
.nldebug
else logging
.WARNING
)
255 # start netlink listener and cache link/addr/netconf dumps
256 nlcache
.NetlinkListenerWithCache
.get_instance().start()
258 # save reference to nlcache
259 self
.netlink
= nlcache
.NetlinkListenerWithCache
.get_instance()
260 self
.netlink
.reset_errorq()
262 # iface dictionary in the below format:
263 # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
265 # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
267 # Each ifaceobject corresponds to a configuration block for
269 # The value in the dictionary is a list because the network
270 # interface configuration file supports more than one iface section
271 # in the interfaces file
272 self
.ifaceobjdict
= OrderedDict()
274 # iface dictionary representing the curr running state of an iface
275 # in the below format:
276 # {'<ifacename>' : <ifaceobject>}
277 self
.ifaceobjcurrdict
= OrderedDict()
279 # Dictionary representing operation and modules
280 # for every operation
281 self
.module_ops
= OrderedDict([('pre-up', []),
284 ('query-checkcurr', []),
285 ('query-running', []),
286 ('query-dependency', []),
293 # For old style /etc/network/ bash scripts
294 self
.script_ops
= OrderedDict([('pre-up', []),
302 self
.logger
= logging
.getLogger('ifupdown')
303 ifupdownflags
.flags
.FORCE
= force
304 ifupdownflags
.flags
.DRYRUN
= dryrun
305 ifupdownflags
.flags
.WITHDEFAULTS
= withdefaults
306 ifupdownflags
.flags
.NOWAIT
= nowait
307 ifupdownflags
.flags
.PERFMODE
= perfmode
308 ifupdownflags
.flags
.CACHE
= cache
309 ifupdownflags
.flags
.WITH_DEPENDS
= withdepends
311 # Can be used to provide hints for caching
312 ifupdownflags
.flags
.CACHE_FLAGS
= 0x0
314 self
.flags
= ifupdownMainFlags()
316 self
.flags
.STATEMANAGER_ENABLE
= statemanager_enable
317 self
.interfacesfile
= interfacesfile
318 self
.interfacesfileiobuf
= interfacesfileiobuf
319 self
.interfacesfileformat
= interfacesfileformat
321 self
.logger
.debug(self
.config
)
322 self
.blacklisted_ifaces_present
= False
324 self
.type = ifaceType
.UNKNOWN
326 self
.flags
.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG
= False
327 self
.flags
.ADDONS_ENABLE
= addons_enable
329 self
.ifaces
= OrderedDict()
331 self
.pp
= pprint
.PrettyPrinter(indent
=4)
332 self
.modules
= OrderedDict({})
333 self
.module_attrs
= {}
334 self
.overridden_ifupdown_scripts
= []
336 if self
.config
.get('addon_python_modules_support', '1') == '1':
337 self
.load_addon_modules(self
.addon_modules_dir
)
338 if self
.config
.get('addon_scripts_support', '0') == '1':
339 self
.load_scripts(self
.scripts_dir
)
340 self
.dependency_graph
= OrderedDict({})
342 self
._cache
_no
_repeats
= {}
344 # initialize global config object with config passed by the user
345 # This makes config available to addon modules
346 ifupdownConfig
.config
= self
.config
347 statemanager
.statemanager_api
.init()
349 if self
.flags
.STATEMANAGER_ENABLE
:
350 self
.statemanager
= statemanager
.statemanager_api
352 self
.statemanager
.read_saved_state()
353 except Exception as e
:
354 # if read_saved_state fails, state file might be corrupt.
355 # Ignore old state and continue
356 self
.logger
.warning('error reading state (%s)' %str
(e
))
358 traceback
.print_exc()
360 self
.flags
.STATEMANAGER_UPDATE
= False
361 self
._delay
_admin
_state
= True if self
.config
.get(
362 'delay_admin_state_change', '0') == '1' else False
363 self
._delay
_admin
_state
_iface
_queue
= []
364 if self
._delay
_admin
_state
:
365 self
.logger
.info('\'delay_admin_state_change\' is set. admin ' +
366 'state changes will be delayed till the end.')
368 self
._link
_master
_slave
= True if self
.config
.get(
369 'link_master_slave', '0') == '1' else False
370 if self
._link
_master
_slave
:
371 self
.logger
.info('\'link_master_slave\' is set. slave admin ' +
372 'state changes will be delayed till the ' +
373 'masters admin state change.')
375 # squash iface objects for same interface both internal and
376 # external representation. It is off by default.
377 self
._ifaceobj
_squash
= True if self
.config
.get(
378 'ifaceobj_squash', '0') == '1' else False
380 # squash iface objects for same interface internal
381 # representation only. External representation as seen by ifquery
382 # will continue to see multiple iface stanzas if it was specified
383 # that way by the user. It is on by default.
384 self
._ifaceobj
_squash
_internal
= True if self
.config
.get(
385 'ifaceobj_squash_internal', '1') == '1' else False
387 self
.mgmt_iface_default_prefix
= self
._get
_mgmt
_iface
_default
_prefix
()
388 self
.logger
.info('using mgmt iface default prefix %s' %self
.mgmt_iface_default_prefix
)
390 self
.validate_keywords
= {
391 '<mac>': self
._keyword
_mac
,
392 '<text>': self
._keyword
_text
,
393 '<ipv4>': self
._keyword
_ipv
4,
394 '<ipv6>': self
._keyword
_ipv
6,
395 '<ip>': self
._keyword
_ip
,
396 '<number>': self
._keyword
_number
,
397 '<interface>': self
._keyword
_interface
,
398 '<ipv4-vrf-text>': self
._keyword
_ipv
4_vrf
_text
,
399 '<number-ipv4-list>': self
._keyword
_number
_ipv
4_list
,
400 '<interface-list>': self
._keyword
_interface
_list
,
401 '<ipv4/prefixlen>': self
._keyword
_ipv
4_prefixlen
,
402 '<ipv6/prefixlen>': self
._keyword
_ipv
6_prefixlen
,
403 '<ip/prefixlen>': self
._keyword
_ip
_prefixlen
,
404 '<number-range-list>': self
._keyword
_number
_range
_list
,
405 '<number-comma-range-list>': self
._keyword
_number
_comma
_range
_list
,
406 '<interface-range-list>': self
._keyword
_interface
_range
_list
,
407 '<interface-range-list-multiple-of-16>': self
._keyword
_interface
_range
_list
_multiple
_of
_16,
408 '<mac-ip/prefixlen-list>': self
._keyword
_mac
_ip
_prefixlen
_list
,
409 '<number-interface-list>': self
._keyword
_number
_interface
_list
,
410 '<interface-yes-no-list>': self
._keyword
_interface
_yes
_no
_list
,
411 '<interface-on-off-list>': self
._keyword
_interface
_on
_off
_list
,
412 '<interface-yes-no-0-1-list>': self
._keyword
_interface
_yes
_no
_0_1_list
,
413 '<interface-disabled-automatic-enabled>': self
._keyword
_interface
_disabled
_automatic
_enabled
_list
,
414 '<interface-yes-no-auto-list>': self
._keyword
_interface
_yes
_no
_auto
_list
,
415 '<interface-l2protocol-tunnel-list>': self
._keyword
_interface
_l2protocol
_tunnel
_list
418 def _get_mgmt_iface_default_prefix(self
):
419 mgmt_iface_default_prefix
= None
421 mgmt_iface_default_prefix
= ifupdown2
.ifupdown
.policymanager
.policymanager_api
.get_module_globals(
422 module_name
='main', attr
='mgmt_intf_prefix'
426 mgmt_iface_default_prefix
= ifupdown
.policymanager
.policymanager_api
.get_module_globals(
427 module_name
='main', attr
='mgmt_intf_prefix'
431 if not mgmt_iface_default_prefix
:
432 mgmt_iface_default_prefix
= "eth"
434 return mgmt_iface_default_prefix
436 def link_master_slave_ignore_error(self
, errorstr
):
437 # If link master slave flag is set,
438 # there may be cases where the lowerdev may not be
439 # up resulting in 'Network is down' error
440 # This can happen if the lowerdev is a LINK_SLAVE
441 # of another interface which is not up yet
442 # example of such a case:
443 # bringing up a vlan on a bond interface and the bond
444 # is a LINK_SLAVE of a bridge (in other words the bond is
445 # part of a bridge) which is not up yet
446 if self
._link
_master
_slave
:
447 if 'Network is down' in errorstr
:
451 def get_ifaceobjs(self
, ifacename
):
452 return self
.ifaceobjdict
.get(ifacename
)
454 def get_ifaceobjs_saved(self
, ifacename
):
455 """ Return ifaceobjects from statemanager """
456 if self
.flags
.STATEMANAGER_ENABLE
:
457 return self
.statemanager
.get_ifaceobjs(ifacename
)
461 def get_ifaceobj_first(self
, ifacename
):
462 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
467 def get_ifacenames(self
):
468 return list(self
.ifaceobjdict
.keys())
470 def get_iface_obj_last(self
, ifacename
):
471 return self
.ifaceobjdict
.get(ifacename
)[-1]
474 def must_follow_upperifaces(self
, ifacename
):
476 # XXX: This bleeds the knowledge of iface
477 # types in the infrastructure module.
478 # Cant think of a better fix at the moment.
479 # In future maybe the module can set a flag
480 # to indicate if we should follow upperifaces
482 ifaceobj
= self
.get_ifaceobj_first(ifacename
)
483 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
487 def create_n_save_ifaceobj(self
, ifacename
, priv_flags
=None,
489 """ creates a iface object and adds it to the iface dictionary """
491 ifaceobj
.name
= ifacename
492 ifaceobj
.priv_flags
= priv_flags
494 if not self
._link
_master
_slave
:
495 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
497 ifaceobj
.inc_refcnt()
498 self
.ifaceobjdict
[ifacename
] = [ifaceobj
]
501 def create_n_save_ifaceobjcurr(self
, ifaceobj
):
502 """ creates a copy of iface object and adds it to the iface
503 dict containing current iface objects
505 ifaceobjcurr
= iface()
506 ifaceobjcurr
.name
= ifaceobj
.name
507 ifaceobjcurr
.type = ifaceobj
.type
508 ifaceobjcurr
.lowerifaces
= ifaceobj
.lowerifaces
509 ifaceobjcurr
.priv_flags
= copy
.deepcopy(ifaceobj
.priv_flags
)
510 ifaceobjcurr
.auto
= ifaceobj
.auto
511 self
.ifaceobjcurrdict
.setdefault(ifaceobj
.name
,
512 []).append(ifaceobjcurr
)
515 def get_ifaceobjcurr(self
, ifacename
, idx
=0):
516 ifaceobjlist
= self
.ifaceobjcurrdict
.get(ifacename
)
522 return ifaceobjlist
[idx
]
524 def get_iface_refcnt(self
, ifacename
):
525 """ Return iface ref count """
527 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
535 def is_iface_builtin_byname(self
, ifacename
):
536 """ Returns true if iface name is a builtin interface.
538 A builtin interface is an interface which ifupdown understands.
539 The following are currently considered builtin ifaces:
540 - vlan interfaces in the format <ifacename>.<vlanid>
542 return '.' in ifacename
544 def is_ifaceobj_builtin(self
, ifaceobj
):
545 """ Returns true if iface name is a builtin interface.
547 A builtin interface is an interface which ifupdown understands.
548 The following are currently considered builtin ifaces:
549 - vlan interfaces in the format <ifacename>.<vlanid>
551 if (ifaceobj
.priv_flags
and ifaceobj
.priv_flags
.BUILTIN
):
555 def is_ifaceobj_noconfig(self
, ifaceobj
):
556 """ Returns true if iface object did not have a user defined config.
558 These interfaces appear only when they are dependents of interfaces
559 which have user defined config
561 return (ifaceobj
.priv_flags
and ifaceobj
.priv_flags
.NOCONFIG
)
563 def is_iface_noconfig(self
, ifacename
):
564 """ Returns true if iface has no config """
566 ifaceobj
= self
.get_ifaceobj_first(ifacename
)
567 if not ifaceobj
: return True
568 return self
.is_ifaceobj_noconfig(ifaceobj
)
570 def check_shared_dependents(self
, ifaceobj
, dlist
):
571 """ ABSOLETE: Check if dlist intersects with any other
572 interface with slave dependents.
573 example: bond and bridges.
574 This function logs such errors """
575 setdlist
= set(dlist
)
576 for ifacename
, ifacedlist
in list(self
.dependency_graph
.items()):
579 check_depends
= False
580 iobjs
= self
.get_ifaceobjs(ifacename
)
584 if (i
.dependency_type
== ifaceDependencyType
.MASTER_SLAVE
):
587 common
= set(ifacedlist
).intersection(setdlist
)
589 self
.logger
.error('misconfig..?. iface %s and %s '
590 %(ifaceobj
.name
, ifacename
) +
591 'seem to share dependents/ports %s' %str
(list(common
)))
593 def _set_iface_role(self
, ifaceobj
, role
, upperifaceobj
):
594 if (self
.flags
.CHECK_SHARED_DEPENDENTS
and
595 (ifaceobj
.role
& ifaceRole
.SLAVE
) and
596 (role
== ifaceRole
.SLAVE
) and (upperifaceobj
.role
& ifaceRole
.MASTER
)):
597 self
.logger
.error("misconfig..? %s %s is enslaved to multiple interfaces %s"
599 ifaceLinkPrivFlags
.get_str(ifaceobj
.link_privflags
), str(ifaceobj
.upperifaces
)))
600 ifaceobj
.set_status(ifaceStatus
.ERROR
)
604 def _set_iface_role_n_kind(self
, ifaceobj
, upperifaceobj
):
605 if (upperifaceobj
.link_kind
& ifaceLinkKind
.BOND
):
606 self
._set
_iface
_role
(ifaceobj
, ifaceRole
.SLAVE
, upperifaceobj
)
607 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BOND_SLAVE
609 if (upperifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
):
610 self
._set
_iface
_role
(ifaceobj
, ifaceRole
.SLAVE
, upperifaceobj
)
611 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_PORT
613 if (ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
) \
614 and (upperifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
):
615 upperifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.BRIDGE_VXLAN
617 # vrf masters get processed after slaves, which means
618 # check both link_kind vrf and vrf slave
619 if ((upperifaceobj
.link_kind
& ifaceLinkKind
.VRF
) or
620 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
)):
621 self
._set
_iface
_role
(ifaceobj
, ifaceRole
.SLAVE
, upperifaceobj
)
622 ifaceobj
.link_privflags |
= ifaceLinkPrivFlags
.VRF_SLAVE
623 if self
._link
_master
_slave
:
624 if upperifaceobj
.link_type
== ifaceLinkType
.LINK_MASTER
:
625 ifaceobj
.link_type
= ifaceLinkType
.LINK_SLAVE
627 upperifaceobj
.link_type
= ifaceLinkType
.LINK_NA
628 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
630 def dump_iface_dependency_info(self
):
631 """ debug funtion to print raw dependency
632 info - lower and upper devices"""
634 for ifacename
, ifaceobjs
in self
.ifaceobjdict
.items():
636 self
.logger
.info("%s: refcnt: %d, lower: %s, upper: %s" %(ifacename
,
637 self
.get_iface_refcnt(ifacename
),
638 str(iobj
.lowerifaces
) if iobj
.lowerifaces
else [],
639 str(iobj
.upperifaces
) if iobj
.upperifaces
else []))
642 def preprocess_dependency_list(self
, upperifaceobj
, dlist
, ops
):
643 """ We go through the dependency list and
644 delete or add interfaces from the interfaces dict by
645 applying the following rules:
646 if flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
647 we only consider devices whose configuration was
648 specified in the network interfaces file. We delete
649 any interface whose config was not specified except
650 for vlan devices. vlan devices get special treatment.
651 Even if they are not present they are created and added
653 elif flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
654 we create objects for all dependent devices that are not
655 present in the ifacesdict
660 dilist
= self
.get_ifaceobjs(d
)
663 if self
.is_iface_builtin_byname(d
):
664 ni
= self
.create_n_save_ifaceobj(d
,
665 ifacePrivFlags(True, True), True)
666 elif not self
.flags
.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG
:
667 ni
= self
.create_n_save_ifaceobj(d
,
668 ifacePrivFlags(False, True), True)
672 ni
.add_to_upperifaces(upperifaceobj
.name
)
673 self
._set
_iface
_role
_n
_kind
(ni
, upperifaceobj
)
677 di
.add_to_upperifaces(upperifaceobj
.name
)
678 self
._set
_iface
_role
_n
_kind
(di
, upperifaceobj
)
682 def preprocess_upperiface(self
, lowerifaceobj
, ulist
, ops
):
684 if (lowerifaceobj
.upperifaces
and
685 u
in lowerifaceobj
.upperifaces
):
687 lowerifaceobj
.add_to_upperifaces(u
)
688 uifacelist
= self
.get_ifaceobjs(u
)
690 for ui
in uifacelist
:
691 lowerifaceobj
.inc_refcnt()
692 self
._set
_iface
_role
_n
_kind
(lowerifaceobj
, ui
)
693 ui
.add_to_lowerifaces(lowerifaceobj
.name
)
695 def query_lowerifaces(self
, ifaceobj
, ops
, ifacenames
, type=None):
696 """ Gets iface dependents by calling into respective modules """
699 # Get dependents for interface by querying respective modules
700 for module
in list(self
.modules
.values()):
702 if ops
[0] == 'query-running':
703 if (not hasattr(module
,
704 'get_dependent_ifacenames_running')):
706 dlist
= module
.get_dependent_ifacenames_running(ifaceobj
)
708 if (not hasattr(module
, 'get_dependent_ifacenames')):
710 dlist
= module
.get_dependent_ifacenames(ifaceobj
,
712 except Exception as e
:
713 self
.logger
.warning('%s: error getting dependent interfaces (%s)'
714 %(ifaceobj
.name
, str(e
)))
717 if dlist
: ret_dlist
.extend(dlist
)
718 return list(set(ret_dlist
))
720 def query_upperifaces(self
, ifaceobj
, ops
, ifacenames
, type=None):
721 """ Gets iface upperifaces by calling into respective modules """
724 # Get upperifaces for interface by querying respective modules
725 for module
in list(self
.modules
.values()):
727 if ops
[0] == 'query-running':
728 if (not hasattr(module
,
729 'get_upper_ifacenames_running')):
731 ulist
= module
.get_upper_ifacenames_running(ifaceobj
)
733 if (not hasattr(module
, 'get_upper_ifacenames')):
735 ulist
= module
.get_upper_ifacenames(ifaceobj
, ifacenames
)
736 except Exception as e
:
737 self
.logger
.warning('%s: error getting upper interfaces (%s)'
738 %(ifaceobj
.name
, str(e
)))
741 if ulist
: ret_ulist
.extend(ulist
)
742 return list(set(ret_ulist
))
744 def _remove_circular_veth_dependencies(self
, ifaceobj
, dlist
):
745 # if ifaceobj isn't a veth link, ignore it.
746 if ifaceobj
.get_attr_value_first('link-type') != "veth":
750 difaceobj
= self
.get_ifaceobj_first(diface
)
751 # If the dependent iface isn't a veth link - which shouldn't
752 # happen - ignore it to be save.
753 if not difaceobj
or (difaceobj
and difaceobj
.get_attr_value_first('link-type') != "veth"):
756 # If the peer has a desired peer name set and this is us,
757 # see if the peer has a dependency to us too and remove our
758 # redundant dependency to the peer.
759 diface_peer_name
= difaceobj
.get_attr_value_first('veth-peer-name')
760 if diface_peer_name
and diface_peer_name
== ifaceobj
.name
:
761 peer_dlist
= difaceobj
.lowerifaces
763 # Not list of dependent interface on the peer.
766 # We aleady are in the peers dlist, don't add dependcy from us to peer
767 if ifaceobj
.name
in peer_dlist
:
768 dlist
.remove(difaceobj
.name
)
770 def populate_dependency_info(self
, ops
, ifacenames
=None):
771 """ recursive function to generate iface dependency info """
774 ifacenames
= list(self
.ifaceobjdict
.keys())
776 iqueue
= deque(ifacenames
)
779 # Go through all modules and find dependent ifaces
782 ifaceobjs
= self
.get_ifaceobjs(i
)
785 dependents_processed
= False
787 # Store all dependency info in the first ifaceobj
788 # but get dependency info from all ifaceobjs
789 ifaceobj
= ifaceobjs
[0]
790 for iobj
in ifaceobjs
:
791 ulist
= self
.query_upperifaces(iobj
, ops
, ifacenames
)
793 dependents_processed
= True
795 dlist
= self
.query_lowerifaces(iobj
, ops
, ifacenames
)
799 self
.preprocess_upperiface(ifaceobj
, ulist
, ops
)
800 if dependents_processed
:
803 self
._remove
_circular
_veth
_dependencies
(ifaceobj
, dlist
)
804 self
.preprocess_dependency_list(ifaceobj
,
806 ifaceobj
.lowerifaces
= dlist
807 [iqueue
.append(d
) for d
in dlist
]
808 #if not self.dependency_graph.get(i):
809 # self.dependency_graph[i] = dlist
811 for i
in list(self
.ifaceobjdict
.keys()):
812 iobj
= self
.get_ifaceobj_first(i
)
813 if (not iobj
.link_kind
and
814 not (iobj
.link_privflags
& ifaceLinkPrivFlags
.LOOPBACK
) and
816 iobj
.link_privflags |
= ifaceLinkPrivFlags
.LOOPBACK
817 if iobj
.name
.startswith(self
.mgmt_iface_default_prefix
):
818 self
.logger
.debug('%s: marking interface with mgmt flag' %iobj
.name
)
819 iobj
.link_privflags |
= ifaceLinkPrivFlags
.MGMT_INTF
821 self
.dependency_graph
[i
] = iobj
.lowerifaces
823 self
.dependency_graph
[i
] = []
825 if not self
.blacklisted_ifaces_present
:
828 # Walk through the dependency graph and remove blacklisted
829 # interfaces that were picked up as dependents
830 for i
in list(self
.dependency_graph
.keys()):
831 ifaceobj
= self
.get_ifaceobj_first(i
)
835 if ifaceobj
.blacklisted
and not ifaceobj
.upperifaces
:
836 # if blacklisted and was not picked up as a
837 # dependent of a upper interface, delete the
838 # interface from the dependency graph
839 dlist
= ifaceobj
.lowerifaces
842 difaceobjs
= self
.get_ifaceobjs(d
)
848 d
.upperifaces
.remove(i
)
850 self
.logger
.debug('error removing %s from %s upperifaces' %(i
, d
))
852 self
.logger
.debug("populate_dependency_info: deleting blacklisted interface %s" %i)
853 del self
.dependency_graph
[i
]
856 def _check_config_no_repeats(self
, ifaceobj
):
857 """ check if object has an attribute that is
858 restricted to a single object in the system.
859 if yes, warn and return """
860 for k
,v
in list(self
._cache
_no
_repeats
.items()):
861 iv
= ifaceobj
.config
.get(k
)
862 if iv
and iv
[0] == v
:
863 self
.logger
.error('ignoring interface %s. ' %ifaceobj
.name
+
864 'Only one object with attribute ' +
865 '\'%s %s\' allowed.' %(k
, v
))
867 for k
, v
in list(self
.config
.get('no_repeats', {}).items()):
868 iv
= ifaceobj
.config
.get(k
)
869 if iv
and iv
[0] == v
:
870 self
._cache
_no
_repeats
[k
] = v
873 def _save_iface_squash(self
, ifaceobj
):
874 """ squash ifaceobjects belonging to same iface
875 into a single object """
876 if self
._check
_config
_no
_repeats
(ifaceobj
):
878 ifaceobj
.priv_flags
= ifacePrivFlags()
879 if not self
._link
_master
_slave
:
880 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
881 currentifaceobjlist
= self
.ifaceobjdict
.get(ifaceobj
.name
)
882 if not currentifaceobjlist
:
883 self
.ifaceobjdict
[ifaceobj
.name
] = [ifaceobj
]
885 if ifaceobj
.compare(currentifaceobjlist
[0]):
886 self
.logger
.warning('duplicate interface %s found' %ifaceobj
.name
)
888 for obj
in self
.ifaceobjdict
[ifaceobj
.name
]:
889 if obj
.type == ifaceobj
.type:
892 self
.ifaceobjdict
[ifaceobj
.name
].append(ifaceobj
)
894 def _save_iface(self
, ifaceobj
):
895 if self
._check
_config
_no
_repeats
(ifaceobj
):
897 ifaceobj
.priv_flags
= ifacePrivFlags()
898 if not self
._link
_master
_slave
:
899 ifaceobj
.link_type
= ifaceLinkType
.LINK_NA
900 currentifaceobjlist
= self
.ifaceobjdict
.get(ifaceobj
.name
)
901 if not currentifaceobjlist
:
902 self
.ifaceobjdict
[ifaceobj
.name
]= [ifaceobj
]
903 if not self
._ifaceobj
_squash
:
904 ifaceobj
.flags |
= ifaceobj
.YOUNGEST_SIBLING
906 if ifaceobj
.compare(currentifaceobjlist
[0]):
907 self
.logger
.warning('duplicate interface %s found' %ifaceobj
.name
)
909 if currentifaceobjlist
[0].type == ifaceobj
.type:
910 currentifaceobjlist
[0].flags |
= ifaceobj
.HAS_SIBLINGS
911 ifaceobj
.flags |
= ifaceobj
.HAS_SIBLINGS
912 # clear the OLDEST_SIBLING from all the siblings
913 for iface
in self
.ifaceobjdict
[ifaceobj
.name
]:
914 iface
.flags
&= ~ifaceobj
.OLDEST_SIBLING
915 # current sibling is the oldest
916 ifaceobj
.flags |
= ifaceobj
.OLDEST_SIBLING
917 self
.ifaceobjdict
[ifaceobj
.name
].append(ifaceobj
)
919 def _keyword_text(self
, value
, validrange
=None):
920 return isinstance(value
, str) and len(value
) > 0
922 def _keyword_mac(self
, value
, validrange
=None):
923 if value
.strip().startswith('ether'):
924 value
= value
.strip()[6:]
925 return re
.match('[0-9a-f]{1,2}([-:])[0-9a-f]{1,2}(\\1[0-9a-f]{1,2}){4}$',
928 def _keyword_check_list(self
, _list
, obj
, limit
=None):
930 if limit
and limit
> 0:
931 for i
in range(0, limit
):
933 return len(_list
) == limit
938 except Exception as e
:
939 self
.logger
.debug('keyword: check list: %s' % str(e
))
942 def _keyword_ipv4(self
, value
, validrange
=None):
943 return self
._keyword
_check
_list
(value
.split(), ipnetwork
.IPv4Address
, limit
=1)
945 def _keyword_ipv4_prefixlen(self
, value
, validrange
=None):
946 return self
._keyword
_check
_list
(value
.split(), ipnetwork
.IPv4Network
, limit
=1)
948 def _keyword_ipv6(self
, value
, validrange
=None):
949 return self
._keyword
_check
_list
(value
.split(), ipnetwork
.IPv6Address
, limit
=1)
951 def _keyword_ipv6_prefixlen(self
, value
, validrange
=None):
952 return self
._keyword
_check
_list
(value
.split(), ipnetwork
.IPv6Network
, limit
=1)
954 def _keyword_ip(self
, value
, validrange
=None):
955 return self
._keyword
_check
_list
(value
.split(), ipnetwork
.IPAddress
, limit
=1)
957 def _keyword_ip_prefixlen(self
, value
, validrange
=None):
958 return self
._keyword
_check
_list
(value
.split(), ipnetwork
.IPNetwork
, limit
=1)
960 def _keyword_mac_ip_prefixlen_list(self
, value
, validrange
=None):
962 MAC address followed by optional list of ip addresses
963 <mac> [<ip> <ip> ...]
964 ex: address-virtual 00:11:22:33:44:01 11.0.1.1/24 11.0.1.2/24
968 if not self
._keyword
_mac
(res
[0]):
971 if not self
._keyword
_ip
_prefixlen
(ip
):
974 except Exception as e
:
975 self
.logger
.debug('keyword: mac ipaddr prefixlen: %s' % str(e
))
978 def _keyword_number_ipv4_list(self
, value
, validrange
=None):
980 <number>=<ipv4> [<number>=<ipv4> ...]
981 ex: bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1
984 elements
= value
.split(' ')
987 for elem
in elements
:
990 ipnetwork
.IPv4Address(v
[1])
992 except Exception as e
:
993 self
.logger
.debug('keyword: number ipv4: %s' % str(e
))
996 def _keyword_interface(self
, ifacename
, validrange
=None):
997 return self
.get_ifaceobjs(ifacename
)
999 def _keyword_ipv4_vrf_text(self
, value
, validrange
=None):
1002 ex: clagd-backup-ip 10.10.10.42 vrf blue
1004 values
= value
.split()
1007 if size
> 3 or size
< 1:
1010 ipnetwork
.IPv4Address(values
[0])
1012 if values
[1] != 'vrf':
1015 if not self
._keyword
_text
(values
[2]):
1018 except Exception as e
:
1019 self
.logger
.debug('keyword: ipv4 vrf text: %s' % str(e
))
1022 def _keyword_interface_list_with_value(self
, value
, validvals
):
1023 values
= value
.split()
1025 if len(values
) == 1:
1026 if values
[0] in validvals
:
1029 iface_value
= v
.split('=')
1030 size
= len(iface_value
)
1032 if iface_value
[0] == 'glob' or iface_value
[0] == 'regex':
1035 if not iface_value
[1] in validvals
:
1038 except Exception as e
:
1039 self
.logger
.debug('keyword: interface list with value: %s' % str(e
))
1042 def _keyword_interface_on_off_list(self
, value
, validrange
=None):
1044 <yes|no> | ( <interface>=<on|off> [<interface>=<on|off> ...] )
1045 ex: bridge-learning swp1=on swp2=off
1047 return self
._keyword
_interface
_list
_with
_value
(value
, ['on', 'off'])
1049 def _keyword_interface_yes_no_list(self
, value
, validrange
=None):
1051 <yes|no> | ( <interface>=<yes|no> [<interface>=<yes|no> ...] )
1052 ex: mstpctl-portrestrrole swp1=yes swp2=no
1054 return self
._keyword
_interface
_list
_with
_value
(value
, ['yes', 'no'])
1056 def _keyword_interface_yes_no_auto_list(self
, value
, validrange
=None):
1059 ( <interface>=<yes|no|auto> [<interface>=<yes|no|auto> ...] )
1060 ex: mstpctl-portp2p swp1=yes swp2=no swp3=auto
1062 return self
._keyword
_interface
_list
_with
_value
(value
,
1063 ['yes', 'no', 'auto'])
1065 def _keyword_interface_l2protocol_tunnel_list(self
, value
, validrange
=None):
1067 bridge-l2protocol-tunnel swpX=lacp,stp swpY=cdp swpZ=all
1068 bridge-l2protocol-tunnel lacp stp,lldp,cdp
1069 bridge-l2protocol-tunnel stp lacp cdp
1070 bridge-l2protocol-tunnel lldp pvst
1071 bridge-l2protocol-tunnel stp
1072 bridge-l2protocol-tunnel all
1076 for intf_arg
in value
.split():
1077 intf_arg_split
= intf_arg
.split('=')
1078 for arg
in intf_arg_split
[1].replace(",", " ").split():
1079 if arg
not in ['all', 'stp', 'lldp', 'lacp', 'cdp', 'pvst']:
1082 for arg
in value
.replace(",", " ").split():
1083 if arg
not in ['all', 'stp', 'lldp', 'lacp', 'cdp', 'pvst']:
1089 def _keyword_interface_yes_no_0_1_list(self
, value
, validrange
=None):
1092 ( <interface>=<yes|no|0|1> [<interface>=<yes|no|0|1> ...] )
1093 ex: bridge-portmcrouter swp1=yes swp2=yes swp3=1
1095 return self
._keyword
_interface
_list
_with
_value
(value
,
1096 ['yes', 'no', '1', '0', '2'])
1098 def _keyword_interface_disabled_automatic_enabled_list(self
, value
, validrange
=None):
1099 return self
._keyword
_interface
_list
_with
_value
(value
, [
1100 '0', 'disabled', 'no',
1101 '1', 'automatic', 'yes',
1104 def _keyword_interface_range_list_multiple_of_16(self
, value
, validrange
):
1105 return self
._keyword
_interface
_range
_list
(value
, validrange
, multiple
=16)
1107 def _keyword_interface_range_list(self
, value
, validrange
, multiple
=None):
1109 <number> | ( <interface>=<number> [ <interface>=number> ...] )
1110 ex: mstpctl-portpathcost swp1=0 swp2=1
1112 values
= value
.split()
1114 if len(values
) == 1 and '=' not in values
[0]:
1117 if n
< int(validrange
[0]) or n
> int(
1119 raise invalidValueError('value of out range "%s":'
1120 ' valid attribute range: %s'
1122 '-'.join(validrange
)))
1124 if multiple
is not None:
1125 if not (n
% multiple
== 0):
1126 raise invalidValueError('invalid value %s: must be a multiple of %s' % (n
, multiple
))
1129 except invalidValueError
as e
:
1131 except Exception as e
:
1132 self
.logger
.debug('keyword: interface range list: %s'
1136 iface_value
= v
.split('=')
1137 size
= len(iface_value
)
1140 number
= int(iface_value
[1])
1141 if number
< int(validrange
[0]) or number
> int(
1143 raise invalidValueError(
1144 'value of out range "%s" for iface "%s":'
1145 ' valid attribute range: %s'
1148 '-'.join(validrange
)))
1150 if multiple
is not None:
1151 if not (number
% multiple
== 0):
1152 raise invalidValueError('invalid value %s: must be a multiple of %s' % (number
, multiple
))
1155 except invalidValueError
as e
:
1157 except Exception as e
:
1158 self
.logger
.debug('keyword: interface range list: %s' % str(e
))
1161 def _keyword_interface_list(self
, value
, validrange
=None):
1163 [glob|regex] <interface> [ [glob|regex] <interface> ...]
1164 ex: bridge-ports swp1 swp2 glob swp3-5.100 regex (swp[6|7|8].100)
1166 interface_list
= value
.split()
1167 size
= len(interface_list
)
1170 if interface_list
[i
] == 'glob' or interface_list
[i
] == 'regex':
1173 if not self
._keyword
_interface
(interface_list
[i
]):
1178 def _keyword_number_range_list(self
, value
, validrange
=None):
1180 <number> [<number>-<number>]
1181 ex: bridge-vids 42 100-200
1183 number_list
= value
.split()
1186 while i
< len(number_list
):
1187 if '-' in number_list
[i
]:
1188 range = number_list
[i
].split('-')
1197 except Exception as e
:
1198 self
.logger
.debug('keyword: number range list: %s' % str(e
))
1201 def _keyword_number_interface_list(self
, value
, validrange
=None):
1203 <number> <interface> [<interface>... [<number> <interface> ... ]]
1204 bridge-waitport 42 swp1 swp2 swp3 9 swp4
1206 interface_list
= value
.split()
1207 if not interface_list
:
1210 int(interface_list
[0])
1212 for elem
in interface_list
[1:]:
1221 except Exception as e
:
1222 self
.logger
.debug('keyword: number interface list: %s' % str(e
))
1225 def _keyword_number(self
, value
, validrange
=None):
1227 int_value
= int(value
)
1228 if validrange
is not None:
1229 return int(validrange
[0]) <= int_value
<= int(validrange
[1])
1231 except Exception as e
:
1232 self
.logger
.debug('keyword: number: %s' % str(e
))
1235 def _is_keyword(self
, value
):
1236 if isinstance(value
, tuple):
1238 keyword_found
= value
in self
.validate_keywords
1239 if value
.startswith('<') and value
.endswith('>') and not keyword_found
:
1240 raise Exception('%s: invalid keyword, please make sure to use'
1241 ' a valid keyword see `ifquery -s`' % value
)
1242 return keyword_found
1244 def _check_validvals_value(self
, attrname
, value
, validvals
, validrange
):
1245 if validvals
and value
not in validvals
:
1247 for keyword
in validvals
:
1248 if self
._is
_keyword
(keyword
):
1250 if self
.validate_keywords
[keyword
](value
, validrange
):
1251 return {'result': True}
1253 if self
.validate_keywords
[keyword
](value
):
1254 return {'result': True}
1258 'message': 'invalid value "%s": valid attribute values: %s'
1259 % (value
, validvals
)
1261 elif validvals
and value
in validvals
:
1264 if len(validrange
) != 2:
1265 raise Exception('%s: invalid range in addon configuration'
1266 % '-'.join(validrange
))
1268 if _value
< int(validrange
[0]) or _value
> int(validrange
[1]):
1271 'message': 'value of out range "%s": '
1272 'valid attribute range: %s'
1273 % (value
, '-'.join(validrange
))
1275 return {'result': True}
1277 def _check_validvals(self
, ifacename
, module_name
, attrs
):
1278 ifaceobj
= self
.get_ifaceobjs(ifacename
)
1282 for attrname
, attrvalue
in list(ifaceobj
[0].config
.items()):
1284 attrname_dict
= attrs
.get(attrname
, {})
1285 validvals
= attrname_dict
.get('validvals', [])
1286 validrange
= attrname_dict
.get('validrange', [])
1287 for value
in attrvalue
:
1288 res
= self
._check
_validvals
_value
(attrname
,
1292 if not res
['result']:
1293 self
.logger
.warning('%s: %s: %s' %
1294 (ifacename
, attrname
, res
['message']))
1296 except Exception as e
:
1297 self
.logger
.warning('addon \'%s\': %s: %s' % (module_name
,
1303 def _module_syntax_check(self
, filtered_ifacenames
):
1305 for ifacename
in filtered_ifacenames
:
1306 for module
in list(self
.modules
.values()):
1308 if hasattr(module
, '_modinfo'):
1309 if not self
._check
_validvals
(ifacename
,
1310 module
.__class
__.__name
__,
1311 module
._modinfo
.get('attrs', {})):
1313 if hasattr(module
, 'syntax_check') and callable(module
.syntax_check
):
1314 if not module
.syntax_check(self
.get_ifaceobjs(ifacename
)[0],
1315 self
.get_ifaceobjs
):
1317 except Exception as e
:
1318 self
.logger
.warning('%s: %s' % (ifacename
, str(e
)))
1322 def _iface_configattr_syntax_checker(self
, attrname
, attrval
):
1323 for m
, mdict
in list(self
.module_attrs
.items()):
1326 attrsdict
= mdict
.get('attrs')
1328 a
= attrsdict
.get(attrname
)
1330 if a
.get('deprecated'):
1331 newa
= a
.get('new-attribute')
1333 self
.logger
.warning('attribute %s is deprecated. use %s instead.' %(attrname
, newa
))
1335 self
.logger
.warning('attribute %s is deprecated.'
1339 for key
in attrsdict
:
1340 if 'aliases' in attrsdict
[key
]:
1341 if attrname
in attrsdict
[key
]['aliases']:
1343 except AttributeError:
1347 def _ifaceobj_syntax_checker(self
, ifaceobj
):
1349 for attrname
, attrvalue
in list(ifaceobj
.config
.items()):
1351 for k
, v
in list(self
.module_attrs
.items()):
1352 if v
and v
.get('attrs', {}).get(attrname
):
1357 self
.logger
.warning('%s: unsupported attribute \'%s\'' \
1358 % (ifaceobj
.name
, attrname
))
1362 def read_iface_config(self
, raw
=False):
1363 """ Reads default network interface config /etc/network/interfaces. """
1365 nifaces
= networkInterfaces(self
.interfacesfile
,
1366 self
.interfacesfileiobuf
,
1367 self
.interfacesfileformat
,
1368 template_enable
=self
.config
.get('template_enable', 0),
1369 template_engine
=self
.config
.get('template_engine'),
1370 template_lookuppath
=self
.config
.get('template_lookuppath'),
1372 if self
._ifaceobj
_squash
or self
._ifaceobj
_squash
_internal
:
1373 nifaces
.subscribe('iface_found', self
._save
_iface
_squash
)
1375 nifaces
.subscribe('iface_found', self
._save
_iface
)
1376 if self
.config
.get('addon_syntax_check', '1') == '1':
1377 nifaces
.subscribe('validateifaceattr',
1378 self
._iface
_configattr
_syntax
_checker
)
1379 nifaces
.subscribe('validateifaceobj', self
._ifaceobj
_syntax
_checker
)
1381 if nifaces
.errors
or nifaces
.warns
:
1384 self
._schedule
_addon
_translate
()
1387 def read_old_iface_config(self
):
1388 """ Reads the saved iface config instead of default iface config.
1389 And saved iface config is already read by the statemanager """
1390 self
.ifaceobjdict
= copy
.deepcopy(self
.statemanager
.ifaceobjdict
)
1392 def _load_addon_modules_config(self
):
1393 """ Load addon modules config file """
1395 with
open(self
.addon_modules_configfile
, 'r') as f
:
1396 lines
= f
.readlines()
1399 litems
= l
.strip(' \n\t\r').split(',')
1400 if not litems
or len(litems
) < 2:
1402 operation
= litems
[0]
1404 self
.module_ops
[operation
].append(mname
)
1405 except Exception as e
:
1406 self
.logger
.warning('error reading line \'%s\' %s:' %(l
, str(e
)))
1409 def load_addon_modules(self
, modules_dir_list
):
1410 """ load python modules from modules_dir
1412 Default modules_dir is /usr/share/ifupdownmodules
1415 failed_import
= list()
1417 self
.logger
.info('loading builtin modules from %s' % str(modules_dir_list
))
1418 self
._load
_addon
_modules
_config
()
1420 for modules_dir
in modules_dir_list
:
1421 if not modules_dir
in sys
.path
:
1422 sys
.path
.insert(1, modules_dir
)
1424 for op
, mlist
in list(self
.module_ops
.items()):
1426 if self
.modules
.get(mname
):
1428 mpath
= modules_dir
+ '/' + mname
+ '.py'
1429 if os
.path
.exists(mpath
) and mpath
not in failed_import
:
1431 m
= __import__(mname
)
1432 mclass
= getattr(m
, mname
)
1433 except Exception as e
:
1434 self
.logger
.warning('cannot load "%s" module: %s' % (mname
, str(e
)))
1435 failed_import
.append(mpath
)
1438 minstance
= mclass()
1439 script_override
= minstance
.get_overrides_ifupdown_scripts()
1440 self
.overridden_ifupdown_scripts
.extend(script_override
)
1441 except moduleNotSupported
as e
:
1442 self
.logger
.info('module %s not loaded (%s)'
1447 self
.modules
[mname
] = minstance
1449 self
.module_attrs
[mname
] = minstance
.get_modinfo()
1455 # Assign all modules to query operations
1456 self
.module_ops
['query-checkcurr'] = list(self
.modules
.keys())
1457 self
.module_ops
['query-running'] = list(self
.modules
.keys())
1458 self
.module_ops
['query-dependency'] = list(self
.modules
.keys())
1459 self
.module_ops
['query'] = list(self
.modules
.keys())
1460 self
.module_ops
['query-raw'] = list(self
.modules
.keys())
1462 def _keyword_number_comma_range_list(self
, value
, validrange
=None):
1463 return self
._keyword
_number
_range
_list
(value
.replace(',', ' '), validrange
=validrange
)
1466 def _modules_help(self
, fmt
):
1467 """ Prints addon modules supported syntax """
1471 for key
, value
in list(self
.modules
.items()):
1472 if hasattr(value
, '_modinfo'):
1474 'mhelp': value
._modinfo
['mhelp'],
1475 'attrs': value
.merge_modinfo_with_policy_files()
1477 print(json
.dumps(modinfos
))
1480 for m
, mdict
in list(self
.module_attrs
.items()):
1483 print(('%s: %s' %(m
, mdict
.get('mhelp'))))
1484 attrdict
= self
.modules
[m
].merge_modinfo_with_policy_files()
1488 for attrname
, attrvaldict
in list(attrdict
.items()):
1489 if attrvaldict
.get('compat', False):
1491 print(('%s%s' %(indent
, attrname
)))
1492 print(('%shelp: %s' %(indent
+ ' ',
1493 attrvaldict
.get('help', ''))))
1494 print(('%srequired: %s' %(indent
+ ' ',
1495 attrvaldict
.get('required', False))))
1496 default
= attrvaldict
.get('default')
1498 print(('%sdefault: %s' %(indent
+ ' ', default
)))
1500 validrange
= attrvaldict
.get('validrange')
1502 print(('%svalidrange: %s-%s'
1503 %(indent
+ ' ', validrange
[0], validrange
[1])))
1505 validvals
= attrvaldict
.get('validvals')
1507 print(('%svalidvals: %s'
1508 %(indent
+ ' ', ','.join(validvals
))))
1510 examples
= attrvaldict
.get('example')
1514 print('%sexample:' %(indent
+ ' '))
1516 print('%s%s' %(indent
+ ' ', e
))
1521 def load_scripts(self
, modules_dir
):
1522 """ loading user modules from /etc/network/.
1524 Note that previously loaded python modules override modules found
1525 under /etc/network if any
1529 self
.logger
.info('looking for user scripts under %s' %modules_dir
)
1530 for op
, mlist
in list(self
.script_ops
.items()):
1531 msubdir
= modules_dir
+ '/if-%s.d' %op
1532 self
.logger
.info('loading scripts under %s ...' %msubdir
)
1534 module_list
= os
.listdir(msubdir
)
1535 for module
in module_list
:
1536 if self
.modules
.get(module
) or module
in self
.overridden_ifupdown_scripts
:
1538 self
.script_ops
[op
].append(msubdir
+ '/' + module
)
1544 def _schedule_addon_translate(self
):
1545 merged_ifaceobjs
= list(itertools
.chain
.from_iterable(self
.ifaceobjdict
.values()))
1547 for addon
in self
.modules
.values():
1549 addon
.translate(merged_ifaceobjs
)
1550 except AttributeError:
1553 def _sched_ifaces(self
, ifacenames
, ops
, skipupperifaces
=False,
1554 followdependents
=True, sort
=False):
1555 self
.logger
.debug('scheduling \'%s\' for %s'
1556 %(str(ops
), str(ifacenames
)))
1557 self
._pretty
_print
_ordered
_dict
('dependency graph',
1558 self
.dependency_graph
)
1559 ifaceScheduler
.sched_ifaces(self
, ifacenames
, ops
,
1560 dependency_graph
=self
.dependency_graph
,
1561 order
=ifaceSchedulerFlags
.INORDER
1563 else ifaceSchedulerFlags
.POSTORDER
,
1564 followdependents
=followdependents
,
1565 skipupperifaces
=skipupperifaces
,
1566 sort
=True if (sort
or ifupdownflags
.flags
.CLASS
) else False)
1567 return ifaceScheduler
.get_sched_status()
1569 def _render_ifacename(self
, ifacename
):
1571 vlan_match
= re
.match("^([\d]+)-([\d]+)", ifacename
)
1573 vlan_groups
= vlan_match
.groups()
1574 if vlan_groups
[0] and vlan_groups
[1]:
1575 [new_ifacenames
.append('%d' %v
)
1576 for v
in range(int(vlan_groups
[0]),
1577 int(vlan_groups
[1])+1)]
1578 return new_ifacenames
1580 def _preprocess_ifacenames(self
, ifacenames
):
1581 """ validates interface list for config existance.
1583 returns -1 if one or more interface not found. else, returns 0
1588 for i
in ifacenames
:
1589 ifaceobjs
= self
.get_ifaceobjs(i
)
1591 # if name not available, render interface name and check again
1592 rendered_ifacenames
= utils
.expand_iface_range(i
)
1593 if rendered_ifacenames
:
1594 for ri
in rendered_ifacenames
:
1595 ifaceobjs
= self
.get_ifaceobjs(ri
)
1597 err_iface
+= ' ' + ri
1599 new_ifacenames
.append(ri
)
1601 err_iface
+= ' ' + i
1603 new_ifacenames
.append(i
)
1605 raise Exception('cannot find interfaces:%s' %err_iface
)
1606 return new_ifacenames
1608 def _iface_whitelisted(self
, auto
, allow_classes
, excludepats
, ifacename
):
1609 """ Checks if interface is whitelisted depending on set of parameters.
1611 interfaces are checked against the allow_classes and auto lists.
1617 # Check if interface matches the exclude patter
1619 for e
in excludepats
:
1620 if re
.search(e
, ifacename
):
1622 ifaceobjs
= self
.get_ifaceobjs(ifacename
)
1625 self
.logger
.debug('iface %s' %ifacename
+ ' not found')
1627 # If matched exclude pattern, return false
1630 i
.blacklisted
= True
1631 self
.blacklisted_ifaces_present
= True
1633 # Check if interface belongs to the class
1634 # the user is interested in, if not return false
1639 common
= set(allow_classes
).intersection(set(i
.classes
))
1643 # If a class was requested and interface does not belong
1644 # to the class, only then mark the ifaceobjs as blacklisted
1645 self
.blacklisted_ifaces_present
= True
1647 i
.blacklisted
= True
1649 # If the user has requested auto class, check if the interface
1657 # If auto was requested and interface was not marked auto,
1658 # only then mark all of them as blacklisted
1659 self
.blacklisted_ifaces_present
= True
1661 i
.blacklisted
= True
1664 def _compat_conv_op_to_mode(self
, op
):
1665 """ Returns old op name to work with existing scripts """
1673 def generate_running_env(self
, ifaceobj
, op
):
1674 """ Generates a dictionary with env variables required for
1675 an interface. Used to support script execution for interfaces.
1679 iface_env
= ifaceobj
.get_env()
1681 cenv
= dict(os
.environ
)
1683 cenv
.update(iface_env
)
1688 cenv
['MODE'] = self
._compat
_conv
_op
_to
_mode
(op
)
1693 def _save_state(self
):
1694 if (not self
.flags
.STATEMANAGER_ENABLE
or
1695 not self
.flags
.STATEMANAGER_UPDATE
):
1698 # Update persistant iface states
1699 self
.statemanager
.save_state()
1700 except Exception as e
:
1701 if self
.logger
.isEnabledFor(logging
.DEBUG
):
1702 t
= sys
.exc_info()[2]
1703 traceback
.print_tb(t
)
1704 self
.logger
.warning('error saving state (%s)' %str
(e
))
1706 def set_type(self
, type):
1708 self
.type = ifaceType
.IFACE
1709 elif type == 'vlan':
1710 self
.type = ifaceType
.BRIDGE_VLAN
1712 self
.type = ifaceType
.UNKNOWN
1714 def _process_delay_admin_state_queue(self
, op
):
1715 if not self
._delay
_admin
_state
_iface
_queue
:
1718 func
= self
.netlink
.link_up
1720 func
= self
.netlink
.link_down
1723 for i
in self
._delay
_admin
_state
_iface
_queue
:
1725 if self
.link_exists(i
):
1727 except Exception as e
:
1728 self
.logger
.warning(str(e
))
1731 def _get_iface_exclude_companion(self
, ifacename
):
1733 return ifupdown2
.ifupdown
.policymanager
.policymanager_api
.get_iface_default(
1734 module_name
='main', ifname
=ifacename
,
1735 attr
='exclude-companion')
1737 return ifupdown
.policymanager
.policymanager_api
.get_iface_default(
1738 module_name
='main', ifname
=ifacename
,
1739 attr
='exclude-companion')
1741 def _preprocess_excludepats(self
, excludepats
):
1742 new_excludepats
= excludepats
1743 for e
in excludepats
:
1744 ifaceobjs
= self
.get_ifaceobjs(e
)
1745 for iobj
in ifaceobjs
or []:
1746 ec
= iobj
.get_attr_value_first('exclude-companion')
1748 ec
= self
._get
_iface
_exclude
_companion
(e
)
1752 for ee
in ec
.split():
1753 if ee
in new_excludepats
:
1755 if self
.get_ifaceobjs(ee
):
1756 # if we know the object add it to the new
1758 new_excludepats
.append(ee
)
1759 self
.logger
.info('excludepats after processing companions [%s]' %' '.join(new_excludepats
))
1760 return new_excludepats
1762 def up(self
, ops
, auto
=False, allow_classes
=None, ifacenames
=None,
1763 excludepats
=None, printdependency
=None, syntaxcheck
=False,
1764 type=None, skipupperifaces
=False):
1765 """This brings the interface(s) up
1768 ops (list): list of ops to perform on the interface(s).
1769 Eg: ['pre-up', 'up', 'post-up'
1772 auto (bool): act on interfaces marked auto
1773 allow_classes (list): act on interfaces belonging to classes in the list
1774 ifacenames (list): act on interfaces specified in this list
1775 excludepats (list): list of patterns of interfaces to exclude
1776 syntaxcheck (bool): only perform syntax check
1782 ifupdownflags
.flags
.CLASS
= True
1783 if not self
.flags
.ADDONS_ENABLE
:
1784 self
.flags
.STATEMANAGER_UPDATE
= False
1786 ifupdownflags
.flags
.ALL
= True
1787 ifupdownflags
.flags
.WITH_DEPENDS
= True
1789 iface_read_ret
= self
.read_iface_config()
1794 excludepats
= self
._preprocess
_excludepats
(excludepats
)
1796 filtered_ifacenames
= None
1798 ifacenames
= self
._preprocess
_ifacenames
(ifacenames
)
1801 filtered_ifacenames
= self
._get
_filtered
_ifacenames
_with
_classes
(auto
, allow_classes
, excludepats
, ifacenames
)
1803 # if iface list not given by user, assume all from config file
1804 if not ifacenames
: ifacenames
= list(self
.ifaceobjdict
.keys())
1806 if not filtered_ifacenames
:
1807 # filter interfaces based on auto and allow classes
1808 filtered_ifacenames
= [i
for i
in ifacenames
1809 if self
._iface
_whitelisted
(auto
, allow_classes
,
1812 if not filtered_ifacenames
:
1813 raise Exception('no ifaces found matching given allow lists')
1816 self
.populate_dependency_info(ops
, filtered_ifacenames
)
1817 self
.print_dependency(filtered_ifacenames
, printdependency
)
1820 self
.populate_dependency_info(ops
)
1822 # If only syntax check was requested, return here.
1823 # return here because we want to make sure most
1824 # errors above are caught and reported.
1826 if not self
._module
_syntax
_check
(filtered_ifacenames
):
1828 if not iface_read_ret
:
1830 elif self
._any
_iface
_errors
(filtered_ifacenames
):
1836 ret
= self
._sched
_ifaces
(filtered_ifacenames
, ops
,
1837 skipupperifaces
=skipupperifaces
,
1838 followdependents
=True
1839 if ifupdownflags
.flags
.WITH_DEPENDS
1842 self
._process
_delay
_admin
_state
_queue
('up')
1843 if not ifupdownflags
.flags
.DRYRUN
and self
.flags
.ADDONS_ENABLE
:
1846 if not iface_read_ret
or not ret
:
1849 self
.check_running_configuration(filtered_ifacenames
)
1851 def check_running_configuration(self
, filtered_ifacenames
, all
=False):
1853 Print warning and better info message when we don't recognize an interface
1854 AKA when the interface wasn't created.
1856 :param filtered_ifacenames:
1860 if not filtered_ifacenames
:
1861 filtered_ifacenames
= []
1863 for ifname
, ifaceobj_list
in self
.ifaceobjdict
.items():
1865 if not all
and ifname
not in filtered_ifacenames
:
1870 for ifaceobj
in ifaceobj_list
:
1871 if not ifaceobj
.auto
:
1875 if not ifupdownflags
.flags
.DRYRUN
and auto
and not os
.path
.exists("/sys/class/net/%s" % ifname
):
1876 self
.logger
.warning("%s: interface not recognized - please check interface configuration" % ifname
)
1878 def _get_filtered_ifacenames_with_classes(self
, auto
, allow_classes
, excludepats
, ifacenames
):
1879 # if user has specified ifacelist and allow_classes
1880 # append the allow_classes interfaces to user
1882 filtered_ifacenames
= [i
for i
in list(self
.ifaceobjdict
.keys())
1883 if self
._iface
_whitelisted
(auto
, allow_classes
,
1885 filtered_ifacenames
+= ifacenames
1887 for intf
in ifacenames
:
1888 for obj
in self
.get_ifaceobjs(intf
) or []:
1889 obj
.blacklisted
= False
1891 return filtered_ifacenames
1893 def down(self
, ops
, auto
=False, allow_classes
=None, ifacenames
=None,
1894 excludepats
=None, printdependency
=None, usecurrentconfig
=False,
1896 """ down an interface """
1901 ifupdownflags
.flags
.CLASS
= True
1902 if not self
.flags
.ADDONS_ENABLE
:
1903 self
.flags
.STATEMANAGER_UPDATE
= False
1905 ifupdownflags
.flags
.ALL
= True
1906 ifupdownflags
.flags
.WITH_DEPENDS
= True
1907 # For down we need to look at old state, unless usecurrentconfig
1909 if (not usecurrentconfig
and self
.flags
.STATEMANAGER_ENABLE
and
1910 self
.statemanager
.ifaceobjdict
):
1911 # Since we are using state manager objects,
1912 # skip the updating of state manager objects
1913 self
.logger
.debug('Looking at old state ..')
1914 self
.read_old_iface_config()
1916 # If no old state available
1918 self
.read_iface_config()
1919 except Exception as e
:
1920 raise Exception('error reading iface config (%s)' %str
(e
))
1923 excludepats
= self
._preprocess
_excludepats
(excludepats
)
1925 filtered_ifacenames
= None
1927 # If iface list is given by the caller, always check if iface
1930 ifacenames
= self
._preprocess
_ifacenames
(ifacenames
)
1933 filtered_ifacenames
= self
._get
_filtered
_ifacenames
_with
_classes
(auto
, allow_classes
, excludepats
, ifacenames
)
1935 except Exception as e
:
1936 raise Exception('%s' %str
(e
) +
1937 ' (interface was probably never up ?)')
1940 # if iface list not given by user, assume all from config file
1941 if not ifacenames
: ifacenames
= list(self
.ifaceobjdict
.keys())
1943 if not filtered_ifacenames
:
1944 # filter interfaces based on auto and allow classes
1945 filtered_ifacenames
= [i
for i
in ifacenames
1946 if self
._iface
_whitelisted
(auto
, allow_classes
,
1949 if not filtered_ifacenames
:
1950 raise Exception('no ifaces found matching given allow lists ' +
1951 '(or interfaces were probably never up ?)')
1954 self
.populate_dependency_info(ops
, filtered_ifacenames
)
1955 self
.print_dependency(filtered_ifacenames
, printdependency
)
1958 self
.populate_dependency_info(ops
)
1961 self
._sched
_ifaces
(filtered_ifacenames
, ops
,
1962 followdependents
=True
1963 if ifupdownflags
.flags
.WITH_DEPENDS
else False)
1965 self
._process
_delay
_admin
_state
_queue
('down')
1966 if not ifupdownflags
.flags
.DRYRUN
and self
.flags
.ADDONS_ENABLE
:
1969 def query(self
, ops
, auto
=False, format_list
=False, allow_classes
=None,
1971 excludepats
=None, printdependency
=None,
1972 format
='native', type=None):
1973 """ query an interface """
1977 # Let us forget internal squashing when it comes to
1978 # ifquery. It can surprise people relying of ifquery
1980 self
._ifaceobj
_squash
_internal
= False
1983 ifupdownflags
.flags
.CLASS
= True
1984 if self
.flags
.STATEMANAGER_ENABLE
and ops
[0] == 'query-savedstate':
1985 return self
.statemanager
.dump_pretty(ifacenames
)
1986 self
.flags
.STATEMANAGER_UPDATE
= False
1988 iface_read_ret
= True
1991 self
.logger
.debug('setting flag ALL')
1992 ifupdownflags
.flags
.ALL
= True
1993 ifupdownflags
.flags
.WITH_DEPENDS
= True
1995 if ops
[0] == 'query-syntax':
1996 self
._modules
_help
(format
)
1998 elif ops
[0] == 'query-running':
1999 # create fake devices to all dependents that dont have config
2000 for i
in ifacenames
:
2001 self
.create_n_save_ifaceobj(i
, ifacePrivFlags(False, True))
2004 iface_read_ret
= self
.read_iface_config(raw
=ops
[0] == "query-raw")
2008 if ifacenames
and ops
[0] != 'query-running':
2009 # If iface list is given, always check if iface is present
2010 ifacenames
= self
._preprocess
_ifacenames
(ifacenames
)
2013 filtered_ifacenames
= self
._get
_filtered
_ifacenames
_with
_classes
(auto
, allow_classes
, excludepats
, ifacenames
)
2015 # if iface list not given by user, assume all from config file
2016 if not ifacenames
: ifacenames
= list(self
.ifaceobjdict
.keys())
2018 # filter interfaces based on auto and allow classes
2019 if ops
[0] == 'query-running':
2020 filtered_ifacenames
= ifacenames
2021 elif not allow_classes
:
2022 filtered_ifacenames
= [
2023 i
for i
in ifacenames
2024 if self
._iface
_whitelisted
(
2031 if not filtered_ifacenames
:
2032 raise Exception('no ifaces found matching ' +
2033 'given allow lists')
2035 self
.populate_dependency_info(ops
)
2036 if ops
[0] == 'query-dependency' and printdependency
:
2037 self
.print_dependency(filtered_ifacenames
, printdependency
)
2040 if format_list
and (ops
[0] == 'query' or ops
[0] == 'query-raw'):
2041 return self
.print_ifaceobjs_list(filtered_ifacenames
)
2043 if ops
[0] == 'query' and not ifupdownflags
.flags
.WITHDEFAULTS
:
2044 return self
.print_ifaceobjs_pretty(filtered_ifacenames
, format
)
2045 elif ops
[0] == 'query-raw':
2046 return self
.print_ifaceobjs_raw(filtered_ifacenames
, format
)
2048 ret
= self
._sched
_ifaces
(filtered_ifacenames
, ops
,
2049 followdependents
=True
2050 if ifupdownflags
.flags
.WITH_DEPENDS
else False)
2052 if ops
[0] == 'query' and ifupdownflags
.flags
.WITHDEFAULTS
:
2053 return self
.print_ifaceobjs_pretty(filtered_ifacenames
, format
)
2054 elif ops
[0] == 'query-checkcurr':
2055 if self
.print_ifaceobjscurr_pretty(filtered_ifacenames
, format
):
2056 # if any of the object has an error, signal that silently
2058 elif ops
[0] == 'query-running':
2059 self
.print_ifaceobjsrunning_pretty(filtered_ifacenames
, format
)
2062 if not iface_read_ret
or not ret
:
2065 def _reload_currentlyup(self
, upops
, downops
, auto
=False, allow
=None,
2066 ifacenames
=None, excludepats
=None, usecurrentconfig
=False,
2067 syntaxcheck
=False, **extra_args
):
2068 """ reload currently up interfaces """
2069 new_ifaceobjdict
= {}
2071 self
.logger
.info('reloading interfaces that are currently up ..')
2074 iface_read_ret
= self
.read_iface_config()
2077 if not self
.ifaceobjdict
:
2078 self
.logger
.warning("nothing to reload ..exiting.")
2080 already_up_ifacenames
= []
2081 if not ifacenames
: ifacenames
= list(self
.ifaceobjdict
.keys())
2083 if (not usecurrentconfig
and self
.flags
.STATEMANAGER_ENABLE
2084 and self
.statemanager
.ifaceobjdict
):
2085 already_up_ifacenames
= list(self
.statemanager
.ifaceobjdict
.keys())
2087 # Get already up interfaces that still exist in the interfaces file
2088 already_up_ifacenames_not_present
= set(
2089 already_up_ifacenames
).difference(ifacenames
)
2090 already_up_ifacenames_still_present
= set(
2091 already_up_ifacenames
).difference(
2092 already_up_ifacenames_not_present
)
2094 interfaces_to_up
= already_up_ifacenames_still_present
2096 # generate dependency graph of interfaces
2097 self
.populate_dependency_info(upops
, interfaces_to_up
)
2099 # If only syntax check was requested, return here.
2100 # return here because we want to make sure most
2101 # errors above are caught and reported.
2103 if not self
._module
_syntax
_check
(interfaces_to_up
):
2105 if not iface_read_ret
:
2107 elif self
._any
_iface
_errors
(interfaces_to_up
):
2111 if (already_up_ifacenames_not_present
and
2112 self
.config
.get('ifreload_currentlyup_down_notpresent') == '1'):
2113 self
.logger
.info('reload: schedule down on interfaces: %s'
2114 %str
(already_up_ifacenames_not_present
))
2116 # Save a copy of new iface objects and dependency_graph
2117 new_ifaceobjdict
= dict(self
.ifaceobjdict
)
2118 new_dependency_graph
= dict(self
.dependency_graph
)
2120 # old interface config is read into self.ifaceobjdict
2121 self
.read_old_iface_config()
2123 # reinitialize dependency graph
2124 self
.dependency_graph
= OrderedDict({})
2125 falready_up_ifacenames_not_present
= [i
for i
in
2126 already_up_ifacenames_not_present
2127 if self
._iface
_whitelisted
(auto
, allow
,
2129 self
.populate_dependency_info(downops
,
2130 falready_up_ifacenames_not_present
)
2131 self
._sched
_ifaces
(falready_up_ifacenames_not_present
, downops
,
2132 followdependents
=False, sort
=True)
2134 self
.logger
.info('no interfaces to down ..')
2136 # Now, run 'up' with new config dict
2137 # reset statemanager update flag to default
2139 ifupdownflags
.flags
.ALL
= True
2140 ifupdownflags
.flags
.WITH_DEPENDS
= True
2141 if new_ifaceobjdict
:
2142 # and now, ifaceobjdict is back to current config
2143 self
.ifaceobjdict
= new_ifaceobjdict
2144 self
.dependency_graph
= new_dependency_graph
2146 if not self
.ifaceobjdict
:
2147 self
.logger
.info('no interfaces to up')
2149 self
.logger
.info('reload: scheduling up on interfaces: %s'
2150 %str
(interfaces_to_up
))
2151 ret
= self
._sched
_ifaces
(interfaces_to_up
, upops
,
2152 followdependents
=True
2153 if ifupdownflags
.flags
.WITH_DEPENDS
else False)
2154 if ifupdownflags
.flags
.DRYRUN
:
2158 if not iface_read_ret
or not ret
:
2161 def _reload_default(self
, upops
, downops
, auto
=False, allow
=None,
2162 ifacenames
=None, excludepats
=None, usecurrentconfig
=False,
2163 syntaxcheck
=False, **extra_args
):
2164 """ reload interface config """
2165 new_ifaceobjdict
= {}
2168 iface_read_ret
= self
.read_iface_config()
2172 if not self
.ifaceobjdict
:
2173 self
.logger
.warning("nothing to reload ..exiting.")
2176 if not ifacenames
: ifacenames
= list(self
.ifaceobjdict
.keys())
2177 new_filtered_ifacenames
= [i
for i
in ifacenames
2178 if self
._iface
_whitelisted
(auto
, allow
,
2180 # generate dependency graph of interfaces
2181 self
.populate_dependency_info(upops
)
2183 # If only syntax check was requested, return here.
2184 # return here because we want to make sure most
2185 # errors above are caught and reported.
2187 if not self
._module
_syntax
_check
(new_filtered_ifacenames
):
2189 if not iface_read_ret
:
2191 elif self
._any
_iface
_errors
(new_filtered_ifacenames
):
2195 if (not usecurrentconfig
and self
.flags
.STATEMANAGER_ENABLE
2196 and self
.statemanager
.ifaceobjdict
):
2197 # Save a copy of new iface objects and dependency_graph
2198 new_ifaceobjdict
= dict(self
.ifaceobjdict
)
2199 new_dependency_graph
= dict(self
.dependency_graph
)
2201 self
.ifaceobjdict
= OrderedDict({})
2202 self
.dependency_graph
= OrderedDict({})
2204 # if old state is present, read old state and mark op for 'down'
2205 # followed by 'up' aka: reload
2206 # old interface config is read into self.ifaceobjdict
2207 self
.read_old_iface_config()
2210 # oldconfig not available, continue with 'up' with new config
2212 new_ifaceobjdict
= self
.ifaceobjdict
2213 new_dependency_graph
= self
.dependency_graph
2216 excludepats
= self
._preprocess
_excludepats
(excludepats
)
2218 if op
== 'reload' and ifacenames
:
2219 ifacenames
= list(self
.ifaceobjdict
.keys())
2220 old_filtered_ifacenames
= [i
for i
in ifacenames
2221 if self
._iface
_whitelisted
(auto
, allow
,
2224 # generate dependency graph of old interfaces,
2225 # This should make sure built in interfaces are
2226 # populated. disable check shared dependents as an optimization.
2227 # these are saved interfaces and dependency for these
2228 # have been checked before they became part of saved state.
2230 self
.flags
.CHECK_SHARED_DEPENDENTS
= False
2231 self
.populate_dependency_info(upops
)
2232 self
.flags
.CHECK_SHARED_DEPENDENTS
= True
2233 except Exception as e
:
2234 self
.logger
.info("error generating dependency graph for "
2235 "saved interfaces (%s)" %str
(e
))
2238 # make sure we pick up built-in interfaces
2239 # if config file had 'ifreload_down_changed' variable
2240 # set, also look for interfaces that changed to down them
2241 down_changed
= int(self
.config
.get('ifreload_down_changed', '1'))
2243 # Generate the interface down list
2244 # Interfaces that go into the down list:
2245 # - interfaces that were present in last config and are not
2246 # present in the new config
2247 # - interfaces that were changed between the last and current
2250 for ifname
in list(self
.ifaceobjdict
.keys()):
2251 lastifaceobjlist
= self
.ifaceobjdict
.get(ifname
)
2252 if not self
.is_ifaceobj_builtin(lastifaceobjlist
[0]):
2253 # if interface is not built-in and is not in
2254 # old filtered ifacenames
2255 if ifname
not in old_filtered_ifacenames
:
2258 # If interface is not present in the new file
2259 # append it to the down list
2260 newifaceobjlist
= new_ifaceobjdict
.get(ifname
)
2261 if not newifaceobjlist
:
2262 ifacedownlist
.append(ifname
)
2264 # If ifaceobj was present in the old interfaces file,
2265 # and does not have a config in the new interfaces file
2266 # but has been picked up as a dependent of another
2267 # interface, catch it here. This catches a common error
2268 # for example: remove a bond section from the interfaces
2269 # file, but leave it around as a bridge port
2270 # XXX: Ideally its better to just add it to the
2271 # ifacedownlist. But we will be cautious here
2272 # and just print a warning
2273 if (self
.is_ifaceobj_noconfig(newifaceobjlist
[0]) and
2274 not self
.is_ifaceobj_builtin(newifaceobjlist
[0]) and
2275 lastifaceobjlist
[0].is_config_present() and
2276 lastifaceobjlist
[0].link_kind
):
2278 # Check if interface is picked up by a regex in the upperifaces.
2279 print_warning
= True
2281 for upper
in newifaceobjlist
[objidx
].upperifaces
or []:
2283 for upper_ifaceobj
in self
.ifaceobjdict
.get(upper
):
2284 slaves
.extend(upper_ifaceobj
.get_attr_value("bond-slaves") or [])
2285 slaves
.extend(upper_ifaceobj
.get_attr_value("bridge-ports") or [])
2286 slaves_string
= " ".join(slaves
)
2287 if newifaceobjlist
[objidx
].name
not in slaves_string
:
2288 print_warning
= "regex" not in slaves_string
2289 if not print_warning
:
2291 ###############################################################
2293 warning_no_config_regex
= (
2294 "%s: misconfig ? removed but still exists as a dependency of %s.\n"
2295 "Please remove the dependency manually `ifdown %s` if it is being "
2296 "picked up as part of a regex" % (
2297 newifaceobjlist
[objidx
].name
,
2298 str(newifaceobjlist
[objidx
].upperifaces
),
2299 newifaceobjlist
[objidx
].name
2304 self
.logger
.warning(warning_no_config_regex
)
2306 # The warning shouldn't be printed because we've detected that this
2307 # interface was pick up as part of a regex but the config doesn't
2308 # exist anymore. It was most likely removed from the config file itself
2309 # We should down this interface and remove it from the ifaceobjdict
2310 # and dependency graph used for the following ifreload.
2311 ifname_to_remove
= newifaceobjlist
[objidx
].name
2312 ifacedownlist
.append(ifname_to_remove
)
2315 if new_ifaceobjdict
:
2316 del new_ifaceobjdict
[ifname_to_remove
]
2318 for k
, v
in new_dependency_graph
.items():
2319 if ifname_to_remove
in v
:
2320 v
.remove(ifname_to_remove
)
2321 del new_dependency_graph
[ifname_to_remove
]
2322 except Exception as e
:
2323 self
.logger
.warning(warning_no_config_regex
)
2324 self
.logger
.warning("while trying to fix this situation "
2325 "we ran into the following issues: %s" % str(e
))
2327 elif (lastifaceobjlist
[0].link_kind
and
2328 not newifaceobjlist
[0].link_kind
):
2329 self
.logger
.warning('%s: moved from being a %s to a'
2330 ' physical interface (non-logical interface).'
2331 'This interface will be downed.\n'
2332 ' If this was not intentional, please restore the'
2333 ' original interface definition and execute ifreload'
2334 % (newifaceobjlist
[objidx
].name
,
2335 ifaceLinkKind
.to_str(lastifaceobjlist
[0].link_kind
)))
2336 ifacedownlist
.append(newifaceobjlist
[objidx
].name
)
2337 if not down_changed
:
2339 if len(newifaceobjlist
) != len(lastifaceobjlist
):
2340 ifacedownlist
.append(ifname
)
2343 # If interface has changed between the current file
2344 # and the last installed append it to the down list
2345 # compare object list
2346 for objidx
in range(0, len(lastifaceobjlist
)):
2347 oldobj
= lastifaceobjlist
[objidx
]
2348 newobj
= newifaceobjlist
[objidx
]
2349 if not newobj
.compare(oldobj
):
2350 ifacedownlist
.append(ifname
)
2354 self
.logger
.info('reload: scheduling down on interfaces: %s'
2355 %str
(ifacedownlist
))
2356 # reinitialize dependency graph
2357 self
.dependency_graph
= OrderedDict({})
2359 # Generate dependency info for old config
2360 self
.flags
.CHECK_SHARED_DEPENDENTS
= False
2361 self
.populate_dependency_info(downops
, ifacedownlist
)
2362 self
.flags
.CHECK_SHARED_DEPENDENTS
= True
2365 # XXX: Hack to skip checking upperifaces during down.
2366 # the dependency list is not complete here
2367 # and we dont want to down the upperiface.
2368 # Hence during reload, set this to true.
2369 # This is being added to avoid a failure in
2370 # scheduler._check_upperifaces when we are dowing
2371 # a builtin bridge port
2372 self
.flags
.SCHED_SKIP_CHECK_UPPERIFACES
= True
2373 self
._sched
_ifaces
(ifacedownlist
, downops
,
2374 followdependents
=False,
2376 except Exception as e
:
2377 self
.logger
.error(str(e
))
2380 self
.flags
.SCHED_SKIP_CHECK_UPPERIFACES
= False
2381 self
._process
_delay
_admin
_state
_queue
('down')
2383 self
.logger
.info('no interfaces to down ..')
2385 # Now, run 'up' with new config dict
2386 # reset statemanager update flag to default
2387 if not new_ifaceobjdict
:
2388 self
.logger
.debug('no interfaces to up')
2392 ifupdownflags
.flags
.ALL
= True
2393 ifupdownflags
.flags
.WITH_DEPENDS
= True
2394 # and now, we are back to the current config in ifaceobjdict
2395 self
.ifaceobjdict
= new_ifaceobjdict
2396 self
.dependency_graph
= new_dependency_graph
2398 self
.logger
.info('reload: scheduling up on interfaces: %s'
2399 %str
(new_filtered_ifacenames
))
2400 ifupdownflags
.flags
.CACHE
= True
2402 ret
= self
._sched
_ifaces
(new_filtered_ifacenames
, upops
,
2403 followdependents
=True
2404 if ifupdownflags
.flags
.WITH_DEPENDS
2406 except Exception as e
:
2408 self
.logger
.error(str(e
))
2410 self
._process
_delay
_admin
_state
_queue
('up')
2411 if ifupdownflags
.flags
.DRYRUN
:
2415 if not iface_read_ret
or not ret
:
2418 def reload(self
, *args
, **kargs
):
2419 """ reload interface config """
2420 self
.logger
.debug('reloading interface config ..')
2421 if kargs
.get('currentlyup', False):
2422 self
._reload
_currentlyup
(*args
, **kargs
)
2424 self
._reload
_default
(*args
, **kargs
)
2426 self
.check_running_configuration([], all
=True)
2428 def _any_iface_errors(self
, ifacenames
):
2429 for i
in ifacenames
:
2430 ifaceobjs
= self
.get_ifaceobjs(i
)
2431 if not ifaceobjs
: continue
2432 for ifaceobj
in ifaceobjs
:
2433 if (ifaceobj
.status
== ifaceStatus
.NOTFOUND
or
2434 ifaceobj
.status
== ifaceStatus
.ERROR
):
2438 def _pretty_print_ordered_dict(self
, prefix
, argdict
):
2439 outbuf
= prefix
+ ' {\n'
2440 for k
, vlist
in list(argdict
.items()):
2441 outbuf
+= '\t%s : %s\n' %(k
, str(vlist
))
2442 self
.logger
.debug(outbuf
+ '}')
2444 def print_dependency(self
, ifacenames
, format
):
2445 """ prints iface dependency information """
2448 ifacenames
= list(self
.ifaceobjdict
.keys())
2449 if format
== 'list':
2450 for k
,v
in list(self
.dependency_graph
.items()):
2451 print('%s : %s' %(k
, str(v
)))
2452 elif format
== 'dot':
2454 for i
in list(self
.dependency_graph
.keys()):
2455 indegrees
.update({i
: self
.get_iface_refcnt(i
)})
2456 graph
.generate_dots(self
.dependency_graph
, indegrees
)
2458 def print_ifaceobjs_list(self
, ifacenames
):
2459 for i
in ifacenames
:
2462 def print_ifaceobjs_raw(self
, ifacenames
, format
=None):
2463 """ prints raw lines for ifaces from config file """
2465 if format
== "json":
2466 self
.print_ifaceobjs_pretty(ifacenames
, format
)
2469 for i
in ifacenames
:
2470 for ifaceobj
in self
.get_ifaceobjs(i
):
2471 if self
.is_ifaceobj_builtin(ifaceobj
):
2473 ifaceobj
.dump_raw(self
.logger
)
2474 if (ifupdownflags
.flags
.WITH_DEPENDS
and
2475 not ifupdownflags
.flags
.ALL
):
2476 dlist
= ifaceobj
.lowerifaces
2477 if not dlist
: continue
2478 self
.print_ifaceobjs_raw(dlist
)
2480 def _get_ifaceobjs_pretty(self
, ifacenames
, ifaceobjs
, running
=False):
2481 """ returns iface obj list """
2483 for i
in ifacenames
:
2484 for ifaceobj
in self
.get_ifaceobjs(i
):
2485 if ((not running
and self
.is_ifaceobj_noconfig(ifaceobj
)) or
2486 (running
and not ifaceobj
.is_config_present() and
2487 not self
.is_iface_builtin_byname(i
) and
2488 not ifaceobj
.upperifaces
)):
2490 ifaceobjs
.append(ifaceobj
)
2491 if (ifupdownflags
.flags
.WITH_DEPENDS
and
2492 not ifupdownflags
.flags
.ALL
):
2493 dlist
= ifaceobj
.lowerifaces
2494 if not dlist
: continue
2495 self
._get
_ifaceobjs
_pretty
(dlist
, ifaceobjs
, running
)
2497 def print_ifaceobjs_pretty(self
, ifacenames
, format
='native'):
2498 """ pretty prints iface in format given by keyword arg format """
2501 self
._get
_ifaceobjs
_pretty
(ifacenames
, ifaceobjs
)
2502 if not ifaceobjs
: return
2503 if format
== 'json':
2504 print(json
.dumps(ifaceobjs
, cls
=ifaceJsonEncoder
,
2505 indent
=4, separators
=(',', ': ')))
2507 expand
= int(self
.config
.get('ifquery_ifacename_expand_range', '0'))
2509 if not expand
and (i
.flags
& iface
.IFACERANGE_ENTRY
):
2510 # print only the first one
2511 if i
.flags
& iface
.IFACERANGE_START
:
2512 i
.dump_pretty(use_realname
=True)
2516 def _get_ifaceobjscurr_pretty(self
, ifacenames
, ifaceobjs
):
2518 for i
in ifacenames
:
2519 ifaceobjscurr
= self
.get_ifaceobjcurr(i
)
2520 if not ifaceobjscurr
: continue
2521 for ifaceobj
in ifaceobjscurr
:
2522 if (ifaceobj
.status
== ifaceStatus
.NOTFOUND
or
2523 ifaceobj
.status
== ifaceStatus
.ERROR
):
2525 if self
.is_ifaceobj_noconfig(ifaceobj
):
2527 ifaceobjs
.append(ifaceobj
)
2528 if (ifupdownflags
.flags
.WITH_DEPENDS
and
2529 not ifupdownflags
.flags
.ALL
):
2530 dlist
= ifaceobj
.lowerifaces
2531 if not dlist
: continue
2532 dret
= self
._get
_ifaceobjscurr
_pretty
(dlist
, ifaceobjs
)
2536 def print_ifaceobjscurr_pretty(self
, ifacenames
, format
='native'):
2537 """ pretty prints current running state of interfaces with status.
2539 returns 1 if any of the interface has an error,
2543 ret
= self
._get
_ifaceobjscurr
_pretty
(ifacenames
, ifaceobjs
)
2544 if not ifaceobjs
: return
2546 # override ifaceStatusUserStrs
2547 ifaceStatusUserStrs
.SUCCESS
= self
.config
.get('ifquery_check_success_str', _success_sym
)
2548 ifaceStatusUserStrs
.ERROR
= self
.config
.get('ifquery_check_error_str', _error_sym
)
2549 ifaceStatusUserStrs
.UNKNOWN
= self
.config
.get('ifquery_check_unknown_str', '')
2550 if format
== 'json':
2551 print(json
.dumps(ifaceobjs
, cls
=ifaceJsonEncoderWithStatus
,
2552 indent
=2, separators
=(',', ': ')))
2554 for ifaceobj
in ifaceobjs
:
2555 ifaceobj
.dump_pretty(with_status
=True)
2558 def print_ifaceobjsrunning_pretty(self
, ifacenames
, format
='native'):
2559 """ pretty prints iface running state """
2562 self
._get
_ifaceobjs
_pretty
(ifacenames
, ifaceobjs
, running
=True)
2563 if not ifaceobjs
: return
2564 if format
== 'json':
2565 print(json
.dumps(ifaceobjs
, cls
=ifaceJsonEncoder
, indent
=2,
2566 separators
=(',', ': ')))
2572 print('ifupdown main object dump')
2573 print(self
.pp
.pprint(self
.modules
))
2574 print(self
.pp
.pprint(self
.ifaceobjdict
))
2576 def _dump_ifaceobjs(self
, ifacenames
):
2577 for i
in ifacenames
:
2578 ifaceobjs
= self
.get_ifaceobjs(i
)