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 dcbe18b commit 06a11b5
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 69 deletions.
1 change: 1 addition & 0 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ type Config struct {
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"`
AdditionalRouteMapCIDRs []string `required:"false" default:"10.240.0.0/12" desc:"additional route map entries, typically the pod/service CIDRs, one or more CIDR for ipv4 or ipv6, separated by comma" envconfig:"additional_route_map_cidrs"`
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 @@ -35,6 +35,8 @@ type Core struct {

pxeVlanID uint16
additionalRouteMapCIDRs []string

bgpNeighborStateFile string
}

type Config struct {
Expand Down Expand Up @@ -62,6 +64,8 @@ type Config struct {

PXEVlanID uint16
AdditionalRouteMapCIDRs []string

BGPNeighborStateFile string
}

func New(c Config) *Core {
Expand All @@ -85,5 +89,6 @@ func New(c Config) *Core {
metrics: c.Metrics,
pxeVlanID: c.PXEVlanID,
additionalRouteMapCIDRs: c.AdditionalRouteMapCIDRs,
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 @@ -103,6 +103,7 @@ func Run() {
Metrics: metrics,
PXEVlanID: cfg.PXEVlanID,
AdditionalRouteMapCIDRs: cfg.AdditionalRouteMapCIDRs,
BGPNeighborStateFile: cfg.BGPNeighborStateFile,
})

err = c.RegisterSwitch()
Expand Down
54 changes: 28 additions & 26 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
module github.com/metal-stack/metal-core

go 1.23
go 1.23.0

toolchain go1.23.3

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.7
github.com/metal-stack/metal-api v0.34.0
github.com/metal-stack/metal-go v0.34.0
github.com/metal-stack/metal-go v0.39.3-0.20241115075449-a32f0b74c86a
github.com/metal-stack/v v1.0.3
github.com/prometheus/client_golang v1.20.2
github.com/prometheus/client_golang v1.20.5
github.com/redis/go-redis/v9 v9.6.1
github.com/stretchr/testify v1.9.0
github.com/vishvananda/netlink v1.3.0
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
golang.org/x/text v0.18.0
google.golang.org/grpc v1.66.0
google.golang.org/protobuf v1.34.2
golang.org/x/text v0.20.0
google.golang.org/grpc v1.68.0
google.golang.org/protobuf v1.35.1
gopkg.in/yaml.v3 v3.0.1
)

Expand All @@ -35,52 +42,47 @@ 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/v4 v4.5.0 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/compress v1.17.10 // indirect
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.6 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/jwx/v2 v2.1.1 // indirect
github.com/lestrrat-go/jwx/v2 v2.1.2 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 // indirect
github.com/mdlayher/lldp v0.0.0-20150915211757-afd9f83164c5 // indirect
github.com/metal-stack/metal-lib v0.18.1 // indirect
github.com/metal-stack/security v0.8.1 // indirect
github.com/metal-stack/metal-lib v0.19.0 // indirect
github.com/metal-stack/security v0.9.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.58.0 // indirect
github.com/prometheus/common v0.59.1 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
go.mongodb.org/mongo-driver v1.16.1 // indirect
go.opentelemetry.io/otel v1.29.0 // indirect
go.opentelemetry.io/otel/metric v1.29.0 // indirect
go.opentelemetry.io/otel/trace v1.29.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/net v0.28.0 // indirect
go.mongodb.org/mongo-driver v1.17.1 // indirect
go.opentelemetry.io/otel v1.30.0 // indirect
go.opentelemetry.io/otel/metric v1.30.0 // indirect
go.opentelemetry.io/otel/trace v1.30.0 // indirect
golang.org/x/crypto v0.29.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.25.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
golang.org/x/sync v0.9.0 // indirect
golang.org/x/sys v0.27.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 // indirect
)
Loading

0 comments on commit 06a11b5

Please sign in to comment.