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  }