Files
akvorado/demoexporter/bmp/config.go
2025-11-04 08:05:54 +01:00

123 lines
3.7 KiB
Go

// SPDX-FileCopyrightText: 2022 Free Mobile
// SPDX-License-Identifier: AGPL-3.0-only
package bmp
import (
"errors"
"fmt"
"net/netip"
"strconv"
"strings"
"time"
"github.com/osrg/gobgp/v4/pkg/packet/bgp"
)
// Configuration describes the configuration for the BMP component. Only one peer is emulated.
type Configuration struct {
// Target specify the IP address and port to generate BMP routes to. Empty if this component is disabled.
Target string `validate:"isdefault|hostname_port"`
// Routes is the set of routes to announce to the collector using BMP.
Routes []RouteConfiguration `validate:"dive"`
// LocalASN is the local AS number
LocalASN uint16 `validate:"required,min=1"`
// PeerASN is the peer AS number
PeerASN uint16 `validate:"required,min=1"`
// LocalIP is the local IP address.
LocalIP netip.Addr `validate:"required"`
// PeerIP is the peer IP address.
PeerIP netip.Addr `validate:"required"`
// RetryAfter tells how much time to wait before retrying
RetryAfter time.Duration `validate:"min=0s"`
// StatsDelay tells how much time to wait between two BMP stats message (to check connection liveness)
StatsDelay time.Duration `validate:"min=0s"`
}
// RouteConfiguration describes a route to be generated with BMP.
type RouteConfiguration struct {
// Prefix is the set of prefixes to announce.
Prefixes []netip.Prefix `validate:"min=1"`
// ASPath is the AS path to associate with the prefixes.
ASPath []uint32 `validate:"min=1"`
// Communities are the set of standard communities to associate with the prefixes.
Communities []Community
// LargeCommunities are the set of large communities to associate with the prefixes.
LargeCommunities []LargeCommunity
}
// DefaultConfiguration represents the default configuration for the BMP component.
func DefaultConfiguration() Configuration {
return Configuration{
LocalASN: 64496,
PeerASN: 64497,
LocalIP: netip.MustParseAddr("2001:db8::1"),
PeerIP: netip.MustParseAddr("2001:db8::2"),
RetryAfter: time.Duration(5 * time.Second),
StatsDelay: time.Duration(time.Minute),
}
}
// Community is a standard community.
type Community uint32
// UnmarshalText parses a standard community.
func (comm *Community) UnmarshalText(input []byte) error {
text := string(input)
elems := strings.Split(text, ":")
if len(elems) != 2 {
return errors.New("community should be ASN:XX")
}
asn, err := strconv.ParseUint(elems[0], 10, 16)
if err != nil {
return errors.New("community should be ASN2:XX")
}
local, err := strconv.ParseUint(elems[1], 10, 16)
if err != nil {
return errors.New("community should be ASN:XX2")
}
*comm = Community((asn << 16) + local)
return nil
}
// String turns a community to a string.
func (comm Community) String() string {
return fmt.Sprintf("%d:%d", comm>>16, comm&0xffff)
}
// LargeCommunity represents a large community.
type LargeCommunity bgp.LargeCommunity
// UnmarshalText parses a large community
func (comm *LargeCommunity) UnmarshalText(input []byte) error {
text := string(input)
elems := strings.Split(text, ":")
if len(elems) != 3 {
return errors.New("community should be ASN:XX:YY")
}
asn, err := strconv.ParseUint(elems[0], 10, 32)
if err != nil {
return errors.New("community should be ASN4:XX:YY")
}
local1, err := strconv.ParseUint(elems[1], 10, 32)
if err != nil {
return errors.New("community should be ASN:XX4:YY")
}
local2, err := strconv.ParseUint(elems[2], 10, 32)
if err != nil {
return errors.New("community should be ASN:XX:YY4")
}
*comm = LargeCommunity{
ASN: uint32(asn),
LocalData1: uint32(local1),
LocalData2: uint32(local2),
}
return nil
}
// String turns a large community to a string.
func (comm LargeCommunity) String() string {
b := bgp.LargeCommunity(comm)
return b.String()
}