summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Sommerseth <davids@redhat.com>2010-04-28 17:04:26 +0200
committerDavid Sommerseth <davids@redhat.com>2010-04-28 17:04:26 +0200
commit4f0295fca2cfd933f4b9b539d5505cb24e4d420c (patch)
treedd765ba839c30cbf45217983bbc39533c575c695
parentd3fd6b84f461a4d7ffbf3f3eae37381150b69e82 (diff)
downloadpython-ethtool-4f0295fca2cfd933f4b9b539d5505cb24e4d420c.tar.gz
python-ethtool-4f0295fca2cfd933f4b9b539d5505cb24e4d420c.tar.xz
python-ethtool-4f0295fca2cfd933f4b9b539d5505cb24e4d420c.zip
Updated to fetch the interface information when the "getter" function triggers
-rw-r--r--python-ethtool/etherinfo.c141
-rw-r--r--python-ethtool/etherinfo.h20
-rw-r--r--python-ethtool/etherinfo_obj.c66
-rw-r--r--python-ethtool/etherinfo_obj.h14
-rw-r--r--python-ethtool/etherinfo_struct.h29
-rw-r--r--python-ethtool/ethtool.c89
6 files changed, 222 insertions, 137 deletions
diff --git a/python-ethtool/etherinfo.c b/python-ethtool/etherinfo.c
index 6075f30..7ae5798 100644
--- a/python-ethtool/etherinfo.c
+++ b/python-ethtool/etherinfo.c
@@ -24,14 +24,9 @@
#include <stdlib.h>
#include <asm/types.h>
#include <sys/socket.h>
-#include <netlink/addr.h>
-#include <netlink/netlink.h>
-#include <netlink/handlers.h>
-#include <netlink/route/link.h>
-#include <netlink/route/addr.h>
-#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
+#include "etherinfo_struct.h"
#include "etherinfo.h"
/*
@@ -39,20 +34,6 @@
* Internal functions for working with struct etherinfo
*
*/
-
-inline struct etherinfo *new_etherinfo_record()
-{
- struct etherinfo *ptr;
-
- ptr = malloc(sizeof(struct etherinfo)+1);
- if( ptr ) {
- memset(ptr, 0, sizeof(struct etherinfo)+1);
- }
-
- return ptr;
-}
-
-
void free_etherinfo(struct etherinfo *ptr)
{
if( ptr == NULL ) { // Just for safety
@@ -82,6 +63,13 @@ void free_etherinfo(struct etherinfo *ptr)
*
*/
+#define SET_STR_VALUE(dst, src) { \
+ if( dst ) { \
+ free(dst); \
+ }; \
+ dst = strdup(src); \
+ }
+
static void callback_nl_link(struct nl_object *obj, void *arg)
{
struct etherinfo *ethi = (struct etherinfo *) arg;
@@ -110,7 +98,7 @@ static void callback_nl_link(struct nl_object *obj, void *arg)
ptr += 3;
}
}
- ethi->hwaddress = strdup(hwaddr);
+ SET_STR_VALUE(ethi->hwaddress, hwaddr);
}
@@ -137,16 +125,16 @@ static void callback_nl_address(struct nl_object *obj, void *arg)
struct nl_addr *brdcst = rtnl_addr_get_broadcast((struct rtnl_addr *)obj);
char brdcst_str[66];
- ethi->ipv4_address = strdup(ip_str);
+ SET_STR_VALUE(ethi->ipv4_address, ip_str);
ethi->ipv4_netmask = rtnl_addr_get_prefixlen((struct rtnl_addr*) obj);
if( brdcst ) {
memset(&brdcst_str, 0, 66);
inet_ntop(family, nl_addr_get_binary_addr(brdcst), (char *)&brdcst_str, 64);
- ethi->ipv4_broadcast = strdup(brdcst_str);
+ SET_STR_VALUE(ethi->ipv4_broadcast, brdcst_str);
}
} else {
- ethi->ipv6_address = strdup(ip_str);
+ SET_STR_VALUE(ethi->ipv6_address, ip_str);
ethi->ipv6_netmask = rtnl_addr_get_prefixlen((struct rtnl_addr*) obj);
}
return;
@@ -186,70 +174,59 @@ void dump_etherinfo(FILE *fp, struct etherinfo *ptr)
fprintf(fp, "\n");
}
-struct etherinfo *get_etherinfo(const char *ifdevname)
+
+int get_etherinfo(struct etherinfo *ethinf, struct _nlconnection *nlc, nlQuery query)
{
- struct etherinfo *ethinf = NULL;
- struct nl_handle *handle;
struct nl_cache *link_cache;
struct nl_cache *addr_cache;
struct rtnl_addr *addr;
struct rtnl_link *link;
- int ifindex;
-
- /* Establish connection to NETLINK */
- handle = nl_handle_alloc();
- nl_connect(handle, NETLINK_ROUTE);
-
- /* Find the interface index we're looking up */
- link_cache = rtnl_link_alloc_cache(handle);
- ifindex = rtnl_link_name2i(link_cache, ifdevname);
- if( ifindex < 0 ) {
- return NULL;
- }
-
- /* Create an empty record, where ethernet information will be saved */
- ethinf = new_etherinfo_record();
- if( !ethinf ) {
- return NULL;
- }
- ethinf->index = ifindex;
- ethinf->device = strdup(ifdevname); /* Should extract via libnl - nl_link callback? */
-
- /* Extract MAC/hardware address of the interface */
- link = rtnl_link_alloc();
- rtnl_link_set_ifindex(link, ifindex);
- nl_cache_foreach_filter(link_cache, (struct nl_object *)link, callback_nl_link, ethinf);
- rtnl_link_put(link);
- nl_cache_free(link_cache);
-
- /* Extract IP address information */
- addr_cache = rtnl_addr_alloc_cache(handle);
- addr = rtnl_addr_alloc();
- rtnl_addr_set_ifindex(addr, ifindex);
- nl_cache_foreach_filter(addr_cache, (struct nl_object *)addr, callback_nl_address, ethinf);
- rtnl_addr_put(addr);
- nl_cache_free(addr_cache);
-
- /* Close NETLINK connection */
- nl_close(handle);
- nl_handle_destroy(handle);
-
- return ethinf;
-}
+ int ret = 0;
-#ifdef TESTPROG
-// Simple standalone test program
-int main(int argc, char **argv) {
- struct etherinfo *inf = NULL;
-
- inf = get_etherinfo(argv[1]);
- if( inf == NULL ) {
- fprintf(stderr, "Operation failed. Could not retrieve ethernet information\n");
- exit(2);
+ if( !ethinf || !nlc ) {
+ return 0;
}
- dump_etherinfo(stdout, inf);
- free_etherinfo(inf);
- return 0;
+ /* Find the interface index we're looking up.
+ * As we don't expect it to change, we're reusing a "cached"
+ * interface index if we have that
+ */
+ if( ethinf->index < 0 ) {
+ link_cache = rtnl_link_alloc_cache(nlc->nlrt_handle);
+ ethinf->index = rtnl_link_name2i(link_cache, ethinf->device);
+ if( ethinf->index < 0 ) {
+ return 0;
+ }
+ nl_cache_free(link_cache);
+ }
+
+ /* Query the for requested info vai NETLINK */
+ switch( query ) {
+ case NLQRY_LINK:
+ /* Extract MAC/hardware address of the interface */
+ link_cache = rtnl_link_alloc_cache(nlc->nlrt_handle);
+ 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);
+ rtnl_link_put(link);
+ nl_cache_free(link_cache);
+ ret = 1;
+ break;
+
+ case NLQRY_ADDR:
+ /* Extract IP address information */
+ addr_cache = rtnl_addr_alloc_cache(nlc->nlrt_handle);
+ addr = rtnl_addr_alloc();
+ rtnl_addr_set_ifindex(addr, ethinf->index);
+ nl_cache_foreach_filter(addr_cache, (struct nl_object *)addr, callback_nl_address, ethinf);
+ rtnl_addr_put(addr);
+ nl_cache_free(addr_cache);
+ ret = 1;
+ break;
+
+ default:
+ ret = 0;
+ }
+ return ret;
}
-#endif
+
diff --git a/python-ethtool/etherinfo.h b/python-ethtool/etherinfo.h
index bda5185..1b8c425 100644
--- a/python-ethtool/etherinfo.h
+++ b/python-ethtool/etherinfo.h
@@ -17,18 +17,16 @@
#ifndef _ETHERINFO_H
#define _ETHERINFO_H
-struct etherinfo {
- int index;
- char *device;
- char *hwaddress;
- char *ipv4_address;
- int ipv4_netmask;
- char *ipv4_broadcast;
- char *ipv6_address;
- int ipv6_netmask;
-};
+#include <netlink/addr.h>
+#include <netlink/netlink.h>
+#include <netlink/handlers.h>
+#include <netlink/route/link.h>
+#include <netlink/route/addr.h>
+#include <arpa/inet.h>
-struct etherinfo *get_etherinfo();
+typedef enum {NLQRY_LINK, NLQRY_ADDR} nlQuery;
+
+int get_etherinfo(struct etherinfo *ethinf, struct _nlconnection *nlc, nlQuery query);
void free_etherinfo(struct etherinfo *ptr);
void dump_etherinfo(FILE *, struct etherinfo *);
diff --git a/python-ethtool/etherinfo_obj.c b/python-ethtool/etherinfo_obj.c
index ebdda80..a20ed6b 100644
--- a/python-ethtool/etherinfo_obj.c
+++ b/python-ethtool/etherinfo_obj.c
@@ -9,8 +9,9 @@
#include <Python.h>
#include "structmember.h"
-#include "etherinfo.h"
+
#include "etherinfo_struct.h"
+#include "etherinfo.h"
/**
@@ -20,8 +21,11 @@
*/
void _ethtool_etherinfo_dealloc(etherinfo_py *self)
{
- if( self->info ) {
- free_etherinfo(self->info);
+ if( self->data ) {
+ if( self->data->ethinfo ) {
+ free_etherinfo(self->data->ethinfo);
+ }
+ free(self->data);
}
self->ob_type->tp_free((PyObject*)self);
}
@@ -63,7 +67,7 @@ int _ethtool_etherinfo_init(etherinfo_py *self, PyObject *args, PyObject *kwds)
PyErr_SetString(PyExc_AttributeError, "Invalid data pointer to constructor");
return -1;
}
- self->info = (struct etherinfo *) PyCObject_AsVoidPtr(ethinf_ptr);
+ self->data = (struct etherinfo_obj_data *) PyCObject_AsVoidPtr(ethinf_ptr);
return 0;
}
@@ -86,29 +90,38 @@ int _ethtool_etherinfo_init(etherinfo_py *self, PyObject *args, PyObject *kwds)
*/
PyObject *_ethtool_etherinfo_getter(etherinfo_py *self, PyObject *attr_o)
{
+ PyObject *ret;
char *attr = PyString_AsString(attr_o);
- if( !self || !self->info ) {
+ if( !self || !self->data ) {
PyErr_SetString(PyExc_AttributeError, "No data available");
return NULL;
}
if( strcmp(attr, "device") == 0 ) {
- return RETURN_STRING(self->info->device);
+ ret = RETURN_STRING(self->data->ethinfo->device);
} else if( strcmp(attr, "mac_address") == 0 ) {
- return RETURN_STRING(self->info->hwaddress);
+ get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_LINK);
+ ret = RETURN_STRING(self->data->ethinfo->hwaddress);
} else if( strcmp(attr, "ipv4_address") == 0 ) {
- return RETURN_STRING(self->info->ipv4_address);
+ get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_LINK);
+ ret = RETURN_STRING(self->data->ethinfo->ipv4_address);
} else if( strcmp(attr, "ipv4_netmask") == 0 ) {
- return PyInt_FromLong(self->info->ipv4_netmask);
+ get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
+ ret = PyInt_FromLong(self->data->ethinfo->ipv4_netmask);
} else if( strcmp(attr, "ipv4_broadcast") == 0 ) {
- return RETURN_STRING(self->info->ipv4_broadcast);
+ get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
+ ret = RETURN_STRING(self->data->ethinfo->ipv4_broadcast);
} else if( strcmp(attr, "ipv6_address") == 0 ) {
- return RETURN_STRING(self->info->ipv6_address);
+ get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
+ ret = RETURN_STRING(self->data->ethinfo->ipv6_address);
} else if( strcmp(attr, "ipv6_netmask") == 0 ) {
- return PyInt_FromLong(self->info->ipv6_netmask);
+ get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
+ ret = PyInt_FromLong(self->data->ethinfo->ipv6_netmask);
+ } else {
+ ret = PyObject_GenericGetAttr((PyObject *)self, attr_o);
}
- return PyObject_GenericGetAttr((PyObject *)self, attr_o);
+ return ret;
}
@@ -140,34 +153,37 @@ PyObject *_ethtool_etherinfo_str(etherinfo_py *self)
{
PyObject *ret = NULL;
- if( !self || !self->info ) {
+ if( !self || !self->data || !self->data->nlc || !self->data->ethinfo ) {
PyErr_SetString(PyExc_AttributeError, "No data available");
return NULL;
}
- ret = PyString_FromFormat("Device %s:\n", self->info->device);
- if( self->info->hwaddress ) {
- PyObject *tmp = PyString_FromFormat("\tMAC address: %s\n", self->info->hwaddress);
+ get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_LINK);
+ get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
+
+ ret = PyString_FromFormat("Device %s:\n", self->data->ethinfo->device);
+ if( self->data->ethinfo->hwaddress ) {
+ PyObject *tmp = PyString_FromFormat("\tMAC address: %s\n", self->data->ethinfo->hwaddress);
PyString_Concat(&ret, tmp);
}
- if( self->info->ipv4_address ) {
+ if( self->data->ethinfo->ipv4_address ) {
PyObject *tmp = PyString_FromFormat("\tIPv4 address: %s/%i",
- self->info->ipv4_address,
- self->info->ipv4_netmask);
- if( self->info->ipv4_broadcast ) {
+ self->data->ethinfo->ipv4_address,
+ self->data->ethinfo->ipv4_netmask);
+ if( self->data->ethinfo->ipv4_broadcast ) {
PyObject *tmp2 = PyString_FromFormat(" Broadcast: %s",
- self->info->ipv4_broadcast);
+ self->data->ethinfo->ipv4_broadcast);
PyString_Concat(&tmp, tmp2);
}
PyString_Concat(&tmp, PyString_FromString("\n"));
PyString_Concat(&ret, tmp);
}
- if( self->info->ipv6_address ) {
+ if( self->data->ethinfo->ipv6_address ) {
PyObject *tmp = PyString_FromFormat("\tIPv6 address: %s/%i\n",
- self->info->ipv6_address,
- self->info->ipv6_netmask);
+ self->data->ethinfo->ipv6_address,
+ self->data->ethinfo->ipv6_netmask);
PyString_Concat(&ret, tmp);
}
return ret;
diff --git a/python-ethtool/etherinfo_obj.h b/python-ethtool/etherinfo_obj.h
index 8ffdf7d..340dea8 100644
--- a/python-ethtool/etherinfo_obj.h
+++ b/python-ethtool/etherinfo_obj.h
@@ -36,19 +36,19 @@ static PyMethodDef _ethtool_etherinfo_methods[] = {
*
*/
static PyMemberDef _ethtool_etherinfo_members[] = {
- {"device", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
+ {"device", T_OBJECT_EX, offsetof(etherinfo_py, data), 0,
"Device name of the interface"},
- {"mac_address", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
+ {"mac_address", T_OBJECT_EX, offsetof(etherinfo_py, data), 0,
"MAC address / hardware address of the interface"},
- {"ipv4_address", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
+ {"ipv4_address", T_OBJECT_EX, offsetof(etherinfo_py, data), 0,
"IPv4 address"},
- {"ipv4_netmask", T_INT, offsetof(etherinfo_py, info), 0,
+ {"ipv4_netmask", T_INT, offsetof(etherinfo_py, data), 0,
"IPv4 netmask in bits"},
- {"ipv4_broadcast", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
+ {"ipv4_broadcast", T_OBJECT_EX, offsetof(etherinfo_py, data), 0,
"IPv4 broadcast address"},
- {"ipv6_address", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
+ {"ipv6_address", T_OBJECT_EX, offsetof(etherinfo_py, data), 0,
"IPv6 address"},
- {"ipv6_netmask", T_INT, offsetof(etherinfo_py, info), 0,
+ {"ipv6_netmask", T_INT, offsetof(etherinfo_py, data), 0,
"IPv6 netmask in bits"},
{NULL} /* End of member list */
};
diff --git a/python-ethtool/etherinfo_struct.h b/python-ethtool/etherinfo_struct.h
index 641dcb4..b09b49c 100644
--- a/python-ethtool/etherinfo_struct.h
+++ b/python-ethtool/etherinfo_struct.h
@@ -10,14 +10,39 @@
#ifndef _ETHERINFO_STRUCT_H
#define _ETHERINFO_STRUCT_H
+
+struct etherinfo {
+ char *device;
+ int index;
+ char *hwaddress;
+ char *ipv4_address;
+ int ipv4_netmask;
+ char *ipv4_broadcast;
+ char *ipv6_address;
+ int ipv6_netmask;
+};
+
+/*
+ * NETLINK connection handle and related information to be shared
+ * among all the instantiated etherinfo objects.
+ */
+struct _nlconnection {
+ struct nl_handle *nlrt_handle;
+};
+
/**
* Contains the internal data structure of the
* ethtool.etherinfo object.
*
*/
+struct etherinfo_obj_data {
+ struct _nlconnection *nlc; /**< Contains NETLINK connection info */
+ struct etherinfo *ethinfo; /**< Contains info about our current interface */
+};
+
typedef struct {
- PyObject_HEAD
- struct etherinfo *info; /**< Contains information about one ethernet device */
+ PyObject_HEAD
+ struct etherinfo_obj_data *data;
} etherinfo_py;
#endif
diff --git a/python-ethtool/ethtool.c b/python-ethtool/ethtool.c
index d84bc79..04d37ca 100644
--- a/python-ethtool/ethtool.c
+++ b/python-ethtool/ethtool.c
@@ -26,8 +26,11 @@
#include <sys/ioctl.h>
#include <sys/types.h>
-#include "etherinfo.h"
+#include "etherinfo_struct.h"
#include "etherinfo_obj.h"
+#include "etherinfo.h"
+
+static struct _nlconnection nlconnection;
#ifndef IFF_DYNAMIC
#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses*/
@@ -233,7 +236,6 @@ static PyObject *get_ipaddress(PyObject *self __unused, PyObject *args)
static PyObject *get_interface_info(PyObject *self __unused, PyObject *args) {
PyObject *devlist = NULL, *ethinf_py = NULL;
PyObject *inargs = NULL;
- struct etherinfo *devinfo = NULL;
char **fetch_devs;
int i = 0, fetch_devs_len = 0;
@@ -280,16 +282,32 @@ static PyObject *get_interface_info(PyObject *self __unused, PyObject *args) {
}
}
-
+ devlist = PyList_New(0);
for( i = 0; i < fetch_devs_len; i++ ) {
- devinfo = get_etherinfo(fetch_devs[i]);
- if( !devinfo ) {
+ struct etherinfo_obj_data *objdata = NULL;
+
+ /* Allocate memory for data structures for each device */
+ objdata = calloc(1, sizeof(struct etherinfo_obj_data));
+ if( !objdata ) {
PyErr_SetString(PyExc_OSError, strerror(errno));
return NULL;
}
+ objdata->ethinfo = calloc(1, sizeof(struct etherinfo));
+ if( !objdata->ethinfo ) {
+ PyErr_SetString(PyExc_OSError, strerror(errno));
+ return NULL;
+ }
+
+ /* Store the device name and a reference to the NETLINK connection for
+ * objects to use when quering for device info
+ */
+ objdata->ethinfo->device = strdup(fetch_devs[i]);
+ objdata->ethinfo->index = -1;
+ objdata->nlc = &nlconnection; /* Global variable */
+
/* Instantiate a new etherinfo object with the device information */
- ethinf_py = PyCObject_FromVoidPtr(devinfo, NULL);
+ ethinf_py = PyCObject_FromVoidPtr(objdata, NULL);
if( ethinf_py ) {
/* Prepare the argument list for the object constructor */
PyObject *args = PyTuple_New(1);
@@ -297,10 +315,9 @@ static PyObject *get_interface_info(PyObject *self __unused, PyObject *args) {
/* Create the object */
PyObject *dev = PyObject_CallObject((PyObject *)&ethtool_etherinfoType, args);
- PyList_Append(devlist, dev);
- }
- if( devinfo != NULL ) {
- free_etherinfo(devinfo);
+ if( dev ) {
+ PyList_Append(devlist, dev);
+ }
}
}
if( fetch_devs_len > 0 ) {
@@ -948,6 +965,52 @@ static struct PyMethodDef PyEthModuleMethods[] = {
};
+/**
+ * Connects to the NETLINK interface and stores the connection handles in the given struct. This
+ * should be called as part of the main ethtool module init.
+ *
+ * @param nlc Structure which keeps the NETLINK connection handle
+ *
+ * @return Returns 1 on success, otherwise 0.
+ */
+int open_netlink(struct _nlconnection *nlc)
+{
+ if( !nlc ) {
+ return 0;
+ }
+
+ nlc->nlrt_handle = nl_handle_alloc();
+ nl_connect(nlc->nlrt_handle, NETLINK_ROUTE);
+ return (nlc->nlrt_handle != NULL);
+}
+
+
+/**
+ * Closes the NETLINK connection. This should be called automatically whenever
+ * the ethtool module is unloaded from Python.
+ *
+ * @param ptr Points at a struct _nlconnection object with an open NETLINK connection
+ */
+void close_netlink(void *ptr)
+{
+ struct _nlconnection *nlc;
+
+ if( !ptr ) {
+ return;
+ }
+
+ nlc = (struct _nlconnection *) ptr;
+ if( !nlc->nlrt_handle ) {
+ return;
+ }
+
+ /* Close NETLINK connection */
+ nl_close(nlc->nlrt_handle);
+ nl_handle_destroy(nlc->nlrt_handle);
+ nlc->nlrt_handle = NULL;
+}
+
+
PyMODINIT_FUNC initethtool(void)
{
PyObject *m;
@@ -959,6 +1022,12 @@ PyMODINIT_FUNC initethtool(void)
Py_INCREF(&ethtool_etherinfoType);
PyModule_AddObject(m, "etherinfo", (PyObject *)&ethtool_etherinfoType);
+ // 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. */