diff --git a/data/configd-include.json b/data/configd-include.json
index eed858363..4959e5020 100644
--- a/data/configd-include.json
+++ b/data/configd-include.json
@@ -1,71 +1,70 @@
 [
 "bcast_relay.py",
 "dhcp_relay.py",
 "dhcpv6_relay.py",
 "dns_forwarding.py",
 "dynamic_dns.py",
 "firewall_options.py",
 "host_name.py",
 "https.py",
 "igmp_proxy.py",
 "intel_qat.py",
 "interfaces-bonding.py",
 "interfaces-bridge.py",
 "interfaces-dummy.py",
 "interfaces-ethernet.py",
 "interfaces-geneve.py",
 "interfaces-l2tpv3.py",
 "interfaces-loopback.py",
 "interfaces-macsec.py",
 "interfaces-openvpn.py",
 "interfaces-pppoe.py",
 "interfaces-pseudo-ethernet.py",
 "interfaces-tunnel.py",
-"interfaces-erspan.py",
 "interfaces-vxlan.py",
 "interfaces-wireguard.py",
 "interfaces-wireless.py",
 "interfaces-wirelessmodem.py",
 "ipsec-settings.py",
 "lldp.py",
 "nat.py",
 "nat66.py",
 "ntp.py",
 "policy-local-route.py",
 "protocols_bfd.py",
 "protocols_bgp.py",
 "protocols_igmp.py",
 "protocols_isis.py",
 "protocols_mpls.py",
 "protocols_ospf.py",
 "protocols_ospfv3.py",
 "protocols_pim.py",
 "protocols_rip.py",
 "protocols_ripng.py",
 "protocols_static.py",
 "protocols_static_multicast.py",
 "salt-minion.py",
 "service_console-server.py",
 "service_ids_fastnetmon.py",
 "service_ipoe-server.py",
 "service_mdns-repeater.py",
 "service_pppoe-server.py",
 "service_router-advert.py",
 "ssh.py",
 "system-ip.py",
 "system-ipv6.py",
 "system-login-banner.py",
 "system-option.py",
 "system-syslog.py",
 "system-timezone.py",
 "system_console.py",
 "system_lcd.py",
 "task_scheduler.py",
 "tftp_server.py",
 "vpn_l2tp.py",
 "vpn_pptp.py",
 "vpn_sstp.py",
 "vrf.py",
 "vrrp.py",
 "vyos_cert.py"
 ]
diff --git a/interface-definitions/interfaces-erspan.xml.in b/interface-definitions/interfaces-erspan.xml.in
deleted file mode 100644
index 769899415..000000000
--- a/interface-definitions/interfaces-erspan.xml.in
+++ /dev/null
@@ -1,114 +0,0 @@
-<?xml version="1.0"?>
-<interfaceDefinition>
-  <node name="interfaces">
-    <children>
-      <tagNode name="erspan" owner="${vyos_conf_scripts_dir}/interfaces-erspan.py">
-        <properties>
-          <help>Encapsulated Remote SPAN over GRE and IPv4/IPv6 Tunnel Interface</help>
-          <priority>310</priority>
-          <constraint>
-            <regex>^ersp[0-9]+$</regex>
-          </constraint>
-          <constraintErrorMessage>ERSPAN tunnel interface must be named erspN</constraintErrorMessage>
-          <valueHelp>
-            <format>erspN</format>
-            <description>ERSPAN Tunnel interface name</description>
-          </valueHelp>
-        </properties>
-        <children>
-          #include <include/interface/interface-description.xml.i>
-          #include <include/interface/interface-disable.xml.i>
-          #include <include/interface/interface-disable-link-detect.xml.i>
-          #include <include/interface/interface-mtu-64-8024.xml.i>
-          #include <include/source-address-ipv4-ipv6.xml.i>
-          #include <include/interface/tunnel-remote.xml.i>
-          <leafNode name="encapsulation">
-            <properties>
-              <help>Encapsulation of this tunnel interface</help>
-              <completionHelp>
-                <list>erspan ip6erspan</list>
-              </completionHelp>
-              <valueHelp>
-                <format>erspan</format>
-                <description>Generic Routing Encapsulation</description>
-              </valueHelp>
-              <valueHelp>
-                <format>ip6erspan</format>
-                <description>Generic Routing Encapsulation bridge interface</description>
-              </valueHelp>
-              <constraint>
-                <regex>^(erspan|ip6erspan)$</regex>
-              </constraint>
-              <constraintErrorMessage>Invalid encapsulation, must be one of: erspan, ip6erspan</constraintErrorMessage>
-            </properties>
-          </leafNode>
-          <node name="parameters">
-            <properties>
-              <help>ERSPAN Tunnel parameters</help>
-            </properties>
-            <children>
-              <node name="ip">
-                <properties>
-                  <help>IPv4 specific tunnel parameters</help>
-                </properties>
-                <children>
-                  #include <include/interface/interface-parameters-key.xml.i>
-                  #include <include/interface/interface-parameters-tos.xml.i>
-                  #include <include/interface/interface-parameters-ttl.xml.i>
-                </children>
-              </node>
-              <leafNode name="version">
-                <properties>
-                  <help>ERSPAN version number setting(default:1)</help>
-                  <constraint>
-                    <validator name="numeric" argument="--range 1-2"/>
-                  </constraint>
-                  <constraintErrorMessage>The version number of ERSPAN must be 1 or 2</constraintErrorMessage>
-                </properties>
-                <defaultValue>1</defaultValue>
-              </leafNode>
-              <leafNode name="direction">
-                <properties>
-                  <help>Specifies mirrored traffic direction</help>
-                  <completionHelp>
-                    <list>ingress egress</list>
-                  </completionHelp>
-                  <valueHelp>
-                    <format>ingress</format>
-                    <description>Mirror ingress direction</description>
-                  </valueHelp>
-                  <valueHelp>
-                    <format>egress</format>
-                    <description>Mirror egress direction</description>
-                  </valueHelp>
-                  <constraint>
-                    <regex>^(ingress|egress)$</regex>
-                  </constraint>
-                  <constraintErrorMessage>The mirror direction of ERSPAN must be ingress or egress</constraintErrorMessage>
-                </properties>
-              </leafNode>
-              <leafNode name="hwid">
-                <properties>
-                  <help>an unique identifier of an ERSPAN v2 engine within a system</help>
-                  <constraint>
-                    <validator name="numeric" argument="--range 1-1048575"/>
-                  </constraint>
-                  <constraintErrorMessage>ERSPAN hwid must be a number(range:0-1048575)</constraintErrorMessage>
-                </properties>
-              </leafNode>
-              <leafNode name="idx">
-                <properties>
-                  <help>specifies the ERSPAN v1 index field</help>
-                  <constraint>
-                    <validator name="numeric" argument="--range 0-63"/>
-                  </constraint>
-                  <constraintErrorMessage>ERSPAN idx must be a number(range:0-63)</constraintErrorMessage>
-                </properties>
-              </leafNode>
-            </children>
-          </node>
-        </children>
-      </tagNode>
-    </children>
-  </node>
-</interfaceDefinition>
diff --git a/interface-definitions/interfaces-tunnel.xml.in b/interface-definitions/interfaces-tunnel.xml.in
index e3aad2719..e4bdcb3d7 100644
--- a/interface-definitions/interfaces-tunnel.xml.in
+++ b/interface-definitions/interfaces-tunnel.xml.in
@@ -1,228 +1,311 @@
 <?xml version="1.0"?>
 <interfaceDefinition>
   <node name="interfaces">
     <children>
       <tagNode name="tunnel" owner="${vyos_conf_scripts_dir}/interfaces-tunnel.py">
         <properties>
           <help>Tunnel interface</help>
           <priority>380</priority>
           <constraint>
             <regex>^tun[0-9]+$</regex>
           </constraint>
           <constraintErrorMessage>tunnel interface must be named tunN</constraintErrorMessage>
           <valueHelp>
             <format>tunN</format>
             <description>Tunnel interface name</description>
           </valueHelp>
         </properties>
         <children>
           #include <include/interface/interface-description.xml.i>
           #include <include/interface/address-ipv4-ipv6.xml.i>
           #include <include/interface/interface-disable.xml.i>
           #include <include/interface/interface-disable-link-detect.xml.i>
           #include <include/interface/interface-vrf.xml.i>
           #include <include/interface/interface-mtu-64-8024.xml.i>
           <leafNode name="mtu">
             <defaultValue>1476</defaultValue>
           </leafNode>
           #include <include/interface/interface-ipv4-options.xml.i>
           #include <include/interface/interface-ipv6-options.xml.i>
           #include <include/source-address-ipv4-ipv6.xml.i>
           #include <include/interface/tunnel-remote.xml.i>
           <leafNode name="source-interface">
             <properties>
               <help>Physical Interface used for underlaying traffic</help>
               <completionHelp>
                 <script>${vyos_completion_dir}/list_interfaces.py</script>
               </completionHelp>
             </properties>
           </leafNode>
           <leafNode name="6rd-prefix">
             <properties>
               <help>6rd network prefix</help>
               <valueHelp>
                 <format>ipv6</format>
                 <description>IPv6 address and prefix length</description>
               </valueHelp>
               <constraint>
                 <validator name="ipv6-prefix"/>
               </constraint>
             </properties>
           </leafNode>
           <leafNode name="6rd-relay-prefix">
             <properties>
               <help>6rd relay prefix</help>
               <valueHelp>
                 <format>ipv4net</format>
                 <description>IPv4 prefix of interface for 6rd</description>
               </valueHelp>
               <constraint>
                 <validator name="ipv4-prefix"/>
               </constraint>
             </properties>
           </leafNode>
           <leafNode name="dhcp-interface">
             <properties>
               <help>dhcp interface</help>
               <valueHelp>
                 <format>interface</format>
                 <description>DHCP interface that supplies the local IP address for this tunnel</description>
               </valueHelp>
               <completionHelp>
                 <script>${vyos_completion_dir}/list_interfaces.py</script>
               </completionHelp>
               <constraint>
                 <regex>^(en|eth|br|bond|gnv|vxlan|wg|tun)[0-9]+$</regex>
               </constraint>
             </properties>
           </leafNode>
           <leafNode name="encapsulation">
             <properties>
               <help>Encapsulation of this tunnel interface</help>
               <completionHelp>
-                <list>gre gretap ip6gre ip6gretap ip6ip6 ipip ipip6 sit</list>
+                <list>erspan gre gretap ip6erspan ip6gre ip6gretap ip6ip6 ipip ipip6 sit</list>
               </completionHelp>
+              <valueHelp>
+                <format>erspan</format>
+                <description>Encapsulated Remote Switched Port Analyzer</description>
+              </valueHelp>
               <valueHelp>
                 <format>gre</format>
                 <description>Generic Routing Encapsulation</description>
               </valueHelp>
               <valueHelp>
                 <format>gretap</format>
                 <description>Generic Routing Encapsulation (virtual L2 tunnel)</description>
               </valueHelp>
+              <valueHelp>
+                <format>ip6erspan</format>
+                <description>Encapsulated Remote Switched Port Analyzer over IPv6 network</description>
+              </valueHelp>
               <valueHelp>
                 <format>ip6gre</format>
                 <description>GRE over IPv6 network</description>
               </valueHelp>
               <valueHelp>
                 <format>ip6gretap</format>
                 <description>Generic Routing Encapsulation over IPv6 (virtual L2 tunnel)</description>
               </valueHelp>
               <valueHelp>
                 <format>ip6ip6</format>
                 <description>IP6 in IP6 encapsulation</description>
               </valueHelp>
               <valueHelp>
                 <format>ipip</format>
                 <description>IP in IP encapsulation</description>
               </valueHelp>
               <valueHelp>
                 <format>ipip6</format>
                 <description>IP in IP6 encapsulation</description>
               </valueHelp>
               <valueHelp>
                 <format>sit</format>
                 <description>Simple Internet Transition encapsulation</description>
               </valueHelp>
               <constraint>
-                <regex>^(gre|gretap|ip6gre|ip6gretap|ip6ip6|ipip|ipip6|sit)$</regex>
+                <regex>^(erspan|gre|gretap|ip6erspan|ip6gre|ip6gretap|ip6ip6|ipip|ipip6|sit)$</regex>
               </constraint>
-              <constraintErrorMessage>Invalid encapsulation, must be one of: gre, gretap, ip6gre, ip6gretap, ipip, sit, ipip6 or ip6ip6</constraintErrorMessage>
+              <constraintErrorMessage>Invalid encapsulation, must be one of: erspan, gre, gretap, ip6erspan, ip6gre, ip6gretap, ipip, sit, ipip6 or ip6ip6</constraintErrorMessage>
             </properties>
           </leafNode>
           <leafNode name="multicast">
             <properties>
               <help>Multicast operation over tunnel</help>
               <completionHelp>
                 <list>enable disable</list>
               </completionHelp>
               <valueHelp>
                 <format>enable</format>
                 <description>Enable Multicast</description>
               </valueHelp>
               <valueHelp>
                 <format>disable</format>
                 <description>Disable Multicast (default)</description>
               </valueHelp>
               <constraint>
                 <regex>^(enable|disable)$</regex>
               </constraint>
               <constraintErrorMessage>Must be 'disable' or 'enable'</constraintErrorMessage>
             </properties>
           </leafNode>
           <node name="parameters">
             <properties>
               <help>Tunnel parameters</help>
             </properties>
             <children>
+              <node name="erspan">
+                <properties>
+                  <help>ERSPAN Tunnel parameters</help>
+                </properties>
+                <children>
+
+<!---
+Temporary disabled b/c of https://github.com/shemminger/iproute2/issues/41
+                  <leafNode name="direction">
+                    <properties>
+                      <help>Specifies mirrored traffic direction</help>
+                      <completionHelp>
+                        <list>ingress egress</list>
+                      </completionHelp>
+                      <valueHelp>
+                        <format>ingress</format>
+                        <description>Mirror ingress direction</description>
+                      </valueHelp>
+                      <valueHelp>
+                        <format>egress</format>
+                        <description>Mirror egress direction</description>
+                      </valueHelp>
+                      <constraint>
+                        <regex>^(ingress|egress)$</regex>
+                      </constraint>
+                    </properties>
+                  </leafNode>
+                  <leafNode name="hw-id">
+                    <properties>
+                      <help>Unique identifier of ERSPAN engine within a system</help>
+                      <valueHelp>
+                        <format>0-1048575</format>
+                        <description>Unique identifier of ERSPAN engine</description>
+                      </valueHelp>
+                      <constraint>
+fix double hyphen below ...
+                        <validator name="numeric" argument="- -range 0-1048575"/>
+                      </constraint>
+                    </properties>
+                  </leafNode>
+-->
+                  <leafNode name="index">
+                    <properties>
+                      <help>Specifify ERSPAN version 1 index field</help>
+                      <valueHelp>
+                        <format>0-63</format>
+                        <description>Platform-depedent field for specifying port number and direction</description>
+                      </valueHelp>
+                      <constraint>
+                        <validator name="numeric" argument="--range 0-63"/>
+                      </constraint>
+                    </properties>
+                  </leafNode>
+                  <leafNode name="version">
+                    <properties>
+                      <help>Protocol version</help>
+                      <valueHelp>
+                        <format>1</format>
+                        <description>ERSPAN Type II</description>
+                      </valueHelp>
+<!--
+Temporary disabled b/c of https://github.com/shemminger/iproute2/issues/41
+                      <valueHelp>
+                        <format>2</format>
+                        <description>ERSPAN Type III</description>
+                      </valueHelp>
+-->
+                      <constraint>
+                        <validator name="numeric" argument="--range 1-1"/>
+                      </constraint>
+                    </properties>
+                    <defaultValue>1</defaultValue>
+                  </leafNode>
+                </children>
+              </node>
               <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>
                   #include <include/interface/interface-parameters-key.xml.i>
                   #include <include/interface/interface-parameters-tos.xml.i>
                   #include <include/interface/interface-parameters-ttl.xml.i>
                 </children>
               </node>
               <node name="ipv6">
                 <properties>
                   <help>IPv6 specific tunnel parameters</help>
                 </properties>
                 <children>
                   <leafNode name="encaplimit">
                     <properties>
                       <help>Set fixed encapsulation limit</help>
                       <completionHelp>
                         <list>none</list>
                       </completionHelp>
                       <valueHelp>
                         <format>0-255</format>
                         <description>Encaplimit (default: 4)</description>
                       </valueHelp>
                       <valueHelp>
                         <format>none</format>
                         <description>Encaplimit disabled</description>
                       </valueHelp>
                       <constraint>
                         <regex>^(none)$</regex>
                         <validator name="numeric" argument="--range 0-255"/>
                       </constraint>
                       <constraintErrorMessage>Tunnel encaplimit must be 0-255 or none</constraintErrorMessage>
                     </properties>
                     <defaultValue>4</defaultValue>
                   </leafNode>
                   #include <include/interface/interface-parameters-flowlabel.xml.i>
                   <leafNode name="hoplimit">
                     <properties>
                       <help>Hoplimit</help>
                       <valueHelp>
                         <format>0-255</format>
                         <description>Hoplimit (default 64)</description>
                       </valueHelp>
                       <constraint>
                         <validator name="numeric" argument="--range 0-255"/>
                       </constraint>
                       <constraintErrorMessage>hoplimit must be between 0-255</constraintErrorMessage>
                     </properties>
                     <defaultValue>64</defaultValue>
                   </leafNode>
                   <leafNode name="tclass">
                     <properties>
                       <help>Traffic class (Tclass)</help>
                       <valueHelp>
                         <format>0x0-0x0FFFFF</format>
                         <description>Traffic class, 'inherit' or hex value</description>
                       </valueHelp>
                       <constraint>
                         <regex>(0x){0,1}(0?[0-9A-Fa-f]{1,2})</regex>
                       </constraint>
                       <constraintErrorMessage>Must be 'inherit' or a number</constraintErrorMessage>
                     </properties>
                     <defaultValue>inherit</defaultValue>
                   </leafNode>
                 </children>
               </node>
             </children>
           </node>
         </children>
       </tagNode>
     </children>
   </node>
 </interfaceDefinition>
diff --git a/python/vyos/ifconfig/__init__.py b/python/vyos/ifconfig/__init__.py
index f5dfa8e05..e9da1e9f5 100644
--- a/python/vyos/ifconfig/__init__.py
+++ b/python/vyos/ifconfig/__init__.py
@@ -1,39 +1,37 @@
 # 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
 # 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.section import Section
 from vyos.ifconfig.control import Control
 from vyos.ifconfig.interface import Interface
 from vyos.ifconfig.operational import Operational
 from vyos.ifconfig.vrrp import VRRP
 
 from vyos.ifconfig.bond import BondIf
 from vyos.ifconfig.bridge import BridgeIf
 from vyos.ifconfig.dummy import DummyIf
 from vyos.ifconfig.ethernet import EthernetIf
 from vyos.ifconfig.geneve import GeneveIf
 from vyos.ifconfig.loopback import LoopbackIf
 from vyos.ifconfig.macvlan import MACVLANIf
 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 TunnelIf
-from vyos.ifconfig.erspan import ERSpanIf
-from vyos.ifconfig.erspan import ER6SpanIf
 from vyos.ifconfig.wireless import WiFiIf
 from vyos.ifconfig.l2tpv3 import L2TPv3If
 from vyos.ifconfig.macsec import MACsecIf
diff --git a/python/vyos/ifconfig/erspan.py b/python/vyos/ifconfig/erspan.py
deleted file mode 100755
index 03b2acdbf..000000000
--- a/python/vyos/ifconfig/erspan.py
+++ /dev/null
@@ -1,170 +0,0 @@
-# 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
-# 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/>.
-
-# https://developers.redhat.com/blog/2019/05/17/an-introduction-to-linux-virtual-interfaces-tunnels/#erspan
-# http://vger.kernel.org/lpc_net2018_talks/erspan-linux-presentation.pdf
-
-from copy import deepcopy
-
-from netaddr import EUI
-from netaddr import mac_unix_expanded
-from random import getrandbits
-
-from vyos.util import dict_search
-from vyos.ifconfig.interface import Interface
-from vyos.validate import assert_list
-
-@Interface.register
-class _ERSpan(Interface):
-    """
-    _ERSpan: private base class for ERSPAN tunnels
-    """
-    iftype = 'erspan'
-    definition = {
-        **Interface.definition,
-        **{
-            'section': 'erspan',
-            'prefixes': ['ersp',],
-        },
-    }
-
-    def __init__(self,ifname,**config):
-        self.config = deepcopy(config) if config else {}
-        super().__init__(ifname, **self.config)
-
-    def change_options(self):
-        pass
-
-    def _create(self):
-        pass
-
-class ERSpanIf(_ERSpan):
-    """
-    ERSpanIf: private base class for ERSPAN Over GRE and IPv4 tunnels
-    """
-
-    def _create(self):
-        ifname = self.config['ifname']
-        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 {source_address} remote {remote} seq key {key} erspan_ver {version}'
-
-        if int(version) == 1:
-            idx=dict_search('parameters.erspan.idx',self.config)
-            if idx:
-                command += f' erspan {idx}'
-        elif int(version) == 2:
-            direction=dict_search('parameters.erspan.direction',self.config)
-            if direction:
-                command += f' erspan_dir {direction}'
-            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']
-        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 {source_address} remote {remote} seq key {key} erspan_ver {version}'
-
-        if int(version) == 1:
-            idx=dict_search('parameters.erspan.idx',self.config)
-            if idx:
-                command += f' erspan {idx}'
-        elif int(version) == 2:
-            direction=dict_search('parameters.erspan.direction',self.config)
-            if direction:
-                command += f' erspan_dir {direction}'
-            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']
-        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 {source_address} remote {remote} seq key {key} erspan_ver {version}'
-
-        if int(version) == 1:
-            idx=dict_search('parameters.erspan.idx',self.config)
-            if idx:
-                command += f' erspan {idx}'
-        elif int(version) == 2:
-            direction=dict_search('parameters.erspan.direction',self.config)
-            if direction:
-                command += f' erspan_dir {direction}'
-            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']
-        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 {source_address} remote {remote} seq key {key} erspan_ver {version}'
-
-        if int(version) == 1:
-            idx=dict_search('parameters.erspan.idx',self.config)
-            if idx:
-                command += f' erspan {idx}'
-        elif int(version) == 2:
-            direction=dict_search('parameters.erspan.direction',self.config)
-            if direction:
-                command += f' erspan_dir {direction}'
-            hwid=dict_search('parameters.erspan.hwid',self.config)
-            if hwid:
-                command += f' erspan_hwid {hwid}'
-
-        self._cmd(command)
diff --git a/python/vyos/ifconfig/tunnel.py b/python/vyos/ifconfig/tunnel.py
index e5e1300b2..08854a3b0 100644
--- a/python/vyos/ifconfig/tunnel.py
+++ b/python/vyos/ifconfig/tunnel.py
@@ -1,188 +1,196 @@
 # 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
 # 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/>.
 
 # 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 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):
     if value == 'enable':
         return 'on'
     if value == 'disable':
         return 'off'
     raise ValueError(f'expect enable or disable but got "{value}"')
 
 @Interface.register
 class TunnelIf(Interface):
     """
     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
     """
     definition = {
         **Interface.definition,
         **{
             'section': 'tunnel',
             'prefixes': ['tun',],
         },
     }
 
     # 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',
+        'parameters.erspan.direction'     : 'erspan_dir',
+        'parameters.erspan.hw_id'         : 'erspan_hwid',
+        'parameters.erspan.index'         : 'erspan',
+        'parameters.erspan.version'       : 'erspan_ver',
     }
     mapping_ipv6 = {
         'parameters.ipv6.encaplimit'      : 'encaplimit',
         'parameters.ipv6.flowlabel'       : 'flowlabel',
         'parameters.ipv6.hoplimit'        : 'hoplimit',
         'parameters.ipv6.tclass'          : 'tclass',
     }
 
     # TODO: This is surely used for more than tunnels
     # TODO: could be refactored elsewhere
     _command_set = {
         **Interface._command_set,
         **{
             'multicast': {
                 'validate': lambda v: assert_list(v, ['enable', 'disable']),
                 'convert': enable_to_on,
                 'shellcmd': 'ip link set dev {ifname} multicast {value}',
             },
             'allmulticast': {
                 'validate': lambda v: assert_list(v, ['enable', 'disable']),
                 'convert': enable_to_on,
                 'shellcmd': 'ip link set dev {ifname} allmulticast {value}',
             },
         }
     }
 
     def __init__(self, ifname, **kargs):
         # T3357: we do not have the 'encapsulation' in kargs when calling this
         # class from op-mode like "show interfaces tunnel"
         if 'encapsulation' in kargs:
             self.iftype = kargs['encapsulation']
             # The gretap interface has the possibility to act as L2 bridge
             if self.iftype in ['gretap', 'ip6gretap']:
                 # no multicast, ttl or tos for gretap
                 self.definition = {
                     **TunnelIf.definition,
                     **{
                         'bridgeable': True,
                     },
                 }
 
         super().__init__(ifname, **kargs)
 
     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 {encapsulation}'
-        if self.iftype in ['gretap', 'ip6gretap']:
+        if self.iftype in ['gretap', 'ip6gretap', 'erspan', 'ip6erspan']:
             cmd = 'ip link add name {ifname} type {encapsulation}'
+            # ERSPAN requires the serialisation of packets
+            if self.iftype in ['erspan', 'ip6erspan']:
+                cmd += ' seq'
+
         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 _change_options(self):
         # gretap interfaces do not support changing any parameter
-        if self.iftype in ['gretap', 'ip6gretap']:
+        if self.iftype in ['gretap', 'ip6gretap', 'erspan', 'ip6erspan']:
             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):
         """
         Get current interface MAC (Media Access Contrl) address used.
 
         NOTE: Tunnel interfaces have no "MAC" address by default. The content
               of the 'address' file in /sys/class/net/device contains the
               local-ip thus we generate a random MAC address instead
 
         Example:
         >>> from vyos.ifconfig import Interface
         >>> Interface('eth0').get_mac()
         '00:50:ab:cd:ef:00'
         """
         # we choose 40 random bytes for the MAC address, this gives
         # us e.g. EUI('00-EA-EE-D6-A3-C8') or EUI('00-41-B9-0D-F2-2A')
         tmp = EUI(getrandbits(48)).value
         # set locally administered bit in MAC address
         tmp |= 0xf20000000000
         # convert integer to "real" MAC address representation
         mac = EUI(hex(tmp).split('x')[-1])
         # change dialect to use : as delimiter instead of -
         mac.dialect = mac_unix_expanded
         return str(mac)
 
     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. """
         # Adjust iproute2 tunnel parameters if necessary
         self._change_options()
 
         # call base class first
         super().update(config)
diff --git a/smoketest/scripts/cli/test_interfaces_tunnel.py b/smoketest/scripts/cli/test_interfaces_tunnel.py
index 6af31ddff..0e021b385 100755
--- a/smoketest/scripts/cli/test_interfaces_tunnel.py
+++ b/smoketest/scripts/cli/test_interfaces_tunnel.py
@@ -1,236 +1,322 @@
 #!/usr/bin/env python3
 #
 # Copyright (C) 2020-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/>.
 
 import unittest
 
 from base_interfaces_test import BasicInterfaceTest
 
 from vyos.configsession import ConfigSessionError
 from vyos.util import get_interface_config
 from vyos.template import inc_ip
 
 remote_ip4 = '192.0.2.100'
 remote_ip6 = '2001:db8::ffff'
 source_if = 'dum2222'
 mtu = 1476
 
 class TunnelInterfaceTest(BasicInterfaceTest.TestCase):
     @classmethod
     def setUpClass(cls):
         cls._test_ip = True
         cls._test_ipv6 = True
         cls._test_mtu = True
         cls._base_path = ['interfaces', 'tunnel']
         cls.local_v4 = '192.0.2.1'
         cls.local_v6 = '2001:db8::1'
         cls._options = {
             '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)
         # call base-classes classmethod
         super(cls, cls).setUpClass()
 
     def setUp(self):
         super().setUp()
         self.cli_set(['interfaces', 'dummy', source_if, 'address', self.local_v4 + '/32'])
         self.cli_set(['interfaces', 'dummy', source_if, 'address', self.local_v6 + '/128'])
 
     def tearDown(self):
         self.cli_delete(['interfaces', 'dummy', source_if])
         super().tearDown()
 
     def test_ipv4_encapsulations(self):
         # When running tests ensure that for certain encapsulation types the
         # local and remote IP address is actually an IPv4 address
 
         interface = f'tun1000'
         local_if_addr = f'10.10.200.1/24'
         for encapsulation in ['ipip', 'sit', 'gre', 'gretap']:
             self.cli_set(self._base_path + [interface, 'address', local_if_addr])
             self.cli_set(self._base_path + [interface, 'encapsulation', encapsulation])
             self.cli_set(self._base_path + [interface, 'source-address', self.local_v6])
             self.cli_set(self._base_path + [interface, 'remote', remote_ip6])
 
             # Encapsulation mode requires IPv4 source-address
             with self.assertRaises(ConfigSessionError):
                 self.cli_commit()
             self.cli_set(self._base_path + [interface, 'source-address', self.local_v4])
 
             # Encapsulation mode requires IPv4 remote
             with self.assertRaises(ConfigSessionError):
                 self.cli_commit()
             self.cli_set(self._base_path + [interface, 'remote', remote_ip4])
             self.cli_set(self._base_path + [interface, 'source-interface', source_if])
 
             # Source interface can not be used with sit and gretap
             if encapsulation in ['sit', 'gretap']:
                 with self.assertRaises(ConfigSessionError):
                     self.cli_commit()
                 self.cli_delete(self._base_path + [interface, 'source-interface'])
 
             # Check if commit is ok
             self.cli_commit()
 
             conf = get_interface_config(interface)
             if encapsulation not in ['sit', 'gretap']:
                 self.assertEqual(source_if, conf['link'])
 
             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.assertTrue(conf['linkinfo']['info_data']['pmtudisc'])
 
             # cleanup this instance
             self.cli_delete(self._base_path + [interface])
             self.cli_commit()
 
     def test_ipv6_encapsulations(self):
         # When running tests ensure that for certain encapsulation types the
         # local and remote IP address is actually an IPv6 address
 
         interface = f'tun1010'
         local_if_addr = f'10.10.200.1/24'
         for encapsulation in ['ipip6', 'ip6ip6', 'ip6gre', 'ip6gretap']:
             self.cli_set(self._base_path + [interface, 'address', local_if_addr])
             self.cli_set(self._base_path + [interface, 'encapsulation', encapsulation])
             self.cli_set(self._base_path + [interface, 'source-address', self.local_v4])
             self.cli_set(self._base_path + [interface, 'remote', remote_ip4])
 
             # Encapsulation mode requires IPv6 source-address
             with self.assertRaises(ConfigSessionError):
                 self.cli_commit()
             self.cli_set(self._base_path + [interface, 'source-address', self.local_v6])
 
             # Encapsulation mode requires IPv6 remote
             with self.assertRaises(ConfigSessionError):
                 self.cli_commit()
             self.cli_set(self._base_path + [interface, 'remote', remote_ip6])
 
             # Configure Tunnel Source interface
             self.cli_set(self._base_path + [interface, 'source-interface', source_if])
             # Source interface can not be used with ip6gretap
             if encapsulation in ['ip6gretap']:
                 with self.assertRaises(ConfigSessionError):
                     self.cli_commit()
                 self.cli_delete(self._base_path + [interface, 'source-interface'])
 
             # Check if commit is ok
             self.cli_commit()
 
             conf = get_interface_config(interface)
             if encapsulation not in ['ip6gretap']:
                 self.assertEqual(source_if, conf['link'])
 
             self.assertEqual(interface, conf['ifname'])
             self.assertEqual(mtu, conf['mtu'])
 
             # Not applicable for ip6gre
             if 'proto' in conf['linkinfo']['info_data']:
                 self.assertEqual(encapsulation, conf['linkinfo']['info_data']['proto'])
 
             # 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'])
 
             # cleanup this instance
             self.cli_delete(self._base_path + [interface])
             self.cli_commit()
 
     def test_tunnel_verify_local_dhcp(self):
         # 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.cli_set(self._base_path + [interface, 'address', local_if_addr])
         self.cli_set(self._base_path + [interface, 'encapsulation', 'gre'])
         self.cli_set(self._base_path + [interface, 'source-address', self.local_v4])
         self.cli_set(self._base_path + [interface, 'remote', remote_ip4])
         self.cli_set(self._base_path + [interface, 'dhcp-interface', 'eth0'])
 
         # source-address and dhcp-interface can not be used at the same time
         with self.assertRaises(ConfigSessionError):
             self.cli_commit()
         self.cli_delete(self._base_path + [interface, 'dhcp-interface'])
 
         # Check if commit is ok
         self.cli_commit()
 
     def test_tunnel_parameters_gre(self):
         interface = f'tun1030'
         gre_key = '10'
         encapsulation = 'gre'
         tos = '20'
 
         self.cli_set(self._base_path + [interface, 'encapsulation', encapsulation])
         self.cli_set(self._base_path + [interface, 'source-address', self.local_v4])
         self.cli_set(self._base_path + [interface, 'remote', remote_ip4])
 
         self.cli_set(self._base_path + [interface, 'parameters', 'ip', 'no-pmtu-discovery'])
         self.cli_set(self._base_path + [interface, 'parameters', 'ip', 'key', gre_key])
         self.cli_set(self._base_path + [interface, 'parameters', 'ip', 'tos', tos])
 
         # Check if commit is ok
         self.cli_commit()
 
         conf = get_interface_config(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'])
         self.assertFalse(               conf['linkinfo']['info_data']['pmtudisc'])
 
     def test_gretap_parameters_change(self):
         interface = f'tun1040'
         gre_key = '10'
         encapsulation = 'gretap'
         tos = '20'
 
         self.cli_set(self._base_path + [interface, 'encapsulation', encapsulation])
         self.cli_set(self._base_path + [interface, 'source-address', self.local_v4])
         self.cli_set(self._base_path + [interface, 'remote', remote_ip4])
 
         # Check if commit is ok
         self.cli_commit()
 
         conf = get_interface_config(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.cli_set(self._base_path + [interface, 'remote', new_remote])
         # Check if commit is ok
         self.cli_commit()
 
         conf = get_interface_config(interface)
         self.assertEqual(new_remote,    conf['linkinfo']['info_data']['remote'])
 
+    def test_erspan(self):
+        interface = f'tun1070'
+        encapsulation = 'erspan'
+        ip_key = '77'
+        idx = '20'
+
+        self.cli_set(self._base_path + [interface, 'encapsulation', encapsulation])
+        self.cli_set(self._base_path + [interface, 'source-address', self.local_v4])
+        self.cli_set(self._base_path + [interface, 'remote', remote_ip4])
+
+        self.cli_set(self._base_path + [interface, 'parameters', 'erspan', 'index', idx])
+
+        # ERSPAN requires ip key parameter
+        with self.assertRaises(ConfigSessionError):
+            self.cli_commit()
+        self.cli_set(self._base_path + [interface, 'parameters', 'ip', 'key', ip_key])
+
+        # Check if commit is ok
+        self.cli_commit()
+
+        conf = get_interface_config(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'])
+        self.assertEqual(f'0.0.0.{ip_key}', conf['linkinfo']['info_data']['ikey'])
+        self.assertEqual(f'0.0.0.{ip_key}', conf['linkinfo']['info_data']['okey'])
+        self.assertEqual(int(idx),          conf['linkinfo']['info_data']['erspan_index'])
+        self.assertEqual(1,                 conf['linkinfo']['info_data']['erspan_ver'])
+        self.assertTrue(                    conf['linkinfo']['info_data']['iseq'])
+        self.assertTrue(                    conf['linkinfo']['info_data']['oseq'])
+
+        # Change remote ip address (inc host by 2
+        new_remote = inc_ip(remote_ip4, 2)
+        self.cli_set(self._base_path + [interface, 'remote', new_remote])
+        # Check if commit is ok
+        self.cli_commit()
+
+        conf = get_interface_config(interface)
+        self.assertEqual(new_remote,    conf['linkinfo']['info_data']['remote'])
+
+    def test_ip6erspan(self):
+        interface = f'tun1070'
+        encapsulation = 'ip6erspan'
+        ip_key = '77'
+        erspan_ver = '2'
+        direction = 'ingres'
+
+        self.cli_set(self._base_path + [interface, 'encapsulation', encapsulation])
+        self.cli_set(self._base_path + [interface, 'source-address', self.local_v6])
+        self.cli_set(self._base_path + [interface, 'remote', remote_ip6])
+
+        self.cli_set(self._base_path + [interface, 'parameters', 'erspan', 'index', '10'])
+
+        # ERSPAN requires ip key parameter
+        with self.assertRaises(ConfigSessionError):
+            self.cli_commit()
+        self.cli_set(self._base_path + [interface, 'parameters', 'ip', 'key', ip_key])
+
+        # Check if commit is ok
+        self.cli_commit()
+
+        conf = get_interface_config(interface)
+        self.assertEqual(mtu,               conf['mtu'])
+        self.assertEqual(interface,         conf['ifname'])
+        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'])
+        self.assertEqual(0,                 conf['linkinfo']['info_data']['ttl'])
+        self.assertEqual(f'0.0.0.{ip_key}', conf['linkinfo']['info_data']['ikey'])
+        self.assertEqual(f'0.0.0.{ip_key}', conf['linkinfo']['info_data']['okey'])
+        self.assertEqual(1,                 conf['linkinfo']['info_data']['erspan_ver'])
+        self.assertTrue(                    conf['linkinfo']['info_data']['iseq'])
+        self.assertTrue(                    conf['linkinfo']['info_data']['oseq'])
+
+        # Change remote ip address (inc host by 2
+        new_remote = inc_ip(remote_ip6, 2)
+        self.cli_set(self._base_path + [interface, 'remote', new_remote])
+        # Check if commit is ok
+        self.cli_commit()
+
+        conf = get_interface_config(interface)
+        self.assertEqual(new_remote,    conf['linkinfo']['info_data']['remote'])
+
 if __name__ == '__main__':
     unittest.main(verbosity=2)
diff --git a/src/conf_mode/interfaces-erspan.py b/src/conf_mode/interfaces-erspan.py
deleted file mode 100755
index 97ae3cf55..000000000
--- a/src/conf_mode/interfaces-erspan.py
+++ /dev/null
@@ -1,108 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2018-2020 VyOS maintainers and contributors
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-import os
-
-from sys import exit
-from copy import deepcopy
-from netifaces import interfaces
-
-from vyos.config import Config
-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_mtu_ipv6
-from vyos.configverify import verify_tunnel
-from vyos.ifconfig import Interface
-from vyos.ifconfig import ERSpanIf
-from vyos.ifconfig import ER6SpanIf
-from vyos.template import is_ipv4
-from vyos.template import is_ipv6
-from vyos.util import dict_search
-from vyos import ConfigError
-from vyos import airbag
-airbag.enable()
-
-def get_config(config=None):
-    """
-    Retrive CLI config as dictionary. Dictionary can never be empty, as at least
-    the interface name will be added or a deleted flag
-    """
-    if config:
-        conf = config
-    else:
-        conf = Config()
-    base = ['interfaces', 'erspan']
-    erspan = get_interface_dict(conf, base)
-
-    tmp = leaf_node_changed(conf, ['encapsulation'])
-    if tmp:
-        erspan.update({'encapsulation_changed': {}})
-
-    return erspan
-
-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
-
-    dispatch = {
-        'erspan': ERSpanIf,
-        'ip6erspan': ER6SpanIf
-    }
-
-    # We need to re-map the tunnel encapsulation proto to a valid interface class
-    encap = erspan['encapsulation']
-    klass = dispatch[encap]
-
-    erspan_tunnel = klass(**erspan)
-    erspan_tunnel.change_options()
-    erspan_tunnel.update(erspan)
-
-    return None
-
-if __name__ == '__main__':
-    try:
-        c = get_config()
-        generate(c)
-        verify(c)
-        apply(c)
-    except ConfigError as e:
-        print(e)
-        exit(1)
diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py
index cab94a5b0..4e6c8a9ab 100755
--- a/src/conf_mode/interfaces-tunnel.py
+++ b/src/conf_mode/interfaces-tunnel.py
@@ -1,132 +1,148 @@
 #!/usr/bin/env python3
 #
 # Copyright (C) 2018-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/>.
 
 import os
 
 from sys import exit
 from netifaces import interfaces
 
 from vyos.config import Config
 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_address
 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 TunnelIf
 from vyos.template import is_ipv4
 from vyos.template import is_ipv6
 from vyos.util import get_interface_config
 from vyos.util import dict_search
 from vyos import ConfigError
 from vyos import airbag
 airbag.enable()
 
 def get_config(config=None):
     """
     Retrive CLI config as dictionary. Dictionary can never be empty, as at least
     the interface name will be added or a deleted flag
     """
     if config:
         conf = config
     else:
         conf = Config()
     base = ['interfaces', 'tunnel']
     tunnel = get_interface_dict(conf, base)
 
     tmp = leaf_node_changed(conf, ['encapsulation'])
     if tmp: tunnel.update({'encapsulation_changed': {}})
 
     # We must check if our interface is configured to be a DMVPN member
     nhrp_base = ['protocols', 'nhrp', 'tunnel']
     conf.set_level(nhrp_base)
     nhrp = conf.get_config_dict([], key_mangling=('-', '_'), get_first_key=True)
     if nhrp: tunnel.update({'nhrp' : list(nhrp.keys())})
 
+    if 'encapsulation' in tunnel and tunnel['encapsulation'] not in ['erspan', 'ip6erspan']:
+        del tunnel['parameters']['erspan']
+
     return tunnel
 
 def verify(tunnel):
     if 'deleted' in tunnel:
         verify_bridge_delete(tunnel)
 
         if 'nhrp' in tunnel and tunnel['ifname'] in tunnel['nhrp']:
             raise ConfigError('Tunnel used for NHRP, it can not be deleted!')
 
         return None
 
-    if 'encapsulation' not in tunnel:
-        error = 'Must configure encapsulation for "{ifname}"!'
-        raise ConfigError(error.format(**tunnel))
+    verify_tunnel(tunnel)
+
+    if tunnel['encapsulation'] in ['erspan', 'ip6erspan']:
+        if dict_search('parameters.ip.key', tunnel) == None:
+            raise ConfigError('ERSPAN requires ip key parameter!')
+
+        # this is a default field
+        ver = int(tunnel['parameters']['erspan']['version'])
+        if ver == 1:
+            if 'hw_id' in tunnel['parameters']['erspan']:
+                raise ConfigError('ERSPAN version 1 does not support hw-id!')
+            if 'direction' in tunnel['parameters']['erspan']:
+                raise ConfigError('ERSPAN version 1 does not support direction!')
+        elif ver == 2:
+            if 'idx' in tunnel['parameters']['erspan']:
+                raise ConfigError('ERSPAN version 2 does not index parameter!')
+            if 'direction' not in tunnel['parameters']['erspan']:
+                raise ConfigError('ERSPAN version 2 requires direction to be set!')
 
     verify_mtu_ipv6(tunnel)
     verify_address(tunnel)
     verify_vrf(tunnel)
-    verify_tunnel(tunnel)
 
     if 'source_interface' in tunnel:
         verify_interface_exists(tunnel['source_interface'])
 
     # TTL != 0 and nopmtudisc are incompatible, parameters and ip use default
     # values, thus the keys are always present.
     if dict_search('parameters.ip.no_pmtu_discovery', tunnel) != None:
         if dict_search('parameters.ip.ttl', tunnel) != '0':
             raise ConfigError('Disabled PMTU requires TTL set to "0"!')
         if tunnel['encapsulation'] in ['ipip6', 'ip6ip6', 'ip6gre']:
             raise ConfigError('Can not disable PMTU discovery for given encapsulation')
 
-
 def generate(tunnel):
     return None
 
 def apply(tunnel):
     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 = ''
     remote = ''
     tmp = get_interface_config(interface)
     if tmp:
         encap = dict_search('linkinfo.info_kind', tmp)
         remote = dict_search('linkinfo.info_data.remote', tmp)
 
-    if ('deleted' in tunnel or 'encapsulation_changed' in tunnel or
-        encap in ['gretap', 'ip6gretap'] or remote in ['any']):
+    if ('deleted' in tunnel or 'encapsulation_changed' in tunnel or encap in
+        ['gretap', 'ip6gretap', 'erspan', 'ip6erspan'] or remote in ['any']):
         if interface in interfaces():
             tmp = Interface(interface)
             tmp.remove()
         if 'deleted' in tunnel:
             return None
 
     tun = TunnelIf(**tunnel)
     tun.update(tunnel)
 
     return None
 
 if __name__ == '__main__':
     try:
         c = get_config()
         generate(c)
         verify(c)
         apply(c)
     except ConfigError as e:
         print(e)
         exit(1)