]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/ifupdown/ifupdownmain.py
0633dc36ceefaaf73de687a7bc2b6830fc68f26b
[mirror_ifupdown2.git] / ifupdown2 / ifupdown / ifupdownmain.py
1 #!/usr/bin/python
2 #
3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 #
6 # ifupdownMain --
7 # ifupdown main module
8 #
9
10 import pprint
11
12 from collections import OrderedDict
13
14 from ipaddr import IPNetwork, IPv4Network, IPv6Network, IPAddress, IPv4Address, IPv6Address
15
16 try:
17 import ifupdown2.ifupdownaddons.cache
18 import ifupdown2.ifupdownaddons.LinkUtils
19 import ifupdown2.ifupdownaddons.mstpctlutil
20
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
26
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
33 except ImportError:
34 import ifupdownaddons.cache
35 import ifupdownaddons.LinkUtils
36 import ifupdownaddons.mstpctlutil
37
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
43
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
50
51
52 """
53 .. module:: ifupdownmain
54 :synopsis: main module for ifupdown package
55
56 .. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
57
58 """
59
60 _tickmark = u'\u2713'
61 _crossmark = u'\u2717'
62 _success_sym = '(%s)' %_tickmark
63 _error_sym = '(%s)' %_crossmark
64
65 class ifupdownMainFlags():
66 COMPAT_EXEC_SCRIPTS = False
67 STATEMANAGER_ENABLE = True
68 STATEMANAGER_UPDATE = True
69 ADDONS_ENABLE = False
70 DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
71 SCHED_SKIP_CHECK_UPPERIFACES = False
72 CHECK_SHARED_DEPENDENTS = True
73
74 class ifacePrivFlags():
75 # priv flags to mark iface objects
76 BUILTIN = False
77 NOCONFIG = False
78
79 def __init__(self, builtin=False, noconfig=False):
80 self.BUILTIN = builtin
81 self.NOCONFIG = noconfig
82
83 class ifupdownMain(ifupdownBase):
84 """ ifupdown2 main class """
85
86 scripts_dir = '/etc/network'
87 addon_modules_dir = ADDON_MODULES_DIR
88 addon_modules_configfile = ADDONS_CONF_PATH
89
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:
95 return
96 if ((ifaceobj.link_kind & ifaceLinkKind.VRF) or
97 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE)):
98 self._keep_link_down(ifaceobj)
99 return
100 if self._delay_admin_state:
101 self._delay_admin_state_iface_queue.append(ifaceobj.name)
102 return
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:
108 return
109 if not self.link_exists(ifaceobj.name):
110 return
111 if self._keep_link_down(ifaceobj):
112 return
113 try:
114 self.link_up(ifaceobj.name)
115 except:
116 if ifaceobj.addr_method == 'manual':
117 pass
118 else:
119 raise
120
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)
127 return True
128 return False
129
130 def run_down(self, ifaceobj):
131 if ((ifaceobj.link_kind & ifaceLinkKind.VRF) or
132 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE)):
133 return
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:
137 return
138 if self._delay_admin_state:
139 self._delay_admin_state_iface_queue.append(ifaceobj.name)
140 return
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:
146 return
147 if not self.link_exists(ifaceobj.name):
148 return
149 try:
150 self.link_down(ifaceobj.name)
151 except:
152 if ifaceobj.addr_method == 'manual':
153 pass
154 else:
155 raise
156
157 # ifupdown object interface operation handlers
158 ops_handlers = OrderedDict([('up', run_up),
159 ('down', run_down)])
160
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)):
164 return
165 if self.flags.STATEMANAGER_UPDATE:
166 self.statemanager.ifaceobj_sync(ifaceobj, op)
167
168 # ifupdown object interface scheduler pre and posthooks
169 sched_hooks = {'posthook' : run_sched_ifaceobj_posthook}
170
171 def reset_ifupdown2(self):
172 ifaceScheduler.reset()
173
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()
180
181 ifupdown2.ifupdownaddons.cache.linkCache.reset()
182 ifupdown2.ifupdownaddons.cache.MSTPAttrsCache.invalidate()
183
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',
191 withdefaults=False):
192 """This member function initializes the ifupdownmain object.
193
194 Kwargs:
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'
201
202 Raises:
203 AttributeError, KeyError """
204
205 if daemon:
206 self.reset_ifupdown2()
207
208 # iface dictionary in the below format:
209 # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
210 # eg:
211 # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
212 #
213 # Each ifaceobject corresponds to a configuration block for
214 # that interface
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()
219
220 # iface dictionary representing the curr running state of an iface
221 # in the below format:
222 # {'<ifacename>' : <ifaceobject>}
223 self.ifaceobjcurrdict = OrderedDict()
224
225 # Dictionary representing operation and modules
226 # for every operation
227 self.module_ops = OrderedDict([('pre-up', []),
228 ('up', []),
229 ('post-up', []),
230 ('query-checkcurr', []),
231 ('query-running', []),
232 ('query-dependency', []),
233 ('query', []),
234 ('query-raw', []),
235 ('pre-down', []),
236 ('down', []),
237 ('post-down', [])])
238
239 # For old style /etc/network/ bash scripts
240 self.script_ops = OrderedDict([('pre-up', []),
241 ('up', []),
242 ('post-up', []),
243 ('pre-down', []),
244 ('down', []),
245 ('post-down', [])])
246
247
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
256
257 # Can be used to provide hints for caching
258 ifupdownflags.flags.CACHE_FLAGS = 0x0
259
260 self.flags = ifupdownMainFlags()
261
262 self.flags.STATEMANAGER_ENABLE = statemanager_enable
263 self.interfacesfile = interfacesfile
264 self.interfacesfileiobuf = interfacesfileiobuf
265 self.interfacesfileformat = interfacesfileformat
266 self.config = config
267 self.logger.debug(self.config)
268 self.blacklisted_ifaces_present = False
269
270 self.type = ifaceType.UNKNOWN
271
272 self.flags.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
273 self.flags.ADDONS_ENABLE = addons_enable
274
275 self.ifaces = OrderedDict()
276 self.njobs = njobs
277 self.pp = pprint.PrettyPrinter(indent=4)
278 self.modules = OrderedDict({})
279 self.module_attrs = {}
280 self.overridden_ifupdown_scripts = []
281
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({})
287
288 self._cache_no_repeats = {}
289
290 if self.flags.STATEMANAGER_ENABLE:
291 self.statemanager = statemanager.statemanager_api
292 try:
293 self.statemanager.read_saved_state()
294 except Exception, e:
295 # if read_saved_state fails, state file might be corrupt.
296 # Ignore old state and continue
297 self.logger.warning('error reading state (%s)' %str(e))
298 else:
299 self.flags.STATEMANAGER_UPDATE = False
300 self._delay_admin_state = True if self.config.get(
301 'delay_admin_state_change', '0') == '1' else False
302 self._delay_admin_state_iface_queue = []
303 if self._delay_admin_state:
304 self.logger.info('\'delay_admin_state_change\' is set. admin ' +
305 'state changes will be delayed till the end.')
306
307 self._link_master_slave = True if self.config.get(
308 'link_master_slave', '0') == '1' else False
309 if self._link_master_slave:
310 self.logger.info('\'link_master_slave\' is set. slave admin ' +
311 'state changes will be delayed till the ' +
312 'masters admin state change.')
313
314 # squash iface objects for same interface both internal and
315 # external representation. It is off by default.
316 self._ifaceobj_squash = True if self.config.get(
317 'ifaceobj_squash', '0') == '1' else False
318
319 # squash iface objects for same interface internal
320 # representation only. External representation as seen by ifquery
321 # will continue to see multiple iface stanzas if it was specified
322 # that way by the user. It is on by default.
323 self._ifaceobj_squash_internal = True if self.config.get(
324 'ifaceobj_squash_internal', '1') == '1' else False
325
326 # initialize global config object with config passed by the user
327 # This makes config available to addon modules
328 ifupdownConfig.config = self.config
329
330 self.validate_keywords = {
331 '<mac>': self._keyword_mac,
332 '<text>': self._keyword_text,
333 '<ipv4>': self._keyword_ipv4,
334 '<ipv6>': self._keyword_ipv6,
335 '<ip>': self._keyword_ip,
336 '<number>': self._keyword_number,
337 '<interface>': self._keyword_interface,
338 '<ipv4-vrf-text>': self._keyword_ipv4_vrf_text,
339 '<number-ipv4-list>': self._keyword_number_ipv4_list,
340 '<interface-list>': self._keyword_interface_list,
341 '<ipv4/prefixlen>': self._keyword_ipv4_prefixlen,
342 '<ipv6/prefixlen>': self._keyword_ipv6_prefixlen,
343 '<ip/prefixlen>': self._keyword_ip_prefixlen,
344 '<number-range-list>': self._keyword_number_range_list,
345 '<number-comma-range-list>': self._keyword_number_comma_range_list,
346 '<interface-range-list>': self._keyword_interface_range_list,
347 '<interface-range-list-multiple-of-16>': self._keyword_interface_range_list_multiple_of_16,
348 '<mac-ip/prefixlen-list>': self._keyword_mac_ip_prefixlen_list,
349 '<number-interface-list>': self._keyword_number_interface_list,
350 '<interface-yes-no-list>': self._keyword_interface_yes_no_list,
351 '<interface-on-off-list>': self._keyword_interface_on_off_list,
352 '<interface-yes-no-0-1-list>': self._keyword_interface_yes_no_0_1_list,
353 '<interface-disabled-automatic-enabled>': self._keyword_interface_disabled_automatic_enabled_list,
354 '<interface-yes-no-auto-list>': self._keyword_interface_yes_no_auto_list,
355 '<interface-l2protocol-tunnel-list>': self._keyword_interface_l2protocol_tunnel_list
356 }
357
358 def link_master_slave_ignore_error(self, errorstr):
359 # If link master slave flag is set,
360 # there may be cases where the lowerdev may not be
361 # up resulting in 'Network is down' error
362 # This can happen if the lowerdev is a LINK_SLAVE
363 # of another interface which is not up yet
364 # example of such a case:
365 # bringing up a vlan on a bond interface and the bond
366 # is a LINK_SLAVE of a bridge (in other words the bond is
367 # part of a bridge) which is not up yet
368 if self._link_master_slave:
369 if 'Network is down' in errorstr:
370 return True
371 return False
372
373 def get_ifaceobjs(self, ifacename):
374 return self.ifaceobjdict.get(ifacename)
375
376 def get_ifaceobjs_saved(self, ifacename):
377 """ Return ifaceobjects from statemanager """
378 if self.flags.STATEMANAGER_ENABLE:
379 return self.statemanager.get_ifaceobjs(ifacename)
380 else:
381 return None
382
383 def get_ifaceobj_first(self, ifacename):
384 ifaceobjs = self.get_ifaceobjs(ifacename)
385 if ifaceobjs:
386 return ifaceobjs[0]
387 return None
388
389 def get_ifacenames(self):
390 return self.ifaceobjdict.keys()
391
392 def get_iface_obj_last(self, ifacename):
393 return self.ifaceobjdict.get(ifacename)[-1]
394
395
396 def must_follow_upperifaces(self, ifacename):
397 #
398 # XXX: This bleeds the knowledge of iface
399 # types in the infrastructure module.
400 # Cant think of a better fix at the moment.
401 # In future maybe the module can set a flag
402 # to indicate if we should follow upperifaces
403 #
404 ifaceobj = self.get_ifaceobj_first(ifacename)
405 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
406 return False
407 return True
408
409 def create_n_save_ifaceobj(self, ifacename, priv_flags=None,
410 increfcnt=False):
411 """ creates a iface object and adds it to the iface dictionary """
412 ifaceobj = iface()
413 ifaceobj.name = ifacename
414 ifaceobj.priv_flags = priv_flags
415 ifaceobj.auto = True
416 if not self._link_master_slave:
417 ifaceobj.link_type = ifaceLinkType.LINK_NA
418 if increfcnt:
419 ifaceobj.inc_refcnt()
420 self.ifaceobjdict[ifacename] = [ifaceobj]
421 return ifaceobj
422
423 def create_n_save_ifaceobjcurr(self, ifaceobj):
424 """ creates a copy of iface object and adds it to the iface
425 dict containing current iface objects
426 """
427 ifaceobjcurr = iface()
428 ifaceobjcurr.name = ifaceobj.name
429 ifaceobjcurr.type = ifaceobj.type
430 ifaceobjcurr.lowerifaces = ifaceobj.lowerifaces
431 ifaceobjcurr.priv_flags = copy.deepcopy(ifaceobj.priv_flags)
432 ifaceobjcurr.auto = ifaceobj.auto
433 self.ifaceobjcurrdict.setdefault(ifaceobj.name,
434 []).append(ifaceobjcurr)
435 return ifaceobjcurr
436
437 def get_ifaceobjcurr(self, ifacename, idx=0):
438 ifaceobjlist = self.ifaceobjcurrdict.get(ifacename)
439 if not ifaceobjlist:
440 return None
441 if not idx:
442 return ifaceobjlist
443 else:
444 return ifaceobjlist[idx]
445
446 def get_ifaceobjrunning(self, ifacename):
447 return self.ifaceobjrunningdict.get(ifacename)
448
449 def get_iface_refcnt(self, ifacename):
450 """ Return iface ref count """
451 max = 0
452 ifaceobjs = self.get_ifaceobjs(ifacename)
453 if not ifaceobjs:
454 return 0
455 for i in ifaceobjs:
456 if i.refcnt > max:
457 max = i.refcnt
458 return max
459
460 def is_iface_builtin_byname(self, ifacename):
461 """ Returns true if iface name is a builtin interface.
462
463 A builtin interface is an interface which ifupdown understands.
464 The following are currently considered builtin ifaces:
465 - vlan interfaces in the format <ifacename>.<vlanid>
466 """
467 return '.' in ifacename
468
469 def is_ifaceobj_builtin(self, ifaceobj):
470 """ Returns true if iface name is a builtin interface.
471
472 A builtin interface is an interface which ifupdown understands.
473 The following are currently considered builtin ifaces:
474 - vlan interfaces in the format <ifacename>.<vlanid>
475 """
476 if (ifaceobj.priv_flags and ifaceobj.priv_flags.BUILTIN):
477 return True
478 return False
479
480 def is_ifaceobj_noconfig(self, ifaceobj):
481 """ Returns true if iface object did not have a user defined config.
482
483 These interfaces appear only when they are dependents of interfaces
484 which have user defined config
485 """
486 return (ifaceobj.priv_flags and ifaceobj.priv_flags.NOCONFIG)
487
488 def is_iface_noconfig(self, ifacename):
489 """ Returns true if iface has no config """
490
491 ifaceobj = self.get_ifaceobj_first(ifacename)
492 if not ifaceobj: return True
493 return self.is_ifaceobj_noconfig(ifaceobj)
494
495 def check_shared_dependents(self, ifaceobj, dlist):
496 """ ABSOLETE: Check if dlist intersects with any other
497 interface with slave dependents.
498 example: bond and bridges.
499 This function logs such errors """
500 setdlist = Set(dlist)
501 for ifacename, ifacedlist in self.dependency_graph.items():
502 if not ifacedlist:
503 continue
504 check_depends = False
505 iobjs = self.get_ifaceobjs(ifacename)
506 if not iobjs:
507 continue
508 for i in iobjs:
509 if (i.dependency_type == ifaceDependencyType.MASTER_SLAVE):
510 check_depends = True
511 if check_depends:
512 common = Set(ifacedlist).intersection(setdlist)
513 if common:
514 self.logger.error('misconfig..?. iface %s and %s '
515 %(ifaceobj.name, ifacename) +
516 'seem to share dependents/ports %s' %str(list(common)))
517
518 def _set_iface_role(self, ifaceobj, role, upperifaceobj):
519 if (self.flags.CHECK_SHARED_DEPENDENTS and
520 (ifaceobj.role & ifaceRole.SLAVE) and
521 (role == ifaceRole.SLAVE) and (upperifaceobj.role & ifaceRole.MASTER)):
522 self.logger.error("misconfig..? %s %s is enslaved to multiple interfaces %s"
523 %(ifaceobj.name,
524 ifaceLinkPrivFlags.get_all_str(ifaceobj.link_privflags), str(ifaceobj.upperifaces)))
525 ifaceobj.set_status(ifaceStatus.ERROR)
526 return
527 ifaceobj.role = role
528
529 def _set_iface_role_n_kind(self, ifaceobj, upperifaceobj):
530 if (upperifaceobj.link_kind & ifaceLinkKind.BOND):
531 self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
532 ifaceobj.link_privflags |= ifaceLinkPrivFlags.BOND_SLAVE
533
534 if (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE):
535 self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
536 ifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_PORT
537
538 if (ifaceobj.link_kind & ifaceLinkKind.VXLAN) \
539 and (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE):
540 upperifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_VXLAN
541
542 # vrf masters get processed after slaves, which means
543 # check both link_kind vrf and vrf slave
544 if ((upperifaceobj.link_kind & ifaceLinkKind.VRF) or
545 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE)):
546 self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
547 ifaceobj.link_privflags |= ifaceLinkPrivFlags.VRF_SLAVE
548 if self._link_master_slave:
549 if upperifaceobj.link_type == ifaceLinkType.LINK_MASTER:
550 ifaceobj.link_type = ifaceLinkType.LINK_SLAVE
551 else:
552 upperifaceobj.link_type = ifaceLinkType.LINK_NA
553 ifaceobj.link_type = ifaceLinkType.LINK_NA
554
555 def dump_iface_dependency_info(self):
556 """ debug funtion to print raw dependency
557 info - lower and upper devices"""
558
559 for ifacename, ifaceobjs in self.ifaceobjdict.iteritems():
560 iobj = ifaceobjs[0]
561 self.logger.info("%s: refcnt: %d, lower: %s, upper: %s" %(ifacename,
562 self.get_iface_refcnt(ifacename),
563 str(iobj.lowerifaces) if iobj.lowerifaces else [],
564 str(iobj.upperifaces) if iobj.upperifaces else []))
565
566
567 def preprocess_dependency_list(self, upperifaceobj, dlist, ops):
568 """ We go through the dependency list and
569 delete or add interfaces from the interfaces dict by
570 applying the following rules:
571 if flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
572 we only consider devices whose configuration was
573 specified in the network interfaces file. We delete
574 any interface whose config was not specified except
575 for vlan devices. vlan devices get special treatment.
576 Even if they are not present they are created and added
577 to the ifacesdict
578 elif flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
579 we create objects for all dependent devices that are not
580 present in the ifacesdict
581 """
582 del_list = []
583
584 for d in dlist:
585 dilist = self.get_ifaceobjs(d)
586 if not dilist:
587 ni = None
588 if self.is_iface_builtin_byname(d):
589 ni = self.create_n_save_ifaceobj(d,
590 ifacePrivFlags(True, True), True)
591 elif not self.flags.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG:
592 ni = self.create_n_save_ifaceobj(d,
593 ifacePrivFlags(False, True), True)
594 else:
595 del_list.append(d)
596 if ni:
597 ni.add_to_upperifaces(upperifaceobj.name)
598 self._set_iface_role_n_kind(ni, upperifaceobj)
599 else:
600 for di in dilist:
601 di.inc_refcnt()
602 di.add_to_upperifaces(upperifaceobj.name)
603 self._set_iface_role_n_kind(di, upperifaceobj)
604 for d in del_list:
605 dlist.remove(d)
606
607 def preprocess_upperiface(self, lowerifaceobj, ulist, ops):
608 for u in ulist:
609 if (lowerifaceobj.upperifaces and
610 u in lowerifaceobj.upperifaces):
611 continue
612 lowerifaceobj.add_to_upperifaces(u)
613 uifacelist = self.get_ifaceobjs(u)
614 if uifacelist:
615 for ui in uifacelist:
616 lowerifaceobj.inc_refcnt()
617 self._set_iface_role_n_kind(lowerifaceobj, ui)
618 ui.add_to_lowerifaces(lowerifaceobj.name)
619
620 def query_lowerifaces(self, ifaceobj, ops, ifacenames, type=None):
621 """ Gets iface dependents by calling into respective modules """
622 ret_dlist = []
623
624 # Get dependents for interface by querying respective modules
625 for module in self.modules.values():
626 try:
627 if ops[0] == 'query-running':
628 if (not hasattr(module,
629 'get_dependent_ifacenames_running')):
630 continue
631 dlist = module.get_dependent_ifacenames_running(ifaceobj)
632 else:
633 if (not hasattr(module, 'get_dependent_ifacenames')):
634 continue
635 dlist = module.get_dependent_ifacenames(ifaceobj,
636 ifacenames)
637 except Exception, e:
638 self.logger.warn('%s: error getting dependent interfaces (%s)'
639 %(ifaceobj.name, str(e)))
640 dlist = None
641 pass
642 if dlist: ret_dlist.extend(dlist)
643 return list(set(ret_dlist))
644
645 def query_upperifaces(self, ifaceobj, ops, ifacenames, type=None):
646 """ Gets iface upperifaces by calling into respective modules """
647 ret_ulist = []
648
649 # Get upperifaces for interface by querying respective modules
650 for module in self.modules.values():
651 try:
652 if ops[0] == 'query-running':
653 if (not hasattr(module,
654 'get_upper_ifacenames_running')):
655 continue
656 ulist = module.get_upper_ifacenames_running(ifaceobj)
657 else:
658 if (not hasattr(module, 'get_upper_ifacenames')):
659 continue
660 ulist = module.get_upper_ifacenames(ifaceobj, ifacenames)
661 except Exception, e:
662 self.logger.warn('%s: error getting upper interfaces (%s)'
663 %(ifaceobj.name, str(e)))
664 ulist = None
665 pass
666 if ulist: ret_ulist.extend(ulist)
667 return list(set(ret_ulist))
668
669 def populate_dependency_info(self, ops, ifacenames=None):
670 """ recursive function to generate iface dependency info """
671
672 if not ifacenames:
673 ifacenames = self.ifaceobjdict.keys()
674
675 iqueue = deque(ifacenames)
676 while iqueue:
677 i = iqueue.popleft()
678 # Go through all modules and find dependent ifaces
679 dlist = None
680 ulist = None
681 ifaceobjs = self.get_ifaceobjs(i)
682 if not ifaceobjs:
683 continue
684 dependents_processed = False
685
686 # Store all dependency info in the first ifaceobj
687 # but get dependency info from all ifaceobjs
688 ifaceobj = ifaceobjs[0]
689 for iobj in ifaceobjs:
690 ulist = self.query_upperifaces(iobj, ops, ifacenames)
691 if iobj.lowerifaces:
692 dependents_processed = True
693 break
694 dlist = self.query_lowerifaces(iobj, ops, ifacenames)
695 if dlist:
696 break
697 if ulist:
698 self.preprocess_upperiface(ifaceobj, ulist, ops)
699 if dependents_processed:
700 continue
701 if dlist:
702 self.preprocess_dependency_list(ifaceobj,
703 dlist, ops)
704 ifaceobj.lowerifaces = dlist
705 [iqueue.append(d) for d in dlist]
706 #if not self.dependency_graph.get(i):
707 # self.dependency_graph[i] = dlist
708
709 for i in self.ifaceobjdict.keys():
710 iobj = self.get_ifaceobj_first(i)
711 if (not iobj.link_kind and
712 not (iobj.link_privflags & ifaceLinkPrivFlags.LOOPBACK) and
713 iobj.name == 'lo'):
714 iobj.link_privflags |= ifaceLinkPrivFlags.LOOPBACK
715 if iobj.lowerifaces:
716 self.dependency_graph[i] = iobj.lowerifaces
717 else:
718 self.dependency_graph[i] = []
719
720 if not self.blacklisted_ifaces_present:
721 return
722
723 # Walk through the dependency graph and remove blacklisted
724 # interfaces that were picked up as dependents
725 for i in self.dependency_graph.keys():
726 ifaceobj = self.get_ifaceobj_first(i)
727 if not ifaceobj:
728 continue
729
730 if ifaceobj.blacklisted and not ifaceobj.upperifaces:
731 # if blacklisted and was not picked up as a
732 # dependent of a upper interface, delete the
733 # interface from the dependency graph
734 dlist = ifaceobj.lowerifaces
735 if dlist:
736 for d in dlist:
737 difaceobjs = self.get_ifaceobjs(d)
738 if not difaceobjs:
739 continue
740 try:
741 for d in difaceobjs:
742 d.dec_refcnt()
743 d.upperifaces.remove(i)
744 except:
745 self.logger.debug('error removing %s from %s upperifaces' %(i, d))
746 pass
747 self.logger.debug("populate_dependency_info: deleting blacklisted interface %s" %i)
748 del self.dependency_graph[i]
749 continue
750
751 def _check_config_no_repeats(self, ifaceobj):
752 """ check if object has an attribute that is
753 restricted to a single object in the system.
754 if yes, warn and return """
755 for k,v in self._cache_no_repeats.items():
756 iv = ifaceobj.config.get(k)
757 if iv and iv[0] == v:
758 self.logger.error('ignoring interface %s. ' %ifaceobj.name +
759 'Only one object with attribute ' +
760 '\'%s %s\' allowed.' %(k, v))
761 return True
762 for k, v in self.config.get('no_repeats', {}).items():
763 iv = ifaceobj.config.get(k)
764 if iv and iv[0] == v:
765 self._cache_no_repeats[k] = v
766 return False
767
768 def _save_iface_squash(self, ifaceobj):
769 """ squash ifaceobjects belonging to same iface
770 into a single object """
771 if self._check_config_no_repeats(ifaceobj):
772 return
773 ifaceobj.priv_flags = ifacePrivFlags()
774 if not self._link_master_slave:
775 ifaceobj.link_type = ifaceLinkType.LINK_NA
776 currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
777 if not currentifaceobjlist:
778 self.ifaceobjdict[ifaceobj.name] = [ifaceobj]
779 return
780 if ifaceobj.compare(currentifaceobjlist[0]):
781 self.logger.warn('duplicate interface %s found' %ifaceobj.name)
782 return
783 for obj in self.ifaceobjdict[ifaceobj.name]:
784 if obj.type == ifaceobj.type:
785 obj.squash(ifaceobj)
786 return
787 self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
788
789 def _save_iface(self, ifaceobj):
790 if self._check_config_no_repeats(ifaceobj):
791 return
792 ifaceobj.priv_flags = ifacePrivFlags()
793 if not self._link_master_slave:
794 ifaceobj.link_type = ifaceLinkType.LINK_NA
795 currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
796 if not currentifaceobjlist:
797 self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
798 if not self._ifaceobj_squash:
799 ifaceobj.flags |= ifaceobj.YOUNGEST_SIBLING
800 return
801 if ifaceobj.compare(currentifaceobjlist[0]):
802 self.logger.warn('duplicate interface %s found' %ifaceobj.name)
803 return
804 if currentifaceobjlist[0].type == ifaceobj.type:
805 currentifaceobjlist[0].flags |= ifaceobj.HAS_SIBLINGS
806 ifaceobj.flags |= ifaceobj.HAS_SIBLINGS
807 # clear the OLDEST_SIBLING from all the siblings
808 for iface in self.ifaceobjdict[ifaceobj.name]:
809 iface.flags &= ~ifaceobj.OLDEST_SIBLING
810 # current sibling is the oldest
811 ifaceobj.flags |= ifaceobj.OLDEST_SIBLING
812 self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
813
814 def _keyword_text(self, value, validrange=None):
815 return isinstance(value, str) and len(value) > 0
816
817 def _keyword_mac(self, value, validrange=None):
818 if value.strip().startswith('ether'):
819 value = value.strip()[6:]
820 return re.match('[0-9a-f]{1,2}([-:])[0-9a-f]{1,2}(\\1[0-9a-f]{1,2}){4}$',
821 value.lower())
822
823 def _keyword_check_list(self, _list, obj, limit=None):
824 try:
825 if limit and limit > 0:
826 for i in xrange(0, limit):
827 obj(_list[i])
828 return len(_list) == limit
829 else:
830 for elem in _list:
831 obj(elem)
832 return True
833 except Exception as e:
834 self.logger.debug('keyword: check list: %s' % str(e))
835 return False
836
837 def _keyword_ipv4(self, value, validrange=None):
838 return self._keyword_check_list(value.split(), IPv4Address, limit=1)
839
840 def _keyword_ipv4_prefixlen(self, value, validrange=None):
841 return self._keyword_check_list(value.split(), IPv4Network, limit=1)
842
843 def _keyword_ipv6(self, value, validrange=None):
844 return self._keyword_check_list(value.split(), IPv6Address, limit=1)
845
846 def _keyword_ipv6_prefixlen(self, value, validrange=None):
847 return self._keyword_check_list(value.split(), IPv6Network, limit=1)
848
849 def _keyword_ip(self, value, validrange=None):
850 return self._keyword_check_list(value.split(), IPAddress, limit=1)
851
852 def _keyword_ip_prefixlen(self, value, validrange=None):
853 return self._keyword_check_list(value.split(), IPNetwork, limit=1)
854
855 def _keyword_mac_ip_prefixlen_list(self, value, validrange=None):
856 """
857 <mac> <ip> [<ip> ...]
858 ex: address-virtual 00:11:22:33:44:01 11.0.1.1/24 11.0.1.2/24
859 """
860 try:
861 res = value.split()
862 if len(res) < 2:
863 return False
864 if not self._keyword_mac(res[0]):
865 return False
866 for ip in res[1:]:
867 if not self._keyword_ip_prefixlen(ip):
868 return False
869 return True
870 except Exception as e:
871 self.logger.debug('keyword: mac ipaddr prefixlen: %s' % str(e))
872 return False
873
874 def _keyword_number_ipv4_list(self, value, validrange=None):
875 """
876 <number>=<ipv4> [<number>=<ipv4> ...]
877 ex: bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1
878 """
879 try:
880 elements = value.split(' ')
881 if not elements:
882 return False
883 for elem in elements:
884 v = elem.split('=')
885 int(v[0])
886 IPv4Address(v[1])
887 return True
888 except Exception as e:
889 self.logger.debug('keyword: number ipv4: %s' % str(e))
890 return False
891
892 def _keyword_interface(self, ifacename, validrange=None):
893 return self.get_ifaceobjs(ifacename)
894
895 def _keyword_ipv4_vrf_text(self, value, validrange=None):
896 """
897 <ipv4> "vrf" <text>
898 ex: clagd-backup-ip 10.10.10.42 vrf blue
899 """
900 values = value.split()
901 size = len(values)
902
903 if size > 3 or size < 1:
904 return False
905 try:
906 IPv4Address(values[0])
907 if size > 1:
908 if values[1] != 'vrf':
909 return False
910 if size > 2:
911 if not self._keyword_text(values[2]):
912 return False
913 return True
914 except Exception as e:
915 self.logger.debug('keyword: ipv4 vrf text: %s' % str(e))
916 return False
917
918 def _keyword_interface_list_with_value(self, value, validvals):
919 values = value.split()
920 try:
921 if len(values) == 1:
922 if values[0] in validvals:
923 return True
924 for v in values:
925 iface_value = v.split('=')
926 size = len(iface_value)
927 if size != 2:
928 if iface_value[0] == 'glob' or iface_value[0] == 'regex':
929 continue
930 return False
931 if not iface_value[1] in validvals:
932 return False
933 return True
934 except Exception as e:
935 self.logger.debug('keyword: interface list with value: %s' % str(e))
936 return False
937
938 def _keyword_interface_on_off_list(self, value, validrange=None):
939 """
940 <yes|no> | ( <interface>=<on|off> [<interface>=<on|off> ...] )
941 ex: bridge-learning swp1=on swp2=off
942 """
943 return self._keyword_interface_list_with_value(value, ['on', 'off'])
944
945 def _keyword_interface_yes_no_list(self, value, validrange=None):
946 """
947 <yes|no> | ( <interface>=<yes|no> [<interface>=<yes|no> ...] )
948 ex: mstpctl-portrestrrole swp1=yes swp2=no
949 """
950 return self._keyword_interface_list_with_value(value, ['yes', 'no'])
951
952 def _keyword_interface_yes_no_auto_list(self, value, validrange=None):
953 """
954 <yes|no|auto> |
955 ( <interface>=<yes|no|auto> [<interface>=<yes|no|auto> ...] )
956 ex: mstpctl-portp2p swp1=yes swp2=no swp3=auto
957 """
958 return self._keyword_interface_list_with_value(value,
959 ['yes', 'no', 'auto'])
960
961 def _keyword_interface_l2protocol_tunnel_list(self, value, validrange=None):
962 """
963 bridge-l2protocol-tunnel swpX=lacp,stp swpY=cdp swpZ=all
964 bridge-l2protocol-tunnel lacp stp,lldp,cdp
965 bridge-l2protocol-tunnel stp lacp cdp
966 bridge-l2protocol-tunnel lldp pvst
967 bridge-l2protocol-tunnel stp
968 bridge-l2protocol-tunnel all
969 """
970 try:
971 if '=' in value:
972 for intf_arg in value.split():
973 intf_arg_split = intf_arg.split('=')
974 for arg in re.split(',|\s*', intf_arg_split[1]):
975 if arg not in ['all', 'stp', 'lldp', 'lacp', 'cdp', 'pvst']:
976 return False
977 else:
978 for arg in re.split(',|\s*', value):
979 if arg not in ['all', 'stp', 'lldp', 'lacp', 'cdp', 'pvst']:
980 return False
981 except:
982 return False
983 return True
984
985 def _keyword_interface_yes_no_0_1_list(self, value, validrange=None):
986 """
987 <yes|no|0|1> |
988 ( <interface>=<yes|no|0|1> [<interface>=<yes|no|0|1> ...] )
989 ex: bridge-portmcrouter swp1=yes swp2=yes swp3=1
990 """
991 return self._keyword_interface_list_with_value(value,
992 ['yes', 'no', '1', '0', '2'])
993
994 def _keyword_interface_disabled_automatic_enabled_list(self, value, validrange=None):
995 return self._keyword_interface_list_with_value(value, [
996 '0', 'disabled', 'no',
997 '1', 'automatic', 'yes',
998 '2', 'enabled'])
999
1000 def _keyword_interface_range_list_multiple_of_16(self, value, validrange):
1001 return self._keyword_interface_range_list(value, validrange, multiple=16)
1002
1003 def _keyword_interface_range_list(self, value, validrange, multiple=None):
1004 """
1005 <number> | ( <interface>=<number> [ <interface>=number> ...] )
1006 ex: mstpctl-portpathcost swp1=0 swp2=1
1007 """
1008 values = value.split()
1009 try:
1010 if len(values) == 1 and '=' not in values[0]:
1011 try:
1012 n = int(values[0])
1013 if n < int(validrange[0]) or n > int(
1014 validrange[1]):
1015 raise invalidValueError('value of out range "%s":'
1016 ' valid attribute range: %s'
1017 % (values[0],
1018 '-'.join(validrange)))
1019
1020 if multiple is not None:
1021 if not (n % multiple == 0):
1022 raise invalidValueError('invalid value %s: must be a multiple of %s' % (n, multiple))
1023
1024 return True
1025 except invalidValueError as e:
1026 raise e
1027 except Exception as e:
1028 self.logger.debug('keyword: interface range list: %s'
1029 % str(e))
1030 return False
1031 for v in values:
1032 iface_value = v.split('=')
1033 size = len(iface_value)
1034 if size != 2:
1035 return False
1036 number = int(iface_value[1])
1037 if number < int(validrange[0]) or number > int(
1038 validrange[1]):
1039 raise invalidValueError(
1040 'value of out range "%s" for iface "%s":'
1041 ' valid attribute range: %s'
1042 % (iface_value[1],
1043 iface_value[0],
1044 '-'.join(validrange)))
1045
1046 if multiple is not None:
1047 if not (number % multiple == 0):
1048 raise invalidValueError('invalid value %s: must be a multiple of %s' % (number, multiple))
1049
1050 return True
1051 except invalidValueError as e:
1052 raise e
1053 except Exception as e:
1054 self.logger.debug('keyword: interface range list: %s' % str(e))
1055 return False
1056
1057 def _keyword_interface_list(self, value, validrange=None):
1058 """
1059 [glob|regex] <interface> [ [glob|regex] <interface> ...]
1060 ex: bridge-ports swp1 swp2 glob swp3-5.100 regex (swp[6|7|8].100)
1061 """
1062 interface_list = value.split()
1063 size = len(interface_list)
1064 i = 0
1065 while i < size:
1066 if interface_list[i] == 'glob' or interface_list[i] == 'regex':
1067 i += 1
1068 else:
1069 if not self._keyword_interface(interface_list[i]):
1070 return False
1071 i += 1
1072 return True
1073
1074 def _keyword_number_range_list(self, value, validrange=None):
1075 """
1076 <number> [<number>-<number>]
1077 ex: bridge-vids 42 100-200
1078 """
1079 number_list = value.split()
1080 try:
1081 i = 0
1082 while i < len(number_list):
1083 if '-' in number_list[i]:
1084 range = number_list[i].split('-')
1085 a = int(range[0])
1086 b = int(range[1])
1087 if a > b:
1088 return False
1089 else:
1090 int(number_list[i])
1091 i += 1
1092 return True
1093 except Exception as e:
1094 self.logger.debug('keyword: number range list: %s' % str(e))
1095 return False
1096
1097 def _keyword_number_interface_list(self, value, validrange=None):
1098 """
1099 <number> <interface> [<interface>... [<number> <interface> ... ]]
1100 bridge-waitport 42 swp1 swp2 swp3 9 swp4
1101 """
1102 interface_list = value.split()
1103 if not interface_list:
1104 return False
1105 try:
1106 int(interface_list[0])
1107 prev = True
1108 for elem in interface_list[1:]:
1109 try:
1110 int(elem)
1111 if prev:
1112 return False
1113 prev = True
1114 except:
1115 prev = False
1116 return not prev
1117 except Exception as e:
1118 self.logger.debug('keyword: number interface list: %s' % str(e))
1119 return False
1120
1121 def _keyword_number(self, value, validrange=None):
1122 try:
1123 int(value)
1124 return True
1125 except Exception as e:
1126 self.logger.debug('keyword: number: %s' % str(e))
1127 return False
1128
1129 def _is_keyword(self, value):
1130 if isinstance(value, tuple):
1131 return True
1132 keyword_found = value in self.validate_keywords
1133 if value.startswith('<') and value.endswith('>') and not keyword_found:
1134 raise Exception('%s: invalid keyword, please make sure to use'
1135 ' a valid keyword see `ifquery -s`' % value)
1136 return keyword_found
1137
1138 def _check_validvals_value(self, attrname, value, validvals, validrange):
1139 if validvals and value not in validvals:
1140 is_valid = False
1141 for keyword in validvals:
1142 if self._is_keyword(keyword):
1143 if validrange:
1144 if self.validate_keywords[keyword](value, validrange):
1145 return {'result': True}
1146 else:
1147 if self.validate_keywords[keyword](value):
1148 return {'result': True}
1149 if not is_valid:
1150 return {
1151 'result': False,
1152 'message': 'invalid value "%s": valid attribute values: %s'
1153 % (value, validvals)
1154 }
1155 elif validvals and value in validvals:
1156 pass
1157 elif validrange:
1158 if len(validrange) != 2:
1159 raise Exception('%s: invalid range in addon configuration'
1160 % '-'.join(validrange))
1161 _value = int(value)
1162 if _value < int(validrange[0]) or _value > int(validrange[1]):
1163 return {
1164 'result': False,
1165 'message': 'value of out range "%s": '
1166 'valid attribute range: %s'
1167 % (value, '-'.join(validrange))
1168 }
1169 return {'result': True}
1170
1171 def _check_validvals(self, ifacename, module_name, attrs):
1172 ifaceobj = self.get_ifaceobjs(ifacename)
1173 if not ifaceobj:
1174 return
1175 success = True
1176 for attrname, attrvalue in ifaceobj[0].config.items():
1177 try:
1178 attrname_dict = attrs.get(attrname, {})
1179 validvals = attrname_dict.get('validvals', [])
1180 validrange = attrname_dict.get('validrange', [])
1181 for value in attrvalue:
1182 res = self._check_validvals_value(attrname,
1183 value,
1184 validvals,
1185 validrange)
1186 if not res['result']:
1187 self.logger.warn('%s: %s: %s' %
1188 (ifacename, attrname, res['message']))
1189 success = False
1190 except Exception as e:
1191 self.logger.warn('addon \'%s\': %s: %s' % (module_name,
1192 attrname,
1193 str(e)))
1194 success = False
1195 return success
1196
1197 def _module_syntax_check(self, filtered_ifacenames):
1198 result = True
1199 for ifacename in filtered_ifacenames:
1200 for module in self.modules.values():
1201 try:
1202 if hasattr(module, '_modinfo'):
1203 if not self._check_validvals(ifacename,
1204 module.__class__.__name__,
1205 module._modinfo.get('attrs', {})):
1206 result = False
1207 if hasattr(module, 'syntax_check') and callable(module.syntax_check):
1208 if not module.syntax_check(self.get_ifaceobjs(ifacename)[0],
1209 self.get_ifaceobjs):
1210 result = False
1211 except Exception, e:
1212 self.logger.warn('%s: %s' % (ifacename, str(e)))
1213 result = False
1214 return result
1215
1216 def _iface_configattr_syntax_checker(self, attrname, attrval):
1217 for m, mdict in self.module_attrs.items():
1218 if not mdict:
1219 continue
1220 attrsdict = mdict.get('attrs')
1221 try:
1222 a = attrsdict.get(attrname)
1223 if a:
1224 if a.get('deprecated'):
1225 newa = a.get('new-attribute')
1226 if newa:
1227 self.logger.warn('attribute %s is deprecated. use %s instead.' %(attrname, newa))
1228 else:
1229 self.logger.warn('attribute %s is deprecated.'
1230 %attrname)
1231 return True
1232 else:
1233 for key in attrsdict:
1234 if 'aliases' in attrsdict[key]:
1235 if attrname in attrsdict[key]['aliases']:
1236 return True
1237 except AttributeError:
1238 pass
1239 return False
1240
1241 def _ifaceobj_syntax_checker(self, ifaceobj):
1242 ret = True
1243 for attrname, attrvalue in ifaceobj.config.items():
1244 found = False
1245 for k, v in self.module_attrs.items():
1246 if v and v.get('attrs', {}).get(attrname):
1247 found = True
1248 break
1249 if not found:
1250 ret = False
1251 self.logger.warn('%s: unsupported attribute \'%s\'' \
1252 % (ifaceobj.name, attrname))
1253 continue
1254 return ret
1255
1256 def read_iface_config(self):
1257 """ Reads default network interface config /etc/network/interfaces. """
1258 ret = True
1259 nifaces = networkInterfaces(self.interfacesfile,
1260 self.interfacesfileiobuf,
1261 self.interfacesfileformat,
1262 template_enable=self.config.get('template_enable', 0),
1263 template_engine=self.config.get('template_engine'),
1264 template_lookuppath=self.config.get('template_lookuppath'))
1265 if self._ifaceobj_squash or self._ifaceobj_squash_internal:
1266 nifaces.subscribe('iface_found', self._save_iface_squash)
1267 else:
1268 nifaces.subscribe('iface_found', self._save_iface)
1269 if self.config.get('addon_syntax_check', '1') == '1':
1270 nifaces.subscribe('validateifaceattr',
1271 self._iface_configattr_syntax_checker)
1272 nifaces.subscribe('validateifaceobj', self._ifaceobj_syntax_checker)
1273 nifaces.load()
1274 if nifaces.errors or nifaces.warns:
1275 ret = False
1276 return ret
1277
1278 def read_old_iface_config(self):
1279 """ Reads the saved iface config instead of default iface config.
1280 And saved iface config is already read by the statemanager """
1281 self.ifaceobjdict = copy.deepcopy(self.statemanager.ifaceobjdict)
1282
1283 def _load_addon_modules_config(self):
1284 """ Load addon modules config file """
1285
1286 with open(self.addon_modules_configfile, 'r') as f:
1287 lines = f.readlines()
1288 for l in lines:
1289 try:
1290 litems = l.strip(' \n\t\r').split(',')
1291 if not litems or len(litems) < 2:
1292 continue
1293 operation = litems[0]
1294 mname = litems[1]
1295 self.module_ops[operation].append(mname)
1296 except Exception, e:
1297 self.logger.warn('error reading line \'%s\' %s:' %(l, str(e)))
1298 continue
1299
1300 def load_addon_modules(self, modules_dir_list):
1301 """ load python modules from modules_dir
1302
1303 Default modules_dir is /usr/share/ifupdownmodules
1304
1305 """
1306 failed_import = list()
1307
1308 self.logger.info('loading builtin modules from %s' % str(modules_dir_list))
1309 self._load_addon_modules_config()
1310
1311 for modules_dir in modules_dir_list:
1312 if not modules_dir in sys.path:
1313 sys.path.insert(1, modules_dir)
1314 try:
1315 for op, mlist in self.module_ops.items():
1316 for mname in mlist:
1317 if self.modules.get(mname):
1318 continue
1319 mpath = modules_dir + '/' + mname + '.py'
1320 if os.path.exists(mpath) and mpath not in failed_import:
1321 try:
1322 m = __import__(mname)
1323 mclass = getattr(m, mname)
1324 except Exception as e:
1325 self.logger.warning('cannot load "%s" module: %s' % (mname, str(e)))
1326 failed_import.append(mpath)
1327 continue
1328 try:
1329 minstance = mclass()
1330 script_override = minstance.get_overrides_ifupdown_scripts()
1331 self.overridden_ifupdown_scripts.extend(script_override)
1332 except moduleNotSupported, e:
1333 self.logger.info('module %s not loaded (%s)\n'
1334 %(mname, str(e)))
1335 continue
1336 except:
1337 raise
1338 self.modules[mname] = minstance
1339 try:
1340 self.module_attrs[mname] = minstance.get_modinfo()
1341 except:
1342 pass
1343 except:
1344 raise
1345
1346 # Assign all modules to query operations
1347 self.module_ops['query-checkcurr'] = self.modules.keys()
1348 self.module_ops['query-running'] = self.modules.keys()
1349 self.module_ops['query-dependency'] = self.modules.keys()
1350 self.module_ops['query'] = self.modules.keys()
1351 self.module_ops['query-raw'] = self.modules.keys()
1352
1353 def _keyword_number_comma_range_list(self, value, validrange=None):
1354 return self._keyword_number_range_list(value.replace(',', ' '), validrange=validrange)
1355
1356
1357 def _modules_help(self, fmt):
1358 """ Prints addon modules supported syntax """
1359
1360 if fmt == 'json':
1361 modinfos = {}
1362 for key, value in self.modules.items():
1363 if hasattr(value, '_modinfo'):
1364 modinfos[key] = {
1365 'mhelp': value._modinfo['mhelp'],
1366 'attrs': value.merge_modinfo_with_policy_files()
1367 }
1368 print json.dumps(modinfos)
1369 else:
1370 indent = ' '
1371 for m, mdict in self.module_attrs.items():
1372 if not mdict:
1373 continue
1374 print('%s: %s' %(m, mdict.get('mhelp')))
1375 attrdict = self.modules[m].merge_modinfo_with_policy_files()
1376 if not attrdict:
1377 continue
1378 try:
1379 for attrname, attrvaldict in attrdict.items():
1380 if attrvaldict.get('compat', False):
1381 continue
1382 print('%s%s' %(indent, attrname))
1383 print('%shelp: %s' %(indent + ' ',
1384 attrvaldict.get('help', '')))
1385 print ('%srequired: %s' %(indent + ' ',
1386 attrvaldict.get('required', False)))
1387 default = attrvaldict.get('default')
1388 if default:
1389 print('%sdefault: %s' %(indent + ' ', default))
1390
1391 validrange = attrvaldict.get('validrange')
1392 if validrange:
1393 print('%svalidrange: %s-%s'
1394 %(indent + ' ', validrange[0], validrange[1]))
1395
1396 validvals = attrvaldict.get('validvals')
1397 if validvals:
1398 print('%svalidvals: %s'
1399 %(indent + ' ', ','.join(validvals)))
1400
1401 examples = attrvaldict.get('example')
1402 if not examples:
1403 continue
1404
1405 print '%sexample:' %(indent + ' ')
1406 for e in examples:
1407 print '%s%s' %(indent + ' ', e)
1408 except:
1409 pass
1410 print ''
1411
1412 def load_scripts(self, modules_dir):
1413 """ loading user modules from /etc/network/.
1414
1415 Note that previously loaded python modules override modules found
1416 under /etc/network if any
1417
1418 """
1419
1420 self.logger.info('looking for user scripts under %s' %modules_dir)
1421 for op, mlist in self.script_ops.items():
1422 msubdir = modules_dir + '/if-%s.d' %op
1423 self.logger.info('loading scripts under %s ...' %msubdir)
1424 try:
1425 module_list = os.listdir(msubdir)
1426 for module in module_list:
1427 if self.modules.get(module) or module in self.overridden_ifupdown_scripts:
1428 continue
1429 self.script_ops[op].append(msubdir + '/' + module)
1430 except:
1431 # continue reading
1432 pass
1433
1434 def _sched_ifaces(self, ifacenames, ops, skipupperifaces=False,
1435 followdependents=True, sort=False):
1436 self.logger.debug('scheduling \'%s\' for %s'
1437 %(str(ops), str(ifacenames)))
1438 self._pretty_print_ordered_dict('dependency graph',
1439 self.dependency_graph)
1440 ifaceScheduler.sched_ifaces(self, ifacenames, ops,
1441 dependency_graph=self.dependency_graph,
1442 order=ifaceSchedulerFlags.INORDER
1443 if 'down' in ops[0]
1444 else ifaceSchedulerFlags.POSTORDER,
1445 followdependents=followdependents,
1446 skipupperifaces=skipupperifaces,
1447 sort=True if (sort or ifupdownflags.flags.CLASS) else False)
1448 return ifaceScheduler.get_sched_status()
1449
1450 def _render_ifacename(self, ifacename):
1451 new_ifacenames = []
1452 vlan_match = re.match("^([\d]+)-([\d]+)", ifacename)
1453 if vlan_match:
1454 vlan_groups = vlan_match.groups()
1455 if vlan_groups[0] and vlan_groups[1]:
1456 [new_ifacenames.append('%d' %v)
1457 for v in range(int(vlan_groups[0]),
1458 int(vlan_groups[1])+1)]
1459 return new_ifacenames
1460
1461 def _preprocess_ifacenames(self, ifacenames):
1462 """ validates interface list for config existance.
1463
1464 returns -1 if one or more interface not found. else, returns 0
1465
1466 """
1467 new_ifacenames = []
1468 err_iface = ''
1469 for i in ifacenames:
1470 ifaceobjs = self.get_ifaceobjs(i)
1471 if not ifaceobjs:
1472 # if name not available, render interface name and check again
1473 rendered_ifacenames = utils.expand_iface_range(i)
1474 if rendered_ifacenames:
1475 for ri in rendered_ifacenames:
1476 ifaceobjs = self.get_ifaceobjs(ri)
1477 if not ifaceobjs:
1478 err_iface += ' ' + ri
1479 else:
1480 new_ifacenames.append(ri)
1481 else:
1482 err_iface += ' ' + i
1483 else:
1484 new_ifacenames.append(i)
1485 if err_iface:
1486 raise Exception('cannot find interfaces:%s' %err_iface)
1487 return new_ifacenames
1488
1489 def _iface_whitelisted(self, auto, allow_classes, excludepats, ifacename):
1490 """ Checks if interface is whitelisted depending on set of parameters.
1491
1492 interfaces are checked against the allow_classes and auto lists.
1493
1494 """
1495
1496 ret = True
1497
1498 # Check if interface matches the exclude patter
1499 if excludepats:
1500 for e in excludepats:
1501 if re.search(e, ifacename):
1502 ret = False
1503 ifaceobjs = self.get_ifaceobjs(ifacename)
1504 if not ifaceobjs:
1505 if ret:
1506 self.logger.debug('iface %s' %ifacename + ' not found')
1507 return ret
1508 # If matched exclude pattern, return false
1509 if not ret:
1510 for i in ifaceobjs:
1511 i.blacklisted = True
1512 self.blacklisted_ifaces_present = True
1513 return ret
1514 # Check if interface belongs to the class
1515 # the user is interested in, if not return false
1516 if allow_classes:
1517 ret = False
1518 for i in ifaceobjs:
1519 if i.classes:
1520 common = Set(allow_classes).intersection(
1521 Set(i.classes))
1522 if common:
1523 ret = True
1524 if not ret:
1525 # If a class was requested and interface does not belong
1526 # to the class, only then mark the ifaceobjs as blacklisted
1527 self.blacklisted_ifaces_present = True
1528 for i in ifaceobjs:
1529 i.blacklisted = True
1530 return ret
1531 # If the user has requested auto class, check if the interface
1532 # is marked auto
1533 if auto:
1534 ret = False
1535 for i in ifaceobjs:
1536 if i.auto:
1537 ret = True
1538 if not ret:
1539 # If auto was requested and interface was not marked auto,
1540 # only then mark all of them as blacklisted
1541 self.blacklisted_ifaces_present = True
1542 for i in ifaceobjs:
1543 i.blacklisted = True
1544 return ret
1545
1546 def _compat_conv_op_to_mode(self, op):
1547 """ Returns old op name to work with existing scripts """
1548 if 'up' in op:
1549 return 'start'
1550 elif 'down' in op:
1551 return 'stop'
1552 else:
1553 return op
1554
1555 def generate_running_env(self, ifaceobj, op):
1556 """ Generates a dictionary with env variables required for
1557 an interface. Used to support script execution for interfaces.
1558 """
1559
1560 cenv = None
1561 iface_env = ifaceobj.get_env()
1562 if iface_env:
1563 cenv = dict(os.environ)
1564 if cenv:
1565 cenv.update(iface_env)
1566 else:
1567 cenv = iface_env
1568 else:
1569 cenv = {}
1570 cenv['MODE'] = self._compat_conv_op_to_mode(op)
1571 cenv['PHASE'] = op
1572
1573 return cenv
1574
1575 def _save_state(self):
1576 if (not self.flags.STATEMANAGER_ENABLE or
1577 not self.flags.STATEMANAGER_UPDATE):
1578 return
1579 try:
1580 # Update persistant iface states
1581 self.statemanager.save_state()
1582 except Exception, e:
1583 if self.logger.isEnabledFor(logging.DEBUG):
1584 t = sys.exc_info()[2]
1585 traceback.print_tb(t)
1586 self.logger.warning('error saving state (%s)' %str(e))
1587
1588 def set_type(self, type):
1589 if type == 'iface':
1590 self.type = ifaceType.IFACE
1591 elif type == 'vlan':
1592 self.type = ifaceType.BRIDGE_VLAN
1593 else:
1594 self.type = ifaceType.UNKNOWN
1595
1596 def _process_delay_admin_state_queue(self, op):
1597 if not self._delay_admin_state_iface_queue:
1598 return
1599 if op == 'up':
1600 func = self.link_up
1601 elif op == 'down':
1602 func = self.link_down
1603 else:
1604 return
1605 for i in self._delay_admin_state_iface_queue:
1606 try:
1607 if self.link_exists(i):
1608 func(i)
1609 except Exception, e:
1610 self.logger.warn(str(e))
1611 pass
1612
1613 def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
1614 excludepats=None, printdependency=None, syntaxcheck=False,
1615 type=None, skipupperifaces=False):
1616 """This brings the interface(s) up
1617
1618 Args:
1619 ops (list): list of ops to perform on the interface(s).
1620 Eg: ['pre-up', 'up', 'post-up'
1621
1622 Kwargs:
1623 auto (bool): act on interfaces marked auto
1624 allow_classes (list): act on interfaces belonging to classes in the list
1625 ifacenames (list): act on interfaces specified in this list
1626 excludepats (list): list of patterns of interfaces to exclude
1627 syntaxcheck (bool): only perform syntax check
1628 """
1629
1630 self.set_type(type)
1631
1632 if allow_classes:
1633 ifupdownflags.flags.CLASS = True
1634 if not self.flags.ADDONS_ENABLE:
1635 self.flags.STATEMANAGER_UPDATE = False
1636 if auto:
1637 ifupdownflags.flags.ALL = True
1638 ifupdownflags.flags.WITH_DEPENDS = True
1639 try:
1640 iface_read_ret = self.read_iface_config()
1641 except Exception:
1642 raise
1643
1644 filtered_ifacenames = None
1645 if ifacenames:
1646 ifacenames = self._preprocess_ifacenames(ifacenames)
1647
1648 if allow_classes:
1649 filtered_ifacenames = self._get_filtered_ifacenames_with_classes(auto, allow_classes, excludepats, ifacenames)
1650
1651 # if iface list not given by user, assume all from config file
1652 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1653
1654 if not filtered_ifacenames:
1655 # filter interfaces based on auto and allow classes
1656 filtered_ifacenames = [i for i in ifacenames
1657 if self._iface_whitelisted(auto, allow_classes,
1658 excludepats, i)]
1659
1660 if not filtered_ifacenames:
1661 raise Exception('no ifaces found matching given allow lists')
1662
1663 if printdependency:
1664 self.populate_dependency_info(ops, filtered_ifacenames)
1665 self.print_dependency(filtered_ifacenames, printdependency)
1666 return
1667 else:
1668 self.populate_dependency_info(ops)
1669
1670 # If only syntax check was requested, return here.
1671 # return here because we want to make sure most
1672 # errors above are caught and reported.
1673 if syntaxcheck:
1674 if not self._module_syntax_check(filtered_ifacenames):
1675 raise Exception()
1676 if not iface_read_ret:
1677 raise Exception()
1678 elif self._any_iface_errors(filtered_ifacenames):
1679 raise Exception()
1680 return
1681
1682 ret = None
1683 try:
1684 ret = self._sched_ifaces(filtered_ifacenames, ops,
1685 skipupperifaces=skipupperifaces,
1686 followdependents=True
1687 if ifupdownflags.flags.WITH_DEPENDS
1688 else False)
1689 finally:
1690 self._process_delay_admin_state_queue('up')
1691 if not ifupdownflags.flags.DRYRUN and self.flags.ADDONS_ENABLE:
1692 self._save_state()
1693
1694 if not iface_read_ret or not ret:
1695 raise Exception()
1696
1697 def _get_filtered_ifacenames_with_classes(self, auto, allow_classes, excludepats, ifacenames):
1698 # if user has specified ifacelist and allow_classes
1699 # append the allow_classes interfaces to user
1700 # ifacelist
1701 filtered_ifacenames = [i for i in self.ifaceobjdict.keys()
1702 if self._iface_whitelisted(auto, allow_classes,
1703 excludepats, i)]
1704 filtered_ifacenames += ifacenames
1705
1706 for intf in ifacenames:
1707 for obj in self.get_ifaceobjs(intf) or []:
1708 obj.blacklisted = False
1709
1710 return filtered_ifacenames
1711
1712 def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
1713 excludepats=None, printdependency=None, usecurrentconfig=False,
1714 type=None):
1715 """ down an interface """
1716
1717 self.set_type(type)
1718
1719 if allow_classes:
1720 ifupdownflags.flags.CLASS = True
1721 if not self.flags.ADDONS_ENABLE:
1722 self.flags.STATEMANAGER_UPDATE = False
1723 if auto:
1724 ifupdownflags.flags.ALL = True
1725 ifupdownflags.flags.WITH_DEPENDS = True
1726 # For down we need to look at old state, unless usecurrentconfig
1727 # is set
1728 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE and
1729 self.statemanager.ifaceobjdict):
1730 # Since we are using state manager objects,
1731 # skip the updating of state manager objects
1732 self.logger.debug('Looking at old state ..')
1733 self.read_old_iface_config()
1734 else:
1735 # If no old state available
1736 try:
1737 self.read_iface_config()
1738 except Exception, e:
1739 raise Exception('error reading iface config (%s)' %str(e))
1740 filtered_ifacenames = None
1741 if ifacenames:
1742 # If iface list is given by the caller, always check if iface
1743 # is present
1744 try:
1745 ifacenames = self._preprocess_ifacenames(ifacenames)
1746
1747 if allow_classes:
1748 filtered_ifacenames = self._get_filtered_ifacenames_with_classes(auto, allow_classes, excludepats, ifacenames)
1749
1750 except Exception, e:
1751 raise Exception('%s' %str(e) +
1752 ' (interface was probably never up ?)')
1753
1754
1755 # if iface list not given by user, assume all from config file
1756 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1757
1758 if not filtered_ifacenames:
1759 # filter interfaces based on auto and allow classes
1760 filtered_ifacenames = [i for i in ifacenames
1761 if self._iface_whitelisted(auto, allow_classes,
1762 excludepats, i)]
1763
1764 if not filtered_ifacenames:
1765 raise Exception('no ifaces found matching given allow lists ' +
1766 '(or interfaces were probably never up ?)')
1767
1768 if printdependency:
1769 self.populate_dependency_info(ops, filtered_ifacenames)
1770 self.print_dependency(filtered_ifacenames, printdependency)
1771 return
1772 else:
1773 self.populate_dependency_info(ops)
1774
1775 try:
1776 self._sched_ifaces(filtered_ifacenames, ops,
1777 followdependents=True
1778 if ifupdownflags.flags.WITH_DEPENDS else False)
1779 finally:
1780 self._process_delay_admin_state_queue('down')
1781 if not ifupdownflags.flags.DRYRUN and self.flags.ADDONS_ENABLE:
1782 self._save_state()
1783
1784 def query(self, ops, auto=False, format_list=False, allow_classes=None,
1785 ifacenames=None,
1786 excludepats=None, printdependency=None,
1787 format='native', type=None):
1788 """ query an interface """
1789
1790 self.set_type(type)
1791
1792 # Let us forget internal squashing when it comes to
1793 # ifquery. It can surprise people relying of ifquery
1794 # output
1795 self._ifaceobj_squash_internal = False
1796
1797 if allow_classes:
1798 ifupdownflags.flags.CLASS = True
1799 if self.flags.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
1800 return self.statemanager.dump_pretty(ifacenames)
1801 self.flags.STATEMANAGER_UPDATE = False
1802 if auto:
1803 self.logger.debug('setting flag ALL')
1804 ifupdownflags.flags.ALL = True
1805 ifupdownflags.flags.WITH_DEPENDS = True
1806
1807 if ops[0] == 'query-syntax':
1808 self._modules_help(format)
1809 return
1810 elif ops[0] == 'query-running':
1811 # create fake devices to all dependents that dont have config
1812 map(lambda i: self.create_n_save_ifaceobj(i,
1813 ifacePrivFlags(False, True)), ifacenames)
1814 else:
1815 try:
1816 self.read_iface_config()
1817 except Exception:
1818 raise
1819
1820 if ifacenames and ops[0] != 'query-running':
1821 # If iface list is given, always check if iface is present
1822 ifacenames = self._preprocess_ifacenames(ifacenames)
1823
1824 if allow_classes:
1825 filtered_ifacenames = self._get_filtered_ifacenames_with_classes(auto, allow_classes, excludepats, ifacenames)
1826
1827 # if iface list not given by user, assume all from config file
1828 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1829
1830 # filter interfaces based on auto and allow classes
1831 if ops[0] == 'query-running':
1832 filtered_ifacenames = ifacenames
1833 elif not allow_classes:
1834 filtered_ifacenames = [
1835 i for i in ifacenames
1836 if self._iface_whitelisted(
1837 auto,
1838 allow_classes,
1839 excludepats, i
1840 )
1841 ]
1842
1843 if not filtered_ifacenames:
1844 raise Exception('no ifaces found matching ' +
1845 'given allow lists')
1846
1847 self.populate_dependency_info(ops)
1848 if ops[0] == 'query-dependency' and printdependency:
1849 self.print_dependency(filtered_ifacenames, printdependency)
1850 return
1851
1852 if format_list and (ops[0] == 'query' or ops[0] == 'query-raw'):
1853 return self.print_ifaceobjs_list(filtered_ifacenames)
1854
1855 if ops[0] == 'query' and not ifupdownflags.flags.WITHDEFAULTS:
1856 return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
1857 elif ops[0] == 'query-raw':
1858 return self.print_ifaceobjs_raw(filtered_ifacenames)
1859
1860 ret = self._sched_ifaces(filtered_ifacenames, ops,
1861 followdependents=True
1862 if ifupdownflags.flags.WITH_DEPENDS else False)
1863
1864 if ops[0] == 'query' and ifupdownflags.flags.WITHDEFAULTS:
1865 return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
1866 elif ops[0] == 'query-checkcurr':
1867 ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format)
1868 if ret != 0:
1869 # if any of the object has an error, signal that silently
1870 raise Exception('')
1871 elif ops[0] == 'query-running':
1872 self.print_ifaceobjsrunning_pretty(filtered_ifacenames, format)
1873 return
1874
1875 def _reload_currentlyup(self, upops, downops, auto=False, allow=None,
1876 ifacenames=None, excludepats=None, usecurrentconfig=False,
1877 syntaxcheck=False, **extra_args):
1878 """ reload currently up interfaces """
1879 new_ifaceobjdict = {}
1880
1881 self.logger.info('reloading interfaces that are currently up ..')
1882
1883 try:
1884 iface_read_ret = self.read_iface_config()
1885 except:
1886 raise
1887 if not self.ifaceobjdict:
1888 self.logger.warn("nothing to reload ..exiting.")
1889 return
1890 already_up_ifacenames = []
1891 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1892
1893 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE
1894 and self.statemanager.ifaceobjdict):
1895 already_up_ifacenames = self.statemanager.ifaceobjdict.keys()
1896
1897 # Get already up interfaces that still exist in the interfaces file
1898 already_up_ifacenames_not_present = Set(
1899 already_up_ifacenames).difference(ifacenames)
1900 already_up_ifacenames_still_present = Set(
1901 already_up_ifacenames).difference(
1902 already_up_ifacenames_not_present)
1903
1904 interfaces_to_up = already_up_ifacenames_still_present
1905
1906 # generate dependency graph of interfaces
1907 self.populate_dependency_info(upops, interfaces_to_up)
1908
1909 # If only syntax check was requested, return here.
1910 # return here because we want to make sure most
1911 # errors above are caught and reported.
1912 if syntaxcheck:
1913 if not self._module_syntax_check(interfaces_to_up):
1914 raise Exception()
1915 if not iface_read_ret:
1916 raise Exception()
1917 elif self._any_iface_errors(interfaces_to_up):
1918 raise Exception()
1919 return
1920
1921 if (already_up_ifacenames_not_present and
1922 self.config.get('ifreload_currentlyup_down_notpresent') == '1'):
1923 self.logger.info('reload: schedule down on interfaces: %s'
1924 %str(already_up_ifacenames_not_present))
1925
1926 # Save a copy of new iface objects and dependency_graph
1927 new_ifaceobjdict = dict(self.ifaceobjdict)
1928 new_dependency_graph = dict(self.dependency_graph)
1929
1930 # old interface config is read into self.ifaceobjdict
1931 self.read_old_iface_config()
1932
1933 # reinitialize dependency graph
1934 self.dependency_graph = OrderedDict({})
1935 falready_up_ifacenames_not_present = [i for i in
1936 already_up_ifacenames_not_present
1937 if self._iface_whitelisted(auto, allow,
1938 excludepats, i)]
1939 self.populate_dependency_info(downops,
1940 falready_up_ifacenames_not_present)
1941 self._sched_ifaces(falready_up_ifacenames_not_present, downops,
1942 followdependents=False, sort=True)
1943 else:
1944 self.logger.info('no interfaces to down ..')
1945
1946 # Now, run 'up' with new config dict
1947 # reset statemanager update flag to default
1948 if auto:
1949 ifupdownflags.flags.ALL = True
1950 ifupdownflags.flags.WITH_DEPENDS = True
1951 if new_ifaceobjdict:
1952 # and now, ifaceobjdict is back to current config
1953 self.ifaceobjdict = new_ifaceobjdict
1954 self.dependency_graph = new_dependency_graph
1955
1956 if not self.ifaceobjdict:
1957 self.logger.info('no interfaces to up')
1958 return
1959 self.logger.info('reload: scheduling up on interfaces: %s'
1960 %str(interfaces_to_up))
1961 ret = self._sched_ifaces(interfaces_to_up, upops,
1962 followdependents=True
1963 if ifupdownflags.flags.WITH_DEPENDS else False)
1964 if ifupdownflags.flags.DRYRUN:
1965 return
1966 self._save_state()
1967
1968 if not iface_read_ret or not ret:
1969 raise Exception()
1970
1971 def _reload_default(self, upops, downops, auto=False, allow=None,
1972 ifacenames=None, excludepats=None, usecurrentconfig=False,
1973 syntaxcheck=False, **extra_args):
1974 """ reload interface config """
1975 new_ifaceobjdict = {}
1976
1977 try:
1978 iface_read_ret = self.read_iface_config()
1979 except:
1980 raise
1981
1982 if not self.ifaceobjdict:
1983 self.logger.warn("nothing to reload ..exiting.")
1984 return
1985
1986 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1987 new_filtered_ifacenames = [i for i in ifacenames
1988 if self._iface_whitelisted(auto, allow,
1989 excludepats, i)]
1990 # generate dependency graph of interfaces
1991 self.populate_dependency_info(upops)
1992
1993 # If only syntax check was requested, return here.
1994 # return here because we want to make sure most
1995 # errors above are caught and reported.
1996 if syntaxcheck:
1997 if not self._module_syntax_check(new_filtered_ifacenames):
1998 raise Exception()
1999 if not iface_read_ret:
2000 raise Exception()
2001 elif self._any_iface_errors(new_filtered_ifacenames):
2002 raise Exception()
2003 return
2004
2005 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE
2006 and self.statemanager.ifaceobjdict):
2007 # Save a copy of new iface objects and dependency_graph
2008 new_ifaceobjdict = dict(self.ifaceobjdict)
2009 new_dependency_graph = dict(self.dependency_graph)
2010
2011 self.ifaceobjdict = OrderedDict({})
2012 self.dependency_graph = OrderedDict({})
2013
2014 # if old state is present, read old state and mark op for 'down'
2015 # followed by 'up' aka: reload
2016 # old interface config is read into self.ifaceobjdict
2017 self.read_old_iface_config()
2018 op = 'reload'
2019 else:
2020 # oldconfig not available, continue with 'up' with new config
2021 op = 'up'
2022 new_ifaceobjdict = self.ifaceobjdict
2023 new_dependency_graph = self.dependency_graph
2024
2025 if op == 'reload' and ifacenames:
2026 ifacenames = self.ifaceobjdict.keys()
2027 old_filtered_ifacenames = [i for i in ifacenames
2028 if self._iface_whitelisted(auto, allow,
2029 excludepats, i)]
2030
2031 # generate dependency graph of old interfaces,
2032 # This should make sure built in interfaces are
2033 # populated. disable check shared dependents as an optimization.
2034 # these are saved interfaces and dependency for these
2035 # have been checked before they became part of saved state.
2036 try:
2037 self.flags.CHECK_SHARED_DEPENDENTS = False
2038 self.populate_dependency_info(upops)
2039 self.flags.CHECK_SHARED_DEPENDENTS = True
2040 except Exception, e:
2041 self.logger.info("error generating dependency graph for "
2042 "saved interfaces (%s)" %str(e))
2043 pass
2044
2045 # make sure we pick up built-in interfaces
2046 # if config file had 'ifreload_down_changed' variable
2047 # set, also look for interfaces that changed to down them
2048 down_changed = int(self.config.get('ifreload_down_changed', '1'))
2049
2050 # Generate the interface down list
2051 # Interfaces that go into the down list:
2052 # - interfaces that were present in last config and are not
2053 # present in the new config
2054 # - interfaces that were changed between the last and current
2055 # config
2056 ifacedownlist = []
2057 for ifname in self.ifaceobjdict.keys():
2058 lastifaceobjlist = self.ifaceobjdict.get(ifname)
2059 if not self.is_ifaceobj_builtin(lastifaceobjlist[0]):
2060 # if interface is not built-in and is not in
2061 # old filtered ifacenames
2062 if ifname not in old_filtered_ifacenames:
2063 continue
2064 objidx = 0
2065 # If interface is not present in the new file
2066 # append it to the down list
2067 newifaceobjlist = new_ifaceobjdict.get(ifname)
2068 if not newifaceobjlist:
2069 ifacedownlist.append(ifname)
2070 continue
2071 # If ifaceobj was present in the old interfaces file,
2072 # and does not have a config in the new interfaces file
2073 # but has been picked up as a dependent of another
2074 # interface, catch it here. This catches a common error
2075 # for example: remove a bond section from the interfaces
2076 # file, but leave it around as a bridge port
2077 # XXX: Ideally its better to just add it to the
2078 # ifacedownlist. But we will be cautious here
2079 # and just print a warning
2080 if (self.is_ifaceobj_noconfig(newifaceobjlist[0]) and
2081 not self.is_ifaceobj_builtin(newifaceobjlist[0]) and
2082 lastifaceobjlist[0].is_config_present() and
2083 lastifaceobjlist[0].link_kind):
2084 self.logger.warn('%s: misconfig ? removed but still exists '
2085 'as a dependency of %s.\nPlease remove '
2086 'the dependency manually `ifdown %s` if '
2087 'it is being picked up as part of a regex'
2088 % (newifaceobjlist[objidx].name,
2089 str(newifaceobjlist[objidx].upperifaces),
2090 newifaceobjlist[objidx].name))
2091 if (lastifaceobjlist[0].link_kind and
2092 not newifaceobjlist[0].link_kind):
2093 self.logger.warn('%s: moved from being a %s to a'
2094 ' physical interface (non-logical interface).'
2095 'This interface will be downed.\n'
2096 ' If this was not intentional, please restore the'
2097 ' original interface definition and execute ifreload'
2098 % (newifaceobjlist[objidx].name,
2099 ifaceLinkKind.to_str(lastifaceobjlist[0].link_kind)))
2100 ifacedownlist.append(newifaceobjlist[objidx].name)
2101 if not down_changed:
2102 continue
2103 if len(newifaceobjlist) != len(lastifaceobjlist):
2104 ifacedownlist.append(ifname)
2105 continue
2106
2107 # If interface has changed between the current file
2108 # and the last installed append it to the down list
2109 # compare object list
2110 for objidx in range(0, len(lastifaceobjlist)):
2111 oldobj = lastifaceobjlist[objidx]
2112 newobj = newifaceobjlist[objidx]
2113 if not newobj.compare(oldobj):
2114 ifacedownlist.append(ifname)
2115 continue
2116
2117 if ifacedownlist:
2118 self.logger.info('reload: scheduling down on interfaces: %s'
2119 %str(ifacedownlist))
2120 # reinitialize dependency graph
2121 self.dependency_graph = OrderedDict({})
2122
2123 # Generate dependency info for old config
2124 self.flags.CHECK_SHARED_DEPENDENTS = False
2125 self.populate_dependency_info(downops, ifacedownlist)
2126 self.flags.CHECK_SHARED_DEPENDENTS = True
2127
2128 try:
2129 # XXX: Hack to skip checking upperifaces during down.
2130 # the dependency list is not complete here
2131 # and we dont want to down the upperiface.
2132 # Hence during reload, set this to true.
2133 # This is being added to avoid a failure in
2134 # scheduler._check_upperifaces when we are dowing
2135 # a builtin bridge port
2136 self.flags.SCHED_SKIP_CHECK_UPPERIFACES = True
2137 self._sched_ifaces(ifacedownlist, downops,
2138 followdependents=False,
2139 sort=True)
2140 except Exception, e:
2141 self.logger.error(str(e))
2142 pass
2143 finally:
2144 self.flags.SCHED_SKIP_CHECK_UPPERIFACES = False
2145 self._process_delay_admin_state_queue('down')
2146 else:
2147 self.logger.info('no interfaces to down ..')
2148
2149 # Now, run 'up' with new config dict
2150 # reset statemanager update flag to default
2151 if not new_ifaceobjdict:
2152 self.logger.debug('no interfaces to up')
2153 return
2154
2155 if auto:
2156 ifupdownflags.flags.ALL = True
2157 ifupdownflags.flags.WITH_DEPENDS = True
2158 # and now, we are back to the current config in ifaceobjdict
2159 self.ifaceobjdict = new_ifaceobjdict
2160 self.dependency_graph = new_dependency_graph
2161
2162 self.logger.info('reload: scheduling up on interfaces: %s'
2163 %str(new_filtered_ifacenames))
2164 ifupdownflags.flags.CACHE = True
2165 try:
2166 ret = self._sched_ifaces(new_filtered_ifacenames, upops,
2167 followdependents=True
2168 if ifupdownflags.flags.WITH_DEPENDS
2169 else False)
2170 except Exception, e:
2171 ret = None
2172 self.logger.error(str(e))
2173 finally:
2174 self._process_delay_admin_state_queue('up')
2175 if ifupdownflags.flags.DRYRUN:
2176 return
2177 self._save_state()
2178
2179 if not iface_read_ret or not ret:
2180 raise Exception()
2181
2182 def reload(self, *args, **kargs):
2183 """ reload interface config """
2184 self.logger.debug('reloading interface config ..')
2185 if kargs.get('currentlyup', False):
2186 self._reload_currentlyup(*args, **kargs)
2187 else:
2188 self._reload_default(*args, **kargs)
2189
2190 def _any_iface_errors(self, ifacenames):
2191 for i in ifacenames:
2192 ifaceobjs = self.get_ifaceobjs(i)
2193 if not ifaceobjs: continue
2194 for ifaceobj in ifaceobjs:
2195 if (ifaceobj.status == ifaceStatus.NOTFOUND or
2196 ifaceobj.status == ifaceStatus.ERROR):
2197 return True
2198 return False
2199
2200 def _pretty_print_ordered_dict(self, prefix, argdict):
2201 outbuf = prefix + ' {\n'
2202 for k, vlist in argdict.items():
2203 outbuf += '\t%s : %s\n' %(k, str(vlist))
2204 self.logger.debug(outbuf + '}')
2205
2206 def print_dependency(self, ifacenames, format):
2207 """ prints iface dependency information """
2208
2209 if not ifacenames:
2210 ifacenames = self.ifaceobjdict.keys()
2211 if format == 'list':
2212 for k,v in self.dependency_graph.items():
2213 print '%s : %s' %(k, str(v))
2214 elif format == 'dot':
2215 indegrees = {}
2216 map(lambda i: indegrees.update({i :
2217 self.get_iface_refcnt(i)}),
2218 self.dependency_graph.keys())
2219 graph.generate_dots(self.dependency_graph, indegrees)
2220
2221 def print_ifaceobjs_list(self, ifacenames):
2222 for i in ifacenames:
2223 print i
2224
2225 def print_ifaceobjs_raw(self, ifacenames):
2226 """ prints raw lines for ifaces from config file """
2227
2228 for i in ifacenames:
2229 for ifaceobj in self.get_ifaceobjs(i):
2230 if self.is_ifaceobj_builtin(ifaceobj):
2231 continue
2232 ifaceobj.dump_raw(self.logger)
2233 if (ifupdownflags.flags.WITH_DEPENDS and
2234 not ifupdownflags.flags.ALL):
2235 dlist = ifaceobj.lowerifaces
2236 if not dlist: continue
2237 self.print_ifaceobjs_raw(dlist)
2238
2239 def _get_ifaceobjs_pretty(self, ifacenames, ifaceobjs, running=False):
2240 """ returns iface obj list """
2241
2242 for i in ifacenames:
2243 for ifaceobj in self.get_ifaceobjs(i):
2244 if ((not running and self.is_ifaceobj_noconfig(ifaceobj)) or
2245 (running and not ifaceobj.is_config_present() and
2246 not self.is_iface_builtin_byname(i) and
2247 not ifaceobj.upperifaces)):
2248 continue
2249 ifaceobjs.append(ifaceobj)
2250 if (ifupdownflags.flags.WITH_DEPENDS and
2251 not ifupdownflags.flags.ALL):
2252 dlist = ifaceobj.lowerifaces
2253 if not dlist: continue
2254 self._get_ifaceobjs_pretty(dlist, ifaceobjs, running)
2255
2256 def print_ifaceobjs_pretty(self, ifacenames, format='native'):
2257 """ pretty prints iface in format given by keyword arg format """
2258
2259 ifaceobjs = []
2260 self._get_ifaceobjs_pretty(ifacenames, ifaceobjs)
2261 if not ifaceobjs: return
2262 if format == 'json':
2263 print json.dumps(ifaceobjs, cls=ifaceJsonEncoder,
2264 indent=4, separators=(',', ': '))
2265 else:
2266 expand = int(self.config.get('ifquery_ifacename_expand_range', '0'))
2267 for i in ifaceobjs:
2268 if not expand and (i.flags & iface.IFACERANGE_ENTRY):
2269 # print only the first one
2270 if i.flags & iface.IFACERANGE_START:
2271 i.dump_pretty(use_realname=True)
2272 else:
2273 i.dump_pretty()
2274
2275 def _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs):
2276 ret = 0
2277 for i in ifacenames:
2278 ifaceobjscurr = self.get_ifaceobjcurr(i)
2279 if not ifaceobjscurr: continue
2280 for ifaceobj in ifaceobjscurr:
2281 if (ifaceobj.status == ifaceStatus.NOTFOUND or
2282 ifaceobj.status == ifaceStatus.ERROR):
2283 ret = 1
2284 if self.is_ifaceobj_noconfig(ifaceobj):
2285 continue
2286 ifaceobjs.append(ifaceobj)
2287 if (ifupdownflags.flags.WITH_DEPENDS and
2288 not ifupdownflags.flags.ALL):
2289 dlist = ifaceobj.lowerifaces
2290 if not dlist: continue
2291 dret = self._get_ifaceobjscurr_pretty(dlist, ifaceobjs)
2292 if dret: ret = 1
2293 return ret
2294
2295 def print_ifaceobjscurr_pretty(self, ifacenames, format='native'):
2296 """ pretty prints current running state of interfaces with status.
2297
2298 returns 1 if any of the interface has an error,
2299 else returns 0
2300 """
2301
2302 ifaceobjs = []
2303 ret = self._get_ifaceobjscurr_pretty(ifacenames, ifaceobjs)
2304 if not ifaceobjs: return
2305
2306 # override ifaceStatusUserStrs
2307 ifaceStatusUserStrs.SUCCESS = self.config.get('ifquery_check_success_str', _success_sym)
2308 ifaceStatusUserStrs.ERROR = self.config.get('ifquery_check_error_str', _error_sym)
2309 ifaceStatusUserStrs.UNKNOWN = self.config.get('ifquery_check_unknown_str', '')
2310 if format == 'json':
2311 print json.dumps(ifaceobjs, cls=ifaceJsonEncoderWithStatus,
2312 indent=2, separators=(',', ': '))
2313 else:
2314 map(lambda i: i.dump_pretty(with_status=True), ifaceobjs)
2315 return ret
2316
2317 def print_ifaceobjsrunning_pretty(self, ifacenames, format='native'):
2318 """ pretty prints iface running state """
2319
2320 ifaceobjs = []
2321 self._get_ifaceobjs_pretty(ifacenames, ifaceobjs, running=True)
2322 if not ifaceobjs: return
2323 if format == 'json':
2324 print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
2325 separators=(',', ': '))
2326 else:
2327 map(lambda i: i.dump_pretty(), ifaceobjs)
2328
2329 def _dump(self):
2330 print 'ifupdown main object dump'
2331 print self.pp.pprint(self.modules)
2332 print self.pp.pprint(self.ifaceobjdict)
2333
2334 def _dump_ifaceobjs(self, ifacenames):
2335 for i in ifacenames:
2336 ifaceobjs = self.get_ifaceobjs(i)
2337 for i in ifaceobjs:
2338 i.dump(self.logger)
2339 print '\n'