1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3 4from lib.py import ksft_run, ksft_exit, ksft_pr 5from lib.py import ksft_ge, ksft_eq, ksft_in, ksft_true, ksft_raises, KsftSkipEx, KsftXfailEx 6from lib.py import EthtoolFamily, NetdevFamily, RtnlFamily, NlError 7from lib.py import NetDrvEnv 8 9ethnl = EthtoolFamily() 10netfam = NetdevFamily() 11rtnl = RtnlFamily() 12 13 14def check_pause(cfg) -> None: 15 global ethnl 16 17 try: 18 ethnl.pause_get({"header": {"dev-index": cfg.ifindex}}) 19 except NlError as e: 20 if e.error == 95: 21 raise KsftXfailEx("pause not supported by the device") 22 raise 23 24 data = ethnl.pause_get({"header": {"dev-index": cfg.ifindex, 25 "flags": {'stats'}}}) 26 ksft_true(data['stats'], "driver does not report stats") 27 28 29def check_fec(cfg) -> None: 30 global ethnl 31 32 try: 33 ethnl.fec_get({"header": {"dev-index": cfg.ifindex}}) 34 except NlError as e: 35 if e.error == 95: 36 raise KsftXfailEx("FEC not supported by the device") 37 raise 38 39 data = ethnl.fec_get({"header": {"dev-index": cfg.ifindex, 40 "flags": {'stats'}}}) 41 ksft_true(data['stats'], "driver does not report stats") 42 43 44def pkt_byte_sum(cfg) -> None: 45 global netfam, rtnl 46 47 def get_qstat(test): 48 global netfam 49 stats = netfam.qstats_get({}, dump=True) 50 if stats: 51 for qs in stats: 52 if qs["ifindex"]== test.ifindex: 53 return qs 54 55 qstat = get_qstat(cfg) 56 if qstat is None: 57 raise KsftSkipEx("qstats not supported by the device") 58 59 for key in ['tx-packets', 'tx-bytes', 'rx-packets', 'rx-bytes']: 60 ksft_in(key, qstat, "Drivers should always report basic keys") 61 62 # Compare stats, rtnl stats and qstats must match, 63 # but the interface may be up, so do a series of dumps 64 # each time the more "recent" stats must be higher or same. 65 def stat_cmp(rstat, qstat): 66 for key in ['tx-packets', 'tx-bytes', 'rx-packets', 'rx-bytes']: 67 if rstat[key] != qstat[key]: 68 return rstat[key] - qstat[key] 69 return 0 70 71 for _ in range(10): 72 rtstat = rtnl.getlink({"ifi-index": cfg.ifindex})['stats'] 73 if stat_cmp(rtstat, qstat) < 0: 74 raise Exception("RTNL stats are lower, fetched later") 75 qstat = get_qstat(cfg) 76 if stat_cmp(rtstat, qstat) > 0: 77 raise Exception("Qstats are lower, fetched later") 78 79 80def qstat_by_ifindex(cfg) -> None: 81 global netfam 82 global rtnl 83 84 # Construct a map ifindex -> [dump, by-index, dump] 85 ifindexes = {} 86 stats = netfam.qstats_get({}, dump=True) 87 for entry in stats: 88 ifindexes[entry['ifindex']] = [entry, None, None] 89 90 for ifindex in ifindexes.keys(): 91 entry = netfam.qstats_get({"ifindex": ifindex}, dump=True) 92 ksft_eq(len(entry), 1) 93 ifindexes[entry[0]['ifindex']][1] = entry[0] 94 95 stats = netfam.qstats_get({}, dump=True) 96 for entry in stats: 97 ifindexes[entry['ifindex']][2] = entry 98 99 if len(ifindexes) == 0: 100 raise KsftSkipEx("No ifindex supports qstats") 101 102 # Now make sure the stats match/make sense 103 for ifindex, triple in ifindexes.items(): 104 all_keys = triple[0].keys() | triple[1].keys() | triple[2].keys() 105 106 for key in all_keys: 107 ksft_ge(triple[1][key], triple[0][key], comment="bad key: " + key) 108 ksft_ge(triple[2][key], triple[1][key], comment="bad key: " + key) 109 110 # Test invalid dumps 111 # 0 is invalid 112 with ksft_raises(NlError) as cm: 113 netfam.qstats_get({"ifindex": 0}, dump=True) 114 ksft_eq(cm.exception.nl_msg.error, -34) 115 ksft_eq(cm.exception.nl_msg.extack['bad-attr'], '.ifindex') 116 117 # loopback has no stats 118 with ksft_raises(NlError) as cm: 119 netfam.qstats_get({"ifindex": 1}, dump=True) 120 ksft_eq(cm.exception.nl_msg.error, -95) 121 ksft_eq(cm.exception.nl_msg.extack['bad-attr'], '.ifindex') 122 123 # Try to get stats for lowest unused ifindex but not 0 124 devs = rtnl.getlink({}, dump=True) 125 all_ifindexes = set([dev["ifi-index"] for dev in devs]) 126 lowest = 2 127 while lowest in all_ifindexes: 128 lowest += 1 129 130 with ksft_raises(NlError) as cm: 131 netfam.qstats_get({"ifindex": lowest}, dump=True) 132 ksft_eq(cm.exception.nl_msg.error, -19) 133 ksft_eq(cm.exception.nl_msg.extack['bad-attr'], '.ifindex') 134 135 136def main() -> None: 137 with NetDrvEnv(__file__) as cfg: 138 ksft_run([check_pause, check_fec, pkt_byte_sum, qstat_by_ifindex], 139 args=(cfg, )) 140 ksft_exit() 141 142 143if __name__ == "__main__": 144 main() 145