github.com/aclisp/heapster@v0.19.2-0.20160613100040-51756f899a96/Godeps/_workspace/src/k8s.io/kubernetes/pkg/util/net/interface.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors All rights reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package net 18 19 import ( 20 "bufio" 21 "encoding/hex" 22 "fmt" 23 "io" 24 "net" 25 "os" 26 27 "strings" 28 29 "github.com/golang/glog" 30 ) 31 32 type Route struct { 33 Interface string 34 Destination net.IP 35 Gateway net.IP 36 // TODO: add more fields here if needed 37 } 38 39 func getRoutes(input io.Reader) ([]Route, error) { 40 routes := []Route{} 41 if input == nil { 42 return nil, fmt.Errorf("input is nil") 43 } 44 scanner := bufio.NewReader(input) 45 for { 46 line, err := scanner.ReadString('\n') 47 if err == io.EOF { 48 break 49 } 50 //ignore the headers in the route info 51 if strings.HasPrefix(line, "Iface") { 52 continue 53 } 54 fields := strings.Fields(line) 55 routes = append(routes, Route{}) 56 route := &routes[len(routes)-1] 57 route.Interface = fields[0] 58 ip, err := parseIP(fields[1]) 59 if err != nil { 60 return nil, err 61 } 62 route.Destination = ip 63 ip, err = parseIP(fields[2]) 64 if err != nil { 65 return nil, err 66 } 67 route.Gateway = ip 68 } 69 return routes, nil 70 } 71 72 func parseIP(str string) (net.IP, error) { 73 if str == "" { 74 return nil, fmt.Errorf("input is nil") 75 } 76 bytes, err := hex.DecodeString(str) 77 if err != nil { 78 return nil, err 79 } 80 //TODO add ipv6 support 81 if len(bytes) != net.IPv4len { 82 return nil, fmt.Errorf("only IPv4 is supported") 83 } 84 bytes[0], bytes[1], bytes[2], bytes[3] = bytes[3], bytes[2], bytes[1], bytes[0] 85 return net.IP(bytes), nil 86 } 87 88 func isInterfaceUp(intf *net.Interface) bool { 89 if intf == nil { 90 return false 91 } 92 if intf.Flags&net.FlagUp != 0 { 93 glog.V(4).Infof("Interface %v is up", intf.Name) 94 return true 95 } 96 return false 97 } 98 99 //getFinalIP method receives all the IP addrs of a Interface 100 //and returns a nil if the address is Loopback, Ipv6, link-local or nil. 101 //It returns a valid IPv4 if an Ipv4 address is found in the array. 102 func getFinalIP(addrs []net.Addr) (net.IP, error) { 103 if len(addrs) > 0 { 104 for i := range addrs { 105 glog.V(4).Infof("Checking addr %s.", addrs[i].String()) 106 ip, _, err := net.ParseCIDR(addrs[i].String()) 107 if err != nil { 108 return nil, err 109 } 110 //Only IPv4 111 //TODO : add IPv6 support 112 if ip.To4() != nil { 113 if !ip.IsLoopback() && !ip.IsLinkLocalMulticast() && !ip.IsLinkLocalUnicast() { 114 glog.V(4).Infof("IP found %v", ip) 115 return ip, nil 116 } else { 117 glog.V(4).Infof("Loopback/link-local found %v", ip) 118 } 119 } else { 120 glog.V(4).Infof("%v is not a valid IPv4 address", ip) 121 } 122 123 } 124 } 125 return nil, nil 126 } 127 128 func getIPFromInterface(intfName string, nw networkInterfacer) (net.IP, error) { 129 intf, err := nw.InterfaceByName(intfName) 130 if err != nil { 131 return nil, err 132 } 133 if isInterfaceUp(intf) { 134 addrs, err := nw.Addrs(intf) 135 if err != nil { 136 return nil, err 137 } 138 glog.V(4).Infof("Interface %q has %d addresses :%v.", intfName, len(addrs), addrs) 139 finalIP, err := getFinalIP(addrs) 140 if err != nil { 141 return nil, err 142 } 143 if finalIP != nil { 144 glog.V(4).Infof("valid IPv4 address for interface %q found as %v.", intfName, finalIP) 145 return finalIP, nil 146 } 147 } 148 149 return nil, nil 150 } 151 152 func flagsSet(flags net.Flags, test net.Flags) bool { 153 return flags&test != 0 154 } 155 156 func flagsClear(flags net.Flags, test net.Flags) bool { 157 return flags&test == 0 158 } 159 160 func chooseHostInterfaceNativeGo() (net.IP, error) { 161 intfs, err := net.Interfaces() 162 if err != nil { 163 return nil, err 164 } 165 i := 0 166 var ip net.IP 167 for i = range intfs { 168 if flagsSet(intfs[i].Flags, net.FlagUp) && flagsClear(intfs[i].Flags, net.FlagLoopback|net.FlagPointToPoint) { 169 addrs, err := intfs[i].Addrs() 170 if err != nil { 171 return nil, err 172 } 173 if len(addrs) > 0 { 174 for _, addr := range addrs { 175 if addrIP, _, err := net.ParseCIDR(addr.String()); err == nil { 176 if addrIP.To4() != nil { 177 ip = addrIP.To4() 178 if !ip.IsLinkLocalMulticast() && !ip.IsLinkLocalUnicast() { 179 break 180 } 181 } 182 } 183 } 184 if ip != nil { 185 // This interface should suffice. 186 break 187 } 188 } 189 } 190 } 191 if ip == nil { 192 return nil, fmt.Errorf("no acceptable interface from host") 193 } 194 glog.V(4).Infof("Choosing interface %s (IP %v) as default", intfs[i].Name, ip) 195 return ip, nil 196 } 197 198 //ChooseHostInterface is a method used fetch an IP for a daemon. 199 //It uses data from /proc/net/route file. 200 //For a node with no internet connection ,it returns error 201 //For a multi n/w interface node it returns the IP of the interface with gateway on it. 202 func ChooseHostInterface() (net.IP, error) { 203 inFile, err := os.Open("/proc/net/route") 204 if err != nil { 205 if os.IsNotExist(err) { 206 return chooseHostInterfaceNativeGo() 207 } 208 return nil, err 209 } 210 defer inFile.Close() 211 var nw networkInterfacer = networkInterface{} 212 return chooseHostInterfaceFromRoute(inFile, nw) 213 } 214 215 type networkInterfacer interface { 216 InterfaceByName(intfName string) (*net.Interface, error) 217 Addrs(intf *net.Interface) ([]net.Addr, error) 218 } 219 220 type networkInterface struct{} 221 222 func (_ networkInterface) InterfaceByName(intfName string) (*net.Interface, error) { 223 intf, err := net.InterfaceByName(intfName) 224 if err != nil { 225 return nil, err 226 } 227 return intf, nil 228 } 229 230 func (_ networkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { 231 addrs, err := intf.Addrs() 232 if err != nil { 233 return nil, err 234 } 235 return addrs, nil 236 } 237 238 func chooseHostInterfaceFromRoute(inFile io.Reader, nw networkInterfacer) (net.IP, error) { 239 routes, err := getRoutes(inFile) 240 if err != nil { 241 return nil, err 242 } 243 zero := net.IP{0, 0, 0, 0} 244 var finalIP net.IP 245 for i := range routes { 246 //find interface with gateway 247 if routes[i].Destination.Equal(zero) { 248 glog.V(4).Infof("Default route transits interface %q", routes[i].Interface) 249 finalIP, err := getIPFromInterface(routes[i].Interface, nw) 250 if err != nil { 251 return nil, err 252 } 253 if finalIP != nil { 254 glog.V(4).Infof("Choosing IP %v ", finalIP) 255 return finalIP, nil 256 } 257 } 258 } 259 glog.V(4).Infof("No valid IP found") 260 if finalIP == nil { 261 return nil, fmt.Errorf("Unable to select an IP.") 262 } 263 return nil, nil 264 } 265 266 // If bind-address is usable, return it directly 267 // If bind-address is not usable (unset, 0.0.0.0, or loopback), we will use the host's default 268 // interface. 269 func ChooseBindAddress(bindAddress net.IP) (net.IP, error) { 270 if bindAddress == nil || bindAddress.IsUnspecified() || bindAddress.IsLoopback() { 271 hostIP, err := ChooseHostInterface() 272 if err != nil { 273 return nil, err 274 } 275 bindAddress = hostIP 276 } 277 return bindAddress, nil 278 }