diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 4f19267..6689abb 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -700,7 +700,28 @@ components: Settings: type: object - description: KV настройки tenant/глобальные лимиты и feature flags. + description: | + KV настройки tenant/глобальные лимиты и feature flags. + Параметры BIRD (строки в `global_settings`, JSON-значения — обычно строка или число): + `bird_router_id`, `bird_local_ipv4`, `bird_local_ipv6`, `bird_local_asn`; + опционально `bird_bgp_source_ipv4` / `bird_bgp_source_ipv6` — явный адрес для директивы + `source address` у BGP-пиров (если не заданы, используется эффективный локальный адрес, как для `local` в шаблоне). + properties: + bird_router_id: + type: string + description: BIRD `router id` (рекомендуется IPv4 dotted quad). + bird_local_ipv4: + type: string + bird_local_ipv6: + type: string + bird_local_asn: + type: integer + bird_bgp_source_ipv4: + type: string + description: Исходящий IPv4 для `source address` в блоках `protocol bgp … from bgp_template`. + bird_bgp_source_ipv6: + type: string + description: Исходящий IPv6 для `source address` у пиров IPv6. additionalProperties: true RevisionDiff: diff --git a/internal/pipeline/refresh.go b/internal/pipeline/refresh.go index 7c0eaac..5de1c06 100644 --- a/internal/pipeline/refresh.go +++ b/internal/pipeline/refresh.go @@ -333,6 +333,9 @@ type birdLocals struct { localV4 string localV6 string localASN uint32 + // Optional BGP TCP source (BIRD "source address"); empty => use effective local per peer. + sourceV4 string + sourceV6 string } func birdLocalsFromStore(st store.Backend, tenantID string) birdLocals { @@ -359,9 +362,29 @@ func birdLocalsFromStore(st store.Backend, tenantID string) birdLocals { if n := uint32FromSettingsMap(settings, "bird_local_asn"); n != 0 { loc.localASN = n } + if s := stringFromSettingsMap(settings, "bird_bgp_source_ipv4"); s != "" { + loc.sourceV4 = s + } + if s := stringFromSettingsMap(settings, "bird_bgp_source_ipv6"); s != "" { + loc.sourceV6 = s + } return loc } +func bgpPeerSourceIPv4(loc birdLocals, effectiveLocal string) string { + if s := strings.TrimSpace(loc.sourceV4); s != "" { + return s + } + return effectiveLocal +} + +func bgpPeerSourceIPv6(loc birdLocals, effectiveLocal string) string { + if s := strings.TrimSpace(loc.sourceV6); s != "" { + return s + } + return effectiveLocal +} + func stringFromSettingsMap(m map[string]any, key string) string { v, ok := m[key] if !ok || v == nil { @@ -455,7 +478,7 @@ func renderPeersBirdFragment(st store.Backend, tenantID string, loc birdLocals) TemplateName: birdfmt.BGPTemplateNameV4, NeighborIP: addr.String(), NeighborASN: ra, - SourceAddress: lv4, + SourceAddress: bgpPeerSourceIPv4(loc, lv4), } if peerNeedsLocalOverride(loc, lv4, asn, true) { opts.OverrideLocalIP = lv4 @@ -474,7 +497,7 @@ func renderPeersBirdFragment(st store.Backend, tenantID string, loc birdLocals) TemplateName: birdfmt.BGPTemplateNameV6, NeighborIP: addr.String(), NeighborASN: ra, - SourceAddress: lv6, + SourceAddress: bgpPeerSourceIPv6(loc, lv6), } if peerNeedsLocalOverride(loc, lv6, asn, false) { opts.OverrideLocalIP = lv6 diff --git a/web/src/routes/settings/+page.svelte b/web/src/routes/settings/+page.svelte index 0858b0f..b8bfdd8 100644 --- a/web/src/routes/settings/+page.svelte +++ b/web/src/routes/settings/+page.svelte @@ -95,8 +95,11 @@ Настройки системы (API) - GET/PATCH /v1/settings — глобальные параметры control plane. - Требуется роль operator. + GET/PATCH /v1/settings — глобальные параметры control plane (хранятся в БД). + Требуется роль operator. Для BIRD, например: + bird_local_ipv4, + bird_bgp_source_ipv4 (опционально — только для строки + source address у BGP-пиров).