summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poessinger <christian@poessinger.com>2019-09-07 12:29:12 +0200
committerChristian Poessinger <christian@poessinger.com>2019-09-20 21:28:53 +0200
commita610e328750e3cfc23c29a2cafb40d7ef7082b13 (patch)
tree5cbdc864b0d036b92bb3ef60d3246b879016a187
parent4ae44c074e15fa102718d5a4512c23db447d6dc8 (diff)
downloadvyos-1x-a610e328750e3cfc23c29a2cafb40d7ef7082b13.tar.gz
vyos-1x-a610e328750e3cfc23c29a2cafb40d7ef7082b13.zip
ethernet: T1637: initial rewrite in XML/Python style
-rw-r--r--Makefile6
-rw-r--r--interface-definitions/interfaces-ethernet.xml856
-rw-r--r--python/vyos/ifconfig.py13
-rwxr-xr-xsrc/conf_mode/interface-ethernet.py298
4 files changed, 1170 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 61bc06c47..881fc36b1 100644
--- a/Makefile
+++ b/Makefile
@@ -11,8 +11,12 @@ interface_definitions:
# XXX: delete top level node.def's that now live in other packages
rm -f $(TMPL_DIR)/firewall/node.def
rm -f $(TMPL_DIR)/interfaces/node.def
- rm -f $(TMPL_DIR)/interfaces/bridge/node.tag/ip/node.def
rm -f $(TMPL_DIR)/interfaces/bonding/node.tag/ip/node.def
+ rm -f $(TMPL_DIR)/interfaces/bridge/node.tag/ip/node.def
+ rm -f $(TMPL_DIR)/interfaces/ethernet/node.tag/ip/node.def
+ rm -f $(TMPL_DIR)/interfaces/ethernet/node.tag/vif/node.tag/ip/node.def
+ rm -f $(TMPL_DIR)/interfaces/ethernet/node.tag/vif-s/node.tag/ip/node.def
+ rm -f $(TMPL_DIR)/interfaces/ethernet/node.tag/vif-s/node.tag/vif-c/node.tag/ip/node.def
rm -f $(TMPL_DIR)/interfaces/vxlan/node.tag/ip/node.def
rm -f $(TMPL_DIR)/protocols/node.def
rm -f $(TMPL_DIR)/protocols/static/node.def
diff --git a/interface-definitions/interfaces-ethernet.xml b/interface-definitions/interfaces-ethernet.xml
new file mode 100644
index 000000000..a2de4aeb3
--- /dev/null
+++ b/interface-definitions/interfaces-ethernet.xml
@@ -0,0 +1,856 @@
+<?xml version="1.0"?>
+<interfaceDefinition>
+ <node name="interfaces">
+ <children>
+ <tagNode name="ethernet" owner="${vyos_conf_scripts_dir}/interface-ethernet.py">
+ <properties>
+ <help>Ethernet interface name</help>
+ <priority>318</priority>
+ <constraint>
+ <regex>((eth|lan)[0-9]+|(eno|ens|enp|enx).+)$</regex>
+ </constraint>
+ <constraintErrorMessage>Invalid Ethernet interface name</constraintErrorMessage>
+ <valueHelp>
+ <format>ethN</format>
+ <description>Ethernet interface name</description>
+ </valueHelp>
+ <valueHelp>
+ <format>en[ospx]N</format>
+ <description>Ethernet interface name</description>
+ </valueHelp>
+ </properties>
+ <children>
+ <leafNode name="address">
+ <properties>
+ <help>IP address</help>
+ <completionHelp>
+ <list>dhcp dhcpv6</list>
+ </completionHelp>
+ <valueHelp>
+ <format>ipv4net</format>
+ <description>IPv4 address and prefix length</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 address and prefix length</description>
+ </valueHelp>
+ <valueHelp>
+ <format>dhcp</format>
+ <description>Dynamic Host Configuration Protocol</description>
+ </valueHelp>
+ <valueHelp>
+ <format>dhcpv6</format>
+ <description>Dynamic Host Configuration Protocol for IPv6</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ip-cidr"/>
+ <regex>(dhcp|dhcpv6)</regex>
+ </constraint>
+ <multi/>
+ </properties>
+ </leafNode>
+ <leafNode name="description">
+ <properties>
+ <help>Interface description</help>
+ <constraint>
+ <regex>^.{1,256}$</regex>
+ </constraint>
+ <constraintErrorMessage>Interface description too long (limit 256 characters)</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <node name="dhcp-options">
+ <properties>
+ <help>DHCP options</help>
+ </properties>
+ <children>
+ <leafNode name="client-id">
+ <properties>
+ <help>DHCP client identifier</help>
+ </properties>
+ </leafNode>
+ <leafNode name="host-name">
+ <properties>
+ <help>DHCP client host name (overrides the system host name)</help>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <node name="dhcpv6-options">
+ <properties>
+ <help>DHCPv6 options</help>
+ <priority>319</priority>
+ </properties>
+ <children>
+ <leafNode name="parameters-only">
+ <properties>
+ <help>Acquire only config parameters, no address</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="temporary">
+ <properties>
+ <help>IPv6 "temporary" address</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="disable-flow-control">
+ <properties>
+ <help>Disable Ethernet flow control (pause frames)</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="disable-link-detect">
+ <properties>
+ <help>Ignore link state changes</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="disable">
+ <properties>
+ <help>Disable this bridge interface</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="duplex">
+ <properties>
+ <help>Duplex mode</help>
+ <completionHelp>
+ <list>auto half full</list>
+ </completionHelp>
+ <valueHelp>
+ <format>auto</format>
+ <description>Auto negotiation (default)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>half</format>
+ <description>Half duplex</description>
+ </valueHelp>
+ <valueHelp>
+ <format>full</format>
+ <description>Full duplex</description>
+ </valueHelp>
+ <constraint>
+ <regex>(auto|half|full)</regex>
+ </constraint>
+ <constraintErrorMessage>duplex must be auto, half or full</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="hw-id">
+ <properties>
+ <help>Media Access Control (MAC) address</help>
+ <valueHelp>
+ <format>h:h:h:h:h:h</format>
+ <description>Hardware (MAC) address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="mac-address"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <node name="ip">
+ <children>
+ <leafNode name="arp-cache-timeout">
+ <properties>
+ <help>ARP cache entry timeout in seconds</help>
+ <valueHelp>
+ <format>1-86400</format>
+ <description>ARP cache entry timout in seconds (default 30)</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-86400"/>
+ </constraint>
+ <constraintErrorMessage>ARP cache entry timeout must be between 1 and 86400 seconds</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="enable-proxy-arp">
+ <properties>
+ <help>Enable proxy-arp on this interface</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="proxy-arp-pvlan">
+ <properties>
+ <help>Enable private VLAN proxy ARP on this interface</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="mac">
+ <properties>
+ <help>Media Access Control (MAC) address</help>
+ <valueHelp>
+ <format>h:h:h:h:h:h</format>
+ <description>Hardware (MAC) address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="mac-address"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="mtu">
+ <properties>
+ <help>Maximum Transmission Unit (MTU)</help>
+ <valueHelp>
+ <format>68-9000</format>
+ <description>Maximum Transmission Unit</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 68-9000"/>
+ </constraint>
+ <constraintErrorMessage>MTU must be between 68 and 9000</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <node name="offload-options">
+ <properties>
+ <help>Configurable offload options</help>
+ </properties>
+ <children>
+ <leafNode name="generic-receive">
+ <properties>
+ <help>Configure GRO (generic receive offload)</help>
+ <completionHelp>
+ <list>on off</list>
+ </completionHelp>
+ <valueHelp>
+ <format>on</format>
+ <description>Enable GRO (generic receive offload)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>off</format>
+ <description>Disable GRO (generic receive offload)</description>
+ </valueHelp>
+ <constraint>
+ <regex>(on|off)</regex>
+ </constraint>
+ <constraintErrorMessage>Must be either 'on' or 'off'</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="generic-segmentation">
+ <properties>
+ <help>Configure GSO (generic segmentation offload)</help>
+ <completionHelp>
+ <list>on off</list>
+ </completionHelp>
+ <valueHelp>
+ <format>on</format>
+ <description>Enable GSO (generic segmentation offload)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>off</format>
+ <description>Disable GSO (generic segmentation offload)</description>
+ </valueHelp>
+ <constraint>
+ <regex>(on|off)</regex>
+ </constraint>
+ <constraintErrorMessage>Must be either 'on' or 'off'</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="scatter-gather">
+ <properties>
+ <help>Configure scatter-gather option</help>
+ <completionHelp>
+ <list>on off</list>
+ </completionHelp>
+ <valueHelp>
+ <format>on</format>
+ <description>Enable scatter-gather</description>
+ </valueHelp>
+ <valueHelp>
+ <format>off</format>
+ <description>Disable scatter-gather</description>
+ </valueHelp>
+ <constraint>
+ <regex>(on|off)</regex>
+ </constraint>
+ <constraintErrorMessage>Must be either 'on' or 'off'</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="tcp-segmentation">
+ <properties>
+ <help>Configure TSO (TCP segmentation offloading)</help>
+ <completionHelp>
+ <list>on off</list>
+ </completionHelp>
+ <valueHelp>
+ <format>on</format>
+ <description>Enable TSO (TCP segmentation offloading)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>off</format>
+ <description>Disable TSO (TCP segmentation offloading)</description>
+ </valueHelp>
+ <constraint>
+ <regex>(on|off)</regex>
+ </constraint>
+ <constraintErrorMessage>Must be either 'on' or 'off'</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="udp-fragmentation">
+ <properties>
+ <help>Configure UDP fragmentation offloading</help>
+ <completionHelp>
+ <list>on off</list>
+ </completionHelp>
+ <valueHelp>
+ <format>on</format>
+ <description>Enable UDP fragmentation offloading</description>
+ </valueHelp>
+ <valueHelp>
+ <format>off</format>
+ <description>Disable UDP fragmentation offloading</description>
+ </valueHelp>
+ <constraint>
+ <regex>(on|off)</regex>
+ </constraint>
+ <constraintErrorMessage>Must be either 'on' or 'off'</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="smp-affinity">
+ <properties>
+ <help>CPU interrupt affinity mask</help>
+ <completionHelp>
+ <list>auto 10 100 1000 2500 5000 10000</list>
+ </completionHelp>
+ <valueHelp>
+ <format>auto</format>
+ <description>Auto negotiation (default)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>hex</format>
+ <description>Bitmask representing CPUs that this NIC will interrupt</description>
+ </valueHelp>
+ <valueHelp>
+ <format>hex,hex</format>
+ <description>Bitmasks representing CPUs for interrupt and receive processing</description>
+ </valueHelp>
+ <constraint>
+ <regex>(auto)</regex>
+ <regex>[0-9a-f]+(|,[0-9a-f]+)$</regex>
+ </constraint>
+ <constraintErrorMessage>IRQ affinity mask must be hex value or auto</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="speed">
+ <properties>
+ <help>Link speed</help>
+ <completionHelp>
+ <list>auto 10 100 1000 2500 5000 10000</list>
+ </completionHelp>
+ <valueHelp>
+ <format>auto</format>
+ <description>Auto negotiation (default)</description>
+ </valueHelp>
+ <valueHelp>
+ <format>10</format>
+ <description>10 Mbit/sec</description>
+ </valueHelp>
+ <valueHelp>
+ <format>100</format>
+ <description>100 Mbit/sec</description>
+ </valueHelp>
+ <valueHelp>
+ <format>1000</format>
+ <description>1 Gbit/sec</description>
+ </valueHelp>
+ <valueHelp>
+ <format>2500</format>
+ <description>2.5 Gbit/sec</description>
+ </valueHelp>
+ <valueHelp>
+ <format>5000</format>
+ <description>5 Gbit/sec</description>
+ </valueHelp>
+ <valueHelp>
+ <format>10000</format>
+ <description>10 Gbit/sec</description>
+ </valueHelp>
+ <constraint>
+ <regex>(auto|10|100|1000|2500|5000|10000)</regex>
+ </constraint>
+ <constraintErrorMessage>Speed must be auto, 10, 100, 1000, 2500, 5000 or 10000</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <tagNode name="vif-s">
+ <properties>
+ <help>QinQ TAG-S Virtual Local Area Network (VLAN) ID</help>
+ <constraint>
+ <validator name="numeric" argument="--range 0-4094"/>
+ </constraint>
+ <constraintErrorMessage>VLAN ID must be between 0 and 4094</constraintErrorMessage>
+ </properties>
+ <children>
+ <leafNode name="address">
+ <properties>
+ <help>IP address</help>
+ <completionHelp>
+ <list>dhcp dhcpv6</list>
+ </completionHelp>
+ <valueHelp>
+ <format>ipv4net</format>
+ <description>IPv4 address and prefix length</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 address and prefix length</description>
+ </valueHelp>
+ <valueHelp>
+ <format>dhcp</format>
+ <description>Dynamic Host Configuration Protocol</description>
+ </valueHelp>
+ <valueHelp>
+ <format>dhcpv6</format>
+ <description>Dynamic Host Configuration Protocol for IPv6</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ip-cidr"/>
+ <regex>(dhcp|dhcpv6)</regex>
+ </constraint>
+ <multi/>
+ </properties>
+ </leafNode>
+ <leafNode name="description">
+ <properties>
+ <help>Interface description</help>
+ <constraint>
+ <regex>^.{1,256}$</regex>
+ </constraint>
+ <constraintErrorMessage>Interface description too long (limit 256 characters)</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <node name="dhcp-options">
+ <properties>
+ <help>DHCP options</help>
+ </properties>
+ <children>
+ <leafNode name="client-id">
+ <properties>
+ <help>DHCP client identifier</help>
+ </properties>
+ </leafNode>
+ <leafNode name="host-name">
+ <properties>
+ <help>DHCP client host name (overrides the system host name)</help>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <node name="dhcpv6-options">
+ <properties>
+ <help>DHCPv6 options</help>
+ <priority>319</priority>
+ </properties>
+ <children>
+ <leafNode name="parameters-only">
+ <properties>
+ <help>Acquire only config parameters, no address</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="temporary">
+ <properties>
+ <help>IPv6 "temporary" address</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="disable-link-detect">
+ <properties>
+ <help>Ignore link state changes</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="disable">
+ <properties>
+ <help>Disable this bridge interface</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="ethertype">
+ <properties>
+ <help>Set Ethertype</help>
+ <completionHelp>
+ <list>0x88A8 0x8100</list>
+ </completionHelp>
+ <valueHelp>
+ <format>0x88A8</format>
+ <description>802.1ad</description>
+ </valueHelp>
+ <valueHelp>
+ <format>0x8100</format>
+ <description>802.1q</description>
+ </valueHelp>
+ <constraint>
+ <regex>(0x88A8|0x8100)</regex>
+ </constraint>
+ <constraintErrorMessage>Ethertype must be 0x88A8 or 0x8100</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <node name="ip">
+ <children>
+ <leafNode name="enable-proxy-arp">
+ <properties>
+ <help>Enable proxy-arp on this interface</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="proxy-arp-pvlan">
+ <properties>
+ <help>Enable private VLAN proxy ARP on this interface</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="mac">
+ <properties>
+ <help>Media Access Control (MAC) address</help>
+ <valueHelp>
+ <format>h:h:h:h:h:h</format>
+ <description>Hardware (MAC) address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="mac-address"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="mtu">
+ <properties>
+ <help>Maximum Transmission Unit (MTU)</help>
+ <valueHelp>
+ <format>68-9000</format>
+ <description>Maximum Transmission Unit</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 68-9000"/>
+ </constraint>
+ <constraintErrorMessage>MTU must be between 68 and 9000</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <tagNode name="vif-c">
+ <properties>
+ <help>QinQ TAG-C Virtual Local Area Network (VLAN) ID</help>
+ <constraint>
+ <validator name="numeric" argument="--range 0-4094"/>
+ </constraint>
+ <constraintErrorMessage>VLAN ID must be between 0 and 4094</constraintErrorMessage>
+ </properties>
+ <children>
+ <leafNode name="address">
+ <properties>
+ <help>IP address</help>
+ <completionHelp>
+ <list>dhcp dhcpv6</list>
+ </completionHelp>
+ <valueHelp>
+ <format>ipv4net</format>
+ <description>IPv4 address and prefix length</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 address and prefix length</description>
+ </valueHelp>
+ <valueHelp>
+ <format>dhcp</format>
+ <description>Dynamic Host Configuration Protocol</description>
+ </valueHelp>
+ <valueHelp>
+ <format>dhcpv6</format>
+ <description>Dynamic Host Configuration Protocol for IPv6</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ip-cidr"/>
+ <regex>(dhcp|dhcpv6)</regex>
+ </constraint>
+ <multi/>
+ </properties>
+ </leafNode>
+ <leafNode name="description">
+ <properties>
+ <help>Interface description</help>
+ <constraint>
+ <regex>^.{1,256}$</regex>
+ </constraint>
+ <constraintErrorMessage>Interface description too long (limit 256 characters)</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <node name="dhcp-options">
+ <properties>
+ <help>DHCP options</help>
+ </properties>
+ <children>
+ <leafNode name="client-id">
+ <properties>
+ <help>DHCP client identifier</help>
+ </properties>
+ </leafNode>
+ <leafNode name="host-name">
+ <properties>
+ <help>DHCP client host name (overrides the system host name)</help>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <node name="dhcpv6-options">
+ <properties>
+ <help>DHCPv6 options</help>
+ <priority>319</priority>
+ </properties>
+ <children>
+ <leafNode name="parameters-only">
+ <properties>
+ <help>Acquire only config parameters, no address</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="temporary">
+ <properties>
+ <help>IPv6 "temporary" address</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="disable-link-detect">
+ <properties>
+ <help>Ignore link state changes</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="disable">
+ <properties>
+ <help>Disable this bridge interface</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <node name="ip">
+ <children>
+ <leafNode name="enable-proxy-arp">
+ <properties>
+ <help>Enable proxy-arp on this interface</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="proxy-arp-pvlan">
+ <properties>
+ <help>Enable private VLAN proxy ARP on this interface</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="mac">
+ <properties>
+ <help>Media Access Control (MAC) address</help>
+ <valueHelp>
+ <format>h:h:h:h:h:h</format>
+ <description>Hardware (MAC) address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="mac-address"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="mtu">
+ <properties>
+ <help>Maximum Transmission Unit (MTU)</help>
+ <valueHelp>
+ <format>68-9000</format>
+ <description>Maximum Transmission Unit</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 68-9000"/>
+ </constraint>
+ <constraintErrorMessage>MTU must be between 68 and 9000</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
+ </children>
+ </tagNode>
+ <tagNode name="vif">
+ <properties>
+ <help>Virtual Local Area Network (VLAN) ID</help>
+ <constraint>
+ <validator name="numeric" argument="--range 0-4094"/>
+ </constraint>
+ <constraintErrorMessage>VLAN ID must be between 0 and 4094</constraintErrorMessage>
+ </properties>
+ <children>
+ <leafNode name="address">
+ <properties>
+ <help>IP address</help>
+ <completionHelp>
+ <list>dhcp dhcpv6</list>
+ </completionHelp>
+ <valueHelp>
+ <format>ipv4net</format>
+ <description>IPv4 address and prefix length</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 address and prefix length</description>
+ </valueHelp>
+ <valueHelp>
+ <format>dhcp</format>
+ <description>Dynamic Host Configuration Protocol</description>
+ </valueHelp>
+ <valueHelp>
+ <format>dhcpv6</format>
+ <description>Dynamic Host Configuration Protocol for IPv6</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ip-cidr"/>
+ <regex>(dhcp|dhcpv6)</regex>
+ </constraint>
+ <multi/>
+ </properties>
+ </leafNode>
+ <leafNode name="description">
+ <properties>
+ <help>Interface description</help>
+ <constraint>
+ <regex>^.{1,256}$</regex>
+ </constraint>
+ <constraintErrorMessage>Interface description too long (limit 256 characters)</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <node name="dhcp-options">
+ <properties>
+ <help>DHCP options</help>
+ </properties>
+ <children>
+ <leafNode name="client-id">
+ <properties>
+ <help>DHCP client identifier</help>
+ </properties>
+ </leafNode>
+ <leafNode name="host-name">
+ <properties>
+ <help>DHCP client host name (overrides the system host name)</help>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <node name="dhcpv6-options">
+ <properties>
+ <help>DHCPv6 options</help>
+ <priority>319</priority>
+ </properties>
+ <children>
+ <leafNode name="parameters-only">
+ <properties>
+ <help>Acquire only config parameters, no address</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="temporary">
+ <properties>
+ <help>IPv6 "temporary" address</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="disable-link-detect">
+ <properties>
+ <help>Ignore link state changes</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="disable">
+ <properties>
+ <help>Disable this bridge interface</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="egress-qos">
+ <properties>
+ <help>VLAN egress QoS</help>
+ <completionHelp>
+ <script>echo Format for qos mapping \"0:1 1:6 7:6\"</script>
+ </completionHelp>
+ <constraint>
+ <regex>[:0-7 ]+$</regex>
+ </constraint>
+ <constraintErrorMessage>QoS mapping should be in the format of \"0:7 2:3\" with numbers 0-9</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="ingress-qos">
+ <properties>
+ <help>VLAN ingress QoS</help>
+ <completionHelp>
+ <script>echo Format for qos mapping \"0:1 1:6 7:6\"</script>
+ </completionHelp>
+ <constraint>
+ <regex>[:0-7 ]+$</regex>
+ </constraint>
+ <constraintErrorMessage>QoS mapping should be in the format of \"0:7 2:3\" with numbers 0-9</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <node name="ip">
+ <children>
+ <leafNode name="arp-cache-timeout">
+ <properties>
+ <help>ARP cache entry timeout in seconds</help>
+ <valueHelp>
+ <format>1-86400</format>
+ <description>ARP cache entry timout in seconds (default 30)</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-86400"/>
+ </constraint>
+ <constraintErrorMessage>ARP cache entry timeout must be between 1 and 86400 seconds</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="enable-proxy-arp">
+ <properties>
+ <help>Enable proxy-arp on this interface</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="proxy-arp-pvlan">
+ <properties>
+ <help>Enable private VLAN proxy ARP on this interface</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="mac">
+ <properties>
+ <help>Media Access Control (MAC) address</help>
+ <valueHelp>
+ <format>h:h:h:h:h:h</format>
+ <description>Hardware (MAC) address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="mac-address"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="mtu">
+ <properties>
+ <help>Maximum Transmission Unit (MTU)</help>
+ <valueHelp>
+ <format>68-9000</format>
+ <description>Maximum Transmission Unit</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 68-9000"/>
+ </constraint>
+ <constraintErrorMessage>MTU must be between 68 and 9000</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
+ </children>
+ </tagNode>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py
index 524c0f276..7181ff42f 100644
--- a/python/vyos/ifconfig.py
+++ b/python/vyos/ifconfig.py
@@ -1047,8 +1047,18 @@ class VLANIf(Interface):
tmp.remove()
-class BondIf(VLANIf):
+class EthernetIf(VLANIf):
+ """
+ Abstraction of a Linux Ethernet Interface
+ """
+ def __init__(self, ifname):
+ super().__init__(ifname)
+ def remove(self):
+ raise OSError('Ethernet interfaces can not be removed')
+
+
+class BondIf(VLANIf):
"""
The Linux bonding driver provides a method for aggregating multiple network
interfaces into a single logical "bonded" interface. The behavior of the
@@ -1056,7 +1066,6 @@ class BondIf(VLANIf):
either hot standby or load balancing services. Additionally, link integrity
monitoring may be performed.
"""
-
def __init__(self, ifname):
super().__init__(ifname, type='bond')
diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py
new file mode 100755
index 000000000..4aed13a62
--- /dev/null
+++ b/src/conf_mode/interface-ethernet.py
@@ -0,0 +1,298 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2019 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+
+from copy import deepcopy
+from sys import exit
+
+from vyos.ifconfig import EthernetIf, VLANIf
+from vyos.configdict import list_diff, vlan_to_dict
+from vyos.config import Config
+from vyos import ConfigError
+
+default_config_data = {
+ 'address': [],
+ 'address_remove': [],
+ 'description': '',
+ 'deleted': False,
+ 'dhcp_client_id': '',
+ 'dhcp_hostname': '',
+ 'dhcpv6_prm_only': False,
+ 'dhcpv6_temporary': False,
+ 'disable': False,
+ 'disable_link_detect': 1,
+ 'hw_id': '',
+ 'ip_arp_cache_tmo': 30,
+ 'ip_proxy_arp': 0,
+ 'ip_proxy_arp_pvlan': 0,
+ 'intf': '',
+ 'mac': '',
+ 'mtu': 1500,
+ 'vif_s': [],
+ 'vif_s_remove': [],
+ 'vif': [],
+ 'vif_remove': []
+}
+
+
+def apply_vlan_config(vlan, config):
+ """
+ Generic function to apply a VLAN configuration from a dictionary
+ to a VLAN interface
+ """
+
+ if type(vlan) != type(VLANIf("lo")):
+ raise TypeError()
+
+ # update interface description used e.g. within SNMP
+ vlan.ifalias = config['description']
+ # ignore link state changes
+ vlan.link_detect = config['disable_link_detect']
+ # Maximum Transmission Unit (MTU)
+ vlan.mtu = config['mtu']
+ # Change VLAN interface MAC address
+ if config['mac']:
+ vlan.mac = config['mac']
+
+ # enable/disable VLAN interface
+ if config['disable']:
+ vlan.state = 'down'
+ else:
+ vlan.state = 'up'
+
+ # Configure interface address(es)
+ # - not longer required addresses get removed first
+ # - newly addresses will be added second
+ for addr in config['address_remove']:
+ vlan.del_addr(addr)
+ for addr in config['address']:
+ vlan.add_addr(addr)
+
+
+def get_config():
+ eth = deepcopy(default_config_data)
+ conf = Config()
+
+ # determine tagNode instance
+ try:
+ eth['intf'] = os.environ['VYOS_TAGNODE_VALUE']
+ except KeyError as E:
+ print("Interface not specified")
+
+ # check if ethernet interface has been removed
+ cfg_base = 'interfaces ethernet ' + eth['intf']
+ if not conf.exists(cfg_base):
+ eth['deleted'] = True
+ # we can not bail out early as ethernet interface can not be removed
+ # Kernel will complain with: RTNETLINK answers: Operation not supported.
+ # Thus we need to remove individual settings
+ return eth
+
+ # set new configuration level
+ conf.set_level(cfg_base)
+
+ # retrieve configured interface addresses
+ if conf.exists('address'):
+ eth['address'] = conf.return_values('address')
+
+ # get interface addresses (currently effective) - to determine which
+ # address is no longer valid and needs to be removed
+ eff_addr = conf.return_effective_values('address')
+ eth['address_remove'] = list_diff(eff_addr, eth['address'])
+
+ # retrieve interface description
+ if conf.exists('description'):
+ eth['description'] = conf.return_value('description')
+ else:
+ eth['description'] = eth['intf']
+
+ # get DHCP client identifier
+ if conf.exists('dhcp-options client-id'):
+ eth['dhcp_client_id'] = conf.return_value('dhcp-options client-id')
+
+ # DHCP client host name (overrides the system host name)
+ if conf.exists('dhcp-options host-name'):
+ eth['dhcp_hostname'] = conf.return_value('dhcp-options host-name')
+
+ # DHCPv6 only acquire config parameters, no address
+ if conf.exists('dhcpv6-options parameters-only'):
+ eth['dhcpv6_prm_only'] = conf.return_value('dhcpv6-options parameters-only')
+
+ # DHCPv6 temporary IPv6 address
+ if conf.exists('dhcpv6-options temporary'):
+ eth['dhcpv6_temporary'] = conf.return_value('dhcpv6-options temporary')
+
+ # ignore link state changes
+ if conf.exists('disable-link-detect'):
+ eth['disable_link_detect'] = 2
+
+ # disable interface
+ if conf.exists('disable'):
+ eth['disable'] = True
+
+ # ARP cache entry timeout in seconds
+ if conf.exists('ip arp-cache-timeout'):
+ eth['ip_arp_cache_tmo'] = int(conf.return_value('ip arp-cache-timeout'))
+
+ # Enable proxy-arp on this interface
+ if conf.exists('ip enable-proxy-arp'):
+ eth['ip_proxy_arp'] = 1
+
+ # Enable private VLAN proxy ARP on this interface
+ if conf.exists('ip proxy-arp-pvlan'):
+ eth['ip_proxy_arp_pvlan'] = 1
+
+ # Media Access Control (MAC) address
+ if conf.exists('mac'):
+ eth['mac'] = conf.return_value('mac')
+
+ # Maximum Transmission Unit (MTU)
+ if conf.exists('mtu'):
+ eth['mtu'] = int(conf.return_value('mtu'))
+
+ # re-set configuration level and retrieve vif-s interfaces
+ conf.set_level(cfg_base)
+ # get vif-s interfaces (currently effective) - to determine which vif-s
+ # interface is no longer present and needs to be removed
+ eff_intf = conf.list_effective_nodes('vif-s')
+ act_intf = conf.list_nodes('vif-s')
+ eth['vif_s_remove'] = list_diff(eff_intf, act_intf)
+
+ if conf.exists('vif-s'):
+ for vif_s in conf.list_nodes('vif-s'):
+ # set config level to vif-s interface
+ conf.set_level(cfg_base + ' vif-s ' + vif_s)
+ eth['vif_s'].append(vlan_to_dict(conf))
+
+ # re-set configuration level and retrieve vif-s interfaces
+ conf.set_level(cfg_base)
+ # Determine vif interfaces (currently effective) - to determine which
+ # vif interface is no longer present and needs to be removed
+ eff_intf = conf.list_effective_nodes('vif')
+ act_intf = conf.list_nodes('vif')
+ eth['vif_remove'] = list_diff(eff_intf, act_intf)
+
+ if conf.exists('vif'):
+ for vif in conf.list_nodes('vif'):
+ # set config level to vif interface
+ conf.set_level(cfg_base + ' vif ' + vif)
+ eth['vif'].append(vlan_to_dict(conf))
+
+ return eth
+
+
+def verify(eth):
+ conf = Config()
+ # some options can not be changed when interface is enslaved to a bond
+ for bond in conf.list_nodes('interfaces bonding'):
+ if conf.exists('interfaces bonding ' + bond + ' member interface'):
+ if eth['name'] in conf.return_values('interfaces bonding ' + bond + ' member interface'):
+ if eth['disable']:
+ raise ConfigError('Can not disable interface {} which is a member of {}').format(eth['intf'], bond)
+
+ if eth['address']:
+ raise ConfigError('Can not assign address to interface {} which is a member of {}').format(eth['intf'], bond)
+
+
+ return None
+
+
+def generate(eth):
+ import pprint
+ pprint.pprint(eth)
+ return None
+
+
+def apply(eth):
+ e = EthernetIf(eth['intf'])
+ # update interface description used e.g. within SNMP
+ e.ifalias = eth['description']
+
+ #
+ # missing DHCP/DHCPv6 options go here
+ #
+
+ # ignore link state changes
+ e.link_detect = eth['disable_link_detect']
+ # configure ARP cache timeout in milliseconds
+ e.arp_cache_tmp = eth['ip_arp_cache_tmo']
+ # Enable proxy-arp on this interface
+ e.proxy_arp = eth['ip_proxy_arp']
+ # Enable private VLAN proxy ARP on this interface
+ e.proxy_arp_pvlan = eth['ip_proxy_arp_pvlan']
+
+ # Change interface MAC address
+ if eth['mac']:
+ e.mac = eth['mac']
+
+ # Maximum Transmission Unit (MTU)
+ e.mtu = eth['mtu']
+
+ # Configure interface address(es)
+ # - not longer required addresses get removed first
+ # - newly addresses will be added second
+ for addr in eth['address_remove']:
+ e.del_addr(addr)
+ for addr in eth['address']:
+ e.add_addr(addr)
+
+ # Enable/Disable interface
+ if eth['disable']:
+ e.state = 'down'
+ else:
+ e.state = 'up'
+
+ # remove no longer required service VLAN interfaces (vif-s)
+ for vif_s in eth['vif_s_remove']:
+ e.del_vlan(vif_s)
+
+ # create service VLAN interfaces (vif-s)
+ for vif_s in eth['vif_s']:
+ s_vlan = e.add_vlan(vif_s['id'], ethertype=vif_s['ethertype'])
+ apply_vlan_config(s_vlan, vif_s)
+
+ # remove no longer required client VLAN interfaces (vif-c)
+ # on lower service VLAN interface
+ for vif_c in vif_s['vif_c_remove']:
+ s_vlan.del_vlan(vif_c)
+
+ # create client VLAN interfaces (vif-c)
+ # on lower service VLAN interface
+ for vif_c in vif_s['vif_c']:
+ c_vlan = s_vlan.add_vlan(vif_c['id'])
+ apply_vlan_config(c_vlan, vif_c)
+
+ # remove no longer required VLAN interfaces (vif)
+ for vif in eth['vif_remove']:
+ e.del_vlan(vif)
+
+ # create VLAN interfaces (vif)
+ for vif in eth['vif']:
+ vlan = e.add_vlan(vif['id'])
+ apply_vlan_config(vlan, vif)
+
+ return None
+
+if __name__ == '__main__':
+ try:
+ c = get_config()
+ verify(c)
+ generate(c)
+ apply(c)
+ except ConfigError as e:
+ print(e)
+ exit(1)