Merge pull request #967 from Luap99/ipam-none
libnetwork: allow new none ipam driver
This commit is contained in:
commit
8c96512c34
|
|
@ -128,21 +128,12 @@ 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
|
||||
}
|
||||
|
||||
if ipam.PluginType != types.HostLocalIPAMDriver {
|
||||
// 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
|
||||
}
|
||||
|
||||
case types.HostLocalIPAMDriver:
|
||||
network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver
|
||||
for _, r := range ipam.Ranges {
|
||||
for _, ipam := range r {
|
||||
|
|
@ -199,6 +190,15 @@ func convertIPAMConfToNetwork(network *types.Network, ipam *ipamConfig, confPath
|
|||
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)
|
||||
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,48 +260,22 @@ 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)
|
||||
opts, err := parseOptions(network.Options, network.Driver)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
isGateway := true
|
||||
ipMasq := true
|
||||
if network.Internal {
|
||||
|
|
@ -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,12 +145,14 @@ func newHostLocalBridge(name string, isGateWay, ipMasq bool, mtu, vlan int, ipam
|
|||
MTU: mtu,
|
||||
HairpinMode: true,
|
||||
Vlan: vlan,
|
||||
IPAM: *ipamConf,
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
if network.Internal {
|
||||
return errors.New("internal is not supported with macvlan and dhcp ipam driver")
|
||||
}
|
||||
} 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,6 +125,17 @@ func CNIResultToStatus(res cnitypes.Result) (types.StatusBlock, error) {
|
|||
result.DNSSearchDomains = cniResult.DNS.Search
|
||||
|
||||
interfaces := make(map[string]types.NetInterface)
|
||||
for intIndex, netInterface := range cniResult.Interfaces {
|
||||
// we are only interested about interfaces in the container namespace
|
||||
if netInterface.Sandbox == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
mac, err := net.ParseMAC(netInterface.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
|
||||
|
|
@ -133,26 +144,18 @@ func CNIResultToStatus(res cnitypes.Result) (types.StatusBlock, error) {
|
|||
if len(cniResult.Interfaces) <= *ip.Interface {
|
||||
return result, errors.Errorf("invalid cni result, interface index %d out of range", *ip.Interface)
|
||||
}
|
||||
cniInt := cniResult.Interfaces[*ip.Interface]
|
||||
netInt, ok := interfaces[cniInt.Name]
|
||||
if ok {
|
||||
netInt.Subnets = append(netInt.Subnets, types.NetAddress{
|
||||
|
||||
// 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[cniInt.Name] = netInt
|
||||
} else {
|
||||
mac, err := net.ParseMAC(cniInt.Mac)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
interfaces[cniInt.Name] = types.NetInterface{
|
||||
}
|
||||
interfaces[netInterface.Name] = types.NetInterface{
|
||||
MacAddress: types.HardwareAddr(mac),
|
||||
Subnets: []types.NetAddress{{
|
||||
IPNet: types.IPNet{IPNet: ip.Address},
|
||||
Gateway: ip.Gateway,
|
||||
}},
|
||||
}
|
||||
Subnets: subnets,
|
||||
}
|
||||
}
|
||||
result.Interfaces = interfaces
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 supported with netavark")
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
// 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