CI / changes (push) Successful in 10s
CI / openapi (push) Has been skipped
CI / go (push) Successful in 35s
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, , evobgp-web) (push) Successful in 1m27s
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, evobgp-all, evobgp-web-all) (push) Successful in 1m16s
CI / docker-bird (push) Has been skipped
CI / bird2 (push) Successful in 19s
CI / docker-go (deploy/docker/evobgp-agent/Dockerfile, , evobgp-agent) (push) Successful in 1m17s
CI / docker-go (evobgp-all, 1, deploy/docker/gobinary/Dockerfile, , evobgp-all) (push) Successful in 1m48s
CI / docker-go (evobgp-api, 1, deploy/docker/gobinary/Dockerfile, , evobgp-api) (push) Successful in 1m49s
CI / docker-go (evobgp-deploy, 0, deploy/docker/gobinary/Dockerfile, , evobgp-deploy) (push) Successful in 1m28s
CI / docker-go (evobgp-ingest, 0, deploy/docker/gobinary/Dockerfile, , evobgp-ingest) (push) Successful in 1m35s
CI / docker-go (evobgp-node, 0, deploy/docker/gobinary/Dockerfile, , evobgp-node) (push) Successful in 1m15s
CI / docker-go (evobgp-render, 0, deploy/docker/gobinary/Dockerfile, , evobgp-render) (push) Successful in 1m27s
CI / docker-go (evobgp-scheduler, 0, deploy/docker/gobinary/Dockerfile, , evobgp-scheduler) (push) Successful in 1m23s
138 lines
3.2 KiB
Go
138 lines
3.2 KiB
Go
package birdfmt
|
|
|
|
import (
|
|
"net/netip"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// StaticRoute is one static route line in BIRD (optionally with a per-route body).
|
|
type StaticRoute struct {
|
|
Prefix netip.Prefix
|
|
RouteBody string // optional lines inside `route P unreachable { ... }`
|
|
}
|
|
|
|
// RenderStaticIPv4Routes renders a BIRD 2 protocol static block for IPv4.
|
|
func RenderStaticIPv4Routes(protocolName string, routes []StaticRoute) string {
|
|
if protocolName == "" {
|
|
protocolName = "evobgp_prefixes_v4"
|
|
}
|
|
type key struct {
|
|
p string
|
|
b string
|
|
}
|
|
uniq := make(map[key]StaticRoute)
|
|
for _, r := range routes {
|
|
if !r.Prefix.Addr().Is4() {
|
|
continue
|
|
}
|
|
p := r.Prefix.Masked()
|
|
body := strings.TrimSpace(r.RouteBody)
|
|
uniq[key{p.String(), body}] = StaticRoute{Prefix: p, RouteBody: body}
|
|
}
|
|
keys := make([]key, 0, len(uniq))
|
|
for k := range uniq {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Slice(keys, func(i, j int) bool {
|
|
if keys[i].p != keys[j].p {
|
|
return keys[i].p < keys[j].p
|
|
}
|
|
return keys[i].b < keys[j].b
|
|
})
|
|
|
|
var b strings.Builder
|
|
b.WriteString("protocol static ")
|
|
b.WriteString(protocolName)
|
|
b.WriteString(" {\n ipv4;\n")
|
|
for _, k := range keys {
|
|
r := uniq[k]
|
|
p := r.Prefix.String()
|
|
if r.RouteBody == "" {
|
|
b.WriteString(" route ")
|
|
b.WriteString(p)
|
|
b.WriteString(" unreachable;\n")
|
|
continue
|
|
}
|
|
b.WriteString(" route ")
|
|
b.WriteString(p)
|
|
b.WriteString(" unreachable {\n")
|
|
for _, line := range strings.Split(r.RouteBody, "\n") {
|
|
line = strings.TrimRight(line, "\r")
|
|
if strings.TrimSpace(line) == "" {
|
|
continue
|
|
}
|
|
if !strings.HasPrefix(line, " ") && !strings.HasPrefix(line, "\t") {
|
|
b.WriteString(" ")
|
|
}
|
|
b.WriteString(line)
|
|
b.WriteByte('\n')
|
|
}
|
|
b.WriteString(" };\n")
|
|
}
|
|
b.WriteString("}\n")
|
|
return b.String()
|
|
}
|
|
|
|
// RenderStaticIPv6Routes renders a BIRD 2 protocol static block for IPv6.
|
|
func RenderStaticIPv6Routes(protocolName string, routes []StaticRoute) string {
|
|
if protocolName == "" {
|
|
protocolName = "evobgp_prefixes_v6"
|
|
}
|
|
type key struct {
|
|
p string
|
|
b string
|
|
}
|
|
uniq := make(map[key]StaticRoute)
|
|
for _, r := range routes {
|
|
if !r.Prefix.Addr().Is6() {
|
|
continue
|
|
}
|
|
p := r.Prefix.Masked()
|
|
body := strings.TrimSpace(r.RouteBody)
|
|
uniq[key{p.String(), body}] = StaticRoute{Prefix: p, RouteBody: body}
|
|
}
|
|
keys := make([]key, 0, len(uniq))
|
|
for k := range uniq {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Slice(keys, func(i, j int) bool {
|
|
if keys[i].p != keys[j].p {
|
|
return keys[i].p < keys[j].p
|
|
}
|
|
return keys[i].b < keys[j].b
|
|
})
|
|
|
|
var b strings.Builder
|
|
b.WriteString("protocol static ")
|
|
b.WriteString(protocolName)
|
|
b.WriteString(" {\n ipv6;\n")
|
|
for _, k := range keys {
|
|
r := uniq[k]
|
|
p := r.Prefix.String()
|
|
if r.RouteBody == "" {
|
|
b.WriteString(" route ")
|
|
b.WriteString(p)
|
|
b.WriteString(" unreachable;\n")
|
|
continue
|
|
}
|
|
b.WriteString(" route ")
|
|
b.WriteString(p)
|
|
b.WriteString(" unreachable {\n")
|
|
for _, line := range strings.Split(r.RouteBody, "\n") {
|
|
line = strings.TrimRight(line, "\r")
|
|
if strings.TrimSpace(line) == "" {
|
|
continue
|
|
}
|
|
if !strings.HasPrefix(line, " ") && !strings.HasPrefix(line, "\t") {
|
|
b.WriteString(" ")
|
|
}
|
|
b.WriteString(line)
|
|
b.WriteByte('\n')
|
|
}
|
|
b.WriteString(" };\n")
|
|
}
|
|
b.WriteString("}\n")
|
|
return b.String()
|
|
}
|