feat: enhance RefreshModule to support legacy ASN resolution and improve prefix handling. Introduce sorting of ASNs and manage announced prefixes with polite pauses for better API interaction. Update buildPreviewFragments to streamline route rendering for BIRD configurations.
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
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
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
package birdfmt
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var standardPairRE = regexp.MustCompile(`^\s*(\d{1,5}):(\d{1,5})\s*$`)
|
||||
|
||||
// RouteCommunityAttrs returns BIRD 2 lines (indented with 4 spaces) for use inside a static `route … { … }` block.
|
||||
// Empty string means no community attributes.
|
||||
func RouteCommunityAttrs(kind, name, valueJSON string) (string, error) {
|
||||
name = strings.TrimSpace(name)
|
||||
raw := strings.TrimSpace(valueJSON)
|
||||
if raw == "" {
|
||||
raw = "{}"
|
||||
}
|
||||
|
||||
if s, ok := parseLargeFromJSONLoose(raw); ok {
|
||||
return s, nil
|
||||
}
|
||||
_ = kind // reserved for future kinds (e.g. extended communities)
|
||||
|
||||
if m := standardPairRE.FindStringSubmatch(name); len(m) == 3 {
|
||||
return standardAddLine(m[1], m[2])
|
||||
}
|
||||
|
||||
var obj map[string]any
|
||||
if json.Unmarshal([]byte(raw), &obj) == nil {
|
||||
if v, ok := obj["standard"].(string); ok {
|
||||
if m := standardPairRE.FindStringSubmatch(v); len(m) == 3 {
|
||||
return standardAddLine(m[1], m[2])
|
||||
}
|
||||
}
|
||||
if arr, ok := obj["standard"].([]any); ok && len(arr) == 2 {
|
||||
a, aok := numberToUint32String(arr[0])
|
||||
b, bok := numberToUint32String(arr[1])
|
||||
if aok && bok {
|
||||
return standardAddLine(a, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var strVal string
|
||||
if json.Unmarshal([]byte(raw), &strVal) == nil {
|
||||
if m := standardPairRE.FindStringSubmatch(strVal); len(m) == 3 {
|
||||
return standardAddLine(m[1], m[2])
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func standardAddLine(a, b string) (string, error) {
|
||||
ai, err1 := strconv.ParseUint(strings.TrimSpace(a), 10, 16)
|
||||
bi, err2 := strconv.ParseUint(strings.TrimSpace(b), 10, 16)
|
||||
if err1 != nil || err2 != nil {
|
||||
return "", fmt.Errorf("birdfmt: standard community parts must be 0..65535 (%s:%s)", a, b)
|
||||
}
|
||||
return fmt.Sprintf(" bgp_community.add((%d,%d));", ai, bi), nil
|
||||
}
|
||||
|
||||
func parseLargeFromJSONLoose(raw string) (string, bool) {
|
||||
var obj map[string]any
|
||||
if json.Unmarshal([]byte(raw), &obj) != nil {
|
||||
return "", false
|
||||
}
|
||||
arr, ok := obj["large"].([]any)
|
||||
if !ok || len(arr) == 0 {
|
||||
return "", false
|
||||
}
|
||||
var b strings.Builder
|
||||
for _, row := range arr {
|
||||
triple, ok := row.([]any)
|
||||
if !ok || len(triple) != 3 {
|
||||
continue
|
||||
}
|
||||
a, ok1 := numberToUint32String(triple[0])
|
||||
bb, ok2 := numberToUint32String(triple[1])
|
||||
c, ok3 := numberToUint32String(triple[2])
|
||||
if !ok1 || !ok2 || !ok3 {
|
||||
continue
|
||||
}
|
||||
ai, _ := strconv.ParseUint(a, 10, 32)
|
||||
bi, _ := strconv.ParseUint(bb, 10, 32)
|
||||
ci, _ := strconv.ParseUint(c, 10, 32)
|
||||
fmt.Fprintf(&b, " bgp_large_community.add((%d,%d,%d));\n", ai, bi, ci)
|
||||
}
|
||||
s := strings.TrimRight(b.String(), "\r\n")
|
||||
return s, s != ""
|
||||
}
|
||||
|
||||
func numberToUint32String(v any) (string, bool) {
|
||||
switch x := v.(type) {
|
||||
case float64:
|
||||
if x < 0 || x > 4294967295 {
|
||||
return "", false
|
||||
}
|
||||
return strconv.FormatUint(uint64(x), 10), true
|
||||
case json.Number:
|
||||
n, err := x.Int64()
|
||||
if err != nil || n < 0 || n > 4294967295 {
|
||||
return "", false
|
||||
}
|
||||
return strconv.FormatUint(uint64(n), 10), true
|
||||
case int:
|
||||
if x < 0 || x > 4294967295 {
|
||||
return "", false
|
||||
}
|
||||
return strconv.FormatUint(uint64(x), 10), true
|
||||
case string:
|
||||
n, err := strconv.ParseUint(strings.TrimSpace(x), 10, 32)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
return strconv.FormatUint(n, 10), true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user