Skip to content

Commit

Permalink
fix BGP group label for old EX devices, add info label with filter po…
Browse files Browse the repository at this point in the history
…llicy, add metrics for MED, pref and hold time
  • Loading branch information
czerwonk committed Sep 18, 2023
1 parent 08fdbbc commit 659ce4c
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 43 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ config.yml
artifacts
config/tests/config_local.yml
.vscode*
notes.txt
notes.txt
.DS_Store/
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
log "github.com/sirupsen/logrus"
)

const version string = "0.11.0"
const version string = "0.12.0"

var (
showVersion = flag.Bool("version", false, "Print version information.")
Expand Down
96 changes: 66 additions & 30 deletions pkg/features/bgp/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
package bgp

import (
"fmt"
"math"
"strconv"

"github.com/czerwonk/junos_exporter/pkg/collector"
"github.com/prometheus/client_golang/prometheus"
Expand All @@ -26,6 +28,10 @@ var (
flapsDesc *prometheus.Desc
prefixesLimitCountDesc *prometheus.Desc
prefixesLimitPercentageDesc *prometheus.Desc
infoDesc *prometheus.Desc
medDesc *prometheus.Desc
preferenceDesc *prometheus.Desc
holdTimeDesc *prometheus.Desc
)

func init() {
Expand All @@ -35,6 +41,12 @@ func init() {
inputMessagesDesc = prometheus.NewDesc(prefix+"messages_input_count", "Number of received messages", l, nil)
outputMessagesDesc = prometheus.NewDesc(prefix+"messages_output_count", "Number of transmitted messages", l, nil)
flapsDesc = prometheus.NewDesc(prefix+"flap_count", "Number of session flaps", l, nil)
medDesc = prometheus.NewDesc(prefix+"metric_out", "MED configured for the session", l, nil)
preferenceDesc = prometheus.NewDesc(prefix+"preference", "Preference configured for the session", l, nil)
holdTimeDesc = prometheus.NewDesc(prefix+"hold_time_seconds", "Hold time configured for the session", l, nil)

infoLabels := append(l, "local_as", "import_policy", "export_policy")
infoDesc = prometheus.NewDesc(prefix+"info", "Information about the session (e.g. configuration)", infoLabels, nil)

l = append(l, "table")

Expand All @@ -51,6 +63,8 @@ type bgpCollector struct {
LogicalSystem string
}

type groupMap map[int64]group

// NewCollector creates a new collector
func NewCollector(logicalSystem string) collector.RPCCollector {
return &bgpCollector{LogicalSystem: logicalSystem}
Expand All @@ -74,6 +88,10 @@ func (*bgpCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- flapsDesc
ch <- prefixesLimitCountDesc
ch <- prefixesLimitPercentageDesc
ch <- infoDesc
ch <- medDesc
ch <- preferenceDesc
ch <- holdTimeDesc
}

// Collect collects metrics from JunOS
Expand All @@ -86,29 +104,59 @@ func (c *bgpCollector) Collect(client collector.Client, ch chan<- prometheus.Met
return nil
}

func (c *bgpCollector) collectGroups(client collector.Client) (groupMap, error) {
var x = groupResult{}
var cmd strings.Builder
cmd.WriteString("show bgp group")
if c.LogicalSystem != "" {
cmd.WriteString(" logical-system " + c.LogicalSystem)
}

err := client.RunCommandAndParse(cmd.String(), &x)
if err != nil {
return nil, err
}

groups := make(groupMap)
for _, g := range x.Information.Groups {
groups[g.Index] = g
}

return groups, err
}

func (c *bgpCollector) collect(client collector.Client, ch chan<- prometheus.Metric, labelValues []string) error {
groups, err := c.collectGroups(client)
if err != nil {
return fmt.Errorf("could not retrieve BGP group information: %w", err)
}

var x = result{}
var cmd strings.Builder
cmd.WriteString("show bgp neighbor")
if c.LogicalSystem != "" {
cmd.WriteString(" logical-system " + c.LogicalSystem)
}

err := client.RunCommandAndParse(cmd.String(), &x)
err = client.RunCommandAndParse(cmd.String(), &x)
if err != nil {
return err
}

for _, peer := range x.Information.Peers {
c.collectForPeer(peer, ch, labelValues)
c.collectForPeer(peer, groups, ch, labelValues)
}

return nil
}

func (c *bgpCollector) collectForPeer(p peer, ch chan<- prometheus.Metric, labelValues []string) {
func (c *bgpCollector) collectForPeer(p peer, groups groupMap, ch chan<- prometheus.Metric, labelValues []string) {
ip := strings.Split(p.IP, "+")
l := append(labelValues, []string{p.ASN, ip[0], p.Description, p.Group}...)
l := append(labelValues, []string{
p.ASN,
ip[0],
p.Description,
groupForPeer(p, groups)}...)

up := 0
if p.State == "Established" {
Expand All @@ -120,6 +168,15 @@ func (c *bgpCollector) collectForPeer(p peer, ch chan<- prometheus.Metric, label
ch <- prometheus.MustNewConstMetric(inputMessagesDesc, prometheus.GaugeValue, float64(p.InputMessages), l...)
ch <- prometheus.MustNewConstMetric(outputMessagesDesc, prometheus.GaugeValue, float64(p.OutputMessages), l...)
ch <- prometheus.MustNewConstMetric(flapsDesc, prometheus.GaugeValue, float64(p.Flaps), l...)
ch <- prometheus.MustNewConstMetric(preferenceDesc, prometheus.GaugeValue, float64(p.OptionInformation.Preference), l...)
ch <- prometheus.MustNewConstMetric(medDesc, prometheus.GaugeValue, float64(p.OptionInformation.MetricOut), l...)
ch <- prometheus.MustNewConstMetric(holdTimeDesc, prometheus.GaugeValue, float64(p.OptionInformation.Holdtime), l...)

infoValues := append(l,
strconv.FormatInt(p.OptionInformation.LocalAs, 10),
formatPolicy(p.OptionInformation.ImportPolicy),
formatPolicy(p.OptionInformation.ExportPolicy))
ch <- prometheus.MustNewConstMetric(infoDesc, prometheus.GaugeValue, 1, infoValues...)

c.collectRIBForPeer(p, ch, l)
}
Expand All @@ -128,7 +185,7 @@ func (*bgpCollector) collectRIBForPeer(p peer, ch chan<- prometheus.Metric, labe
var rib_name string

// derive the name of the rib for which the prefix limit is configured by examining the NLRI type
switch nlri_type := p.BGPOI.PrefixLimit.NlriType; nlri_type {
switch nlri_type := p.OptionInformation.PrefixLimit.NlriType; nlri_type {
case "inet-unicast":
rib_name = "inet.0"
case "inet6-unicast":
Expand All @@ -142,8 +199,8 @@ func (*bgpCollector) collectRIBForPeer(p peer, ch chan<- prometheus.Metric, labe
rib_name = p.CFGRTI + "." + rib_name
}

if p.BGPOI.PrefixLimit.PrefixCount > 0 {
ch <- prometheus.MustNewConstMetric(prefixesLimitCountDesc, prometheus.GaugeValue, float64(p.BGPOI.PrefixLimit.PrefixCount), append(labelValues, rib_name)...)
if p.OptionInformation.PrefixLimit.PrefixCount > 0 {
ch <- prometheus.MustNewConstMetric(prefixesLimitCountDesc, prometheus.GaugeValue, float64(p.OptionInformation.PrefixLimit.PrefixCount), append(labelValues, rib_name)...)
}

for _, rib := range p.RIBs {
Expand All @@ -155,31 +212,10 @@ func (*bgpCollector) collectRIBForPeer(p peer, ch chan<- prometheus.Metric, labe
ch <- prometheus.MustNewConstMetric(advertisedPrefixesDesc, prometheus.GaugeValue, float64(rib.AdvertisedPrefixes), l...)

if rib.Name == rib_name {
if p.BGPOI.PrefixLimit.PrefixCount > 0 {
prefixesLimitPercent := float64(rib.ReceivedPrefixes) / float64(p.BGPOI.PrefixLimit.PrefixCount)
if p.OptionInformation.PrefixLimit.PrefixCount > 0 {
prefixesLimitPercent := float64(rib.ReceivedPrefixes) / float64(p.OptionInformation.PrefixLimit.PrefixCount)
ch <- prometheus.MustNewConstMetric(prefixesLimitPercentageDesc, prometheus.GaugeValue, math.Round(prefixesLimitPercent*100)/100, l...)
}
}
}
}

func bgpStateToNumber(bgpState string) float64 {
switch bgpState {
case "Active":
return 1
case "Connect":
return 2
case "Established":
return 3
case "Idle":
return 4
case "Openconfirm":
return 5
case "OpenSent":
return 6
case "route reflector client":
return 7
default:
return 0
}
}
38 changes: 38 additions & 0 deletions pkg/features/bgp/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: MIT

package bgp

import "strings"

func groupForPeer(p peer, groups groupMap) string {
if len(p.Group) > 0 {
return p.Group
}

return groups[p.GroupIndex].Name
}

func formatPolicy(s string) string {
return strings.Trim(s, "\n ")
}

func bgpStateToNumber(bgpState string) float64 {
switch bgpState {
case "Active":
return 1
case "Connect":
return 2
case "Established":
return 3
case "Idle":
return 4
case "Openconfirm":
return 5
case "OpenSent":
return 6
case "route reflector client":
return 7
default:
return 0
}
}
33 changes: 22 additions & 11 deletions pkg/features/bgp/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ type result struct {
}

type peer struct {
CFGRTI string `xml:"peer-cfg-rti"`
IP string `xml:"peer-address"`
ASN string `xml:"peer-as"`
State string `xml:"peer-state"`
Group string `xml:"peer-group"`
Description string `xml:"description"`
Flaps int64 `xml:"flap-count"`
InputMessages int64 `xml:"input-messages"`
OutputMessages int64 `xml:"output-messages"`
RIBs []rib `xml:"bgp-rib"`
BGPOI optionInformation `xml:"bgp-option-information"`
CFGRTI string `xml:"peer-cfg-rti"`
IP string `xml:"peer-address"`
ASN string `xml:"peer-as"`
State string `xml:"peer-state"`
Group string `xml:"peer-group"`
GroupIndex int64 `xml:"peer-group-index"`
Description string `xml:"description"`
Flaps int64 `xml:"flap-count"`
InputMessages int64 `xml:"input-messages"`
OutputMessages int64 `xml:"output-messages"`
RIBs []rib `xml:"bgp-rib"`
OptionInformation optionInformation `xml:"bgp-option-information"`
}

type rib struct {
Expand Down Expand Up @@ -50,3 +51,13 @@ type prefixLimit struct {
LimitAction string `xml:"limit-action"`
WarningPercentage int64 `xml:"warning-percentage"`
}

type groupResult struct {
Information struct {
Groups []group `xml:"bgp-group"`
} `xml:"bgp-group-information"`
}
type group struct {
Index int64 `xml:"group-index"`
Name string `xml:"name"`
}

0 comments on commit 659ce4c

Please sign in to comment.