2 # SPDX-License-Identifier: GPL-2.0
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()
17 def check_pause(cfg
) -> None:
21 ethnl
.pause_get({"header": {"dev-index": cfg
.ifindex
}})
23 if e
.error
== errno
.EOPNOTSUPP
:
24 raise KsftXfailEx("pause not supported by the device")
27 data
= ethnl
.pause_get({"header": {"dev-index": cfg
.ifindex
,
29 ksft_true(data
['stats'], "driver does not report stats")
32 def check_fec(cfg
) -> None:
36 ethnl
.fec_get({"header": {"dev-index": cfg
.ifindex
}})
38 if e
.error
== errno
.EOPNOTSUPP
:
39 raise KsftXfailEx("FEC not supported by the device")
42 data
= ethnl
.fec_get({"header": {"dev-index": cfg
.ifindex
,
44 ksft_true(data
['stats'], "driver does not report stats")
47 def pkt_byte_sum(cfg
) -> None:
52 stats
= netfam
.qstats_get({}, dump
=True)
55 if qs
["ifindex"]== test
.ifindex
:
58 qstat
= get_qstat(cfg
)
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
]
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:
87 # Construct a map ifindex -> [dump, by-index, dump]
89 stats
= netfam
.qstats_get({}, dump
=True)
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)
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()
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
)
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
])
130 while lowest
in all_ifindexes
:
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')
140 def check_down(cfg
) -> None:
142 qstat
= netfam
.qstats_get({"ifindex": cfg
.ifindex
}, dump
=True)[0]
144 if e
.error
== errno
.EOPNOTSUPP
:
145 raise KsftSkipEx("qstats not supported by the device")
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)
161 with
NetDrvEnv(__file__
) as cfg
:
162 ksft_run([check_pause
, check_fec
, pkt_byte_sum
, qstat_by_ifindex
,
168 if __name__
== "__main__":