Layer 2 and Layer 3 examples
Number of ARP entries across all devices
let data = `*:/Smash/arp/status/_counts`
sum(data | map(merge(_value)) | where(dictHasKey(_value, "arpEntry")) | map(_value["arpEntry"]))
BGP States
BGP Session Status
let neighbors = `analytics:/Devices/*/versioned-data/routing/bgp/status/vrf/default/bgpPeerInfoStatusEntry/*`
# Dict to store the states and counts
let res = newDict()
# Loop over each device
for device, deviceSessions in neighbors{
# Loop over each session on each device
for ip, sessionData in deviceSessions{
let data = merge(sessionData)
# Have we used this status yet?
let status = data["bgpState"]["Name"]
if !dictHasKey(res, status) {
# If not lets set it use count to zero
res[status] = 0
}
# Add one to the total times this status is used
res[status] = res[status] + 1
}
}
res
BGP Session Details in the Default VRF for all Devices
let devices = merge(`analytics:/tags/labels/devices/pod_name/value/<_POD_NAME>/elements`)
if str(_POD_NAME) == "" {
let bgpNeighbors =`analytics:/Devices/*/versioned-data/routing/bgp/status/vrf/default/bgpPeerInfoStatusEntry/*`
} else {
let bgpNeighbors =`analytics:/Devices/*/versioned-data/routing/bgp/status/vrf/default/bgpPeerInfoStatusEntry/*` | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")))
}
# This is the table
let res = newDict()
let id = 0
# Lets loop over every device
for device, deviceSessions in bgpNeighbors{
# And each session on the devices
for ip, sessionData in deviceSessions{
let data = merge(sessionData)
# Add one to the ID
let id = id + 1
res[id] = newDict()
# This is where we add the various columns
res[id]["0. Device"] = device
res[id]["1. Status"] = data["bgpState"]["Name"]
res[id]["2. Peering Address"] = data["bgpPeerLocalAddr"]
res[id]["3. Neighbor Address"] = data["key"]
res[id]["4. Neighbor AS"] = data["bgpPeerAs"]["value"]
}
}
res
BGP Sessions that are Not Established
let devices = merge(`analytics:/tags/labels/devices/pod_name/value/<_POD_NAME>/elements`)
if str(_POD_NAME) == "" {
let bgpNeighbors =`analytics:/Devices/*/versioned-data/routing/bgp/status/vrf/default/bgpPeerInfoStatusEntry/*`
} else {
let bgpNeighbors =`analytics:/Devices/*/versioned-data/routing/bgp/status/vrf/default/bgpPeerInfoStatusEntry/*` | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")))
}
# This is the table
let res = newDict()
let id = 0
# Lets loop over every device
for device, deviceSessions in bgpNeighbors{
# And each session on the devices
for ip, sessionData in deviceSessions{
let data = merge(sessionData)
# Add one to the ID
let id = id + 1
res[id] = newDict()
# This is where we add the various columns
res[id]["0. Device"] = device
res[id]["1. Status"] = data["bgpState"]["Name"]
res[id]["2. Peering Address"] = data["bgpPeerLocalAddr"]
res[id]["3. Neighbor Address"] = data["key"]
res[id]["4. Neighbor AS"] = data["bgpPeerAs"]["value"]
}
}
res | where(_value["1. Status"] != "Established")
TAC Webinar03 2023 - BGP States
This dashboards helps to provide current and historical BGP status and provides link flap counters.
Note
Some of the BGP states are not streamed by default and the /Smash/routing/bgp/bgpPeerInfoStatus/default/bgpPeerStatisticsEntry
needs to be added to the TerminAttr include list using the tastreaming.TerminattrStreaming service API.
Examples can be found here
Pre-requisites
Devices will need to be tagged with tag label
site_name
and the label value of the site’s name, for example a customer has 3 sites: ABC, DEF, XYZTag
site_name:ALL
to all devicesTag
site_name:ABC
to ABC devicesrepeat for DEF and XYZ
Devices with multiple supervisors upon supervisor failover might not show the correct states
BGP Summary
# set vars
let afis = newDict()
let afi_name = newDict()
let bgpPeerAfiSafiActive = newDict() | setFields("l2vpnEvpn", 3, "ipv4Unicast", 1)
let bgpPeerAfiSafiActiveName = newDict() | setFields("l2vpnEvpn","L2VPN EVPN", "ipv4Unicast", "IPv4 Unicast")
# Get all devices from a specific site
let devices = merge(`analytics:/tags/labels/devices/site_name/value/<_SITE_NAME>/elements`)
let bgpNeighbors =`analytics:/Devices/*/versioned-data/routing/bgp/status/vrf/*/bgpPeerInfoStatusEntry/*`
if _device != "" {
let bgpNeighbors = bgpNeighbors | fields(_device)
} else {
if str(_SITE_NAME) != "" {
let bgpNeighbors = bgpNeighbors | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")))
}
}
let bgpPeerInfoStatusEntry = `*:/Sysdb/cell/1/routing/bgp/export/vrfBgpPeerInfoStatusEntryTable/*/bgpPeerInfoStatusEntry/*`
let bgpPeerStatisticsEntry = `*:/Smash/routing/bgp/bgpPeerInfoStatus/*/bgpPeerStatisticsEntry`
# This is the table
let result = newDict()
let id = 0
# Lets loop over every device
for deviceKey, deviceSessions in bgpNeighbors{
# And each session on the devices
if _device == "" || deviceKey == _device {
for vrfKey, vrfValue in deviceSessions{
# Check if _vrf is empty or if the current vrfKey is in _vrf
if length(_vrf) == 0 || _vrf == vrfKey {
for ip, sessionData in vrfValue {
let data = merge(sessionData)
# Add one to the ID
let id = id + 1
result[id] = newDict()
# This is where we add the various columns
result[id]["0. Device"] = deviceKey
result[id]["1. Status"] = data["bgpState"]["Name"]
result[id]["2. Peering Address"] = data["bgpPeerLocalAddr"]
result[id]["3. Neighbor Address"] = data["key"]
result[id]["4. Neighbor AS"] = data["bgpPeerAs"]["value"]
result[id]["6. VRF"] = vrfKey
if dictHasKey(bgpPeerInfoStatusEntry, deviceKey) && dictHasKey(bgpPeerStatisticsEntry, deviceKey) {
if dictHasKey(bgpPeerInfoStatusEntry[deviceKey], vrfKey) {
let test = merge(bgpPeerInfoStatusEntry[deviceKey][vrfKey][ip])
for kafi, kval in test["bgpPeerAfiSafiActive"]{
if kval == true {
afis[deviceKey] = bgpPeerAfiSafiActive[kafi]
afi_name[deviceKey] = bgpPeerAfiSafiActiveName[kafi]
result[id]["7. AFI/SAFI"] = afi_name[deviceKey]
}
}
result[id]["5. Peer Description"] = test["bgpPeerDescription"]
}
if dictHasKey(bgpPeerStatisticsEntry[deviceKey], vrfKey) {
let bgpPeerAfiSafiStats = merge(bgpPeerStatisticsEntry[deviceKey][vrfKey])
if dictHasKey(afis, deviceKey) && dictHasKey(bgpPeerAfiSafiStats, ip){
result[id]["8. PfxRcd"] = bgpPeerAfiSafiStats[ip]["bgpPeerAfiSafiStats"][afis[deviceKey]]["prefixIn"]
result[id]["9. PfxAcc"] = bgpPeerAfiSafiStats[ip]["bgpPeerAfiSafiStats"][afis[deviceKey]]["prefixAcceptedIn"]
}
}
} else {
# need to figure out why sometimes there's no prefix info
result[id]["8. PfxRcd"] = "N/A"
result[id]["9. PfxAcc"] = "N/A"
}
if dictHasKey(data, "bgpPeerIntoOrOutOfEstablishedTime") {
result[id]["10. Up/Down"] = str(duration(1000000000*round(num(now() - time(data["bgpPeerIntoOrOutOfEstablishedTime"]*1000000000))/1000000000)))
}
}
}
}
}
}
result
BGP Sessions Flaps
let data =`analytics:/Devices/*/versioned-data/routing/bgp/status/vrf/default/bgpPeerInfoStatusEntry/*`[24h]
let devices = merge(`analytics:/tags/labels/devices/site_name/value/<_SITE_NAME>/elements`)
let data = data | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")))
let result = newDict()
for device, deviceValues in data {
let establishedNeighbors = newDict()
let flapCount = 0
for ip, tseries in deviceValues{
for timestamp, values in tseries {
if dictHasKey(values, "bgpState"){
if values["bgpState"]["Name"] == "Established"{
let flapCount = flapCount +1
establishedNeighbors[ip] = true
}
}
}
}
let count = flapCount - length(establishedNeighbors)
if count > 0 {
result[device] = newDict() | setFields("Flaps", count )
}
}
result
BGP Historical state tracker
# BGP Session historical state tracker
let data = `analytics:/Devices/<_bgpDevice>/versioned-data/routing/bgp/status/vrf/default/bgpPeerInfoStatusEntry/*`[4h]
let res = newDict()
for ip, tseries in data {
for timestamp, values in tseries {
# only show selected neighbors or all if none selected
if length(_NeighborIP) == 0 || dictHasKey(_NeighborIP, ip){
if !dictHasKey(res, str(timestamp)) {
res[str(timestamp)] = newDict() | setFields(ip, dictHasKey(values, "bgpState") ? values["bgpState"]["Name"] : 0)
} else {
res[str(timestamp)][ip] = dictHasKey(values, "bgpState") ? values["bgpState"]["Name"] : 0
}
}
}
}
res
BGP Syslog Messages
let data = `<_bgpDevice>:/Logs/var/log/messages`[48h] | field("line") | where(reMatch(_value, "BGP"))
let logs = newDict()
for timest, logentry in data {
logs[str(timest+(_tz_offset))] = newDict()
logs[str(timest+(_tz_offset))]["Log"] = logentry
}
logs
Capacity Planning Routing and Switching
High Density Leaf Switches Numbers (7050X3) Tagged with HDL Label
let devices = merge(`analytics:/tags/labels/devices/pod_name/value/<_POD_NAME>/elements`)
let devicesSwitchLabel = merge(`analytics:/tags/labels/devices/switch_role/value/HDL/elements`)
if str(_POD_NAME) == "" {
let macConfigCount =`*:/Sysdb/bridging/config/_counts` | where(dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
let macStatusCount =`*:/Smash/bridging/status/_counts` | where(dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
let vrfCount =`*:/Sysdb/routing/vrf/config/vrfConfig` | where(dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}"))) | map(length(_value) == 0 ? 0 : _value)
let arpCount = `*:/Smash/arp/status/_counts` | where(dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
} else {
let macConfigCount =`*:/Sysdb/bridging/config/_counts` | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")) && dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
let macStatusCount =`*:/Smash/bridging/status/_counts` | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")) && dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
let vrfCount =`*:/Sysdb/routing/vrf/config/vrfConfig` | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")) && dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}"))) | map(length(_value) == 0 ? 0 : _value)
let arpCount = `*:/Smash/arp/status/_counts` | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")) && dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
}
let smash = macStatusCount | map(merge(_value) | fields("smashFdbStatus"))
let nbvlan = macConfigCount | map(merge(_value) | fields("vlanConfig"))
let nbVRF = vrfCount | map(length(merge(_value)))
let nbARP = arpCount | map(merge(_value))
for deviceKey, deviceValue in nbVRF {
let nbr = newDict()
nbr["VRF number"]=deviceValue
nbVRF[deviceKey]= nbr
}
for devicekey, devicevalue in smash {
smash[devicekey]["VLAN count"]=nbvlan[devicekey]["vlanConfig"]
smash[devicekey]["VRF count"]=nbVRF[devicekey]["VRF number"]
smash[devicekey]["ARP count"]=nbARP[devicekey]["arpEntry"]
smash[devicekey]["ND count"]=nbARP[devicekey]["neighborEntry"]
}
smash | map(_value | renameFields("smashFdbStatus","MAC count"))
Low Density Leaf Switches Numbers (7020R) Tagged with the LDL Label
let devices = merge(`analytics:/tags/labels/devices/pod_name/value/<_POD_NAME>/elements`)
let devicesSwitchLabel = merge(`analytics:/tags/labels/devices/switch_role/value/LDL/elements`)
if str(_POD_NAME) == "" {
let macConfigCount =`*:/Sysdb/bridging/config/_counts` | where(dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
let macStatusCount =`*:/Smash/bridging/status/_counts` | where(dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
let vrfCount =`*:/Sysdb/routing/vrf/config/vrfConfig` | where(dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}"))) | map(length(_value) == 0 ? 0 : _value)
let arpCount = `*:/Smash/arp/status/_counts` | where(dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
} else {
let macConfigCount =`*:/Sysdb/bridging/config/_counts` | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")) && dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
let macStatusCount =`*:/Smash/bridging/status/_counts` | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")) && dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
let vrfCount =`*:/Sysdb/routing/vrf/config/vrfConfig` | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")) && dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}"))) | map(length(_value) == 0 ? 0 : _value)
let arpCount = `*:/Smash/arp/status/_counts` | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")) && dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
}
let smash = macStatusCount | map(merge(_value) | fields("smashFdbStatus"))
let nbvlan = macConfigCount | map(merge(_value) | fields("vlanConfig"))
let nbVRF = vrfCount | map(length(merge(_value)))
let nbARP = arpCount | map(merge(_value))
for deviceKey, deviceValue in nbVRF {
let nbr = newDict()
nbr["VRF number"] = deviceValue
nbVRF[deviceKey] = nbr
}
for devicekey, devicevalue in smash {
smash[devicekey]["VLAN count"] = nbvlan[devicekey]["vlanConfig"]
smash[devicekey]["VRF count"] = dictHasKey(nbVRF, devicekey)? nbVRF[devicekey]["VRF number"] : 0
smash[devicekey]["ARP count"] = nbARP[devicekey]["arpEntry"]
smash[devicekey]["ND count"] = nbARP[devicekey]["neighborEntry"]
}
smash | map(_value | renameFields("smashFdbStatus","MAC count"))
EVPN Gateways Numbers (7280R2)
let devices = merge(`analytics:/tags/labels/devices/pod_name/value/<_POD_NAME>/elements`)
let devicesSwitchLabel = merge(`analytics:/tags/labels/devices/switch_role/value/EGW/elements`)
if str(_POD_NAME) == "" {
let macConfigCount =`*:/Sysdb/bridging/config/_counts` | where(dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
let macStatusCount =`*:/Smash/bridging/status/_counts` | where(dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
let vrfCount =`*:/Sysdb/routing/vrf/config/vrfConfig` | where(dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}"))) | map(length(_value) == 0 ? 0 : _value)
let arpCount = `*:/Smash/arp/status/_counts` | where(dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
} else {
let macConfigCount =`*:/Sysdb/bridging/config/_counts` | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")) && dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
let macStatusCount =`*:/Smash/bridging/status/_counts` | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")) && dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
let vrfCount =`*:/Sysdb/routing/vrf/config/vrfConfig` | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")) && dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}"))) | map(length(_value) == 0 ? 0 : _value)
let arpCount = `*:/Smash/arp/status/_counts` | where(dictHasKey(devices, complexKey("{\"deviceID\": \""+_key+"\"}")) && dictHasKey(devicesSwitchLabel, complexKey("{\"deviceID\": \""+_key+"\"}")))
}
let smash = macStatusCount | map(merge(_value) | fields("smashFdbStatus"))
let nbvlan = macConfigCount | map(merge(_value) | fields("vlanConfig"))
let nbVRF = vrfCount | map(length(merge(_value)))
let nbARP = arpCount | map(merge(_value))
for deviceKey, deviceValue in nbVRF {
let nbr = newDict()
nbr["VRF number"]=deviceValue
nbVRF[deviceKey]= nbr
}
for devicekey, devicevalue in smash {
smash[devicekey]["VLAN count"]=nbvlan[devicekey]["vlanConfig"]
smash[devicekey]["VRF count"]=nbVRF[devicekey]["VRF number"]
smash[devicekey]["ARP count"]=nbARP[devicekey]["arpEntry"]
smash[devicekey]["ND count"]=nbARP[devicekey]["neighborEntry"]
}
smash | map(_value | renameFields("smashFdbStatus","MAC count"))
IGMP Snooping Table
Note
IGMP Snooping states are not streamed by default and the “/Sysdb/bridging/igmpsnooping” needs to be added to the TerminAttr include list using the tastreaming.TerminattrStreaming service API. Examples can be found on Examples
let igmpSnooping = `<_device>:/Sysdb/bridging/igmpsnooping/forwarding/status/vlanStatus/*/ethGroup/*/intf`
let filteredIgmpSnooping = igmpSnooping | recmap(2, merge(_value))
let result = newDict()
for vlanKey, macAddrIntf in filteredIgmpSnooping {
for macAddr, intfState in macAddrIntf {
# Create a list of interfaces a vlan is mapped to
let interfaceList = ""
if length(intfState) > 1{
for interface, intfBool in intfState {
let interfaceList = interfaceList + str(interface) + ", "
}
} else {
# if there is only 1 interface no need to add a comma
let interfaceList = str(dictKeys(intfState)[0])
}
let vlan = reFindCaptures(str(vlanKey), "{\"value\":(\d+)}")[0][1]
result[macAddr] = newDict() | setFields("VLAN", vlan, "Members", interfaceList)
}
}
result
Number of MAC addresses across all devices
let data = `*:/Smash/bridging/status/_counts`
sum(data | map(merge(_value)) | where(dictHasKey(_value, "smashFdbStatus")) | map(_value["smashFdbStatus"]))
Number of MACs per device per interface
let data = merge(`<_device>:/Smash/bridging/status/smashFdbStatus`)
let numberMAC = newDict()
for deviceKey, deviceValue in data {
if dictHasKey(numberMAC, data[deviceKey]["intf"]) {
numberMAC[data[deviceKey]["intf"]]["MACs"] = numberMAC[data[deviceKey]["intf"]]["MACs"] + 1
} else {
numberMAC[data[deviceKey]["intf"]] = newDict()
numberMAC[data[deviceKey]["intf"]]["MACs"] = 1
}
}
numberMAC
List of Configured VLANs per VRFs
# Get the VRF configuration for all routed interfaces for all devices
let data=`*:/Sysdb/l3/intf/config/intfConfig/*`
# Build a new dictionary and select only the SVIs that are configured in a specific VRF
let res = newDict()
let id = 0
for deviceKey, deviceValue in data {
for interfaceKey, interfaceValue in deviceValue {
if strContains(interfaceKey, "Vlan"){
let data1 = merge(interfaceValue)
if data1["vrf"]["value"] == _VRF {
let id = id + 1
res[id] = newDict()
res[id]["Device"] = deviceKey
res[id]["Interfaces"] = interfaceKey
res[id]["VRFs"] = _VRF
}
}
}
}
res
# Get the VRF configuration for all routed interfaces for all devices
let data=`*:/Sysdb/l3/intf/config/intfConfig/*`
# Build a new dictionary and select only the SVIs and the VRFs they are configured in
let res = newDict()
let id = 0
for deviceKey, deviceValue in data {
for interfaceKey, interfaceValue in deviceValue {
if strContains(interfaceKey, "Vlan"){
let id = id + 1
res[id] = newDict()
res[id]["Device"] = deviceKey
res[id]["Interfaces"] = interfaceKey
res[id]["VRFs"] = merge(interfaceValue)["vrf"]["value"]
}
}
}
res