Exemple #1
0
func (*UtilsSuite) TestParseInterfaceType(c *gc.C) {
	fakeSysPath := filepath.Join(c.MkDir(), network.SysClassNetPath)
	err := os.MkdirAll(fakeSysPath, 0700)
	c.Check(err, jc.ErrorIsNil)

	writeFakeUEvent := func(interfaceName string, lines ...string) string {
		fakeInterfacePath := filepath.Join(fakeSysPath, interfaceName)
		err := os.MkdirAll(fakeInterfacePath, 0700)
		c.Check(err, jc.ErrorIsNil)

		fakeUEventPath := filepath.Join(fakeInterfacePath, "uevent")
		contents := strings.Join(lines, "\n")
		err = ioutil.WriteFile(fakeUEventPath, []byte(contents), 0644)
		c.Check(err, jc.ErrorIsNil)
		return fakeUEventPath
	}

	result := network.ParseInterfaceType(fakeSysPath, "missing")
	c.Check(result, gc.Equals, network.UnknownInterface)

	writeFakeUEvent("eth0", "IFINDEX=1", "INTERFACE=eth0")
	result = network.ParseInterfaceType(fakeSysPath, "eth0")
	c.Check(result, gc.Equals, network.UnknownInterface)

	fakeUEventPath := writeFakeUEvent("eth0.42", "DEVTYPE=vlan")
	result = network.ParseInterfaceType(fakeSysPath, "eth0.42")
	c.Check(result, gc.Equals, network.VLAN_8021QInterface)

	os.Chmod(fakeUEventPath, 0000) // permission denied error is OK
	result = network.ParseInterfaceType(fakeSysPath, "eth0.42")
	c.Check(result, gc.Equals, network.UnknownInterface)

	writeFakeUEvent("bond0", "DEVTYPE=bond")
	result = network.ParseInterfaceType(fakeSysPath, "bond0")
	c.Check(result, gc.Equals, network.BondInterface)

	writeFakeUEvent("br-ens4", "DEVTYPE=bridge")
	result = network.ParseInterfaceType(fakeSysPath, "br-ens4")
	c.Check(result, gc.Equals, network.BridgeInterface)

	// First DEVTYPE found wins.
	writeFakeUEvent("foo", "DEVTYPE=vlan", "DEVTYPE=bridge")
	result = network.ParseInterfaceType(fakeSysPath, "foo")
	c.Check(result, gc.Equals, network.VLAN_8021QInterface)

	writeFakeUEvent("fake", "DEVTYPE=warp-drive")
	result = network.ParseInterfaceType(fakeSysPath, "fake")
	c.Check(result, gc.Equals, network.UnknownInterface)
}
Exemple #2
0
// GetObservedNetworkConfig uses the given source to find all available network
// interfaces and their assigned addresses, and returns the result as
// []params.NetworkConfig. In addition to what the source returns, a few
// additional transformations are done:
//
// * On any OS, the state (UP/DOWN) of each interface and the DeviceIndex field,
//   will be correctly populated. Loopback interfaces are also properly detected
//   and will have InterfaceType set LoopbackInterface.
// * On Linux only, the InterfaceType field will be reliably detected for a few
//   types: BondInterface, BridgeInterface, VLAN_8021QInterface.
// * Also on Linux, for interfaces that are discovered to be ports on a bridge,
//   the ParentInterfaceName will be populated with the name of the bridge.
// * ConfigType fields will be set to ConfigManual when no address is detected,
//   or ConfigStatic when it is.
// * TODO: any IPv6 addresses found will be ignored and treated as empty ATM.
//
// Result entries will be grouped by InterfaceName, in the same order they are
// returned by the given source.
func GetObservedNetworkConfig(source NetworkConfigSource) ([]params.NetworkConfig, error) {
	logger.Tracef("discovering observed machine network config...")

	interfaces, err := source.Interfaces()
	if err != nil {
		return nil, errors.Annotate(err, "cannot get network interfaces")
	}

	var namesOrder []string
	nameToConfigs := make(map[string][]params.NetworkConfig)
	sysClassNetPath := source.SysClassNetPath()
	for _, nic := range interfaces {
		nicType := network.ParseInterfaceType(sysClassNetPath, nic.Name)
		nicConfig := interfaceToNetworkConfig(nic, nicType)

		if nicType == network.BridgeInterface {
			updateParentForBridgePorts(nic.Name, sysClassNetPath, nameToConfigs)
		}

		seenSoFar := false
		if existing, ok := nameToConfigs[nic.Name]; ok {
			nicConfig.ParentInterfaceName = existing[0].ParentInterfaceName
			// If only ParentInterfaceName was set in a previous iteration (e.g.
			// if the bridge appeared before the port), treat the interface as
			// not yet seen.
			seenSoFar = existing[0].InterfaceName != ""
		}

		if !seenSoFar {
			nameToConfigs[nic.Name] = []params.NetworkConfig(nil)
			namesOrder = append(namesOrder, nic.Name)
		}

		addrs, err := source.InterfaceAddresses(nic.Name)
		if err != nil {
			return nil, errors.Annotatef(err, "cannot get interface %q addresses", nic.Name)
		}

		if len(addrs) == 0 {
			logger.Infof("no addresses observed on interface %q", nic.Name)
			nameToConfigs[nic.Name] = append(nameToConfigs[nic.Name], nicConfig)
			continue
		}

		for _, addr := range addrs {
			addressConfig, err := interfaceAddressToNetworkConfig(nic.Name, nicConfig.ConfigType, addr)
			if err != nil {
				return nil, errors.Trace(err)
			}

			// Need to copy nicConfig so only the fields relevant for the
			// current address are updated.
			nicConfigCopy := nicConfig
			nicConfigCopy.Address = addressConfig.Address
			nicConfigCopy.CIDR = addressConfig.CIDR
			nicConfigCopy.ConfigType = addressConfig.ConfigType
			nameToConfigs[nic.Name] = append(nameToConfigs[nic.Name], nicConfigCopy)
		}
	}

	// Return all interfaces configs in input order.
	var observedConfig []params.NetworkConfig
	for _, name := range namesOrder {
		observedConfig = append(observedConfig, nameToConfigs[name]...)
	}
	logger.Tracef("observed network config: %+v", observedConfig)
	return observedConfig, nil
}