summaryrefslogtreecommitdiff
path: root/python/vyos/ifconfig/vlan.py
blob: 7b1e00d87aa850c4cb98cbe280b12868b113c527 (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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# Copyright 2019 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/>.


import os
import re

from vyos.ifconfig.interface import Interface


# This is an internal implementation class
class VLAN:
    """
    This class handels the creation and removal of a VLAN interface. It serves
    as base class for BondIf and EthernetIf.
    """

    _novlan_remove = lambda : None

    @classmethod
    def enable (cls,adaptee):
        adaptee._novlan_remove = adaptee.remove
        adaptee.remove = cls.remove
        adaptee.add_vlan = cls.add_vlan
        adaptee.del_vlan = cls.del_vlan
        adaptee.definition['vlan'] = True
        return adaptee

    def remove(self):
        """
        Remove interface from operating system. Removing the interface
        deconfigures all assigned IP addresses and clear possible DHCP(v6)
        client processes.

        Example:
        >>> from vyos.ifconfig import Interface
        >>> i = Interface('eth0')
        >>> i.remove()
        """
        ifname = self.config['ifname']

        # Do we have sub interfaces (VLANs)? We apply a regex matching
        # subinterfaces (indicated by a .) of a parent interface.
        #
        # As interfaces need to be deleted "in order" starting from Q-in-Q
        # we delete them first.
        vlan_ifs = [f for f in os.listdir(r'/sys/class/net')
                    if re.match(ifname + r'(?:\.\d+)(?:\.\d+)', f)]

        for vlan in vlan_ifs:
            Interface(vlan).remove()

        # After deleting all Q-in-Q interfaces delete other VLAN interfaces
        # which probably acted as parent to Q-in-Q or have been regular 802.1q
        # interface.
        vlan_ifs = [f for f in os.listdir(r'/sys/class/net')
                    if re.match(ifname + r'(?:\.\d+)', f)]

        for vlan in vlan_ifs:
            # self.__class__ is already VLAN.enabled
            self.__class__(vlan)._novlan_remove()

        # All subinterfaces are now removed, continue on the physical interface
        self._novlan_remove()

    def add_vlan(self, vlan_id, ethertype='', ingress_qos='', egress_qos=''):
        """
        A virtual LAN (VLAN) is any broadcast domain that is partitioned and
        isolated in a computer network at the data link layer (OSI layer 2).
        Use this function to create a new VLAN interface on a given physical
        interface.

        This function creates both 802.1q and 802.1ad (Q-in-Q) interfaces. Proto
        parameter is used to indicate VLAN type.

        A new object of type VLANIf is returned once the interface has been
        created.

        @param ethertype: If specified, create 802.1ad or 802.1q Q-in-Q VLAN
                          interface
        @param ingress_qos: Defines a mapping of VLAN header prio field to the
                            Linux internal packet priority on incoming frames.
        @param ingress_qos: Defines a mapping of Linux internal packet priority
                            to VLAN header prio field but for outgoing frames.

        Example:
        >>> from vyos.ifconfig import MACVLANIf
        >>> i = MACVLANIf('eth0')
        >>> i.add_vlan(10)
        """
        vlan_ifname = self.config['ifname'] + '.' + str(vlan_id)
        if not os.path.exists(f'/sys/class/net/{vlan_ifname}'):
            self._vlan_id = int(vlan_id)

            if ethertype:
                self._ethertype = ethertype
                ethertype = 'proto {}'.format(ethertype)

            # Optional ingress QOS mapping
            opt_i = ''
            if ingress_qos:
                opt_i = 'ingress-qos-map ' + ingress_qos
            # Optional egress QOS mapping
            opt_e = ''
            if egress_qos:
                opt_e = 'egress-qos-map ' + egress_qos

            # create interface in the system
            cmd = 'ip link add link {ifname} name {ifname}.{vlan} type vlan {proto} id {vlan} {opt_e} {opt_i}' \
                .format(ifname=self.config['ifname'], vlan=self._vlan_id, proto=ethertype, opt_e=opt_e, opt_i=opt_i)
            self._cmd(cmd)

        # return new object mapping to the newly created interface
        # we can now work on this object for e.g. IP address setting
        # or interface description and so on
        return self.__class__(vlan_ifname)

    def del_vlan(self, vlan_id):
        """
        Remove VLAN interface from operating system. Removing the interface
        deconfigures all assigned IP addresses and clear possible DHCP(v6)
        client processes.

        Example:
        >>> from vyos.ifconfig import MACVLANIf
        >>> i = MACVLANIf('eth0.10')
        >>> i.del_vlan()
        """
        ifname = self.config['ifname']
        self.__class__(f'{ifname}.{vlan_id}')._novlan_remove()