398 lines
10 KiB
Rust
398 lines
10 KiB
Rust
//! Server configuration
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
|
|
|
/// TLS configuration
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct TlsConfig {
|
|
/// Path to certificate file (PEM)
|
|
pub cert_file: String,
|
|
|
|
/// Path to private key file (PEM)
|
|
pub key_file: String,
|
|
|
|
/// Path to CA certificate for client verification (optional, for mTLS)
|
|
pub ca_file: Option<String>,
|
|
|
|
/// Require client certificates (mTLS)
|
|
#[serde(default)]
|
|
pub require_client_cert: bool,
|
|
}
|
|
|
|
/// Metadata storage backend
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum MetadataBackend {
|
|
/// FlareDB distributed metadata database
|
|
FlareDb,
|
|
/// PostgreSQL metadata database
|
|
Postgres,
|
|
/// SQLite metadata database (single-node only)
|
|
Sqlite,
|
|
}
|
|
|
|
impl Default for MetadataBackend {
|
|
fn default() -> Self {
|
|
Self::FlareDb
|
|
}
|
|
}
|
|
|
|
/// Server configuration
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct ServerConfig {
|
|
/// gRPC management API address
|
|
pub grpc_addr: SocketAddr,
|
|
|
|
/// ChainFire endpoint used for cluster coordination only
|
|
pub chainfire_endpoint: Option<String>,
|
|
|
|
/// FlareDB endpoint used for metadata and tenant data storage
|
|
pub flaredb_endpoint: Option<String>,
|
|
|
|
/// Metadata backend selection (flaredb, postgres, sqlite)
|
|
#[serde(default)]
|
|
pub metadata_backend: MetadataBackend,
|
|
|
|
/// SQL database URL for metadata when backend is postgres or sqlite
|
|
pub metadata_database_url: Option<String>,
|
|
|
|
/// Allow single-node mode (required for SQLite)
|
|
#[serde(default)]
|
|
pub single_node: bool,
|
|
|
|
/// Log level
|
|
pub log_level: String,
|
|
|
|
/// TLS configuration (optional)
|
|
pub tls: Option<TlsConfig>,
|
|
|
|
/// Authentication configuration
|
|
#[serde(default)]
|
|
pub auth: AuthConfig,
|
|
|
|
/// Backend health checker configuration
|
|
#[serde(default)]
|
|
pub health: HealthRuntimeConfig,
|
|
|
|
/// VIP advertisement reconciliation configuration
|
|
#[serde(default)]
|
|
pub vip_advertisement: VipAdvertisementConfig,
|
|
|
|
/// Local VIP ownership configuration.
|
|
#[serde(default)]
|
|
pub vip_ownership: VipOwnershipConfig,
|
|
|
|
/// Native BGP speaker configuration
|
|
#[serde(default)]
|
|
pub bgp: BgpConfig,
|
|
}
|
|
|
|
/// Authentication configuration
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct AuthConfig {
|
|
/// IAM server endpoint
|
|
#[serde(default = "default_iam_server_addr")]
|
|
pub iam_server_addr: String,
|
|
}
|
|
|
|
fn default_iam_server_addr() -> String {
|
|
"127.0.0.1:50051".to_string()
|
|
}
|
|
|
|
/// Backend health checker runtime configuration.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct HealthRuntimeConfig {
|
|
/// Interval between backend health check sweeps.
|
|
#[serde(default = "default_health_check_interval_secs")]
|
|
pub interval_secs: u64,
|
|
|
|
/// Timeout for individual backend checks.
|
|
#[serde(default = "default_health_check_timeout_secs")]
|
|
pub timeout_secs: u64,
|
|
}
|
|
|
|
fn default_health_check_interval_secs() -> u64 {
|
|
5
|
|
}
|
|
|
|
fn default_health_check_timeout_secs() -> u64 {
|
|
5
|
|
}
|
|
|
|
impl Default for HealthRuntimeConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
interval_secs: default_health_check_interval_secs(),
|
|
timeout_secs: default_health_check_timeout_secs(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// VIP advertisement reconciliation runtime configuration.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct VipAdvertisementConfig {
|
|
/// Interval between BGP advertisement reconciliation sweeps.
|
|
#[serde(default = "default_vip_check_interval_secs")]
|
|
pub interval_secs: u64,
|
|
|
|
/// Presence of this file puts the node into control-plane drain mode.
|
|
#[serde(default = "default_vip_drain_file")]
|
|
pub drain_file: String,
|
|
|
|
/// Time to keep a locally owned VIP after withdrawing it for drain.
|
|
#[serde(default = "default_vip_drain_hold_time_secs")]
|
|
pub drain_hold_time_secs: u64,
|
|
}
|
|
|
|
fn default_vip_check_interval_secs() -> u64 {
|
|
3
|
|
}
|
|
|
|
fn default_vip_drain_file() -> String {
|
|
"/var/lib/fiberlb/drain".to_string()
|
|
}
|
|
|
|
fn default_vip_drain_hold_time_secs() -> u64 {
|
|
5
|
|
}
|
|
|
|
impl Default for VipAdvertisementConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
interval_secs: default_vip_check_interval_secs(),
|
|
drain_file: default_vip_drain_file(),
|
|
drain_hold_time_secs: default_vip_drain_hold_time_secs(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Local VIP ownership runtime configuration.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct VipOwnershipConfig {
|
|
/// Whether FiberLB should claim VIP /32 addresses on the local node.
|
|
#[serde(default)]
|
|
pub enabled: bool,
|
|
|
|
/// Interface used for local VIP ownership.
|
|
#[serde(default = "default_vip_ownership_interface")]
|
|
pub interface: String,
|
|
}
|
|
|
|
fn default_vip_ownership_interface() -> String {
|
|
"lo".to_string()
|
|
}
|
|
|
|
impl Default for VipOwnershipConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
enabled: false,
|
|
interface: default_vip_ownership_interface(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Static BGP peer configuration.
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct BgpPeerConfig {
|
|
/// Peer IP address or hostname.
|
|
pub address: String,
|
|
|
|
/// Peer TCP port.
|
|
#[serde(default = "default_bgp_peer_port")]
|
|
pub port: u16,
|
|
|
|
/// Peer AS number.
|
|
pub asn: u32,
|
|
|
|
/// Optional operator-visible description.
|
|
#[serde(default)]
|
|
pub description: String,
|
|
|
|
/// Optional export policy applied to announcements sent to this peer.
|
|
#[serde(default)]
|
|
pub export_policy: BgpExportPolicyConfig,
|
|
|
|
/// Optional single-hop BFD session parameters for this peer.
|
|
#[serde(default)]
|
|
pub bfd: BfdConfig,
|
|
}
|
|
|
|
fn default_bgp_peer_port() -> u16 {
|
|
179
|
|
}
|
|
|
|
/// Peer-scoped BGP export policy.
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
|
|
pub struct BgpExportPolicyConfig {
|
|
/// Optional MED attached to announced VIP routes.
|
|
#[serde(default)]
|
|
pub med: Option<u32>,
|
|
|
|
/// Optional standard communities attached to announced VIP routes.
|
|
#[serde(default)]
|
|
pub communities: Vec<String>,
|
|
}
|
|
|
|
/// Single-hop BFD configuration for a BGP peer.
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct BfdConfig {
|
|
/// Whether BFD should gate route advertisement for this peer.
|
|
#[serde(default)]
|
|
pub enabled: bool,
|
|
|
|
/// Desired transmit interval in milliseconds.
|
|
#[serde(default = "default_bfd_desired_min_tx_millis")]
|
|
pub desired_min_tx_millis: u64,
|
|
|
|
/// Required receive interval in milliseconds.
|
|
#[serde(default = "default_bfd_required_min_rx_millis")]
|
|
pub required_min_rx_millis: u64,
|
|
|
|
/// Detection multiplier.
|
|
#[serde(default = "default_bfd_detect_multiplier")]
|
|
pub detect_multiplier: u8,
|
|
|
|
/// Maximum time to wait for the session to reach Up after BGP establishment.
|
|
#[serde(default = "default_bfd_bootstrap_timeout_secs")]
|
|
pub bootstrap_timeout_secs: u64,
|
|
}
|
|
|
|
fn default_bfd_desired_min_tx_millis() -> u64 {
|
|
300
|
|
}
|
|
|
|
fn default_bfd_required_min_rx_millis() -> u64 {
|
|
300
|
|
}
|
|
|
|
fn default_bfd_detect_multiplier() -> u8 {
|
|
3
|
|
}
|
|
|
|
fn default_bfd_bootstrap_timeout_secs() -> u64 {
|
|
10
|
|
}
|
|
|
|
impl Default for BfdConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
enabled: false,
|
|
desired_min_tx_millis: default_bfd_desired_min_tx_millis(),
|
|
required_min_rx_millis: default_bfd_required_min_rx_millis(),
|
|
detect_multiplier: default_bfd_detect_multiplier(),
|
|
bootstrap_timeout_secs: default_bfd_bootstrap_timeout_secs(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Native BGP speaker configuration.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct BgpConfig {
|
|
/// Whether FiberLB should originate VIP routes itself.
|
|
#[serde(default)]
|
|
pub enabled: bool,
|
|
|
|
/// Local AS number.
|
|
#[serde(default = "default_bgp_local_as")]
|
|
pub local_as: u32,
|
|
|
|
/// BGP router ID. Must be IPv4.
|
|
#[serde(default = "default_bgp_router_id")]
|
|
pub router_id: String,
|
|
|
|
/// Optional explicit next-hop address. Falls back to router_id.
|
|
#[serde(default)]
|
|
pub next_hop: Option<String>,
|
|
|
|
/// Requested hold time in seconds.
|
|
#[serde(default = "default_bgp_hold_time_secs")]
|
|
pub hold_time_secs: u16,
|
|
|
|
/// Keepalive interval in seconds.
|
|
#[serde(default = "default_bgp_keepalive_secs")]
|
|
pub keepalive_secs: u16,
|
|
|
|
/// Delay before reconnecting to a failed peer.
|
|
#[serde(default = "default_bgp_connect_retry_secs")]
|
|
pub connect_retry_secs: u64,
|
|
|
|
/// Static peers for outbound eBGP sessions.
|
|
#[serde(default)]
|
|
pub peers: Vec<BgpPeerConfig>,
|
|
}
|
|
|
|
fn default_bgp_local_as() -> u32 {
|
|
65001
|
|
}
|
|
|
|
fn default_bgp_router_id() -> String {
|
|
Ipv4Addr::new(127, 0, 0, 1).to_string()
|
|
}
|
|
|
|
fn default_bgp_hold_time_secs() -> u16 {
|
|
90
|
|
}
|
|
|
|
fn default_bgp_keepalive_secs() -> u16 {
|
|
30
|
|
}
|
|
|
|
fn default_bgp_connect_retry_secs() -> u64 {
|
|
5
|
|
}
|
|
|
|
impl BgpConfig {
|
|
/// Effective next hop advertised in UPDATE messages.
|
|
pub fn next_hop_addr(&self) -> std::result::Result<IpAddr, std::net::AddrParseError> {
|
|
self.next_hop.as_deref().unwrap_or(&self.router_id).parse()
|
|
}
|
|
|
|
/// Parsed router ID as IPv4.
|
|
pub fn router_id_addr(&self) -> std::result::Result<Ipv4Addr, std::net::AddrParseError> {
|
|
self.router_id.parse()
|
|
}
|
|
}
|
|
|
|
impl Default for BgpConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
enabled: false,
|
|
local_as: default_bgp_local_as(),
|
|
router_id: default_bgp_router_id(),
|
|
next_hop: None,
|
|
hold_time_secs: default_bgp_hold_time_secs(),
|
|
keepalive_secs: default_bgp_keepalive_secs(),
|
|
connect_retry_secs: default_bgp_connect_retry_secs(),
|
|
peers: Vec::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for AuthConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
iam_server_addr: default_iam_server_addr(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for ServerConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
grpc_addr: "0.0.0.0:9080".parse().unwrap(),
|
|
chainfire_endpoint: None,
|
|
flaredb_endpoint: None,
|
|
metadata_backend: MetadataBackend::FlareDb,
|
|
metadata_database_url: None,
|
|
single_node: false,
|
|
log_level: "info".to_string(),
|
|
tls: None,
|
|
auth: AuthConfig::default(),
|
|
health: HealthRuntimeConfig::default(),
|
|
vip_advertisement: VipAdvertisementConfig::default(),
|
|
vip_ownership: VipOwnershipConfig::default(),
|
|
bgp: BgpConfig::default(),
|
|
}
|
|
}
|
|
}
|