From 85a4abed155402d37fef9ea29836dbcdf816cb08 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Wed, 12 Apr 2023 18:22:52 -0700 Subject: tools: ynl: Rename ethtool to ethtool.py Make it explicit that this tool is not a drop-in replacement for ethtool. This tool is intended for testing ethtool functionality implemented in the kernel and should use a name that differentiates it from the ethtool utility. Signed-off-by: Rahul Rameshbabu Link: https://lore.kernel.org/r/20230413012252.184434-2-rrameshbabu@nvidia.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/ethtool | 424 ----------------------------------------------- tools/net/ynl/ethtool.py | 424 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 424 insertions(+), 424 deletions(-) delete mode 100755 tools/net/ynl/ethtool create mode 100755 tools/net/ynl/ethtool.py (limited to 'tools/net') diff --git a/tools/net/ynl/ethtool b/tools/net/ynl/ethtool deleted file mode 100755 index 6c9f7e31250c..000000000000 --- a/tools/net/ynl/ethtool +++ /dev/null @@ -1,424 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause - -import argparse -import json -import pprint -import sys -import re - -from lib import YnlFamily - -def args_to_req(ynl, op_name, args, req): - """ - Verify and convert command-line arguments to the ynl-compatible request. - """ - valid_attrs = ynl.operation_do_attributes(op_name) - valid_attrs.remove('header') # not user-provided - - if len(args) == 0: - print(f'no attributes, expected: {valid_attrs}') - sys.exit(1) - - i = 0 - while i < len(args): - attr = args[i] - if i + 1 >= len(args): - print(f'expected value for \'{attr}\'') - sys.exit(1) - - if attr not in valid_attrs: - print(f'invalid attribute \'{attr}\', expected: {valid_attrs}') - sys.exit(1) - - val = args[i+1] - i += 2 - - req[attr] = val - -def print_field(reply, *desc): - """ - Pretty-print a set of fields from the reply. desc specifies the - fields and the optional type (bool/yn). - """ - if len(desc) == 0: - return print_field(reply, *zip(reply.keys(), reply.keys())) - - for spec in desc: - try: - field, name, tp = spec - except: - field, name = spec - tp = 'int' - - value = reply.get(field, None) - if tp == 'yn': - value = 'yes' if value else 'no' - elif tp == 'bool' or isinstance(value, bool): - value = 'on' if value else 'off' - else: - value = 'n/a' if value is None else value - - print(f'{name}: {value}') - -def print_speed(name, value): - """ - Print out the speed-like strings from the value dict. - """ - speed_re = re.compile(r'[0-9]+base[^/]+/.+') - speed = [ k for k, v in value.items() if v and speed_re.match(k) ] - print(f'{name}: {" ".join(speed)}') - -def doit(ynl, args, op_name): - """ - Prepare request header, parse arguments and doit. - """ - req = { - 'header': { - 'dev-name': args.device, - }, - } - - args_to_req(ynl, op_name, args.args, req) - ynl.do(op_name, req) - -def dumpit(ynl, args, op_name, extra = {}): - """ - Prepare request header, parse arguments and dumpit (filtering out the - devices we're not interested in). - """ - reply = ynl.dump(op_name, { 'header': {} } | extra) - if not reply: - return {} - - for msg in reply: - if msg['header']['dev-name'] == args.device: - if args.json: - pprint.PrettyPrinter().pprint(msg) - sys.exit(0) - msg.pop('header', None) - return msg - - print(f"Not supported for device {args.device}") - sys.exit(1) - -def bits_to_dict(attr): - """ - Convert ynl-formatted bitmask to a dict of bit=value. - """ - ret = {} - if 'bits' not in attr: - return dict() - if 'bit' not in attr['bits']: - return dict() - for bit in attr['bits']['bit']: - if bit['name'] == '': - continue - name = bit['name'] - value = bit.get('value', False) - ret[name] = value - return ret - -def main(): - parser = argparse.ArgumentParser(description='ethtool wannabe') - parser.add_argument('--json', action=argparse.BooleanOptionalAction) - parser.add_argument('--show-priv-flags', action=argparse.BooleanOptionalAction) - parser.add_argument('--set-priv-flags', action=argparse.BooleanOptionalAction) - parser.add_argument('--show-eee', action=argparse.BooleanOptionalAction) - parser.add_argument('--set-eee', action=argparse.BooleanOptionalAction) - parser.add_argument('-a', '--show-pause', action=argparse.BooleanOptionalAction) - parser.add_argument('-A', '--set-pause', action=argparse.BooleanOptionalAction) - parser.add_argument('-c', '--show-coalesce', action=argparse.BooleanOptionalAction) - parser.add_argument('-C', '--set-coalesce', action=argparse.BooleanOptionalAction) - parser.add_argument('-g', '--show-ring', action=argparse.BooleanOptionalAction) - parser.add_argument('-G', '--set-ring', action=argparse.BooleanOptionalAction) - parser.add_argument('-k', '--show-features', action=argparse.BooleanOptionalAction) - parser.add_argument('-K', '--set-features', action=argparse.BooleanOptionalAction) - parser.add_argument('-l', '--show-channels', action=argparse.BooleanOptionalAction) - parser.add_argument('-L', '--set-channels', action=argparse.BooleanOptionalAction) - parser.add_argument('-T', '--show-time-stamping', action=argparse.BooleanOptionalAction) - parser.add_argument('-S', '--statistics', action=argparse.BooleanOptionalAction) - # TODO: --show-tunnels tunnel-info-get - # TODO: --show-module module-get - # TODO: --get-plca-cfg plca-get - # TODO: --get-plca-status plca-get-status - # TODO: --show-mm mm-get - # TODO: --show-fec fec-get - # TODO: --dump-module-eerpom module-eeprom-get - # TODO: pse-get - # TODO: rss-get - parser.add_argument('device', metavar='device', type=str) - parser.add_argument('args', metavar='args', type=str, nargs='*') - global args - args = parser.parse_args() - - spec = '../../../Documentation/netlink/specs/ethtool.yaml' - schema = '../../../Documentation/netlink/genetlink-legacy.yaml' - - ynl = YnlFamily(spec, schema) - - if args.set_priv_flags: - # TODO: parse the bitmask - print("not implemented") - return - - if args.set_eee: - return doit(ynl, args, 'eee-set') - - if args.set_pause: - return doit(ynl, args, 'pause-set') - - if args.set_coalesce: - return doit(ynl, args, 'coalesce-set') - - if args.set_features: - # TODO: parse the bitmask - print("not implemented") - return - - if args.set_channels: - return doit(ynl, args, 'channels-set') - - if args.set_ring: - return doit(ynl, args, 'rings-set') - - if args.show_priv_flags: - flags = bits_to_dict(dumpit(ynl, args, 'privflags-get')['flags']) - print_field(flags) - return - - if args.show_eee: - eee = dumpit(ynl, args, 'eee-get') - ours = bits_to_dict(eee['modes-ours']) - peer = bits_to_dict(eee['modes-peer']) - - if 'enabled' in eee: - status = 'enabled' if eee['enabled'] else 'disabled' - if 'active' in eee and eee['active']: - status = status + ' - active' - else: - status = status + ' - inactive' - else: - status = 'not supported' - - print(f'EEE status: {status}') - print_field(eee, ('tx-lpi-timer', 'Tx LPI')) - print_speed('Advertised EEE link modes', ours) - print_speed('Link partner advertised EEE link modes', peer) - - return - - if args.show_pause: - print_field(dumpit(ynl, args, 'pause-get'), - ('autoneg', 'Autonegotiate', 'bool'), - ('rx', 'RX', 'bool'), - ('tx', 'TX', 'bool')) - return - - if args.show_coalesce: - print_field(dumpit(ynl, args, 'coalesce-get')) - return - - if args.show_features: - reply = dumpit(ynl, args, 'features-get') - available = bits_to_dict(reply['hw']) - requested = bits_to_dict(reply['wanted']).keys() - active = bits_to_dict(reply['active']).keys() - never_changed = bits_to_dict(reply['nochange']).keys() - - for f in sorted(available): - value = "off" - if f in active: - value = "on" - - fixed = "" - if f not in available or f in never_changed: - fixed = " [fixed]" - - req = "" - if f in requested: - if f in active: - req = " [requested on]" - else: - req = " [requested off]" - - print(f'{f}: {value}{fixed}{req}') - - return - - if args.show_channels: - reply = dumpit(ynl, args, 'channels-get') - print(f'Channel parameters for {args.device}:') - - print(f'Pre-set maximums:') - print_field(reply, - ('rx-max', 'RX'), - ('tx-max', 'TX'), - ('other-max', 'Other'), - ('combined-max', 'Combined')) - - print(f'Current hardware settings:') - print_field(reply, - ('rx-count', 'RX'), - ('tx-count', 'TX'), - ('other-count', 'Other'), - ('combined-count', 'Combined')) - - return - - if args.show_ring: - reply = dumpit(ynl, args, 'channels-get') - - print(f'Ring parameters for {args.device}:') - - print(f'Pre-set maximums:') - print_field(reply, - ('rx-max', 'RX'), - ('rx-mini-max', 'RX Mini'), - ('rx-jumbo-max', 'RX Jumbo'), - ('tx-max', 'TX')) - - print(f'Current hardware settings:') - print_field(reply, - ('rx', 'RX'), - ('rx-mini', 'RX Mini'), - ('rx-jumbo', 'RX Jumbo'), - ('tx', 'TX')) - - print_field(reply, - ('rx-buf-len', 'RX Buf Len'), - ('cqe-size', 'CQE Size'), - ('tx-push', 'TX Push', 'bool')) - - return - - if args.statistics: - print(f'NIC statistics:') - - # TODO: pass id? - strset = dumpit(ynl, args, 'strset-get') - pprint.PrettyPrinter().pprint(strset) - - req = { - 'groups': { - 'size': 1, - 'bits': { - 'bit': - # TODO: support passing the bitmask - #[ - #{ 'name': 'eth-phy', 'value': True }, - { 'name': 'eth-mac', 'value': True }, - #{ 'name': 'eth-ctrl', 'value': True }, - #{ 'name': 'rmon', 'value': True }, - #], - }, - }, - } - - rsp = dumpit(ynl, args, 'stats-get', req) - pprint.PrettyPrinter().pprint(rsp) - return - - if args.show_time_stamping: - tsinfo = dumpit(ynl, args, 'tsinfo-get') - - print(f'Time stamping parameters for {args.device}:') - - print('Capabilities:') - [print(f'\t{v}') for v in bits_to_dict(tsinfo['timestamping'])] - - print(f'PTP Hardware Clock: {tsinfo["phc-index"]}') - - print('Hardware Transmit Timestamp Modes:') - [print(f'\t{v}') for v in bits_to_dict(tsinfo['tx-types'])] - - print('Hardware Receive Filter Modes:') - [print(f'\t{v}') for v in bits_to_dict(tsinfo['rx-filters'])] - return - - print(f'Settings for {args.device}:') - linkmodes = dumpit(ynl, args, 'linkmodes-get') - ours = bits_to_dict(linkmodes['ours']) - - supported_ports = ('TP', 'AUI', 'BNC', 'MII', 'FIBRE', 'Backplane') - ports = [ p for p in supported_ports if ours.get(p, False)] - print(f'Supported ports: [ {" ".join(ports)} ]') - - print_speed('Supported link modes', ours) - - print_field(ours, ('Pause', 'Supported pause frame use', 'yn')) - print_field(ours, ('Autoneg', 'Supports auto-negotiation', 'yn')) - - supported_fec = ('None', 'PS', 'BASER', 'LLRS') - fec = [ p for p in supported_fec if ours.get(p, False)] - fec_str = " ".join(fec) - if len(fec) == 0: - fec_str = "Not reported" - - print(f'Supported FEC modes: {fec_str}') - - speed = 'Unknown!' - if linkmodes['speed'] > 0 and linkmodes['speed'] < 0xffffffff: - speed = f'{linkmodes["speed"]}Mb/s' - print(f'Speed: {speed}') - - duplex_modes = { - 0: 'Half', - 1: 'Full', - } - duplex = duplex_modes.get(linkmodes["duplex"], None) - if not duplex: - duplex = f'Unknown! ({linkmodes["duplex"]})' - print(f'Duplex: {duplex}') - - autoneg = "off" - if linkmodes.get("autoneg", 0) != 0: - autoneg = "on" - print(f'Auto-negotiation: {autoneg}') - - ports = { - 0: 'Twisted Pair', - 1: 'AUI', - 2: 'MII', - 3: 'FIBRE', - 4: 'BNC', - 5: 'Directly Attached Copper', - 0xef: 'None', - } - linkinfo = dumpit(ynl, args, 'linkinfo-get') - print(f'Port: {ports.get(linkinfo["port"], "Other")}') - - print_field(linkinfo, ('phyaddr', 'PHYAD')) - - transceiver = { - 0: 'Internal', - 1: 'External', - } - print(f'Transceiver: {transceiver.get(linkinfo["transceiver"], "Unknown")}') - - mdix_ctrl = { - 1: 'off', - 2: 'on', - } - mdix = mdix_ctrl.get(linkinfo['tp-mdix-ctrl'], None) - if mdix: - mdix = mdix + ' (forced)' - else: - mdix = mdix_ctrl.get(linkinfo['tp-mdix'], 'Unknown (auto)') - print(f'MDI-X: {mdix}') - - debug = dumpit(ynl, args, 'debug-get') - msgmask = bits_to_dict(debug.get("msgmask", [])).keys() - print(f'Current message level: {" ".join(msgmask)}') - - linkstate = dumpit(ynl, args, 'linkstate-get') - detected_states = { - 0: 'no', - 1: 'yes', - } - # TODO: wol-get - detected = detected_states.get(linkstate['link'], 'unknown') - print(f'Link detected: {detected}') - -if __name__ == '__main__': - main() diff --git a/tools/net/ynl/ethtool.py b/tools/net/ynl/ethtool.py new file mode 100755 index 000000000000..6c9f7e31250c --- /dev/null +++ b/tools/net/ynl/ethtool.py @@ -0,0 +1,424 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + +import argparse +import json +import pprint +import sys +import re + +from lib import YnlFamily + +def args_to_req(ynl, op_name, args, req): + """ + Verify and convert command-line arguments to the ynl-compatible request. + """ + valid_attrs = ynl.operation_do_attributes(op_name) + valid_attrs.remove('header') # not user-provided + + if len(args) == 0: + print(f'no attributes, expected: {valid_attrs}') + sys.exit(1) + + i = 0 + while i < len(args): + attr = args[i] + if i + 1 >= len(args): + print(f'expected value for \'{attr}\'') + sys.exit(1) + + if attr not in valid_attrs: + print(f'invalid attribute \'{attr}\', expected: {valid_attrs}') + sys.exit(1) + + val = args[i+1] + i += 2 + + req[attr] = val + +def print_field(reply, *desc): + """ + Pretty-print a set of fields from the reply. desc specifies the + fields and the optional type (bool/yn). + """ + if len(desc) == 0: + return print_field(reply, *zip(reply.keys(), reply.keys())) + + for spec in desc: + try: + field, name, tp = spec + except: + field, name = spec + tp = 'int' + + value = reply.get(field, None) + if tp == 'yn': + value = 'yes' if value else 'no' + elif tp == 'bool' or isinstance(value, bool): + value = 'on' if value else 'off' + else: + value = 'n/a' if value is None else value + + print(f'{name}: {value}') + +def print_speed(name, value): + """ + Print out the speed-like strings from the value dict. + """ + speed_re = re.compile(r'[0-9]+base[^/]+/.+') + speed = [ k for k, v in value.items() if v and speed_re.match(k) ] + print(f'{name}: {" ".join(speed)}') + +def doit(ynl, args, op_name): + """ + Prepare request header, parse arguments and doit. + """ + req = { + 'header': { + 'dev-name': args.device, + }, + } + + args_to_req(ynl, op_name, args.args, req) + ynl.do(op_name, req) + +def dumpit(ynl, args, op_name, extra = {}): + """ + Prepare request header, parse arguments and dumpit (filtering out the + devices we're not interested in). + """ + reply = ynl.dump(op_name, { 'header': {} } | extra) + if not reply: + return {} + + for msg in reply: + if msg['header']['dev-name'] == args.device: + if args.json: + pprint.PrettyPrinter().pprint(msg) + sys.exit(0) + msg.pop('header', None) + return msg + + print(f"Not supported for device {args.device}") + sys.exit(1) + +def bits_to_dict(attr): + """ + Convert ynl-formatted bitmask to a dict of bit=value. + """ + ret = {} + if 'bits' not in attr: + return dict() + if 'bit' not in attr['bits']: + return dict() + for bit in attr['bits']['bit']: + if bit['name'] == '': + continue + name = bit['name'] + value = bit.get('value', False) + ret[name] = value + return ret + +def main(): + parser = argparse.ArgumentParser(description='ethtool wannabe') + parser.add_argument('--json', action=argparse.BooleanOptionalAction) + parser.add_argument('--show-priv-flags', action=argparse.BooleanOptionalAction) + parser.add_argument('--set-priv-flags', action=argparse.BooleanOptionalAction) + parser.add_argument('--show-eee', action=argparse.BooleanOptionalAction) + parser.add_argument('--set-eee', action=argparse.BooleanOptionalAction) + parser.add_argument('-a', '--show-pause', action=argparse.BooleanOptionalAction) + parser.add_argument('-A', '--set-pause', action=argparse.BooleanOptionalAction) + parser.add_argument('-c', '--show-coalesce', action=argparse.BooleanOptionalAction) + parser.add_argument('-C', '--set-coalesce', action=argparse.BooleanOptionalAction) + parser.add_argument('-g', '--show-ring', action=argparse.BooleanOptionalAction) + parser.add_argument('-G', '--set-ring', action=argparse.BooleanOptionalAction) + parser.add_argument('-k', '--show-features', action=argparse.BooleanOptionalAction) + parser.add_argument('-K', '--set-features', action=argparse.BooleanOptionalAction) + parser.add_argument('-l', '--show-channels', action=argparse.BooleanOptionalAction) + parser.add_argument('-L', '--set-channels', action=argparse.BooleanOptionalAction) + parser.add_argument('-T', '--show-time-stamping', action=argparse.BooleanOptionalAction) + parser.add_argument('-S', '--statistics', action=argparse.BooleanOptionalAction) + # TODO: --show-tunnels tunnel-info-get + # TODO: --show-module module-get + # TODO: --get-plca-cfg plca-get + # TODO: --get-plca-status plca-get-status + # TODO: --show-mm mm-get + # TODO: --show-fec fec-get + # TODO: --dump-module-eerpom module-eeprom-get + # TODO: pse-get + # TODO: rss-get + parser.add_argument('device', metavar='device', type=str) + parser.add_argument('args', metavar='args', type=str, nargs='*') + global args + args = parser.parse_args() + + spec = '../../../Documentation/netlink/specs/ethtool.yaml' + schema = '../../../Documentation/netlink/genetlink-legacy.yaml' + + ynl = YnlFamily(spec, schema) + + if args.set_priv_flags: + # TODO: parse the bitmask + print("not implemented") + return + + if args.set_eee: + return doit(ynl, args, 'eee-set') + + if args.set_pause: + return doit(ynl, args, 'pause-set') + + if args.set_coalesce: + return doit(ynl, args, 'coalesce-set') + + if args.set_features: + # TODO: parse the bitmask + print("not implemented") + return + + if args.set_channels: + return doit(ynl, args, 'channels-set') + + if args.set_ring: + return doit(ynl, args, 'rings-set') + + if args.show_priv_flags: + flags = bits_to_dict(dumpit(ynl, args, 'privflags-get')['flags']) + print_field(flags) + return + + if args.show_eee: + eee = dumpit(ynl, args, 'eee-get') + ours = bits_to_dict(eee['modes-ours']) + peer = bits_to_dict(eee['modes-peer']) + + if 'enabled' in eee: + status = 'enabled' if eee['enabled'] else 'disabled' + if 'active' in eee and eee['active']: + status = status + ' - active' + else: + status = status + ' - inactive' + else: + status = 'not supported' + + print(f'EEE status: {status}') + print_field(eee, ('tx-lpi-timer', 'Tx LPI')) + print_speed('Advertised EEE link modes', ours) + print_speed('Link partner advertised EEE link modes', peer) + + return + + if args.show_pause: + print_field(dumpit(ynl, args, 'pause-get'), + ('autoneg', 'Autonegotiate', 'bool'), + ('rx', 'RX', 'bool'), + ('tx', 'TX', 'bool')) + return + + if args.show_coalesce: + print_field(dumpit(ynl, args, 'coalesce-get')) + return + + if args.show_features: + reply = dumpit(ynl, args, 'features-get') + available = bits_to_dict(reply['hw']) + requested = bits_to_dict(reply['wanted']).keys() + active = bits_to_dict(reply['active']).keys() + never_changed = bits_to_dict(reply['nochange']).keys() + + for f in sorted(available): + value = "off" + if f in active: + value = "on" + + fixed = "" + if f not in available or f in never_changed: + fixed = " [fixed]" + + req = "" + if f in requested: + if f in active: + req = " [requested on]" + else: + req = " [requested off]" + + print(f'{f}: {value}{fixed}{req}') + + return + + if args.show_channels: + reply = dumpit(ynl, args, 'channels-get') + print(f'Channel parameters for {args.device}:') + + print(f'Pre-set maximums:') + print_field(reply, + ('rx-max', 'RX'), + ('tx-max', 'TX'), + ('other-max', 'Other'), + ('combined-max', 'Combined')) + + print(f'Current hardware settings:') + print_field(reply, + ('rx-count', 'RX'), + ('tx-count', 'TX'), + ('other-count', 'Other'), + ('combined-count', 'Combined')) + + return + + if args.show_ring: + reply = dumpit(ynl, args, 'channels-get') + + print(f'Ring parameters for {args.device}:') + + print(f'Pre-set maximums:') + print_field(reply, + ('rx-max', 'RX'), + ('rx-mini-max', 'RX Mini'), + ('rx-jumbo-max', 'RX Jumbo'), + ('tx-max', 'TX')) + + print(f'Current hardware settings:') + print_field(reply, + ('rx', 'RX'), + ('rx-mini', 'RX Mini'), + ('rx-jumbo', 'RX Jumbo'), + ('tx', 'TX')) + + print_field(reply, + ('rx-buf-len', 'RX Buf Len'), + ('cqe-size', 'CQE Size'), + ('tx-push', 'TX Push', 'bool')) + + return + + if args.statistics: + print(f'NIC statistics:') + + # TODO: pass id? + strset = dumpit(ynl, args, 'strset-get') + pprint.PrettyPrinter().pprint(strset) + + req = { + 'groups': { + 'size': 1, + 'bits': { + 'bit': + # TODO: support passing the bitmask + #[ + #{ 'name': 'eth-phy', 'value': True }, + { 'name': 'eth-mac', 'value': True }, + #{ 'name': 'eth-ctrl', 'value': True }, + #{ 'name': 'rmon', 'value': True }, + #], + }, + }, + } + + rsp = dumpit(ynl, args, 'stats-get', req) + pprint.PrettyPrinter().pprint(rsp) + return + + if args.show_time_stamping: + tsinfo = dumpit(ynl, args, 'tsinfo-get') + + print(f'Time stamping parameters for {args.device}:') + + print('Capabilities:') + [print(f'\t{v}') for v in bits_to_dict(tsinfo['timestamping'])] + + print(f'PTP Hardware Clock: {tsinfo["phc-index"]}') + + print('Hardware Transmit Timestamp Modes:') + [print(f'\t{v}') for v in bits_to_dict(tsinfo['tx-types'])] + + print('Hardware Receive Filter Modes:') + [print(f'\t{v}') for v in bits_to_dict(tsinfo['rx-filters'])] + return + + print(f'Settings for {args.device}:') + linkmodes = dumpit(ynl, args, 'linkmodes-get') + ours = bits_to_dict(linkmodes['ours']) + + supported_ports = ('TP', 'AUI', 'BNC', 'MII', 'FIBRE', 'Backplane') + ports = [ p for p in supported_ports if ours.get(p, False)] + print(f'Supported ports: [ {" ".join(ports)} ]') + + print_speed('Supported link modes', ours) + + print_field(ours, ('Pause', 'Supported pause frame use', 'yn')) + print_field(ours, ('Autoneg', 'Supports auto-negotiation', 'yn')) + + supported_fec = ('None', 'PS', 'BASER', 'LLRS') + fec = [ p for p in supported_fec if ours.get(p, False)] + fec_str = " ".join(fec) + if len(fec) == 0: + fec_str = "Not reported" + + print(f'Supported FEC modes: {fec_str}') + + speed = 'Unknown!' + if linkmodes['speed'] > 0 and linkmodes['speed'] < 0xffffffff: + speed = f'{linkmodes["speed"]}Mb/s' + print(f'Speed: {speed}') + + duplex_modes = { + 0: 'Half', + 1: 'Full', + } + duplex = duplex_modes.get(linkmodes["duplex"], None) + if not duplex: + duplex = f'Unknown! ({linkmodes["duplex"]})' + print(f'Duplex: {duplex}') + + autoneg = "off" + if linkmodes.get("autoneg", 0) != 0: + autoneg = "on" + print(f'Auto-negotiation: {autoneg}') + + ports = { + 0: 'Twisted Pair', + 1: 'AUI', + 2: 'MII', + 3: 'FIBRE', + 4: 'BNC', + 5: 'Directly Attached Copper', + 0xef: 'None', + } + linkinfo = dumpit(ynl, args, 'linkinfo-get') + print(f'Port: {ports.get(linkinfo["port"], "Other")}') + + print_field(linkinfo, ('phyaddr', 'PHYAD')) + + transceiver = { + 0: 'Internal', + 1: 'External', + } + print(f'Transceiver: {transceiver.get(linkinfo["transceiver"], "Unknown")}') + + mdix_ctrl = { + 1: 'off', + 2: 'on', + } + mdix = mdix_ctrl.get(linkinfo['tp-mdix-ctrl'], None) + if mdix: + mdix = mdix + ' (forced)' + else: + mdix = mdix_ctrl.get(linkinfo['tp-mdix'], 'Unknown (auto)') + print(f'MDI-X: {mdix}') + + debug = dumpit(ynl, args, 'debug-get') + msgmask = bits_to_dict(debug.get("msgmask", [])).keys() + print(f'Current message level: {" ".join(msgmask)}') + + linkstate = dumpit(ynl, args, 'linkstate-get') + detected_states = { + 0: 'no', + 1: 'yes', + } + # TODO: wol-get + detected = detected_states.get(linkstate['link'], 'unknown') + print(f'Link detected: {detected}') + +if __name__ == '__main__': + main() -- cgit v1.2.3