--- description: EvoBGP — BIRD2, BGP policy, IP/CIDR, маршрутизация, валидация конфигов globs: - internal/birdfmt/** - internal/birddeploy/** - internal/pipeline/** - deploy/bird/** - "**/testdata/scenarios/**" alwaysApply: false --- # Networking & Routing Rules Общие правила: `.cursor/rules/engineering.mdc`. Пакет BIRD: `internal/birdfmt/doc.go`. ## Single source of truth | Домен | SSOT | |-------|------| | Префиксы для анонса | Модули tenant → materialized snapshot → ревизия (`store`, `pipeline`, `CreateRenderRevision`) | | Текст BIRD-фрагментов | `internal/birdfmt` — только генератор `evobgp_*.conf` | | Каркас `bird.conf` | Operator skeleton + `include` (`StandardIncludeFragments`) | | Параметры BIRD tenant | Global settings: `bird_router_id`, `bird_local_asn`, … (`docs/manual.md`) | | BGP peers | `BGPPeer` + `ParsePeerNeighbor` | **BIRD2 docs:** https://bird.nic.cz/?get_doc --- ## A. BIRD2 Configuration Rules **BIRD-01** | MUST | Имена фрагментов — константы `Fragment*` (`evobgp_prefixes_v4.conf`, …); include `bird.d/`. *Rationale:* совместимость deploy. *Проверка:* `layout.go`; `go test ./internal/birdfmt/...` **BIRD-02** | MUST | Порядок include: filters v4/v6 → BGP template → prefixes v4/v6 → peers (`StandardIncludeFragments`). *Rationale:* фильтры до ссылок. *Проверка:* scenario `standard_layout`; `bird -p` **BIRD-03** | MUST | `bird.conf` (router id, device, direct, includes) отдельно от `bird.d/evobgp_*` (политика, префиксы). *Rationale:* атомарная подмена фрагментов. *Проверка:* review layout. **BIRD-04** | MUST | Новая логика фильтрации — функция в `birdfmt` + unit-тест; NEVER дублировать filter-блок в два `.conf` вручную. *Rationale:* DRY v4/v6. *Проверка:* `filter_test.go`; review. **BIRD-05** | MUST | Filter: префикс `evobgp_`, суффикс `_v4`/`_v6`; templates `bgp_template` / `bgp_template_v6`. *Проверка:* `bgp.go`, `layout.go`. **BIRD-06** | MUST | `router id` — валидный IPv4 dotted-quad (`RenderMainBirdConf`). *Проверка:* `birdfmt` error; `bird -p` **BIRD-07** | MUST | Communities — `RouteCommunityAttrs`; синтаксис `((a,b))` в `add()`, не `add(65000,1)`. *Проверка:* `community_bird_test.go` **BIRD-08** | SHOULD | Комментарии `#` в preamble; в фрагментах — revision/module id где уместно. *Проверка:* review. **BIRD-09** | NEVER | Ручное редактирование `evobgp_*.conf` на ноде без ревизии/бандла в control plane. *Rationale:* drift. *Проверка:* `evobgp-deploy` logs. **BIRD-10** | MUST | Новый scenario: `testdata/scenarios//bird.conf` (+ `bird.d/`) проходит `bird -p`. *Проверка:* CI `bird2` **BIRD-11** | MUST | Только BIRD **2.x**, не 1.6. *Проверка:* `bird --version` **BIRD-12** | MUST | Apply: staging → `bird -p` → atomic swap → `birdc configure`; NEVER configure без parse check. *Проверка:* `birdctl.go`; `birddeploy` review. --- ## B. Routing Policy Rules **RTE-01** | MUST | BGP template: `import none` на каждый AFI, если задача явно не добавляет import policy. *Rationale:* deny-by-default. *Проверка:* `bgp.go` **RTE-02** | MUST | Export filter завершается `reject;`. *Проверка:* `filter.go`; `filter_export` scenario. **RTE-03** | MUST | Анонс только префиксов materialized revision; NEVER static `route` вне pipeline/birdfmt без operator approval. *Проверка:* store snapshot; review. **RTE-04** | NEVER | Анонс `0.0.0.0/0`, `::/0`, RFC1918/ULA, loopback, link-local, multicast, reserved без documented exception. *Проверка:* ingest validation; review. **RTE-05** | NEVER | Префиксы чужих ASN без авторизации (IRR/RPKI — ops review). *Проверка:* ops review. **RTE-06** | MUST | Отдельные export filters IPv4 и IPv6. *Проверка:* `RenderExportFilterIPv4/IPv6` **RTE-07** | SHOULD | AS_PATH match — ASN из tenant modules; дедуп `filterUniqueASNs`. *Проверка:* unit tests. **RTE-08** | MUST | Peer import/export overrides — расширение `birdfmt`, не ad-hoc в operator `bird.conf`. *Проверка:* review. **RTE-09** | SHOULD | hold 90s / keepalive 30s — менять только с обоснованием в settings/docs. *Проверка:* review. **RTE-10** | MUST | После apply — post-check `birdc`/метрики (`mergeBirdPostApplyMeta`, `EVOBGP_BIRDC_SOCKET`). *Проверка:* jobs meta; observability poller. --- ## C. IP Addressing Rules **IP-01** | MUST | CIDR в Go — `netip.Prefix`; строка — `Masked().String()`. *Проверка:* `pipeline/parse.go` **IP-02** | MUST | IPv4/IPv6 — отдельные fragments/filters. *Проверка:* `layout.go` **IP-03** | MUST | BGP neighbor — `ParsePeerNeighbor`; `/32`/`/128` нормализуются в host addr. *Проверка:* `peer_neighbor_test.go` **IP-04** | NEVER | Hardcoded production CIDR вне testdata/fixtures. *Проверка:* grep; review. **IP-05** | MUST | Fixtures/docs — TEST-NET (RFC 5737, 3849): `203.0.113.0/24`, `198.51.100.0/24`, `2001:db8::/32`. *Проверка:* scenarios. **IP-06** | MUST | Domain→IP: host routes `/32`, `/128` via `ipToHostPrefix`; invalid отбрасывается. *Проверка:* `collect_parallel.go` **IP-07** | MUST | IP range entries — валидный CIDR на границе API/store. *Проверка:* httpapi; review. **IP-08** | SHOULD | Множество префиксов — без дубликатов; агрегация — policy decision. *Проверка:* snapshot dedup. **IP-09** | MUST | `router id`, `local as` — из tenant settings, не hardcode в callers `birdfmt`. *Проверка:* `docs/manual.md` **IP-10** | NEVER | Reserved blocks (`0.0.0.0/8`, `127.0.0.0/8`, `169.254.0.0/16`, `224.0.0.0/4`, IPv6 analogs) в materialized prefixes. *Проверка:* review; future validator. --- ## D. Internet Compliance **COMP-01** | SHOULD | Policy changes — сверка RFC 4271, 4760, 7454 (обзор). *Проверка:* review. **COMP-02** | MUST | No excessive deaggregation без need. *Проверка:* review prefix list. **COMP-03** | MUST | Standard community 0..65535; large — schema store. *Проверка:* `community_bird_test.go` **COMP-04** | NEVER | AS_PATH/MED manipulation без product spec. *Проверка:* review output. **COMP-05** | SHOULD | Revision/job meta: source, counts, samples (`revisionLogEntry`). *Проверка:* jobs. **COMP-06** | MUST | Node: `evobgp-node verify-bundle` перед apply. *Проверка:* `docs/access.md` **COMP-07** | SHOULD | `bird_local_asn` = `local as` в templates/peers. *Проверка:* settings + birdfmt. **COMP-08** | NEVER | Default route leak без named `default-originate` policy. *Проверка:* export filter review. --- ## Validation & Observability **VAL-01** | MUST | Перед деплоем: `bird -c -p` (main + includes). *Проверка:* CI `bird2`; `ParseCheck` **VAL-02** | MUST | Preview ревизии read-only; apply — jobs/apply/bundle only. *Проверка:* OpenAPI + httpapi. **VAL-03** | MUST | Изменения birdfmt — `go test ./internal/birdfmt/...`. *Проверка:* CI `go` **VAL-04** | SHOULD | Dry-run apply где API поддерживает `dry_run`. *Проверка:* routes.go. **VAL-05** | MUST | `/metrics` Prometheus; `EVOBGP_BIRDC_SOCKET` — BGP session poller. *Проверка:* `observability` **VAL-06** | MUST | Логировать job_id, revision_id, speaker_id на apply/refresh/rollback. *Проверка:* jobs API. **VAL-07** | SHOULD | После apply — `birdc show protocols` / parsers в `birdfmt`. *Проверка:* `protocols.go` **VAL-08** | MUST | Мониторить drift: `last_applied_revision_id` vs published (`evobgp-deploy`). *Проверка:* deploy worker. --- ## Documentation Sync **DOC-SYNC-05** | MUST | BIRD — https://bird.nic.cz/?get_doc **DOC-SYNC-08** | MUST | BGP policy — RFC 4271, 4760, 7454 + BIRD docs + `birdfmt` **DOC-SYNC-09** | MUST | CIDR — https://pkg.go.dev/net/netip ; примеры — RFC 5737, 3849 --- ## Enforcement ```powershell go test ./internal/birdfmt/... ./internal/pipeline/... -count=1 bird -c internal/birdfmt/testdata/scenarios//bird.conf -p ``` **PR checklist `birdfmt/**`, `pipeline/**`, `deploy/bird/**`:** - [ ] filter + unit-test + `bird -p` - [ ] нет дубли filter logic v4/v6 без общей Go-функции - [ ] префиксы только store/revision path - [ ] `import none` на templates сохранён