Skip to content

Commit

Permalink
feat: support IPv6 in metallb
Browse files Browse the repository at this point in the history
  • Loading branch information
rainest committed Jul 29, 2023
1 parent 760bccc commit 183d115
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 16 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ require (
github.com/spf13/cobra v1.7.0
github.com/spf13/viper v1.16.0
github.com/stretchr/testify v1.8.4
go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28
golang.org/x/oauth2 v0.10.0
golang.org/x/sync v0.3.0
google.golang.org/api v0.132.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,8 @@ go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0H
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28 h1:zLxFnORHDFTSkJPawMU7LzsuGQJ4MUFS653jJHpORow=
go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28/go.mod h1:TQvodOM+hJTioNQJilmLXu08JNb8i+ccq418+KWu1/Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
Expand Down
27 changes: 19 additions & 8 deletions pkg/clusters/addons/metallb/metallb.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
"fmt"
"io"
"net"
"net/netip"
"os"
"time"

"go4.org/netipx"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -26,7 +28,6 @@ import (
"github.com/kong/kubernetes-testing-framework/pkg/clusters/types/kind"
"github.com/kong/kubernetes-testing-framework/pkg/utils/docker"
"github.com/kong/kubernetes-testing-framework/pkg/utils/kubernetes/kubectl"
"github.com/kong/kubernetes-testing-framework/pkg/utils/networking"
)

// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -203,11 +204,12 @@ func deployMetallbForKindCluster(ctx context.Context, cluster clusters.Cluster,

func createIPAddressPool(ctx context.Context, cluster clusters.Cluster, dockerNetwork string) error {
// get an IP range for the docker container network to use for MetalLB
network, err := docker.GetDockerContainerIPNetwork(docker.GetKindContainerID(cluster.Name()), dockerNetwork)
network, network6, err := docker.GetDockerContainerIPNetwork(docker.GetKindContainerID(cluster.Name()), dockerNetwork)
if err != nil {
return err
}
ipStart, ipEnd := getIPRangeForMetallb(*network)
ip6Start, ip6End := getIPRangeForMetallb(*network6)

dynamicClient, err := dynamic.NewForConfig(cluster.Config())
if err != nil {
Expand All @@ -230,7 +232,8 @@ func createIPAddressPool(ctx context.Context, cluster clusters.Cluster, dockerNe
},
"spec": map[string]interface{}{
"addresses": []string{
networking.GetIPRangeStr(ipStart, ipEnd),
fmt.Sprintf("%s-%s", ipStart, ipEnd),
fmt.Sprintf("%s-%s", ip6Start, ip6End),
},
},
},
Expand Down Expand Up @@ -299,15 +302,23 @@ func createL2Advertisement(ctx context.Context, cluster clusters.Cluster) error
return nil
}

// TODO use netip throughout. this converts because old public APIs used net/ip instead of net/netip

// getIPRangeForMetallb provides a range of IP addresses to use for MetalLB given an IPv4 Network
//
// TODO: Just choosing specific default IPs for now, need to check range validity and dynamically assign IPs.
// TODO: this just chooses (most of) the upper half of the Docker network, although those IPs may be in use. Speaker
// will happily assign those, but they won't work. In practice this doesn't appear to cause many problems, since
// the IPs are normally not in use by KIND components (it appears to assign starting from the bottom of the Docker net)
//
// See: https://github.com/Kong/kubernetes-testing-framework/issues/24
func getIPRangeForMetallb(network net.IPNet) (startIP, endIP net.IP) {
startIP = networking.ConvertUint32ToIPv4(networking.ConvertIPv4ToUint32(network.IP) | networking.ConvertIPv4ToUint32(defaultStartIP))
endIP = networking.ConvertUint32ToIPv4(networking.ConvertIPv4ToUint32(network.IP) | networking.ConvertIPv4ToUint32(defaultEndIP))
return
func getIPRangeForMetallb(network net.IPNet) (startIP, endIP netip.Addr) {
// we trust that this is a valid prefix here because we already checked it in docker.GetDockerContainerIPNetwork
prefix := netip.MustParsePrefix(network.String())
half := prefix.Bits() + 1
wholeRange := netipx.RangeOfPrefix(prefix)
upperHalfPrefix := netip.PrefixFrom(wholeRange.To(), half).Masked()
halfRange := netipx.RangeOfPrefix(upperHalfPrefix)
return halfRange.From().Next(), halfRange.To().Prev()
}

// TODO: needs to be replaced with non-kubectl, just used this originally for speed.
Expand Down
3 changes: 0 additions & 3 deletions pkg/clusters/addons/metallb/metallb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/kong/kubernetes-testing-framework/pkg/utils/networking"
)

func TestHelperFunctions(t *testing.T) {
Expand All @@ -17,5 +15,4 @@ func TestHelperFunctions(t *testing.T) {
ip1, ip2 := getIPRangeForMetallb(network)
assert.Equal(t, ip1.String(), net.IPv4(192, 168, 1, 100).String())
assert.Equal(t, ip2.String(), net.IPv4(192, 168, 1, 250).String())
assert.Equal(t, networking.GetIPRangeStr(ip1, ip2), "192.168.1.100-192.168.1.250")
}
14 changes: 9 additions & 5 deletions pkg/utils/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,23 @@ func InspectDockerContainer(containerID string) (*types.ContainerJSON, error) {
return &containerJSON, err
}

// TODO should be converted to net/ip to net/netip, but this requires a breaking change to a public function

// GetDockerContainerIPNetwork supports retreiving the *net.IP4Net of a container specified
// by name (and a specified network name for the case of multiple networks).
func GetDockerContainerIPNetwork(containerID, networkName string) (*net.IPNet, error) {
func GetDockerContainerIPNetwork(containerID, networkName string) (*net.IPNet, *net.IPNet, error) {
container, err := InspectDockerContainer(containerID)
if err != nil {
return nil, err
return nil, nil, err
}

dockerNetwork := container.NetworkSettings.Networks[networkName]
_, network, err := net.ParseCIDR(fmt.Sprintf("%s/%d", dockerNetwork.Gateway, dockerNetwork.IPPrefixLen))
if err != nil {
return nil, err
_, network6, err6 := net.ParseCIDR(fmt.Sprintf("%s/%d", dockerNetwork.IPv6Gateway, dockerNetwork.GlobalIPv6PrefixLen))

if network == nil && network6 == nil {
return nil, nil, fmt.Errorf("no addresses found, IPv4Error(\"%s\"), IPv6Error(\"%s\")", err, err6)
}

return network, nil
return network, network6, nil
}
4 changes: 4 additions & 0 deletions pkg/utils/networking/networking.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import (
// Public Functions - Helper
// -----------------------------------------------------------------------------

// TODO the tools in this file are no longer used internally. they have been replaced with stdlib+third party packages.
// they remain here because they were public and removing them counts as a breaking change, but we probably should
// remove them.

const (
ipv4len = 16
ipv4bytes = 4
Expand Down

0 comments on commit 183d115

Please sign in to comment.