diff --git a/junos/interfaces.nix b/junos/interfaces.nix
new file mode 100644
index 0000000..f5094a8
--- /dev/null
+++ b/junos/interfaces.nix
@@ -0,0 +1,128 @@
+{ lib, config, ... }:
+with lib;
+let
+ interface =
+ { name, config, ... }:
+ let
+ intf-name = name;
+ unit =
+ { name, config, ... }:
+ {
+ options = {
+ enable = mkEnableOption "the logical interface ${intf-name}.${name}" // { default = true; };
+ family = {
+ ethernet-switching = {
+ enable = mkEnableOption "the ethernet on the logical interface ${intf-name}.${name}";
+ interface-mode = mkOption {
+ type = types.nullOr (
+ types.enum [
+ "trunk"
+ "access"
+ ]
+ );
+ default = null;
+ };
+ vlans = mkOption {
+ type = types.listOf (types.either types.str types.ints.unsigned);
+ default = [ ];
+ };
+ };
+ #TODO : DHCP
+ inet = {
+ enable = mkEnableOption "the IPv4 configuration of the logical interface ${intf-name}.${name}";
+ address = mkOption {
+ type = types.listOf types.str;
+ default = [ ];
+ };
+ };
+ inet6 = {
+ enable = mkEnableOption "the IPv6 configuration of the logical interface ${intf-name}.${name}";
+ address = mkOption {
+ type = types.listOf types.str;
+ default = [ ];
+ };
+ };
+ };
+ xml = mkOption {
+ type = types.str;
+ visible = false;
+ readOnly = true;
+ };
+ };
+ config.xml =
+ let
+ members = map (
+ vlan: "${builtins.toString vlan}"
+ ) config.family.ethernet-switching.vlans;
+ eth = optionalString config.family.ethernet-switching.enable ''
+
+ ${config.family.ethernet-switching.interface-mode}
+ ${builtins.concatStringsSep "" members}
+ default
+
+ '';
+
+ addr4 = map (addr: "${addr}") config.family.inet.address;
+ inet = optionalString config.family.inet.enable ''
+
+ ${builtins.concatStringsSep "" addr4}
+
+ '';
+
+ addr6 = map (addr: "${addr}") config.family.inet6.address;
+ inet6 = optionalString config.family.inet6.enable ''
+
+ ${builtins.concatStringsSep "" addr6}
+
+ '';
+ in
+ ''
+
+ ${name}
+ ${optionalString (!config.enable) ""}
+
+ ${eth}${inet}${inet6}
+
+ '';
+ };
+ in
+ {
+ options = {
+ enable = mkEnableOption "the physical interface ${intf-name}";
+ unit = mkOption { type = types.attrsOf (types.submodule unit); default = {}; };
+ xml = mkOption {
+ type = types.str;
+ visible = false;
+ readOnly = true;
+ };
+ };
+ config.xml =
+ let
+ units = attrsets.mapAttrsToList (_: unit: unit.xml) config.unit;
+ in
+ ''
+
+ ${name}
+ ${optionalString (!config.enable) ""}
+ ${builtins.concatStringsSep "" units}
+
+ '';
+ };
+in
+{
+ options = {
+ interfaces = mkOption { type = types.attrsOf (types.submodule interface); };
+ netconf.xmls.interfaces = mkOption {
+ type = types.str;
+ visible = false;
+ readOnly = true;
+ };
+ };
+ config.netconf.xmls.interfaces = ''
+
+ ${
+ builtins.concatStringsSep "" (attrsets.mapAttrsToList (_: intf: intf.xml) config.interfaces)
+ }
+
+ '';
+}