Cisco Nexus transceiver temperature

Overview

A customer noticed that some SFPs installed in a Cisco Nexus were particularly 🔥hot🔥 and asked for a command to be able to see the temperature of all the transceivers. Sounds like a good opportunity to write some code!

One of the things I love most about my job is when customers call me with odd requests. These unique challenges are not just a break from the routine; they are fantastic opportunities to learn something new and expand my horizons. Each unusual request is a chance to dive into uncharted territory, solve intriguing problems, and ultimately grow both personally and professionally.

I advised the client to get a monitoring tool that would read all the temperatures by saving them to a database (like LibreNMS, but that did not stop me from fulfilling the request as well.

Python

NXOS includes a Python interpreter to help us working with commands output.

Even better we can use also grep, tr and awk.

Putting it all together, a short script can collect the list of switch interfaces and for each print the current temperature:

 1from cli import *
 2ilist = cli('sh inte status | grep Eth.*connected | grep -v "base-T" | grep -v \. | tr -s " " | awk \'{print $1, $NF}\'')
 3for i in list(filter(None,ilist.split("\n")):
 4    interface,transceiver = i.split(" ")
 5    command=f"show interface {interface} transceiver details | grep Temperature | sort | uniq"
 6    temperature = cli(command)
 7    if temperature:
 8        t = temperature.split()
 9        print(f"{interface}\t{t[1].rstrip()}\t{transceiver}")
10    else:
11	    print(f"{interface}\t{0.0}\t{transceiver}")

Sample output:

 1Eth1/1  43.73   10Gbase-SR
 2Eth1/2  41.83   10Gbase-SR
 3Eth1/5  43.74   10/25Gbase-CSR
 4Eth1/6  44.24   10/25Gbase-CSR
 5Eth1/7  42.25   10Gbase-SR
 6Eth1/8  43.24   10/25Gbase-CSR
 7Eth1/9  0.0     1000base-SX
 8Eth1/10 0.0     1000base-SX
 9Eth1/11 43.19   10/25Gbase-CSR
10Eth1/12 43.58   10/25Gbase-CSR
11Eth1/14 43.08   10/25Gbase-CSR
12Eth1/15 48.69   10Gbase-ER
13Eth1/16 47.57   10Gbase-ER
14Eth1/17 47.74   10Gbase-ER
15Eth1/18 46.90   10Gbase-ER
16Eth1/19 46.48   10Gbase-ER
17Eth1/20 45.55   10Gbase-ER
18Eth1/21 44.68   10Gbase-ER
19Eth1/22 46.55   10Gbase-ER
20Eth1/23 40.28   10/25Gbase-CSR
21Eth1/24 39.89   10/25Gbase-CSR
22Eth1/25 39.75   10/25Gbase-CSR
23Eth1/26 40.30   10/25Gbase-CSR
24Eth1/27 39.26   10/25Gbase-CSR
25Eth1/28 38.82   10/25Gbase-CSR
26Eth1/29 39.49   10Gbase-SR
27Eth1/30 37.12   10Gbase-SR
28Eth1/31 37.75   10/25Gbase-CSR
29Eth1/32 37.77   10/25Gbase-CSR
30Eth1/33 39.18   10Gbase-LR
31Eth1/34 43.75   10Gbase-LR
32Eth1/35 35.86   10Gbase-LR
33Eth1/36 36.57   1000base-SX
34Eth1/37 34.71   1000base-SX
35Eth1/39 34.83   10/25Gbase-CSR
36Eth1/41 35.20   10Gbase-SR
37Eth1/42 35.54   10Gbase-SR
38Eth1/43 36.27   10/25Gbase-CSR
39Eth1/44 37.82   10/25Gbase-CSR
40Eth1/45 37.07   10/25Gbase-CSR
41Eth1/46 38.51   10/25Gbase-CSR
42Eth1/47 34.12   10Gbase-SR
43Eth1/48 36.71   10Gbase-SR
44Eth1/49 37.56   QSFP-100G-SR4
45Eth1/50 39.49   QSFP-100G-SR4
46Eth1/51 64.66   QSFP-100G-DWDM-2
47Eth1/52 68.07   QSFP-100G-DWDM-2
48Eth1/53 46.33   QSFP-100G40G-BIDI
49Eth1/54 48.03   QSFP-100G40G-BIDI

Not all transceivers are equal

Notice that }some SFP don't provide the temperature, so the script writes 0.0 instead. Let's try to understand a little more about it

This is fine:

 1sh inte e1/36 transceiver 
 2
 3Ethernet1/36
 4    transceiver is present
 5    type is 1000base-SX
 6    name is CISCO-OPLINK
 7    part number is 1837022038
 8    revision is 01
 9    serial number is OPM24xxxxxx
10    nominal bitrate is 1300 MBit/sec
11    cisco id is 3
12    cisco extended id number is 4
13    cisco part number is 10-2626-03
14    cisco product id is GLC-SX-MMD
15    cisco version id is V03

This doesn't show the temperature:

 1sh inte e1/9 transceiver 
 2Ethernet1/9
 3    transceiver is present
 4    type is 1000base-SX
 5    name is CISCO-FINISAR
 6    part number is FTLF8519P2BCL-C5
 7    revision is A
 8    serial number is FNS15xxxxxx
 9    nominal bitrate is 1300 MBit/sec
10    cisco id is 3
11    cisco extended id number is 4
12    cisco part number is 30-1301-04
13    cisco product id is GLC-SX-MM
14    cisco version id is V04

Notice that the transceivers are both GLC-SX-MMD but are manufactured by different vendors, CISCO-OPLINK and CISCO-FINISAR.

In this switch we can see }six different manufacturers of optical interfaces, all procured via an official Cisco distributor:

1show interface transceiver | grep CISCO- | sort | uniq
2    name is CISCO-ACCELINK
3    name is CISCO-AVAGO
4    name is CISCO-FINISAR
5    name is CISCO-FOIT
6    name is CISCO-INNOLIGHT
7    name is CISCO-OPLINK

Probably not all SFPs have the same functionality, in our case FINISARs do not show the temperature in the output of the command.

What if we use Json?

As an exercise I tried to redo the same script by taking advantage of NXOS's feature of producing output in JSON format. This way you can avoid using awk, grep,sed, which can be an advantage for those who are not familiar with these commands.

Here's the code:

 1from cli import *
 2ilist = json.loads(cli('sh inte status | json')
 3interfaces = ilist['TABLE_interface']['ROW_interface']
 4# filter only connected interfaces
 5data = [interface for interface in interfaces if interface['state'] == 'connected']
 6data = [interface for interface in interfaces if interface.get('type') and interface.get('type') != '--' and interface.get('type') != '1000base-T']
 7for interface in data:
 8    command=f"show interface {interface.get('interface')} transceiver details | json"
 9    transceiverDetails = json.loads(cli(command)['TABLE_interface']['ROW_interface']
10    if transceiverDetails.get('TABLE_lane'):
11        if isinstance(transceiverDetails.get('TABLE_lane').get('ROW_lane'),list):
12            temperature = transceiverDetails.get('TABLE_lane').get('ROW_lane')[0].get('temperature')
13        else:
14            temperature = transceiverDetails.get('TABLE_lane').get('ROW_lane').get('temperature')
15    else:
16        temperature = 0
17    pid = transceiverDetails.get("cisco_product_id",transceiverDetails.get("type")
18    print(f"{interface.get('interface')}\t{temperature}\t{pid}")

You can see that the obtained JSON sometimes returns a list, and sometimes does not, some intefaces do not contain the temperature so I print the value 0, others do not contain the product ID, which I replaced with the "type" of the interface.

} This clearly shows that the output in JSON is far from optimal for programmability. It would have been more useful and consistent to always return lists, even for a single element, and return Null in the absence of the value, but still creating the key in the dictionary.

In the end the first script is shorter and also more readable, but this is subjective, YMMW.

Wrap up

I really like having GNU and Python scriptig tools on NXOS. It saves me a lot of copying/pasting or exporting command outputs and then processing them on my laptop. The use of JSON has proven useful but requires attention, I prefer it as an approach but it still seems a bit immature, there is room for improvement. The version of NXOS in use is 10.2(5)

Ultimately, the bottom line of this post is that all network engineers should seriously consider supplementing their training with at least the basics of Linux and Python to be more efficient and autonomous.