diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md index 6784b8faf6..df46f6da80 100644 --- a/doc/Command-Reference.md +++ b/doc/Command-Reference.md @@ -202,6 +202,9 @@ * [MACsec config command](#macsec-config-command) * [MACsec show command](#macsec-show-command) * [MACsec clear command](#macsec-clear-command) +* [SFP Utilities Commands](#sfp-utilities-commands) + * [SFP Utilities read command](#sfp-utilities-read-command) + * [SFP Utilities write command](#sfp-utilities-write-command) * [Static DNS Commands](#static-dns-commands) * [Static DNS config command](#static-dns-config-command) * [Static DNS show command](#static-dns-show-command) @@ -12793,6 +12796,78 @@ Clear MACsec counters which is to reset all MACsec counters to ZERO. Go Back To [Beginning of the document](#) or [Beginning of this section](#macsec-commands) +# SFP Utilities Commands + +This sub-section explains the list of commands available for SFP utilities feature. + +# SFP Utilities read command + +- Read SFP EEPROM data + +``` +admin@sonic:~$ sfputil read-eeprom --help +Usage: sfputil read-eeprom [OPTIONS] + + Read SFP EEPROM data + +Options: + -p, --port Logical port name [required] + -n, --page EEPROM page number [required] + -o, --offset EEPROM offset within the page [required] + -s, --size Size of byte to be read [required] + --no-format Display non formatted data + --wire-addr TEXT Wire address of sff8472 + --help Show this message and exit. +``` + +``` +admin@sonic:~$ sfputil read-eeprom -p Ethernet0 -n 0 -o 100 -s 2 + 00000064 4a 44 |..| + +admin@sonic:~$ sfputil read-eeprom --port Ethernet0 --page 0 --offset 0 --size 32 + 00000000 11 08 06 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + +admin@sonic:~$ sfputil read-eeprom --port Ethernet0 --page 0 --offset 100 --size 2 --no-format +4a44 +``` + +# SFP Utilities write command + +- Write SFP EEPROM data + +``` +admin@sonic:~$ sfputil write-eeprom --help +Usage: sfputil write-eeprom [OPTIONS] + + Write SFP EEPROM data + +Options: + -p, --port Logical port name [required] + -n, --page EEPROM page number [required] + -o, --offset EEPROM offset within the page [required] + -d, --data Hex string EEPROM data [required] + --wire-addr TEXT Wire address of sff8472 + --verify Verify the data by reading back + --help Show this message and exit. +``` + +- Write success +``` +admin@sonic:~$ sfputil write-eeprom -p Ethernet0 -n 0 -o 100 -d 4a44 + +admin@sonic:~$ sfputil write-eeprom --port Etherent0 --page 0 --offset 100 --data 0000 --verify + +``` + +- Write fail +``` +admin@sonic:~$ sfputil write-eeprom -p Etherent0 -n 0 -o 100 -d 4a44 --verify +Error: Write data failed! Write: 4a44, read: 0000. +``` + +Go Back To [Beginning of the document](#) or [Beginning of this section](#sfp-utilities-commands) + # Static DNS Commands This sub-section explains the list of the configuration options available for static DNS feature. diff --git a/sfputil/main.py b/sfputil/main.py index 454287cae2..ad227e4163 100644 --- a/sfputil/main.py +++ b/sfputil/main.py @@ -50,6 +50,15 @@ PAGE_OFFSET = 128 SFF8472_A0_SIZE = 256 +MAX_EEPROM_PAGE = 255 +MAX_EEPROM_OFFSET = 255 +MIN_OFFSET_FOR_NON_PAGE0 = 128 +MAX_OFFSET_FOR_A0H_UPPER_PAGE = 255 +MAX_OFFSET_FOR_A0H_LOWER_PAGE = 127 +MAX_OFFSET_FOR_A2H = 255 +PAGE_SIZE_FOR_A0H = 256 + +EEPROM_DUMP_INDENT = ' ' * 8 # TODO: We should share these maps and the formatting functions between sfputil and sfpshow QSFP_DD_DATA_MAP = { @@ -793,33 +802,62 @@ def eeprom_hexdump_sff8636(port, physical_port, page): return output + +def eeprom_dump_general(physical_port, page, overall_offset, size, page_offset, no_format=False): + """ + Dump module EEPROM for given pages in hex format. + Args: + logical_port_name: logical port name + pages: a list of pages to be dumped. The list always include a default page list and the target_page input by + user + target_page: user input page number, optional. target_page is only for display purpose + Returns: + tuple(0, dump string) if success else tuple(error_code, error_message) + """ + sfp = platform_chassis.get_sfp(physical_port) + page_dump = sfp.read_eeprom(overall_offset, size) + if page_dump is None: + return ERROR_NOT_IMPLEMENTED, f'Error: Failed to read EEPROM for page {page:x}h, overall_offset {overall_offset}, page_offset {page_offset}, size {size}!' + if not no_format: + return 0, hexdump(EEPROM_DUMP_INDENT, page_dump, page_offset, start_newline=False) + else: + return 0, ''.join('{:02x}'.format(x) for x in page_dump) + + def convert_byte_to_valid_ascii_char(byte): if byte < 32 or 126 < byte: return '.' else: return chr(byte) -def hexdump(indent, data, mem_address): - ascii_string = '' - result = '' - for byte in data: - ascii_string = ascii_string + convert_byte_to_valid_ascii_char(byte) - byte_string = "{:02x}".format(byte) - if mem_address % 16 == 0: - mem_address_string = "{:08x}".format(mem_address) - result += '\n{}{} '.format(indent, mem_address_string) - result += '{} '.format(byte_string) - elif mem_address % 16 == 15: - result += '{} '.format(byte_string) - result += '|{}|'.format(ascii_string) - ascii_string = "" - elif mem_address % 16 == 8: - result += ' {} '.format(byte_string) +def hexdump(indent, data, mem_address, start_newline=True): + size = len(data) + offset = 0 + lines = [''] if start_newline else [] + while size > 0: + offset_str = "{}{:08x}".format(indent, mem_address) + if size >= 16: + first_half = ' '.join("{:02x}".format(x) for x in data[offset:offset + 8]) + second_half = ' '.join("{:02x}".format(x) for x in data[offset + 8:offset + 16]) + ascii_str = ''.join(convert_byte_to_valid_ascii_char(x) for x in data[offset:offset + 16]) + lines.append(f'{offset_str} {first_half} {second_half} |{ascii_str}|') + elif size > 8: + first_half = ' '.join("{:02x}".format(x) for x in data[offset:offset + 8]) + second_half = ' '.join("{:02x}".format(x) for x in data[offset + 8:offset + size]) + padding = ' ' * (16 - size) + ascii_str = ''.join(convert_byte_to_valid_ascii_char(x) for x in data[offset:offset + size]) + lines.append(f'{offset_str} {first_half} {second_half}{padding} |{ascii_str}|') + break else: - result += '{} '.format(byte_string) - mem_address += 1 - - return result + hex_part = ' '.join("{:02x}".format(x) for x in data[offset:offset + size]) + padding = ' ' * (16 - size) + ascii_str = ''.join(convert_byte_to_valid_ascii_char(x) for x in data[offset:offset + size]) + lines.append(f'{offset_str} {hex_part} {padding} |{ascii_str}|') + break + size -= 16 + offset += 16 + mem_address += 16 + return '\n'.join(lines) # 'presence' subcommand @show.command() @@ -1564,5 +1602,177 @@ def target(port_name, target): click.echo("Target Mode set failed!") sys.exit(EXIT_FAIL) + +# 'read-eeprom' subcommand +@cli.command() +@click.option('-p', '--port', metavar='', help="Logical port name", required=True) +@click.option('-n', '--page', metavar='', type=click.IntRange(0, MAX_EEPROM_PAGE), help="EEPROM page number", required=True) +@click.option('-o', '--offset', metavar='', type=click.IntRange(0, MAX_EEPROM_OFFSET), help="EEPROM offset within the page", required=True) +@click.option('-s', '--size', metavar='', type=click.IntRange(1, MAX_EEPROM_OFFSET + 1), help="Size of byte to be read", required=True) +@click.option('--no-format', is_flag=True, help="Display non formatted data") +@click.option('--wire-addr', help="Wire address of sff8472") +def read_eeprom(port, page, offset, size, no_format, wire_addr): + """Read SFP EEPROM data + """ + try: + if platform_sfputil.is_logical_port(port) == 0: + click.echo("Error: invalid port {}".format(port)) + print_all_valid_port_values() + sys.exit(ERROR_INVALID_PORT) + + if is_port_type_rj45(port): + click.echo("This functionality is not applicable for RJ45 port {}.".format(port)) + sys.exit(EXIT_FAIL) + + physical_port = logical_port_to_physical_port_index(port) + sfp = platform_chassis.get_sfp(physical_port) + if not sfp.get_presence(): + click.echo("{}: SFP EEPROM not detected\n".format(port)) + sys.exit(EXIT_FAIL) + + from sonic_platform_base.sonic_xcvr.api.public import sff8472 + api = sfp.get_xcvr_api() + if api is None: + click.echo('Error: SFP EEPROM not detected!') + if not isinstance(api, sff8472.Sff8472Api): + overall_offset = get_overall_offset_general(api, page, offset, size) + else: + overall_offset = get_overall_offset_sff8472(api, page, offset, size, wire_addr) + return_code, output = eeprom_dump_general(physical_port, page, overall_offset, size, offset, no_format) + if return_code != 0: + click.echo("Error: Failed to read EEPROM!") + sys.exit(return_code) + click.echo(output) + except NotImplementedError: + click.echo("This functionality is currently not implemented for this platform") + sys.exit(ERROR_NOT_IMPLEMENTED) + except ValueError as e: + click.echo(f"Error: {e}") + sys.exit(EXIT_FAIL) + + +# 'write-eeprom' subcommand +@cli.command() +@click.option('-p', '--port', metavar='', help="Logical port name", required=True) +@click.option('-n', '--page', metavar='', type=click.IntRange(0, MAX_EEPROM_PAGE), help="EEPROM page number", required=True) +@click.option('-o', '--offset', metavar='', type=click.IntRange(0, MAX_EEPROM_OFFSET), help="EEPROM offset within the page", required=True) +@click.option('-d', '--data', metavar='', help="Hex string EEPROM data", required=True) +@click.option('--wire-addr', help="Wire address of sff8472") +@click.option('--verify', is_flag=True, help="Verify the data by reading back") +def write_eeprom(port, page, offset, data, wire_addr, verify): + """Write SFP EEPROM data""" + try: + if platform_sfputil.is_logical_port(port) == 0: + click.echo("Error: invalid port {}".format(port)) + print_all_valid_port_values() + sys.exit(ERROR_INVALID_PORT) + + if is_port_type_rj45(port): + click.echo("This functionality is not applicable for RJ45 port {}.".format(port)) + sys.exit(EXIT_FAIL) + + physical_port = logical_port_to_physical_port_index(port) + sfp = platform_chassis.get_sfp(physical_port) + if not sfp.get_presence(): + click.echo("{}: SFP EEPROM not detected\n".format(port)) + sys.exit(EXIT_FAIL) + + try: + bytes = bytearray.fromhex(data) + except ValueError: + click.echo("Error: Data must be a hex string of even length!") + sys.exit(EXIT_FAIL) + + from sonic_platform_base.sonic_xcvr.api.public import sff8472 + api = sfp.get_xcvr_api() + if api is None: + click.echo('Error: SFP EEPROM not detected!') + sys.exit(EXIT_FAIL) + + if not isinstance(api, sff8472.Sff8472Api): + overall_offset = get_overall_offset_general(api, page, offset, len(bytes)) + else: + overall_offset = get_overall_offset_sff8472(api, page, offset, len(bytes), wire_addr) + success = sfp.write_eeprom(overall_offset, len(bytes), bytes) + if not success: + click.echo("Error: Failed to write EEPROM!") + sys.exit(ERROR_NOT_IMPLEMENTED) + if verify: + read_data = sfp.read_eeprom(overall_offset, len(bytes)) + if read_data != bytes: + click.echo(f"Error: Write data failed! Write: {''.join('{:02x}'.format(x) for x in bytes)}, read: {''.join('{:02x}'.format(x) for x in read_data)}") + sys.exit(EXIT_FAIL) + except NotImplementedError: + click.echo("This functionality is currently not implemented for this platform") + sys.exit(ERROR_NOT_IMPLEMENTED) + except ValueError as e: + click.echo("Error: {}".format(e)) + sys.exit(EXIT_FAIL) + + +def get_overall_offset_general(api, page, offset, size): + """ + Validate input parameter page, offset, size and translate them to overall offset + Args: + api: cable API object + page: module EEPROM page number. + offset: module EEPROM page offset. + size: number bytes of the data to be read/write + + Returns: + The overall offset + """ + if api.is_flat_memory(): + if page != 0: + raise ValueError(f'Invalid page number {page}, only page 0 is supported') + + if page != 0: + if offset < MIN_OFFSET_FOR_NON_PAGE0: + raise ValueError(f'Invalid offset {offset} for page {page}, valid range: [128, 255]') + + if size + offset - 1 > MAX_EEPROM_OFFSET: + raise ValueError(f'Invalid size {size}, valid range: [1, {255 - offset + 1}]') + + return page * PAGE_SIZE + offset + + +def get_overall_offset_sff8472(api, page, offset, size, wire_addr): + """ + Validate input parameter page, offset, size, wire_addr and translate them to overall offset + Args: + api: cable API object + page: module EEPROM page number. + offset: module EEPROM page offset. + size: number bytes of the data to be read/write + wire_addr: case-insensitive wire address string. Only valid for sff8472, a0h or a2h. + + Returns: + The overall offset + """ + if not wire_addr: + raise ValueError("Invalid wire address for sff8472, must a0h or a2h") + + is_active_cable = not api.is_copper() + valid_wire_address = ('a0h', 'a2h') if is_active_cable else ('a0h',) + wire_addr = wire_addr.lower() + if wire_addr not in valid_wire_address: + raise ValueError(f"Invalid wire address {wire_addr} for sff8472, must be {' or '.join(valid_wire_address)}") + + if wire_addr == 'a0h': + if page != 0: + raise ValueError(f'Invalid page number {page} for wire address {wire_addr}, only page 0 is supported') + max_offset = MAX_OFFSET_FOR_A0H_UPPER_PAGE if is_active_cable else MAX_OFFSET_FOR_A0H_LOWER_PAGE + if offset > max_offset: + raise ValueError(f'Invalid offset {offset} for wire address {wire_addr}, valid range: [0, {max_offset}]') + if size + offset - 1 > max_offset: + raise ValueError( + f'Invalid size {size} for wire address {wire_addr}, valid range: [1, {max_offset - offset + 1}]') + return offset + else: + if size + offset - 1 > MAX_OFFSET_FOR_A2H: + raise ValueError(f'Invalid size {size} for wire address {wire_addr}, valid range: [1, {255 - offset + 1}]') + return page * PAGE_SIZE + offset + PAGE_SIZE_FOR_A0H + + if __name__ == '__main__': cli() diff --git a/tests/sfputil_test.py b/tests/sfputil_test.py index bed8e994d7..10ca69240b 100644 --- a/tests/sfputil_test.py +++ b/tests/sfputil_test.py @@ -968,6 +968,271 @@ def test_update_firmware_info_to_state_db(self, mock_chassis): sfputil.update_firmware_info_to_state_db("Ethernet0") + @patch('sfputil.main.is_port_type_rj45', MagicMock(return_value=False)) + @patch('sfputil.main.logical_port_to_physical_port_index', MagicMock(return_value=1)) + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=1))) + @patch('sfputil.main.platform_chassis') + def test_read_eeprom(self, mock_chassis): + mock_sfp = MagicMock() + mock_chassis.get_sfp = MagicMock(return_value=mock_sfp) + + mock_sfp.get_presence = MagicMock(return_value=False) + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '1']) + assert result.exit_code == EXIT_FAIL + + mock_sfp.get_presence.return_value = True + mock_sfp.read_eeprom = MagicMock(return_value=None) + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '1']) + assert result.exit_code == ERROR_NOT_IMPLEMENTED + + mock_sfp.read_eeprom.return_value = bytearray([0x00, 0x01]) + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '2', '--no-format']) + assert result.exit_code == 0 + assert result.output == '0001\n' + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '5', '-s', '2']) + assert result.exit_code == 0 + expected_output = """ 00000005 00 01 |..| +""" + print(result.output) + assert result.output == expected_output + + mock_sfp.read_eeprom.side_effect = NotImplementedError + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '5', '-s', '2']) + assert result.exit_code == ERROR_NOT_IMPLEMENTED + + mock_sfp.read_eeprom.side_effect = ValueError + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '5', '-s', '2']) + assert result.exit_code == EXIT_FAIL + + @patch('sfputil.main.is_port_type_rj45', MagicMock(return_value=False)) + @patch('sfputil.main.logical_port_to_physical_port_index', MagicMock(return_value=1)) + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=1))) + @patch('sfputil.main.platform_chassis') + def test_write_eeprom(self, mock_chassis): + mock_sfp = MagicMock() + mock_chassis.get_sfp = MagicMock(return_value=mock_sfp) + + mock_sfp.get_presence = MagicMock(return_value=False) + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '01']) + assert result.exit_code == EXIT_FAIL + + # invalid hex string, hex string must have even length + mock_sfp.get_presence.return_value = True + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '1']) + assert result.exit_code == EXIT_FAIL + + # invalid hex string + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '+0']) + assert result.exit_code == EXIT_FAIL + + # write failed + mock_sfp.write_eeprom = MagicMock(return_value=False) + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '10']) + print(result.output) + assert result.exit_code == ERROR_NOT_IMPLEMENTED + + # write success + mock_sfp.write_eeprom.return_value = True + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '10']) + assert result.exit_code == 0 + + # write verify success + mock_sfp.read_eeprom = MagicMock(return_value=bytearray([16])) + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '10', '--verify']) + assert result.exit_code == 0 + + # write verify failed + mock_sfp.read_eeprom = MagicMock(return_value=bytearray([10])) + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '11', '--verify']) + assert result.exit_code != 0 + + # Not implemented + mock_sfp.write_eeprom.side_effect = NotImplementedError + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '10']) + assert result.exit_code == ERROR_NOT_IMPLEMENTED + + # Value error + mock_sfp.write_eeprom.side_effect = ValueError + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '10']) + assert result.exit_code == EXIT_FAIL + + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=0))) + def test_read_eeprom_invalid_port(self): + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '1']) + assert result.exit_code == ERROR_INVALID_PORT + + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=0))) + def test_write_eeprom_invalid_port(self): + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '00']) + assert result.exit_code == ERROR_INVALID_PORT + + @patch('sfputil.main.is_port_type_rj45', MagicMock(return_value=True)) + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=1))) + def test_read_eeprom_rj45(self): + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '1']) + assert result.exit_code == EXIT_FAIL + + @patch('sfputil.main.is_port_type_rj45', MagicMock(return_value=True)) + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=1))) + def test_write_eeprom_rj45(self): + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-d', '00']) + assert result.exit_code == EXIT_FAIL + + @patch('sfputil.main.is_port_type_rj45', MagicMock(return_value=False)) + @patch('sfputil.main.logical_port_to_physical_port_index', MagicMock(return_value=1)) + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=1))) + @patch('sfputil.main.platform_chassis') + def test_get_overall_offset_general(self, mock_chassis): + api = MagicMock() + api.is_flat_memory = MagicMock(return_value=False) + mock_sfp = MagicMock() + mock_chassis.get_sfp = MagicMock(return_value=mock_sfp) + + mock_sfp.get_presence = MagicMock(return_value=True) + mock_sfp.get_xcvr_api = MagicMock(return_value=api) + + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '-1', '-o', '0', '-d', '01']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '256', '-o', '0', '-d', '01']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '-1', '-d', '01']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '256', '-d', '01']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '1', '-o', '127', '-d', '01']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '1', '-o', '256', '-d', '01']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '0']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '257']) + assert result.exit_code != 0 + + result = runner.invoke(sfputil.cli.commands['write-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '1', '-d', '01']) + assert result.exit_code == 0 + + @patch('sfputil.main.isinstance', MagicMock(return_value=True)) + @patch('sfputil.main.is_port_type_rj45', MagicMock(return_value=False)) + @patch('sfputil.main.logical_port_to_physical_port_index', MagicMock(return_value=1)) + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=1))) + @patch('sfputil.main.platform_chassis') + def test_get_overall_offset_sff8472(self, mock_chassis): + api = MagicMock() + api.is_copper = MagicMock(return_value=False) + mock_sfp = MagicMock() + mock_chassis.get_sfp = MagicMock(return_value=mock_sfp) + + mock_sfp.get_presence = MagicMock(return_value=True) + mock_sfp.get_xcvr_api = MagicMock(return_value=api) + + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '-n', '0', '-o', '0', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'invalid', '-n', '0', '-o', '0', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'a0h', '-n', '1', '-o', '0', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'A0h', '-n', '0', '-o', '-1', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'A0h', '-n', '0', '-o', '256', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'A0h', '-n', '0', '-o', '0', '-s', '0']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'A0h', '-n', '0', '-o', '0', '-s', '257']) + assert result.exit_code != 0 + print(result.output) + + assert sfputil.get_overall_offset_sff8472(api, 0, 2, 2, wire_addr='A0h') == 2 + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'a2h', '-n', '-1', '-o', '0', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'a2h', '-n', '256', '-o', '0', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'a2h', '-n', '0', '-o', '-1', '-s', '1']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'a2h', '-n', '0', '-o', '0', '-s', '0']) + assert result.exit_code != 0 + print(result.output) + + result = runner.invoke(sfputil.cli.commands['read-eeprom'], + ['-p', "Ethernet0", '--wire-addr', 'a2h', '-n', '0', '-o', '0', '-s', '257']) + assert result.exit_code != 0 + print(result.output) + + assert sfputil.get_overall_offset_sff8472(api, 0, 2, 2, wire_addr='A2h') == 258 + @patch('sfputil.main.platform_chassis') @patch('sfputil.main.logical_port_to_physical_port_index', MagicMock(return_value=1)) def test_target_firmware(self, mock_chassis): @@ -998,5 +1263,3 @@ def test_target_firmware(self, mock_chassis): result = runner.invoke(sfputil.cli.commands['firmware'].commands['target'], ["Ethernet0", "1"]) assert result.output == 'Target Mode set failed!\n' assert result.exit_code == EXIT_FAIL - -