Skip to main content

Overview

This solution gathers port status information for fabric extender ports using Forward Networks' Network Query Engine (NQE). This custom query enables the extraction of port status that isn't available by default. By creating a decorator around the query, it becomes easy to identify when fabric extender ports are down, allowing for quicker troubleshooting. This approach provides access to valuable data and reduces the time needed to detect and address port issues.

Benefits 

  • Improved visibility: Gain access to detailed fabric extender port status that is not typically modeled by default, providing critical insights for network management.
  • Faster troubleshooting: Quickly identify and address issues with fabric extender ports through custom queries and decorators, reducing time spent on diagnosing problems.
  • Enhanced network monitoring: Automate the process of monitoring port status with NQE, ensuring consistent oversight of network health and potential port failures.

How it works

This query parses the show FEX details to gather state information of Fabric Extender ports and their respective port status. So in this case, we will get the status of the Port Channel (Po12) and associated ports (Eth3/3 | Eth3/4). To do this, we’ll use custom commands to gather the ports and their status and then add decorators to make it easy to identify the affected ports.  

 

sampleBlock="""
FEX: 100 Description: FEX0100 state: Online
FEX version: 4.2(1)N1(1) 4Switch version: 4.2(1)N1(1)]
FEX Interim version: 4.2(1)N1(0.309)
Switch Interim version: 4.2(1)N1(0.309)
Extender Model: N5K-C5110T-BF-1GE, Extender Serial: JAF1237ABSE
Part No: 73-12009-02
Card Id: 70, Mac Addr: 00:0d:ec:b1:13:02, Num Macs: 64
Module Sw Gen: 12594 Switch Sw Gen: 21]
post level: complete
pinning-mode: static Max-links: 1
Fabric port for control traffic: Eth3/3
Fabric interface state:
Po12 - Interface Up. State: Active
Eth3/3 - Interface Up. State: Active
Eth3/4 - Interface Up. State: Active
Fex Port State Fabric Port Primary Fabric
Eth100/1/1 Up Po12 Po12
Eth100/1/2 Up Po12 Po12
Eth100/1/3 Up Po12 Po12
Eth100/1/4 Up Po12 Po12
Eth100/1/5 Up Po12 Po12
Eth100/1/6 Up Po12 Po12
Eth100/1/7 Up Po12 Po12
Eth100/1/8 Up Po12 Po12
Eth100/1/9 Up Po12 Po12
Eth100/1/10 Up Po12 Po12
Eth100/1/11 Up Po12 Po12
Eth100/1/12 Up Po12 Po12
Eth100/1/13 Up Po12 Po12
Eth100/1/14 Up Po12 Po12
Eth100/1/15 Up Po12 Po12
Eth100/1/16 Up Po12 Po12
Eth100/1/17 Up Po12 Po12
Eth100/1/18 Up Po12 Po12
Eth100/1/19 Up Po12 Po12
Eth100/1/20 Up Po12 Po12
Eth100/1/21 Up Po12 Po12
Eth100/1/22 Up Po12 Po12
Eth100/1/23 Up Po12 Po12
""";
pattern = ```
Fabric interface state:
{poInt:string} - Interface {intStatus:string} State: {intState:string}
```;
foreach block in csampleBlock]
let fexConfig=parseConfigBlocks(OS.NXOS, block)
let matches=blockMatches(fexConfig, pattern)
foreach match in matches
let intStatus = replace(match.data.intStatus, ".", "")
select {
poInt: match.data.poInt,
intStatus: intStatus,
intState: match.data.intState
}

 

 

Check out these other posts using custom commands and decorators:

 

I like this elegant NQE. One question.  Why is it

select {
poInt: match.data.poInt,
intStatus: intStatus,
intState: match.data.intState
}

and not

select {
poInt: match.data.poInt,
intStatus: match.data.intStatus,
intState: match.data.intState
}

?


Hello @NQEwizard 

Yes the intent behind the difference is to remove the period or “.” from the data source. Its used as a replacement filler. Your alternative option works as well. 


i wanted to show capture a little more information for the port-channel used for the FEXs and in particular with FEX it related to. So i choose to see if i could extend this NQE.

I have two patterns

  • to match the fexID
  • to match the details such as the port-channel and the interfaces that are listed for it.

In addition, some of the fields caused me issues because we have devices with descriptions that have spaces, so i removed some of the items we can collect in the patterns to avoid complication. I also indented the patterns as I believe it’s needed based on the output of the custom command i choose, which is “show fex detail”.

I used a couple of functions to split the data based on the fexID into port-channel ID and interfaces that are within it, see getPortChannel and getMembers.

I further extract interfaces to group by the state, so we cna then consider any interface that isn’t UP within the port-channel as a violation and produce a message to go with it. 

// placeholder for custom command that was run
customCommand = "show fex detail";

// extract interfaces for a fexId that match Po
getPortChannel(matches, fexId) =
min(foreach match in matches
where match.data.fexId == fexId
where prefix(match.data.interfaceName, 2) == "Po"
select match);

// extract interfaces for a fexId that do not match Po
getMembers(matches, fexId) =
foreach match in matches
where match.data.fexId == fexId
where prefix(match.data.interfaceName, 2) != "Po"
select match;

// pattern to grab fexId and interfaces in the channel along with their status.
patternInterfaces =
```
FEX: {fexId:number}
Fabric interface state:
{interfaceName:string} - Interface {status:string} State: {state:string}
```;

// pattern to grab the fexId's
patternFex = ```
FEX: {fexId:number}
```;

foreach device in network.devices
where device.platform.os == OS.NXOS
foreach command in device.outputs.commands
where command.commandText == customCommand
let parsedResponse = parseConfigBlocks(device.platform.os, command.response)
// get all the FEX IDs
let matchesFexIDs = blockMatches(parsedResponse, patternFex)
let matchesPortChannel = blockMatches(parsedResponse, patternInterfaces)
let matchesMembers = blockMatches(parsedResponse, patternInterfaces)
foreach match in matchesFexIDs
let portChannel = getPortChannel(matchesPortChannel, match.data.fexId)
let members = getMembers(matchesMembers, match.data.fexId)
// get the port channels members and group by status, and extract the status and interfaceName
let membersByStatus = (foreach member in members
group member.data.interfaceName as interfaceName
by member.data.status as status
select {
interfaceName: interfaceName,
status: replace(status, ".", "")
})
// obtain interface stated as Up
let enabledMembers = min(foreach member in membersByStatus
where member.status == "Up"
select member)
// get the members that do not have the Up status
let disabledMembers = min(foreach member in membersByStatus
where member.status != "Up"
select member)
// violation is when any member is not in the Up state
let violation = isPresent(disabledMembers)
let violationMessage = if violation
then join(" ", n"PortChannel for",
toString(match.data.fexId),
"has",
toString(length(members)),
"but",
toString(length(disabledMembers.interfaceName)),
"are not enabled"
])
else ""
// ouptut the results
select {
deviceName: device.name,
fexId: match.data.fexId,
portChannelName: portChannel.data.interfaceName,
portChannelStatus: replace(portChannel.data.status, ".", ""),
portChannelState: portChannel.data.state,
enabledMembers: if isPresent(enabledMembers)
then join(", ", enabledMembers.interfaceName)
else "",
disabledMembers: if isPresent(disabledMembers)
then join(", ", disabledMembers.interfaceName)
else "",
violation: violation,
violationMessage: violationMessage
}

I hope this is interesting to others.

Caveat: I’ve not tested this on any device that causes a violation, so please advise if that logic is not correct should you use this.


Reply