Allow to configure empty ipam for macvlan
This PR add the option to configure an empty ipam for the macvlan cni plugin. When using the macvlan cni plugin with an empty ipam the requeted pod will get the macvlan interface but without any ip address. One of the use cases for this feature is for projects that runs a dhcp server inside the pod like KubeVirt. In KubeVirt we need to let the vm running inside the pod to make the dhcp request so it will be able to make a release an renew request when needed.
This commit is contained in:
parent
44297f6ba3
commit
af692de1b8
@ -26,7 +26,7 @@ Since each macvlan interface has its own MAC address, it makes it easy to use wi
|
|||||||
* `master` (string, required): name of the host interface to enslave
|
* `master` (string, required): name of the host interface to enslave
|
||||||
* `mode` (string, optional): one of "bridge", "private", "vepa", "passthru". Defaults to "bridge".
|
* `mode` (string, optional): one of "bridge", "private", "vepa", "passthru". Defaults to "bridge".
|
||||||
* `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. For interface only without ip address, create empty dictionary.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
@ -169,6 +169,8 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isLayer3 := n.IPAM.Type != ""
|
||||||
|
|
||||||
netns, err := ns.GetNS(args.Netns)
|
netns, err := ns.GetNS(args.Netns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open netns %q: %v", netns, err)
|
return fmt.Errorf("failed to open netns %q: %v", netns, err)
|
||||||
@ -189,6 +191,10 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Assume L2 interface only
|
||||||
|
result := ¤t.Result{CNIVersion: cniVersion, Interfaces: []*current.Interface{macvlanInterface}}
|
||||||
|
|
||||||
|
if isLayer3 {
|
||||||
// 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 {
|
||||||
@ -205,15 +211,17 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Convert whatever the IPAM result was into the current Result type
|
// Convert whatever the IPAM result was into the current Result type
|
||||||
result, err := current.NewResultFromResult(r)
|
ipamResult, err := current.NewResultFromResult(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(result.IPs) == 0 {
|
if len(ipamResult.IPs) == 0 {
|
||||||
return errors.New("IPAM plugin returned missing IP config")
|
return errors.New("IPAM plugin returned missing IP config")
|
||||||
}
|
}
|
||||||
result.Interfaces = []*current.Interface{macvlanInterface}
|
|
||||||
|
result.IPs = ipamResult.IPs
|
||||||
|
result.Routes = ipamResult.Routes
|
||||||
|
|
||||||
for _, ipc := range result.IPs {
|
for _, ipc := range result.IPs {
|
||||||
// All addresses apply to the container macvlan interface
|
// All addresses apply to the container macvlan interface
|
||||||
@ -240,6 +248,24 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// For L2 just change interface status to up
|
||||||
|
err = netns.Do(func(_ ns.NetNS) error {
|
||||||
|
macvlanInterfaceLink, err := netlink.LinkByName(args.IfName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to find interface name %q: %v", macvlanInterface.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := netlink.LinkSetUp(macvlanInterfaceLink); err != nil {
|
||||||
|
return fmt.Errorf("failed to set %q UP: %v", args.IfName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result.DNS = n.DNS
|
result.DNS = n.DNS
|
||||||
|
|
||||||
@ -252,10 +278,14 @@ func cmdDel(args *skel.CmdArgs) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isLayer3 := n.IPAM.Type != ""
|
||||||
|
|
||||||
|
if isLayer3 {
|
||||||
err = ipam.ExecDel(n.IPAM.Type, args.StdinData)
|
err = ipam.ExecDel(n.IPAM.Type, args.StdinData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if args.Netns == "" {
|
if args.Netns == "" {
|
||||||
return nil
|
return nil
|
||||||
@ -285,17 +315,21 @@ func cmdCheck(args *skel.CmdArgs) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
isLayer3 := n.IPAM.Type != ""
|
||||||
|
|
||||||
netns, err := ns.GetNS(args.Netns)
|
netns, err := ns.GetNS(args.Netns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open netns %q: %v", args.Netns, err)
|
return fmt.Errorf("failed to open netns %q: %v", args.Netns, err)
|
||||||
}
|
}
|
||||||
defer netns.Close()
|
defer netns.Close()
|
||||||
|
|
||||||
|
if isLayer3 {
|
||||||
// run the IPAM plugin and get back the config to apply
|
// run the IPAM plugin and get back the config to apply
|
||||||
err = ipam.ExecCheck(n.IPAM.Type, args.StdinData)
|
err = ipam.ExecCheck(n.IPAM.Type, args.StdinData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parse previous result.
|
// Parse previous result.
|
||||||
if n.NetConf.RawPrevResult == nil {
|
if n.NetConf.RawPrevResult == nil {
|
||||||
|
@ -286,6 +286,89 @@ var _ = Describe("macvlan Operations", func() {
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("configures and deconfigures a l2 macvlan link with ADD/DEL", func() {
|
||||||
|
const IFNAME = "macvl0"
|
||||||
|
|
||||||
|
conf := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "0.3.1",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "macvlan",
|
||||||
|
"master": "%s",
|
||||||
|
"ipam": {}
|
||||||
|
}`, MASTER_NAME)
|
||||||
|
|
||||||
|
targetNs, err := testutils.NewNS()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
defer targetNs.Close()
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: targetNs.Path(),
|
||||||
|
IfName: IFNAME,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
}
|
||||||
|
|
||||||
|
var result *current.Result
|
||||||
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
result, err = current.GetResult(r)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(len(result.Interfaces)).To(Equal(1))
|
||||||
|
Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
|
||||||
|
Expect(len(result.IPs)).To(Equal(0))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// Make sure macvlan link exists in the target namespace
|
||||||
|
err = targetNs.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
link, err := netlink.LinkByName(IFNAME)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(link.Attrs().Name).To(Equal(IFNAME))
|
||||||
|
|
||||||
|
hwaddr, err := net.ParseMAC(result.Interfaces[0].Mac)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(link.Attrs().HardwareAddr).To(Equal(hwaddr))
|
||||||
|
|
||||||
|
addrs, err := netlink.AddrList(link, syscall.AF_INET)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(len(addrs)).To(Equal(0))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
err := testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// Make sure macvlan link has been deleted
|
||||||
|
err = targetNs.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
link, err := netlink.LinkByName(IFNAME)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(link).To(BeNil())
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
It("configures and deconfigures a cniVersion 0.4.0 macvlan link with ADD/DEL", func() {
|
It("configures and deconfigures a cniVersion 0.4.0 macvlan link with ADD/DEL", func() {
|
||||||
const IFNAME = "macvl0"
|
const IFNAME = "macvl0"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user