summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interface-definitions/include/interface-parameters-flowlabel.xml.i1
-rw-r--r--interface-definitions/include/radius-server-ipv4-ipv6.xml.i22
-rw-r--r--interface-definitions/include/source-address-ipv4-ipv6.xml.i1
-rw-r--r--interface-definitions/include/tunnel-local-remote-ip.xml.i37
-rw-r--r--interface-definitions/include/tunnel-remote.xml.i18
-rw-r--r--interface-definitions/interfaces-erspan.xml.in3
-rw-r--r--interface-definitions/interfaces-geneve.xml.in13
-rw-r--r--interface-definitions/interfaces-macsec.xml.in8
-rw-r--r--interface-definitions/interfaces-tunnel.xml.in13
-rw-r--r--interface-definitions/interfaces-vxlan.xml.in49
-rw-r--r--python/vyos/configverify.py41
-rw-r--r--python/vyos/ifconfig/__init__.py12
-rw-r--r--python/vyos/ifconfig/bond.py6
-rw-r--r--python/vyos/ifconfig/bridge.py21
-rw-r--r--python/vyos/ifconfig/control.py2
-rw-r--r--python/vyos/ifconfig/dummy.py6
-rwxr-xr-xpython/vyos/ifconfig/erspan.py83
-rw-r--r--python/vyos/ifconfig/ethernet.py5
-rw-r--r--python/vyos/ifconfig/geneve.py11
-rw-r--r--python/vyos/ifconfig/input.py3
-rw-r--r--python/vyos/ifconfig/interface.py40
-rw-r--r--python/vyos/ifconfig/l2tpv3.py38
-rw-r--r--python/vyos/ifconfig/loopback.py10
-rw-r--r--python/vyos/ifconfig/macsec.py17
-rw-r--r--python/vyos/ifconfig/macvlan.py19
-rw-r--r--python/vyos/ifconfig/pppoe.py41
-rw-r--r--python/vyos/ifconfig/tunnel.py275
-rw-r--r--python/vyos/ifconfig/vti.py6
-rw-r--r--python/vyos/ifconfig/vtun.py8
-rw-r--r--python/vyos/ifconfig/vxlan.py75
-rw-r--r--python/vyos/ifconfig/wireguard.py18
-rw-r--r--python/vyos/ifconfig/wireless.py27
-rw-r--r--smoketest/configs/tunnel-broker103
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_erspan.py61
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_macsec.py39
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_tunnel.py107
-rwxr-xr-xsrc/conf_mode/interfaces-erspan.py32
-rwxr-xr-xsrc/conf_mode/interfaces-geneve.py12
-rwxr-xr-xsrc/conf_mode/interfaces-l2tpv3.py22
-rwxr-xr-xsrc/conf_mode/interfaces-macsec.py10
-rwxr-xr-xsrc/conf_mode/interfaces-openvpn.py5
-rwxr-xr-xsrc/conf_mode/interfaces-pseudo-ethernet.py12
-rwxr-xr-xsrc/conf_mode/interfaces-tunnel.py91
-rwxr-xr-xsrc/conf_mode/interfaces-vxlan.py13
-rwxr-xr-xsrc/conf_mode/interfaces-wireless.py11
-rwxr-xr-xsrc/migration-scripts/interfaces/19-to-2061
46 files changed, 652 insertions, 856 deletions
diff --git a/interface-definitions/include/interface-parameters-flowlabel.xml.i b/interface-definitions/include/interface-parameters-flowlabel.xml.i
index ae65c27c9..0723c4b47 100644
--- a/interface-definitions/include/interface-parameters-flowlabel.xml.i
+++ b/interface-definitions/include/interface-parameters-flowlabel.xml.i
@@ -11,6 +11,5 @@
</constraint>
<constraintErrorMessage>Must be 'inherit' or a number</constraintErrorMessage>
</properties>
- <defaultValue>inherit</defaultValue>
</leafNode>
<!-- included end -->
diff --git a/interface-definitions/include/radius-server-ipv4-ipv6.xml.i b/interface-definitions/include/radius-server-ipv4-ipv6.xml.i
index ab3c6d72a..c57d39b6b 100644
--- a/interface-definitions/include/radius-server-ipv4-ipv6.xml.i
+++ b/interface-definitions/include/radius-server-ipv4-ipv6.xml.i
@@ -26,7 +26,27 @@
#include <include/radius-server-port.xml.i>
</children>
</tagNode>
- #include <include/source-address-ipv4-ipv6.xml.i>
+ <leafNode name="source-address">
+ <properties>
+ <help>Source IP address used to initiate connection</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_local_ips.sh --both</script>
+ </completionHelp>
+ <valueHelp>
+ <format>ipv4</format>
+ <description>IPv4 source address</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 source address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv4-address"/>
+ <validator name="ipv6-address"/>
+ </constraint>
+ <multi/>
+ </properties>
+ </leafNode>
</children>
</node>
<!-- included end -->
diff --git a/interface-definitions/include/source-address-ipv4-ipv6.xml.i b/interface-definitions/include/source-address-ipv4-ipv6.xml.i
index 4da4698c2..004e04f7b 100644
--- a/interface-definitions/include/source-address-ipv4-ipv6.xml.i
+++ b/interface-definitions/include/source-address-ipv4-ipv6.xml.i
@@ -17,7 +17,6 @@
<validator name="ipv4-address"/>
<validator name="ipv6-address"/>
</constraint>
- <multi/>
</properties>
</leafNode>
<!-- included end -->
diff --git a/interface-definitions/include/tunnel-local-remote-ip.xml.i b/interface-definitions/include/tunnel-local-remote-ip.xml.i
deleted file mode 100644
index 85c20f482..000000000
--- a/interface-definitions/include/tunnel-local-remote-ip.xml.i
+++ /dev/null
@@ -1,37 +0,0 @@
-<!-- included start from tunnel-local-remote-ip.xml.i -->
-<leafNode name="local-ip">
- <properties>
- <help>Local IP address for this tunnel</help>
- <valueHelp>
- <format>ipv4</format>
- <description>Local IPv4 address for this tunnel</description>
- </valueHelp>
- <valueHelp>
- <format>ipv6</format>
- <description>Local IPv6 address for this tunnel</description>
- </valueHelp>
- <completionHelp>
- <script>${vyos_completion_dir}/list_local_ips.sh --both</script>
- </completionHelp>
- <constraint>
- <validator name="ip-address"/>
- </constraint>
- </properties>
-</leafNode>
-<leafNode name="remote-ip">
- <properties>
- <help>Remote IP address for this tunnel</help>
- <valueHelp>
- <format>ipv4</format>
- <description>Remote IPv4 address for this tunnel</description>
- </valueHelp>
- <valueHelp>
- <format>ipv6</format>
- <description>Remote IPv6 address for this tunnel</description>
- </valueHelp>
- <constraint>
- <!-- does it need fixing/changing to be more restrictive ? -->
- <validator name="ip-address"/>
- </constraint>
- </properties>
-</leafNode>
diff --git a/interface-definitions/include/tunnel-remote.xml.i b/interface-definitions/include/tunnel-remote.xml.i
new file mode 100644
index 000000000..d5b50d3f6
--- /dev/null
+++ b/interface-definitions/include/tunnel-remote.xml.i
@@ -0,0 +1,18 @@
+<!-- included start from tunnel-remote.xml.i -->
+<leafNode name="remote">
+ <properties>
+ <help>Tunnel remote address</help>
+ <valueHelp>
+ <format>ipv4</format>
+ <description>Tunnel remote IPv4 address</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>Tunnel remote IPv6 address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ip-address"/>
+ </constraint>
+ </properties>
+</leafNode>
+<!-- included end -->
diff --git a/interface-definitions/interfaces-erspan.xml.in b/interface-definitions/interfaces-erspan.xml.in
index e36a64d3a..2394d3534 100644
--- a/interface-definitions/interfaces-erspan.xml.in
+++ b/interface-definitions/interfaces-erspan.xml.in
@@ -20,7 +20,8 @@
#include <include/interface-disable.xml.i>
#include <include/interface-disable-link-detect.xml.i>
#include <include/interface-mtu-64-8024.xml.i>
- #include <include/tunnel-local-remote-ip.xml.i>
+ #include <include/source-address-ipv4-ipv6.xml.i>
+ #include <include/tunnel-remote.xml.i>
<leafNode name="encapsulation">
<properties>
<help>Encapsulation of this tunnel interface</help>
diff --git a/interface-definitions/interfaces-geneve.xml.in b/interface-definitions/interfaces-geneve.xml.in
index 1064b2c18..5894f580c 100644
--- a/interface-definitions/interfaces-geneve.xml.in
+++ b/interface-definitions/interfaces-geneve.xml.in
@@ -23,18 +23,7 @@
#include <include/interface-ipv6-options.xml.i>
#include <include/interface-mac.xml.i>
#include <include/interface-mtu-1450-16000.xml.i>
- <leafNode name="remote">
- <properties>
- <help>Remote address of GENEVE tunnel</help>
- <valueHelp>
- <format>ipv4</format>
- <description>Remote address of GENEVE tunnel</description>
- </valueHelp>
- <constraint>
- <validator name="ipv4-address"/>
- </constraint>
- </properties>
- </leafNode>
+ #include <include/tunnel-remote.xml.i>
#include <include/vni.xml.i>
</children>
</tagNode>
diff --git a/interface-definitions/interfaces-macsec.xml.in b/interface-definitions/interfaces-macsec.xml.in
index 94d78c6dd..3f2e5bb69 100644
--- a/interface-definitions/interfaces-macsec.xml.in
+++ b/interface-definitions/interfaces-macsec.xml.in
@@ -28,14 +28,18 @@
<properties>
<help>Cipher suite used</help>
<completionHelp>
- <list>gcm-aes-128</list>
+ <list>gcm-aes-128 gcm-aes-256</list>
</completionHelp>
<valueHelp>
<format>gcm-aes-128</format>
<description>Galois/Counter Mode of AES cipher with 128-bit key (default)</description>
</valueHelp>
+ <valueHelp>
+ <format>gcm-aes-256</format>
+ <description>Galois/Counter Mode of AES cipher with 256-bit key</description>
+ </valueHelp>
<constraint>
- <regex>(gcm-aes-128)</regex>
+ <regex>^(gcm-aes-128|gcm-aes-256)$</regex>
</constraint>
</properties>
</leafNode>
diff --git a/interface-definitions/interfaces-tunnel.xml.in b/interface-definitions/interfaces-tunnel.xml.in
index 7a97980a2..c2d03c5ea 100644
--- a/interface-definitions/interfaces-tunnel.xml.in
+++ b/interface-definitions/interfaces-tunnel.xml.in
@@ -27,7 +27,8 @@
</leafNode>
#include <include/interface-ipv4-options.xml.i>
#include <include/interface-ipv6-options.xml.i>
- #include <include/tunnel-local-remote-ip.xml.i>
+ #include <include/source-address-ipv4-ipv6.xml.i>
+ #include <include/tunnel-remote.xml.i>
<leafNode name="source-interface">
<properties>
<help>Physical Interface used for underlaying traffic</help>
@@ -79,15 +80,15 @@
<properties>
<help>Encapsulation of this tunnel interface</help>
<completionHelp>
- <list>gre gre-bridge ip6gre ip6ip6 ipip ipip6 sit</list>
+ <list>gre gretap ip6gre ip6ip6 ipip ipip6 sit</list>
</completionHelp>
<valueHelp>
<format>gre</format>
<description>Generic Routing Encapsulation</description>
</valueHelp>
<valueHelp>
- <format>gre-bridge</format>
- <description>Generic Routing Encapsulation bridge interface</description>
+ <format>gretap</format>
+ <description>Generic Routing Encapsulation (virtual L2 tunnel)</description>
</valueHelp>
<valueHelp>
<format>ip6gre</format>
@@ -110,9 +111,9 @@
<description>Simple Internet Transition encapsulation</description>
</valueHelp>
<constraint>
- <regex>^(gre|gre-bridge|ip6gre|ip6ip6|ipip|ipip6|sit)$</regex>
+ <regex>^(gre|gretap|ip6gre|ip6ip6|ipip|ipip6|sit)$</regex>
</constraint>
- <constraintErrorMessage>Invalid encapsulation, must be one of: gre, gre-bridge, ipip, sit, ipip6, ip6ip6, ip6gre</constraintErrorMessage>
+ <constraintErrorMessage>Invalid encapsulation, must be one of: gre, gretap, ipip, sit, ipip6, ip6ip6, ip6gre</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="multicast">
diff --git a/interface-definitions/interfaces-vxlan.xml.in b/interface-definitions/interfaces-vxlan.xml.in
index 234770971..efe6218e1 100644
--- a/interface-definitions/interfaces-vxlan.xml.in
+++ b/interface-definitions/interfaces-vxlan.xml.in
@@ -44,22 +44,43 @@
<leafNode name="mtu">
<defaultValue>1450</defaultValue>
</leafNode>
- <leafNode name="remote">
+ #include <include/tunnel-remote.xml.i>
+ <node name="parameters">
<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>
+ <help>VXLAN tunnel parameters</help>
</properties>
- </leafNode>
+ <children>
+ <node name="ip">
+ <properties>
+ <help>IPv4 specific tunnel parameters</help>
+ </properties>
+ <children>
+ <leafNode name="df">
+ <properties>
+ <help>Specifies the usage of the do not fragment (DF) bit</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ #include <include/interface-parameters-tos.xml.i>
+ #include <include/interface-parameters-ttl.xml.i>
+ </children>
+ </node>
+ <node name="ipv6">
+ <properties>
+ <help>IPv6 specific tunnel parameters</help>
+ </properties>
+ <children>
+ #include <include/interface-parameters-flowlabel.xml.i>
+ </children>
+ </node>
+ <leafNode name="nolearning">
+ <properties>
+ <help>Do not add unknown addresses into forwarding database</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
<leafNode name="port">
<properties>
<help>Destination port of VXLAN tunnel (default: 8472)</help>
diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py
index 5a4d14c68..db3e7cc57 100644
--- a/python/vyos/configverify.py
+++ b/python/vyos/configverify.py
@@ -95,41 +95,42 @@ def verify_tunnel(config):
"""
from vyos.template import is_ipv4
from vyos.template import is_ipv6
-
+
if 'encapsulation' not in config:
raise ConfigError('Must configure the tunnel encapsulation for '\
'{ifname}!'.format(**config))
-
- if 'local_ip' not in config and 'dhcp_interface' not in config:
- raise ConfigError('local-ip is mandatory for tunnel')
- if 'remote_ip' not in config and config['encapsulation'] != 'gre':
- raise ConfigError('remote-ip is mandatory for tunnel')
+ if 'source_address' not in config and 'dhcp_interface' not in config:
+ raise ConfigError('source-address is mandatory for tunnel')
+
+ if 'remote' not in config and config['encapsulation'] != 'gre':
+ raise ConfigError('remote ip address is mandatory for tunnel')
- if {'local_ip', 'dhcp_interface'} <= set(config):
- raise ConfigError('Can not use both local-ip and dhcp-interface')
+ if {'source_address', 'dhcp_interface'} <= set(config):
+ raise ConfigError('Can not use both source-address and dhcp-interface')
if config['encapsulation'] in ['ipip6', 'ip6ip6', 'ip6gre', 'ip6erspan']:
error_ipv6 = 'Encapsulation mode requires IPv6'
- if 'local_ip' in config and not is_ipv6(config['local_ip']):
- raise ConfigError(f'{error_ipv6} local-ip')
+ if 'source_address' in config and not is_ipv6(config['source_address']):
+ raise ConfigError(f'{error_ipv6} source-address')
- if 'remote_ip' in config and not is_ipv6(config['remote_ip']):
- raise ConfigError(f'{error_ipv6} remote-ip')
+ if 'remote' in config and not is_ipv6(config['remote']):
+ raise ConfigError(f'{error_ipv6} remote')
else:
error_ipv4 = 'Encapsulation mode requires IPv4'
- if 'local_ip' in config and not is_ipv4(config['local_ip']):
- raise ConfigError(f'{error_ipv4} local-ip')
+ if 'source_address' in config and not is_ipv4(config['source_address']):
+ raise ConfigError(f'{error_ipv4} source-address')
- if 'remote_ip' in config and not is_ipv4(config['remote_ip']):
- raise ConfigError(f'{error_ipv4} remote-ip')
+ if 'remote' in config and not is_ipv4(config['remote']):
+ raise ConfigError(f'{error_ipv4} remote address')
- if config['encapsulation'] in ['sit', 'gre-bridge']:
+ if config['encapsulation'] in ['sit', 'gretap']:
if 'source_interface' in config:
- raise ConfigError('Option source-interface can not be used with ' \
- 'encapsulation "sit" or "gre-bridge"')
+ encapsulation = config['encapsulation']
+ raise ConfigError(f'Option source-interface can not be used with ' \
+ f'encapsulation "{encapsulation}"!')
elif config['encapsulation'] == 'gre':
- if 'local_ip' in config and is_ipv6(config['local_ip']):
+ if 'source_address' in config and is_ipv6(config['source_address']):
raise ConfigError('Can not use local IPv6 address is for mGRE tunnels')
def verify_eapol(config):
diff --git a/python/vyos/ifconfig/__init__.py b/python/vyos/ifconfig/__init__.py
index f7b55c9dd..9d797d7f1 100644
--- a/python/vyos/ifconfig/__init__.py
+++ b/python/vyos/ifconfig/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 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
@@ -30,15 +30,7 @@ from vyos.ifconfig.vxlan import VXLANIf
from vyos.ifconfig.wireguard import WireGuardIf
from vyos.ifconfig.vtun import VTunIf
from vyos.ifconfig.vti import VTIIf
-from vyos.ifconfig.pppoe import PPPoEIf
-from vyos.ifconfig.tunnel import GREIf
-from vyos.ifconfig.tunnel import GRETapIf
-from vyos.ifconfig.tunnel import IP6GREIf
-from vyos.ifconfig.tunnel import IPIPIf
-from vyos.ifconfig.tunnel import IPIP6If
-from vyos.ifconfig.tunnel import IP6IP6If
-from vyos.ifconfig.tunnel import SitIf
-from vyos.ifconfig.tunnel import Sit6RDIf
+from vyos.ifconfig.tunnel import TunnelIf
from vyos.ifconfig.erspan import ERSpanIf
from vyos.ifconfig.erspan import ER6SpanIf
from vyos.ifconfig.wireless import WiFiIf
diff --git a/python/vyos/ifconfig/bond.py b/python/vyos/ifconfig/bond.py
index 709222b09..28b5da3ee 100644
--- a/python/vyos/ifconfig/bond.py
+++ b/python/vyos/ifconfig/bond.py
@@ -1,4 +1,4 @@
-# Copyright 2019-2020 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 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
@@ -31,9 +31,7 @@ class BondIf(Interface):
monitoring may be performed.
"""
- default = {
- 'type': 'bond',
- }
+ iftype = 'bond'
definition = {
**Interface.definition,
** {
diff --git a/python/vyos/ifconfig/bridge.py b/python/vyos/ifconfig/bridge.py
index 1bd617a05..69f652547 100644
--- a/python/vyos/ifconfig/bridge.py
+++ b/python/vyos/ifconfig/bridge.py
@@ -1,4 +1,4 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 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
@@ -34,10 +34,7 @@ class BridgeIf(Interface):
The Linux bridge code implements a subset of the ANSI/IEEE 802.1d standard.
"""
-
- default = {
- 'type': 'bridge',
- }
+ iftype = 'bridge'
definition = {
**Interface.definition,
**{
@@ -283,21 +280,21 @@ class BridgeIf(Interface):
if int(vlan_filter):
add_vlan = []
cur_vlan_ids = get_vlan_ids(ifname)
-
+
tmp = dict_search('vif', config)
if tmp:
for vif, vif_config in tmp.items():
add_vlan.append(vif)
-
+
# Remove redundant VLANs from the system
for vlan in list_diff(cur_vlan_ids, add_vlan):
cmd = f'bridge vlan del dev {ifname} vid {vlan} self'
self._cmd(cmd)
-
+
for vlan in add_vlan:
cmd = f'bridge vlan add dev {ifname} vid {vlan} self'
self._cmd(cmd)
-
+
# VLAN of bridge parent interface is always 1
# VLAN 1 is the default VLAN for all unlabeled packets
cmd = f'bridge vlan add dev {ifname} vid 1 pvid untagged self'
@@ -337,7 +334,7 @@ class BridgeIf(Interface):
native_vlan_id = None
allowed_vlan_ids= []
cur_vlan_ids = get_vlan_ids(interface)
-
+
if 'native_vlan' in interface_config:
vlan_id = interface_config['native_vlan']
add_vlan.append(vlan_id)
@@ -353,12 +350,12 @@ class BridgeIf(Interface):
else:
add_vlan.append(vlan)
allowed_vlan_ids.append(vlan)
-
+
# Remove redundant VLANs from the system
for vlan in list_diff(cur_vlan_ids, add_vlan):
cmd = f'bridge vlan del dev {interface} vid {vlan} master'
self._cmd(cmd)
-
+
for vlan in allowed_vlan_ids:
cmd = f'bridge vlan add dev {interface} vid {vlan} master'
self._cmd(cmd)
diff --git a/python/vyos/ifconfig/control.py b/python/vyos/ifconfig/control.py
index 43136f361..d41dfef47 100644
--- a/python/vyos/ifconfig/control.py
+++ b/python/vyos/ifconfig/control.py
@@ -1,4 +1,4 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 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
diff --git a/python/vyos/ifconfig/dummy.py b/python/vyos/ifconfig/dummy.py
index 19ef9d304..0019fc52b 100644
--- a/python/vyos/ifconfig/dummy.py
+++ b/python/vyos/ifconfig/dummy.py
@@ -1,4 +1,4 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 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
@@ -23,9 +23,7 @@ class DummyIf(Interface):
packets through without actually transmitting them.
"""
- default = {
- 'type': 'dummy',
- }
+ iftype = 'dummy'
definition = {
**Interface.definition,
**{
diff --git a/python/vyos/ifconfig/erspan.py b/python/vyos/ifconfig/erspan.py
index 50230e14a..9e24cf6cd 100755
--- a/python/vyos/ifconfig/erspan.py
+++ b/python/vyos/ifconfig/erspan.py
@@ -1,4 +1,4 @@
-# Copyright 2019-2020 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 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
@@ -31,12 +31,7 @@ class _ERSpan(Interface):
"""
_ERSpan: private base class for ERSPAN tunnels
"""
- default = {
- **Interface.default,
- **{
- 'type': 'erspan',
- }
- }
+ iftype = 'erspan'
definition = {
**Interface.definition,
**{
@@ -44,18 +39,23 @@ class _ERSpan(Interface):
'prefixes': ['ersp',],
},
}
-
- options = ['local_ip','remote_ip','encapsulation','parameters']
-
+
def __init__(self,ifname,**config):
self.config = deepcopy(config) if config else {}
super().__init__(ifname, **self.config)
-
+
def change_options(self):
pass
-
+
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
@@ -63,10 +63,9 @@ class _ERSpan(Interface):
# as certain parameters can only be changed when the interface is
# in admin-down state. This ensures the link does not flap during
# reconfiguration.
- super().update(config)
state = 'down' if 'disable' in config else 'up'
self.set_admin_state(state)
-
+
def _create(self):
pass
@@ -74,15 +73,15 @@ class ERSpanIf(_ERSpan):
"""
ERSpanIf: private base class for ERSPAN Over GRE and IPv4 tunnels
"""
-
+
def _create(self):
ifname = self.config['ifname']
- local_ip = self.config['local_ip']
- remote_ip = self.config['remote_ip']
+ source_address = self.config['source_address']
+ remote = self.config['remote']
key = self.config['parameters']['ip']['key']
version = self.config['parameters']['version']
- command = f'ip link add dev {ifname} type erspan local {local_ip} remote {remote_ip} seq key {key} erspan_ver {version}'
-
+ command = f'ip link add dev {ifname} type erspan local {source_address} remote {remote} seq key {key} erspan_ver {version}'
+
if int(version) == 1:
idx=dict_search('parameters.erspan.idx',self.config)
if idx:
@@ -94,24 +93,24 @@ class ERSpanIf(_ERSpan):
hwid=dict_search('parameters.erspan.hwid',self.config)
if hwid:
command += f' erspan_hwid {hwid}'
-
+
ttl = dict_search('parameters.ip.ttl',self.config)
if ttl:
command += f' ttl {ttl}'
tos = dict_search('parameters.ip.tos',self.config)
if tos:
command += f' tos {tos}'
-
+
self._cmd(command)
-
+
def change_options(self):
ifname = self.config['ifname']
- local_ip = self.config['local_ip']
- remote_ip = self.config['remote_ip']
+ source_address = self.config['source_address']
+ remote = self.config['remote']
key = self.config['parameters']['ip']['key']
version = self.config['parameters']['version']
- command = f'ip link set dev {ifname} type erspan local {local_ip} remote {remote_ip} seq key {key} erspan_ver {version}'
-
+ command = f'ip link set dev {ifname} type erspan local {source_address} remote {remote} seq key {key} erspan_ver {version}'
+
if int(version) == 1:
idx=dict_search('parameters.erspan.idx',self.config)
if idx:
@@ -123,29 +122,29 @@ class ERSpanIf(_ERSpan):
hwid=dict_search('parameters.erspan.hwid',self.config)
if hwid:
command += f' erspan_hwid {hwid}'
-
+
ttl = dict_search('parameters.ip.ttl',self.config)
if ttl:
command += f' ttl {ttl}'
tos = dict_search('parameters.ip.tos',self.config)
if tos:
command += f' tos {tos}'
-
+
self._cmd(command)
class ER6SpanIf(_ERSpan):
"""
ER6SpanIf: private base class for ERSPAN Over GRE and IPv6 tunnels
"""
-
+
def _create(self):
ifname = self.config['ifname']
- local_ip = self.config['local_ip']
- remote_ip = self.config['remote_ip']
+ source_address = self.config['source_address']
+ remote = self.config['remote']
key = self.config['parameters']['ip']['key']
version = self.config['parameters']['version']
- command = f'ip link add dev {ifname} type ip6erspan local {local_ip} remote {remote_ip} seq key {key} erspan_ver {version}'
-
+ command = f'ip link add dev {ifname} type ip6erspan local {source_address} remote {remote} seq key {key} erspan_ver {version}'
+
if int(version) == 1:
idx=dict_search('parameters.erspan.idx',self.config)
if idx:
@@ -157,24 +156,24 @@ class ER6SpanIf(_ERSpan):
hwid=dict_search('parameters.erspan.hwid',self.config)
if hwid:
command += f' erspan_hwid {hwid}'
-
+
ttl = dict_search('parameters.ip.ttl',self.config)
if ttl:
command += f' ttl {ttl}'
tos = dict_search('parameters.ip.tos',self.config)
if tos:
command += f' tos {tos}'
-
+
self._cmd(command)
-
+
def change_options(self):
ifname = self.config['ifname']
- local_ip = self.config['local_ip']
- remote_ip = self.config['remote_ip']
+ source_address = self.config['source_address']
+ remote = self.config['remote']
key = self.config['parameters']['ip']['key']
version = self.config['parameters']['version']
- command = f'ip link set dev {ifname} type ip6erspan local {local_ip} remote {remote_ip} seq key {key} erspan_ver {version}'
-
+ command = f'ip link set dev {ifname} type ip6erspan local {source_address} remote {remote} seq key {key} erspan_ver {version}'
+
if int(version) == 1:
idx=dict_search('parameters.erspan.idx',self.config)
if idx:
@@ -186,5 +185,5 @@ class ER6SpanIf(_ERSpan):
hwid=dict_search('parameters.erspan.hwid',self.config)
if hwid:
command += f' erspan_hwid {hwid}'
-
+
self._cmd(command)
diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py
index 547b54b84..aca0aeead 100644
--- a/python/vyos/ifconfig/ethernet.py
+++ b/python/vyos/ifconfig/ethernet.py
@@ -26,10 +26,7 @@ class EthernetIf(Interface):
"""
Abstraction of a Linux Ethernet Interface
"""
-
- default = {
- 'type': 'ethernet',
- }
+ iftype = 'ethernet'
definition = {
**Interface.definition,
**{
diff --git a/python/vyos/ifconfig/geneve.py b/python/vyos/ifconfig/geneve.py
index 5c4597be8..1b3ee0dc9 100644
--- a/python/vyos/ifconfig/geneve.py
+++ b/python/vyos/ifconfig/geneve.py
@@ -1,4 +1,4 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 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
@@ -26,14 +26,7 @@ class GeneveIf(Interface):
https://developers.redhat.com/blog/2019/05/17/an-introduction-to-linux-virtual-interfaces-tunnels/#geneve
https://lwn.net/Articles/644938/
"""
-
- default = {
- 'type': 'geneve',
- 'vni': 0,
- 'remote': '',
- }
- options = Interface.options + \
- ['vni', 'remote']
+ iftype = 'geneve'
definition = {
**Interface.definition,
**{
diff --git a/python/vyos/ifconfig/input.py b/python/vyos/ifconfig/input.py
index a6e566d87..db7d2b6b4 100644
--- a/python/vyos/ifconfig/input.py
+++ b/python/vyos/ifconfig/input.py
@@ -17,9 +17,6 @@ from vyos.ifconfig.interface import Interface
@Interface.register
class InputIf(Interface):
- default = {
- 'type': '',
- }
definition = {
**Interface.definition,
**{
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index 4bdabd432..9c0ee2ab1 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -1,4 +1,4 @@
-# Copyright 2019-2020 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 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
@@ -60,7 +60,6 @@ class Interface(Control):
options = ['debug', 'create']
required = []
default = {
- 'type': '',
'debug': True,
'create': True,
}
@@ -232,26 +231,21 @@ class Interface(Control):
>>> from vyos.ifconfig import Interface
>>> i = Interface('eth0')
"""
+ self.config = deepcopy(kargs)
+ self.config['ifname'] = self.ifname = ifname
- 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']:
+ # 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.iftype:
raise Exception(f'interface "{ifname}" not found')
+ self.config['type'] = self.iftype
# Should an Instance of a child class (EthernetIf, DummyIf, ..)
# be required, then create should be set to False to not accidentally create it.
@@ -1300,17 +1294,7 @@ class Interface(Control):
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']
+ iftype = 'vlan'
def remove(self):
"""
@@ -1339,11 +1323,11 @@ class VLANIf(Interface):
return
cmd = 'ip link add link {source_interface} name {ifname} type vlan id {vlan_id}'
- if self.config['protocol']:
+ if 'protocol' in self.config:
cmd += ' protocol {protocol}'
- if self.config['ingress_qos']:
+ if 'ingress_qos' in self.config:
cmd += ' ingress-qos-map {ingress_qos}'
- if self.config['egress_qos']:
+ if 'egress_qos' in self.config:
cmd += ' egress-qos-map {egress_qos}'
self._cmd(cmd.format(**self.config))
diff --git a/python/vyos/ifconfig/l2tpv3.py b/python/vyos/ifconfig/l2tpv3.py
index 8ed3d5afb..34f8cd4d3 100644
--- a/python/vyos/ifconfig/l2tpv3.py
+++ b/python/vyos/ifconfig/l2tpv3.py
@@ -1,4 +1,4 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 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
@@ -24,19 +24,7 @@ class L2TPv3If(Interface):
either hot standby or load balancing services. Additionally, link integrity
monitoring may be performed.
"""
-
- default = {
- 'type': 'l2tp',
- 'peer_tunnel_id': '',
- 'local_port': 0,
- 'remote_port': 0,
- 'encapsulation': 'udp',
- 'local_address': '',
- 'remote_address': '',
- 'session_id': '',
- 'tunnel_id': '',
- 'peer_session_id': ''
- }
+ iftype = 'l2tp'
definition = {
**Interface.definition,
**{
@@ -45,20 +33,16 @@ class L2TPv3If(Interface):
'bridgeable': True,
}
}
- options = Interface.options + \
- ['tunnel_id', 'peer_tunnel_id', 'local_port', 'remote_port',
- 'encapsulation', 'local_address', 'remote_address', 'session_id',
- 'peer_session_id']
def _create(self):
# create tunnel interface
cmd = 'ip l2tp add tunnel tunnel_id {tunnel_id}'
cmd += ' peer_tunnel_id {peer_tunnel_id}'
- cmd += ' udp_sport {local_port}'
- cmd += ' udp_dport {remote_port}'
+ cmd += ' udp_sport {source_port}'
+ cmd += ' udp_dport {destination_port}'
cmd += ' encap {encapsulation}'
- cmd += ' local {local_address}'
- cmd += ' remote {remote_address}'
+ cmd += ' local {local_ip}'
+ cmd += ' remote {remote_ip}'
self._cmd(cmd.format(**self.config))
# setup session
@@ -82,20 +66,20 @@ class L2TPv3If(Interface):
>>> i.remove()
"""
- if self.exists(self.config['ifname']):
+ if self.exists(self.ifname):
# interface is always A/D down. It needs to be enabled explicitly
self.set_admin_state('down')
- if self.config['tunnel_id'] and self.config['session_id']:
+ if {'tunnel_id', 'session_id'} <= set(self.config):
cmd = 'ip l2tp del session tunnel_id {tunnel_id}'
cmd += ' session_id {session_id}'
self._cmd(cmd.format(**self.config))
- if self.config['tunnel_id']:
+ if 'tunnel_id' in self.config:
cmd = 'ip l2tp del tunnel tunnel_id {tunnel_id}'
self._cmd(cmd.format(**self.config))
-
-
+
+
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
diff --git a/python/vyos/ifconfig/loopback.py b/python/vyos/ifconfig/loopback.py
index 0e632d826..d323feed8 100644
--- a/python/vyos/ifconfig/loopback.py
+++ b/python/vyos/ifconfig/loopback.py
@@ -1,4 +1,4 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 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
@@ -22,9 +22,8 @@ class LoopbackIf(Interface):
uses to communicate with itself.
"""
_persistent_addresses = ['127.0.0.1/8', '::1/128']
- default = {
- 'type': 'loopback',
- }
+ iftype = 'loopback'
+
definition = {
**Interface.definition,
**{
@@ -33,9 +32,6 @@ class LoopbackIf(Interface):
'bridgeable': True,
}
}
-
- name = 'loopback'
-
def remove(self):
"""
Loopback interface can not be deleted from operating system. We can
diff --git a/python/vyos/ifconfig/macsec.py b/python/vyos/ifconfig/macsec.py
index 456686ea6..c15273080 100644
--- a/python/vyos/ifconfig/macsec.py
+++ b/python/vyos/ifconfig/macsec.py
@@ -1,4 +1,4 @@
-# Copyright 2020 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2020-2021 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
@@ -27,12 +27,7 @@ class MACsecIf(Interface):
other security solutions such as IPsec (layer 3) or TLS (layer 4), as all
those solutions are used for their own specific use cases.
"""
-
- default = {
- 'type': 'macsec',
- 'security_cipher': '',
- 'source_interface': ''
- }
+ iftype = 'macsec'
definition = {
**Interface.definition,
**{
@@ -40,8 +35,6 @@ class MACsecIf(Interface):
'prefixes': ['macsec', ],
},
}
- options = Interface.options + \
- ['security_cipher', 'source_interface']
def _create(self):
"""
@@ -49,9 +42,9 @@ class MACsecIf(Interface):
down by default.
"""
# create tunnel interface
- cmd = 'ip link add link {source_interface} {ifname} type {type}'
- cmd += ' cipher {security_cipher}'
- self._cmd(cmd.format(**self.config))
+ cmd = 'ip link add link {source_interface} {ifname} type {type}'.format(**self.config)
+ cmd += f' cipher {self.config["security"]["cipher"]}'
+ self._cmd(cmd)
# interface is always A/D down. It needs to be enabled explicitly
self.set_admin_state('down')
diff --git a/python/vyos/ifconfig/macvlan.py b/python/vyos/ifconfig/macvlan.py
index 2447fec77..73e2eea9e 100644
--- a/python/vyos/ifconfig/macvlan.py
+++ b/python/vyos/ifconfig/macvlan.py
@@ -1,4 +1,4 @@
-# Copyright 2019-2020 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 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
@@ -20,13 +20,7 @@ class MACVLANIf(Interface):
"""
Abstraction of a Linux MACvlan interface
"""
-
- default = {
- 'type': 'macvlan',
- 'address': '',
- 'source_interface': '',
- 'mode': '',
- }
+ iftype = 'macvlan'
definition = {
**Interface.definition,
**{
@@ -34,17 +28,10 @@ class MACVLANIf(Interface):
'prefixes': ['peth', ],
},
}
- options = Interface.options + \
- ['source_interface', 'mode']
def _create(self):
# please do not change the order when assembling the command
- cmd = 'ip link add {ifname}'
- if self.config['source_interface']:
- cmd += ' link {source_interface}'
- cmd += ' type macvlan'
- if self.config['mode']:
- cmd += ' mode {mode}'
+ cmd = 'ip link add {ifname} link {source_interface} type {type} mode {mode}'
self._cmd(cmd.format(**self.config))
def set_mode(self, mode):
diff --git a/python/vyos/ifconfig/pppoe.py b/python/vyos/ifconfig/pppoe.py
deleted file mode 100644
index 787245696..000000000
--- a/python/vyos/ifconfig/pppoe.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 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/>.
-
-
-from vyos.ifconfig.interface import Interface
-
-
-@Interface.register
-class PPPoEIf(Interface):
- default = {
- 'type': 'pppoe',
- }
- definition = {
- **Interface.definition,
- **{
- 'section': 'pppoe',
- 'prefixes': ['pppoe', ],
- },
- }
-
- # stub this interface is created in the configure script
-
- def _create(self):
- # we can not create this interface as it is managed outside
- pass
-
- def _delete(self):
- # we can not create this interface as it is managed outside
- pass
diff --git a/python/vyos/ifconfig/tunnel.py b/python/vyos/ifconfig/tunnel.py
index 4320bf8bc..bb940b0cf 100644
--- a/python/vyos/ifconfig/tunnel.py
+++ b/python/vyos/ifconfig/tunnel.py
@@ -1,4 +1,4 @@
-# Copyright 2019-2020 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 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
@@ -16,13 +16,12 @@
# https://developers.redhat.com/blog/2019/05/17/an-introduction-to-linux-virtual-interfaces-tunnels/
# https://community.hetzner.com/tutorials/linux-setup-gre-tunnel
-from copy import deepcopy
-
from netaddr import EUI
from netaddr import mac_unix_expanded
from random import getrandbits
from vyos.ifconfig.interface import Interface
+from vyos.util import dict_search
from vyos.validate import assert_list
def enable_to_on(value):
@@ -32,11 +31,10 @@ def enable_to_on(value):
return 'off'
raise ValueError(f'expect enable or disable but got "{value}"')
-
@Interface.register
-class _Tunnel(Interface):
+class TunnelIf(Interface):
"""
- _Tunnel: private base class for tunnels
+ Tunnel: private base class for tunnels
https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/ip/tunnel.c
https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/ip/ip6tunnel.c
"""
@@ -48,16 +46,30 @@ class _Tunnel(Interface):
},
}
- default = {
- 'local' : '',
- 'remote': '',
- 'dev' : '',
- 'ttl' : '',
- 'tos' : '',
- 'key' : '',
- 'raw' : '',
+ # This table represents a mapping from VyOS internal config dict to
+ # arguments used by iproute2. For more information please refer to:
+ # - https://man7.org/linux/man-pages/man8/ip-link.8.html
+ # - https://man7.org/linux/man-pages/man8/ip-tunnel.8.html
+ mapping = {
+ 'source_address' : 'local',
+ 'source_interface' : 'dev',
+ 'remote' : 'remote',
+ 'parameters.ip.key' : 'key',
+ 'parameters.ip.tos' : 'tos',
+ 'parameters.ip.ttl' : 'ttl',
+ }
+ mapping_ipv4 = {
+ 'parameters.ip.key' : 'key',
+ 'parameters.ip.no_pmtu_discovery' : 'nopmtudisc',
+ 'parameters.ip.tos' : 'tos',
+ 'parameters.ip.ttl' : 'ttl',
+ }
+ mapping_ipv6 = {
+ 'parameters.ipv6.encaplimit' : 'encaplimit',
+ 'parameters.ipv6.flowlabel' : 'flowlabel',
+ 'parameters.ipv6.hoplimit' : 'hoplimit',
+ 'parameters.ipv6.tclass' : 'tclass',
}
- options = Interface.options + list(default.keys())
# TODO: This is surely used for more than tunnels
# TODO: could be refactored elsewhere
@@ -76,28 +88,67 @@ class _Tunnel(Interface):
},
}
}
- _create_cmd = 'ip tunnel add {ifname} mode {type}'
+
+ def __init__(self, ifname, **kargs):
+ self.iftype = kargs['encapsulation']
+ super().__init__(ifname, **kargs)
+
+ # The gretap interface has the possibility to act as L2 bridge
+ if self.iftype == 'gretap':
+ # no multicast, ttl or tos for gretap
+ self.definition = {
+ **TunnelIf.definition,
+ **{
+ 'bridgeable': True,
+ },
+ }
+
def _create(self):
- # add " option-name option-name-value ..." for all options set
- options = ' '.join(['{} {}'.format(k, self.config[k])
- for k,v in self.config.items() if v and k not in
- ['ifname', 'type', 'raw']])
- if 'raw' in self.config:
- options += ' ' + ' '.join(self.config['raw'])
- self._cmd('{} {}'.format(self._create_cmd.format(**self.config), options))
- self.set_admin_state('down')
+ if self.config['encapsulation'] in ['ipip6', 'ip6ip6', 'ip6gre']:
+ mapping = { **self.mapping, **self.mapping_ipv6 }
+ else:
+ mapping = { **self.mapping, **self.mapping_ipv4 }
+
+ cmd = 'ip tunnel add {ifname} mode {encapsulation}'
+ if self.iftype == 'gretap':
+ cmd = 'ip link add name {ifname} type {encapsulation}'
+ for vyos_key, iproute2_key in mapping.items():
+ # dict_search will return an empty dict "{}" for valueless nodes like
+ # "parameters.nolearning" - thus we need to test the nodes existence
+ # by using isinstance()
+ tmp = dict_search(vyos_key, self.config)
+ if isinstance(tmp, dict):
+ cmd += f' {iproute2_key}'
+ elif tmp != None:
+ cmd += f' {iproute2_key} {tmp}'
+
+ self._cmd(cmd.format(**self.config))
- def change_options(self):
- change = 'ip tunnel change {ifname} mode {type}'
+ self.set_admin_state('down')
- # add " option-name option-name-value ..." for all options set
- options = ' '.join(['{} {}'.format(k, self.config[k])
- for k,v in self.config.items() if v and k not in
- ['ifname', 'type', 'raw']])
- if 'raw' in self.config:
- options += ' ' + ' '.join(self.config['raw'])
- self._cmd('{} {}'.format(change.format(**self.config), options))
+ def _change_options(self):
+ # gretap interfaces do not support changing any parameter
+ if self.iftype == 'gretap':
+ return
+
+ if self.config['encapsulation'] in ['ipip6', 'ip6ip6', 'ip6gre']:
+ mapping = { **self.mapping, **self.mapping_ipv6 }
+ else:
+ mapping = { **self.mapping, **self.mapping_ipv4 }
+
+ cmd = 'ip tunnel change {ifname} mode {encapsulation}'
+ for vyos_key, iproute2_key in mapping.items():
+ # dict_search will return an empty dict "{}" for valueless nodes like
+ # "parameters.nolearning" - thus we need to test the nodes existence
+ # by using isinstance()
+ tmp = dict_search(vyos_key, self.config)
+ if isinstance(tmp, dict):
+ cmd += f' {iproute2_key}'
+ elif tmp != None:
+ cmd += f' {iproute2_key} {tmp}'
+
+ self._cmd(cmd.format(**self.config))
def get_mac(self):
"""
@@ -128,6 +179,8 @@ class _Tunnel(Interface):
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. """
+ # Adjust iproute2 tunnel parameters if necessary
+ self._change_options()
# call base class first
super().update(config)
@@ -141,159 +194,3 @@ class _Tunnel(Interface):
# reconfiguration.
state = 'down' if 'disable' in config else 'up'
self.set_admin_state(state)
-
-class GREIf(_Tunnel):
- """
- GRE: Generic Routing Encapsulation
-
- For more information please refer to:
- RFC1701, RFC1702, RFC2784
- https://tools.ietf.org/html/rfc2784
- https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/ip/link_gre.c
- """
-
- default = {
- **_Tunnel.default,
- **{
- 'type': 'gre',
- 'raw' : ['pmtudisc'], # parameters that we can pass raw to ip command
- },
- }
-
-# GreTap also called GRE Bridge
-class GRETapIf(_Tunnel):
- """
- GRETapIF: GreIF using TAP instead of TUN
-
- https://en.wikipedia.org/wiki/TUN/TAP
- """
- # no multicast, ttl or tos for gretap
- definition = {
- **_Tunnel.definition,
- **{
- 'bridgeable': True,
- },
- }
- default = {
- 'type': 'gretap',
- 'local': '',
- 'remote': '',
- 'dev': '',
- 'raw' : ['pmtudisc'], # parameters that we can pass raw to ip command
- }
-
- _create_cmd = 'ip link add name {ifname} type {type}'
-
- def change_options(self):
- pass
-
-class IP6GREIf(_Tunnel):
- """
- IP6Gre: IPv6 Support for Generic Routing Encapsulation (GRE)
-
- For more information please refer to:
- https://tools.ietf.org/html/rfc7676
- https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/ip/link_gre6.c
- """
- default = {
- **_Tunnel.default,
- **{
- 'type': 'ip6gre',
- 'encaplimit': '',
- 'hoplimit': '',
- 'tclass': '',
- 'flowlabel': '',
- },
- }
-
-class IPIPIf(_Tunnel):
- """
- IPIP: IP Encapsulation within IP
-
- For more information please refer to:
- https://tools.ietf.org/html/rfc2003
- """
- # IPIP does not allow to pass multicast, unlike GRE
- # but the interface itself can be set with multicast
- default = {
- **_Tunnel.default,
- **{
- 'type': 'ipip',
- 'raw' : ['pmtudisc'], # parameters that we can pass raw to ip command
- },
- }
-
-class IPIP6If(_Tunnel):
- """
- IPIP6: IPv4 over IPv6 tunnel
-
- For more information please refer to:
- https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/ip/link_ip6tnl.c
- """
- default = {
- **_Tunnel.default,
- **{
- 'type': 'ipip6',
- 'encaplimit': '',
- 'hoplimit': '',
- 'tclass': '',
- 'flowlabel': '',
- },
- }
-
-class IP6IP6If(IPIP6If):
- """
- IP6IP6: IPv6 over IPv6 tunnel
-
- For more information please refer to:
- https://tools.ietf.org/html/rfc2473
- """
- default = {
- **_Tunnel.default,
- **{
- 'type': 'ip6ip6',
- },
- }
-
-
-class SitIf(_Tunnel):
- """
- Sit: Simple Internet Transition
-
- For more information please refer to:
- https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/ip/link_iptnl.c
- """
- default = {
- **_Tunnel.default,
- **{
- 'type': 'sit',
- },
- }
-
-class Sit6RDIf(SitIf):
- """
- Sit6RDIf: Simple Internet Transition with 6RD
-
- https://en.wikipedia.org/wiki/IPv6_rapid_deployment
- """
- # TODO: check if key can really be used with 6RD
- default = {
- **_Tunnel.default,
- **{
- 'type': '6rd',
- '6rd_prefix' : '',
- '6rd_relay_prefix' : '',
- },
- }
-
- def _create(self):
- # do not call _Tunnel.create, building fully here
-
- create = 'ip tunnel add {ifname} mode {type} remote {remote}'
- self._cmd(create.format(**self.config))
- self.set_interface('state','down')
-
- set6rd = 'ip tunnel 6rd dev {ifname} 6rd-prefix {6rd-prefix}'
- if '6rd-relay-prefix' in self.config:
- set6rd += ' 6rd-relay-prefix {6rd-relay-prefix}'
- self._cmd(set6rd.format(**self.config))
diff --git a/python/vyos/ifconfig/vti.py b/python/vyos/ifconfig/vti.py
index d0745898c..e2090c889 100644
--- a/python/vyos/ifconfig/vti.py
+++ b/python/vyos/ifconfig/vti.py
@@ -1,4 +1,4 @@
-# Copyright 2020 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2021 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
@@ -17,9 +17,7 @@ from vyos.ifconfig.interface import Interface
@Interface.register
class VTIIf(Interface):
- default = {
- 'type': 'vti',
- }
+ iftype = 'vti'
definition = {
**Interface.definition,
**{
diff --git a/python/vyos/ifconfig/vtun.py b/python/vyos/ifconfig/vtun.py
index 99a592b3e..8f027cf9d 100644
--- a/python/vyos/ifconfig/vtun.py
+++ b/python/vyos/ifconfig/vtun.py
@@ -1,4 +1,4 @@
-# Copyright 2020 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2020-2021 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
@@ -17,10 +17,7 @@ from vyos.ifconfig.interface import Interface
@Interface.register
class VTunIf(Interface):
- default = {
- 'type': 'vtun',
- 'device_type': 'tun',
- }
+ iftype = 'vtun'
definition = {
**Interface.definition,
**{
@@ -29,7 +26,6 @@ class VTunIf(Interface):
'bridgeable': True,
},
}
- options = Interface.options + ['device_type']
def _create(self):
""" Depending on OpenVPN operation mode the interface is created
diff --git a/python/vyos/ifconfig/vxlan.py b/python/vyos/ifconfig/vxlan.py
index ad1f605ed..291332a77 100644
--- a/python/vyos/ifconfig/vxlan.py
+++ b/python/vyos/ifconfig/vxlan.py
@@ -1,4 +1,4 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 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
@@ -15,6 +15,7 @@
from vyos import ConfigError
from vyos.ifconfig.interface import Interface
+from vyos.util import dict_search
@Interface.register
class VXLANIf(Interface):
@@ -38,16 +39,7 @@ class VXLANIf(Interface):
https://www.kernel.org/doc/Documentation/networking/vxlan.txt
"""
- default = {
- 'type': 'vxlan',
- 'group': '',
- 'port': 8472, # The Linux implementation of VXLAN pre-dates
- # the IANA's selection of a standard destination port
- 'remote': '',
- 'source_address': '',
- 'source_interface': '',
- 'vni': 0
- }
+ iftype = 'vxlan'
definition = {
**Interface.definition,
**{
@@ -56,44 +48,35 @@ class VXLANIf(Interface):
'bridgeable': True,
}
}
- options = Interface.options + \
- ['group', 'remote', 'source_interface', 'port', 'vni', 'source_address']
-
- mapping = {
- 'ifname': 'add',
- 'vni': 'id',
- 'port': 'dstport',
- 'source_address': 'local',
- 'source_interface': 'dev',
- }
def _create(self):
- cmdline = ['ifname', 'type', 'vni', 'port']
-
- if self.config['source_address']:
- cmdline.append('source_address')
-
- if self.config['remote']:
- cmdline.append('remote')
-
- if self.config['group'] or self.config['source_interface']:
- if self.config['group'] and self.config['source_interface']:
- cmdline.append('group')
- cmdline.append('source_interface')
- else:
- ifname = self.config['ifname']
- raise ConfigError(
- f'VXLAN "{ifname}" is missing mandatory underlay multicast'
- 'group or source interface for a multicast network.')
-
- cmd = 'ip link'
- for key in cmdline:
- value = self.config.get(key, '')
- if not value:
- continue
- cmd += ' {} {}'.format(self.mapping.get(key, key), value)
+ # This table represents a mapping from VyOS internal config dict to
+ # arguments used by iproute2. For more information please refer to:
+ # - https://man7.org/linux/man-pages/man8/ip-link.8.html
+ mapping = {
+ 'source_address' : 'local',
+ 'source_interface' : 'dev',
+ 'remote' : 'remote',
+ 'group' : 'group',
+ 'parameters.ip.tos' : 'tos',
+ 'parameters.ip.ttl' : 'ttl',
+ 'parameters.ipv6.flowlabel' : 'flowlabel',
+ 'parameters.nolearning' : 'nolearning',
+ }
- self._cmd(cmd)
+ cmd = 'ip link add {ifname} type {type} id {vni} dstport {port}'
+ for vyos_key, iproute2_key in mapping.items():
+ # dict_search will return an empty dict "{}" for valueless nodes like
+ # "parameters.nolearning" - thus we need to test the nodes existence
+ # by using isinstance()
+ tmp = dict_search(vyos_key, self.config)
+ if isinstance(tmp, dict):
+ cmd += f' {iproute2_key}'
+ elif tmp != None:
+ cmd += f' {iproute2_key} {tmp}'
+
+ self._cmd(cmd.format(**self.config))
+ self.set_admin_state('down')
def update(self, config):
""" General helper function which works on a dictionary retrived by
diff --git a/python/vyos/ifconfig/wireguard.py b/python/vyos/ifconfig/wireguard.py
index 9ee798ee8..f377e2b1d 100644
--- a/python/vyos/ifconfig/wireguard.py
+++ b/python/vyos/ifconfig/wireguard.py
@@ -1,4 +1,4 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 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
@@ -148,18 +148,7 @@ class WireGuardOperational(Operational):
@Interface.register
class WireGuardIf(Interface):
OperationalClass = WireGuardOperational
-
- default = {
- 'type': 'wireguard',
- 'port': 0,
- 'private_key': None,
- 'pubkey': None,
- 'psk': '',
- 'allowed_ips': [],
- 'fwmark': 0x00,
- 'endpoint': None,
- 'keepalive': 0
- }
+ iftype = 'wireguard'
definition = {
**Interface.definition,
**{
@@ -168,9 +157,6 @@ class WireGuardIf(Interface):
'bridgeable': False,
}
}
- options = Interface.options + \
- ['port', 'private_key', 'pubkey', 'psk',
- 'allowed_ips', 'fwmark', 'endpoint', 'keepalive']
def get_mac(self):
"""
diff --git a/python/vyos/ifconfig/wireless.py b/python/vyos/ifconfig/wireless.py
index 37703d242..6c0eeec44 100644
--- a/python/vyos/ifconfig/wireless.py
+++ b/python/vyos/ifconfig/wireless.py
@@ -1,4 +1,4 @@
-# Copyright 2020 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2020-2021 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
@@ -20,11 +20,7 @@ class WiFiIf(Interface):
"""
Handle WIFI/WLAN interfaces.
"""
-
- default = {
- 'type': 'wifi',
- 'phy': 'phy0'
- }
+ iftype = 'wifi'
definition = {
**Interface.definition,
**{
@@ -33,14 +29,10 @@ class WiFiIf(Interface):
'bridgeable': True,
}
}
- options = Interface.options + \
- ['phy', 'op_mode']
-
def _create(self):
# all interfaces will be added in monitor mode
- cmd = 'iw phy {phy} interface add {ifname} type monitor' \
- .format(**self.config)
- self._cmd(cmd)
+ cmd = 'iw phy {physical_device} interface add {ifname} type monitor'
+ self._cmd(cmd.format(**self.config))
# wireless interface is administratively down by default
self.set_admin_state('down')
@@ -81,14 +73,3 @@ class WiFiIf(Interface):
# reconfiguration.
state = 'down' if 'disable' in config else 'up'
self.set_admin_state(state)
-
-
-@Interface.register
-class WiFiModemIf(WiFiIf):
- definition = {
- **WiFiIf.definition,
- **{
- 'section': 'wirelessmodem',
- 'prefixes': ['wlm', ],
- }
- }
diff --git a/smoketest/configs/tunnel-broker b/smoketest/configs/tunnel-broker
new file mode 100644
index 000000000..54e63abda
--- /dev/null
+++ b/smoketest/configs/tunnel-broker
@@ -0,0 +1,103 @@
+interfaces {
+ dummy dum0 {
+ address 192.0.2.0/32
+ }
+ dummy dum1 {
+ address 192.0.2.1/32
+ }
+ dummy dum2 {
+ address 192.0.2.2/32
+ }
+ dummy dum3 {
+ address 192.0.2.3/32
+ }
+ dummy dum4 {
+ address 192.0.2.4/32
+ }
+ ethernet eth0 {
+ duplex auto
+ smp-affinity auto
+ speed auto
+ address 172.18.202.10/24
+ }
+ tunnel tun100 {
+ address 172.16.0.1/30
+ encapsulation gre-bridge
+ local-ip 192.0.2.0
+ remote-ip 192.0.2.100
+ }
+ tunnel tun200 {
+ address 172.16.0.5/30
+ encapsulation gre
+ local-ip 192.0.2.1
+ remote-ip 192.0.2.101
+ }
+ tunnel tun300 {
+ address 172.16.0.9/30
+ encapsulation ipip
+ local-ip 192.0.2.2
+ remote-ip 192.0.2.102
+ }
+ tunnel tun400 {
+ address 172.16.0.13/30
+ encapsulation gre-bridge
+ local-ip 192.0.2.3
+ remote-ip 192.0.2.103
+ }
+ tunnel tun500 {
+ address 172.16.0.17/30
+ encapsulation gre
+ local-ip 192.0.2.4
+ remote-ip 192.0.2.104
+ }
+}
+protocols {
+ static {
+ route 0.0.0.0/0 {
+ next-hop 172.18.202.1 {
+ distance 10
+ }
+ }
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0
+ plaintext-password ""
+ }
+ }
+ }
+ ntp {
+ server 0.pool.ntp.org {
+ }
+ server 1.pool.ntp.org {
+ }
+ server 2.pool.ntp.org {
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+}
+
+/* Warning: Do not remove the following line. */
+/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@10:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */
+/* Release version: 1.2.6-S1 */
diff --git a/smoketest/scripts/cli/test_interfaces_erspan.py b/smoketest/scripts/cli/test_interfaces_erspan.py
index c180f0a34..d0814f2fb 100755
--- a/smoketest/scripts/cli/test_interfaces_erspan.py
+++ b/smoketest/scripts/cli/test_interfaces_erspan.py
@@ -27,51 +27,6 @@ mtu = 1500
def erspan_conf(interface):
tmp = cmd(f'ip -d -j link show {interface}')
- '''
- [
- {
- "ifindex": 17,
- "link": null,
- "ifname": "ersp0",
- "flags": [
- "BROADCAST",
- "MULTICAST"
- ],
- "mtu": 1450,
- "qdisc": "noop",
- "operstate": "DOWN",
- "linkmode": "DEFAULT",
- "group": "default",
- "txqlen": 1000,
- "link_type": "ether",
- "address": "22:27:14:7b:0d:79",
- "broadcast": "ff:ff:ff:ff:ff:ff",
- "promiscuity": 0,
- "min_mtu": 68,
- "max_mtu": 0,
- "linkinfo": {
- "info_kind": "erspan",
- "info_data": {
- "remote": "10.2.2.2",
- "local": "10.1.1.1",
- "ttl": 0,
- "pmtudisc": true,
- "ikey": "0.0.0.123",
- "okey": "0.0.0.123",
- "iseq": true,
- "oseq": true,
- "erspan_index": 0,
- "erspan_ver": 1
- }
- },
- "inet6_addr_gen_mode": "eui64",
- "num_tx_queues": 1,
- "num_rx_queues": 1,
- "gso_max_size": 65536,
- "gso_max_segs": 65535
- }
- ]
- '''
return json.loads(tmp)[0]
class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest):
@@ -96,8 +51,8 @@ class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest):
key = 123
self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
- self.session.set(self._base_path + [interface, 'remote-ip', self.remote_v4])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v4])
+ self.session.set(self._base_path + [interface, 'remote', self.remote_v4])
self.session.set(self._base_path + [interface, 'parameters', 'ip' , 'key', str(key)])
self.session.commit()
@@ -107,8 +62,8 @@ class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest):
self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
self.assertEqual(mtu, conf['mtu'])
- self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local'])
- self.assertEqual(self.remote_v4, conf['linkinfo']['info_data']['remote'])
+ self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local'])
+ self.assertEqual(self.remote_v4, conf['linkinfo']['info_data']['remote'])
def test_erspan_ipv6(self):
@@ -117,8 +72,8 @@ class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest):
key = 123
self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v6])
- self.session.set(self._base_path + [interface, 'remote-ip', self.remote_v6])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v6])
+ self.session.set(self._base_path + [interface, 'remote', self.remote_v6])
self.session.set(self._base_path + [interface, 'parameters', 'ip' , 'key', str(key)])
self.session.commit()
@@ -128,8 +83,8 @@ class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest):
self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
self.assertEqual(mtu, conf['mtu'])
- self.assertEqual(self.local_v6, conf['linkinfo']['info_data']['local'])
- self.assertEqual(self.remote_v6, conf['linkinfo']['info_data']['remote'])
+ self.assertEqual(self.local_v6, conf['linkinfo']['info_data']['local'])
+ self.assertEqual(self.remote_v6, conf['linkinfo']['info_data']['remote'])
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_interfaces_macsec.py b/smoketest/scripts/cli/test_interfaces_macsec.py
index 3a3e7bff3..d6bef993a 100755
--- a/smoketest/scripts/cli/test_interfaces_macsec.py
+++ b/smoketest/scripts/cli/test_interfaces_macsec.py
@@ -14,6 +14,7 @@
# 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 re
import unittest
@@ -22,6 +23,7 @@ from netifaces import interfaces
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
+from vyos.util import cmd
from vyos.util import read_file
from vyos.util import process_named_running
@@ -30,6 +32,16 @@ def get_config_value(interface, key):
tmp = re.findall(r'\n?{}=(.*)'.format(key), tmp)
return tmp[0]
+def get_cipher(interface):
+ """ Returns the used encapsulation protocol for given interface.
+ If interface does not exist, None is returned.
+ """
+ if not os.path.exists(f'/sys/class/net/{interface}'):
+ return None
+ from json import loads
+ tmp = loads(cmd(f'ip -d -j link show {interface}'))[0]
+ return tmp['linkinfo']['info_data']['cipher_suite'].lower()
+
class MACsecInterfaceTest(BasicInterfaceTest.BaseTest):
@classmethod
def setUpClass(cls):
@@ -107,8 +119,30 @@ class MACsecInterfaceTest(BasicInterfaceTest.BaseTest):
# Check for running process
self.assertTrue(process_named_running('wpa_supplicant'))
- def test_macsec_mandatory_options(self):
+ def test_macsec_gcm_aes_128(self):
interface = 'macsec1'
+ cipher = 'gcm-aes-128'
+ self.session.set(self._base_path + [interface])
+
+ # check validate() - source interface is mandatory
+ with self.assertRaises(ConfigSessionError):
+ self.session.commit()
+ self.session.set(self._base_path + [interface, 'source-interface', 'eth0'])
+
+ # check validate() - cipher is mandatory
+ with self.assertRaises(ConfigSessionError):
+ self.session.commit()
+ self.session.set(self._base_path + [interface, 'security', 'cipher', cipher])
+
+ # final commit and verify
+ self.session.commit()
+ self.assertIn(interface, interfaces())
+ self.assertIn(interface, interfaces())
+ self.assertEqual(cipher, get_cipher(interface))
+
+ def test_macsec_gcm_aes_256(self):
+ interface = 'macsec4'
+ cipher = 'gcm-aes-256'
self.session.set(self._base_path + [interface])
# check validate() - source interface is mandatory
@@ -119,11 +153,12 @@ class MACsecInterfaceTest(BasicInterfaceTest.BaseTest):
# check validate() - cipher is mandatory
with self.assertRaises(ConfigSessionError):
self.session.commit()
- self.session.set(self._base_path + [interface, 'security', 'cipher', 'gcm-aes-128'])
+ self.session.set(self._base_path + [interface, 'security', 'cipher', cipher])
# final commit and verify
self.session.commit()
self.assertIn(interface, interfaces())
+ self.assertEqual(cipher, get_cipher(interface))
def test_macsec_source_interface(self):
# Ensure source-interface can bot be part of any other bond or bridge
diff --git a/smoketest/scripts/cli/test_interfaces_tunnel.py b/smoketest/scripts/cli/test_interfaces_tunnel.py
index a9250e3e5..cc8fbd527 100755
--- a/smoketest/scripts/cli/test_interfaces_tunnel.py
+++ b/smoketest/scripts/cli/test_interfaces_tunnel.py
@@ -20,6 +20,7 @@ import json
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.util import cmd
+from vyos.template import inc_ip
from base_interfaces_test import BasicInterfaceTest
@@ -70,8 +71,8 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
cls.local_v4 = '192.0.2.1'
cls.local_v6 = '2001:db8::1'
cls._options = {
- 'tun10': ['encapsulation ipip', 'remote-ip 192.0.2.10', 'local-ip ' + cls.local_v4],
- 'tun20': ['encapsulation gre', 'remote-ip 192.0.2.20', 'local-ip ' + cls.local_v4],
+ 'tun10': ['encapsulation ipip', 'remote 192.0.2.10', 'source-address ' + cls.local_v4],
+ 'tun20': ['encapsulation gre', 'remote 192.0.2.20', 'source-address ' + cls.local_v4],
}
cls._interfaces = list(cls._options)
@@ -90,25 +91,25 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
interface = f'tun1000'
local_if_addr = f'10.10.200.1/24'
- for encapsulation in ['ipip', 'sit', 'gre', 'gre-bridge']:
+ for encapsulation in ['ipip', 'sit', 'gre', 'gretap']:
self.session.set(self._base_path + [interface, 'address', local_if_addr])
self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v6])
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip6])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v6])
+ self.session.set(self._base_path + [interface, 'remote', remote_ip6])
- # Encapsulation mode requires IPv4 local-ip
+ # Encapsulation mode requires IPv4 source-address
with self.assertRaises(ConfigSessionError):
self.session.commit()
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v4])
- # Encapsulation mode requires IPv4 local-ip
+ # Encapsulation mode requires IPv4 remote
with self.assertRaises(ConfigSessionError):
self.session.commit()
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4])
+ self.session.set(self._base_path + [interface, 'remote', remote_ip4])
self.session.set(self._base_path + [interface, 'source-interface', source_if])
- # Source interface can not be used with sit and gre-bridge
- if encapsulation in ['sit', 'gre-bridge']:
+ # Source interface can not be used with sit and gretap
+ if encapsulation in ['sit', 'gretap']:
with self.assertRaises(ConfigSessionError):
self.session.commit()
self.session.delete(self._base_path + [interface, 'source-interface'])
@@ -117,17 +118,14 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
self.session.commit()
conf = tunnel_conf(interface)
- self.assertEqual(interface, conf['ifname'])
- self.assertEqual(mtu, conf['mtu'])
-
- if encapsulation not in ['sit', 'gre-bridge']:
+ if encapsulation not in ['sit', 'gretap']:
self.assertEqual(source_if, conf['link'])
- self.assertEqual(encapsulation, conf['link_type'])
- elif encapsulation in ['gre-bridge']:
- self.assertEqual('ether', conf['link_type'])
+ self.assertEqual(interface, conf['ifname'])
+ self.assertEqual(mtu, conf['mtu'])
+ self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local'])
- self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote'])
+ self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote'])
self.assertTrue(conf['linkinfo']['info_data']['pmtudisc'])
# cleanup this instance
@@ -143,18 +141,18 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
for encapsulation in ['ipip6', 'ip6ip6', 'ip6gre']:
self.session.set(self._base_path + [interface, 'address', local_if_addr])
self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v4])
+ self.session.set(self._base_path + [interface, 'remote', remote_ip4])
- # Encapsulation mode requires IPv6 local-ip
+ # Encapsulation mode requires IPv6 source-address
with self.assertRaises(ConfigSessionError):
self.session.commit()
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v6])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v6])
- # Encapsulation mode requires IPv6 local-ip
+ # Encapsulation mode requires IPv6 remote
with self.assertRaises(ConfigSessionError):
self.session.commit()
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip6])
+ self.session.set(self._base_path + [interface, 'remote', remote_ip6])
# Configure Tunnel Source interface
self.session.set(self._base_path + [interface, 'source-interface', source_if])
@@ -167,14 +165,15 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
self.assertEqual(mtu, conf['mtu'])
self.assertEqual(source_if, conf['link'])
- # remap encapsulation protocol(s)
- if encapsulation in ['ipip6', 'ip6ip6']:
- encapsulation = 'tunnel6'
- elif encapsulation in ['ip6gre']:
- encapsulation = 'gre6'
+ # Not applicable for ip6gre
+ if 'proto' in conf['linkinfo']['info_data']:
+ self.assertEqual(encapsulation, conf['linkinfo']['info_data']['proto'])
- self.assertEqual(encapsulation, conf['link_type'])
+ # remap encapsulation protocol(s) only for ipip6, ip6ip6
+ if encapsulation in ['ipip6', 'ip6ip6']:
+ encapsulation = 'ip6tnl'
+ self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
self.assertEqual(self.local_v6, conf['linkinfo']['info_data']['local'])
self.assertEqual(remote_ip6, conf['linkinfo']['info_data']['remote'])
@@ -183,18 +182,18 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
self.session.commit()
def test_tunnel_verify_local_dhcp(self):
- # We can not use local-ip and dhcp-interface at the same time
+ # We can not use source-address and dhcp-interface at the same time
interface = f'tun1020'
local_if_addr = f'10.0.0.1/24'
self.session.set(self._base_path + [interface, 'address', local_if_addr])
self.session.set(self._base_path + [interface, 'encapsulation', 'gre'])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v4])
+ self.session.set(self._base_path + [interface, 'remote', remote_ip4])
self.session.set(self._base_path + [interface, 'dhcp-interface', 'eth0'])
- # local-ip and dhcp-interface can not be used at the same time
+ # source-address and dhcp-interface can not be used at the same time
with self.assertRaises(ConfigSessionError):
self.session.commit()
self.session.delete(self._base_path + [interface, 'dhcp-interface'])
@@ -209,8 +208,8 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
tos = '20'
self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
- self.session.set(self._base_path + [interface, 'local-ip', self.local_v4])
- self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v4])
+ self.session.set(self._base_path + [interface, 'remote', remote_ip4])
self.session.set(self._base_path + [interface, 'parameters', 'ip', 'no-pmtu-discovery'])
self.session.set(self._base_path + [interface, 'parameters', 'ip', 'key', gre_key])
@@ -222,11 +221,41 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest):
conf = tunnel_conf(interface)
self.assertEqual(mtu, conf['mtu'])
self.assertEqual(interface, conf['ifname'])
- self.assertEqual(encapsulation, conf['link_type'])
+ self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local'])
self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote'])
self.assertEqual(0, conf['linkinfo']['info_data']['ttl'])
self.assertFalse( conf['linkinfo']['info_data']['pmtudisc'])
+ def test_gretap_parameters_change(self):
+ interface = f'tun1040'
+ gre_key = '10'
+ encapsulation = 'gretap'
+ tos = '20'
+
+ self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
+ self.session.set(self._base_path + [interface, 'source-address', self.local_v4])
+ self.session.set(self._base_path + [interface, 'remote', remote_ip4])
+
+ # Check if commit is ok
+ self.session.commit()
+
+ conf = tunnel_conf(interface)
+ self.assertEqual(mtu, conf['mtu'])
+ self.assertEqual(interface, conf['ifname'])
+ self.assertEqual(encapsulation, conf['linkinfo']['info_kind'])
+ self.assertEqual(self.local_v4, conf['linkinfo']['info_data']['local'])
+ self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote'])
+ self.assertEqual(0, conf['linkinfo']['info_data']['ttl'])
+
+ # Change remote ip address (inc host by 2
+ new_remote = inc_ip(remote_ip4, 2)
+ self.session.set(self._base_path + [interface, 'remote', new_remote])
+ # Check if commit is ok
+ self.session.commit()
+
+ conf = tunnel_conf(interface)
+ self.assertEqual(new_remote, conf['linkinfo']['info_data']['remote'])
+
if __name__ == '__main__':
- unittest.main(verbosity=2)
+ unittest.main(verbosity=2, failfast=True)
diff --git a/src/conf_mode/interfaces-erspan.py b/src/conf_mode/interfaces-erspan.py
index 2d65b834c..97ae3cf55 100755
--- a/src/conf_mode/interfaces-erspan.py
+++ b/src/conf_mode/interfaces-erspan.py
@@ -48,7 +48,7 @@ def get_config(config=None):
conf = Config()
base = ['interfaces', 'erspan']
erspan = get_interface_dict(conf, base)
-
+
tmp = leaf_node_changed(conf, ['encapsulation'])
if tmp:
erspan.update({'encapsulation_changed': {}})
@@ -58,30 +58,30 @@ def get_config(config=None):
def verify(erspan):
if 'deleted' in erspan:
return None
-
+
if 'encapsulation' not in erspan:
raise ConfigError('Unable to detect the following ERSPAN tunnel encapsulation'\
'{ifname}!'.format(**erspan))
verify_mtu_ipv6(erspan)
verify_tunnel(erspan)
-
+
key = dict_search('parameters.ip.key',erspan)
if key == None:
raise ConfigError('parameters.ip.key is mandatory for ERSPAN tunnel')
-
+
def generate(erspan):
return None
def apply(erspan):
- if 'deleted' in erspan or 'encapsulation_changed' in erspan:
- if erspan['ifname'] in interfaces():
- tmp = Interface(erspan['ifname'])
- tmp.remove()
- if 'deleted' in erspan:
- return None
-
+ if 'deleted' in erspan or 'encapsulation_changed' in erspan:
+ if erspan['ifname'] in interfaces():
+ tmp = Interface(erspan['ifname'])
+ tmp.remove()
+ if 'deleted' in erspan:
+ return None
+
dispatch = {
'erspan': ERSpanIf,
'ip6erspan': ER6SpanIf
@@ -90,14 +90,8 @@ def apply(erspan):
# We need to re-map the tunnel encapsulation proto to a valid interface class
encap = erspan['encapsulation']
klass = dispatch[encap]
-
- conf = deepcopy(erspan)
-
- conf.update(klass.get_config())
-
- del conf['ifname']
-
- erspan_tunnel = klass(erspan['ifname'],**conf)
+
+ erspan_tunnel = klass(**erspan)
erspan_tunnel.change_options()
erspan_tunnel.update(erspan)
diff --git a/src/conf_mode/interfaces-geneve.py b/src/conf_mode/interfaces-geneve.py
index 979a5612e..2a63b60aa 100755
--- a/src/conf_mode/interfaces-geneve.py
+++ b/src/conf_mode/interfaces-geneve.py
@@ -72,18 +72,8 @@ def apply(geneve):
g.remove()
if 'deleted' not in geneve:
- # This is a special type of interface which needs additional parameters
- # when created using iproute2. Instead of passing a ton of arguments,
- # use a dictionary provided by the interface class which holds all the
- # options necessary.
- conf = GeneveIf.get_config()
-
- # Assign GENEVE instance configuration parameters to config dict
- conf['vni'] = geneve['vni']
- conf['remote'] = geneve['remote']
-
# Finally create the new interface
- g = GeneveIf(geneve['ifname'], **conf)
+ g = GeneveIf(**geneve)
g.update(geneve)
return None
diff --git a/src/conf_mode/interfaces-l2tpv3.py b/src/conf_mode/interfaces-l2tpv3.py
index 7b3afa058..5bae66074 100755
--- a/src/conf_mode/interfaces-l2tpv3.py
+++ b/src/conf_mode/interfaces-l2tpv3.py
@@ -83,34 +83,16 @@ def generate(l2tpv3):
return None
def apply(l2tpv3):
- # This is a special type of interface which needs additional parameters
- # when created using iproute2. Instead of passing a ton of arguments,
- # use a dictionary provided by the interface class which holds all the
- # options necessary.
- conf = L2TPv3If.get_config()
-
# Check if L2TPv3 interface already exists
if l2tpv3['ifname'] in interfaces():
# L2TPv3 is picky when changing tunnels/sessions, thus we can simply
# always delete it first.
- conf['session_id'] = l2tpv3['session_id']
- conf['tunnel_id'] = l2tpv3['tunnel_id']
- l = L2TPv3If(l2tpv3['ifname'], **conf)
+ l = L2TPv3If(**l2tpv3)
l.remove()
if 'deleted' not in l2tpv3:
- conf['peer_tunnel_id'] = l2tpv3['peer_tunnel_id']
- conf['local_port'] = l2tpv3['source_port']
- conf['remote_port'] = l2tpv3['destination_port']
- conf['encapsulation'] = l2tpv3['encapsulation']
- conf['local_address'] = l2tpv3['local_ip']
- conf['remote_address'] = l2tpv3['remote_ip']
- conf['session_id'] = l2tpv3['session_id']
- conf['tunnel_id'] = l2tpv3['tunnel_id']
- conf['peer_session_id'] = l2tpv3['peer_session_id']
-
# Finally create the new interface
- l = L2TPv3If(l2tpv3['ifname'], **conf)
+ l = L2TPv3If(**l2tpv3)
l.update(l2tpv3)
return None
diff --git a/src/conf_mode/interfaces-macsec.py b/src/conf_mode/interfaces-macsec.py
index bfebed7e4..eab69f36e 100755
--- a/src/conf_mode/interfaces-macsec.py
+++ b/src/conf_mode/interfaces-macsec.py
@@ -115,17 +115,9 @@ def apply(macsec):
os.unlink(wpa_suppl_conf.format(**macsec))
else:
- # This is a special type of interface which needs additional parameters
- # when created using iproute2. Instead of passing a ton of arguments,
- # use a dictionary provided by the interface class which holds all the
- # options necessary.
- conf = MACsecIf.get_config()
- conf['source_interface'] = macsec['source_interface']
- conf['security_cipher'] = macsec['security']['cipher']
-
# It is safe to "re-create" the interface always, there is a sanity
# check that the interface will only be create if its non existent
- i = MACsecIf(macsec['ifname'], **conf)
+ i = MACsecIf(**macsec)
i.update(macsec)
call('systemctl restart wpa_supplicant-macsec@{source_interface}'
diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py
index ee6f05fcd..4afb85526 100755
--- a/src/conf_mode/interfaces-openvpn.py
+++ b/src/conf_mode/interfaces-openvpn.py
@@ -502,10 +502,7 @@ def apply(openvpn):
# existed - nevertheless, spawn new OpenVPN process
call(f'systemctl start openvpn@{interface}.service')
- conf = VTunIf.get_config()
- conf['device_type'] = openvpn['device_type']
-
- o = VTunIf(interface, **conf)
+ o = VTunIf(**openvpn)
o.update(openvpn)
return None
diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py
index ddbef56ac..34a054837 100755
--- a/src/conf_mode/interfaces-pseudo-ethernet.py
+++ b/src/conf_mode/interfaces-pseudo-ethernet.py
@@ -75,19 +75,9 @@ def apply(peth):
if 'mode_old' in peth:
MACVLANIf(peth['ifname']).remove()
- # This is a special type of interface which needs additional parameters
- # when created using iproute2. Instead of passing a ton of arguments,
- # use a dictionary provided by the interface class which holds all the
- # options necessary.
- conf = MACVLANIf.get_config()
-
- # Assign MACVLAN instance configuration parameters to config dict
- conf['source_interface'] = peth['source_interface']
- conf['mode'] = peth['mode']
-
# It is safe to "re-create" the interface always, there is a sanity check
# that the interface will only be create if its non existent
- p = MACVLANIf(peth['ifname'], **conf)
+ p = MACVLANIf(**peth)
p.update(peth)
return None
diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py
index 87da214a8..2d2f29f94 100755
--- a/src/conf_mode/interfaces-tunnel.py
+++ b/src/conf_mode/interfaces-tunnel.py
@@ -31,21 +31,25 @@ from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_vrf
from vyos.configverify import verify_tunnel
from vyos.ifconfig import Interface
-from vyos.ifconfig import GREIf
-from vyos.ifconfig import GRETapIf
-from vyos.ifconfig import IPIPIf
-from vyos.ifconfig import IP6GREIf
-from vyos.ifconfig import IPIP6If
-from vyos.ifconfig import IP6IP6If
-from vyos.ifconfig import SitIf
-from vyos.ifconfig import Sit6RDIf
+from vyos.ifconfig import TunnelIf
from vyos.template import is_ipv4
from vyos.template import is_ipv6
+from vyos.util import cmd
from vyos.util import dict_search
from vyos import ConfigError
from vyos import airbag
airbag.enable()
+def get_tunnel_encapsulation(interface):
+ """ Returns the used encapsulation protocol for given interface.
+ If interface does not exist, None is returned.
+ """
+ if not os.path.exists(f'/sys/class/net/{interface}'):
+ return None
+ from json import loads
+ tmp = loads(cmd(f'ip -d -j link show {interface}'))[0]
+ return tmp['linkinfo']['info_kind']
+
def get_config(config=None):
"""
Retrive CLI config as dictionary. Dictionary can never be empty, as at least
@@ -79,8 +83,8 @@ def verify(tunnel):
return None
if 'encapsulation' not in tunnel:
- raise ConfigError('Must configure the tunnel encapsulation for '\
- '{ifname}!'.format(**tunnel))
+ error = 'Must configure encapsulation for "{ifname}"!'
+ raise ConfigError(error.format(**tunnel))
verify_mtu_ipv6(tunnel)
verify_address(tunnel)
@@ -103,67 +107,20 @@ def generate(tunnel):
return None
def apply(tunnel):
- if 'deleted' in tunnel or 'encapsulation_changed' in tunnel:
- if tunnel['ifname'] in interfaces():
- tmp = Interface(tunnel['ifname'])
+ interface = tunnel['ifname']
+ # If a gretap tunnel is already existing we can not "simply" change local or
+ # remote addresses. This returns "Operation not supported" by the Kernel.
+ # There is no other solution to destroy and recreate the tunnel.
+ encap = get_tunnel_encapsulation(interface)
+
+ if 'deleted' in tunnel or 'encapsulation_changed' in tunnel or encap == 'gretap':
+ if interface in interfaces():
+ tmp = Interface(interface)
tmp.remove()
if 'deleted' in tunnel:
return None
- dispatch = {
- 'gre': GREIf,
- 'gre-bridge': GRETapIf,
- 'ipip': IPIPIf,
- 'ipip6': IPIP6If,
- 'ip6ip6': IP6IP6If,
- 'ip6gre': IP6GREIf,
- 'sit': SitIf,
- }
-
- # We need to re-map the tunnel encapsulation proto to a valid interface class
- encap = tunnel['encapsulation']
- klass = dispatch[encap]
-
- # This is a special type of interface which needs additional parameters
- # when created using iproute2. Instead of passing a ton of arguments,
- # use a dictionary provided by the interface class which holds all the
- # options necessary.
- conf = klass.get_config()
-
- # Copy/re-assign our dictionary values to values understood by the
- # derived _Tunnel classes
- mapping = {
- # this : get_config()
- 'local_ip' : 'local',
- 'remote_ip' : 'remote',
- 'source_interface' : 'dev',
- 'parameters.ip.ttl' : 'ttl',
- 'parameters.ip.tos' : 'tos',
- 'parameters.ip.key' : 'key',
- }
-
- # Add additional IPv6 options if tunnel is IPv6 aware
- if tunnel['encapsulation'] in ['ipip6', 'ip6ip6', 'ip6gre']:
- mappingv6 = {
- # this : get_config()
- 'parameters.ipv6.encaplimit' : 'encaplimit',
- 'parameters.ipv6.flowlabel' : 'flowlabel',
- 'parameters.ipv6.hoplimit' : 'hoplimit',
- 'parameters.ipv6.tclass' : 'flowlabel'
- }
- mapping.update(mappingv6)
-
- for our_key, their_key in mapping.items():
- if dict_search(our_key, tunnel) and their_key in conf:
- conf[their_key] = dict_search(our_key, tunnel)
-
- if dict_search('parameters.ip.no_pmtu_discovery', tunnel) != None:
- if 'pmtudisc' in conf['raw']:
- conf['raw'].remove('pmtudisc')
- conf['raw'].append('nopmtudisc')
-
- tun = klass(tunnel['ifname'], **conf)
- tun.change_options()
+ tun = TunnelIf(**tunnel)
tun.update(tunnel)
return None
diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py
index 9a6d72772..8e6247a30 100755
--- a/src/conf_mode/interfaces-vxlan.py
+++ b/src/conf_mode/interfaces-vxlan.py
@@ -90,19 +90,8 @@ def apply(vxlan):
v.remove()
if 'deleted' not in vxlan:
- # This is a special type of interface which needs additional parameters
- # when created using iproute2. Instead of passing a ton of arguments,
- # use a dictionary provided by the interface class which holds all the
- # options necessary.
- conf = VXLANIf.get_config()
-
- # Assign VXLAN instance configuration parameters to config dict
- for tmp in ['vni', 'group', 'source_address', 'source_interface', 'remote', 'port']:
- if tmp in vxlan:
- conf[tmp] = vxlan[tmp]
-
# Finally create the new interface
- v = VXLANIf(vxlan['ifname'], **conf)
+ v = VXLANIf(**vxlan)
v.update(vxlan)
return None
diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py
index b25fcd4e0..7b3de6e8a 100755
--- a/src/conf_mode/interfaces-wireless.py
+++ b/src/conf_mode/interfaces-wireless.py
@@ -255,17 +255,8 @@ def apply(wifi):
if 'deleted' in wifi:
WiFiIf(interface).remove()
else:
- # This is a special type of interface which needs additional parameters
- # when created using iproute2. Instead of passing a ton of arguments,
- # use a dictionary provided by the interface class which holds all the
- # options necessary.
- conf = WiFiIf.get_config()
-
- # Assign WiFi instance configuration parameters to config dict
- conf['phy'] = wifi['physical_device']
-
# Finally create the new interface
- w = WiFiIf(interface, **conf)
+ w = WiFiIf(**wifi)
w.update(wifi)
# Enable/Disable interface - interface is always placed in
diff --git a/src/migration-scripts/interfaces/19-to-20 b/src/migration-scripts/interfaces/19-to-20
new file mode 100755
index 000000000..ed2780b92
--- /dev/null
+++ b/src/migration-scripts/interfaces/19-to-20
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 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/>.
+
+from sys import argv
+from sys import exit
+from vyos.configtree import ConfigTree
+
+if __name__ == '__main__':
+ if (len(argv) < 1):
+ print("Must specify file name!")
+ exit(1)
+
+ file_name = argv[1]
+ with open(file_name, 'r') as f:
+ config_file = f.read()
+
+ config = ConfigTree(config_file)
+ base = ['interfaces', 'tunnel']
+
+ if not config.exists(base):
+ # Nothing to do
+ exit(0)
+
+ #
+ # Migrate "interface tunnel <tunX> encapsulation gre-bridge" to gretap
+ # Migrate "interface tunnel <tunX> local-ip" to source-address
+ # Migrate "interface tunnel <tunX> remote-ip" to remote
+ for interface in config.list_nodes(base):
+ encap_path = base + [interface, 'encapsulation']
+ if config.exists(encap_path):
+ tmp = config.return_value(encap_path)
+ if tmp == 'gre-bridge':
+ config.set(encap_path, value='gretap')
+
+ local_ip_path = base + [interface, 'local-ip']
+ if config.exists(local_ip_path):
+ config.rename(local_ip_path, 'source-address')
+
+ remote_ip_path = base + [interface, 'remote-ip']
+ if config.exists(remote_ip_path):
+ config.rename(remote_ip_path, 'remote')
+
+ try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+ except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ exit(1)