github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/node/node_address_linux.go (about) 1 // Copyright 2016-2018 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // +build !darwin 16 17 package node 18 19 import ( 20 "bytes" 21 "errors" 22 "fmt" 23 "net" 24 "sort" 25 26 "golang.org/x/sys/unix" 27 28 "github.com/cilium/cilium/pkg/ip" 29 30 "github.com/vishvananda/netlink" 31 ) 32 33 func firstGlobalAddr(intf string, preferredIP net.IP, family int) (net.IP, error) { 34 var link netlink.Link 35 var ipLen int 36 var err error 37 38 ipsToExclude := ip.GetExcludedIPs() 39 linkScopeMax := unix.RT_SCOPE_UNIVERSE 40 if family == netlink.FAMILY_V4 { 41 ipLen = 4 42 } else { 43 ipLen = 16 44 } 45 46 if intf != "" && intf != "undefined" { 47 link, err = netlink.LinkByName(intf) 48 if err != nil { 49 link = nil 50 } else { 51 ipsToExclude = []net.IP{} 52 } 53 } 54 55 retryInterface: 56 addr, err := netlink.AddrList(link, family) 57 if err != nil { 58 return nil, err 59 } 60 61 retryScope: 62 ipsPublic := []net.IP{} 63 ipsPrivate := []net.IP{} 64 hasPreferred := false 65 66 for _, a := range addr { 67 if a.Scope <= linkScopeMax { 68 if ip.IsExcluded(ipsToExclude, a.IP) { 69 continue 70 } 71 if len(a.IP) >= ipLen { 72 if ip.IsPublicAddr(a.IP) { 73 ipsPublic = append(ipsPublic, a.IP) 74 } else { 75 ipsPrivate = append(ipsPrivate, a.IP) 76 } 77 // If the IP is the same as the preferredIP, that 78 // means that maybe it is restored from node_config.h, 79 // so if it is present we prefer this one. 80 if a.IP.Equal(preferredIP) { 81 hasPreferred = true 82 } 83 } 84 } 85 } 86 87 if len(ipsPublic) != 0 { 88 if hasPreferred && ip.IsPublicAddr(preferredIP) { 89 return preferredIP, nil 90 } 91 92 // Just make sure that we always return the same one and not a 93 // random one. More info in the issue GH-7637. 94 sort.Slice(ipsPublic, func(i, j int) bool { 95 return bytes.Compare(ipsPublic[i], ipsPublic[j]) < 0 96 }) 97 98 return ipsPublic[0], nil 99 } 100 101 if len(ipsPrivate) != 0 { 102 if hasPreferred && !ip.IsPublicAddr(preferredIP) { 103 return preferredIP, nil 104 } 105 106 // Same stable order, see above ipsPublic. 107 sort.Slice(ipsPrivate, func(i, j int) bool { 108 return bytes.Compare(ipsPrivate[i], ipsPrivate[j]) < 0 109 }) 110 111 return ipsPrivate[0], nil 112 } 113 114 // First, if a device is specified, fall back to anything wider 115 // than link (site, custom, ...) before trying all devices. 116 if linkScopeMax != unix.RT_SCOPE_SITE { 117 linkScopeMax = unix.RT_SCOPE_SITE 118 goto retryScope 119 } 120 121 // Fall back with retry for all interfaces with full scope again 122 // (which then goes back to lower scope again for all interfaces 123 // before we give up completely). 124 if link != nil { 125 linkScopeMax = unix.RT_SCOPE_UNIVERSE 126 link = nil 127 goto retryInterface 128 } 129 130 return nil, fmt.Errorf("No address found") 131 } 132 133 // firstGlobalV4Addr returns the first IPv4 global IP of an interface, 134 // where the IPs are sorted in ascending order. 135 // 136 // Public IPs are preferred over private ones. When intf is defined only 137 // IPs belonging to that interface are considered. 138 // 139 // If preferredIP is present in the IP list it is returned irrespective of 140 // the sort order. However, if preferredIP is a private IP and there are 141 // public IPs, then public one is selected. 142 // 143 // Passing intf and preferredIP will only return preferredIP if it is in 144 // the IPs that belong to intf. 145 // 146 // In all cases, if intf is not found all interfaces are considered. 147 // 148 // If a intf-specific global address couldn't be found, we retry to find 149 // an address with reduced scope (site, custom) on that particular device. 150 // 151 // If the latter fails as well, we retry on all interfaces beginning with 152 // universe scope again (and then falling back to reduced scope). 153 // 154 // In case none of the above helped, we bail out with error. 155 func firstGlobalV4Addr(intf string, preferredIP net.IP) (net.IP, error) { 156 return firstGlobalAddr(intf, preferredIP, netlink.FAMILY_V4) 157 } 158 159 // firstGlobalV6Addr returns first IPv6 global IP of an interface, see 160 // firstGlobalV4Addr for more details. 161 func firstGlobalV6Addr(intf string, preferredIP net.IP) (net.IP, error) { 162 return firstGlobalAddr(intf, preferredIP, netlink.FAMILY_V6) 163 } 164 165 // getCiliumHostIPsFromNetDev returns the first IPv4 link local and returns 166 // it 167 func getCiliumHostIPsFromNetDev(devName string) (ipv4GW, ipv6Router net.IP) { 168 hostDev, err := netlink.LinkByName(devName) 169 if err != nil { 170 return nil, nil 171 } 172 addrs, err := netlink.AddrList(hostDev, netlink.FAMILY_ALL) 173 if err != nil { 174 return nil, nil 175 } 176 for _, addr := range addrs { 177 if addr.IP.To4() != nil { 178 if addr.Scope == int(netlink.SCOPE_LINK) { 179 ipv4GW = addr.IP 180 } 181 } else { 182 if addr.Scope != int(netlink.SCOPE_LINK) { 183 ipv6Router = addr.IP 184 } 185 } 186 } 187 return ipv4GW, ipv6Router 188 } 189 190 // SetInternalIPv4From sets the internal IPv4 with the first global address 191 // found in that interface. 192 func SetInternalIPv4From(ifaceName string) error { 193 l, err := netlink.LinkByName(ifaceName) 194 if err != nil { 195 return errors.New("unable to retrieve interface attributes") 196 } 197 v4Addrs, err := netlink.AddrList(l, netlink.FAMILY_V4) 198 if err != nil { 199 return errors.New("unable to retrieve interface IPv4 address") 200 } 201 for _, ip := range v4Addrs { 202 if netlink.Scope(ip.Scope) == netlink.SCOPE_UNIVERSE { 203 SetInternalIPv4(ip.IP) 204 return nil 205 } 206 } 207 return errors.New("unable to find IP addresses with scope global") 208 }