Skip to content

Commit

Permalink
Merge pull request #1390 from Luap99/netavark-ipvlan
Browse files Browse the repository at this point in the history
Netavark add ipvlan support
  • Loading branch information
openshift-merge-robot committed Mar 31, 2023
2 parents ddf389e + 735fd0b commit a0cf73f
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 9 deletions.
46 changes: 38 additions & 8 deletions libnetwork/netavark/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@ func (n *netavarkNetwork) networkCreate(newNetwork *types.Network, defaultNet bo
return nil, fmt.Errorf("unsupported bridge network option %s", key)
}
}
case types.MacVLANNetworkDriver:
err = createMacvlan(newNetwork)
case types.MacVLANNetworkDriver, types.IPVLANNetworkDriver:
err = createIpvlanOrMacvlan(newNetwork)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -245,7 +245,10 @@ func (n *netavarkNetwork) networkCreate(newNetwork *types.Network, defaultNet bo
return newNetwork, nil
}

func createMacvlan(network *types.Network) error {
// ipvlan shares the same mac address so supporting DHCP is not really possible
var errIpvlanNoDHCP = errors.New("ipam driver dhcp is not supported with ipvlan")

func createIpvlanOrMacvlan(network *types.Network) error {
if network.NetworkInterface != "" {
interfaceNames, err := internalutil.GetLiveNetworkNames()
if err != nil {
Expand All @@ -256,6 +259,12 @@ func createMacvlan(network *types.Network) error {
}
}

driver := network.Driver
isMacVlan := true
if driver == types.IPVLANNetworkDriver {
isMacVlan = false
}

// always turn dns off with macvlan, it is not implemented in netavark
// and makes little sense to support with macvlan
// see https://github.com/containers/netavark/pull/467
Expand All @@ -264,27 +273,48 @@ func createMacvlan(network *types.Network) error {
// we already validated the drivers before so we just have to set the default here
switch network.IPAMOptions[types.Driver] {
case "":
network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver
if len(network.Subnets) == 0 {
// if no subnets and no driver choose dhcp
network.IPAMOptions[types.Driver] = types.DHCPIPAMDriver
if !isMacVlan {
return errIpvlanNoDHCP
}
} else {
network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver
}
case types.HostLocalIPAMDriver:
if len(network.Subnets) == 0 {
return fmt.Errorf("macvlan driver needs at least one subnet specified, when the host-local ipam driver is set")
return fmt.Errorf("%s driver needs at least one subnet specified when the host-local ipam driver is set", driver)
}
case types.DHCPIPAMDriver:
if !isMacVlan {
return errIpvlanNoDHCP
}
if len(network.Subnets) > 0 {
return fmt.Errorf("ipam driver dhcp set but subnets are 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 {
switch key {
case types.ModeOption:
if !util.StringInSlice(value, types.ValidMacVLANModes) {
return fmt.Errorf("unknown macvlan mode %q", value)
if isMacVlan {
if !util.StringInSlice(value, types.ValidMacVLANModes) {
return fmt.Errorf("unknown macvlan mode %q", value)
}
} else {
if !util.StringInSlice(value, types.ValidIPVLANModes) {
return fmt.Errorf("unknown ipvlan mode %q", value)
}
}
case types.MTUOption:
_, err := internalutil.ParseMTU(value)
if err != nil {
return err
}
default:
return fmt.Errorf("unsupported macvlan network option %s", key)
return fmt.Errorf("unsupported %s network option %s", driver, key)
}
}
return nil
Expand Down
103 changes: 102 additions & 1 deletion libnetwork/netavark/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -996,8 +996,19 @@ var _ = Describe("Config", func() {

It("create macvlan config without subnet", func() {
network := types.Network{Driver: "macvlan"}
_, err := libpodNet.NetworkCreate(network, nil)
network1, err := libpodNet.NetworkCreate(network, nil)
Expect(err).ToNot(HaveOccurred())
Expect(network1.IPAMOptions[types.Driver]).To(Equal(types.DHCPIPAMDriver))
})

It("create macvlan config without subnet and host-local", func() {
network := types.Network{
Driver: "macvlan",
IPAMOptions: map[string]string{types.Driver: types.HostLocalIPAMDriver},
}
_, err := libpodNet.NetworkCreate(network, nil)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("macvlan driver needs at least one subnet specified when the host-local ipam driver is set"))
})

It("create macvlan config with internal", func() {
Expand Down Expand Up @@ -1226,6 +1237,96 @@ var _ = Describe("Config", func() {
EqualNetwork(network2, network1)
})

It("create ipvlan config without subnet", func() {
network := types.Network{Driver: "ipvlan"}
_, err := libpodNet.NetworkCreate(network, nil)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("ipam driver dhcp is not supported with ipvlan"))
})

It("create ipvlan config without subnet and host-local", func() {
network := types.Network{
Driver: "ipvlan",
IPAMOptions: map[string]string{types.Driver: types.HostLocalIPAMDriver},
}
_, err := libpodNet.NetworkCreate(network, nil)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("ipvlan driver needs at least one subnet specified when the host-local ipam driver is set"))
})

It("create ipvlan config with subnet", func() {
subnet := "10.1.0.0/24"
n, _ := types.ParseCIDR(subnet)
network := types.Network{
Driver: "ipvlan",
Subnets: []types.Subnet{
{Subnet: n},
},
}
network1, err := libpodNet.NetworkCreate(network, nil)
Expect(err).To(BeNil())
Expect(network1.Name).ToNot(BeEmpty())
path := filepath.Join(networkConfDir, network1.Name+".json")
Expect(path).To(BeARegularFile())
Expect(network1.ID).ToNot(BeEmpty())
Expect(network1.Driver).To(Equal("ipvlan"))
Expect(network1.NetworkInterface).To(Equal(""))
Expect(network1.Labels).To(BeEmpty())
Expect(network1.Options).To(BeEmpty())
Expect(network1.Subnets).To(HaveLen(1))
Expect(network1.Subnets[0].Subnet.String()).To(Equal(subnet))
Expect(network1.Subnets[0].Gateway.String()).To(Equal("10.1.0.1"))
Expect(network1.Subnets[0].LeaseRange).To(BeNil())
Expect(network1.DNSEnabled).To(BeFalse())
Expect(network1.Internal).To(BeFalse())
Expect(network1.IPAMOptions).To(HaveKeyWithValue("driver", "host-local"))
})

It("create ipvlan config with dhcp driver", func() {
network := types.Network{
Driver: "ipvlan",
IPAMOptions: map[string]string{types.Driver: types.DHCPIPAMDriver},
}
_, err := libpodNet.NetworkCreate(network, nil)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("ipam driver dhcp is not supported with ipvlan"))
})

It("create ipvlan config with mode", func() {
subnet := "10.1.0.0/24"
n, _ := types.ParseCIDR(subnet)
network := types.Network{
Driver: "ipvlan",
Subnets: []types.Subnet{
{Subnet: n},
},
Options: map[string]string{
types.ModeOption: "l2",
},
}
network1, err := libpodNet.NetworkCreate(network, nil)
Expect(err).To(BeNil())
Expect(network1.Name).ToNot(BeEmpty())
Expect(network1.Options).To(HaveKeyWithValue("mode", "l2"))
})

It("create ipvlan config with invalid mode", func() {
subnet := "10.1.0.0/24"
n, _ := types.ParseCIDR(subnet)
network := types.Network{
Driver: "ipvlan",
Subnets: []types.Subnet{
{Subnet: n},
},
Options: map[string]string{
types.ModeOption: "abc",
},
}
_, err := libpodNet.NetworkCreate(network, nil)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("unknown ipvlan mode \"abc\""))
})

It("create network with isolate option", func() {
for _, val := range []string{"true", "1"} {
network := types.Network{
Expand Down

0 comments on commit a0cf73f

Please sign in to comment.