summaryrefslogtreecommitdiff
path: root/python/vyos
diff options
context:
space:
mode:
Diffstat (limited to 'python/vyos')
-rw-r--r--python/vyos/ifconfig/__init__.py2
-rwxr-xr-xpython/vyos/ifconfig/erspan.py190
2 files changed, 192 insertions, 0 deletions
diff --git a/python/vyos/ifconfig/__init__.py b/python/vyos/ifconfig/__init__.py
index 9cd8d44c1..f7b55c9dd 100644
--- a/python/vyos/ifconfig/__init__.py
+++ b/python/vyos/ifconfig/__init__.py
@@ -39,6 +39,8 @@ 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.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
new file mode 100755
index 000000000..848840144
--- /dev/null
+++ b/python/vyos/ifconfig/erspan.py
@@ -0,0 +1,190 @@
+# Copyright 2019-2020 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+# 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
+ """
+ default = {
+ **Interface.default,
+ **{
+ 'type': 'erspan',
+ }
+ }
+ definition = {
+ **Interface.definition,
+ **{
+ 'section': 'erspan',
+ 'prefixes': ['ersp',],
+ },
+ }
+
+ options = ['local_ip','remote_ip','encapsulation','parameters']
+
+ def __init__(self,ifname,**config):
+ self.config = deepcopy(config) if config else {}
+ super().__init__(ifname, **self.config)
+
+ def change_options(self):
+ pass
+
+ def update(self, config):
+
+ # Enable/Disable of an interface must always be done at the end of the
+ # derived class to make use of the ref-counting set_admin_state()
+ # function. We will only enable the interface if 'up' was called as
+ # often as 'down'. This is required by some interface implementations
+ # as certain parameters can only be changed when the interface is
+ # in admin-down state. This ensures the link does not flap during
+ # reconfiguration.
+ super().update(config)
+ state = 'down' if 'disable' in config else 'up'
+ self.set_admin_state(state)
+
+ 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']
+ local_ip = self.config['local_ip']
+ remote_ip = self.config['remote_ip']
+ 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}'
+
+ 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']
+ local_ip = self.config['local_ip']
+ remote_ip = self.config['remote_ip']
+ 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}'
+
+ 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']
+ local_ip = self.config['local_ip']
+ remote_ip = self.config['remote_ip']
+ 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}'
+
+ 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, config):
+ ifname = self.config['ifname']
+ local_ip = self.config['local_ip']
+ remote_ip = self.config['remote_ip']
+ 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}'
+
+ 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)