]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown/ifupdownmain.py
addons: vrf: Ensures fib rule for local table have higher pref than fib vrf rule
[mirror_ifupdown2.git] / ifupdown / ifupdownmain.py
CommitLineData
a6f80f0e 1#!/usr/bin/python
3e8ee54f 2#
904908bc 3# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
3e8ee54f 4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6# ifupdownMain --
7# ifupdown main module
8#
a6f80f0e 9
10import os
11import re
3e8ee54f 12import imp
13import pprint
14import logging
15import sys, traceback
cb7cc592 16import copy
2cd06f78 17import json
55072bd1 18import ifupdown.statemanager as statemanager
0582f185 19import ifupdown.ifupdownconfig as ifupdownConfig
a6f80f0e 20from networkinterfaces import *
21from iface import *
22from scheduler import *
23from collections import deque
24from collections import OrderedDict
a6f80f0e 25from graph import *
3e8ee54f 26from sets import Set
a6f80f0e 27
2c0ad8b3
RP
28"""
29.. module:: ifupdownmain
30:synopsis: main module for ifupdown package
31
32.. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
33
34"""
35
86fc62e2 36_tickmark = u'\u2713'
37_crossmark = u'\u2717'
e74d01e1
RP
38_success_sym = '(%s)' %_tickmark
39_error_sym = '(%s)' %_crossmark
86fc62e2 40
84ca006f
RP
41class ifupdownFlags():
42 FORCE = False
43 DRYRUN = False
44 NOWAIT = False
45 PERFMODE = False
46 CACHE = False
47
48 # Flags
49 CACHE_FLAGS = 0x0
50
dbc018d3 51class ifupdownMainFlags():
cca03c30 52 WITH_DEPENDS = False
a6f80f0e 53 ALL = False
5ee3e1a8 54 IFACE_CLASS = False
6bd7fc74 55 COMPAT_EXEC_SCRIPTS = False
20dd6242 56 STATEMANAGER_ENABLE = True
57 STATEMANAGER_UPDATE = True
58 ADDONS_ENABLE = False
dbc018d3
RP
59 DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
60 SCHED_SKIP_CHECK_UPPERIFACES = False
61 CHECK_SHARED_DEPENDENTS = True
a6f80f0e 62
dbc018d3 63class ifacePrivFlags():
37c0543d 64 # priv flags to mark iface objects
dbc018d3
RP
65 BUILTIN = False
66 NOCONFIG = False
67
68 def __init__(self, builtin=False, noconfig=False):
69 self.BUILTIN = builtin
70 self.NOCONFIG = noconfig
71
72class ifupdownMain(ifupdownBase):
73 """ ifupdown2 main class """
37c0543d 74
75 scripts_dir='/etc/network'
1642c64b
RP
76 addon_modules_dir='/usr/share/ifupdown2/addons'
77 addon_modules_configfile='/etc/network/ifupdown2/addons.conf'
a6f80f0e 78
79 # iface dictionary in the below format:
80 # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
81 # eg:
53b00224 82 # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
a6f80f0e 83 #
84 # Each ifaceobject corresponds to a configuration block for
85 # that interface
53b00224 86 # The value in the dictionary is a list because the network
87 # interface configuration file supports more than one iface section
88 # in the interfaces file
a6f80f0e 89 ifaceobjdict = OrderedDict()
90
a6f80f0e 91 # iface dictionary representing the curr running state of an iface
92 # in the below format:
93 # {'<ifacename>' : <ifaceobject>}
94 ifaceobjcurrdict = OrderedDict()
95
be0b20f2 96 # Dictionary representing operation and modules
97 # for every operation
98 module_ops = OrderedDict([('pre-up', []),
d08d5f54 99 ('up' , []),
100 ('post-up' , []),
101 ('query-checkcurr', []),
102 ('query-running', []),
103 ('query-dependency', []),
75730152 104 ('query', []),
105 ('query-raw', []),
d08d5f54 106 ('pre-down', []),
107 ('down' , []),
108 ('post-down' , [])])
37c0543d 109
110 # For old style /etc/network/ bash scripts
be0b20f2 111 script_ops = OrderedDict([('pre-up', []),
d08d5f54 112 ('up' , []),
113 ('post-up' , []),
114 ('pre-down', []),
115 ('down' , []),
116 ('post-down' , [])])
a6f80f0e 117
be0b20f2 118 # Handlers for ops that ifupdown2 owns
119 def run_up(self, ifaceobj):
496745cd
RP
120 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs).
121 # there is no real interface behind it
122 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
123 return
a070c90e
RP
124 if (ifaceobj.addr_method and
125 ifaceobj.addr_method == 'manual'):
126 return
127 if self._delay_admin_state:
128 self._delay_admin_state_iface_queue.append(ifaceobj.name)
129 return
7f045fd8
RP
130 # If this object is a link slave, ie its link is controlled
131 # by its link master interface, then dont set the link state.
132 # But do allow user to change state of the link if the interface
133 # is already with its link master (hence the master check).
7e2e64fb 134 if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
7f045fd8 135 return
a070c90e 136 if not self.link_exists(ifaceobj.name):
7e2e64fb 137 return
a070c90e 138 self.link_up(ifaceobj.name)
be0b20f2 139
140 def run_down(self, ifaceobj):
496745cd
RP
141 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs)
142 # there is no real interface behind it
143 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
144 return
a070c90e
RP
145 if (ifaceobj.addr_method and
146 ifaceobj.addr_method == 'manual'):
147 return
148 if self._delay_admin_state:
149 self._delay_admin_state_iface_queue.append(ifaceobj.name)
150 return
7f045fd8
RP
151 # If this object is a link slave, ie its link is controlled
152 # by its link master interface, then dont set the link state.
153 # But do allow user to change state of the link if the interface
154 # is already with its link master (hence the master check).
7e2e64fb
RP
155 if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
156 return
a070c90e 157 if not self.link_exists(ifaceobj.name):
7e2e64fb 158 return
a070c90e 159 self.link_down(ifaceobj.name)
be0b20f2 160
31a5f4c3 161 # ifupdown object interface operation handlers
be0b20f2 162 ops_handlers = OrderedDict([('up', run_up),
163 ('down', run_down)])
a6f80f0e 164
cb7cc592 165 def run_sched_ifaceobj_posthook(self, ifaceobj, op):
dbc018d3
RP
166 if (ifaceobj.priv_flags and (ifaceobj.priv_flags.BUILTIN or
167 ifaceobj.priv_flags.NOCONFIG)):
5c721925 168 return
dbc018d3 169 if self.flags.STATEMANAGER_UPDATE:
cb7cc592 170 self.statemanager.ifaceobj_sync(ifaceobj, op)
31a5f4c3 171
172 # ifupdown object interface scheduler pre and posthooks
173 sched_hooks = {'posthook' : run_sched_ifaceobj_posthook}
174
14dc390d 175 def __init__(self, config={},
176 force=False, dryrun=False, nowait=False,
cca03c30 177 perfmode=False, withdepends=False, njobs=1,
14dc390d 178 cache=False, addons_enable=True, statemanager_enable=True,
3dcc1d0e 179 interfacesfile='/etc/network/interfaces',
180 interfacesfileiobuf=None,
181 interfacesfileformat='native'):
2c0ad8b3
RP
182 """This member function initializes the ifupdownmain object.
183
184 Kwargs:
185 config (dict): config dict from /etc/network/ifupdown2/ifupdown2.conf
186 force (bool): force interface configuration
187 dryrun (bool): dryrun interface configuration
188 withdepends (bool): apply interface configuration on all depends
189 interfacesfile (str): interfaces file. default is /etc/network/interfaces
190 interfacesfileformat (str): default is 'native'. Other choices are 'json'
191
192 Raises:
193 AttributeError, KeyError """
194
a6f80f0e 195 self.logger = logging.getLogger('ifupdown')
eab25b7c 196 self.FORCE = force
197 self.DRYRUN = dryrun
198 self.NOWAIT = nowait
199 self.PERFMODE = perfmode
739f665b 200 self.CACHE = cache
dbc018d3
RP
201 # Can be used to provide hints for caching
202 self.CACHE_FLAGS = 0x0
203
204 self.flags = ifupdownMainFlags()
205
206 self.flags.WITH_DEPENDS = withdepends
207 self.flags.STATEMANAGER_ENABLE = statemanager_enable
14dc390d 208 self.interfacesfile = interfacesfile
3dcc1d0e 209 self.interfacesfileiobuf = interfacesfileiobuf
210 self.interfacesfileformat = interfacesfileformat
14dc390d 211 self.config = config
212 self.logger.debug(self.config)
67cfaeb1 213 self.blacklisted_ifaces_present = False
a690dfae 214
2da58137
RP
215 self.type = ifaceType.UNKNOWN
216
dbc018d3
RP
217 self.flags.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
218 self.flags.ADDONS_ENABLE = addons_enable
eab25b7c 219
84ca006f
RP
220 # Copy flags into ifupdownFlags
221 # XXX: before we transition fully to ifupdownFlags
222 ifupdownFlags.FORCE = force
223 ifupdownFlags.DRYRUN = dryrun
224 ifupdownFlags.NOWAIT = nowait
225 ifupdownFlags.PERFMODE = perfmode
226 ifupdownFlags.CACHE = cache
227
a6f80f0e 228 self.ifaces = OrderedDict()
eab25b7c 229 self.njobs = njobs
a6f80f0e 230 self.pp = pprint.PrettyPrinter(indent=4)
37c0543d 231 self.modules = OrderedDict({})
d08d5f54 232 self.module_attrs = {}
20dd6242 233
37c0543d 234 self.load_addon_modules(self.addon_modules_dir)
dbc018d3 235 if self.flags.COMPAT_EXEC_SCRIPTS:
e938bfec 236 self.load_scripts(self.scripts_dir)
d08d5f54 237 self.dependency_graph = OrderedDict({})
a6f80f0e 238
8e113d63
RP
239 self._cache_no_repeats = {}
240
dbc018d3 241 if self.flags.STATEMANAGER_ENABLE:
20dd6242 242 try:
55072bd1 243 self.statemanager = statemanager.statemanager_api
20dd6242 244 self.statemanager.read_saved_state()
245 except Exception, e:
246 # XXX Maybe we should continue by ignoring old state
247 self.logger.warning('error reading state (%s)' %str(e))
248 raise
249 else:
dbc018d3 250 self.flags.STATEMANAGER_UPDATE = False
a070c90e
RP
251 self._delay_admin_state = True if self.config.get(
252 'delay_admin_state_change', '0') == '1' else False
253 self._delay_admin_state_iface_queue = []
cebe79c9
RP
254 if self._delay_admin_state:
255 self.logger.info('\'delay_admin_state_change\' is set. admin ' +
256 'state changes will be delayed till the end.')
257
258 self._link_master_slave = True if self.config.get(
a070c90e 259 'link_master_slave', '0') == '1' else False
cebe79c9
RP
260 if self._link_master_slave:
261 self.logger.info('\'link_master_slave\' is set. slave admin ' +
262 'state changes will be delayed till the ' +
263 'masters admin state change.')
a6f80f0e 264
0582f185
RP
265 # initialize global config object with config passed by the user
266 # This makes config available to addon modules
267 ifupdownConfig.config = self.config
268
61c4d724
RP
269 def link_master_slave_ignore_error(self, errorstr):
270 # If link master slave flag is set,
271 # there may be cases where the lowerdev may not be
272 # up resulting in 'Network is down' error
273 # This can happen if the lowerdev is a LINK_SLAVE
274 # of another interface which is not up yet
275 # example of such a case:
276 # bringing up a vlan on a bond interface and the bond
277 # is a LINK_SLAVE of a bridge (in other words the bond is
278 # part of a bridge) which is not up yet
279 if self._link_master_slave:
280 if 'Network is down':
281 return True
282 return False
283
31a5f4c3 284 def get_ifaceobjs(self, ifacename):
a6f80f0e 285 return self.ifaceobjdict.get(ifacename)
286
a9ab1b4f
RP
287 def get_ifaceobjs_saved(self, ifacename):
288 """ Return ifaceobjects from statemanager """
dbc018d3 289 if self.flags.STATEMANAGER_ENABLE:
a9ab1b4f
RP
290 return self.statemanager.get_ifaceobjs(ifacename)
291 else:
292 None
293
31a5f4c3 294 def get_ifaceobj_first(self, ifacename):
295 ifaceobjs = self.get_ifaceobjs(ifacename)
296 if ifaceobjs:
a6f80f0e 297 return ifaceobjs[0]
298 return None
299
c798b0f4 300 def get_ifacenames(self):
301 return self.ifaceobjdict.keys()
302
a6f80f0e 303 def get_iface_obj_last(self, ifacename):
304 return self.ifaceobjdict.get(ifacename)[-1]
305
a9ab1b4f 306
8c13865c
RP
307 def must_follow_upperifaces(self, ifacename):
308 #
309 # XXX: This bleeds the knowledge of iface
310 # types in the infrastructure module.
311 # Cant think of a better fix at the moment.
312 # In future maybe the module can set a flag
313 # to indicate if we should follow upperifaces
314 #
315 ifaceobj = self.get_ifaceobj_first(ifacename)
cb46a208 316 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
8c13865c
RP
317 return False
318 return True
319
53b00224 320 def create_n_save_ifaceobj(self, ifacename, priv_flags=None,
321 increfcnt=False):
322 """ creates a iface object and adds it to the iface dictionary """
323 ifaceobj = iface()
324 ifaceobj.name = ifacename
325 ifaceobj.priv_flags = priv_flags
326 ifaceobj.auto = True
f3b69969
RP
327 if not self._link_master_slave:
328 ifaceobj.link_type = ifaceLinkType.LINK_NA
53b00224 329 if increfcnt:
330 ifaceobj.inc_refcnt()
331 self.ifaceobjdict[ifacename] = [ifaceobj]
332 return ifaceobj
333
d08d5f54 334 def create_n_save_ifaceobjcurr(self, ifaceobj):
923290bd 335 """ creates a copy of iface object and adds it to the iface
336 dict containing current iface objects
53b00224 337 """
739f665b 338 ifaceobjcurr = iface()
53b00224 339 ifaceobjcurr.name = ifaceobj.name
cb46a208 340 ifaceobjcurr.type = ifaceobj.type
62ddec8b 341 ifaceobjcurr.lowerifaces = ifaceobj.lowerifaces
dbc018d3 342 ifaceobjcurr.priv_flags = copy.deepcopy(ifaceobj.priv_flags)
2cd06f78 343 ifaceobjcurr.auto = ifaceobj.auto
923290bd 344 self.ifaceobjcurrdict.setdefault(ifaceobj.name,
345 []).append(ifaceobjcurr)
d08d5f54 346 return ifaceobjcurr
a6f80f0e 347
923290bd 348 def get_ifaceobjcurr(self, ifacename, idx=0):
349 ifaceobjlist = self.ifaceobjcurrdict.get(ifacename)
350 if not ifaceobjlist:
351 return None
352 if not idx:
353 return ifaceobjlist
354 else:
355 return ifaceobjlist[idx]
a6f80f0e 356
739f665b 357 def get_ifaceobjrunning(self, ifacename):
358 return self.ifaceobjrunningdict.get(ifacename)
359
a6f80f0e 360 def get_iface_refcnt(self, ifacename):
53b00224 361 """ Return iface ref count """
a6f80f0e 362 max = 0
31a5f4c3 363 ifaceobjs = self.get_ifaceobjs(ifacename)
20dd6242 364 if not ifaceobjs:
365 return 0
a6f80f0e 366 for i in ifaceobjs:
62ddec8b 367 if i.refcnt > max:
368 max = i.refcnt
a6f80f0e 369 return max
370
d08d5f54 371 def is_iface_builtin_byname(self, ifacename):
cca03c30 372 """ Returns true if iface name is a builtin interface.
a6f80f0e 373
cca03c30 374 A builtin interface is an interface which ifupdown understands.
375 The following are currently considered builtin ifaces:
376 - vlan interfaces in the format <ifacename>.<vlanid>
a6f80f0e 377 """
d08d5f54 378 return '.' in ifacename
a6f80f0e 379
37c0543d 380 def is_ifaceobj_builtin(self, ifaceobj):
381 """ Returns true if iface name is a builtin interface.
382
383 A builtin interface is an interface which ifupdown understands.
384 The following are currently considered builtin ifaces:
385 - vlan interfaces in the format <ifacename>.<vlanid>
386 """
dbc018d3
RP
387
388 return (ifaceobj.priv_flags and ifaceobj.priv_flags.BUILTIN)
37c0543d 389
390 def is_ifaceobj_noconfig(self, ifaceobj):
53b00224 391 """ Returns true if iface object did not have a user defined config.
37c0543d 392
393 These interfaces appear only when they are dependents of interfaces
394 which have user defined config
395 """
dbc018d3 396 return (ifaceobj.priv_flags and ifaceobj.priv_flags.NOCONFIG)
37c0543d 397
d08d5f54 398 def is_iface_noconfig(self, ifacename):
399 """ Returns true if iface has no config """
37c0543d 400
31a5f4c3 401 ifaceobj = self.get_ifaceobj_first(ifacename)
d08d5f54 402 if not ifaceobj: return True
d08d5f54 403 return self.is_ifaceobj_noconfig(ifaceobj)
404
45ca0b6d
RP
405 def check_shared_dependents(self, ifaceobj, dlist):
406 """ Check if dlist intersects with any other
407 interface with slave dependents.
408 example: bond and bridges.
409 This function logs such errors """
410 setdlist = Set(dlist)
411 for ifacename, ifacedlist in self.dependency_graph.items():
412 if not ifacedlist:
413 continue
414 check_depends = False
415 iobjs = self.get_ifaceobjs(ifacename)
dbc018d3
RP
416 if not iobjs:
417 continue
45ca0b6d
RP
418 for i in iobjs:
419 if (i.dependency_type == ifaceDependencyType.MASTER_SLAVE):
420 check_depends = True
421 if check_depends:
422 common = Set(ifacedlist).intersection(setdlist)
423 if common:
1cda1e43 424 self.logger.error('misconfig..?. iface %s and %s '
45ca0b6d 425 %(ifaceobj.name, ifacename) +
1cda1e43 426 'seem to share dependents/ports %s' %str(list(common)))
45ca0b6d 427
65e0c276
RP
428 def _set_iface_role_n_kind(self, ifaceobj, upperifaceobj):
429 if (upperifaceobj.link_kind & ifaceLinkKind.BOND):
430 ifaceobj.role |= ifaceRole.SLAVE
431 ifaceobj.link_kind |= ifaceLinkKind.BOND_SLAVE
432 if (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE):
433 ifaceobj.role |= ifaceRole.SLAVE
434 ifaceobj.link_kind |= ifaceLinkKind.BRIDGE_PORT
768b4ec5
RP
435 if self._link_master_slave:
436 if upperifaceobj.link_type == ifaceLinkType.LINK_MASTER:
437 ifaceobj.link_type = ifaceLinkType.LINK_SLAVE
438 else:
439 upperifaceobj.link_type = ifaceLinkType.LINK_NA
440 ifaceobj.link_type = ifaceLinkType.LINK_NA
21289e4a
RP
441 if (ifaceobj.link_kind == ifaceLinkKind.BOND_SLAVE and
442 len(ifaceobj.upperifaces) > 1):
443 self.logger.warn("misconfig..? bond slave \'%s\' is enslaved to multiple interfaces %s" %(ifaceobj.name, str(ifaceobj.upperifaces)))
65e0c276 444
7f045fd8 445 def preprocess_dependency_list(self, upperifaceobj, dlist, ops):
739f665b 446 """ We go through the dependency list and
447 delete or add interfaces from the interfaces dict by
448 applying the following rules:
dbc018d3 449 if flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
739f665b 450 we only consider devices whose configuration was
451 specified in the network interfaces file. We delete
452 any interface whose config was not specified except
453 for vlan devices. vlan devices get special treatment.
454 Even if they are not present they are created and added
455 to the ifacesdict
dbc018d3 456 elif flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
739f665b 457 we create objects for all dependent devices that are not
458 present in the ifacesdict
459 """
a6f80f0e 460 del_list = []
461
dbc018d3
RP
462 if (upperifaceobj.dependency_type == ifaceDependencyType.MASTER_SLAVE
463 and self.flags.CHECK_SHARED_DEPENDENTS):
45ca0b6d
RP
464 self.check_shared_dependents(upperifaceobj, dlist)
465
a6f80f0e 466 for d in dlist:
31a5f4c3 467 dilist = self.get_ifaceobjs(d)
d08d5f54 468 if not dilist:
7f045fd8 469 ni = None
d08d5f54 470 if self.is_iface_builtin_byname(d):
a070c90e 471 ni = self.create_n_save_ifaceobj(d,
dbc018d3
RP
472 ifacePrivFlags(True, True), True)
473 elif not self.flags.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG:
474 ni = self.create_n_save_ifaceobj(d,
475 ifacePrivFlags(False, True), True)
a6f80f0e 476 else:
a6f80f0e 477 del_list.append(d)
7f045fd8
RP
478 if ni:
479 ni.add_to_upperifaces(upperifaceobj.name)
21289e4a 480 self._set_iface_role_n_kind(ni, upperifaceobj)
a6f80f0e 481 else:
482 for di in dilist:
483 di.inc_refcnt()
7f045fd8 484 di.add_to_upperifaces(upperifaceobj.name)
21289e4a 485 self._set_iface_role_n_kind(di, upperifaceobj)
a6f80f0e 486 for d in del_list:
487 dlist.remove(d)
488
4cc2df04
RP
489 def preprocess_upperiface(self, lowerifaceobj, ulist, ops):
490 uifacelist = self.get_ifaceobjs(ulist[0])
491 if uifacelist:
492 lowerifaceobj.inc_refcnt()
493 for ui in uifacelist:
768b4ec5 494 self._set_iface_role_n_kind(lowerifaceobj, ui)
4cc2df04
RP
495 ui.add_to_lowerifaces(lowerifaceobj.name)
496
497 def query_lowerifaces(self, ifaceobj, ops, ifacenames, type=None):
a6f80f0e 498 """ Gets iface dependents by calling into respective modules """
41febf89 499 ret_dlist = []
a6f80f0e 500
20dd6242 501 # Get dependents for interface by querying respective modules
ee3fcf44 502 for module in self.modules.values():
7949b8a5 503 try:
504 if ops[0] == 'query-running':
505 if (not hasattr(module,
506 'get_dependent_ifacenames_running')):
507 continue
508 dlist = module.get_dependent_ifacenames_running(ifaceobj)
509 else:
510 if (not hasattr(module, 'get_dependent_ifacenames')):
511 continue
512 dlist = module.get_dependent_ifacenames(ifaceobj,
ee3fcf44 513 ifacenames)
7949b8a5 514 except Exception, e:
515 self.logger.warn('%s: error getting dependent interfaces (%s)'
516 %(ifaceobj.name, str(e)))
517 dlist = None
518 pass
41febf89 519 if dlist: ret_dlist.extend(dlist)
84ca006f 520 return list(set(ret_dlist))
20dd6242 521
4cc2df04
RP
522 def query_upperifaces(self, ifaceobj, ops, ifacenames, type=None):
523 """ Gets iface upperifaces by calling into respective modules """
524 ret_ulist = []
525
526 # Get upperifaces for interface by querying respective modules
527 for module in self.modules.values():
528 try:
529 if ops[0] == 'query-running':
530 if (not hasattr(module,
531 'get_upper_ifacenames_running')):
532 continue
533 ulist = module.get_upper_ifacenames_running(ifaceobj)
534 else:
535 if (not hasattr(module, 'get_upper_ifacenames')):
536 continue
537 ulist = module.get_upper_ifacenames(ifaceobj, ifacenames)
538 except Exception, e:
539 self.logger.warn('%s: error getting upper interfaces (%s)'
540 %(ifaceobj.name, str(e)))
541 ulist = None
542 pass
543 if ulist: ret_ulist.extend(ulist)
544 return list(set(ret_ulist))
45ca0b6d 545
e1601369
RP
546 def populate_dependency_info(self, ops, ifacenames=None):
547 """ recursive function to generate iface dependency info """
548
549 if not ifacenames:
550 ifacenames = self.ifaceobjdict.keys()
551
4cc2df04 552
e1601369
RP
553 iqueue = deque(ifacenames)
554 while iqueue:
555 i = iqueue.popleft()
556 # Go through all modules and find dependent ifaces
557 dlist = None
4cc2df04 558 ulist = None
2d8b307b
RP
559 ifaceobjs = self.get_ifaceobjs(i)
560 if not ifaceobjs:
e1601369 561 continue
4cc2df04 562 dependents_processed = False
2d8b307b
RP
563
564 # Store all dependency info in the first ifaceobj
565 # but get dependency info from all ifaceobjs
566 ifaceobj = ifaceobjs[0]
567 for iobj in ifaceobjs:
4cc2df04 568 ulist = self.query_upperifaces(iobj, ops, ifacenames)
2d8b307b 569 if iobj.lowerifaces:
4cc2df04 570 dependents_processed = True
2d8b307b 571 break
4cc2df04 572 dlist = self.query_lowerifaces(iobj, ops, ifacenames)
2d8b307b
RP
573 if dlist:
574 break
4cc2df04
RP
575 if ulist:
576 self.preprocess_upperiface(ifaceobj, ulist, ops)
577 ifaceobj.add_to_upperifaces(ulist)
578 if dependents_processed:
e1601369
RP
579 continue
580 if dlist:
7f045fd8 581 self.preprocess_dependency_list(ifaceobj,
e1601369
RP
582 dlist, ops)
583 ifaceobj.lowerifaces = dlist
584 [iqueue.append(d) for d in dlist]
4cc2df04
RP
585 #if not self.dependency_graph.get(i):
586 # self.dependency_graph[i] = dlist
587
588 for i in self.ifaceobjdict.keys():
589 iobj = self.get_ifaceobj_first(i)
590 if iobj.lowerifaces:
591 self.dependency_graph[i] = iobj.lowerifaces
592 else:
593 self.dependency_graph[i] = []
e1601369 594
67cfaeb1
RP
595 if not self.blacklisted_ifaces_present:
596 return
597
598 # Walk through the dependency graph and remove blacklisted
599 # interfaces that were picked up as dependents
600 for i in self.dependency_graph.keys():
601 ifaceobj = self.get_ifaceobj_first(i)
602 if not ifaceobj:
603 continue
604 if ifaceobj.blacklisted and not ifaceobj.upperifaces:
605 # if blacklisted and was not picked up as a
606 # dependent of a upper interface, delete the
607 # interface from the dependency graph
608 dlist = ifaceobj.lowerifaces
609 if dlist:
610 for d in dlist:
397214a5
RP
611 difaceobjs = self.get_ifaceobjs(d)
612 if not difaceobjs:
67cfaeb1 613 continue
67cfaeb1 614 try:
397214a5
RP
615 for d in difaceobjs:
616 d.dec_refcnt()
617 d.upperifaces.remove(i)
67cfaeb1
RP
618 except:
619 self.logger.debug('error removing %s from %s upperifaces' %(i, d))
620 pass
621 self.logger.debug("populate_dependency_info: deleting blacklisted interface %s" %i)
622 del self.dependency_graph[i]
623
8e113d63
RP
624 def _check_config_no_repeats(self, ifaceobj):
625 """ check if object has an attribute that is
626 restricted to a single object in the system.
627 if yes, warn and return """
628 for k,v in self._cache_no_repeats.items():
629 iv = ifaceobj.config.get(k)
630 if iv and iv[0] == v:
631 self.logger.error('ignoring interface %s. ' %ifaceobj.name +
632 'Only one object with attribute ' +
633 '\'%s %s\' allowed.' %(k, v))
634 return True
635 for k, v in self.config.get('no_repeats', {}).items():
636 iv = ifaceobj.config.get(k)
637 if iv and iv[0] == v:
638 self._cache_no_repeats[k] = v
639 return False
a6f80f0e 640
41febf89 641 def _save_iface(self, ifaceobj):
8e113d63
RP
642 if self._check_config_no_repeats(ifaceobj):
643 return
dbc018d3 644 ifaceobj.priv_flags = ifacePrivFlags()
7e2e64fb
RP
645 if not self._link_master_slave:
646 ifaceobj.link_type = ifaceLinkType.LINK_NA
679e6567
RP
647 currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
648 if not currentifaceobjlist:
649 self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
0582f185 650 ifaceobj.flags |= ifaceobj.YOUNGEST_SIBLING
679e6567
RP
651 return
652 if ifaceobj.compare(currentifaceobjlist[0]):
653 self.logger.warn('duplicate interface %s found' %ifaceobj.name)
654 return
8e113d63 655 if currentifaceobjlist[0].type == ifaceobj.type:
7444feea
ST
656 currentifaceobjlist[0].flags |= ifaceobj.HAS_SIBLINGS
657 ifaceobj.flags |= ifaceobj.HAS_SIBLINGS
658 # clear the OLDEST_SIBLING from all the siblings
659 for iface in self.ifaceobjdict[ifaceobj.name]:
660 iface.flags &= ~ifaceobj.OLDEST_SIBLING
661 # current sibling is the oldest
662 ifaceobj.flags |= ifaceobj.OLDEST_SIBLING
679e6567 663 self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
41febf89 664
3dcc1d0e 665 def _iface_configattr_syntax_checker(self, attrname, attrval):
d08d5f54 666 for m, mdict in self.module_attrs.items():
7949b8a5 667 if not mdict:
668 continue
d08d5f54 669 attrsdict = mdict.get('attrs')
7949b8a5 670 try:
671 if attrsdict.get(attrname):
672 return True
673 except AttributeError:
674 pass
d08d5f54 675 return False
676
3dcc1d0e 677 def _ifaceobj_syntax_checker(self, ifaceobj):
cfa06db6 678 ret = True
8e113d63 679 for attrname, attrvalue in ifaceobj.config.items():
3dcc1d0e 680 found = False
681 for k, v in self.module_attrs.items():
682 if v and v.get('attrs', {}).get(attrname):
683 found = True
684 break
685 if not found:
cfa06db6 686 ret = False
fa714fa2
ST
687 self.logger.warn('%s: unsupported attribute \'%s\'' \
688 % (ifaceobj.name, attrname))
3dcc1d0e 689 continue
cfa06db6 690 return ret
3dcc1d0e 691
14dc390d 692 def read_iface_config(self):
a6f80f0e 693 """ Reads default network interface config /etc/network/interfaces. """
cfa06db6 694 ret = True
14dc390d 695 nifaces = networkInterfaces(self.interfacesfile,
3dcc1d0e 696 self.interfacesfileiobuf,
697 self.interfacesfileformat,
14dc390d 698 template_engine=self.config.get('template_engine'),
699 template_lookuppath=self.config.get('template_lookuppath'))
d08d5f54 700 nifaces.subscribe('iface_found', self._save_iface)
3dcc1d0e 701 nifaces.subscribe('validateifaceattr',
702 self._iface_configattr_syntax_checker)
703 nifaces.subscribe('validateifaceobj', self._ifaceobj_syntax_checker)
a6f80f0e 704 nifaces.load()
cfa06db6
RP
705 if nifaces.errors or nifaces.warns:
706 ret = False
707 return ret
a6f80f0e 708
a6f80f0e 709 def read_old_iface_config(self):
14dc390d 710 """ Reads the saved iface config instead of default iface config.
711 And saved iface config is already read by the statemanager """
cb7cc592 712 self.ifaceobjdict = copy.deepcopy(self.statemanager.ifaceobjdict)
a6f80f0e 713
53b00224 714 def _load_addon_modules_config(self):
715 """ Load addon modules config file """
a6f80f0e 716
37c0543d 717 with open(self.addon_modules_configfile, 'r') as f:
718 lines = f.readlines()
719 for l in lines:
7bbc9340
RP
720 try:
721 litems = l.strip(' \n\t\r').split(',')
722 if not litems or len(litems) < 2:
723 continue
724 operation = litems[0]
725 mname = litems[1]
726 self.module_ops[operation].append(mname)
727 except Exception, e:
728 self.logger.warn('error reading line \'%s\'' %(l, str(e)))
729 continue
37c0543d 730
731 def load_addon_modules(self, modules_dir):
a6f80f0e 732 """ load python modules from modules_dir
733
734 Default modules_dir is /usr/share/ifupdownmodules
735
736 """
a6f80f0e 737 self.logger.info('loading builtin modules from %s' %modules_dir)
53b00224 738 self._load_addon_modules_config()
a6f80f0e 739 if not modules_dir in sys.path:
37c0543d 740 sys.path.append(modules_dir)
a6f80f0e 741 try:
be0b20f2 742 for op, mlist in self.module_ops.items():
d08d5f54 743 for mname in mlist:
53b00224 744 if self.modules.get(mname):
d08d5f54 745 continue
746 mpath = modules_dir + '/' + mname + '.py'
747 if os.path.exists(mpath):
748 try:
749 m = __import__(mname)
750 mclass = getattr(m, mname)
751 except:
752 raise
753 minstance = mclass(force=self.FORCE,
754 dryrun=self.DRYRUN,
755 nowait=self.NOWAIT,
756 perfmode=self.PERFMODE,
a690dfae 757 cache=self.CACHE,
758 cacheflags=self.CACHE_FLAGS)
d08d5f54 759 self.modules[mname] = minstance
53b00224 760 try:
d08d5f54 761 self.module_attrs[mname] = minstance.get_modinfo()
53b00224 762 except:
763 pass
a6f80f0e 764 except:
765 raise
766
37c0543d 767 # Assign all modules to query operations
be0b20f2 768 self.module_ops['query-checkcurr'] = self.modules.keys()
769 self.module_ops['query-running'] = self.modules.keys()
770 self.module_ops['query-dependency'] = self.modules.keys()
771 self.module_ops['query'] = self.modules.keys()
772 self.module_ops['query-raw'] = self.modules.keys()
d08d5f54 773
14dc390d 774
53b00224 775 def _modules_help(self):
776 """ Prints addon modules supported syntax """
777
d08d5f54 778 indent = ' '
779 for m, mdict in self.module_attrs.items():
780 if not mdict:
781 continue
782 print('%s: %s' %(m, mdict.get('mhelp')))
783 attrdict = mdict.get('attrs')
784 if not attrdict:
785 continue
786 try:
787 for attrname, attrvaldict in attrdict.items():
788 if attrvaldict.get('compat', False):
789 continue
790 print('%s%s' %(indent, attrname))
791 print('%shelp: %s' %(indent + ' ',
792 attrvaldict.get('help', '')))
793 print ('%srequired: %s' %(indent + ' ',
794 attrvaldict.get('required', False)))
795 default = attrvaldict.get('default')
796 if default:
797 print('%sdefault: %s' %(indent + ' ', default))
798
799 validrange = attrvaldict.get('validrange')
800 if validrange:
1b0b81a2 801 print('%svalidrange: %s-%s'
7949b8a5 802 %(indent + ' ', validrange[0], validrange[1]))
d08d5f54 803
804 validvals = attrvaldict.get('validvals')
805 if validvals:
806 print('%svalidvals: %s'
807 %(indent + ' ', ','.join(validvals)))
808
809 examples = attrvaldict.get('example')
810 if not examples:
811 continue
a6f80f0e 812
d08d5f54 813 print '%sexample:' %(indent + ' ')
814 for e in examples:
815 print '%s%s' %(indent + ' ', e)
816 except:
817 pass
818 print ''
819
37c0543d 820 def load_scripts(self, modules_dir):
a6f80f0e 821 """ loading user modules from /etc/network/.
822
823 Note that previously loaded python modules override modules found
824 under /etc/network if any
825
826 """
827
37c0543d 828 self.logger.info('looking for user scripts under %s' %modules_dir)
be0b20f2 829 for op, mlist in self.script_ops.items():
d08d5f54 830 msubdir = modules_dir + '/if-%s.d' %op
831 self.logger.info('loading scripts under %s ...' %msubdir)
832 try:
833 module_list = os.listdir(msubdir)
834 for module in module_list:
835 if self.modules.get(module) is not None:
836 continue
be0b20f2 837 self.script_ops[op].append(
a6f80f0e 838 msubdir + '/' + module)
d08d5f54 839 except:
f802fe3c 840 # continue reading
841 pass
a6f80f0e 842
a4912b99 843 def _sched_ifaces(self, ifacenames, ops, skipupperifaces=False,
e308cb82 844 followdependents=True, sort=False):
c798b0f4 845 self.logger.debug('scheduling \'%s\' for %s'
d08d5f54 846 %(str(ops), str(ifacenames)))
7538dc77 847 self._pretty_print_ordered_dict('dependency graph',
848 self.dependency_graph)
c798b0f4 849 return ifaceScheduler.sched_ifaces(self, ifacenames, ops,
850 dependency_graph=self.dependency_graph,
d08d5f54 851 order=ifaceSchedulerFlags.INORDER
852 if 'down' in ops[0]
c798b0f4 853 else ifaceSchedulerFlags.POSTORDER,
a4912b99 854 followdependents=followdependents,
e308cb82 855 skipupperifaces=skipupperifaces,
dbc018d3 856 sort=True if (sort or self.flags.IFACE_CLASS) else False)
a6f80f0e 857
41febf89
RP
858 def _render_ifacename(self, ifacename):
859 new_ifacenames = []
679e6567 860 vlan_match = re.match("^([\d]+)-([\d]+)", ifacename)
41febf89
RP
861 if vlan_match:
862 vlan_groups = vlan_match.groups()
863 if vlan_groups[0] and vlan_groups[1]:
679e6567 864 [new_ifacenames.append('%d' %v)
41febf89
RP
865 for v in range(int(vlan_groups[0]),
866 int(vlan_groups[1])+1)]
867 return new_ifacenames
868
869 def _preprocess_ifacenames(self, ifacenames):
a6f80f0e 870 """ validates interface list for config existance.
871
872 returns -1 if one or more interface not found. else, returns 0
873
874 """
41febf89 875 new_ifacenames = []
a6f80f0e 876 err_iface = ''
877 for i in ifacenames:
31a5f4c3 878 ifaceobjs = self.get_ifaceobjs(i)
879 if not ifaceobjs:
41febf89 880 # if name not available, render interface name and check again
679e6567 881 rendered_ifacenames = utils.expand_iface_range(i)
41febf89
RP
882 if rendered_ifacenames:
883 for ri in rendered_ifacenames:
884 ifaceobjs = self.get_ifaceobjs(ri)
885 if not ifaceobjs:
886 err_iface += ' ' + ri
887 else:
888 new_ifacenames.append(ri)
889 else:
890 err_iface += ' ' + i
891 else:
892 new_ifacenames.append(i)
fe0a57d3 893 if err_iface:
31c58787 894 raise Exception('cannot find interfaces:%s' %err_iface)
41febf89 895 return new_ifacenames
a6f80f0e 896
53b00224 897 def _iface_whitelisted(self, auto, allow_classes, excludepats, ifacename):
a6f80f0e 898 """ Checks if interface is whitelisted depending on set of parameters.
899
a6f80f0e 900 interfaces are checked against the allow_classes and auto lists.
901
902 """
1042b709 903
0532f0a3
RP
904 ret = True
905
19e2bf8c 906 # Check if interface matches the exclude patter
fe0a57d3 907 if excludepats:
3e8ee54f 908 for e in excludepats:
d08d5f54 909 if re.search(e, ifacename):
0532f0a3 910 ret = False
31a5f4c3 911 ifaceobjs = self.get_ifaceobjs(ifacename)
912 if not ifaceobjs:
0532f0a3
RP
913 if ret:
914 self.logger.debug('iface %s' %ifacename + ' not found')
915 return ret
67cfaeb1 916 # If matched exclude pattern, return false
0532f0a3
RP
917 if not ret:
918 for i in ifaceobjs:
919 i.blacklisted = True
67cfaeb1 920 self.blacklisted_ifaces_present = True
0532f0a3
RP
921 return ret
922 # Check if interface belongs to the class
67cfaeb1 923 # the user is interested in, if not return false
fe0a57d3 924 if allow_classes:
19e2bf8c 925 ret = False
a6f80f0e 926 for i in ifaceobjs:
62ddec8b 927 if i.classes:
3e8ee54f 928 common = Set([allow_classes]).intersection(
62ddec8b 929 Set(i.classes))
fe0a57d3 930 if common:
0532f0a3 931 ret = True
0532f0a3 932 if not ret:
19e2bf8c
RP
933 # If a class was requested and interface does not belong
934 # to the class, only then mark the ifaceobjs as blacklisted
935 self.blacklisted_ifaces_present = True
936 for i in ifaceobjs:
937 i.blacklisted = True
938 return ret
67cfaeb1
RP
939 # If the user has requested auto class, check if the interface
940 # is marked auto
d08d5f54 941 if auto:
19e2bf8c 942 ret = False
a6f80f0e 943 for i in ifaceobjs:
62ddec8b 944 if i.auto:
0532f0a3 945 ret = True
19e2bf8c
RP
946 if not ret:
947 # If auto was requested and interface was not marked auto,
948 # only then mark all of them as blacklisted
949 self.blacklisted_ifaces_present = True
950 for i in ifaceobjs:
0532f0a3
RP
951 i.blacklisted = True
952 return ret
a6f80f0e 953
53b00224 954 def _compat_conv_op_to_mode(self, op):
955 """ Returns old op name to work with existing scripts """
956 if op == 'pre-up':
957 return 'start'
958 elif op == 'pre-down':
959 return 'stop'
960 else:
961 return op
962
a6f80f0e 963 def generate_running_env(self, ifaceobj, op):
739f665b 964 """ Generates a dictionary with env variables required for
965 an interface. Used to support script execution for interfaces.
a6f80f0e 966 """
967
968 cenv = None
62ddec8b 969 iface_env = ifaceobj.env
970 if iface_env:
a6f80f0e 971 cenv = os.environ
d08d5f54 972 if cenv:
a6f80f0e 973 cenv.update(iface_env)
974 else:
975 cenv = iface_env
53b00224 976 cenv['MODE'] = self._compat_conv_op_to_mode(op)
a6f80f0e 977 return cenv
978
53b00224 979 def _save_state(self):
dbc018d3
RP
980 if (not self.flags.STATEMANAGER_ENABLE or
981 not self.flags.STATEMANAGER_UPDATE):
20dd6242 982 return
983 try:
984 # Update persistant iface states
985 self.statemanager.save_state()
986 except Exception, e:
987 if self.logger.isEnabledFor(logging.DEBUG):
988 t = sys.exc_info()[2]
989 traceback.print_tb(t)
990 self.logger.warning('error saving state (%s)' %str(e))
991
2da58137
RP
992 def set_type(self, type):
993 if type == 'iface':
994 self.type = ifaceType.IFACE
995 elif type == 'vlan':
996 self.type = ifaceType.BRIDGE_VLAN
997 else:
998 self.type = ifaceType.UNKNOWN
999
a070c90e
RP
1000 def _process_delay_admin_state_queue(self, op):
1001 if not self._delay_admin_state_iface_queue:
1002 return
1003 if op == 'up':
1004 func = self.link_up
1005 elif op == 'down':
1006 func = self.link_down
1007 else:
1008 return
1009 for i in self._delay_admin_state_iface_queue:
1010 try:
1011 if self.link_exists(i):
1012 func(i)
1013 except Exception, e:
1014 self.logger.warn(str(e))
1015 pass
1016
d08d5f54 1017 def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
2da58137 1018 excludepats=None, printdependency=None, syntaxcheck=False,
ad25e7bb 1019 type=None, skipupperifaces=False):
2c0ad8b3
RP
1020 """This brings the interface(s) up
1021
1022 Args:
41febf89
RP
1023 ops (list): list of ops to perform on the interface(s).
1024 Eg: ['pre-up', 'up', 'post-up'
2c0ad8b3
RP
1025
1026 Kwargs:
1027 auto (bool): act on interfaces marked auto
1028 allow_classes (list): act on interfaces belonging to classes in the list
1029 ifacenames (list): act on interfaces specified in this list
1030 excludepats (list): list of patterns of interfaces to exclude
1031 syntaxcheck (bool): only perform syntax check
1032 """
53b00224 1033
2da58137
RP
1034 self.set_type(type)
1035
5ee3e1a8 1036 if allow_classes:
dbc018d3
RP
1037 self.flags.IFACE_CLASS = True
1038 if not self.flags.ADDONS_ENABLE:
1039 self.flags.STATEMANAGER_UPDATE = False
d08d5f54 1040 if auto:
dbc018d3
RP
1041 self.flags.ALL = True
1042 self.flags.WITH_DEPENDS = True
d08d5f54 1043 try:
cfa06db6 1044 iface_read_ret = self.read_iface_config()
62ddec8b 1045 except Exception:
d08d5f54 1046 raise
a6f80f0e 1047
31a5f4c3 1048 if ifacenames:
41febf89 1049 ifacenames = self._preprocess_ifacenames(ifacenames)
a6f80f0e 1050
1051 # if iface list not given by user, assume all from config file
31a5f4c3 1052 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
a6f80f0e 1053
1054 # filter interfaces based on auto and allow classes
cca03c30 1055 filtered_ifacenames = [i for i in ifacenames
53b00224 1056 if self._iface_whitelisted(auto, allow_classes,
d08d5f54 1057 excludepats, i)]
fe0a57d3 1058 if not filtered_ifacenames:
d08d5f54 1059 raise Exception('no ifaces found matching given allow lists')
a6f80f0e 1060
20dd6242 1061 if printdependency:
c798b0f4 1062 self.populate_dependency_info(ops, filtered_ifacenames)
d08d5f54 1063 self.print_dependency(filtered_ifacenames, printdependency)
739f665b 1064 return
cca03c30 1065 else:
c798b0f4 1066 self.populate_dependency_info(ops)
1067
cfa06db6
RP
1068 # If only syntax check was requested, return here.
1069 # return here because we want to make sure most
1070 # errors above are caught and reported.
21289e4a 1071 if syntaxcheck:
cfa06db6
RP
1072 if not iface_read_ret:
1073 raise Exception()
21289e4a
RP
1074 return
1075
525f0a30 1076 try:
ad25e7bb 1077 self._sched_ifaces(filtered_ifacenames, ops,
a4912b99 1078 skipupperifaces=skipupperifaces,
dbc018d3 1079 followdependents=True if self.flags.WITH_DEPENDS else False)
525f0a30 1080 finally:
a070c90e 1081 self._process_delay_admin_state_queue('up')
dbc018d3 1082 if not self.DRYRUN and self.flags.ADDONS_ENABLE:
525f0a30 1083 self._save_state()
a6f80f0e 1084
d08d5f54 1085 def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
2da58137
RP
1086 excludepats=None, printdependency=None, usecurrentconfig=False,
1087 type=None):
53b00224 1088 """ down an interface """
1089
2da58137
RP
1090 self.set_type(type)
1091
5ee3e1a8 1092 if allow_classes:
dbc018d3
RP
1093 self.flags.IFACE_CLASS = True
1094 if not self.flags.ADDONS_ENABLE:
1095 self.flags.STATEMANAGER_UPDATE = False
d08d5f54 1096 if auto:
dbc018d3
RP
1097 self.flags.ALL = True
1098 self.flags.WITH_DEPENDS = True
5c721925 1099 # For down we need to look at old state, unless usecurrentconfig
1100 # is set
dbc018d3 1101 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE and
53b00224 1102 self.statemanager.ifaceobjdict):
31a5f4c3 1103 # Since we are using state manager objects,
1104 # skip the updating of state manager objects
5c721925 1105 self.logger.debug('Looking at old state ..')
d08d5f54 1106 self.read_old_iface_config()
fe0a57d3 1107 else:
d08d5f54 1108 # If no old state available
d08d5f54 1109 try:
1110 self.read_iface_config()
1111 except Exception, e:
1112 raise Exception('error reading iface config (%s)' %str(e))
d08d5f54 1113 if ifacenames:
1114 # If iface list is given by the caller, always check if iface
1115 # is present
31c58787 1116 try:
41febf89 1117 ifacenames = self._preprocess_ifacenames(ifacenames)
31c58787 1118 except Exception, e:
1119 raise Exception('%s' %str(e) +
1120 ' (interface was probably never up ?)')
1121
d08d5f54 1122 # if iface list not given by user, assume all from config file
fe0a57d3 1123 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
53b00224 1124
d08d5f54 1125 # filter interfaces based on auto and allow classes
1126 filtered_ifacenames = [i for i in ifacenames
53b00224 1127 if self._iface_whitelisted(auto, allow_classes,
d08d5f54 1128 excludepats, i)]
fe0a57d3 1129 if not filtered_ifacenames:
c0071225 1130 raise Exception('no ifaces found matching given allow lists ' +
41febf89 1131 '(or interfaces were probably never up ?)')
14dc390d 1132
d08d5f54 1133 if printdependency:
99b212b0 1134 self.populate_dependency_info(ops, filtered_ifacenames)
d08d5f54 1135 self.print_dependency(filtered_ifacenames, printdependency)
1136 return
99b212b0 1137 else:
1138 self.populate_dependency_info(ops)
525f0a30 1139
1140 try:
a4912b99 1141 self._sched_ifaces(filtered_ifacenames, ops,
dbc018d3
RP
1142 followdependents=True
1143 if self.flags.WITH_DEPENDS else False)
525f0a30 1144 finally:
a070c90e 1145 self._process_delay_admin_state_queue('down')
dbc018d3 1146 if not self.DRYRUN and self.flags.ADDONS_ENABLE:
525f0a30 1147 self._save_state()
d08d5f54 1148
1149 def query(self, ops, auto=False, allow_classes=None, ifacenames=None,
739f665b 1150 excludepats=None, printdependency=None,
2da58137 1151 format='native', type=None):
53b00224 1152 """ query an interface """
1153
2da58137
RP
1154 self.set_type(type)
1155
5ee3e1a8 1156 if allow_classes:
dbc018d3
RP
1157 self.flags.IFACE_CLASS = True
1158 if self.flags.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
5c721925 1159 return self.statemanager.dump_pretty(ifacenames)
dbc018d3 1160 self.flags.STATEMANAGER_UPDATE = False
d08d5f54 1161 if auto:
739f665b 1162 self.logger.debug('setting flag ALL')
dbc018d3
RP
1163 self.flags.ALL = True
1164 self.flags.WITH_DEPENDS = True
739f665b 1165
d08d5f54 1166 if ops[0] == 'query-syntax':
53b00224 1167 self._modules_help()
d08d5f54 1168 return
1169 elif ops[0] == 'query-running':
739f665b 1170 # create fake devices to all dependents that dont have config
dbc018d3
RP
1171 map(lambda i: self.create_n_save_ifaceobj(i,
1172 ifacePrivFlags(False, True)), ifacenames)
739f665b 1173 else:
1174 try:
1175 self.read_iface_config()
1176 except Exception:
1177 raise
1178
53b00224 1179 if ifacenames and ops[0] != 'query-running':
41febf89
RP
1180 # If iface list is given, always check if iface is present
1181 ifacenames = self._preprocess_ifacenames(ifacenames)
739f665b 1182
1183 # if iface list not given by user, assume all from config file
31a5f4c3 1184 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
739f665b 1185
1186 # filter interfaces based on auto and allow classes
d08d5f54 1187 if ops[0] == 'query-running':
739f665b 1188 filtered_ifacenames = ifacenames
1189 else:
1190 filtered_ifacenames = [i for i in ifacenames
53b00224 1191 if self._iface_whitelisted(auto, allow_classes,
d08d5f54 1192 excludepats, i)]
fe0a57d3 1193 if not filtered_ifacenames:
739f665b 1194 raise Exception('no ifaces found matching ' +
1195 'given allow lists')
37c0543d 1196
e1601369 1197 self.populate_dependency_info(ops)
d08d5f54 1198 if ops[0] == 'query-dependency' and printdependency:
1199 self.print_dependency(filtered_ifacenames, printdependency)
1200 return
739f665b 1201
75730152 1202 if ops[0] == 'query':
1203 return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
1204 elif ops[0] == 'query-raw':
1205 return self.print_ifaceobjs_raw(filtered_ifacenames)
1206
a4912b99 1207 self._sched_ifaces(filtered_ifacenames, ops,
dbc018d3
RP
1208 followdependents=True
1209 if self.flags.WITH_DEPENDS else False)
739f665b 1210
d08d5f54 1211 if ops[0] == 'query-checkcurr':
1212 ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format)
739f665b 1213 if ret != 0:
1214 # if any of the object has an error, signal that silently
1215 raise Exception('')
d08d5f54 1216 elif ops[0] == 'query-running':
1217 self.print_ifaceobjsrunning_pretty(filtered_ifacenames, format)
739f665b 1218 return
1219
2da58137
RP
1220 def _reload_currentlyup(self, upops, downops, auto=True, allow=None,
1221 ifacenames=None, excludepats=None, usecurrentconfig=False,
cfa06db6 1222 syntaxcheck=False, **extra_args):
2da58137 1223 """ reload currently up interfaces """
c0071225 1224 new_ifaceobjdict = {}
739f665b 1225
2da58137
RP
1226 # Override auto to true
1227 auto = True
2da58137 1228 try:
cfa06db6 1229 iface_read_ret = self.read_iface_config()
2da58137
RP
1230 except:
1231 raise
2da58137
RP
1232 if not self.ifaceobjdict:
1233 self.logger.warn("nothing to reload ..exiting.")
1234 return
2da58137 1235 already_up_ifacenames = []
1042b709
RP
1236 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1237 filtered_ifacenames = [i for i in ifacenames
1238 if self._iface_whitelisted(auto, allow,
1239 excludepats, i)]
1240
2da58137
RP
1241 # generate dependency graph of interfaces
1242 self.populate_dependency_info(upops)
cfa06db6
RP
1243
1244 # If only syntax check was requested, return here.
1245 # return here because we want to make sure most
1246 # errors above are caught and reported.
1247 if syntaxcheck:
1248 if not iface_read_ret:
1249 raise Exception()
1250 return
1251
dbc018d3 1252 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE
2da58137
RP
1253 and self.statemanager.ifaceobjdict):
1254 already_up_ifacenames = self.statemanager.ifaceobjdict.keys()
1255
2da58137
RP
1256 # Get already up interfaces that still exist in the interfaces file
1257 already_up_ifacenames_not_present = Set(
1258 already_up_ifacenames).difference(ifacenames)
1259 already_up_ifacenames_still_present = Set(
1260 already_up_ifacenames).difference(
1261 already_up_ifacenames_not_present)
1262 interfaces_to_up = Set(already_up_ifacenames_still_present).union(
1263 filtered_ifacenames)
1264
1265 if (already_up_ifacenames_not_present and
1266 self.config.get('ifreload_currentlyup_down_notpresent') == '1'):
1267 self.logger.info('reload: schedule down on interfaces: %s'
1268 %str(already_up_ifacenames_not_present))
1269
1270 # Save a copy of new iface objects and dependency_graph
1271 new_ifaceobjdict = dict(self.ifaceobjdict)
1272 new_dependency_graph = dict(self.dependency_graph)
1273
1274 # old interface config is read into self.ifaceobjdict
1275 self.read_old_iface_config()
1276
1277 # reinitialize dependency graph
1278 self.dependency_graph = OrderedDict({})
1042b709
RP
1279 falready_up_ifacenames_not_present = [i for i in
1280 already_up_ifacenames_not_present
1281 if self._iface_whitelisted(auto, allow,
1282 excludepats, i)]
2da58137 1283 self.populate_dependency_info(downops,
1042b709
RP
1284 falready_up_ifacenames_not_present)
1285 self._sched_ifaces(falready_up_ifacenames_not_present, downops,
e308cb82 1286 followdependents=False, sort=True)
2da58137
RP
1287 else:
1288 self.logger.debug('no interfaces to down ..')
1289
1290 # Now, run 'up' with new config dict
1291 # reset statemanager update flag to default
e308cb82 1292 if auto:
dbc018d3
RP
1293 self.flags.ALL = True
1294 self.flags.WITH_DEPENDS = True
2da58137 1295 if new_ifaceobjdict:
3d44fbd0 1296 # and now, ifaceobjdict is back to current config
2da58137
RP
1297 self.ifaceobjdict = new_ifaceobjdict
1298 self.dependency_graph = new_dependency_graph
1299
1300 if not self.ifaceobjdict:
1301 return
1302 self.logger.info('reload: scheduling up on interfaces: %s'
1303 %str(interfaces_to_up))
a4912b99 1304 self._sched_ifaces(interfaces_to_up, upops,
dbc018d3
RP
1305 followdependents=True
1306 if self.flags.WITH_DEPENDS else False)
2da58137
RP
1307 if self.DRYRUN:
1308 return
1309 self._save_state()
1310
1311 def _reload_default(self, upops, downops, auto=False, allow=None,
1312 ifacenames=None, excludepats=None, usecurrentconfig=False,
cfa06db6 1313 syntaxcheck=False, **extra_args):
2da58137 1314 """ reload interface config """
2da58137 1315 new_ifaceobjdict = {}
739f665b 1316
1317 try:
cfa06db6 1318 iface_read_ret = self.read_iface_config()
20dd6242 1319 except:
739f665b 1320 raise
1321
c0071225
RP
1322 if not self.ifaceobjdict:
1323 self.logger.warn("nothing to reload ..exiting.")
1324 return
1042b709
RP
1325
1326 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1327 new_filtered_ifacenames = [i for i in ifacenames
1328 if self._iface_whitelisted(auto, allow,
1329 excludepats, i)]
37c0543d 1330 # generate dependency graph of interfaces
c798b0f4 1331 self.populate_dependency_info(upops)
1042b709 1332
cfa06db6
RP
1333 # If only syntax check was requested, return here.
1334 # return here because we want to make sure most
1335 # errors above are caught and reported.
1336 if syntaxcheck:
1337 if not iface_read_ret:
1338 raise Exception()
1339 return
1340
dbc018d3 1341 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE
14dc390d 1342 and self.statemanager.ifaceobjdict):
1343 # Save a copy of new iface objects and dependency_graph
1344 new_ifaceobjdict = dict(self.ifaceobjdict)
1345 new_dependency_graph = dict(self.dependency_graph)
37c0543d 1346
dbc018d3
RP
1347 self.ifaceobjdict = OrderedDict({})
1348 self.dependency_graph = OrderedDict({})
1349
739f665b 1350 # if old state is present, read old state and mark op for 'down'
1351 # followed by 'up' aka: reload
37c0543d 1352 # old interface config is read into self.ifaceobjdict
739f665b 1353 self.read_old_iface_config()
1354 op = 'reload'
1355 else:
1356 # oldconfig not available, continue with 'up' with new config
1357 op = 'up'
1358
fe0a57d3 1359 if op == 'reload' and ifacenames:
93b399fb 1360 ifacenames = self.ifaceobjdict.keys()
1042b709
RP
1361 old_filtered_ifacenames = [i for i in ifacenames
1362 if self._iface_whitelisted(auto, allow,
d08d5f54 1363 excludepats, i)]
e308cb82 1364
dbc018d3
RP
1365 # generate dependency graph of old interfaces,
1366 # This should make sure built in interfaces are
1367 # populated. disable check shared dependents as an optimization.
1368 # these are saved interfaces and dependency for these
1369 # have been checked before they became part of saved state.
1370 self.flags.CHECK_SHARED_DEPENDENTS = False
1371 self.populate_dependency_info(upops)
1372 self.flags.CHECK_SHARED_DEPENDENTS = True
1373
1374 # make sure we pick up built-in interfaces
e308cb82
RP
1375 # if config file had 'ifreload_down_changed' variable
1376 # set, also look for interfaces that changed to down them
1377 down_changed = int(self.config.get('ifreload_down_changed', '1'))
1378
37c0543d 1379 # Generate the interface down list
1380 # Interfaces that go into the down list:
1381 # - interfaces that were present in last config and are not
1382 # present in the new config
1383 # - interfaces that were changed between the last and current
1384 # config
37c0543d 1385 ifacedownlist = []
dbc018d3 1386 for ifname in self.ifaceobjdict.keys():
2da58137 1387 lastifaceobjlist = self.ifaceobjdict.get(ifname)
dbc018d3
RP
1388 if not self.is_ifaceobj_builtin(lastifaceobjlist[0]):
1389 # if interface is not built-in and is not in
1390 # old filtered ifacenames
1391 if ifname not in old_filtered_ifacenames:
1392 continue
37c0543d 1393 objidx = 0
37c0543d 1394 # If interface is not present in the new file
1395 # append it to the down list
53b00224 1396 newifaceobjlist = new_ifaceobjdict.get(ifname)
1397 if not newifaceobjlist:
37c0543d 1398 ifacedownlist.append(ifname)
1399 continue
21289e4a
RP
1400 # If ifaceobj was present in the old interfaces file,
1401 # and does not have a config in the new interfaces file
1402 # but has been picked up as a dependent of another
1403 # interface, catch it here. This catches a common error
1404 # for example: remove a bond section from the interfaces
1405 # file, but leave it around as a bridge port
1406 # XXX: Ideally its better to just add it to the
1407 # ifacedownlist. But we will be cautious here
1408 # and just print a warning
1409 if (self.is_ifaceobj_noconfig(newifaceobjlist[0]) and
dbc018d3 1410 not self.is_ifaceobj_builtin(newifaceobjlist[0]) and
21289e4a
RP
1411 lastifaceobjlist[0].is_config_present()):
1412 self.logger.warn('%s: misconfig ? removed but still exists as a dependency of %s' %(newifaceobjlist[objidx].name,
1413 str(newifaceobjlist[objidx].upperifaces)))
26434da6
RP
1414 if not down_changed:
1415 continue
53b00224 1416 if len(newifaceobjlist) != len(lastifaceobjlist):
37c0543d 1417 ifacedownlist.append(ifname)
1418 continue
e308cb82
RP
1419
1420 # If interface has changed between the current file
1421 # and the last installed append it to the down list
37c0543d 1422 # compare object list
53b00224 1423 for objidx in range(0, len(lastifaceobjlist)):
1424 oldobj = lastifaceobjlist[objidx]
1425 newobj = newifaceobjlist[objidx]
ca3f4fc7 1426 if not newobj.compare(oldobj):
37c0543d 1427 ifacedownlist.append(ifname)
1428 continue
1429
fe0a57d3 1430 if ifacedownlist:
2da58137 1431 self.logger.info('reload: scheduling down on interfaces: %s'
739f665b 1432 %str(ifacedownlist))
20dd6242 1433 # reinitialize dependency graph
1434 self.dependency_graph = OrderedDict({})
dbc018d3 1435
37c0543d 1436 # Generate dependency info for old config
14dc390d 1437 self.populate_dependency_info(downops, ifacedownlist)
a070c90e 1438 try:
dbc018d3
RP
1439 # XXX: Hack to skip checking upperifaces during down.
1440 # the dependency list is not complete here
1441 # and we dont want to down the upperiface.
1442 # Hence during reload, set this to true.
1443 # This is being added to avoid a failure in
1444 # scheduler._check_upperifaces when we are dowing
1445 # a builtin bridge port
1446 self.flags.SCHED_SKIP_CHECK_UPPERIFACES = True
a4912b99 1447 self._sched_ifaces(ifacedownlist, downops,
e308cb82
RP
1448 followdependents=False,
1449 sort=True)
a070c90e
RP
1450 except Exception, e:
1451 self.logger.error(str(e))
1452 pass
1453 finally:
dbc018d3 1454 self.flags.SCHED_SKIP_CHECK_UPPERIFACES = False
a070c90e 1455 self._process_delay_admin_state_queue('down')
37c0543d 1456 else:
1457 self.logger.debug('no interfaces to down ..')
739f665b 1458
20dd6242 1459 # Now, run 'up' with new config dict
1460 # reset statemanager update flag to default
c0071225
RP
1461 if not new_ifaceobjdict:
1462 return
e308cb82
RP
1463
1464 if auto:
dbc018d3
RP
1465 self.flags.ALL = True
1466 self.flags.WITH_DEPENDS = True
3d44fbd0 1467 # and now, we are back to the current config in ifaceobjdict
53b00224 1468 self.ifaceobjdict = new_ifaceobjdict
1469 self.dependency_graph = new_dependency_graph
c798b0f4 1470
2da58137 1471 self.logger.info('reload: scheduling up on interfaces: %s'
1042b709 1472 %str(new_filtered_ifacenames))
a070c90e 1473 try:
1042b709 1474 self._sched_ifaces(new_filtered_ifacenames, upops,
dbc018d3
RP
1475 followdependents=True
1476 if self.flags.WITH_DEPENDS else False)
a070c90e
RP
1477 except Exception, e:
1478 self.logger.error(str(e))
1479 pass
1480 finally:
1481 self._process_delay_admin_state_queue('up')
e37ad4a6 1482 if self.DRYRUN:
1483 return
53b00224 1484 self._save_state()
a6f80f0e 1485
2da58137
RP
1486 def reload(self, *args, **kargs):
1487 """ reload interface config """
2da58137
RP
1488 self.logger.debug('reloading interface config ..')
1489 if kargs.get('currentlyup', False):
1490 self._reload_currentlyup(*args, **kargs)
1491 else:
1492 self._reload_default(*args, **kargs)
1493
7538dc77 1494 def _pretty_print_ordered_dict(self, prefix, argdict):
525f0a30 1495 outbuf = prefix + ' {\n'
53b00224 1496 for k, vlist in argdict.items():
525f0a30 1497 outbuf += '\t%s : %s\n' %(k, str(vlist))
7538dc77 1498 self.logger.debug(outbuf + '}')
a6f80f0e 1499
53b00224 1500 def print_dependency(self, ifacenames, format):
1501 """ prints iface dependency information """
a6f80f0e 1502
53b00224 1503 if not ifacenames:
1504 ifacenames = self.ifaceobjdict.keys()
1505 if format == 'list':
1506 for k,v in self.dependency_graph.items():
1507 print '%s : %s' %(k, str(v))
1508 elif format == 'dot':
1509 indegrees = {}
1510 map(lambda i: indegrees.update({i :
1511 self.get_iface_refcnt(i)}),
1512 self.dependency_graph.keys())
1513 graph.generate_dots(self.dependency_graph, indegrees)
a6f80f0e 1514
739f665b 1515 def print_ifaceobjs_raw(self, ifacenames):
53b00224 1516 """ prints raw lines for ifaces from config file """
1517
739f665b 1518 for i in ifacenames:
31a5f4c3 1519 for ifaceobj in self.get_ifaceobjs(i):
75730152 1520 if (self.is_ifaceobj_builtin(ifaceobj) or
1521 not ifaceobj.is_config_present()):
1522 continue
1523 ifaceobj.dump_raw(self.logger)
739f665b 1524 print '\n'
dbc018d3 1525 if self.flags.WITH_DEPENDS and not self.flags.ALL:
62ddec8b 1526 dlist = ifaceobj.lowerifaces
fe0a57d3 1527 if not dlist: continue
53b00224 1528 self.print_ifaceobjs_raw(dlist)
739f665b 1529
2cd06f78 1530 def _get_ifaceobjs_pretty(self, ifacenames, ifaceobjs, running=False):
1531 """ returns iface obj list """
53b00224 1532
a6f80f0e 1533 for i in ifacenames:
31a5f4c3 1534 for ifaceobj in self.get_ifaceobjs(i):
2cd06f78 1535 if ((not running and self.is_ifaceobj_noconfig(ifaceobj)) or
1536 (running and not ifaceobj.is_config_present())):
75730152 1537 continue
2cd06f78 1538 ifaceobjs.append(ifaceobj)
dbc018d3 1539 if self.flags.WITH_DEPENDS and not self.flags.ALL:
62ddec8b 1540 dlist = ifaceobj.lowerifaces
fe0a57d3 1541 if not dlist: continue
2cd06f78 1542 self._get_ifaceobjs_pretty(dlist, ifaceobjs, running)
739f665b 1543
2cd06f78 1544 def print_ifaceobjs_pretty(self, ifacenames, format='native'):
1545 """ pretty prints iface in format given by keyword arg format """
eab25b7c 1546
2cd06f78 1547 ifaceobjs = []
1548 self._get_ifaceobjs_pretty(ifacenames, ifaceobjs)
1549 if not ifaceobjs: return
1550 if format == 'json':
3dcc1d0e 1551 print json.dumps(ifaceobjs, cls=ifaceJsonEncoder,
1552 indent=4, separators=(',', ': '))
2cd06f78 1553 else:
2da58137
RP
1554 expand = int(self.config.get('ifquery_ifacename_expand_range', '0'))
1555 for i in ifaceobjs:
1556 if not expand and (i.flags & iface.IFACERANGE_ENTRY):
1557 # print only the first one
1558 if i.flags & iface.IFACERANGE_START:
1559 i.dump_pretty(use_realname=True)
1560 else:
1561 i.dump_pretty()
53b00224 1562
2cd06f78 1563 def _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs):
eab25b7c 1564 ret = 0
a6f80f0e 1565 for i in ifacenames:
923290bd 1566 ifaceobjscurr = self.get_ifaceobjcurr(i)
1567 if not ifaceobjscurr: continue
1568 for ifaceobj in ifaceobjscurr:
1569 if (ifaceobj.status == ifaceStatus.NOTFOUND or
1570 ifaceobj.status == ifaceStatus.ERROR):
1571 ret = 1
1572 if self.is_ifaceobj_noconfig(ifaceobj):
1573 continue
1574 ifaceobjs.append(ifaceobj)
dbc018d3 1575 if self.flags.WITH_DEPENDS and not self.flags.ALL:
923290bd 1576 dlist = ifaceobj.lowerifaces
1577 if not dlist: continue
1578 dret = self._get_ifaceobjscurr_pretty(dlist, ifaceobjs)
1579 if dret: ret = 1
2cd06f78 1580 return ret
1581
1582 def print_ifaceobjscurr_pretty(self, ifacenames, format='native'):
1583 """ pretty prints current running state of interfaces with status.
1584
1585 returns 1 if any of the interface has an error,
1586 else returns 0
1587 """
1588
1589 ifaceobjs = []
1590 ret = self._get_ifaceobjscurr_pretty(ifacenames, ifaceobjs)
1591 if not ifaceobjs: return
307e06bb
RP
1592
1593 # override ifaceStatusUserStrs
1594 ifaceStatusUserStrs.SUCCESS = self.config.get('ifquery_check_success_str', _success_sym)
1595 ifaceStatusUserStrs.ERROR = self.config.get('ifquery_check_error_str', _error_sym)
1596 ifaceStatusUserStrs.UNKNOWN = self.config.get('ifquery_check_unknown_str', '')
2cd06f78 1597 if format == 'json':
307e06bb
RP
1598 print json.dumps(ifaceobjs, cls=ifaceJsonEncoderWithStatus,
1599 indent=2, separators=(',', ': '))
2cd06f78 1600 else:
fb10449e 1601 map(lambda i: i.dump_pretty(with_status=True), ifaceobjs)
eab25b7c 1602 return ret
a6f80f0e 1603
d08d5f54 1604 def print_ifaceobjsrunning_pretty(self, ifacenames, format='native'):
53b00224 1605 """ pretty prints iface running state """
1606
2cd06f78 1607 ifaceobjs = []
1608 self._get_ifaceobjs_pretty(ifacenames, ifaceobjs, running=True)
1609 if not ifaceobjs: return
1610 if format == 'json':
1611 print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
1612 separators=(',', ': '))
1613 else:
1614 map(lambda i: i.dump_pretty(), ifaceobjs)
53b00224 1615
1616 def _dump(self):
1617 print 'ifupdown main object dump'
1618 print self.pp.pprint(self.modules)
1619 print self.pp.pprint(self.ifaceobjdict)
1620
1621 def _dump_ifaceobjs(self, ifacenames):
1622 for i in ifacenames:
1623 ifaceobjs = self.get_ifaceobjs(i)
1624 for i in ifaceobjs:
1625 i.dump(self.logger)
1626 print '\n'