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  }