From 660685a8af69fa36294deecd63eb15747ef9cd6d Mon Sep 17 00:00:00 2001 From: Tomofumi Hayashi Date: Thu, 20 Jun 2019 17:11:47 +0900 Subject: [PATCH] Support ips capability in static and mac capability in tuning This change introduces new capability flag to change MAC address and to specify IP addresses by tuning and static. --- plugins/ipam/static/README.md | 4 ++ plugins/ipam/static/main.go | 12 ++++++ plugins/ipam/static/static_test.go | 69 ++++++++++++++++++++++++++++++ plugins/meta/tuning/README.md | 3 ++ plugins/meta/tuning/tuning.go | 24 ++++++++--- plugins/meta/tuning/tuning_test.go | 64 +++++++++++++++++++++++++++ 6 files changed, 169 insertions(+), 7 deletions(-) diff --git a/plugins/ipam/static/README.md b/plugins/ipam/static/README.md index d9ca28c5b..e5d9a88c6 100644 --- a/plugins/ipam/static/README.md +++ b/plugins/ipam/static/README.md @@ -52,3 +52,7 @@ The following [CNI_ARGS](https://github.com/containernetworking/cni/blob/master/ * `GATEWAY`: request a specific gateway address (example: CNI_ARGS="IP=10.10.0.1/24;GATEWAY=10.10.0.254") + +The plugin also support following [capability argument](https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md). + +* `ips`: Pass IP addresses for CNI interface diff --git a/plugins/ipam/static/main.go b/plugins/ipam/static/main.go index b5c501a1f..3acd62e11 100644 --- a/plugins/ipam/static/main.go +++ b/plugins/ipam/static/main.go @@ -34,6 +34,10 @@ type Net struct { Name string `json:"name"` CNIVersion string `json:"cniVersion"` IPAM *IPAMConfig `json:"ipam"` + + RuntimeConfig struct { + IPs []string `json:"ips,omitempty"` + } `json:"runtimeConfig,omitempty"` } type IPAMConfig struct { @@ -134,6 +138,14 @@ func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) { return nil, "", err } + if len(n.RuntimeConfig.IPs) != 0 { + // args IP overwrites IP, so clear IPAM Config + n.IPAM.Addresses = make([]Address, 0, len(n.RuntimeConfig.IPs)) + for _, addr := range n.RuntimeConfig.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 c6d9aea65..0e007502f 100644 --- a/plugins/ipam/static/static_test.go +++ b/plugins/ipam/static/static_test.go @@ -265,6 +265,75 @@ var _ = Describe("static Operations", func() { }) Expect(err).NotTo(HaveOccurred()) }) + + It("allocates and releases multiple addresses with ADD/DEL, from RuntimeConfig", func() { + const ifname string = "eth0" + const nspath string = "/some/where" + + conf := `{ + "cniVersion": "0.3.1", + "name": "mynet", + "type": "ipvlan", + "master": "foo0", + "capabilities": {"ips": true}, + "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" ] + } + }, + "RuntimeConfig": { + "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 455073806..c547ac7bc 100644 --- a/plugins/meta/tuning/README.md +++ b/plugins/meta/tuning/README.md @@ -61,3 +61,6 @@ The following [CNI_ARGS](https://github.com/containernetworking/cni/blob/master/ Note: You may add `IgnoreUnknown=true` to allow loose CNI argument verification (see CNI's issue[#560](https://github.com/containernetworking/cni/issues/560)). +The plugin also support following [capability argument](https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md). + +* `mac`: Pass MAC addresses for CNI interface diff --git a/plugins/meta/tuning/tuning.go b/plugins/meta/tuning/tuning.go index f8d0f3ad4..9ea7c2c43 100644 --- a/plugins/meta/tuning/tuning.go +++ b/plugins/meta/tuning/tuning.go @@ -43,9 +43,14 @@ type TuningConf struct { Mac string `json:"mac,omitempty"` Promisc bool `json:"promisc,omitempty"` Mtu int `json:"mtu,omitempty"` + + RuntimeConfig struct { + Mac string `json:"mac,omitempty"` + } `json:"runtimeConfig,omitempty"` } -type MACEnvArgs struct { +// MacEnvArgs represents CNI_ARG +type MacEnvArgs struct { types.CommonArgs MAC types.UnmarshallableString `json:"mac,omitempty"` } @@ -56,9 +61,9 @@ func parseConf(data []byte, envArgs string) (*TuningConf, error) { return nil, fmt.Errorf("failed to load netconf: %v", err) } - // Parse custom MAC from both env args + // Parse custom Mac from both env args if envArgs != "" { - e := MACEnvArgs{} + e := MacEnvArgs{} err := types.LoadArgs(envArgs, &e) if err != nil { return nil, err @@ -69,6 +74,11 @@ func parseConf(data []byte, envArgs string) (*TuningConf, error) { } } + // Parse custom Mac from RuntimeConfig + if conf.RuntimeConfig.Mac != "" { + conf.Mac = conf.RuntimeConfig.Mac + } + return &conf, nil } @@ -230,7 +240,7 @@ func cmdCheck(args *skel.CmdArgs) error { err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error { // Check each configured value vs what's currently in the container - for key, conf_value := range tuningConf.SysCtl { + for key, confValue := range tuningConf.SysCtl { fileName := filepath.Join("/proc/sys", strings.Replace(key, ".", "/", -1)) fileName = filepath.Clean(fileName) @@ -238,9 +248,9 @@ func cmdCheck(args *skel.CmdArgs) error { if err != nil { return err } - cur_value := strings.TrimSuffix(string(contents), "\n") - if conf_value != cur_value { - return fmt.Errorf("Error: Tuning configured value of %s is %s, current value is %s", fileName, conf_value, cur_value) + curValue := strings.TrimSuffix(string(contents), "\n") + if confValue != curValue { + return fmt.Errorf("Error: Tuning configured value of %s is %s, current value is %s", fileName, confValue, curValue) } } diff --git a/plugins/meta/tuning/tuning_test.go b/plugins/meta/tuning/tuning_test.go index 87dd2619e..9f9b3112a 100644 --- a/plugins/meta/tuning/tuning_test.go +++ b/plugins/meta/tuning/tuning_test.go @@ -379,6 +379,7 @@ var _ = Describe("tuning plugin", func() { Expect(err).NotTo(HaveOccurred()) hw, err := net.ParseMAC("c2:11:22:33:44:66") Expect(err).NotTo(HaveOccurred()) + fmt.Printf("%v, %v\n", link.Attrs().HardwareAddr, hw) Expect(link.Attrs().HardwareAddr).To(Equal(hw)) err = testutils.CmdDel(originalNS.Path(), @@ -681,4 +682,67 @@ var _ = Describe("tuning plugin", func() { }) Expect(err).NotTo(HaveOccurred()) }) + + It("configures and deconfigures mac address (from RuntimeConfig) with ADD/DEL", func() { + conf := []byte(`{ + "name": "test", + "type": "iplink", + "cniVersion": "0.3.1", + "capabilities": {"mac": true}, + "RuntimeConfig": { + "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()) + }) + })