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, XYZ

    • Tag site_name:ALL to all devices

    • Tag site_name:ABC to ABC devices

    • repeat 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 Summary BGP Summary2 BGP Summary23

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 Flaps and Historical state tracker

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
BGP Syslog Messages

Download the Dashboard JSON here