Skip to content

Commit 824f72f

Browse files
committed
ethtool: binding for ETHTOOL_SCOALESCE
And support in pethtool (aka ethtool-cmd.py) for setting all the coalesce parameters, providing, as usual, an interface that mimics the one provided by the ethtool command. This cset also introduces struct_desc_from_dict, that will help with other dict based python bindings, not just in python-ethtool. Please let me know if I'm reinventing the wheel, i.e. if there are other Python dict to C struct facilities out there (I bet there is, but heck, this one was easy enough to implement and doesn't requires external support to get this done 8)). Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent 0da7f23 commit 824f72f

File tree

2 files changed

+154
-10
lines changed

2 files changed

+154
-10
lines changed

ethtool-cmd.py

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,29 @@ def usage():
1818
print '''Usage: ethtool [OPTIONS] [<interface>]
1919
-h|--help Give this help list
2020
-c|--show-coalesce Show coalesce options
21+
-C|--coalesce Set coalesce options
22+
[adaptive-rx on|off]
23+
[adaptive-tx on|off]
24+
[rx-usecs N]
25+
[rx-frames N]
26+
[rx-usecs-irq N]
27+
[rx-frames-irq N]
28+
[tx-usecs N]
29+
[tx-frames N]
30+
[tx-usecs-irq N]
31+
[tx-frames-irq N]
32+
[stats-block-usecs N]
33+
[pkt-rate-low N]
34+
[rx-usecs-low N]
35+
[rx-frames-low N]
36+
[tx-usecs-low N]
37+
[tx-frames-low N]
38+
[pkt-rate-high N]
39+
[rx-usecs-high N]
40+
[rx-frames-high N]
41+
[tx-usecs-high N]
42+
[tx-frames-high N]
43+
[sample-interval N]
2144
-i|--driver Show driver information
2245
-k|--show-offload Get protocol offload information
2346
-K|--offload Set protocol offload
@@ -28,6 +51,8 @@ def usage():
2851
def printtab(msg):
2952
print tab + msg
3053

54+
all_devices = []
55+
3156
ethtool_coalesce_msgs = (
3257
( "stats-block-usecs",
3358
"stats_block_coalesce_usecs" ),
@@ -75,6 +100,19 @@ def printtab(msg):
75100
"tx_max_coalesced_frames_high"),
76101
)
77102

103+
def get_coalesce_dict_entry(ethtool_name):
104+
if ethtool_name == "adaptive-rx":
105+
return "use_adaptive_rx_coalesce"
106+
107+
if ethtool_name == "adaptive-tx":
108+
return "use_adaptive_tx_coalesce"
109+
110+
for name in ethtool_coalesce_msgs:
111+
if name[0] == ethtool_name:
112+
return name[1]
113+
114+
return None
115+
78116
def show_coalesce(interface, args = None):
79117
printtab("Coalesce parameters for %s:" % interface)
80118
try:
@@ -102,6 +140,36 @@ def show_coalesce(interface, args = None):
102140
if tunable not in printed:
103141
printtab("%s %s" % (tunable, coal[tunable]))
104142

143+
def set_coalesce(interface, args):
144+
try:
145+
coal = ethtool.get_coalesce(interface)
146+
except IOError:
147+
printtab("Interrupt coalescing NOT supported on %s!" % interface)
148+
return
149+
150+
changed = False
151+
args = [a.lower() for a in args]
152+
for arg, value in [ ( args[i], args[i + 1] ) for i in range(0, len(args), 2) ]:
153+
real_arg = get_coalesce_dict_entry(arg)
154+
if not real_arg:
155+
continue
156+
if value == "on":
157+
value = 1
158+
elif value == "off":
159+
value = 0
160+
else:
161+
try:
162+
value = int(value)
163+
except:
164+
continue
165+
if coal[real_arg] != value:
166+
coal[real_arg] = value
167+
changed = True
168+
169+
if not changed:
170+
return
171+
172+
ethtool.set_coalesce(interface, coal)
105173

106174
def show_offload(interface, args = None):
107175
try:
@@ -154,12 +222,12 @@ def show_driver(interface, args = None):
154222
printtab("bus-info: %s" % bus)
155223

156224
def run_cmd(cmd, interface, args):
157-
global tab
225+
global tab, all_devices
158226

159227
active_devices = ethtool.get_active_devices()
160228
if not interface:
161229
tab = " "
162-
for interface in ethtool.get_devices():
230+
for interface in all_devices:
163231
inactive = " (not active)"
164232
if interface in active_devices:
165233
inactive = ""
@@ -172,14 +240,19 @@ def run_cmd_noargs(cmd, args):
172240
if args:
173241
run_cmd(cmd, args[0], None)
174242
else:
243+
global all_devices
244+
all_devices = ethtool.get_devices()
175245
run_cmd(cmd, None, None)
176246

177247
def main():
248+
global all_devices
249+
178250
try:
179251
opts, args = getopt.getopt(sys.argv[1:],
180-
"hcikK",
252+
"hcCikK",
181253
("help",
182254
"show-coalesce",
255+
"coalesce",
183256
"driver",
184257
"show-offload",
185258
"offload"))
@@ -205,16 +278,25 @@ def main():
205278
elif o in ("-k", "--show-offload"):
206279
run_cmd_noargs(show_offload, args)
207280
break
208-
elif o in ("-K", "--offload"):
209-
if len(args) == 2:
281+
elif o in ("-K", "--offload",
282+
"-C", "--coalesce"):
283+
all_devices = ethtool.get_devices()
284+
if len(args) < 2:
285+
usage()
286+
sys.exit(1)
287+
288+
if args[0] not in all_devices:
210289
interface = None
211-
elif len(args) == 3:
290+
else:
212291
interface = args[0]
213292
args = args[1:]
214-
else:
215-
usage()
216-
sys.exit(1)
217-
run_cmd(set_offload, interface, args)
293+
294+
if o in ("-K", "--offload"):
295+
cmd = set_offload
296+
elif o in ("-C", "--coalesce"):
297+
cmd = set_coalesce
298+
299+
run_cmd(cmd, interface, args)
218300
break
219301

220302
if __name__ == '__main__':

python-ethtool/ethtool.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,44 @@ static PyObject *__struct_desc_create_dict(struct struct_desc *table,
603603
#define struct_desc_create_dict(table, values) \
604604
__struct_desc_create_dict(table, ARRAY_SIZE(table), values)
605605

606+
static int __struct_desc_from_dict(struct struct_desc *table,
607+
int nr_entries, void *to, PyObject *dict)
608+
{
609+
char buf[2048];
610+
int i;
611+
612+
for (i = 0; i < nr_entries; ++i) {
613+
struct struct_desc *d = &table[i];
614+
void *val = to + d->offset;
615+
PyObject *obj;
616+
617+
switch (d->size) {
618+
case sizeof(uint32_t):
619+
obj = PyDict_GetItemString(dict, d->name);
620+
if (obj == NULL) {
621+
snprintf(buf, sizeof(buf),
622+
"Missing dict entry for field %s",
623+
d->name);
624+
PyErr_SetString(PyExc_IOError, buf);
625+
return -1;
626+
}
627+
*(uint32_t *)val = PyInt_AsLong(obj);
628+
break;
629+
default:
630+
snprintf(buf, sizeof(buf),
631+
"Invalid type size %d for field %s",
632+
d->size, d->name);
633+
PyErr_SetString(PyExc_IOError, buf);
634+
return -1;
635+
}
636+
}
637+
638+
return 0;
639+
}
640+
641+
#define struct_desc_from_dict(table, to, dict) \
642+
__struct_desc_from_dict(table, ARRAY_SIZE(table), to, dict)
643+
606644
static PyObject *get_coalesce(PyObject *self __unused, PyObject *args)
607645
{
608646
struct ethtool_coalesce coal;
@@ -613,6 +651,25 @@ static PyObject *get_coalesce(PyObject *self __unused, PyObject *args)
613651
return struct_desc_create_dict(ethtool_coalesce_desc, &coal);
614652
}
615653

654+
static PyObject *set_coalesce(PyObject *self __unused, PyObject *args)
655+
{
656+
struct ethtool_coalesce coal;
657+
char *devname;
658+
PyObject *dict;
659+
660+
if (!PyArg_ParseTuple(args, "sO", &devname, &dict))
661+
return NULL;
662+
663+
if (struct_desc_from_dict(ethtool_coalesce_desc, &coal, dict) != 0)
664+
return NULL;
665+
666+
if (send_command(ETHTOOL_SCOALESCE, devname, &coal))
667+
return NULL;
668+
669+
Py_INCREF(Py_None);
670+
return Py_None;
671+
}
672+
616673
static struct PyMethodDef PyEthModuleMethods[] = {
617674
{
618675
.ml_name = "get_module",
@@ -649,6 +706,11 @@ static struct PyMethodDef PyEthModuleMethods[] = {
649706
.ml_meth = (PyCFunction)get_coalesce,
650707
.ml_flags = METH_VARARGS,
651708
},
709+
{
710+
.ml_name = "set_coalesce",
711+
.ml_meth = (PyCFunction)set_coalesce,
712+
.ml_flags = METH_VARARGS,
713+
},
652714
{
653715
.ml_name = "get_devices",
654716
.ml_meth = (PyCFunction)get_devices,

0 commit comments

Comments
 (0)