Antoni Segura Puimedon has uploaded a new change for review.

Change subject: netlink: User libnl-3 when available
......................................................................

netlink: User libnl-3 when available

On new distibutions (Fedora, ubuntu, el7, etc) python-ethtool uses
libnl3 while vdsm was using libnl1. The problem was that libnl1
and libnl3 use the same algorithm for allocating netlink ports and
collided. This patch fixes it by using libnl3 if it is in the system
(which reasonably means that the python-ethtool version will be new
enough as to use it as well)

Change-Id: I45f043a8416e57d5fb550e2e817e6df38cd793b1
Bug-Url: https://bugzilla.redhat.com/1078312
Signed-off-by: Antoni S. Puimedon <asegu...@redhat.com>
---
M lib/vdsm/netlink.py
1 file changed, 89 insertions(+), 37 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/14/26514/1

diff --git a/lib/vdsm/netlink.py b/lib/vdsm/netlink.py
index c90f3da..60a16e8 100644
--- a/lib/vdsm/netlink.py
+++ b/lib/vdsm/netlink.py
@@ -18,7 +18,7 @@
 #
 
 from contextlib import contextmanager
-from ctypes import (CDLL, CFUNCTYPE, c_char, c_char_p, c_int, c_void_p,
+from ctypes import (CDLL, CFUNCTYPE, byref, c_char, c_char_p, c_int, c_void_p,
                     c_size_t, get_errno, sizeof)
 from functools import partial
 from Queue import Empty, Queue
@@ -28,7 +28,6 @@
 NETLINK_ROUTE = 0
 _POOL_SIZE = 5
 CHARBUFFSIZE = 40  # Increased to fit IPv6 expanded representations
-LIBNL = CDLL('libnl.so.1', use_errno=True)
 
 # C function prototypes
 # http://docs.python.org/2/library/ctypes.html#function-prototypes
@@ -38,49 +37,96 @@
 _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)
+try:
+    LIBNL = LIBNL3 = CDLL('libnl-3.so.200',  use_errno=True)
+
+    _nl_socket_alloc = CFUNCTYPE(c_void_p)(('nl_socket_alloc', LIBNL3))
+    _nl_socket_free = CFUNCTYPE(None, c_void_p)(('nl_socket_free', LIBNL3))
+
+    LIBNL_ROUTE = CDLL('libnl-route-3.so',  use_errno=True)
+
+    def _rtnl_link_alloc_cache(sock):
+        AF_UNSPEC = 0
+        __rtnl_link_alloc_cache = CFUNCTYPE(c_int, c_void_p, c_int, c_void_p)(
+            ('rtnl_link_alloc_cache', LIBNL_ROUTE))
+        cache = c_void_p()
+        err = __rtnl_link_alloc_cache(sock, AF_UNSPEC, byref(cache))
+        if err:
+            return None
+        else:
+            return cache
+
+    def _rtnl_addr_alloc_cache(sock):
+        __rtnl_addr_alloc_cache = CFUNCTYPE(c_int, c_void_p, c_void_p)(
+            ('rtnl_addr_alloc_cache', LIBNL_ROUTE))
+        cache = c_void_p()
+        err = __rtnl_addr_alloc_cache(sock, byref(cache))
+        if err:
+            return None
+        else:
+            return cache
+
+    _rtnl_link_get_type = _char_proto(('rtnl_link_get_type', LIBNL_ROUTE))
+
+    def _rtnl_link_vlan_get_id(link):
+        __rtnl_link_is_vlan = _int_proto(('rtnl_link_is_vlan', LIBNL_ROUTE))
+        __rtnl_link_vlan_get_id = _int_proto(('rtnl_link_vlan_get_id',
+                                             LIBNL_ROUTE))
+        if __rtnl_link_is_vlan(link):
+            return __rtnl_link_vlan_get_id(link)
+        else:
+            return -1
+
+except OSError:  # libnl3 is not present, fallback to libnl1
+    LIBNL_ROUTE = LIBNL = CDLL('libnl.so.1', use_errno=True)
+    LIBNL3 = None
+
+    _nl_handle_alloc = CFUNCTYPE(c_void_p)(('nl_handle_alloc', LIBNL))
+    _nl_handle_destroy = CFUNCTYPE(None, c_void_p)(('nl_handle_destroy',
+                                                    LIBNL))
+
+    _rtnl_link_alloc_cache = _void_proto(('rtnl_link_alloc_cache', LIBNL))
+    _rtnl_addr_alloc_cache = _void_proto(('rtnl_addr_alloc_cache', LIBNL))
+
+    _rtnl_link_vlan_get_id = _int_proto(('rtnl_link_vlan_get_id', LIBNL))
 
 _nl_connect = CFUNCTYPE(c_int, c_void_p, c_int)(('nl_connect', LIBNL))
-_nl_handle_alloc = CFUNCTYPE(c_void_p)(('nl_handle_alloc', LIBNL))
-_nl_handle_destroy = CFUNCTYPE(None, c_void_p)(('nl_handle_destroy', LIBNL))
-
 _nl_geterror = CFUNCTYPE(c_char_p)(('nl_geterror', LIBNL))
 
 _nl_cache_free = CFUNCTYPE(None, c_void_p)(('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_alloc_cache = _void_proto(('rtnl_link_alloc_cache', LIBNL))
-_rtnl_addr_alloc_cache = _void_proto(('rtnl_addr_alloc_cache', LIBNL))
 
-_rtnl_link_get_addr = _void_proto(('rtnl_link_get_addr', LIBNL))
-_rtnl_link_get_flags = _int_proto(('rtnl_link_get_flags', LIBNL))
-_rtnl_link_get_ifindex = _int_proto(('rtnl_link_get_ifindex', LIBNL))
-_rtnl_link_get_link = _int_proto(('rtnl_link_get_link', LIBNL))
-_rtnl_link_get_master = _int_proto(('rtnl_link_get_master', LIBNL))
-_rtnl_link_get_mtu = _int_proto(('rtnl_link_get_mtu', LIBNL))
-_rtnl_link_get_name = _char_proto(('rtnl_link_get_name', LIBNL))
-_rtnl_link_get_operstate = _int_proto(('rtnl_link_get_operstate', LIBNL))
-_rtnl_link_get_qdisc = _char_proto(('rtnl_link_get_qdisc', LIBNL))
-_rtnl_link_vlan_get_id = _int_proto(('rtnl_link_vlan_get_id', 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))
-_rtnl_addr_get_ifindex = _int_proto(('rtnl_addr_get_ifindex', LIBNL))
-_rtnl_addr_get_family = _int_proto(('rtnl_addr_get_family', LIBNL))
-_rtnl_addr_get_prefixlen = _int_proto(('rtnl_addr_get_prefixlen', LIBNL))
-_rtnl_addr_get_scope = _int_proto(('rtnl_addr_get_scope', LIBNL))
-_rtnl_addr_get_flags = _int_proto(('rtnl_addr_get_flags', LIBNL))
-_rtnl_addr_get_local = _void_proto(('rtnl_addr_get_local', LIBNL))
+_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_int)((
+_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))
-_rtnl_link_i2name = CFUNCTYPE(c_char_p, c_void_p, c_int, c_char_p, c_int)((
-    'rtnl_link_i2name', LIBNL))
+    '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))
-_nl_af2str = CFUNCTYPE(c_char_p, c_int, c_char_p, c_int)(('nl_af2str', LIBNL))
-_rtnl_scope2str = CFUNCTYPE(c_char_p, c_int, c_char_p, c_int)((
-    'rtnl_scope2str', LIBNL))
+    '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))
 
 
 class NLSocketPool(object):
@@ -110,20 +156,23 @@
 
 def _open_socket():
     """Returns an open netlink socket."""
-    handle = _nl_handle_alloc()
+    handle = _nl_handle_alloc() if LIBNL3 is None else _nl_socket_alloc()
     if handle is None:
         raise IOError(get_errno(), 'Failed to allocate netlink handle')
 
     err = _nl_connect(handle, NETLINK_ROUTE)
     if err:
-        _nl_handle_destroy(handle)
+        _close_socket(handle)
         raise IOError(-err, _nl_geterror())
     return handle
 
 
 def _close_socket(sock):
     """Closes and frees the resources of the passed netlink socket."""
-    _nl_handle_destroy(sock)
+    if LIBNL3 is None:
+        _nl_handle_destroy(sock)
+    else:
+        _nl_socket_free(sock)
 
 
 def iter_links():
@@ -204,8 +253,11 @@
 
     # libnl-1 has a bug when getting type information.
     # https://github.com/tgraf/libnl-1.1-stable/issues/1
-    # TODO: Add the following line (and prototype) when the above bug is fixed.
-    # info['type'] = _rtnl_link_get_info_type(link)
+    # TODO: Add for libnl1 if the bug is fixed
+    if 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:


-- 
To view, visit http://gerrit.ovirt.org/26514
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I45f043a8416e57d5fb550e2e817e6df38cd793b1
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Antoni Segura Puimedon <asegu...@redhat.com>
_______________________________________________
vdsm-patches mailing list
vdsm-patches@lists.fedorahosted.org
https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches

Reply via email to