summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/common/completion.go4
-rw-r--r--cmd/podman/machine/ssh.go29
-rw-r--r--docs/source/markdown/podman-machine-ssh.1.md6
-rw-r--r--docs/source/markdown/podman-network-create.1.md17
-rw-r--r--libpod/network/cni/cni_conversion.go41
-rw-r--r--libpod/network/cni/cni_types.go20
-rw-r--r--libpod/network/cni/config.go6
-rw-r--r--libpod/network/cni/config_test.go102
-rw-r--r--libpod/network/cni/network.go2
-rw-r--r--libpod/network/types/const.go2
10 files changed, 184 insertions, 45 deletions
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/cmd/podman/machine/ssh.go b/cmd/podman/machine/ssh.go
index 84e9e88ab..da0a09338 100644
--- a/cmd/podman/machine/ssh.go
+++ b/cmd/podman/machine/ssh.go
@@ -5,6 +5,7 @@ package machine
import (
"net/url"
+ "github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/pkg/machine"
@@ -15,7 +16,7 @@ import (
var (
sshCmd = &cobra.Command{
- Use: "ssh [NAME] [COMMAND [ARG ...]]",
+ Use: "ssh [options] [NAME] [COMMAND [ARG ...]]",
Short: "SSH into an existing machine",
Long: "SSH into a managed virtual machine ",
RunE: ssh,
@@ -35,6 +36,10 @@ func init() {
Command: sshCmd,
Parent: machineCmd,
})
+ flags := sshCmd.Flags()
+ usernameFlagName := "username"
+ flags.StringVar(&sshOpts.Username, usernameFlagName, "", "Username to use when ssh-ing into the VM.")
+ _ = sshCmd.RegisterFlagCompletionFunc(usernameFlagName, completion.AutocompleteNone)
}
func ssh(cmd *cobra.Command, args []string) error {
@@ -48,13 +53,6 @@ func ssh(cmd *cobra.Command, args []string) error {
// Set the VM to default
vmName := defaultMachineName
- // If we're not given a VM name, use the remote username from the connection config
- if len(args) == 0 {
- sshOpts.Username, err = remoteConnectionUsername()
- if err != nil {
- return err
- }
- }
// If len is greater than 0, it means we may have been
// provided the VM name. If so, we check. The VM name,
// if provided, must be in args[0].
@@ -68,10 +66,6 @@ func ssh(cmd *cobra.Command, args []string) error {
if validVM {
vmName = args[0]
} else {
- sshOpts.Username, err = remoteConnectionUsername()
- if err != nil {
- return err
- }
sshOpts.Args = append(sshOpts.Args, args[0])
}
}
@@ -83,14 +77,17 @@ func ssh(cmd *cobra.Command, args []string) error {
if validVM {
sshOpts.Args = args[1:]
} else {
- sshOpts.Username, err = remoteConnectionUsername()
- if err != nil {
- return err
- }
sshOpts.Args = args
}
}
+ if !validVM && sshOpts.Username == "" {
+ sshOpts.Username, err = remoteConnectionUsername()
+ if err != nil {
+ return err
+ }
+ }
+
switch vmType {
default:
vm, err = qemu.LoadVMByName(vmName)
diff --git a/docs/source/markdown/podman-machine-ssh.1.md b/docs/source/markdown/podman-machine-ssh.1.md
index a5cf69107..c4c732819 100644
--- a/docs/source/markdown/podman-machine-ssh.1.md
+++ b/docs/source/markdown/podman-machine-ssh.1.md
@@ -4,7 +4,7 @@
podman\-machine\-ssh - SSH into a virtual machine
## SYNOPSIS
-**podman machine ssh** [*name*] [*command* [*arg* ...]]
+**podman machine ssh** [*options*] [*name*] [*command* [*arg* ...]]
## DESCRIPTION
@@ -21,6 +21,10 @@ with the virtual machine is established.
Print usage statement.
+#### **--username**=*name*
+
+Username to use when SSH-ing into the VM.
+
## EXAMPLES
To get an interactive session with the default virtual machine:
diff --git a/docs/source/markdown/podman-network-create.1.md b/docs/source/markdown/podman-network-create.1.md
index 816dd53ea..d48509581 100644
--- a/docs/source/markdown/podman-network-create.1.md
+++ b/docs/source/markdown/podman-network-create.1.md
@@ -25,16 +25,23 @@ 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**
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` 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 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 060794ebe..d69dd7eb3 100644
--- a/libpod/network/cni/cni_conversion.go
+++ b/libpod/network/cni/cni_conversion.go
@@ -81,20 +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 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
}
@@ -207,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.
@@ -237,6 +241,7 @@ func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writ
vlan := 0
mtu := 0
+ vlanPluginMode := ""
for k, v := range network.Options {
switch k {
case "mtu":
@@ -251,6 +256,21 @@ func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writ
return nil, "", err
}
+ case "mode":
+ 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)
+ }
+ vlanPluginMode = v
+
default:
return nil, "", errors.Errorf("unsupported network option %s", k)
}
@@ -281,7 +301,10 @@ func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writ
}
case types.MacVLANNetworkDriver:
- plugins = append(plugins, newMacVLANPlugin(network.NetworkInterface, 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 91fd1c27b..fbf917c2d 100644
--- a/libpod/network/cni/cni_types.go
+++ b/libpod/network/cni/cni_types.go
@@ -50,7 +50,7 @@ type hostLocalBridge struct {
PromiscMode bool `json:"promiscMode,omitempty"`
Vlan int `json:"vlan,omitempty"`
IPAM ipamConfig `json:"ipam"`
- Capabilities map[string]bool `json:"capabilities"`
+ Capabilities map[string]bool `json:"capabilities,omitempty"`
}
// ipamConfig describes an IPAM configuration
@@ -82,13 +82,14 @@ 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"`
MTU int `json:"mtu,omitempty"`
- Capabilities map[string]bool `json:"capabilities"`
+ Mode string `json:"mode,omitempty"`
+ Capabilities map[string]bool `json:"capabilities,omitempty"`
}
// firewallConfig describes the firewall plugin
@@ -259,15 +260,18 @@ func hasDNSNamePlugin(paths []string) bool {
return false
}
-// newMacVLANPlugin creates a macvlanconfig with a given device name
-func newMacVLANPlugin(device 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 {
m.MTU = mtu
}
+ if len(mode) > 0 {
+ m.Mode = mode
+ }
// CNI is supposed to use the default route if a
// parent device is not provided
if len(device) > 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 11ad71870..a0a0ea1af 100644
--- a/libpod/network/cni/config_test.go
+++ b/libpod/network/cni/config_test.go
@@ -250,6 +250,67 @@ 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{
+ Driver: "macvlan",
+ 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("macvlan"))
+ Expect(network1.Options).To(HaveKeyWithValue("mode", mode))
+ Expect(network1.IPAMOptions).ToNot(BeEmpty())
+ Expect(network1.IPAMOptions).To(HaveKeyWithValue("driver", "dhcp"))
+ grepInFile(path, `"mode": "`+mode+`"`)
+ }
+ })
+
+ It("create macvlan config with invalid mode", func() {
+ network := types.Network{
+ Driver: "macvlan",
+ Options: map[string]string{
+ "mode": "test",
+ },
+ }
+ _, err := libpodNet.NetworkCreate(network)
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring(`unknown macvlan mode "test"`))
+ })
+
It("create macvlan config with invalid device", func() {
network := types.Network{
Driver: "macvlan",
@@ -270,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