let module_inst = { interfaces = let AP = { # AP interface-mode = "trunk"; vlans = [ "users" "admin" ]; }; off.interface-mode = "none"; in { "ge-0/0/0" = off; "ge-0/0/1" = off; "ge-0/0/2" = off; "ge-0/0/3" = off; "ge-0/0/4" = off; "ge-0/0/5" = off; "ge-0/0/6" = off; "ge-0/0/7" = off; "ge-0/0/8" = off; "ge-0/0/9" = off; "ge-0/0/10" = off; "ge-0/0/11" = off; "ge-0/0/12" = AP; "ge-0/0/13" = AP; "ge-0/0/14" = AP; "ge-0/0/15" = AP; "ge-0/0/16" = AP; "ge-0/0/17" = AP; "ge-0/0/18" = off; "ge-0/0/19" = off; "ge-0/0/20" = off; "ge-0/0/21" = off; "ge-0/0/22" = off; "ge-0/0/23" = off; "ge-0/0/24" = off; "ge-0/0/25" = off; "ge-0/0/26" = off; "ge-0/0/27" = off; "ge-0/0/28" = off; "ge-0/0/29" = off; "ge-0/0/30" = off; "ge-0/0/31" = off; "ge-0/0/32" = off; "ge-0/0/33" = off; "ge-0/0/34" = off; "ge-0/0/35" = off; "ge-0/0/36" = off; "ge-0/0/37" = off; "ge-0/0/38" = off; "ge-0/0/39" = off; "ge-0/0/40" = off; "ge-0/0/41" = off; "ge-0/0/42" = off; "ge-0/0/43" = off; "ge-0/0/44" = off; "ge-0/0/45" = off; "ge-0/0/46" = off; "ge-0/0/47" = off; "ge-0/1/0" = { # upstream interface-mode = "trunk"; vlans = [ "all" ]; dhcp_trusted = true; management = true; }; "ge-0/1/1" = off; "ge-0/1/2" = off; "ge-0/1/3" = off; "xe-0/1/0" = off; "xe-0/1/1" = off; "xe-0/1/2" = off; "xe-0/1/3" = off; "me0" = { # mgmt interface-mode = "none"; management = true; }; }; vlans = { "users" = [ { begin = 3045; end = 4094; } ]; "admin" = [ 3000 ]; }; }; module = { lib, config, ... }: with lib; { # NOTE: dhcp should be configured at vlan level, but this is not very satisfying, # so this module tries to configured dhcp-trust on interfaces # -> this implies that interfaces change the config of their vlans options = { interfaces = let vlan_type = types.either (types.strMatching "[^\n\r]+") (types.ints.unsigned); interface = {config, ...}: { options = { interface-mode = mkOption { type = types.enum [ "trunk" "access" "none" ]; #TODO: default = if ; }; vlans = mkOption { type = types.listOf vlan_type; }; dhcp_trusted = mkOption { type = types.bool; default = false; }; management = mkOption { type = types.bool; default = false; }; xmlGen = mkOption { type = types.uniq types.unspecified; }; }; config.vlans = lib.mkIf (config.interface-mode == "none") (lib.mkForce [ ]); config.xmlGen = name: let mgmt_fam = if config.management then "" else ""; eth_switch = if config.interface-mode == "none" then "" else '' ${config.interface-mode} ${builtins.concatStringsSep "" (map (vlan: "${builtins.toString vlan}") config.vlans)} ''; in '' ${name} 0 ${mgmt_fam} ${eth_switch} ''; }; in mkOption { type = types.attrsOf (types.submodule interface); }; vlans = let range_type.options = { begin = mkOption { type = types.ints.unsigned; }; end = mkOption { type = types.ints.unsigned; }; }; in mkOption { type = types.attrsOf (types.listOf (types.either types.ints.unsigned (types.submodule range_type))); }; # NOTE, HACK: placeholder for now toplevel = mkOption { type = types.uniq types.anything; }; }; config.toplevel = let interfaces = builtins.attrValues (builtins.mapAttrs (name: mod: mod.xmlGen name) config.interfaces); # { vlan = { trust = [String]; notrust = [String]; } } interface_names = builtins.attrNames config.interfaces; vlan_map = inter: vlan: if builtins.isString vlan then if config.interfaces.${inter}.dhcp_trusted then { ${vlan}.trust = inter; } else { ${vlan}.notrust = inter; } else {}; int_map = inter: map (vlan_map inter) config.interfaces.${inter}.vlans; vlan_trust_table = builtins.zipAttrsWith (vlan: values: builtins.zipAttrsWith (_: ints: ints ) values) (builtins.concatMap int_map interface_names); vlans = map (vlan: let ids = map (id: let list = if builtins.isInt id then builtins.toString id else "${builtins.toString id.begin}-${builtins.toString id.end}"; in ''${list}'') config.vlans.${vlan}; in '' ${vlan} ${builtins.concatStringsSep "\n" ids} '') (builtins.attrNames config.vlans); in [ '' ${builtins.concatStringsSep "\n" interfaces} ${builtins.concatStringsSep "\n" vlans} '' vlan_trust_table]; }; in (import ).evalModules { modules = [ module module_inst ]; }