diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 525f619..8767277 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -704,8 +704,8 @@ components: 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-пиров (если не заданы — эффективный `bird_local_ipv4` / политика пира). - Если задан `bird_bgp_source_ipv4`, он же подставляется как BIRD `router id` (перекрывает `bird_router_id`). + если задан `bird_bgp_source_ipv4`, он подставляется как BIRD `router id` (перекрывает `bird_router_id`). + Ключи `bird_bgp_source_ipv4` / `bird_bgp_source_ipv6` в сгенерированном BGP для пиров не используются (оставлены для совместимости API). Шаблон BGP в конфиге: `local as ;` без локального IP. properties: bird_router_id: @@ -720,11 +720,10 @@ components: bird_bgp_source_ipv4: type: string description: | - Исходящий IPv4 для `source address` у пиров; также задаёт `router id`, если указан. - На стороне MikroTik в BGP Connection поле **Remote address** должно совпадать с этим адресом (или с тем, с которого реально устанавливается TCP-сессия к 179/tcp), иначе сессия не поднимется. + Если задан — используется как BIRD `router id` (IPv4). В блоках `protocol bgp … from bgp_template` строка `source address` не генерируется. bird_bgp_source_ipv6: type: string - description: Исходящий IPv6 для `source address` у пиров IPv6. + description: Зарезервировано; в текущей генерации BGP не используется. additionalProperties: true RevisionDiff: diff --git a/internal/birdfmt/bgp.go b/internal/birdfmt/bgp.go index c9d83c2..5690a9c 100644 --- a/internal/birdfmt/bgp.go +++ b/internal/birdfmt/bgp.go @@ -12,7 +12,7 @@ const ( ) // BGPTemplatesOptions holds ASN and export filters for template bgp bgp_template (+ v6 mirror). -// Templates use "local as ;" only (no local IP); peers supply source address / optional local override. +// Templates use "local as ;" only (no local IP); peers add neighbor / multihop / passive and optional "local … as …" override. type BGPTemplatesOptions struct { LocalASN uint32 ExportFilterV4 string @@ -43,8 +43,6 @@ func RenderBGPTemplates(opts BGPTemplatesOptions) (string, error) { b.WriteString(" };\n") b.WriteString(" hold time 90;\n") b.WriteString(" keepalive time 30;\n") - // Жёсткая привязка к source address (см. пир): полезно в Docker / bridge, иначе listen может уйти на 0.0.0.0. - b.WriteString(" strict bind on;\n") b.WriteString("}\n\n") fmt.Fprintf(&b, "template bgp %s {\n", BGPTemplateNameV6) fmt.Fprintf(&b, " local as %d;\n", opts.LocalASN) @@ -56,7 +54,6 @@ func RenderBGPTemplates(opts BGPTemplatesOptions) (string, error) { b.WriteString(" };\n") b.WriteString(" hold time 90;\n") b.WriteString(" keepalive time 30;\n") - b.WriteString(" strict bind on;\n") b.WriteString("}\n") return b.String(), nil } @@ -67,14 +64,12 @@ type BGPPeerFromTemplateOptions struct { 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; strict bind; passive; }. -// strict bind дублируется и в шаблоне, и в каждом пире — явная фиксация на сессию. +// RenderProtocolBGPFromTemplate renders protocol bgp … from TEMPLATE { neighbor; multihop; passive; }. func RenderProtocolBGPFromTemplate(opts BGPPeerFromTemplateOptions) (string, error) { if strings.TrimSpace(opts.ProtocolName) == "" { return "", fmt.Errorf("birdfmt: protocol name is required") @@ -82,8 +77,8 @@ func RenderProtocolBGPFromTemplate(opts BGPPeerFromTemplateOptions) (string, err 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 strings.TrimSpace(opts.NeighborIP) == "" { + return "", fmt.Errorf("birdfmt: neighbor is required") } if opts.NeighborASN == 0 { return "", fmt.Errorf("birdfmt: neighbor ASN must be non-zero") @@ -107,10 +102,6 @@ func RenderProtocolBGPFromTemplate(opts BGPPeerFromTemplateOptions) (string, err 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(" strict bind on;\n") b.WriteString(" passive;\n") b.WriteString("}\n") return b.String(), nil diff --git a/internal/birdfmt/bgp_test.go b/internal/birdfmt/bgp_test.go index 5bf76d0..22b955e 100644 --- a/internal/birdfmt/bgp_test.go +++ b/internal/birdfmt/bgp_test.go @@ -37,11 +37,10 @@ func TestRenderBGPTemplates_Validation(t *testing.T) { func TestRenderProtocolBGPFromTemplate_MultihopPassive(t *testing.T) { got, err := RenderProtocolBGPFromTemplate(BGPPeerFromTemplateOptions{ - ProtocolName: "evobgp_p_x", - TemplateName: BGPTemplateNameV4, - NeighborIP: "94.142.140.141", - NeighborASN: 65002, - SourceAddress: "77.232.38.173", + ProtocolName: "evobgp_p_x", + TemplateName: BGPTemplateNameV4, + NeighborIP: "94.142.140.141", + NeighborASN: 65002, }) if err != nil { t.Fatal(err) @@ -52,10 +51,7 @@ func TestRenderProtocolBGPFromTemplate_MultihopPassive(t *testing.T) { if !strings.Contains(got, "multihop;") || !strings.Contains(got, "passive;") { t.Fatal(got) } - if !strings.Contains(got, "source address 77.232.38.173;") { - t.Fatal(got) - } - if !strings.Contains(got, "strict bind on;") { + if strings.Contains(got, "source address") || strings.Contains(got, "strict bind") { t.Fatal(got) } } @@ -66,7 +62,6 @@ func TestRenderProtocolBGPFromTemplate_OverrideLocal(t *testing.T) { TemplateName: BGPTemplateNameV4, NeighborIP: "192.0.2.2", NeighborASN: 2, - SourceAddress: "10.0.0.1", OverrideLocalIP: "10.0.0.1", OverrideLocalASN: 65099, }) diff --git a/internal/birdfmt/standard_layout_test.go b/internal/birdfmt/standard_layout_test.go index 0c72685..2b8b3ba 100644 --- a/internal/birdfmt/standard_layout_test.go +++ b/internal/birdfmt/standard_layout_test.go @@ -40,11 +40,10 @@ func TestStandardLayout_GeneratorMatchesFixtures(t *testing.T) { assertFileEquals(t, "testdata/scenarios/standard_layout/bird.d/evobgp_bgp_template.conf", tpl) peer, err := RenderProtocolBGPFromTemplate(BGPPeerFromTemplateOptions{ - ProtocolName: "evobgp_peer_ci", - TemplateName: BGPTemplateNameV4, - NeighborIP: "192.0.2.2", - NeighborASN: 65002, - SourceAddress: "192.0.2.1", + ProtocolName: "evobgp_peer_ci", + TemplateName: BGPTemplateNameV4, + NeighborIP: "192.0.2.2", + NeighborASN: 65002, }) if err != nil { t.Fatal(err) diff --git a/internal/birdfmt/testdata/scenarios/standard_layout/bird.d/evobgp_bgp_template.conf b/internal/birdfmt/testdata/scenarios/standard_layout/bird.d/evobgp_bgp_template.conf index 1ecc5fa..72f51e9 100644 --- a/internal/birdfmt/testdata/scenarios/standard_layout/bird.d/evobgp_bgp_template.conf +++ b/internal/birdfmt/testdata/scenarios/standard_layout/bird.d/evobgp_bgp_template.conf @@ -6,7 +6,6 @@ template bgp bgp_template { }; hold time 90; keepalive time 30; - strict bind on; } template bgp bgp_template_v6 { @@ -17,5 +16,4 @@ template bgp bgp_template_v6 { }; hold time 90; keepalive time 30; - strict bind on; } diff --git a/internal/birdfmt/testdata/scenarios/standard_layout/bird.d/evobgp_peers.conf b/internal/birdfmt/testdata/scenarios/standard_layout/bird.d/evobgp_peers.conf index 8208944..dca1b1a 100644 --- a/internal/birdfmt/testdata/scenarios/standard_layout/bird.d/evobgp_peers.conf +++ b/internal/birdfmt/testdata/scenarios/standard_layout/bird.d/evobgp_peers.conf @@ -1,7 +1,5 @@ protocol bgp evobgp_peer_ci from bgp_template { neighbor 192.0.2.2 as 65002; multihop; - source address 192.0.2.1; - strict bind on; passive; } diff --git a/internal/pipeline/refresh.go b/internal/pipeline/refresh.go index c91f703..ce66a83 100644 --- a/internal/pipeline/refresh.go +++ b/internal/pipeline/refresh.go @@ -331,9 +331,6 @@ 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 { @@ -361,30 +358,12 @@ func birdLocalsFromStore(st store.Backend, tenantID string) birdLocals { loc.localASN = n } if s := stringFromSettingsMap(settings, "bird_bgp_source_ipv4"); s != "" { - loc.sourceV4 = s - // BIRD router id must be an IPv4 address; align with BGP source when operator sets it. + // BIRD router id must be an IPv4 address; historically aligned with optional BGP source setting. loc.routerID = strings.TrimSpace(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 { @@ -474,11 +453,10 @@ func renderPeersBirdFragment(st store.Backend, tenantID string, loc birdLocals) ra := uint32(p.RemoteASN) if addr.Is4() { opts := birdfmt.BGPPeerFromTemplateOptions{ - ProtocolName: proto, - TemplateName: birdfmt.BGPTemplateNameV4, - NeighborIP: addr.String(), - NeighborASN: ra, - SourceAddress: bgpPeerSourceIPv4(loc, lv4), + ProtocolName: proto, + TemplateName: birdfmt.BGPTemplateNameV4, + NeighborIP: addr.String(), + NeighborASN: ra, } if peerNeedsLocalOverride(loc, lv4, asn, true) { opts.OverrideLocalIP = lv4 @@ -493,11 +471,10 @@ func renderPeersBirdFragment(st store.Backend, tenantID string, loc birdLocals) } if addr.Is6() { opts := birdfmt.BGPPeerFromTemplateOptions{ - ProtocolName: proto, - TemplateName: birdfmt.BGPTemplateNameV6, - NeighborIP: addr.String(), - NeighborASN: ra, - SourceAddress: bgpPeerSourceIPv6(loc, lv6), + ProtocolName: proto, + TemplateName: birdfmt.BGPTemplateNameV6, + NeighborIP: addr.String(), + NeighborASN: ra, } 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 d6977ac..1bf1678 100644 --- a/web/src/routes/settings/+page.svelte +++ b/web/src/routes/settings/+page.svelte @@ -98,8 +98,8 @@ GET/PATCH /v1/settings — глобальные параметры control plane (хранятся в БД). Требуется роль operator. Для BIRD, например: bird_local_ipv4, - bird_bgp_source_ipv4 (опционально — только для строки - source address у BGP-пиров). + bird_bgp_source_ipv4 (опционально — задаёт BIRD + router id). @@ -111,7 +111,7 @@

Должен быть строго валидный JSON: ключи и строки в двойных кавычках, без точки с запятой. Пример: {`{"bird_bgp_source_ipv4": "178.250.186.111"}`}{`{"bird_router_id": "203.0.113.1", "bird_local_asn": 65001}`}