Skip to content

Commit

Permalink
Merge pull request #3726 from lzhecheng/fix-ipv6-cnm-imds-lb
Browse files Browse the repository at this point in the history
[IPv6] Fix CNM not properly handling IPv6 from imds LB
  • Loading branch information
k8s-ci-robot committed Apr 14, 2023
2 parents fe6f721 + 2ff03aa commit ee7e2bf
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 16 deletions.
45 changes: 29 additions & 16 deletions pkg/provider/azure_instance_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"io"
"net/http"
"strings"

"k8s.io/klog/v2"

Expand Down Expand Up @@ -119,6 +120,33 @@ func NewInstanceMetadataService(imdsServer string) (*InstanceMetadataService, er
return ims, nil
}

// fillNetInterfacePublicIPs finds PIPs from imds load balancer and fills them into net interface config.
func fillNetInterfacePublicIPs(publicIPs []PublicIPMetadata, netInterface *NetworkInterface) {
// IPv6 IPs from imds load balancer are wrapped by brackets while those from imds are not.
trimIP := func(ip string) string {
return strings.Trim(strings.Trim(ip, "["), "]")
}

if len(netInterface.IPV4.IPAddress) > 0 && len(netInterface.IPV4.IPAddress[0].PrivateIP) > 0 {
for _, pip := range publicIPs {
if pip.PrivateIPAddress == netInterface.IPV4.IPAddress[0].PrivateIP {
netInterface.IPV4.IPAddress[0].PublicIP = pip.FrontendIPAddress
break
}
}
}
if len(netInterface.IPV6.IPAddress) > 0 && len(netInterface.IPV6.IPAddress[0].PrivateIP) > 0 {
for _, pip := range publicIPs {
privateIP := trimIP(pip.PrivateIPAddress)
frontendIP := trimIP(pip.FrontendIPAddress)
if privateIP == netInterface.IPV6.IPAddress[0].PrivateIP {
netInterface.IPV6.IPAddress[0].PublicIP = frontendIP
break
}
}
}
}

func (ims *InstanceMetadataService) getMetadata(key string) (interface{}, error) {
instanceMetadata, err := ims.getInstanceMetadata(key)
if err != nil {
Expand All @@ -142,22 +170,7 @@ func (ims *InstanceMetadataService) getMetadata(key string) (interface{}, error)
}

publicIPs := loadBalancerMetadata.LoadBalancer.PublicIPAddresses
if len(netInterface.IPV4.IPAddress) > 0 && len(netInterface.IPV4.IPAddress[0].PrivateIP) > 0 {
for _, pip := range publicIPs {
if pip.PrivateIPAddress == netInterface.IPV4.IPAddress[0].PrivateIP {
netInterface.IPV4.IPAddress[0].PublicIP = pip.FrontendIPAddress
break
}
}
}
if len(netInterface.IPV6.IPAddress) > 0 && len(netInterface.IPV6.IPAddress[0].PrivateIP) > 0 {
for _, pip := range publicIPs {
if pip.PrivateIPAddress == netInterface.IPV6.IPAddress[0].PrivateIP {
netInterface.IPV6.IPAddress[0].PublicIP = pip.FrontendIPAddress
break
}
}
}
fillNetInterfacePublicIPs(publicIPs, &netInterface)
}

return instanceMetadata, nil
Expand Down
89 changes: 89 additions & 0 deletions pkg/provider/azure_instance_metadata_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package provider

import (
"testing"

"github.com/stretchr/testify/assert"
)

// TestFillNetInterfacePublicIPs tests if IPv6 IPs from imds load balancer are
// properly handled.
func TestFillNetInterfacePublicIPs(t *testing.T) {
testcases := []struct {
desc string
publicIPs []PublicIPMetadata
netInterface *NetworkInterface
expectedNetInterface *NetworkInterface
}{
{
desc: "IPv6/DualStack",
publicIPs: []PublicIPMetadata{
{
FrontendIPAddress: "20.0.0.0",
PrivateIPAddress: "10.244.0.0",
},
{
FrontendIPAddress: "[2001::1]",
PrivateIPAddress: "[fd00::1]",
},
},
netInterface: &NetworkInterface{
IPV4: NetworkData{
IPAddress: []IPAddress{
{
PrivateIP: "10.244.0.0",
},
},
},
IPV6: NetworkData{
IPAddress: []IPAddress{
{
PrivateIP: "fd00::1",
},
},
},
},
expectedNetInterface: &NetworkInterface{
IPV4: NetworkData{
IPAddress: []IPAddress{
{
PrivateIP: "10.244.0.0",
PublicIP: "20.0.0.0",
},
},
},
IPV6: NetworkData{
IPAddress: []IPAddress{
{
PrivateIP: "fd00::1",
PublicIP: "2001::1",
},
},
},
},
},
}

for _, tc := range testcases {
t.Run(tc.desc, func(t *testing.T) {
fillNetInterfacePublicIPs(tc.publicIPs, tc.netInterface)
assert.Equal(t, tc.expectedNetInterface, tc.netInterface)
})
}
}

0 comments on commit ee7e2bf

Please sign in to comment.