ipvlan: support enslaving an interface returned by ipam
For IP allocation schemes that cannot be interface agnostic, master can be set to "ipam". In this configuration, the IPAM plugin is required to return a single interface name for the ipvlan plugin to enslave.
This commit is contained in:
@ -27,7 +27,7 @@ Because all ipvlan interfaces share the MAC address with the host interface, DHC
|
|||||||
|
|
||||||
* `name` (string, required): the name of the network.
|
* `name` (string, required): the name of the network.
|
||||||
* `type` (string, required): "ipvlan".
|
* `type` (string, required): "ipvlan".
|
||||||
* `master` (string, required): name of the host interface to enslave.
|
* `master` (string, required): name of the host interface to enslave or "ipam" to enslave an interface returned by ipam.
|
||||||
* `mode` (string, optional): one of "l2", "l3". Defaults to "l2".
|
* `mode` (string, optional): one of "l2", "l3". Defaults to "l2".
|
||||||
* `mtu` (integer, optional): explicitly set MTU to the specified value. Defaults to the value chosen by the kernel.
|
* `mtu` (integer, optional): explicitly set MTU to the specified value. Defaults to the value chosen by the kernel.
|
||||||
* `ipam` (dictionary, required): IPAM configuration to be used for this network.
|
* `ipam` (dictionary, required): IPAM configuration to be used for this network.
|
||||||
@ -38,3 +38,4 @@ Because all ipvlan interfaces share the MAC address with the host interface, DHC
|
|||||||
Therefore the container will not be able to reach the host via `ipvlan` interface.
|
Therefore the container will not be able to reach the host via `ipvlan` interface.
|
||||||
Be sure to also have container join a network that provides connectivity to the host (e.g. `ptp`).
|
Be sure to also have container join a network that provides connectivity to the host (e.g. `ptp`).
|
||||||
* A single master interface can not be enslaved by both `macvlan` and `ipvlan`.
|
* A single master interface can not be enslaved by both `macvlan` and `ipvlan`.
|
||||||
|
* For IP allocation schemes that cannot be interface agnostic, master can be set to `ipam`. In this configuration, the ipam plugin is required to return a single interface name for the ipvlan plugin to enslave.
|
||||||
|
@ -138,11 +138,6 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
defer netns.Close()
|
defer netns.Close()
|
||||||
|
|
||||||
ipvlanInterface, err := createIpvlan(n, args.IfName, netns)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// run the IPAM plugin and get back the config to apply
|
// run the IPAM plugin and get back the config to apply
|
||||||
r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
|
r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -157,6 +152,21 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
if len(result.IPs) == 0 {
|
if len(result.IPs) == 0 {
|
||||||
return errors.New("IPAM plugin returned missing IP config")
|
return errors.New("IPAM plugin returned missing IP config")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if n.Master == "ipam" {
|
||||||
|
// Use an IPAM supplied master interface
|
||||||
|
if len(result.Interfaces) == 1 && result.Interfaces[0].Name != "" {
|
||||||
|
n.Master = result.Interfaces[0].Name
|
||||||
|
} else {
|
||||||
|
return errors.New("IPAM plugin returned missing master interface")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ipvlanInterface, err := createIpvlan(n, args.IfName, netns)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
for _, ipc := range result.IPs {
|
for _, ipc := range result.IPs {
|
||||||
// All addresses belong to the ipvlan interface
|
// All addresses belong to the ipvlan interface
|
||||||
ipc.Interface = current.Int(0)
|
ipc.Interface = current.Int(0)
|
||||||
|
@ -224,4 +224,40 @@ var _ = Describe("ipvlan Operations", func() {
|
|||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("errors if master should originate from ipam but an ipam interface is not returned", func() {
|
||||||
|
const IFNAME = "ipvl0"
|
||||||
|
|
||||||
|
conf := `{
|
||||||
|
"cniVersion": "0.3.1",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "ipvlan",
|
||||||
|
"master": "ipam",
|
||||||
|
"ipam": {
|
||||||
|
"type": "host-local",
|
||||||
|
"subnet": "10.1.2.0/24"
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
targetNs, err := ns.NewNS()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
defer targetNs.Close()
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: targetNs.Path(),
|
||||||
|
IfName: IFNAME,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
}
|
||||||
|
|
||||||
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
_, _, err := testutils.CmdAddWithResult(targetNs.Path(), IFNAME, []byte(conf), func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err.Error()).To(Equal("IPAM plugin returned missing master interface"))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user