diff --git a/staging/src/k8s.io/apimachinery/pkg/util/net/interface.go b/staging/src/k8s.io/apimachinery/pkg/util/net/interface.go index 6d22d38c2ff..9adf4cfe477 100644 --- a/staging/src/k8s.io/apimachinery/pkg/util/net/interface.go +++ b/staging/src/k8s.io/apimachinery/pkg/util/net/interface.go @@ -266,6 +266,36 @@ func getIPFromInterface(intfName string, forFamily AddressFamily, nw networkInte return nil, nil } +// getIPFromLoopbackInterface gets the IPs on a loopback interface and returns a global unicast address, if any. +// The loopback interface must be up, the IP must in the family requested, and the IP must be a global unicast address. +func getIPFromLoopbackInterface(forFamily AddressFamily, nw networkInterfacer) (net.IP, error) { + intfs, err := nw.Interfaces() + if err != nil { + return nil, err + } + for _, intf := range intfs { + if !isInterfaceUp(&intf) { + continue + } + if intf.Flags&(net.FlagLoopback) != 0 { + addrs, err := nw.Addrs(&intf) + if err != nil { + return nil, err + } + klog.V(4).Infof("Interface %q has %d addresses :%v.", intf.Name, len(addrs), addrs) + matchingIP, err := getMatchingGlobalIP(addrs, forFamily) + if err != nil { + return nil, err + } + if matchingIP != nil { + klog.V(4).Infof("Found valid IPv%d address %v for interface %q.", int(forFamily), matchingIP, intf.Name) + return matchingIP, nil + } + } + } + return nil, nil +} + // memberOf tells if the IP is of the desired family. Used for checking interface addresses. func memberOf(ip net.IP, family AddressFamily) bool { if ip.To4() != nil { @@ -414,8 +444,8 @@ func chooseHostInterfaceFromRoute(routes []Route, nw networkInterfacer, addressF } // In case of network setups where default routes are present, but network // interfaces use only link-local addresses (e.g. as described in RFC5549). - // the global IP is assigned to the loopback interface - loopbackIP, err := getIPFromInterface(LoopbackInterfaceName, family, nw) + // the global IP is assigned to the loopback interface, and we should use it + loopbackIP, err := getIPFromLoopbackInterface(family, nw) if err != nil { return nil, err } diff --git a/staging/src/k8s.io/apimachinery/pkg/util/net/interface_test.go b/staging/src/k8s.io/apimachinery/pkg/util/net/interface_test.go index fb4702603c8..fac078d20f2 100644 --- a/staging/src/k8s.io/apimachinery/pkg/util/net/interface_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/util/net/interface_test.go @@ -579,6 +579,33 @@ func TestGetIPFromInterface(t *testing.T) { } } +func TestGetIPFromLoopbackInterface(t *testing.T) { + testCases := []struct { + tcase string + family AddressFamily + nw networkInterfacer + expected net.IP + errStrFrag string + }{ + {"ipv4", familyIPv4, linkLocalLoopbackNetworkInterface{}, net.ParseIP("10.1.1.1"), ""}, + {"ipv6", familyIPv6, linkLocalLoopbackNetworkInterface{}, net.ParseIP("fd00:1:1::1"), ""}, + {"no global ipv4", familyIPv4, loopbackNetworkInterface{}, nil, ""}, + {"no global ipv6", familyIPv6, loopbackNetworkInterface{}, nil, ""}, + } + for _, tc := range testCases { + ip, err := getIPFromLoopbackInterface(tc.family, tc.nw) + if err != nil { + if !strings.Contains(err.Error(), tc.errStrFrag) { + t.Errorf("case[%s]: Error string %q does not contain %q", tc.tcase, err, tc.errStrFrag) + } + } else if tc.errStrFrag != "" { + t.Errorf("case[%s]: Error %q expected, but seen %v", tc.tcase, tc.errStrFrag, err) + } else if !ip.Equal(tc.expected) { + t.Errorf("case[%v]: expected %v, got %+v .err : %v", tc.tcase, tc.expected, ip, err) + } + } +} + func TestChooseHostInterfaceFromRoute(t *testing.T) { testCases := []struct { tcase string