summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Sommerseth <davids@redhat.com>2011-04-11 16:36:56 +0200
committerDavid Sommerseth <davids@redhat.com>2011-04-11 16:36:56 +0200
commit508ffffbb3c48eeeb11eeab2bf971180fe4e1940 (patch)
tree2b8133c62a904fd400f0cef0a3e2abb12048149a
parentabc7f912f66d41dd734a10900429d4cad9377da5 (diff)
downloadpython-ethtool-508ffffbb3c48eeeb11eeab2bf971180fe4e1940.tar.gz
python-ethtool-508ffffbb3c48eeeb11eeab2bf971180fe4e1940.tar.xz
python-ethtool-508ffffbb3c48eeeb11eeab2bf971180fe4e1940.zip
Only open the NETLINK interface when needed
Do not open a NETLINK connection when loading the module, but rahter open it when needed. In a case where multiple users needs the connection, it will be shared and only closed when the last active user is done. Signed-off-by: David Sommerseth <davids@redhat.com>
-rw-r--r--python-ethtool/etherinfo.c97
-rw-r--r--python-ethtool/etherinfo.h7
-rw-r--r--python-ethtool/etherinfo_obj.c19
-rw-r--r--python-ethtool/etherinfo_struct.h6
-rw-r--r--python-ethtool/ethtool.c58
-rw-r--r--setup.py6
6 files changed, 118 insertions, 75 deletions
diff --git a/python-ethtool/etherinfo.c b/python-ethtool/etherinfo.c
index 5539cf7..42973ad 100644
--- a/python-ethtool/etherinfo.c
+++ b/python-ethtool/etherinfo.c
@@ -1,6 +1,6 @@
/* etherinfo.c - Retrieve ethernet interface info via NETLINK
*
- * Copyright (C) 2009-2010 Red Hat Inc.
+ * Copyright (C) 2009-2011 Red Hat Inc.
*
* David Sommerseth <davids@redhat.com>
* Parts of this code is based on ideas and solutions in iproute2
@@ -27,9 +27,12 @@
#include <netlink/route/rtnl.h>
#include <assert.h>
#include <errno.h>
+#include <pthread.h>
#include "etherinfo_struct.h"
#include "etherinfo.h"
+pthread_mutex_t nlc_counter_mtx = PTHREAD_MUTEX_INITIALIZER;
+
/*
*
* Internal functions for working with struct etherinfo
@@ -274,15 +277,25 @@ void dump_etherinfo(FILE *fp, struct etherinfo *ptr)
*
* @return Returns 1 on success, otherwise 0.
*/
-int get_etherinfo(struct etherinfo *ethinf, struct nl_handle *nlc, nlQuery query)
+int get_etherinfo(struct etherinfo_obj_data *data, nlQuery query)
{
struct nl_cache *link_cache;
struct nl_cache *addr_cache;
struct rtnl_addr *addr;
struct rtnl_link *link;
+ struct etherinfo *ethinf = NULL;
int ret = 0;
- if( !ethinf || !nlc ) {
+ if( !data || !data->ethinfo ) {
+ return 0;
+ }
+ ethinf = data->ethinfo;
+
+ /* Open a NETLINK connection on-the-fly */
+ if( !open_netlink(data) ) {
+ PyErr_Format(PyExc_RuntimeError,
+ "Could not open a NETLINK connection for %s",
+ ethinf->device);
return 0;
}
@@ -291,7 +304,7 @@ int get_etherinfo(struct etherinfo *ethinf, struct nl_handle *nlc, nlQuery query
* interface index if we have that
*/
if( ethinf->index < 0 ) {
- link_cache = rtnl_link_alloc_cache(nlc);
+ link_cache = rtnl_link_alloc_cache(*data->nlc);
ethinf->index = rtnl_link_name2i(link_cache, ethinf->device);
if( ethinf->index < 0 ) {
return 0;
@@ -303,7 +316,7 @@ int get_etherinfo(struct etherinfo *ethinf, struct nl_handle *nlc, nlQuery query
switch( query ) {
case NLQRY_LINK:
/* Extract MAC/hardware address of the interface */
- link_cache = rtnl_link_alloc_cache(nlc);
+ link_cache = rtnl_link_alloc_cache(*data->nlc);
link = rtnl_link_alloc();
rtnl_link_set_ifindex(link, ethinf->index);
nl_cache_foreach_filter(link_cache, (struct nl_object *)link, callback_nl_link, ethinf);
@@ -314,7 +327,7 @@ int get_etherinfo(struct etherinfo *ethinf, struct nl_handle *nlc, nlQuery query
case NLQRY_ADDR:
/* Extract IP address information */
- addr_cache = rtnl_addr_alloc_cache(nlc);
+ addr_cache = rtnl_addr_alloc_cache(*data->nlc);
addr = rtnl_addr_alloc();
rtnl_addr_set_ifindex(addr, ethinf->index);
@@ -337,3 +350,75 @@ int get_etherinfo(struct etherinfo *ethinf, struct nl_handle *nlc, nlQuery query
return ret;
}
+
+/**
+ * Connects to the NETLINK interface. This will be called
+ * for each etherinfo object being generated, and it will
+ * keep a separate file descriptor open for each object
+ *
+ * @param data etherinfo_obj_data structure
+ *
+ * @return Returns 1 on success, otherwise 0.
+ */
+int open_netlink(struct etherinfo_obj_data *data)
+{
+ if( !data ) {
+ return 0;
+ }
+
+ /* Reuse already established NETLINK connection, if a connection exists */
+ if( *data->nlc ) {
+ /* If this object has not used NETLINK earlier, tag it as a user */
+ if( !data->nlc_active ) {
+ pthread_mutex_lock(&nlc_counter_mtx);
+ (*data->nlc_users)++;
+ pthread_mutex_unlock(&nlc_counter_mtx);
+ }
+ data->nlc_active = 1;
+ return 1;
+ }
+
+ /* No earlier connections exists, establish a new one */
+ *data->nlc = nl_handle_alloc();
+ nl_connect(*data->nlc, NETLINK_ROUTE);
+ if( (*data->nlc != NULL) ) {
+ /* Tag this object as an active user */
+ pthread_mutex_lock(&nlc_counter_mtx);
+ (*data->nlc_users)++;
+ pthread_mutex_unlock(&nlc_counter_mtx);
+ data->nlc_active = 1;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+/**
+ * Closes the NETLINK connection. This should be called automatically whenever
+ * the corresponding etherinfo object is deleted.
+ *
+ * @param ptr Pointer to the pointer of struct nl_handle, which contains the NETLINK connection
+ */
+void close_netlink(struct etherinfo_obj_data *data)
+{
+ if( !data || !(*data->nlc) ) {
+ return;
+ }
+
+ /* Untag this object as a NETLINK user */
+ data->nlc_active = 0;
+ pthread_mutex_lock(&nlc_counter_mtx);
+ (*data->nlc_users)--;
+ pthread_mutex_unlock(&nlc_counter_mtx);
+
+ /* Don't close the connection if there are more users */
+ if( *data->nlc_users > 0) {
+ return;
+ }
+
+ /* Close NETLINK connection */
+ nl_close(*data->nlc);
+ nl_handle_destroy(*data->nlc);
+ *data->nlc = NULL;
+}
diff --git a/python-ethtool/etherinfo.h b/python-ethtool/etherinfo.h
index db368db..5e1056a 100644
--- a/python-ethtool/etherinfo.h
+++ b/python-ethtool/etherinfo.h
@@ -1,6 +1,6 @@
/* etherinfo.h - Retrieve ethernet interface info via NETLINK
*
- * Copyright (C) 2009-2010 Red Hat Inc.
+ * Copyright (C) 2009-2011 Red Hat Inc.
*
* David Sommerseth <davids@redhat.com>
*
@@ -26,10 +26,13 @@
typedef enum {NLQRY_LINK, NLQRY_ADDR} nlQuery; /**< Supported query types in the etherinfo code */
-int get_etherinfo(struct etherinfo *ethinf, struct nl_handle *nlc, nlQuery query);
+int get_etherinfo(struct etherinfo_obj_data *data, nlQuery query);
void free_etherinfo(struct etherinfo *ptr);
void dump_etherinfo(FILE *, struct etherinfo *);
void free_ipv6addresses(struct ipv6address *ptr);
+int open_netlink(struct etherinfo_obj_data *);
+void close_netlink(struct etherinfo_obj_data *);
+
#endif
diff --git a/python-ethtool/etherinfo_obj.c b/python-ethtool/etherinfo_obj.c
index e1e03fe..cf90601 100644
--- a/python-ethtool/etherinfo_obj.c
+++ b/python-ethtool/etherinfo_obj.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2010 Red Hat Inc.
+ * Copyright (C) 2009-2011 Red Hat Inc.
*
* David Sommerseth <davids@redhat.com>
*
@@ -40,6 +40,8 @@ extern PyTypeObject ethtool_etherinfoIPv6Type;
void _ethtool_etherinfo_dealloc(etherinfo_py *self)
{
if( self->data ) {
+ close_netlink(self->data);
+
if( self->data->ethinfo ) {
free_etherinfo(self->data->ethinfo);
}
@@ -110,20 +112,21 @@ PyObject *_ethtool_etherinfo_getter(etherinfo_py *self, PyObject *attr_o)
if( strcmp(attr, "device") == 0 ) {
ret = RETURN_STRING(self->data->ethinfo->device);
} else if( strcmp(attr, "mac_address") == 0 ) {
- get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_LINK);
+ get_etherinfo(self->data, NLQRY_LINK);
ret = RETURN_STRING(self->data->ethinfo->hwaddress);
} else if( strcmp(attr, "ipv4_address") == 0 ) {
- get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
+ get_etherinfo(self->data, NLQRY_ADDR);
ret = RETURN_STRING(self->data->ethinfo->ipv4_address);
} else if( strcmp(attr, "ipv4_netmask") == 0 ) {
- get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
+ get_etherinfo(self->data, NLQRY_ADDR);
ret = PyInt_FromLong(self->data->ethinfo->ipv4_netmask);
} else if( strcmp(attr, "ipv4_broadcast") == 0 ) {
- get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
+ get_etherinfo(self->data, NLQRY_ADDR);
ret = RETURN_STRING(self->data->ethinfo->ipv4_broadcast);
} else {
ret = PyObject_GenericGetAttr((PyObject *)self, attr_o);
}
+
return ret;
}
@@ -160,8 +163,8 @@ PyObject *_ethtool_etherinfo_str(etherinfo_py *self)
return NULL;
}
- get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_LINK);
- get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
+ get_etherinfo(self->data, NLQRY_LINK);
+ get_etherinfo(self->data, NLQRY_ADDR);
ret = PyString_FromFormat("Device %s:\n", self->data->ethinfo->device);
if( self->data->ethinfo->hwaddress ) {
@@ -223,7 +226,7 @@ PyObject * _ethtool_etherinfo_get_ipv6_addresses(etherinfo_py *self, PyObject *n
return NULL;
}
- get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
+ get_etherinfo(self->data, NLQRY_ADDR);
ipv6 = self->data->ethinfo->ipv6_addresses;
ret = PyTuple_New(1);
if( !ret ) {
diff --git a/python-ethtool/etherinfo_struct.h b/python-ethtool/etherinfo_struct.h
index 3ae037f..f294637 100644
--- a/python-ethtool/etherinfo_struct.h
+++ b/python-ethtool/etherinfo_struct.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2010 Red Hat Inc.
+ * Copyright (C) 2009-2011 Red Hat Inc.
*
* David Sommerseth <davids@redhat.com>
*
@@ -58,7 +58,9 @@ struct ipv6address {
*
*/
struct etherinfo_obj_data {
- struct nl_handle *nlc; /**< Contains NETLINK connection info */
+ struct nl_handle **nlc; /**< Contains NETLINK connection info (global) */
+ unsigned int *nlc_users; /**< Resource counter for the NETLINK connection (global) */
+ unsigned short nlc_active; /**< Is this instance using NETLINK? */
struct etherinfo *ethinfo; /**< Contains info about our current interface */
};
diff --git a/python-ethtool/ethtool.c b/python-ethtool/ethtool.c
index 60e407c..b3fc65b 100644
--- a/python-ethtool/ethtool.c
+++ b/python-ethtool/ethtool.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2010 Red Hat Inc.
+ * Copyright (C) 2008-2011 Red Hat Inc.
*
* Arnaldo Carvalho de Melo <acme@redhat.com>
* David Sommerseth <davids@redhat.com>
@@ -32,6 +32,7 @@
#include "etherinfo.h"
static struct nl_handle *nlconnection = NULL;
+unsigned int nlconnection_users = 0; /* How many NETLINK users are active? */
extern PyTypeObject ethtool_etherinfoType;
extern PyTypeObject ethtool_etherinfoIPv6Type;
@@ -314,7 +315,8 @@ static PyObject *get_interfaces_info(PyObject *self __unused, PyObject *args) {
*/
objdata->ethinfo->device = strdup(fetch_devs[i]);
objdata->ethinfo->index = -1;
- objdata->nlc = nlconnection; /* Global variable */
+ objdata->nlc = &nlconnection;
+ objdata->nlc_users = &nlconnection_users;
/* Instantiate a new etherinfo object with the device information */
ethinf_py = PyCObject_FromVoidPtr(objdata, NULL);
@@ -979,52 +981,6 @@ static struct PyMethodDef PyEthModuleMethods[] = {
};
-/**
- * Connects to the NETLINK interface. This should only be
- * called once as part of the main ethtool module init.
- *
- * @param nlc Structure which keeps the NETLINK connection handle (struct nl_handle)
- *
- * @return Returns 1 on success, otherwise 0.
- */
-int open_netlink(struct nl_handle **nlc)
-{
- if( *nlc ) {
- return 0;
- }
-
- *nlc = nl_handle_alloc();
- nl_connect(*nlc, NETLINK_ROUTE);
- return (*nlc != NULL);
-}
-
-
-/**
- * Closes the NETLINK connection. This should be called automatically whenever
- * the ethtool module is unloaded from Python.
- *
- * @param ptr Pointer to the pointer of struct nl_handle, which contains the NETLINK connection
- */
-void close_netlink(void **ptr)
-{
- struct nl_handle *nlc;
-
- if( !ptr && !*ptr ) {
- return;
- }
-
- nlc = (struct nl_handle *) *ptr;
- if( !nlc ) {
- return;
- }
-
- /* Close NETLINK connection */
- nl_close(nlc);
- nl_handle_destroy(nlc);
- *ptr = NULL; /* reset the pointers pointer address */
-}
-
-
PyMODINIT_FUNC initethtool(void)
{
PyObject *m;
@@ -1042,12 +998,6 @@ PyMODINIT_FUNC initethtool(void)
Py_INCREF(&ethtool_etherinfoIPv6Type);
PyModule_AddObject(m, "etherinfo_ipv6addr", (PyObject *)&ethtool_etherinfoIPv6Type);
- // Prepare an internal netlink connection object
- if( open_netlink(&nlconnection) ) {
- PyModule_AddObject(m, "__nlconnection",
- PyCObject_FromVoidPtr(&nlconnection, close_netlink));
- }
-
// Setup constants
PyModule_AddIntConstant(m, "IFF_UP", IFF_UP); /* Interface is up. */
PyModule_AddIntConstant(m, "IFF_BROADCAST", IFF_BROADCAST); /* Broadcast address valid. */
diff --git a/setup.py b/setup.py
index bde04dc..b8cbe9f 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@ from distutils.core import setup, Extension
import commands
import sys
-version = '0.6'
+version = '0.7'
ethtool = Extension('ethtool',
sources = ['python-ethtool/ethtool.c',
@@ -53,8 +53,8 @@ libnl = pkgconfig('libnl-1')
setup(name='ethtool',
version=version,
description='Python module to interface with ethtool',
- author='Harald Hoyer & Arnaldo Carvalho de Melo',
- author_email='acme@redhat.com',
+ author='Harald Hoyer, Arnaldo Carvalho de Melo, David Sommerseth',
+ author_email='davids@redhat.com',
url='http://fedoraproject.org/wiki/python-ethtool',
ext_modules=[
Extension(