Skip to content

Commit

Permalink
feat: report bgp states of connected neighbors
Browse files Browse the repository at this point in the history
  • Loading branch information
mwennrich committed Nov 25, 2024
1 parent d8c102d commit e287b5c
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 11 deletions.
1 change: 1 addition & 0 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ type Config struct {
GrpcClientCertFile string `required:"false" desc:"the gRPC client certificate file" envconfig:"grpc_client_cert_file"`
GrpcClientKeyFile string `required:"false" desc:"the gRPC client key file" envconfig:"grpc_client_key_file"`
PXEVlanID uint16 `required:"false" default:"4000" desc:"the id of the pxe vlan" envconfig:"pxe_vlan_id"`
BGPNeighborStateFile string `required:"false" default:"/var/run/bgp-neighbors/bgp-neighbors.json" desc:"the file to read the BGP neighbor state from" envconfig:"bgp_neighbor_state_file"`
}
5 changes: 5 additions & 0 deletions cmd/internal/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ type Core struct {
metrics *metrics.Metrics

pxeVlanID uint16

bgpNeighborStateFile string
}

type Config struct {
Expand All @@ -60,6 +62,8 @@ type Config struct {
Metrics *metrics.Metrics

PXEVlanID uint16

BGPNeighborStateFile string
}

func New(c Config) *Core {
Expand All @@ -82,5 +86,6 @@ func New(c Config) *Core {
eventServiceClient: c.EventServiceClient,
metrics: c.Metrics,
pxeVlanID: c.PXEVlanID,
bgpNeighborStateFile: c.BGPNeighborStateFile,
}
}
16 changes: 13 additions & 3 deletions cmd/internal/core/reconfigure-switch.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/vishvananda/netlink"

"github.com/metal-stack/metal-core/cmd/internal/frr"
"github.com/metal-stack/metal-core/cmd/internal/switcher/types"
"github.com/metal-stack/metal-core/cmd/internal/vlan"
sw "github.com/metal-stack/metal-go/api/client/switch_operations"
Expand All @@ -32,8 +33,9 @@ func (c *Core) ReconfigureSwitch() {
params.ID = host
ns := elapsed.Nanoseconds()
nr := &models.V1SwitchNotifyRequest{
SyncDuration: &ns,
PortStates: make(map[string]string),
SyncDuration: &ns,
PortStates: make(map[string]string),
BgpPortStates: make(map[string]models.V1SwitchBGPPortState),
}
if err != nil {
errStr := err.Error()
Expand Down Expand Up @@ -69,9 +71,17 @@ func (c *Core) ReconfigureSwitch() {
} else {
nr.PortStates[*n.Name] = models.V1SwitchNicActualDOWN
}

}

if c.bgpNeighborStateFile != "" {
bgpportstates, err := frr.GetBGPStates(c.bgpNeighborStateFile)
if err != nil {
c.log.Error("could not get BGP states", "error", err)
c.metrics.CountError("switch-reconfiguration")
}
c.log.Debug("bgp port states", "bgpportstates", bgpportstates)
nr.BgpPortStates = bgpportstates
}
params.Body = nr
_, err = c.driver.SwitchOperations().NotifySwitch(params, nil)
if err != nil {
Expand Down
115 changes: 115 additions & 0 deletions cmd/internal/frr/frr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package frr

import (
"encoding/json"
"fmt"
"io"
"os"
"time"

"github.com/metal-stack/metal-go/api/models"
)

type Vrf struct {
VrfID int
VrfName string
Ports Ports
}

type Port struct {
Hostname string `json:"hostname"`
PeerGroup string `json:"peerGroup"`
BgpState string `json:"bgpState"`
BgpTimerUpEstablished int64 `json:"bgpTimerUpEstablishedEpoch"`

AddressFamilyInfo struct {
IPv4UnicastCumulus struct {
SentPrefixCounter int64 `json:"sentPrefixCounter"`
AcceptedPrefixCounter int64 `json:"acceptedPrefixCounter"`
} `json:"IPv4 Unicast"`
IPv6UnicastCumulus struct {
SentPrefixCounter int64 `json:"sentPrefixCounter"`
AcceptedPrefixCounter int64 `json:"acceptedPrefixCounter"`
} `json:"IPv6 Unicast"`
IPv4UnicastSonic struct {
SentPrefixCounter int64 `json:"sentPrefixCounter"`
AcceptedPrefixCounter int64 `json:"acceptedPrefixCounter"`
} `json:"ipv4Unicast"`
IPv6UnicastSonic struct {
SentPrefixCounter int64 `json:"sentPrefixCounter"`
AcceptedPrefixCounter int64 `json:"acceptedPrefixCounter"`
} `json:"ipv6Unicast"`
} `json:"addressFamilyInfo"`
}

type Vrfs map[string]Vrf
type Ports map[string]Port

func GetBGPStates(filepath string) (map[string]models.V1SwitchBGPPortState, error) {

fileInfo, err := os.Stat(filepath)
if err != nil {
return nil, fmt.Errorf("error getting file info for %s: %w", filepath, err)
}

if time.Since(fileInfo.ModTime()) > time.Hour {
return nil, fmt.Errorf("file %s is too old", filepath)
}

file, err := os.Open(filepath)
if err != nil {
return nil, fmt.Errorf("error opening frr bgp state json file %s: %w", filepath, err)
}
defer file.Close()

byteValue, err := io.ReadAll(file)
if err != nil {
return nil, fmt.Errorf("error reading frr bgp state json file %s: %w", filepath, err)
}

var tempData map[string]map[string]json.RawMessage
if err := json.Unmarshal(byteValue, &tempData); err != nil {
return nil, fmt.Errorf("error unmarshalling bgp vrf all neigh output: %w", err)
}

bgpstates := make(map[string]models.V1SwitchBGPPortState)
for _, vrfData := range tempData {

var VrfName string
if err := json.Unmarshal(vrfData["vrfName"], &VrfName); err != nil {
return nil, fmt.Errorf("error parsing vrfName: %w", err)
}

for key, value := range vrfData {
if key == "vrfId" || key == "vrfName" {
continue
}
var port Port
if err := json.Unmarshal(value, &port); err != nil {
return nil, fmt.Errorf("error parsing port info for %s: %w", key, err)
}
bgptimerup := port.BgpTimerUpEstablished
sentPrefixCounter := port.AddressFamilyInfo.IPv4UnicastCumulus.SentPrefixCounter +
port.AddressFamilyInfo.IPv6UnicastCumulus.SentPrefixCounter +
port.AddressFamilyInfo.IPv4UnicastSonic.SentPrefixCounter +
port.AddressFamilyInfo.IPv6UnicastSonic.SentPrefixCounter

acceptedPrefixCounter := port.AddressFamilyInfo.IPv4UnicastCumulus.AcceptedPrefixCounter +
port.AddressFamilyInfo.IPv6UnicastCumulus.AcceptedPrefixCounter +
port.AddressFamilyInfo.IPv4UnicastSonic.AcceptedPrefixCounter +
port.AddressFamilyInfo.IPv6UnicastSonic.AcceptedPrefixCounter

bgpstates[key] = models.V1SwitchBGPPortState{
Neighbor: &port.Hostname,
PeerGroup: &port.PeerGroup,
BgpState: &port.BgpState,
BgpTimerUpEstablished: &bgptimerup,
VrfName: &VrfName,
SentPrefixCounter: &sentPrefixCounter,
AcceptedPrefixCounter: &acceptedPrefixCounter,
}
}
}

return bgpstates, nil
}
1 change: 1 addition & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ func Run() {
EventServiceClient: grpcClient.NewEventClient(),
Metrics: metrics,
PXEVlanID: cfg.PXEVlanID,
BGPNeighborStateFile: cfg.BGPNeighborStateFile,
})

err = c.RegisterSwitch()
Expand Down
12 changes: 6 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ go 1.23.0
require (
github.com/avast/retry-go/v4 v4.6.0
github.com/coreos/go-systemd/v22 v22.5.0
github.com/go-openapi/errors v0.22.0
github.com/go-openapi/runtime v0.28.0
github.com/go-openapi/strfmt v0.23.0
github.com/go-openapi/swag v0.23.0
github.com/go-openapi/validate v0.24.0
github.com/go-redis/redismock/v9 v9.2.0
github.com/google/go-cmp v0.6.0
github.com/kelseyhightower/envconfig v1.4.0
github.com/metal-stack/go-lldpd v0.4.8
github.com/metal-stack/metal-api v0.39.4
github.com/metal-stack/metal-go v0.39.4
github.com/metal-stack/metal-go v0.39.5-0.20241125142836-85a6ff656afd
github.com/metal-stack/v v1.0.3
github.com/prometheus/client_golang v1.20.5
github.com/redis/go-redis/v9 v9.7.0
Expand All @@ -35,15 +40,10 @@ require (
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.23.0 // indirect
github.com/go-openapi/errors v0.22.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/loads v0.22.0 // indirect
github.com/go-openapi/runtime v0.28.0 // indirect
github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/strfmt v0.23.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-openapi/validate v0.24.0 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ github.com/metal-stack/go-lldpd v0.4.8 h1:xQxvbS0a2X663EQL9BR4r87xBb7tZolJ4G5HRi
github.com/metal-stack/go-lldpd v0.4.8/go.mod h1:jI8gpcb57+CuZjaPP4nQRDsGG6dljHOM9sOL5pMUEIs=
github.com/metal-stack/metal-api v0.39.4 h1:A+sLiOvipMHotMDMjhKCkyCAhdifb6YGdZ85E/I5z14=
github.com/metal-stack/metal-api v0.39.4/go.mod h1:VIBQva4qsl9WAl78Djr6oFKO21TLT3/MKNlC4US72sc=
github.com/metal-stack/metal-go v0.39.4 h1:UaYSsBc5JaGmVLI2uV8mOo5+T2v1pHUN+GwKXaNcmaE=
github.com/metal-stack/metal-go v0.39.4/go.mod h1:ltItf/Md/z588c7Dr3X6iemCeOFh3rJ8nDL5Dpb9zFQ=
github.com/metal-stack/metal-go v0.39.5-0.20241125142836-85a6ff656afd h1:qhYHfYwwNw3tkhw3pCdZgGZUmKOF35t2Y3yTDL1QtvQ=
github.com/metal-stack/metal-go v0.39.5-0.20241125142836-85a6ff656afd/go.mod h1:ltItf/Md/z588c7Dr3X6iemCeOFh3rJ8nDL5Dpb9zFQ=
github.com/metal-stack/metal-lib v0.19.0 h1:4yBnp/jPGgX9KeCje3A4MFL2oDjgjOjgsIK391LltRI=
github.com/metal-stack/metal-lib v0.19.0/go.mod h1:fCMaWwVGA/xAoGvBk72/nfzqBkHly0iOzrWpc55Fau4=
github.com/metal-stack/security v0.9.0 h1:FYBXJfNJwUw2E0HBa+jay37XF7b6EikEuf4Mw8u04EY=
Expand Down

0 comments on commit e287b5c

Please sign in to comment.