From b1b35707aae57d299933f029eb0adc0a9000f97f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Mon, 23 Nov 2020 22:04:06 +0100 Subject: [PATCH 1/4] Add podman network create option for bridge mtu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Anders F Björklund --- cmd/podman/networks/create.go | 9 ++++++++ .../markdown/podman-network-create.1.md | 7 ++++++ libpod/network/create.go | 23 ++++++++++++++++++- libpod/network/netconflist.go | 3 ++- pkg/domain/entities/network.go | 2 ++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/cmd/podman/networks/create.go b/cmd/podman/networks/create.go index 938b8da778..8db4bb89a6 100644 --- a/cmd/podman/networks/create.go +++ b/cmd/podman/networks/create.go @@ -30,6 +30,7 @@ var ( var ( networkCreateOptions entities.NetworkCreateOptions labels []string + opts []string ) func networkCreateFlags(cmd *cobra.Command) { @@ -39,6 +40,10 @@ func networkCreateFlags(cmd *cobra.Command) { flags.StringVarP(&networkCreateOptions.Driver, driverFlagName, "d", "bridge", "driver to manage the network") _ = cmd.RegisterFlagCompletionFunc(driverFlagName, common.AutocompleteNetworkDriver) + optFlagName := "opt" + flags.StringArrayVarP(&opts, optFlagName, "o", []string{}, "Set driver specific options (default [])") + _ = cmd.RegisterFlagCompletionFunc(optFlagName, completion.AutocompleteNone) + gatewayFlagName := "gateway" flags.IPVar(&networkCreateOptions.Gateway, gatewayFlagName, nil, "IPv4 or IPv6 gateway for the subnet") _ = cmd.RegisterFlagCompletionFunc(gatewayFlagName, completion.AutocompleteNone) @@ -93,6 +98,10 @@ func networkCreate(cmd *cobra.Command, args []string) error { if err != nil { return errors.Wrap(err, "failed to parse labels") } + networkCreateOptions.Options, err = parse.GetAllLabels([]string{}, opts) + if err != nil { + return errors.Wrapf(err, "unable to process options") + } response, err := registry.ContainerEngine().NetworkCreate(registry.Context(), name, networkCreateOptions) if err != nil { return err diff --git a/docs/source/markdown/podman-network-create.1.md b/docs/source/markdown/podman-network-create.1.md index d787809cd2..235bf9a6c4 100644 --- a/docs/source/markdown/podman-network-create.1.md +++ b/docs/source/markdown/podman-network-create.1.md @@ -26,6 +26,13 @@ resolution. Driver to manage the network (default "bridge"). Currently only `bridge` is supported. +#### **--opt**=*option*, **-o** + +Set driver specific options. + +For the `bridge` driver the following options are supported: `mtu`. +The `mtu` option sets the Maximum Transmission Unit (MTU) and takes an integer value. + #### **--gateway** Define a gateway for the subnet. If you want to provide a gateway address, you must also provide a diff --git a/libpod/network/create.go b/libpod/network/create.go index cac4389637..50337013dd 100644 --- a/libpod/network/create.go +++ b/libpod/network/create.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strconv" "github.com/containernetworking/cni/pkg/version" "github.com/containers/common/pkg/config" @@ -76,6 +77,21 @@ func validateBridgeOptions(options entities.NetworkCreateOptions) error { } +// parseMTU parses the mtu option +func parseMTU(mtu string) (int, error) { + if mtu == "" { + return 0, nil // default + } + m, err := strconv.Atoi(mtu) + if err != nil { + return 0, err + } + if m < 0 { + return 0, errors.Errorf("the value %d for mtu is less than zero", m) + } + return m, nil +} + // createBridge creates a CNI network func createBridge(name string, options entities.NetworkCreateOptions, runtimeConfig *config.Config) (string, error) { var ( @@ -149,6 +165,11 @@ func createBridge(name string, options entities.NetworkCreateOptions, runtimeCon ipMasq = false } + mtu, err := parseMTU(options.Options["mtu"]) + if err != nil { + return "", err + } + // obtain host bridge name bridgeDeviceName, err := GetFreeDeviceName(runtimeConfig) if err != nil { @@ -172,7 +193,7 @@ func createBridge(name string, options entities.NetworkCreateOptions, runtimeCon ncList := NewNcList(name, version.Current(), options.Labels) var plugins []CNIPlugins // TODO need to iron out the role of isDefaultGW and IPMasq - bridge := NewHostLocalBridge(bridgeDeviceName, isGateway, false, ipMasq, ipamConfig) + bridge := NewHostLocalBridge(bridgeDeviceName, isGateway, false, ipMasq, mtu, ipamConfig) plugins = append(plugins, bridge) plugins = append(plugins, NewPortMapPlugin()) plugins = append(plugins, NewFirewallPlugin()) diff --git a/libpod/network/netconflist.go b/libpod/network/netconflist.go index 3db38485bf..8cbad39cb5 100644 --- a/libpod/network/netconflist.go +++ b/libpod/network/netconflist.go @@ -41,11 +41,12 @@ func NewNcList(name, version string, labels NcLabels) NcList { } // NewHostLocalBridge creates a new LocalBridge for host-local -func NewHostLocalBridge(name string, isGateWay, isDefaultGW, ipMasq bool, ipamConf IPAMHostLocalConf) *HostLocalBridge { +func NewHostLocalBridge(name string, isGateWay, isDefaultGW, ipMasq bool, mtu int, ipamConf IPAMHostLocalConf) *HostLocalBridge { hostLocalBridge := HostLocalBridge{ PluginType: "bridge", BrName: name, IPMasq: ipMasq, + MTU: mtu, HairpinMode: true, IPAM: ipamConf, } diff --git a/pkg/domain/entities/network.go b/pkg/domain/entities/network.go index f14cac7efc..65a110fd98 100644 --- a/pkg/domain/entities/network.go +++ b/pkg/domain/entities/network.go @@ -45,6 +45,8 @@ type NetworkCreateOptions struct { Range net.IPNet Subnet net.IPNet IPv6 bool + // Mapping of driver options and values. + Options map[string]string } // NetworkCreateReport describes a created network for the cli From 7f1be76b5c388efe34cb658fb8eebb2bcec2a004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Thu, 26 Nov 2020 17:38:38 +0100 Subject: [PATCH 2/4] Add podman network create option for bridge vlan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Anders F Björklund --- docs/source/markdown/podman-network-create.1.md | 3 ++- libpod/network/create.go | 15 ++++++++++++++- libpod/network/netconflist.go | 3 ++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/source/markdown/podman-network-create.1.md b/docs/source/markdown/podman-network-create.1.md index 235bf9a6c4..16e4e3bdb3 100644 --- a/docs/source/markdown/podman-network-create.1.md +++ b/docs/source/markdown/podman-network-create.1.md @@ -30,8 +30,9 @@ Driver to manage the network (default "bridge"). Currently only `bridge` is sup Set driver specific options. -For the `bridge` driver the following options are supported: `mtu`. +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. #### **--gateway** diff --git a/libpod/network/create.go b/libpod/network/create.go index 50337013dd..e9ab932624 100644 --- a/libpod/network/create.go +++ b/libpod/network/create.go @@ -92,6 +92,14 @@ func parseMTU(mtu string) (int, error) { return m, nil } +// parseVlan parses the vlan option +func parseVlan(vlan string) (int, error) { + if vlan == "" { + return 0, nil // default + } + return strconv.Atoi(vlan) +} + // createBridge creates a CNI network func createBridge(name string, options entities.NetworkCreateOptions, runtimeConfig *config.Config) (string, error) { var ( @@ -170,6 +178,11 @@ func createBridge(name string, options entities.NetworkCreateOptions, runtimeCon return "", err } + vlan, err := parseVlan(options.Options["vlan"]) + if err != nil { + return "", err + } + // obtain host bridge name bridgeDeviceName, err := GetFreeDeviceName(runtimeConfig) if err != nil { @@ -193,7 +206,7 @@ func createBridge(name string, options entities.NetworkCreateOptions, runtimeCon ncList := NewNcList(name, version.Current(), options.Labels) var plugins []CNIPlugins // TODO need to iron out the role of isDefaultGW and IPMasq - bridge := NewHostLocalBridge(bridgeDeviceName, isGateway, false, ipMasq, mtu, ipamConfig) + bridge := NewHostLocalBridge(bridgeDeviceName, isGateway, false, ipMasq, mtu, vlan, ipamConfig) plugins = append(plugins, bridge) plugins = append(plugins, NewPortMapPlugin()) plugins = append(plugins, NewFirewallPlugin()) diff --git a/libpod/network/netconflist.go b/libpod/network/netconflist.go index 8cbad39cb5..a5fec5e80e 100644 --- a/libpod/network/netconflist.go +++ b/libpod/network/netconflist.go @@ -41,13 +41,14 @@ func NewNcList(name, version string, labels NcLabels) NcList { } // NewHostLocalBridge creates a new LocalBridge for host-local -func NewHostLocalBridge(name string, isGateWay, isDefaultGW, ipMasq bool, mtu int, ipamConf IPAMHostLocalConf) *HostLocalBridge { +func NewHostLocalBridge(name string, isGateWay, isDefaultGW, ipMasq bool, mtu int, vlan int, ipamConf IPAMHostLocalConf) *HostLocalBridge { hostLocalBridge := HostLocalBridge{ PluginType: "bridge", BrName: name, IPMasq: ipMasq, MTU: mtu, HairpinMode: true, + Vlan: vlan, IPAM: ipamConf, } if isGateWay { From de2b15f4d5a8cd3bf9006d0f3ecdfa75b316f495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Thu, 26 Nov 2020 17:48:17 +0100 Subject: [PATCH 3/4] Add integration test for the bridge options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks Luap99 for doing the implementation Signed-off-by: Anders F Björklund --- test/e2e/network_create_test.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go index 043046c33d..1afd7cec4c 100644 --- a/test/e2e/network_create_test.go +++ b/test/e2e/network_create_test.go @@ -329,4 +329,30 @@ var _ = Describe("Podman network create", func() { Expect(nc).To(ExitWithError()) }) + It("podman network create with mtu option", func() { + net := "mtu-test" + nc := podmanTest.Podman([]string{"network", "create", "--opt", "mtu=9000", net}) + nc.WaitWithDefaultTimeout() + Expect(nc.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(net) + + nc = podmanTest.Podman([]string{"network", "inspect", net}) + nc.WaitWithDefaultTimeout() + Expect(nc.ExitCode()).To(BeZero()) + Expect(nc.OutputToString()).To(ContainSubstring(`"mtu": 9000,`)) + }) + + It("podman network create with vlan option", func() { + net := "vlan-test" + nc := podmanTest.Podman([]string{"network", "create", "--opt", "vlan=9", net}) + nc.WaitWithDefaultTimeout() + Expect(nc.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(net) + + nc = podmanTest.Podman([]string{"network", "inspect", net}) + nc.WaitWithDefaultTimeout() + Expect(nc.ExitCode()).To(BeZero()) + Expect(nc.OutputToString()).To(ContainSubstring(`"vlan": 9`)) + }) + }) From db70e91bde90514ace510f66a1069207217a8d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Thu, 26 Nov 2020 18:05:00 +0100 Subject: [PATCH 4/4] Validate that the bridge option is supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks Luap99 for the validation suggestion Signed-off-by: Anders F Björklund --- libpod/network/create.go | 26 +++++++++++++++++++------- test/e2e/network_create_test.go | 7 +++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/libpod/network/create.go b/libpod/network/create.go index e9ab932624..094fbe3498 100644 --- a/libpod/network/create.go +++ b/libpod/network/create.go @@ -173,14 +173,26 @@ func createBridge(name string, options entities.NetworkCreateOptions, runtimeCon ipMasq = false } - mtu, err := parseMTU(options.Options["mtu"]) - if err != nil { - return "", err - } + var mtu int + var vlan int + for k, v := range options.Options { + var err error + switch k { + case "mtu": + mtu, err = parseMTU(v) + if err != nil { + return "", err + } - vlan, err := parseVlan(options.Options["vlan"]) - if err != nil { - return "", err + case "vlan": + vlan, err = parseVlan(v) + if err != nil { + return "", err + } + + default: + return "", errors.Errorf("unsupported option %s", k) + } } // obtain host bridge name diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go index 1afd7cec4c..21b3074fc7 100644 --- a/test/e2e/network_create_test.go +++ b/test/e2e/network_create_test.go @@ -355,4 +355,11 @@ var _ = Describe("Podman network create", func() { Expect(nc.OutputToString()).To(ContainSubstring(`"vlan": 9`)) }) + It("podman network create with invalid option", func() { + net := "invalid-test" + nc := podmanTest.Podman([]string{"network", "create", "--opt", "foo=bar", net}) + nc.WaitWithDefaultTimeout() + Expect(nc).To(ExitWithError()) + }) + })