2 # Netlink interface based on libnl
4 # Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
7 """netlink library based on libnl
9 This module provides an interface to netlink sockets
11 The module contains the following public classes:
12 - Socket -- The netlink socket
13 - Object -- Abstract object (based on struct nl_obect in libnl) used as
14 base class for all object types which can be put into a Cache
15 - Cache -- A collection of objects which are derived from the base
16 class Object. Used for netlink protocols which maintain a list
20 The following exceptions are defined:
21 - NetlinkError -- Base exception for all general purpose exceptions raised.
22 - KernelError -- Raised when the kernel returns an error as response to a
25 All other classes or functions in this module are considered implementation
28 from __future__ import absolute_import
59 NETLINK_FIB_LOOKUP = 10
60 NETLINK_CONNECTOR = 11
61 NETLINK_NETFILTER = 12
64 NETLINK_KOBJECT_UEVENT = 15
66 NETLINK_SCSITRANSPORT = 18
85 NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH
92 class NetlinkError(Exception):
93 def __init__(self, error):
95 self._msg = capi.nl_geterror(error)
100 class KernelError(NetlinkError):
102 return 'Kernel returned: {0}'.format(self._msg)
104 class ImmutableError(NetlinkError):
105 def __init__(self, msg):
109 return 'Immutable attribute: {0}'.format(self._msg)
111 class Message(object):
112 """Netlink message"""
114 def __init__(self, size=0):
116 self._msg = capi.nlmsg_alloc()
118 self._msg = capi.nlmsg_alloc_size(size)
120 if self._msg is None:
121 raise Exception('Message allocation returned NULL')
124 capi.nlmsg_free(self._msg)
127 return capi.nlmsg_len(nlmsg_hdr(self._msg))
131 return capi.nlmsg_get_proto(self._msg)
134 def protocol(self, value):
135 capi.nlmsg_set_proto(self._msg, value)
139 return capi.nlmsg_get_max_size(self._msg)
143 return capi.nlmsg_hdr(self._msg)
147 return capi.nlmsg_data(self._msg)
151 return capi.nlmsg_attrdata(self._msg)
153 def send(self, sock):
156 class Socket(object):
159 def __init__(self, cb=None):
161 self._sock = capi.nl_socket_alloc()
163 self._sock = capi.nl_socket_alloc_cb(cb)
165 if self._sock is None:
166 raise Exception('NULL pointer returned while allocating socket')
169 capi.nl_socket_free(self._sock)
172 return 'nlsock<{0}>'.format(self.localPort)
175 def local_port(self):
176 return capi.nl_socket_get_local_port(self._sock)
179 def local_port(self, value):
180 capi.nl_socket_set_local_port(self._sock, int(value))
184 return capi.nl_socket_get_peer_port(self._sock)
187 def peer_port(self, value):
188 capi.nl_socket_set_peer_port(self._sock, int(value))
191 def peer_groups(self):
192 return capi.nl_socket_get_peer_groups(self._sock)
195 def peer_groups(self, value):
196 capi.nl_socket_set_peer_groups(self._sock, value)
198 def set_bufsize(self, rx, tx):
199 capi.nl_socket_set_buffer_size(self._sock, rx, tx)
201 def connect(self, proto):
202 capi.nl_connect(self._sock, proto)
205 def disconnect(self):
206 capi.nl_close(self._sock)
208 def sendto(self, buf):
209 ret = capi.nl_sendto(self._sock, buf, len(buf))
211 raise Exception('Failed to send')
217 def lookup_socket(protocol):
219 sock = _sockets[protocol]
222 sock.connect(protocol)
223 _sockets[protocol] = sock
227 class DumpParams(object):
228 """Dumping parameters"""
230 def __init__(self, type_=NL_DUMP_LINE):
231 self._dp = capi.alloc_dump_params()
233 raise Exception('Unable to allocate struct nl_dump_params')
235 self._dp.dp_type = type_
238 capi.free_dump_params(self._dp)
242 return self._dp.dp_type
245 def type(self, value):
246 self._dp.dp_type = value
250 return self._dp.dp_prefix
253 def prefix(self, value):
254 self._dp.dp_prefix = value
256 # underscore this to make sure it is deleted first upon module deletion
257 _defaultDumpParams = DumpParams(NL_DUMP_LINE)
259 class Object(object):
260 """Cacheable object (base class)"""
262 def __init__(self, obj_name, name, obj=None):
263 self._obj_name = obj_name
268 obj = capi.object_alloc_name(self._obj_name)
270 self._nl_object = obj
272 # Create a clone which stores the original state to notice
274 clone_obj = capi.nl_object_clone(self._nl_object)
275 self._orig = self._obj2type(clone_obj)
278 if not self._nl_object:
281 capi.nl_object_put(self._nl_object)
284 if hasattr(self, 'format'):
287 return capi.nl_object_dump_buf(self._nl_object, 4096).rstrip()
289 def _new_instance(self):
290 raise NotImplementedError()
294 return self._new_instance(capi.nl_object_clone(self._nl_object))
296 def _module_lookup(self, path, constructor=None):
297 """Lookup object specific module and load it
299 Object implementations consisting of multiple types may
300 offload some type specific code to separate modules which
301 are loadable on demand, e.g. a VLAN link or a specific
302 queueing discipline implementation.
304 Loads the module `path` and calls the constructor if
305 supplied or `module`.init()
307 The constructor/init function typically assigns a new
308 object covering the type specific implementation aspects
309 to the new object, e.g. link.vlan = VLANLink()
316 module = sys.modules[path]
319 ret = getattr(module, constructor)(self)
321 ret = module.init(self)
324 self._modules.append(ret)
326 def _module_brief(self):
329 for module in self._modules:
330 if hasattr(module, 'brief'):
331 ret += module.brief()
335 def dump(self, params=None):
336 """Dump object as human readable text"""
338 params = _defaultDumpParams
340 capi.nl_object_dump(self._nl_object, params._dp)
345 return bool(capi.nl_object_is_marked(self._nl_object))
348 def mark(self, value):
350 capi.nl_object_mark(self._nl_object)
352 capi.nl_object_unmark(self._nl_object)
356 return capi.nl_object_shared(self._nl_object) != 0
360 attr_list = capi.nl_object_attr_list(self._nl_object, 1024)
361 return attr_list[0].split()
365 return capi.nl_object_get_refcnt(self._nl_object)
367 # this method resolves multiple levels of sub types to allow
368 # accessing properties of subclass/subtypes (e.g. link.vlan.id)
369 def _resolve(self, attr):
373 obj = getattr(obj, l.pop(0))
374 return (obj, l.pop(0))
376 def _setattr(self, attr, val):
377 obj, attr = self._resolve(attr)
378 return setattr(obj, attr, val)
380 def _hasattr(self, attr):
381 obj, attr = self._resolve(attr)
382 return hasattr(obj, attr)
384 class ObjIterator(object):
385 def __init__(self, cache, obj):
387 self._nl_object = None
392 capi.nl_object_get(obj)
393 self._nl_object = obj
399 capi.nl_object_put(self._nl_object)
405 return capi.nl_cache_get_next(self._nl_object)
409 raise StopIteration()
412 ret = self._nl_object
415 ret = self.get_next()
418 raise StopIteration()
420 # return ref of previous element and acquire ref of current
421 # element to have object stay around until we fetched the
423 capi.nl_object_put(self._nl_object)
424 capi.nl_object_get(ret)
425 self._nl_object = ret
427 # reference used inside object
428 capi.nl_object_get(ret)
429 return self._cache._new_object(ret)
432 class ReverseObjIterator(ObjIterator):
434 return capi.nl_cache_get_prev(self._nl_object)
437 """Collection of netlink objects"""
439 if self.__class__ is Cache:
440 raise NotImplementedError()
445 capi.nl_cache_free(self._nl_cache)
448 return capi.nl_cache_nitems(self._nl_cache)
451 obj = capi.nl_cache_get_first(self._nl_cache)
452 return ObjIterator(self, obj)
454 def __reversed__(self):
455 obj = capi.nl_cache_get_last(self._nl_cache)
456 return ReverseObjIterator(self, obj)
458 def __contains__(self, item):
459 obj = capi.nl_cache_search(self._nl_cache, item._nl_object)
463 capi.nl_object_put(obj)
466 # called by sub classes to allocate type specific caches by name
468 def _alloc_cache_name(name):
469 return capi.alloc_cache_name(name)
471 # implemented by sub classes, must return new instasnce of cacheable
474 def _new_object(obj):
475 raise NotImplementedError()
477 # implemented by sub classes, must return instance of sub class
478 def _new_cache(self, cache):
479 raise NotImplementedError()
481 def subset(self, filter_):
482 """Return new cache containing subset of cache
484 Cretes a new cache containing all objects which match the
490 c = capi.nl_cache_subset(self._nl_cache, filter_._nl_object)
491 return self._new_cache(cache=c)
493 def dump(self, params=None, filter_=None):
494 """Dump (print) cache as human readable text"""
496 params = _defaultDumpParams
499 filter_ = filter_._nl_object
501 capi.nl_cache_dump_filter(self._nl_cache, params._dp, filter_)
504 """Remove all cache entries"""
505 capi.nl_cache_clear(self._nl_cache)
507 # Called by sub classes to set first cache argument
508 def _set_arg1(self, arg):
510 capi.nl_cache_set_arg1(self._nl_cache, arg)
512 # Called by sub classes to set second cache argument
513 def _set_arg2(self, arg):
515 capi.nl_cache_set_arg2(self._nl_cache, arg)
517 def refill(self, socket=None):
518 """Clear cache and refill it"""
520 socket = lookup_socket(self._protocol)
522 capi.nl_cache_refill(socket._sock, self._nl_cache)
525 def resync(self, socket=None, cb=None):
526 """Synchronize cache with content in kernel"""
528 socket = lookup_socket(self._protocol)
530 capi.nl_cache_resync(socket._sock, self._nl_cache, cb)
533 """Provide this cache to others
535 Caches which have been "provided" are made available
536 to other users (of the same application context) which
537 "require" it. F.e. a link cache is generally provided
538 to allow others to translate interface indexes to
542 capi.nl_cache_mngt_provide(self._nl_cache)
545 """Unprovide this cache
547 No longer make the cache available to others. If the cache
548 has been handed out already, that reference will still
551 capi.nl_cache_mngt_unprovide(self._nl_cache)
553 # Cache Manager (Work in Progress)
555 class CacheManager(object):
556 def __init__(self, protocol, flags=None):
558 self._sock = Socket()
559 self._sock.connect(protocol)
562 flags = NL_AUTO_PROVIDE
564 self._mngr = capi.cache_mngr_alloc(self._sock._sock, protocol, flags)
568 self._sock.disconnect()
571 capi.nl_cache_mngr_free(self._mngr)
574 capi.cache_mngr_add(self._mngr, name, None, None)
576 class AddressFamily(object):
577 """Address family representation
579 af = AddressFamily('inet6')
581 # - ValueError if family name is not known
582 # - TypeError if invalid type is specified for family
584 print af # => 'inet6' (string representation)
585 print int(af) # => 10 (numeric representation)
586 print repr(af) # => AddressFamily('inet6')
588 def __init__(self, family=socket.AF_UNSPEC):
589 if isinstance(family, str):
590 family = capi.nl_str2af(family)
592 raise ValueError('Unknown family name')
593 elif not isinstance(family, int):
596 self._family = family
599 return capi.nl_af2str(self._family, 32)[0]
605 return 'AddressFamily({0!r})'.format(str(self))
608 class AbstractAddress(object):
609 """Abstract address object
611 addr = AbstractAddress('127.0.0.1/8')
612 print addr # => '127.0.0.1/8'
613 print addr.prefixlen # => '8'
614 print addr.family # => 'inet'
615 print len(addr) # => '4' (32bit ipv4 address)
617 a = AbstractAddress('10.0.0.1/24')
618 b = AbstractAddress('10.0.0.2/24')
619 print a == b # => False
623 def __init__(self, addr):
626 if isinstance(addr, str):
627 addr = capi.addr_parse(addr, socket.AF_UNSPEC)
629 raise ValueError('Invalid address format')
631 capi.nl_addr_get(addr)
637 capi.nl_addr_put(self._nl_addr)
639 def __cmp__(self, other):
640 if isinstance(other, str):
641 other = AbstractAddress(other)
643 diff = self.prefixlen - other.prefixlen
645 diff = capi.nl_addr_cmp(self._nl_addr, other._nl_addr)
649 def contains(self, item):
650 diff = int(self.family) - int(item.family)
654 if item.prefixlen < self.prefixlen:
657 diff = capi.nl_addr_cmp_prefix(self._nl_addr, item._nl_addr)
660 def __nonzero__(self):
662 return not capi.nl_addr_iszero(self._nl_addr)
668 return capi.nl_addr_get_len(self._nl_addr)
674 return capi.nl_addr2str(self._nl_addr, 64)[0]
680 """True if address is shared (multiple users)"""
682 return capi.nl_addr_shared(self._nl_addr) != 0
688 """Length of prefix (number of bits)"""
690 return capi.nl_addr_get_prefixlen(self._nl_addr)
695 def prefixlen(self, value):
696 if not self._nl_addr:
699 capi.nl_addr_set_prefixlen(self._nl_addr, int(value))
706 f = capi.nl_addr_get_family(self._nl_addr)
708 return AddressFamily(f)
711 def family(self, value):
712 if not self._nl_addr:
715 if not isinstance(value, AddressFamily):
716 value = AddressFamily(value)
718 capi.nl_addr_set_family(self._nl_addr, int(value))
722 # type = { int | str }
723 # immutable = { True | False }
724 # fmt = func (formatting function)
728 """netlink object attribute decorator
730 decorator used to mark mutable and immutable properties
731 of netlink objects. All properties marked as such are
732 regarded to be accessable.
735 @netlink.nlattr(type=int)
742 func.formatinfo = kwds