feat: enhance peer type classification and configuration

- Added regex support for peer type prefixes in getPeerType function.
- Introduced new test for regex-based peer type classification.
- Updated settings parsing to include additional config paths and fallback to alternative config names.
This commit is contained in:
2026-09-03 10:39:42 +02:00
parent 5b21f58a33
commit 130f7d3847
4 changed files with 89 additions and 47 deletions
+43 -43
View File
@@ -58,28 +58,28 @@ Configuration can be set in:
Configuration is handled by [viper](https://github.com/spf13/viper), any config format supported by it can be used.
| Config Key | Parameter | Environment Variable | Description |
| ---------- | --------- | -------------------- | ----------- |
| servers | --servers | BIRDLG_SERVERS | server name prefixes, separated by comma |
| domain | --domain | BIRDLG_DOMAIN | server name domain suffixes |
| listen | --listen | BIRDLG_LISTEN | address bird-lg is listening on (default "5000") |
| proxy_port | --proxy-port | BIRDLG_PROXY_PORT | port bird-lgproxy is running on (default 8000) |
| whois | --whois | BIRDLG_WHOIS | whois server for queries (default "whois.verisign-grs.com"). Start with "/" to specify a local whois binary (e.g. "/usr/local/bin/whois"). |
| dns_interface | --dns-interface | BIRDLG_DNS_INTERFACE | dns zone to query ASN information (default "asn.cymru.com") |
| bgpmap_info | --bgpmap-info | BIRDLG_BGPMAP_INFO | the infos displayed in bgpmap, separated by comma, start with `:` means allow multiline (default "asn,as-name,ASName,descr") |
| title_brand | --title-brand | BIRDLG_TITLE_BRAND | prefix of page titles in browser tabs (default "Bird-lg Go") |
| navbar_brand | --navbar-brand | BIRDLG_NAVBAR_BRAND | brand to show in the navigation bar (default same as title_brand) |
| navbar_brand_url | --navbar-brand-url | BIRDLG_NAVBAR_BRAND_URL | the url of the brand to show in the navigation bar (default "/") |
| navbar_all_servers | --navbar-all-servers | BIRDLG_NAVBAR_ALL_SERVERS | the text of "All servers" button in the navigation bar (default "All Servers") |
| navbar_all_url | --navbar-all-url | BIRDLG_NAVBAR_ALL_URL | the URL of "All servers" button (default "all") |
| net_specific_mode | --net-specific-mode | BIRDLG_NET_SPECIFIC_MODE | apply network-specific changes for some networks, use "dn42" for BIRD in dn42 network |
| protocol_filter | --protocol-filter | BIRDLG_PROTOCOL_FILTER | protocol types to show in summary tables (comma separated list); defaults to all if not set |
| name_filter | --name-filter | BIRDLG_NAME_FILTER | protocol name regex to hide in summary tables (RE2 syntax); defaults to none if not set |
| timeout | --time-out | BIRDLG_TIMEOUT | time before backend HTTP request times out, in seconds (default 120) |
| connection_timeout | --connection-time-out | BIRDLG_CONNECTION_TIMEOUT | time before backend TCP connection times out, in seconds (default 5) |
| trust_proxy_headers | --trust-proxy-headers | BIRDLG_TRUST_PROXY_HEADERS | trust X-Forwarded-For, X-Real-IP, X-Forwarded-Proto and X-Forwarded-Host headers sent by a reverse proxy (default false) |
| vrf | --vrf | BIRDLG_VRF | VRF device to bind TCP sockets to (Linux only) |
| peer_types | *(config file only)* | *(config file only)* | classification of BGP sessions in the summary table (badges + filter buttons), matched by protocol-name prefix. Structured list, so it can only be set from a config file. Defaults to a built-in set (Internal, Transit, IXP Route Server, Route Collector, Downstream, IXP Peering, PNI Peering, BYOIP). |
| Config Key | Parameter | Environment Variable | Description |
| ------------------- | --------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| servers | --servers | BIRDLG_SERVERS | server name prefixes, separated by comma |
| domain | --domain | BIRDLG_DOMAIN | server name domain suffixes |
| listen | --listen | BIRDLG_LISTEN | address bird-lg is listening on (default "5000") |
| proxy_port | --proxy-port | BIRDLG_PROXY_PORT | port bird-lgproxy is running on (default 8000) |
| whois | --whois | BIRDLG_WHOIS | whois server for queries (default "whois.verisign-grs.com"). Start with "/" to specify a local whois binary (e.g. "/usr/local/bin/whois"). |
| dns_interface | --dns-interface | BIRDLG_DNS_INTERFACE | dns zone to query ASN information (default "asn.cymru.com") |
| bgpmap_info | --bgpmap-info | BIRDLG_BGPMAP_INFO | the infos displayed in bgpmap, separated by comma, start with `:` means allow multiline (default "asn,as-name,ASName,descr") |
| title_brand | --title-brand | BIRDLG_TITLE_BRAND | prefix of page titles in browser tabs (default "Bird-lg Go") |
| navbar_brand | --navbar-brand | BIRDLG_NAVBAR_BRAND | brand to show in the navigation bar (default same as title_brand) |
| navbar_brand_url | --navbar-brand-url | BIRDLG_NAVBAR_BRAND_URL | the url of the brand to show in the navigation bar (default "/") |
| navbar_all_servers | --navbar-all-servers | BIRDLG_NAVBAR_ALL_SERVERS | the text of "All servers" button in the navigation bar (default "All Servers") |
| navbar_all_url | --navbar-all-url | BIRDLG_NAVBAR_ALL_URL | the URL of "All servers" button (default "all") |
| net_specific_mode | --net-specific-mode | BIRDLG_NET_SPECIFIC_MODE | apply network-specific changes for some networks, use "dn42" for BIRD in dn42 network |
| protocol_filter | --protocol-filter | BIRDLG_PROTOCOL_FILTER | protocol types to show in summary tables (comma separated list); defaults to all if not set |
| name_filter | --name-filter | BIRDLG_NAME_FILTER | protocol name regex to hide in summary tables (RE2 syntax); defaults to none if not set |
| timeout | --time-out | BIRDLG_TIMEOUT | time before backend HTTP request times out, in seconds (default 120) |
| connection_timeout | --connection-time-out | BIRDLG_CONNECTION_TIMEOUT | time before backend TCP connection times out, in seconds (default 5) |
| trust_proxy_headers | --trust-proxy-headers | BIRDLG_TRUST_PROXY_HEADERS | trust X-Forwarded-For, X-Real-IP, X-Forwarded-Proto and X-Forwarded-Host headers sent by a reverse proxy (default false) |
| vrf | --vrf | BIRDLG_VRF | VRF device to bind TCP sockets to (Linux only) |
| peer_types | _(config file only)_ | _(config file only)_ | classification of BGP sessions in the summary table (badges + filter buttons), matched by protocol-name prefix. Structured list, so it can only be set from a config file. Defaults to a built-in set (Internal, Transit, IXP Route Server, Route Collector, Downstream, IXP Peering, PNI Peering, BYOIP). |
#### Configuring peer types
@@ -95,16 +95,16 @@ If `peer_types` is not set, the built-in defaults are used. When set, the list
Each entry supports:
| Field | Required | Description |
| ----- | -------- | ----------- |
| `name` | yes | Badge label and identifier used to match the filter button. Must be unique. |
| `prefixes` | yes | List of protocol-name prefixes (case-insensitive) that classify a session into this type. |
| `icon` | yes | Font Awesome icon class, e.g. `fa-arrow-circle-up`. |
| `color` | yes | Bootstrap colour suffix for the badge, e.g. `warning`, `info`, `primary`, `success`. |
| `label` | no | Shorter text for the filter button (falls back to `name`). |
| `button_color` | no | Overrides `color` for the filter button (useful when `color` is `light`). |
| `text_dark` | no | Add `text-dark` to the badge (for light backgrounds such as `warning`). |
| `border` | no | Add a border to the badge (for `light` badges). |
| Field | Required | Description |
| -------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | yes | Badge label and identifier used to match the filter button. Must be unique. |
| `prefixes` | yes | List of protocol-name prefixes or RE2 regex patterns (case-insensitive) that classify a session into this type. Plain strings match from the start of the protocol name; regex patterns are also matched from the start unless they already include `^`. |
| `icon` | yes | Font Awesome icon class, e.g. `fa-arrow-circle-up`. |
| `color` | yes | Bootstrap colour suffix for the badge, e.g. `warning`, `info`, `primary`, `success`. |
| `label` | no | Shorter text for the filter button (falls back to `name`). |
| `button_color` | no | Overrides `color` for the filter button (useful when `color` is `light`). |
| `text_dark` | no | Add `text-dark` to the badge (for light backgrounds such as `warning`). |
| `border` | no | Add a border to the badge (for `light` badges). |
Sessions whose name matches no prefix are shown as `Unknown`. Order matters:
the first type whose prefix matches wins.
@@ -181,17 +181,17 @@ Configuration can be set in:
Configuration is handled by [viper](https://github.com/spf13/viper), any config format supported by it can be used.
| Config Key | Parameter | Environment Variable | Description |
| ---------- | --------- | -------------------- | ----------- |
| bird_socket | --bird | BIRD_SOCKET | socket file for bird (default "/var/run/bird/bird.ctl") |
| bird_restrict_cmds | --bird-restrict-cmds | BIRDLG_BIRD_RESTRICT_CMDS | restrict bird commands to `show protocols` and `show route` only (default true) |
| listen | --listen | BIRDLG_LISTEN / BIRDLG_PROXY_PORT | listen address (default "8000") |
| allowed_ips | --allowed | ALLOWED_IPS | IPs or networks allowed to access this proxy, separated by commas; allow all if not set |
| traceroute_bin | --traceroute-bin | BIRDLG_TRACEROUTE_BIN | traceroute binary file |
| traceroute_flags | --traceroute-flags | BIRDLG_TRACEROUTE_FLAGS | traceroute flags, supports multiple flags separated with space |
| traceroute_raw | --traceroute-raw | BIRDLG_TRACEROUTE_RAW | whether to display traceroute outputs raw (default false) |
| traceroute_max_concurrent | --traceroute-max-concurrent | BIRDLG_TRACEROUTE_MAX_CONCURRENT | max concurrent traceroute requests allowed (default 10) |
| vrf | --vrf | BIRDLG_VRF | VRF device to bind TCP sockets to (Linux only) |
| Config Key | Parameter | Environment Variable | Description |
| ------------------------- | --------------------------- | --------------------------------- | --------------------------------------------------------------------------------------- |
| bird_socket | --bird | BIRD_SOCKET | socket file for bird (default "/var/run/bird/bird.ctl") |
| bird_restrict_cmds | --bird-restrict-cmds | BIRDLG_BIRD_RESTRICT_CMDS | restrict bird commands to `show protocols` and `show route` only (default true) |
| listen | --listen | BIRDLG_LISTEN / BIRDLG_PROXY_PORT | listen address (default "8000") |
| allowed_ips | --allowed | ALLOWED_IPS | IPs or networks allowed to access this proxy, separated by commas; allow all if not set |
| traceroute_bin | --traceroute-bin | BIRDLG_TRACEROUTE_BIN | traceroute binary file |
| traceroute_flags | --traceroute-flags | BIRDLG_TRACEROUTE_FLAGS | traceroute flags, supports multiple flags separated with space |
| traceroute_raw | --traceroute-raw | BIRDLG_TRACEROUTE_RAW | whether to display traceroute outputs raw (default false) |
| traceroute_max_concurrent | --traceroute-max-concurrent | BIRDLG_TRACEROUTE_MAX_CONCURRENT | max concurrent traceroute requests allowed (default 10) |
| vrf | --vrf | BIRDLG_VRF | VRF device to bind TCP sockets to (Linux only) |
### Traceroute Binary Autodetection
+24 -3
View File
@@ -1,6 +1,9 @@
package main
import "strings"
import (
"regexp"
"strings"
)
// PeerType describes how a BGP session is classified and displayed in the
// summary table and filter bar. Sessions are matched to a type by testing
@@ -89,14 +92,32 @@ func activePeerTypes() []PeerType {
// getPeerType classifies a BGP session by its protocol name. Non-BGP protocols
// return "" (no type); unmatched BGP sessions return "Unknown".
func looksLikeRegex(pattern string) bool {
if pattern == "" {
return false
}
return strings.ContainsAny(pattern, `.^$*+?[]()|\\`)
}
func peerTypePrefixMatches(name, pattern string) bool {
if looksLikeRegex(pattern) {
if !strings.HasPrefix(pattern, "^") {
pattern = "^" + pattern
}
if re, err := regexp.Compile("(?i)" + pattern); err == nil && re.MatchString(name) {
return true
}
}
return strings.HasPrefix(strings.ToLower(name), strings.ToLower(pattern))
}
func getPeerType(name, proto string) string {
if !strings.EqualFold(proto, "BGP") {
return ""
}
lower := strings.ToLower(name)
for _, pt := range activePeerTypes() {
for _, prefix := range pt.Prefixes {
if strings.HasPrefix(lower, strings.ToLower(prefix)) {
if peerTypePrefixMatches(name, prefix) {
return pt.Name
}
}
+14
View File
@@ -51,6 +51,20 @@ func TestGetPeerTypeConfigured(t *testing.T) {
assert.Equal(t, getPeerType("ibgp_core", "BGP"), "Unknown")
}
func TestGetPeerTypeRegexPrefixes(t *testing.T) {
setting.peerTypes = []PeerType{
{Name: "Customer", Prefixes: []string{"^cust_.*(acme|beta)$"}, Icon: "fa-user", Color: "primary"},
{Name: "Upstream", Prefixes: []string{"^up(?:stream|-).*"}, Icon: "fa-arrow-up", Color: "warning"},
}
defer func() { setting.peerTypes = nil }()
assert.Equal(t, getPeerType("cust_acme", "BGP"), "Customer")
assert.Equal(t, getPeerType("cust_beta", "BGP"), "Customer")
assert.Equal(t, getPeerType("upstream_123", "BGP"), "Upstream")
assert.Equal(t, getPeerType("up-123", "BGP"), "Upstream")
assert.Equal(t, getPeerType("other_peer", "BGP"), "Unknown")
}
// TestTypeInfo verifies display-info resolution and badge/button helpers.
func TestTypeInfo(t *testing.T) {
setting.peerTypes = nil
+8 -1
View File
@@ -42,6 +42,8 @@ func parseSettings() {
viper.AddConfigPath(".")
viper.AddConfigPath("/etc/bird-lg")
viper.AddConfigPath("/etc")
viper.AddConfigPath("/root")
viper.SetConfigName("bird-lg")
viper.AllowEmptyEnv(true)
viper.AutomaticEnv()
@@ -118,7 +120,12 @@ func parseSettings() {
}
if err := viper.ReadInConfig(); err != nil {
println("Warning on reading config: " + err.Error())
viper.SetConfigName("bird")
if err2 := viper.ReadInConfig(); err2 != nil {
println("Warning on reading config: " + err.Error())
} else {
println("Loaded config from bird.yaml / bird.yml")
}
}
viperSettings := viperSettingType{}