Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#!/usr/bin/env python3
2# SPDX-License-Identifier: GPL-2.0
3
4"""
5Test channel and ring size configuration via ethtool (-L / -G).
6"""
7
8from lib.py import ksft_run, ksft_exit, ksft_pr
9from lib.py import ksft_eq
10from lib.py import NetDrvEpEnv, EthtoolFamily, GenerateTraffic
11from lib.py import defer, NlError
12
13
14def channels(cfg) -> None:
15 """
16 Twiddle channel counts in various combinations of parameters.
17 We're only looking for driver adhering to the requested config
18 if the config is accepted and crashes.
19 """
20 ehdr = {'header':{'dev-index': cfg.ifindex}}
21 chans = cfg.eth.channels_get(ehdr)
22
23 all_keys = ["rx", "tx", "combined"]
24 mixes = [{"combined"}, {"rx", "tx"}, {"rx", "combined"}, {"tx", "combined"},
25 {"rx", "tx", "combined"},]
26
27 # Get the set of keys that device actually supports
28 restore = {}
29 supported = set()
30 for key in all_keys:
31 if key + "-max" in chans:
32 supported.add(key)
33 restore |= {key + "-count": chans[key + "-count"]}
34
35 defer(cfg.eth.channels_set, ehdr | restore)
36
37 def test_config(config):
38 try:
39 cfg.eth.channels_set(ehdr | config)
40 get = cfg.eth.channels_get(ehdr)
41 for k, v in config.items():
42 ksft_eq(get.get(k, 0), v)
43 except NlError as e:
44 failed.append(mix)
45 ksft_pr("Can't set", config, e)
46 else:
47 ksft_pr("Okay", config)
48
49 failed = []
50 for mix in mixes:
51 if not mix.issubset(supported):
52 continue
53
54 # Set all the values in the mix to 1, other supported to 0
55 config = {}
56 for key in all_keys:
57 config[key + "-count"] = 1 if key in mix else 0
58 test_config(config)
59
60 for mix in mixes:
61 if not mix.issubset(supported):
62 continue
63 if mix in failed:
64 continue
65
66 # Set all the values in the mix to max, other supported to 0
67 config = {}
68 for key in all_keys:
69 config[key + "-count"] = chans[key + '-max'] if key in mix else 0
70 test_config(config)
71
72
73def _configure_min_ring_cnt(cfg) -> None:
74 """ Try to configure a single Rx/Tx ring. """
75 ehdr = {'header':{'dev-index': cfg.ifindex}}
76 chans = cfg.eth.channels_get(ehdr)
77
78 all_keys = ["rx-count", "tx-count", "combined-count"]
79 restore = {}
80 config = {}
81 for key in all_keys:
82 if key in chans:
83 restore[key] = chans[key]
84 config[key] = 0
85
86 if chans.get('combined-count', 0) > 1:
87 config['combined-count'] = 1
88 elif chans.get('rx-count', 0) > 1 and chans.get('tx-count', 0) > 1:
89 config['tx-count'] = 1
90 config['rx-count'] = 1
91 else:
92 # looks like we're already on 1 channel
93 return
94
95 cfg.eth.channels_set(ehdr | config)
96 defer(cfg.eth.channels_set, ehdr | restore)
97
98
99def ringparam(cfg) -> None:
100 """
101 Tweak the ringparam configuration. Try to run some traffic over min
102 ring size to make sure it actually functions.
103 """
104 ehdr = {'header':{'dev-index': cfg.ifindex}}
105 rings = cfg.eth.rings_get(ehdr)
106
107 restore = {}
108 maxes = {}
109 params = set()
110 for key in rings.keys():
111 if 'max' in key:
112 param = key[:-4]
113 maxes[param] = rings[key]
114 params.add(param)
115 restore[param] = rings[param]
116
117 defer(cfg.eth.rings_set, ehdr | restore)
118
119 # Speed up the reconfig by configuring just one ring
120 _configure_min_ring_cnt(cfg)
121
122 # Try to reach min on all settings
123 for param in params:
124 val = rings[param]
125 while True:
126 try:
127 cfg.eth.rings_set({'header':{'dev-index': cfg.ifindex},
128 param: val // 2})
129 if val == 0:
130 break
131 val //= 2
132 except NlError:
133 break
134
135 get = cfg.eth.rings_get(ehdr)
136 ksft_eq(get[param], val)
137
138 ksft_pr(f"Reached min for '{param}' at {val} (max {rings[param]})")
139
140 GenerateTraffic(cfg).wait_pkts_and_stop(10000)
141
142 # Try max across all params, if the driver supports large rings
143 # this may OOM so we ignore errors
144 try:
145 ksft_pr("Applying max settings")
146 config = {p: maxes[p] for p in params}
147 cfg.eth.rings_set(ehdr | config)
148 except NlError as e:
149 ksft_pr("Can't set max params", config, e)
150 else:
151 GenerateTraffic(cfg).wait_pkts_and_stop(10000)
152
153
154def main() -> None:
155 """ Ksft boiler plate main """
156
157 with NetDrvEpEnv(__file__) as cfg:
158 cfg.eth = EthtoolFamily()
159
160 ksft_run([channels,
161 ringparam],
162 args=(cfg, ))
163 ksft_exit()
164
165
166if __name__ == "__main__":
167 main()