diff options
author | David Sommerseth <davids@redhat.com> | 2010-04-26 20:38:57 +0200 |
---|---|---|
committer | David Sommerseth <davids@redhat.com> | 2010-04-26 20:38:57 +0200 |
commit | d3fd6b84f461a4d7ffbf3f3eae37381150b69e82 (patch) | |
tree | 4de791e5b791b50fe42056443b6dbfae2c3a29f1 | |
parent | bfdcac6b16806416a6c0295fcfad5d820595d88c (diff) | |
download | python-ethtool-d3fd6b84f461a4d7ffbf3f3eae37381150b69e82.tar.gz python-ethtool-d3fd6b84f461a4d7ffbf3f3eae37381150b69e82.tar.xz python-ethtool-d3fd6b84f461a4d7ffbf3f3eae37381150b69e82.zip |
Rewritten ethtool to make use of libnl instead of accessing NETLINK directly
-rw-r--r-- | python-ethtool/etherinfo.c | 510 | ||||
-rw-r--r-- | python-ethtool/etherinfo.h | 4 | ||||
-rw-r--r-- | python-ethtool/ethtool.c | 52 | ||||
-rw-r--r-- | setup.py | 54 |
4 files changed, 186 insertions, 434 deletions
diff --git a/python-ethtool/etherinfo.c b/python-ethtool/etherinfo.c index f06b448..6075f30 100644 --- a/python-ethtool/etherinfo.c +++ b/python-ethtool/etherinfo.c @@ -24,23 +24,16 @@ #include <stdlib.h> #include <asm/types.h> #include <sys/socket.h> -#include <linux/netlink.h> -#include <linux/rtnetlink.h> -#include <linux/if_arp.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.h" -#define GET_LINK 1 -#define GET_IPV4 2 -#define GET_IPV6 4 - -struct nl_request { - struct nlmsghdr nlmsg_info; - struct ifaddrmsg ifaddrmsg_info; -}; - /* * * Internal functions for working with struct etherinfo @@ -60,54 +53,17 @@ inline struct etherinfo *new_etherinfo_record() } -#define SET_STRVALUE(ptr, val) if ( (ptr == NULL) && (val != NULL) ) ptr = val; - -int update_etherinfo(struct etherinfo *ipadrchain, int index, int af_type, - char *ipadr, int ipmask, char *ipv4brd) -{ - struct etherinfo *ptr = NULL; - - // Look up the record we will update - for( ptr = ipadrchain; ptr != NULL; ptr = ptr->next) { - if( ptr->index == index ) { - break; - } - } - if( ptr == NULL ) { - PyErr_SetString(PyExc_RuntimeError, - "Could not locate interface record"); - return 0; - } - - switch( af_type ) { - case AF_INET: - SET_STRVALUE(ptr->ipv4_address, ipadr); - ptr->ipv4_netmask = ipmask; - SET_STRVALUE(ptr->ipv4_broadcast, ipv4brd); - break; - case AF_INET6: - SET_STRVALUE(ptr->ipv6_address, ipadr); - ptr->ipv6_netmask = ipmask; - break; - } - return 1; -} - - void free_etherinfo(struct etherinfo *ptr) { if( ptr == NULL ) { // Just for safety return; } - if( ptr->next != NULL ) { - free_etherinfo(ptr->next); - } free(ptr->device); - if( ptr->hwaddress ) { - free(ptr->hwaddress); - } + if( ptr->hwaddress ) { + free(ptr->hwaddress); + } if( ptr->ipv4_address ) { free(ptr->ipv4_address); } @@ -122,401 +78,171 @@ void free_etherinfo(struct etherinfo *ptr) /* - * - * NETLINK specific functions + * libnl callback functions * */ -int open_netlink_socket(struct sockaddr_nl *local) +static void callback_nl_link(struct nl_object *obj, void *arg) { - int fd; - - assert( local != NULL && local->nl_family == AF_NETLINK ); - - fd = socket(local->nl_family, SOCK_RAW, NETLINK_ROUTE); - if(fd < 0) { - PyErr_SetString(PyExc_OSError, strerror(errno)); - return -1; + struct etherinfo *ethi = (struct etherinfo *) arg; + struct rtnl_link *link = (struct rtnl_link *) obj; + struct nl_addr *addr = rtnl_link_get_addr(link); + unsigned int i, len; + unsigned char *binaddr; + char hwaddr[130], *ptr; + + if( (ethi == NULL) || (ethi->hwaddress != NULL) ) { + return; } - if(bind(fd, (struct sockaddr*) local, sizeof(*local)) < 0) { - PyErr_SetString(PyExc_OSError, strerror(errno)); - return -1; + binaddr = nl_addr_get_binary_addr(addr); + memset(&hwaddr, 0, 130); + len = 20; + ptr = (char *)&hwaddr; + for( i = 0; i < 6; i++ ) { + if( i == 0 ) { + snprintf(ptr, len, "%02X", *(binaddr+i)); + len -= 2; + ptr += 2; + } else { + snprintf(ptr, len, ":%02X", *(binaddr+i)); + len -= 3; + ptr += 3; + } } - - return fd; + ethi->hwaddress = strdup(hwaddr); } -int send_netlink_query(int fd, int get_type) +static void callback_nl_address(struct nl_object *obj, void *arg) { - struct sockaddr_nl peer; - struct msghdr msg_info; - struct nl_request netlink_req; - struct iovec iov_info; - - memset(&peer, 0, sizeof(peer)); - peer.nl_family = AF_NETLINK; - peer.nl_pad = 0; - peer.nl_pid = 0; - peer.nl_groups = 0; - - memset(&msg_info, 0, sizeof(msg_info)); - msg_info.msg_name = (void *) &peer; - msg_info.msg_namelen = sizeof(peer); - - memset(&netlink_req, 0, sizeof(netlink_req)); - netlink_req.nlmsg_info.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - netlink_req.nlmsg_info.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - netlink_req.nlmsg_info.nlmsg_pid = getpid(); - - // Set the information we want to query for - netlink_req.nlmsg_info.nlmsg_type = (get_type == GET_LINK ? RTM_GETLINK : RTM_GETADDR); - netlink_req.ifaddrmsg_info.ifa_family = (get_type == GET_IPV6 ? AF_INET6 : AF_INET); - - iov_info.iov_base = (void *) &netlink_req.nlmsg_info; - iov_info.iov_len = netlink_req.nlmsg_info.nlmsg_len; - msg_info.msg_iov = &iov_info; - msg_info.msg_iovlen = 1; - - if( sendmsg(fd, &msg_info, 0) < 0 ) { - PyErr_SetString(PyExc_OSError, strerror(errno)); - return 0; - } - return 1; -} + struct etherinfo *ethi = (struct etherinfo *) arg; + struct nl_addr *addr; + char ip_str[66]; + int family; + if( ethi == NULL ) { + return; + } -int read_netlink_results(int fd, struct sockaddr_nl *local, - int (*callback)(struct nlmsghdr *, struct etherinfo *, struct etherinfo **idxptr), - struct etherinfo *ethinf) -{ - struct etherinfo *process_ethinfo_idxptr = NULL; // Int. index ptr for callback function - struct sockaddr_nl nladdr; - struct iovec iov; - struct msghdr msg; - char buf[16384]; - - memset(&nladdr, 0, sizeof(nladdr)); - memset(&iov, 0, sizeof(iov)); - memset(&msg, 0, sizeof(msg)); - memset(&buf, 0, sizeof(buf)); - - msg.msg_name = &nladdr; - msg.msg_namelen = sizeof(nladdr); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - iov.iov_base = buf; - while (1) { - int status; - struct nlmsghdr *h; - - iov.iov_len = sizeof(buf); - status = recvmsg(fd, &msg, 0); - - if (status < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - PyErr_SetString(PyExc_OSError, strerror(errno)); - return 0; - } - - if (status == 0) { - PyErr_SetString(PyExc_RuntimeError, "EOF on netlink"); - return 0; - } + addr = rtnl_addr_get_local((struct rtnl_addr *)obj); + family = nl_addr_get_family(addr); + switch( family ) { + case AF_INET: + case AF_INET6: + memset(&ip_str, 0, 66); + inet_ntop(family, nl_addr_get_binary_addr(addr), (char *)&ip_str, 64); - h = (struct nlmsghdr *)buf; - while (NLMSG_OK(h, status)) { - if (nladdr.nl_pid != 0 || - h->nlmsg_pid != local->nl_pid ) { - goto skip_data; - } + if( family == AF_INET ) { + struct nl_addr *brdcst = rtnl_addr_get_broadcast((struct rtnl_addr *)obj); + char brdcst_str[66]; - if (h->nlmsg_type == NLMSG_DONE) { - return 1; - } + ethi->ipv4_address = strdup(ip_str); + ethi->ipv4_netmask = rtnl_addr_get_prefixlen((struct rtnl_addr*) obj); - if (h->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); - - if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { - PyErr_SetString(PyExc_RuntimeError, - "Error message truncated\n"); - } else { - errno = -err->error; - PyErr_SetString(PyExc_OSError, strerror(errno)); - } - return 0; - } - // Process/decode data - if( !callback(h, ethinf, &process_ethinfo_idxptr) ) { - // Error already set in callback - return 0; + 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); } - skip_data: - h = NLMSG_NEXT(h, status); - } - - if (msg.msg_flags & MSG_TRUNC) { - PyErr_SetString(PyExc_RuntimeError, "Message truncated\n"); - continue; - } - if (status) { - PyErr_SetString(PyExc_RuntimeError, "Not all data available was processed"); - return 0; + } else { + ethi->ipv6_address = strdup(ip_str); + ethi->ipv6_netmask = rtnl_addr_get_prefixlen((struct rtnl_addr*) obj); } + return; + default: + return; } } + /* * - * Internal functions for processing NETLINK_ROUTE results + * Exported functions - API frontend * */ -/* ll_addr_n2a - stolen from iproute2 source */ -const char *ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int blen) +void dump_etherinfo(FILE *fp, struct etherinfo *ptr) { - int i; - int l; - if (alen == 4 && - (type == ARPHRD_TUNNEL || type == ARPHRD_SIT || type == ARPHRD_IPGRE)) { - return inet_ntop(AF_INET, addr, buf, blen); + fprintf(fp, "*** Interface [%i] %s ", ptr->index, ptr->device); + if( ptr->hwaddress ) { + fprintf(fp, "MAC address: %s", ptr->hwaddress); } - if (alen == 16 && type == ARPHRD_TUNNEL6) { - return inet_ntop(AF_INET6, addr, buf, blen); - } - l = 0; - for (i=0; i<alen; i++) { - if (i==0) { - snprintf(buf+l, blen, "%02x", addr[i]); - blen -= 2; - l += 2; - } else { - snprintf(buf+l, blen, ":%02x", addr[i]); - blen -= 3; - l += 3; - } - } - return buf; - -} - - -// Callback function for processing RTM_GETLINK results -int etherinfo_proc_getlink(struct nlmsghdr *msg, struct etherinfo *ethinfchain, struct etherinfo **idxptr) -{ - int len = 0; - struct ifinfomsg *ifinfo = NLMSG_DATA(msg); - struct rtattr *rta = NULL; - - assert( ethinfchain != NULL ); - - rta = IFLA_RTA(ifinfo); - len = IFLA_PAYLOAD(msg); - - // Set the index pointer to the record we will update/register - *idxptr = ((*idxptr) == NULL ? ethinfchain : (*idxptr)->next); - if( (*idxptr)->next == NULL ) { - // Append new record if we hit the end of the chain - (*idxptr)->next = new_etherinfo_record(); - if( *idxptr == NULL ) { - PyErr_SetString(PyExc_RuntimeError, - "Could not allocate memory to another interface"); - return 0; - } - } - - // Store information - (*idxptr)->index = ifinfo->ifi_index; - (*idxptr)->type = ifinfo->ifi_type; - while( RTA_OK(rta, len) ) { - switch( rta->rta_type ) { - case IFLA_IFNAME: - (*idxptr)->device = strdup((char *)RTA_DATA(rta)); - if( !(*idxptr)->device ) { - PyErr_SetString(PyExc_RuntimeError, - "Could not allocate memory for interface name"); - return 0; - } - break; - - case IFLA_ADDRESS: - (*idxptr)->hwaddress = (char *)malloc(258); - if( !(*idxptr)->hwaddress ) { - PyErr_SetString(PyExc_RuntimeError, - "Could not allocate memory for hardware address"); - return 0; - } - memset((*idxptr)->hwaddress, 0, 258); - ll_addr_n2a(RTA_DATA(rta), RTA_PAYLOAD(rta), ifinfo->ifi_type, - (*idxptr)->hwaddress, 256); - break; - default: - break; + fprintf(fp, "\n"); + if( ptr->ipv4_address ) { + fprintf(fp, "\tIPv4 Address: %s/%i", + ptr->ipv4_address, ptr->ipv4_netmask); + if( ptr->ipv4_broadcast ) { + fprintf(fp, " - Broadcast: %s", ptr->ipv4_broadcast); } - - rta = RTA_NEXT(rta, len); + fprintf(fp, "\n"); } - return 1; -} - -// Callback function for processing RTM_GETADDR results -int etherinfo_proc_getaddr(struct nlmsghdr *msg, struct etherinfo *ethinfchain, struct etherinfo **idxptr) -{ - int len = 0; - struct ifaddrmsg *ifaddr = NLMSG_DATA(msg); - struct rtattr *rta = NULL; - char *ifa_addr = NULL, *ifa_brd = NULL; - int ifa_netmask = 0; - - assert( ethinfchain != NULL ); - - rta = IFA_RTA(ifaddr); - len = IFA_PAYLOAD(msg); - - // Copy interesting information to our buffers - while( RTA_OK(rta, len) ) { - switch( rta->rta_type ) { - case IFA_ADDRESS: // IP address + netmask - ifa_addr = (char *) malloc(130); - if( !ifa_addr ) { - PyErr_SetString(PyExc_RuntimeError, - "Could not allocate memory for IP address"); - return 0; - } - memset(ifa_addr, 0, 130); - inet_ntop(ifaddr->ifa_family, RTA_DATA(rta), ifa_addr, 128); - ifa_netmask = ifaddr->ifa_prefixlen; - break; - - case IFA_BROADCAST: - ifa_brd = (char *) malloc(130); - if( !ifa_brd ) { - PyErr_SetString(PyExc_RuntimeError, - "Could not allocate memory for broadcase address"); - return 0; - } - memset(ifa_brd, 0, 130); - inet_ntop(ifaddr->ifa_family, RTA_DATA(rta), ifa_brd, 128); - break; - - default: - break; - } - rta = RTA_NEXT(rta, len); + if( ptr->ipv6_address ) { + fprintf(fp, "\tIPv6 address: %s/%i\n", + ptr->ipv6_address, ptr->ipv6_netmask); } - - // Update the corresponding etherinfo record - return update_etherinfo(ethinfchain, ifaddr->ifa_index, ifaddr->ifa_family, - ifa_addr, ifa_netmask, ifa_brd); + fprintf(fp, "\n"); } - -/* - * - * Exported functions - API frontend - * - */ - -void dump_etherinfo(FILE *fp, struct etherinfo *ethinfo) +struct etherinfo *get_etherinfo(const char *ifdevname) { - struct etherinfo *ptr; - - for( ptr = ethinfo; ptr->next != NULL; ptr = ptr->next ) { - if( (ptr->type != ARPHRD_ETHER) && (ptr->type != ARPHRD_LOOPBACK) ) { - continue; - } - fprintf(fp, "*** Interface [%i] %s ", ptr->index, ptr->device); - if( ptr->hwaddress ) { - fprintf(fp, "MAC address: %s", ptr->hwaddress); - } - fprintf(fp, "\n"); - if( ptr->ipv4_address ) { - fprintf(fp, "\tIPv4 Address: %s/%i", - ptr->ipv4_address, ptr->ipv4_netmask); - if( ptr->ipv4_broadcast ) { - fprintf(fp, " - Broadcast: %s", ptr->ipv4_broadcast); - } - fprintf(fp, "\n"); - } - if( ptr->ipv6_address ) { - fprintf(fp, "\tIPv6 address: %s/%i\n", - ptr->ipv6_address, ptr->ipv6_netmask); - } - fprintf(fp, "\n"); - } -} - -struct etherinfo *get_etherinfo() -{ - int fd; - struct sockaddr_nl local; struct etherinfo *ethinf = NULL; - - // open NETLINK socket - memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_pad = 0; - local.nl_pid = getpid(); - local.nl_groups = 0; - fd = open_netlink_socket(&local); - if( fd < 0 ) { + 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 + /* 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? */ - // Get some hardware info - ifname, type and hwaddress. Populates ethinf - if( !send_netlink_query(fd, GET_LINK) ) { - goto error; - } - if( !read_netlink_results(fd, &local, etherinfo_proc_getlink, ethinf) ) { - goto error; - } - + /* 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); - // IPv4 information - updates the interfaces found in ethinfo - if( !send_netlink_query(fd, GET_IPV4) ) { - goto error; - } - if( !read_netlink_results(fd, &local, etherinfo_proc_getaddr, ethinf) ) { - goto error; - } - - - // IPv6 information - updates the interfaces found in ethinfo - if( !send_netlink_query(fd, GET_IPV6) ) { - goto error; - } - if( !read_netlink_results(fd, &local, etherinfo_proc_getaddr, ethinf) ) { - goto error; - } - goto exit; + /* 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); - error: - free_etherinfo(ethinf); - ethinf = NULL; + /* Close NETLINK connection */ + nl_close(handle); + nl_handle_destroy(handle); - exit: - close(fd); return ethinf; } #ifdef TESTPROG // Simple standalone test program -int main() { +int main(int argc, char **argv) { struct etherinfo *inf = NULL; - inf = get_etherinfo(); + inf = get_etherinfo(argv[1]); if( inf == NULL ) { fprintf(stderr, "Operation failed. Could not retrieve ethernet information\n"); exit(2); diff --git a/python-ethtool/etherinfo.h b/python-ethtool/etherinfo.h index 996bd45..bda5185 100644 --- a/python-ethtool/etherinfo.h +++ b/python-ethtool/etherinfo.h @@ -18,8 +18,7 @@ #define _ETHERINFO_H struct etherinfo { - int index; - int type; + int index; char *device; char *hwaddress; char *ipv4_address; @@ -27,7 +26,6 @@ struct etherinfo { char *ipv4_broadcast; char *ipv6_address; int ipv6_netmask; - struct etherinfo *next; }; struct etherinfo *get_etherinfo(); diff --git a/python-ethtool/ethtool.c b/python-ethtool/ethtool.c index 8d67844..d84bc79 100644 --- a/python-ethtool/ethtool.c +++ b/python-ethtool/ethtool.c @@ -233,9 +233,9 @@ 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, *ptr = NULL; + struct etherinfo *devinfo = NULL; char **fetch_devs; - int fetch_devs_len = 0; + int i = 0, fetch_devs_len = 0; if (!PyArg_ParseTuple(args, "|O", &inargs)) { PyErr_SetString(PyExc_LookupError, @@ -250,7 +250,7 @@ static PyObject *get_interface_info(PyObject *self __unused, PyObject *args) { fetch_devs = calloc(1, sizeof(char *)); fetch_devs[0] = PyString_AsString(inargs); } else if( PyTuple_Check(inargs) ) { /* Input argument is a tuple list with devices */ - int i, j = 0; + int j = 0; fetch_devs_len = PyTuple_Size(inargs); fetch_devs = calloc(fetch_devs_len+1, sizeof(char *)); @@ -262,7 +262,7 @@ static PyObject *get_interface_info(PyObject *self __unused, PyObject *args) { } fetch_devs_len = j; } else if( PyList_Check(inargs) ) { /* Input argument is a list with devices */ - int i, j = 0; + int j = 0; fetch_devs_len = PyList_Size(inargs); fetch_devs = calloc(fetch_devs_len+1, sizeof(char *)); @@ -279,35 +279,15 @@ static PyObject *get_interface_info(PyObject *self __unused, PyObject *args) { return NULL; } } - devinfo = get_etherinfo(); - if( !devinfo ) { - PyErr_SetString(PyExc_OSError, strerror(errno)); - return NULL; - } - /* Slice up the etherinfo struct and populate individual objects with - * the current ethernet information. - */ - devlist = PyList_New(0); - while( devinfo->next != NULL ) { - /* Get copy of pointers, before we start slicing it up */ - ptr = devinfo->next; /* Fetch the pointer to the next element first */ - devinfo->next = NULL; /* Make the current slice do not point anywhere else */ - - /* Skip this device only if we have a list of devices and the current one */ - /* does not match */ - if( fetch_devs_len > 0) { - int i; - for( i = 0; i < fetch_devs_len; i++ ) { - if( fetch_devs[i] && (strcmp(fetch_devs[i], devinfo->device) == 0) ) { - goto found_dev; /* Add this device to the devlist */ - } - } - /* Free the info which we don't need, and continue */ - free_etherinfo(devinfo); - goto next_dev; + + for( i = 0; i < fetch_devs_len; i++ ) { + devinfo = get_etherinfo(fetch_devs[i]); + if( !devinfo ) { + PyErr_SetString(PyExc_OSError, strerror(errno)); + return NULL; } - found_dev: + /* Instantiate a new etherinfo object with the device information */ ethinf_py = PyCObject_FromVoidPtr(devinfo, NULL); if( ethinf_py ) { @@ -319,14 +299,10 @@ static PyObject *get_interface_info(PyObject *self __unused, PyObject *args) { PyObject *dev = PyObject_CallObject((PyObject *)ðtool_etherinfoType, args); PyList_Append(devlist, dev); } - next_dev: - devinfo = ptr; /* Go to the next element */ - } - /* clean up headers which might not be used or considered interesting */ - if( devinfo != NULL ) { - free_etherinfo(devinfo); + if( devinfo != NULL ) { + free_etherinfo(devinfo); + } } - if( fetch_devs_len > 0 ) { free(fetch_devs); } @@ -1,11 +1,51 @@ #!/usr/bin/python2 from distutils.core import setup, Extension +import commands ethtool = Extension('ethtool', sources = ['python-ethtool/ethtool.c', 'python-ethtool/etherinfo.c', 'python-ethtool/etherinfo_obj.c']) +def pkgconfig(pkg): + def _str2list(pkgstr, onlystr): + res = [] + for l in pkgstr.split(" "): + if l.find(onlystr) == 0: + res.append(l.replace(onlystr, "", 1)) + return res + + (res, cflags) = commands.getstatusoutput('pkg-config --cflags-only-other %s' % pkg) + if res != 0: + print 'Failed to query pkg-config --cflags-only-other %s' % pkg + sys.exit(1) + + (res, includes) = commands.getstatusoutput('pkg-config --cflags-only-I %s' % pkg) + if res != 0: + print 'Failed to query pkg-config --cflags-only-I %s' % pkg + sys.exit(1) + + (res, libs) = commands.getstatusoutput('pkg-config --libs-only-l %s' % pkg) + if res != 0: + print 'Failed to query pkg-config --libs-only-l %s' % pkg + sys.exit(1) + + (res, libdirs) = commands.getstatusoutput('pkg-config --libs-only-L %s' % pkg) + if res != 0: + print 'Failed to query pkg-config --libs-only-L %s' % pkg + sys.exit(1) + + + # Clean up the results and return what we've extracted from pkg-config + return {'cflags': cflags, + 'include': _str2list(includes, '-I'), + 'libs': _str2list(libs, '-l'), + 'libdirs': _str2list(libdirs, '-L') + } + + +libnl = pkgconfig('libnl-1') + # don't reformat this line, Makefile parses it setup(name='ethtool', version='0.2', @@ -13,4 +53,16 @@ setup(name='ethtool', author='Harald Hoyer & Arnaldo Carvalho de Melo', author_email='acme@redhat.com', url='http://fedoraproject.org/wiki/python-ethtool', - ext_modules=[ethtool]) + ext_modules=[ + Extension( + 'ethtool', + sources = [ + 'python-ethtool/ethtool.c', + 'python-ethtool/etherinfo.c', + 'python-ethtool/etherinfo_obj.c'], + include_dirs = libnl['include'], + library_dirs = libnl['libdirs'], + libraries = libnl['libs'] + ) + ] +) |