Merge pull request #967 from Luap99/ipam-none
libnetwork: allow new none ipam driver
This commit is contained in:
		
						commit
						8c96512c34
					
				| 
						 | 
				
			
			@ -128,76 +128,76 @@ func findPluginByName(plugins []*libcni.NetworkConfig, name string) bool {
 | 
			
		|||
// convertIPAMConfToNetwork converts A cni IPAMConfig to libpod network subnets.
 | 
			
		||||
// It returns an array of subnets and an extra bool if dhcp is configured.
 | 
			
		||||
func convertIPAMConfToNetwork(network *types.Network, ipam *ipamConfig, confPath string) error {
 | 
			
		||||
	if ipam.PluginType == types.DHCPIPAMDriver {
 | 
			
		||||
	switch ipam.PluginType {
 | 
			
		||||
	case "":
 | 
			
		||||
		network.IPAMOptions[types.Driver] = types.NoneIPAMDriver
 | 
			
		||||
	case types.DHCPIPAMDriver:
 | 
			
		||||
		network.IPAMOptions[types.Driver] = types.DHCPIPAMDriver
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	case types.HostLocalIPAMDriver:
 | 
			
		||||
		network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver
 | 
			
		||||
		for _, r := range ipam.Ranges {
 | 
			
		||||
			for _, ipam := range r {
 | 
			
		||||
				s := types.Subnet{}
 | 
			
		||||
 | 
			
		||||
	if ipam.PluginType != types.HostLocalIPAMDriver {
 | 
			
		||||
				// Do not use types.ParseCIDR() because we want the ip to be
 | 
			
		||||
				// the network address and not a random ip in the sub.
 | 
			
		||||
				_, sub, err := net.ParseCIDR(ipam.Subnet)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				s.Subnet = types.IPNet{IPNet: *sub}
 | 
			
		||||
 | 
			
		||||
				// gateway
 | 
			
		||||
				var gateway net.IP
 | 
			
		||||
				if ipam.Gateway != "" {
 | 
			
		||||
					gateway = net.ParseIP(ipam.Gateway)
 | 
			
		||||
					if gateway == nil {
 | 
			
		||||
						return errors.Errorf("failed to parse gateway ip %s", ipam.Gateway)
 | 
			
		||||
					}
 | 
			
		||||
					// convert to 4 byte if ipv4
 | 
			
		||||
					util.NormalizeIP(&gateway)
 | 
			
		||||
				} else if !network.Internal {
 | 
			
		||||
					// only add a gateway address if the network is not internal
 | 
			
		||||
					gateway, err = util.FirstIPInSubnet(sub)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return errors.Errorf("failed to get first ip in subnet %s", sub.String())
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				s.Gateway = gateway
 | 
			
		||||
 | 
			
		||||
				var rangeStart net.IP
 | 
			
		||||
				var rangeEnd net.IP
 | 
			
		||||
				if ipam.RangeStart != "" {
 | 
			
		||||
					rangeStart = net.ParseIP(ipam.RangeStart)
 | 
			
		||||
					if rangeStart == nil {
 | 
			
		||||
						return errors.Errorf("failed to parse range start ip %s", ipam.RangeStart)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if ipam.RangeEnd != "" {
 | 
			
		||||
					rangeEnd = net.ParseIP(ipam.RangeEnd)
 | 
			
		||||
					if rangeEnd == nil {
 | 
			
		||||
						return errors.Errorf("failed to parse range end ip %s", ipam.RangeEnd)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if rangeStart != nil || rangeEnd != nil {
 | 
			
		||||
					s.LeaseRange = &types.LeaseRange{}
 | 
			
		||||
					s.LeaseRange.StartIP = rangeStart
 | 
			
		||||
					s.LeaseRange.EndIP = rangeEnd
 | 
			
		||||
				}
 | 
			
		||||
				if util.IsIPv6(s.Subnet.IP) {
 | 
			
		||||
					network.IPv6Enabled = true
 | 
			
		||||
				}
 | 
			
		||||
				network.Subnets = append(network.Subnets, s)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		// This is not an error. While we only support certain ipam drivers, we
 | 
			
		||||
		// cannot make it fail for unsupported ones. CNI is still able to use them,
 | 
			
		||||
		// just our translation logic cannot convert this into a Network.
 | 
			
		||||
		// For the same reason this is not warning, it would just be annoying for
 | 
			
		||||
		// everyone using a unknown ipam driver.
 | 
			
		||||
		logrus.Infof("unsupported ipam plugin %q in %s", ipam.PluginType, confPath)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver
 | 
			
		||||
	for _, r := range ipam.Ranges {
 | 
			
		||||
		for _, ipam := range r {
 | 
			
		||||
			s := types.Subnet{}
 | 
			
		||||
 | 
			
		||||
			// Do not use types.ParseCIDR() because we want the ip to be
 | 
			
		||||
			// the network address and not a random ip in the sub.
 | 
			
		||||
			_, sub, err := net.ParseCIDR(ipam.Subnet)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			s.Subnet = types.IPNet{IPNet: *sub}
 | 
			
		||||
 | 
			
		||||
			// gateway
 | 
			
		||||
			var gateway net.IP
 | 
			
		||||
			if ipam.Gateway != "" {
 | 
			
		||||
				gateway = net.ParseIP(ipam.Gateway)
 | 
			
		||||
				if gateway == nil {
 | 
			
		||||
					return errors.Errorf("failed to parse gateway ip %s", ipam.Gateway)
 | 
			
		||||
				}
 | 
			
		||||
				// convert to 4 byte if ipv4
 | 
			
		||||
				util.NormalizeIP(&gateway)
 | 
			
		||||
			} else if !network.Internal {
 | 
			
		||||
				// only add a gateway address if the network is not internal
 | 
			
		||||
				gateway, err = util.FirstIPInSubnet(sub)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return errors.Errorf("failed to get first ip in subnet %s", sub.String())
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			s.Gateway = gateway
 | 
			
		||||
 | 
			
		||||
			var rangeStart net.IP
 | 
			
		||||
			var rangeEnd net.IP
 | 
			
		||||
			if ipam.RangeStart != "" {
 | 
			
		||||
				rangeStart = net.ParseIP(ipam.RangeStart)
 | 
			
		||||
				if rangeStart == nil {
 | 
			
		||||
					return errors.Errorf("failed to parse range start ip %s", ipam.RangeStart)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if ipam.RangeEnd != "" {
 | 
			
		||||
				rangeEnd = net.ParseIP(ipam.RangeEnd)
 | 
			
		||||
				if rangeEnd == nil {
 | 
			
		||||
					return errors.Errorf("failed to parse range end ip %s", ipam.RangeEnd)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if rangeStart != nil || rangeEnd != nil {
 | 
			
		||||
				s.LeaseRange = &types.LeaseRange{}
 | 
			
		||||
				s.LeaseRange.StartIP = rangeStart
 | 
			
		||||
				s.LeaseRange.EndIP = rangeEnd
 | 
			
		||||
			}
 | 
			
		||||
			if util.IsIPv6(s.Subnet.IP) {
 | 
			
		||||
				network.IPv6Enabled = true
 | 
			
		||||
			}
 | 
			
		||||
			network.Subnets = append(network.Subnets, s)
 | 
			
		||||
		}
 | 
			
		||||
		network.IPAMOptions[types.Driver] = ipam.PluginType
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -225,10 +225,13 @@ func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writ
 | 
			
		|||
	var (
 | 
			
		||||
		routes     []ipamRoute
 | 
			
		||||
		ipamRanges [][]ipamLocalHostRangeConf
 | 
			
		||||
		ipamConf   ipamConfig
 | 
			
		||||
		ipamConf   *ipamConfig
 | 
			
		||||
		err        error
 | 
			
		||||
	)
 | 
			
		||||
	if len(network.Subnets) > 0 {
 | 
			
		||||
 | 
			
		||||
	ipamDriver := network.IPAMOptions[types.Driver]
 | 
			
		||||
	switch ipamDriver {
 | 
			
		||||
	case types.HostLocalIPAMDriver:
 | 
			
		||||
		defIpv4Route := false
 | 
			
		||||
		defIpv6Route := false
 | 
			
		||||
		for _, subnet := range network.Subnets {
 | 
			
		||||
| 
						 | 
				
			
			@ -257,46 +260,20 @@ func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writ
 | 
			
		|||
				routes = append(routes, route)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ipamConf = newIPAMHostLocalConf(routes, ipamRanges)
 | 
			
		||||
	} else {
 | 
			
		||||
		ipamConf = ipamConfig{PluginType: "dhcp"}
 | 
			
		||||
		conf := newIPAMHostLocalConf(routes, ipamRanges)
 | 
			
		||||
		ipamConf = &conf
 | 
			
		||||
	case types.DHCPIPAMDriver:
 | 
			
		||||
		ipamConf = &ipamConfig{PluginType: "dhcp"}
 | 
			
		||||
 | 
			
		||||
	case types.NoneIPAMDriver:
 | 
			
		||||
		// do nothing
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, "", errors.Errorf("unsupported ipam driver %q", ipamDriver)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vlan := 0
 | 
			
		||||
	mtu := 0
 | 
			
		||||
	vlanPluginMode := ""
 | 
			
		||||
	for k, v := range network.Options {
 | 
			
		||||
		switch k {
 | 
			
		||||
		case "mtu":
 | 
			
		||||
			mtu, err = internalutil.ParseMTU(v)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, "", err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case "vlan":
 | 
			
		||||
			vlan, err = internalutil.ParseVlan(v)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, "", err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case "mode":
 | 
			
		||||
			switch network.Driver {
 | 
			
		||||
			case types.MacVLANNetworkDriver:
 | 
			
		||||
				if !pkgutil.StringInSlice(v, types.ValidMacVLANModes) {
 | 
			
		||||
					return nil, "", errors.Errorf("unknown macvlan mode %q", v)
 | 
			
		||||
				}
 | 
			
		||||
			case types.IPVLANNetworkDriver:
 | 
			
		||||
				if !pkgutil.StringInSlice(v, types.ValidIPVLANModes) {
 | 
			
		||||
					return nil, "", errors.Errorf("unknown ipvlan mode %q", v)
 | 
			
		||||
				}
 | 
			
		||||
			default:
 | 
			
		||||
				return nil, "", errors.Errorf("cannot set option \"mode\" with driver %q", network.Driver)
 | 
			
		||||
			}
 | 
			
		||||
			vlanPluginMode = v
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			return nil, "", errors.Errorf("unsupported network option %s", k)
 | 
			
		||||
		}
 | 
			
		||||
	opts, err := parseOptions(network.Options, network.Driver)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	isGateway := true
 | 
			
		||||
| 
						 | 
				
			
			@ -314,7 +291,7 @@ func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writ
 | 
			
		|||
 | 
			
		||||
	switch network.Driver {
 | 
			
		||||
	case types.BridgeNetworkDriver:
 | 
			
		||||
		bridge := newHostLocalBridge(network.NetworkInterface, isGateway, ipMasq, mtu, vlan, &ipamConf)
 | 
			
		||||
		bridge := newHostLocalBridge(network.NetworkInterface, isGateway, ipMasq, opts.mtu, opts.vlan, ipamConf)
 | 
			
		||||
		plugins = append(plugins, bridge, newPortMapPlugin(), newFirewallPlugin(), newTuningPlugin())
 | 
			
		||||
		// if we find the dnsname plugin we add configuration for it
 | 
			
		||||
		if hasDNSNamePlugin(n.cniPluginDirs) && network.DNSEnabled {
 | 
			
		||||
| 
						 | 
				
			
			@ -323,10 +300,10 @@ func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writ
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
	case types.MacVLANNetworkDriver:
 | 
			
		||||
		plugins = append(plugins, newVLANPlugin(types.MacVLANNetworkDriver, network.NetworkInterface, vlanPluginMode, mtu, &ipamConf))
 | 
			
		||||
		plugins = append(plugins, newVLANPlugin(types.MacVLANNetworkDriver, network.NetworkInterface, opts.vlanPluginMode, opts.mtu, ipamConf))
 | 
			
		||||
 | 
			
		||||
	case types.IPVLANNetworkDriver:
 | 
			
		||||
		plugins = append(plugins, newVLANPlugin(types.IPVLANNetworkDriver, network.NetworkInterface, vlanPluginMode, mtu, &ipamConf))
 | 
			
		||||
		plugins = append(plugins, newVLANPlugin(types.IPVLANNetworkDriver, network.NetworkInterface, opts.vlanPluginMode, opts.mtu, ipamConf))
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, "", errors.Errorf("driver %q is not supported by cni", network.Driver)
 | 
			
		||||
| 
						 | 
				
			
			@ -402,3 +379,48 @@ func removeMachinePlugin(conf *libcni.NetworkConfigList) *libcni.NetworkConfigLi
 | 
			
		|||
	conf.Plugins = plugins
 | 
			
		||||
	return conf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type options struct {
 | 
			
		||||
	vlan           int
 | 
			
		||||
	mtu            int
 | 
			
		||||
	vlanPluginMode string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseOptions(networkOptions map[string]string, networkDriver string) (*options, error) {
 | 
			
		||||
	opt := &options{}
 | 
			
		||||
	var err error
 | 
			
		||||
	for k, v := range networkOptions {
 | 
			
		||||
		switch k {
 | 
			
		||||
		case "mtu":
 | 
			
		||||
			opt.mtu, err = internalutil.ParseMTU(v)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case "vlan":
 | 
			
		||||
			opt.vlan, err = internalutil.ParseVlan(v)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case "mode":
 | 
			
		||||
			switch networkDriver {
 | 
			
		||||
			case types.MacVLANNetworkDriver:
 | 
			
		||||
				if !pkgutil.StringInSlice(v, types.ValidMacVLANModes) {
 | 
			
		||||
					return nil, errors.Errorf("unknown macvlan mode %q", v)
 | 
			
		||||
				}
 | 
			
		||||
			case types.IPVLANNetworkDriver:
 | 
			
		||||
				if !pkgutil.StringInSlice(v, types.ValidIPVLANModes) {
 | 
			
		||||
					return nil, errors.Errorf("unknown ipvlan mode %q", v)
 | 
			
		||||
				}
 | 
			
		||||
			default:
 | 
			
		||||
				return nil, errors.Errorf("cannot set option \"mode\" with driver %q", networkDriver)
 | 
			
		||||
			}
 | 
			
		||||
			opt.vlanPluginMode = v
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			return nil, errors.Errorf("unsupported network option %s", k)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return opt, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -145,11 +145,13 @@ func newHostLocalBridge(name string, isGateWay, ipMasq bool, mtu, vlan int, ipam
 | 
			
		|||
		MTU:         mtu,
 | 
			
		||||
		HairpinMode: true,
 | 
			
		||||
		Vlan:        vlan,
 | 
			
		||||
		IPAM:        *ipamConf,
 | 
			
		||||
	}
 | 
			
		||||
	// if we use host-local set the ips cap to ensure we can set static ips via runtime config
 | 
			
		||||
	if ipamConf.PluginType == types.HostLocalIPAMDriver {
 | 
			
		||||
		bridge.Capabilities = caps
 | 
			
		||||
	if ipamConf != nil {
 | 
			
		||||
		bridge.IPAM = *ipamConf
 | 
			
		||||
		// if we use host-local set the ips cap to ensure we can set static ips via runtime config
 | 
			
		||||
		if ipamConf.PluginType == types.HostLocalIPAMDriver {
 | 
			
		||||
			bridge.Capabilities = caps
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return &bridge
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -259,7 +261,9 @@ func hasDNSNamePlugin(paths []string) bool {
 | 
			
		|||
func newVLANPlugin(pluginType, device, mode string, mtu int, ipam *ipamConfig) VLANConfig {
 | 
			
		||||
	m := VLANConfig{
 | 
			
		||||
		PluginType: pluginType,
 | 
			
		||||
		IPAM:       *ipam,
 | 
			
		||||
	}
 | 
			
		||||
	if ipam != nil {
 | 
			
		||||
		m.IPAM = *ipam
 | 
			
		||||
	}
 | 
			
		||||
	if mtu > 0 {
 | 
			
		||||
		m.MTU = mtu
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,6 +53,11 @@ func (n *cniNetwork) networkCreate(newNetwork *types.Network, defaultNet bool) (
 | 
			
		|||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = validateIPAMDriver(newNetwork)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Only get the used networks for validation if we do not create the default network.
 | 
			
		||||
	// The default network should not be validated against used subnets, we have to ensure
 | 
			
		||||
	// that this network can always be created even when a subnet is already used on the host.
 | 
			
		||||
| 
						 | 
				
			
			@ -197,13 +202,38 @@ func createIPMACVLAN(network *types.Network) error {
 | 
			
		|||
			return errors.Errorf("parent interface %s does not exist", network.NetworkInterface)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(network.Subnets) == 0 {
 | 
			
		||||
		network.IPAMOptions[types.Driver] = types.DHCPIPAMDriver
 | 
			
		||||
		if network.Internal {
 | 
			
		||||
			return errors.New("internal is not supported with macvlan and dhcp ipam driver")
 | 
			
		||||
 | 
			
		||||
	switch network.IPAMOptions[types.Driver] {
 | 
			
		||||
	// set default
 | 
			
		||||
	case "":
 | 
			
		||||
		if len(network.Subnets) == 0 {
 | 
			
		||||
			// if no subnets and no driver choose dhcp
 | 
			
		||||
			network.IPAMOptions[types.Driver] = types.DHCPIPAMDriver
 | 
			
		||||
		} else {
 | 
			
		||||
			network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver
 | 
			
		||||
	case types.HostLocalIPAMDriver:
 | 
			
		||||
		if len(network.Subnets) == 0 {
 | 
			
		||||
			return errors.New("host-local ipam driver set but no subnets are given")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if network.IPAMOptions[types.Driver] == types.DHCPIPAMDriver && network.Internal {
 | 
			
		||||
		return errors.New("internal is not supported with macvlan and dhcp ipam driver")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateIPAMDriver(n *types.Network) error {
 | 
			
		||||
	ipamDriver := n.IPAMOptions[types.Driver]
 | 
			
		||||
	switch ipamDriver {
 | 
			
		||||
	case "", types.HostLocalIPAMDriver:
 | 
			
		||||
	case types.DHCPIPAMDriver, types.NoneIPAMDriver:
 | 
			
		||||
		if len(n.Subnets) > 0 {
 | 
			
		||||
			return errors.Errorf("%s ipam driver is set but subnets are given", ipamDriver)
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		return errors.Errorf("unsupported ipam driver %q", ipamDriver)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -167,6 +167,86 @@ var _ = Describe("Config", func() {
 | 
			
		|||
			Expect(network1.Internal).To(BeFalse())
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("create bridge config with none ipam driver", func() {
 | 
			
		||||
			network := types.Network{
 | 
			
		||||
				Driver: "bridge",
 | 
			
		||||
				IPAMOptions: map[string]string{
 | 
			
		||||
					"driver": "none",
 | 
			
		||||
				},
 | 
			
		||||
			}
 | 
			
		||||
			network1, err := libpodNet.NetworkCreate(network)
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
			Expect(network1.Driver).To(Equal("bridge"))
 | 
			
		||||
			Expect(network1.IPAMOptions).ToNot(BeEmpty())
 | 
			
		||||
			Expect(network1.IPAMOptions).To(HaveKeyWithValue("driver", "none"))
 | 
			
		||||
			Expect(network1.Subnets).To(HaveLen(0))
 | 
			
		||||
 | 
			
		||||
			// reload configs from disk
 | 
			
		||||
			libpodNet, err = getNetworkInterface(cniConfDir)
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
 | 
			
		||||
			network2, err := libpodNet.NetworkInspect(network1.Name)
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
			Expect(network2).To(Equal(network1))
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("create bridge config with none ipam driver and subnets", func() {
 | 
			
		||||
			subnet := "10.1.0.0/24"
 | 
			
		||||
			n, _ := types.ParseCIDR(subnet)
 | 
			
		||||
			network := types.Network{
 | 
			
		||||
				Driver: "bridge",
 | 
			
		||||
				IPAMOptions: map[string]string{
 | 
			
		||||
					"driver": "none",
 | 
			
		||||
				},
 | 
			
		||||
				Subnets: []types.Subnet{
 | 
			
		||||
					{Subnet: n},
 | 
			
		||||
				},
 | 
			
		||||
			}
 | 
			
		||||
			_, err := libpodNet.NetworkCreate(network)
 | 
			
		||||
			Expect(err).To(HaveOccurred())
 | 
			
		||||
			Expect(err.Error()).To(Equal("none ipam driver is set but subnets are given"))
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("create bridge config with dhcp ipam driver", func() {
 | 
			
		||||
			network := types.Network{
 | 
			
		||||
				Driver: "bridge",
 | 
			
		||||
				IPAMOptions: map[string]string{
 | 
			
		||||
					"driver": "dhcp",
 | 
			
		||||
				},
 | 
			
		||||
			}
 | 
			
		||||
			network1, err := libpodNet.NetworkCreate(network)
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
			Expect(network1.Driver).To(Equal("bridge"))
 | 
			
		||||
			Expect(network1.IPAMOptions).ToNot(BeEmpty())
 | 
			
		||||
			Expect(network1.IPAMOptions).To(HaveKeyWithValue("driver", "dhcp"))
 | 
			
		||||
			Expect(network1.Subnets).To(HaveLen(0))
 | 
			
		||||
 | 
			
		||||
			// reload configs from disk
 | 
			
		||||
			libpodNet, err = getNetworkInterface(cniConfDir)
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
 | 
			
		||||
			network2, err := libpodNet.NetworkInspect(network1.Name)
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
			Expect(network2).To(Equal(network1))
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("create bridge config with none hdcp driver and subnets", func() {
 | 
			
		||||
			subnet := "10.1.0.0/24"
 | 
			
		||||
			n, _ := types.ParseCIDR(subnet)
 | 
			
		||||
			network := types.Network{
 | 
			
		||||
				Driver: "bridge",
 | 
			
		||||
				IPAMOptions: map[string]string{
 | 
			
		||||
					"driver": "dhcp",
 | 
			
		||||
				},
 | 
			
		||||
				Subnets: []types.Subnet{
 | 
			
		||||
					{Subnet: n},
 | 
			
		||||
				},
 | 
			
		||||
			}
 | 
			
		||||
			_, err := libpodNet.NetworkCreate(network)
 | 
			
		||||
			Expect(err).To(HaveOccurred())
 | 
			
		||||
			Expect(err.Error()).To(Equal("dhcp ipam driver is set but subnets are given"))
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("create bridge with same name should fail", func() {
 | 
			
		||||
			network := types.Network{
 | 
			
		||||
				Driver:           "bridge",
 | 
			
		||||
| 
						 | 
				
			
			@ -1070,6 +1150,18 @@ var _ = Describe("Config", func() {
 | 
			
		|||
			Expect(err).To(HaveOccurred())
 | 
			
		||||
			Expect(err.Error()).To(ContainSubstring("subnet 10.10.0.0/24 is already used on the host or by another config"))
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("create network with invalid ipam driver", func() {
 | 
			
		||||
			network := types.Network{
 | 
			
		||||
				Driver: "bridge",
 | 
			
		||||
				IPAMOptions: map[string]string{
 | 
			
		||||
					"driver": "blah",
 | 
			
		||||
				},
 | 
			
		||||
			}
 | 
			
		||||
			_, err := libpodNet.NetworkCreate(network)
 | 
			
		||||
			Expect(err).To(HaveOccurred())
 | 
			
		||||
			Expect(err.Error()).To(Equal("unsupported ipam driver \"blah\""))
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	Context("network load valid existing ones", func() {
 | 
			
		||||
| 
						 | 
				
			
			@ -1114,8 +1206,6 @@ var _ = Describe("Config", func() {
 | 
			
		|||
			// check for the unsupported ipam plugin message
 | 
			
		||||
			logString := logBuffer.String()
 | 
			
		||||
			Expect(logString).ToNot(BeEmpty())
 | 
			
		||||
			Expect(logString).To(ContainSubstring("unsupported ipam plugin \\\"\\\" in %s", cniConfDir+"/ipam-none.conflist"))
 | 
			
		||||
			Expect(logString).To(ContainSubstring("unsupported ipam plugin \\\"\\\" in %s", cniConfDir+"/ipam-empty.conflist"))
 | 
			
		||||
			Expect(logString).To(ContainSubstring("unsupported ipam plugin \\\"static\\\" in %s", cniConfDir+"/ipam-static.conflist"))
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1258,6 +1348,27 @@ var _ = Describe("Config", func() {
 | 
			
		|||
			Expect(network.ID).To(HaveLen(64))
 | 
			
		||||
			Expect(network.Driver).To(Equal("bridge"))
 | 
			
		||||
			Expect(network.Subnets).To(HaveLen(0))
 | 
			
		||||
			Expect(network.IPAMOptions).To(HaveKeyWithValue("driver", "static"))
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("ipam none network", func() {
 | 
			
		||||
			network, err := libpodNet.NetworkInspect("ipam-none")
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
			Expect(network.Name).To(Equal("ipam-none"))
 | 
			
		||||
			Expect(network.ID).To(HaveLen(64))
 | 
			
		||||
			Expect(network.Driver).To(Equal("bridge"))
 | 
			
		||||
			Expect(network.Subnets).To(HaveLen(0))
 | 
			
		||||
			Expect(network.IPAMOptions).To(HaveKeyWithValue("driver", "none"))
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("ipam empty network", func() {
 | 
			
		||||
			network, err := libpodNet.NetworkInspect("ipam-empty")
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
			Expect(network.Name).To(Equal("ipam-empty"))
 | 
			
		||||
			Expect(network.ID).To(HaveLen(64))
 | 
			
		||||
			Expect(network.Driver).To(Equal("bridge"))
 | 
			
		||||
			Expect(network.Subnets).To(HaveLen(0))
 | 
			
		||||
			Expect(network.IPAMOptions).To(HaveKeyWithValue("driver", "none"))
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("network list with filters (name)", func() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -125,35 +125,38 @@ func CNIResultToStatus(res cnitypes.Result) (types.StatusBlock, error) {
 | 
			
		|||
	result.DNSSearchDomains = cniResult.DNS.Search
 | 
			
		||||
 | 
			
		||||
	interfaces := make(map[string]types.NetInterface)
 | 
			
		||||
	for _, ip := range cniResult.IPs {
 | 
			
		||||
		if ip.Interface == nil {
 | 
			
		||||
			// we do no expect ips without an interface
 | 
			
		||||
	for intIndex, netInterface := range cniResult.Interfaces {
 | 
			
		||||
		// we are only interested about interfaces in the container namespace
 | 
			
		||||
		if netInterface.Sandbox == "" {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if len(cniResult.Interfaces) <= *ip.Interface {
 | 
			
		||||
			return result, errors.Errorf("invalid cni result, interface index %d out of range", *ip.Interface)
 | 
			
		||||
 | 
			
		||||
		mac, err := net.ParseMAC(netInterface.Mac)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return result, err
 | 
			
		||||
		}
 | 
			
		||||
		cniInt := cniResult.Interfaces[*ip.Interface]
 | 
			
		||||
		netInt, ok := interfaces[cniInt.Name]
 | 
			
		||||
		if ok {
 | 
			
		||||
			netInt.Subnets = append(netInt.Subnets, types.NetAddress{
 | 
			
		||||
				IPNet:   types.IPNet{IPNet: ip.Address},
 | 
			
		||||
				Gateway: ip.Gateway,
 | 
			
		||||
			})
 | 
			
		||||
			interfaces[cniInt.Name] = netInt
 | 
			
		||||
		} else {
 | 
			
		||||
			mac, err := net.ParseMAC(cniInt.Mac)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return result, err
 | 
			
		||||
		subnets := make([]types.NetAddress, 0, len(cniResult.IPs))
 | 
			
		||||
		for _, ip := range cniResult.IPs {
 | 
			
		||||
			if ip.Interface == nil {
 | 
			
		||||
				// we do no expect ips without an interface
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			interfaces[cniInt.Name] = types.NetInterface{
 | 
			
		||||
				MacAddress: types.HardwareAddr(mac),
 | 
			
		||||
				Subnets: []types.NetAddress{{
 | 
			
		||||
			if len(cniResult.Interfaces) <= *ip.Interface {
 | 
			
		||||
				return result, errors.Errorf("invalid cni result, interface index %d out of range", *ip.Interface)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// when we have a ip for this interface add it to the subnets
 | 
			
		||||
			if *ip.Interface == intIndex {
 | 
			
		||||
				subnets = append(subnets, types.NetAddress{
 | 
			
		||||
					IPNet:   types.IPNet{IPNet: ip.Address},
 | 
			
		||||
					Gateway: ip.Gateway,
 | 
			
		||||
				}},
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		interfaces[netInterface.Name] = types.NetInterface{
 | 
			
		||||
			MacAddress: types.HardwareAddr(mac),
 | 
			
		||||
			Subnets:    subnets,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	result.Interfaces = interfaces
 | 
			
		||||
	return result, nil
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -830,6 +830,91 @@ var _ = Describe("run CNI", func() {
 | 
			
		|||
				Expect(err).To(BeNil())
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("setup ipam driver none network", func() {
 | 
			
		||||
			runTest(func() {
 | 
			
		||||
				network := types.Network{
 | 
			
		||||
					IPAMOptions: map[string]string{
 | 
			
		||||
						types.Driver: types.NoneIPAMDriver,
 | 
			
		||||
					},
 | 
			
		||||
				}
 | 
			
		||||
				network1, err := libpodNet.NetworkCreate(network)
 | 
			
		||||
				Expect(err).To(BeNil())
 | 
			
		||||
 | 
			
		||||
				intName1 := "eth0"
 | 
			
		||||
				netName1 := network1.Name
 | 
			
		||||
 | 
			
		||||
				setupOpts := types.SetupOptions{
 | 
			
		||||
					NetworkOptions: types.NetworkOptions{
 | 
			
		||||
						ContainerID: stringid.GenerateNonCryptoID(),
 | 
			
		||||
						Networks: map[string]types.PerNetworkOptions{
 | 
			
		||||
							netName1: {
 | 
			
		||||
								InterfaceName: intName1,
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
 | 
			
		||||
				Expect(err).To(BeNil())
 | 
			
		||||
				Expect(res).To(HaveLen(1))
 | 
			
		||||
 | 
			
		||||
				Expect(res).To(HaveKey(netName1))
 | 
			
		||||
				Expect(res[netName1].Interfaces).To(HaveKey(intName1))
 | 
			
		||||
				Expect(res[netName1].Interfaces[intName1].Subnets).To(HaveLen(0))
 | 
			
		||||
				macInt1 := res[netName1].Interfaces[intName1].MacAddress
 | 
			
		||||
				Expect(macInt1).To(HaveLen(6))
 | 
			
		||||
 | 
			
		||||
				// check in the container namespace if the settings are applied
 | 
			
		||||
				err = netNSContainer.Do(func(_ ns.NetNS) error {
 | 
			
		||||
					defer GinkgoRecover()
 | 
			
		||||
					i, err := net.InterfaceByName(intName1)
 | 
			
		||||
					Expect(err).To(BeNil())
 | 
			
		||||
					Expect(i.Name).To(Equal(intName1))
 | 
			
		||||
					Expect(i.HardwareAddr).To(Equal(net.HardwareAddr(macInt1)))
 | 
			
		||||
					addrs, err := i.Addrs()
 | 
			
		||||
					Expect(err).To(BeNil())
 | 
			
		||||
					// we still have the ipv6 link local address
 | 
			
		||||
					Expect(addrs).To(HaveLen(1))
 | 
			
		||||
					addr, ok := addrs[0].(*net.IPNet)
 | 
			
		||||
					Expect(ok).To(BeTrue(), "cast address to ipnet")
 | 
			
		||||
					// make sure we are link local
 | 
			
		||||
					Expect(addr.IP.IsLinkLocalUnicast()).To(BeTrue(), "ip is link local address")
 | 
			
		||||
 | 
			
		||||
					// check loopback adapter
 | 
			
		||||
					i, err = net.InterfaceByName("lo")
 | 
			
		||||
					Expect(err).To(BeNil())
 | 
			
		||||
					Expect(i.Name).To(Equal("lo"))
 | 
			
		||||
					Expect(i.Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
 | 
			
		||||
					Expect(i.Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
 | 
			
		||||
					return nil
 | 
			
		||||
				})
 | 
			
		||||
				Expect(err).To(BeNil())
 | 
			
		||||
 | 
			
		||||
				err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts))
 | 
			
		||||
				Expect(err).To(BeNil())
 | 
			
		||||
				logString := logBuffer.String()
 | 
			
		||||
				Expect(logString).To(BeEmpty())
 | 
			
		||||
 | 
			
		||||
				// check in the container namespace that the interface is removed
 | 
			
		||||
				err = netNSContainer.Do(func(_ ns.NetNS) error {
 | 
			
		||||
					defer GinkgoRecover()
 | 
			
		||||
					_, err := net.InterfaceByName(intName1)
 | 
			
		||||
					Expect(err).To(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
					// check that only the loopback adapter is left
 | 
			
		||||
					ints, err := net.Interfaces()
 | 
			
		||||
					Expect(err).To(BeNil())
 | 
			
		||||
					Expect(ints).To(HaveLen(1))
 | 
			
		||||
					Expect(ints[0].Name).To(Equal("lo"))
 | 
			
		||||
					Expect(ints[0].Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
 | 
			
		||||
					Expect(ints[0].Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
 | 
			
		||||
 | 
			
		||||
					return nil
 | 
			
		||||
				})
 | 
			
		||||
				Expect(err).To(BeNil())
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	Context("network setup test with networks from disk", func() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,9 @@ func CreateBridge(n NetUtil, network *types.Network, usedNetworks []*net.IPNet,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if network.IPAMOptions[types.Driver] != types.DHCPIPAMDriver {
 | 
			
		||||
	ipamDriver := network.IPAMOptions[types.Driver]
 | 
			
		||||
	// also do this when the driver is unset
 | 
			
		||||
	if ipamDriver == "" || ipamDriver == types.HostLocalIPAMDriver {
 | 
			
		||||
		if len(network.Subnets) == 0 {
 | 
			
		||||
			freeSubnet, err := GetFreeIPv4NetworkSubnet(usedNetworks, subnetPools)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,6 +67,11 @@ func (n *netavarkNetwork) networkCreate(newNetwork *types.Network, defaultNet bo
 | 
			
		|||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = validateIPAMDriver(newNetwork)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Only get the used networks for validation if we do not create the default network.
 | 
			
		||||
	// The default network should not be validated against used subnets, we have to ensure
 | 
			
		||||
	// that this network can always be created even when a subnet is already used on the host.
 | 
			
		||||
| 
						 | 
				
			
			@ -153,10 +158,19 @@ func createMacvlan(network *types.Network) error {
 | 
			
		|||
			return errors.Errorf("parent interface %s does not exist", network.NetworkInterface)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(network.Subnets) == 0 {
 | 
			
		||||
		return errors.Errorf("macvlan driver needs at least one subnet specified, DHCP is not supported with netavark")
 | 
			
		||||
 | 
			
		||||
	// we already validated the drivers before so we just have to set the default here
 | 
			
		||||
	switch network.IPAMOptions[types.Driver] {
 | 
			
		||||
	case "":
 | 
			
		||||
		if len(network.Subnets) == 0 {
 | 
			
		||||
			return errors.Errorf("macvlan driver needs at least one subnet specified, DHCP is not yet supported with netavark")
 | 
			
		||||
		}
 | 
			
		||||
		network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver
 | 
			
		||||
	case types.HostLocalIPAMDriver:
 | 
			
		||||
		if len(network.Subnets) == 0 {
 | 
			
		||||
			return errors.Errorf("macvlan driver needs at least one subnet specified, when the host-local ipam driver is set")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver
 | 
			
		||||
 | 
			
		||||
	// validate the given options, we do not need them but just check to make sure they are valid
 | 
			
		||||
	for key, value := range network.Options {
 | 
			
		||||
| 
						 | 
				
			
			@ -246,3 +260,19 @@ func (n *netavarkNetwork) NetworkInspect(nameOrID string) (types.Network, error)
 | 
			
		|||
	}
 | 
			
		||||
	return *network, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateIPAMDriver(n *types.Network) error {
 | 
			
		||||
	ipamDriver := n.IPAMOptions[types.Driver]
 | 
			
		||||
	switch ipamDriver {
 | 
			
		||||
	case "", types.HostLocalIPAMDriver:
 | 
			
		||||
	case types.NoneIPAMDriver:
 | 
			
		||||
		if len(n.Subnets) > 0 {
 | 
			
		||||
			return errors.New("none ipam driver is set but subnets are given")
 | 
			
		||||
		}
 | 
			
		||||
	case types.DHCPIPAMDriver:
 | 
			
		||||
		return errors.New("dhcp ipam driver is not yet supported with netavark")
 | 
			
		||||
	default:
 | 
			
		||||
		return errors.Errorf("unsupported ipam driver %q", ipamDriver)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -794,7 +794,7 @@ var _ = Describe("Config", func() {
 | 
			
		|||
			network := types.Network{Driver: "macvlan"}
 | 
			
		||||
			_, err := libpodNet.NetworkCreate(network)
 | 
			
		||||
			Expect(err).To(HaveOccurred())
 | 
			
		||||
			Expect(err.Error()).To(Equal("macvlan driver needs at least one subnet specified, DHCP is not supported with netavark"))
 | 
			
		||||
			Expect(err.Error()).To(Equal("macvlan driver needs at least one subnet specified, DHCP is not yet supported with netavark"))
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("create macvlan config with internal", func() {
 | 
			
		||||
| 
						 | 
				
			
			@ -957,6 +957,69 @@ var _ = Describe("Config", func() {
 | 
			
		|||
			Expect(network1.Options).To(HaveKeyWithValue("mtu", "9000"))
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("create bridge config with none ipam driver", func() {
 | 
			
		||||
			network := types.Network{
 | 
			
		||||
				Driver: "bridge",
 | 
			
		||||
				IPAMOptions: map[string]string{
 | 
			
		||||
					"driver": "none",
 | 
			
		||||
				},
 | 
			
		||||
			}
 | 
			
		||||
			network1, err := libpodNet.NetworkCreate(network)
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
			Expect(network1.Driver).To(Equal("bridge"))
 | 
			
		||||
			Expect(network1.IPAMOptions).ToNot(BeEmpty())
 | 
			
		||||
			Expect(network1.IPAMOptions).To(HaveKeyWithValue("driver", "none"))
 | 
			
		||||
			Expect(network1.Subnets).To(HaveLen(0))
 | 
			
		||||
 | 
			
		||||
			// reload configs from disk
 | 
			
		||||
			libpodNet, err = getNetworkInterface(networkConfDir)
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
 | 
			
		||||
			network2, err := libpodNet.NetworkInspect(network1.Name)
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
			EqualNetwork(network2, network1)
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("create bridge config with none ipam driver and subnets", func() {
 | 
			
		||||
			subnet := "10.1.0.0/24"
 | 
			
		||||
			n, _ := types.ParseCIDR(subnet)
 | 
			
		||||
			network := types.Network{
 | 
			
		||||
				Driver: "bridge",
 | 
			
		||||
				IPAMOptions: map[string]string{
 | 
			
		||||
					"driver": "none",
 | 
			
		||||
				},
 | 
			
		||||
				Subnets: []types.Subnet{
 | 
			
		||||
					{Subnet: n},
 | 
			
		||||
				},
 | 
			
		||||
			}
 | 
			
		||||
			_, err := libpodNet.NetworkCreate(network)
 | 
			
		||||
			Expect(err).To(HaveOccurred())
 | 
			
		||||
			Expect(err.Error()).To(Equal("none ipam driver is set but subnets are given"))
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("create macvlan config with none ipam driver", func() {
 | 
			
		||||
			network := types.Network{
 | 
			
		||||
				Driver: "macvlan",
 | 
			
		||||
				IPAMOptions: map[string]string{
 | 
			
		||||
					"driver": "none",
 | 
			
		||||
				},
 | 
			
		||||
			}
 | 
			
		||||
			network1, err := libpodNet.NetworkCreate(network)
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
			Expect(network1.Driver).To(Equal("macvlan"))
 | 
			
		||||
			Expect(network1.IPAMOptions).ToNot(BeEmpty())
 | 
			
		||||
			Expect(network1.IPAMOptions).To(HaveKeyWithValue("driver", "none"))
 | 
			
		||||
			Expect(network1.Subnets).To(HaveLen(0))
 | 
			
		||||
 | 
			
		||||
			// reload configs from disk
 | 
			
		||||
			libpodNet, err = getNetworkInterface(networkConfDir)
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
 | 
			
		||||
			network2, err := libpodNet.NetworkInspect(network1.Name)
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
			EqualNetwork(network2, network1)
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	Context("network load valid existing ones", func() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -399,10 +399,10 @@ var _ = Describe("IPAM", func() {
 | 
			
		|||
		}
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	It("ipam with dhcp driver should not set ips", func() {
 | 
			
		||||
	It("ipam with none driver should not set ips", func() {
 | 
			
		||||
		network, err := networkInterface.NetworkCreate(types.Network{
 | 
			
		||||
			IPAMOptions: map[string]string{
 | 
			
		||||
				"driver": types.DHCPIPAMDriver,
 | 
			
		||||
				"driver": types.NoneIPAMDriver,
 | 
			
		||||
			},
 | 
			
		||||
		})
 | 
			
		||||
		Expect(err).ToNot(HaveOccurred())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -700,6 +700,89 @@ var _ = Describe("run netavark", func() {
 | 
			
		|||
			Expect(err.Error()).To(ContainSubstring("interface eth0 already exists on container namespace"))
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	It("setup ipam driver none network", func() {
 | 
			
		||||
		runTest(func() {
 | 
			
		||||
			network := types.Network{
 | 
			
		||||
				IPAMOptions: map[string]string{
 | 
			
		||||
					types.Driver: types.NoneIPAMDriver,
 | 
			
		||||
				},
 | 
			
		||||
			}
 | 
			
		||||
			network1, err := libpodNet.NetworkCreate(network)
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
 | 
			
		||||
			intName1 := "eth0"
 | 
			
		||||
			netName1 := network1.Name
 | 
			
		||||
 | 
			
		||||
			setupOpts := types.SetupOptions{
 | 
			
		||||
				NetworkOptions: types.NetworkOptions{
 | 
			
		||||
					ContainerID: stringid.GenerateNonCryptoID(),
 | 
			
		||||
					Networks: map[string]types.PerNetworkOptions{
 | 
			
		||||
						netName1: {
 | 
			
		||||
							InterfaceName: intName1,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
			Expect(res).To(HaveLen(1))
 | 
			
		||||
 | 
			
		||||
			Expect(res).To(HaveKey(netName1))
 | 
			
		||||
			Expect(res[netName1].Interfaces).To(HaveKey(intName1))
 | 
			
		||||
			Expect(res[netName1].Interfaces[intName1].Subnets).To(HaveLen(0))
 | 
			
		||||
			macInt1 := res[netName1].Interfaces[intName1].MacAddress
 | 
			
		||||
			Expect(macInt1).To(HaveLen(6))
 | 
			
		||||
 | 
			
		||||
			// check in the container namespace if the settings are applied
 | 
			
		||||
			err = netNSContainer.Do(func(_ ns.NetNS) error {
 | 
			
		||||
				defer GinkgoRecover()
 | 
			
		||||
				i, err := net.InterfaceByName(intName1)
 | 
			
		||||
				Expect(err).To(BeNil())
 | 
			
		||||
				Expect(i.Name).To(Equal(intName1))
 | 
			
		||||
				Expect(i.HardwareAddr).To(Equal(net.HardwareAddr(macInt1)))
 | 
			
		||||
				addrs, err := i.Addrs()
 | 
			
		||||
				Expect(err).To(BeNil())
 | 
			
		||||
				// we still have the ipv6 link local address
 | 
			
		||||
				Expect(addrs).To(HaveLen(1))
 | 
			
		||||
				addr, ok := addrs[0].(*net.IPNet)
 | 
			
		||||
				Expect(ok).To(BeTrue(), "cast address to ipnet")
 | 
			
		||||
				// make sure we are link local
 | 
			
		||||
				Expect(addr.IP.IsLinkLocalUnicast()).To(BeTrue(), "ip is link local address")
 | 
			
		||||
 | 
			
		||||
				// check loopback adapter
 | 
			
		||||
				i, err = net.InterfaceByName("lo")
 | 
			
		||||
				Expect(err).To(BeNil())
 | 
			
		||||
				Expect(i.Name).To(Equal("lo"))
 | 
			
		||||
				Expect(i.Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
 | 
			
		||||
				Expect(i.Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
 | 
			
		||||
				return nil
 | 
			
		||||
			})
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
 | 
			
		||||
			err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts))
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
 | 
			
		||||
			// check in the container namespace that the interface is removed
 | 
			
		||||
			err = netNSContainer.Do(func(_ ns.NetNS) error {
 | 
			
		||||
				defer GinkgoRecover()
 | 
			
		||||
				_, err := net.InterfaceByName(intName1)
 | 
			
		||||
				Expect(err).To(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
				// check that only the loopback adapter is left
 | 
			
		||||
				ints, err := net.Interfaces()
 | 
			
		||||
				Expect(err).To(BeNil())
 | 
			
		||||
				Expect(ints).To(HaveLen(1))
 | 
			
		||||
				Expect(ints[0].Name).To(Equal("lo"))
 | 
			
		||||
				Expect(ints[0].Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
 | 
			
		||||
				Expect(ints[0].Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
 | 
			
		||||
 | 
			
		||||
				return nil
 | 
			
		||||
			})
 | 
			
		||||
			Expect(err).To(BeNil())
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
func runNetListener(wg *sync.WaitGroup, protocol, ip string, port int, expectedData string) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,10 +12,12 @@ const (
 | 
			
		|||
 | 
			
		||||
	// IPAM drivers
 | 
			
		||||
	Driver = "driver"
 | 
			
		||||
	// HostLocalIPAMDriver store the ip
 | 
			
		||||
	// HostLocalIPAMDriver store the ip locally in a db
 | 
			
		||||
	HostLocalIPAMDriver = "host-local"
 | 
			
		||||
	// DHCPIPAMDriver get subnet and ip from dhcp server
 | 
			
		||||
	DHCPIPAMDriver = "dhcp"
 | 
			
		||||
	// NoneIPAMDriver do not provide ipam management
 | 
			
		||||
	NoneIPAMDriver = "none"
 | 
			
		||||
 | 
			
		||||
	// DefaultSubnet is the name that will be used for the default CNI network.
 | 
			
		||||
	DefaultNetworkName = "podman"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue