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