Skip to content

Commit 4c301d9

Browse files
author
David Sommerseth
committed
Reduce the NETLINK pointer complexity
Make the NETLINK connection pointer and user counter local global variables inside netlink.c only. Where NETLINK calls via libnl is required, rather use get_nlc() to get a NETLINK connection. This also prepares the next step, to get rid of the struct etherinfo_obj_data wrapper. Signed-off-by: David Sommerseth <davids@redhat.com>
1 parent e978498 commit 4c301d9

File tree

6 files changed

+58
-50
lines changed

6 files changed

+58
-50
lines changed

python-ethtool/etherinfo.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ static void callback_nl_address(struct nl_object *obj, void *arg)
142142
*
143143
* @return Returns 1 on success, otherwise 0.
144144
*/
145-
int get_etherinfo(struct etherinfo_obj_data *data, nlQuery query)
145+
int get_etherinfo(etherinfo_py *self, nlQuery query)
146146
{
147147
struct nl_cache *link_cache;
148148
struct nl_cache *addr_cache;
@@ -153,13 +153,13 @@ int get_etherinfo(struct etherinfo_obj_data *data, nlQuery query)
153153

154154
int ret = 0;
155155

156-
if( !data || !data->ethinfo ) {
156+
if( !self || !self->data || !self->data->ethinfo ) {
157157
return 0;
158158
}
159-
ethinf = data->ethinfo;
159+
ethinf = self->data->ethinfo;
160160

161161
/* Open a NETLINK connection on-the-fly */
162-
if( !open_netlink(data) ) {
162+
if( !open_netlink(self) ) {
163163
PyErr_Format(PyExc_RuntimeError,
164164
"Could not open a NETLINK connection for %s",
165165
ethinf->device);
@@ -171,7 +171,7 @@ int get_etherinfo(struct etherinfo_obj_data *data, nlQuery query)
171171
* interface index if we have that
172172
*/
173173
if( ethinf->index < 0 ) {
174-
if( rtnl_link_alloc_cache(*data->nlc, AF_UNSPEC, &link_cache) < 0) {
174+
if( rtnl_link_alloc_cache(get_nlc(), AF_UNSPEC, &link_cache) < 0) {
175175
return 0;
176176
}
177177

@@ -195,7 +195,7 @@ int get_etherinfo(struct etherinfo_obj_data *data, nlQuery query)
195195
switch( query ) {
196196
case NLQRY_LINK:
197197
/* Extract MAC/hardware address of the interface */
198-
if( rtnl_link_alloc_cache(*data->nlc, AF_UNSPEC, &link_cache) < 0) {
198+
if( rtnl_link_alloc_cache(get_nlc(), AF_UNSPEC, &link_cache) < 0) {
199199
return 0;
200200
}
201201
link = rtnl_link_alloc();
@@ -209,7 +209,7 @@ int get_etherinfo(struct etherinfo_obj_data *data, nlQuery query)
209209
case NLQRY_ADDR4:
210210
case NLQRY_ADDR6:
211211
/* Extract IP address information */
212-
if( rtnl_addr_alloc_cache(*data->nlc, &addr_cache) < 0) {
212+
if( rtnl_addr_alloc_cache(get_nlc(), &addr_cache) < 0) {
213213
nl_cache_free(addr_cache);
214214
return 0;
215215
}

python-ethtool/etherinfo.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@
1919

2020
typedef enum {NLQRY_LINK, NLQRY_ADDR4, NLQRY_ADDR6} nlQuery; /**< Supported query types in the etherinfo code */
2121

22-
int get_etherinfo(struct etherinfo_obj_data *data, nlQuery query);
22+
int get_etherinfo(etherinfo_py *data, nlQuery query);
2323
void free_etherinfo(struct etherinfo *ptr);
2424

25-
int open_netlink(struct etherinfo_obj_data *);
26-
void close_netlink(struct etherinfo_obj_data *);
25+
int open_netlink(etherinfo_py *);
26+
struct nl_sock * get_nlc();
27+
void close_netlink(etherinfo_py *);
2728

2829
#endif

python-ethtool/etherinfo_obj.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ extern PyTypeObject ethtool_etherinfoIPv6Type;
4141
void _ethtool_etherinfo_dealloc(etherinfo_py *self)
4242
{
4343
if( self->data ) {
44-
close_netlink(self->data);
44+
close_netlink(self);
4545

4646
if( self->data->ethinfo ) {
4747
free_etherinfo(self->data->ethinfo);
@@ -151,11 +151,11 @@ PyObject *_ethtool_etherinfo_getter(etherinfo_py *self, PyObject *attr_o)
151151
return Py_INCREF(Py_None), Py_None;
152152
}
153153
} else if( strcmp(attr, "mac_address") == 0 ) {
154-
get_etherinfo(self->data, NLQRY_LINK);
154+
get_etherinfo(self, NLQRY_LINK);
155155
Py_INCREF(self->data->ethinfo->hwaddress);
156156
return self->data->ethinfo->hwaddress;
157157
} else if( strcmp(attr, "ipv4_address") == 0 ) {
158-
get_etherinfo(self->data, NLQRY_ADDR4);
158+
get_etherinfo(self, NLQRY_ADDR4);
159159
/* For compatiblity with old approach, return last IPv4 address: */
160160
py_addr = get_last_ipv4_address(self);
161161
if (py_addr) {
@@ -166,14 +166,14 @@ PyObject *_ethtool_etherinfo_getter(etherinfo_py *self, PyObject *attr_o)
166166
}
167167
Py_RETURN_NONE;
168168
} else if( strcmp(attr, "ipv4_netmask") == 0 ) {
169-
get_etherinfo(self->data, NLQRY_ADDR4);
169+
get_etherinfo(self, NLQRY_ADDR4);
170170
py_addr = get_last_ipv4_address(self);
171171
if (py_addr) {
172172
return PyInt_FromLong(py_addr->prefixlen);
173173
}
174174
return PyInt_FromLong(0);
175175
} else if( strcmp(attr, "ipv4_broadcast") == 0 ) {
176-
get_etherinfo(self->data, NLQRY_ADDR4);
176+
get_etherinfo(self, NLQRY_ADDR4);
177177
py_addr = get_last_ipv4_address(self);
178178
if (py_addr) {
179179
if (py_addr->ipv4_broadcast) {
@@ -215,14 +215,14 @@ PyObject *_ethtool_etherinfo_str(etherinfo_py *self)
215215
{
216216
PyObject *ret = NULL;
217217

218-
if( !self || !self->data || !self->data->nlc || !self->data->ethinfo ) {
218+
if( !self || !self->data || !self->data->ethinfo ) {
219219
PyErr_SetString(PyExc_AttributeError, "No data available");
220220
return NULL;
221221
}
222222

223-
get_etherinfo(self->data, NLQRY_LINK);
224-
get_etherinfo(self->data, NLQRY_ADDR4);
225-
get_etherinfo(self->data, NLQRY_ADDR6);
223+
get_etherinfo(self, NLQRY_LINK);
224+
get_etherinfo(self, NLQRY_ADDR4);
225+
get_etherinfo(self, NLQRY_ADDR6);
226226

227227
ret = PyString_FromFormat("Device %s:\n", self->data->ethinfo->device);
228228
if( self->data->ethinfo->hwaddress ) {
@@ -281,7 +281,7 @@ static PyObject *_ethtool_etherinfo_get_ipv4_addresses(etherinfo_py *self, PyObj
281281
return NULL;
282282
}
283283

284-
get_etherinfo(self->data, NLQRY_ADDR4);
284+
get_etherinfo(self, NLQRY_ADDR4);
285285

286286
/* Transfer ownership of reference: */
287287
ret = self->data->ethinfo->ipv4_addresses;
@@ -307,7 +307,7 @@ static PyObject *_ethtool_etherinfo_get_ipv6_addresses(etherinfo_py *self, PyObj
307307
return NULL;
308308
}
309309

310-
get_etherinfo(self->data, NLQRY_ADDR6);
310+
get_etherinfo(self, NLQRY_ADDR6);
311311

312312
/* Transfer ownership of reference: */
313313
ret = self->data->ethinfo->ipv6_addresses;

python-ethtool/etherinfo_struct.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,6 @@ extern PyTypeObject ethtool_netlink_ip_address_Type;
5656
*
5757
*/
5858
struct etherinfo_obj_data {
59-
struct nl_sock **nlc; /**< Contains NETLINK connection info (global) */
60-
unsigned int *nlc_users; /**< Resource counter for the NETLINK connection (global) */
61-
unsigned short nlc_active; /**< Is this instance using NETLINK? */
6259
struct etherinfo *ethinfo; /**< Contains info about our current interface */
6360
};
6461

@@ -69,6 +66,7 @@ struct etherinfo_obj_data {
6966
typedef struct {
7067
PyObject_HEAD
7168
struct etherinfo_obj_data *data; /* IPv4 and IPv6 address information, only one element used */
69+
unsigned short nlc_active; /**< Is this instance using NETLINK? */
7270
} etherinfo_py;
7371

7472

python-ethtool/ethtool.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@
3232
#include "etherinfo_obj.h"
3333
#include "etherinfo.h"
3434

35-
static struct nl_sock *nlconnection = NULL;
36-
unsigned int nlconnection_users = 0; /* How many NETLINK users are active? */
3735
extern PyTypeObject ethtool_etherinfoType;
3836

3937
#ifndef IFF_DYNAMIC
@@ -292,8 +290,6 @@ static PyObject *get_interfaces_info(PyObject *self __unused, PyObject *args) {
292290
*/
293291
objdata->ethinfo->device = strdup(fetch_devs[i]);
294292
objdata->ethinfo->index = -1;
295-
objdata->nlc = &nlconnection;
296-
objdata->nlc_users = &nlconnection_users;
297293

298294
/* Instantiate a new etherinfo object with the device information */
299295
ethinf_py = PyCObject_FromVoidPtr(objdata, NULL);

python-ethtool/netlink.c

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,85 +24,98 @@
2424
#include "etherinfo_struct.h"
2525

2626
pthread_mutex_t nlc_counter_mtx = PTHREAD_MUTEX_INITIALIZER;
27+
static struct nl_sock *nlconnection = NULL;
28+
static unsigned int nlconnection_users = 0; /* How many NETLINK users are active? */
2729

2830

2931
/**
3032
* Connects to the NETLINK interface. This will be called
3133
* for each etherinfo object being generated, and it will
3234
* keep a separate file descriptor open for each object
3335
*
34-
* @param data etherinfo_obj_data structure
36+
* @param ethi etherinfo_py structure (basically the "self" object)
3537
*
3638
* @return Returns 1 on success, otherwise 0.
3739
*/
38-
int open_netlink(struct etherinfo_obj_data *data)
40+
int open_netlink(etherinfo_py *ethi)
3941
{
40-
if( !data ) {
42+
if( !ethi ) {
4143
return 0;
4244
}
4345

4446
/* Reuse already established NETLINK connection, if a connection exists */
45-
if( *data->nlc ) {
47+
if( nlconnection ) {
4648
/* If this object has not used NETLINK earlier, tag it as a user */
47-
if( !data->nlc_active ) {
49+
if( !ethi->nlc_active ) {
4850
pthread_mutex_lock(&nlc_counter_mtx);
49-
(*data->nlc_users)++;
51+
nlconnection_users++;
5052
pthread_mutex_unlock(&nlc_counter_mtx);
5153
}
52-
data->nlc_active = 1;
54+
ethi->nlc_active = 1;
5355
return 1;
5456
}
5557

5658
/* No earlier connections exists, establish a new one */
57-
*data->nlc = nl_socket_alloc();
58-
nl_connect(*data->nlc, NETLINK_ROUTE);
59-
if( (*data->nlc != NULL) ) {
59+
nlconnection = nl_socket_alloc();
60+
nl_connect(nlconnection, NETLINK_ROUTE);
61+
if( (nlconnection != NULL) ) {
6062
/* Force O_CLOEXEC flag on the NETLINK socket */
61-
if( fcntl(nl_socket_get_fd(*data->nlc), F_SETFD, FD_CLOEXEC) == -1 ) {
63+
if( fcntl(nl_socket_get_fd(nlconnection), F_SETFD, FD_CLOEXEC) == -1 ) {
6264
fprintf(stderr,
6365
"**WARNING** Failed to set O_CLOEXEC on NETLINK socket: %s\n",
6466
strerror(errno));
6567
}
6668

6769
/* Tag this object as an active user */
6870
pthread_mutex_lock(&nlc_counter_mtx);
69-
(*data->nlc_users)++;
71+
nlconnection_users++;
7072
pthread_mutex_unlock(&nlc_counter_mtx);
71-
data->nlc_active = 1;
73+
ethi->nlc_active = 1;
7274
return 1;
7375
} else {
7476
return 0;
7577
}
7678
}
7779

7880

81+
/**
82+
* Return a reference to the global netlink connection
83+
*
84+
* @returns Returns a pointer to a NETLINK connection libnl functions can use
85+
*/
86+
struct nl_sock * get_nlc()
87+
{
88+
assert(nlconnection);
89+
return nlconnection;
90+
}
91+
7992
/**
8093
* Closes the NETLINK connection. This should be called automatically whenever
8194
* the corresponding etherinfo object is deleted.
8295
*
83-
* @param ptr Pointer to the pointer of struct nl_handle, which contains the NETLINK connection
96+
* @param ethi etherinfo_py structure (basically the "self" object)
8497
*/
85-
void close_netlink(struct etherinfo_obj_data *data)
98+
void close_netlink(etherinfo_py *ethi)
8699
{
87-
if( !data || !(*data->nlc) ) {
100+
if( !ethi || !nlconnection ) {
88101
return;
89102
}
90103

91104
/* Untag this object as a NETLINK user */
92-
data->nlc_active = 0;
105+
ethi->nlc_active = 0;
93106
pthread_mutex_lock(&nlc_counter_mtx);
94-
(*data->nlc_users)--;
107+
nlconnection_users--;
95108
pthread_mutex_unlock(&nlc_counter_mtx);
96109

97110
/* Don't close the connection if there are more users */
98-
if( *data->nlc_users > 0) {
111+
if( nlconnection_users > 0) {
99112
return;
100113
}
101114

102115
/* Close NETLINK connection */
103-
nl_close(*data->nlc);
104-
nl_socket_free(*data->nlc);
105-
*data->nlc = NULL;
116+
nl_close(nlconnection);
117+
nl_socket_free(nlconnection);
118+
nlconnection = NULL;
106119
}
107120

108121
/*

0 commit comments

Comments
 (0)