-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <[email protected]>
- Loading branch information
David Sommerseth
committed
Apr 11, 2011
1 parent
abc7f91
commit 508ffff
Showing
6 changed files
with
118 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <[email protected]> | ||
* 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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <[email protected]> | ||
* | ||
|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
/* | ||
* Copyright (C) 2009-2010 Red Hat Inc. | ||
* Copyright (C) 2009-2011 Red Hat Inc. | ||
* | ||
* David Sommerseth <[email protected]> | ||
* | ||
|
@@ -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 ) { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
/* | ||
* Copyright (C) 2009-2010 Red Hat Inc. | ||
* Copyright (C) 2009-2011 Red Hat Inc. | ||
* | ||
* David Sommerseth <[email protected]> | ||
* | ||
|
@@ -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 */ | ||
}; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
/* | ||
* Copyright (C) 2008-2010 Red Hat Inc. | ||
* Copyright (C) 2008-2011 Red Hat Inc. | ||
* | ||
* Arnaldo Carvalho de Melo <[email protected]> | ||
* David Sommerseth <[email protected]> | ||
|
@@ -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(ðtool_etherinfoIPv6Type); | ||
PyModule_AddObject(m, "etherinfo_ipv6addr", (PyObject *)ðtool_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. */ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters