Skip to content

Commit 0be405b

Browse files
author
David Sommerseth
committed
First cut at a python etherinfo class in C. Does nothing useful yet.
1 parent e957168 commit 0be405b

File tree

6 files changed

+264
-4
lines changed

6 files changed

+264
-4
lines changed

python-ethtool/etherinfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct etherinfo {
3131
};
3232

3333
struct etherinfo *get_etherinfo();
34+
void free_etherinfo(struct etherinfo *ptr);
3435
void dump_etherinfo(FILE *, struct etherinfo *);
3536

3637
#endif

python-ethtool/etherinfo_obj.c

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/**
2+
* @file etherinfo_obj.c
3+
* @author David Sommerseth <davids@redhat.com>
4+
* @date Fri Sep 4 18:41:28 2009
5+
*
6+
* @brief Python ethtool.etherinfo class functions.
7+
*
8+
*/
9+
10+
#include <Python.h>
11+
#include "structmember.h"
12+
#include "etherinfo.h"
13+
#include "etherinfo_struct.h"
14+
15+
16+
/**
17+
* ethtool.etherinfo deallocator - cleans up when a object is deleted
18+
*
19+
* @param self etherinfo_py object structure
20+
*/
21+
void _ethtool_etherinfo_dealloc(etherinfo_py *self)
22+
{
23+
if( self->info ) {
24+
free_etherinfo(self->info);
25+
}
26+
self->ob_type->tp_free((PyObject*)self);
27+
}
28+
29+
30+
/**
31+
* ethtool.etherinfo function, creating a new etherinfo object
32+
*
33+
* @param type
34+
* @param args
35+
* @param kwds
36+
*
37+
* @return Returns in PyObject with the new object on success, otherwise NULL
38+
*/
39+
PyObject *_ethtool_etherinfo_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
40+
{
41+
etherinfo_py *self;
42+
43+
self = (etherinfo_py *)type->tp_alloc(type, 0);
44+
if (self != NULL) {
45+
}
46+
return (PyObject *)self;
47+
}
48+
49+
50+
/**
51+
* ethtool.etherinfo init (constructor) method. Makes sure the object is initialised correctly.
52+
*
53+
* @param self
54+
* @param args
55+
* @param kwds
56+
*
57+
* @return Returns 0 on success.
58+
*/
59+
int _ethtool_etherinfo_init(etherinfo_py *self, PyObject *args, PyObject *kwds)
60+
{
61+
self->info = (struct etherinfo *) malloc(sizeof(struct etherinfo)+2);
62+
memset(self->info, 0, sizeof(struct etherinfo)+2);
63+
self->info->device = strdup("test");
64+
return 0;
65+
}
66+
67+
68+
/**
69+
* ethtool.etherinfo function for retrieving data from a Python object.
70+
*
71+
* @param self
72+
* @param attr_o contains the object member request (which element to return)
73+
*
74+
* @return Returns a PyObject with the value requested on success, otherwise NULL
75+
*/
76+
PyObject *_ethtool_etherinfo_getter(etherinfo_py *self, PyObject *attr_o)
77+
{
78+
char *attr = PyString_AsString(attr_o);
79+
80+
if( !self || !self->info ) {
81+
PyErr_SetString(PyExc_AttributeError, "No data available");
82+
return NULL;
83+
}
84+
85+
if( strcmp(attr, "device") == 0 ) {
86+
return PyString_FromString(self->info->device);
87+
} else if( strcmp(attr, "mac_address") == 0 ) {
88+
return PyString_FromString(self->info->hwaddress);
89+
} else if( strcmp(attr, "ipv4_address") == 0 ) {
90+
return PyString_FromString(self->info->ipv4_address);
91+
} else if( strcmp(attr, "ipv4_netmask") == 0 ) {
92+
return PyInt_FromLong(self->info->ipv4_netmask);
93+
} else if( strcmp(attr, "ipv4_broadcast") == 0 ) {
94+
return PyString_FromString(self->info->ipv4_broadcast);
95+
} else if( strcmp(attr, "ipv6_address") == 0 ) {
96+
return PyString_FromString(self->info->ipv6_address);
97+
} else if( strcmp(attr, "ipv6_netmask") == 0 ) {
98+
return PyInt_FromLong(self->info->ipv6_netmask);
99+
}
100+
PyErr_SetString(PyExc_AttributeError, "Unknown attribute name");
101+
return NULL;
102+
}
103+
104+
105+
/**
106+
* ethtool.etherinfo function for setting a value to a object member. This feature is
107+
* disabled by always returning -1, as the values are read-only by the user.
108+
*
109+
* @param self
110+
* @param attr_o
111+
* @param val_o
112+
*
113+
* @return Returns always -1 (failure).
114+
*/
115+
int _ethtool_etherinfo_setter(etherinfo_py *self, PyObject *attr_o, PyObject *val_o)
116+
{
117+
PyErr_SetString(PyExc_AttributeError, "etherinfo member values are read-only.");
118+
return -1;
119+
}
120+
121+

python-ethtool/etherinfo_obj.h

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/**
2+
* @file etherinfo_obj.c
3+
* @author David Sommerseth <davids@redhat.com>
4+
* @date Fri Sep 4 18:41:28 2009
5+
*
6+
* @brief Python ethtool.etherinfo class functions (header file).
7+
*
8+
*/
9+
10+
#ifndef __ETHERINFO_OBJ_H
11+
#define __ETHERINFO_OBJ_H
12+
13+
#include <Python.h>
14+
#include "structmember.h"
15+
#include "etherinfo.h"
16+
#include "etherinfo_struct.h"
17+
18+
void _ethtool_etherinfo_dealloc(etherinfo_py *);
19+
PyObject *_ethtool_etherinfo_new(PyTypeObject *, PyObject *, PyObject *);
20+
int _ethtool_etherinfo_init(etherinfo_py *, PyObject *, PyObject *);
21+
PyObject *_ethtool_etherinfo_getter(etherinfo_py *, PyObject *);
22+
int _ethtool_etherinfo_setter(etherinfo_py *, PyObject *, PyObject *);
23+
24+
/**
25+
* This is required by Python, which lists all accessible methods
26+
* in the object. But no methods are provided.
27+
*
28+
*/
29+
static PyMethodDef _ethtool_etherinfo_methods[] = {
30+
{NULL} /**< No methods defined */
31+
};
32+
33+
/**
34+
* Defines all accessible object members
35+
*
36+
*/
37+
static PyMemberDef _ethtool_etherinfo_members[] = {
38+
{"device", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
39+
"Device name of the interface"},
40+
{"mac_address", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
41+
"MAC address / hardware address of the interface"},
42+
{"ipv4_address", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
43+
"IPv4 address"},
44+
{"ipv4_netmask", T_INT, offsetof(etherinfo_py, info), 0,
45+
"IPv4 netmask in bits"},
46+
{"ipv4_broadcast", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
47+
"IPv4 broadcast address"},
48+
{"ipv6_address", T_OBJECT_EX, offsetof(etherinfo_py, info), 0,
49+
"IPv6 address"},
50+
{"ipv6_netmask", T_INT, offsetof(etherinfo_py, info), 0,
51+
"IPv6 netmask in bits"},
52+
{NULL} /* End of member list */
53+
};
54+
55+
/**
56+
* Definition of the functions a Python class/object requires.
57+
*
58+
*/
59+
PyTypeObject ethtool_etherinfoType = {
60+
PyObject_HEAD_INIT(NULL)
61+
0, /*ob_size*/
62+
"ethtool.etherinfo", /*tp_name*/
63+
sizeof(etherinfo_py), /*tp_basicsize*/
64+
0, /*tp_itemsize*/
65+
(destructor)_ethtool_etherinfo_dealloc,/*tp_dealloc*/
66+
0, /*tp_print*/
67+
0, /*tp_getattr*/
68+
0, /*tp_setattr*/
69+
0, /*tp_compare*/
70+
0, /*tp_repr*/
71+
0, /*tp_as_number*/
72+
0, /*tp_as_sequence*/
73+
0, /*tp_as_mapping*/
74+
0, /*tp_hash */
75+
0, /*tp_call*/
76+
0, /*tp_str*/
77+
(getattrofunc)_ethtool_etherinfo_getter, /*tp_getattro*/
78+
(setattrofunc)_ethtool_etherinfo_setter, /*tp_setattro*/
79+
0, /*tp_as_buffer*/
80+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
81+
"Contains information about a specific ethernet device", /* tp_doc */
82+
0, /* tp_traverse */
83+
0, /* tp_clear */
84+
0, /* tp_richcompare */
85+
0, /* tp_weaklistoffset */
86+
0, /* tp_iter */
87+
0, /* tp_iternext */
88+
_ethtool_etherinfo_methods, /* tp_methods */
89+
_ethtool_etherinfo_members, /* tp_members */
90+
0, /* tp_getset */
91+
0, /* tp_base */
92+
0, /* tp_dict */
93+
0, /* tp_descr_get */
94+
0, /* tp_descr_set */
95+
0, /* tp_dictoffset */
96+
(initproc)_ethtool_etherinfo_init, /* tp_init */
97+
0, /* tp_alloc */
98+
_ethtool_etherinfo_new, /* tp_new */
99+
};
100+
101+
#endif

python-ethtool/etherinfo_struct.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* @file etherinfo_struct.h
3+
* @author David Sommerseth <dsommers@wsdsommers.usersys.redhat.com>
4+
* @date Fri Sep 4 19:06:06 2009
5+
*
6+
* @brief Contains the internal ethtool.etherinfo data structure
7+
*
8+
*/
9+
10+
#ifndef _ETHERINFO_STRUCT_H
11+
#define _ETHERINFO_STRUCT_H
12+
13+
/**
14+
* Contains the internal data structure of the
15+
* ethtool.etherinfo object.
16+
*
17+
*/
18+
typedef struct {
19+
PyObject_HEAD
20+
struct etherinfo *info; /**< Contains information about one ethernet device */
21+
} etherinfo_py;
22+
23+
#endif

python-ethtool/ethtool.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <sys/types.h>
2828

2929
#include "etherinfo.h"
30+
#include "etherinfo_obj.h"
3031

3132
#ifndef IFF_DYNAMIC
3233
#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses*/
@@ -45,6 +46,7 @@ typedef __uint8_t u8;
4546
#define _PATH_PROCNET_DEV "/proc/net/dev"
4647

4748
struct etherinfo *ethernet_devices = NULL;
49+
int etherinfo_cache_dirty = 0;
4850

4951
static PyObject *get_active_devices(PyObject *self __unused, PyObject *args __unused)
5052
{
@@ -225,6 +227,10 @@ static PyObject *get_ipaddresses(PyObject *self __unused, PyObject *args) {
225227
PyObject *devlist = NULL;
226228
struct etherinfo *ethptr = NULL;
227229

230+
if( ethernet_devices == NULL ) {
231+
ethernet_devices = get_etherinfo();
232+
}
233+
228234
devlist = PyList_New(0);
229235
for( ethptr = ethernet_devices; ethptr->next != NULL; ethptr = ethptr->next) {
230236
if( ethptr->ipv4_address ) {
@@ -883,10 +889,19 @@ static struct PyMethodDef PyEthModuleMethods[] = {
883889
{ .ml_name = NULL, },
884890
};
885891

892+
886893
PyMODINIT_FUNC initethtool(void)
887894
{
888895
PyObject *m;
889-
m = Py_InitModule("ethtool", PyEthModuleMethods);
896+
m = Py_InitModule3("ethtool", PyEthModuleMethods, "Python ethtool module");
897+
898+
// Prepare the ethtool.etherinfo class
899+
if (PyType_Ready(&ethtool_etherinfoType) < 0)
900+
return;
901+
Py_INCREF(&ethtool_etherinfoType);
902+
PyModule_AddObject(m, "etherinfo", (PyObject *)&ethtool_etherinfoType);
903+
904+
// Setup constants
890905
PyModule_AddIntConstant(m, "IFF_UP", IFF_UP); /* Interface is up. */
891906
PyModule_AddIntConstant(m, "IFF_BROADCAST", IFF_BROADCAST); /* Broadcast address valid. */
892907
PyModule_AddIntConstant(m, "IFF_DEBUG", IFF_DEBUG); /* Turn on debugging. */
@@ -905,7 +920,5 @@ PyMODINIT_FUNC initethtool(void)
905920
PyModule_AddIntConstant(m, "IFF_DYNAMIC", IFF_DYNAMIC); /* Dialup device with changing addresses. */
906921
PyModule_AddIntConstant(m, "AF_INET", AF_INET); /* IPv4 interface */
907922
PyModule_AddIntConstant(m, "AF_INET6", AF_INET6); /* IPv6 interface */
908-
909-
ethernet_devices = get_etherinfo();
910923
}
911924

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
from distutils.core import setup, Extension
44

55
ethtool = Extension('ethtool',
6-
sources = ['python-ethtool/ethtool.c', 'python-ethtool/etherinfo.c'])
6+
sources = ['python-ethtool/ethtool.c',
7+
'python-ethtool/etherinfo.c', 'python-ethtool/etherinfo_obj.c'])
78

89
# don't reformat this line, Makefile parses it
910
setup(name='ethtool',

0 commit comments

Comments
 (0)