Skip to content

Commit 052d432

Browse files
author
David Sommerseth
committed
Re-implement the IPv6 support
This uses the same approach as IPv4 uses. Signed-off-by: David Sommerseth <davids@redhat.com>
1 parent abab733 commit 052d432

File tree

5 files changed

+194
-13
lines changed

5 files changed

+194
-13
lines changed

python-ethtool/etherinfo.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ void free_etherinfo(struct etherinfo *ptr)
7878
free(ptr->hwaddress);
7979
}
8080
Py_XDECREF(ptr->ipv4_addresses);
81+
Py_XDECREF(ptr->ipv6_addresses);
8182

8283
free(ptr);
8384
}
@@ -117,18 +118,32 @@ append_object_for_netlink_address(struct etherinfo *ethi,
117118

118119
assert(ethi);
119120
assert(ethi->ipv4_addresses);
121+
assert(ethi->ipv6_addresses);
120122
assert(addr);
121123

122124
addr_obj = make_python_address_from_rtnl_addr(addr);
123125
if (!addr_obj) {
124126
return -1;
125127
}
126128

127-
if (-1 == PyList_Append(ethi->ipv4_addresses, addr_obj)) {
128-
Py_DECREF(addr_obj);
129-
return -1;
130-
}
129+
switch (rtnl_addr_get_family(addr)) {
130+
case AF_INET:
131+
if (-1 == PyList_Append(ethi->ipv4_addresses, addr_obj)) {
132+
Py_DECREF(addr_obj);
133+
return -1;
134+
}
135+
break;
136+
137+
case AF_INET6:
138+
if (-1 == PyList_Append(ethi->ipv6_addresses, addr_obj)) {
139+
Py_DECREF(addr_obj);
140+
return -1;
141+
}
142+
break;
131143

144+
default:
145+
return -1;
146+
}
132147
Py_DECREF(addr_obj);
133148

134149
/* Success */
@@ -153,6 +168,7 @@ static void callback_nl_address(struct nl_object *obj, void *arg)
153168

154169
switch( rtnl_addr_get_family(rtaddr) ) {
155170
case AF_INET:
171+
case AF_INET6:
156172
append_object_for_netlink_address(ethi, rtaddr);
157173
return;
158174
default:
@@ -168,7 +184,6 @@ static void callback_nl_address(struct nl_object *obj, void *arg)
168184
*
169185
*/
170186

171-
172187
/**
173188
* Query NETLINK for ethernet configuration
174189
*
@@ -252,6 +267,13 @@ int get_etherinfo(struct etherinfo_obj_data *data, nlQuery query)
252267
return 0;
253268
}
254269

270+
/* Likewise for IPv6 addresses: */
271+
Py_XDECREF(ethinf->ipv6_addresses);
272+
ethinf->ipv6_addresses = PyList_New(0);
273+
if (!ethinf->ipv6_addresses) {
274+
return 0;
275+
}
276+
255277
/* Retrieve all address information */
256278
nl_cache_foreach_filter(addr_cache, OBJ_CAST(addr), callback_nl_address, ethinf);
257279
rtnl_addr_put(addr);

python-ethtool/etherinfo_obj.c

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2009-2011 Red Hat Inc.
2+
* Copyright (C) 2009-2013 Red Hat Inc.
33
*
44
* David Sommerseth <davids@redhat.com>
55
*
@@ -27,6 +27,7 @@
2727
#include "structmember.h"
2828

2929
#include <netlink/route/rtnl.h>
30+
#include <netlink/route/addr.h>
3031
#include "etherinfo_struct.h"
3132
#include "etherinfo.h"
3233

@@ -242,11 +243,32 @@ PyObject *_ethtool_etherinfo_str(etherinfo_py *self)
242243
}
243244
}
244245

246+
if( self->data->ethinfo->ipv6_addresses ) {
247+
Py_ssize_t i;
248+
for (i = 0; i < PyList_Size(self->data->ethinfo->ipv6_addresses); i++) {
249+
PyNetlinkIPv6Address *py_addr = (PyNetlinkIPv6Address *)PyList_GetItem(self->data->ethinfo->ipv6_addresses, i);
250+
PyObject *tmp = PyString_FromFormat("\tIPv6 address: [");
251+
PyString_Concat(&tmp, py_addr->ipv6_scope);
252+
PyString_ConcatAndDel(&tmp, PyString_FromString("] "));
253+
PyString_Concat(&tmp, py_addr->ipv6_address);
254+
PyString_ConcatAndDel(&tmp, PyString_FromFormat("/%d", py_addr->ipv6_netmask));
255+
PyString_ConcatAndDel(&tmp, PyString_FromString("\n"));
256+
PyString_ConcatAndDel(&ret, tmp);
257+
}
258+
}
259+
245260
return ret;
246261
}
247262

248-
static PyObject *
249-
_ethtool_etherinfo_get_ipv4_addresses(etherinfo_py *self, PyObject *notused) {
263+
/**
264+
* Returns a tuple list of configured IPv4 addresses
265+
*
266+
* @param self
267+
* @param notused
268+
*
269+
* @return Returns a Python tuple list of NetlinkIP4Address objects
270+
*/
271+
static PyObject *_ethtool_etherinfo_get_ipv4_addresses(etherinfo_py *self, PyObject *notused) {
250272
PyObject *ret;
251273

252274
if( !self || !self->data ) {
@@ -264,13 +286,42 @@ _ethtool_etherinfo_get_ipv4_addresses(etherinfo_py *self, PyObject *notused) {
264286
}
265287

266288

289+
/**
290+
* Returns a tuple list of configured IPv4 addresses
291+
*
292+
* @param self
293+
* @param notused
294+
*
295+
* @return Returns a Python tuple list of NetlinkIP6Address objects
296+
*/
297+
static PyObject *_ethtool_etherinfo_get_ipv6_addresses(etherinfo_py *self, PyObject *notused) {
298+
PyObject *ret;
299+
300+
if( !self || !self->data ) {
301+
PyErr_SetString(PyExc_AttributeError, "No data available");
302+
return NULL;
303+
}
304+
305+
get_etherinfo(self->data, NLQRY_ADDR);
306+
307+
/* Transfer ownership of reference: */
308+
ret = self->data->ethinfo->ipv6_addresses;
309+
self->data->ethinfo->ipv6_addresses = NULL;
310+
311+
return ret;
312+
}
313+
314+
267315
/**
268316
* Defines all available methods in the ethtool.etherinfo class
269317
*
270318
*/
271319
static PyMethodDef _ethtool_etherinfo_methods[] = {
272320
{"get_ipv4_addresses", (PyCFunction)_ethtool_etherinfo_get_ipv4_addresses, METH_NOARGS,
273321
"Retrieve configured IPv4 addresses. Returns a list of NetlinkIP4Address objects"},
322+
{"get_ipv6_addresses", (PyCFunction)_ethtool_etherinfo_get_ipv6_addresses, METH_NOARGS,
323+
"Retrieve configured IPv6 addresses. Returns a list of NetlinkIP6Address objects"},
324+
274325
{NULL} /**< No methods defined */
275326
};
276327

python-ethtool/etherinfo_struct.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ struct etherinfo {
3535
int index; /**< NETLINK index reference */
3636
char *hwaddress; /**< HW address / MAC address of device */
3737
PyObject *ipv4_addresses; /**< list of PyNetlinkIPv4Address instances */
38+
PyObject *ipv6_addresses; /**< list of PyNetlinkIPv6Addresses instances */
3839
};
3940

4041
/* Python object containing data baked from a (struct rtnl_addr) */
@@ -46,6 +47,15 @@ typedef struct PyNetlinkIPv4Address {
4647
} PyNetlinkIPv4Address;
4748
extern PyTypeObject ethtool_netlink_ipv4_address_Type;
4849

50+
/* Python object containing data baked from a (struct rtnl_addr) */
51+
typedef struct PyNetlinkIPv6Address {
52+
PyObject_HEAD
53+
PyObject *ipv6_address; /**< string: Configured IPv6 address */
54+
int ipv6_netmask; /**< int: Configured IPv6 prefix */
55+
PyObject *ipv6_scope; /**< string: IPv6 address scope */
56+
} PyNetlinkIPv6Address;
57+
extern PyTypeObject ethtool_netlink_ipv6_address_Type;
58+
4959
/**
5060
* Contains the internal data structure of the
5161
* ethtool.etherinfo object.

python-ethtool/ethtool.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -962,7 +962,9 @@ PyMODINIT_FUNC initethtool(void)
962962
Py_INCREF(&ethtool_etherinfoType);
963963
PyModule_AddObject(m, "etherinfo", (PyObject *)&ethtool_etherinfoType);
964964

965-
// Prepare the ethtool IPv4 address types
965+
// Prepare the ethtool IPv6 and IPv4 address types
966+
if (PyType_Ready(&ethtool_netlink_ipv6_address_Type) < 0)
967+
return;
966968
if (PyType_Ready(&ethtool_netlink_ipv4_address_Type))
967969
return;
968970

python-ethtool/netlink-address.c

Lines changed: 100 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2011, 2012 Red Hat Inc.
2+
* Copyright (C) 2011 - 2013 Red Hat Inc.
33
*
44
* David Malcolm <dmalcolm@redhat.com>
55
*
@@ -20,9 +20,106 @@
2020
#include <arpa/inet.h>
2121
#include <netlink/addr.h>
2222
#include <netlink/route/addr.h>
23+
#include <netlink/route/rtnl.h>
2324
#include "etherinfo_struct.h"
2425
#include "etherinfo.h"
2526

27+
/* IPv6 Addresses: */
28+
static PyObject *
29+
PyNetlinkIPv6Address_from_rtnl_addr(struct rtnl_addr *addr)
30+
{
31+
PyNetlinkIPv6Address *py_obj;
32+
char buf[INET6_ADDRSTRLEN+1];
33+
34+
py_obj = PyObject_New(PyNetlinkIPv6Address,
35+
&ethtool_netlink_ipv6_address_Type);
36+
if (!py_obj) {
37+
return NULL;
38+
}
39+
40+
/* Set ipv6_address: */
41+
memset(&buf, 0, sizeof(buf));
42+
if (!inet_ntop(AF_INET6, nl_addr_get_binary_addr(rtnl_addr_get_local(addr)),
43+
buf, sizeof(buf))) {
44+
PyErr_SetFromErrno(PyExc_RuntimeError);
45+
goto error;
46+
}
47+
py_obj->ipv6_address = PyString_FromString(buf);
48+
if (!py_obj->ipv6_address) {
49+
goto error;
50+
}
51+
52+
/* Set ipv6_netmask: */
53+
py_obj->ipv6_netmask = rtnl_addr_get_prefixlen(addr);
54+
55+
56+
/* Set ipv6_scope: */
57+
memset(&buf, 0, sizeof(buf));
58+
rtnl_scope2str(rtnl_addr_get_scope(addr), buf, sizeof(buf));
59+
py_obj->ipv6_scope = PyString_FromString(buf);
60+
61+
return (PyObject*)py_obj;
62+
63+
error:
64+
Py_DECREF(py_obj);
65+
return NULL;
66+
}
67+
68+
static void
69+
netlink_ipv6_address_dealloc(PyNetlinkIPv6Address *obj)
70+
{
71+
Py_DECREF(obj->ipv6_address);
72+
Py_DECREF(obj->ipv6_scope);
73+
74+
/* We can call PyObject_Del directly rather than calling through
75+
tp_free since the type is not subtypable (Py_TPFLAGS_BASETYPE is
76+
not set): */
77+
PyObject_Del(obj);
78+
}
79+
80+
static PyObject*
81+
netlink_ipv6_address_repr(PyNetlinkIPv6Address *obj)
82+
{
83+
PyObject *result = PyString_FromString("ethtool.NetlinkIPv6Address(address='");
84+
PyString_Concat(&result, obj->ipv6_address);
85+
PyString_ConcatAndDel(&result,
86+
PyString_FromFormat("/%d', scope=",
87+
obj->ipv6_netmask));
88+
PyString_Concat(&result, obj->ipv6_scope);
89+
PyString_ConcatAndDel(&result, PyString_FromString(")"));
90+
return result;
91+
}
92+
93+
static PyMemberDef _ethtool_netlink_ipv6_address_members[] = {
94+
{"address",
95+
T_OBJECT_EX,
96+
offsetof(PyNetlinkIPv6Address, ipv6_address),
97+
0,
98+
NULL},
99+
{"netmask",
100+
T_INT,
101+
offsetof(PyNetlinkIPv6Address, ipv6_netmask),
102+
0,
103+
NULL},
104+
{"scope",
105+
T_OBJECT_EX,
106+
offsetof(PyNetlinkIPv6Address, ipv6_scope),
107+
0,
108+
NULL},
109+
{NULL} /* End of member list */
110+
};
111+
112+
PyTypeObject ethtool_netlink_ipv6_address_Type = {
113+
PyVarObject_HEAD_INIT(0, 0)
114+
.tp_name = "ethtool.NetlinkIPv6Address",
115+
.tp_basicsize = sizeof(PyNetlinkIPv6Address),
116+
.tp_dealloc = (destructor)netlink_ipv6_address_dealloc,
117+
.tp_repr = (reprfunc)netlink_ipv6_address_repr,
118+
.tp_members = _ethtool_netlink_ipv6_address_members,
119+
};
120+
121+
122+
26123
/* IPv4 Addresses: */
27124
static PyObject *
28125
PyNetlinkIPv4Address_from_rtnl_addr(struct rtnl_addr *addr)
@@ -143,9 +240,8 @@ make_python_address_from_rtnl_addr(struct rtnl_addr *addr)
143240
case AF_INET:
144241
return PyNetlinkIPv4Address_from_rtnl_addr(addr);
145242

146-
/*
147-
For now, we just support IPv4 addresses.
148-
*/
243+
case AF_INET6:
244+
return PyNetlinkIPv6Address_from_rtnl_addr(addr);
149245

150246
default:
151247
return PyErr_SetFromErrno(PyExc_RuntimeError);

0 commit comments

Comments
 (0)