xref: /linux/tools/net/ynl/tests/ethtool.py (revision 91a4855d6c03e770e42f17c798a36a3c46e63de2)
122ef8a26SHangbin Liu#!/usr/bin/env python3
222ef8a26SHangbin Liu# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
322ef8a26SHangbin Liu#
422ef8a26SHangbin Liu# pylint: disable=too-many-locals, too-many-branches, too-many-statements
522ef8a26SHangbin Liu# pylint: disable=too-many-return-statements
622ef8a26SHangbin Liu
722ef8a26SHangbin Liu""" YNL ethtool utility """
822ef8a26SHangbin Liu
922ef8a26SHangbin Liuimport argparse
1022ef8a26SHangbin Liuimport pathlib
1122ef8a26SHangbin Liuimport pprint
1222ef8a26SHangbin Liuimport sys
1322ef8a26SHangbin Liuimport re
1422ef8a26SHangbin Liuimport os
1522ef8a26SHangbin Liu
1622ef8a26SHangbin Liu# pylint: disable=no-name-in-module,wrong-import-position
1722ef8a26SHangbin Liusys.path.append(pathlib.Path(__file__).resolve().parent.parent.joinpath('pyynl').as_posix())
1822ef8a26SHangbin Liu# pylint: disable=import-error
1922ef8a26SHangbin Liufrom cli import schema_dir, spec_dir
2022ef8a26SHangbin Liufrom lib import YnlFamily
2122ef8a26SHangbin Liu
2222ef8a26SHangbin Liu
2322ef8a26SHangbin Liudef args_to_req(ynl, op_name, args, req):
2422ef8a26SHangbin Liu    """
2522ef8a26SHangbin Liu    Verify and convert command-line arguments to the ynl-compatible request.
2622ef8a26SHangbin Liu    """
2722ef8a26SHangbin Liu    valid_attrs = ynl.operation_do_attributes(op_name)
2822ef8a26SHangbin Liu    valid_attrs.remove('header') # not user-provided
2922ef8a26SHangbin Liu
3022ef8a26SHangbin Liu    if len(args) == 0:
3122ef8a26SHangbin Liu        print(f'no attributes, expected: {valid_attrs}')
3222ef8a26SHangbin Liu        sys.exit(1)
3322ef8a26SHangbin Liu
3422ef8a26SHangbin Liu    i = 0
3522ef8a26SHangbin Liu    while i < len(args):
3622ef8a26SHangbin Liu        attr = args[i]
3722ef8a26SHangbin Liu        if i + 1 >= len(args):
3822ef8a26SHangbin Liu            print(f'expected value for \'{attr}\'')
3922ef8a26SHangbin Liu            sys.exit(1)
4022ef8a26SHangbin Liu
4122ef8a26SHangbin Liu        if attr not in valid_attrs:
4222ef8a26SHangbin Liu            print(f'invalid attribute \'{attr}\', expected: {valid_attrs}')
4322ef8a26SHangbin Liu            sys.exit(1)
4422ef8a26SHangbin Liu
4522ef8a26SHangbin Liu        val = args[i+1]
4622ef8a26SHangbin Liu        i += 2
4722ef8a26SHangbin Liu
4822ef8a26SHangbin Liu        req[attr] = val
4922ef8a26SHangbin Liu
5022ef8a26SHangbin Liudef print_field(reply, *desc):
5122ef8a26SHangbin Liu    """
5222ef8a26SHangbin Liu    Pretty-print a set of fields from the reply. desc specifies the
5322ef8a26SHangbin Liu    fields and the optional type (bool/yn).
5422ef8a26SHangbin Liu    """
5522ef8a26SHangbin Liu    if not reply:
5622ef8a26SHangbin Liu        return
5722ef8a26SHangbin Liu
5822ef8a26SHangbin Liu    if len(desc) == 0:
5922ef8a26SHangbin Liu        print_field(reply, *zip(reply.keys(), reply.keys()))
6022ef8a26SHangbin Liu        return
6122ef8a26SHangbin Liu
6222ef8a26SHangbin Liu    for spec in desc:
6322ef8a26SHangbin Liu        try:
6422ef8a26SHangbin Liu            field, name, tp = spec
6522ef8a26SHangbin Liu        except ValueError:
6622ef8a26SHangbin Liu            field, name = spec
6722ef8a26SHangbin Liu            tp = 'int'
6822ef8a26SHangbin Liu
6922ef8a26SHangbin Liu        value = reply.get(field, None)
7022ef8a26SHangbin Liu        if tp == 'yn':
7122ef8a26SHangbin Liu            value = 'yes' if value else 'no'
7222ef8a26SHangbin Liu        elif tp == 'bool' or isinstance(value, bool):
7322ef8a26SHangbin Liu            value = 'on' if value else 'off'
7422ef8a26SHangbin Liu        else:
7522ef8a26SHangbin Liu            value = 'n/a' if value is None else value
7622ef8a26SHangbin Liu
7722ef8a26SHangbin Liu        print(f'{name}: {value}')
7822ef8a26SHangbin Liu
7922ef8a26SHangbin Liudef print_speed(name, value):
8022ef8a26SHangbin Liu    """
8122ef8a26SHangbin Liu    Print out the speed-like strings from the value dict.
8222ef8a26SHangbin Liu    """
8322ef8a26SHangbin Liu    speed_re = re.compile(r'[0-9]+base[^/]+/.+')
8422ef8a26SHangbin Liu    speed = [ k for k, v in value.items() if v and speed_re.match(k) ]
8522ef8a26SHangbin Liu    print(f'{name}: {" ".join(speed)}')
8622ef8a26SHangbin Liu
871c43d471SHangbin Liudef do_set(ynl, args, op_name):
8822ef8a26SHangbin Liu    """
891c43d471SHangbin Liu    Prepare request header, parse arguments and do a set operation.
9022ef8a26SHangbin Liu    """
9122ef8a26SHangbin Liu    req = {
9222ef8a26SHangbin Liu        'header': {
9322ef8a26SHangbin Liu          'dev-name': args.device,
9422ef8a26SHangbin Liu        },
9522ef8a26SHangbin Liu    }
9622ef8a26SHangbin Liu
9722ef8a26SHangbin Liu    args_to_req(ynl, op_name, args.args, req)
9822ef8a26SHangbin Liu    ynl.do(op_name, req)
9922ef8a26SHangbin Liu
1001c43d471SHangbin Liudef do_get(ynl, args, op_name, extra=None):
10122ef8a26SHangbin Liu    """
1021c43d471SHangbin Liu    Prepare request header and get info for a specific device using doit.
10322ef8a26SHangbin Liu    """
10422ef8a26SHangbin Liu    extra = extra or {}
1051c43d471SHangbin Liu    req = {'header': {'dev-name': args.device}}
1061c43d471SHangbin Liu    req['header'].update(extra.pop('header', {}))
1071c43d471SHangbin Liu    req.update(extra)
1081c43d471SHangbin Liu
1091c43d471SHangbin Liu    reply = ynl.do(op_name, req)
11022ef8a26SHangbin Liu    if not reply:
11122ef8a26SHangbin Liu        return {}
11222ef8a26SHangbin Liu
11322ef8a26SHangbin Liu    if args.json:
1141c43d471SHangbin Liu        pprint.PrettyPrinter().pprint(reply)
11522ef8a26SHangbin Liu        sys.exit(0)
1161c43d471SHangbin Liu    reply.pop('header', None)
1171c43d471SHangbin Liu    return reply
11822ef8a26SHangbin Liu
11922ef8a26SHangbin Liudef bits_to_dict(attr):
12022ef8a26SHangbin Liu    """
12122ef8a26SHangbin Liu    Convert ynl-formatted bitmask to a dict of bit=value.
12222ef8a26SHangbin Liu    """
12322ef8a26SHangbin Liu    ret = {}
12422ef8a26SHangbin Liu    if 'bits' not in attr:
12522ef8a26SHangbin Liu        return {}
12622ef8a26SHangbin Liu    if 'bit' not in attr['bits']:
12722ef8a26SHangbin Liu        return {}
12822ef8a26SHangbin Liu    for bit in attr['bits']['bit']:
12922ef8a26SHangbin Liu        if bit['name'] == '':
13022ef8a26SHangbin Liu            continue
13122ef8a26SHangbin Liu        name = bit['name']
13222ef8a26SHangbin Liu        value = bit.get('value', False)
13322ef8a26SHangbin Liu        ret[name] = value
13422ef8a26SHangbin Liu    return ret
13522ef8a26SHangbin Liu
13622ef8a26SHangbin Liudef main():
13722ef8a26SHangbin Liu    """ YNL ethtool utility """
13822ef8a26SHangbin Liu
13922ef8a26SHangbin Liu    parser = argparse.ArgumentParser(description='ethtool wannabe')
14022ef8a26SHangbin Liu    parser.add_argument('--json', action=argparse.BooleanOptionalAction)
14122ef8a26SHangbin Liu    parser.add_argument('--show-priv-flags', action=argparse.BooleanOptionalAction)
14222ef8a26SHangbin Liu    parser.add_argument('--set-priv-flags', action=argparse.BooleanOptionalAction)
14322ef8a26SHangbin Liu    parser.add_argument('--show-eee', action=argparse.BooleanOptionalAction)
14422ef8a26SHangbin Liu    parser.add_argument('--set-eee', action=argparse.BooleanOptionalAction)
14522ef8a26SHangbin Liu    parser.add_argument('-a', '--show-pause', action=argparse.BooleanOptionalAction)
14622ef8a26SHangbin Liu    parser.add_argument('-A', '--set-pause', action=argparse.BooleanOptionalAction)
14722ef8a26SHangbin Liu    parser.add_argument('-c', '--show-coalesce', action=argparse.BooleanOptionalAction)
14822ef8a26SHangbin Liu    parser.add_argument('-C', '--set-coalesce', action=argparse.BooleanOptionalAction)
14922ef8a26SHangbin Liu    parser.add_argument('-g', '--show-ring', action=argparse.BooleanOptionalAction)
15022ef8a26SHangbin Liu    parser.add_argument('-G', '--set-ring', action=argparse.BooleanOptionalAction)
15122ef8a26SHangbin Liu    parser.add_argument('-k', '--show-features', action=argparse.BooleanOptionalAction)
15222ef8a26SHangbin Liu    parser.add_argument('-K', '--set-features', action=argparse.BooleanOptionalAction)
15322ef8a26SHangbin Liu    parser.add_argument('-l', '--show-channels', action=argparse.BooleanOptionalAction)
15422ef8a26SHangbin Liu    parser.add_argument('-L', '--set-channels', action=argparse.BooleanOptionalAction)
15522ef8a26SHangbin Liu    parser.add_argument('-T', '--show-time-stamping', action=argparse.BooleanOptionalAction)
15622ef8a26SHangbin Liu    parser.add_argument('-S', '--statistics', action=argparse.BooleanOptionalAction)
15722ef8a26SHangbin Liu    # TODO: --show-tunnels        tunnel-info-get
15822ef8a26SHangbin Liu    # TODO: --show-module         module-get
15922ef8a26SHangbin Liu    # TODO: --get-plca-cfg        plca-get
16022ef8a26SHangbin Liu    # TODO: --get-plca-status     plca-get-status
16122ef8a26SHangbin Liu    # TODO: --show-mm             mm-get
16222ef8a26SHangbin Liu    # TODO: --show-fec            fec-get
16322ef8a26SHangbin Liu    # TODO: --dump-module-eerpom  module-eeprom-get
16422ef8a26SHangbin Liu    # TODO:                       pse-get
16522ef8a26SHangbin Liu    # TODO:                       rss-get
16622ef8a26SHangbin Liu    parser.add_argument('device', metavar='device', type=str)
16722ef8a26SHangbin Liu    parser.add_argument('args', metavar='args', type=str, nargs='*')
16822ef8a26SHangbin Liu
169*594ba447SHangbin Liu    dbg_group = parser.add_argument_group('Debug options')
170*594ba447SHangbin Liu    dbg_group.add_argument('--dbg-small-recv', default=0, const=4000,
171*594ba447SHangbin Liu                           action='store', nargs='?', type=int, metavar='INT',
172*594ba447SHangbin Liu                           help="Length of buffers used for recv()")
173*594ba447SHangbin Liu
17422ef8a26SHangbin Liu    args = parser.parse_args()
17522ef8a26SHangbin Liu
17622ef8a26SHangbin Liu    spec = os.path.join(spec_dir(), 'ethtool.yaml')
17722ef8a26SHangbin Liu    schema = os.path.join(schema_dir(), 'genetlink-legacy.yaml')
17822ef8a26SHangbin Liu
179*594ba447SHangbin Liu    ynl = YnlFamily(spec, schema, recv_size=args.dbg_small_recv)
180*594ba447SHangbin Liu    if args.dbg_small_recv:
181*594ba447SHangbin Liu        ynl.set_recv_dbg(True)
18222ef8a26SHangbin Liu
18322ef8a26SHangbin Liu    if args.set_priv_flags:
18422ef8a26SHangbin Liu        # TODO: parse the bitmask
18522ef8a26SHangbin Liu        print("not implemented")
18622ef8a26SHangbin Liu        return
18722ef8a26SHangbin Liu
18822ef8a26SHangbin Liu    if args.set_eee:
1891c43d471SHangbin Liu        do_set(ynl, args, 'eee-set')
19022ef8a26SHangbin Liu        return
19122ef8a26SHangbin Liu
19222ef8a26SHangbin Liu    if args.set_pause:
1931c43d471SHangbin Liu        do_set(ynl, args, 'pause-set')
19422ef8a26SHangbin Liu        return
19522ef8a26SHangbin Liu
19622ef8a26SHangbin Liu    if args.set_coalesce:
1971c43d471SHangbin Liu        do_set(ynl, args, 'coalesce-set')
19822ef8a26SHangbin Liu        return
19922ef8a26SHangbin Liu
20022ef8a26SHangbin Liu    if args.set_features:
20122ef8a26SHangbin Liu        # TODO: parse the bitmask
20222ef8a26SHangbin Liu        print("not implemented")
20322ef8a26SHangbin Liu        return
20422ef8a26SHangbin Liu
20522ef8a26SHangbin Liu    if args.set_channels:
2061c43d471SHangbin Liu        do_set(ynl, args, 'channels-set')
20722ef8a26SHangbin Liu        return
20822ef8a26SHangbin Liu
20922ef8a26SHangbin Liu    if args.set_ring:
2101c43d471SHangbin Liu        do_set(ynl, args, 'rings-set')
21122ef8a26SHangbin Liu        return
21222ef8a26SHangbin Liu
21322ef8a26SHangbin Liu    if args.show_priv_flags:
2141c43d471SHangbin Liu        flags = bits_to_dict(do_get(ynl, args, 'privflags-get')['flags'])
21522ef8a26SHangbin Liu        print_field(flags)
21622ef8a26SHangbin Liu        return
21722ef8a26SHangbin Liu
21822ef8a26SHangbin Liu    if args.show_eee:
2191c43d471SHangbin Liu        eee = do_get(ynl, args, 'eee-get')
22022ef8a26SHangbin Liu        ours = bits_to_dict(eee['modes-ours'])
22122ef8a26SHangbin Liu        peer = bits_to_dict(eee['modes-peer'])
22222ef8a26SHangbin Liu
22322ef8a26SHangbin Liu        if 'enabled' in eee:
22422ef8a26SHangbin Liu            status = 'enabled' if eee['enabled'] else 'disabled'
22522ef8a26SHangbin Liu            if 'active' in eee and eee['active']:
22622ef8a26SHangbin Liu                status = status + ' - active'
22722ef8a26SHangbin Liu            else:
22822ef8a26SHangbin Liu                status = status + ' - inactive'
22922ef8a26SHangbin Liu        else:
23022ef8a26SHangbin Liu            status = 'not supported'
23122ef8a26SHangbin Liu
23222ef8a26SHangbin Liu        print(f'EEE status: {status}')
23322ef8a26SHangbin Liu        print_field(eee, ('tx-lpi-timer', 'Tx LPI'))
23422ef8a26SHangbin Liu        print_speed('Advertised EEE link modes', ours)
23522ef8a26SHangbin Liu        print_speed('Link partner advertised EEE link modes', peer)
23622ef8a26SHangbin Liu
23722ef8a26SHangbin Liu        return
23822ef8a26SHangbin Liu
23922ef8a26SHangbin Liu    if args.show_pause:
2401c43d471SHangbin Liu        print_field(do_get(ynl, args, 'pause-get'),
24122ef8a26SHangbin Liu                ('autoneg', 'Autonegotiate', 'bool'),
24222ef8a26SHangbin Liu                ('rx', 'RX', 'bool'),
24322ef8a26SHangbin Liu                ('tx', 'TX', 'bool'))
24422ef8a26SHangbin Liu        return
24522ef8a26SHangbin Liu
24622ef8a26SHangbin Liu    if args.show_coalesce:
2471c43d471SHangbin Liu        print_field(do_get(ynl, args, 'coalesce-get'))
24822ef8a26SHangbin Liu        return
24922ef8a26SHangbin Liu
25022ef8a26SHangbin Liu    if args.show_features:
2511c43d471SHangbin Liu        reply = do_get(ynl, args, 'features-get')
25222ef8a26SHangbin Liu        available = bits_to_dict(reply['hw'])
25322ef8a26SHangbin Liu        requested = bits_to_dict(reply['wanted']).keys()
25422ef8a26SHangbin Liu        active = bits_to_dict(reply['active']).keys()
25522ef8a26SHangbin Liu        never_changed = bits_to_dict(reply['nochange']).keys()
25622ef8a26SHangbin Liu
25722ef8a26SHangbin Liu        for f in sorted(available):
25822ef8a26SHangbin Liu            value = "off"
25922ef8a26SHangbin Liu            if f in active:
26022ef8a26SHangbin Liu                value = "on"
26122ef8a26SHangbin Liu
26222ef8a26SHangbin Liu            fixed = ""
26322ef8a26SHangbin Liu            if f not in available or f in never_changed:
26422ef8a26SHangbin Liu                fixed = " [fixed]"
26522ef8a26SHangbin Liu
26622ef8a26SHangbin Liu            req = ""
26722ef8a26SHangbin Liu            if f in requested:
26822ef8a26SHangbin Liu                if f in active:
26922ef8a26SHangbin Liu                    req = " [requested on]"
27022ef8a26SHangbin Liu                else:
27122ef8a26SHangbin Liu                    req = " [requested off]"
27222ef8a26SHangbin Liu
27322ef8a26SHangbin Liu            print(f'{f}: {value}{fixed}{req}')
27422ef8a26SHangbin Liu
27522ef8a26SHangbin Liu        return
27622ef8a26SHangbin Liu
27722ef8a26SHangbin Liu    if args.show_channels:
2781c43d471SHangbin Liu        reply = do_get(ynl, args, 'channels-get')
27922ef8a26SHangbin Liu        print(f'Channel parameters for {args.device}:')
28022ef8a26SHangbin Liu
28122ef8a26SHangbin Liu        print('Pre-set maximums:')
28222ef8a26SHangbin Liu        print_field(reply,
28322ef8a26SHangbin Liu            ('rx-max', 'RX'),
28422ef8a26SHangbin Liu            ('tx-max', 'TX'),
28522ef8a26SHangbin Liu            ('other-max', 'Other'),
28622ef8a26SHangbin Liu            ('combined-max', 'Combined'))
28722ef8a26SHangbin Liu
28822ef8a26SHangbin Liu        print('Current hardware settings:')
28922ef8a26SHangbin Liu        print_field(reply,
29022ef8a26SHangbin Liu            ('rx-count', 'RX'),
29122ef8a26SHangbin Liu            ('tx-count', 'TX'),
29222ef8a26SHangbin Liu            ('other-count', 'Other'),
29322ef8a26SHangbin Liu            ('combined-count', 'Combined'))
29422ef8a26SHangbin Liu
29522ef8a26SHangbin Liu        return
29622ef8a26SHangbin Liu
29722ef8a26SHangbin Liu    if args.show_ring:
2981c43d471SHangbin Liu        reply = do_get(ynl, args, 'channels-get')
29922ef8a26SHangbin Liu
30022ef8a26SHangbin Liu        print(f'Ring parameters for {args.device}:')
30122ef8a26SHangbin Liu
30222ef8a26SHangbin Liu        print('Pre-set maximums:')
30322ef8a26SHangbin Liu        print_field(reply,
30422ef8a26SHangbin Liu            ('rx-max', 'RX'),
30522ef8a26SHangbin Liu            ('rx-mini-max', 'RX Mini'),
30622ef8a26SHangbin Liu            ('rx-jumbo-max', 'RX Jumbo'),
30722ef8a26SHangbin Liu            ('tx-max', 'TX'))
30822ef8a26SHangbin Liu
30922ef8a26SHangbin Liu        print('Current hardware settings:')
31022ef8a26SHangbin Liu        print_field(reply,
31122ef8a26SHangbin Liu            ('rx', 'RX'),
31222ef8a26SHangbin Liu            ('rx-mini', 'RX Mini'),
31322ef8a26SHangbin Liu            ('rx-jumbo', 'RX Jumbo'),
31422ef8a26SHangbin Liu            ('tx', 'TX'))
31522ef8a26SHangbin Liu
31622ef8a26SHangbin Liu        print_field(reply,
31722ef8a26SHangbin Liu            ('rx-buf-len', 'RX Buf Len'),
31822ef8a26SHangbin Liu            ('cqe-size', 'CQE Size'),
31922ef8a26SHangbin Liu            ('tx-push', 'TX Push', 'bool'))
32022ef8a26SHangbin Liu
32122ef8a26SHangbin Liu        return
32222ef8a26SHangbin Liu
32322ef8a26SHangbin Liu    if args.statistics:
32422ef8a26SHangbin Liu        print('NIC statistics:')
32522ef8a26SHangbin Liu
32622ef8a26SHangbin Liu        # TODO: pass id?
3271c43d471SHangbin Liu        strset = do_get(ynl, args, 'strset-get')
32822ef8a26SHangbin Liu        pprint.PrettyPrinter().pprint(strset)
32922ef8a26SHangbin Liu
33022ef8a26SHangbin Liu        req = {
33122ef8a26SHangbin Liu          'groups': {
33222ef8a26SHangbin Liu            'size': 1,
33322ef8a26SHangbin Liu            'bits': {
33422ef8a26SHangbin Liu              'bit':
33522ef8a26SHangbin Liu                # TODO: support passing the bitmask
33622ef8a26SHangbin Liu                #[
33722ef8a26SHangbin Liu                  #{ 'name': 'eth-phy', 'value': True },
33822ef8a26SHangbin Liu                  { 'name': 'eth-mac', 'value': True },
33922ef8a26SHangbin Liu                  #{ 'name': 'eth-ctrl', 'value': True },
34022ef8a26SHangbin Liu                  #{ 'name': 'rmon', 'value': True },
34122ef8a26SHangbin Liu                #],
34222ef8a26SHangbin Liu            },
34322ef8a26SHangbin Liu          },
34422ef8a26SHangbin Liu        }
34522ef8a26SHangbin Liu
3461c43d471SHangbin Liu        rsp = do_get(ynl, args, 'stats-get', req)
34722ef8a26SHangbin Liu        pprint.PrettyPrinter().pprint(rsp)
34822ef8a26SHangbin Liu        return
34922ef8a26SHangbin Liu
35022ef8a26SHangbin Liu    if args.show_time_stamping:
35122ef8a26SHangbin Liu        req = {
35222ef8a26SHangbin Liu          'header': {
35322ef8a26SHangbin Liu            'flags': 'stats',
35422ef8a26SHangbin Liu          },
35522ef8a26SHangbin Liu        }
35622ef8a26SHangbin Liu
3571c43d471SHangbin Liu        tsinfo = do_get(ynl, args, 'tsinfo-get', req)
35822ef8a26SHangbin Liu
35922ef8a26SHangbin Liu        print(f'Time stamping parameters for {args.device}:')
36022ef8a26SHangbin Liu
36122ef8a26SHangbin Liu        print('Capabilities:')
36222ef8a26SHangbin Liu        _ = [print(f'\t{v}') for v in bits_to_dict(tsinfo['timestamping'])]
36322ef8a26SHangbin Liu
36422ef8a26SHangbin Liu        print(f'PTP Hardware Clock: {tsinfo.get("phc-index", "none")}')
36522ef8a26SHangbin Liu
36622ef8a26SHangbin Liu        if 'tx-types' in tsinfo:
36722ef8a26SHangbin Liu            print('Hardware Transmit Timestamp Modes:')
36822ef8a26SHangbin Liu            _ = [print(f'\t{v}') for v in bits_to_dict(tsinfo['tx-types'])]
36922ef8a26SHangbin Liu        else:
37022ef8a26SHangbin Liu            print('Hardware Transmit Timestamp Modes: none')
37122ef8a26SHangbin Liu
37222ef8a26SHangbin Liu        if 'rx-filters' in tsinfo:
37322ef8a26SHangbin Liu            print('Hardware Receive Filter Modes:')
37422ef8a26SHangbin Liu            _ = [print(f'\t{v}') for v in bits_to_dict(tsinfo['rx-filters'])]
37522ef8a26SHangbin Liu        else:
37622ef8a26SHangbin Liu            print('Hardware Receive Filter Modes: none')
37722ef8a26SHangbin Liu
37822ef8a26SHangbin Liu        if 'stats' in tsinfo and tsinfo['stats']:
37922ef8a26SHangbin Liu            print('Statistics:')
38022ef8a26SHangbin Liu            _ = [print(f'\t{k}: {v}') for k, v in tsinfo['stats'].items()]
38122ef8a26SHangbin Liu
38222ef8a26SHangbin Liu        return
38322ef8a26SHangbin Liu
38422ef8a26SHangbin Liu    print(f'Settings for {args.device}:')
3851c43d471SHangbin Liu    linkmodes = do_get(ynl, args, 'linkmodes-get')
38622ef8a26SHangbin Liu    ours = bits_to_dict(linkmodes['ours'])
38722ef8a26SHangbin Liu
38822ef8a26SHangbin Liu    supported_ports = ('TP',  'AUI', 'BNC', 'MII', 'FIBRE', 'Backplane')
38922ef8a26SHangbin Liu    ports = [ p for p in supported_ports if ours.get(p, False)]
39022ef8a26SHangbin Liu    print(f'Supported ports: [ {" ".join(ports)} ]')
39122ef8a26SHangbin Liu
39222ef8a26SHangbin Liu    print_speed('Supported link modes', ours)
39322ef8a26SHangbin Liu
39422ef8a26SHangbin Liu    print_field(ours, ('Pause', 'Supported pause frame use', 'yn'))
39522ef8a26SHangbin Liu    print_field(ours, ('Autoneg', 'Supports auto-negotiation', 'yn'))
39622ef8a26SHangbin Liu
39722ef8a26SHangbin Liu    supported_fec = ('None',  'PS', 'BASER', 'LLRS')
39822ef8a26SHangbin Liu    fec = [ p for p in supported_fec if ours.get(p, False)]
39922ef8a26SHangbin Liu    fec_str = " ".join(fec)
40022ef8a26SHangbin Liu    if len(fec) == 0:
40122ef8a26SHangbin Liu        fec_str = "Not reported"
40222ef8a26SHangbin Liu
40322ef8a26SHangbin Liu    print(f'Supported FEC modes: {fec_str}')
40422ef8a26SHangbin Liu
40522ef8a26SHangbin Liu    speed = 'Unknown!'
40622ef8a26SHangbin Liu    if linkmodes['speed'] > 0 and linkmodes['speed'] < 0xffffffff:
40722ef8a26SHangbin Liu        speed = f'{linkmodes["speed"]}Mb/s'
40822ef8a26SHangbin Liu    print(f'Speed: {speed}')
40922ef8a26SHangbin Liu
41022ef8a26SHangbin Liu    duplex_modes = {
41122ef8a26SHangbin Liu            0: 'Half',
41222ef8a26SHangbin Liu            1: 'Full',
41322ef8a26SHangbin Liu    }
41422ef8a26SHangbin Liu    duplex = duplex_modes.get(linkmodes["duplex"], None)
41522ef8a26SHangbin Liu    if not duplex:
41622ef8a26SHangbin Liu        duplex = f'Unknown! ({linkmodes["duplex"]})'
41722ef8a26SHangbin Liu    print(f'Duplex: {duplex}')
41822ef8a26SHangbin Liu
41922ef8a26SHangbin Liu    autoneg = "off"
42022ef8a26SHangbin Liu    if linkmodes.get("autoneg", 0) != 0:
42122ef8a26SHangbin Liu        autoneg = "on"
42222ef8a26SHangbin Liu    print(f'Auto-negotiation: {autoneg}')
42322ef8a26SHangbin Liu
42422ef8a26SHangbin Liu    ports = {
42522ef8a26SHangbin Liu            0: 'Twisted Pair',
42622ef8a26SHangbin Liu            1: 'AUI',
42722ef8a26SHangbin Liu            2: 'MII',
42822ef8a26SHangbin Liu            3: 'FIBRE',
42922ef8a26SHangbin Liu            4: 'BNC',
43022ef8a26SHangbin Liu            5: 'Directly Attached Copper',
43122ef8a26SHangbin Liu            0xef: 'None',
43222ef8a26SHangbin Liu    }
4331c43d471SHangbin Liu    linkinfo = do_get(ynl, args, 'linkinfo-get')
43422ef8a26SHangbin Liu    print(f'Port: {ports.get(linkinfo["port"], "Other")}')
43522ef8a26SHangbin Liu
43622ef8a26SHangbin Liu    print_field(linkinfo, ('phyaddr', 'PHYAD'))
43722ef8a26SHangbin Liu
43822ef8a26SHangbin Liu    transceiver = {
43922ef8a26SHangbin Liu            0: 'Internal',
44022ef8a26SHangbin Liu            1: 'External',
44122ef8a26SHangbin Liu    }
44222ef8a26SHangbin Liu    print(f'Transceiver: {transceiver.get(linkinfo["transceiver"], "Unknown")}')
44322ef8a26SHangbin Liu
44422ef8a26SHangbin Liu    mdix_ctrl = {
44522ef8a26SHangbin Liu            1: 'off',
44622ef8a26SHangbin Liu            2: 'on',
44722ef8a26SHangbin Liu    }
44822ef8a26SHangbin Liu    mdix = mdix_ctrl.get(linkinfo['tp-mdix-ctrl'], None)
44922ef8a26SHangbin Liu    if mdix:
45022ef8a26SHangbin Liu        mdix = mdix + ' (forced)'
45122ef8a26SHangbin Liu    else:
45222ef8a26SHangbin Liu        mdix = mdix_ctrl.get(linkinfo['tp-mdix'], 'Unknown (auto)')
45322ef8a26SHangbin Liu    print(f'MDI-X: {mdix}')
45422ef8a26SHangbin Liu
4551c43d471SHangbin Liu    debug = do_get(ynl, args, 'debug-get')
45622ef8a26SHangbin Liu    msgmask = bits_to_dict(debug.get("msgmask", [])).keys()
45722ef8a26SHangbin Liu    print(f'Current message level: {" ".join(msgmask)}')
45822ef8a26SHangbin Liu
4591c43d471SHangbin Liu    linkstate = do_get(ynl, args, 'linkstate-get')
46022ef8a26SHangbin Liu    detected_states = {
46122ef8a26SHangbin Liu            0: 'no',
46222ef8a26SHangbin Liu            1: 'yes',
46322ef8a26SHangbin Liu    }
46422ef8a26SHangbin Liu    # TODO: wol-get
46522ef8a26SHangbin Liu    detected = detected_states.get(linkstate['link'], 'unknown')
46622ef8a26SHangbin Liu    print(f'Link detected: {detected}')
46722ef8a26SHangbin Liu
46822ef8a26SHangbin Liuif __name__ == '__main__':
46922ef8a26SHangbin Liu    main()
470