Files
Denozordec 1c5a9c91bb
CI / changes (push) Successful in 5s
CI / openapi (push) Has been skipped
CI / go (push) Successful in 38s
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-prime (push) Successful in 24s
CI / docker-go (deploy/docker/evobgp-agent/Dockerfile, , evobgp-agent) (push) Successful in 59s
CI / docker-go (evobgp-all, 1, deploy/docker/gobinary/Dockerfile, , evobgp-all) (push) Successful in 2m6s
CI / docker-go (evobgp-api, 1, deploy/docker/gobinary/Dockerfile, , evobgp-api) (push) Successful in 1m22s
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 1m8s
CI / docker-go (evobgp-render, 0, deploy/docker/gobinary/Dockerfile, , evobgp-render) (push) Successful in 1m23s
CI / docker-go (evobgp-scheduler, 0, deploy/docker/gobinary/Dockerfile, , evobgp-scheduler) (push) Successful in 1m22s
feat: refactor materialization logic to group static routes by community in the refresh pipeline. Introduce a new structure for managing static routes, enhancing the handling of IPv4 and IPv6 routes while preserving community associations. Update related functions to support the new grouping mechanism.
2026-04-06 20:20:52 +07:00

150 lines
3.6 KiB
Go

package pipeline
import (
"fmt"
"net/netip"
"sort"
"strconv"
"strings"
"evobgp/internal/birdfmt"
"evobgp/internal/store"
)
type staticCommunityRoutes struct {
CommunityID string
RoutesV4 []birdfmt.StaticRoute
RoutesV6 []birdfmt.StaticRoute
}
// materializeRowsForBird turns prefix rows into export-filter CIDR lists, optional AS_PATH rules,
// and static routes grouped by community. The same prefix can appear in multiple community groups.
func materializeRowsForBird(st store.Backend, tenantID string, rows []store.PrefixRow) (
filterV4, filterV6 []netip.Prefix,
pathASNs []int64,
staticByCommunity []staticCommunityRoutes,
err error,
) {
var pathSeen map[int64]struct{}
addPath := func(n int64) {
if pathSeen == nil {
pathSeen = make(map[int64]struct{})
}
if _, ok := pathSeen[n]; ok {
return
}
pathSeen[n] = struct{}{}
pathASNs = append(pathASNs, n)
}
filterSeen := make(map[string]struct{})
type staticGroup struct {
v4 map[string]birdfmt.StaticRoute
v6 map[string]birdfmt.StaticRoute
}
staticGroups := make(map[string]*staticGroup)
routeBodyByCommunity := make(map[string]string)
for _, pr := range rows {
p := strings.TrimSpace(pr.Prefix)
if strings.HasPrefix(p, "as:") {
n, err := strconv.ParseInt(strings.TrimPrefix(p, "as:"), 10, 64)
if err != nil || !store.ValidASN(n) {
continue
}
addPath(n)
continue
}
pfx, err := netip.ParsePrefix(p)
if err != nil {
continue
}
pfx = pfx.Masked()
key := pfx.String()
if _, ok := filterSeen[key]; !ok {
filterSeen[key] = struct{}{}
if pfx.Addr().Is4() {
filterV4 = append(filterV4, pfx)
} else {
filterV6 = append(filterV6, pfx)
}
}
communityID := ""
if pr.CommunityID != nil {
communityID = strings.TrimSpace(*pr.CommunityID)
}
body, ok := routeBodyByCommunity[communityID]
if !ok {
body, err = communityRouteBody(st, tenantID, pr.CommunityID)
if err != nil {
return nil, nil, nil, nil, err
}
routeBodyByCommunity[communityID] = body
}
grp, ok := staticGroups[communityID]
if !ok {
grp = &staticGroup{
v4: make(map[string]birdfmt.StaticRoute),
v6: make(map[string]birdfmt.StaticRoute),
}
staticGroups[communityID] = grp
}
if pfx.Addr().Is4() {
if _, exists := grp.v4[key]; !exists {
grp.v4[key] = birdfmt.StaticRoute{Prefix: pfx, RouteBody: body}
}
} else if pfx.Addr().Is6() {
if _, exists := grp.v6[key]; !exists {
grp.v6[key] = birdfmt.StaticRoute{Prefix: pfx, RouteBody: body}
}
}
}
groupKeys := make([]string, 0, len(staticGroups))
for k := range staticGroups {
groupKeys = append(groupKeys, k)
}
sort.Strings(groupKeys)
for _, gid := range groupKeys {
grp := staticGroups[gid]
out := staticCommunityRoutes{CommunityID: gid}
v4Keys := make([]string, 0, len(grp.v4))
for k := range grp.v4 {
v4Keys = append(v4Keys, k)
}
sort.Strings(v4Keys)
for _, k := range v4Keys {
out.RoutesV4 = append(out.RoutesV4, grp.v4[k])
}
v6Keys := make([]string, 0, len(grp.v6))
for k := range grp.v6 {
v6Keys = append(v6Keys, k)
}
sort.Strings(v6Keys)
for _, k := range v6Keys {
out.RoutesV6 = append(out.RoutesV6, grp.v6[k])
}
staticByCommunity = append(staticByCommunity, out)
}
return filterV4, filterV6, pathASNs, staticByCommunity, nil
}
func communityRouteBody(st store.Backend, tenantID string, cid *string) (string, error) {
if cid == nil {
return "", nil
}
id := strings.TrimSpace(*cid)
if id == "" {
return "", nil
}
c, err := st.GetCommunity(tenantID, id)
if err != nil {
return "", fmt.Errorf("community %s: %w", id, err)
}
return birdfmt.RouteCommunityAttrs("", c.Community, c.ValueJSON)
}