From c7d0865455c9bbf078765b7a53811286cf3dfb8b Mon Sep 17 00:00:00 2001
From: jack9603301 <jack9603301@163.com>
Date: Sun, 13 Dec 2020 20:30:23 +0800
Subject: tunnel: T3030: Modify the command line to streamline configuration
 (support package type automatic detection)

---
 .../include/tunnel-local-remote-ip.xml.i           |  37 ++++++++
 .../include/tunnel-parameters-ip.xml.i             |  49 ++++++++++
 interface-definitions/interfaces-erspan.xml.in     |  96 +------------------
 interface-definitions/interfaces-tunnel.xml.in     | 103 +--------------------
 python/vyos/configverify.py                        |  43 +++++++++
 python/vyos/ifconfig/erspan.py                     |   2 +-
 smoketest/scripts/cli/test_interfaces_erspan.py    |  28 +-----
 src/conf_mode/interfaces-erspan.py                 |  52 +++--------
 src/conf_mode/interfaces-tunnel.py                 |  34 +------
 9 files changed, 151 insertions(+), 293 deletions(-)
 create mode 100644 interface-definitions/include/tunnel-local-remote-ip.xml.i
 create mode 100644 interface-definitions/include/tunnel-parameters-ip.xml.i

diff --git a/interface-definitions/include/tunnel-local-remote-ip.xml.i b/interface-definitions/include/tunnel-local-remote-ip.xml.i
new file mode 100644
index 000000000..85c20f482
--- /dev/null
+++ b/interface-definitions/include/tunnel-local-remote-ip.xml.i
@@ -0,0 +1,37 @@
+<!-- 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-parameters-ip.xml.i b/interface-definitions/include/tunnel-parameters-ip.xml.i
new file mode 100644
index 000000000..c304bd3ff
--- /dev/null
+++ b/interface-definitions/include/tunnel-parameters-ip.xml.i
@@ -0,0 +1,49 @@
+<!-- included start from tunnel-parameters-ip.xml.i -->
+<node name="ip">
+  <properties>
+    <help>IPv4 specific tunnel parameters</help>
+  </properties>
+  <children>
+    <leafNode name="ttl">
+      <properties>
+        <help>Time to live field</help>
+        <valueHelp>
+          <format>0-255</format>
+          <description>Time to live (default 255)</description>
+        </valueHelp>
+        <constraint>
+          <validator name="numeric" argument="--range 0-255"/>
+        </constraint>
+        <constraintErrorMessage>TTL must be between 0 and 255</constraintErrorMessage>
+      </properties>
+      <defaultValue>255</defaultValue>
+    </leafNode>
+    <leafNode name="tos">
+      <properties>
+        <help>Type of Service (TOS)</help>
+        <valueHelp>
+          <format>0-99</format>
+          <description>Type of Service (TOS)</description>
+        </valueHelp>
+        <constraint>
+          <validator name="numeric" argument="--range 0-99"/>
+        </constraint>
+        <constraintErrorMessage>TOS must be between 0 and 99</constraintErrorMessage>
+      </properties>
+      <defaultValue>inherit</defaultValue>
+    </leafNode>
+    <leafNode name="key">
+      <properties>
+        <help>Tunnel key</help>
+        <valueHelp>
+          <format>u32</format>
+          <description>Tunnel key</description>
+        </valueHelp>
+        <constraint>
+          <validator name="numeric" argument="--range 0-4294967295"/>
+        </constraint>
+        <constraintErrorMessage>key must be between 0-4294967295</constraintErrorMessage>
+      </properties>
+    </leafNode>
+  </children>
+</node>
diff --git a/interface-definitions/interfaces-erspan.xml.in b/interface-definitions/interfaces-erspan.xml.in
index 6b98b0730..afc29a658 100644
--- a/interface-definitions/interfaces-erspan.xml.in
+++ b/interface-definitions/interfaces-erspan.xml.in
@@ -17,62 +17,23 @@
         </properties>
         <children>
           #include <include/interface-description.xml.i>
-          #include <include/address-ipv4-ipv6.xml.i>
           #include <include/interface-disable.xml.i>
           #include <include/interface-disable-link-detect.xml.i>
-          #include <include/interface-vrf.xml.i>
           #include <include/interface-mtu-64-8024.xml.i>
-          #include <include/interface-ipv4-options.xml.i>
-          #include <include/interface-ipv6-options.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 ERSPAN tunnel</description>
-              </valueHelp>
-              <valueHelp>
-                <format>ipv6</format>
-                <description>Local IPv6 address for this tunnel [NOTICE: unavailable for mGRE tunnels]</description>
-              </valueHelp>
-              <completionHelp>
-                <script>${vyos_completion_dir}/list_local.py</script>
-              </completionHelp>
-              <constraint>
-                <validator name="ip-address"/>
-              </constraint>
-            </properties>
-          </leafNode>
-          <leafNode name="remote-ip">
-            <properties>
-              <help>Remote IP address for this ERSPAN 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>
+          #include <include/tunnel-local-remote-ip.xml.i>
           <leafNode name="encapsulation">
             <properties>
-              <help>Encapsulation of this ERSPAN tunnel interface</help>
+              <help>Encapsulation of this tunnel interface</help>
               <completionHelp>
                 <list>erspan ip6erspan</list>
               </completionHelp>
               <valueHelp>
                 <format>erspan</format>
-                <description>Encapsulated Remote SPAN over GRE and IPv4</description>
+                <description>Generic Routing Encapsulation</description>
               </valueHelp>
               <valueHelp>
                 <format>ip6erspan</format>
-                <description>Encapsulated Remote SPAN over GRE and IPv6</description>
+                <description>Generic Routing Encapsulation bridge interface</description>
               </valueHelp>
               <constraint>
                 <regex>^(erspan|ip6erspan)$</regex>
@@ -85,54 +46,7 @@
               <help>ERSPAN Tunnel parameters</help>
             </properties>
             <children>
-              <node name="ip">
-                <properties>
-                  <help>IP specific ERSPAN tunnel parameters</help>
-                </properties>
-                <children>
-                  <leafNode name="ttl">
-                    <properties>
-                      <help>Time to live field</help>
-                      <valueHelp>
-                        <format>0-255</format>
-                        <description>Time to live (default 255)</description>
-                      </valueHelp>
-                      <constraint>
-                        <validator name="numeric" argument="--range 0-255"/>
-                      </constraint>
-                      <constraintErrorMessage>TTL must be between 0 and 255</constraintErrorMessage>
-                    </properties>
-                    <defaultValue>255</defaultValue>
-                  </leafNode>
-                  <leafNode name="tos">
-                    <properties>
-                      <help>Type of Service (TOS)</help>
-                      <valueHelp>
-                        <format>0-99</format>
-                        <description>Type of Service (TOS)</description>
-                      </valueHelp>
-                      <constraint>
-                        <validator name="numeric" argument="--range 0-99"/>
-                      </constraint>
-                      <constraintErrorMessage>TOS must be between 0 and 99</constraintErrorMessage>
-                    </properties>
-                    <defaultValue>inherit</defaultValue>
-                  </leafNode>
-                  <leafNode name="key">
-                    <properties>
-                      <help>ERSPAN Tunnel key</help>
-                      <valueHelp>
-                        <format>0-4294967295</format>
-                        <description>Tunnel key</description>
-                      </valueHelp>
-                      <constraint>
-                        <validator name="numeric" argument="--range 0-4294967295"/>
-                      </constraint>
-                      <constraintErrorMessage>key must be between 0-4294967295</constraintErrorMessage>
-                    </properties>
-                  </leafNode>
-                </children>
-              </node>
+              #include <include/tunnel-parameters-ip.xml.i>
               <leafNode name="version">
                 <properties>
                   <help>ERSPAN version number setting(default:1)</help>
diff --git a/interface-definitions/interfaces-tunnel.xml.in b/interface-definitions/interfaces-tunnel.xml.in
index 7fa847ab0..279c05cca 100644
--- a/interface-definitions/interfaces-tunnel.xml.in
+++ b/interface-definitions/interfaces-tunnel.xml.in
@@ -27,42 +27,7 @@
           </leafNode>
           #include <include/interface-ipv4-options.xml.i>
           #include <include/interface-ipv6-options.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 [NOTICE: unavailable for mGRE tunnels]</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>
+          #include <include/tunnel-local-remote-ip.xml.i>
           <leafNode name="source-interface">
             <properties>
               <help>Physical Interface used for underlaying traffic</help>
@@ -175,71 +140,7 @@
               <help>Tunnel parameters</help>
             </properties>
             <children>
-              <node name="ip">
-                <properties>
-                  <help>IPv4 specific tunnel parameters</help>
-                </properties>
-                <children>
-                  <leafNode name="no-pmtu-discovery">
-                    <properties>
-                      <help>Disable path MTU discovery</help>
-                      <valueless/>
-                    </properties>
-                  </leafNode>
-                  <leafNode name="ttl">
-                    <properties>
-                      <help>Time to live (default: 0)</help>
-                      <valueHelp>
-                        <format>0</format>
-                        <description>Copy value from original IP header</description>
-                      </valueHelp>
-                      <valueHelp>
-                        <format>1-255</format>
-                        <description>Time to Live</description>
-                      </valueHelp>
-                      <constraint>
-                        <validator name="numeric" argument="--range 0-255"/>
-                      </constraint>
-                      <constraintErrorMessage>TTL must be between 0 and 255</constraintErrorMessage>
-                    </properties>
-                    <defaultValue>0</defaultValue>
-                  </leafNode>
-                  <leafNode name="tos">
-                    <properties>
-                      <help>Type of Service (default: 0)</help>
-                      <completionHelp>
-                        <list>inherit</list>
-                      </completionHelp>
-                      <valueHelp>
-                        <format>0</format>
-                        <description>Copy value from original IP header</description>
-                      </valueHelp>
-                      <valueHelp>
-                        <format>1-99</format>
-                        <description>Type of Service (TOS)</description>
-                      </valueHelp>
-                      <constraint>
-                        <validator name="numeric" argument="--range 0-99"/>
-                      </constraint>
-                      <constraintErrorMessage>TOS must be between 0 and 99</constraintErrorMessage>
-                    </properties>
-                    <defaultValue>0</defaultValue>
-                  </leafNode>
-                  <leafNode name="key">
-                    <properties>
-                      <help>Tunnel key</help>
-                      <valueHelp>
-                        <format>u32</format>
-                        <description>Tunnel key</description>
-                      </valueHelp>
-                      <constraint>
-                        <validator name="numeric" argument="--range 0-4294967295"/>
-                      </constraint>
-                      <constraintErrorMessage>Key must be in range 0-4294967295</constraintErrorMessage>
-                    </properties>
-                  </leafNode>
-                </children>
-              </node>
+              #include <include/tunnel-parameters-ip.xml.i>
               <node name="ipv6">
                 <properties>
                   <help>IPv6 specific tunnel parameters</help>
diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py
index a888791ba..e71e4e1c5 100644
--- a/python/vyos/configverify.py
+++ b/python/vyos/configverify.py
@@ -89,6 +89,49 @@ def verify_vrf(config):
                 'Interface "{ifname}" cannot be both a member of VRF "{vrf}" '
                 'and bridge "{is_bridge_member}"!'.format(**config))
 
+def verify_tunnel(config):
+    """
+    This helper is used to verify the common part of the tunnel
+    """
+    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 {'local_ip', 'dhcp_interface'} <= set(config):
+        raise ConfigError('Can not use both local-ip 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 '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 '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 'source_interface' in config:
+            raise ConfigError('Option source-interface can not be used with ' \
+                              'encapsulation "sit" or "gre-bridge"')
+    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')
+
 def verify_eapol(config):
     """
     Common helper function used by interface implementations to perform
diff --git a/python/vyos/ifconfig/erspan.py b/python/vyos/ifconfig/erspan.py
index 848840144..50230e14a 100755
--- a/python/vyos/ifconfig/erspan.py
+++ b/python/vyos/ifconfig/erspan.py
@@ -167,7 +167,7 @@ class ER6SpanIf(_ERSpan):
                 
         self._cmd(command)
     
-    def change_options(self, config):
+    def change_options(self):
         ifname = self.config['ifname']
         local_ip = self.config['local_ip']
         remote_ip = self.config['remote_ip']
diff --git a/smoketest/scripts/cli/test_interfaces_erspan.py b/smoketest/scripts/cli/test_interfaces_erspan.py
index d21b3ab9b..c180f0a34 100755
--- a/smoketest/scripts/cli/test_interfaces_erspan.py
+++ b/smoketest/scripts/cli/test_interfaces_erspan.py
@@ -93,24 +93,11 @@ class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest):
     def test_erspan_ipv4(self):
         interface = 'ersp100'
         encapsulation = 'erspan'
-        address_v4 = '10.1.1.1/24'
         key = 123
 
-        self.session.set(self._base_path + [interface, 'address', address_v4])
-
-        # Must configure the ERSPAN tunnel encapsulation for ersp100
-        with self.assertRaises(ConfigSessionError):
-            self.session.commit()
         self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
-
-        # local-ip is mandatory for ERSPAN tunnel
-        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, 'remote-ip', self.remote_v4])
-
         self.session.set(self._base_path + [interface, 'parameters', 'ip' , 'key', str(key)])
 
         self.session.commit()
@@ -127,24 +114,11 @@ class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest):
     def test_erspan_ipv6(self):
         interface = 'ersp1000'
         encapsulation = 'ip6erspan'
-        address_v6 = '2001:db8::1/24'
         key = 123
 
-        self.session.set(self._base_path + [interface, 'address', address_v6])
-
-        # Must configure the ERSPAN tunnel encapsulation for ersp100
-        with self.assertRaises(ConfigSessionError):
-            self.session.commit()
         self.session.set(self._base_path + [interface, 'encapsulation', encapsulation])
-
-        # local-ip is mandatory for ERSPAN tunnel
-        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, 'remote-ip', self.remote_v6])
-
         self.session.set(self._base_path + [interface, 'parameters', 'ip' , 'key', str(key)])
 
         self.session.commit()
@@ -158,4 +132,4 @@ class ERSPanTunnelInterfaceTest(BasicInterfaceTest.BaseTest):
         self.assertEqual(self.remote_v6,     conf['linkinfo']['info_data']['remote'])
 
 if __name__ == '__main__':
-    unittest.main()
+    unittest.main(verbosity=2)
diff --git a/src/conf_mode/interfaces-erspan.py b/src/conf_mode/interfaces-erspan.py
index 1bb5a4a9d..2d65b834c 100755
--- a/src/conf_mode/interfaces-erspan.py
+++ b/src/conf_mode/interfaces-erspan.py
@@ -25,9 +25,8 @@ from vyos.configdict import dict_merge
 from vyos.configdict import get_interface_dict
 from vyos.configdict import node_changed
 from vyos.configdict import leaf_node_changed
-from vyos.configverify import verify_vrf
-from vyos.configverify import verify_address
 from vyos.configverify import verify_mtu_ipv6
+from vyos.configverify import verify_tunnel
 from vyos.ifconfig import Interface
 from vyos.ifconfig import ERSpanIf
 from vyos.ifconfig import ER6SpanIf
@@ -51,7 +50,7 @@ def get_config(config=None):
     erspan = get_interface_dict(conf, base)
     
     tmp = leaf_node_changed(conf, ['encapsulation'])
-    if tmp: 
+    if tmp:
         erspan.update({'encapsulation_changed': {}})
 
     return erspan
@@ -61,57 +60,28 @@ def verify(erspan):
         return None
     
     if 'encapsulation' not in erspan:
-        raise ConfigError('Must configure the ERSPAN tunnel encapsulation for '\
+        raise ConfigError('Unable to detect the following ERSPAN tunnel encapsulation'\
                           '{ifname}!'.format(**erspan))
 
     verify_mtu_ipv6(erspan)
-    verify_address(erspan)
-    verify_vrf(erspan)
-
-    if 'local_ip' not in erspan:
-        raise ConfigError('local-ip is mandatory for ERSPAN tunnel')
-
-    if 'remote_ip' not in erspan:
-        raise ConfigError('remote-ip is mandatory for ERSPAN tunnel')
-
-    if erspan['encapsulation'] in ['ip6erspan']:
-        error_ipv6 = 'Encapsulation mode requires IPv6'
-        if 'local_ip' in erspan and not is_ipv6(erspan['local_ip']):
-            raise ConfigError(f'{error_ipv6} local-ip')
-
-        if 'remote_ip' in erspan and not is_ipv6(erspan['remote_ip']):
-            raise ConfigError(f'{error_ipv6} remote-ip')
-    else:
-        error_ipv4 = 'Encapsulation mode requires IPv4'
-        if 'local_ip' in erspan and not is_ipv4(erspan['local_ip']):
-            raise ConfigError(f'{error_ipv4} local-ip')
-
-        if 'remote_ip' in erspan and not is_ipv4(erspan['remote_ip']):
-            raise ConfigError(f'{error_ipv4} remote-ip')
-    
-    if 'parameters' not in erspan:
-        raise ConfigError('parameters is mandatory for ERSPAN tunnel')
+    verify_tunnel(erspan)
     
     key = dict_search('parameters.ip.key',erspan)
     if key == None:
         raise ConfigError('parameters.ip.key is mandatory for ERSPAN tunnel')
-    
-    if erspan['encapsulation'] == 'erspan':
-        if 'local_ip' in erspan and is_ipv6(erspan['local_ip']):
-            raise ConfigError('Can not use local IPv6 address is for ERSPAN tunnels')
             
 
 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
diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py
index f03bc9d5d..034bd6dd1 100755
--- a/src/conf_mode/interfaces-tunnel.py
+++ b/src/conf_mode/interfaces-tunnel.py
@@ -29,6 +29,7 @@ from vyos.configverify import verify_bridge_delete
 from vyos.configverify import verify_interface_exists
 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
@@ -84,38 +85,7 @@ def verify(tunnel):
     verify_mtu_ipv6(tunnel)
     verify_address(tunnel)
     verify_vrf(tunnel)
-
-    if 'local_ip' not in tunnel and 'dhcp_interface' not in tunnel:
-        raise ConfigError('local-ip is mandatory for tunnel')
-
-    if 'remote_ip' not in tunnel and tunnel['encapsulation'] != 'gre':
-        raise ConfigError('remote-ip is mandatory for tunnel')
-
-    if {'local_ip', 'dhcp_interface'} <= set(tunnel):
-        raise ConfigError('Can not use both local-ip and dhcp-interface')
-
-    if tunnel['encapsulation'] in ['ipip6', 'ip6ip6', 'ip6gre']:
-        error_ipv6 = 'Encapsulation mode requires IPv6'
-        if 'local_ip' in tunnel and not is_ipv6(tunnel['local_ip']):
-            raise ConfigError(f'{error_ipv6} local-ip')
-
-        if 'remote_ip' in tunnel and not is_ipv6(tunnel['remote_ip']):
-            raise ConfigError(f'{error_ipv6} remote-ip')
-    else:
-        error_ipv4 = 'Encapsulation mode requires IPv4'
-        if 'local_ip' in tunnel and not is_ipv4(tunnel['local_ip']):
-            raise ConfigError(f'{error_ipv4} local-ip')
-
-        if 'remote_ip' in tunnel and not is_ipv4(tunnel['remote_ip']):
-            raise ConfigError(f'{error_ipv4} remote-ip')
-
-    if tunnel['encapsulation'] in ['sit', 'gre-bridge']:
-        if 'source_interface' in tunnel:
-            raise ConfigError('Option source-interface can not be used with ' \
-                              'encapsulation "sit" or "gre-bridge"')
-    elif tunnel['encapsulation'] == 'gre':
-        if 'local_ip' in tunnel and is_ipv6(tunnel['local_ip']):
-            raise ConfigError('Can not use local IPv6 address is for mGRE tunnels')
+    verify_tunnel(tunnel)
 
     if 'source_interface' in tunnel:
         verify_interface_exists(tunnel['source_interface'])
-- 
cgit v1.2.3