Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F119063618
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
135 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/interface-definitions/include/interface-disable-forwarding.xml.i b/interface-definitions/include/interface-disable-forwarding.xml.i
new file mode 100644
index 000000000..7cbb726ec
--- /dev/null
+++ b/interface-definitions/include/interface-disable-forwarding.xml.i
@@ -0,0 +1,8 @@
+<!-- included start from interface-disable-forwarding.xml.i -->
+<leafNode name="disable-forwarding">
+ <properties>
+ <help>Disable IPv4 forwarding on this interface</help>
+ <valueless/>
+ </properties>
+</leafNode>
+<!-- included end -->
diff --git a/interface-definitions/include/interface-ipv4.xml.i b/interface-definitions/include/interface-ipv4.xml.i
index 551059247..66842ab9b 100644
--- a/interface-definitions/include/interface-ipv4.xml.i
+++ b/interface-definitions/include/interface-ipv4.xml.i
@@ -1,13 +1,14 @@
<!-- included start from interface-ipv4.xml.i -->
<node name="ip">
<properties>
<help>IPv4 routing parameters</help>
</properties>
<children>
#include <include/interface-disable-arp-filter.xml.i>
+ #include <include/interface-disable-forwarding.xml.i>
#include <include/interface-enable-arp-accept.xml.i>
#include <include/interface-enable-arp-announce.xml.i>
#include <include/interface-enable-arp-ignore.xml.i>
</children>
</node>
<!-- included end -->
diff --git a/interface-definitions/include/vif.xml.i b/interface-definitions/include/vif.xml.i
index 15c453fcc..a0f7c0bc8 100644
--- a/interface-definitions/include/vif.xml.i
+++ b/interface-definitions/include/vif.xml.i
@@ -1,68 +1,69 @@
<!-- included start from vif.xml.i -->
<tagNode name="vif">
<properties>
<help>Virtual Local Area Network (VLAN) ID</help>
<valueHelp>
<format>0-4094</format>
<description>Virtual Local Area Network (VLAN) ID</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-4094"/>
</constraint>
<constraintErrorMessage>VLAN ID must be between 0 and 4094</constraintErrorMessage>
</properties>
<children>
#include <include/address-ipv4-ipv6-dhcp.xml.i>
#include <include/interface-description.xml.i>
#include <include/dhcp-options.xml.i>
#include <include/dhcpv6-options.xml.i>
#include <include/interface-disable-link-detect.xml.i>
#include <include/interface-disable.xml.i>
#include <include/interface-vrf.xml.i>
<leafNode name="egress-qos">
<properties>
<help>VLAN egress QoS</help>
<completionHelp>
<script>echo Format for qos mapping, e.g.: '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>
#include <include/interface-arp-cache-timeout.xml.i>
#include <include/interface-disable-arp-filter.xml.i>
+ #include <include/interface-disable-forwarding.xml.i>
#include <include/interface-enable-arp-accept.xml.i>
#include <include/interface-enable-arp-announce.xml.i>
#include <include/interface-enable-arp-ignore.xml.i>
#include <include/interface-enable-proxy-arp.xml.i>
#include <include/interface-proxy-arp-pvlan.xml.i>
</children>
</node>
<node name="ipv6">
<children>
#include <include/ipv6-address.xml.i>
#include <include/ipv6-disable-forwarding.xml.i>
#include <include/ipv6-dup-addr-detect-transmits.xml.i>
</children>
</node>
#include <include/interface-mac.xml.i>
#include <include/interface-mtu-68-9000.xml.i>
</children>
</tagNode>
<!-- included end -->
diff --git a/interface-definitions/interfaces-bonding.xml.in b/interface-definitions/interfaces-bonding.xml.in
index b28be387b..4e2c61d07 100644
--- a/interface-definitions/interfaces-bonding.xml.in
+++ b/interface-definitions/interfaces-bonding.xml.in
@@ -1,187 +1,188 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="interfaces">
<children>
<tagNode name="bonding" owner="${vyos_conf_scripts_dir}/interfaces-bonding.py">
<properties>
<help>Bonding Interface/Link Aggregation</help>
<priority>320</priority>
<constraint>
<regex>^bond[0-9]+$</regex>
</constraint>
<constraintErrorMessage>Bonding interface must be named bondN</constraintErrorMessage>
<valueHelp>
<format>bondN</format>
<description>Bonding interface name</description>
</valueHelp>
</properties>
<children>
#include <include/address-ipv4-ipv6-dhcp.xml.i>
<node name="arp-monitor">
<properties>
<help>ARP link monitoring parameters</help>
</properties>
<children>
<leafNode name="interval">
<properties>
<help>ARP link monitoring interval</help>
<valueHelp>
<format>0-4294967295</format>
<description>Specifies the ARP link monitoring frequency in milliseconds</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-4294967295"/>
</constraint>
</properties>
</leafNode>
<leafNode name="target">
<properties>
<help>IP address used for ARP monitoring</help>
<valueHelp>
<format>ipv4</format>
<description>Specify IPv4 address of ARP requests when interval is enabled</description>
</valueHelp>
<constraint>
<validator name="ipv4-address"/>
</constraint>
<multi/>
</properties>
</leafNode>
</children>
</node>
#include <include/interface-description.xml.i>
#include <include/dhcp-options.xml.i>
#include <include/dhcpv6-options.xml.i>
#include <include/interface-disable-link-detect.xml.i>
#include <include/interface-disable.xml.i>
#include <include/interface-vrf.xml.i>
<leafNode name="hash-policy">
<properties>
<help>Bonding transmit hash policy</help>
<completionHelp>
<list>layer2 layer2+3 layer3+4</list>
</completionHelp>
<valueHelp>
<format>layer2</format>
<description>use MAC addresses to generate the hash (802.3ad, default)</description>
</valueHelp>
<valueHelp>
<format>layer2+3</format>
<description>combine MAC address and IP address to make hash</description>
</valueHelp>
<valueHelp>
<format>layer3+4</format>
<description>combine IP address and port to make hash</description>
</valueHelp>
<constraint>
<regex>(layer2\+3|layer3\+4|layer2)</regex>
</constraint>
<constraintErrorMessage>hash-policy must be layer2 layer2+3 or layer3+4</constraintErrorMessage>
</properties>
<defaultValue>layer2</defaultValue>
</leafNode>
<node name="ip">
<children>
#include <include/interface-arp-cache-timeout.xml.i>
#include <include/interface-disable-arp-filter.xml.i>
+ #include <include/interface-disable-forwarding.xml.i>
#include <include/interface-enable-arp-accept.xml.i>
#include <include/interface-enable-arp-announce.xml.i>
#include <include/interface-enable-arp-ignore.xml.i>
#include <include/interface-enable-proxy-arp.xml.i>
#include <include/interface-proxy-arp-pvlan.xml.i>
</children>
</node>
<node name="ipv6">
<children>
#include <include/ipv6-address.xml.i>
#include <include/ipv6-disable-forwarding.xml.i>
#include <include/ipv6-dup-addr-detect-transmits.xml.i>
</children>
</node>
#include <include/interface-mac.xml.i>
<leafNode name="min-links">
<properties>
<help>Minimum number of member interfaces required up before enabling bond</help>
<valueHelp>
<format><0-16></format>
<description>Minimum number of member interfaces required up before enabling bond</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-16"/>
</constraint>
</properties>
<defaultValue>0</defaultValue>
</leafNode>
<leafNode name="mode">
<properties>
<help>Bonding mode</help>
<completionHelp>
<list>802.3ad active-backup broadcast round-robin transmit-load-balance adaptive-load-balance xor-hash</list>
</completionHelp>
<valueHelp>
<format>802.3ad</format>
<description>IEEE 802.3ad Dynamic link aggregation (Default)</description>
</valueHelp>
<valueHelp>
<format>active-backup</format>
<description>Fault tolerant: only one slave in the bond is active</description>
</valueHelp>
<valueHelp>
<format>broadcast</format>
<description>Fault tolerant: transmits everything on all slave interfaces</description>
</valueHelp>
<valueHelp>
<format>round-robin</format>
<description>Load balance: transmit packets in sequential order</description>
</valueHelp>
<valueHelp>
<format>transmit-load-balance</format>
<description>Load balance: adapts based on transmit load and speed</description>
</valueHelp>
<valueHelp>
<format>adaptive-load-balance</format>
<description>Load balance: adapts based on transmit and receive plus ARP</description>
</valueHelp>
<valueHelp>
<format>xor-hash</format>
<description>Distribute based on MAC address</description>
</valueHelp>
<constraint>
<regex>(802.3ad|active-backup|broadcast|round-robin|transmit-load-balance|adaptive-load-balance|xor-hash)</regex>
</constraint>
<constraintErrorMessage>mode must be 802.3ad, active-backup, broadcast, round-robin, transmit-load-balance, adaptive-load-balance, or xor</constraintErrorMessage>
</properties>
<defaultValue>802.3ad</defaultValue>
</leafNode>
<node name="member">
<properties>
<help>Bridge member interfaces</help>
</properties>
<children>
<leafNode name="interface">
<properties>
<help>Member interface name</help>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces.py --bondable</script>
</completionHelp>
<multi/>
</properties>
</leafNode>
</children>
</node>
#include <include/interface-mtu-68-9000.xml.i>
<leafNode name="primary">
<properties>
<help>Primary device interface</help>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces.py --bondable</script>
</completionHelp>
</properties>
</leafNode>
#include <include/vif-s.xml.i>
#include <include/vif.xml.i>
</children>
</tagNode>
</children>
</node>
</interfaceDefinition>
diff --git a/interface-definitions/interfaces-bridge.xml.in b/interface-definitions/interfaces-bridge.xml.in
index 92356d696..787e856d7 100644
--- a/interface-definitions/interfaces-bridge.xml.in
+++ b/interface-definitions/interfaces-bridge.xml.in
@@ -1,184 +1,185 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="interfaces">
<children>
<tagNode name="bridge" owner="${vyos_conf_scripts_dir}/interfaces-bridge.py">
<properties>
<help>Bridge Interface</help>
<priority>489</priority>
<constraint>
<regex>^br[0-9]+$</regex>
</constraint>
<constraintErrorMessage>Bridge interface must be named brN</constraintErrorMessage>
<valueHelp>
<format>brN</format>
<description>Bridge interface name</description>
</valueHelp>
</properties>
<children>
#include <include/address-ipv4-ipv6-dhcp.xml.i>
<leafNode name="aging">
<properties>
<help>MAC address aging interval</help>
<valueHelp>
<format>0</format>
<description>Disable MAC address learning (always flood)</description>
</valueHelp>
<valueHelp>
<format>10-1000000</format>
<description>MAC address aging time in seconds (default: 300)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-0 --range 10-1000000"/>
</constraint>
</properties>
<defaultValue>300</defaultValue>
</leafNode>
#include <include/interface-description.xml.i>
#include <include/dhcp-options.xml.i>
#include <include/dhcpv6-options.xml.i>
#include <include/interface-disable-link-detect.xml.i>
#include <include/interface-disable.xml.i>
#include <include/interface-vrf.xml.i>
<leafNode name="forwarding-delay">
<properties>
<help>Forwarding delay</help>
<valueHelp>
<format>0-200</format>
<description>Spanning Tree Protocol forwarding delay in seconds (default 15)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-200"/>
</constraint>
<constraintErrorMessage>Forwarding delay must be between 0 and 200 seconds</constraintErrorMessage>
</properties>
<defaultValue>14</defaultValue>
</leafNode>
<leafNode name="hello-time">
<properties>
<help>Hello packet advertisment interval</help>
<valueHelp>
<format>1-10</format>
<description>Spanning Tree Protocol hello advertisement interval in seconds (default 2)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-10"/>
</constraint>
<constraintErrorMessage>Bridge Hello interval must be between 1 and 10 seconds</constraintErrorMessage>
</properties>
<defaultValue>2</defaultValue>
</leafNode>
<node name="igmp">
<properties>
<help>Internet Group Management Protocol (IGMP) settings</help>
</properties>
<children>
<leafNode name="querier">
<properties>
<help>Enable IGMP querier</help>
<valueless/>
</properties>
</leafNode>
</children>
</node>
<node name="ip">
<children>
#include <include/interface-arp-cache-timeout.xml.i>
#include <include/interface-enable-arp-accept.xml.i>
+ #include <include/interface-disable-forwarding.xml.i>
#include <include/interface-enable-arp-announce.xml.i>
#include <include/interface-enable-arp-ignore.xml.i>
#include <include/interface-disable-arp-filter.xml.i>
</children>
</node>
<node name="ipv6">
<children>
#include <include/ipv6-address.xml.i>
#include <include/ipv6-disable-forwarding.xml.i>
#include <include/ipv6-dup-addr-detect-transmits.xml.i>
</children>
</node>
#include <include/interface-mac.xml.i>
<leafNode name="max-age">
<properties>
<help>Interval at which neighbor bridges are removed</help>
<valueHelp>
<format>1-40</format>
<description>Bridge maximum aging time in seconds (default 20)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-40"/>
</constraint>
<constraintErrorMessage>Bridge max aging value must be between 1 and 40 seconds</constraintErrorMessage>
</properties>
<defaultValue>20</defaultValue>
</leafNode>
<node name="member">
<properties>
<help>Bridge member interfaces</help>
</properties>
<children>
<tagNode name="interface">
<properties>
<help>Member interface name</help>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces.py --bridgeable</script>
</completionHelp>
</properties>
<children>
<leafNode name="cost">
<properties>
<help>Bridge port cost</help>
<valueHelp>
<format>1-65535</format>
<description>Path cost value for Spanning Tree Protocol</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-65535"/>
</constraint>
<constraintErrorMessage>Path cost value must be between 1 and 65535</constraintErrorMessage>
</properties>
<defaultValue>100</defaultValue>
</leafNode>
<leafNode name="priority">
<properties>
<help>Bridge port priority</help>
<valueHelp>
<format>0-63</format>
<description>Bridge port priority</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-63"/>
</constraint>
<constraintErrorMessage>Port priority value must be between 0 and 63</constraintErrorMessage>
</properties>
<defaultValue>32</defaultValue>
</leafNode>
</children>
</tagNode>
</children>
</node>
<leafNode name="priority">
<properties>
<help>Priority for this bridge</help>
<valueHelp>
<format>0-65535</format>
<description>Bridge priority (default 32768)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-65535"/>
</constraint>
<constraintErrorMessage>Bridge priority must be between 0 and 65535 (multiples of 4096)</constraintErrorMessage>
</properties>
<defaultValue>32768</defaultValue>
</leafNode>
<leafNode name="stp">
<properties>
<help>Enable spanning tree protocol</help>
<valueless/>
</properties>
</leafNode>
</children>
</tagNode>
</children>
</node>
</interfaceDefinition>
diff --git a/interface-definitions/interfaces-ethernet.xml.in b/interface-definitions/interfaces-ethernet.xml.in
index 0aef0d332..a19a766d3 100644
--- a/interface-definitions/interfaces-ethernet.xml.in
+++ b/interface-definitions/interfaces-ethernet.xml.in
@@ -1,308 +1,309 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="interfaces">
<children>
<tagNode name="ethernet" owner="${vyos_conf_scripts_dir}/interfaces-ethernet.py">
<properties>
<help>Ethernet Interface</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>
#include <include/address-ipv4-ipv6-dhcp.xml.i>
#include <include/interface-description.xml.i>
#include <include/dhcp-options.xml.i>
#include <include/dhcpv6-options.xml.i>
<leafNode name="disable-flow-control">
<properties>
<help>Disable Ethernet flow control (pause frames)</help>
<valueless/>
</properties>
</leafNode>
#include <include/interface-disable-link-detect.xml.i>
#include <include/interface-disable.xml.i>
#include <include/interface-vrf.xml.i>
<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>
<defaultValue>auto</defaultValue>
</leafNode>
#include <include/interface-hw-id.xml.i>
<node name="ip">
<children>
#include <include/interface-arp-cache-timeout.xml.i>
#include <include/interface-disable-arp-filter.xml.i>
+ #include <include/interface-disable-forwarding.xml.i>
#include <include/interface-enable-arp-accept.xml.i>
#include <include/interface-enable-arp-announce.xml.i>
#include <include/interface-enable-arp-ignore.xml.i>
#include <include/interface-enable-proxy-arp.xml.i>
#include <include/interface-proxy-arp-pvlan.xml.i>
</children>
</node>
<node name="ipv6">
<children>
#include <include/ipv6-address.xml.i>
#include <include/ipv6-disable-forwarding.xml.i>
#include <include/ipv6-dup-addr-detect-transmits.xml.i>
</children>
</node>
#include <include/interface-mac.xml.i>
#include <include/interface-mtu-68-9000.xml.i>
<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 25000 40000 50000 100000</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>
<valueHelp>
<format>25000</format>
<description>25 Gbit/sec</description>
</valueHelp>
<valueHelp>
<format>40000</format>
<description>40 Gbit/sec</description>
</valueHelp>
<valueHelp>
<format>50000</format>
<description>50 Gbit/sec</description>
</valueHelp>
<valueHelp>
<format>100000</format>
<description>100 Gbit/sec</description>
</valueHelp>
<constraint>
<regex>(auto|10|100|1000|2500|5000|10000|25000|40000|50000|100000)</regex>
</constraint>
<constraintErrorMessage>Speed must be auto, 10, 100, 1000, 2500, 5000, 10000, 25000, 40000, 50000 or 100000</constraintErrorMessage>
</properties>
<defaultValue>auto</defaultValue>
</leafNode>
<node name="ring-buffer">
<properties>
<help>Shared buffer between the device driver and NIC</help>
</properties>
<children>
<leafNode name="rx">
<properties>
<help>RX ring buffer</help>
<valueHelp>
<format>80-16384</format>
<description>ring buffer size</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 80-16384"/>
</constraint>
</properties>
</leafNode>
<leafNode name="tx">
<properties>
<help>TX ring buffer</help>
<valueHelp>
<format>80-16384</format>
<description>ring buffer size</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 80-16384"/>
</constraint>
</properties>
</leafNode>
</children>
</node>
#include <include/vif-s.xml.i>
#include <include/vif.xml.i>
</children>
</tagNode>
</children>
</node>
</interfaceDefinition>
diff --git a/interface-definitions/interfaces-pseudo-ethernet.xml.in b/interface-definitions/interfaces-pseudo-ethernet.xml.in
index 4382db598..3fceb70b6 100644
--- a/interface-definitions/interfaces-pseudo-ethernet.xml.in
+++ b/interface-definitions/interfaces-pseudo-ethernet.xml.in
@@ -1,82 +1,83 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="interfaces">
<children>
<tagNode name="pseudo-ethernet" owner="${vyos_conf_scripts_dir}/interfaces-pseudo-ethernet.py">
<properties>
<help>Pseudo Ethernet</help>
<priority>321</priority>
<constraint>
<regex>^peth[0-9]+$</regex>
</constraint>
<constraintErrorMessage>Pseudo Ethernet interface must be named pethN</constraintErrorMessage>
<valueHelp>
<format>pethN</format>
<description>Pseudo Ethernet interface name</description>
</valueHelp>
</properties>
<children>
#include <include/address-ipv4-ipv6-dhcp.xml.i>
#include <include/interface-description.xml.i>
#include <include/dhcp-options.xml.i>
#include <include/dhcpv6-options.xml.i>
#include <include/interface-disable-link-detect.xml.i>
#include <include/interface-disable.xml.i>
#include <include/interface-vrf.xml.i>
<node name="ip">
<children>
#include <include/interface-arp-cache-timeout.xml.i>
#include <include/interface-disable-arp-filter.xml.i>
+ #include <include/interface-disable-forwarding.xml.i>
#include <include/interface-enable-arp-accept.xml.i>
#include <include/interface-enable-arp-announce.xml.i>
#include <include/interface-enable-arp-ignore.xml.i>
#include <include/interface-enable-proxy-arp.xml.i>
#include <include/interface-proxy-arp-pvlan.xml.i>
</children>
</node>
<node name="ipv6">
<children>
#include <include/ipv6-address.xml.i>
#include <include/ipv6-disable-forwarding.xml.i>
#include <include/ipv6-dup-addr-detect-transmits.xml.i>
</children>
</node>
#include <include/source-interface-ethernet.xml.i>
#include <include/interface-mac.xml.i>
<leafNode name="mode">
<properties>
<help>Receive mode (default: private)</help>
<completionHelp>
<list>private vepa bridge passthru</list>
</completionHelp>
<valueHelp>
<format>private</format>
<description>No communication with other pseudo-devices</description>
</valueHelp>
<valueHelp>
<format>vepa</format>
<description>Virtual Ethernet Port Aggregator reflective relay</description>
</valueHelp>
<valueHelp>
<format>bridge</format>
<description>Simple bridge between pseudo-devices</description>
</valueHelp>
<valueHelp>
<format>passthru</format>
<description>Promicious mode passthrough of underlying device</description>
</valueHelp>
<constraint>
<regex>(private|vepa|bridge|passthru)</regex>
</constraint>
<constraintErrorMessage>mode must be private, vepa, bridge or passthru</constraintErrorMessage>
</properties>
<defaultValue>private</defaultValue>
</leafNode>
#include <include/interface-mtu-68-9000.xml.i>
#include <include/vif-s.xml.i>
#include <include/vif.xml.i>
</children>
</tagNode>
</children>
</node>
</interfaceDefinition>
diff --git a/interface-definitions/interfaces-vxlan.xml.in b/interface-definitions/interfaces-vxlan.xml.in
index 67001174f..7fdead16a 100644
--- a/interface-definitions/interfaces-vxlan.xml.in
+++ b/interface-definitions/interfaces-vxlan.xml.in
@@ -1,115 +1,116 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="interfaces">
<children>
<tagNode name="vxlan" owner="${vyos_conf_scripts_dir}/interfaces-vxlan.py">
<properties>
<help>Virtual Extensible LAN (VXLAN) Interface</help>
<priority>460</priority>
<constraint>
<regex>^vxlan[0-9]+$</regex>
</constraint>
<constraintErrorMessage>VXLAN interface must be named vxlanN</constraintErrorMessage>
<valueHelp>
<format>vxlanN</format>
<description>VXLAN interface name</description>
</valueHelp>
</properties>
<children>
#include <include/address-ipv4-ipv6.xml.i>
#include <include/interface-description.xml.i>
#include <include/interface-disable.xml.i>
<leafNode name="group">
<properties>
<help>Multicast group address for VXLAN interface</help>
<valueHelp>
<format>ipv4</format>
<description>Multicast IPv4 group address</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>Multicast IPv6 group address</description>
</valueHelp>
<constraint>
<validator name="ip-address"/>
</constraint>
</properties>
</leafNode>
<node name="ip">
<children>
#include <include/interface-arp-cache-timeout.xml.i>
#include <include/interface-disable-arp-filter.xml.i>
+ #include <include/interface-disable-forwarding.xml.i>
#include <include/interface-enable-arp-accept.xml.i>
#include <include/interface-enable-arp-announce.xml.i>
#include <include/interface-enable-arp-ignore.xml.i>
#include <include/interface-enable-proxy-arp.xml.i>
</children>
</node>
<node name="ipv6">
<children>
#include <include/ipv6-address.xml.i>
#include <include/ipv6-disable-forwarding.xml.i>
#include <include/ipv6-dup-addr-detect-transmits.xml.i>
</children>
</node>
<leafNode name="source-address">
<properties>
<help>VXLAN source address</help>
<valueHelp>
<format>ipv4</format>
<description>IPv4 source-address of VXLAN tunnel</description>
</valueHelp>
<constraint>
<validator name="ipv4-address"/>
</constraint>
</properties>
</leafNode>
#include <include/source-interface.xml.i>
#include <include/interface-mac.xml.i>
#include <include/interface-mtu-1200-9000.xml.i>
<leafNode name="remote">
<properties>
<help>Remote address of VXLAN tunnel</help>
<valueHelp>
<format>ipv4</format>
<description>Remote IPv4 address of VXLAN tunnel</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>Remote IPv6 address of VXLAN tunnel</description>
</valueHelp>
<constraint>
<validator name="ip-address"/>
</constraint>
</properties>
</leafNode>
<leafNode name="port">
<properties>
<help>Destination port of VXLAN tunnel (default: 8472)</help>
<valueHelp>
<format>1-65535</format>
<description>Numeric IP port</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-65535"/>
</constraint>
</properties>
<defaultValue>8472</defaultValue>
</leafNode>
<leafNode name="vni">
<properties>
<help>Virtual Network Identifier</help>
<valueHelp>
<format>0-16777214</format>
<description>VXLAN virtual network identifier</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-16777214"/>
</constraint>
</properties>
</leafNode>
</children>
</tagNode>
</children>
</node>
</interfaceDefinition>
diff --git a/interface-definitions/interfaces-wireless.xml.in b/interface-definitions/interfaces-wireless.xml.in
index 90d0675da..423ec7ba2 100644
--- a/interface-definitions/interfaces-wireless.xml.in
+++ b/interface-definitions/interfaces-wireless.xml.in
@@ -1,805 +1,806 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="interfaces">
<children>
<tagNode name="wireless" owner="${vyos_conf_scripts_dir}/interfaces-wireless.py">
<properties>
<help>Wireless (WiFi/WLAN) Network Interface</help>
<priority>400</priority>
<constraint>
<regex>^wlan[0-9]+$</regex>
</constraint>
<constraintErrorMessage>Wireless interface must be named wlanN</constraintErrorMessage>
<valueHelp>
<format>wlanN</format>
<description>Wireless (WiFi/WLAN) interface name</description>
</valueHelp>
</properties>
<children>
#include <include/address-ipv4-ipv6-dhcp.xml.i>
<node name="capabilities">
<properties>
<help>HT and VHT capabilities for your card</help>
</properties>
<children>
<node name="ht">
<properties>
<help>HT (High Throughput) settings</help>
</properties>
<children>
<leafNode name="40mhz-incapable">
<properties>
<help>40MHz intolerance, use 20MHz only!</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="auto-powersave">
<properties>
<help>Enable WMM-PS unscheduled automatic power aave delivery [U-APSD]</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="channel-set-width">
<properties>
<help>Supported channel set width</help>
<completionHelp>
<list>ht20 ht40+ ht40-</list>
</completionHelp>
<valueHelp>
<format>ht20</format>
<description>Supported channel set width both 20 MHz only</description>
</valueHelp>
<valueHelp>
<format>ht40+</format>
<description>Supported channel set width both 20 MHz and 40 MHz with secondary channel above primary channel</description>
</valueHelp>
<valueHelp>
<format>ht40-</format>
<description>Supported channel set width both 20 MHz and 40 MHz with secondary channel below primary channel</description>
</valueHelp>
<constraint>
<regex>(ht20|ht40\+|ht40-)</regex>
</constraint>
<multi/>
</properties>
</leafNode>
<leafNode name="delayed-block-ack">
<properties>
<help>Enable HT-delayed block ack</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="dsss-cck-40">
<properties>
<help>Enable DSSS_CCK-40</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="greenfield">
<properties>
<help>Enable HT-greenfield</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="ldpc">
<properties>
<help>Enable LDPC coding capability</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="lsig-protection">
<properties>
<help>Enable L-SIG TXOP protection capability</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="max-amsdu">
<properties>
<help>Set maximum A-MSDU length</help>
<completionHelp>
<list>3839 7935</list>
</completionHelp>
<valueHelp>
<format>3839</format>
<description>Set maximum A-MSDU length to 3839 octets</description>
</valueHelp>
<valueHelp>
<format>7935</format>
<description>Set maximum A-MSDU length to 7935 octets</description>
</valueHelp>
<constraint>
<regex>(3839|7935)</regex>
</constraint>
</properties>
</leafNode>
<leafNode name="short-gi">
<properties>
<help>Short GI capabilities</help>
<completionHelp>
<list>20 40</list>
</completionHelp>
<valueHelp>
<format>20</format>
<description>Short GI for 20 MHz</description>
</valueHelp>
<valueHelp>
<format>40</format>
<description>Short GI for 40 MHz</description>
</valueHelp>
<constraint>
<regex>(20|40)</regex>
</constraint>
<multi/>
</properties>
</leafNode>
<leafNode name="smps">
<properties>
<help>Spatial Multiplexing Power Save (SMPS) settings</help>
<completionHelp>
<list>static dynamic</list>
</completionHelp>
<valueHelp>
<format>static</format>
<description>STATIC Spatial Multiplexing (SM) Power Save</description>
</valueHelp>
<valueHelp>
<format>dynamic</format>
<description>DYNAMIC Spatial Multiplexing (SM) Power Save</description>
</valueHelp>
<constraint>
<regex>(static|dynamic)</regex>
</constraint>
</properties>
</leafNode>
<node name="stbc">
<properties>
<help>Support for sending and receiving PPDU using STBC (Space Time Block Coding)</help>
</properties>
<children>
<leafNode name="rx">
<properties>
<help>Enable receiving PPDU using STBC (Space Time Block Coding)</help>
<valueHelp>
<format>[1-3]+</format>
<description>Number of spacial streams that can use RX STBC</description>
</valueHelp>
<constraint>
<regex>[1-3]+</regex>
</constraint>
<constraintErrorMessage>Invalid capability item</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="tx">
<properties>
<help>Enable sending PPDU using STBC (Space Time Block Coding)</help>
<valueless/>
</properties>
</leafNode>
</children>
</node>
</children>
</node>
<leafNode name="require-ht">
<properties>
<help>Require stations to support HT PHY (reject association if they do not)</help>
<completionHelp>
<script>echo If you reject non-HT, you also disable 802.11g</script>
</completionHelp>
<valueless/>
</properties>
</leafNode>
<leafNode name="require-vht">
<properties>
<help>Require stations to support VHT PHY (reject association if they do not)</help>
<completionHelp>
<script>echo If you reject non-VHT, you also disable 802.11n</script>
</completionHelp>
<valueless/>
</properties>
</leafNode>
<node name="vht">
<properties>
<help>VHT (Very High Throughput) settings</help>
</properties>
<children>
<leafNode name="antenna-count">
<properties>
<help>Number of antennas on this card</help>
<valueHelp>
<format>1-8</format>
<description>Number of antennas for this card</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-8"/>
</constraint>
</properties>
</leafNode>
<leafNode name="antenna-pattern-fixed">
<properties>
<help>Set if antenna pattern does not change during the lifetime of an association</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="beamform">
<properties>
<help>Beamforming capabilities</help>
<completionHelp>
<list>single-user-beamformer single-user-beamformee multi-user-beamformer multi-user-beamformee</list>
</completionHelp>
<valueHelp>
<format>single-user-beamformer</format>
<description>Support for operation as single user beamformer</description>
</valueHelp>
<valueHelp>
<format>single-user-beamformee</format>
<description>Support for operation as single user beamformee</description>
</valueHelp>
<valueHelp>
<format>multi-user-beamformer</format>
<description>Support for operation as multi user beamformer</description>
</valueHelp>
<valueHelp>
<format>multi-user-beamformee</format>
<description>Support for operation as multi user beamformee</description>
</valueHelp>
<constraint>
<regex>(single-user-beamformer|single-user-beamformee|multi-user-beamformer|multi-user-beamformee)</regex>
</constraint>
<multi/>
</properties>
</leafNode>
<node name="center-channel-freq">
<properties>
<help>VHT operating channel center frequency</help>
</properties>
<children>
<leafNode name="freq-1">
<properties>
<help>VHT operating channel center frequency - center freq 1 (for use with 80, 80+80 and 160 modes)</help>
<valueHelp>
<format><34-173></format>
<description>5Ghz (802.11 a/h/j/n/ac) center channel index (use 42 for primary 80MHz channel 36)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 34-173"/>
</constraint>
<constraintErrorMessage>Channel center value must be between 34 and 173</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="freq-2">
<properties>
<help>VHT operating channel center frequency - center freq 2 (for use with the 80+80 mode)</help>
<valueHelp>
<format>34-173</format>
<description>5Ghz (802.11 a/h/j/n/ac) center channel index (use 58 for primary 80MHz channel 52)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 34-173"/>
</constraint>
<constraintErrorMessage>Channel center value must be between 34 and 173</constraintErrorMessage>
</properties>
</leafNode>
</children>
</node>
<leafNode name="channel-set-width">
<properties>
<help>VHT operating Channel width</help>
<completionHelp>
<list>0 1 2 3</list>
</completionHelp>
<valueHelp>
<format>0</format>
<description>20 or 40 MHz channel width (default)</description>
</valueHelp>
<valueHelp>
<format>1</format>
<description>80 MHz channel width</description>
</valueHelp>
<valueHelp>
<format>2</format>
<description>160 MHz channel width</description>
</valueHelp>
<valueHelp>
<format>3</format>
<description>80+80 MHz channel width</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-3"/>
</constraint>
</properties>
</leafNode>
<leafNode name="ldpc">
<properties>
<help>Enable LDPC (Low Density Parity Check) coding capability</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="link-adaptation">
<properties>
<help>VHT link adaptation capabilities</help>
<completionHelp>
<list>unsolicited both</list>
</completionHelp>
<valueHelp>
<format>unsolicited</format>
<description>Station provides only unsolicited VHT MFB</description>
</valueHelp>
<valueHelp>
<format>both</format>
<description>Station can provide VHT MFB in response to VHT MRQ and unsolicited VHT MFB</description>
</valueHelp>
<constraint>
<regex>(unsolicited|both)</regex>
</constraint>
<constraintErrorMessage>Invalid capability item</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="max-mpdu-exp">
<properties>
<help>Set the maximum length of A-MPDU pre-EOF padding that the station can receive</help>
<valueHelp>
<format><0-7></format>
<description>Maximum length of A-MPDU pre-EOF padding = 2 pow(13 + x) -1 octets</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-7"/>
</constraint>
</properties>
</leafNode>
<leafNode name="max-mpdu">
<properties>
<help>Increase Maximum MPDU length to 7991 or 11454 octets (otherwise: 3895 octets)</help>
<completionHelp>
<list>7991 11454</list>
</completionHelp>
<valueHelp>
<format>7991</format>
<description>ncrease Maximum MPDU length to 7991 octets</description>
</valueHelp>
<valueHelp>
<format>11454</format>
<description>ncrease Maximum MPDU length to 11454 octets</description>
</valueHelp>
<constraint>
<regex>(7991|11454)</regex>
</constraint>
</properties>
</leafNode>
<leafNode name="short-gi">
<properties>
<help>Short GI capabilities</help>
<completionHelp>
<list>80 160</list>
</completionHelp>
<valueHelp>
<format>80</format>
<description>Short GI for 80 MHz</description>
</valueHelp>
<valueHelp>
<format>160</format>
<description>Short GI for 160 MHz</description>
</valueHelp>
<constraint>
<regex>(80|160)</regex>
</constraint>
<multi/>
</properties>
</leafNode>
<node name="stbc">
<properties>
<help>Support for sending and receiving PPDU using STBC (Space Time Block Coding)</help>
</properties>
<children>
<leafNode name="rx">
<properties>
<help>Enable receiving PPDU using STBC (Space Time Block Coding)</help>
<valueHelp>
<format>[1-4]+</format>
<description>Number of spacial streams that can use RX STBC</description>
</valueHelp>
<constraint>
<regex>[1-4]+</regex>
</constraint>
<constraintErrorMessage>Invalid capability item</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="tx">
<properties>
<help>Enable sending PPDU using STBC (Space Time Block Coding)</help>
<valueless/>
</properties>
</leafNode>
</children>
</node>
<leafNode name="tx-powersave">
<properties>
<help>Enable VHT TXOP Power Save Mode</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="vht-cf">
<properties>
<help>Station supports receiving VHT variant HT Control field</help>
<valueless/>
</properties>
</leafNode>
</children>
</node>
</children>
</node>
<leafNode name="channel">
<properties>
<help>Wireless radio channel (use 0 for ACS auto channel selection)</help>
<valueHelp>
<format><1-14></format>
<description>2.4Ghz (802.11 b/g/n) Channel</description>
</valueHelp>
<valueHelp>
<format><0,34-173></format>
<description>5Ghz (802.11 a/h/j/n/ac) Channel</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-0 --range 1-14 --range 34-173"/>
</constraint>
</properties>
</leafNode>
#include <include/interface-description.xml.i>
#include <include/dhcp-options.xml.i>
#include <include/dhcpv6-options.xml.i>
<leafNode name="disable-broadcast-ssid">
<properties>
<help>Disable broadcast of SSID from access-point</help>
<valueless/>
</properties>
</leafNode>
#include <include/interface-disable-link-detect.xml.i>
#include <include/interface-disable.xml.i>
#include <include/interface-vrf.xml.i>
<leafNode name="expunge-failing-stations">
<properties>
<help>Disassociate stations based on excessive transmission failures</help>
<valueless/>
</properties>
</leafNode>
<node name="ip">
<children>
#include <include/interface-arp-cache-timeout.xml.i>
#include <include/interface-disable-arp-filter.xml.i>
+ #include <include/interface-disable-forwarding.xml.i>
#include <include/interface-enable-arp-accept.xml.i>
#include <include/interface-enable-arp-announce.xml.i>
#include <include/interface-enable-arp-ignore.xml.i>
#include <include/interface-enable-proxy-arp.xml.i>
#include <include/interface-proxy-arp-pvlan.xml.i>
</children>
</node>
<node name="ipv6">
<children>
#include <include/ipv6-address.xml.i>
#include <include/ipv6-disable-forwarding.xml.i>
#include <include/ipv6-dup-addr-detect-transmits.xml.i>
</children>
</node>
#include <include/interface-hw-id.xml.i>
<leafNode name="isolate-stations">
<properties>
<help>Isolate stations on the AP so they cannot see each other</help>
<valueless/>
</properties>
</leafNode>
#include <include/interface-mac.xml.i>
<leafNode name="max-stations">
<properties>
<help>Maximum number of wireless radio stations. Excess stations will be rejected upon authentication request.</help>
<valueHelp>
<format><1-2007></format>
<description>Number of allowed stations</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-2007"/>
</constraint>
<constraintErrorMessage>Number of stations must be between 1 and 2007</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="mgmt-frame-protection">
<properties>
<help>Management Frame Protection (MFP) according to IEEE 802.11w</help>
<completionHelp>
<list>disabled optional required</list>
</completionHelp>
<valueHelp>
<format>disabled</format>
<description>no MFP (hostapd default)</description>
</valueHelp>
<valueHelp>
<format>optional</format>
<description>MFP optional</description>
</valueHelp>
<valueHelp>
<format>required</format>
<description>MFP enforced</description>
</valueHelp>
<constraint>
<regex>(disabled|optional|required)</regex>
</constraint>
</properties>
</leafNode>
<leafNode name="mode">
<properties>
<help>Wireless radio mode</help>
<completionHelp>
<list>a b g n ac</list>
</completionHelp>
<valueHelp>
<format>a</format>
<description>802.11a - 54 Mbits/sec</description>
</valueHelp>
<valueHelp>
<format>b</format>
<description>802.11b - 11 Mbits/sec</description>
</valueHelp>
<valueHelp>
<format>g</format>
<description>802.11g - 54 Mbits/sec (default)</description>
</valueHelp>
<valueHelp>
<format>n</format>
<description>802.11n - 600 Mbits/sec</description>
</valueHelp>
<valueHelp>
<format>ac</format>
<description>802.11ac - 1300 Mbits/sec</description>
</valueHelp>
<constraint>
<regex>^(a|b|g|n|ac)$</regex>
</constraint>
</properties>
<defaultValue>g</defaultValue>
</leafNode>
<leafNode name="physical-device">
<properties>
<help>Wireless physical device</help>
<completionHelp>
<script>${vyos_completion_dir}/list_wireless_phys.sh</script>
</completionHelp>
<constraint>
<validator name="wireless-phy"/>
</constraint>
</properties>
</leafNode>
<leafNode name="reduce-transmit-power">
<properties>
<help>Transmission power reduction in dBm</help>
<valueHelp>
<format><0-255></format>
<description>TX power reduction in dBm</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-255"/>
</constraint>
<constraintErrorMessage>dBm value must be between 0 and 255</constraintErrorMessage>
</properties>
</leafNode>
<node name="security">
<properties>
<help>Wireless security settings</help>
</properties>
<children>
<node name="wep">
<properties>
<help>Wired Equivalent Privacy (WEP) parameters</help>
</properties>
<children>
<leafNode name="key">
<properties>
<help>WEP encryption key</help>
<valueHelp>
<format><hexdigits></format>
<description>Wired Equivalent Privacy key</description>
</valueHelp>
<constraint>
<regex>([a-fA-F0-9]{10}|[a-fA-F0-9]{26}|[a-fA-F0-9]{32})</regex>
</constraint>
<constraintErrorMessage>Invalid WEP key</constraintErrorMessage>
<multi/>
</properties>
</leafNode>
</children>
</node>
<node name="wpa">
<properties>
<help>Wifi Protected Access (WPA) parameters</help>
</properties>
<children>
<leafNode name="cipher">
<properties>
<help>Cipher suite for WPA unicast packets</help>
<completionHelp>
<list>GCMP-256 GCMP CCMP-256 CCMP TKIP</list>
</completionHelp>
<valueHelp>
<format>GCMP-256</format>
<description>AES in Galois/counter mode with 256-bit key</description>
</valueHelp>
<valueHelp>
<format>GCMP</format>
<description>AES in Galois/counter mode with 128-bit key</description>
</valueHelp>
<valueHelp>
<format>CCMP-256</format>
<description>AES in Counter mode with CBC-MAC with 256-bit key</description>
</valueHelp>
<valueHelp>
<format>CCMP</format>
<description>AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] (supported on all WPA2 APs)</description>
</valueHelp>
<valueHelp>
<format>TKIP</format>
<description>Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]</description>
</valueHelp>
<constraint>
<regex>^(GCMP-256|GCMP|CCMP-256|CCMP|TKIP)$</regex>
</constraint>
<constraintErrorMessage>Invalid cipher selection</constraintErrorMessage>
<multi/>
</properties>
</leafNode>
<leafNode name="group-cipher">
<properties>
<help>Cipher suite for WPA multicast and broadcast packets</help>
<completionHelp>
<list>GCMP-256 GCMP CCMP-256 CCMP TKIP</list>
</completionHelp>
<valueHelp>
<format>GCMP-256</format>
<description>AES in Galois/counter mode with 256-bit key</description>
</valueHelp>
<valueHelp>
<format>GCMP</format>
<description>AES in Galois/counter mode with 128-bit key</description>
</valueHelp>
<valueHelp>
<format>CCMP-256</format>
<description>AES in Counter mode with CBC-MAC with 256-bit key</description>
</valueHelp>
<valueHelp>
<format>CCMP</format>
<description>AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] (supported on all WPA2 APs)</description>
</valueHelp>
<valueHelp>
<format>TKIP</format>
<description>Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]</description>
</valueHelp>
<constraint>
<regex>^(GCMP-256|GCMP|CCMP-256|CCMP|TKIP)$</regex>
</constraint>
<constraintErrorMessage>Invalid group cipher selection</constraintErrorMessage>
<multi/>
</properties>
</leafNode>
<leafNode name="mode">
<properties>
<help>WPA mode</help>
<completionHelp>
<list>wpa wpa2 both</list>
</completionHelp>
<valueHelp>
<format>wpa</format>
<description>WPA (IEEE 802.11i/D3.0)</description>
</valueHelp>
<valueHelp>
<format>wpa2</format>
<description>WPA2 (full IEEE 802.11i/RSN)</description>
</valueHelp>
<valueHelp>
<format>both</format>
<description>Allow both WPA and WPA2</description>
</valueHelp>
<constraint>
<regex>^(wpa|wpa2|both)$</regex>
</constraint>
<constraintErrorMessage>Unknown WPA mode</constraintErrorMessage>
</properties>
<defaultValue>both</defaultValue>
</leafNode>
<leafNode name="passphrase">
<properties>
<help>WPA personal shared pass phrase. If you are
using special characters in the WPA passphrase then single
quotes are required.</help>
<valueHelp>
<format><text></format>
<description>Passphrase of at least 8 but not more than 63 printable characters</description>
</valueHelp>
<constraint>
<regex>.{8,63}$</regex>
</constraint>
<constraintErrorMessage>Invalid WPA pass phrase, must be 8 to 63 printable characters!</constraintErrorMessage>
</properties>
</leafNode>
#include <include/radius-server.xml.i>
<node name="radius">
<children>
<tagNode name="server">
<children>
<leafNode name="accounting">
<properties>
<help>Enable RADIUS server to receive accounting info</help>
<valueless/>
</properties>
</leafNode>
</children>
</tagNode>
</children>
</node>
</children>
</node>
</children>
</node>
<leafNode name="ssid">
<properties>
<help>Wireless access-point service set identifier (SSID)</help>
<constraint>
<regex>.{1,32}$</regex>
</constraint>
<constraintErrorMessage>Invalid SSID</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="type">
<properties>
<help>Wireless device type for this interface</help>
<completionHelp>
<list>access-point station monitor</list>
</completionHelp>
<valueHelp>
<format>access-point</format>
<description>Access-point forwards packets between other nodes</description>
</valueHelp>
<valueHelp>
<format>station</format>
<description>Connects to another access point</description>
</valueHelp>
<valueHelp>
<format>monitor</format>
<description>Passively monitor all packets on the frequency/channel</description>
</valueHelp>
<constraint>
<regex>^(access-point|station|monitor)$</regex>
</constraint>
<constraintErrorMessage>Type must be access-point, station or monitor</constraintErrorMessage>
</properties>
<defaultValue>monitor</defaultValue>
</leafNode>
#include <include/vif.xml.i>
#include <include/vif-s.xml.i>
<leafNode name="wds">
<properties>
<help>Enable WDS (Wireless Distribution System)</help>
<valueless/>
</properties>
</leafNode>
</children>
</tagNode>
</children>
</node>
<node name="system">
<children>
<leafNode name="wifi-regulatory-domain" owner="${vyos_conf_scripts_dir}/system-wifi-regdom.py">
<properties>
<help>Wireless regulatory domain (mandatory)</help>
<priority>305</priority>
<completionHelp>
<list>US EU JP DE UK CN</list>
</completionHelp>
<valueHelp>
<format><code%gt;</format>
<description>Country code (ISO/IEC 3166-1)</description>
</valueHelp>
<constraint>
<regex>[A-Z][A-Z]$</regex>
</constraint>
<constraintErrorMessage>invalid country code</constraintErrorMessage>
</properties>
</leafNode>
</children>
</node>
</interfaceDefinition>
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index d200fc7a8..47ec94bd3 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -1,1181 +1,1196 @@
# Copyright 2019-2020 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
import os
import re
import json
import jmespath
from copy import deepcopy
from glob import glob
from ipaddress import IPv4Network
from ipaddress import IPv6Address
from ipaddress import IPv6Network
from netifaces import ifaddresses
# this is not the same as socket.AF_INET/INET6
from netifaces import AF_INET
from netifaces import AF_INET6
from vyos import ConfigError
from vyos.configdict import list_diff
from vyos.configdict import dict_merge
from vyos.template import render
from vyos.util import mac2eui64
from vyos.util import vyos_dict_search
from vyos.validate import is_ipv4
from vyos.validate import is_ipv6
from vyos.validate import is_intf_addr_assigned
from vyos.validate import assert_boolean
from vyos.validate import assert_list
from vyos.validate import assert_mac
from vyos.validate import assert_mtu
from vyos.validate import assert_positive
from vyos.validate import assert_range
from vyos.ifconfig.control import Control
from vyos.ifconfig.vrrp import VRRP
from vyos.ifconfig.operational import Operational
from vyos.ifconfig import Section
class Interface(Control):
# This is the class which will be used to create
# self.operational, it allows subclasses, such as
# WireGuard to modify their display behaviour
OperationalClass = Operational
options = ['debug', 'create']
required = []
default = {
'type': '',
'debug': True,
'create': True,
}
definition = {
'section': '',
'prefixes': [],
'vlan': False,
'bondable': False,
'broadcast': False,
'bridgeable': False,
'eternal': '',
}
_command_get = {
'admin_state': {
'shellcmd': 'ip -json link show dev {ifname}',
'format': lambda j: 'up' if 'UP' in jmespath.search('[*].flags | [0]', json.loads(j)) else 'down',
},
'min_mtu': {
'shellcmd': 'ip -json -detail link list dev {ifname}',
'format': lambda j: jmespath.search('[*].min_mtu | [0]', json.loads(j)),
},
'max_mtu': {
'shellcmd': 'ip -json -detail link list dev {ifname}',
'format': lambda j: jmespath.search('[*].max_mtu | [0]', json.loads(j)),
},
}
_command_set = {
'admin_state': {
'validate': lambda v: assert_list(v, ['up', 'down']),
'shellcmd': 'ip link set dev {ifname} {value}',
},
'mac': {
'validate': assert_mac,
'shellcmd': 'ip link set dev {ifname} address {value}',
},
'vrf': {
'convert': lambda v: f'master {v}' if v else 'nomaster',
'shellcmd': 'ip link set dev {ifname} {value}',
},
}
_sysfs_get = {
'alias': {
'location': '/sys/class/net/{ifname}/ifalias',
},
'mac': {
'location': '/sys/class/net/{ifname}/address',
},
'mtu': {
'location': '/sys/class/net/{ifname}/mtu',
},
'oper_state':{
'location': '/sys/class/net/{ifname}/operstate',
},
}
_sysfs_set = {
'alias': {
'convert': lambda name: name if name else '\0',
'location': '/sys/class/net/{ifname}/ifalias',
},
'mtu': {
'validate': assert_mtu,
'location': '/sys/class/net/{ifname}/mtu',
},
'arp_cache_tmo': {
'convert': lambda tmo: (int(tmo) * 1000),
'location': '/proc/sys/net/ipv4/neigh/{ifname}/base_reachable_time_ms',
},
'arp_filter': {
'validate': assert_boolean,
'location': '/proc/sys/net/ipv4/conf/{ifname}/arp_filter',
},
'arp_accept': {
'validate': lambda arp: assert_range(arp,0,2),
'location': '/proc/sys/net/ipv4/conf/{ifname}/arp_accept',
},
'arp_announce': {
'validate': assert_boolean,
'location': '/proc/sys/net/ipv4/conf/{ifname}/arp_announce',
},
'arp_ignore': {
'validate': assert_boolean,
'location': '/proc/sys/net/ipv4/conf/{ifname}/arp_ignore',
},
+ 'ipv4_forwarding': {
+ 'validate': assert_boolean,
+ 'location': '/proc/sys/net/ipv4/conf/{ifname}/forwarding',
+ },
'ipv6_accept_ra': {
'validate': lambda ara: assert_range(ara,0,3),
'location': '/proc/sys/net/ipv6/conf/{ifname}/accept_ra',
},
'ipv6_autoconf': {
'validate': lambda aco: assert_range(aco,0,2),
'location': '/proc/sys/net/ipv6/conf/{ifname}/autoconf',
},
'ipv6_forwarding': {
'validate': lambda fwd: assert_range(fwd,0,2),
'location': '/proc/sys/net/ipv6/conf/{ifname}/forwarding',
},
'ipv6_dad_transmits': {
'validate': assert_positive,
'location': '/proc/sys/net/ipv6/conf/{ifname}/dad_transmits',
},
'proxy_arp': {
'validate': assert_boolean,
'location': '/proc/sys/net/ipv4/conf/{ifname}/proxy_arp',
},
'proxy_arp_pvlan': {
'validate': assert_boolean,
'location': '/proc/sys/net/ipv4/conf/{ifname}/proxy_arp_pvlan',
},
# link_detect vs link_filter name weirdness
'link_detect': {
'validate': lambda link: assert_range(link,0,3),
'location': '/proc/sys/net/ipv4/conf/{ifname}/link_filter',
},
}
@classmethod
def exists(cls, ifname):
return os.path.exists(f'/sys/class/net/{ifname}')
@classmethod
def get_config(cls):
"""
Some but not all interfaces require a configuration when they are added
using iproute2. This method will provide the configuration dictionary
used by this class.
"""
return deepcopy(cls.default)
def __init__(self, ifname, **kargs):
"""
This is the base interface class which supports basic IP/MAC address
operations as well as DHCP(v6). Other interface which represent e.g.
and ethernet bridge are implemented as derived classes adding all
additional functionality.
For creation you will need to provide the interface type, otherwise
the existing interface is used
DEBUG:
This class has embedded debugging (print) which can be enabled by
creating the following file:
vyos@vyos# touch /tmp/vyos.ifconfig.debug
Example:
>>> from vyos.ifconfig import Interface
>>> i = Interface('eth0')
"""
self.config = deepcopy(self.default)
for k in self.options:
if k in kargs:
self.config[k] = kargs[k]
# make sure the ifname is the first argument and not from the dict
self.config['ifname'] = ifname
self._admin_state_down_cnt = 0
# we must have updated config before initialising the Interface
super().__init__(**kargs)
self.ifname = ifname
if not self.exists(ifname):
# Any instance of Interface, such as Interface('eth0')
# can be used safely to access the generic function in this class
# as 'type' is unset, the class can not be created
if not self.config['type']:
raise Exception(f'interface "{ifname}" not found')
# Should an Instance of a child class (EthernetIf, DummyIf, ..)
# be required, then create should be set to False to not accidentally create it.
# In case a subclass does not define it, we use get to set the default to True
if self.config.get('create',True):
for k in self.required:
if k not in kargs:
name = self.default['type']
raise ConfigError(f'missing required option {k} for {name} {ifname} creation')
self._create()
# If we can not connect to the interface then let the caller know
# as the class could not be correctly initialised
else:
raise Exception('interface "{}" not found'.format(self.config['ifname']))
# temporary list of assigned IP addresses
self._addr = []
self.operational = self.OperationalClass(ifname)
self.vrrp = VRRP(ifname)
def _create(self):
cmd = 'ip link add dev {ifname} type {type}'.format(**self.config)
self._cmd(cmd)
def remove(self):
"""
Remove interface from operating system. Removing the interface
deconfigures all assigned IP addresses and clear possible DHCP(v6)
client processes.
Example:
>>> from vyos.ifconfig import Interface
>>> i = Interface('eth0')
>>> i.remove()
"""
# remove all assigned IP addresses from interface - this is a bit redundant
# as the kernel will remove all addresses on interface deletion, but we
# can not delete ALL interfaces, see below
self.flush_addrs()
# ---------------------------------------------------------------------
# Any class can define an eternal regex in its definition
# interface matching the regex will not be deleted
eternal = self.definition['eternal']
if not eternal:
self._delete()
elif not re.match(eternal, self.ifname):
self._delete()
def _delete(self):
# NOTE (Improvement):
# after interface removal no other commands should be allowed
# to be called and instead should raise an Exception:
cmd = 'ip link del dev {ifname}'.format(**self.config)
return self._cmd(cmd)
def get_min_mtu(self):
"""
Get hardware minimum supported MTU
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').get_min_mtu()
'60'
"""
return int(self.get_interface('min_mtu'))
def get_max_mtu(self):
"""
Get hardware maximum supported MTU
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').get_max_mtu()
'9000'
"""
return int(self.get_interface('max_mtu'))
def get_mtu(self):
"""
Get/set interface mtu in bytes.
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').get_mtu()
'1500'
"""
return int(self.get_interface('mtu'))
def set_mtu(self, mtu):
"""
Get/set interface mtu in bytes.
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').set_mtu(1400)
>>> Interface('eth0').get_mtu()
'1400'
"""
return self.set_interface('mtu', mtu)
def get_mac(self):
"""
Get current interface MAC (Media Access Contrl) address used.
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').get_mac()
'00:50:ab:cd:ef:00'
"""
return self.get_interface('mac')
def set_mac(self, mac):
"""
Set interface MAC (Media Access Contrl) address to given value.
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').set_mac('00:50:ab:cd:ef:01')
"""
# If MAC is unchanged, bail out early
if mac == self.get_mac():
return None
# MAC address can only be changed if interface is in 'down' state
prev_state = self.get_admin_state()
if prev_state == 'up':
self.set_admin_state('down')
self.set_interface('mac', mac)
# Turn an interface to the 'up' state if it was changed to 'down' by this fucntion
if prev_state == 'up':
self.set_admin_state('up')
def set_vrf(self, vrf=''):
"""
Add/Remove interface from given VRF instance.
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').set_vrf('foo')
>>> Interface('eth0').set_vrf()
"""
self.set_interface('vrf', vrf)
def set_arp_cache_tmo(self, tmo):
"""
Set ARP cache timeout value in seconds. Internal Kernel representation
is in milliseconds.
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').set_arp_cache_tmo(40)
"""
return self.set_interface('arp_cache_tmo', tmo)
def set_arp_filter(self, arp_filter):
"""
Filter ARP requests
1 - Allows you to have multiple network interfaces on the same
subnet, and have the ARPs for each interface be answered
based on whether or not the kernel would route a packet from
the ARP'd IP out that interface (therefore you must use source
based routing for this to work). In other words it allows control
of which cards (usually 1) will respond to an arp request.
0 - (default) The kernel can respond to arp requests with addresses
from other interfaces. This may seem wrong but it usually makes
sense, because it increases the chance of successful communication.
IP addresses are owned by the complete host on Linux, not by
particular interfaces. Only for more complex setups like load-
balancing, does this behaviour cause problems.
"""
return self.set_interface('arp_filter', arp_filter)
def set_arp_accept(self, arp_accept):
"""
Define behavior for gratuitous ARP frames who's IP is not
already present in the ARP table:
0 - don't create new entries in the ARP table
1 - create new entries in the ARP table
Both replies and requests type gratuitous arp will trigger the
ARP table to be updated, if this setting is on.
If the ARP table already contains the IP address of the
gratuitous arp frame, the arp table will be updated regardless
if this setting is on or off.
"""
return self.set_interface('arp_accept', arp_accept)
def set_arp_announce(self, arp_announce):
"""
Define different restriction levels for announcing the local
source IP address from IP packets in ARP requests sent on
interface:
0 - (default) Use any local address, configured on any interface
1 - Try to avoid local addresses that are not in the target's
subnet for this interface. This mode is useful when target
hosts reachable via this interface require the source IP
address in ARP requests to be part of their logical network
configured on the receiving interface. When we generate the
request we will check all our subnets that include the
target IP and will preserve the source address if it is from
such subnet.
Increasing the restriction level gives more chance for
receiving answer from the resolved target while decreasing
the level announces more valid sender's information.
"""
return self.set_interface('arp_announce', arp_announce)
def set_arp_ignore(self, arp_ignore):
"""
Define different modes for sending replies in response to received ARP
requests that resolve local target IP addresses:
0 - (default): reply for any local target IP address, configured
on any interface
1 - reply only if the target IP address is local address
configured on the incoming interface
"""
return self.set_interface('arp_ignore', arp_ignore)
+ def set_ipv4_forwarding(self, forwarding):
+ """
+ Configure IPv4 forwarding.
+ """
+ return self.set_interface('ipv4_forwarding', forwarding)
+
def set_ipv6_accept_ra(self, accept_ra):
"""
Accept Router Advertisements; autoconfigure using them.
It also determines whether or not to transmit Router Solicitations.
If and only if the functional setting is to accept Router
Advertisements, Router Solicitations will be transmitted.
0 - Do not accept Router Advertisements.
1 - (default) Accept Router Advertisements if forwarding is disabled.
2 - Overrule forwarding behaviour. Accept Router Advertisements even if
forwarding is enabled.
"""
return self.set_interface('ipv6_accept_ra', accept_ra)
def set_ipv6_autoconf(self, autoconf):
"""
Autoconfigure addresses using Prefix Information in Router
Advertisements.
"""
return self.set_interface('ipv6_autoconf', autoconf)
def add_ipv6_eui64_address(self, prefix):
"""
Extended Unique Identifier (EUI), as per RFC2373, allows a host to
assign itself a unique IPv6 address based on a given IPv6 prefix.
Calculate the EUI64 from the interface's MAC, then assign it
with the given prefix to the interface.
"""
# T2863: only add a link-local IPv6 address if the interface returns
# a MAC address. This is not the case on e.g. WireGuard interfaces.
mac = self.get_mac()
if mac:
eui64 = mac2eui64(mac, prefix)
prefixlen = prefix.split('/')[1]
self.add_addr(f'{eui64}/{prefixlen}')
def del_ipv6_eui64_address(self, prefix):
"""
Delete the address based on the interface's MAC-based EUI64
combined with the prefix address.
"""
eui64 = mac2eui64(self.get_mac(), prefix)
prefixlen = prefix.split('/')[1]
self.del_addr(f'{eui64}/{prefixlen}')
def set_ipv6_forwarding(self, forwarding):
"""
Configure IPv6 interface-specific Host/Router behaviour.
False:
By default, Host behaviour is assumed. This means:
1. IsRouter flag is not set in Neighbour Advertisements.
2. If accept_ra is TRUE (default), transmit Router
Solicitations.
3. If accept_ra is TRUE (default), accept Router
Advertisements (and do autoconfiguration).
4. If accept_redirects is TRUE (default), accept Redirects.
True:
If local forwarding is enabled, Router behaviour is assumed.
This means exactly the reverse from the above:
1. IsRouter flag is set in Neighbour Advertisements.
2. Router Solicitations are not sent unless accept_ra is 2.
3. Router Advertisements are ignored unless accept_ra is 2.
4. Redirects are ignored.
"""
return self.set_interface('ipv6_forwarding', forwarding)
def set_ipv6_dad_messages(self, dad):
"""
The amount of Duplicate Address Detection probes to send.
Default: 1
"""
return self.set_interface('ipv6_dad_transmits', dad)
def set_link_detect(self, link_filter):
"""
Configure kernel response in packets received on interfaces that are 'down'
0 - Allow packets to be received for the address on this interface
even if interface is disabled or no carrier.
1 - Ignore packets received if interface associated with the incoming
address is down.
2 - Ignore packets received if interface associated with the incoming
address is down or has no carrier.
Default value is 0. Note that some distributions enable it in startup
scripts.
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').set_link_detect(1)
"""
return self.set_interface('link_detect', link_filter)
def get_alias(self):
"""
Get interface alias name used by e.g. SNMP
Example:
>>> Interface('eth0').get_alias()
'interface description as set by user'
"""
return self.get_interface('alias')
def set_alias(self, ifalias=''):
"""
Set interface alias name used by e.g. SNMP
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').set_alias('VyOS upstream interface')
to clear alias e.g. delete it use:
>>> Interface('eth0').set_ifalias('')
"""
self.set_interface('alias', ifalias)
def get_admin_state(self):
"""
Get interface administrative state. Function will return 'up' or 'down'
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').get_admin_state()
'up'
"""
return self.get_interface('admin_state')
def set_admin_state(self, state):
"""
Set interface administrative state to be 'up' or 'down'
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').set_admin_state('down')
>>> Interface('eth0').get_admin_state()
'down'
"""
if state == 'up':
self._admin_state_down_cnt -= 1
if self._admin_state_down_cnt < 1:
return self.set_interface('admin_state', state)
else:
self._admin_state_down_cnt += 1
return self.set_interface('admin_state', state)
def set_proxy_arp(self, enable):
"""
Set per interface proxy ARP configuration
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').set_proxy_arp(1)
"""
self.set_interface('proxy_arp', enable)
def set_proxy_arp_pvlan(self, enable):
"""
Private VLAN proxy arp.
Basically allow proxy arp replies back to the same interface
(from which the ARP request/solicitation was received).
This is done to support (ethernet) switch features, like RFC
3069, where the individual ports are NOT allowed to
communicate with each other, but they are allowed to talk to
the upstream router. As described in RFC 3069, it is possible
to allow these hosts to communicate through the upstream
router by proxy_arp'ing. Don't need to be used together with
proxy_arp.
This technology is known by different names:
In RFC 3069 it is called VLAN Aggregation.
Cisco and Allied Telesyn call it Private VLAN.
Hewlett-Packard call it Source-Port filtering or port-isolation.
Ericsson call it MAC-Forced Forwarding (RFC Draft).
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').set_proxy_arp_pvlan(1)
"""
self.set_interface('proxy_arp_pvlan', enable)
def get_addr(self):
"""
Retrieve assigned IPv4 and IPv6 addresses from given interface.
This is done using the netifaces and ipaddress python modules.
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0').get_addrs()
['172.16.33.30/24', 'fe80::20c:29ff:fe11:a174/64']
"""
ipv4 = []
ipv6 = []
if AF_INET in ifaddresses(self.config['ifname']).keys():
for v4_addr in ifaddresses(self.config['ifname'])[AF_INET]:
# we need to manually assemble a list of IPv4 address/prefix
prefix = '/' + \
str(IPv4Network('0.0.0.0/' + v4_addr['netmask']).prefixlen)
ipv4.append(v4_addr['addr'] + prefix)
if AF_INET6 in ifaddresses(self.config['ifname']).keys():
for v6_addr in ifaddresses(self.config['ifname'])[AF_INET6]:
# Note that currently expanded netmasks are not supported. That means
# 2001:db00::0/24 is a valid argument while 2001:db00::0/ffff:ff00:: not.
# see https://docs.python.org/3/library/ipaddress.html
bits = bin(
int(v6_addr['netmask'].replace(':', ''), 16)).count('1')
prefix = '/' + str(bits)
# we alsoneed to remove the interface suffix on link local
# addresses
v6_addr['addr'] = v6_addr['addr'].split('%')[0]
ipv6.append(v6_addr['addr'] + prefix)
return ipv4 + ipv6
def add_addr(self, addr):
"""
Add IP(v6) address to interface. Address is only added if it is not
already assigned to that interface. Address format must be validated
and compressed/normalized before calling this function.
addr: can be an IPv4 address, IPv6 address, dhcp or dhcpv6!
IPv4: add IPv4 address to interface
IPv6: add IPv6 address to interface
dhcp: start dhclient (IPv4) on interface
dhcpv6: start WIDE DHCPv6 (IPv6) on interface
Returns False if address is already assigned and wasn't re-added.
Example:
>>> from vyos.ifconfig import Interface
>>> j = Interface('eth0')
>>> j.add_addr('192.0.2.1/24')
>>> j.add_addr('2001:db8::ffff/64')
>>> j.get_addr()
['192.0.2.1/24', '2001:db8::ffff/64']
"""
# XXX: normalize/compress with ipaddress if calling functions don't?
# is subnet mask always passed, and in the same way?
# do not add same address twice
if addr in self._addr:
return False
addr_is_v4 = is_ipv4(addr)
# we can't have both DHCP and static IPv4 addresses assigned
for a in self._addr:
if ( ( addr == 'dhcp' and a != 'dhcpv6' and is_ipv4(a) ) or
( a == 'dhcp' and addr != 'dhcpv6' and addr_is_v4 ) ):
raise ConfigError((
"Can't configure both static IPv4 and DHCP address "
"on the same interface"))
# add to interface
if addr == 'dhcp':
self.set_dhcp(True)
elif addr == 'dhcpv6':
self.set_dhcpv6(True)
elif not is_intf_addr_assigned(self.ifname, addr):
self._cmd(f'ip addr add "{addr}" '
f'{"brd + " if addr_is_v4 else ""}dev "{self.ifname}"')
else:
return False
# add to cache
self._addr.append(addr)
return True
def del_addr(self, addr):
"""
Delete IP(v6) address from interface. Address is only deleted if it is
assigned to that interface. Address format must be exactly the same as
was used when adding the address.
addr: can be an IPv4 address, IPv6 address, dhcp or dhcpv6!
IPv4: delete IPv4 address from interface
IPv6: delete IPv6 address from interface
dhcp: stop dhclient (IPv4) on interface
dhcpv6: stop dhclient (IPv6) on interface
Returns False if address isn't already assigned and wasn't deleted.
Example:
>>> from vyos.ifconfig import Interface
>>> j = Interface('eth0')
>>> j.add_addr('2001:db8::ffff/64')
>>> j.add_addr('192.0.2.1/24')
>>> j.get_addr()
['192.0.2.1/24', '2001:db8::ffff/64']
>>> j.del_addr('192.0.2.1/24')
>>> j.get_addr()
['2001:db8::ffff/64']
"""
# remove from interface
if addr == 'dhcp':
self.set_dhcp(False)
elif addr == 'dhcpv6':
self.set_dhcpv6(False)
elif is_intf_addr_assigned(self.ifname, addr):
self._cmd(f'ip addr del "{addr}" dev "{self.ifname}"')
else:
return False
# remove from cache
if addr in self._addr:
self._addr.remove(addr)
return True
def flush_addrs(self):
"""
Flush all addresses from an interface, including DHCP.
Will raise an exception on error.
"""
# stop DHCP(v6) if running
self.set_dhcp(False)
self.set_dhcpv6(False)
# flush all addresses
self._cmd(f'ip addr flush dev "{self.ifname}"')
def add_to_bridge(self, br):
"""
Adds the interface to the bridge with the passed port config.
Returns False if bridge doesn't exist.
"""
# check if the bridge exists (on boot it doesn't)
if br not in Section.interfaces('bridge'):
return False
self.flush_addrs()
# add interface to bridge - use Section.klass to get BridgeIf class
Section.klass(br)(br, create=False).add_port(self.ifname)
# TODO: port config (STP)
return True
def set_dhcp(self, enable):
"""
Enable/Disable DHCP client on a given interface.
"""
if enable not in [True, False]:
raise ValueError()
ifname = self.ifname
config_base = r'/var/lib/dhcp/dhclient'
config_file = f'{config_base}_{ifname}.conf'
options_file = f'{config_base}_{ifname}.options'
pid_file = f'{config_base}_{ifname}.pid'
lease_file = f'{config_base}_{ifname}.leases'
if enable and 'disable' not in self._config:
if vyos_dict_search('dhcp_options.host_name', self._config) == None:
# read configured system hostname.
# maybe change to vyos hostd client ???
hostname = 'vyos'
with open('/etc/hostname', 'r') as f:
hostname = f.read().rstrip('\n')
tmp = {'dhcp_options' : { 'host_name' : hostname}}
self._config = dict_merge(tmp, self._config)
render(options_file, 'dhcp-client/daemon-options.tmpl',
self._config, trim_blocks=True)
render(config_file, 'dhcp-client/ipv4.tmpl',
self._config, trim_blocks=True)
# 'up' check is mandatory b/c even if the interface is A/D, as soon as
# the DHCP client is started the interface will be placed in u/u state.
# This is not what we intended to do when disabling an interface.
return self._cmd(f'systemctl restart dhclient@{ifname}.service')
else:
self._cmd(f'systemctl stop dhclient@{ifname}.service')
# cleanup old config files
for file in [config_file, options_file, pid_file, lease_file]:
if os.path.isfile(file):
os.remove(file)
def set_dhcpv6(self, enable):
"""
Enable/Disable DHCPv6 client on a given interface.
"""
if enable not in [True, False]:
raise ValueError()
ifname = self.ifname
config_file = f'/run/dhcp6c/dhcp6c.{ifname}.conf'
if enable and 'disable' not in self._config:
render(config_file, 'dhcp-client/ipv6.tmpl',
self._config, trim_blocks=True)
# We must ignore any return codes. This is required to enable DHCPv6-PD
# for interfaces which are yet not up and running.
return self._popen(f'systemctl restart dhcp6c@{ifname}.service')
else:
self._popen(f'systemctl stop dhcp6c@{ifname}.service')
if os.path.isfile(config_file):
os.remove(config_file)
def update(self, config):
""" General helper function which works on a dictionary retrived by
get_config_dict(). It's main intention is to consolidate the scattered
interface setup code and provide a single point of entry when workin
on any interface. """
# Cache the configuration - it will be reused inside e.g. DHCP handler
# XXX: maybe pass the option via __init__ in the future and rename this
# method to apply()?
self._config = config
# Update interface description
self.set_alias(config.get('description', ''))
# Ignore link state changes
value = '2' if 'disable_link_detect' in config else '1'
self.set_link_detect(value)
# Configure assigned interface IP addresses. No longer
# configured addresses will be removed first
new_addr = config.get('address', [])
# always ensure DHCP client is stopped (when not configured explicitly)
if 'dhcp' not in new_addr:
self.del_addr('dhcp')
# always ensure DHCPv6 client is stopped (when not configured as client
# for IPv6 address or prefix delegation
dhcpv6pd = vyos_dict_search('dhcpv6_options.pd', config)
if 'dhcpv6' not in new_addr or dhcpv6pd == None:
self.del_addr('dhcpv6')
# determine IP addresses which are assigned to the interface and build a
# list of addresses which are no longer in the dict so they can be removed
cur_addr = self.get_addr()
for addr in list_diff(cur_addr, new_addr):
self.del_addr(addr)
for addr in new_addr:
self.add_addr(addr)
# start DHCPv6 client when only PD was configured
if dhcpv6pd != None:
self.set_dhcpv6(True)
# There are some items in the configuration which can only be applied
# if this instance is not bound to a bridge. This should be checked
# by the caller but better save then sorry!
if not any(k in ['is_bond_member', 'is_bridge_member'] for k in config):
# Bind interface to given VRF or unbind it if vrf node is not set.
# unbinding will call 'ip link set dev eth0 nomaster' which will
# also drop the interface out of a bridge or bond - thus this is
# checked before
self.set_vrf(config.get('vrf', ''))
# Configure ARP cache timeout in milliseconds - has default value
tmp = vyos_dict_search('ip.arp_cache_timeout', config)
value = tmp if (tmp != None) else '30'
self.set_arp_cache_tmo(value)
# Configure ARP filter configuration
tmp = vyos_dict_search('ip.disable_arp_filter', config)
value = '0' if (tmp != None) else '1'
self.set_arp_filter(value)
# Configure ARP accept
tmp = vyos_dict_search('ip.enable_arp_accept', config)
value = '1' if (tmp != None) else '0'
self.set_arp_accept(value)
# Configure ARP announce
tmp = vyos_dict_search('ip.enable_arp_announce', config)
value = '1' if (tmp != None) else '0'
self.set_arp_announce(value)
# Configure ARP ignore
tmp = vyos_dict_search('ip.enable_arp_ignore', config)
value = '1' if (tmp != None) else '0'
self.set_arp_ignore(value)
# Enable proxy-arp on this interface
tmp = vyos_dict_search('ip.enable_proxy_arp', config)
value = '1' if (tmp != None) else '0'
self.set_proxy_arp(value)
# Enable private VLAN proxy ARP on this interface
tmp = vyos_dict_search('ip.proxy_arp_pvlan', config)
value = '1' if (tmp != None) else '0'
self.set_proxy_arp_pvlan(value)
+ # IPv4 forwarding
+ tmp = vyos_dict_search('ip.disable_forwarding', config)
+ value = '0' if (tmp != None) else '1'
+ self.set_ipv4_forwarding(value)
+
# IPv6 forwarding
tmp = vyos_dict_search('ipv6.disable_forwarding', config)
value = '0' if (tmp != None) else '1'
self.set_ipv6_forwarding(value)
# IPv6 router advertisements
tmp = vyos_dict_search('ipv6.address.autoconf', config)
value = '2' if (tmp != None) else '1'
if 'dhcpv6' in new_addr:
value = '2'
self.set_ipv6_accept_ra(value)
# IPv6 address autoconfiguration
tmp = vyos_dict_search('ipv6.address.autoconf', config)
value = '1' if (tmp != None) else '0'
self.set_ipv6_autoconf(value)
# IPv6 Duplicate Address Detection (DAD) tries
tmp = vyos_dict_search('ipv6.dup_addr_detect_transmits', config)
value = tmp if (tmp != None) else '1'
self.set_ipv6_dad_messages(value)
# MTU - Maximum Transfer Unit
if 'mtu' in config:
self.set_mtu(config.get('mtu'))
# Delete old IPv6 EUI64 addresses before changing MAC
tmp = vyos_dict_search('ipv6.address.eui64_old', config)
if tmp:
for addr in tmp:
self.del_ipv6_eui64_address(addr)
# Change interface MAC address - re-set to real hardware address (hw-id)
# if custom mac is removed. Skip if bond member.
if 'is_bond_member' not in config:
mac = config.get('hw_id')
if 'mac' in config:
mac = config.get('mac')
if mac:
self.set_mac(mac)
# Manage IPv6 link-local addresses
tmp = vyos_dict_search('ipv6.address.no_default_link_local', config)
# we must check explicitly for None type as if the key is set we will
# get an empty dict (<class 'dict'>)
if tmp is not None:
self.del_ipv6_eui64_address('fe80::/64')
else:
self.add_ipv6_eui64_address('fe80::/64')
# Add IPv6 EUI-based addresses
tmp = vyos_dict_search('ipv6.address.eui64', config)
if tmp:
for addr in tmp:
self.add_ipv6_eui64_address(addr)
# re-add ourselves to any bridge we might have fallen out of
if 'is_bridge_member' in config:
bridge = config.get('is_bridge_member')
self.add_to_bridge(bridge)
# remove no longer required 802.1ad (Q-in-Q VLANs)
ifname = config['ifname']
for vif_s_id in config.get('vif_s_remove', {}):
vif_s_ifname = f'{ifname}.{vif_s_id}'
VLANIf(vif_s_ifname).remove()
# create/update 802.1ad (Q-in-Q VLANs)
for vif_s_id, vif_s_config in config.get('vif_s', {}).items():
tmp = deepcopy(VLANIf.get_config())
tmp['protocol'] = vif_s_config['protocol']
tmp['source_interface'] = ifname
tmp['vlan_id'] = vif_s_id
vif_s_ifname = f'{ifname}.{vif_s_id}'
vif_s_config['ifname'] = vif_s_ifname
s_vlan = VLANIf(vif_s_ifname, **tmp)
s_vlan.update(vif_s_config)
# remove no longer required client VLAN (vif-c)
for vif_c_id in vif_s_config.get('vif_c_remove', {}):
vif_c_ifname = f'{vif_s_ifname}.{vif_c_id}'
VLANIf(vif_c_ifname).remove()
# create/update client VLAN (vif-c) interface
for vif_c_id, vif_c_config in vif_s_config.get('vif_c', {}).items():
tmp = deepcopy(VLANIf.get_config())
tmp['source_interface'] = vif_s_ifname
tmp['vlan_id'] = vif_c_id
vif_c_ifname = f'{vif_s_ifname}.{vif_c_id}'
vif_c_config['ifname'] = vif_c_ifname
c_vlan = VLANIf(vif_c_ifname, **tmp)
c_vlan.update(vif_c_config)
# remove no longer required 802.1q VLAN interfaces
for vif_id in config.get('vif_remove', {}):
vif_ifname = f'{ifname}.{vif_id}'
VLANIf(vif_ifname).remove()
# create/update 802.1q VLAN interfaces
for vif_id, vif_config in config.get('vif', {}).items():
tmp = deepcopy(VLANIf.get_config())
tmp['source_interface'] = ifname
tmp['vlan_id'] = vif_id
vif_ifname = f'{ifname}.{vif_id}'
vif_config['ifname'] = vif_ifname
vlan = VLANIf(vif_ifname, **tmp)
vlan.update(vif_config)
class VLANIf(Interface):
""" Specific class which abstracts 802.1q and 802.1ad (Q-in-Q) VLAN interfaces """
default = {
'type': 'vlan',
'source_interface': '',
'vlan_id': '',
'protocol': '',
'ingress_qos': '',
'egress_qos': '',
}
options = Interface.options + \
['source_interface', 'vlan_id', 'protocol', 'ingress_qos', 'egress_qos']
def remove(self):
"""
Remove interface from operating system. Removing the interface
deconfigures all assigned IP addresses and clear possible DHCP(v6)
client processes.
Example:
>>> from vyos.ifconfig import Interface
>>> VLANIf('eth0.10').remove
"""
# Do we have sub interfaces (VLANs)? As interfaces need to be deleted
# "in order" starting from Q-in-Q we delete them first.
for upper in glob(f'/sys/class/net/{self.ifname}/upper*'):
# an upper interface could be named: upper_bond0.1000.1100, thus
# we need top drop the upper_ prefix
vif_c = os.path.basename(upper)
vif_c = vif_c.replace('upper_', '')
VLANIf(vif_c).remove()
super().remove()
def _create(self):
# bail out early if interface already exists
if self.exists(f'{self.ifname}'):
return
cmd = 'ip link add link {source_interface} name {ifname} type vlan id {vlan_id}'
if self.config['protocol']:
cmd += ' protocol {protocol}'
if self.config['ingress_qos']:
cmd += ' ingress-qos-map {ingress_qos}'
if self.config['egress_qos']:
cmd += ' egress-qos-map {egress_qos}'
self._cmd(cmd.format(**self.config))
# interface is always A/D down. It needs to be enabled explicitly
self.set_admin_state('down')
def set_admin_state(self, state):
"""
Set interface administrative state to be 'up' or 'down'
Example:
>>> from vyos.ifconfig import Interface
>>> Interface('eth0.10').set_admin_state('down')
>>> Interface('eth0.10').get_admin_state()
'down'
"""
# A VLAN interface can only be placed in admin up state when
# the lower interface is up, too
lower_interface = glob(f'/sys/class/net/{self.ifname}/lower*/flags')[0]
with open(lower_interface, 'r') as f:
flags = f.read()
# If parent is not up - bail out as we can not bring up the VLAN.
# Flags are defined in kernel source include/uapi/linux/if.h
if not int(flags, 16) & 1:
return None
return super().set_admin_state(state)
def update(self, config):
""" General helper function which works on a dictionary retrived by
get_config_dict(). It's main intention is to consolidate the scattered
interface setup code and provide a single point of entry when workin
on any interface. """
# call base class first
super().update(config)
# Enable/Disable of an interface must always be done at the end of the
# derived class to make use of the ref-counting set_admin_state()
# function. We will only enable the interface if 'up' was called as
# often as 'down'. This is required by some interface implementations
# as certain parameters can only be changed when the interface is
# in admin-down state. This ensures the link does not flap during
# reconfiguration.
state = 'down' if 'disable' in config else 'up'
self.set_admin_state(state)
diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py
index 047c19dd0..d94a5d962 100644
--- a/smoketest/scripts/cli/base_interfaces_test.py
+++ b/smoketest/scripts/cli/base_interfaces_test.py
@@ -1,276 +1,280 @@
# Copyright (C) 2019-2020 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
import unittest
import json
from netifaces import ifaddresses, AF_INET, AF_INET6
from vyos.configsession import ConfigSession
from vyos.ifconfig import Interface
from vyos.util import read_file
from vyos.util import cmd
from vyos.util import vyos_dict_search
from vyos.validate import is_intf_addr_assigned, is_ipv6_link_local
class BasicInterfaceTest:
class BaseTest(unittest.TestCase):
_test_ip = False
_test_mtu = False
_test_vlan = False
_test_qinq = False
_test_ipv6 = False
_base_path = []
_options = {}
_interfaces = []
_qinq_range = ['10', '20', '30']
_vlan_range = ['100', '200', '300', '2000']
# choose IPv6 minimum MTU value for tests - this must always work
_mtu = '1280'
def setUp(self):
self.session = ConfigSession(os.getpid())
self._test_addr = ['192.0.2.1/26', '192.0.2.255/31', '192.0.2.64/32',
'2001:db8:1::ffff/64', '2001:db8:101::1/112']
self._test_mtu = False
self._options = {}
def tearDown(self):
# we should not remove ethernet from the overall CLI
if 'ethernet' in self._base_path:
for interface in self._interfaces:
# when using a dedicated interface to test via TEST_ETH environment
# variable only this one will be cleared in the end - usable to test
# ethernet interfaces via SSH
self.session.delete(self._base_path + [interface])
self.session.set(self._base_path + [interface, 'duplex', 'auto'])
self.session.set(self._base_path + [interface, 'speed', 'auto'])
self.session.set(self._base_path + [interface, 'smp-affinity', 'auto'])
else:
self.session.delete(self._base_path)
self.session.commit()
del self.session
def test_add_description(self):
"""
Check if description can be added to interface
"""
for intf in self._interfaces:
test_string='Description-Test-{}'.format(intf)
self.session.set(self._base_path + [intf, 'description', test_string])
for option in self._options.get(intf, []):
self.session.set(self._base_path + [intf] + option.split())
self.session.commit()
# Validate interface description
for intf in self._interfaces:
test_string='Description-Test-{}'.format(intf)
with open('/sys/class/net/{}/ifalias'.format(intf), 'r') as f:
tmp = f.read().rstrip()
self.assertTrue(tmp, test_string)
def test_add_address_single(self):
"""
Check if a single address can be added to interface.
"""
addr = '192.0.2.0/31'
for intf in self._interfaces:
self.session.set(self._base_path + [intf, 'address', addr])
for option in self._options.get(intf, []):
self.session.set(self._base_path + [intf] + option.split())
self.session.commit()
for intf in self._interfaces:
self.assertTrue(is_intf_addr_assigned(intf, addr))
def test_add_address_multi(self):
"""
Check if IPv4/IPv6 addresses can be added to interface.
"""
# Add address
for intf in self._interfaces:
for addr in self._test_addr:
self.session.set(self._base_path + [intf, 'address', addr])
for option in self._options.get(intf, []):
self.session.set(self._base_path + [intf] + option.split())
self.session.commit()
# Validate address
for intf in self._interfaces:
for af in AF_INET, AF_INET6:
for addr in ifaddresses(intf)[af]:
# checking link local addresses makes no sense
if is_ipv6_link_local(addr['addr']):
continue
self.assertTrue(is_intf_addr_assigned(intf, addr['addr']))
def test_ipv6_link_local(self):
""" Common function for IPv6 link-local address assignemnts """
if not self._test_ipv6:
return None
for interface in self._interfaces:
base = self._base_path + [interface]
for option in self._options.get(interface, []):
self.session.set(base + option.split())
# after commit we must have an IPv6 link-local address
self.session.commit()
for interface in self._interfaces:
for addr in ifaddresses(interface)[AF_INET6]:
self.assertTrue(is_ipv6_link_local(addr['addr']))
# disable IPv6 link-local address assignment
for interface in self._interfaces:
base = self._base_path + [interface]
self.session.set(base + ['ipv6', 'address', 'no-default-link-local'])
# after commit we must have no IPv6 link-local address
self.session.commit()
for interface in self._interfaces:
self.assertTrue(AF_INET6 not in ifaddresses(interface))
def _mtu_test(self, intf):
""" helper function to verify MTU size """
with open('/sys/class/net/{}/mtu'.format(intf), 'r') as f:
tmp = f.read().rstrip()
self.assertEqual(tmp, self._mtu)
def test_change_mtu(self):
""" Testcase if MTU can be changed on interface """
if not self._test_mtu:
return None
for intf in self._interfaces:
base = self._base_path + [intf]
self.session.set(base + ['mtu', self._mtu])
for option in self._options.get(intf, []):
self.session.set(base + option.split())
self.session.commit()
for intf in self._interfaces:
self._mtu_test(intf)
def test_8021q_vlan(self):
""" Testcase for 802.1q VLAN interfaces """
if not self._test_vlan:
return None
for interface in self._interfaces:
base = self._base_path + [interface]
for option in self._options.get(interface, []):
self.session.set(base + option.split())
for vlan in self._vlan_range:
base = self._base_path + [interface, 'vif', vlan]
self.session.set(base + ['mtu', self._mtu])
for address in self._test_addr:
self.session.set(base + ['address', address])
self.session.commit()
for intf in self._interfaces:
for vlan in self._vlan_range:
vif = f'{intf}.{vlan}'
for address in self._test_addr:
self.assertTrue(is_intf_addr_assigned(vif, address))
self._mtu_test(vif)
def test_8021ad_qinq_vlan(self):
""" Testcase for 802.1ad Q-in-Q VLAN interfaces """
if not self._test_qinq:
return None
for interface in self._interfaces:
base = self._base_path + [interface]
for option in self._options.get(interface, []):
self.session.set(base + option.split())
for vif_s in self._qinq_range:
for vif_c in self._vlan_range:
base = self._base_path + [interface, 'vif-s', vif_s, 'vif-c', vif_c]
self.session.set(base + ['mtu', self._mtu])
for address in self._test_addr:
self.session.set(base + ['address', address])
self.session.commit()
for interface in self._interfaces:
for vif_s in self._qinq_range:
tmp = json.loads(cmd(f'ip -d -j link show dev {interface}.{vif_s}'))[0]
self.assertEqual(vyos_dict_search('linkinfo.info_data.protocol', tmp), '802.1ad')
for vif_c in self._vlan_range:
vif = f'{interface}.{vif_s}.{vif_c}'
for address in self._test_addr:
self.assertTrue(is_intf_addr_assigned(vif, address))
self._mtu_test(vif)
def test_ip_options(self):
""" test IP options like arp """
if not self._test_ip:
return None
for interface in self._interfaces:
arp_tmo = '300'
path = self._base_path + [interface]
for option in self._options.get(interface, []):
self.session.set(path + option.split())
# Options
self.session.set(path + ['ip', 'arp-cache-timeout', arp_tmo])
self.session.set(path + ['ip', 'disable-arp-filter'])
+ self.session.set(path + ['ip', 'disable-forwarding'])
self.session.set(path + ['ip', 'enable-arp-accept'])
self.session.set(path + ['ip', 'enable-arp-announce'])
self.session.set(path + ['ip', 'enable-arp-ignore'])
self.session.set(path + ['ip', 'enable-proxy-arp'])
self.session.set(path + ['ip', 'proxy-arp-pvlan'])
self.session.set(path + ['ip', 'source-validation', 'loose'])
self.session.commit()
for interface in self._interfaces:
tmp = read_file(f'/proc/sys/net/ipv4/neigh/{interface}/base_reachable_time_ms')
self.assertEqual(tmp, str((int(arp_tmo) * 1000))) # tmo value is in milli seconds
tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/arp_filter')
self.assertEqual('0', tmp)
tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/arp_accept')
self.assertEqual('1', tmp)
tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/arp_announce')
self.assertEqual('1', tmp)
tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/arp_ignore')
self.assertEqual('1', tmp)
+ tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/forwarding')
+ self.assertEqual('0', tmp)
+
tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/proxy_arp')
self.assertEqual('1', tmp)
tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/proxy_arp_pvlan')
self.assertEqual('1', tmp)
tmp = read_file(f'/proc/sys/net/ipv4/conf/{interface}/rp_filter')
self.assertEqual('2', tmp)
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Nov 6, 8:54 AM (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4653621
Default Alt Text
(135 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment