Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / tools / testing / selftests / drivers / net / stats.py
blob63e3c045a3b25bbab296558d04f5769fa7dcbbb4
1 #!/usr/bin/env python3
2 # SPDX-License-Identifier: GPL-2.0
4 import errno
5 from lib.py import ksft_run, ksft_exit, ksft_pr
6 from lib.py import ksft_ge, ksft_eq, ksft_in, ksft_true, ksft_raises, KsftSkipEx, KsftXfailEx
7 from lib.py import ksft_disruptive
8 from lib.py import EthtoolFamily, NetdevFamily, RtnlFamily, NlError
9 from lib.py import NetDrvEnv
10 from lib.py import ip, defer
12 ethnl = EthtoolFamily()
13 netfam = NetdevFamily()
14 rtnl = RtnlFamily()
17 def check_pause(cfg) -> None:
18 global ethnl
20 try:
21 ethnl.pause_get({"header": {"dev-index": cfg.ifindex}})
22 except NlError as e:
23 if e.error == errno.EOPNOTSUPP:
24 raise KsftXfailEx("pause not supported by the device")
25 raise
27 data = ethnl.pause_get({"header": {"dev-index": cfg.ifindex,
28 "flags": {'stats'}}})
29 ksft_true(data['stats'], "driver does not report stats")
32 def check_fec(cfg) -> None:
33 global ethnl
35 try:
36 ethnl.fec_get({"header": {"dev-index": cfg.ifindex}})
37 except NlError as e:
38 if e.error == errno.EOPNOTSUPP:
39 raise KsftXfailEx("FEC not supported by the device")
40 raise
42 data = ethnl.fec_get({"header": {"dev-index": cfg.ifindex,
43 "flags": {'stats'}}})
44 ksft_true(data['stats'], "driver does not report stats")
47 def pkt_byte_sum(cfg) -> None:
48 global netfam, rtnl
50 def get_qstat(test):
51 global netfam
52 stats = netfam.qstats_get({}, dump=True)
53 if stats:
54 for qs in stats:
55 if qs["ifindex"]== test.ifindex:
56 return qs
58 qstat = get_qstat(cfg)
59 if qstat is None:
60 raise KsftSkipEx("qstats not supported by the device")
62 for key in ['tx-packets', 'tx-bytes', 'rx-packets', 'rx-bytes']:
63 ksft_in(key, qstat, "Drivers should always report basic keys")
65 # Compare stats, rtnl stats and qstats must match,
66 # but the interface may be up, so do a series of dumps
67 # each time the more "recent" stats must be higher or same.
68 def stat_cmp(rstat, qstat):
69 for key in ['tx-packets', 'tx-bytes', 'rx-packets', 'rx-bytes']:
70 if rstat[key] != qstat[key]:
71 return rstat[key] - qstat[key]
72 return 0
74 for _ in range(10):
75 rtstat = rtnl.getlink({"ifi-index": cfg.ifindex})['stats64']
76 if stat_cmp(rtstat, qstat) < 0:
77 raise Exception("RTNL stats are lower, fetched later")
78 qstat = get_qstat(cfg)
79 if stat_cmp(rtstat, qstat) > 0:
80 raise Exception("Qstats are lower, fetched later")
83 def qstat_by_ifindex(cfg) -> None:
84 global netfam
85 global rtnl
87 # Construct a map ifindex -> [dump, by-index, dump]
88 ifindexes = {}
89 stats = netfam.qstats_get({}, dump=True)
90 for entry in stats:
91 ifindexes[entry['ifindex']] = [entry, None, None]
93 for ifindex in ifindexes.keys():
94 entry = netfam.qstats_get({"ifindex": ifindex}, dump=True)
95 ksft_eq(len(entry), 1)
96 ifindexes[entry[0]['ifindex']][1] = entry[0]
98 stats = netfam.qstats_get({}, dump=True)
99 for entry in stats:
100 ifindexes[entry['ifindex']][2] = entry
102 if len(ifindexes) == 0:
103 raise KsftSkipEx("No ifindex supports qstats")
105 # Now make sure the stats match/make sense
106 for ifindex, triple in ifindexes.items():
107 all_keys = triple[0].keys() | triple[1].keys() | triple[2].keys()
109 for key in all_keys:
110 ksft_ge(triple[1][key], triple[0][key], comment="bad key: " + key)
111 ksft_ge(triple[2][key], triple[1][key], comment="bad key: " + key)
113 # Test invalid dumps
114 # 0 is invalid
115 with ksft_raises(NlError) as cm:
116 netfam.qstats_get({"ifindex": 0}, dump=True)
117 ksft_eq(cm.exception.nl_msg.error, -34)
118 ksft_eq(cm.exception.nl_msg.extack['bad-attr'], '.ifindex')
120 # loopback has no stats
121 with ksft_raises(NlError) as cm:
122 netfam.qstats_get({"ifindex": 1}, dump=True)
123 ksft_eq(cm.exception.nl_msg.error, -errno.EOPNOTSUPP)
124 ksft_eq(cm.exception.nl_msg.extack['bad-attr'], '.ifindex')
126 # Try to get stats for lowest unused ifindex but not 0
127 devs = rtnl.getlink({}, dump=True)
128 all_ifindexes = set([dev["ifi-index"] for dev in devs])
129 lowest = 2
130 while lowest in all_ifindexes:
131 lowest += 1
133 with ksft_raises(NlError) as cm:
134 netfam.qstats_get({"ifindex": lowest}, dump=True)
135 ksft_eq(cm.exception.nl_msg.error, -19)
136 ksft_eq(cm.exception.nl_msg.extack['bad-attr'], '.ifindex')
139 @ksft_disruptive
140 def check_down(cfg) -> None:
141 try:
142 qstat = netfam.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0]
143 except NlError as e:
144 if e.error == errno.EOPNOTSUPP:
145 raise KsftSkipEx("qstats not supported by the device")
146 raise
148 ip(f"link set dev {cfg.dev['ifname']} down")
149 defer(ip, f"link set dev {cfg.dev['ifname']} up")
151 qstat2 = netfam.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0]
152 for k, v in qstat.items():
153 ksft_ge(qstat2[k], qstat[k], comment=f"{k} went backwards on device down")
155 # exercise per-queue API to make sure that "device down" state
156 # is handled correctly and doesn't crash
157 netfam.qstats_get({"ifindex": cfg.ifindex, "scope": "queue"}, dump=True)
160 def main() -> None:
161 with NetDrvEnv(__file__) as cfg:
162 ksft_run([check_pause, check_fec, pkt_byte_sum, qstat_by_ifindex,
163 check_down],
164 args=(cfg, ))
165 ksft_exit()
168 if __name__ == "__main__":
169 main()