]>
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 ifaceStatusUserStrs():
21 """ This class declares strings user can see during an ifquery --check
22 for example. These strings can be overridden by user defined strings from
34 """ ifaceRole is used to classify the ifaceobj.role of
35 MASTER or SLAVE where there is a bond or bridge
36 with bond-slaves or bridge-ports. A bond in a bridge
37 is both a master and slave (0x3)
43 class ifaceLinkKind():
44 """ ifaceLlinkKind is used to identify interfaces
45 in the ifaceobj.link_kind attribute. Dependents of the bridge or
46 bond have an ifaceobj.role attribute of SLAVE and the bridge or
47 bond itself has ifaceobj.role of MASTER.
56 class ifaceLinkPrivFlags():
57 """ This corresponds to kernel netdev->priv_flags
58 and can be BRIDGE_PORT, BOND_SLAVE etc """
63 BRIDGE_VLAN_AWARE
= 0x1000
66 def get_str(cls
, flag
):
67 if flag
== cls
.UNKNOWN
:
69 elif flag
== cls
.BRIDGE_PORT
:
71 elif flag
== cls
.BOND_SLAVE
:
73 elif flag
== cls
.VRF_SLAVE
:
75 elif flag
== cls
.BRIDGE_VLAN_AWARE
:
76 return 'vlan aware bridge'
79 def get_all_str(cls
, flags
):
81 if (flags
& cls
.BRIDGE_PORT
):
83 if (flags
== cls
.BOND_SLAVE
):
85 elif flags
== cls
.VRF_SLAVE
:
87 elif flags
== cls
.BRIDGE_VLAN_AWARE
:
88 str += 'vlanawarebridge '
91 class ifaceLinkType():
97 class ifaceDependencyType():
98 """ Indicates type of dependency.
100 This class enumerates types of dependency relationships
103 iface dependency relationships can be classified
108 In a 'link' dependency relationship, dependency can be shared
109 between interfaces. example: swp1.100 and
110 swp1.200 can both have 'link' swp1. swp1 is also a dependency
111 of swp1.100 and swp1.200. As you can see dependency
112 swp1 is shared between swp1.100 and swp1.200.
114 In a master/slave relationship like bridge and
115 its ports: eg: bridge br0 and its ports swp1 and swp2.
116 dependency swp1 and swp2 cannot be shared with any other
117 interface with the same dependency relationship.
118 ie, swp1 and swp2 cannot be in a slave relationship
119 with another interface. Understanding the dependency type is
120 required for any semantic checks between dependencies.
128 """Enumerates iface status """
137 def to_str(cls
, state
):
138 if state
== cls
.UNKNOWN
:
140 elif state
== cls
.SUCCESS
:
142 elif state
== cls
.ERROR
:
144 elif state
== cls
.NOTFOUND
:
148 def from_str(cls
, state_str
):
149 if state_str
== 'unknown':
151 elif state_str
== 'success':
153 elif state_str
== 'error':
157 """Enumerates iface state """
169 QUERY_CHECKCURR
= 0x9
173 def to_str(cls
, state
):
174 if state
== cls
.UNKNOWN
:
176 elif state
== cls
.NEW
:
178 elif state
== cls
.PRE_UP
:
180 elif state
== cls
.UP
:
182 elif state
== cls
.POST_UP
:
184 elif state
== cls
.PRE_DOWN
:
186 elif state
== cls
.DOWN
:
188 elif state
== cls
.POST_DOWN
:
190 elif state
== cls
.QUERY_CHECKCURR
:
191 return 'query-checkcurr'
192 elif state
== cls
.QUERY_RUNNING
:
193 return 'query-running'
196 def from_str(cls
, state_str
):
197 if state_str
== 'unknown':
199 elif state_str
== 'new':
201 elif state_str
== 'pre-up':
203 elif state_str
== 'up':
205 elif state_str
== 'post-up':
207 elif state_str
== 'pre-down':
209 elif state_str
== 'down':
211 elif state_str
== 'post-down':
213 elif state_str
== 'query-checkcurr':
214 return cls
.QUERY_CHECKCURR
215 elif state_str
== 'query-running':
216 return cls
.QUERY_RUNNING
218 class ifaceJsonEncoder(json
.JSONEncoder
):
219 def default(self
, o
):
221 retifacedict
= OrderedDict([])
223 retconfig
= dict((k
, (v
[0] if len(v
) == 1 else v
))
224 for k
,v
in o
.config
.items())
225 retifacedict
['name'] = o
.name
227 retifacedict
['addr_method'] = o
.addr_method
229 retifacedict
['addr_family'] = o
.addr_family
230 retifacedict
['auto'] = o
.auto
231 retifacedict
['config'] = retconfig
235 class ifaceJsonEncoderWithStatus(json
.JSONEncoder
):
236 def default(self
, o
):
238 retconfig_status
= {}
239 retifacedict
= OrderedDict([])
241 for k
,v
in o
.config
.items():
245 s
= o
.get_config_attr_status(k
, idx
)
247 status_str
= ifaceStatusUserStrs
.UNKNOWN
249 status_str
= ifaceStatusUserStrs
.ERROR
251 status_str
= ifaceStatusUserStrs
.SUCCESS
252 vitem_status
.append('%s' %status
_str
)
254 retconfig
[k
] = v
[0] if len(v
) == 1 else v
255 retconfig_status
[k
] = vitem_status
[0] if len(vitem_status
) == 1 else vitem_status
257 if (o
.status
== ifaceStatus
.NOTFOUND
or
258 o
.status
== ifaceStatus
.ERROR
):
259 status
= ifaceStatusUserStrs
.ERROR
261 status
= ifaceStatusUserStrs
.SUCCESS
263 retifacedict
['name'] = o
.name
265 retifacedict
['addr_method'] = o
.addr_method
267 retifacedict
['addr_family'] = o
.addr_family
268 retifacedict
['auto'] = o
.auto
269 retifacedict
['config'] = retconfig
270 retifacedict
['config_status'] = retconfig_status
271 retifacedict
['status'] = status
275 class ifaceJsonDecoder():
277 def json_to_ifaceobj(cls
, ifaceattrdict
):
278 ifaceattrdict
['config'] = OrderedDict([(k
, (v
if isinstance(v
, list)
280 for k
,v
in ifaceattrdict
.get('config',
281 OrderedDict()).items()])
282 return iface(attrsdict
=ifaceattrdict
)
285 """ ifupdown2 iface object class
288 **name** Name of the interface
290 **addr_family** Address family eg, inet, inet6. Can be None to
291 indicate both address families
293 **addr_method** Address method eg, static, manual or None for
294 static address method
296 **config** dictionary of config lines for this interface
298 **state** Configuration state of an interface as defined by
301 **status** Configuration status of an interface as defined by
304 **flags** Internal flags used by iface processing
306 **priv_flags** private flags owned by module using this class
308 **module_flags** module flags owned by module using this class
310 **refcnt** reference count, indicating number of interfaces
311 dependent on this iface
313 **lowerifaces** list of interface names lower to this interface or
314 this interface depends on
316 **upperifaces** list of interface names upper to this interface or
317 the interfaces that depend on this interface
319 **auto** True if interface belongs to the auto class
321 **classes** List of classes the interface belongs to
323 **env** shell environment the interface needs during
326 **raw_config** raw interface config from file
329 # flag to indicate that the object was created from pickled state
330 # XXX: Move these flags into a separate iface flags class
331 _PICKLED
= 0x00000001
332 HAS_SIBLINGS
= 0x00000010
333 IFACERANGE_ENTRY
= 0x00000100
334 IFACERANGE_START
= 0x00001000
335 OLDEST_SIBLING
= 0x00010000
336 YOUNGEST_SIBLING
= 0x00100000
340 def __init__(self
, attrsdict
={}):
341 self
._set
_attrs
_from
_dict
(attrsdict
)
342 self
._config
_status
= {}
343 """dict with config status of iface attributes"""
344 self
.state
= ifaceState
.NEW
345 """iface state (of type ifaceState) """
346 self
.status
= ifaceStatus
.UNKNOWN
347 """iface status (of type ifaceStatus) """
348 self
.status_str
= None
349 """iface status str (string representing the status) """
352 self
.priv_flags
= None
353 """iface module flags dictionary with module name: flags"""
354 self
.module_flags
= {}
355 """iface priv flags. can be used by the external object manager """
357 """iface refcnt (incremented for each dependent this interface has) """
358 self
.lowerifaces
= None
359 """lower iface list (in other words: slaves of this interface """
360 self
.upperifaces
= None
361 """upper iface list (in other words: master of this interface """
363 """interface classes this iface belongs to """
365 """environment variable dict required for this interface to run"""
367 """interface config/attributes in raw format (eg: as it appeared in the interfaces file)"""
368 self
.linkstate
= None
369 """linkstate of the interface"""
370 self
.type = ifaceType
.UNKNOWN
372 self
.priv_data
= None
373 self
.role
= ifaceRole
.UNKNOWN
375 self
.link_type
= ifaceLinkType
.LINK_UNKNOWN
376 self
.link_kind
= ifaceLinkKind
.UNKNOWN
377 self
.link_privflags
= ifaceLinkPrivFlags
.UNKNOWN
379 # The below attribute is used to disambiguate between various
380 # types of dependencies
381 self
.dependency_type
= ifaceDependencyType
.UNKNOWN
382 self
.blacklisted
= False
384 def _set_attrs_from_dict(self
, attrdict
):
385 self
.auto
= attrdict
.get('auto', False)
386 self
.name
= attrdict
.get('name')
387 self
.addr_family
= attrdict
.get('addr_family')
388 self
.addr_method
= attrdict
.get('addr_method')
389 self
.config
= attrdict
.get('config', OrderedDict())
391 def inc_refcnt(self
):
392 """ increment refcnt of the interface. Usually used to indicate that
393 it has dependents """
396 def dec_refcnt(self
):
397 """ decrement refcnt of the interface. Usually used to indicate that
398 it has lost its dependent """
401 def is_config_present(self
):
402 """ returns true if the interface has user provided config,
404 addr_method
= self
.addr_method
405 if addr_method
and addr_method
in ['dhcp', 'dhcp6', 'loopback']:
412 def set_class(self
, classname
):
413 """ appends class to the interfaces class list """
414 self
.classes
.append(classname
)
416 def set_state_n_status(self
, state
, status
):
417 """ sets state and status of an interface """
419 if status
> self
.status
:
422 def set_status(self
, status
):
423 """ sets status of an interface """
424 if status
> self
.status
:
427 def set_flag(self
, flag
):
430 def clear_flag(self
, flag
):
433 def add_to_upperifaces(self
, upperifacename
):
434 """ add to the list of upperifaces """
436 if upperifacename
not in self
.upperifaces
:
437 self
.upperifaces
.append(upperifacename
)
439 self
.upperifaces
= [upperifacename
]
441 def add_to_lowerifaces(self
, lowerifacename
):
442 """ add to the list of lowerifaces """
444 if lowerifacename
not in self
.lowerifaces
:
445 self
.lowerifaces
.append(lowerifacename
)
447 self
.lowerifaces
= [lowerifacename
]
449 def get_attr_value(self
, attr_name
):
450 """ add to the list of upperifaces """
451 return self
.config
.get(attr_name
)
453 def get_attr_value_first(self
, attr_name
):
454 """ get first value of the specified attr name """
455 attr_value_list
= self
.config
.get(attr_name
)
457 return attr_value_list
[0]
460 def get_attrs_value_first(self
, attrs
):
461 """ get first value of the first attr in the list.
462 Useful when you have multiple attrs representing the
466 attr_value_list
= self
.config
.get(attr
)
468 return attr_value_list
[0]
471 def get_attr_value_n(self
, attr_name
, attr_index
):
472 """ get n'th value of the specified attr name """
473 attr_value_list
= self
.config
.get(attr_name
)
476 return attr_value_list
[attr_index
]
483 """ get shell environment variables the interface must execute in """
488 def generate_env(self
):
489 """ generate shell environment variables dict interface must execute
490 in. This is used to support legacy ifupdown scripts
494 env
['IFACE'] = self
.name
495 for attr
, attr_value
in config
.items():
496 attr_env_name
= 'IF_%s' %attr
.upper()
497 env
[attr_env_name
] = attr_value
[0]
501 def update_config(self
, attr_name
, attr_value
):
502 """ add attribute name and value to the interface config """
503 self
.config
.setdefault(attr_name
, []).append(attr_value
)
505 def replace_config(self
, attr_name
, attr_value
):
506 """ add attribute name and value to the interface config """
507 self
.config
[attr_name
] = [attr_value
]
509 def delete_config(self
, attr_name
):
510 """ add attribute name and value to the interface config """
512 del self
.config
[attr_name
]
516 def update_config_dict(self
, attrdict
):
517 self
.config
.update(attrdict
)
519 def update_config_with_status(self
, attr_name
, attr_value
, attr_status
=0):
520 """ add attribute name and value to the interface config and also
521 update the config_status dict with status of this attribute config """
524 self
.config
.setdefault(attr_name
, []).append(attr_value
)
525 self
._config
_status
.setdefault(attr_name
, []).append(attr_status
)
526 # set global iface state
528 self
.status
= ifaceStatus
.ERROR
529 elif self
.status
!= ifaceStatus
.ERROR
:
530 # Not already error, mark success
531 self
.status
= ifaceStatus
.SUCCESS
533 def check_n_update_config_with_status_many(self
, ifaceobjorig
, attr_names
,
535 # set multiple attribute status to zero
536 # also updates status only if the attribute is present
537 for attr_name
in attr_names
:
538 if not ifaceobjorig
.get_attr_value_first(attr_name
):
540 self
.config
.setdefault(attr_name
, []).append('')
541 self
._config
_status
.setdefault(attr_name
, []).append(attr_status
)
543 def get_config_attr_status(self
, attr_name
, idx
=0):
544 """ get status of a attribute config on this interface.
546 Looks at the iface _config_status dict"""
547 return self
._config
_status
.get(attr_name
, [])[idx
]
549 def compare(self
, dstiface
):
550 """ compares iface object with iface object passed as argument
552 Returns True if object self is same as dstiface and False otherwise """
554 if self
.name
!= dstiface
.name
: return False
555 if self
.type != dstiface
.type: return False
556 if self
.addr_family
!= dstiface
.addr_family
: return False
557 if self
.addr_method
!= dstiface
.addr_method
: return False
558 if self
.auto
!= dstiface
.auto
: return False
559 if self
.classes
!= dstiface
.classes
: return False
560 if len(self
.config
) != len(dstiface
.config
):
562 if any(True for k
in self
.config
if k
not in dstiface
.config
):
564 if any(True for k
,v
in self
.config
.items()
565 if v
!= dstiface
.config
.get(k
)): return False
568 def squash(self
, newifaceobj
):
569 """ This squashes the iface object """
570 for attrname
, attrlist
in newifaceobj
.config
.iteritems():
571 # if allready present add it to the list
572 # else add it to the end of the dictionary
573 # We need to maintain order.
574 if self
.config
.get(attrname
):
575 self
.config
[attrname
].extend(attrlist
)
577 self
.config
.update([(attrname
, attrlist
)])
579 def __getstate__(self
):
580 odict
= self
.__dict
__.copy()
583 del odict
['lowerifaces']
584 del odict
['upperifaces']
586 del odict
['_config_status']
588 del odict
['priv_flags']
589 del odict
['module_flags']
590 del odict
['raw_config']
591 del odict
['linkstate']
593 del odict
['link_type']
594 del odict
['link_kind']
595 del odict
['link_privflags']
597 del odict
['dependency_type']
598 del odict
['blacklisted']
601 def __setstate__(self
, dict):
602 self
.__dict
__.update(dict)
603 self
._config
_status
= {}
604 self
.state
= ifaceState
.NEW
605 self
.status
= ifaceStatus
.UNKNOWN
608 self
.lowerifaces
= None
609 self
.upperifaces
= None
610 self
.linkstate
= None
612 self
.role
= ifaceRole
.UNKNOWN
613 self
.priv_flags
= None
614 self
.module_flags
= {}
616 self
.flags |
= self
._PICKLED
617 self
.link_type
= ifaceLinkType
.LINK_NA
618 self
.link_kind
= ifaceLinkKind
.UNKNOWN
619 self
.link_privflags
= ifaceLinkPrivFlags
.UNKNOWN
620 self
.dependency_type
= ifaceDependencyType
.UNKNOWN
621 self
.blacklisted
= False
623 def dump_raw(self
, logger
):
626 print 'auto %s' %self
.name
627 print (self
.raw_config
[0])
628 for i
in range(1, len(self
.raw_config
)):
629 print(indent
+ self
.raw_config
[i
])
631 def dump(self
, logger
):
633 logger
.info(self
.name
+ ' : {')
634 logger
.info(indent
+ 'family: %s' %self
.addr_family
)
635 logger
.info(indent
+ 'method: %s' %self
.addr_method
)
636 logger
.info(indent
+ 'flags: %x' %self
.flags
)
637 logger
.info(indent
+ 'state: %s'
638 %ifaceState
.to_str(self
.state
))
639 logger
.info(indent
+ 'status: %s'
640 %ifaceStatus
.to_str(self
.status
))
641 logger
.info(indent
+ 'refcnt: %d' %self
.refcnt
)
644 logger
.info(indent
+ 'lowerdevs: %s' %str
(d
))
646 logger
.info(indent
+ 'lowerdevs: None')
650 logger
.info(indent
+ 'upperdevs: %s' %str
(d
))
652 logger
.info(indent
+ 'upperdevs: None')
654 logger
.info(indent
+ 'config: ')
657 logger
.info(indent
+ indent
+ str(config
))
660 def dump_pretty(self
, with_status
=False, use_realname
=False):
663 if use_realname
and self
.realname
:
664 name
= '%s' %self
.realname
666 name
= '%s' %self
.name
668 outbuf
+= 'auto %s\n' %name
670 if self
.type == ifaceType
.BRIDGE_VLAN
:
671 ifaceline
+= 'vlan %s' %name
673 ifaceline
+= 'iface %s' %name
675 ifaceline
+= ' %s' %self
.addr_family
677 ifaceline
+= ' %s' %self
.addr_method
680 if (self
.status
== ifaceStatus
.ERROR
or
681 self
.status
== ifaceStatus
.NOTFOUND
):
683 ifaceline
+= ' (%s)' %self
.status_str
684 status_str
= '[%s]' %ifaceStatusUserStrs
.ERROR
685 elif self
.status
== ifaceStatus
.SUCCESS
:
686 status_str
= '[%s]' %ifaceStatusUserStrs
.SUCCESS
688 outbuf
+= '{0:65} {1:>8}'.format(ifaceline
, status_str
) + '\n'
690 outbuf
+= ifaceline
+ '\n'
691 if self
.status
== ifaceStatus
.NOTFOUND
:
692 outbuf
= (outbuf
.encode('utf8')
693 if isinstance(outbuf
, unicode) else outbuf
)
697 outbuf
+= ifaceline
+ '\n'
700 for cname
, cvaluelist
in config
.items():
702 for cv
in cvaluelist
:
705 s
= self
.get_config_attr_status(cname
, idx
)
707 status_str
= '[%s]' %ifaceStatusUserStrs
.UNKNOWN
709 status_str
= '[%s]' %ifaceStatusUserStrs
.ERROR
711 status_str
= '[%s]' %ifaceStatusUserStrs
.SUCCESS
713 outbuf
+= (indent
+ '{0:55} {1:>10}'.format(
714 '%s %s' %(cname
, cv
), status_str
)) + '\n'
716 outbuf
+= indent
+ '%s %s\n' %(cname
, cv
)
719 outbuf
= (outbuf
.encode('utf8')
720 if isinstance(outbuf
, unicode) else outbuf
)