feat: enhance BGP template and peer configuration handling. Introduce policies_json parameter for local IP and ASN overrides in BGP speakers. Implement BGP template rendering and update peer configuration to utilize templates, improving flexibility in BGP setup. Add tests for new rendering logic and ensure proper integration with existing configurations.
CI / changes (push) Successful in 6s
CI / openapi (push) Successful in 27s
CI / go (push) Successful in 23s
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, , evobgp-web) (push) Has been skipped
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, evobgp-all, evobgp-web-all) (push) Has been skipped
CI / docker-bird (push) Has been skipped
CI / bird2 (push) Successful in 15s
CI / docker-go (deploy/docker/evobgp-agent/Dockerfile, , evobgp-agent) (push) Successful in 1m1s
CI / docker-go (evobgp-all, 1, deploy/docker/gobinary/Dockerfile, , evobgp-all) (push) Successful in 1m26s
CI / docker-go (evobgp-api, 1, deploy/docker/gobinary/Dockerfile, , evobgp-api) (push) Successful in 1m33s
CI / docker-go (evobgp-deploy, 0, deploy/docker/gobinary/Dockerfile, , evobgp-deploy) (push) Successful in 1m21s
CI / docker-go (evobgp-ingest, 0, deploy/docker/gobinary/Dockerfile, , evobgp-ingest) (push) Successful in 1m24s
CI / docker-go (evobgp-node, 0, deploy/docker/gobinary/Dockerfile, , evobgp-node) (push) Successful in 1m25s
CI / docker-go (evobgp-render, 0, deploy/docker/gobinary/Dockerfile, , evobgp-render) (push) Successful in 1m28s
CI / docker-go (evobgp-scheduler, 0, deploy/docker/gobinary/Dockerfile, , evobgp-scheduler) (push) Successful in 1m21s

This commit is contained in:
Denozordec
2026-04-06 10:18:51 +07:00
parent c958d5af0d
commit be8e7b5742
11 changed files with 279 additions and 51 deletions
+110
View File
@@ -5,6 +5,116 @@ import (
"strings"
)
// BGP template names referenced by generated peers (BIRD 2).
const (
BGPTemplateNameV4 = "bgp_template"
BGPTemplateNameV6 = "bgp_template_v6"
)
// BGPTemplatesOptions holds tenant defaults for template bgp bgp_template (+ v6 mirror).
type BGPTemplatesOptions struct {
LocalIPv4 string
LocalIPv6 string
LocalASN uint32
ExportFilterV4 string
ExportFilterV6 string
}
// RenderBGPTemplates renders two template bgp blocks (IPv4 and IPv6 AFI).
func RenderBGPTemplates(opts BGPTemplatesOptions) (string, error) {
if strings.TrimSpace(opts.LocalIPv4) == "" || strings.TrimSpace(opts.LocalIPv6) == "" {
return "", fmt.Errorf("birdfmt: template local IPv4 and IPv6 are required")
}
if opts.LocalASN == 0 {
return "", fmt.Errorf("birdfmt: template local ASN must be non-zero")
}
exp4 := "all"
if strings.TrimSpace(opts.ExportFilterV4) != "" {
exp4 = "filter " + strings.TrimSpace(opts.ExportFilterV4)
}
exp6 := "all"
if strings.TrimSpace(opts.ExportFilterV6) != "" {
exp6 = "filter " + strings.TrimSpace(opts.ExportFilterV6)
}
var b strings.Builder
fmt.Fprintf(&b, "template bgp %s {\n", BGPTemplateNameV4)
b.WriteString(" local ")
b.WriteString(strings.TrimSpace(opts.LocalIPv4))
fmt.Fprintf(&b, " as %d;\n", opts.LocalASN)
b.WriteString(" ipv4 {\n")
b.WriteString(" import all;\n")
b.WriteString(" export ")
b.WriteString(exp4)
b.WriteString(";\n")
b.WriteString(" };\n")
b.WriteString("}\n\n")
fmt.Fprintf(&b, "template bgp %s {\n", BGPTemplateNameV6)
b.WriteString(" local ")
b.WriteString(strings.TrimSpace(opts.LocalIPv6))
fmt.Fprintf(&b, " as %d;\n", opts.LocalASN)
b.WriteString(" ipv6 {\n")
b.WriteString(" import all;\n")
b.WriteString(" export ")
b.WriteString(exp6)
b.WriteString(";\n")
b.WriteString(" };\n")
b.WriteString("}\n")
return b.String(), nil
}
// BGPPeerFromTemplateOptions describes protocol bgp NAME from TEMPLATE { … }.
type BGPPeerFromTemplateOptions struct {
ProtocolName string
TemplateName string
NeighborIP string
NeighborASN uint32
SourceAddress string
// If set, emits "local … as …" before neighbor (overrides template local/ASN for this peer).
OverrideLocalIP string
OverrideLocalASN uint32
}
// RenderProtocolBGPFromTemplate renders protocol bgp … from TEMPLATE { neighbor; multihop; source address; passive; }.
func RenderProtocolBGPFromTemplate(opts BGPPeerFromTemplateOptions) (string, error) {
if strings.TrimSpace(opts.ProtocolName) == "" {
return "", fmt.Errorf("birdfmt: protocol name is required")
}
if strings.TrimSpace(opts.TemplateName) == "" {
return "", fmt.Errorf("birdfmt: template name is required")
}
if strings.TrimSpace(opts.NeighborIP) == "" || strings.TrimSpace(opts.SourceAddress) == "" {
return "", fmt.Errorf("birdfmt: neighbor and source address are required")
}
if opts.NeighborASN == 0 {
return "", fmt.Errorf("birdfmt: neighbor ASN must be non-zero")
}
if opts.OverrideLocalIP != "" && opts.OverrideLocalASN == 0 {
return "", fmt.Errorf("birdfmt: override local ASN is required when override local IP is set")
}
var b strings.Builder
b.WriteString("protocol bgp ")
b.WriteString(strings.TrimSpace(opts.ProtocolName))
b.WriteString(" from ")
b.WriteString(strings.TrimSpace(opts.TemplateName))
b.WriteString(" {\n")
if ip := strings.TrimSpace(opts.OverrideLocalIP); ip != "" {
b.WriteString(" local ")
b.WriteString(ip)
fmt.Fprintf(&b, " as %d;\n", opts.OverrideLocalASN)
}
b.WriteString(" neighbor ")
b.WriteString(strings.TrimSpace(opts.NeighborIP))
fmt.Fprintf(&b, " as %d;\n", opts.NeighborASN)
b.WriteString(" multihop;\n")
b.WriteString(" source address ")
b.WriteString(strings.TrimSpace(opts.SourceAddress))
b.WriteString(";\n")
b.WriteString(" passive;\n")
b.WriteString("}\n")
return b.String(), nil
}
// BGPPeerIPv4Options describes a single BGP session (BIRD 2, IPv4 AF).
type BGPPeerIPv4Options struct {
ProtocolName string // e.g. evobgp_peer_uplink