|
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
|