github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/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 "sort" 12 "strings" 13 14 "github.com/juju/errors" 15 "github.com/juju/loggo" 16 ) 17 18 var logger = loggo.GetLogger("juju.network") 19 20 // TODO(dimitern): Remove this once we use spaces as per the model. 21 const ( 22 // Id of the default public juju network 23 DefaultPublic = "juju-public" 24 25 // Id of the default private juju network 26 DefaultPrivate = "juju-private" 27 28 // Provider Id for the default network 29 DefaultProviderId = "juju-unknown" 30 ) 31 32 // noAddress represents an error when an address is requested but not available. 33 type noAddress struct { 34 errors.Err 35 } 36 37 // NoAddressf returns an error which satisfies IsNoAddress(). 38 func NoAddressf(format string, args ...interface{}) error { 39 newErr := errors.NewErr(format+" no address", args...) 40 newErr.SetLocation(1) 41 return &noAddress{newErr} 42 } 43 44 // IsNoAddress reports whether err was created with NoAddressf(). 45 func IsNoAddress(err error) bool { 46 err = errors.Cause(err) 47 _, ok := err.(*noAddress) 48 return ok 49 } 50 51 // Id defines a provider-specific network id. 52 type Id string 53 54 // AnySubnet when passed as a subnet id should be interpreted by the 55 // providers as "the subnet id does not matter". It's up to the 56 // provider how to handle this case - it might return an error. 57 const AnySubnet Id = "" 58 59 // SubnetInfo describes the bare minimum information for a subnet, 60 // which the provider knows about but juju might not yet. 61 type SubnetInfo struct { 62 // CIDR of the network, in 123.45.67.89/24 format. Can be empty if 63 // unknown. 64 CIDR string 65 66 // ProviderId is a provider-specific network id. This the only 67 // required field. 68 ProviderId Id 69 70 // VLANTag needs to be between 1 and 4094 for VLANs and 0 for 71 // normal networks. It's defined by IEEE 802.1Q standard, and used 72 // to define a VLAN network. For more information, see: 73 // http://en.wikipedia.org/wiki/IEEE_802.1Q. 74 VLANTag int 75 76 // AllocatableIPLow and AllocatableIPHigh describe the allocatable 77 // portion of the subnet. The provider will only permit allocation 78 // between these limits. If they are empty then none of the subnet is 79 // allocatable. 80 AllocatableIPLow net.IP 81 AllocatableIPHigh net.IP 82 83 // AvailabilityZones describes which availability zone(s) this 84 // subnet is in. It can be empty if the provider does not support 85 // availability zones. 86 AvailabilityZones []string 87 88 // SpaceName holds the juju network space associated with this 89 // subnet. Can be empty if not supported. 90 SpaceName string 91 } 92 93 type SpaceInfo struct { 94 Name string 95 CIDRs []string 96 } 97 type BySpaceName []SpaceInfo 98 99 func (s BySpaceName) Len() int { return len(s) } 100 func (s BySpaceName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 101 func (s BySpaceName) Less(i, j int) bool { 102 return s[i].Name < s[j].Name 103 } 104 105 // InterfaceConfigType defines valid network interface configuration 106 // types. See interfaces(5) for details 107 type InterfaceConfigType string 108 109 const ( 110 ConfigUnknown InterfaceConfigType = "" 111 ConfigDHCP InterfaceConfigType = "dhcp" 112 ConfigStatic InterfaceConfigType = "static" 113 ConfigManual InterfaceConfigType = "manual" 114 // add others when needed 115 ) 116 117 // InterfaceInfo describes a single network interface available on an 118 // instance. For providers that support networks, this will be 119 // available at StartInstance() time. 120 // TODO(mue): Rename to InterfaceConfig due to consistency later. 121 type InterfaceInfo struct { 122 // DeviceIndex specifies the order in which the network interface 123 // appears on the host. The primary interface has an index of 0. 124 DeviceIndex int 125 126 // MACAddress is the network interface's hardware MAC address 127 // (e.g. "aa:bb:cc:dd:ee:ff"). 128 MACAddress string 129 130 // CIDR of the network, in 123.45.67.89/24 format. 131 CIDR string 132 133 // NetworkName is juju-internal name of the network. 134 NetworkName string 135 136 // ProviderId is a provider-specific NIC id. 137 ProviderId Id 138 139 // ProviderSubnetId is the provider-specific id for the associated 140 // subnet. 141 ProviderSubnetId Id 142 143 // AvailabilityZones describes the availability zones the associated 144 // subnet is in. 145 AvailabilityZones []string 146 147 // VLANTag needs to be between 1 and 4094 for VLANs and 0 for 148 // normal networks. It's defined by IEEE 802.1Q standard. 149 VLANTag int 150 151 // InterfaceName is the raw OS-specific network device name (e.g. 152 // "eth1", even for a VLAN eth1.42 virtual interface). 153 InterfaceName string 154 155 // Disabled is true when the interface needs to be disabled on the 156 // machine, e.g. not to configure it. 157 Disabled bool 158 159 // NoAutoStart is true when the interface should not be configured 160 // to start automatically on boot. By default and for 161 // backwards-compatibility, interfaces are configured to 162 // auto-start. 163 NoAutoStart bool 164 165 // ConfigType determines whether the interface should be 166 // configured via DHCP, statically, manually, etc. See 167 // interfaces(5) for more information. 168 ConfigType InterfaceConfigType 169 170 // Address contains an optional static IP address to configure for 171 // this network interface. The subnet mask to set will be inferred 172 // from the CIDR value. 173 Address Address 174 175 // DNSServers contains an optional list of IP addresses and/or 176 // hostnames to configure as DNS servers for this network 177 // interface. 178 DNSServers []Address 179 180 // DNSSearch contains the default DNS domain to use for 181 // non-FQDN lookups. 182 DNSSearch string 183 184 // Gateway address, if set, defines the default gateway to 185 // configure for this network interface. For containers this 186 // usually is (one of) the host address(es). 187 GatewayAddress Address 188 189 // ExtraConfig can contain any valid setting and its value allowed 190 // inside an "iface" section of a interfaces(5) config file, e.g. 191 // "up", "down", "mtu", etc. 192 ExtraConfig map[string]string 193 } 194 195 type interfaceInfoSlice []InterfaceInfo 196 197 func (s interfaceInfoSlice) Len() int { return len(s) } 198 func (s interfaceInfoSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 199 func (s interfaceInfoSlice) Less(i, j int) bool { 200 iface1 := s[i] 201 iface2 := s[j] 202 return iface1.DeviceIndex < iface2.DeviceIndex 203 } 204 205 // SortInterfaceInfo sorts a slice of InterfaceInfo on DeviceIndex in ascending 206 // order. 207 func SortInterfaceInfo(interfaces []InterfaceInfo) { 208 sort.Sort(interfaceInfoSlice(interfaces)) 209 } 210 211 // ActualInterfaceName returns raw interface name for raw interface (e.g. "eth0") and 212 // virtual interface name for virtual interface (e.g. "eth0.42") 213 func (i *InterfaceInfo) ActualInterfaceName() string { 214 if i.VLANTag > 0 { 215 return fmt.Sprintf("%s.%d", i.InterfaceName, i.VLANTag) 216 } 217 return i.InterfaceName 218 } 219 220 // IsVirtual returns true when the interface is a virtual device, as 221 // opposed to a physical device (e.g. a VLAN or a network alias) 222 func (i *InterfaceInfo) IsVirtual() bool { 223 return i.VLANTag > 0 224 } 225 226 // IsVLAN returns true when the interface is a VLAN interface. 227 func (i *InterfaceInfo) IsVLAN() bool { 228 return i.VLANTag > 0 229 } 230 231 // PreferIPv6Getter will be implemented by both the environment and agent 232 // config. 233 type PreferIPv6Getter interface { 234 PreferIPv6() bool 235 } 236 237 // InitializeFromConfig needs to be called once after the environment 238 // or agent configuration is available to configure networking 239 // settings. 240 func InitializeFromConfig(config PreferIPv6Getter) { 241 globalPreferIPv6 = config.PreferIPv6() 242 logger.Infof("setting prefer-ipv6 to %v", globalPreferIPv6) 243 } 244 245 // LXCNetDefaultConfig is the location of the default network config 246 // of the lxc package. It's exported to allow cross-package testing. 247 var LXCNetDefaultConfig = "/etc/default/lxc-net" 248 249 // InterfaceByNameAddrs returns the addresses for the given interface 250 // name. It's exported to facilitate cross-package testing. 251 var InterfaceByNameAddrs = func(name string) ([]net.Addr, error) { 252 iface, err := net.InterfaceByName(name) 253 if err != nil { 254 return nil, err 255 } 256 return iface.Addrs() 257 } 258 259 // FilterLXCAddresses tries to discover the default lxc bridge name 260 // and all of its addresses, then filters those addresses out of the 261 // given ones and returns the result. Any errors encountered during 262 // this process are logged, but not considered fatal. See LP bug 263 // #1416928. 264 func FilterLXCAddresses(addresses []Address) []Address { 265 file, err := os.Open(LXCNetDefaultConfig) 266 if os.IsNotExist(err) { 267 // No lxc-net config found, nothing to do. 268 logger.Debugf("no lxc bridge addresses to filter for machine") 269 return addresses 270 } else if err != nil { 271 // Just log it, as it's not fatal. 272 logger.Warningf("cannot open %q: %v", LXCNetDefaultConfig, err) 273 return addresses 274 } 275 defer file.Close() 276 277 filterAddrs := func(bridgeName string, addrs []net.Addr) []Address { 278 // Filter out any bridge addresses. 279 filtered := make([]Address, 0, len(addresses)) 280 for _, addr := range addresses { 281 found := false 282 for _, ifaceAddr := range addrs { 283 // First check if this is a CIDR, as 284 // net.InterfaceAddrs might return this instead of 285 // a plain IP. 286 ip, ipNet, err := net.ParseCIDR(ifaceAddr.String()) 287 if err != nil { 288 // It's not a CIDR, try parsing as IP. 289 ip = net.ParseIP(ifaceAddr.String()) 290 } 291 if ip == nil { 292 logger.Debugf("cannot parse %q as IP, ignoring", ifaceAddr) 293 continue 294 } 295 // Filter by CIDR if known or single IP otherwise. 296 if ipNet != nil && ipNet.Contains(net.ParseIP(addr.Value)) || 297 ip.String() == addr.Value { 298 found = true 299 logger.Debugf("filtering %q address %s for machine", bridgeName, ifaceAddr.String()) 300 } 301 } 302 if !found { 303 logger.Debugf("not filtering address %s for machine", addr) 304 filtered = append(filtered, addr) 305 } 306 } 307 logger.Debugf("addresses after filtering: %v", filtered) 308 return filtered 309 } 310 311 scanner := bufio.NewScanner(file) 312 for scanner.Scan() { 313 line := strings.TrimSpace(scanner.Text()) 314 switch { 315 case strings.HasPrefix(line, "#"): 316 // Skip comments. 317 case strings.HasPrefix(line, "LXC_BRIDGE"): 318 // Extract <name> from LXC_BRIDGE="<name>". 319 parts := strings.Split(line, `"`) 320 if len(parts) < 2 { 321 logger.Debugf("ignoring invalid line '%s' in %q", line, LXCNetDefaultConfig) 322 continue 323 } 324 bridgeName := strings.TrimSpace(parts[1]) 325 // Discover all addresses of bridgeName interface. 326 addrs, err := InterfaceByNameAddrs(bridgeName) 327 if err != nil { 328 logger.Warningf("cannot get %q addresses: %v (ignoring)", bridgeName, err) 329 continue 330 } 331 logger.Debugf("%q has addresses %v", bridgeName, addrs) 332 return filterAddrs(bridgeName, addrs) 333 } 334 } 335 if err := scanner.Err(); err != nil { 336 logger.Warningf("failed to read %q: %v (ignoring)", LXCNetDefaultConfig, err) 337 } 338 return addresses 339 }