Skip to content

Commit 0da7f23

Browse files
committed
ethtool: implement binding for get_coalesce
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent 736e06f commit 0da7f23

File tree

2 files changed

+188
-9
lines changed

2 files changed

+188
-9
lines changed

ethtool-cmd.py

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
def usage():
1818
print '''Usage: ethtool [OPTIONS] [<interface>]
1919
-h|--help Give this help list
20+
-c|--show-coalesce Show coalesce options
2021
-i|--driver Show driver information
2122
-k|--show-offload Get protocol offload information
2223
-K|--offload Set protocol offload
@@ -27,6 +28,81 @@ def usage():
2728
def printtab(msg):
2829
print tab + msg
2930

31+
ethtool_coalesce_msgs = (
32+
( "stats-block-usecs",
33+
"stats_block_coalesce_usecs" ),
34+
( "sample-interval",
35+
"rate_sample_interval" ),
36+
( "pkt-rate-low",
37+
"pkt_rate_low"),
38+
( "pkt-rate-high",
39+
"pkt_rate_high"),
40+
( "\n" ),
41+
( "rx-usecs",
42+
"rx_coalesce_usecs"),
43+
( "rx-frames",
44+
"rx_max_coalesced_frames"),
45+
( "rx-usecs-irq",
46+
"rx_coalesce_usecs_irq"),
47+
( "rx-frames-irq",
48+
"rx_max_coalesced_frames_irq"),
49+
( "\n" ),
50+
( "tx-usecs",
51+
"tx_coalesce_usecs"),
52+
( "tx-frames",
53+
"tx_max_coalesced_frames"),
54+
( "tx-usecs-irq",
55+
"tx_coalesce_usecs_irq"),
56+
( "tx-frames-irq",
57+
"tx_max_coalesced_frames_irq"),
58+
( "\n" ),
59+
( "rx-usecs-low",
60+
"rx_coalesce_usecs_low"),
61+
( "rx-frame-low",
62+
"rx_max_coalesced_frames_low"),
63+
( "tx-usecs-low",
64+
"tx_coalesce_usecs_low"),
65+
( "tx-frame-low",
66+
"tx_max_coalesced_frames_low"),
67+
( "\n" ),
68+
( "rx-usecs-high",
69+
"rx_coalesce_usecs_high"),
70+
( "rx-frame-high",
71+
"rx_max_coalesced_frames_high"),
72+
( "tx-usecs-high",
73+
"tx_coalesce_usecs_high"),
74+
( "tx-frame-high",
75+
"tx_max_coalesced_frames_high"),
76+
)
77+
78+
def show_coalesce(interface, args = None):
79+
printtab("Coalesce parameters for %s:" % interface)
80+
try:
81+
coal = ethtool.get_coalesce(interface)
82+
except IOError:
83+
printtab(" NOT supported!")
84+
return
85+
86+
printtab("Adaptive RX: %s TX: %s" % (coal["use_adaptive_rx_coalesce"] and "on" or "off",
87+
coal["use_adaptive_tx_coalesce"] and "on" or "off"))
88+
89+
printed = [ "use_adaptive_rx_coalesce",
90+
"use_adaptive_tx_coalesce" ]
91+
for tunable in ethtool_coalesce_msgs:
92+
if tunable[0] == '\n':
93+
print
94+
else:
95+
printtab("%s: %s" % (tunable[0], coal[tunable[1]]))
96+
printed.append(tunable[1])
97+
98+
coalkeys = coal.keys()
99+
if len(coalkeys) != len(printed):
100+
print
101+
for tunable in coalkeys:
102+
if tunable not in printed:
103+
printtab("%s %s" % (tunable, coal[tunable]))
104+
105+
30106
def show_offload(interface, args = None):
31107
try:
32108
sg = ethtool.get_sg(interface) and "on" or "off"
@@ -101,8 +177,9 @@ def run_cmd_noargs(cmd, args):
101177
def main():
102178
try:
103179
opts, args = getopt.getopt(sys.argv[1:],
104-
"hikK",
180+
"hcikK",
105181
("help",
182+
"show-coalesce",
106183
"driver",
107184
"show-offload",
108185
"offload"))
@@ -119,6 +196,9 @@ def main():
119196
if o in ("-h", "--help"):
120197
usage()
121198
return
199+
elif o in ("-c", "--show-coalesce"):
200+
run_cmd_noargs(show_coalesce, args)
201+
break
122202
elif o in ("-i", "--driver"):
123203
run_cmd_noargs(show_driver, args)
124204
break

python-ethtool/ethtool.c

Lines changed: 107 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include <Python.h>
22

33
#include <errno.h>
4+
#include <stddef.h>
5+
#include <stdint.h>
46
#include <unistd.h>
57
#include <sys/socket.h>
68
#include <net/if.h>
@@ -16,6 +18,8 @@ typedef __uint8_t u8;
1618
#include "ethtool-copy.h"
1719
#include <linux/sockios.h> /* for SIOCETHTOOL */
1820

21+
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
22+
1923
#define _PATH_PROCNET_DEV "/proc/net/dev"
2024

2125
static PyObject *get_active_devices(PyObject *self __unused, PyObject *args __unused)
@@ -405,11 +409,12 @@ static PyObject *get_businfo(PyObject *self __unused, PyObject *args)
405409
return PyString_FromString(((struct ethtool_drvinfo *)buf)->bus_info);
406410
}
407411

408-
static int send_command(int cmd, char *devname, struct ethtool_value *eval)
412+
static int send_command(int cmd, char *devname, void *value)
409413
{
410414
/* Setup our control structures. */
411415
int fd, err;
412416
struct ifreq ifr;
417+
struct ethtool_value *eval = value;
413418

414419
memset(&ifr, 0, sizeof(ifr));
415420
strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);
@@ -436,24 +441,27 @@ static int send_command(int cmd, char *devname, struct ethtool_value *eval)
436441
return err;
437442
}
438443

439-
static int get_dev_value(int cmd, PyObject *args, void *value, size_t len)
444+
static int get_dev_value(int cmd, PyObject *args, void *value)
440445
{
441446
char *devname;
442447
int err = -1;
443448

444-
if (PyArg_ParseTuple(args, "s", &devname)) {
445-
struct ethtool_value eval;
449+
if (PyArg_ParseTuple(args, "s", &devname))
446450
/* Setup our control structures. */
447-
err = send_command(cmd, devname, &eval);
448-
memcpy(value, &eval.data, len);
449-
}
451+
err = send_command(cmd, devname, value);
450452

451453
return err;
452454
}
453455

454456
static int get_dev_int_value(int cmd, PyObject *args, int *value)
455457
{
456-
return get_dev_value(cmd, args, value, sizeof(*value));
458+
struct ethtool_value eval;
459+
int rc = get_dev_value(cmd, args, &eval);
460+
461+
if (rc == 0)
462+
*value = *(int *)&eval.data;
463+
464+
return rc;
457465
}
458466

459467
static int dev_set_int_value(int cmd, PyObject *args)
@@ -519,6 +527,92 @@ static PyObject *get_sg(PyObject *self __unused, PyObject *args)
519527
return Py_BuildValue("b", value);
520528
}
521529

530+
struct struct_desc {
531+
char *name;
532+
unsigned short offset;
533+
unsigned short size;
534+
};
535+
536+
#define member_desc(type, member_name) { \
537+
.name = #member_name, \
538+
.offset = offsetof(type, member_name), \
539+
.size = sizeof(((type *)0)->member_name), }
540+
541+
struct struct_desc ethtool_coalesce_desc[] = {
542+
member_desc(struct ethtool_coalesce, rx_coalesce_usecs),
543+
member_desc(struct ethtool_coalesce, rx_max_coalesced_frames),
544+
member_desc(struct ethtool_coalesce, rx_coalesce_usecs_irq),
545+
member_desc(struct ethtool_coalesce, rx_max_coalesced_frames_irq),
546+
member_desc(struct ethtool_coalesce, tx_coalesce_usecs),
547+
member_desc(struct ethtool_coalesce, tx_max_coalesced_frames),
548+
member_desc(struct ethtool_coalesce, tx_coalesce_usecs_irq),
549+
member_desc(struct ethtool_coalesce, tx_max_coalesced_frames_irq),
550+
member_desc(struct ethtool_coalesce, stats_block_coalesce_usecs),
551+
member_desc(struct ethtool_coalesce, use_adaptive_rx_coalesce),
552+
member_desc(struct ethtool_coalesce, use_adaptive_tx_coalesce),
553+
member_desc(struct ethtool_coalesce, pkt_rate_low),
554+
member_desc(struct ethtool_coalesce, rx_coalesce_usecs_low),
555+
member_desc(struct ethtool_coalesce, rx_max_coalesced_frames_low),
556+
member_desc(struct ethtool_coalesce, tx_coalesce_usecs_low),
557+
member_desc(struct ethtool_coalesce, tx_max_coalesced_frames_low),
558+
member_desc(struct ethtool_coalesce, pkt_rate_high),
559+
member_desc(struct ethtool_coalesce, rx_coalesce_usecs_high),
560+
member_desc(struct ethtool_coalesce, rx_max_coalesced_frames_high),
561+
member_desc(struct ethtool_coalesce, tx_coalesce_usecs_high),
562+
member_desc(struct ethtool_coalesce, tx_max_coalesced_frames_high),
563+
member_desc(struct ethtool_coalesce, rate_sample_interval),
564+
};
565+
566+
static PyObject *__struct_desc_create_dict(struct struct_desc *table,
567+
int nr_entries, void *values)
568+
{
569+
int i;
570+
PyObject *dict = PyDict_New();
571+
572+
if (dict == NULL)
573+
goto out;
574+
575+
for (i = 0; i < nr_entries; ++i) {
576+
struct struct_desc *d = &table[i];
577+
PyObject *objval = NULL;
578+
void *val = values + d->offset;
579+
580+
switch (d->size) {
581+
case sizeof(uint32_t):
582+
objval = PyInt_FromLong(*(uint32_t *)val);
583+
break;
584+
}
585+
586+
if (objval == NULL)
587+
goto free_dict;
588+
589+
if (PyDict_SetItemString(dict, d->name, objval) != 0) {
590+
Py_DECREF(objval);
591+
goto free_dict;
592+
}
593+
594+
Py_DECREF(objval);
595+
}
596+
out:
597+
return dict;
598+
free_dict:
599+
goto out;
600+
dict = NULL;
601+
}
602+
603+
#define struct_desc_create_dict(table, values) \
604+
__struct_desc_create_dict(table, ARRAY_SIZE(table), values)
605+
606+
static PyObject *get_coalesce(PyObject *self __unused, PyObject *args)
607+
{
608+
struct ethtool_coalesce coal;
609+
610+
if (get_dev_value(ETHTOOL_GCOALESCE, args, &coal) < 0)
611+
return NULL;
612+
613+
return struct_desc_create_dict(ethtool_coalesce_desc, &coal);
614+
}
615+
522616
static struct PyMethodDef PyEthModuleMethods[] = {
523617
{
524618
.ml_name = "get_module",
@@ -550,6 +644,11 @@ static struct PyMethodDef PyEthModuleMethods[] = {
550644
.ml_meth = (PyCFunction)get_broadcast,
551645
.ml_flags = METH_VARARGS,
552646
},
647+
{
648+
.ml_name = "get_coalesce",
649+
.ml_meth = (PyCFunction)get_coalesce,
650+
.ml_flags = METH_VARARGS,
651+
},
553652
{
554653
.ml_name = "get_devices",
555654
.ml_meth = (PyCFunction)get_devices,

0 commit comments

Comments
 (0)