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