From 052d432d9be11a0b6b69826b540b03d1b80904a4 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 13 Sep 2013 18:46:15 +0200 Subject: Re-implement the IPv6 support This uses the same approach as IPv4 uses. Signed-off-by: David Sommerseth --- python-ethtool/etherinfo.c | 32 ++++++++++-- python-ethtool/etherinfo_obj.c | 57 +++++++++++++++++++-- python-ethtool/etherinfo_struct.h | 10 ++++ python-ethtool/ethtool.c | 4 +- python-ethtool/netlink-address.c | 104 ++++++++++++++++++++++++++++++++++++-- 5 files changed, 194 insertions(+), 13 deletions(-) diff --git a/python-ethtool/etherinfo.c b/python-ethtool/etherinfo.c index 538bcb5..c8bbb0f 100644 --- a/python-ethtool/etherinfo.c +++ b/python-ethtool/etherinfo.c @@ -78,6 +78,7 @@ void free_etherinfo(struct etherinfo *ptr) free(ptr->hwaddress); } Py_XDECREF(ptr->ipv4_addresses); + Py_XDECREF(ptr->ipv6_addresses); free(ptr); } @@ -117,6 +118,7 @@ append_object_for_netlink_address(struct etherinfo *ethi, assert(ethi); assert(ethi->ipv4_addresses); + assert(ethi->ipv6_addresses); assert(addr); addr_obj = make_python_address_from_rtnl_addr(addr); @@ -124,11 +126,24 @@ append_object_for_netlink_address(struct etherinfo *ethi, return -1; } - if (-1 == PyList_Append(ethi->ipv4_addresses, addr_obj)) { - Py_DECREF(addr_obj); - return -1; - } + switch (rtnl_addr_get_family(addr)) { + case AF_INET: + if (-1 == PyList_Append(ethi->ipv4_addresses, addr_obj)) { + Py_DECREF(addr_obj); + return -1; + } + break; + + case AF_INET6: + if (-1 == PyList_Append(ethi->ipv6_addresses, addr_obj)) { + Py_DECREF(addr_obj); + return -1; + } + break; + default: + return -1; + } Py_DECREF(addr_obj); /* Success */ @@ -153,6 +168,7 @@ static void callback_nl_address(struct nl_object *obj, void *arg) switch( rtnl_addr_get_family(rtaddr) ) { case AF_INET: + case AF_INET6: append_object_for_netlink_address(ethi, rtaddr); return; default: @@ -168,7 +184,6 @@ static void callback_nl_address(struct nl_object *obj, void *arg) * */ - /** * Query NETLINK for ethernet configuration * @@ -252,6 +267,13 @@ int get_etherinfo(struct etherinfo_obj_data *data, nlQuery query) return 0; } + /* Likewise for IPv6 addresses: */ + Py_XDECREF(ethinf->ipv6_addresses); + ethinf->ipv6_addresses = PyList_New(0); + if (!ethinf->ipv6_addresses) { + return 0; + } + /* Retrieve all address information */ nl_cache_foreach_filter(addr_cache, OBJ_CAST(addr), callback_nl_address, ethinf); rtnl_addr_put(addr); diff --git a/python-ethtool/etherinfo_obj.c b/python-ethtool/etherinfo_obj.c index c6ebacc..1a62fb8 100644 --- a/python-ethtool/etherinfo_obj.c +++ b/python-ethtool/etherinfo_obj.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 Red Hat Inc. + * Copyright (C) 2009-2013 Red Hat Inc. * * David Sommerseth * @@ -27,6 +27,7 @@ #include "structmember.h" #include +#include #include "etherinfo_struct.h" #include "etherinfo.h" @@ -242,11 +243,32 @@ PyObject *_ethtool_etherinfo_str(etherinfo_py *self) } } + if( self->data->ethinfo->ipv6_addresses ) { + Py_ssize_t i; + for (i = 0; i < PyList_Size(self->data->ethinfo->ipv6_addresses); i++) { + PyNetlinkIPv6Address *py_addr = (PyNetlinkIPv6Address *)PyList_GetItem(self->data->ethinfo->ipv6_addresses, i); + PyObject *tmp = PyString_FromFormat("\tIPv6 address: ["); + PyString_Concat(&tmp, py_addr->ipv6_scope); + PyString_ConcatAndDel(&tmp, PyString_FromString("] ")); + PyString_Concat(&tmp, py_addr->ipv6_address); + PyString_ConcatAndDel(&tmp, PyString_FromFormat("/%d", py_addr->ipv6_netmask)); + PyString_ConcatAndDel(&tmp, PyString_FromString("\n")); + PyString_ConcatAndDel(&ret, tmp); + } + } + return ret; } -static PyObject * -_ethtool_etherinfo_get_ipv4_addresses(etherinfo_py *self, PyObject *notused) { +/** + * Returns a tuple list of configured IPv4 addresses + * + * @param self + * @param notused + * + * @return Returns a Python tuple list of NetlinkIP4Address objects + */ +static PyObject *_ethtool_etherinfo_get_ipv4_addresses(etherinfo_py *self, PyObject *notused) { PyObject *ret; if( !self || !self->data ) { @@ -264,6 +286,32 @@ _ethtool_etherinfo_get_ipv4_addresses(etherinfo_py *self, PyObject *notused) { } +/** + * Returns a tuple list of configured IPv4 addresses + * + * @param self + * @param notused + * + * @return Returns a Python tuple list of NetlinkIP6Address objects + */ +static PyObject *_ethtool_etherinfo_get_ipv6_addresses(etherinfo_py *self, PyObject *notused) { + PyObject *ret; + + if( !self || !self->data ) { + PyErr_SetString(PyExc_AttributeError, "No data available"); + return NULL; + } + + get_etherinfo(self->data, NLQRY_ADDR); + + /* Transfer ownership of reference: */ + ret = self->data->ethinfo->ipv6_addresses; + self->data->ethinfo->ipv6_addresses = NULL; + + return ret; +} + + /** * Defines all available methods in the ethtool.etherinfo class * @@ -271,6 +319,9 @@ _ethtool_etherinfo_get_ipv4_addresses(etherinfo_py *self, PyObject *notused) { static PyMethodDef _ethtool_etherinfo_methods[] = { {"get_ipv4_addresses", (PyCFunction)_ethtool_etherinfo_get_ipv4_addresses, METH_NOARGS, "Retrieve configured IPv4 addresses. Returns a list of NetlinkIP4Address objects"}, + {"get_ipv6_addresses", (PyCFunction)_ethtool_etherinfo_get_ipv6_addresses, METH_NOARGS, + "Retrieve configured IPv6 addresses. Returns a list of NetlinkIP6Address objects"}, + {NULL} /**< No methods defined */ }; diff --git a/python-ethtool/etherinfo_struct.h b/python-ethtool/etherinfo_struct.h index 6ae4d78..dff1105 100644 --- a/python-ethtool/etherinfo_struct.h +++ b/python-ethtool/etherinfo_struct.h @@ -35,6 +35,7 @@ struct etherinfo { int index; /**< NETLINK index reference */ char *hwaddress; /**< HW address / MAC address of device */ PyObject *ipv4_addresses; /**< list of PyNetlinkIPv4Address instances */ + PyObject *ipv6_addresses; /**< list of PyNetlinkIPv6Addresses instances */ }; /* Python object containing data baked from a (struct rtnl_addr) */ @@ -46,6 +47,15 @@ typedef struct PyNetlinkIPv4Address { } PyNetlinkIPv4Address; extern PyTypeObject ethtool_netlink_ipv4_address_Type; +/* Python object containing data baked from a (struct rtnl_addr) */ +typedef struct PyNetlinkIPv6Address { + PyObject_HEAD + PyObject *ipv6_address; /**< string: Configured IPv6 address */ + int ipv6_netmask; /**< int: Configured IPv6 prefix */ + PyObject *ipv6_scope; /**< string: IPv6 address scope */ +} PyNetlinkIPv6Address; +extern PyTypeObject ethtool_netlink_ipv6_address_Type; + /** * Contains the internal data structure of the * ethtool.etherinfo object. diff --git a/python-ethtool/ethtool.c b/python-ethtool/ethtool.c index 4701308..e58d5f9 100644 --- a/python-ethtool/ethtool.c +++ b/python-ethtool/ethtool.c @@ -962,7 +962,9 @@ PyMODINIT_FUNC initethtool(void) Py_INCREF(ðtool_etherinfoType); PyModule_AddObject(m, "etherinfo", (PyObject *)ðtool_etherinfoType); - // Prepare the ethtool IPv4 address types + // Prepare the ethtool IPv6 and IPv4 address types + if (PyType_Ready(ðtool_netlink_ipv6_address_Type) < 0) + return; if (PyType_Ready(ðtool_netlink_ipv4_address_Type)) return; diff --git a/python-ethtool/netlink-address.c b/python-ethtool/netlink-address.c index 35c0849..95c1c86 100644 --- a/python-ethtool/netlink-address.c +++ b/python-ethtool/netlink-address.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012 Red Hat Inc. + * Copyright (C) 2011 - 2013 Red Hat Inc. * * David Malcolm * @@ -20,9 +20,106 @@ #include #include #include +#include #include "etherinfo_struct.h" #include "etherinfo.h" +/* IPv6 Addresses: */ +static PyObject * +PyNetlinkIPv6Address_from_rtnl_addr(struct rtnl_addr *addr) +{ + PyNetlinkIPv6Address *py_obj; + char buf[INET6_ADDRSTRLEN+1]; + + py_obj = PyObject_New(PyNetlinkIPv6Address, + ðtool_netlink_ipv6_address_Type); + if (!py_obj) { + return NULL; + } + + /* Set ipv6_address: */ + memset(&buf, 0, sizeof(buf)); + if (!inet_ntop(AF_INET6, nl_addr_get_binary_addr(rtnl_addr_get_local(addr)), + buf, sizeof(buf))) { + PyErr_SetFromErrno(PyExc_RuntimeError); + goto error; + } + py_obj->ipv6_address = PyString_FromString(buf); + if (!py_obj->ipv6_address) { + goto error; + } + + /* Set ipv6_netmask: */ + py_obj->ipv6_netmask = rtnl_addr_get_prefixlen(addr); + + + /* Set ipv6_scope: */ + memset(&buf, 0, sizeof(buf)); + rtnl_scope2str(rtnl_addr_get_scope(addr), buf, sizeof(buf)); + py_obj->ipv6_scope = PyString_FromString(buf); + + return (PyObject*)py_obj; + + error: + Py_DECREF(py_obj); + return NULL; +} + +static void +netlink_ipv6_address_dealloc(PyNetlinkIPv6Address *obj) +{ + Py_DECREF(obj->ipv6_address); + Py_DECREF(obj->ipv6_scope); + + /* We can call PyObject_Del directly rather than calling through + tp_free since the type is not subtypable (Py_TPFLAGS_BASETYPE is + not set): */ + PyObject_Del(obj); +} + +static PyObject* +netlink_ipv6_address_repr(PyNetlinkIPv6Address *obj) +{ + PyObject *result = PyString_FromString("ethtool.NetlinkIPv6Address(address='"); + PyString_Concat(&result, obj->ipv6_address); + PyString_ConcatAndDel(&result, + PyString_FromFormat("/%d', scope=", + obj->ipv6_netmask)); + PyString_Concat(&result, obj->ipv6_scope); + PyString_ConcatAndDel(&result, PyString_FromString(")")); + return result; +} + +static PyMemberDef _ethtool_netlink_ipv6_address_members[] = { + {"address", + T_OBJECT_EX, + offsetof(PyNetlinkIPv6Address, ipv6_address), + 0, + NULL}, + {"netmask", + T_INT, + offsetof(PyNetlinkIPv6Address, ipv6_netmask), + 0, + NULL}, + {"scope", + T_OBJECT_EX, + offsetof(PyNetlinkIPv6Address, ipv6_scope), + 0, + NULL}, + {NULL} /* End of member list */ +}; + +PyTypeObject ethtool_netlink_ipv6_address_Type = { + PyVarObject_HEAD_INIT(0, 0) + .tp_name = "ethtool.NetlinkIPv6Address", + .tp_basicsize = sizeof(PyNetlinkIPv6Address), + .tp_dealloc = (destructor)netlink_ipv6_address_dealloc, + .tp_repr = (reprfunc)netlink_ipv6_address_repr, + .tp_members = _ethtool_netlink_ipv6_address_members, +}; + + + /* IPv4 Addresses: */ static PyObject * PyNetlinkIPv4Address_from_rtnl_addr(struct rtnl_addr *addr) @@ -143,9 +240,8 @@ make_python_address_from_rtnl_addr(struct rtnl_addr *addr) case AF_INET: return PyNetlinkIPv4Address_from_rtnl_addr(addr); - /* - For now, we just support IPv4 addresses. - */ + case AF_INET6: + return PyNetlinkIPv6Address_from_rtnl_addr(addr); default: return PyErr_SetFromErrno(PyExc_RuntimeError); -- cgit