{ config, lib, pkgs, ... }: with lib; let cfg = config.plasmacloud.network; clusterCfg = config.plasmacloud.cluster; # BGP peer type for FiberLB bgpPeerType = types.submodule { options = { address = mkOption { type = types.str; description = "Peer IP address (ToR switch, upstream router)"; example = "192.168.1.1"; }; asn = mkOption { type = types.int; description = "Peer AS number"; example = 65001; }; description = mkOption { type = types.str; default = ""; description = "Human-readable peer description"; example = "ToR switch rack1"; }; }; }; in { options.plasmacloud.network = { fiberlbBgp = { enable = mkEnableOption "FiberLB BGP VIP advertisement"; vips = mkOption { type = types.listOf types.str; default = []; description = "Legacy static VIP hints. FiberLB native BGP ignores this list and advertises active load balancer VIPs dynamically."; example = [ "203.0.113.10/32" "203.0.113.11/32" ]; }; peers = mkOption { type = types.listOf bgpPeerType; default = []; description = "BGP peers (ToR switches, upstream routers)"; example = literalExpression '' [ { address = "192.168.1.1"; asn = 65001; description = "ToR switch rack1"; } { address = "192.168.1.2"; asn = 65001; description = "ToR switch rack2"; } ] ''; }; routerId = mkOption { type = types.nullOr types.str; default = null; description = "BGP router ID (auto-detected from primary IP if null)"; }; }; prismnetIntegration = { enable = mkEnableOption "PrismNET OVN integration"; }; }; config = mkMerge [ # FiberLB BGP configuration (mkIf cfg.fiberlbBgp.enable { # Assertions assertions = [ { assertion = clusterCfg.bgp.asn > 0; message = "plasmacloud.cluster.bgp.asn must be configured for FiberLB BGP"; } { assertion = (length cfg.fiberlbBgp.peers) > 0; message = "plasmacloud.network.fiberlbBgp.peers must contain at least one BGP peer"; } { assertion = config.services.fiberlb.enable or false; message = "plasmacloud.network.fiberlbBgp.enable requires services.fiberlb.enable"; } ]; services.fiberlb.bgp = { enable = true; localAs = clusterCfg.bgp.asn; routerId = if cfg.fiberlbBgp.routerId != null then cfg.fiberlbBgp.routerId else let hostname = config.networking.hostName; node = clusterCfg.nodes.${hostname} or null; in if node != null then node.ip else "127.0.0.1"; peers = cfg.fiberlbBgp.peers; }; services.fiberlb.vipOwnership.enable = mkDefault true; }) # PrismNET OVN integration (mkIf cfg.prismnetIntegration.enable { # Enable OVN Controller virtualisation.switch.enable = true; virtualisation.ovn = { enable = true; controller = { enable = true; # Use Geneve encapsulation to avoid VXLAN VNI limitations and allow richer metadata encapType = "geneve"; # Auto-detect IP from cluster config encapIp = let hostname = config.networking.hostName; node = clusterCfg.nodes.${hostname} or null; in if node != null then node.ip else "127.0.0.1"; }; }; }) ]; }