From 8bdf5b5216ddafdcee067b5bb8e15f18799c6fe5 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 26 Feb 2021 19:10:47 +0100 Subject: vxlan: T1513: add additional EVPN related CLI options A VXLAN tunnel may now get a TTL, TOS, Flowlabel option specified. It is also possible to disable learning of unknown addresses into the forwarding database. --- .../include/interface-parameters-flowlabel.xml.i | 1 - interface-definitions/interfaces-vxlan.xml.in | 36 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) (limited to 'interface-definitions') 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 @@ Must be 'inherit' or a number - inherit diff --git a/interface-definitions/interfaces-vxlan.xml.in b/interface-definitions/interfaces-vxlan.xml.in index 234770971..2afe8685a 100644 --- a/interface-definitions/interfaces-vxlan.xml.in +++ b/interface-definitions/interfaces-vxlan.xml.in @@ -60,6 +60,42 @@ + + + VXLAN tunnel parameters + + + + + IPv4 specific tunnel parameters + + + + + Specifies the usage of the do not fragment (DF) bit + + + + #include + #include + + + + + IPv6 specific tunnel parameters + + + #include + + + + + Do not add unknown addresses into forwarding database + + + + + Destination port of VXLAN tunnel (default: 8472) -- cgit v1.2.3 From 8f100189086102458ff8e4f61f842cf44a6bf8aa Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Feb 2021 16:04:38 +0100 Subject: tunnel: T3364: rename encapsulation mode "gre-bridge" to "gretap" The following list shows the mapping of VyOS tunnel encapsulation modes to the corresponding Linux modes. VyOS Linux gre gre gre-bridge gretap ipip ipip ipip6 ipip6 ip6ip6 ip6ip6 ip6gre ip6gre sit sit Besides gre-bridge this is pretty consistent. As bridge interfaces are also called tap interfaces gre-bridge will be renamed to gretap to make the post-processing much easier. This means (in detail) that there are no more child classes of _Tunnel and there will be now one geneirc TunnelIf class handling all sorts of encapsulation. --- interface-definitions/interfaces-tunnel.xml.in | 10 +- python/vyos/configverify.py | 7 +- python/vyos/ifconfig/__init__.py | 9 +- python/vyos/ifconfig/tunnel.py | 132 +++++------------------- smoketest/configs/tunnel-broker | 103 ++++++++++++++++++ smoketest/scripts/cli/test_interfaces_tunnel.py | 65 ++++++++---- src/conf_mode/interfaces-tunnel.py | 53 +++++----- src/migration-scripts/interfaces/19-to-20 | 51 +++++++++ 8 files changed, 263 insertions(+), 167 deletions(-) create mode 100644 smoketest/configs/tunnel-broker create mode 100755 src/migration-scripts/interfaces/19-to-20 (limited to 'interface-definitions') diff --git a/interface-definitions/interfaces-tunnel.xml.in b/interface-definitions/interfaces-tunnel.xml.in index 7a97980a2..bb23ba933 100644 --- a/interface-definitions/interfaces-tunnel.xml.in +++ b/interface-definitions/interfaces-tunnel.xml.in @@ -79,15 +79,15 @@ Encapsulation of this tunnel interface - gre gre-bridge ip6gre ip6ip6 ipip ipip6 sit + gre gretap ip6gre ip6ip6 ipip ipip6 sit gre Generic Routing Encapsulation - gre-bridge - Generic Routing Encapsulation bridge interface + gretap + Generic Routing Encapsulation (virtual L2 tunnel) ip6gre @@ -110,9 +110,9 @@ Simple Internet Transition encapsulation - ^(gre|gre-bridge|ip6gre|ip6ip6|ipip|ipip6|sit)$ + ^(gre|gretap|ip6gre|ip6ip6|ipip|ipip6|sit)$ - Invalid encapsulation, must be one of: gre, gre-bridge, ipip, sit, ipip6, ip6ip6, ip6gre + Invalid encapsulation, must be one of: gre, gretap, ipip, sit, ipip6, ip6ip6, ip6gre diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py index 7be78b94b..8286a735c 100644 --- a/python/vyos/configverify.py +++ b/python/vyos/configverify.py @@ -124,10 +124,11 @@ def verify_tunnel(config): if 'remote_ip' in config and not is_ipv4(config['remote_ip']): raise ConfigError(f'{error_ipv4} remote-ip') - 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']): raise ConfigError('Can not use local IPv6 address is for mGRE tunnels') diff --git a/python/vyos/ifconfig/__init__.py b/python/vyos/ifconfig/__init__.py index 129524bda..9d797d7f1 100644 --- a/python/vyos/ifconfig/__init__.py +++ b/python/vyos/ifconfig/__init__.py @@ -30,14 +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.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/tunnel.py b/python/vyos/ifconfig/tunnel.py index 271919b90..a74d50646 100644 --- a/python/vyos/ifconfig/tunnel.py +++ b/python/vyos/ifconfig/tunnel.py @@ -32,9 +32,9 @@ def enable_to_on(value): 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 """ @@ -89,15 +89,30 @@ class _Tunnel(Interface): } } + 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): 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 {type}' - if self.config['encapsulation'] == 'gre-bridge': - cmd = 'ip link add name {ifname} type {type}' + 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 @@ -112,14 +127,17 @@ class _Tunnel(Interface): self.set_admin_state('down') - def change_options(self): + 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 } - self.config['type'] = self.iftype - cmd = 'ip tunnel change {ifname} mode {type}' + 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 @@ -161,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) @@ -174,99 +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 - """ - iftype = 'gre' - -# GreTap also called GRE Bridge -class GRETapIf(_Tunnel): - """ - GRETapIF: GreIF using TAP instead of TUN - https://en.wikipedia.org/wiki/TUN/TAP - """ - iftype = 'gretap' - # no multicast, ttl or tos for gretap - definition = { - **_Tunnel.definition, - **{ - 'bridgeable': True, - }, - } - - 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 - """ - iftype = 'ip6gre' - -class IPIPIf(_Tunnel): - """ - IPIP: IP Encapsulation within IP - - For more information please refer to: - https://tools.ietf.org/html/rfc2003 - """ - iftype = 'ipip' - -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 - """ - iftype = 'ipip6' - -class IP6IP6If(IPIP6If): - """ - IP6IP6: IPv6 over IPv6 tunnel - - For more information please refer to: - https://tools.ietf.org/html/rfc2473 - """ - iftype = '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 - """ - iftype = '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 - iftype = '6rd' - - 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/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_tunnel.py b/smoketest/scripts/cli/test_interfaces_tunnel.py index a9250e3e5..0bbc807db 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 @@ -90,7 +91,7 @@ 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]) @@ -107,8 +108,8 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): self.session.set(self._base_path + [interface, 'remote-ip', 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 @@ -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']) @@ -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, 'local-ip', self.local_v4]) + self.session.set(self._base_path + [interface, 'remote-ip', 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 (inc host by 2 + new_remote = inc_ip(remote_ip4, 2) + self.session.set(self._base_path + [interface, 'remote-ip', 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) diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py index ae28f5101..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,29 +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] - - tun = klass(**tunnel) - tun.change_options() + tun = TunnelIf(**tunnel) tun.update(tunnel) return None diff --git a/src/migration-scripts/interfaces/19-to-20 b/src/migration-scripts/interfaces/19-to-20 new file mode 100755 index 000000000..be42cdd61 --- /dev/null +++ b/src/migration-scripts/interfaces/19-to-20 @@ -0,0 +1,51 @@ +#!/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 . + +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 encapsulation gre-bridge" to gretap + for interface in config.list_nodes(base): + path = base + [interface, 'encapsulation'] + if config.exists(path): + tmp = config.return_value(path) + if tmp == 'gre-bridge': + config.set(path, value='gretap') + + 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) -- cgit v1.2.3 From 582b718221c67ddb71e39fbad0a72241761304a9 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Feb 2021 21:37:15 +0100 Subject: tunnel: T3366: rename local-ip to source-address Streamline the CLI configuration where we try to use source-address when creating connections which are especially sourced from a discrete address. --- .../include/radius-server-ipv4-ipv6.xml.i | 22 ++++++++++++++- .../include/source-address-ipv4-ipv6.xml.i | 1 - .../include/tunnel-local-remote-ip.xml.i | 20 +------------- python/vyos/configverify.py | 18 ++++++------ python/vyos/ifconfig/tunnel.py | 4 +-- smoketest/scripts/cli/test_interfaces_tunnel.py | 32 +++++++++++----------- src/migration-scripts/interfaces/19-to-20 | 13 ++++++--- 7 files changed, 58 insertions(+), 52 deletions(-) (limited to 'interface-definitions') 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 + + + Source IP address used to initiate connection + + + + + ipv4 + IPv4 source address + + + ipv6 + IPv6 source address + + + + + + + + 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 @@ - diff --git a/interface-definitions/include/tunnel-local-remote-ip.xml.i b/interface-definitions/include/tunnel-local-remote-ip.xml.i index 85c20f482..f86e1dd8c 100644 --- a/interface-definitions/include/tunnel-local-remote-ip.xml.i +++ b/interface-definitions/include/tunnel-local-remote-ip.xml.i @@ -1,23 +1,5 @@ - - - Local IP address for this tunnel - - ipv4 - Local IPv4 address for this tunnel - - - ipv6 - Local IPv6 address for this tunnel - - - - - - - - - +#include Remote IP address for this tunnel diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py index 8286a735c..c901ccbc5 100644 --- a/python/vyos/configverify.py +++ b/python/vyos/configverify.py @@ -100,26 +100,26 @@ def verify_tunnel(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 'source_address' not in config and 'dhcp_interface' not in config: + raise ConfigError('source-address is mandatory for tunnel') if 'remote_ip' not in config and config['encapsulation'] != 'gre': raise ConfigError('remote-ip 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') 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') @@ -130,7 +130,7 @@ def verify_tunnel(config): 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/tunnel.py b/python/vyos/ifconfig/tunnel.py index a74d50646..2820e2563 100644 --- a/python/vyos/ifconfig/tunnel.py +++ b/python/vyos/ifconfig/tunnel.py @@ -51,9 +51,9 @@ class TunnelIf(Interface): # - https://man7.org/linux/man-pages/man8/ip-link.8.html # - https://man7.org/linux/man-pages/man8/ip-tunnel.8.html mapping = { - 'local_ip' : 'local', - 'remote_ip' : 'remote', + 'source_address' : 'local', 'source_interface' : 'dev', + 'remote_ip' : 'remote', 'parameters.ip.key' : 'key', 'parameters.ip.tos' : 'tos', 'parameters.ip.ttl' : 'ttl', diff --git a/smoketest/scripts/cli/test_interfaces_tunnel.py b/smoketest/scripts/cli/test_interfaces_tunnel.py index 0bbc807db..cf7e7aac9 100755 --- a/smoketest/scripts/cli/test_interfaces_tunnel.py +++ b/smoketest/scripts/cli/test_interfaces_tunnel.py @@ -71,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-ip 192.0.2.10', 'source-address ' + cls.local_v4], + 'tun20': ['encapsulation gre', 'remote-ip 192.0.2.20', 'source-address ' + cls.local_v4], } cls._interfaces = list(cls._options) @@ -94,15 +94,15 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): 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, 'source-address', self.local_v6]) self.session.set(self._base_path + [interface, 'remote-ip', 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-ip with self.assertRaises(ConfigSessionError): self.session.commit() self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4]) @@ -141,15 +141,15 @@ 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, 'source-address', self.local_v4]) self.session.set(self._base_path + [interface, 'remote-ip', 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-ip with self.assertRaises(ConfigSessionError): self.session.commit() self.session.set(self._base_path + [interface, 'remote-ip', remote_ip6]) @@ -182,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, 'source-address', self.local_v4]) self.session.set(self._base_path + [interface, 'remote-ip', 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']) @@ -208,7 +208,7 @@ 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, 'source-address', self.local_v4]) self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4]) self.session.set(self._base_path + [interface, 'parameters', 'ip', 'no-pmtu-discovery']) @@ -234,7 +234,7 @@ 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, 'source-address', self.local_v4]) self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4]) # Check if commit is ok @@ -258,4 +258,4 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): 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/migration-scripts/interfaces/19-to-20 b/src/migration-scripts/interfaces/19-to-20 index be42cdd61..1727ac4dc 100755 --- a/src/migration-scripts/interfaces/19-to-20 +++ b/src/migration-scripts/interfaces/19-to-20 @@ -36,12 +36,17 @@ if __name__ == '__main__': # # Migrate "interface tunnel encapsulation gre-bridge" to gretap + # Migrate "interface tunnel local-ip" to source-address for interface in config.list_nodes(base): - path = base + [interface, 'encapsulation'] - if config.exists(path): - tmp = config.return_value(path) + encap_path = base + [interface, 'encapsulation'] + if config.exists(encap_path): + tmp = config.return_value(encap_path) if tmp == 'gre-bridge': - config.set(path, value='gretap') + 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') try: with open(file_name, 'w') as f: -- cgit v1.2.3 From 857294427afba3259e683f2360c735f0f4be32b6 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Feb 2021 21:49:00 +0100 Subject: tunnel: T3366: rename remote-ip to remote Streamline the CLI configuration where we try to use remote on other interfaces like vxlan, geneve. --- .../include/tunnel-local-remote-ip.xml.i | 19 ------- interface-definitions/include/tunnel-remote.xml.i | 18 +++++++ interface-definitions/interfaces-erspan.xml.in | 3 +- interface-definitions/interfaces-geneve.xml.in | 13 +---- interface-definitions/interfaces-tunnel.xml.in | 3 +- interface-definitions/interfaces-vxlan.xml.in | 17 +----- python/vyos/configverify.py | 12 ++--- python/vyos/ifconfig/erspan.py | 24 ++++----- python/vyos/ifconfig/tunnel.py | 2 +- smoketest/scripts/cli/test_interfaces_erspan.py | 61 +++------------------- smoketest/scripts/cli/test_interfaces_tunnel.py | 26 ++++----- src/migration-scripts/interfaces/19-to-20 | 5 ++ 12 files changed, 69 insertions(+), 134 deletions(-) delete mode 100644 interface-definitions/include/tunnel-local-remote-ip.xml.i create mode 100644 interface-definitions/include/tunnel-remote.xml.i (limited to 'interface-definitions') 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 f86e1dd8c..000000000 --- a/interface-definitions/include/tunnel-local-remote-ip.xml.i +++ /dev/null @@ -1,19 +0,0 @@ - -#include - - - Remote IP address for this tunnel - - ipv4 - Remote IPv4 address for this tunnel - - - ipv6 - Remote IPv6 address for this tunnel - - - - - - - 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 @@ + + + + Tunnel remote address + + ipv4 + Tunnel remote IPv4 address + + + ipv6 + Tunnel remote IPv6 address + + + + + + + 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 #include - #include + #include + #include Encapsulation of this tunnel interface 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 #include - - - Remote address of GENEVE tunnel - - ipv4 - Remote address of GENEVE tunnel - - - - - - + #include #include diff --git a/interface-definitions/interfaces-tunnel.xml.in b/interface-definitions/interfaces-tunnel.xml.in index bb23ba933..c2d03c5ea 100644 --- a/interface-definitions/interfaces-tunnel.xml.in +++ b/interface-definitions/interfaces-tunnel.xml.in @@ -27,7 +27,8 @@ #include #include - #include + #include + #include Physical Interface used for underlaying traffic diff --git a/interface-definitions/interfaces-vxlan.xml.in b/interface-definitions/interfaces-vxlan.xml.in index 2afe8685a..efe6218e1 100644 --- a/interface-definitions/interfaces-vxlan.xml.in +++ b/interface-definitions/interfaces-vxlan.xml.in @@ -44,22 +44,7 @@ 1450 - - - Remote address of VXLAN tunnel - - ipv4 - Remote IPv4 address of VXLAN tunnel - - - ipv6 - Remote IPv6 address of VXLAN tunnel - - - - - - + #include VXLAN tunnel parameters diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py index c901ccbc5..db3e7cc57 100644 --- a/python/vyos/configverify.py +++ b/python/vyos/configverify.py @@ -103,8 +103,8 @@ def verify_tunnel(config): if 'source_address' not in config and 'dhcp_interface' not in config: raise ConfigError('source-address is mandatory for tunnel') - if 'remote_ip' not in config and config['encapsulation'] != 'gre': - raise ConfigError('remote-ip is mandatory for tunnel') + if 'remote' not in config and config['encapsulation'] != 'gre': + raise ConfigError('remote ip address is mandatory for tunnel') if {'source_address', 'dhcp_interface'} <= set(config): raise ConfigError('Can not use both source-address and dhcp-interface') @@ -114,15 +114,15 @@ def verify_tunnel(config): 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 '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', 'gretap']: if 'source_interface' in config: diff --git a/python/vyos/ifconfig/erspan.py b/python/vyos/ifconfig/erspan.py index e0f72109d..9e24cf6cd 100755 --- a/python/vyos/ifconfig/erspan.py +++ b/python/vyos/ifconfig/erspan.py @@ -76,11 +76,11 @@ class ERSpanIf(_ERSpan): 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) @@ -105,11 +105,11 @@ class ERSpanIf(_ERSpan): 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) @@ -139,11 +139,11 @@ class ER6SpanIf(_ERSpan): 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) @@ -168,11 +168,11 @@ class ER6SpanIf(_ERSpan): 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) diff --git a/python/vyos/ifconfig/tunnel.py b/python/vyos/ifconfig/tunnel.py index 2820e2563..bb940b0cf 100644 --- a/python/vyos/ifconfig/tunnel.py +++ b/python/vyos/ifconfig/tunnel.py @@ -53,7 +53,7 @@ class TunnelIf(Interface): mapping = { 'source_address' : 'local', 'source_interface' : 'dev', - 'remote_ip' : 'remote', + 'remote' : 'remote', 'parameters.ip.key' : 'key', 'parameters.ip.tos' : 'tos', 'parameters.ip.ttl' : 'ttl', 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_tunnel.py b/smoketest/scripts/cli/test_interfaces_tunnel.py index cf7e7aac9..cc8fbd527 100755 --- a/smoketest/scripts/cli/test_interfaces_tunnel.py +++ b/smoketest/scripts/cli/test_interfaces_tunnel.py @@ -71,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', 'source-address ' + cls.local_v4], - 'tun20': ['encapsulation gre', 'remote-ip 192.0.2.20', 'source-address ' + 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) @@ -95,17 +95,17 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): 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, 'source-address', self.local_v6]) - self.session.set(self._base_path + [interface, 'remote-ip', remote_ip6]) + self.session.set(self._base_path + [interface, 'remote', remote_ip6]) # Encapsulation mode requires IPv4 source-address with self.assertRaises(ConfigSessionError): self.session.commit() self.session.set(self._base_path + [interface, 'source-address', self.local_v4]) - # Encapsulation mode requires IPv4 remote-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 gretap @@ -142,17 +142,17 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): 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, 'source-address', self.local_v4]) - self.session.set(self._base_path + [interface, 'remote-ip', remote_ip4]) + self.session.set(self._base_path + [interface, 'remote', remote_ip4]) # Encapsulation mode requires IPv6 source-address with self.assertRaises(ConfigSessionError): self.session.commit() self.session.set(self._base_path + [interface, 'source-address', self.local_v6]) - # Encapsulation mode requires IPv6 remote-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]) @@ -190,7 +190,7 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): 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, 'source-address', self.local_v4]) - 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, 'dhcp-interface', 'eth0']) # source-address and dhcp-interface can not be used at the same time @@ -209,7 +209,7 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): 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-ip', remote_ip4]) + 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]) @@ -235,7 +235,7 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): 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-ip', remote_ip4]) + self.session.set(self._base_path + [interface, 'remote', remote_ip4]) # Check if commit is ok self.session.commit() @@ -248,9 +248,9 @@ class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): self.assertEqual(remote_ip4, conf['linkinfo']['info_data']['remote']) self.assertEqual(0, conf['linkinfo']['info_data']['ttl']) - # Change remote-ip (inc host by 2 + # Change remote ip address (inc host by 2 new_remote = inc_ip(remote_ip4, 2) - self.session.set(self._base_path + [interface, 'remote-ip', new_remote]) + self.session.set(self._base_path + [interface, 'remote', new_remote]) # Check if commit is ok self.session.commit() diff --git a/src/migration-scripts/interfaces/19-to-20 b/src/migration-scripts/interfaces/19-to-20 index 1727ac4dc..ed2780b92 100755 --- a/src/migration-scripts/interfaces/19-to-20 +++ b/src/migration-scripts/interfaces/19-to-20 @@ -37,6 +37,7 @@ if __name__ == '__main__': # # Migrate "interface tunnel encapsulation gre-bridge" to gretap # Migrate "interface tunnel local-ip" to source-address + # Migrate "interface tunnel remote-ip" to remote for interface in config.list_nodes(base): encap_path = base + [interface, 'encapsulation'] if config.exists(encap_path): @@ -48,6 +49,10 @@ if __name__ == '__main__': 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()) -- cgit v1.2.3 From 5bcc549edeaeaa767d77a68b33751e834d467c34 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 27 Feb 2021 22:59:00 +0100 Subject: macsec: T3368: add support for gcm-aes-256 cipher --- interface-definitions/interfaces-macsec.xml.in | 8 +++-- smoketest/scripts/cli/test_interfaces_macsec.py | 39 +++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 4 deletions(-) (limited to 'interface-definitions') 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 @@ Cipher suite used - gcm-aes-128 + gcm-aes-128 gcm-aes-256 gcm-aes-128 Galois/Counter Mode of AES cipher with 128-bit key (default) + + gcm-aes-256 + Galois/Counter Mode of AES cipher with 256-bit key + - (gcm-aes-128) + ^(gcm-aes-128|gcm-aes-256)$ 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 . +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 -- cgit v1.2.3