Skip to content

Commit

Permalink
Merge pull request #2061 from gauravkghildiyal/ipv6-in-target
Browse files Browse the repository at this point in the history
Add IPv6 address when calculating target endpoints within L7EndpointsCalculator
  • Loading branch information
k8s-ci-robot authored Apr 7, 2023
2 parents b42a7b0 + 956f352 commit 0e3f583
Show file tree
Hide file tree
Showing 4 changed files with 327 additions and 103 deletions.
2 changes: 1 addition & 1 deletion pkg/neg/syncers/endpoints_calculator.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ func (l *L7EndpointsCalculator) Mode() types.EndpointsCalculatorMode {

// CalculateEndpoints determines the endpoints in the NEGs based on the current service endpoints and the current NEGs.
func (l *L7EndpointsCalculator) CalculateEndpoints(eds []types.EndpointsData, _ map[string]types.NetworkEndpointSet) (map[string]types.NetworkEndpointSet, types.EndpointPodMap, int, error) {
result, err := toZoneNetworkEndpointMap(eds, l.zoneGetter, l.podLister, l.servicePortName, l.networkEndpointType)
result, err := toZoneNetworkEndpointMap(eds, l.zoneGetter, l.podLister, l.servicePortName, l.networkEndpointType, l.enableDualStackNEG)
return result.NetworkEndpointSet, result.EndpointPodMap, result.DupCount, err
}

Expand Down
84 changes: 60 additions & 24 deletions pkg/neg/syncers/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package syncers

import (
"fmt"
"net"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -225,15 +226,10 @@ type ZoneNetworkEndpointMapResult struct {
}

// toZoneNetworkEndpointMap translates addresses in endpoints object into zone and endpoints map, and also return the count for duplicated endpoints
func toZoneNetworkEndpointMap(
eds []negtypes.EndpointsData,
zoneGetter negtypes.ZoneGetter,
podLister cache.Indexer,
servicePortName string,
networkEndpointType negtypes.NetworkEndpointType,
) (ZoneNetworkEndpointMapResult, error) {
func toZoneNetworkEndpointMap(eds []negtypes.EndpointsData, zoneGetter negtypes.ZoneGetter, podLister cache.Indexer, servicePortName string, networkEndpointType negtypes.NetworkEndpointType, enableDualStackNEG bool) (ZoneNetworkEndpointMapResult, error) {
zoneNetworkEndpointMap := map[string]negtypes.NetworkEndpointSet{}
networkEndpointPodMap := negtypes.EndpointPodMap{}
ipsForPod := ipsForPod(eds)
dupCount := 0
if eds == nil {
klog.Errorf("Endpoint object is nil")
Expand Down Expand Up @@ -262,7 +258,7 @@ func toZoneNetworkEndpointMap(
foundMatchingPort = true

for _, endpointAddress := range ed.Addresses {
if endpointAddress.AddressType != discovery.AddressTypeIPv4 {
if !enableDualStackNEG && endpointAddress.AddressType != discovery.AddressTypeIPv4 {
klog.Infof("Skipping non IPv4 address: %q, in endpoint slice %s/%s", endpointAddress.Addresses, ed.Meta.Namespace, ed.Meta.Name)
continue
}
Expand Down Expand Up @@ -293,24 +289,28 @@ func toZoneNetworkEndpointMap(
zoneNetworkEndpointMap[zone] = negtypes.NewNetworkEndpointSet()
}

for _, address := range endpointAddress.Addresses {
networkEndpoint := negtypes.NetworkEndpoint{IP: address, Port: matchPort, Node: *endpointAddress.NodeName}
if networkEndpointType == negtypes.NonGCPPrivateEndpointType {
// Non-GCP network endpoints don't have associated nodes.
networkEndpoint.Node = ""
}
zoneNetworkEndpointMap[zone].Insert(networkEndpoint)

// if existing name is alphabetically lower than current one, continue and don't replace
if existingPod, contains := networkEndpointPodMap[networkEndpoint]; contains {
dupCount += 1
if existingPod.Name < endpointAddress.TargetRef.Name {
klog.Infof("Found duplicate endpoints for %q, save the pod information from the alphabetically higher pod", address)
continue
}
podIPs := ipsForPod[types.NamespacedName{Namespace: endpointAddress.TargetRef.Namespace, Name: endpointAddress.TargetRef.Name}]
networkEndpoint := negtypes.NetworkEndpoint{IP: podIPs.IP, Port: matchPort, Node: *endpointAddress.NodeName}
if enableDualStackNEG {
// Convert all addresses to a standard form as per rfc5952 to prevent
// accidental diffs resulting from different formats.
networkEndpoint.IPv6 = parseIPAddress(podIPs.IPv6)
}
if networkEndpointType == negtypes.NonGCPPrivateEndpointType {
// Non-GCP network endpoints don't have associated nodes.
networkEndpoint.Node = ""
}
zoneNetworkEndpointMap[zone].Insert(networkEndpoint)

// if existing name is alphabetically lower than current one, continue and don't replace
if existingPod, contains := networkEndpointPodMap[networkEndpoint]; contains {
dupCount += 1
if existingPod.Name < endpointAddress.TargetRef.Name {
klog.Infof("Found duplicate endpoints for %v, save the pod information from the alphabetically higher pod", networkEndpoint)
continue // if existing name is alphabetically lower than current one, continue and don't replace
}
networkEndpointPodMap[networkEndpoint] = types.NamespacedName{Namespace: endpointAddress.TargetRef.Namespace, Name: endpointAddress.TargetRef.Name}
}
networkEndpointPodMap[networkEndpoint] = types.NamespacedName{Namespace: endpointAddress.TargetRef.Namespace, Name: endpointAddress.TargetRef.Name}
}
}
if !foundMatchingPort {
Expand Down Expand Up @@ -457,6 +457,32 @@ func validatePod(pod *apiv1.Pod, nodeLister cache.Indexer) bool {
return true
}

// ipsForPod will return a mapping of pods to their IPv4 and IPv6 addresses.
func ipsForPod(eds []negtypes.EndpointsData) map[types.NamespacedName]negtypes.NetworkEndpoint {
result := make(map[types.NamespacedName]negtypes.NetworkEndpoint)
for _, ed := range eds {
for _, address := range ed.Addresses {
if address.TargetRef == nil || len(address.Addresses) < 1 {
continue
}
podNN := types.NamespacedName{Namespace: address.TargetRef.Namespace, Name: address.TargetRef.Name}
ne := result[podNN]
if address.AddressType == discovery.AddressTypeIPv4 {
// See the discussion in https://issue.k8s.io/106267 regarding why it is
// valid if we just pick the first IP.
ne.IP = address.Addresses[0]
}
if address.AddressType == discovery.AddressTypeIPv6 {
// See the discussion in https://issue.k8s.io/106267 regarding why it is
// valid if we just pick the first IP.
ne.IPv6 = address.Addresses[0]
}
result[podNN] = ne
}
}
return result
}

// retrieveExistingZoneNetworkEndpointMap lists existing network endpoints in the neg and return the zone and endpoints map
func retrieveExistingZoneNetworkEndpointMap(negName string, zoneGetter negtypes.ZoneGetter, cloud negtypes.NetworkEndpointGroupCloud, version meta.Version, mode negtypes.EndpointsCalculatorMode) (map[string]negtypes.NetworkEndpointSet, error) {
// Include zones that have non-candidate nodes currently. It is possible that NEGs were created in those zones previously and the endpoints now became non-candidates.
Expand Down Expand Up @@ -525,3 +551,13 @@ func makeEndpointBatch(endpoints negtypes.NetworkEndpointSet, negType negtypes.N
}
return endpointBatch, nil
}

// parseIPAddress is used to normalize the given IPv4 or IPv6 address. If the
// address is invalid, an empty string is returned.
func parseIPAddress(address string) string {
result := net.ParseIP(address).String()
if result == "<nil>" {
return ""
}
return result
}
Loading

0 comments on commit 0e3f583

Please sign in to comment.