def _render_subnet_routes(cls, iface_cfg, route_cfg, subnets, flavor): # TODO(rjschwei): route configuration on SUSE distro happens via # ifroute-* files, see lp#1812117. SUSE currently carries a local # patch in their package. if flavor == "suse": return for _, subnet in enumerate(subnets, start=len(iface_cfg.children)): subnet_type = subnet.get("type") for route in subnet.get("routes", []): is_ipv6 = subnet.get("ipv6") or is_ipv6_address( route["gateway"] ) # Any dynamic configuration method, slaac, dhcpv6-stateful/ # stateless should get router information from router RA's. if ( _is_default_route(route) and subnet_type not in IPV6_DYNAMIC_TYPES ): if ( subnet.get("ipv4") and route_cfg.has_set_default_ipv4 ) or ( subnet.get("ipv6") and route_cfg.has_set_default_ipv6 ): raise ValueError( "Duplicate declaration of default " "route found for interface '%s'" % (iface_cfg.name) ) # NOTE that instead of defining the route0 settings, # the owning interface provides the default route. # TODO(harlowja): add validation that no other iface has # also provided the default route? iface_cfg["DEFROUTE"] = True if iface_cfg["BOOTPROTO"] in ("dhcp", "dhcp4"): iface_cfg["DHCLIENT_SET_DEFAULT_ROUTE"] = True if "gateway" in route: if is_ipv6: iface_cfg["IPV6_DEFAULTGW"] = route["gateway"] route_cfg.has_set_default_ipv6 = True else: iface_cfg["GATEWAY"] = route["gateway"] route_cfg.has_set_default_ipv4 = True if "metric" in route: iface_cfg["METRIC"] = route["metric"] else: # add default routes only to ifcfg files, not # to route-* or route6-* for old_key, new_name in [ ("gateway", "GATEWAY"), ("metric", "METRIC"), ("prefix", "PREFIX"), ("netmask", "NETMASK"), ("network", "ADDRESS"), ]: if old_key in route: new_key = f"{new_name}{route_cfg.last_idx}" route_cfg[new_key] = route[old_key] route_cfg.last_idx += 1
def handle_physical(self, command): """ command = { 'type': 'physical', 'mac_address': 'c0:d6:9f:2c:e8:80', 'name': 'eth0', 'subnets': [ {'type': 'dhcp4'} ], 'accept-ra': 'true' } """ interfaces = self._network_state.get("interfaces", {}) iface = interfaces.get(command["name"], {}) for param, val in command.get("params", {}).items(): iface.update({param: val}) # convert subnet ipv6 netmask to cidr as needed subnets = _normalize_subnets(command.get("subnets")) # automatically set 'use_ipv6' if any addresses are ipv6 if not self.use_ipv6: for subnet in subnets: if subnet.get("type").endswith("6") or is_ipv6_address( subnet.get("address") ): self.use_ipv6 = True break accept_ra = command.get("accept-ra", None) if accept_ra is not None: accept_ra = util.is_true(accept_ra) wakeonlan = command.get("wakeonlan", None) if wakeonlan is not None: wakeonlan = util.is_true(wakeonlan) iface.update( { "name": command.get("name"), "type": command.get("type"), "mac_address": command.get("mac_address"), "inet": "inet", "mode": "manual", "mtu": command.get("mtu"), "address": None, "gateway": None, "subnets": subnets, "accept-ra": accept_ra, "wakeonlan": wakeonlan, } ) self._network_state["interfaces"].update({command.get("name"): iface}) self.dump_network_state()
def _add_nameserver(self, dns): """ Extends the ipv[46].dns property with a name server. """ # FIXME: the subnet contains IPv4 and IPv6 name server mixed # together. We might be getting an IPv6 name server while # we're dealing with an IPv4 subnet. Sort this out by figuring # out the correct family and making sure a valid section exist. family = "ipv6" if is_ipv6_address(dns) else "ipv4" self._set_default(family, "method", "disabled") self._set_default(family, "dns", "") self.config[family]["dns"] = self.config[family]["dns"] + dns + ";"
def _render_subnets(cls, iface_cfg, subnets, has_default_route, flavor): # setting base values if flavor == "suse": iface_cfg["BOOTPROTO"] = "static" if "BRIDGE" in iface_cfg: iface_cfg["BOOTPROTO"] = "dhcp" iface_cfg.drop("BRIDGE") else: iface_cfg["BOOTPROTO"] = "none" # modifying base values according to subnets for i, subnet in enumerate(subnets, start=len(iface_cfg.children)): mtu_key = "MTU" subnet_type = subnet.get("type") if subnet_type == "dhcp6" or subnet_type == "ipv6_dhcpv6-stateful": if flavor == "suse": # User wants dhcp for both protocols if iface_cfg["BOOTPROTO"] == "dhcp4": iface_cfg["BOOTPROTO"] = "dhcp" else: # Only IPv6 is DHCP, IPv4 may be static iface_cfg["BOOTPROTO"] = "dhcp6" iface_cfg["DHCLIENT6_MODE"] = "managed" # only if rhel AND dhcpv6 stateful elif (flavor == "rhel" and subnet_type == "ipv6_dhcpv6-stateful"): iface_cfg["BOOTPROTO"] = "dhcp" iface_cfg["DHCPV6C"] = True iface_cfg["IPV6INIT"] = True iface_cfg["IPV6_AUTOCONF"] = False else: iface_cfg["IPV6INIT"] = True # Configure network settings using DHCPv6 iface_cfg["DHCPV6C"] = True elif subnet_type == "ipv6_dhcpv6-stateless": if flavor == "suse": # User wants dhcp for both protocols if iface_cfg["BOOTPROTO"] == "dhcp4": iface_cfg["BOOTPROTO"] = "dhcp" else: # Only IPv6 is DHCP, IPv4 may be static iface_cfg["BOOTPROTO"] = "dhcp6" iface_cfg["DHCLIENT6_MODE"] = "info" else: iface_cfg["IPV6INIT"] = True # Configure network settings using SLAAC from RAs and # optional info from dhcp server using DHCPv6 iface_cfg["IPV6_AUTOCONF"] = True iface_cfg["DHCPV6C"] = True # Use Information-request to get only stateless # configuration parameters (i.e., without address). iface_cfg["DHCPV6C_OPTIONS"] = "-S" elif subnet_type == "ipv6_slaac": if flavor == "suse": # User wants dhcp for both protocols if iface_cfg["BOOTPROTO"] == "dhcp4": iface_cfg["BOOTPROTO"] = "dhcp" else: # Only IPv6 is DHCP, IPv4 may be static iface_cfg["BOOTPROTO"] = "dhcp6" iface_cfg["DHCLIENT6_MODE"] = "info" else: iface_cfg["IPV6INIT"] = True # Configure network settings using SLAAC from RAs iface_cfg["IPV6_AUTOCONF"] = True elif subnet_type in ["dhcp4", "dhcp"]: bootproto_in = iface_cfg["BOOTPROTO"] iface_cfg["BOOTPROTO"] = "dhcp" if flavor == "suse" and subnet_type == "dhcp4": # If dhcp6 is already specified the user wants dhcp # for both protocols if bootproto_in != "dhcp6": # Only IPv4 is DHCP, IPv6 may be static iface_cfg["BOOTPROTO"] = "dhcp4" elif subnet_type in ["static", "static6"]: # RH info # grep BOOTPROTO sysconfig.txt -A2 | head -3 # BOOTPROTO=none|bootp|dhcp # 'bootp' or 'dhcp' cause a DHCP client # to run on the device. Any other # value causes any static configuration # in the file to be applied. if subnet_is_ipv6(subnet) and flavor != "suse": mtu_key = "IPV6_MTU" iface_cfg["IPV6INIT"] = True if "mtu" in subnet: mtu_mismatch = bool( mtu_key in iface_cfg and subnet["mtu"] != iface_cfg[mtu_key]) if mtu_mismatch: LOG.warning( "Network config: ignoring %s device-level mtu:%s" " because ipv4 subnet-level mtu:%s provided.", iface_cfg.name, iface_cfg[mtu_key], subnet["mtu"], ) if subnet_is_ipv6(subnet): if flavor == "suse": # TODO(rjschwei) write mtu setting to # /etc/sysctl.d/ pass else: iface_cfg[mtu_key] = subnet["mtu"] else: iface_cfg[mtu_key] = subnet["mtu"] if subnet_is_ipv6(subnet) and flavor == "rhel": iface_cfg["IPV6_FORCE_ACCEPT_RA"] = False iface_cfg["IPV6_AUTOCONF"] = False elif subnet_type == "manual": if flavor == "suse": LOG.debug('Unknown subnet type setting "%s"', subnet_type) else: # If the subnet has an MTU setting, then ONBOOT=True # to apply the setting iface_cfg["ONBOOT"] = mtu_key in iface_cfg else: raise ValueError( "Unknown subnet type '%s' found for interface '%s'" % (subnet_type, iface_cfg.name)) if subnet.get("control") == "manual": if flavor == "suse": iface_cfg["STARTMODE"] = "manual" else: iface_cfg["ONBOOT"] = False # set IPv4 and IPv6 static addresses ipv4_index = -1 ipv6_index = -1 for i, subnet in enumerate(subnets, start=len(iface_cfg.children)): subnet_type = subnet.get("type") # metric may apply to both dhcp and static config if "metric" in subnet: if flavor != "suse": iface_cfg["METRIC"] = subnet["metric"] if subnet_type in ["dhcp", "dhcp4"]: # On SUSE distros 'DHCLIENT_SET_DEFAULT_ROUTE' is a global # setting in /etc/sysconfig/network/dhcp if flavor != "suse": if has_default_route and iface_cfg["BOOTPROTO"] != "none": iface_cfg["DHCLIENT_SET_DEFAULT_ROUTE"] = False continue elif subnet_type in IPV6_DYNAMIC_TYPES: continue elif subnet_type in ["static", "static6"]: if subnet_is_ipv6(subnet): ipv6_index = ipv6_index + 1 ipv6_cidr = "%s/%s" % (subnet["address"], subnet["prefix"]) if ipv6_index == 0: if flavor == "suse": iface_cfg["IPADDR6"] = ipv6_cidr else: iface_cfg["IPV6ADDR"] = ipv6_cidr elif ipv6_index == 1: if flavor == "suse": iface_cfg["IPADDR6_1"] = ipv6_cidr else: iface_cfg["IPV6ADDR_SECONDARIES"] = ipv6_cidr else: if flavor == "suse": iface_cfg["IPADDR6_%d" % ipv6_index] = ipv6_cidr else: iface_cfg["IPV6ADDR_SECONDARIES"] += (" " + ipv6_cidr) else: ipv4_index = ipv4_index + 1 suff = "" if ipv4_index == 0 else str(ipv4_index) iface_cfg["IPADDR" + suff] = subnet["address"] iface_cfg["NETMASK" + suff] = net_prefix_to_ipv4_mask( subnet["prefix"]) if "gateway" in subnet and flavor != "suse": iface_cfg["DEFROUTE"] = True if is_ipv6_address(subnet["gateway"]): iface_cfg["IPV6_DEFAULTGW"] = subnet["gateway"] else: iface_cfg["GATEWAY"] = subnet["gateway"] if "dns_search" in subnet and flavor != "suse": iface_cfg["DOMAIN"] = " ".join(subnet["dns_search"]) if "dns_nameservers" in subnet and flavor != "suse": if len(subnet["dns_nameservers"]) > 3: # per resolv.conf(5) MAXNS sets this to 3. LOG.debug( "%s has %d entries in dns_nameservers. " "Only 3 are used.", iface_cfg.name, len(subnet["dns_nameservers"]), ) for i, k in enumerate(subnet["dns_nameservers"][:3], 1): iface_cfg["DNS" + str(i)] = k