Blame libnmstate/nm/ovs.py

Packit Service 0535c1
#
Packit Service 0535c1
# Copyright (c) 2018-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
import logging
Packit Service 0535c1
from operator import itemgetter
Packit Service 0535c1
Packit Service 0535c1
from libnmstate.schema import OVSBridge as OB
Packit Service 0535c1
from libnmstate.schema import OVSInterface
Packit Service 0535c1
Packit Service 0535c1
from . import connection
Packit Service 0535c1
from .common import NM
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
PORT_PROFILE_PREFIX = "ovs-port-"
Packit Service 0535c1
Packit Service 0535c1
NM_OVS_VLAN_MODE_MAP = {
Packit Service 0535c1
    "trunk": OB.Port.Vlan.Mode.TRUNK,
Packit Service 0535c1
    "access": OB.Port.Vlan.Mode.ACCESS,
Packit Service 0535c1
    "native-tagged": OB.Port.Vlan.Mode.TRUNK,
Packit Service 0535c1
    "native-untagged": OB.Port.Vlan.Mode.UNKNOWN,  # Not supported yet
Packit Service 0535c1
    "dot1q-tunnel": OB.Port.Vlan.Mode.UNKNOWN,  # Not supported yet
Packit Service 0535c1
}
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
class LacpValue:
Packit Service 0535c1
    ACTIVE = "active"
Packit Service 0535c1
    OFF = "off"
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def has_ovs_capability(nm_client):
Packit Service 0535c1
    return NM.Capability.OVS in nm_client.get_capabilities()
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def create_bridge_setting(options_state):
Packit Service 0535c1
    bridge_setting = NM.SettingOvsBridge.new()
Packit Service 0535c1
    for option_name, option_value in options_state.items():
Packit Service 0535c1
        if option_name == "fail-mode":
Packit Service 0535c1
            if option_value:
Packit Service 0535c1
                bridge_setting.props.fail_mode = option_value
Packit Service 0535c1
        elif option_name == "mcast-snooping-enable":
Packit Service 0535c1
            bridge_setting.props.mcast_snooping_enable = option_value
Packit Service 0535c1
        elif option_name == "rstp":
Packit Service 0535c1
            bridge_setting.props.rstp_enable = option_value
Packit Service 0535c1
        elif option_name == "stp":
Packit Service 0535c1
            bridge_setting.props.stp_enable = option_value
Packit Service 0535c1
Packit Service 0535c1
    return bridge_setting
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def create_port_setting(port_state):
Packit Service 0535c1
    port_setting = NM.SettingOvsPort.new()
Packit Service 0535c1
Packit Service 0535c1
    lag_state = port_state.get(OB.Port.LINK_AGGREGATION_SUBTREE)
Packit Service 0535c1
    if lag_state:
Packit Service 0535c1
        mode = lag_state.get(OB.Port.LinkAggregation.MODE)
Packit Service 0535c1
        if mode == OB.Port.LinkAggregation.Mode.LACP:
Packit Service 0535c1
            port_setting.props.lacp = LacpValue.ACTIVE
Packit Service 0535c1
        elif mode in (
Packit Service 0535c1
            OB.Port.LinkAggregation.Mode.ACTIVE_BACKUP,
Packit Service 0535c1
            OB.Port.LinkAggregation.Mode.BALANCE_SLB,
Packit Service 0535c1
        ):
Packit Service 0535c1
            port_setting.props.lacp = LacpValue.OFF
Packit Service 0535c1
            port_setting.props.bond_mode = mode
Packit Service 0535c1
        elif mode == OB.Port.LinkAggregation.Mode.BALANCE_TCP:
Packit Service 0535c1
            port_setting.props.lacp = LacpValue.ACTIVE
Packit Service 0535c1
            port_setting.props.bond_mode = mode
Packit Service 0535c1
Packit Service 0535c1
        down_delay = lag_state.get(OB.Port.LinkAggregation.Options.DOWN_DELAY)
Packit Service 0535c1
        if down_delay:
Packit Service 0535c1
            port_setting.props.bond_downdelay = down_delay
Packit Service 0535c1
        up_delay = lag_state.get(OB.Port.LinkAggregation.Options.UP_DELAY)
Packit Service 0535c1
        if up_delay:
Packit Service 0535c1
            port_setting.props.bond_updelay = up_delay
Packit Service 0535c1
Packit Service 0535c1
    vlan_state = port_state.get(OB.Port.VLAN_SUBTREE, {})
Packit Service 0535c1
    if OB.Port.Vlan.MODE in vlan_state:
Packit Service 0535c1
        if vlan_state[OB.Port.Vlan.MODE] != OB.Port.Vlan.Mode.UNKNOWN:
Packit Service 0535c1
            port_setting.props.vlan_mode = vlan_state[OB.Port.Vlan.MODE]
Packit Service 0535c1
    if OB.Port.Vlan.TAG in vlan_state:
Packit Service 0535c1
        port_setting.props.tag = vlan_state[OB.Port.Vlan.TAG]
Packit Service 0535c1
Packit Service 0535c1
    return port_setting
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def create_interface_setting(patch_state):
Packit Service 0535c1
    interface_setting = NM.SettingOvsInterface.new()
Packit Service 0535c1
    settings = [interface_setting]
Packit Service 0535c1
Packit Service 0535c1
    if patch_state and patch_state.get(OVSInterface.Patch.PEER):
Packit Service 0535c1
        interface_setting.props.type = "patch"
Packit Service 0535c1
        settings.append(create_patch_setting(patch_state))
Packit Service 0535c1
    else:
Packit Service 0535c1
        interface_setting.props.type = "internal"
Packit Service 0535c1
Packit Service 0535c1
    return settings
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def create_patch_setting(patch_state):
Packit Service 0535c1
    patch_setting = NM.SettingOvsPatch.new()
Packit Service 0535c1
    patch_setting.props.peer = patch_state[OVSInterface.Patch.PEER]
Packit Service 0535c1
Packit Service 0535c1
    return patch_setting
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def is_ovs_bridge_type_id(type_id):
Packit Service 0535c1
    return type_id == NM.DeviceType.OVS_BRIDGE
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def is_ovs_port_type_id(type_id):
Packit Service 0535c1
    return type_id == NM.DeviceType.OVS_PORT
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def is_ovs_interface_type_id(type_id):
Packit Service 0535c1
    return type_id == NM.DeviceType.OVS_INTERFACE
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def get_port_by_slave(nmdev):
Packit Service 0535c1
    active_con = connection.get_device_active_connection(nmdev)
Packit Service 0535c1
    if active_con:
Packit Service 0535c1
        master = active_con.get_master()
Packit Service 0535c1
        if master and is_ovs_port_type_id(master.get_device_type()):
Packit Service 0535c1
            return master
Packit Service 0535c1
    return None
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def get_ovs_info(context, bridge_device, devices_info):
Packit Service 99aaff
    port_profiles = _get_slave_profiles(bridge_device, devices_info)
Packit Service 0535c1
    ports = _get_bridge_ports_info(context, port_profiles, devices_info)
Packit Service 0535c1
    options = _get_bridge_options(context, bridge_device)
Packit Service 0535c1
Packit Service 0535c1
    if ports or options:
Packit Service 0535c1
        return {"port": ports, "options": options}
Packit Service 0535c1
    else:
Packit Service 0535c1
        return {}
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def get_interface_info(act_con):
Packit Service 0535c1
    """
Packit Service 0535c1
    Get OVS interface information from the NM profile.
Packit Service 0535c1
    """
Packit Service 0535c1
    info = {}
Packit Service 0535c1
    if act_con:
Packit Service 0535c1
        patch_setting = _get_patch_setting(act_con)
Packit Service 0535c1
        if patch_setting:
Packit Service 0535c1
            info[OVSInterface.PATCH_CONFIG_SUBTREE] = {
Packit Service 0535c1
                OVSInterface.Patch.PEER: patch_setting.props.peer,
Packit Service 0535c1
            }
Packit Service 0535c1
Packit Service 0535c1
    return info
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _get_patch_setting(act_con):
Packit Service 0535c1
    """
Packit Service 0535c1
    Get NM.SettingOvsPatch from NM.ActiveConnection.
Packit Service 0535c1
    For any error, return None.
Packit Service 0535c1
    """
Packit Service 0535c1
    remote_con = act_con.get_connection()
Packit Service 0535c1
    if remote_con:
Packit Service 0535c1
        return remote_con.get_setting_ovs_patch()
Packit Service 0535c1
Packit Service 0535c1
    return None
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def get_slaves(nm_device):
Packit Service 0535c1
    return nm_device.get_slaves()
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _get_bridge_ports_info(context, port_profiles, devices_info):
Packit Service 0535c1
    ports_info = []
Packit Service 0535c1
    for p in port_profiles:
Packit Service 0535c1
        port_info = _get_bridge_port_info(context, p, devices_info)
Packit Service 0535c1
        if port_info:
Packit Service 0535c1
            ports_info.append(port_info)
Packit Service 0535c1
    ports_info.sort(key=itemgetter(OB.Port.NAME))
Packit Service 0535c1
    return ports_info
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _get_bridge_port_info(context, port_profile, devices_info):
Packit Service 0535c1
    """
Packit Service 0535c1
    Report port information.
Packit Service 0535c1
    Note: The current implementation supports only system OVS ports and
Packit Service 0535c1
    access vlan-mode (trunks are not supported).
Packit Service 0535c1
    """
Packit Service 0535c1
    port_info = {}
Packit Service 0535c1
Packit Service 0535c1
    port_setting = port_profile.get_setting(NM.SettingOvsPort)
Packit Service 0535c1
    vlan_mode = port_setting.props.vlan_mode
Packit Service 0535c1
Packit Service 0535c1
    port_name = port_profile.get_interface_name()
Packit Service 99aaff
    port_device = context.get_nm_dev(port_name)
Packit Service 99aaff
    port_slave_profiles = _get_slave_profiles(port_device, devices_info)
Packit Service 0535c1
    port_slave_names = [c.get_interface_name() for c in port_slave_profiles]
Packit Service 0535c1
Packit Service 0535c1
    if port_slave_names:
Packit Service 0535c1
        number_of_interfaces = len(port_slave_names)
Packit Service 0535c1
        if number_of_interfaces == 1:
Packit Service 0535c1
            port_info[OB.Port.NAME] = port_slave_names[0]
Packit Service 0535c1
        else:
Packit Service 0535c1
            port_lag_info = _get_lag_info(
Packit Service 0535c1
                port_name, port_setting, port_slave_names
Packit Service 0535c1
            )
Packit Service 0535c1
            port_info.update(port_lag_info)
Packit Service 0535c1
Packit Service 0535c1
        if vlan_mode:
Packit Service 0535c1
            nmstate_vlan_mode = NM_OVS_VLAN_MODE_MAP.get(
Packit Service 0535c1
                vlan_mode, OB.Port.Vlan.Mode.UNKNOWN
Packit Service 0535c1
            )
Packit Service 0535c1
            if nmstate_vlan_mode == OB.Port.Vlan.Mode.UNKNOWN:
Packit Service 0535c1
                logging.warning(
Packit Service 0535c1
                    f"OVS Port VLAN mode '{vlan_mode}' is not supported yet"
Packit Service 0535c1
                )
Packit Service 0535c1
            port_info[OB.Port.VLAN_SUBTREE] = {
Packit Service 0535c1
                OB.Port.Vlan.MODE: nmstate_vlan_mode,
Packit Service 0535c1
                OB.Port.Vlan.TAG: port_setting.get_tag(),
Packit Service 0535c1
            }
Packit Service 0535c1
    return port_info
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _get_lag_info(port_name, port_setting, port_slave_names):
Packit Service 0535c1
    port_info = {}
Packit Service 0535c1
Packit Service 0535c1
    lacp = port_setting.props.lacp
Packit Service 0535c1
    mode = port_setting.props.bond_mode
Packit Service 0535c1
    if not mode:
Packit Service 0535c1
        if lacp == LacpValue.ACTIVE:
Packit Service 0535c1
            mode = OB.Port.LinkAggregation.Mode.LACP
Packit Service 0535c1
        else:
Packit Service 0535c1
            mode = OB.Port.LinkAggregation.Mode.ACTIVE_BACKUP
Packit Service 0535c1
    port_info[OB.Port.NAME] = port_name
Packit Service 0535c1
    port_info[OB.Port.LINK_AGGREGATION_SUBTREE] = {
Packit Service 0535c1
        OB.Port.LinkAggregation.MODE: mode,
Packit Service 0535c1
        OB.Port.LinkAggregation.SLAVES_SUBTREE: sorted(
Packit Service 0535c1
            [
Packit Service 0535c1
                {OB.Port.LinkAggregation.Slave.NAME: iface_name}
Packit Service 0535c1
                for iface_name in port_slave_names
Packit Service 0535c1
            ],
Packit Service 0535c1
            key=itemgetter(OB.Port.LinkAggregation.Slave.NAME),
Packit Service 0535c1
        ),
Packit Service 0535c1
    }
Packit Service 0535c1
    return port_info
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _get_bridge_options(context, bridge_device):
Packit Service 0535c1
    bridge_options = {}
Packit Service 0535c1
    con = connection.ConnectionProfile(context)
Packit Service 0535c1
    con.import_by_device(bridge_device)
Packit Service 0535c1
    if con.profile:
Packit Service 0535c1
        bridge_setting = con.profile.get_setting(NM.SettingOvsBridge)
Packit Service 0535c1
        bridge_options["stp"] = bridge_setting.props.stp_enable
Packit Service 0535c1
        bridge_options["rstp"] = bridge_setting.props.rstp_enable
Packit Service 0535c1
        bridge_options["fail-mode"] = bridge_setting.props.fail_mode or ""
Packit Service 0535c1
        bridge_options[
Packit Service 0535c1
            "mcast-snooping-enable"
Packit Service 0535c1
        ] = bridge_setting.props.mcast_snooping_enable
Packit Service 0535c1
Packit Service 0535c1
    return bridge_options
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _get_slave_profiles(master_device, devices_info):
Packit Service 0535c1
    slave_profiles = []
Packit Service 0535c1
    for dev, _ in devices_info:
Packit Service 0535c1
        active_con = connection.get_device_active_connection(dev)
Packit Service 0535c1
        if active_con:
Packit Service 0535c1
            master = active_con.props.master
Packit Service 0535c1
            if master and (master.get_iface() == master_device.get_iface()):
Packit Service 99aaff
                slave_profiles.append(active_con.props.connection)
Packit Service 0535c1
    return slave_profiles