From accce3224d23afef9f5832dea0a124b6b43c8a62 Mon Sep 17 00:00:00 2001
From: Daymarvi <31985821+Daymarvi@users.noreply.github.com>
Date: Thu, 2 Jul 2026 09:57:24 +0200
Subject: [PATCH 1/2] docs: add GitHub-style project documentation
---
docs/DOCUMENTATION.md | 530 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 530 insertions(+)
create mode 100644 docs/DOCUMENTATION.md
diff --git a/docs/DOCUMENTATION.md b/docs/DOCUMENTATION.md
new file mode 100644
index 0000000..7f2fc3f
--- /dev/null
+++ b/docs/DOCUMENTATION.md
@@ -0,0 +1,530 @@
+
+
+# WinBGP
+
+**The BGP swiss army knife of networking on Windows**
+
+A pure-PowerShell Windows service that turns a Windows Server into a dynamic,
+health-checked BGP route announcer — with a CLI, a REST API and Prometheus metrics.
+
+
+
+
+
+
+[Project on GitHub](https://github.com/webalexeu/winbgp)
+
+
+
+---
+
+## Table of contents
+
+- [Overview](#overview)
+- [Key features](#key-features)
+- [Architecture](#architecture)
+- [Components](#components)
+- [Prerequisites](#prerequisites)
+- [Installation](#installation)
+- [Configuration](#configuration)
+ - [Global settings](#global-settings)
+ - [API](#api-configuration)
+ - [Router](#router)
+ - [Peers](#peers)
+ - [Routes](#routes)
+ - [Health-check methods](#health-check-methods)
+- [Route lifecycle & status](#route-lifecycle--status)
+- [Command line interface (CLI)](#command-line-interface-cli)
+- [REST API](#rest-api)
+- [Prometheus metrics](#prometheus-metrics)
+- [Logging](#logging)
+- [Building the MSI](#building-the-msi)
+- [Project layout](#project-layout)
+- [Credits](#credits)
+
+---
+
+## Overview
+
+WinBGP runs as a native Windows service and manages BGP route announcements on
+top of the built-in **Remote Access / Routing (RRAS)** BGP feature. It reads a
+single JSON configuration file describing the local router, its BGP peers and the
+routes (VIPs) to announce. For each route it can:
+
+- Mount/unmount the associated IP address on a network interface (dynamic VIP).
+- Announce/withdraw the route to all configured BGP peers.
+- Continuously run a **health check** and automatically withdraw the route when
+ the monitored resource goes down (`WithdrawOnDown`).
+- Be placed in **maintenance** to gracefully drain traffic.
+
+Everything is scriptable through a CLI, controllable over a local REST API, and
+observable via Windows Event Log and Prometheus metrics.
+
+> WinBGP is a good fit for anycast VIPs, active/active service front-ends, and
+> highly available on-prem services that need to be advertised (or withdrawn)
+> based on their real health.
+
+---
+
+## Key features
+
+| Feature | Description |
+| --- | --- |
+| Pure PowerShell service | No compiled agent; a thin `.exe` wrapper invokes the PowerShell engine. |
+| Dynamic VIP management | Automatically adds/removes the route IP on the chosen interface (`DynamicIpSetup`). |
+| Health-check driven | Announce/withdraw a route based on `service`, `process`, `tcp`, `cluster` or `custom` checks. |
+| Rise/Fall thresholds | Debounced state changes (configurable number of consecutive checks). |
+| Maintenance mode | Gracefully drain a route without stopping the service. |
+| Hot reload | Apply configuration changes (routes, peers, policies, API) without a restart. |
+| REST API | Query status and drive operations over HTTP. |
+| Prometheus metrics | `/metrics` endpoint exposing peer and route state. |
+| Signed MSI | Standard installation with WiX; binaries and installer can be Authenticode-signed. |
+
+---
+
+## Architecture
+
+```mermaid
+flowchart TD
+ subgraph Windows Service["WinBGP Windows Service"]
+ SVC["WinBGP-Service.ps1
(SCM wrapper / EXE)"]
+ ENG["WinBGP-Engine.ps1
(main event loop)"]
+ API["WinBGP-API.ps1
(HTTP listener thread)"]
+ HC["WinBGP-HealthCheck.ps1
(one thread per route)"]
+ end
+
+ CLI["WinBGP.ps1 (CLI)"]
+ CFG[("winbgp.json")]
+ RRAS["Windows RRAS / BGP
(Add-BgpCustomRoute, Add-BgpPeer, ...)"]
+ NIC["Network interface
(New-NetIPAddress)"]
+ PROM["Prometheus / clients"]
+
+ SCM["Service Control Manager"] -->|Start/Stop| SVC
+ SVC -->|spawns| ENG
+ CLI -->|named pipe 'Service_WinBGP'| ENG
+ ENG -->|reads| CFG
+ ENG -->|manages threads| API
+ ENG -->|manages threads| HC
+ ENG -->|announce / withdraw| RRAS
+ ENG -->|mount / unmount VIP| NIC
+ HC -->|pipe control messages| ENG
+ API -->|invokes CLI verbs| CLI
+ PROM -->|GET /metrics| API
+```
+
+**Interaction model**
+
+- The **engine** is the long-running process. It owns an event loop driven by a
+ timer and a **named pipe** (`Service_WinBGP`). Control messages
+ (`reload`, `route start|stop`, `maintenance start|stop`,
+ `healthcheck start|stop|restart`, `stop`, ...) are received on this pipe.
+- The **CLI** (`WinBGP.ps1`) and the **API** never touch BGP directly for
+ mutations — they translate user intent into pipe messages sent to the engine,
+ which serializes all state changes in its single event loop.
+- Each route with `WithdrawOnDown = true` gets its own **health-check thread**
+ that, on state transition, sends `route start|stop` messages back to the
+ engine.
+- The **API** runs in a dedicated thread hosting an `HttpListener`.
+
+---
+
+## Components
+
+| File | Role |
+| --- | --- |
+| [service/WinBGP-Service.ps1](../service/WinBGP-Service.ps1) | Service bootstrap / SCM integration. Handles `-Setup`, `-Remove`, `-Start`, `-Stop`, `-Status` and the internal `-SCMStart/-SCMStop/...` verbs. Generates the `WinBGP-Service.exe` wrapper. Based on JFLarvoire's `PSService.ps1`. |
+| [src/WinBGP-Engine.ps1](../src/WinBGP-Engine.ps1) | The core engine: main event loop, pipe handler, config validation & hot reload, BGP/IP management, health-check and API thread lifecycle. |
+| [src/WinBGP-API.ps1](../src/WinBGP-API.ps1) | HTTP listener exposing the REST API and the Prometheus `/metrics` endpoint. Based on stevelee's `HttpListener`. |
+| [src/WinBGP-HealthCheck.ps1](../src/WinBGP-HealthCheck.ps1) | Per-route health-check worker with rise/fall debouncing. |
+| [src/WinBGP.ps1](../src/WinBGP.ps1) | The `WinBGP` CLI to query status and drive operations locally (installed as `C:\Program Files\WinBGP\WinBGP.ps1`). |
+| [src/winbgp.json.example](../src/winbgp.json.example) | Example configuration file. |
+| [builder/build.ps1](../builder/build.ps1) | Build script producing the signed MSI via WiX. |
+| [builder/main.wxs](../builder/main.wxs) / [builder/files.wxs](../builder/files.wxs) | WiX packaging definitions. |
+
+---
+
+## Prerequisites
+
+- **Windows Server 2016, 2019, 2022 or 2025**
+- **PowerShell 5.1**
+- The **Remote Access / Routing** feature must be installed and routing enabled.
+ WinBGP checks this at startup and refuses to run otherwise:
+
+ ```powershell
+ # Install the Routing feature (RRAS)
+ Install-WindowsFeature RemoteAccess, Routing -IncludeManagementTools
+ Install-RemoteAccess -VpnType RoutingOnly
+ ```
+
+ WinBGP validates `(Get-RemoteAccess).RoutingStatus -eq 'Installed'` on start.
+
+---
+
+## Installation
+
+Standard MSI installation. The MSI installs the service files under
+`C:\Program Files\WinBGP\`, registers the `WinBGP` service and creates the
+required firewall rule for the API.
+
+```powershell
+# Install
+msiexec /i WinBGP--amd64.msi /qn
+
+# The configuration file lives here:
+# C:\Program Files\WinBGP\winbgp.json
+
+# Manage the service
+WinBGP -Status
+WinBGP -Start
+WinBGP -Stop
+```
+
+> After installation, copy `winbgp.json.example` to
+> `C:\Program Files\WinBGP\winbgp.json`, adapt it to your environment, then start
+> the service.
+
+---
+
+## Configuration
+
+WinBGP is driven by a single JSON file (`winbgp.json`). The engine validates the
+whole file before (re)loading it; an invalid file aborts the reload and, at
+startup, stops the service. See [src/winbgp.json.example](../src/winbgp.json.example).
+
+```jsonc
+{
+ "global": {
+ "Interval": 5, // Health-check interval (seconds)
+ "Timeout": 1, // Check timeout (seconds)
+ "Rise": 3, // Consecutive OK checks before a route is announced
+ "Fall": 2, // Consecutive KO checks before a route is withdrawn
+ "Metric": 100, // Default BGP MED
+ "Api": true // Enable the REST API
+ },
+ "api": [
+ { "Uri": "http://127.0.0.1:8888", "AuthenticationMethod": "Anonymous" }
+ ],
+ "router": {
+ "BgpIdentifier": "YOUR_IP",
+ "LocalASN": "YOUR_ASN"
+ },
+ "peers": [
+ {
+ "PeerName": "Peer1",
+ "LocalIP": "YOUR_IP",
+ "PeerIP": "Peer1_IP",
+ "LocalASN": "YOUR_ASN",
+ "PeerASN": "Peer1_ASN"
+ }
+ ],
+ "routes": [
+ {
+ "RouteName": "mywinbgpservice.contoso.com",
+ "Network": "10.0.0.10/32",
+ "Interface": "Ethernet",
+ "DynamicIpSetup": true,
+ "WithdrawOnDown": true,
+ "WithdrawOnDownCheck": "service: W32Time",
+ "NextHop": "YOUR_IP",
+ "Community": [ "BGP_COMMUNITY" ]
+ }
+ ]
+}
+```
+
+### Global settings
+
+| Key | Type | Description |
+| --- | --- | --- |
+| `Interval` | int | Default seconds between health checks (can be overridden per route). |
+| `Timeout` | int | Check timeout in seconds. |
+| `Rise` | int | Number of consecutive successful checks before announcing a route. |
+| `Fall` | int | Number of consecutive failed checks before withdrawing a route. |
+| `Metric` | int | Default BGP MED applied via the routing policy. |
+| `Api` | bool | Enable/disable the REST API. Toggling it live starts/stops the API thread. |
+
+### API configuration
+
+`api` is an array of listeners. Each entry:
+
+| Key | Type | Description |
+| --- | --- | --- |
+| `Uri` | string | Listener prefix, e.g. `http://127.0.0.1:8888`. |
+| `AuthenticationMethod` | string | `Anonymous` or `Negotiate` (Kerberos/NTLM). Local requests are always allowed. |
+
+### Router
+
+| Key | Type | Description |
+| --- | --- | --- |
+| `BgpIdentifier` | string | The local BGP router ID (usually the local IP). |
+| `LocalASN` | string | The local autonomous system number. |
+
+### Peers
+
+Array of BGP neighbors:
+
+| Key | Type | Description |
+| --- | --- | --- |
+| `PeerName` | string | Friendly peer name. |
+| `LocalIP` | string | Local IP used for the BGP session. |
+| `PeerIP` | string | Neighbor IP. |
+| `LocalASN` | string | Local ASN. |
+| `PeerASN` | string | Neighbor ASN. |
+
+### Routes
+
+Array of advertised networks (VIPs):
+
+| Key | Type | Description |
+| --- | --- | --- |
+| `RouteName` | string | Unique route identifier (used by the CLI/API). |
+| `Network` | string | CIDR to announce, e.g. `10.0.0.10/32`. |
+| `Interface` | string | Interface alias where the VIP is mounted. |
+| `DynamicIpSetup` | bool | If `true`, WinBGP mounts/unmounts the IP on the interface (SkipAsSource). |
+| `WithdrawOnDown` | bool | If `true`, run a health check and withdraw the route on failure. |
+| `WithdrawOnDownCheck` | string | Health check definition (`method: value`) — required when `WithdrawOnDown` is `true`. |
+| `NextHop` | string | BGP next hop advertised in the routing policy. |
+| `Community` | array | BGP communities to attach. |
+| `Interval` | int | *(optional)* Per-route health-check interval override. |
+| `Metric` | int | *(optional)* Per-route MED override. |
+| `Rise` / `Fall` | int | *(optional)* Per-route thresholds override. |
+
+### Health-check methods
+
+`WithdrawOnDownCheck` uses the format `": "`:
+
+| Method | Example | Behavior |
+| --- | --- | --- |
+| `service` | `service: W32Time` | OK when the Windows service is `Running`. |
+| `process` | `process: myapp` | OK when at least one process with that name exists. |
+| `tcp` | `tcp: 127.0.0.1:443` | OK when a TCP connection to `host:port` succeeds. |
+| `cluster` | `cluster: MyResource` | OK when the failover-cluster resource is `Online` on this node. |
+| `custom` | `custom: if ((...)) {return $true} else {return $false}` | Runs a custom PowerShell expression that **must** return a Boolean. |
+
+State changes are debounced: a route is announced only after `Rise` consecutive
+successes and withdrawn after `Fall` consecutive failures.
+
+---
+
+## Route lifecycle & status
+
+A route reported by `WinBGP` (or the API) has one of the following statuses:
+
+| Status | Meaning |
+| --- | --- |
+| `up` | Route announced, policy present and (if dynamic) VIP mounted. |
+| `down` | Route not announced. |
+| `warning` | Partially configured (e.g. VIP not mounted, or missing routing policy). |
+| `maintenance` | Route manually drained; kept withdrawn regardless of health. |
+
+```mermaid
+stateDiagram-v2
+ [*] --> Down
+ Down --> Up: Rise checks OK
(announce + mount VIP)
+ Up --> Down: Fall checks KO
(withdraw + unmount VIP)
+ Up --> Maintenance: StartMaintenance
+ Down --> Maintenance: StartMaintenance
+ Maintenance --> Down: StopMaintenance
+ Up --> Warning: VIP/policy inconsistency
+ Warning --> Up: reconciled
+```
+
+---
+
+## Command line interface (CLI)
+
+Once installed, the `WinBGP` command is available (wrapper around
+`C:\Program Files\WinBGP\WinBGP.ps1`).
+
+**Service control**
+
+```powershell
+WinBGP -Status # Not installed / Stopped / Running
+WinBGP -Start
+WinBGP -Stop
+WinBGP -Restart
+WinBGP -Version
+```
+
+**Status & introspection**
+
+```powershell
+WinBGP # Default: BGP status (per-route Name/Network/Status/MaintenanceTimestamp)
+WinBGP -Config # Show the current configuration
+WinBGP -Logs -Last 20 # Show the last N log entries
+```
+
+**Route operations** (per route, via `-RouteName`)
+
+```powershell
+WinBGP -RouteName mywinbgpservice.contoso.com -StartRoute
+WinBGP -RouteName mywinbgpservice.contoso.com -StopRoute
+
+WinBGP -RouteName mywinbgpservice.contoso.com -StartMaintenance
+WinBGP -RouteName mywinbgpservice.contoso.com -StopMaintenance
+
+WinBGP -RouteName mywinbgpservice.contoso.com -StartHealthCheck
+WinBGP -RouteName mywinbgpservice.contoso.com -StopHealthCheck
+WinBGP -RouteName mywinbgpservice.contoso.com -RestartHealthCheck
+```
+
+**Configuration / API**
+
+```powershell
+WinBGP -Reload # Validate and hot-reload winbgp.json
+WinBGP -RestartAPI # Restart the API thread
+```
+
+> `-RouteName` supports tab-completion sourced from `winbgp.json`.
+> Operations return `Success`, `WinBGP not ready`, or `Route '' not found`.
+
+---
+
+## REST API
+
+When `global.Api` is enabled, the engine hosts an HTTP listener at the configured
+`Uri` (default `http://127.0.0.1:8888`). Local requests bypass authentication;
+remote requests honor the configured `AuthenticationMethod`.
+
+### GET endpoints
+
+| Endpoint | Description |
+| --- | --- |
+| `GET /api` | Liveness — `{ "message": "WinBGP API running" }`. |
+| `GET /api/config` | Full configuration. |
+| `GET /api/config/` | A single config section (`global`, `router`, `peers`, `routes`, `api`). |
+| `GET /api/logs?Last=` | Last `n` log entries (default 10). |
+| `GET /api/peers` | All BGP peers with connectivity status. |
+| `GET /api/peers/` | A single peer. |
+| `GET /api/router` | Local BGP router info. |
+| `GET /api/routes` | All routes with status and maintenance timestamp. |
+| `GET /api/routes/` | A single route. |
+| `GET /api/statistics` | BGP statistics (via CIM `PS_BgpStatistics`). |
+| `GET /api/status` | Service status — `{ "service": "Running" }`. |
+| `GET /api/version` | CLI version. |
+| `GET /metrics` | Prometheus exposition format. |
+
+### POST endpoints
+
+Operations take the route via the `RouteName` query-string parameter.
+
+| Endpoint | Description |
+| --- | --- |
+| `POST /api/Reload` | Hot-reload the configuration. |
+| `POST /api/StartRoute?RouteName=` | Announce a route. |
+| `POST /api/StopRoute?RouteName=` | Withdraw a route. |
+| `POST /api/StartMaintenance?RouteName=` | Put a route in maintenance. |
+| `POST /api/StopMaintenance?RouteName=` | Remove a route from maintenance. |
+| `POST /stop` | Stop the API listener (local requests only). |
+
+**Examples**
+
+```powershell
+# Status of all routes
+Invoke-RestMethod http://127.0.0.1:8888/api/routes
+
+# Drain a route
+Invoke-RestMethod -Method POST "http://127.0.0.1:8888/api/StartMaintenance?RouteName=mywinbgpservice.contoso.com"
+
+# Reload config
+Invoke-RestMethod -Method POST http://127.0.0.1:8888/api/Reload
+```
+
+POST responses return `{ "output": "Success" }` (HTTP 200) or
+`{ "output": "WinBGP not ready" }` (HTTP 500).
+
+---
+
+## Prometheus metrics
+
+`GET /metrics` exposes gauges suitable for scraping:
+
+| Metric | Labels | Description |
+| --- | --- | --- |
+| `winbgp_state_peer` | `local_asn, local_ip, name, peer_asn, peer_ip, state` | 1 for the peer's current state (`connected`, `connecting`, `stopped`), else 0. |
+| `winbgp_state_route` | `family, maintenance_timestamp, name, network, state` | 1 for the route's current state (`up`, `down`, `maintenance`, `warning`), else 0. |
+
+Example scrape config:
+
+```yaml
+scrape_configs:
+ - job_name: winbgp
+ static_configs:
+ - targets: ["winbgp-host:8888"]
+ metrics_path: /metrics
+```
+
+---
+
+## Logging
+
+WinBGP writes to the **Windows Event Log** (`Application` log, source `WinBGP`,
+plus per-component sources `WinBGP-API`). Per-route entries carry the route name
+as an additional event field. Retrieve recent entries with:
+
+```powershell
+WinBGP -Logs -Last 50
+# or
+Get-EventLog -LogName Application -Source WinBGP -Newest 50
+```
+
+---
+
+## Building the MSI
+
+The MSI is produced with the [WiX Toolset](https://wixtoolset.org/) (v4+) via
+[builder/build.ps1](../builder/build.ps1).
+
+```powershell
+cd builder
+
+# Unsigned build
+.\build.ps1 -Version v1.1.4 -Arch amd64
+
+# Signed build (binaries + MSI)
+.\build.ps1 -Version v1.1.4 -Arch amd64 -Sign -CertificateThumbprint
+```
+
+The script:
+
+1. Copies all `src/*.ps1` scripts into a temporary `engine` folder (Authenticode-signing them when `-Sign` is used).
+2. Runs `wix build` with the Firewall, UI and Util extensions to create `WinBGP--.msi`.
+3. Signs the MSI with `signtool.exe` when `-Sign` is used and copies it to `release/`.
+
+Supported architectures: `amd64` (x64) and `arm64`.
+
+---
+
+## Project layout
+
+```
+WinBGP/
+├── builder/ # MSI build (WiX) + build script
+│ ├── build.ps1
+│ ├── files.wxs
+│ └── main.wxs
+├── service/
+│ └── WinBGP-Service.ps1 # SCM wrapper / service bootstrap
+├── src/
+│ ├── WinBGP.ps1 # CLI
+│ ├── WinBGP-Engine.ps1 # Core engine (event loop)
+│ ├── WinBGP-API.ps1 # REST API + Prometheus metrics
+│ ├── WinBGP-HealthCheck.ps1
+│ └── winbgp.json.example # Sample configuration
+├── CHANGELOG.md
+├── LICENCE
+└── README
+```
+
+---
+
+## Credits
+
+- Service framework based on **JFLarvoire**'s
+ [`PSService.ps1`](https://github.com/JFLarvoire/SysToolsLib) (event-driven
+ service with named-pipe control).
+- HTTP listener based on **stevelee**'s
+ [`HttpListener`](https://www.powershellgallery.com/packages/HttpListener).
+- Copyright © 2024 **Alexandre JARDON | Webalex System**. All rights reserved.
+- Project: [github.com/webalexeu/winbgp](https://github.com/webalexeu/winbgp) —
+ see [LICENSE](https://github.com/webalexeu/winbgp/blob/master/LICENSE).
From 3f731a2530bcc6767b4cdb66029753222bde102c Mon Sep 17 00:00:00 2001
From: Daymarvi <31985821+Daymarvi@users.noreply.github.com>
Date: Thu, 2 Jul 2026 10:00:41 +0200
Subject: [PATCH 2/2] docs: promote documentation to root README.md
---
README | 30 ------------------------------
docs/DOCUMENTATION.md => README.md | 20 ++++++++++----------
2 files changed, 10 insertions(+), 40 deletions(-)
delete mode 100644 README
rename docs/DOCUMENTATION.md => README.md (92%)
diff --git a/README b/README
deleted file mode 100644
index 78bacb8..0000000
--- a/README
+++ /dev/null
@@ -1,30 +0,0 @@
-# WinBGP
-
-WinBGP Service
-
-## Prerequisites
-
-Windows Server 2016, 2019, 2022, 2025
-
-## Installation
-
-Standard MSI installation.
-
-## Contributing
-
-Coder or not, you can contribute to the project! We welcome all contributions.
-
-### For Users
-
-If you don't code, you still sit on valuable information that can make this project even better. If you experience that the
-product does unexpected things, throw errors or is missing functionality, you can help by submitting bugs and feature requests.
-Please see the issues tab on this project and submit a new issue that matches your needs.
-
-### For Developers
-
-If you do code, we'd love to have your contributions. Please read the [Contribution guidelines](CONTRIBUTING.md) for more information.
-You can either help by picking up an existing issue or submit a new one if you have an idea for a new feature or improvement.
-
-## Links
-
-- [Semantic Versioning 2.0.0](https://semver.org/)
diff --git a/docs/DOCUMENTATION.md b/README.md
similarity index 92%
rename from docs/DOCUMENTATION.md
rename to README.md
index 7f2fc3f..86b806b 100644
--- a/docs/DOCUMENTATION.md
+++ b/README.md
@@ -132,14 +132,14 @@ flowchart TD
| File | Role |
| --- | --- |
-| [service/WinBGP-Service.ps1](../service/WinBGP-Service.ps1) | Service bootstrap / SCM integration. Handles `-Setup`, `-Remove`, `-Start`, `-Stop`, `-Status` and the internal `-SCMStart/-SCMStop/...` verbs. Generates the `WinBGP-Service.exe` wrapper. Based on JFLarvoire's `PSService.ps1`. |
-| [src/WinBGP-Engine.ps1](../src/WinBGP-Engine.ps1) | The core engine: main event loop, pipe handler, config validation & hot reload, BGP/IP management, health-check and API thread lifecycle. |
-| [src/WinBGP-API.ps1](../src/WinBGP-API.ps1) | HTTP listener exposing the REST API and the Prometheus `/metrics` endpoint. Based on stevelee's `HttpListener`. |
-| [src/WinBGP-HealthCheck.ps1](../src/WinBGP-HealthCheck.ps1) | Per-route health-check worker with rise/fall debouncing. |
-| [src/WinBGP.ps1](../src/WinBGP.ps1) | The `WinBGP` CLI to query status and drive operations locally (installed as `C:\Program Files\WinBGP\WinBGP.ps1`). |
-| [src/winbgp.json.example](../src/winbgp.json.example) | Example configuration file. |
-| [builder/build.ps1](../builder/build.ps1) | Build script producing the signed MSI via WiX. |
-| [builder/main.wxs](../builder/main.wxs) / [builder/files.wxs](../builder/files.wxs) | WiX packaging definitions. |
+| [service/WinBGP-Service.ps1](service/WinBGP-Service.ps1) | Service bootstrap / SCM integration. Handles `-Setup`, `-Remove`, `-Start`, `-Stop`, `-Status` and the internal `-SCMStart/-SCMStop/...` verbs. Generates the `WinBGP-Service.exe` wrapper. Based on JFLarvoire's `PSService.ps1`. |
+| [src/WinBGP-Engine.ps1](src/WinBGP-Engine.ps1) | The core engine: main event loop, pipe handler, config validation & hot reload, BGP/IP management, health-check and API thread lifecycle. |
+| [src/WinBGP-API.ps1](src/WinBGP-API.ps1) | HTTP listener exposing the REST API and the Prometheus `/metrics` endpoint. Based on stevelee's `HttpListener`. |
+| [src/WinBGP-HealthCheck.ps1](src/WinBGP-HealthCheck.ps1) | Per-route health-check worker with rise/fall debouncing. |
+| [src/WinBGP.ps1](src/WinBGP.ps1) | The `WinBGP` CLI to query status and drive operations locally (installed as `C:\Program Files\WinBGP\WinBGP.ps1`). |
+| [src/winbgp.json.example](src/winbgp.json.example) | Example configuration file. |
+| [builder/build.ps1](builder/build.ps1) | Build script producing the signed MSI via WiX. |
+| [builder/main.wxs](builder/main.wxs) / [builder/files.wxs](builder/files.wxs) | WiX packaging definitions. |
---
@@ -189,7 +189,7 @@ WinBGP -Stop
WinBGP is driven by a single JSON file (`winbgp.json`). The engine validates the
whole file before (re)loading it; an invalid file aborts the reload and, at
-startup, stops the service. See [src/winbgp.json.example](../src/winbgp.json.example).
+startup, stops the service. See [src/winbgp.json.example](src/winbgp.json.example).
```jsonc
{
@@ -473,7 +473,7 @@ Get-EventLog -LogName Application -Source WinBGP -Newest 50
## Building the MSI
The MSI is produced with the [WiX Toolset](https://wixtoolset.org/) (v4+) via
-[builder/build.ps1](../builder/build.ps1).
+[builder/build.ps1](builder/build.ps1).
```powershell
cd builder