Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update nat discovery to support IP family #3311

Open
wants to merge 1 commit into
base: devel
Choose a base branch
from

Conversation

yboaron
Copy link
Contributor

@yboaron yboaron commented Feb 19, 2025

Current code assumes 1:1 mapping between endpoint to nat-discovery and
endpoint to submariner inter-cluster tunnel.

Since we decided that we continue using a single endpoint for each cluster
also for dual-stack, it is necessary to support mapping endpoint up to 2
nat-discovery and inter-cluster tunnels.

Additionally, nat-discovery and submariner-tunnel also need
to support IP family parameter, as both IPv4 and IPv6 should be supported.

This change update nat-discovery to support IP family, to make it clear,
only IPV4 nat-discovery is supported even after this change.

@submariner-bot
Copy link
Contributor

🤖 Created branch: z_pr3311/yboaron/natd_v6
🚀 Full E2E won't run until the "ready-to-test" label is applied. I will add it automatically once the PR has 2 approvals, or you can add it manually.

@yboaron yboaron added the ready-to-test When a PR is ready for full E2E testing label Feb 20, 2025
Current code assumes 1:1 mapping between endpoint to nat-discovery and
endpoint to submariner inter-cluster tunnel.
Since we decided that we continue using a single endpoint for each cluster
also for dual-stack, it is necessary to support mapping endpoint up to 2
nat-discovery and inter-cluster tunnels.

Additionally, nat-discovery and submariner-tunnel also need
to support IP family parameter, as both IPv4 and IPv6 should be supported.

This change update nat-discovery to support IP family,to make it clear,
only IPV4 nat-discovery is supported even after this change.

Signed-off-by: Yossi Boaron <[email protected]>
@@ -156,13 +157,13 @@ func (i *engine) installCableWithNATInfo(rnat *natdiscovery.NATEndpointInfo) err
i.Lock()
defer i.Unlock()

if _, ok := i.natDiscoveryPending[rnat.Endpoint.Spec.CableName]; !ok {
if _, ok := i.natDiscoveryPending[rnat.Endpoint.Spec.GetFamilyCableName(rnat.Family)]; !ok {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could extract GetFamilyCableName to a var as it's referenced several times.


i.natDiscovery.RemoveEndpoint(endpoint.Spec.CableName)
i.natDiscovery.RemoveEndpoint(endpoint.Spec.GetFamilyCableName(family))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here re: extract GetFamilyCableName to a var.

@@ -274,9 +275,9 @@ func (i *engine) RemoveCable(endpoint *v1.Endpoint) error {
return errors.Wrapf(err, "error disconnecting Endpoint cable %q", endpoint.Spec.CableName)
}

delete(i.installedCables, endpoint.Spec.CableName)
delete(i.installedCables, endpoint.Spec.GetFamilyCableName(family))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to be consistent and also index by GetFamilyCableName everywhere we access installedCables (L269 above and in installCableWithNATInfo).

delete(i.natDiscoveryPending, rnat.Endpoint.Spec.CableName)
i.natDiscoveryPending[rnat.Endpoint.Spec.GetFamilyCableName(rnat.Family)]--
if i.natDiscoveryPending[rnat.Endpoint.Spec.GetFamilyCableName(rnat.Family)] == 0 {
delete(i.natDiscoveryPending, rnat.Endpoint.Spec.GetFamilyCableName(rnat.Family))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code below where we check for an active connection is going to also have to take into account the family. I think we're going to have to add a UsingIPFamily field to the Connection struct. But we can address this later when the cable drivers are modified to use the family.

@@ -172,3 +172,15 @@ func (ep *EndpointSpec) GetPrivateIP(family k8snet.IPFamily) string {
func (ep *EndpointSpec) SetPrivateIP(ip string) {
ep.PrivateIPs, ep.PrivateIP = setIP(ep.PrivateIPs, ep.PrivateIP, ip)
}

func (ep *EndpointSpec) GetIPFamilies() [2]k8snet.IPFamily {
Copy link
Contributor

@tpantelis tpantelis Feb 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually returns an array of length 2 with the second element empty: ["4", ""]. We should return []k8snet.IPFamily since it can have 0, 1, or 2 elements.

We should be able to implement this method for real now and add unit tests since we only populate Subnets with IP4.

ipFamilies := set.New[k8snet.IPFamily]()

for _, cidr := range ep.Subnets {
    f := k8snet.IPFamilyOfCIDRString(cidr)
    if f != k8snet.IPFamilyUnknown {
        ipFamilies.Insert(f)
    }
}

return ipFamilies.UnsortedList()

return ipFamilies
}

func (ep *EndpointSpec) GetFamilyCableName(family k8snet.IPFamily) string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a unit test for this function so we don't lose any coverage percentage. You can simply check that the string starts with the cable name and ends with the family.

}

var logger = log.Logger{Logger: logf.Log.WithName("Tunnel")}

func findCommonIPFamilies(local, remote [2]k8snet.IPFamily) []k8snet.IPFamily {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func findCommonIPFamilies(local, remote [2]k8snet.IPFamily) []k8snet.IPFamily {
func findCommonIPFamilies(local, remote []k8snet.IPFamily) []k8snet.IPFamily {

Comment on lines +42 to +53
common := []k8snet.IPFamily{}

for _, lf := range local {
for _, rf := range remote {
if lf == rf {
common = append(common, lf)
break
}
}
}

return common
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can simplify to (import "github.com/submariner-io/admiral/pkg/slices"):

Suggested change
common := []k8snet.IPFamily{}
for _, lf := range local {
for _, rf := range remote {
if lf == rf {
common = append(common, lf)
break
}
}
}
return common
return slices.Intersect(local, remote, func(e k8snet.IPFamily) k8snet.IPFamily {
return e
})

}

return ""
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can restructure and simply these functions as follows:

func getLocalIPv4ForDestination(dst string) string {
	...
}

func GetLocalIPForDestination(dst string, family k8snet.IPFamily) string {
	switch family {
	case k8snet.IPv4:
		return getLocalIPv4ForDestination(dst)
	case k8snet.IPv6:
		// TODO_IPV6: add V6 healthcheck IP
	case k8snet.IPFamilyUnknown:
	}

	return ""
}

func GetLocalIP(family k8snet.IPFamily) string {
	return GetLocalIPForDestination("8.8.8.8", family)
}

@@ -64,7 +69,7 @@ func (nd *natDiscovery) handleRequestFromAddress(req *proto.SubmarinerNATDiscove
return nd.sendResponseToAddress(&response, addr)
}

if req.GetReceiver().GetEndpointId() != localEndpointSpec.CableName {
if req.GetReceiver().GetEndpointId() != localEndpointSpec.GetFamilyCableName(k8snet.IPv4) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we assume v4 here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ready-to-test When a PR is ready for full E2E testing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants