From fdabaa60bea3c61c6f9aa38a19f7e2dcf3b4babc Mon Sep 17 00:00:00 2001 From: Manuel Buil Date: Tue, 19 Sep 2023 18:04:26 +0200 Subject: [PATCH] Take IPFamily precedence based on order Signed-off-by: Manuel Buil --- pkg/agent/config/config.go | 10 ++--- pkg/agent/flannel/setup.go | 3 +- pkg/agent/run.go | 4 +- pkg/cli/server/server.go | 28 +++----------- pkg/cluster/cluster.go | 5 +-- pkg/daemons/config/types.go | 3 +- pkg/util/net.go | 74 +++++++++---------------------------- 7 files changed, 34 insertions(+), 93 deletions(-) diff --git a/pkg/agent/config/config.go b/pkg/agent/config/config.go index a699e792637c..8e4683212bc1 100644 --- a/pkg/agent/config/config.go +++ b/pkg/agent/config/config.go @@ -557,22 +557,18 @@ func get(ctx context.Context, envInfo *cmds.Agent, proxy proxy.Proxy) (*config.N nodeConfig.Certificate = servingCert nodeConfig.AgentConfig.NodeIPs = nodeIPs - nodeIP, listenAddress, _, _, err := util.GetFirstIP(nodeIPs) + listenAddress, _, _, err := util.GetDefaultAddresses(nodeIPs[0]) if err != nil { return nil, errors.Wrap(err, "cannot configure IPv4/IPv6 node-ip") } - nodeConfig.AgentConfig.NodeIP = nodeIP.String() + nodeConfig.AgentConfig.NodeIP = nodeIPs[0].String() nodeConfig.AgentConfig.ListenAddress = listenAddress nodeConfig.AgentConfig.NodeExternalIPs = nodeExternalIPs // if configured, set NodeExternalIP to the first IPv4 address, for legacy clients // unless only IPv6 address given if len(nodeConfig.AgentConfig.NodeExternalIPs) > 0 { - nodeExternalIP, _, _, _, err := util.GetFirstIP(nodeConfig.AgentConfig.NodeExternalIPs) - if err != nil { - return nil, errors.Wrap(err, "cannot configure IPv4/IPv6 node-external-ip") - } - nodeConfig.AgentConfig.NodeExternalIP = nodeExternalIP.String() + nodeConfig.AgentConfig.NodeExternalIP = nodeConfig.AgentConfig.NodeExternalIPs[0].String() } nodeConfig.NoFlannel = nodeConfig.FlannelBackend == config.FlannelBackendNone diff --git a/pkg/agent/flannel/setup.go b/pkg/agent/flannel/setup.go index 40e1bd6f103b..eb9228712e0d 100644 --- a/pkg/agent/flannel/setup.go +++ b/pkg/agent/flannel/setup.go @@ -182,12 +182,13 @@ func createFlannelConf(nodeConfig *config.Node) error { confJSON = strings.ReplaceAll(confJSON, "%IPV6_ENABLED%", "false") confJSON = strings.ReplaceAll(confJSON, "%CIDR_IPV6%", emptyIPv6Network) } else if netMode == (ipv4 + ipv6) { - confJSON = strings.ReplaceAll(confJSON, "%CIDR%", nodeConfig.AgentConfig.ClusterCIDR.String()) confJSON = strings.ReplaceAll(confJSON, "%IPV6_ENABLED%", "true") for _, cidr := range nodeConfig.AgentConfig.ClusterCIDRs { if utilsnet.IsIPv6(cidr.IP) { // Only one ipv6 range available. This might change in future: https://github.com/kubernetes/enhancements/issues/2593 confJSON = strings.ReplaceAll(confJSON, "%CIDR_IPV6%", cidr.String()) + } else { + confJSON = strings.ReplaceAll(confJSON, "%CIDR%", cidr.String()) } } } else { diff --git a/pkg/agent/run.go b/pkg/agent/run.go index a826bde9649a..1feec460aa02 100644 --- a/pkg/agent/run.go +++ b/pkg/agent/run.go @@ -69,12 +69,14 @@ func run(ctx context.Context, cfg cmds.Agent, proxy proxy.Proxy) error { serviceIPv6 := utilsnet.IsIPv6CIDR(nodeConfig.AgentConfig.ServiceCIDR) clusterIPv6 := utilsnet.IsIPv6CIDR(nodeConfig.AgentConfig.ClusterCIDR) nodeIPv6 := utilsnet.IsIPv6String(nodeConfig.AgentConfig.NodeIP) + if (serviceIPv6 != clusterIPv6) || (dualCluster != dualService) || (serviceIPv4 != clusterIPv4) { return fmt.Errorf("cluster-cidr: %v and service-cidr: %v, must share the same IP version (IPv4, IPv6 or dual-stack)", nodeConfig.AgentConfig.ClusterCIDRs, nodeConfig.AgentConfig.ServiceCIDRs) } - if (clusterIPv6 && !nodeIPv6) || (dualCluster && !dualNode) || (clusterIPv4 && !nodeIPv4) { + if (clusterIPv6 && !(nodeIPv6 || dualNode)) || (dualCluster && !dualNode) || (clusterIPv4 && !(nodeIPv4 || dualNode)) { return fmt.Errorf("cluster-cidr: %v and node-ip: %v, must share the same IP version (IPv4, IPv6 or dual-stack)", nodeConfig.AgentConfig.ClusterCIDRs, nodeConfig.AgentConfig.NodeIPs) } + enableIPv6 := dualCluster || clusterIPv6 enableIPv4 := dualCluster || clusterIPv4 diff --git a/pkg/cli/server/server.go b/pkg/cli/server/server.go index 88ee152bc47f..4fa77d4b2dd2 100644 --- a/pkg/cli/server/server.go +++ b/pkg/cli/server/server.go @@ -299,7 +299,7 @@ func run(app *cli.Context, cfg *cmds.Server, leaderControllers server.CustomCont } // configure ClusterIPRanges. Use default 10.42.0.0/16 or fd00:42::/56 if user did not set it - _, _, defaultClusterCIDR, defaultServiceCIDR, _ := util.GetFirstIP(nodeIPs) + _, defaultClusterCIDR, defaultServiceCIDR, _ := util.GetDefaultAddresses(nodeIPs[0]) if len(cmds.ServerConfig.ClusterCIDR) == 0 { cmds.ServerConfig.ClusterCIDR.Set(defaultClusterCIDR) } @@ -311,13 +311,8 @@ func run(app *cli.Context, cfg *cmds.Server, leaderControllers server.CustomCont serverConfig.ControlConfig.ClusterIPRanges = append(serverConfig.ControlConfig.ClusterIPRanges, parsed) } - // set ClusterIPRange to the first IPv4 block, for legacy clients - // unless only IPv6 range given - clusterIPRange, err := util.GetFirstNet(serverConfig.ControlConfig.ClusterIPRanges) - if err != nil { - return errors.Wrap(err, "cannot configure IPv4/IPv6 cluster-cidr") - } - serverConfig.ControlConfig.ClusterIPRange = clusterIPRange + // set ClusterIPRange to the first address (first defined IPFamily is preferred) + serverConfig.ControlConfig.ClusterIPRange = serverConfig.ControlConfig.ClusterIPRanges[0] // configure ServiceIPRanges. Use default 10.43.0.0/16 or fd00:43::/112 if user did not set it if len(cmds.ServerConfig.ServiceCIDR) == 0 { @@ -331,13 +326,8 @@ func run(app *cli.Context, cfg *cmds.Server, leaderControllers server.CustomCont serverConfig.ControlConfig.ServiceIPRanges = append(serverConfig.ControlConfig.ServiceIPRanges, parsed) } - // set ServiceIPRange to the first IPv4 block, for legacy clients - // unless only IPv6 range given - serviceIPRange, err := util.GetFirstNet(serverConfig.ControlConfig.ServiceIPRanges) - if err != nil { - return errors.Wrap(err, "cannot configure IPv4/IPv6 service-cidr") - } - serverConfig.ControlConfig.ServiceIPRange = serviceIPRange + // set ServiceIPRange to the first address (first defined IPFamily is preferred) + serverConfig.ControlConfig.ServiceIPRange = serverConfig.ControlConfig.ServiceIPRanges[0] serverConfig.ControlConfig.ServiceNodePortRange, err = utilnet.ParsePortRange(cfg.ServiceNodePortRange) if err != nil { @@ -373,13 +363,7 @@ func run(app *cli.Context, cfg *cmds.Server, leaderControllers server.CustomCont } } - // Set ClusterDNS to the first IPv4 address, for legacy clients - // unless only IPv6 range given - clusterDNS, _, _, err := util.GetFirstIP(serverConfig.ControlConfig.ClusterDNSs) - if err != nil { - return errors.Wrap(err, "cannot configure IPv4/IPv6 cluster-dns address") - } - serverConfig.ControlConfig.ClusterDNS = clusterDNS + serverConfig.ControlConfig.ClusterDNS = serverConfig.ControlConfig.ClusterDNSs[0] if err := validateNetworkConfiguration(serverConfig); err != nil { return err diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 0ed707ebf1eb..7e3ecf268695 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -10,10 +10,10 @@ import ( "github.com/k3s-io/k3s/pkg/cluster/managed" "github.com/k3s-io/k3s/pkg/daemons/config" "github.com/k3s-io/k3s/pkg/etcd" - "github.com/k3s-io/k3s/pkg/util" "github.com/k3s-io/kine/pkg/endpoint" "github.com/pkg/errors" "github.com/sirupsen/logrus" + utilsnet "k8s.io/utils/net" ) type Cluster struct { @@ -54,8 +54,7 @@ func (c *Cluster) Start(ctx context.Context) (<-chan struct{}, error) { clientURL.Host = clientURL.Hostname() + ":2379" clientURLs = append(clientURLs, clientURL.String()) } - IPv6OnlyService, _ := util.IsIPv6OnlyCIDRs(c.config.ServiceIPRanges) - etcdProxy, err := etcd.NewETCDProxy(ctx, true, c.config.DataDir, clientURLs[0], IPv6OnlyService) + etcdProxy, err := etcd.NewETCDProxy(ctx, true, c.config.DataDir, clientURLs[0], utilsnet.IsIPv6CIDR(c.config.ServiceIPRanges[0])) if err != nil { return nil, err } diff --git a/pkg/daemons/config/types.go b/pkg/daemons/config/types.go index dec2906f727c..27f726d01356 100644 --- a/pkg/daemons/config/types.go +++ b/pkg/daemons/config/types.go @@ -10,7 +10,6 @@ import ( "sync" "time" - "github.com/k3s-io/k3s/pkg/util" "github.com/k3s-io/kine/pkg/endpoint" "github.com/rancher/wrangler/pkg/generated/controllers/core" "github.com/rancher/wrangler/pkg/leader" @@ -250,7 +249,7 @@ func (c *Control) BindAddressOrLoopback(chooseHostInterface, urlSafe bool) strin // service CIDRs indicate an IPv4/Dual-Stack or IPv6 only cluster. If the urlSafe // parameter is true, IPv6 addresses are enclosed in square brackets, as per RFC2732. func (c *Control) Loopback(urlSafe bool) string { - if IPv6OnlyService, _ := util.IsIPv6OnlyCIDRs(c.ServiceIPRanges); IPv6OnlyService { + if utilsnet.IsIPv6CIDR(c.ServiceIPRanges[0]) { if urlSafe { return "[::1]" } diff --git a/pkg/util/net.go b/pkg/util/net.go index 2e4f872ee07c..7bc9f2ec4d79 100644 --- a/pkg/util/net.go +++ b/pkg/util/net.go @@ -133,7 +133,7 @@ func JoinIP6Nets(elems []*net.IPNet) string { // GetHostnameAndIPs takes a node name and list of IPs, usually from CLI args. // If set, these are used to return the node's name and addresses. If not set, -// the system hostname and primary interface address are returned instead. +// the system hostname and primary interface addresses are returned instead. func GetHostnameAndIPs(name string, nodeIPs cli.StringSlice) (string, []net.IP, error) { ips := []net.IP{} if len(nodeIPs) == 0 { @@ -202,40 +202,26 @@ func GetFirstValidIPString(s cli.StringSlice) string { return "" } -// GetFirstIP returns the first IPv4 address from the list of IP addresses. -// If no IPv4 addresses are found, returns the first IPv6 address -// if neither of IPv4 or IPv6 are found an error is raised. -// Additionally matching listen address and default clusterCIDR and serviceCIDR are returned. -func GetFirstIP(nodeIPs []net.IP) (net.IP, string, string, string, error) { - nodeIP, err := getFirst4(nodeIPs) - ListenAddress := "0.0.0.0" - clusterCIDR := "10.42.0.0/16" - serviceCIDR := "10.43.0.0/16" +// GetFirstIP checks what is the IPFamily of the first item. Based on that, returns a set of values +func GetDefaultAddresses(nodeIP net.IP) (string, string, string, error) { - if err != nil { - nodeIP, err = getFirst6(nodeIPs) - if err != nil { - return nil, "", "", "", err - } - ListenAddress = "::" - clusterCIDR = "fd00:42::/56" - serviceCIDR = "fd00:43::/112" + if netutils.IsIPv4(nodeIP) { + ListenAddress := "0.0.0.0" + clusterCIDR := "10.42.0.0/16" + serviceCIDR := "10.43.0.0/16" + + return ListenAddress, clusterCIDR, serviceCIDR, nil } - return nodeIP, ListenAddress, clusterCIDR, serviceCIDR, nil -} -// GetFirstNet returns the first IPv4 network from the list of IP networks. -// If no IPv4 addresses are found, returns the first IPv6 address -// if neither of IPv4 or IPv6 are found an error is raised. -func GetFirstNet(elems []*net.IPNet) (*net.IPNet, error) { - serviceIPRange, err := getFirst4Net(elems) - if err != nil { - serviceIPRange, err = getFirst6Net(elems) - if err != nil { - return nil, err - } + if netutils.IsIPv6(nodeIP) { + ListenAddress := "::" + clusterCIDR := "fd00:42::/56" + serviceCIDR := "fd00:43::/112" + + return ListenAddress, clusterCIDR, serviceCIDR, nil } - return serviceIPRange, nil + + return "", "", "", fmt.Errorf("ip: %v is not ipv4 or ipv6", nodeIP) } // GetFirstString returns the first IP4 address from a list of IP address strings. @@ -254,32 +240,6 @@ func GetFirstString(elems []string) (string, bool, error) { return ip, IPv6only, nil } -// IsIPv6OnlyCIDRs returns if -// - all are valid cidrs -// - at least one cidr from v6 family is found -// - v4 family cidr is not found -func IsIPv6OnlyCIDRs(cidrs []*net.IPNet) (bool, error) { - v4Found := false - v6Found := false - for _, cidr := range cidrs { - if cidr == nil { - return false, fmt.Errorf("cidr %v is invalid", cidr) - } - - if v4Found && v6Found { - continue - } - - if cidr.IP != nil && cidr.IP.To4() == nil { - v6Found = true - continue - } - v4Found = true - } - - return !v4Found && v6Found, nil -} - // IPToIPNet converts an IP to an IPNet, using a fully filled mask appropriate for the address family. func IPToIPNet(ip net.IP) (*net.IPNet, error) { address := ip.String()