mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
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 <pholzing@redhat.com>
This commit is contained in:
@ -1111,7 +1111,7 @@ func AutocompleteManifestFormat(cmd *cobra.Command, args []string, toComplete st
|
|||||||
// AutocompleteNetworkDriver - Autocomplete network driver option.
|
// AutocompleteNetworkDriver - Autocomplete network driver option.
|
||||||
// -> "bridge", "macvlan"
|
// -> "bridge", "macvlan"
|
||||||
func AutocompleteNetworkDriver(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
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
|
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) },
|
"id=": func(s string) ([]string, cobra.ShellCompDirective) { return getNetworks(cmd, s, completeIDs) },
|
||||||
"label=": nil,
|
"label=": nil,
|
||||||
"driver=": func(_ string) ([]string, cobra.ShellCompDirective) {
|
"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,
|
"until=": nil,
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@ resolution.
|
|||||||
|
|
||||||
#### **--driver**, **-d**
|
#### **--driver**, **-d**
|
||||||
|
|
||||||
Driver to manage the network. Currently `bridge` and `macvlan` is supported. Defaults to `bridge`.
|
Driver to manage the network. Currently `bridge`, `macvlan` and `ipvlan` are 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.
|
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**
|
#### **--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:
|
Additionally the `bridge` driver supports the following option:
|
||||||
- `vlan`: This option assign VLAN tag and enables vlan\_filtering. Defaults to none.
|
- `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.
|
- `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**
|
#### **--gateway**
|
||||||
|
|
||||||
|
@ -81,24 +81,24 @@ func createNetworkFromCNIConfigList(conf *libcni.NetworkConfigList, confPath str
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case types.MacVLANNetworkDriver:
|
case types.MacVLANNetworkDriver, types.IPVLANNetworkDriver:
|
||||||
var macvlan macVLANConfig
|
var vlan VLANConfig
|
||||||
err := json.Unmarshal(firstPlugin.Bytes, &macvlan)
|
err := json.Unmarshal(firstPlugin.Bytes, &vlan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to unmarshal the macvlan plugin config in %s", confPath)
|
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
|
// set network options
|
||||||
if macvlan.MTU != 0 {
|
if vlan.MTU != 0 {
|
||||||
network.Options["mtu"] = strconv.Itoa(macvlan.MTU)
|
network.Options["mtu"] = strconv.Itoa(vlan.MTU)
|
||||||
}
|
}
|
||||||
|
|
||||||
if macvlan.Mode != "" {
|
if vlan.Mode != "" {
|
||||||
network.Options["mode"] = macvlan.Mode
|
network.Options["mode"] = vlan.Mode
|
||||||
}
|
}
|
||||||
|
|
||||||
err = convertIPAMConfToNetwork(&network, macvlan.IPAM, confPath)
|
err = convertIPAMConfToNetwork(&network, vlan.IPAM, confPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -211,7 +211,7 @@ func getNetworkArgsFromConfList(args map[string]interface{}, argType string) map
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return map[string]string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// createCNIConfigListFromNetwork will create a cni config file from the given network.
|
// 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
|
vlan := 0
|
||||||
mtu := 0
|
mtu := 0
|
||||||
macvlanMode := ""
|
vlanPluginMode := ""
|
||||||
for k, v := range network.Options {
|
for k, v := range network.Options {
|
||||||
switch k {
|
switch k {
|
||||||
case "mtu":
|
case "mtu":
|
||||||
@ -257,10 +257,19 @@ func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writ
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "mode":
|
case "mode":
|
||||||
if !pkgutil.StringInSlice(v, []string{"", "bridge", "private", "vepa", "passthru"}) {
|
switch network.Driver {
|
||||||
return nil, "", errors.Errorf("unknown macvlan mode %q", v)
|
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:
|
default:
|
||||||
return nil, "", errors.Errorf("unsupported network option %s", k)
|
return nil, "", errors.Errorf("unsupported network option %s", k)
|
||||||
@ -292,7 +301,10 @@ func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writ
|
|||||||
}
|
}
|
||||||
|
|
||||||
case types.MacVLANNetworkDriver:
|
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:
|
default:
|
||||||
return nil, "", errors.Errorf("driver %q is not supported by cni", network.Driver)
|
return nil, "", errors.Errorf("driver %q is not supported by cni", network.Driver)
|
||||||
|
@ -82,8 +82,8 @@ type portMapConfig struct {
|
|||||||
Capabilities map[string]bool `json:"capabilities"`
|
Capabilities map[string]bool `json:"capabilities"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// macVLANConfig describes the macvlan config
|
// VLANConfig describes the macvlan config
|
||||||
type macVLANConfig struct {
|
type VLANConfig struct {
|
||||||
PluginType string `json:"type"`
|
PluginType string `json:"type"`
|
||||||
Master string `json:"master"`
|
Master string `json:"master"`
|
||||||
IPAM ipamConfig `json:"ipam"`
|
IPAM ipamConfig `json:"ipam"`
|
||||||
@ -260,10 +260,10 @@ func hasDNSNamePlugin(paths []string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// newMacVLANPlugin creates a macvlanconfig with a given device name
|
// newVLANPlugin creates a macvlanconfig with a given device name
|
||||||
func newMacVLANPlugin(device, mode string, mtu int, ipam ipamConfig) macVLANConfig {
|
func newVLANPlugin(pluginType, device, mode string, mtu int, ipam ipamConfig) VLANConfig {
|
||||||
m := macVLANConfig{
|
m := VLANConfig{
|
||||||
PluginType: "macvlan",
|
PluginType: pluginType,
|
||||||
IPAM: ipam,
|
IPAM: ipam,
|
||||||
}
|
}
|
||||||
if mtu > 0 {
|
if mtu > 0 {
|
||||||
|
@ -100,8 +100,8 @@ func (n *cniNetwork) networkCreate(newNetwork types.Network, defaultNet bool) (*
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case types.MacVLANNetworkDriver:
|
case types.MacVLANNetworkDriver, types.IPVLANNetworkDriver:
|
||||||
err = createMacVLAN(&newNetwork)
|
err = createIPMACVLAN(&newNetwork)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -214,7 +214,7 @@ func (n *cniNetwork) NetworkInspect(nameOrID string) (types.Network, error) {
|
|||||||
return *network.libpodNet, nil
|
return *network.libpodNet, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMacVLAN(network *types.Network) error {
|
func createIPMACVLAN(network *types.Network) error {
|
||||||
if network.Internal {
|
if network.Internal {
|
||||||
return errors.New("internal is not supported with macvlan")
|
return errors.New("internal is not supported with macvlan")
|
||||||
}
|
}
|
||||||
|
@ -250,6 +250,34 @@ var _ = Describe("Config", func() {
|
|||||||
grepInFile(path, `"type": "host-local"`)
|
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() {
|
It("create macvlan config with mode", func() {
|
||||||
for _, mode := range []string{"bridge", "private", "vepa", "passthru"} {
|
for _, mode := range []string{"bridge", "private", "vepa", "passthru"} {
|
||||||
network := types.Network{
|
network := types.Network{
|
||||||
@ -303,6 +331,47 @@ var _ = Describe("Config", func() {
|
|||||||
Expect(err.Error()).To(ContainSubstring("internal is not supported with macvlan"))
|
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() {
|
It("create bridge with subnet", func() {
|
||||||
subnet := "10.0.0.0/24"
|
subnet := "10.0.0.0/24"
|
||||||
n, _ := types.ParseCIDR(subnet)
|
n, _ := types.ParseCIDR(subnet)
|
||||||
|
@ -109,7 +109,7 @@ func NewCNINetworkInterface(conf InitConfig) (types.ContainerNetwork, error) {
|
|||||||
// Drivers will return the list of supported network drivers
|
// Drivers will return the list of supported network drivers
|
||||||
// for this interface.
|
// for this interface.
|
||||||
func (n *cniNetwork) Drivers() []string {
|
func (n *cniNetwork) Drivers() []string {
|
||||||
return []string{types.BridgeNetworkDriver, types.MacVLANNetworkDriver}
|
return []string{types.BridgeNetworkDriver, types.MacVLANNetworkDriver, types.IPVLANNetworkDriver}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *cniNetwork) loadNetworks() error {
|
func (n *cniNetwork) loadNetworks() error {
|
||||||
|
@ -7,6 +7,8 @@ const (
|
|||||||
DefaultNetworkDriver = BridgeNetworkDriver
|
DefaultNetworkDriver = BridgeNetworkDriver
|
||||||
// MacVLANNetworkDriver defines the macvlan driver
|
// MacVLANNetworkDriver defines the macvlan driver
|
||||||
MacVLANNetworkDriver = "macvlan"
|
MacVLANNetworkDriver = "macvlan"
|
||||||
|
// MacVLANNetworkDriver defines the macvlan driver
|
||||||
|
IPVLANNetworkDriver = "ipvlan"
|
||||||
|
|
||||||
// IPAM drivers
|
// IPAM drivers
|
||||||
// HostLocalIPAMDriver store the ip
|
// HostLocalIPAMDriver store the ip
|
||||||
|
Reference in New Issue
Block a user