Antoni Segura Puimedon has uploaded a new change for review.
Change subject: netlink: move netlink into a lib vdsm subpackage
......................................................................
netlink: move netlink into a lib vdsm subpackage
netlink.py was increasingly getting new netlink entities making the
module difficult to follow. This patch splits each entity on a
separate module of a netlink package so that each new module is
easy to reason about.
Change-Id: I9b393588ccb3ac0c4529446c285570f49cdb1e28
Signed-off-by: Antoni S. Puimedon <asegurap(a)redhat.com>
---
M debian/vdsm-python.install
M lib/vdsm/Makefile.am
M lib/vdsm/ipwrapper.py
M lib/vdsm/netinfo.py
D lib/vdsm/netlink.py
A lib/vdsm/netlink/Makefile.am
A lib/vdsm/netlink/__init__.py
A lib/vdsm/netlink/addr.py
A lib/vdsm/netlink/link.py
M vdsm.spec.in
10 files changed, 446 insertions(+), 338 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/72/27472/1
diff --git a/debian/vdsm-python.install b/debian/vdsm-python.install
index eac4a4b..bb7339e 100644
--- a/debian/vdsm-python.install
+++ b/debian/vdsm-python.install
@@ -11,7 +11,9 @@
./usr/lib/python2.7/dist-packages/vdsm/libvirtconnection.py
./usr/lib/python2.7/dist-packages/vdsm/netconfpersistence.py
./usr/lib/python2.7/dist-packages/vdsm/netinfo.py
-./usr/lib/python2.7/dist-packages/vdsm/netlink.py
+./usr/lib/python2.7/dist-packages/vdsm/netlink/__init__.py
+./usr/lib/python2.7/dist-packages/vdsm/netlink/addr.py
+./usr/lib/python2.7/dist-packages/vdsm/netlink/link.py
./usr/lib/python2.7/dist-packages/vdsm/profile.py
./usr/lib/python2.7/dist-packages/vdsm/qemuimg.py
./usr/lib/python2.7/dist-packages/vdsm/tool/__init__.py
diff --git a/lib/vdsm/Makefile.am b/lib/vdsm/Makefile.am
index bb033e1..90f737e 100644
--- a/lib/vdsm/Makefile.am
+++ b/lib/vdsm/Makefile.am
@@ -19,7 +19,7 @@
#
include $(top_srcdir)/build-aux/Makefile.subs
-SUBDIRS=tool
+SUBDIRS=netlink tool
dist_vdsmpylib_PYTHON = \
__init__.py \
@@ -30,7 +30,6 @@
libvirtconnection.py \
netconfpersistence.py \
netinfo.py \
- netlink.py \
profile.py \
qemuimg.py \
SecureXMLRPCServer.py \
diff --git a/lib/vdsm/ipwrapper.py b/lib/vdsm/ipwrapper.py
index c8d6b36..7cd924d 100644
--- a/lib/vdsm/ipwrapper.py
+++ b/lib/vdsm/ipwrapper.py
@@ -286,12 +286,12 @@
def getLinks():
"""Returns a list of Link objects for each link in the
system."""
- return [Link.fromDict(data) for data in netlink.iter_links()]
+ return [Link.fromDict(data) for data in netlink.link.iter_links()]
def getLink(dev):
"""Returns the Link object for the specified dev."""
- return Link.fromDict(netlink.get_link(dev))
+ return Link.fromDict(netlink.link.get_link(dev))
@equals
diff --git a/lib/vdsm/netinfo.py b/lib/vdsm/netinfo.py
index 1734966..5301290 100644
--- a/lib/vdsm/netinfo.py
+++ b/lib/vdsm/netinfo.py
@@ -42,8 +42,8 @@
from .ipwrapper import routeGet
from .ipwrapper import routeShowGateways, routeShowAllDefaultGateways
from . import libvirtconnection
+from . import netlink
from .netconfpersistence import RunningConfig
-from .netlink import iter_addrs, iter_links
NET_CONF_DIR = '/etc/sysconfig/network-scripts/'
@@ -636,7 +636,7 @@
def _getIpAddrs():
addrs = defaultdict(list)
- for addr in iter_addrs():
+ for addr in netlink.addr.iter_addrs():
addrs[addr['label']].append(addr)
return addrs
@@ -921,7 +921,7 @@
require a NetInfo object."""
if os.path.exists(os.path.join(NET_PATH, iface, 'brport')): # Is it a port
return True
- for linkDict in iter_links():
+ for linkDict in netlink.link.iter_links():
if linkDict['name'] == iface and 'master' in linkDict: # Is it a
slave
return True
if linkDict.get('device') == iface: # Does it back a vlan
@@ -933,6 +933,6 @@
def vlanDevsForIface(iface):
- for linkDict in iter_links():
+ for linkDict in netlink.link.iter_links():
if linkDict.get('device') == iface:
yield linkDict['name']
diff --git a/lib/vdsm/netlink.py b/lib/vdsm/netlink.py
deleted file mode 100644
index 1638ef7..0000000
--- a/lib/vdsm/netlink.py
+++ /dev/null
@@ -1,328 +0,0 @@
-# Copyright 2014 Red Hat, Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-#
-# Refer to the README and COPYING files for full details of the license
-#
-
-from contextlib import contextmanager
-from ctypes import (CDLL, CFUNCTYPE, byref, c_char, c_char_p, c_int, c_void_p,
- c_size_t, get_errno, sizeof)
-from distutils.version import StrictVersion
-from functools import partial
-from Queue import Empty, Queue
-from threading import BoundedSemaphore
-import errno
-import ethtool
-
-NETLINK_ROUTE = 0
-_POOL_SIZE = 5
-CHARBUFFSIZE = 40 # Increased to fit IPv6 expanded representations
-
-
-def iter_links():
- """Generator that yields an information dictionary for each link of
the
- system."""
- with _pool.socket() as sock:
- with _nl_link_cache(sock) as cache:
- link = _nl_cache_get_first(cache)
- while link:
- yield _link_info(cache, link)
- link = _nl_cache_get_next(link)
-
-
-def iter_addrs():
- """Generator that yields an information dictionary for each network
address
- in the system."""
- with _pool.socket() as sock:
- with _nl_addr_cache(sock) as addr_cache:
- with _nl_link_cache(sock) as link_cache: # for index to label
- addr = _nl_cache_get_first(addr_cache)
- while addr:
- yield _addr_info(link_cache, addr)
- addr = _nl_cache_get_next(addr)
-
-
-def get_link(name):
- """Returns the information dictionary of the name specified
link."""
- with _pool.socket() as sock:
- with _nl_link_cache(sock) as cache:
- link = _rtnl_link_get_by_name(cache, name)
- if not link:
- raise IOError(errno.ENODEV, '%s is not present in the system' %
- name)
- return _link_info(cache, link)
-
-
-class NLSocketPool(object):
- """Pool of netlink sockets."""
- def __init__(self, size):
- if size <= 0:
- raise ValueError('Invalid socket pool size %r. Must be positive')
- self._semaphore = BoundedSemaphore(size)
- self._sockets = Queue(maxsize=size)
-
- @contextmanager
- def socket(self):
- """Returns a socket from the pool (creating it when
needed)."""
- with self._semaphore:
- try:
- sock = self._sockets.get_nowait()
- except Empty:
- sock = _open_socket()
- try:
- yield sock
- finally:
- self._sockets.put_nowait(sock)
-
-
-_pool = NLSocketPool(_POOL_SIZE)
-
-
-def _open_socket():
- """Returns an open netlink socket."""
- sock = _nl_socket_alloc()
- if sock is None:
- raise IOError(get_errno(), 'Failed to allocate netlink handle')
-
- err = _nl_connect(sock, NETLINK_ROUTE)
- if err:
- _nl_socket_free(sock)
- raise IOError(-err, _nl_geterror())
- return sock
-
-
-def _close_socket(sock):
- """Closes and frees the resources of the passed netlink
socket."""
- _nl_socket_free(sock)
-
-
-@contextmanager
-def _cache_manager(cache_allocator, sock):
- """Provides a cache using cache_allocator and frees it and its links
upon
- exit."""
- cache = cache_allocator(sock)
- try:
- yield cache
- finally:
- _nl_cache_free(cache)
-
-
-def _addr_info(link_cache, addr):
- """Returns a dictionary with the address
information."""
- index = _rtnl_addr_get_ifindex(addr)
- return {
- 'label': (_rtnl_addr_get_label(addr) or
- _link_index_to_name(link_cache, index)),
- 'index': index,
- 'family': _addr_family(addr),
- 'prefixlen': _rtnl_addr_get_prefixlen(addr),
- 'scope': _addr_scope(addr),
- 'flags': _rtnl_addr_get_flags(addr),
- 'address': _addr_local(addr)}
-
-
-def _link_info(cache, link):
- """Returns a dictionary with the information of the link
object."""
- info = {}
- info['address'] = _link_address(link)
- info['flags'] = _rtnl_link_get_flags(link)
- info['index'] = _rtnl_link_get_ifindex(link)
- info['mtu'] = _rtnl_link_get_mtu(link)
- info['name'] = _rtnl_link_get_name(link)
- info['qdisc'] = _rtnl_link_get_qdisc(link)
- info['state'] = _link_state(link)
-
- # libnl-1 has a bug when getting type information.
- #
https://github.com/tgraf/libnl-1.1-stable/issues/1
- # TODO: Add for libnl1 if the bug is fixed
- if _ethtool_uses_libnl3():
- link_type = _rtnl_link_get_type(link)
- if link_type is not None:
- info['type'] = link_type
-
- underlying_device_index = _rtnl_link_get_link(link)
- if underlying_device_index > 0:
- info['device'] = _link_index_to_name(cache, underlying_device_index)
-
- master_index = _rtnl_link_get_master(link)
- if master_index > 0:
- info['master'] = _link_index_to_name(cache, master_index)
-
- vlanid = _rtnl_link_vlan_get_id(link)
- if vlanid >= 0:
- info['vlanid'] = vlanid
-
- return info
-
-
-def _link_index_to_name(cache, link_index):
- """Returns the textual name of the link with index equal to
link_index."""
- name = (c_char * CHARBUFFSIZE)()
- return _rtnl_link_i2name(cache, link_index, name, sizeof(name))
-
-
-def _link_address(link):
- """Returns the MAC address of a link object or None if the link does
not
- have a physical address."""
- nl_addr = _rtnl_link_get_addr(link)
- if nl_addr:
- address = (c_char * CHARBUFFSIZE)()
- return _nl_addr2str(nl_addr, address, sizeof(address))
- else:
- return None
-
-
-def _link_state(link):
- """Returns the textual representation of the link's
operstate."""
- state = _rtnl_link_get_operstate(link)
- operstate = (c_char * CHARBUFFSIZE)()
- return _rtnl_link_operstate2str(state, operstate, sizeof(operstate))
-
-
-def _addr_scope(addr):
- """Returns the scope name for which the address is
defined."""
- scope = (c_char * CHARBUFFSIZE)()
- return _rtnl_scope2str(_rtnl_addr_get_scope(addr), scope, sizeof(scope))
-
-
-def _addr_family(addr):
- """Returns the family name of the address."""
- family = (c_char * CHARBUFFSIZE)()
- return _nl_af2str(_rtnl_addr_get_family(addr), family, sizeof(family))
-
-
-def _addr_local(addr):
- """Returns the textual representation of the
address."""
- address = (c_char * CHARBUFFSIZE)()
- return _nl_addr2str(_rtnl_addr_get_local(addr), address, sizeof(address))
-
-
-def _ethtool_uses_libnl3():
- """Returns whether ethtool uses libnl3."""
- return (StrictVersion('0.9') <=
- StrictVersion(ethtool.version.split()[1].lstrip('v')))
-
-
-# C function prototypes
-#
http://docs.python.org/2/library/ctypes.html#function-prototypes
-# This helps ctypes know the calling conventions it should use to communicate
-# with the binary interface of libnl and which types it should allocate and
-# cast. Without it ctypes fails when not running on the main thread.
-_int_proto = CFUNCTYPE(c_int, c_void_p)
-_char_proto = CFUNCTYPE(c_char_p, c_void_p)
-_void_proto = CFUNCTYPE(c_void_p, c_void_p)
-_none_proto = CFUNCTYPE(None, c_void_p)
-
-if _ethtool_uses_libnl3():
- LIBNL = CDLL('libnl-3.so.200', use_errno=True)
- LIBNL_ROUTE = CDLL('libnl-route-3.so.200', use_errno=True)
-
- _nl_socket_alloc = CFUNCTYPE(c_void_p)(('nl_socket_alloc', LIBNL))
- _nl_socket_free = _none_proto(('nl_socket_free', LIBNL))
-
- _link_alloc_cache = CFUNCTYPE(c_int, c_void_p, c_int, c_void_p)(
- ('rtnl_link_alloc_cache', LIBNL_ROUTE))
- _addr_alloc_cache = CFUNCTYPE(c_int, c_void_p, c_void_p)(
- ('rtnl_addr_alloc_cache', LIBNL_ROUTE))
- _link_is_vlan = _int_proto(('rtnl_link_is_vlan', LIBNL_ROUTE))
- _vlan_get_id = _int_proto(('rtnl_link_vlan_get_id', LIBNL_ROUTE))
-
- def _rtnl_link_alloc_cache(sock):
- """Wraps the new link alloc cache to expose the libnl1
signature"""
- AF_UNSPEC = 0
- cache = c_void_p()
- err = _link_alloc_cache(sock, AF_UNSPEC, byref(cache))
- if err:
- raise IOError(-err, _nl_geterror())
- return cache
-
- def _rtnl_addr_alloc_cache(sock):
- """Wraps the new addr alloc cache to expose the libnl1
signature"""
- cache = c_void_p()
- err = _addr_alloc_cache(sock, byref(cache))
- if err:
- raise IOError(-err, _nl_geterror())
- return cache
-
- _rtnl_link_get_type = _char_proto(('rtnl_link_get_type', LIBNL_ROUTE))
-
- def _rtnl_link_vlan_get_id(link):
- """Wraps the new vlan id retrieval to expose the libnl1
signature"""
- if _link_is_vlan(link):
- return _vlan_get_id(link)
- else:
- return -1
-else: # libnl-1
- # Change from handle to socket as it is now more accurately called in
- # libnl-3
- LIBNL_ROUTE = LIBNL = CDLL('libnl.so.1', use_errno=True)
-
- _nl_socket_alloc = CFUNCTYPE(c_void_p)(('nl_handle_alloc', LIBNL))
- _nl_socket_free = _none_proto(('nl_handle_destroy', LIBNL))
-
- _rtnl_link_vlan_get_id = _int_proto(('rtnl_link_vlan_get_id', LIBNL))
- _link_alloc_cache = _void_proto(('rtnl_link_alloc_cache', LIBNL))
- _addr_alloc_cache = _void_proto(('rtnl_addr_alloc_cache', LIBNL))
-
- def _alloc_cache(allocator, sock):
- cache = allocator(sock)
- if cache is None:
- raise IOError(get_errno(), 'Failed to allocate the cache')
- return cache
-
- _rtnl_link_alloc_cache = partial(_alloc_cache, _link_alloc_cache)
- _rtnl_addr_alloc_cache = partial(_alloc_cache, _addr_alloc_cache)
-
-_nl_connect = CFUNCTYPE(c_int, c_void_p, c_int)(('nl_connect', LIBNL))
-_nl_geterror = CFUNCTYPE(c_char_p)(('nl_geterror', LIBNL))
-
-_nl_cache_free = _none_proto(('nl_cache_free', LIBNL))
-_nl_cache_get_first = _void_proto(('nl_cache_get_first', LIBNL))
-_nl_cache_get_next = _void_proto(('nl_cache_get_next', LIBNL))
-
-_rtnl_link_get_addr = _void_proto(('rtnl_link_get_addr', LIBNL_ROUTE))
-_rtnl_link_get_flags = _int_proto(('rtnl_link_get_flags', LIBNL_ROUTE))
-_rtnl_link_get_ifindex = _int_proto(('rtnl_link_get_ifindex', LIBNL_ROUTE))
-_rtnl_link_get_link = _int_proto(('rtnl_link_get_link', LIBNL_ROUTE))
-_rtnl_link_get_master = _int_proto(('rtnl_link_get_master', LIBNL_ROUTE))
-_rtnl_link_get_mtu = _int_proto(('rtnl_link_get_mtu', LIBNL_ROUTE))
-_rtnl_link_get_name = _char_proto(('rtnl_link_get_name', LIBNL_ROUTE))
-_rtnl_link_get_operstate = _int_proto(('rtnl_link_get_operstate', LIBNL_ROUTE))
-_rtnl_link_get_qdisc = _char_proto(('rtnl_link_get_qdisc', LIBNL_ROUTE))
-
-_rtnl_addr_get_label = _char_proto(('rtnl_addr_get_label', LIBNL_ROUTE))
-_rtnl_addr_get_ifindex = _int_proto(('rtnl_addr_get_ifindex', LIBNL_ROUTE))
-_rtnl_addr_get_family = _int_proto(('rtnl_addr_get_family', LIBNL_ROUTE))
-_rtnl_addr_get_prefixlen = _int_proto(('rtnl_addr_get_prefixlen', LIBNL_ROUTE))
-_rtnl_addr_get_scope = _int_proto(('rtnl_addr_get_scope', LIBNL_ROUTE))
-_rtnl_addr_get_flags = _int_proto(('rtnl_addr_get_flags', LIBNL_ROUTE))
-_rtnl_addr_get_local = _void_proto(('rtnl_addr_get_local', LIBNL_ROUTE))
-
-_nl_addr2str = CFUNCTYPE(c_char_p, c_void_p, c_char_p, c_size_t)((
- 'nl_addr2str', LIBNL))
-_rtnl_link_get_by_name = CFUNCTYPE(c_void_p, c_void_p, c_char_p)((
- 'rtnl_link_get_by_name', LIBNL_ROUTE))
-_rtnl_link_i2name = CFUNCTYPE(c_char_p, c_void_p, c_int, c_char_p, c_size_t)((
- 'rtnl_link_i2name', LIBNL_ROUTE))
-_rtnl_link_operstate2str = CFUNCTYPE(c_char_p, c_int, c_char_p, c_size_t)((
- 'rtnl_link_operstate2str', LIBNL_ROUTE))
-_nl_af2str = CFUNCTYPE(c_char_p, c_int, c_char_p, c_size_t)(('nl_af2str',
- LIBNL))
-_rtnl_scope2str = CFUNCTYPE(c_char_p, c_int, c_char_p, c_size_t)((
- 'rtnl_scope2str', LIBNL_ROUTE))
-
-_nl_link_cache = partial(_cache_manager, _rtnl_link_alloc_cache)
-_nl_addr_cache = partial(_cache_manager, _rtnl_addr_alloc_cache)
diff --git a/lib/vdsm/netlink/Makefile.am b/lib/vdsm/netlink/Makefile.am
new file mode 100644
index 0000000..a5007c0
--- /dev/null
+++ b/lib/vdsm/netlink/Makefile.am
@@ -0,0 +1,25 @@
+# Copyright 2014 Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+include $(top_srcdir)/build-aux/Makefile.subs
+
+dist_vdsmnetlink_PYTHON = \
+ __init__.py \
+ addr.py \
+ link.py \
+ $(NULL)
diff --git a/lib/vdsm/netlink/__init__.py b/lib/vdsm/netlink/__init__.py
new file mode 100644
index 0000000..c7bb58f
--- /dev/null
+++ b/lib/vdsm/netlink/__init__.py
@@ -0,0 +1,135 @@
+#
+# Copyright 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+from contextlib import contextmanager
+from ctypes import (CDLL, CFUNCTYPE, c_char_p, c_int, c_void_p, c_size_t,
+ get_errno)
+from distutils.version import StrictVersion
+from Queue import Empty, Queue
+from threading import BoundedSemaphore
+
+import ethtool
+
+_POOL_SIZE = 5
+_NETLINK_ROUTE = 0
+
+
+class NLSocketPool(object):
+ """Pool of netlink sockets."""
+ def __init__(self, size):
+ if size <= 0:
+ raise ValueError('Invalid socket pool size %r. Must be positive')
+ self._semaphore = BoundedSemaphore(size)
+ self._sockets = Queue(maxsize=size)
+
+ @contextmanager
+ def socket(self):
+ """Returns a socket from the pool (creating it when
needed)."""
+ with self._semaphore:
+ try:
+ sock = self._sockets.get_nowait()
+ except Empty:
+ sock = _open_socket()
+ try:
+ yield sock
+ finally:
+ self._sockets.put_nowait(sock)
+
+
+_pool = NLSocketPool(_POOL_SIZE)
+
+
+def _open_socket():
+ """Returns an open netlink socket."""
+ sock = _nl_socket_alloc()
+ if sock is None:
+ raise IOError(get_errno(), 'Failed to allocate netlink handle')
+
+ err = _nl_connect(sock, _NETLINK_ROUTE)
+ if err:
+ _nl_socket_free(sock)
+ raise IOError(-err, _nl_geterror())
+ return sock
+
+
+def _close_socket(sock):
+ """Closes and frees the resources of the passed netlink
socket."""
+ _nl_socket_free(sock)
+
+
+@contextmanager
+def _cache_manager(cache_allocator, sock):
+ """Provides a cache using cache_allocator and frees it and its links
upon
+ exit."""
+ cache = cache_allocator(sock)
+ try:
+ yield cache
+ finally:
+ _nl_cache_free(cache)
+
+
+# C function prototypes
+#
http://docs.python.org/2/library/ctypes.html#function-prototypes
+# This helps ctypes know the calling conventions it should use to communicate
+# with the binary interface of libnl and which types it should allocate and
+# cast. Without it ctypes fails when not running on the main thread.
+_int_proto = CFUNCTYPE(c_int, c_void_p)
+_char_proto = CFUNCTYPE(c_char_p, c_void_p)
+_void_proto = CFUNCTYPE(c_void_p, c_void_p)
+_none_proto = CFUNCTYPE(None, c_void_p)
+
+
+def _ethtool_uses_libnl3():
+ """Returns whether ethtool uses libnl3."""
+ return (StrictVersion('0.9') <=
+ StrictVersion(ethtool.version.split()[1].lstrip('v')))
+
+if _ethtool_uses_libnl3():
+ LIBNL = CDLL('libnl-3.so.200', use_errno=True)
+ LIBNL_ROUTE = CDLL('libnl-route-3.so.200', use_errno=True)
+
+ _nl_socket_alloc = CFUNCTYPE(c_void_p)(('nl_socket_alloc', LIBNL))
+ _nl_socket_free = _none_proto(('nl_socket_free', LIBNL))
+
+else: # libnl-1
+ # Change from handle to socket as it is now more accurately called in
+ # libnl-3
+ LIBNL_ROUTE = LIBNL = CDLL('libnl.so.1', use_errno=True)
+
+ _nl_socket_alloc = CFUNCTYPE(c_void_p)(('nl_handle_alloc', LIBNL))
+ _nl_socket_free = _none_proto(('nl_handle_destroy', LIBNL))
+
+ def _alloc_cache(allocator, sock):
+ cache = allocator(sock)
+ if cache is None:
+ raise IOError(get_errno(), 'Failed to allocate the cache')
+ return cache
+
+_nl_connect = CFUNCTYPE(c_int, c_void_p, c_int)(('nl_connect', LIBNL))
+_nl_geterror = CFUNCTYPE(c_char_p)(('nl_geterror', LIBNL))
+
+_nl_cache_free = _none_proto(('nl_cache_free', LIBNL))
+_nl_cache_get_first = _void_proto(('nl_cache_get_first', LIBNL))
+_nl_cache_get_next = _void_proto(('nl_cache_get_next', LIBNL))
+_nl_addr2str = CFUNCTYPE(c_char_p, c_void_p, c_char_p, c_size_t)((
+ 'nl_addr2str', LIBNL))
+_nl_af2str = CFUNCTYPE(c_char_p, c_int, c_char_p, c_size_t)(('nl_af2str',
+ LIBNL))
+_rtnl_scope2str = CFUNCTYPE(c_char_p, c_int, c_char_p, c_size_t)((
+ 'rtnl_scope2str', LIBNL_ROUTE))
diff --git a/lib/vdsm/netlink/addr.py b/lib/vdsm/netlink/addr.py
new file mode 100644
index 0000000..33542f5
--- /dev/null
+++ b/lib/vdsm/netlink/addr.py
@@ -0,0 +1,111 @@
+# Copyright 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+from ctypes import (CFUNCTYPE, byref, c_char, c_char_p, c_int, c_size_t,
+ c_void_p, sizeof)
+from functools import partial
+
+from . import (_alloc_cache, _cache_manager, _nl_cache_get_first,
+ _nl_cache_get_next)
+from . import _char_proto, _int_proto, _void_proto
+from . import (_ethtool_uses_libnl3, LIBNL_ROUTE, _nl_addr2str, _nl_af2str,
+ _nl_geterror, _pool)
+from .link import _nl_link_cache, _link_index_to_name
+
+CHARBUFFSIZE = 40 # Increased to fit IPv6 expanded representations
+
+
+def iter_addrs():
+ """Generator that yields an information dictionary for each network
address
+ in the system."""
+ with _pool.socket() as sock:
+ with _nl_addr_cache(sock) as addr_cache:
+ with _nl_link_cache(sock) as link_cache: # for index to label
+ addr = _nl_cache_get_first(addr_cache)
+ while addr:
+ yield _addr_info(link_cache, addr)
+ addr = _nl_cache_get_next(addr)
+
+
+def _addr_info(link_cache, addr):
+ """Returns a dictionary with the address
information."""
+ index = _rtnl_addr_get_ifindex(addr)
+ return {
+ 'label': (_rtnl_addr_get_label(addr) or
+ _link_index_to_name(link_cache, index)),
+ 'index': index,
+ 'family': _addr_family(addr),
+ 'prefixlen': _rtnl_addr_get_prefixlen(addr),
+ 'scope': _addr_scope(addr),
+ 'flags': _rtnl_addr_get_flags(addr),
+ 'address': _addr_local(addr)}
+
+
+def _addr_scope(addr):
+ """Returns the scope name for which the address is
defined."""
+ scope = (c_char * CHARBUFFSIZE)()
+ return _rtnl_scope2str(_rtnl_addr_get_scope(addr), scope, sizeof(scope))
+
+
+def _addr_family(addr):
+ """Returns the family name of the address."""
+ family = (c_char * CHARBUFFSIZE)()
+ return _nl_af2str(_rtnl_addr_get_family(addr), family, sizeof(family))
+
+
+def _addr_local(addr):
+ """Returns the textual representation of the
address."""
+ address = (c_char * CHARBUFFSIZE)()
+ return _nl_addr2str(_rtnl_addr_get_local(addr), address, sizeof(address))
+
+
+# C function prototypes
+#
http://docs.python.org/2/library/ctypes.html#function-prototypes
+# This helps ctypes know the calling conventions it should use to communicate
+# with the binary interface of libnl and which types it should allocate and
+# cast. Without it ctypes fails when not running on the main thread.
+if _ethtool_uses_libnl3():
+ _addr_alloc_cache = CFUNCTYPE(c_int, c_void_p, c_void_p)(
+ ('rtnl_addr_alloc_cache', LIBNL_ROUTE))
+
+ def _rtnl_addr_alloc_cache(sock):
+ """Wraps the new addr alloc cache to expose the libnl1
signature"""
+ cache = c_void_p()
+ err = _addr_alloc_cache(sock, byref(cache))
+ if err:
+ raise IOError(-err, _nl_geterror())
+ return cache
+
+else: # libnl-1
+ # Change from handle to socket as it is now more accurately called in
+ # libnl-3
+ _addr_alloc_cache = _void_proto(('rtnl_addr_alloc_cache', LIBNL_ROUTE))
+
+ _rtnl_addr_alloc_cache = partial(_alloc_cache, _addr_alloc_cache)
+
+_nl_addr_cache = partial(_cache_manager, _rtnl_addr_alloc_cache)
+
+_rtnl_addr_get_label = _char_proto(('rtnl_addr_get_label', LIBNL_ROUTE))
+_rtnl_addr_get_ifindex = _int_proto(('rtnl_addr_get_ifindex', LIBNL_ROUTE))
+_rtnl_addr_get_family = _int_proto(('rtnl_addr_get_family', LIBNL_ROUTE))
+_rtnl_addr_get_prefixlen = _int_proto(('rtnl_addr_get_prefixlen', LIBNL_ROUTE))
+_rtnl_addr_get_scope = _int_proto(('rtnl_addr_get_scope', LIBNL_ROUTE))
+_rtnl_addr_get_flags = _int_proto(('rtnl_addr_get_flags', LIBNL_ROUTE))
+_rtnl_addr_get_local = _void_proto(('rtnl_addr_get_local', LIBNL_ROUTE))
+_rtnl_scope2str = CFUNCTYPE(c_char_p, c_int, c_char_p, c_size_t)((
+ 'rtnl_scope2str', LIBNL_ROUTE))
diff --git a/lib/vdsm/netlink/link.py b/lib/vdsm/netlink/link.py
new file mode 100644
index 0000000..5c3583d
--- /dev/null
+++ b/lib/vdsm/netlink/link.py
@@ -0,0 +1,161 @@
+# Copyright 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+from ctypes import (CFUNCTYPE, byref, c_char, c_char_p, c_int, c_void_p,
+ c_size_t, sizeof)
+from functools import partial
+import errno
+
+from . import (_alloc_cache, _cache_manager, _nl_cache_get_first,
+ _nl_cache_get_next)
+from . import _char_proto, _int_proto, _void_proto
+from . import (_ethtool_uses_libnl3, LIBNL_ROUTE, _nl_addr2str, _nl_geterror,
+ _pool)
+
+CHARBUFFSIZE = 40 # Increased to fit IPv6 expanded representations
+
+
+def get_link(name):
+ """Returns the information dictionary of the name specified
link."""
+ with _pool.socket() as sock:
+ with _nl_link_cache(sock) as cache:
+ link = _rtnl_link_get_by_name(cache, name)
+ if not link:
+ raise IOError(errno.ENODEV, '%s is not present in the system' %
+ name)
+ return _link_info(cache, link)
+
+
+def iter_links():
+ """Generator that yields an information dictionary for each link of
the
+ system."""
+ with _pool.socket() as sock:
+ with _nl_link_cache(sock) as cache:
+ link = _nl_cache_get_first(cache)
+ while link:
+ yield _link_info(cache, link)
+ link = _nl_cache_get_next(link)
+
+
+def _link_info(cache, link):
+ """Returns a dictionary with the information of the link
object."""
+ info = {}
+ info['address'] = _link_address(link)
+ info['flags'] = _rtnl_link_get_flags(link)
+ info['index'] = _rtnl_link_get_ifindex(link)
+ info['mtu'] = _rtnl_link_get_mtu(link)
+ info['name'] = _rtnl_link_get_name(link)
+ info['qdisc'] = _rtnl_link_get_qdisc(link)
+ info['state'] = _link_state(link)
+
+ # libnl-1 has a bug when getting type information.
+ #
https://github.com/tgraf/libnl-1.1-stable/issues/1
+ # TODO: Add for libnl1 if the bug is fixed
+ if _ethtool_uses_libnl3():
+ link_type = _rtnl_link_get_type(link)
+ if link_type is not None:
+ info['type'] = link_type
+
+ underlying_device_index = _rtnl_link_get_link(link)
+ if underlying_device_index > 0:
+ info['device'] = _link_index_to_name(cache, underlying_device_index)
+
+ master_index = _rtnl_link_get_master(link)
+ if master_index > 0:
+ info['master'] = _link_index_to_name(cache, master_index)
+
+ vlanid = _rtnl_link_vlan_get_id(link)
+ if vlanid >= 0:
+ info['vlanid'] = vlanid
+
+ return info
+
+
+def _link_index_to_name(cache, link_index):
+ """Returns the textual name of the link with index equal to
link_index."""
+ name = (c_char * CHARBUFFSIZE)()
+ return _rtnl_link_i2name(cache, link_index, name, sizeof(name))
+
+
+def _link_address(link):
+ """Returns the MAC address of a link object or None if the link does
not
+ have a physical address."""
+ nl_addr = _rtnl_link_get_addr(link)
+ if nl_addr:
+ address = (c_char * CHARBUFFSIZE)()
+ return _nl_addr2str(nl_addr, address, sizeof(address))
+ else:
+ return None
+
+
+def _link_state(link):
+ """Returns the textual representation of the link's
operstate."""
+ state = _rtnl_link_get_operstate(link)
+ operstate = (c_char * CHARBUFFSIZE)()
+ return _rtnl_link_operstate2str(state, operstate, sizeof(operstate))
+
+
+# C function prototypes
+#
http://docs.python.org/2/library/ctypes.html#function-prototypes
+# This helps ctypes know the calling conventions it should use to communicate
+# with the binary interface of libnl and which types it should allocate and
+# cast. Without it ctypes fails when not running on the main thread.
+if _ethtool_uses_libnl3():
+ _link_alloc_cache = CFUNCTYPE(c_int, c_void_p, c_int, c_void_p)(
+ ('rtnl_link_alloc_cache', LIBNL_ROUTE))
+ _link_is_vlan = _int_proto(('rtnl_link_is_vlan', LIBNL_ROUTE))
+ _vlan_get_id = _int_proto(('rtnl_link_vlan_get_id', LIBNL_ROUTE))
+ _rtnl_link_get_type = _char_proto(('rtnl_link_get_type', LIBNL_ROUTE))
+
+ def _rtnl_link_alloc_cache(sock):
+ """Wraps the new link alloc cache to expose the libnl1
signature"""
+ AF_UNSPEC = 0
+ cache = c_void_p()
+ err = _link_alloc_cache(sock, AF_UNSPEC, byref(cache))
+ if err:
+ raise IOError(-err, _nl_geterror())
+ return cache
+
+ def _rtnl_link_vlan_get_id(link):
+ """Wraps the new vlan id retrieval to expose the libnl1
signature"""
+ if _link_is_vlan(link):
+ return _vlan_get_id(link)
+ else:
+ return -1
+else:
+ _link_alloc_cache = _void_proto(('rtnl_link_alloc_cache', LIBNL_ROUTE))
+ _rtnl_link_alloc_cache = partial(_alloc_cache, _link_alloc_cache)
+ _rtnl_link_vlan_get_id = _int_proto(('rtnl_link_vlan_get_id', LIBNL_ROUTE))
+
+_nl_link_cache = partial(_cache_manager, _rtnl_link_alloc_cache)
+
+_rtnl_link_get_addr = _void_proto(('rtnl_link_get_addr', LIBNL_ROUTE))
+_rtnl_link_get_flags = _int_proto(('rtnl_link_get_flags', LIBNL_ROUTE))
+_rtnl_link_get_ifindex = _int_proto(('rtnl_link_get_ifindex', LIBNL_ROUTE))
+_rtnl_link_get_link = _int_proto(('rtnl_link_get_link', LIBNL_ROUTE))
+_rtnl_link_get_master = _int_proto(('rtnl_link_get_master', LIBNL_ROUTE))
+_rtnl_link_get_mtu = _int_proto(('rtnl_link_get_mtu', LIBNL_ROUTE))
+_rtnl_link_get_name = _char_proto(('rtnl_link_get_name', LIBNL_ROUTE))
+_rtnl_link_get_operstate = _int_proto(('rtnl_link_get_operstate', LIBNL_ROUTE))
+_rtnl_link_get_qdisc = _char_proto(('rtnl_link_get_qdisc', LIBNL_ROUTE))
+_rtnl_link_get_by_name = CFUNCTYPE(c_void_p, c_void_p, c_char_p)((
+ 'rtnl_link_get_by_name', LIBNL_ROUTE))
+_rtnl_link_i2name = CFUNCTYPE(c_char_p, c_void_p, c_int, c_char_p, c_size_t)((
+ 'rtnl_link_i2name', LIBNL_ROUTE))
+_rtnl_link_operstate2str = CFUNCTYPE(c_char_p, c_int, c_char_p, c_size_t)((
+ 'rtnl_link_operstate2str', LIBNL_ROUTE))
diff --git a/vdsm.spec.in b/vdsm.spec.in
index 564ff20..aecb25f 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -1134,6 +1134,7 @@
%defattr(-, root, root, -)
%{_bindir}/vdsm-tool
%dir %{python_sitearch}/%{vdsm_name}
+%dir %{python_sitearch}/%{vdsm_name}/netlink
%dir %{python_sitearch}/%{vdsm_name}/tool
%{python_sitearch}/%{vdsm_name}/__init__.py*
%{python_sitearch}/%{vdsm_name}/compat.py*
@@ -1144,7 +1145,9 @@
%{python_sitearch}/%{vdsm_name}/ipwrapper.py*
%{python_sitearch}/%{vdsm_name}/libvirtconnection.py*
%{python_sitearch}/%{vdsm_name}/netinfo.py*
-%{python_sitearch}/%{vdsm_name}/netlink.py*
+%{python_sitearch}/%{vdsm_name}/netlink/__init__.py*
+%{python_sitearch}/%{vdsm_name}/netlink/addr.py*
+%{python_sitearch}/%{vdsm_name}/netlink/link.py*
%{python_sitearch}/%{vdsm_name}/profile.py*
%{python_sitearch}/%{vdsm_name}/qemuimg.py*
%{python_sitearch}/%{vdsm_name}/SecureXMLRPCServer.py*
--
To view, visit
http://gerrit.ovirt.org/27472
To unsubscribe, visit
http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I9b393588ccb3ac0c4529446c285570f49cdb1e28
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Antoni Segura Puimedon <asegurap(a)redhat.com>