mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-06 19:52:42 +00:00
Merge pull request #4865 from sub-mod/proxier_go_change
use ChooseHostInterface in kube-proxy
This commit is contained in:
190
pkg/util/util.go
190
pkg/util/util.go
@@ -17,9 +17,14 @@ limitations under the License.
|
||||
package util
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"regexp"
|
||||
@@ -252,3 +257,188 @@ func SplitQualifiedName(str string) (string, string) {
|
||||
func JoinQualifiedName(namespace, name string) string {
|
||||
return path.Join(namespace, name)
|
||||
}
|
||||
|
||||
type Route struct {
|
||||
Interface string
|
||||
Destination net.IP
|
||||
Gateway net.IP
|
||||
// TODO: add more fields here if needed
|
||||
}
|
||||
|
||||
func getRoutes(input io.Reader) ([]Route, error) {
|
||||
routes := []Route{}
|
||||
if input == nil {
|
||||
return nil, fmt.Errorf("input is nil")
|
||||
}
|
||||
scanner := bufio.NewReader(input)
|
||||
for {
|
||||
line, err := scanner.ReadString('\n')
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
//ignore the headers in the route info
|
||||
if strings.HasPrefix(line, "Iface") {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
routes = append(routes, Route{})
|
||||
route := &routes[len(routes)-1]
|
||||
route.Interface = fields[0]
|
||||
ip, err := parseIP(fields[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
route.Destination = ip
|
||||
ip, err = parseIP(fields[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
route.Gateway = ip
|
||||
}
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
func parseIP(str string) (net.IP, error) {
|
||||
if str == "" {
|
||||
return nil, fmt.Errorf("input is nil")
|
||||
}
|
||||
bytes, err := hex.DecodeString(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//TODO add ipv6 support
|
||||
if len(bytes) != net.IPv4len {
|
||||
return nil, fmt.Errorf("only IPv4 is supported")
|
||||
}
|
||||
bytes[0], bytes[1], bytes[2], bytes[3] = bytes[3], bytes[2], bytes[1], bytes[0]
|
||||
return net.IP(bytes), nil
|
||||
}
|
||||
|
||||
func isInterfaceUp(intf *net.Interface) bool {
|
||||
if intf == nil {
|
||||
return false
|
||||
}
|
||||
if intf.Flags&net.FlagUp != 0 {
|
||||
glog.V(4).Infof("Interface %v is up", intf.Name)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//getFinalIP method receives all the IP addrs of a Interface
|
||||
//and returns a nil if the address is Loopback , Ipv6 or nil.
|
||||
//It returns a valid IPv4 if an Ipv4 address is found in the array.
|
||||
func getFinalIP(addrs []net.Addr) (net.IP, error) {
|
||||
if len(addrs) > 0 {
|
||||
for i := range addrs {
|
||||
glog.V(4).Infof("Checking addr %s.", addrs[i].String())
|
||||
ip, _, err := net.ParseCIDR(addrs[i].String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//Only IPv4
|
||||
//TODO : add IPv6 support
|
||||
if ip.To4() != nil {
|
||||
if !ip.IsLoopback() {
|
||||
glog.V(4).Infof("IP found %v", ip)
|
||||
return ip, nil
|
||||
} else {
|
||||
glog.V(4).Infof("Loopback found %v", ip)
|
||||
}
|
||||
} else {
|
||||
glog.V(4).Infof("%v is not a valid IPv4 address", ip)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func getIPFromInterface(intfName string, nw networkInterfacer) (net.IP, error) {
|
||||
intf, err := nw.InterfaceByName(intfName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isInterfaceUp(intf) {
|
||||
addrs, err := nw.Addrs(intf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
glog.V(4).Infof("Interface %q has %d addresses :%v.", intfName, len(addrs), addrs)
|
||||
finalIP, err := getFinalIP(addrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if finalIP != nil {
|
||||
glog.V(4).Infof("valid IPv4 address for interface %q found as %v.", intfName, finalIP)
|
||||
return finalIP, 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) {
|
||||
inFile, err := os.Open("/proc/net/route")
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
type networkInterface struct{}
|
||||
|
||||
func (_ networkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
|
||||
intf, err := net.InterfaceByName(intfName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return intf, nil
|
||||
}
|
||||
|
||||
func (_ networkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
|
||||
addrs, err := intf.Addrs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return addrs, nil
|
||||
}
|
||||
|
||||
func chooseHostInterfaceFromRoute(inFile io.Reader, nw networkInterfacer) (net.IP, error) {
|
||||
routes, err := getRoutes(inFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
zero := net.IP{0, 0, 0, 0}
|
||||
var finalIP net.IP
|
||||
for i := range routes {
|
||||
//find interface with gateway
|
||||
if routes[i].Destination.Equal(zero) {
|
||||
glog.V(4).Infof("Default route transits interface %q", routes[i].Interface)
|
||||
finalIP, err := getIPFromInterface(routes[i].Interface, nw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if finalIP != nil {
|
||||
glog.V(4).Infof("Choosing IP %v ", finalIP)
|
||||
return finalIP, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
glog.V(4).Infof("No valid IP found")
|
||||
if finalIP == nil {
|
||||
return nil, fmt.Errorf("Unable to select an IP.")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user