]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/ifupdown/iface.py
ifupdown: ifupdownmain: create a copy of environment dictionary for addons scripts...
[mirror_ifupdown2.git] / ifupdown2 / ifupdown / iface.py
CommitLineData
a6f80f0e 1#!/usr/bin/python
3e8ee54f 2#
d486dd0d 3# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
3e8ee54f 4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6# iface --
7# interface object
8#
62ddec8b 9
10"""ifupdown2 network interface object
11
904908bc 12It is modeled based on the 'iface' section in /etc/network/interfaces
62ddec8b 13file. But can be extended to include any other network interface format
62ddec8b 14"""
15
2cd06f78 16import json
a6f80f0e 17
d486dd0d
JF
18from collections import OrderedDict
19
20
307e06bb
RP
21class ifaceStatusUserStrs():
22 """ This class declares strings user can see during an ifquery --check
23 for example. These strings can be overridden by user defined strings from
24 config file """
fb10449e
RP
25 SUCCESS = "success",
26 FAILURE = "error",
27 UNKNOWN = "unknown"
28
41febf89 29class ifaceType():
858a230f
RP
30 UNKNOWN = 0x00
31 IFACE = 0x01
32 BRIDGE_VLAN = 0x10
0a3bee28
ST
33
34class ifaceRole():
35 """ ifaceRole is used to classify the ifaceobj.role of
36 MASTER or SLAVE where there is a bond or bridge
37 with bond-slaves or bridge-ports. A bond in a bridge
38 is both a master and slave (0x3)
39 """
858a230f
RP
40 UNKNOWN = 0x00
41 SLAVE = 0x01
42 MASTER = 0x10
0a3bee28 43
a9ab1b4f 44class ifaceLinkKind():
0a3bee28
ST
45 """ ifaceLlinkKind is used to identify interfaces
46 in the ifaceobj.link_kind attribute. Dependents of the bridge or
47 bond have an ifaceobj.role attribute of SLAVE and the bridge or
48 bond itself has ifaceobj.role of MASTER.
49 """
d486dd0d
JF
50 UNKNOWN = 0x000000
51 BRIDGE = 0x000001
52 BOND = 0x000010
53 VLAN = 0x000100
54 VXLAN = 0x001000
55 VRF = 0x010000
56 # to indicate logical interface created by an external entity.
57 # the 'kind' of which ifupdown2 does not really understand
58 OTHER = 0x100000
59
60 @classmethod
61 def to_str(cls, kind):
62 if kind == cls.BRIDGE:
63 return "bridge"
64 elif kind == cls.BOND:
65 return "bond"
66 elif kind == cls.VLAN:
67 return "vlan"
68 elif kind == cls.VXLAN:
69 return "vxlan"
70 elif kind == cls.VRF:
71 return "vrf"
858a230f
RP
72
73class ifaceLinkPrivFlags():
74 """ This corresponds to kernel netdev->priv_flags
75 and can be BRIDGE_PORT, BOND_SLAVE etc """
ea9e3c0f
JF
76 UNKNOWN = 0x00000
77 BRIDGE_PORT = 0x00001
78 BOND_SLAVE = 0x00010
79 VRF_SLAVE = 0x00100
80 BRIDGE_VLAN_AWARE = 0x01000
81 BRIDGE_VXLAN = 0x10000
42e85fc8 82 ADDRESS_VIRTUAL_SLAVE = 0x100000
ae330408 83 LOOPBACK = 0x1000000
9858b0a6 84 KEEP_LINK_DOWN = 0x10000000
858a230f
RP
85
86 @classmethod
87 def get_str(cls, flag):
88 if flag == cls.UNKNOWN:
89 return 'unknown'
90 elif flag == cls.BRIDGE_PORT:
91 return 'bridge port'
92 elif flag == cls.BOND_SLAVE:
93 return 'bond slave'
94 elif flag == cls.VRF_SLAVE:
95 return 'vrf slave'
96 elif flag == cls.BRIDGE_VLAN_AWARE:
97 return 'vlan aware bridge'
ea9e3c0f
JF
98 elif flag == cls.BRIDGE_VXLAN:
99 return 'vxlan bridge'
858a230f
RP
100
101 @classmethod
102 def get_all_str(cls, flags):
103 str = ''
ea9e3c0f 104 if flags & cls.BRIDGE_PORT:
858a230f 105 str += 'bridgeport '
ea9e3c0f 106 if flags & cls.BOND_SLAVE:
858a230f 107 str += 'bondslave '
ea9e3c0f 108 if flags & cls.VRF_SLAVE:
858a230f 109 str += 'vrfslave '
ea9e3c0f 110 if flags & cls.BRIDGE_VLAN_AWARE:
858a230f 111 str += 'vlanawarebridge '
ea9e3c0f
JF
112 if flags & cls.BRIDGE_VXLAN:
113 str += 'vxlanbridge '
858a230f 114 return str
a9ab1b4f 115
c416da6a 116class ifaceLinkType():
a070c90e 117 LINK_UNKNOWN = 0x0
c416da6a
RP
118 LINK_SLAVE = 0x1
119 LINK_MASTER = 0x2
a070c90e 120 LINK_NA = 0x3
c416da6a 121
d486dd0d
JF
122class VlanProtocols():
123 # Picked ID values from
124 # http://www.microhowto.info/howto/configure_an_ethernet_interface_as_a_qinq_vlan_trunk.html
125 ETHERTYPES_TO_ID = {
126 '802.1Q' : '0x8100',
127 '802.1AD' : '0x88a8',
128 }
129 ID_TO_ETHERTYPES = {
130 '0x8100' : '802.1Q',
131 '0x88a8' : '802.1AD',
132 }
133
45ca0b6d
RP
134class ifaceDependencyType():
135 """ Indicates type of dependency.
136
137 This class enumerates types of dependency relationships
138 between interfaces.
139
140 iface dependency relationships can be classified
141 into:
142 - link
143 - master/slave
144
145 In a 'link' dependency relationship, dependency can be shared
146 between interfaces. example: swp1.100 and
147 swp1.200 can both have 'link' swp1. swp1 is also a dependency
148 of swp1.100 and swp1.200. As you can see dependency
149 swp1 is shared between swp1.100 and swp1.200.
d486dd0d 150
45ca0b6d
RP
151 In a master/slave relationship like bridge and
152 its ports: eg: bridge br0 and its ports swp1 and swp2.
153 dependency swp1 and swp2 cannot be shared with any other
154 interface with the same dependency relationship.
155 ie, swp1 and swp2 cannot be in a slave relationship
156 with another interface. Understanding the dependency type is
157 required for any semantic checks between dependencies.
158
159 """
160 UNKNOWN = 0x0
161 LINK = 0x1
162 MASTER_SLAVE = 0x2
163
a6f80f0e 164class ifaceStatus():
62ddec8b 165 """Enumerates iface status """
166
a6f80f0e 167 UNKNOWN = 0x1
168 SUCCESS = 0x2
ceed018d
RP
169 WARNING = 0x3
170 ERROR = 0x4
171 NOTFOUND = 0x5
a6f80f0e 172
173 @classmethod
174 def to_str(cls, state):
175 if state == cls.UNKNOWN:
176 return 'unknown'
177 elif state == cls.SUCCESS:
178 return 'success'
179 elif state == cls.ERROR:
180 return 'error'
739f665b 181 elif state == cls.NOTFOUND:
69f58278 182 return 'notfound'
d486dd0d 183
a6f80f0e 184 @classmethod
185 def from_str(cls, state_str):
186 if state_str == 'unknown':
187 return cls.UNKNOWN
188 elif state_str == 'success':
189 return cls.SUCCESS
190 elif state_str == 'error':
191 return cls.ERROR
192
193class ifaceState():
62ddec8b 194 """Enumerates iface state """
a6f80f0e 195
a6f80f0e 196 UNKNOWN = 0x1
197 NEW = 0x2
198 PRE_UP = 0x3
199 UP = 0x4
200 POST_UP = 0x5
201 PRE_DOWN = 0x6
202 DOWN = 0x7
203 POST_DOWN = 0x8
204
d08d5f54 205 # Pseudo states
206 QUERY_CHECKCURR = 0x9
207 QUERY_RUNNING = 0xa
208
a6f80f0e 209 @classmethod
210 def to_str(cls, state):
211 if state == cls.UNKNOWN:
212 return 'unknown'
213 elif state == cls.NEW:
214 return 'new'
215 elif state == cls.PRE_UP:
216 return 'pre-up'
217 elif state == cls.UP:
218 return 'up'
219 elif state == cls.POST_UP:
220 return 'post-up'
221 elif state == cls.PRE_DOWN:
222 return 'pre-down'
d08d5f54 223 elif state == cls.DOWN:
224 return 'down'
a6f80f0e 225 elif state == cls.POST_DOWN:
226 return 'post-down'
d08d5f54 227 elif state == cls.QUERY_CHECKCURR:
228 return 'query-checkcurr'
229 elif state == cls.QUERY_RUNNING:
230 return 'query-running'
a6f80f0e 231
232 @classmethod
233 def from_str(cls, state_str):
234 if state_str == 'unknown':
235 return cls.UNKNOWN
236 elif state_str == 'new':
237 return cls.NEW
238 elif state_str == 'pre-up':
239 return cls.PRE_UP
240 elif state_str == 'up':
241 return cls.UP
242 elif state_str == 'post-up':
243 return cls.POST_UP
244 elif state_str == 'pre-down':
245 return cls.PRE_DOWN
d08d5f54 246 elif state_str == 'down':
247 return cls.DOWN
a6f80f0e 248 elif state_str == 'post-down':
249 return cls.POST_DOWN
d08d5f54 250 elif state_str == 'query-checkcurr':
251 return cls.QUERY_CHECKCURR
252 elif state_str == 'query-running':
253 return cls.QUERY_RUNNING
a6f80f0e 254
d08d5f54 255class ifaceJsonEncoder(json.JSONEncoder):
f012209e 256 def default(self, o):
83c1f241 257 retconfig = {}
fb10449e 258 retifacedict = OrderedDict([])
d486dd0d 259 if o.config:
f012209e
RP
260 retconfig = dict((k, (v[0] if len(v) == 1 else v))
261 for k,v in o.config.items())
262 retifacedict['name'] = o.name
263 if o.addr_method:
b46f4b05
JF
264 if 'inet' in o.addr_family and 'dhcp' in o.addr_method:
265 retifacedict['addr_method'] = 'dhcp'
266 else:
267 retifacedict['addr_method'] = o.addr_method
f012209e 268 if o.addr_family:
b46f4b05
JF
269 if len(o.addr_family) > 1:
270 retifacedict['addr_family'] = o.addr_family
271 else:
272 retifacedict['addr_family'] = ' '.join(o.addr_family)
f012209e
RP
273 retifacedict['auto'] = o.auto
274 retifacedict['config'] = retconfig
275
276 return retifacedict
277
278class ifaceJsonEncoderWithStatus(json.JSONEncoder):
279 def default(self, o):
280 retconfig = {}
281 retconfig_status = {}
282 retifacedict = OrderedDict([])
283 if o.config:
fb10449e
RP
284 for k,v in o.config.items():
285 idx = 0
286 vitem_status = []
287 for vitem in v:
288 s = o.get_config_attr_status(k, idx)
d486dd0d 289 if s == 1:
307e06bb 290 status_str = ifaceStatusUserStrs.ERROR
fb10449e 291 elif s == 0:
307e06bb 292 status_str = ifaceStatusUserStrs.SUCCESS
d486dd0d
JF
293 else:
294 status_str = ifaceStatusUserStrs.UNKNOWN
fb10449e
RP
295 vitem_status.append('%s' %status_str)
296 idx += 1
297 retconfig[k] = v[0] if len(v) == 1 else v
298 retconfig_status[k] = vitem_status[0] if len(vitem_status) == 1 else vitem_status
299
300 if (o.status == ifaceStatus.NOTFOUND or
301 o.status == ifaceStatus.ERROR):
307e06bb 302 status = ifaceStatusUserStrs.ERROR
fb10449e 303 else:
307e06bb 304 status = ifaceStatusUserStrs.SUCCESS
fb10449e
RP
305
306 retifacedict['name'] = o.name
307 if o.addr_method:
308 retifacedict['addr_method'] = o.addr_method
309 if o.addr_family:
b46f4b05
JF
310 if len(o.addr_family) > 1:
311 retifacedict['addr_family'] = o.addr_family
312 else:
313 retifacedict['addr_family'] = ' '.join(o.addr_family)
fb10449e
RP
314 retifacedict['auto'] = o.auto
315 retifacedict['config'] = retconfig
316 retifacedict['config_status'] = retconfig_status
317 retifacedict['status'] = status
318
319 return retifacedict
d08d5f54 320
3dcc1d0e 321class ifaceJsonDecoder():
322 @classmethod
323 def json_to_ifaceobj(cls, ifaceattrdict):
324 ifaceattrdict['config'] = OrderedDict([(k, (v if isinstance(v, list)
fc68074f 325 else [v.strip()]))
3dcc1d0e 326 for k,v in ifaceattrdict.get('config',
327 OrderedDict()).items()])
328 return iface(attrsdict=ifaceattrdict)
329
a6f80f0e 330class iface():
904908bc 331 """ ifupdown2 iface object class
62ddec8b 332 Attributes:
d486dd0d 333 **name** Name of the interface
904908bc
RP
334
335 **addr_family** Address family eg, inet, inet6. Can be None to
336 indicate both address families
337
338 **addr_method** Address method eg, static, manual or None for
339 static address method
340
341 **config** dictionary of config lines for this interface
342
343 **state** Configuration state of an interface as defined by
344 ifaceState
345
346 **status** Configuration status of an interface as defined by
347 ifaceStatus
348
349 **flags** Internal flags used by iface processing
350
351 **priv_flags** private flags owned by module using this class
352
4c773918
ST
353 **module_flags** module flags owned by module using this class
354
904908bc
RP
355 **refcnt** reference count, indicating number of interfaces
356 dependent on this iface
357
358 **lowerifaces** list of interface names lower to this interface or
359 this interface depends on
360
361 **upperifaces** list of interface names upper to this interface or
d486dd0d 362 the interfaces that depend on this interface
904908bc
RP
363
364 **auto** True if interface belongs to the auto class
365
366 **classes** List of classes the interface belongs to
367
368 **env** shell environment the interface needs during
369 execution
370
371 **raw_config** raw interface config from file
62ddec8b 372 """
373
31a5f4c3 374 # flag to indicate that the object was created from pickled state
0582f185 375 # XXX: Move these flags into a separate iface flags class
7444feea
ST
376 _PICKLED = 0x00000001
377 HAS_SIBLINGS = 0x00000010
73c27592
RP
378 IFACERANGE_ENTRY = 0x00000100
379 IFACERANGE_START = 0x00001000
7444feea 380 OLDEST_SIBLING = 0x00010000
0582f185 381 YOUNGEST_SIBLING = 0x00100000
a6f80f0e 382
37c0543d 383 version = '0.1'
384
3dcc1d0e 385 def __init__(self, attrsdict={}):
004d1e65
JF
386 self.addr_family = []
387
3dcc1d0e 388 self._set_attrs_from_dict(attrsdict)
62ddec8b 389 self._config_status = {}
2c0ad8b3 390 """dict with config status of iface attributes"""
a6f80f0e 391 self.state = ifaceState.NEW
2c0ad8b3 392 """iface state (of type ifaceState) """
a6f80f0e 393 self.status = ifaceStatus.UNKNOWN
2c0ad8b3 394 """iface status (of type ifaceStatus) """
e1601369
RP
395 self.status_str = None
396 """iface status str (string representing the status) """
a6f80f0e 397 self.flags = 0x0
2c0ad8b3 398 """iface flags """
dbc018d3 399 self.priv_flags = None
4c773918
ST
400 """iface module flags dictionary with module name: flags"""
401 self.module_flags = {}
2c0ad8b3 402 """iface priv flags. can be used by the external object manager """
a6f80f0e 403 self.refcnt = 0
2c0ad8b3 404 """iface refcnt (incremented for each dependent this interface has) """
d486dd0d 405 self.lowerifaces = None
2c0ad8b3 406 """lower iface list (in other words: slaves of this interface """
f3215127 407 self.upperifaces = None
2c0ad8b3 408 """upper iface list (in other words: master of this interface """
a6f80f0e 409 self.classes = []
2c0ad8b3 410 """interface classes this iface belongs to """
a6f80f0e 411 self.env = None
2c0ad8b3 412 """environment variable dict required for this interface to run"""
62ddec8b 413 self.raw_config = []
2c0ad8b3 414 """interface config/attributes in raw format (eg: as it appeared in the interfaces file)"""
a6f80f0e 415 self.linkstate = None
2c0ad8b3 416 """linkstate of the interface"""
41febf89
RP
417 self.type = ifaceType.UNKNOWN
418 """interface type"""
419 self.priv_data = None
0a3bee28 420 self.role = ifaceRole.UNKNOWN
2da58137 421 self.realname = None
a070c90e 422 self.link_type = ifaceLinkType.LINK_UNKNOWN
c65c2ccd 423 self.link_kind = ifaceLinkKind.UNKNOWN
858a230f 424 self.link_privflags = ifaceLinkPrivFlags.UNKNOWN
a6f80f0e 425
45ca0b6d
RP
426 # The below attribute is used to disambiguate between various
427 # types of dependencies
428 self.dependency_type = ifaceDependencyType.UNKNOWN
0532f0a3 429 self.blacklisted = False
45ca0b6d 430
3dcc1d0e 431 def _set_attrs_from_dict(self, attrdict):
432 self.auto = attrdict.get('auto', False)
433 self.name = attrdict.get('name')
3dcc1d0e 434 self.addr_method = attrdict.get('addr_method')
435 self.config = attrdict.get('config', OrderedDict())
436
004d1e65
JF
437 addr_family = attrdict.get('addr_family')
438 if addr_family:
439 self.addr_family.append(addr_family)
440
a6f80f0e 441 def inc_refcnt(self):
2c0ad8b3
RP
442 """ increment refcnt of the interface. Usually used to indicate that
443 it has dependents """
a6f80f0e 444 self.refcnt += 1
445
446 def dec_refcnt(self):
2c0ad8b3
RP
447 """ decrement refcnt of the interface. Usually used to indicate that
448 it has lost its dependent """
a6f80f0e 449 self.refcnt -= 1
450
cca03c30 451 def is_config_present(self):
2c0ad8b3
RP
452 """ returns true if the interface has user provided config,
453 false otherwise """
62ddec8b 454 addr_method = self.addr_method
2cd06f78 455 if addr_method and addr_method in ['dhcp', 'dhcp6', 'loopback']:
456 return True
fe0a57d3 457 if not self.config:
cca03c30 458 return False
fe0a57d3 459 else:
460 return True
cca03c30 461
3e8ee54f 462 def set_class(self, classname):
2c0ad8b3 463 """ appends class to the interfaces class list """
a6f80f0e 464 self.classes.append(classname)
465
31a5f4c3 466 def set_state_n_status(self, state, status):
2c0ad8b3 467 """ sets state and status of an interface """
31a5f4c3 468 self.state = state
ceed018d
RP
469 if status > self.status:
470 self.status = status
471
472 def set_status(self, status):
473 """ sets status of an interface """
474 if status > self.status:
475 self.status = status
31a5f4c3 476
a6f80f0e 477 def set_flag(self, flag):
478 self.flags |= flag
479
480 def clear_flag(self, flag):
481 self.flags &= ~flag
482
f3215127 483 def add_to_upperifaces(self, upperifacename):
2c0ad8b3 484 """ add to the list of upperifaces """
f3215127 485 if self.upperifaces:
486 if upperifacename not in self.upperifaces:
487 self.upperifaces.append(upperifacename)
488 else:
489 self.upperifaces = [upperifacename]
490
4cc2df04
RP
491 def add_to_lowerifaces(self, lowerifacename):
492 """ add to the list of lowerifaces """
493 if self.lowerifaces:
494 if lowerifacename not in self.lowerifaces:
495 self.lowerifaces.append(lowerifacename)
496 else:
497 self.lowerifaces = [lowerifacename]
498
a6f80f0e 499 def get_attr_value(self, attr_name):
2c0ad8b3 500 """ add to the list of upperifaces """
62ddec8b 501 return self.config.get(attr_name)
d486dd0d 502
a6f80f0e 503 def get_attr_value_first(self, attr_name):
2c0ad8b3 504 """ get first value of the specified attr name """
62ddec8b 505 attr_value_list = self.config.get(attr_name)
fe0a57d3 506 if attr_value_list:
a6f80f0e 507 return attr_value_list[0]
a6f80f0e 508 return None
509
679e6567
RP
510 def get_attrs_value_first(self, attrs):
511 """ get first value of the first attr in the list.
512 Useful when you have multiple attrs representing the
513 same thing.
514 """
515 for attr in attrs:
516 attr_value_list = self.config.get(attr)
517 if attr_value_list:
518 return attr_value_list[0]
519 return None
520
a6f80f0e 521 def get_attr_value_n(self, attr_name, attr_index):
2c0ad8b3 522 """ get n'th value of the specified attr name """
62ddec8b 523 attr_value_list = self.config.get(attr_name)
fe0a57d3 524 if attr_value_list:
a6f80f0e 525 try:
526 return attr_value_list[attr_index]
527 except:
528 return None
a6f80f0e 529 return None
530
531 def get_env(self):
2c0ad8b3 532 """ get shell environment variables the interface must execute in """
fe0a57d3 533 if not self.env:
a6f80f0e 534 self.generate_env()
535 return self.env
536
a6f80f0e 537 def generate_env(self):
2c0ad8b3
RP
538 """ generate shell environment variables dict interface must execute
539 in. This is used to support legacy ifupdown scripts
540 """
a6f80f0e 541 env = {}
62ddec8b 542 config = self.config
543 env['IFACE'] = self.name
a6f80f0e 544 for attr, attr_value in config.items():
60dfcbdf 545 attr_env_name = 'IF_%s' %attr.upper().replace("-", "_")
a6f80f0e 546 env[attr_env_name] = attr_value[0]
60dfcbdf 547 self.env = env
a6f80f0e 548
739f665b 549 def update_config(self, attr_name, attr_value):
2c0ad8b3 550 """ add attribute name and value to the interface config """
62ddec8b 551 self.config.setdefault(attr_name, []).append(attr_value)
739f665b 552
d8e3554d
RP
553 def replace_config(self, attr_name, attr_value):
554 """ add attribute name and value to the interface config """
555 self.config[attr_name] = [attr_value]
556
557 def delete_config(self, attr_name):
558 """ add attribute name and value to the interface config """
559 try:
560 del self.config[attr_name]
561 except:
562 pass
563
739f665b 564 def update_config_dict(self, attrdict):
565 self.config.update(attrdict)
566
567 def update_config_with_status(self, attr_name, attr_value, attr_status=0):
2c0ad8b3
RP
568 """ add attribute name and value to the interface config and also
569 update the config_status dict with status of this attribute config """
69f58278 570 if not attr_value:
a6f80f0e 571 attr_value = ''
62ddec8b 572 self.config.setdefault(attr_name, []).append(attr_value)
573 self._config_status.setdefault(attr_name, []).append(attr_status)
69f58278 574 # set global iface state
e1601369 575 if attr_status == 1:
62ddec8b 576 self.status = ifaceStatus.ERROR
577 elif self.status != ifaceStatus.ERROR:
69f58278 578 # Not already error, mark success
62ddec8b 579 self.status = ifaceStatus.SUCCESS
69f58278 580
a070c90e 581 def check_n_update_config_with_status_many(self, ifaceobjorig, attr_names,
e1601369
RP
582 attr_status=0):
583 # set multiple attribute status to zero
584 # also updates status only if the attribute is present
585 for attr_name in attr_names:
a070c90e
RP
586 if not ifaceobjorig.get_attr_value_first(attr_name):
587 continue
e1601369
RP
588 self.config.setdefault(attr_name, []).append('')
589 self._config_status.setdefault(attr_name, []).append(attr_status)
590
69f58278 591 def get_config_attr_status(self, attr_name, idx=0):
2c0ad8b3 592 """ get status of a attribute config on this interface.
d486dd0d 593
2c0ad8b3 594 Looks at the iface _config_status dict"""
62ddec8b 595 return self._config_status.get(attr_name, [])[idx]
69f58278 596
ca3f4fc7 597 def compare(self, dstiface):
2c0ad8b3 598 """ compares iface object with iface object passed as argument
ca3f4fc7 599
600 Returns True if object self is same as dstiface and False otherwise """
601
602 if self.name != dstiface.name: return False
84ca006f 603 if self.type != dstiface.type: return False
ca3f4fc7 604 if self.addr_family != dstiface.addr_family: return False
605 if self.addr_method != dstiface.addr_method: return False
606 if self.auto != dstiface.auto: return False
607 if self.classes != dstiface.classes: return False
acf92644
RP
608 if len(self.config) != len(dstiface.config):
609 return False
37c0543d 610 if any(True for k in self.config if k not in dstiface.config):
ca3f4fc7 611 return False
37c0543d 612 if any(True for k,v in self.config.items()
ca3f4fc7 613 if v != dstiface.config.get(k)): return False
614 return True
d08d5f54 615
99ce6894
RP
616 def squash(self, newifaceobj):
617 """ This squashes the iface object """
618 for attrname, attrlist in newifaceobj.config.iteritems():
619 # if allready present add it to the list
620 # else add it to the end of the dictionary
621 # We need to maintain order.
622 if self.config.get(attrname):
623 self.config[attrname].extend(attrlist)
624 else:
625 self.config.update([(attrname, attrlist)])
004d1e65
JF
626 # we now support inet and inet6 together
627 self.addr_family.extend(newifaceobj.addr_family)
05bfbb9a
JF
628 # if auto %ifacename is not part of the first stanza
629 # we need to squash it
630 if not self.auto and newifaceobj.auto:
631 self.auto = True
e1601369 632
d08d5f54 633 def __getstate__(self):
634 odict = self.__dict__.copy()
635 del odict['state']
636 del odict['status']
f3215127 637 del odict['lowerifaces']
c798b0f4 638 del odict['upperifaces']
d08d5f54 639 del odict['refcnt']
62ddec8b 640 del odict['_config_status']
5c721925 641 del odict['flags']
642 del odict['priv_flags']
4c773918 643 del odict['module_flags']
62ddec8b 644 del odict['raw_config']
5c721925 645 del odict['linkstate']
646 del odict['env']
c416da6a 647 del odict['link_type']
a9ab1b4f 648 del odict['link_kind']
858a230f 649 del odict['link_privflags']
0a3bee28 650 del odict['role']
45ca0b6d 651 del odict['dependency_type']
0532f0a3 652 del odict['blacklisted']
d08d5f54 653 return odict
654
655 def __setstate__(self, dict):
656 self.__dict__.update(dict)
62ddec8b 657 self._config_status = {}
d08d5f54 658 self.state = ifaceState.NEW
659 self.status = ifaceStatus.UNKNOWN
660 self.refcnt = 0
5c721925 661 self.flags = 0
f3215127 662 self.lowerifaces = None
c798b0f4 663 self.upperifaces = None
d08d5f54 664 self.linkstate = None
5c721925 665 self.env = None
0a3bee28 666 self.role = ifaceRole.UNKNOWN
dbc018d3 667 self.priv_flags = None
4c773918 668 self.module_flags = {}
62ddec8b 669 self.raw_config = []
670 self.flags |= self._PICKLED
f3b69969 671 self.link_type = ifaceLinkType.LINK_NA
a9ab1b4f 672 self.link_kind = ifaceLinkKind.UNKNOWN
858a230f 673 self.link_privflags = ifaceLinkPrivFlags.UNKNOWN
45ca0b6d 674 self.dependency_type = ifaceDependencyType.UNKNOWN
0532f0a3 675 self.blacklisted = False
3dcc1d0e 676
a6f80f0e 677 def dump_raw(self, logger):
678 indent = ' '
53b00224 679 if self.auto:
680 print 'auto %s' %self.name
62ddec8b 681 print (self.raw_config[0])
682 for i in range(1, len(self.raw_config)):
53b00224 683 print(indent + self.raw_config[i])
d486dd0d 684
a6f80f0e 685 def dump(self, logger):
686 indent = '\t'
62ddec8b 687 logger.info(self.name + ' : {')
004d1e65 688 logger.info(indent + 'family: %s' % ' '.join(self.addr_family))
62ddec8b 689 logger.info(indent + 'method: %s' %self.addr_method)
31a5f4c3 690 logger.info(indent + 'flags: %x' %self.flags)
a6f80f0e 691 logger.info(indent + 'state: %s'
62ddec8b 692 %ifaceState.to_str(self.state))
a6f80f0e 693 logger.info(indent + 'status: %s'
62ddec8b 694 %ifaceStatus.to_str(self.status))
695 logger.info(indent + 'refcnt: %d' %self.refcnt)
696 d = self.lowerifaces
fe0a57d3 697 if d:
f3215127 698 logger.info(indent + 'lowerdevs: %s' %str(d))
a6f80f0e 699 else:
f3215127 700 logger.info(indent + 'lowerdevs: None')
739f665b 701
ccbeedcd
RP
702 d = self.upperifaces
703 if d:
704 logger.info(indent + 'upperdevs: %s' %str(d))
705 else:
706 logger.info(indent + 'upperdevs: None')
707
a6f80f0e 708 logger.info(indent + 'config: ')
62ddec8b 709 config = self.config
fe0a57d3 710 if config:
a6f80f0e 711 logger.info(indent + indent + str(config))
712 logger.info('}')
713
004d1e65 714 def _dump_pretty(self, family, first, addr_method, with_status=False, use_realname=False):
a6f80f0e 715 indent = '\t'
cca03c30 716 outbuf = ''
b48ff1a9
RP
717 if use_realname and self.realname:
718 name = '%s' %self.realname
2da58137 719 else:
b48ff1a9 720 name = '%s' %self.name
62ddec8b 721 if self.auto:
2da58137 722 outbuf += 'auto %s\n' %name
5b4d3044 723 ifaceline = ''
cb46a208 724 if self.type == ifaceType.BRIDGE_VLAN:
5b4d3044 725 ifaceline += 'vlan %s' %name
cb46a208 726 else:
5b4d3044 727 ifaceline += 'iface %s' %name
004d1e65
JF
728 if family:
729 ifaceline += ' %s' % family
730 if addr_method:
731 ifaceline += ' %s' % addr_method
2cd06f78 732 if with_status:
5b4d3044 733 status_str = None
e1601369
RP
734 if (self.status == ifaceStatus.ERROR or
735 self.status == ifaceStatus.NOTFOUND):
736 if self.status_str:
5b4d3044 737 ifaceline += ' (%s)' %self.status_str
307e06bb 738 status_str = '[%s]' %ifaceStatusUserStrs.ERROR
86fc62e2 739 elif self.status == ifaceStatus.SUCCESS:
307e06bb 740 status_str = '[%s]' %ifaceStatusUserStrs.SUCCESS
5b4d3044 741 if status_str:
004d1e65 742 outbuf += '{0:65} {1:>8}'.format(ifaceline, status_str) + '\n'
5b4d3044
RP
743 else:
744 outbuf += ifaceline + '\n'
2cd06f78 745 if self.status == ifaceStatus.NOTFOUND:
e1601369
RP
746 outbuf = (outbuf.encode('utf8')
747 if isinstance(outbuf, unicode) else outbuf)
2cd06f78 748 print outbuf + '\n'
749 return
5b4d3044
RP
750 else:
751 outbuf += ifaceline + '\n'
62ddec8b 752 config = self.config
004d1e65 753 if config and first:
eab25b7c 754 for cname, cvaluelist in config.items():
69f58278 755 idx = 0
eab25b7c 756 for cv in cvaluelist:
307e06bb 757 status_str = None
69f58278 758 if with_status:
86fc62e2 759 s = self.get_config_attr_status(cname, idx)
e1601369 760 if s == -1:
307e06bb 761 status_str = '[%s]' %ifaceStatusUserStrs.UNKNOWN
e1601369 762 elif s == 1:
307e06bb 763 status_str = '[%s]' %ifaceStatusUserStrs.ERROR
86fc62e2 764 elif s == 0:
307e06bb
RP
765 status_str = '[%s]' %ifaceStatusUserStrs.SUCCESS
766 if status_str:
5b4d3044 767 outbuf += (indent + '{0:55} {1:>10}'.format(
307e06bb 768 '%s %s' %(cname, cv), status_str)) + '\n'
69f58278 769 else:
770 outbuf += indent + '%s %s\n' %(cname, cv)
771 idx += 1
3dcc1d0e 772 if with_status:
773 outbuf = (outbuf.encode('utf8')
774 if isinstance(outbuf, unicode) else outbuf)
a6f80f0e 775 print outbuf
004d1e65
JF
776
777 def dump_pretty(self, with_status=False, use_realname=False):
778 if not self.addr_family:
779 self._dump_pretty(None, True,
780 self.addr_method,
781 with_status=with_status,
782 use_realname=use_realname)
783 else:
b46f4b05
JF
784 # To allow both inet and inet6 on an interface we changed the
785 # addr_family attribute, it's now a list. Depending on how
786 # stanzas were squashed (and what command was used ie. ifquery -r)
787 # we want to dump the ifaceobj as usual but we will output an
788 # empty stanza for each additional addr_family. The config will
789 # only be displayed once, in the first stanza. Example:
790 # $ ifquery eth0 -r
791 # auto etho
792 # iface eth0 inet dhcp
793 # config...
794 #
795 # auto eth0
796 # iface eth0 inet6 dhcp
797 # $
004d1e65
JF
798 first = True
799 for family in self.addr_family:
b46f4b05
JF
800 addr_method = self.addr_method
801 # We need to make sure we display 'dhcp' for inet family.
802 # In some cases it might take the value 'dhcp6' even if it has
803 # both inet and inet6 addr_family
804 if addr_method and family == 'inet' and 'dhcp' in addr_method:
805 addr_method = 'dhcp'
806 self._dump_pretty(family, first,
807 addr_method=addr_method,
004d1e65
JF
808 with_status=with_status,
809 use_realname=use_realname)
810 first = False