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