Skip to content

Commit

Permalink
Take IPFamily precedence based on order
Browse files Browse the repository at this point in the history
Signed-off-by: Manuel Buil <mbuil@suse.com>
  • Loading branch information
manuelbuil committed Sep 28, 2023
1 parent 8a6685f commit 81e1e96
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 98 deletions.
10 changes: 3 additions & 7 deletions pkg/agent/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion pkg/agent/flannel/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 3 additions & 1 deletion pkg/agent/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
28 changes: 6 additions & 22 deletions pkg/cli/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
5 changes: 2 additions & 3 deletions pkg/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}
Expand Down
3 changes: 1 addition & 2 deletions pkg/daemons/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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.ServiceIPRange) {
if urlSafe {
return "[::1]"
}
Expand Down
10 changes: 5 additions & 5 deletions pkg/etcd/etcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ func generateTestConfig() *config.Control {
agentReady := make(chan struct{})
close(agentReady)
criticalControlArgs := config.CriticalControlArgs{
ClusterDomain: "cluster.local",
ClusterDNS: net.ParseIP("10.43.0.10"),
ClusterIPRange: testutil.ClusterIPNet(),
FlannelBackend: "vxlan",
ServiceIPRange: testutil.ServiceIPNet(),
ClusterDomain: "cluster.local",
ClusterDNS: net.ParseIP("10.43.0.10"),
ClusterIPRange: testutil.ClusterIPNet(),
FlannelBackend: "vxlan",
ServiceIPRange: testutil.ServiceIPNet(),
}
return &config.Control{
Runtime: config.NewRuntime(agentReady),
Expand Down
74 changes: 17 additions & 57 deletions pkg/util/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand All @@ -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()
Expand Down

0 comments on commit 81e1e96

Please sign in to comment.