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

Support ChooseHostInterface on Mac OS X #5497

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pkg/proxy/proxier.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,10 +325,10 @@ func NewProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptables.In
return nil
}
glog.Infof("Setting Proxy IP to %v", hostIP)
return CreateProxier(loadBalancer, listenIP, iptables, hostIP)
return createProxier(loadBalancer, listenIP, iptables, hostIP)
}

func CreateProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptables.Interface, hostIP net.IP) *Proxier {
func createProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptables.Interface, hostIP net.IP) *Proxier {
glog.Infof("Initializing iptables")
// Clean up old messes. Ignore erors.
iptablesDeleteOld(iptables)
Expand Down
20 changes: 10 additions & 10 deletions pkg/proxy/proxier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ func TestTCPProxy(t *testing.T) {
},
})

p := CreateProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
p := createProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
waitForNumProxyLoops(t, p, 0)

svcInfo, err := p.addServiceOnPort("echo", "TCP", 0, time.Second)
Expand All @@ -221,7 +221,7 @@ func TestUDPProxy(t *testing.T) {
},
})

p := CreateProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
p := createProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
waitForNumProxyLoops(t, p, 0)

svcInfo, err := p.addServiceOnPort("echo", "UDP", 0, time.Second)
Expand Down Expand Up @@ -250,7 +250,7 @@ func TestTCPProxyStop(t *testing.T) {
},
})

p := CreateProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
p := createProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
waitForNumProxyLoops(t, p, 0)

svcInfo, err := p.addServiceOnPort("echo", "TCP", 0, time.Second)
Expand Down Expand Up @@ -281,7 +281,7 @@ func TestUDPProxyStop(t *testing.T) {
},
})

p := CreateProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
p := createProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
waitForNumProxyLoops(t, p, 0)

svcInfo, err := p.addServiceOnPort("echo", "UDP", 0, time.Second)
Expand Down Expand Up @@ -312,7 +312,7 @@ func TestTCPProxyUpdateDelete(t *testing.T) {
},
})

p := CreateProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
p := createProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
waitForNumProxyLoops(t, p, 0)

svcInfo, err := p.addServiceOnPort("echo", "TCP", 0, time.Second)
Expand Down Expand Up @@ -342,7 +342,7 @@ func TestUDPProxyUpdateDelete(t *testing.T) {
},
})

p := CreateProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
p := createProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
waitForNumProxyLoops(t, p, 0)

svcInfo, err := p.addServiceOnPort("echo", "UDP", 0, time.Second)
Expand Down Expand Up @@ -372,7 +372,7 @@ func TestTCPProxyUpdateDeleteUpdate(t *testing.T) {
},
})

p := CreateProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
p := createProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
waitForNumProxyLoops(t, p, 0)

svcInfo, err := p.addServiceOnPort("echo", "TCP", 0, time.Second)
Expand Down Expand Up @@ -411,7 +411,7 @@ func TestUDPProxyUpdateDeleteUpdate(t *testing.T) {
},
})

p := CreateProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
p := createProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
waitForNumProxyLoops(t, p, 0)

svcInfo, err := p.addServiceOnPort("echo", "UDP", 0, time.Second)
Expand Down Expand Up @@ -450,7 +450,7 @@ func TestTCPProxyUpdatePort(t *testing.T) {
},
})

p := CreateProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
p := createProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
waitForNumProxyLoops(t, p, 0)

svcInfo, err := p.addServiceOnPort("echo", "TCP", 0, time.Second)
Expand Down Expand Up @@ -486,7 +486,7 @@ func TestUDPProxyUpdatePort(t *testing.T) {
},
})

p := CreateProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
p := createProxier(lb, net.ParseIP("0.0.0.0"), &fakeIptables{}, net.ParseIP("127.0.0.1"))
waitForNumProxyLoops(t, p, 0)

svcInfo, err := p.addServiceOnPort("echo", "UDP", 0, time.Second)
Expand Down
61 changes: 26 additions & 35 deletions pkg/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,68 +378,51 @@ func getIPFromInterface(intfName string, nw networkInterfacer) (net.IP, error) {
return nil, nil
}

func flagsSet(flags net.Flags, test net.Flags) bool {
return flags&test != 0
}

func flagsClear(flags net.Flags, test net.Flags) bool {
return flags&test == 0
}

func chooseHostInterfaceNativeGo() (net.IP, error) {
intfs, err := net.Interfaces()
//chooseHostInterfaceNativeGo is a method used to fetch an IP for a daemon.
//It iterates over the interfaces returned by Interfaces() method
//and picks the first interface which is not Loopback.
//This method may pick docker or other bridges
func chooseHostInterfaceNativeGo(nw networkInterfacer) (net.IP, error) {
Copy link
Member

Choose a reason for hiding this comment

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

Is this significantly better than just returning 127.0.0.1 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it is.
This was for supporting non Linux based systems , like mac and maybe windows.
should 127.0.0.1 be default if there is no other interface on the device ?I thought not.(you have replied it wont work in another PR)
As of now , if a developer is is using his system without any internet connection he cannot start proxy and apiserver .So he has to have a interface , a fake one atleast.

Copy link
Member

Choose a reason for hiding this comment

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

127.0.0.1 will not work for actual use. It might be enough for tests to pass. Let me run some manual tests tomorrow.

@quinton-hoole who is also picking up a bunch of networking related topics (FYI, no action required yet :)

intfs, err := nw.Interfaces()
if err != nil {
return nil, err
}
i := 0
for i = range intfs {
if flagsSet(intfs[i].Flags, net.FlagUp) && flagsClear(intfs[i].Flags, net.FlagLoopback|net.FlagPointToPoint) {
addrs, err := intfs[i].Addrs()
if err != nil {
return nil, err
}
if len(addrs) > 0 {
// This interface should suffice.
break
}
finalIP, err := getIPFromInterface(intfs[i].Name, nw)
if err != nil {
return nil, err
}
if finalIP != nil {
glog.V(4).Infof("Choosing IP %v ", finalIP)
return finalIP, nil
}
}
if i == len(intfs) {
return nil, err
}
glog.V(2).Infof("Choosing interface %s for from-host portals", intfs[i].Name)
addrs, err := intfs[i].Addrs()
if err != nil {
return nil, err
}
glog.V(2).Infof("Interface %s = %s", intfs[i].Name, addrs[0].String())
ip, _, err := net.ParseCIDR(addrs[0].String())
if err != nil {
return nil, err
}
return ip, nil
return nil, nil
}

//ChooseHostInterface is a method used fetch an IP for a daemon.
//It uses data from /proc/net/route file.
//For a node with no internet connection ,it returns error
//For a multi n/w interface node it returns the IP of the interface with gateway on it.
func ChooseHostInterface() (net.IP, error) {
var nw networkInterfacer = networkInterface{}
inFile, err := os.Open("/proc/net/route")
if err != nil {
if os.IsNotExist(err) {
return chooseHostInterfaceNativeGo()
glog.V(4).Infof("Unable to find /proc/net/route file: %v", err)
return chooseHostInterfaceNativeGo(nw)
Copy link
Member

Choose a reason for hiding this comment

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

log this happening - it's important in prod

}
return nil, err
}
defer inFile.Close()
var nw networkInterfacer = networkInterface{}
return chooseHostInterfaceFromRoute(inFile, nw)
}

type networkInterfacer interface {
InterfaceByName(intfName string) (*net.Interface, error)
Addrs(intf *net.Interface) ([]net.Addr, error)
Interfaces() ([]net.Interface, error)
}

type networkInterface struct{}
Expand All @@ -460,6 +443,14 @@ func (_ networkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
return addrs, nil
}

func (_ networkInterface) Interfaces() ([]net.Interface, error) {
intfs, err := net.Interfaces()
if err != nil {
return nil, err
}
return intfs, nil
}

func chooseHostInterfaceFromRoute(inFile io.Reader, nw networkInterfacer) (net.IP, error) {
routes, err := getRoutes(inFile)
if err != nil {
Expand Down
84 changes: 81 additions & 3 deletions pkg/util/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,15 +489,36 @@ type validNetworkInterface struct {
}

func (_ validNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
c := net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp}
var c net.Interface
if intfName == "eth3" {
c = net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp | net.FlagBroadcast | net.FlagMulticast}
} else if intfName == "eth1" {
c = net.Interface{Index: 0, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: net.FlagUp | net.FlagBroadcast | net.FlagMulticast}
} else if intfName == "lo" {
c = net.Interface{Index: 0, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: net.FlagUp | net.FlagLoopback}
}
return &c, nil
}
func (_ validNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
var ifat []net.Addr
ifat = []net.Addr{
addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}, addrStruct{val: "10.254.71.145/17"}}
if intf.Name == "eth3" {
ifat = []net.Addr{
addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}, addrStruct{val: "10.254.71.145/17"}}
} else if intf.Name == "eth1" {
ifat = []net.Addr{
addrStruct{val: "fe80::5484:7aff:fefe:9799/64"}, addrStruct{val: "172.17.42.1/16"}}
} else if intf.Name == "lo" {
ifat = []net.Addr{addrStruct{val: "127.0.0.1/8"}, addrStruct{val: "::1/128"}}
}
return ifat, nil
}
func (_ validNetworkInterface) Interfaces() ([]net.Interface, error) {
lo := net.Interface{Index: 1, MTU: 1500, Name: "lo", HardwareAddr: nil, Flags: net.FlagUp | net.FlagLoopback}
eth1 := net.Interface{Index: 2, MTU: 1500, Name: "eth1", HardwareAddr: nil, Flags: net.FlagUp | net.FlagBroadcast | net.FlagMulticast}
eth3 := net.Interface{Index: 3, MTU: 1500, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp | net.FlagBroadcast | net.FlagMulticast}
var intfs []net.Interface = []net.Interface{lo, eth1, eth3}
return intfs, nil
}

type validNetworkInterfacewithIpv6Only struct {
}
Expand All @@ -511,6 +532,13 @@ func (_ validNetworkInterfacewithIpv6Only) Addrs(intf *net.Interface) ([]net.Add
ifat = []net.Addr{addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}}
return ifat, nil
}
func (_ validNetworkInterfacewithIpv6Only) Interfaces() ([]net.Interface, error) {
lo := net.Interface{Index: 1, MTU: 1500, Name: "lo", HardwareAddr: nil, Flags: net.FlagUp | net.FlagLoopback}
eth1 := net.Interface{Index: 2, MTU: 1500, Name: "eth1", HardwareAddr: nil, Flags: net.FlagUp | net.FlagBroadcast | net.FlagMulticast}
eth3 := net.Interface{Index: 3, MTU: 1500, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp | net.FlagBroadcast | net.FlagMulticast}
var intfs []net.Interface = []net.Interface{lo, eth1, eth3}
return intfs, nil
}

type noNetworkInterface struct {
}
Expand All @@ -521,6 +549,9 @@ func (_ noNetworkInterface) InterfaceByName(intfName string) (*net.Interface, er
func (_ noNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
return nil, nil
}
func (_ noNetworkInterface) Interfaces() ([]net.Interface, error) {
return nil, nil
}

type networkInterfacewithNoAddrs struct {
}
Expand All @@ -532,6 +563,9 @@ func (_ networkInterfacewithNoAddrs) InterfaceByName(intfName string) (*net.Inte
func (_ networkInterfacewithNoAddrs) Addrs(intf *net.Interface) ([]net.Addr, error) {
return nil, fmt.Errorf("unable get Addrs")
}
func (_ networkInterfacewithNoAddrs) Interfaces() ([]net.Interface, error) {
return nil, nil
}

type networkInterfacewithIpv6addrs struct {
}
Expand All @@ -545,6 +579,50 @@ func (_ networkInterfacewithIpv6addrs) Addrs(intf *net.Interface) ([]net.Addr, e
ifat = []net.Addr{addrStruct{val: "fe80::2f7:6ffff:fe6e:2956/64"}}
return ifat, nil
}
func (_ networkInterfacewithIpv6addrs) Interfaces() ([]net.Interface, error) {
lo := net.Interface{Index: 1, MTU: 1500, Name: "lo", HardwareAddr: nil, Flags: net.FlagUp | net.FlagLoopback}
eth1 := net.Interface{Index: 2, MTU: 1500, Name: "eth1", HardwareAddr: nil, Flags: net.FlagUp | net.FlagBroadcast | net.FlagMulticast}
eth3 := net.Interface{Index: 3, MTU: 1500, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp | net.FlagBroadcast | net.FlagMulticast}
var intfs []net.Interface = []net.Interface{lo, eth1, eth3}
return intfs, nil
}

type loopback struct {
}

func (_ loopback) InterfaceByName(intfName string) (*net.Interface, error) {
c := net.Interface{Index: 0, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: net.FlagUp | net.FlagLoopback}
return &c, nil
}
func (_ loopback) Addrs(intf *net.Interface) ([]net.Addr, error) {
var ifat []net.Addr
ifat = []net.Addr{addrStruct{val: "127.0.0.1/8"}, addrStruct{val: "::1/128"}}
return ifat, nil
}
func (_ loopback) Interfaces() ([]net.Interface, error) {
c := net.Interface{Index: 1, MTU: 1500, Name: "lo", HardwareAddr: nil, Flags: net.FlagUp | net.FlagLoopback}
var intfs []net.Interface = []net.Interface{c}
return intfs, nil
}

func TestChooseHostInterfaceNativeGo(t *testing.T) {
testCases := []struct {
tcase string
nw networkInterfacer
expected net.IP
}{
{"valid", validNetworkInterface{}, net.ParseIP("172.17.42.1")},
{"ipv6", validNetworkInterfacewithIpv6Only{}, nil},
{"nothing", noNetworkInterface{}, nil},
{"loopbackOnly", loopback{}, nil},
}
for _, tc := range testCases {
ip, err := chooseHostInterfaceNativeGo(tc.nw)
if !ip.Equal(tc.expected) {
t.Errorf("case[%v]: expected %v, got %+v .err : %v", tc.tcase, tc.expected, ip, err)
}
}
}

func TestGetIPFromInterface(t *testing.T) {
testCases := []struct {
Expand Down