github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/network/network.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package network 5 6 import ( 7 "bufio" 8 "fmt" 9 "net" 10 "os" 11 "regexp" 12 "sort" 13 "strings" 14 "sync/atomic" 15 16 "github.com/juju/errors" 17 "github.com/juju/loggo" 18 "github.com/juju/utils/set" 19 ) 20 21 var logger = loggo.GetLogger("juju.network") 22 23 // SpaceInvalidChars is a regexp for validating that space names contain no 24 // invalid characters. 25 var SpaceInvalidChars = regexp.MustCompile("[^0-9a-z-]") 26 27 // noAddress represents an error when an address is requested but not available. 28 type noAddress struct { 29 errors.Err 30 } 31 32 // NoAddressf returns an error which satisfies IsNoAddress(). 33 func NoAddressf(format string, args ...interface{}) error { 34 newErr := errors.NewErr(format+" no address", args...) 35 newErr.SetLocation(1) 36 return &noAddress{newErr} 37 } 38 39 // IsNoAddress reports whether err was created with NoAddressf(). 40 func IsNoAddress(err error) bool { 41 err = errors.Cause(err) 42 _, ok := err.(*noAddress) 43 return ok 44 } 45 46 // Id defines a provider-specific network id. 47 type Id string 48 49 // AnySubnet when passed as a subnet id should be interpreted by the 50 // providers as "the subnet id does not matter". It's up to the 51 // provider how to handle this case - it might return an error. 52 const AnySubnet Id = "" 53 54 // UnknownId can be used whenever an Id is needed but not known. 55 const UnknownId = "" 56 57 var dashPrefix = regexp.MustCompile("^-*") 58 var dashSuffix = regexp.MustCompile("-*$") 59 var multipleDashes = regexp.MustCompile("--+") 60 61 // ConvertSpaceName converts names between provider space names and valid juju 62 // space names. 63 // TODO(mfoord): once MAAS space name rules are in sync with juju space name 64 // rules this can go away. 65 func ConvertSpaceName(name string, existing set.Strings) string { 66 // First lower case and replace spaces with dashes. 67 name = strings.Replace(name, " ", "-", -1) 68 name = strings.ToLower(name) 69 // Replace any character that isn't in the set "-", "a-z", "0-9". 70 name = SpaceInvalidChars.ReplaceAllString(name, "") 71 // Get rid of any dashes at the start as that isn't valid. 72 name = dashPrefix.ReplaceAllString(name, "") 73 // And any at the end. 74 name = dashSuffix.ReplaceAllString(name, "") 75 // Repleace multiple dashes with a single dash. 76 name = multipleDashes.ReplaceAllString(name, "-") 77 // Special case of when the space name was only dashes or invalid 78 // characters! 79 if name == "" { 80 name = "empty" 81 } 82 // If this name is in use add a numerical suffix. 83 if existing.Contains(name) { 84 counter := 2 85 for existing.Contains(name + fmt.Sprintf("-%d", counter)) { 86 counter += 1 87 } 88 name = name + fmt.Sprintf("-%d", counter) 89 } 90 return name 91 } 92 93 // SubnetInfo describes the bare minimum information for a subnet, 94 // which the provider knows about but juju might not yet. 95 type SubnetInfo struct { 96 // CIDR of the network, in 123.45.67.89/24 format. Can be empty if 97 // unknown. 98 CIDR string 99 100 // ProviderId is a provider-specific network id. This the only 101 // required field. 102 ProviderId Id 103 104 // VLANTag needs to be between 1 and 4094 for VLANs and 0 for 105 // normal networks. It's defined by IEEE 802.1Q standard, and used 106 // to define a VLAN network. For more information, see: 107 // http://en.wikipedia.org/wiki/IEEE_802.1Q. 108 VLANTag int 109 110 // AllocatableIPLow and AllocatableIPHigh describe the allocatable 111 // portion of the subnet. The provider will only permit allocation 112 // between these limits. If they are empty then none of the subnet is 113 // allocatable. 114 AllocatableIPLow net.IP 115 AllocatableIPHigh net.IP 116 117 // AvailabilityZones describes which availability zone(s) this 118 // subnet is in. It can be empty if the provider does not support 119 // availability zones. 120 AvailabilityZones []string 121 122 // SpaceProviderId holds the provider Id of the space associated with 123 // this subnet. Can be empty if not supported. 124 SpaceProviderId Id 125 } 126 127 type SpaceInfo struct { 128 Name string 129 ProviderId Id 130 Subnets []SubnetInfo 131 } 132 type BySpaceName []SpaceInfo 133 134 func (s BySpaceName) Len() int { return len(s) } 135 func (s BySpaceName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 136 func (s BySpaceName) Less(i, j int) bool { 137 return s[i].Name < s[j].Name 138 } 139 140 // InterfaceConfigType defines valid network interface configuration 141 // types. See interfaces(5) for details 142 type InterfaceConfigType string 143 144 const ( 145 ConfigUnknown InterfaceConfigType = "" 146 ConfigDHCP InterfaceConfigType = "dhcp" 147 ConfigStatic InterfaceConfigType = "static" 148 ConfigManual InterfaceConfigType = "manual" 149 ConfigLoopback InterfaceConfigType = "loopback" 150 ) 151 152 // InterfaceType defines valid network interface types. 153 type InterfaceType string 154 155 const ( 156 UnknownInterface InterfaceType = "" 157 LoopbackInterface InterfaceType = "loopback" 158 EthernetInterface InterfaceType = "ethernet" 159 VLAN_8021QInterface InterfaceType = "802.1q" 160 BondInterface InterfaceType = "bond" 161 BridgeInterface InterfaceType = "bridge" 162 ) 163 164 // InterfaceInfo describes a single network interface available on an 165 // instance. For providers that support networks, this will be 166 // available at StartInstance() time. 167 // TODO(mue): Rename to InterfaceConfig due to consistency later. 168 type InterfaceInfo struct { 169 // DeviceIndex specifies the order in which the network interface 170 // appears on the host. The primary interface has an index of 0. 171 DeviceIndex int 172 173 // MACAddress is the network interface's hardware MAC address 174 // (e.g. "aa:bb:cc:dd:ee:ff"). 175 MACAddress string 176 177 // CIDR of the network, in 123.45.67.89/24 format. 178 CIDR string 179 180 // ProviderId is a provider-specific NIC id. 181 ProviderId Id 182 183 // ProviderSubnetId is the provider-specific id for the associated 184 // subnet. 185 ProviderSubnetId Id 186 187 // ProviderSpaceId is the provider-specific id for the associated space, if 188 // known and supported. 189 ProviderSpaceId Id 190 191 // ProviderVLANId is the provider-specific id of the VLAN for this 192 // interface. 193 ProviderVLANId Id 194 195 // ProviderAddressId is the provider-specific id of the assigned address. 196 ProviderAddressId Id 197 198 // AvailabilityZones describes the availability zones the associated 199 // subnet is in. 200 AvailabilityZones []string 201 202 // VLANTag needs to be between 1 and 4094 for VLANs and 0 for 203 // normal networks. It's defined by IEEE 802.1Q standard. 204 VLANTag int 205 206 // InterfaceName is the raw OS-specific network device name (e.g. 207 // "eth1", even for a VLAN eth1.42 virtual interface). 208 InterfaceName string 209 210 // ParentInterfaceName is the name of the parent interface to use, if known. 211 ParentInterfaceName string 212 213 // InterfaceType is the type of the interface. 214 InterfaceType InterfaceType 215 216 // Disabled is true when the interface needs to be disabled on the 217 // machine, e.g. not to configure it. 218 Disabled bool 219 220 // NoAutoStart is true when the interface should not be configured 221 // to start automatically on boot. By default and for 222 // backwards-compatibility, interfaces are configured to 223 // auto-start. 224 NoAutoStart bool 225 226 // ConfigType determines whether the interface should be 227 // configured via DHCP, statically, manually, etc. See 228 // interfaces(5) for more information. 229 ConfigType InterfaceConfigType 230 231 // Address contains an optional static IP address to configure for 232 // this network interface. The subnet mask to set will be inferred 233 // from the CIDR value. 234 Address Address 235 236 // DNSServers contains an optional list of IP addresses and/or 237 // hostnames to configure as DNS servers for this network 238 // interface. 239 DNSServers []Address 240 241 // MTU is the Maximum Transmission Unit controlling the maximum size of the 242 // protocol packats that the interface can pass through. It is only used 243 // when > 0. 244 MTU int 245 246 // DNSSearchDomains contains the default DNS domain to use for non-FQDN 247 // lookups. 248 DNSSearchDomains []string 249 250 // Gateway address, if set, defines the default gateway to 251 // configure for this network interface. For containers this 252 // usually is (one of) the host address(es). 253 GatewayAddress Address 254 } 255 256 type interfaceInfoSlice []InterfaceInfo 257 258 func (s interfaceInfoSlice) Len() int { return len(s) } 259 func (s interfaceInfoSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 260 func (s interfaceInfoSlice) Less(i, j int) bool { 261 iface1 := s[i] 262 iface2 := s[j] 263 return iface1.DeviceIndex < iface2.DeviceIndex 264 } 265 266 // SortInterfaceInfo sorts a slice of InterfaceInfo on DeviceIndex in ascending 267 // order. 268 func SortInterfaceInfo(interfaces []InterfaceInfo) { 269 sort.Sort(interfaceInfoSlice(interfaces)) 270 } 271 272 // ActualInterfaceName returns raw interface name for raw interface (e.g. "eth0") and 273 // virtual interface name for virtual interface (e.g. "eth0.42") 274 func (i *InterfaceInfo) ActualInterfaceName() string { 275 if i.VLANTag > 0 { 276 return fmt.Sprintf("%s.%d", i.InterfaceName, i.VLANTag) 277 } 278 return i.InterfaceName 279 } 280 281 // IsVirtual returns true when the interface is a virtual device, as 282 // opposed to a physical device (e.g. a VLAN or a network alias) 283 func (i *InterfaceInfo) IsVirtual() bool { 284 return i.VLANTag > 0 285 } 286 287 // IsVLAN returns true when the interface is a VLAN interface. 288 func (i *InterfaceInfo) IsVLAN() bool { 289 return i.VLANTag > 0 290 } 291 292 // CIDRAddress returns Address.Value combined with CIDR mask. 293 func (i *InterfaceInfo) CIDRAddress() string { 294 if i.CIDR == "" || i.Address.Value == "" { 295 return "" 296 } 297 _, ipNet, err := net.ParseCIDR(i.CIDR) 298 if err != nil { 299 return errors.Trace(err).Error() 300 } 301 ip := net.ParseIP(i.Address.Value) 302 if ip == nil { 303 return errors.Errorf("cannot parse IP address %q", i.Address.Value).Error() 304 } 305 ipNet.IP = ip 306 return ipNet.String() 307 } 308 309 var preferIPv6 uint32 310 311 // PreferIPV6 returns true if this process prefers IPv6. 312 func PreferIPv6() bool { return atomic.LoadUint32(&preferIPv6) > 0 } 313 314 // SetPreferIPv6 determines whether IPv6 addresses will be preferred when 315 // selecting a public or internal addresses, using the Select*() methods. 316 // SetPreferIPV6 needs to be called to set this flag globally at the 317 // earliest time possible (e.g. at bootstrap, agent startup, before any 318 // CLI command). 319 func SetPreferIPv6(prefer bool) { 320 var b uint32 321 if prefer { 322 b = 1 323 } 324 atomic.StoreUint32(&preferIPv6, b) 325 // TODO(dimitern): Drop prefer-ipv6 entirely. 326 prefer = false 327 logger.Infof("setting prefer-ipv6 to %v", prefer) 328 } 329 330 // LXCNetDefaultConfig is the location of the default network config 331 // of the lxc package. It's exported to allow cross-package testing. 332 var LXCNetDefaultConfig = "/etc/default/lxc-net" 333 334 // InterfaceByNameAddrs returns the addresses for the given interface 335 // name. It's exported to facilitate cross-package testing. 336 var InterfaceByNameAddrs = func(name string) ([]net.Addr, error) { 337 iface, err := net.InterfaceByName(name) 338 if err != nil { 339 return nil, err 340 } 341 return iface.Addrs() 342 } 343 344 // FilterLXCAddresses tries to discover the default lxc bridge name 345 // and all of its addresses, then filters those addresses out of the 346 // given ones and returns the result. Any errors encountered during 347 // this process are logged, but not considered fatal. See LP bug 348 // #1416928. 349 func FilterLXCAddresses(addresses []Address) []Address { 350 file, err := os.Open(LXCNetDefaultConfig) 351 if os.IsNotExist(err) { 352 // No lxc-net config found, nothing to do. 353 logger.Debugf("no lxc bridge addresses to filter for machine") 354 return addresses 355 } else if err != nil { 356 // Just log it, as it's not fatal. 357 logger.Warningf("cannot open %q: %v", LXCNetDefaultConfig, err) 358 return addresses 359 } 360 defer file.Close() 361 362 filterAddrs := func(bridgeName string, addrs []net.Addr) []Address { 363 // Filter out any bridge addresses. 364 filtered := make([]Address, 0, len(addresses)) 365 for _, addr := range addresses { 366 found := false 367 for _, ifaceAddr := range addrs { 368 // First check if this is a CIDR, as 369 // net.InterfaceAddrs might return this instead of 370 // a plain IP. 371 ip, ipNet, err := net.ParseCIDR(ifaceAddr.String()) 372 if err != nil { 373 // It's not a CIDR, try parsing as IP. 374 ip = net.ParseIP(ifaceAddr.String()) 375 } 376 if ip == nil { 377 logger.Debugf("cannot parse %q as IP, ignoring", ifaceAddr) 378 continue 379 } 380 // Filter by CIDR if known or single IP otherwise. 381 if ipNet != nil && ipNet.Contains(net.ParseIP(addr.Value)) || 382 ip.String() == addr.Value { 383 found = true 384 logger.Debugf("filtering %q address %s for machine", bridgeName, ifaceAddr.String()) 385 } 386 } 387 if !found { 388 logger.Debugf("not filtering address %s for machine", addr) 389 filtered = append(filtered, addr) 390 } 391 } 392 logger.Debugf("addresses after filtering: %v", filtered) 393 return filtered 394 } 395 396 scanner := bufio.NewScanner(file) 397 for scanner.Scan() { 398 line := strings.TrimSpace(scanner.Text()) 399 switch { 400 case strings.HasPrefix(line, "#"): 401 // Skip comments. 402 case strings.HasPrefix(line, "LXC_BRIDGE"): 403 // Extract <name> from LXC_BRIDGE="<name>". 404 parts := strings.Split(line, `"`) 405 if len(parts) < 2 { 406 logger.Debugf("ignoring invalid line '%s' in %q", line, LXCNetDefaultConfig) 407 continue 408 } 409 bridgeName := strings.TrimSpace(parts[1]) 410 // Discover all addresses of bridgeName interface. 411 addrs, err := InterfaceByNameAddrs(bridgeName) 412 if err != nil { 413 logger.Warningf("cannot get %q addresses: %v (ignoring)", bridgeName, err) 414 continue 415 } 416 logger.Debugf("%q has addresses %v", bridgeName, addrs) 417 return filterAddrs(bridgeName, addrs) 418 } 419 } 420 if err := scanner.Err(); err != nil { 421 logger.Warningf("failed to read %q: %v (ignoring)", LXCNetDefaultConfig, err) 422 } 423 return addresses 424 }