Blame libnmstate/nm/ipv6.py

Packit Service 0535c1
#
Packit Service 0535c1
# Copyright (c) 2018-2019 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
import socket
Packit Service 0535c1
Packit Service 0535c1
from libnmstate import iplib
Packit Service 0535c1
from libnmstate.error import NmstateNotImplementedError
Packit Service 0535c1
from libnmstate.nm import dns as nm_dns
Packit Service 0535c1
from libnmstate.nm import route as nm_route
Packit Service 0535c1
from libnmstate.schema import InterfaceIPv6
Packit Service 0535c1
from libnmstate.schema import Route
Packit Service 0535c1
Packit Service 0535c1
from ..ifaces import BaseIface
Packit Service 0535c1
from .common import NM
Packit Service 0535c1
Packit Service 0535c1
IPV6_DEFAULT_ROUTE_METRIC = 1024
Packit Service 0535c1
INT32_MAX = 2 ** 31 - 1
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def get_info(active_connection):
Packit Service 0535c1
    info = {InterfaceIPv6.ENABLED: False}
Packit Service 0535c1
    if active_connection is None:
Packit Service 0535c1
        return info
Packit Service 0535c1
Packit Service 0535c1
    info[InterfaceIPv6.DHCP] = False
Packit Service 0535c1
    info[InterfaceIPv6.AUTOCONF] = False
Packit Service 0535c1
Packit Service 0535c1
    is_link_local_method = False
Packit Service 0535c1
    ip_profile = get_ip_profile(active_connection)
Packit Service 0535c1
    if ip_profile:
Packit Service 0535c1
        method = ip_profile.get_method()
Packit Service 0535c1
        if method == NM.SETTING_IP6_CONFIG_METHOD_AUTO:
Packit Service 0535c1
            info[InterfaceIPv6.DHCP] = True
Packit Service 0535c1
            info[InterfaceIPv6.AUTOCONF] = True
Packit Service 0535c1
        elif method == NM.SETTING_IP6_CONFIG_METHOD_DHCP:
Packit Service 0535c1
            info[InterfaceIPv6.DHCP] = True
Packit Service 0535c1
            info[InterfaceIPv6.AUTOCONF] = False
Packit Service 0535c1
        elif method == NM.SETTING_IP6_CONFIG_METHOD_LINK_LOCAL:
Packit Service 0535c1
            is_link_local_method = True
Packit Service 0535c1
        elif method == NM.SETTING_IP6_CONFIG_METHOD_DISABLED:
Packit Service 0535c1
            return info
Packit Service 0535c1
Packit Service 0535c1
        if info[InterfaceIPv6.DHCP] or info[InterfaceIPv6.AUTOCONF]:
Packit Service 0535c1
            props = ip_profile.props
Packit Service 0535c1
            info[InterfaceIPv6.AUTO_ROUTES] = not props.ignore_auto_routes
Packit Service 0535c1
            info[InterfaceIPv6.AUTO_GATEWAY] = not props.never_default
Packit Service 0535c1
            info[InterfaceIPv6.AUTO_DNS] = not props.ignore_auto_dns
Packit Service 0535c1
Packit Service 0535c1
    ipconfig = active_connection.get_ip6_config()
Packit Service 0535c1
    if ipconfig is None:
Packit Service 0535c1
        # When DHCP is enable, it might be possible, the active_connection does
Packit Service 0535c1
        # not got IP address yet. In that case, we still mark
Packit Service 0535c1
        # info[InterfaceIPv6.ENABLED] as True.
Packit Service 0535c1
        if (
Packit Service 0535c1
            info[InterfaceIPv6.DHCP]
Packit Service 0535c1
            or info[InterfaceIPv6.AUTOCONF]
Packit Service 0535c1
            or is_link_local_method
Packit Service 0535c1
        ):
Packit Service 0535c1
            info[InterfaceIPv6.ENABLED] = True
Packit Service 0535c1
            info[InterfaceIPv6.ADDRESS] = []
Packit Service 0535c1
        else:
Packit Service 0535c1
            del info[InterfaceIPv6.DHCP]
Packit Service 0535c1
            del info[InterfaceIPv6.AUTOCONF]
Packit Service 0535c1
        return info
Packit Service 0535c1
Packit Service 0535c1
    addresses = [
Packit Service 0535c1
        {
Packit Service 0535c1
            InterfaceIPv6.ADDRESS_IP: address.get_address(),
Packit Service 0535c1
            InterfaceIPv6.ADDRESS_PREFIX_LENGTH: int(address.get_prefix()),
Packit Service 0535c1
        }
Packit Service 0535c1
        for address in ipconfig.get_addresses()
Packit Service 0535c1
    ]
Packit Service 0535c1
    if not addresses:
Packit Service 0535c1
        return info
Packit Service 0535c1
Packit Service 0535c1
    info[InterfaceIPv6.ENABLED] = True
Packit Service 0535c1
    info[InterfaceIPv6.ADDRESS] = addresses
Packit Service 0535c1
    return info
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def create_setting(config, base_con_profile):
Packit Service 0535c1
    setting_ip = None
Packit Service 0535c1
    if base_con_profile and config and config.get(InterfaceIPv6.ENABLED):
Packit Service 0535c1
        setting_ip = base_con_profile.get_setting_ip6_config()
Packit Service 0535c1
        if setting_ip:
Packit Service 0535c1
            setting_ip = setting_ip.duplicate()
Packit Service 0535c1
            setting_ip.clear_addresses()
Packit Service 0535c1
            setting_ip.props.ignore_auto_routes = False
Packit Service 0535c1
            setting_ip.props.never_default = False
Packit Service 0535c1
            setting_ip.props.ignore_auto_dns = False
Packit Service 0535c1
            setting_ip.clear_routes()
Packit Service fec588
            setting_ip.clear_routing_rules()
Packit Service 0535c1
            setting_ip.props.gateway = None
Packit Service 0535c1
            setting_ip.props.route_table = Route.USE_DEFAULT_ROUTE_TABLE
Packit Service 0535c1
            setting_ip.props.route_metric = Route.USE_DEFAULT_METRIC
Packit Service 0535c1
            setting_ip.clear_dns()
Packit Service 0535c1
            setting_ip.clear_dns_searches()
Packit Service 0535c1
            setting_ip.props.dns_priority = nm_dns.DEFAULT_DNS_PRIORITY
Packit Service 0535c1
Packit Service 0535c1
    if not setting_ip:
Packit Service 0535c1
        setting_ip = NM.SettingIP6Config.new()
Packit Service 0535c1
Packit Service 0535c1
    # Ensure IPv6 RA and DHCPv6 is based on MAC address only
Packit Service 0535c1
    setting_ip.props.addr_gen_mode = NM.SettingIP6ConfigAddrGenMode.EUI64
Packit Service 0535c1
    setting_ip.props.dhcp_duid = "ll"
Packit Service 0535c1
    setting_ip.props.dhcp_iaid = "mac"
Packit Service 0535c1
Packit Service 0535c1
    if not config or not config.get(InterfaceIPv6.ENABLED):
Packit Service 0535c1
        setting_ip.props.method = NM.SETTING_IP6_CONFIG_METHOD_DISABLED
Packit Service 0535c1
        return setting_ip
Packit Service 0535c1
Packit Service 0535c1
    is_dhcp = config.get(InterfaceIPv6.DHCP, False)
Packit Service 0535c1
    is_autoconf = config.get(InterfaceIPv6.AUTOCONF, False)
Packit Service 0535c1
    ip_addresses = config.get(InterfaceIPv6.ADDRESS, ())
Packit Service 0535c1
Packit Service 0535c1
    if is_dhcp or is_autoconf:
Packit Service 0535c1
        _set_dynamic(setting_ip, is_dhcp, is_autoconf)
Packit Service 0535c1
        # NetworkManager will remove the virtual interface when DHCPv6 or
Packit Service 0535c1
        # IPv6-RA timeout, set them to infinity.
Packit Service 0535c1
        setting_ip.props.dhcp_timeout = INT32_MAX
Packit Service 0535c1
        setting_ip.props.ra_timeout = INT32_MAX
Packit Service 0535c1
        setting_ip.props.ignore_auto_routes = not config.get(
Packit Service 0535c1
            InterfaceIPv6.AUTO_ROUTES, True
Packit Service 0535c1
        )
Packit Service 0535c1
        setting_ip.props.never_default = not config.get(
Packit Service 0535c1
            InterfaceIPv6.AUTO_GATEWAY, True
Packit Service 0535c1
        )
Packit Service 0535c1
        setting_ip.props.ignore_auto_dns = not config.get(
Packit Service 0535c1
            InterfaceIPv6.AUTO_DNS, True
Packit Service 0535c1
        )
Packit Service 0535c1
    elif ip_addresses:
Packit Service 0535c1
        _set_static(setting_ip, ip_addresses)
Packit Service 0535c1
    else:
Packit Service 0535c1
        setting_ip.props.method = NM.SETTING_IP6_CONFIG_METHOD_LINK_LOCAL
Packit Service 0535c1
Packit Service 0535c1
    nm_route.add_routes(setting_ip, config.get(BaseIface.ROUTES_METADATA, []))
Packit Service 0535c1
    nm_dns.add_dns(setting_ip, config.get(BaseIface.DNS_METADATA, {}))
Packit Service 0535c1
    nm_route.add_route_rules(
Packit Service 0535c1
        setting_ip,
Packit Service 0535c1
        socket.AF_INET6,
Packit Service 0535c1
        config.get(BaseIface.ROUTE_RULES_METADATA, []),
Packit Service 0535c1
    )
Packit Service 0535c1
    return setting_ip
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _set_dynamic(setting_ip, is_dhcp, is_autoconf):
Packit Service 0535c1
    if not is_dhcp and is_autoconf:
Packit Service 0535c1
        raise NmstateNotImplementedError(
Packit Service 0535c1
            "Autoconf without DHCP is not supported yet"
Packit Service 0535c1
        )
Packit Service 0535c1
Packit Service 0535c1
    if is_dhcp and is_autoconf:
Packit Service 0535c1
        setting_ip.props.method = NM.SETTING_IP6_CONFIG_METHOD_AUTO
Packit Service 0535c1
    elif is_dhcp and not is_autoconf:
Packit Service 0535c1
        setting_ip.props.method = NM.SETTING_IP6_CONFIG_METHOD_DHCP
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _set_static(setting_ip, ip_addresses):
Packit Service 0535c1
    for address in ip_addresses:
Packit Service 0535c1
        if iplib.is_ipv6_link_local_addr(
Packit Service 0535c1
            address[InterfaceIPv6.ADDRESS_IP],
Packit Service 0535c1
            address[InterfaceIPv6.ADDRESS_PREFIX_LENGTH],
Packit Service 0535c1
        ):
Packit Service 0535c1
            logging.warning(
Packit Service 0535c1
                "IPv6 link local address "
Packit Service 0535c1
                "{a[ip]}/{a[prefix-length]} is ignored "
Packit Service 0535c1
                "when applying desired state".format(a=address)
Packit Service 0535c1
            )
Packit Service 0535c1
        else:
Packit Service 0535c1
            naddr = NM.IPAddress.new(
Packit Service 0535c1
                socket.AF_INET6,
Packit Service 0535c1
                address[InterfaceIPv6.ADDRESS_IP],
Packit Service 0535c1
                address[InterfaceIPv6.ADDRESS_PREFIX_LENGTH],
Packit Service 0535c1
            )
Packit Service 0535c1
            setting_ip.add_address(naddr)
Packit Service 0535c1
Packit Service 0535c1
    if setting_ip.props.addresses:
Packit Service 0535c1
        setting_ip.props.method = NM.SETTING_IP6_CONFIG_METHOD_MANUAL
Packit Service 0535c1
    else:
Packit Service 0535c1
        setting_ip.props.method = NM.SETTING_IP6_CONFIG_METHOD_LINK_LOCAL
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def get_ip_profile(active_connection):
Packit Service 0535c1
    """
Packit Service 0535c1
    Get NMSettingIP6Config from NMActiveConnection.
Packit Service 0535c1
    For any error, return None.
Packit Service 0535c1
    """
Packit Service 0535c1
    remote_conn = active_connection.get_connection()
Packit Service 0535c1
    if remote_conn:
Packit Service 0535c1
        return remote_conn.get_setting_ip6_config()
Packit Service 0535c1
    return None
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def get_route_running(nm_client):
Packit Service 0535c1
    return nm_route.get_running(_acs_and_ip_cfgs(nm_client))
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def get_route_config(nm_client):
Packit Service 0535c1
    routes = nm_route.get_config(acs_and_ip_profiles(nm_client))
Packit Service 0535c1
    for route in routes:
Packit Service 0535c1
        if route[Route.METRIC] == 0:
Packit Service 0535c1
            # Kernel will convert 0 to IPV6_DEFAULT_ROUTE_METRIC.
Packit Service 0535c1
            route[Route.METRIC] = IPV6_DEFAULT_ROUTE_METRIC
Packit Service 0535c1
Packit Service 0535c1
    return routes
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _acs_and_ip_cfgs(nm_client):
Packit Service 0535c1
    for ac in nm_client.get_active_connections():
Packit Service 0535c1
        ip_cfg = ac.get_ip6_config()
Packit Service 0535c1
        if not ip_cfg:
Packit Service 0535c1
            continue
Packit Service 0535c1
        yield ac, ip_cfg
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def acs_and_ip_profiles(nm_client):
Packit Service 0535c1
    for ac in nm_client.get_active_connections():
Packit Service 0535c1
        ip_profile = get_ip_profile(ac)
Packit Service 0535c1
        if not ip_profile:
Packit Service 0535c1
            continue
Packit Service 0535c1
        yield ac, ip_profile
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def is_dynamic(active_connection):
Packit Service 0535c1
    ip_profile = get_ip_profile(active_connection)
Packit Service 0535c1
    if ip_profile:
Packit Service 0535c1
        method = ip_profile.get_method()
Packit Service 0535c1
        return method in (
Packit Service 0535c1
            NM.SETTING_IP6_CONFIG_METHOD_AUTO,
Packit Service 0535c1
            NM.SETTING_IP6_CONFIG_METHOD_DHCP,
Packit Service 0535c1
        )
Packit Service 0535c1
    return False
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def get_routing_rule_config(nm_client):
Packit Service 0535c1
    return nm_route.get_routing_rule_config(acs_and_ip_profiles(nm_client))