Page MenuHomeVyOS Platform

tunnel.py
No OneTemporary

Size
7 KB
Referenced Files
None
Subscribers
None

tunnel.py

# 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',
}
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']:
cmd = 'ip link add name {ifname} type {encapsulation}'
for vyos_key, iproute2_key in mapping.items():
# dict_search will return an empty dict "{}" for valueless nodes like
# "parameters.nolearning" - thus we need to test the nodes existence
# by using isinstance()
tmp = dict_search(vyos_key, self.config)
if isinstance(tmp, dict):
cmd += f' {iproute2_key}'
elif tmp != None:
cmd += f' {iproute2_key} {tmp}'
self._cmd(cmd.format(**self.config))
self.set_admin_state('down')
def _change_options(self):
# gretap interfaces do not support changing any parameter
if self.iftype in ['gretap', 'ip6gretap']:
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)

File Metadata

Mime Type
text/x-script.python
Expires
Sat, Sep 26, 1:13 PM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4284158
Default Alt Text
tunnel.py (7 KB)

Event Timeline