Skip to content

Commit 4f0295f

Browse files
author
David Sommerseth
committed
Updated to fetch the interface information when the "getter" function triggers
1 parent d3fd6b8 commit 4f0295f

File tree

6 files changed

+222
-137
lines changed

6 files changed

+222
-137
lines changed

python-ethtool/etherinfo.c

Lines changed: 59 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -24,35 +24,16 @@
2424
#include <stdlib.h>
2525
#include <asm/types.h>
2626
#include <sys/socket.h>
27-
#include <netlink/addr.h>
28-
#include <netlink/netlink.h>
29-
#include <netlink/handlers.h>
30-
#include <netlink/route/link.h>
31-
#include <netlink/route/addr.h>
32-
#include <arpa/inet.h>
3327
#include <assert.h>
3428
#include <errno.h>
29+
#include "etherinfo_struct.h"
3530
#include "etherinfo.h"
3631

3732
/*
3833
*
3934
* Internal functions for working with struct etherinfo
4035
*
4136
*/
42-
43-
inline struct etherinfo *new_etherinfo_record()
44-
{
45-
struct etherinfo *ptr;
46-
47-
ptr = malloc(sizeof(struct etherinfo)+1);
48-
if( ptr ) {
49-
memset(ptr, 0, sizeof(struct etherinfo)+1);
50-
}
51-
52-
return ptr;
53-
}
54-
55-
5637
void free_etherinfo(struct etherinfo *ptr)
5738
{
5839
if( ptr == NULL ) { // Just for safety
@@ -82,6 +63,13 @@ void free_etherinfo(struct etherinfo *ptr)
8263
*
8364
*/
8465

66+
#define SET_STR_VALUE(dst, src) { \
67+
if( dst ) { \
68+
free(dst); \
69+
}; \
70+
dst = strdup(src); \
71+
}
72+
8573
static void callback_nl_link(struct nl_object *obj, void *arg)
8674
{
8775
struct etherinfo *ethi = (struct etherinfo *) arg;
@@ -110,7 +98,7 @@ static void callback_nl_link(struct nl_object *obj, void *arg)
11098
ptr += 3;
11199
}
112100
}
113-
ethi->hwaddress = strdup(hwaddr);
101+
SET_STR_VALUE(ethi->hwaddress, hwaddr);
114102
}
115103

116104

@@ -137,16 +125,16 @@ static void callback_nl_address(struct nl_object *obj, void *arg)
137125
struct nl_addr *brdcst = rtnl_addr_get_broadcast((struct rtnl_addr *)obj);
138126
char brdcst_str[66];
139127

140-
ethi->ipv4_address = strdup(ip_str);
128+
SET_STR_VALUE(ethi->ipv4_address, ip_str);
141129
ethi->ipv4_netmask = rtnl_addr_get_prefixlen((struct rtnl_addr*) obj);
142130

143131
if( brdcst ) {
144132
memset(&brdcst_str, 0, 66);
145133
inet_ntop(family, nl_addr_get_binary_addr(brdcst), (char *)&brdcst_str, 64);
146-
ethi->ipv4_broadcast = strdup(brdcst_str);
134+
SET_STR_VALUE(ethi->ipv4_broadcast, brdcst_str);
147135
}
148136
} else {
149-
ethi->ipv6_address = strdup(ip_str);
137+
SET_STR_VALUE(ethi->ipv6_address, ip_str);
150138
ethi->ipv6_netmask = rtnl_addr_get_prefixlen((struct rtnl_addr*) obj);
151139
}
152140
return;
@@ -186,70 +174,59 @@ void dump_etherinfo(FILE *fp, struct etherinfo *ptr)
186174
fprintf(fp, "\n");
187175
}
188176

189-
struct etherinfo *get_etherinfo(const char *ifdevname)
177+
178+
int get_etherinfo(struct etherinfo *ethinf, struct _nlconnection *nlc, nlQuery query)
190179
{
191-
struct etherinfo *ethinf = NULL;
192-
struct nl_handle *handle;
193180
struct nl_cache *link_cache;
194181
struct nl_cache *addr_cache;
195182
struct rtnl_addr *addr;
196183
struct rtnl_link *link;
197-
int ifindex;
198-
199-
/* Establish connection to NETLINK */
200-
handle = nl_handle_alloc();
201-
nl_connect(handle, NETLINK_ROUTE);
202-
203-
/* Find the interface index we're looking up */
204-
link_cache = rtnl_link_alloc_cache(handle);
205-
ifindex = rtnl_link_name2i(link_cache, ifdevname);
206-
if( ifindex < 0 ) {
207-
return NULL;
208-
}
209-
210-
/* Create an empty record, where ethernet information will be saved */
211-
ethinf = new_etherinfo_record();
212-
if( !ethinf ) {
213-
return NULL;
214-
}
215-
ethinf->index = ifindex;
216-
ethinf->device = strdup(ifdevname); /* Should extract via libnl - nl_link callback? */
217-
218-
/* Extract MAC/hardware address of the interface */
219-
link = rtnl_link_alloc();
220-
rtnl_link_set_ifindex(link, ifindex);
221-
nl_cache_foreach_filter(link_cache, (struct nl_object *)link, callback_nl_link, ethinf);
222-
rtnl_link_put(link);
223-
nl_cache_free(link_cache);
224-
225-
/* Extract IP address information */
226-
addr_cache = rtnl_addr_alloc_cache(handle);
227-
addr = rtnl_addr_alloc();
228-
rtnl_addr_set_ifindex(addr, ifindex);
229-
nl_cache_foreach_filter(addr_cache, (struct nl_object *)addr, callback_nl_address, ethinf);
230-
rtnl_addr_put(addr);
231-
nl_cache_free(addr_cache);
232-
233-
/* Close NETLINK connection */
234-
nl_close(handle);
235-
nl_handle_destroy(handle);
236-
237-
return ethinf;
238-
}
184+
int ret = 0;
239185

240-
#ifdef TESTPROG
241-
// Simple standalone test program
242-
int main(int argc, char **argv) {
243-
struct etherinfo *inf = NULL;
244-
245-
inf = get_etherinfo(argv[1]);
246-
if( inf == NULL ) {
247-
fprintf(stderr, "Operation failed. Could not retrieve ethernet information\n");
248-
exit(2);
186+
if( !ethinf || !nlc ) {
187+
return 0;
249188
}
250-
dump_etherinfo(stdout, inf);
251-
free_etherinfo(inf);
252189

253-
return 0;
190+
/* Find the interface index we're looking up.
191+
* As we don't expect it to change, we're reusing a "cached"
192+
* interface index if we have that
193+
*/
194+
if( ethinf->index < 0 ) {
195+
link_cache = rtnl_link_alloc_cache(nlc->nlrt_handle);
196+
ethinf->index = rtnl_link_name2i(link_cache, ethinf->device);
197+
if( ethinf->index < 0 ) {
198+
return 0;
199+
}
200+
nl_cache_free(link_cache);
201+
}
202+
203+
/* Query the for requested info vai NETLINK */
204+
switch( query ) {
205+
case NLQRY_LINK:
206+
/* Extract MAC/hardware address of the interface */
207+
link_cache = rtnl_link_alloc_cache(nlc->nlrt_handle);
208+
link = rtnl_link_alloc();
209+
rtnl_link_set_ifindex(link, ethinf->index);
210+
nl_cache_foreach_filter(link_cache, (struct nl_object *)link, callback_nl_link, ethinf);
211+
rtnl_link_put(link);
212+
nl_cache_free(link_cache);
213+
ret = 1;
214+
break;
215+
216+
case NLQRY_ADDR:
217+
/* Extract IP address information */
218+
addr_cache = rtnl_addr_alloc_cache(nlc->nlrt_handle);
219+
addr = rtnl_addr_alloc();
220+
rtnl_addr_set_ifindex(addr, ethinf->index);
221+
nl_cache_foreach_filter(addr_cache, (struct nl_object *)addr, callback_nl_address, ethinf);
222+
rtnl_addr_put(addr);
223+
nl_cache_free(addr_cache);
224+
ret = 1;
225+
break;
226+
227+
default:
228+
ret = 0;
229+
}
230+
return ret;
254231
}
255-
#endif
232+

python-ethtool/etherinfo.h

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,16 @@
1717
#ifndef _ETHERINFO_H
1818
#define _ETHERINFO_H
1919

20-
struct etherinfo {
21-
int index;
22-
char *device;
23-
char *hwaddress;
24-
char *ipv4_address;
25-
int ipv4_netmask;
26-
char *ipv4_broadcast;
27-
char *ipv6_address;
28-
int ipv6_netmask;
29-
};
20+
#include <netlink/addr.h>
21+
#include <netlink/netlink.h>
22+
#include <netlink/handlers.h>
23+
#include <netlink/route/link.h>
24+
#include <netlink/route/addr.h>
25+
#include <arpa/inet.h>
3026

31-
struct etherinfo *get_etherinfo();
27+
typedef enum {NLQRY_LINK, NLQRY_ADDR} nlQuery;
28+
29+
int get_etherinfo(struct etherinfo *ethinf, struct _nlconnection *nlc, nlQuery query);
3230
void free_etherinfo(struct etherinfo *ptr);
3331
void dump_etherinfo(FILE *, struct etherinfo *);
3432

python-ethtool/etherinfo_obj.c

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99

1010
#include <Python.h>
1111
#include "structmember.h"
12-
#include "etherinfo.h"
12+
1313
#include "etherinfo_struct.h"
14+
#include "etherinfo.h"
1415

1516

1617
/**
@@ -20,8 +21,11 @@
2021
*/
2122
void _ethtool_etherinfo_dealloc(etherinfo_py *self)
2223
{
23-
if( self->info ) {
24-
free_etherinfo(self->info);
24+
if( self->data ) {
25+
if( self->data->ethinfo ) {
26+
free_etherinfo(self->data->ethinfo);
27+
}
28+
free(self->data);
2529
}
2630
self->ob_type->tp_free((PyObject*)self);
2731
}
@@ -63,7 +67,7 @@ int _ethtool_etherinfo_init(etherinfo_py *self, PyObject *args, PyObject *kwds)
6367
PyErr_SetString(PyExc_AttributeError, "Invalid data pointer to constructor");
6468
return -1;
6569
}
66-
self->info = (struct etherinfo *) PyCObject_AsVoidPtr(ethinf_ptr);
70+
self->data = (struct etherinfo_obj_data *) PyCObject_AsVoidPtr(ethinf_ptr);
6771
return 0;
6872
}
6973

@@ -86,29 +90,38 @@ int _ethtool_etherinfo_init(etherinfo_py *self, PyObject *args, PyObject *kwds)
8690
*/
8791
PyObject *_ethtool_etherinfo_getter(etherinfo_py *self, PyObject *attr_o)
8892
{
93+
PyObject *ret;
8994
char *attr = PyString_AsString(attr_o);
9095

91-
if( !self || !self->info ) {
96+
if( !self || !self->data ) {
9297
PyErr_SetString(PyExc_AttributeError, "No data available");
9398
return NULL;
9499
}
95100

96101
if( strcmp(attr, "device") == 0 ) {
97-
return RETURN_STRING(self->info->device);
102+
ret = RETURN_STRING(self->data->ethinfo->device);
98103
} else if( strcmp(attr, "mac_address") == 0 ) {
99-
return RETURN_STRING(self->info->hwaddress);
104+
get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_LINK);
105+
ret = RETURN_STRING(self->data->ethinfo->hwaddress);
100106
} else if( strcmp(attr, "ipv4_address") == 0 ) {
101-
return RETURN_STRING(self->info->ipv4_address);
107+
get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_LINK);
108+
ret = RETURN_STRING(self->data->ethinfo->ipv4_address);
102109
} else if( strcmp(attr, "ipv4_netmask") == 0 ) {
103-
return PyInt_FromLong(self->info->ipv4_netmask);
110+
get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
111+
ret = PyInt_FromLong(self->data->ethinfo->ipv4_netmask);
104112
} else if( strcmp(attr, "ipv4_broadcast") == 0 ) {
105-
return RETURN_STRING(self->info->ipv4_broadcast);
113+
get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
114+
ret = RETURN_STRING(self->data->ethinfo->ipv4_broadcast);
106115
} else if( strcmp(attr, "ipv6_address") == 0 ) {
107-
return RETURN_STRING(self->info->ipv6_address);
116+
get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
117+
ret = RETURN_STRING(self->data->ethinfo->ipv6_address);
108118
} else if( strcmp(attr, "ipv6_netmask") == 0 ) {
109-
return PyInt_FromLong(self->info->ipv6_netmask);
119+
get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
120+
ret = PyInt_FromLong(self->data->ethinfo->ipv6_netmask);
121+
} else {
122+
ret = PyObject_GenericGetAttr((PyObject *)self, attr_o);
110123
}
111-
return PyObject_GenericGetAttr((PyObject *)self, attr_o);
124+
return ret;
112125
}
113126

114127

@@ -140,34 +153,37 @@ PyObject *_ethtool_etherinfo_str(etherinfo_py *self)
140153
{
141154
PyObject *ret = NULL;
142155

143-
if( !self || !self->info ) {
156+
if( !self || !self->data || !self->data->nlc || !self->data->ethinfo ) {
144157
PyErr_SetString(PyExc_AttributeError, "No data available");
145158
return NULL;
146159
}
147160

148-
ret = PyString_FromFormat("Device %s:\n", self->info->device);
149-
if( self->info->hwaddress ) {
150-
PyObject *tmp = PyString_FromFormat("\tMAC address: %s\n", self->info->hwaddress);
161+
get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_LINK);
162+
get_etherinfo(self->data->ethinfo, self->data->nlc, NLQRY_ADDR);
163+
164+
ret = PyString_FromFormat("Device %s:\n", self->data->ethinfo->device);
165+
if( self->data->ethinfo->hwaddress ) {
166+
PyObject *tmp = PyString_FromFormat("\tMAC address: %s\n", self->data->ethinfo->hwaddress);
151167
PyString_Concat(&ret, tmp);
152168
}
153169

154-
if( self->info->ipv4_address ) {
170+
if( self->data->ethinfo->ipv4_address ) {
155171
PyObject *tmp = PyString_FromFormat("\tIPv4 address: %s/%i",
156-
self->info->ipv4_address,
157-
self->info->ipv4_netmask);
158-
if( self->info->ipv4_broadcast ) {
172+
self->data->ethinfo->ipv4_address,
173+
self->data->ethinfo->ipv4_netmask);
174+
if( self->data->ethinfo->ipv4_broadcast ) {
159175
PyObject *tmp2 = PyString_FromFormat(" Broadcast: %s",
160-
self->info->ipv4_broadcast);
176+
self->data->ethinfo->ipv4_broadcast);
161177
PyString_Concat(&tmp, tmp2);
162178
}
163179
PyString_Concat(&tmp, PyString_FromString("\n"));
164180
PyString_Concat(&ret, tmp);
165181
}
166182

167-
if( self->info->ipv6_address ) {
183+
if( self->data->ethinfo->ipv6_address ) {
168184
PyObject *tmp = PyString_FromFormat("\tIPv6 address: %s/%i\n",
169-
self->info->ipv6_address,
170-
self->info->ipv6_netmask);
185+
self->data->ethinfo->ipv6_address,
186+
self->data->ethinfo->ipv6_netmask);
171187
PyString_Concat(&ret, tmp);
172188
}
173189
return ret;

python-ethtool/etherinfo_obj.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,19 @@ static PyMethodDef _ethtool_etherinfo_methods[] = {
3636
*
3737
*/
3838
static PyMemberDef _ethtool_etherinfo_members[] = {
39-
{"device", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
39+
{"device", T_OBJECT_EX, offsetof(etherinfo_py, data), 0,
4040
"Device name of the interface"},
41-
{"mac_address", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
41+
{"mac_address", T_OBJECT_EX, offsetof(etherinfo_py, data), 0,
4242
"MAC address / hardware address of the interface"},
43-
{"ipv4_address", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
43+
{"ipv4_address", T_OBJECT_EX, offsetof(etherinfo_py, data), 0,
4444
"IPv4 address"},
45-
{"ipv4_netmask", T_INT, offsetof(etherinfo_py, info), 0,
45+
{"ipv4_netmask", T_INT, offsetof(etherinfo_py, data), 0,
4646
"IPv4 netmask in bits"},
47-
{"ipv4_broadcast", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
47+
{"ipv4_broadcast", T_OBJECT_EX, offsetof(etherinfo_py, data), 0,
4848
"IPv4 broadcast address"},
49-
{"ipv6_address", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
49+
{"ipv6_address", T_OBJECT_EX, offsetof(etherinfo_py, data), 0,
5050
"IPv6 address"},
51-
{"ipv6_netmask", T_INT, offsetof(etherinfo_py, info), 0,
51+
{"ipv6_netmask", T_INT, offsetof(etherinfo_py, data), 0,
5252
"IPv6 netmask in bits"},
5353
{NULL} /* End of member list */
5454
};

0 commit comments

Comments
 (0)