]>
git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown/iface.py
3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
10 """ifupdown2 network interface object
12 It is modeled based on the 'iface' section in /etc/network/interfaces
13 file. But can be extended to include any other network interface format
16 from collections
import OrderedDict
20 class ifaceStatusStrs():
32 """ ifaceRole is used to classify the ifaceobj.role of
33 MASTER or SLAVE where there is a bond or bridge
34 with bond-slaves or bridge-ports. A bond in a bridge
35 is both a master and slave (0x3)
41 class ifaceLinkKind():
42 """ ifaceLlinkKind is used to identify interfaces
43 in the ifaceobj.link_kind attribute. Dependents of the bridge or
44 bond have an ifaceobj.role attribute of SLAVE and the bridge or
45 bond itself has ifaceobj.role of MASTER.
52 BRIDGE_VLAN_AWARE
= 0x10
56 class ifaceLinkType():
62 class ifaceDependencyType():
63 """ Indicates type of dependency.
65 This class enumerates types of dependency relationships
68 iface dependency relationships can be classified
73 In a 'link' dependency relationship, dependency can be shared
74 between interfaces. example: swp1.100 and
75 swp1.200 can both have 'link' swp1. swp1 is also a dependency
76 of swp1.100 and swp1.200. As you can see dependency
77 swp1 is shared between swp1.100 and swp1.200.
79 In a master/slave relationship like bridge and
80 its ports: eg: bridge br0 and its ports swp1 and swp2.
81 dependency swp1 and swp2 cannot be shared with any other
82 interface with the same dependency relationship.
83 ie, swp1 and swp2 cannot be in a slave relationship
84 with another interface. Understanding the dependency type is
85 required for any semantic checks between dependencies.
93 """Enumerates iface status """
101 def to_str(cls
, state
):
102 if state
== cls
.UNKNOWN
:
104 elif state
== cls
.SUCCESS
:
106 elif state
== cls
.ERROR
:
108 elif state
== cls
.NOTFOUND
:
112 def from_str(cls
, state_str
):
113 if state_str
== 'unknown':
115 elif state_str
== 'success':
117 elif state_str
== 'error':
121 """Enumerates iface state """
133 QUERY_CHECKCURR
= 0x9
137 def to_str(cls
, state
):
138 if state
== cls
.UNKNOWN
:
140 elif state
== cls
.NEW
:
142 elif state
== cls
.PRE_UP
:
144 elif state
== cls
.UP
:
146 elif state
== cls
.POST_UP
:
148 elif state
== cls
.PRE_DOWN
:
150 elif state
== cls
.DOWN
:
152 elif state
== cls
.POST_DOWN
:
154 elif state
== cls
.QUERY_CHECKCURR
:
155 return 'query-checkcurr'
156 elif state
== cls
.QUERY_RUNNING
:
157 return 'query-running'
160 def from_str(cls
, state_str
):
161 if state_str
== 'unknown':
163 elif state_str
== 'new':
165 elif state_str
== 'pre-up':
167 elif state_str
== 'up':
169 elif state_str
== 'post-up':
171 elif state_str
== 'pre-down':
173 elif state_str
== 'down':
175 elif state_str
== 'post-down':
177 elif state_str
== 'query-checkcurr':
178 return cls
.QUERY_CHECKCURR
179 elif state_str
== 'query-running':
180 return cls
.QUERY_RUNNING
182 class ifaceJsonEncoder(json
.JSONEncoder
):
183 def default(self
, o
):
185 retifacedict
= OrderedDict([])
187 retconfig
= dict((k
, (v
[0] if len(v
) == 1 else v
))
188 for k
,v
in o
.config
.items())
189 retifacedict
['name'] = o
.name
191 retifacedict
['addr_method'] = o
.addr_method
193 retifacedict
['addr_family'] = o
.addr_family
194 retifacedict
['auto'] = o
.auto
195 retifacedict
['config'] = retconfig
199 class ifaceJsonEncoderWithStatus(json
.JSONEncoder
):
200 def default(self
, o
):
202 retconfig_status
= {}
203 retifacedict
= OrderedDict([])
205 for k
,v
in o
.config
.items():
209 s
= o
.get_config_attr_status(k
, idx
)
211 status_str
= ifaceStatusStrs
.UNKNOWN
213 status_str
= ifaceStatusStrs
.ERROR
215 status_str
= ifaceStatusStrs
.SUCCESS
216 vitem_status
.append('%s' %status
_str
)
218 retconfig
[k
] = v
[0] if len(v
) == 1 else v
219 retconfig_status
[k
] = vitem_status
[0] if len(vitem_status
) == 1 else vitem_status
221 if (o
.status
== ifaceStatus
.NOTFOUND
or
222 o
.status
== ifaceStatus
.ERROR
):
223 status
= ifaceStatusStrs
.ERROR
225 status
= ifaceStatusStrs
.SUCCESS
227 retifacedict
['name'] = o
.name
229 retifacedict
['addr_method'] = o
.addr_method
231 retifacedict
['addr_family'] = o
.addr_family
232 retifacedict
['auto'] = o
.auto
233 retifacedict
['config'] = retconfig
234 retifacedict
['config_status'] = retconfig_status
235 retifacedict
['status'] = status
239 class ifaceJsonDecoder():
241 def json_to_ifaceobj(cls
, ifaceattrdict
):
242 ifaceattrdict
['config'] = OrderedDict([(k
, (v
if isinstance(v
, list)
244 for k
,v
in ifaceattrdict
.get('config',
245 OrderedDict()).items()])
246 return iface(attrsdict
=ifaceattrdict
)
249 """ ifupdown2 iface object class
252 **name** Name of the interface
254 **addr_family** Address family eg, inet, inet6. Can be None to
255 indicate both address families
257 **addr_method** Address method eg, static, manual or None for
258 static address method
260 **config** dictionary of config lines for this interface
262 **state** Configuration state of an interface as defined by
265 **status** Configuration status of an interface as defined by
268 **flags** Internal flags used by iface processing
270 **priv_flags** private flags owned by module using this class
272 **module_flags** module flags owned by module using this class
274 **refcnt** reference count, indicating number of interfaces
275 dependent on this iface
277 **lowerifaces** list of interface names lower to this interface or
278 this interface depends on
280 **upperifaces** list of interface names upper to this interface or
281 the interfaces that depend on this interface
283 **auto** True if interface belongs to the auto class
285 **classes** List of classes the interface belongs to
287 **env** shell environment the interface needs during
290 **raw_config** raw interface config from file
293 # flag to indicate that the object was created from pickled state
294 # XXX: Move these flags into a separate iface flags class
295 _PICKLED
= 0x00000001
296 HAS_SIBLINGS
= 0x00000010
297 IFACERANGE_ENTRY
= 0x00000100
298 IFACERANGE_START
= 0x00001000
299 OLDEST_SIBLING
= 0x00010000
300 YOUNGEST_SIBLING
= 0x00100000
304 def __init__(self
, attrsdict
={}):
305 self
._set
_attrs
_from
_dict
(attrsdict
)
306 self
._config
_status
= {}
307 """dict with config status of iface attributes"""
308 self
.state
= ifaceState
.NEW
309 """iface state (of type ifaceState) """
310 self
.status
= ifaceStatus
.UNKNOWN
311 """iface status (of type ifaceStatus) """
312 self
.status_str
= None
313 """iface status str (string representing the status) """
316 self
.priv_flags
= 0x0
317 """iface module flags dictionary with module name: flags"""
318 self
.module_flags
= {}
319 """iface priv flags. can be used by the external object manager """
321 """iface refcnt (incremented for each dependent this interface has) """
322 self
.lowerifaces
= None
323 """lower iface list (in other words: slaves of this interface """
324 self
.upperifaces
= None
325 """upper iface list (in other words: master of this interface """
327 """interface classes this iface belongs to """
329 """environment variable dict required for this interface to run"""
331 """interface config/attributes in raw format (eg: as it appeared in the interfaces file)"""
332 self
.linkstate
= None
333 """linkstate of the interface"""
334 self
.type = ifaceType
.UNKNOWN
336 self
.priv_data
= None
337 self
.role
= ifaceRole
.UNKNOWN
339 self
.link_type
= ifaceLinkType
.LINK_UNKNOWN
340 self
.link_kind
= ifaceLinkKind
.UNKNOWN
342 # The below attribute is used to disambiguate between various
343 # types of dependencies
344 self
.dependency_type
= ifaceDependencyType
.UNKNOWN
345 self
.blacklisted
= False
347 def _set_attrs_from_dict(self
, attrdict
):
348 self
.auto
= attrdict
.get('auto', False)
349 self
.name
= attrdict
.get('name')
350 self
.addr_family
= attrdict
.get('addr_family')
351 self
.addr_method
= attrdict
.get('addr_method')
352 self
.config
= attrdict
.get('config', OrderedDict())
354 def inc_refcnt(self
):
355 """ increment refcnt of the interface. Usually used to indicate that
356 it has dependents """
359 def dec_refcnt(self
):
360 """ decrement refcnt of the interface. Usually used to indicate that
361 it has lost its dependent """
364 def is_config_present(self
):
365 """ returns true if the interface has user provided config,
367 addr_method
= self
.addr_method
368 if addr_method
and addr_method
in ['dhcp', 'dhcp6', 'loopback']:
375 def set_class(self
, classname
):
376 """ appends class to the interfaces class list """
377 self
.classes
.append(classname
)
379 def set_state_n_status(self
, state
, status
):
380 """ sets state and status of an interface """
384 def set_flag(self
, flag
):
387 def clear_flag(self
, flag
):
390 def add_to_upperifaces(self
, upperifacename
):
391 """ add to the list of upperifaces """
393 if upperifacename
not in self
.upperifaces
:
394 self
.upperifaces
.append(upperifacename
)
396 self
.upperifaces
= [upperifacename
]
398 def get_attr_value(self
, attr_name
):
399 """ add to the list of upperifaces """
400 return self
.config
.get(attr_name
)
402 def get_attr_value_first(self
, attr_name
):
403 """ get first value of the specified attr name """
404 attr_value_list
= self
.config
.get(attr_name
)
406 return attr_value_list
[0]
409 def get_attrs_value_first(self
, attrs
):
410 """ get first value of the first attr in the list.
411 Useful when you have multiple attrs representing the
415 attr_value_list
= self
.config
.get(attr
)
417 return attr_value_list
[0]
420 def get_attr_value_n(self
, attr_name
, attr_index
):
421 """ get n'th value of the specified attr name """
422 attr_value_list
= self
.config
.get(attr_name
)
425 return attr_value_list
[attr_index
]
432 """ get shell environment variables the interface must execute in """
437 def generate_env(self
):
438 """ generate shell environment variables dict interface must execute
439 in. This is used to support legacy ifupdown scripts
443 env
['IFACE'] = self
.name
444 for attr
, attr_value
in config
.items():
445 attr_env_name
= 'IF_%s' %attr
.upper()
446 env
[attr_env_name
] = attr_value
[0]
450 def update_config(self
, attr_name
, attr_value
):
451 """ add attribute name and value to the interface config """
452 self
.config
.setdefault(attr_name
, []).append(attr_value
)
454 def replace_config(self
, attr_name
, attr_value
):
455 """ add attribute name and value to the interface config """
456 self
.config
[attr_name
] = [attr_value
]
458 def delete_config(self
, attr_name
):
459 """ add attribute name and value to the interface config """
461 del self
.config
[attr_name
]
465 def update_config_dict(self
, attrdict
):
466 self
.config
.update(attrdict
)
468 def update_config_with_status(self
, attr_name
, attr_value
, attr_status
=0):
469 """ add attribute name and value to the interface config and also
470 update the config_status dict with status of this attribute config """
473 self
.config
.setdefault(attr_name
, []).append(attr_value
)
474 self
._config
_status
.setdefault(attr_name
, []).append(attr_status
)
475 # set global iface state
477 self
.status
= ifaceStatus
.ERROR
478 elif self
.status
!= ifaceStatus
.ERROR
:
479 # Not already error, mark success
480 self
.status
= ifaceStatus
.SUCCESS
482 def check_n_update_config_with_status_many(self
, ifaceobjorig
, attr_names
,
484 # set multiple attribute status to zero
485 # also updates status only if the attribute is present
486 for attr_name
in attr_names
:
487 if not ifaceobjorig
.get_attr_value_first(attr_name
):
489 self
.config
.setdefault(attr_name
, []).append('')
490 self
._config
_status
.setdefault(attr_name
, []).append(attr_status
)
492 def get_config_attr_status(self
, attr_name
, idx
=0):
493 """ get status of a attribute config on this interface.
495 Looks at the iface _config_status dict"""
496 return self
._config
_status
.get(attr_name
, [])[idx
]
498 def compare(self
, dstiface
):
499 """ compares iface object with iface object passed as argument
501 Returns True if object self is same as dstiface and False otherwise """
503 if self
.name
!= dstiface
.name
: return False
504 if self
.type != dstiface
.type: return False
505 if self
.addr_family
!= dstiface
.addr_family
: return False
506 if self
.addr_method
!= dstiface
.addr_method
: return False
507 if self
.auto
!= dstiface
.auto
: return False
508 if self
.classes
!= dstiface
.classes
: return False
509 if len(self
.config
) != len(dstiface
.config
):
511 if any(True for k
in self
.config
if k
not in dstiface
.config
):
513 if any(True for k
,v
in self
.config
.items()
514 if v
!= dstiface
.config
.get(k
)): return False
518 def __getstate__(self
):
519 odict
= self
.__dict
__.copy()
522 del odict
['lowerifaces']
523 del odict
['upperifaces']
525 del odict
['_config_status']
527 del odict
['priv_flags']
528 del odict
['module_flags']
529 del odict
['raw_config']
530 del odict
['linkstate']
532 del odict
['link_type']
533 del odict
['link_kind']
535 del odict
['dependency_type']
536 del odict
['blacklisted']
539 def __setstate__(self
, dict):
540 self
.__dict
__.update(dict)
541 self
._config
_status
= {}
542 self
.state
= ifaceState
.NEW
543 self
.status
= ifaceStatus
.UNKNOWN
546 self
.lowerifaces
= None
547 self
.upperifaces
= None
548 self
.linkstate
= None
550 self
.role
= ifaceRole
.UNKNOWN
552 self
.module_flags
= {}
554 self
.flags |
= self
._PICKLED
555 self
.link_type
= ifaceLinkType
.LINK_NA
556 self
.link_kind
= ifaceLinkKind
.UNKNOWN
557 self
.dependency_type
= ifaceDependencyType
.UNKNOWN
558 self
.blacklisted
= False
560 def dump_raw(self
, logger
):
563 print 'auto %s' %self
.name
564 print (self
.raw_config
[0])
565 for i
in range(1, len(self
.raw_config
)):
566 print(indent
+ self
.raw_config
[i
])
568 def dump(self
, logger
):
570 logger
.info(self
.name
+ ' : {')
571 logger
.info(indent
+ 'family: %s' %self
.addr_family
)
572 logger
.info(indent
+ 'method: %s' %self
.addr_method
)
573 logger
.info(indent
+ 'flags: %x' %self
.flags
)
574 logger
.info(indent
+ 'state: %s'
575 %ifaceState
.to_str(self
.state
))
576 logger
.info(indent
+ 'status: %s'
577 %ifaceStatus
.to_str(self
.status
))
578 logger
.info(indent
+ 'refcnt: %d' %self
.refcnt
)
581 logger
.info(indent
+ 'lowerdevs: %s' %str
(d
))
583 logger
.info(indent
+ 'lowerdevs: None')
585 logger
.info(indent
+ 'config: ')
588 logger
.info(indent
+ indent
+ str(config
))
591 def dump_pretty(self
, with_status
=False, use_realname
=False):
594 if use_realname
and self
.realname
:
595 name
= '%s' %self
.realname
597 name
= '%s' %self
.name
599 outbuf
+= 'auto %s\n' %name
601 if self
.type == ifaceType
.BRIDGE_VLAN
:
602 ifaceline
+= 'vlan %s' %name
604 ifaceline
+= 'iface %s' %name
606 ifaceline
+= ' %s' %self
.addr_family
608 ifaceline
+= ' %s' %self
.addr_method
611 if (self
.status
== ifaceStatus
.ERROR
or
612 self
.status
== ifaceStatus
.NOTFOUND
):
614 ifaceline
+= ' (%s)' %self
.status_str
615 status_str
= '[%s]' %ifaceStatusStrs
.ERROR
616 elif self
.status
== ifaceStatus
.SUCCESS
:
617 status_str
= '[%s]' %ifaceStatusStrs
.SUCCESS
619 outbuf
+= '{0:65} {1:>8}'.format(ifaceline
, status_str
) + '\n'
621 outbuf
+= ifaceline
+ '\n'
622 if self
.status
== ifaceStatus
.NOTFOUND
:
623 outbuf
= (outbuf
.encode('utf8')
624 if isinstance(outbuf
, unicode) else outbuf
)
628 outbuf
+= ifaceline
+ '\n'
631 for cname
, cvaluelist
in config
.items():
633 for cv
in cvaluelist
:
635 s
= self
.get_config_attr_status(cname
, idx
)
637 status_str
= '[%s]' %ifaceStatusStrs
.UNKNOWN
639 status_str
= '[%s]' %ifaceStatusStrs
.ERROR
641 status_str
= '[%s]' %ifaceStatusStrs
.SUCCESS
642 outbuf
+= (indent
+ '{0:55} {1:>10}'.format(
643 '%s %s' %(cname
, cv
), status_str
)) + '\n'
645 outbuf
+= indent
+ '%s %s\n' %(cname
, cv
)
648 outbuf
= (outbuf
.encode('utf8')
649 if isinstance(outbuf
, unicode) else outbuf
)