{ lib }: with lib; rec { # Generate systemd network unit files from nix-nos network config generateNetworkdConfig = { interfaces }: listToAttrs (map (iface: { name = "10-${iface.name}"; value = { matchConfig.Name = iface.name; networkConfig = { DHCP = "no"; } // optionalAttrs (iface.mtu != null) { MTU = toString iface.mtu; }; address = iface.addresses; }; }) interfaces); # Generate BGP peer configurations in a backend-agnostic format generateBgpPeers = { asn, routerId, peers }: map (peer: { inherit (peer) address description; inherit asn; peerAsn = peer.asn; inherit routerId; }) peers; # Generate route table entries generateRouteTable = { routes }: map (route: { inherit (route) destination; gateway = route.gateway or null; interface = route.interface or null; metric = route.metric or 100; }) routes; # Helper: Convert CIDR to netmask cidrToNetmask = cidr: let parts = splitString "/" cidr; prefixLength = toInt (elemAt parts 1); # IPv4 netmask calculation masks = { "8" = "255.0.0.0"; "16" = "255.255.0.0"; "24" = "255.255.255.0"; "32" = "255.255.255.255"; }; in masks.${toString prefixLength} or (throw "Unsupported prefix length: ${toString prefixLength}"); # Helper: Extract IP from CIDR notation cidrToIp = cidr: let parts = splitString "/" cidr; in elemAt parts 0; # Helper: Extract prefix length from CIDR notation cidrToPrefixLength = cidr: let parts = splitString "/" cidr; in toInt (elemAt parts 1); # Validate IP address format isValidIpv4 = ip: let parts = splitString "." ip; validOctet = octet: let n = toInt octet; in n >= 0 && n <= 255; in (length parts == 4) && all validOctet parts; # Validate IPv6 address (simplified check) isValidIpv6 = ip: hasInfix ":" ip; # Validate CIDR notation isValidCidr = cidr: let parts = splitString "/" cidr; ip = elemAt parts 0; prefixLength = toInt (elemAt parts 1); in (length parts == 2) && (isValidIpv4 ip || isValidIpv6 ip) && (prefixLength >= 0) && (if isValidIpv4 ip then prefixLength <= 32 else prefixLength <= 128); }