summaryrefslogtreecommitdiffstats
path: root/python-ethtool/etherinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'python-ethtool/etherinfo.c')
-rw-r--r--python-ethtool/etherinfo.c97
1 files changed, 91 insertions, 6 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;
+}