Blame libnmstate/nm/bridge_port_vlan.py

Packit Service 0535c1
#
Packit Service 0535c1
# Copyright (c) 2020 Red Hat, Inc.
Packit Service 0535c1
#
Packit Service 0535c1
# This file is part of nmstate
Packit Service 0535c1
#
Packit Service 0535c1
# This program is free software: you can redistribute it and/or modify
Packit Service 0535c1
# it under the terms of the GNU Lesser General Public License as published by
Packit Service 0535c1
# the Free Software Foundation, either version 2.1 of the License, or
Packit Service 0535c1
# (at your option) any later version.
Packit Service 0535c1
#
Packit Service 0535c1
# This program is distributed in the hope that it will be useful,
Packit Service 0535c1
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 0535c1
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 0535c1
# GNU Lesser General Public License for more details.
Packit Service 0535c1
#
Packit Service 0535c1
# You should have received a copy of the GNU Lesser General Public License
Packit Service 0535c1
# along with this program. If not, see <https://www.gnu.org/licenses/>.
Packit Service 0535c1
#
Packit Service 0535c1
Packit Service 0535c1
from libnmstate.schema import LinuxBridge as LB
Packit Service 0535c1
Packit Service 0535c1
from .common import NM
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
class PortVlanFilter:
Packit Service 0535c1
    def __init__(self):
Packit Service 0535c1
        self._trunk_tags = []
Packit Service 0535c1
        self._tag = None
Packit Service 0535c1
        self._is_native = None
Packit Service 0535c1
        self._port_mode = None
Packit Service 0535c1
Packit Service 0535c1
    def create_configuration(self, trunk_tags, tag, is_native_vlan=False):
Packit Service 0535c1
        """
Packit Service 0535c1
        Fill the PortVlanFilter object with data whose format is tied to the
Packit Service 0535c1
        API.
Packit Service 0535c1
        :param trunk_tags: list of schema.LinuxBridge.Port.Vlan.TrunkTags
Packit Service 0535c1
               objects.
Packit Service 0535c1
        :param tag: the access tag for access ports, the native vlan ID for
Packit Service 0535c1
               trunk ports
Packit Service 0535c1
        :param is_native_vlan: boolean attribute indicating if the trunk port
Packit Service 0535c1
               has a native vlan.
Packit Service 0535c1
        """
Packit Service 0535c1
        self._trunk_tags = trunk_tags
Packit Service 0535c1
        self._tag = tag
Packit Service 0535c1
        self._is_native = is_native_vlan
Packit Service 0535c1
        self._port_mode = (
Packit Service 0535c1
            LB.Port.Vlan.Mode.TRUNK if trunk_tags else LB.Port.Vlan.Mode.ACCESS
Packit Service 0535c1
        )
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def trunk_tags(self):
Packit Service 0535c1
        return self._trunk_tags
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def tag(self):
Packit Service 0535c1
        return self._tag
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def is_native(self):
Packit Service 0535c1
        return self._is_native
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def port_mode(self):
Packit Service 0535c1
        return self._port_mode
Packit Service 0535c1
Packit Service 0535c1
    def to_nm(self):
Packit Service 0535c1
        """
Packit Service 0535c1
        Generate a list of NM.BridgeVlan objects from the encapsulated
Packit Service 0535c1
        PortVlanFilter data
Packit Service 0535c1
        """
Packit Service 0535c1
Packit Service 0535c1
        port_vlan_config = []
Packit Service 0535c1
        if self._port_mode == LB.Port.Vlan.Mode.TRUNK:
Packit Service 0535c1
            port_vlan_config += map(
Packit Service 0535c1
                PortVlanFilter._generate_vlan_trunk_port_config,
Packit Service 0535c1
                self._trunk_tags,
Packit Service 0535c1
            )
Packit Service 0535c1
            if self._is_native and self._tag:
Packit Service 0535c1
                port_vlan_config.append(
Packit Service 0535c1
                    PortVlanFilter._generate_vlan_access_port_config(self._tag)
Packit Service 0535c1
                )
Packit Service 0535c1
        elif self._port_mode == LB.Port.Vlan.Mode.ACCESS and self._tag:
Packit Service 0535c1
            port_vlan_config.append(
Packit Service 0535c1
                PortVlanFilter._generate_vlan_access_port_config(self._tag)
Packit Service 0535c1
            )
Packit Service 0535c1
Packit Service 0535c1
        return port_vlan_config
Packit Service 0535c1
Packit Service 0535c1
    def to_dict(self):
Packit Service 0535c1
        """
Packit Service 0535c1
        Get the port vlan filtering configuration in dict format - e.g. in yaml
Packit Service 0535c1
        format:
Packit Service 0535c1
        - name: eth1
Packit Service 0535c1
          vlan:
Packit Service 0535c1
            type: trunk
Packit Service 0535c1
            trunk-tags:
Packit Service 0535c1
              - id: 101
Packit Service 0535c1
              - id-range:
Packit Service 0535c1
                  min: 200
Packit Service 0535c1
                  max: 4095
Packit Service 0535c1
            tag: 100
Packit Service 0535c1
            enable-native: true
Packit Service 0535c1
        """
Packit Service 0535c1
Packit Service 0535c1
        port_vlan_state = {
Packit Service 0535c1
            LB.Port.Vlan.MODE: self._port_mode,
Packit Service 0535c1
            LB.Port.Vlan.TRUNK_TAGS: self._trunk_tags,
Packit Service 0535c1
        }
Packit Service 0535c1
        if self._tag:
Packit Service 0535c1
            port_vlan_state[LB.Port.Vlan.TAG] = self._tag
Packit Service 0535c1
        if self._port_mode == LB.Port.Vlan.Mode.TRUNK:
Packit Service 0535c1
            port_vlan_state[LB.Port.Vlan.ENABLE_NATIVE] = self._is_native
Packit Service 0535c1
        return port_vlan_state
Packit Service 0535c1
Packit Service 0535c1
    def import_from_bridge_settings(self, nm_bridge_vlans):
Packit Service 0535c1
        """
Packit Service 0535c1
        Instantiates a PortVlanFilter object from a list of NM.BridgeVlan
Packit Service 0535c1
        objects.
Packit Service 0535c1
        """
Packit Service 0535c1
Packit Service 0535c1
        self._is_native = False
Packit Service 0535c1
        trunk_tags = []
Packit Service 0535c1
Packit Service 0535c1
        is_access_port = PortVlanFilter._is_access_port(nm_bridge_vlans)
Packit Service 0535c1
        for nm_bridge_vlan in nm_bridge_vlans:
Packit Service 0535c1
            vlan_min, vlan_max = PortVlanFilter.get_vlan_tag_range(
Packit Service 0535c1
                nm_bridge_vlan
Packit Service 0535c1
            )
Packit Service 0535c1
            if is_access_port:
Packit Service 0535c1
                self._tag = vlan_min
Packit Service 0535c1
            elif nm_bridge_vlan.is_pvid() and nm_bridge_vlan.is_untagged():
Packit Service 0535c1
                # an NM.BridgeVlan has a range and can be PVID and/or untagged
Packit Service 0535c1
                # according to NM's model, PVID / untagged apply to the 'max'
Packit Service 0535c1
                # part of the range
Packit Service 0535c1
                self._tag = vlan_max
Packit Service 0535c1
                self._is_native = True
Packit Service 0535c1
            else:
Packit Service 0535c1
                trunk_tags.append(
Packit Service 0535c1
                    PortVlanFilter._translate_nm_bridge_vlan_to_trunk_tags(
Packit Service 0535c1
                        vlan_min, vlan_max
Packit Service 0535c1
                    )
Packit Service 0535c1
                )
Packit Service 0535c1
Packit Service 0535c1
        self._trunk_tags = trunk_tags
Packit Service 0535c1
        self._port_mode = (
Packit Service 0535c1
            LB.Port.Vlan.Mode.TRUNK if trunk_tags else LB.Port.Vlan.Mode.ACCESS
Packit Service 0535c1
        )
Packit Service 0535c1
Packit Service 0535c1
    @staticmethod
Packit Service 0535c1
    def get_vlan_tag_range(nm_bridge_vlan):
Packit Service 0535c1
        """
Packit Service 0535c1
        Extract the vlan tags from the NM.BridgeVlan object.
Packit Service 0535c1
        A single NM.BridgeVlan object can have a range of vlan tags, or a
Packit Service 0535c1
        single one.
Packit Service 0535c1
        When a NM.BridgeVlan holds a single tag, the min_range and max_range
Packit Service 0535c1
        returned will have the same vlan tag.
Packit Service 0535c1
        :return: min_range, max_range
Packit Service 0535c1
        """
Packit Service 0535c1
Packit Service 0535c1
        port_vlan_tags = nm_bridge_vlan.to_str().split()
Packit Service 0535c1
Packit Service 0535c1
        if "-" in port_vlan_tags[0]:
Packit Service 0535c1
            vlan_min, vlan_max = port_vlan_tags[0].split("-")
Packit Service 0535c1
            return int(vlan_min), int(vlan_max)
Packit Service 0535c1
        else:
Packit Service 0535c1
            tag = int(port_vlan_tags[0])
Packit Service 0535c1
            return tag, tag
Packit Service 0535c1
Packit Service 0535c1
    @staticmethod
Packit Service 0535c1
    def _is_access_port(nm_bridge_vlan_ports):
Packit Service 0535c1
        return (
Packit Service 0535c1
            len(nm_bridge_vlan_ports) == 1
Packit Service 0535c1
            and nm_bridge_vlan_ports[0].is_pvid()
Packit Service 0535c1
            and nm_bridge_vlan_ports[0].is_untagged()
Packit Service 0535c1
        )
Packit Service 0535c1
Packit Service 0535c1
    @staticmethod
Packit Service 0535c1
    def _translate_nm_bridge_vlan_to_trunk_tags(min_vlan, max_vlan):
Packit Service 0535c1
        if max_vlan != min_vlan:
Packit Service 0535c1
            port_data = {
Packit Service 0535c1
                LB.Port.Vlan.TrunkTags.ID_RANGE: {
Packit Service 0535c1
                    LB.Port.Vlan.TrunkTags.MIN_RANGE: min_vlan,
Packit Service 0535c1
                    LB.Port.Vlan.TrunkTags.MAX_RANGE: max_vlan,
Packit Service 0535c1
                }
Packit Service 0535c1
            }
Packit Service 0535c1
        else:
Packit Service 0535c1
            port_data = {LB.Port.Vlan.TrunkTags.ID: min_vlan}
Packit Service 0535c1
Packit Service 0535c1
        return port_data
Packit Service 0535c1
Packit Service 0535c1
    @staticmethod
Packit Service 0535c1
    def _generate_vlan_trunk_port_config(trunk_port):
Packit Service 0535c1
        min_range = max_range = trunk_port.get(LB.Port.Vlan.TrunkTags.ID)
Packit Service 0535c1
        if min_range is None:
Packit Service 0535c1
            ranged_vlan_tags = trunk_port.get(LB.Port.Vlan.TrunkTags.ID_RANGE)
Packit Service 0535c1
            min_range = ranged_vlan_tags[LB.Port.Vlan.TrunkTags.MIN_RANGE]
Packit Service 0535c1
            max_range = ranged_vlan_tags[LB.Port.Vlan.TrunkTags.MAX_RANGE]
Packit Service 0535c1
        port_vlan = NM.BridgeVlan.new(min_range, max_range)
Packit Service 0535c1
        port_vlan.set_untagged(False)
Packit Service 0535c1
        port_vlan.set_pvid(False)
Packit Service 0535c1
        return port_vlan
Packit Service 0535c1
Packit Service 0535c1
    @staticmethod
Packit Service 0535c1
    def _generate_vlan_access_port_config(vlan_tag):
Packit Service 0535c1
        port_vlan = NM.BridgeVlan.new(vlan_tag, vlan_tag)
Packit Service 0535c1
        port_vlan.set_untagged(True)
Packit Service 0535c1
        port_vlan.set_pvid(True)
Packit Service 0535c1
        return port_vlan