diff --git a/plugins/ipam/static/README.md b/plugins/ipam/static/README.md index e5d9a88c..000fb486 100644 --- a/plugins/ipam/static/README.md +++ b/plugins/ipam/static/README.md @@ -56,3 +56,7 @@ The following [CNI_ARGS](https://github.com/containernetworking/cni/blob/master/ The plugin also support following [capability argument](https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md). * `ips`: Pass IP addresses for CNI interface + +The following [args conventions](https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md#args-in-network-config) are supported: + +* `ips` (array of strings): A list of custom IPs to attempt to allocate, with prefix (e.g. '10.10.0.1/24') diff --git a/plugins/ipam/static/main.go b/plugins/ipam/static/main.go index 3acd62e1..41a46e69 100644 --- a/plugins/ipam/static/main.go +++ b/plugins/ipam/static/main.go @@ -38,6 +38,9 @@ type Net struct { RuntimeConfig struct { IPs []string `json:"ips,omitempty"` } `json:"runtimeConfig,omitempty"` + Args *struct { + A *IPAMArgs `json:"cni"` + } `json:"args"` } type IPAMConfig struct { @@ -54,6 +57,10 @@ type IPAMEnvArgs struct { GATEWAY types.UnmarshallableString `json:"gateway,omitempty"` } +type IPAMArgs struct { + IPs []string `json:"ips"` +} + type Address struct { AddressStr string `json:"address"` Gateway net.IP `json:"gateway,omitempty"` @@ -146,6 +153,15 @@ func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) { } } + // import address from args + if n.Args != nil && n.Args.A != nil && len(n.Args.A.IPs) != 0 { + // args IP overwrites IP, so clear IPAM Config + n.IPAM.Addresses = make([]Address, 0, len(n.Args.A.IPs)) + for _, addr := range n.Args.A.IPs { + n.IPAM.Addresses = append(n.IPAM.Addresses, Address{AddressStr: addr}) + } + } + if n.IPAM == nil { return nil, "", fmt.Errorf("IPAM config missing 'ipam' key") } diff --git a/plugins/ipam/static/static_test.go b/plugins/ipam/static/static_test.go index 0e007502..8239b74f 100644 --- a/plugins/ipam/static/static_test.go +++ b/plugins/ipam/static/static_test.go @@ -334,6 +334,76 @@ var _ = Describe("static Operations", func() { }) Expect(err).NotTo(HaveOccurred()) }) + + It("allocates and releases multiple addresses with ADD/DEL, from args", func() { + const ifname string = "eth0" + const nspath string = "/some/where" + + conf := `{ + "cniVersion": "0.3.1", + "name": "mynet", + "type": "ipvlan", + "master": "foo0", + "ipam": { + "type": "static", + "routes": [ + { "dst": "0.0.0.0/0", "gw": "10.10.0.254" }, + { "dst": "3ffe:ffff:0:01ff::1/64", + "gw": "3ffe:ffff:0::1" } ], + "dns": { + "nameservers" : ["8.8.8.8"], + "domain": "example.com", + "search": [ "example.com" ] + } + }, + "args": { + "cni": { + "ips" : ["10.10.0.1/24", "3ffe:ffff:0:01ff::1/64"] + } + } + }` + + args := &skel.CmdArgs{ + ContainerID: "dummy", + Netns: nspath, + IfName: ifname, + StdinData: []byte(conf), + } + + // Allocate the IP + r, raw, err := testutils.CmdAddWithArgs(args, func() error { + return cmdAdd(args) + }) + Expect(err).NotTo(HaveOccurred()) + Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0)) + + result, err := current.GetResult(r) + Expect(err).NotTo(HaveOccurred()) + + // Gomega is cranky about slices with different caps + Expect(*result.IPs[0]).To(Equal( + current.IPConfig{ + Version: "4", + Address: mustCIDR("10.10.0.1/24"), + })) + Expect(*result.IPs[1]).To(Equal( + current.IPConfig{ + Version: "6", + Address: mustCIDR("3ffe:ffff:0:01ff::1/64"), + }, + )) + Expect(len(result.IPs)).To(Equal(2)) + Expect(result.Routes).To(Equal([]*types.Route{ + {Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")}, + {Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")}, + })) + + // Release the IP + err = testutils.CmdDelWithArgs(args, func() error { + return cmdDel(args) + }) + Expect(err).NotTo(HaveOccurred()) + }) }) func mustCIDR(s string) net.IPNet { diff --git a/plugins/meta/tuning/README.md b/plugins/meta/tuning/README.md index c547ac7b..631194d8 100644 --- a/plugins/meta/tuning/README.md +++ b/plugins/meta/tuning/README.md @@ -64,3 +64,10 @@ Note: You may add `IgnoreUnknown=true` to allow loose CNI argument verification The plugin also support following [capability argument](https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md). * `mac`: Pass MAC addresses for CNI interface + +The following [args conventions](https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md#args-in-network-config) are supported: + +* `mac` (string, optional): MAC address (i.e. hardware address) of interface +* `mtu` (integer, optional): MTU of interface +* `promisc` (bool, optional): Change the promiscuous mode of interface +* `sysctl` (object, optional): Change system controls diff --git a/plugins/meta/tuning/tuning.go b/plugins/meta/tuning/tuning.go index d62734cf..a28394d9 100644 --- a/plugins/meta/tuning/tuning.go +++ b/plugins/meta/tuning/tuning.go @@ -47,6 +47,16 @@ type TuningConf struct { RuntimeConfig struct { Mac string `json:"mac,omitempty"` } `json:"runtimeConfig,omitempty"` + Args *struct { + A *IPAMArgs `json:"cni"` + } `json:"args"` +} + +type IPAMArgs struct { + SysCtl *map[string]string `json:"sysctl"` + Mac *string `json:"mac,omitempty"` + Promisc *bool `json:"promisc,omitempty"` + Mtu *int `json:"mtu,omitempty"` } // MacEnvArgs represents CNI_ARG @@ -79,6 +89,28 @@ func parseConf(data []byte, envArgs string) (*TuningConf, error) { conf.Mac = conf.RuntimeConfig.Mac } + // Get args + if conf.Args != nil && conf.Args.A != nil { + if conf.Args.A.SysCtl != nil { + for k, v := range *conf.Args.A.SysCtl { + conf.SysCtl[k] = v + } + } + + if conf.Args.A.Mac != nil { + conf.Mac = *conf.Args.A.Mac + } + + if conf.Args.A.Promisc != nil { + conf.Promisc = *conf.Args.A.Promisc + } + + if conf.Args.A.Mtu != nil { + conf.Mtu = *conf.Args.A.Mtu + } + + } + return &conf, nil } diff --git a/plugins/meta/tuning/tuning_test.go b/plugins/meta/tuning/tuning_test.go index 9f9b3112..658332db 100644 --- a/plugins/meta/tuning/tuning_test.go +++ b/plugins/meta/tuning/tuning_test.go @@ -215,6 +215,67 @@ var _ = Describe("tuning plugin", func() { Expect(err).NotTo(HaveOccurred()) }) + It("configures and deconfigures promiscuous mode from args with ADD/DEL", func() { + conf := []byte(`{ + "name": "test", + "type": "iplink", + "cniVersion": "0.3.1", + "args": { + "cni": { + "promisc": true + } + }, + "prevResult": { + "interfaces": [ + {"name": "dummy0", "sandbox":"netns"} + ], + "ips": [ + { + "version": "4", + "address": "10.0.0.2/24", + "gateway": "10.0.0.1", + "interface": 0 + } + ] + } +}`) + + args := &skel.CmdArgs{ + ContainerID: "dummy", + Netns: originalNS.Path(), + IfName: IFNAME, + StdinData: conf, + } + + 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(1)) + Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24")) + + link, err := netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().Promisc).To(Equal(1)) + + err = testutils.CmdDel(originalNS.Path(), + args.ContainerID, "", func() error { return cmdDel(args) }) + Expect(err).NotTo(HaveOccurred()) + + return nil + }) + Expect(err).NotTo(HaveOccurred()) + }) + It("configures and deconfigures mtu with ADD/DEL", func() { conf := []byte(`{ "name": "test", @@ -272,6 +333,67 @@ var _ = Describe("tuning plugin", func() { Expect(err).NotTo(HaveOccurred()) }) + It("configures and deconfigures mtu from args with ADD/DEL", func() { + conf := []byte(`{ + "name": "test", + "type": "iplink", + "cniVersion": "0.3.1", + "args": { + "cni": { + "mtu": 1454 + } + }, + "prevResult": { + "interfaces": [ + {"name": "dummy0", "sandbox":"netns"} + ], + "ips": [ + { + "version": "4", + "address": "10.0.0.2/24", + "gateway": "10.0.0.1", + "interface": 0 + } + ] + } +}`) + + args := &skel.CmdArgs{ + ContainerID: "dummy", + Netns: originalNS.Path(), + IfName: IFNAME, + StdinData: conf, + } + + 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(1)) + Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24")) + + link, err := netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().MTU).To(Equal(1454)) + + err = testutils.CmdDel(originalNS.Path(), + args.ContainerID, "", func() error { return cmdDel(args) }) + Expect(err).NotTo(HaveOccurred()) + + return nil + }) + Expect(err).NotTo(HaveOccurred()) + }) + It("configures and deconfigures mac address (from conf file) with ADD/DEL", func() { conf := []byte(`{ "name": "test", @@ -331,6 +453,69 @@ var _ = Describe("tuning plugin", func() { Expect(err).NotTo(HaveOccurred()) }) + It("configures and deconfigures mac address (from args) with ADD/DEL", func() { + conf := []byte(`{ + "name": "test", + "type": "iplink", + "cniVersion": "0.3.1", + "args": { + "cni": { + "mac": "c2:11:22:33:44:55" + } + }, + "prevResult": { + "interfaces": [ + {"name": "dummy0", "sandbox":"netns"} + ], + "ips": [ + { + "version": "4", + "address": "10.0.0.2/24", + "gateway": "10.0.0.1", + "interface": 0 + } + ] + } +}`) + + args := &skel.CmdArgs{ + ContainerID: "dummy", + Netns: originalNS.Path(), + IfName: IFNAME, + StdinData: conf, + } + + 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(1)) + Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24")) + + link, err := netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + hw, err := net.ParseMAC("c2:11:22:33:44:55") + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().HardwareAddr).To(Equal(hw)) + + err = testutils.CmdDel(originalNS.Path(), + args.ContainerID, "", func() error { return cmdDel(args) }) + Expect(err).NotTo(HaveOccurred()) + + return nil + }) + Expect(err).NotTo(HaveOccurred()) + }) + It("configures and deconfigures mac address (from CNI_ARGS) with ADD/DEL", func() { conf := []byte(`{ "name": "test",