Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@
* [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 show commands](#sfp-utilities-show-commands)
* [Static DNS Commands](#static-dns-commands)
* [Static DNS config command](#static-dns-config-command)
* [Static DNS show command](#static-dns-show-command)
Expand Down Expand Up @@ -12748,6 +12750,89 @@ 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 show commands

- Show SFP EEPROM hex dump

```
admin@sonic:~$ sfputil show eeprom-hexdump --help
Usage: sfputil show eeprom-hexdump [OPTIONS]
Display EEPROM hexdump of SFP transceiver(s)
Options:
-p, --port <port_name> Display SFP EEPROM hexdump for port <port_name>
-n, --page <page_number> Display SFP EEEPROM hexdump for
<page_number_in_hex>
--help Show this message and exit.
```

```
admin@sonic:~$ sfputil show eeprom-hexdump --port Ethernet0 --page 0
EEPROM hexdump for port Ethernet0 page 0h
Lower page 0h
00000000 11 06 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 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000060 00 00 00 00 00 00 00 00 00 00 00 00 02 00 04 00 |................|
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Upper page 0h
00000080 11 00 23 88 00 00 00 00 00 00 00 00 ff 00 00 00 |..#.............|
00000090 00 00 03 a0 4d 65 6c 6c 61 6e 6f 78 20 20 20 20 |....Mellanox |
000000a0 20 20 20 20 00 00 02 c9 4d 43 50 31 36 30 30 2d | ....MCP1600-|
000000b0 43 30 30 33 20 20 20 20 41 32 06 08 0a 10 00 2e |C003 A2......|
000000c0 0b 00 00 00 4d 54 31 36 32 33 56 53 30 30 37 37 |....MT1623VS0077|
000000d0 39 20 20 20 31 36 30 36 30 34 20 20 00 00 67 60 |9 160604 ..g`|
000000e0 31 32 38 38 36 32 31 35 56 43 42 56 00 00 00 00 |12886215VCBV....|
000000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 30 00 00 |.............0..|
admin@sonic:~$ sfputil show eeprom-hexdump
EEPROM hexdump for module 1
Lower page 0h
00000000 11 06 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 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000060 00 00 00 00 00 00 00 00 00 00 00 00 02 00 04 00 |................|
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Upper page 0h
00000080 11 00 23 88 00 00 00 00 00 00 00 00 ff 00 00 00 |..#.............|
00000090 00 00 03 a0 4d 65 6c 6c 61 6e 6f 78 20 20 20 20 |....Mellanox |
000000a0 20 20 20 20 00 00 02 c9 4d 43 50 31 36 30 30 2d | ....MCP1600-|
000000b0 43 30 30 33 20 20 20 20 41 32 06 08 0a 10 00 2e |C003 A2......|
000000c0 0b 00 00 00 4d 54 31 36 32 33 56 53 30 30 37 37 |....MT1623VS0077|
000000d0 39 20 20 20 31 36 30 36 30 34 20 20 00 00 67 60 |9 160604 ..g`|
000000e0 31 32 38 38 36 32 31 35 56 43 42 56 00 00 00 00 |12886215VCBV....|
000000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 30 00 00 |.............0..|
EEPROM hexdump for module 2
Lower page 0h
00000000 11 07 02 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 2b d6 00 00 82 22 00 00 00 00 |......+...."....|
00000020 00 00 1c 00 1a ea 1a d0 19 64 0d 2f 0d 2f 0d 2f |.........d./././|
00000030 0d 2f 23 0c 24 c3 28 18 27 72 00 00 00 00 00 00 |./#.$.(.'r......|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 |................|
00000060 00 00 ff 00 ff ff ff ff ff 00 00 00 00 00 08 00 |................|
00000070 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Upper page 0h
00000080 11 8c 23 80 00 00 00 00 00 00 00 05 ff 00 00 00 |..#.............|
00000090 00 00 03 00 4d 65 6c 6c 61 6e 6f 78 20 20 20 20 |....Mellanox |
000000a0 20 20 20 20 00 00 02 c9 4d 46 41 31 41 30 30 2d | ....MFA1A00-|
000000b0 43 30 30 33 20 20 20 20 42 32 42 68 0b b8 46 a2 |C003 B2Bh..F.|
000000c0 01 07 f5 9e 4d 54 31 39 30 37 46 54 30 38 30 38 |....MT1907FT0808|
000000d0 32 20 20 20 31 39 30 32 31 35 00 00 0c 10 67 be |2 190215....g.|
000000e0 39 30 32 46 4d 41 32 30 32 4a 36 34 31 31 20 20 |902FMA202J6411 |
000000f0 00 00 00 00 00 00 00 00 00 00 01 00 0e 00 00 00 |................|
...
```

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.
Expand Down
1 change: 1 addition & 0 deletions scripts/generate_dump
Original file line number Diff line number Diff line change
Expand Up @@ -1728,6 +1728,7 @@ main() {
save_cmd "show interface transceiver presence" "interface.xcvrs.presence" &
save_cmd "show interface transceiver eeprom --dom" "interface.xcvrs.eeprom" &
save_cmd "show ip interface -d all" "ip.interface" &
save_cmd "sfputil show eeprom-hexdump" "interface.xcvrs.eeprom.raw" &
wait

save_cmd "lldpctl" "lldpctl" &
Expand Down
190 changes: 168 additions & 22 deletions sfputil/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
ERROR_PORT_CONFIG_LOAD = 4
ERROR_NOT_IMPLEMENTED = 5
ERROR_INVALID_PORT = 6
ERROR_INVALID_PAGE = 7
SMBUS_BLOCK_WRITE_SIZE = 32
# Default host password as per CMIS spec:
# http://www.qsfp-dd.com/wp-content/uploads/2021/05/CMIS5p0.pdf
Expand All @@ -51,6 +52,8 @@

SFF8472_A0_SIZE = 256

EEPROM_DUMP_INDENT = ' ' * 8

# TODO: We should share these maps and the formatting functions between sfputil and sfpshow
QSFP_DD_DATA_MAP = {
'model': 'Vendor PN',
Expand Down Expand Up @@ -678,14 +681,20 @@ def eeprom(port, dump_dom, namespace):

click.echo(output)


# 'eeprom-hexdump' subcommand
@show.command()
@click.option('-p', '--port', metavar='<port_name>', required=True, help="Display SFP EEPROM hexdump for port <port_name>")
@click.option('-p', '--port', metavar='<port_name>', help="Display SFP EEPROM hexdump for port <port_name>")
@click.option('-n', '--page', metavar='<page_number>', help="Display SFP EEEPROM hexdump for <page_number_in_hex>")
def eeprom_hexdump(port, page):
"""Display EEPROM hexdump of SFP transceiver(s) for a given port name and page number"""
output = ""
"""Display EEPROM hexdump of SFP transceiver(s)"""
if port:
dump_eeprom_for_single_port(port, page)
else:
dump_eeprom_for_all_ports(page)


def dump_eeprom_for_single_port(port, page):
if platform_sfputil.is_logical_port(port) == 0:
click.echo("Error: invalid port {}".format(port))
print_all_valid_port_values()
Expand Down Expand Up @@ -729,6 +738,134 @@ def eeprom_hexdump(port, page):

click.echo(output)


def dump_eeprom_for_all_ports(page):
lines = []

if page is not None:
try:
page = int(page)
# Only do simple validation to a given page, user is responsible to make sure the page existence
if page < 0 or page > 255:
click.echo(f"Invalid page {page}")
sys.exit(ERROR_INVALID_PAGE)
except ValueError:
click.echo(f"Page {page} is not a valid number")
sys.exit(ERROR_INVALID_PAGE)

for index, sfp in enumerate(platform_chassis.get_all_sfps()):
try:
presence = sfp.get_presence()
if not presence:
lines.append(f'\nModule {index + 1} not present')
else:
lines.append(f'\nEEPROM hexdump for module {index + 1}')
eeprom_data = dump_sfp_eeprom(sfp, page)
if eeprom_data is None:
lines.append(f'{EEPROM_DUMP_INDENT}N/A\n')
else:
lines.append(eeprom_data)
except NotImplementedError:
lines.append(f'\nModule {index + 1} not supported')
except Exception as e:
lines.append(f'\nModule {index + 1} get EEPROM failed: {e}')

click.echo('\n'.join(lines))


def dump_sfp_eeprom(sfp, page):
api = sfp.get_xcvr_api()
if api is None:
return f'{EEPROM_DUMP_INDENT}N/A\n'

from sonic_platform_base.sonic_xcvr.api.public import sff8636, sff8436, cmis, sff8472
from sonic_platform_base.sonic_xcvr.fields import consts
if isinstance(api, cmis.CmisApi):
if page is None:
if api.is_flat_memory():
pages = [0]
else:
pages = [0, 1, 2, 16, 17]
if api.is_coherent_module():
pages.extend([0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x38, 0x39, 0x3a, 0x3b])
cdb_support = api.xcvr_eeprom.read(consts.CDB_SUPPORT)
if cdb_support != 0:
pages.append(0x9f)
else:
pages = [page]
return dump_eeprom_pages(sfp, pages)
elif isinstance(api, sff8636.Sff8636Api) or isinstance(api, sff8436.Sff8436Api):
if page is None:
if api.is_flat_memory():
pages = [0]
else:
pages = [0, 1, 2, 3]
else:
pages = [page]
return dump_eeprom_pages(sfp, pages)
elif isinstance(api, sff8472.Sff8472Api):
if page is None:
is_active_cable = api.xcvr_eeprom.read(consts.SFP_CABLE_TECH_FIELD) == 'Active Cable'
if is_active_cable:
pages = [0, 1, 2]
else:
pages = [0]
else:
pages = [page]
return dump_eeprom_pages_sff8472(sfp, pages, api.is_flat_memory())


def dump_eeprom_pages(sfp, pages):
lines = []
first = True
for page in pages:
if first:
first = False
else:
lines.append('')
if page == 0:
lines.append(f'{EEPROM_DUMP_INDENT}Lower page 0h')
lines.append(dump_eeprom_single_page(sfp, 0, PAGE_SIZE, 0))
lines.append(f'\n{EEPROM_DUMP_INDENT}Upper page 0h')
lines.append(dump_eeprom_single_page(sfp, PAGE_OFFSET, PAGE_SIZE, PAGE_OFFSET))
else:
lines.append(f'{EEPROM_DUMP_INDENT}Page {page:x}h')
lines.append(dump_eeprom_single_page(sfp, 256 + (page - 1) * PAGE_SIZE, PAGE_SIZE, PAGE_OFFSET))
return '\n'.join(lines)


def dump_eeprom_pages_sff8472(sfp, pages, is_flat_memory):
lines = []
first = True
for page in pages:
if first:
first = False
else:
lines.append('')
if page == 0:
if not is_flat_memory:
lines.append(f'{EEPROM_DUMP_INDENT}A0h dump')
lines.append(dump_eeprom_single_page(sfp, 0, SFF8472_A0_SIZE, 0))
else:
lines.append(f'{EEPROM_DUMP_INDENT}A0h dump')
lines.append(dump_eeprom_single_page(sfp, 0, PAGE_SIZE, 0))
elif page == 1:
lines.append(f'{EEPROM_DUMP_INDENT}A2h dump (lower 128 bytes)')
lines.append(dump_eeprom_single_page(sfp, SFF8472_A0_SIZE, PAGE_SIZE, 0))
elif page == 2:
lines.append(f'{EEPROM_DUMP_INDENT}A2h dump (upper 128 bytes)')
lines.append(dump_eeprom_single_page(sfp, SFF8472_A0_SIZE + PAGE_SIZE, PAGE_SIZE, 0))
return '\n'.join(lines)


def dump_eeprom_single_page(sfp, overall_offset, size, page_offset):
page_data = sfp.read_eeprom(overall_offset, size)
if page_data:
return hexdump(EEPROM_DUMP_INDENT, page_data, page_offset, start_newline=False)
else:
return f'{EEPROM_DUMP_INDENT}Failed to read EEPROM'


def eeprom_hexdump_sff8472(port, physical_port, page):
try:
output = ""
Expand Down Expand Up @@ -799,27 +936,36 @@ def convert_byte_to_valid_ascii_char(byte):
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
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)

return result

# 'presence' subcommand
@show.command()
Expand Down
Loading