Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F118309633
interfaces-tunnel.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
interfaces-tunnel.py
View Options
#!/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
ipaddress
import
IPv4Address
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
Section
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
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!'
)
# If tunnel source address any and key not set
if
tunnel
[
'encapsulation'
]
in
[
'gre'
]
and
\
dict_search
(
'source_address'
,
tunnel
)
==
'0.0.0.0'
and
\
dict_search
(
'parameters.ip.key'
,
tunnel
)
==
None
:
raise
ConfigError
(
'Tunnel parameters ip key must be set!'
)
if
tunnel
[
'encapsulation'
]
in
[
'gre'
,
'gretap'
]:
# Check pairs tunnel source-address/encapsulation/key with exists tunnels.
# Prevent the same key for 2 tunnels with same source-address/encap. T2920
for
tunnel_if
in
Section
.
interfaces
(
'tunnel'
):
# It makes no sense to run the test against our own interface we
# are currently configuring
if
tunnel
[
'ifname'
]
==
tunnel_if
:
continue
tunnel_cfg
=
get_interface_config
(
tunnel_if
)
# no match on encapsulation - bail out
if
dict_search
(
'linkinfo.info_kind'
,
tunnel_cfg
)
!=
tunnel
[
'encapsulation'
]:
continue
new_source_address
=
dict_search
(
'source_address'
,
tunnel
)
new_source_interface
=
dict_search
(
'source_interface'
,
tunnel
)
if
dict_search
(
'parameters.ip.key'
,
tunnel
)
!=
None
:
# Convert tunnel key to ip key, format "ip -j link show"
# 1 => 0.0.0.1, 999 => 0.0.3.231
orig_new_key
=
dict_search
(
'parameters.ip.key'
,
tunnel
)
new_key
=
IPv4Address
(
int
(
orig_new_key
))
new_key
=
str
(
new_key
)
if
dict_search
(
'address'
,
tunnel_cfg
)
==
new_source_address
and
\
dict_search
(
'linkinfo.info_data.ikey'
,
tunnel_cfg
)
==
new_key
:
raise
ConfigError
(
f
'Key "{orig_new_key}" for source-address "{new_source_address}" '
\
f
'is already used for tunnel "{tunnel_if}"!'
)
else
:
# If no IP GRE key is used we can not have more then one GRE tunnel
# bound to any one interface/IP address. This will result in a OS
# PermissionError: add tunnel "gre0" failed: File exists
if
(
dict_search
(
'address'
,
tunnel_cfg
)
==
new_source_address
or
(
dict_search
(
'address'
,
tunnel_cfg
)
==
'0.0.0.0'
and
dict_search
(
'link'
,
tunnel_cfg
)
==
new_source_interface
)):
raise
ConfigError
(
f
'Missing required "ip key" parameter when
\
running more then one GRE based tunnel on the
\
same source-interface/source-address'
)
# Keys are not allowed with ipip and sit tunnels
if
tunnel
[
'encapsulation'
]
in
[
'ipip'
,
'sit'
]:
if
dict_search
(
'parameters.ip.key'
,
tunnel
)
!=
None
:
raise
ConfigError
(
'Keys are not allowed with ipip and sit tunnels!'
)
verify_mtu_ipv6
(
tunnel
)
verify_address
(
tunnel
)
verify_vrf
(
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'
)
if
dict_search
(
'parameters.ip.ignore_df'
,
tunnel
)
!=
None
:
if
tunnel
[
'encapsulation'
]
not
in
[
'gretap'
]:
raise
ConfigError
(
'Option ignore-df can only be used on GRETAP tunnels!'
)
if
dict_search
(
'parameters.ip.no_pmtu_discovery'
,
tunnel
)
==
None
:
raise
ConfigError
(
'Option ignore-df requires path MTU discovery to be disabled!'
)
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'
,
'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
)
File Metadata
Details
Attached
Mime Type
text/x-script.python
Expires
Sat, Oct 17, 12:50 AM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4355270
Default Alt Text
interfaces-tunnel.py (8 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment