This is to discuss a common practice with the use of the interface Description field.
It is really common to look at CDP or LLDP and find the neighbor device name, then put that remote device name into the interface Description of the interface that connects these two devices together. It is also common to add the remote device interface as well.
/**
* @intent Verify if the interface description includes the device name of the linked device
* @description Use the Link element of the data model to determine the device name and interface
* of a networking device that is connected to this interface.
* Verify that the remote device name and remote interface an included in the interface Description.
*/
export getL3Interfaces(device: Device) =
foreach iface in device.interfaces
where length(iface.links) > 0
foreach ifaceIpInfo in getSvis(iface) + getSubIfaces(iface)
select {
name: ifaceIpInfo.name,
adminStatus: ifaceIpInfo.adminStatus,
operStatus: ifaceIpInfo.operStatus,
ipv4: ifaceIpInfo.ipv4,
ipv6: ifaceIpInfo.ipv6,
descr: ifaceIpInfo.descr,
vrf: ifaceIpInfo.vrf,
vlan: ifaceIpInfo.vlan,
acls: ifaceIpInfo.acls,
iface,
subIface: ifaceIpInfo.subIface,
remoteDevice: max(foreach link in iface.links
select link.deviceName),
remoteIface: max(foreach link in iface.links
select link.ifaceName)
};
getSubIfaces(iface) =
foreach subIface in iface.subinterfaces
select {
name: subIface.name,
adminStatus: subIface.adminStatus,
operStatus: subIface.operStatus,
ipv4: subIface.ipv4,
ipv6: subIface.ipv6,
descr: subIface.description,
vrf: subIface.networkInstanceName,
vlan: if isPresent(subIface.vlan)
then when subIface.vlan is VLAN_ID(v) -> v; otherwise -> null : Number
else null : Number,
acls: subIface.acls,
subIface
};
getSvis(iface) =
foreach x in b1] // If not SVI return empty list
where isPresent(iface.routedVlan)
select {
name: iface.name,
adminStatus: iface.adminStatus,
operStatus: iface.operStatus,
ipv4: iface.routedVlan.ipv4,
ipv6: iface.routedVlan.ipv6,
descr: iface.description,
vrf: iface.routedVlan.networkInstanceName,
vlan: iface.routedVlan.vlan,
acls: iface.acls,
subIface: null : SubInterface
};
foreach device in network.devices
where device.platform.os == OS.IOS_XE
foreach iface in getL3Interfaces(device)
let remoteDeviceInDescr = if isPresent(iface.descr)
then matches(toLowerCase(iface.descr), "*" +
toLowerCase(iface.remoteDevice) +
"*")
else false
let remoteIfaceInDescr = if isPresent(iface.descr)
then matches(toLowerCase(iface.descr), "*" +
toLowerCase(iface.remoteIface) +
"*")
else false
let ifaceIP = max(iface.ipv4.addresses)
select {
remoteDeviceInDescr,
remoteIfaceInDescr,
device: device.name,
name: iface.name,
subIface: max(iface.subIface.aliases),
remoteDevice: iface.remoteDevice,
remoteIface: iface.remoteIface,
adminStatus: iface.adminStatus,
operStatus: iface.operStatus,
ipv4: if isPresent(ifaceIP)
then ipSubnet(ifaceIP?.ip, ifaceIP?.prefixLength)
else null : IpSubnet,
ipv6: iface.ipv6,
descr: iface.descr,
vrf: iface.vrf,
vlan: iface.vlan
}
An important line in this output is this
let remoteDeviceInDescr = if isPresent(iface.descr)
then matches(toLowerCase(iface.descr), "*" +
toLowerCase(iface.remoteDevice) +
"*")
else false
This is where the comparison is being made. Notice that "toLowerCase" was added to make sure that the elements being compared are using the same case for their alphabetic characters. This piece:
"*" + toLowerCase(iface.remoteDevice) + "*"
The iface.remoteDevice is already a string that was obtained earlier in the NQE query. First the "toLowerCase" is added and then we use the + sign to add a string character of the asterisk. The asterisk is added before and after the device name. This asterisk is a wildcard. This way there may or may not be characters before or after the remote device name.
If the remote device name is "myRouter01" then this search string ends up looking like:
"*myrouter01*"
It will match any of these example interface descriptions:
description myRouter01 Eth1/0
description remote device is myRouter01
description connects to myRouter01 Eth1/0
Then a separate column that is printed in the results of the query is "remoteDeviceInDescr". If it is Passed, then the remote device name is present within the Description field. If the result is Failed, then the device name is not present in the Description field.
There is also a similar column for "remoteIfaceInDescr". This indicates whether the remote interface is in the interface Description field. They are separate checks so that you can look for one, or the other, or both remote device name and remote interface name in the Description field.