Exemple #1
0
    def _is_interface_routable(self, ifname, routes):
        """
        And interface is able to support routes if:
        - It exists.
        - It is not DOWN or ABSENT.
        - It is not IPv4/6 disabled (corresponding to the routes).
        """
        ifstate = self.interfaces.get(ifname)
        if not ifstate:
            return False

        iface_up = ifstate.get(Interface.STATE) not in NON_UP_STATES
        if iface_up:
            ipv4_state = ifstate.get(Interface.IPV4, {})
            ipv4_disabled = ipv4_state.get(InterfaceIPv4.ENABLED) is False
            if ipv4_disabled and any(
                not is_ipv6_address(r.destination) for r in routes
            ):
                return False

            ipv6_state = ifstate.get(Interface.IPV6, {})
            ipv6_disabled = ipv6_state.get(InterfaceIPv6.ENABLED) is False
            if ipv6_disabled and any(
                is_ipv6_address(r.destination) for r in routes
            ):
                return False

            return True

        return False
Exemple #2
0
 def _validate(self):
     if (len(self._config_servers) > 2
             and any(is_ipv6_address(n) for n in self._config_servers)
             and any(not is_ipv6_address(n) for n in self._config_servers)):
         raise NmstateNotImplementedError(
             "Three or more nameservers are only supported when using "
             "either IPv4 or IPv6 nameservers but not both.")
Exemple #3
0
def validate_routes(desired_state, current_state):
    """
    A route has several requirements it must comply with:
    - Next-hop interface must be provided
    - The next-hop interface must:
        - Exist and be up (no down/absent)
        - Have the relevant IPv4/6 stack enabled.
    """
    for iface_name, routes in desired_state.config_iface_routes.items():
        if not routes:
            continue

        desired_iface_state = desired_state.interfaces.get(iface_name)
        current_iface_state = current_state.interfaces.get(iface_name)
        if desired_iface_state or current_iface_state:
            _assert_iface_is_up(desired_iface_state, current_iface_state)
            if any(is_ipv6_address(route.destination) for route in routes):
                _assert_iface_ipv6_enabled(
                    desired_iface_state, current_iface_state
                )
            if any(not is_ipv6_address(route.destination) for route in routes):
                _assert_iface_ipv4_enabled(
                    desired_iface_state, current_iface_state
                )
        else:
            raise NmstateRouteWithNoInterfaceError(str(routes))
Exemple #4
0
 def is_ipv6(self):
     if self.ip_from:
         return is_ipv6_address(self.ip_from)
     elif self.ip_to:
         return is_ipv6_address(self.ip_to)
     else:
         logging.warning(
             f"Neither {RouteRule.IP_FROM} nor {RouteRule.IP_TO} "
             "is defined, treating it a IPv4 route rule")
         return False
Exemple #5
0
 def _index_route_rule_by_route_table(self):
     index_rules_v4 = defaultdict(list)
     index_rules_v6 = defaultdict(list)
     for rule in self._config_route_rules:
         entry = RouteRuleEntry(rule)
         if is_ipv6_address(entry.ip_from) or is_ipv6_address(entry.ip_to):
             index_rules_v6[entry.route_table].append(entry)
         else:
             index_rules_v4[entry.route_table].append(entry)
     for rules in index_rules_v4.values():
         rules.sort()
     for rules in index_rules_v6.values():
         rules.sort()
     return index_rules_v4, index_rules_v6
Exemple #6
0
def _validate_routes(
    iface_route_sets,
    iface_enable_states,
    ipv4_enable_states,
    ipv6_enable_states,
):
    """
    Check whether user desire routes next hop to:
        * down/absent interface
        * Non-exit interface
        * IPv4/IPv6 disabled
    """
    for iface_name, route_set in iface_route_sets.items():
        if not route_set:
            continue
        iface_enable_state = iface_enable_states.get(iface_name)
        if iface_enable_state is None:
            raise NmstateValueError("Cannot set route to non-exist interface")
        if iface_enable_state != InterfaceState.UP:
            raise NmstateValueError(
                "Cannot set route to {} interface".format(iface_enable_state)
            )
        # Interface is already check, so the ip enable status should be defined
        ipv4_enabled = ipv4_enable_states[iface_name]
        ipv6_enabled = ipv6_enable_states[iface_name]
        for route_obj in route_set:
            if iplib.is_ipv6_address(route_obj.destination):
                if not ipv6_enabled:
                    raise NmstateValueError(
                        "Cannot set IPv6 route when IPv6 is disabled"
                    )
            elif not ipv4_enabled:
                raise NmstateValueError(
                    "Cannot set IPv4 route when IPv4 is disabled"
                )
Exemple #7
0
def _save_dns_metadata(desired_state, current_state, ipv4_iface, ipv6_iface,
                       servers, searches):
    index = 0
    searches_saved = False
    for server in servers:
        iface_name = None
        if iplib.is_ipv6_address(server):
            iface_name = ipv6_iface
            family = Interface.IPV6
        else:
            iface_name = ipv4_iface
            family = Interface.IPV4
        if not iface_name:
            raise NmstateValueError(
                "Failed to find suitable interface for saving DNS "
                "name servers: %s" % server)

        _include_name_only_iface_state(desired_state, current_state,
                                       [iface_name])
        iface_state = desired_state.interfaces[iface_name]
        if family not in iface_state:
            iface_state[family] = {}

        if DNS_METADATA not in iface_state[family]:
            iface_state[family][DNS_METADATA] = {
                DNS.SERVER: [server],
                DNS.SEARCH: [] if searches_saved else searches,
                DNS_METADATA_PRIORITY: nm.dns.DNS_PRIORITY_STATIC_BASE + index,
            }
        else:
            iface_state[family][DNS_METADATA][DNS.SERVER].append(server)
        searches_saved = True
        index += 1
Exemple #8
0
def _attach_route_metadata(iface_state, routes):
    _init_iface_route_metadata(iface_state, Interface.IPV4)
    _init_iface_route_metadata(iface_state, Interface.IPV6)

    for route in routes:
        if iplib.is_ipv6_address(route.destination):
            iface_state[Interface.IPV6][ROUTES].append(route.to_dict())
        else:
            iface_state[Interface.IPV4][ROUTES].append(route.to_dict())
Exemple #9
0
def ip_rule_exist_in_os(ip_from, ip_to, priority, table):
    expected_rule = locals()
    logging.debug("Checking ip rule for {}".format(expected_rule))
    cmds = ["ip"]
    if (ip_from and iplib.is_ipv6_address(ip_from)) or (
            ip_to and iplib.is_ipv6_address(ip_to)):
        cmds.append("-6")
    if ip_from and "/" not in ip_from:
        ip_from = iplib.to_ip_address_full(ip_from)
    if ip_to and "/" not in ip_to:
        ip_to = iplib.to_ip_address_full(ip_to)
    result = cmdlib.exec_cmd(cmds + ["--json", "rule"])
    logging.debug(f"Current ip rules in OS: {result[1]}")
    assert result[0] == 0
    current_rules = json.loads(result[1])
    found = True
    for rule in current_rules:
        if rule.get("src") == "all" or rule.get("dst") == "all":
            continue

        if rule.get("table") == "main":
            rule["table"] = f"{iplib.KERNEL_MAIN_ROUTE_TABLE_ID}"

        logging.debug(f"Checking ip rule is OS: {rule}")
        found = True
        if ip_from and ip_from != iplib.to_ip_address_full(
                rule["src"], rule.get("srclen")):
            found = False
            continue
        if ip_to and ip_to != iplib.to_ip_address_full(rule["dst"],
                                                       rule.get("dstlen")):
            found = False
            continue
        if priority is not None and rule["priority"] != priority:
            found = False
            continue
        if table is not None and rule["table"] != f"{table}":
            found = False
            continue
        if found:
            break
    if not found:
        logging.debug(f"Failed to find expected ip rule: {expected_rule}")
    assert found
Exemple #10
0
def validate_dns(state):
    """
    Only support at most 2 name servers now:
    https://nmstate.atlassian.net/browse/NMSTATE-220
    """
    dns_servers = (
        state.get(DNS.KEY, {}).get(DNS.CONFIG, {}).get(DNS.SERVER, [])
    )
    if len(dns_servers) > 3:
        logging.warning(
            "The libc resolver may not support more than 3 nameservers."
        )
    if (
        len(dns_servers) > 2
        and any(is_ipv6_address(n) for n in dns_servers)
        and any(not is_ipv6_address(n) for n in dns_servers)
    ):
        raise NmstateNotImplementedError(
            "Three or more nameservers are only supported when using "
            "either IPv4 or IPv6 nameservers but not both."
        )
Exemple #11
0
def _get_default_route_config(gateway, metric, default_table_id, iface_name):
    if iplib.is_ipv6_address(gateway):
        destination = IPV6_DEFAULT_GATEWAY_DESTINATION
    else:
        destination = IPV4_DEFAULT_GATEWAY_DESTINATION
    return {
        Route.TABLE_ID: default_table_id,
        Route.DESTINATION: destination,
        Route.NEXT_HOP_INTERFACE: iface_name,
        Route.NEXT_HOP_ADDRESS: gateway,
        Route.METRIC: metric,
    }
Exemple #12
0
def _get_gateway(setting_ip):
    gateway = setting_ip.props.gateway
    if iplib.is_ipv6_address(gateway):
        destination = IPV6_DEFAULT_GATEWAY_DESTINATION
    else:
        destination = IPV4_DEFAULT_GATEWAY_DESTINATION
    return {
        Route.TABLE_ID: setting_ip.get_route_table(),
        Route.DESTINATION: destination,
        Route.NEXT_HOP_ADDRESS: gateway,
        Route.METRIC: setting_ip.get_route_metric(),
    }
Exemple #13
0
    def _route_is_next_hop_to_dynamic_ip_iface(self, route):
        ifname = route.next_hop_interface
        if not ifname:
            return False
        iface_state = self.interfaces.get(ifname)
        if not iface_state:
            return False

        if is_ipv6_address(route.destination):
            ip_state = iface_state.get(Interface.IPV6)
            return ip_state and (ip_state.get(InterfaceIPv6.AUTOCONF)
                                 or ip_state.get(InterfaceIPv6.DHCP))
        else:
            ip_state = iface_state.get(Interface.IPV4, {})
            return ip_state.get(InterfaceIPv4.DHCP, False)
Exemple #14
0
def _add_specfic_route(setting_ip, route):
    destination, prefix_len = route[Route.DESTINATION].split("/")
    prefix_len = int(prefix_len)
    if iplib.is_ipv6_address(destination):
        family = socket.AF_INET6
    else:
        family = socket.AF_INET
    metric = route.get(Route.METRIC, Route.USE_DEFAULT_METRIC)
    next_hop = route[Route.NEXT_HOP_ADDRESS]
    ip_route = NM.IPRoute.new(family, destination, prefix_len, next_hop,
                              metric)
    table_id = route.get(Route.TABLE_ID, Route.USE_DEFAULT_ROUTE_TABLE)
    ip_route.set_attribute(NM_ROUTE_TABLE_ATTRIBUTE,
                           GLib.Variant.new_uint32(table_id))
    # Duplicate route entry will be ignored by libnm.
    setting_ip.add_route(ip_route)
Exemple #15
0
def _route_is_valid(route_obj, iface_enable_states, ipv4_enable_states,
                    ipv6_enable_states):
    """
    Return False when route is next hop to any of these interfaces:
        * Interface not in InterfaceState.UP state.
        * Interface does not exists.
        * Interface has IPv4/IPv6 disabled.
    """
    iface_name = route_obj.next_hop_interface
    iface_enable_state = iface_enable_states.get(iface_name)
    if iface_enable_state != InterfaceState.UP:
        return False
    if iplib.is_ipv6_address(route_obj.destination):
        if not ipv6_enable_states.get(iface_name):
            return False
    else:
        if not ipv4_enable_states.get(iface_name):
            return False
    return True
Exemple #16
0
def _generate_route_rule_metadata(desired_state):
    routes_v4 = []
    routes_v6 = []
    for routes in desired_state.config_iface_routes.values():
        for route in routes:
            if iplib.is_ipv6_address(route.destination):
                routes_v6.append(route)
            else:
                routes_v4.append(route)

    _generate_route_rule_per_stack_metadata(
        Interface.IPV4,
        desired_state.config_route_table_rules_v4,
        routes_v4,
        desired_state,
    )
    _generate_route_rule_per_stack_metadata(
        Interface.IPV6,
        desired_state.config_route_table_rules_v6,
        routes_v6,
        desired_state,
    )
Exemple #17
0
 def is_ipv6(self):
     return is_ipv6_address(self.destination)
Exemple #18
0
 def gen_metadata(self, ifaces, route_state):
     """
     Return DNS configure targeting to store as metadata of interface.
     Data structure returned is:
         {
             iface_name: {
                 Interface.IPV4: {
                     DNS.SERVER: dns_servers,
                     DNS.SEARCH: dns_searches,
                 },
                 Interface.IPV6: {
                     DNS.SERVER: dns_servers,
                     DNS.SEARCH: dns_searches,
                 },
             }
         }
     """
     iface_metadata = {}
     if not self._config_servers and not self._config_searches:
         return iface_metadata
     ipv4_iface, ipv6_iface = self._find_ifaces_for_name_servers(
         ifaces, route_state
     )
     if ipv4_iface == ipv6_iface:
         iface_metadata = {
             ipv4_iface: {
                 Interface.IPV4: {DNS.SERVER: [], DNS.SEARCH: []},
                 Interface.IPV6: {DNS.SERVER: [], DNS.SEARCH: []},
             },
         }
     else:
         if ipv4_iface:
             iface_metadata[ipv4_iface] = {
                 Interface.IPV4: {DNS.SERVER: [], DNS.SEARCH: []},
             }
         if ipv6_iface:
             iface_metadata[ipv6_iface] = {
                 Interface.IPV6: {DNS.SERVER: [], DNS.SEARCH: []},
             }
     index = 0
     searches_saved = False
     for server in self._config_servers:
         iface_name = None
         if is_ipv6_address(server):
             iface_name = ipv6_iface
             family = Interface.IPV6
         else:
             iface_name = ipv4_iface
             family = Interface.IPV4
         if not iface_name:
             raise NmstateValueError(
                 "Failed to find suitable interface for saving DNS "
                 "name servers: %s" % server
             )
         iface_dns_metada = iface_metadata[iface_name][family]
         iface_dns_metada[DNS.SERVER].append(server)
         iface_dns_metada.setdefault(DnsState.PRIORITY_METADATA, index)
         if not searches_saved:
             iface_dns_metada[DNS.SEARCH] = self._config_searches
         searches_saved = True
         index += 1
     return iface_metadata