added blackhole community config parsing
This commit is contained in:
parent
27a6b9806d
commit
b5b5148dec
@ -174,18 +174,32 @@ func (c BGPCommunityMap) Communities() Communities {
|
||||
return communities
|
||||
}
|
||||
|
||||
// BGPCommunityRange describes a range within a bgp community:
|
||||
// It is a tuple with two values, the start and end.
|
||||
type BGPCommunityRange []int
|
||||
// BGPCommunity types: Standard, Extended and Large
|
||||
const (
|
||||
BGPCommunityTypeStd = iota
|
||||
BGPCommunityTypeExt
|
||||
BGPCommunityTypeLarge
|
||||
)
|
||||
|
||||
// RangedBGPCommunity is a list of BGPCommunity ranges,
|
||||
// with 3 ranges in large communities.
|
||||
type RangedBGPCommunity []interface{}
|
||||
|
||||
// Type classifies the BGP Ranged BGP Community into: std, large, ext
|
||||
func (c RangedBGPCommunity) Type() int {
|
||||
if len(c) == 2 {
|
||||
return BGPCommunityTypeStd
|
||||
}
|
||||
if _, ok := c[0].([]string); ok {
|
||||
return BGPCommunityTypeExt
|
||||
}
|
||||
return BGPCommunityTypeLarge
|
||||
}
|
||||
|
||||
// A BGPCommunitiesSet is a set of communities, large and extended.
|
||||
// The communities are described as ranges.
|
||||
type BGPCommunitiesSet struct {
|
||||
Communities []RangedBGPCommunity `json:"communities"`
|
||||
ExtCommunities []RangedBGPCommunity `json:"ext_communities"`
|
||||
LargeCommunities []RangedBGPCommunity `json:"large_communities"`
|
||||
Communities []RangedBGPCommunity `json:"standard"`
|
||||
ExtCommunities []RangedBGPCommunity `json:"extended"`
|
||||
LargeCommunities []RangedBGPCommunity `json:"large"`
|
||||
}
|
||||
|
121
pkg/config/bgp_communities.go
Normal file
121
pkg/config/bgp_communities.go
Normal file
@ -0,0 +1,121 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/alice-lg/alice-lg/pkg/api"
|
||||
"github.com/alice-lg/alice-lg/pkg/decoders"
|
||||
)
|
||||
|
||||
// ErrInvalidCommunity creates an invalid community error
|
||||
func ErrInvalidCommunity(s string) error {
|
||||
return fmt.Errorf("invalid community: %s", s)
|
||||
}
|
||||
|
||||
// Helper parse communities from a section body
|
||||
func parseAndMergeCommunities(
|
||||
communities api.BGPCommunityMap, body string,
|
||||
) api.BGPCommunityMap {
|
||||
|
||||
// Parse and merge communities
|
||||
lines := strings.Split(body, "\n")
|
||||
for _, line := range lines {
|
||||
kv := strings.SplitN(line, "=", 2)
|
||||
if len(kv) != 2 {
|
||||
log.Println("Skipping malformed BGP community:", line)
|
||||
continue
|
||||
}
|
||||
|
||||
community := strings.TrimSpace(kv[0])
|
||||
label := strings.TrimSpace(kv[1])
|
||||
communities.Set(community, label)
|
||||
}
|
||||
|
||||
return communities
|
||||
}
|
||||
|
||||
// Parse a communities set with ranged communities
|
||||
func parseRangeCommunitiesSet(body string) (*api.BGPCommunitiesSet, error) {
|
||||
comms := []api.RangedBGPCommunity{}
|
||||
large := []api.RangedBGPCommunity{}
|
||||
ext := []api.RangedBGPCommunity{}
|
||||
|
||||
lines := strings.Split(body, "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue // Empty
|
||||
}
|
||||
if strings.HasPrefix(line, "#") {
|
||||
continue // Comment
|
||||
}
|
||||
comm, err := parseRangeCommunity(line)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch comm.Type() {
|
||||
case api.BGPCommunityTypeStd:
|
||||
comms = append(comms, comm)
|
||||
case api.BGPCommunityTypeLarge:
|
||||
large = append(large, comm)
|
||||
case api.BGPCommunityTypeExt:
|
||||
ext = append(ext, comm)
|
||||
}
|
||||
}
|
||||
|
||||
set := &api.BGPCommunitiesSet{
|
||||
Communities: comms,
|
||||
LargeCommunities: large,
|
||||
ExtCommunities: ext,
|
||||
}
|
||||
return set, nil
|
||||
}
|
||||
|
||||
func parseRangeCommunity(s string) (api.RangedBGPCommunity, error) {
|
||||
tokens := strings.Split(s, ":")
|
||||
if len(tokens) < 2 {
|
||||
return nil, ErrInvalidCommunity(s)
|
||||
}
|
||||
|
||||
// Extract ranges and make uniform structure
|
||||
parts := make([][]string, 0, len(tokens))
|
||||
for _, t := range tokens {
|
||||
values := strings.SplitN(t, "-", 2)
|
||||
if len(values) == 0 {
|
||||
return nil, ErrInvalidCommunity(s)
|
||||
}
|
||||
if len(values) == 1 {
|
||||
parts = append(parts, []string{values[0], values[0]})
|
||||
} else {
|
||||
parts = append(parts, []string{values[0], values[1]})
|
||||
}
|
||||
}
|
||||
if len(parts) <= 1 {
|
||||
return nil, ErrInvalidCommunity(s)
|
||||
}
|
||||
|
||||
// Check if this might be an ext community
|
||||
isExt := false
|
||||
if _, err := strconv.Atoi(parts[0][0]); err != nil {
|
||||
isExt = true // At least it looks like...
|
||||
}
|
||||
|
||||
if isExt && len(parts) != 3 {
|
||||
return nil, ErrInvalidCommunity(s)
|
||||
}
|
||||
if isExt {
|
||||
return api.RangedBGPCommunity{
|
||||
[]string{parts[0][0], parts[0][0]},
|
||||
decoders.IntListFromStrings(parts[1]),
|
||||
decoders.IntListFromStrings(parts[2]),
|
||||
}, nil
|
||||
}
|
||||
comm := api.RangedBGPCommunity{}
|
||||
for _, p := range parts {
|
||||
comm = append(comm, decoders.IntListFromStrings(p))
|
||||
}
|
||||
return comm, nil
|
||||
}
|
@ -388,28 +388,6 @@ func getLookupColumns(config *ini.File) (
|
||||
return columns, order, nil
|
||||
}
|
||||
|
||||
// Helper parse communities from a section body
|
||||
func parseAndMergeCommunities(
|
||||
communities api.BGPCommunityMap, body string,
|
||||
) api.BGPCommunityMap {
|
||||
|
||||
// Parse and merge communities
|
||||
lines := strings.Split(body, "\n")
|
||||
for _, line := range lines {
|
||||
kv := strings.SplitN(line, "=", 2)
|
||||
if len(kv) != 2 {
|
||||
log.Println("Skipping malformed BGP community:", line)
|
||||
continue
|
||||
}
|
||||
|
||||
community := strings.TrimSpace(kv[0])
|
||||
label := strings.TrimSpace(kv[1])
|
||||
communities.Set(community, label)
|
||||
}
|
||||
|
||||
return communities
|
||||
}
|
||||
|
||||
// Get UI config: BGP Communities
|
||||
func getBGPCommunityMap(config *ini.File) api.BGPCommunityMap {
|
||||
// Load defaults
|
||||
@ -460,6 +438,19 @@ func getRoutesNoexports(config *ini.File) (NoexportsConfig, error) {
|
||||
return noexportsConfig, nil
|
||||
}
|
||||
|
||||
// Get UI config: blackhole communities
|
||||
func getBlackholeCommunities(config *ini.File) (api.BGPCommunitiesSet, error) {
|
||||
section := config.Section("blackhole_communities")
|
||||
if section == nil {
|
||||
return api.BGPCommunitiesSet{}, nil
|
||||
}
|
||||
set, err := parseRangeCommunitiesSet(section.Body())
|
||||
if err != nil {
|
||||
return api.BGPCommunitiesSet{}, err
|
||||
}
|
||||
return *set, nil
|
||||
}
|
||||
|
||||
// Get UI config: Reject candidates
|
||||
func getRejectCandidatesConfig(config *ini.File) (RejectCandidatesConfig, error) {
|
||||
candidateCommunities := config.Section(
|
||||
@ -619,6 +610,12 @@ func getUIConfig(config *ini.File) (UIConfig, error) {
|
||||
return uiConfig, err
|
||||
}
|
||||
|
||||
// Blackhole communities
|
||||
blackholeCommunities, err := getBlackholeCommunities(config)
|
||||
if err != nil {
|
||||
return uiConfig, err
|
||||
}
|
||||
|
||||
// Theme configuration: Theming is optional, if no settings
|
||||
// are found, it will be ignored
|
||||
themeConfig := getThemeConfig(config)
|
||||
@ -641,8 +638,9 @@ func getUIConfig(config *ini.File) (UIConfig, error) {
|
||||
RoutesNoexports: noexports,
|
||||
RoutesRejectCandidates: rejectCandidates,
|
||||
|
||||
BGPCommunities: getBGPCommunityMap(config),
|
||||
Rpki: rpki,
|
||||
BGPBlackholeCommunities: blackholeCommunities,
|
||||
BGPCommunities: getBGPCommunityMap(config),
|
||||
Rpki: rpki,
|
||||
|
||||
Theme: themeConfig,
|
||||
|
||||
@ -831,6 +829,7 @@ func LoadConfig(file string) (*Config, error) {
|
||||
parsedConfig, err := ini.LoadSources(ini.LoadOptions{
|
||||
UnparseableSections: []string{
|
||||
"bgp_communities",
|
||||
"blackhole_communities",
|
||||
"rejection_reasons",
|
||||
"noexport_reasons",
|
||||
},
|
||||
|
@ -227,7 +227,7 @@ func TestRejectCandidatesConfig(t *testing.T) {
|
||||
func TestDefaultHTTPTimeout(t *testing.T) {
|
||||
config, err := LoadConfig("testdata/alice.conf")
|
||||
if err != nil {
|
||||
t.Error("Could not load test config:", err)
|
||||
t.Fatal("Could not load test config:", err)
|
||||
}
|
||||
|
||||
if config.Server.HTTPTimeout != DefaultHTTPTimeout {
|
||||
@ -249,3 +249,19 @@ func TestPostgresStoreConfig(t *testing.T) {
|
||||
}
|
||||
t.Log(config.Postgres)
|
||||
}
|
||||
|
||||
func TestGetBlackholeCommunities(t *testing.T) {
|
||||
config, _ := LoadConfig("testdata/alice.conf")
|
||||
comms := config.UI.BGPBlackholeCommunities
|
||||
|
||||
if comms.Communities[0][0].([]int)[0] != 1337 {
|
||||
t.Error("unexpected community:", comms.Communities[0])
|
||||
}
|
||||
if len(comms.ExtCommunities) != 1 {
|
||||
t.Error("unexpected communities:", comms.ExtCommunities)
|
||||
}
|
||||
if len(comms.LargeCommunities) != 1 {
|
||||
t.Error("unexpected communities:", comms.LargeCommunities)
|
||||
}
|
||||
t.Log(comms)
|
||||
}
|
||||
|
9
pkg/config/testdata/alice.conf
vendored
9
pkg/config/testdata/alice.conf
vendored
@ -88,6 +88,10 @@ load_on_demand = true # Default: false
|
||||
|
||||
23:46:1 = Some other made up reason
|
||||
|
||||
[blackhole_communities]
|
||||
1337:666
|
||||
rt:1324:4200000000-4200010000
|
||||
2342:65530-65535:665-667
|
||||
|
||||
[rpki]
|
||||
# shows rpki validation status in the client, based on the presence of a large
|
||||
@ -129,11 +133,6 @@ invalid = 23042:1000:4-*
|
||||
# Description The neighbour's description with link to routes page
|
||||
#
|
||||
#
|
||||
[blackhole_communities]
|
||||
65535:666
|
||||
12345:1105-1189:*
|
||||
12345:1111:10-90
|
||||
rt:1234:4200000000-4200010000
|
||||
|
||||
[neighbours_columns]
|
||||
address = Neighbour
|
||||
|
Loading…
x
Reference in New Issue
Block a user