summaryrefslogtreecommitdiff
path: root/python/vyos/ifconfig/l2tpv3.py
blob: c1f2803eec6d590e575e46181ba7f53a95a9d2be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# Copyright 2019-2023 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 time import sleep
from time import time

from vyos.utils.process import run
from vyos.ifconfig.interface import Interface

def wait_for_add_l2tpv3(timeout=10, sleep_interval=1, cmd=None):
    '''
    In some cases, we need to wait until local address is assigned.
    And only then can the l2tpv3 tunnel be configured.
    For example when ipv6 address in tentative state
    or we wait for some routing daemon for remote address.
    '''
    start_time = time()
    test_command = cmd
    while True:
        if (start_time + timeout) < time():
            return None
        result = run(test_command)
        if result == 0:
            return True
        sleep(sleep_interval)

@Interface.register
class L2TPv3If(Interface):
    """
    The Linux bonding driver provides a method for aggregating multiple network
    interfaces into a single logical "bonded" interface. The behavior of the
    bonded interfaces depends upon the mode; generally speaking, modes provide
    either hot standby or load balancing services. Additionally, link integrity
    monitoring may be performed.
    """
    iftype = 'l2tp'
    definition = {
        **Interface.definition,
        **{
            'section': 'l2tpeth',
            'prefixes': ['l2tpeth', ],
            'bridgeable': True,
        }
    }

    def _create(self):
        # create tunnel interface
        cmd = 'ip l2tp add tunnel tunnel_id {tunnel_id}'
        cmd += ' peer_tunnel_id {peer_tunnel_id}'
        cmd += ' udp_sport {source_port}'
        cmd += ' udp_dport {destination_port}'
        cmd += ' encap {encapsulation}'
        cmd += ' local {source_address}'
        cmd += ' remote {remote}'
        c = cmd.format(**self.config)
        # wait until the local/remote address is available, but no more 10 sec.
        wait_for_add_l2tpv3(cmd=c)

        # setup session
        cmd = 'ip l2tp add session name {ifname}'
        cmd += ' tunnel_id {tunnel_id}'
        cmd += ' session_id {session_id}'
        cmd += ' peer_session_id {peer_session_id}'
        self._cmd(cmd.format(**self.config))

        # No need for interface shut down. There exist no function to permanently enable tunnel.
        # But you can disable interface permanently with shutdown/disable command.
        self.set_admin_state('up')

    def remove(self):
        """
        Remove interface from operating system. Removing the interface
        deconfigures all assigned IP addresses.
        Example:
        >>> from vyos.ifconfig import L2TPv3If
        >>> i = L2TPv3If('l2tpeth0')
        >>> i.remove()
        """

        if self.exists(self.ifname):
            self.set_admin_state('down')

            # remove all assigned IP addresses from interface - this is a bit redundant
            # as the kernel will remove all addresses on interface deletion
            self.flush_addrs()

            # remove interface from conntrack VRF interface map, here explicitly and do not
            # rely on the base class implementation as the interface will
            # vanish as soon as the l2tp session is deleted
            self._del_interface_from_ct_iface_map()

            if {'tunnel_id', 'session_id'} <= set(self.config):
                cmd = 'ip l2tp del session tunnel_id {tunnel_id}'
                cmd += ' session_id {session_id}'
                self._cmd(cmd.format(**self.config))

            if 'tunnel_id' in self.config:
                cmd = 'ip l2tp del tunnel tunnel_id {tunnel_id}'
                self._cmd(cmd.format(**self.config))

            # No need to call the baseclass as the interface is now already gone