mirror of
https://github.com/optim-enterprises-bv/kubernetes.git
synced 2025-12-11 10:35:37 +00:00
autodetect global addresses on loopback interfaces
There are some network scenarios that, in order to have high availability based on routing protocols, you may have multiple interfaces in the host and you use a routing protocol to configure the routing in the host. It is common to not use global addresses on those interfaces because you don't want them to be reachable, so you assign the global address to the loopback interface. Loopback interfaces are always up, regardless of the states of physical interfaces. They are not subject to interface problems, i.e., if the interface is down or flapping you can not reach the IP despite you have connectivity through another interface. We should consider global ip addresses on loopback interfaces when: - the host has default routes - there are no global IPs on those interfaces. There can be more cases in which you have global addresses on the interfaces too, but that will open an explosion of scenarios hard to support and to "autodetect" It will be a cluster admin responsability to configure the network in such scenarios.
This commit is contained in:
@@ -393,8 +393,9 @@ func getAllDefaultRoutes() ([]Route, error) {
|
||||
}
|
||||
|
||||
// chooseHostInterfaceFromRoute cycles through each default route provided, looking for a
|
||||
// global IP address from the interface for the route. addressFamilies determines whether it
|
||||
// prefers IPv4 or IPv6
|
||||
// global IP address from the interface for the route. If there are routes but no global
|
||||
// address is obtained from the interfaces, it checks if the loopback interface has a global address.
|
||||
// addressFamilies determines whether it prefers IPv4 or IPv6
|
||||
func chooseHostInterfaceFromRoute(routes []Route, nw networkInterfacer, addressFamilies AddressFamilyPreference) (net.IP, error) {
|
||||
for _, family := range addressFamilies {
|
||||
klog.V(4).Infof("Looking for default routes with IPv%d addresses", uint(family))
|
||||
@@ -411,6 +412,17 @@ func chooseHostInterfaceFromRoute(routes []Route, nw networkInterfacer, addressF
|
||||
klog.V(4).Infof("Found active IP %v ", finalIP)
|
||||
return finalIP, nil
|
||||
}
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if loopbackIP != nil {
|
||||
klog.V(4).Infof("Found active IP %v on Loopback interface", loopbackIP)
|
||||
return loopbackIP, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
klog.V(4).Infof("No active IP found by looking at default routes")
|
||||
|
||||
@@ -453,6 +453,55 @@ func (_ p2pNetworkInterface) Interfaces() ([]net.Interface, error) {
|
||||
return []net.Interface{p2pIntf}, nil
|
||||
}
|
||||
|
||||
// Interface with link locals and loopback interface with global addresses
|
||||
type linkLocalLoopbackNetworkInterface struct {
|
||||
}
|
||||
|
||||
func (_ linkLocalLoopbackNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
|
||||
if intfName == LoopbackInterfaceName {
|
||||
return &loopbackIntf, nil
|
||||
}
|
||||
return &upIntf, nil
|
||||
}
|
||||
func (_ linkLocalLoopbackNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
|
||||
var ifat []net.Addr
|
||||
ifat = []net.Addr{addrStruct{val: "169.254.162.166/16"}, addrStruct{val: "fe80::200/10"}}
|
||||
if intf.Name == LoopbackInterfaceName {
|
||||
ifat = []net.Addr{addrStruct{val: "::1/128"}, addrStruct{val: "127.0.0.1/8"},
|
||||
// global addresses on loopback interface
|
||||
addrStruct{val: "10.1.1.1/32"}, addrStruct{val: "fd00:1:1::1/128"}}
|
||||
}
|
||||
return ifat, nil
|
||||
}
|
||||
func (_ linkLocalLoopbackNetworkInterface) Interfaces() ([]net.Interface, error) {
|
||||
return []net.Interface{upIntf, loopbackIntf}, nil
|
||||
}
|
||||
|
||||
// Interface and loopback interface with global addresses
|
||||
type globalsNetworkInterface struct {
|
||||
}
|
||||
|
||||
func (_ globalsNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
|
||||
if intfName == LoopbackInterfaceName {
|
||||
return &loopbackIntf, nil
|
||||
}
|
||||
return &upIntf, nil
|
||||
}
|
||||
func (_ globalsNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
|
||||
var ifat []net.Addr
|
||||
ifat = []net.Addr{addrStruct{val: "169.254.162.166/16"}, addrStruct{val: "fe80::200/10"},
|
||||
addrStruct{val: "192.168.1.1/31"}, addrStruct{val: "fd00::200/127"}}
|
||||
if intf.Name == LoopbackInterfaceName {
|
||||
ifat = []net.Addr{addrStruct{val: "::1/128"}, addrStruct{val: "127.0.0.1/8"},
|
||||
// global addresses on loopback interface
|
||||
addrStruct{val: "10.1.1.1/32"}, addrStruct{val: "fd00:1:1::1/128"}}
|
||||
}
|
||||
return ifat, nil
|
||||
}
|
||||
func (_ globalsNetworkInterface) Interfaces() ([]net.Interface, error) {
|
||||
return []net.Interface{upIntf, loopbackIntf}, nil
|
||||
}
|
||||
|
||||
// Unable to get IP addresses for interface
|
||||
type networkInterfaceFailGetAddrs struct {
|
||||
}
|
||||
@@ -544,6 +593,16 @@ func TestChooseHostInterfaceFromRoute(t *testing.T) {
|
||||
{"single-stack ipv6, prefer v6", routeV6, ipv6NetworkInterface{}, preferIPv6, net.ParseIP("2001::200")},
|
||||
{"dual stack", bothRoutes, v4v6NetworkInterface{}, preferIPv4, net.ParseIP("10.254.71.145")},
|
||||
{"dual stack, prefer v6", bothRoutes, v4v6NetworkInterface{}, preferIPv6, net.ParseIP("2001::10")},
|
||||
{"LLA and loopback with global, IPv4", routeV4, linkLocalLoopbackNetworkInterface{}, preferIPv4, net.ParseIP("10.1.1.1")},
|
||||
{"LLA and loopback with global, IPv6", routeV6, linkLocalLoopbackNetworkInterface{}, preferIPv6, net.ParseIP("fd00:1:1::1")},
|
||||
{"LLA and loopback with global, dual stack prefer IPv4", bothRoutes, linkLocalLoopbackNetworkInterface{}, preferIPv4, net.ParseIP("10.1.1.1")},
|
||||
{"LLA and loopback with global, dual stack prefer IPv6", bothRoutes, linkLocalLoopbackNetworkInterface{}, preferIPv6, net.ParseIP("fd00:1:1::1")},
|
||||
{"LLA and loopback with global, no routes", noRoutes, linkLocalLoopbackNetworkInterface{}, preferIPv6, nil},
|
||||
{"interface and loopback with global, IPv4", routeV4, globalsNetworkInterface{}, preferIPv4, net.ParseIP("192.168.1.1")},
|
||||
{"interface and loopback with global, IPv6", routeV6, globalsNetworkInterface{}, preferIPv6, net.ParseIP("fd00::200")},
|
||||
{"interface and loopback with global, dual stack prefer IPv4", bothRoutes, globalsNetworkInterface{}, preferIPv4, net.ParseIP("192.168.1.1")},
|
||||
{"interface and loopback with global, dual stack prefer IPv6", bothRoutes, globalsNetworkInterface{}, preferIPv6, net.ParseIP("fd00::200")},
|
||||
{"interface and loopback with global, no routes", noRoutes, globalsNetworkInterface{}, preferIPv6, nil},
|
||||
{"all LLA", routeV4, networkInterfaceWithOnlyLinkLocals{}, preferIPv4, nil},
|
||||
{"no routes", noRoutes, validNetworkInterface{}, preferIPv4, nil},
|
||||
{"fail get IP", routeV4, networkInterfaceFailGetAddrs{}, preferIPv4, nil},
|
||||
|
||||
Reference in New Issue
Block a user