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  }