From c20f61148cfc7c51f72bf266e154d1903db68c6a Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Thu, 16 Sep 2021 14:03:49 +0200 Subject: CNI: network create support macvlan modes Support setting the macvlan mode with `podman network create -d macvlan --opt mode=bridge`. This will correctly set the specified macvlan mode in the cni conflist file. Signed-off-by: Paul Holzinger --- docs/source/markdown/podman-network-create.1.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'docs/source') diff --git a/docs/source/markdown/podman-network-create.1.md b/docs/source/markdown/podman-network-create.1.md index 816dd53ea..1eb96be11 100644 --- a/docs/source/markdown/podman-network-create.1.md +++ b/docs/source/markdown/podman-network-create.1.md @@ -32,9 +32,14 @@ As rootless the `macvlan` driver has no access to the host network interfaces be Set driver specific options. -For the `bridge` driver the following options are supported: `mtu` and `vlan`. -The `mtu` option sets the Maximum Transmission Unit (MTU) and takes an integer value. -The `vlan` option assign VLAN tag and enables vlan\_filtering. Defaults to none. +All drivers accept the `mtu` option. The `mtu` option sets the Maximum Transmission Unit (MTU) and takes an integer value. + +Additionally the `bridge` driver supports the following option: +- `vlan`: This option assign VLAN tag and enables vlan\_filtering. Defaults to none. + +The `macvlan` driver supports the following options: +- `parent`: The host device which should be used for the macvlan interface. Defaults to the default route interface. +- `mode`: This options sets the specified macvlan mode on the interface. Supported values are `bridge`, `private`, `vepa`, `passthru`. Defaults to `bridge`. #### **--gateway** -- cgit v1.2.3-54-g00ecf From aee0ab98cd3e3b552ac6eb0e7534a9f548b3109f Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Thu, 16 Sep 2021 14:51:51 +0200 Subject: CNI: add ipvlan driver Add support for the ipvlan cni plugin. This allows us to create, inspect and list ipvlan networks correctly. Fixes #10478 Signed-off-by: Paul Holzinger --- cmd/podman/common/completion.go | 4 +- docs/source/markdown/podman-network-create.1.md | 10 ++-- libpod/network/cni/cni_conversion.go | 42 +++++++++------ libpod/network/cni/cni_types.go | 12 ++--- libpod/network/cni/config.go | 6 +-- libpod/network/cni/config_test.go | 69 +++++++++++++++++++++++++ libpod/network/cni/network.go | 2 +- libpod/network/types/const.go | 2 + 8 files changed, 116 insertions(+), 31 deletions(-) (limited to 'docs/source') diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go index 193f09e85..2ea5fa10f 100644 --- a/cmd/podman/common/completion.go +++ b/cmd/podman/common/completion.go @@ -1111,7 +1111,7 @@ func AutocompleteManifestFormat(cmd *cobra.Command, args []string, toComplete st // AutocompleteNetworkDriver - Autocomplete network driver option. // -> "bridge", "macvlan" func AutocompleteNetworkDriver(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - drivers := []string{types.BridgeNetworkDriver, types.MacVLANNetworkDriver} + drivers := []string{types.BridgeNetworkDriver, types.MacVLANNetworkDriver, types.IPVLANNetworkDriver} return drivers, cobra.ShellCompDirectiveNoFileComp } @@ -1257,7 +1257,7 @@ func AutocompleteNetworkFilters(cmd *cobra.Command, args []string, toComplete st "id=": func(s string) ([]string, cobra.ShellCompDirective) { return getNetworks(cmd, s, completeIDs) }, "label=": nil, "driver=": func(_ string) ([]string, cobra.ShellCompDirective) { - return []string{types.BridgeNetworkDriver, types.MacVLANNetworkDriver}, cobra.ShellCompDirectiveNoFileComp + return []string{types.BridgeNetworkDriver, types.MacVLANNetworkDriver, types.IPVLANNetworkDriver}, cobra.ShellCompDirectiveNoFileComp }, "until=": nil, } diff --git a/docs/source/markdown/podman-network-create.1.md b/docs/source/markdown/podman-network-create.1.md index 1eb96be11..d48509581 100644 --- a/docs/source/markdown/podman-network-create.1.md +++ b/docs/source/markdown/podman-network-create.1.md @@ -25,8 +25,8 @@ resolution. #### **--driver**, **-d** -Driver to manage the network. Currently `bridge` and `macvlan` is supported. Defaults to `bridge`. -As rootless the `macvlan` driver has no access to the host network interfaces because rootless networking requires a separate network namespace. +Driver to manage the network. Currently `bridge`, `macvlan` and `ipvlan` are supported. Defaults to `bridge`. +As rootless the `macvlan` and `ipvlan` driver have no access to the host network interfaces because rootless networking requires a separate network namespace. #### **--opt**=*option*, **-o** @@ -37,9 +37,11 @@ All drivers accept the `mtu` option. The `mtu` option sets the Maximum Transmiss Additionally the `bridge` driver supports the following option: - `vlan`: This option assign VLAN tag and enables vlan\_filtering. Defaults to none. -The `macvlan` driver supports the following options: +The `macvlan` and `ipvlan` driver support the following options: - `parent`: The host device which should be used for the macvlan interface. Defaults to the default route interface. -- `mode`: This options sets the specified macvlan mode on the interface. Supported values are `bridge`, `private`, `vepa`, `passthru`. Defaults to `bridge`. +- `mode`: This options sets the specified ip/macvlan mode on the interface. + - Supported values for `macvlan` are `bridge`, `private`, `vepa`, `passthru`. Defaults to `bridge`. + - Supported values for `ipvlan` are `l2`, `l3`, `l3s`. Defaults to `l2`. #### **--gateway** diff --git a/libpod/network/cni/cni_conversion.go b/libpod/network/cni/cni_conversion.go index 32dcc62de..d69dd7eb3 100644 --- a/libpod/network/cni/cni_conversion.go +++ b/libpod/network/cni/cni_conversion.go @@ -81,24 +81,24 @@ func createNetworkFromCNIConfigList(conf *libcni.NetworkConfigList, confPath str return nil, err } - case types.MacVLANNetworkDriver: - var macvlan macVLANConfig - err := json.Unmarshal(firstPlugin.Bytes, &macvlan) + case types.MacVLANNetworkDriver, types.IPVLANNetworkDriver: + var vlan VLANConfig + err := json.Unmarshal(firstPlugin.Bytes, &vlan) if err != nil { return nil, errors.Wrapf(err, "failed to unmarshal the macvlan plugin config in %s", confPath) } - network.NetworkInterface = macvlan.Master + network.NetworkInterface = vlan.Master // set network options - if macvlan.MTU != 0 { - network.Options["mtu"] = strconv.Itoa(macvlan.MTU) + if vlan.MTU != 0 { + network.Options["mtu"] = strconv.Itoa(vlan.MTU) } - if macvlan.Mode != "" { - network.Options["mode"] = macvlan.Mode + if vlan.Mode != "" { + network.Options["mode"] = vlan.Mode } - err = convertIPAMConfToNetwork(&network, macvlan.IPAM, confPath) + err = convertIPAMConfToNetwork(&network, vlan.IPAM, confPath) if err != nil { return nil, err } @@ -211,7 +211,7 @@ func getNetworkArgsFromConfList(args map[string]interface{}, argType string) map return result } } - return nil + return map[string]string{} } // createCNIConfigListFromNetwork will create a cni config file from the given network. @@ -241,7 +241,7 @@ func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writ vlan := 0 mtu := 0 - macvlanMode := "" + vlanPluginMode := "" for k, v := range network.Options { switch k { case "mtu": @@ -257,10 +257,19 @@ func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writ } case "mode": - if !pkgutil.StringInSlice(v, []string{"", "bridge", "private", "vepa", "passthru"}) { - return nil, "", errors.Errorf("unknown macvlan mode %q", v) + switch network.Driver { + case types.MacVLANNetworkDriver: + if !pkgutil.StringInSlice(v, []string{"", "bridge", "private", "vepa", "passthru"}) { + return nil, "", errors.Errorf("unknown macvlan mode %q", v) + } + case types.IPVLANNetworkDriver: + if !pkgutil.StringInSlice(v, []string{"", "l2", "l3", "l3s"}) { + return nil, "", errors.Errorf("unknown ipvlan mode %q", v) + } + default: + return nil, "", errors.Errorf("cannot set option \"mode\" with driver %q", network.Driver) } - macvlanMode = v + vlanPluginMode = v default: return nil, "", errors.Errorf("unsupported network option %s", k) @@ -292,7 +301,10 @@ func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writ } case types.MacVLANNetworkDriver: - plugins = append(plugins, newMacVLANPlugin(network.NetworkInterface, macvlanMode, mtu, ipamConf)) + plugins = append(plugins, newVLANPlugin(types.MacVLANNetworkDriver, network.NetworkInterface, vlanPluginMode, mtu, ipamConf)) + + case types.IPVLANNetworkDriver: + plugins = append(plugins, newVLANPlugin(types.IPVLANNetworkDriver, network.NetworkInterface, vlanPluginMode, mtu, ipamConf)) default: return nil, "", errors.Errorf("driver %q is not supported by cni", network.Driver) diff --git a/libpod/network/cni/cni_types.go b/libpod/network/cni/cni_types.go index 0a7bb066e..fbf917c2d 100644 --- a/libpod/network/cni/cni_types.go +++ b/libpod/network/cni/cni_types.go @@ -82,8 +82,8 @@ type portMapConfig struct { Capabilities map[string]bool `json:"capabilities"` } -// macVLANConfig describes the macvlan config -type macVLANConfig struct { +// VLANConfig describes the macvlan config +type VLANConfig struct { PluginType string `json:"type"` Master string `json:"master"` IPAM ipamConfig `json:"ipam"` @@ -260,10 +260,10 @@ func hasDNSNamePlugin(paths []string) bool { return false } -// newMacVLANPlugin creates a macvlanconfig with a given device name -func newMacVLANPlugin(device, mode string, mtu int, ipam ipamConfig) macVLANConfig { - m := macVLANConfig{ - PluginType: "macvlan", +// newVLANPlugin creates a macvlanconfig with a given device name +func newVLANPlugin(pluginType, device, mode string, mtu int, ipam ipamConfig) VLANConfig { + m := VLANConfig{ + PluginType: pluginType, IPAM: ipam, } if mtu > 0 { diff --git a/libpod/network/cni/config.go b/libpod/network/cni/config.go index d31cd3002..2a6ad8eb3 100644 --- a/libpod/network/cni/config.go +++ b/libpod/network/cni/config.go @@ -100,8 +100,8 @@ func (n *cniNetwork) networkCreate(newNetwork types.Network, defaultNet bool) (* if err != nil { return nil, err } - case types.MacVLANNetworkDriver: - err = createMacVLAN(&newNetwork) + case types.MacVLANNetworkDriver, types.IPVLANNetworkDriver: + err = createIPMACVLAN(&newNetwork) if err != nil { return nil, err } @@ -214,7 +214,7 @@ func (n *cniNetwork) NetworkInspect(nameOrID string) (types.Network, error) { return *network.libpodNet, nil } -func createMacVLAN(network *types.Network) error { +func createIPMACVLAN(network *types.Network) error { if network.Internal { return errors.New("internal is not supported with macvlan") } diff --git a/libpod/network/cni/config_test.go b/libpod/network/cni/config_test.go index 62b6ef837..a0a0ea1af 100644 --- a/libpod/network/cni/config_test.go +++ b/libpod/network/cni/config_test.go @@ -250,6 +250,34 @@ var _ = Describe("Config", func() { grepInFile(path, `"type": "host-local"`) }) + 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) + Expect(err).To(BeNil()) + Expect(network1.Name).ToNot(BeEmpty()) + path := filepath.Join(cniConfDir, network1.Name+".conflist") + Expect(path).To(BeARegularFile()) + Expect(network1.ID).ToNot(BeEmpty()) + Expect(network1.Driver).To(Equal("ipvlan")) + 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")) + grepInFile(path, `"type": "host-local"`) + }) + It("create macvlan config with mode", func() { for _, mode := range []string{"bridge", "private", "vepa", "passthru"} { network := types.Network{ @@ -303,6 +331,47 @@ var _ = Describe("Config", func() { Expect(err.Error()).To(ContainSubstring("internal is not supported with macvlan")) }) + It("create ipvlan config with mode", func() { + for _, mode := range []string{"l2", "l3", "l3s"} { + network := types.Network{ + Driver: "ipvlan", + Options: map[string]string{ + "mode": mode, + }, + } + network1, err := libpodNet.NetworkCreate(network) + Expect(err).To(BeNil()) + Expect(network1.Name).ToNot(BeEmpty()) + path := filepath.Join(cniConfDir, network1.Name+".conflist") + Expect(path).To(BeARegularFile()) + Expect(network1.Driver).To(Equal("ipvlan")) + Expect(network1.Options).To(HaveKeyWithValue("mode", mode)) + Expect(network1.IPAMOptions).ToNot(BeEmpty()) + Expect(network1.IPAMOptions).To(HaveKeyWithValue("driver", "dhcp")) + grepInFile(path, `"mode": "`+mode+`"`) + + // reload configs from disk + libpodNet, err = getNetworkInterface(cniConfDir, false) + Expect(err).To(BeNil()) + + network2, err := libpodNet.NetworkInspect(network1.Name) + Expect(err).To(BeNil()) + Expect(network2).To(Equal(network1)) + } + }) + + It("create ipvlan config with invalid mode", func() { + network := types.Network{ + Driver: "ipvlan", + Options: map[string]string{ + "mode": "test", + }, + } + _, err := libpodNet.NetworkCreate(network) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring(`unknown ipvlan mode "test"`)) + }) + It("create bridge with subnet", func() { subnet := "10.0.0.0/24" n, _ := types.ParseCIDR(subnet) diff --git a/libpod/network/cni/network.go b/libpod/network/cni/network.go index 46e07f780..d77e63a5d 100644 --- a/libpod/network/cni/network.go +++ b/libpod/network/cni/network.go @@ -109,7 +109,7 @@ func NewCNINetworkInterface(conf InitConfig) (types.ContainerNetwork, error) { // Drivers will return the list of supported network drivers // for this interface. func (n *cniNetwork) Drivers() []string { - return []string{types.BridgeNetworkDriver, types.MacVLANNetworkDriver} + return []string{types.BridgeNetworkDriver, types.MacVLANNetworkDriver, types.IPVLANNetworkDriver} } func (n *cniNetwork) loadNetworks() error { diff --git a/libpod/network/types/const.go b/libpod/network/types/const.go index be7ef03cf..916c6e6bf 100644 --- a/libpod/network/types/const.go +++ b/libpod/network/types/const.go @@ -7,6 +7,8 @@ const ( DefaultNetworkDriver = BridgeNetworkDriver // MacVLANNetworkDriver defines the macvlan driver MacVLANNetworkDriver = "macvlan" + // MacVLANNetworkDriver defines the macvlan driver + IPVLANNetworkDriver = "ipvlan" // IPAM drivers // HostLocalIPAMDriver store the ip -- cgit v1.2.3-54-g00ecf