diff options
author | David Sommerseth <davids@redhat.com> | 2010-04-28 17:04:26 +0200 |
---|---|---|
committer | David Sommerseth <davids@redhat.com> | 2010-04-28 17:04:26 +0200 |
commit | 4f0295fca2cfd933f4b9b539d5505cb24e4d420c (patch) | |
tree | dd765ba839c30cbf45217983bbc39533c575c695 | |
parent | d3fd6b84f461a4d7ffbf3f3eae37381150b69e82 (diff) | |
download | python-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.c | 141 | ||||
-rw-r--r-- | python-ethtool/etherinfo.h | 20 | ||||
-rw-r--r-- | python-ethtool/etherinfo_obj.c | 66 | ||||
-rw-r--r-- | python-ethtool/etherinfo_obj.h | 14 | ||||
-rw-r--r-- | python-ethtool/etherinfo_struct.h | 29 | ||||
-rw-r--r-- | python-ethtool/ethtool.c | 89 |
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 *)ðtool_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(ðtool_etherinfoType); PyModule_AddObject(m, "etherinfo", (PyObject *)ðtool_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. */ |