diff --git a/plugins/meta/tuning/README.md b/plugins/meta/tuning/README.md index 631194d8f..4663bec39 100644 --- a/plugins/meta/tuning/README.md +++ b/plugins/meta/tuning/README.md @@ -46,6 +46,8 @@ The parameters, "mac", "mtu" and "promisc", changes the interface attributes as } ``` +All the interface attributes set by tuning plugin will be restored to original values on container's removal. + ## Interface attribute configuration reference * `mac` (string, optional): MAC address (i.e. hardware address) of interface @@ -71,3 +73,7 @@ The following [args conventions](https://github.com/containernetworking/cni/blob * `mtu` (integer, optional): MTU of interface * `promisc` (bool, optional): Change the promiscuous mode of interface * `sysctl` (object, optional): Change system controls +* `dataDir` (string, optional): Path to a directory to use for interfaces configuration backup + +## Files +Backup data for each interface is stored in `/var/lib/cni/tuning`. The path can be customized with the dataDir option listed above. diff --git a/plugins/meta/tuning/tuning.go b/plugins/meta/tuning/tuning.go index 581f224be..5a87b01d2 100644 --- a/plugins/meta/tuning/tuning.go +++ b/plugins/meta/tuning/tuning.go @@ -20,8 +20,11 @@ package main import ( "encoding/json" "fmt" + "io" "io/ioutil" "net" + "os" + "path" "path/filepath" "strings" @@ -37,9 +40,12 @@ import ( bv "github.com/containernetworking/plugins/pkg/utils/buildversion" ) +const defaultDataDir = "/var/lib/cni/tuning" + // TuningConf represents the network tuning configuration. type TuningConf struct { types.NetConf + DataDir string `json:"dataDir,omitempty"` SysCtl map[string]string `json:"sysctl"` Mac string `json:"mac,omitempty"` Promisc bool `json:"promisc,omitempty"` @@ -60,6 +66,14 @@ type IPAMArgs struct { Mtu *int `json:"mtu,omitempty"` } +// configToRestore will contain interface attributes that should be restored on cmdDel +type configToRestore struct { + Tuned bool `json:"tuned"` + Mac string `json:"mac,omitempty"` + Promisc *bool `json:"promisc,omitempty"` + Mtu int `json:"mtu,omitempty"` +} + // MacEnvArgs represents CNI_ARG type MacEnvArgs struct { types.CommonArgs @@ -72,6 +86,10 @@ func parseConf(data []byte, envArgs string) (*TuningConf, error) { return nil, fmt.Errorf("failed to load netconf: %v", err) } + if conf.DataDir == "" { + conf.DataDir = defaultDataDir + } + // Parse custom Mac from both env args if envArgs != "" { e := MacEnvArgs{} @@ -165,6 +183,122 @@ func changeMtu(ifName string, mtu int) error { return netlink.LinkSetMTU(link, mtu) } +func createBackup(ifName, containerID, backupPath string, tuned bool, tuningConf *TuningConf) error { + config := configToRestore{Tuned: tuned} + if tuned { + link, err := netlink.LinkByName(ifName) + if err != nil { + return fmt.Errorf("failed to get %q: %v", ifName, err) + } + if tuningConf.Mac != "" { + config.Mac = link.Attrs().HardwareAddr.String() + } + if tuningConf.Promisc { + config.Promisc = new(bool) + *config.Promisc = (link.Attrs().Promisc != 0) + } + if tuningConf.Mtu != 0 { + config.Mtu = link.Attrs().MTU + } + } + + backupDir := path.Join(backupPath, containerID) + + if _, err := os.Stat(backupDir); os.IsNotExist(err) { + if err = os.MkdirAll(backupDir, 0600); err != nil { + return fmt.Errorf("failed to create backup directory: %v", err) + } + } + + data, err := json.MarshalIndent(config, "", " ") + if err != nil { + return fmt.Errorf("failed to marshall data for %q: %v", ifName, err) + } + if err = ioutil.WriteFile(path.Join(backupDir, ifName+".json"), data, 0600); err != nil { + return fmt.Errorf("failed to save file %s.json: %v", ifName, err) + } + + return nil +} + +func restoreBackup(ifName, containerID, backupPath string) error { + backupDir := path.Join(backupPath, containerID) + filePath := path.Join(backupDir, ifName+".json") + + file, err := ioutil.ReadFile(filePath) + if err != nil { + return fmt.Errorf("failed to open file %q: %v", filePath, err) + } + + config := configToRestore{} + if err = json.Unmarshal([]byte(file), &config); err != nil { + return fmt.Errorf("failed to unmarshall file %q: %v", filePath, err) + } + + var errStr []string + + if config.Tuned { + _, err = netlink.LinkByName(ifName) + if err != nil { + return fmt.Errorf("failed to get %q: %v", ifName, err) + } + + if config.Mtu != 0 { + if err = changeMtu(ifName, config.Mtu); err != nil { + err = fmt.Errorf("failed to restore MAC address: %v", err) + errStr = append(errStr, err.Error()) + } + } + if config.Mac != "" { + if err = changeMacAddr(ifName, config.Mac); err != nil { + err = fmt.Errorf("failed to restore MAC address: %v", err) + errStr = append(errStr, err.Error()) + } + } + if config.Promisc != nil { + if err = changePromisc(ifName, *config.Promisc); err != nil { + err = fmt.Errorf("failed to restore promiscuous mode: %v", err) + errStr = append(errStr, err.Error()) + } + } + } + + if len(errStr) > 0 { + return fmt.Errorf(strings.Join(errStr, "; ")) + } + + if err = os.Remove(filePath); err != nil { + return fmt.Errorf("failed to remove file %v: %v", filePath, err) + } + + if err = delDirIfEmpty(backupDir); err != nil { + return err + } + + if err = delDirIfEmpty(backupPath); err != nil { + return err + } + + return nil +} + +func delDirIfEmpty(path string) error { + dir, err := os.Open(path) + if err != nil { + return err + } + defer dir.Close() + + _, err = dir.Readdir(1) + if err == io.EOF { + if err = os.Remove(path); err != nil { + return fmt.Errorf("failed to remove directory %v: %v", path, err) + } + } + + return nil +} + func cmdAdd(args *skel.CmdArgs) error { tuningConf, err := parseConf(args.StdinData, args.Args) if err != nil { @@ -173,7 +307,7 @@ func cmdAdd(args *skel.CmdArgs) error { // Parse previous result. if tuningConf.RawPrevResult == nil { - return fmt.Errorf("Required prevResult missing") + return fmt.Errorf("required prevResult missing") } if err := version.ParsePrevResult(&tuningConf.NetConf); err != nil { @@ -189,6 +323,7 @@ func cmdAdd(args *skel.CmdArgs) error { // network namespace before writing on it. err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error { + for key, value := range tuningConf.SysCtl { fileName := filepath.Join("/proc/sys", strings.Replace(key, ".", "/", -1)) fileName = filepath.Clean(fileName) @@ -205,6 +340,11 @@ func cmdAdd(args *skel.CmdArgs) error { } } + isTuned := (tuningConf.Mac != "" || tuningConf.Mtu != 0 || tuningConf.Promisc) + if err = createBackup(args.IfName, args.ContainerID, tuningConf.DataDir, isTuned, tuningConf); err != nil { + return err + } + if tuningConf.Mac != "" { if err = changeMacAddr(args.IfName, tuningConf.Mac); err != nil { return err @@ -219,7 +359,7 @@ func cmdAdd(args *skel.CmdArgs) error { updateResultsMacAddr(*tuningConf, args.IfName, tuningConf.Mac) } - if tuningConf.Promisc != false { + if tuningConf.Promisc { if err = changePromisc(args.IfName, true); err != nil { return err } @@ -239,11 +379,18 @@ func cmdAdd(args *skel.CmdArgs) error { return types.PrintResult(tuningConf.PrevResult, tuningConf.CNIVersion) } +// cmdDel will restore NIC attributes to the original ones when called func cmdDel(args *skel.CmdArgs) error { - // TODO: the settings are not reverted to the previous values. Reverting the - // settings is not useful when the whole container goes away but it could be - // useful in scenarios where plugins are added and removed at runtime. - return nil + tuningConf, err := parseConf(args.StdinData, args.Args) + if err != nil { + return err + } + + err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error { + // MAC address, MTU and promiscuous mode settings will be restored + return restoreBackup(args.IfName, args.ContainerID, tuningConf.DataDir) + }) + return err } func main() { @@ -258,7 +405,7 @@ func cmdCheck(args *skel.CmdArgs) error { // Parse previous result. if tuningConf.RawPrevResult == nil { - return fmt.Errorf("Required prevResult missing") + return fmt.Errorf("required prevResult missing") } if err := version.ParsePrevResult(&tuningConf.NetConf); err != nil { @@ -282,42 +429,44 @@ func cmdCheck(args *skel.CmdArgs) error { } 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) + return fmt.Errorf("error: Tuning configured value of %s is %s, current value is %s", fileName, confValue, curValue) } } link, err := netlink.LinkByName(args.IfName) if err != nil { - return fmt.Errorf("Cannot find container link %v", args.IfName) + return fmt.Errorf("cannot find container link %v", args.IfName) } if tuningConf.Mac != "" { if tuningConf.Mac != link.Attrs().HardwareAddr.String() { - return fmt.Errorf("Error: Tuning configured Ethernet of %s is %s, current value is %s", + return fmt.Errorf("error: Tuning configured Ethernet of %s is %s, current value is %s", args.IfName, tuningConf.Mac, link.Attrs().HardwareAddr) } } if tuningConf.Promisc { if link.Attrs().Promisc == 0 { - return fmt.Errorf("Error: Tuning link %s configured promisc is %v, current value is %d", + return fmt.Errorf("error: Tuning link %s configured promisc is %v, current value is %d", args.IfName, tuningConf.Promisc, link.Attrs().Promisc) } } else { if link.Attrs().Promisc != 0 { - return fmt.Errorf("Error: Tuning link %s configured promisc is %v, current value is %d", + return fmt.Errorf("error: Tuning link %s configured promisc is %v, current value is %d", args.IfName, tuningConf.Promisc, link.Attrs().Promisc) } } if tuningConf.Mtu != 0 { if tuningConf.Mtu != link.Attrs().MTU { - return fmt.Errorf("Error: Tuning configured MTU of %s is %d, current value is %d", + return fmt.Errorf("error: Tuning configured MTU of %s is %d, current value is %d", args.IfName, tuningConf.Mtu, link.Attrs().MTU) } } + return nil }) + if err != nil { return err } diff --git a/plugins/meta/tuning/tuning_test.go b/plugins/meta/tuning/tuning_test.go index 658332db2..b3f2774ac 100644 --- a/plugins/meta/tuning/tuning_test.go +++ b/plugins/meta/tuning/tuning_test.go @@ -17,13 +17,13 @@ package main import ( "encoding/json" "fmt" + "net" "github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" "github.com/containernetworking/plugins/pkg/ns" "github.com/containernetworking/plugins/pkg/testutils" - "net" "github.com/vishvananda/netlink" @@ -77,6 +77,7 @@ func buildOneConfig(name, cniVersion string, orig *TuningConf, prevResult types. var _ = Describe("tuning plugin", func() { var originalNS ns.NetNS const IFNAME string = "dummy0" + var beforeConf configToRestore BeforeEach(func() { // Create a new NetNS so we don't modify the host @@ -93,8 +94,14 @@ var _ = Describe("tuning plugin", func() { }, }) Expect(err).NotTo(HaveOccurred()) - _, err = netlink.LinkByName(IFNAME) + link, err := netlink.LinkByName(IFNAME) Expect(err).NotTo(HaveOccurred()) + + beforeConf.Tuned = true + beforeConf.Mac = link.Attrs().HardwareAddr.String() + beforeConf.Mtu = link.Attrs().MTU + beforeConf.Promisc = new(bool) + *beforeConf.Promisc = (link.Attrs().Promisc != 0) return nil }) Expect(err).NotTo(HaveOccurred()) @@ -106,26 +113,26 @@ var _ = Describe("tuning plugin", func() { It("passes prevResult through unchanged", func() { conf := []byte(`{ - "name": "test", - "type": "tuning", - "cniVersion": "0.3.1", - "sysctl": { - "net.ipv4.conf.all.log_martians": "1" - }, - "prevResult": { - "interfaces": [ - {"name": "dummy0", "sandbox":"netns"} - ], - "ips": [ - { - "version": "4", - "address": "10.0.0.2/24", - "gateway": "10.0.0.1", - "interface": 0 - } - ] - } -}`) + "name": "test", + "type": "tuning", + "cniVersion": "0.3.1", + "sysctl": { + "net.ipv4.conf.all.log_martians": "1" + }, + "prevResult": { + "interfaces": [ + {"name": "dummy0", "sandbox":"netns"} + ], + "ips": [ + { + "version": "4", + "address": "10.0.0.2/24", + "gateway": "10.0.0.1", + "interface": 0 + } + ] + } + }`) targetNs, err := testutils.NewNS() Expect(err).NotTo(HaveOccurred()) @@ -138,6 +145,8 @@ var _ = Describe("tuning plugin", func() { StdinData: conf, } + beforeConf = configToRestore{Tuned: false} + err = originalNS.Do(func(ns.NetNS) error { defer GinkgoRecover() @@ -153,6 +162,11 @@ var _ = Describe("tuning plugin", func() { 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")) + + err = testutils.CmdDel(originalNS.Path(), + args.ContainerID, "", func() error { return cmdDel(args) }) + Expect(err).NotTo(HaveOccurred()) + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -160,24 +174,24 @@ var _ = Describe("tuning plugin", func() { It("configures and deconfigures promiscuous mode with ADD/DEL", func() { conf := []byte(`{ - "name": "test", - "type": "iplink", - "cniVersion": "0.3.1", - "promisc": true, - "prevResult": { - "interfaces": [ - {"name": "dummy0", "sandbox":"netns"} - ], - "ips": [ - { - "version": "4", - "address": "10.0.0.2/24", - "gateway": "10.0.0.1", - "interface": 0 - } - ] - } -}`) + "name": "test", + "type": "iplink", + "cniVersion": "0.3.1", + "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", @@ -210,6 +224,10 @@ var _ = Describe("tuning plugin", func() { args.ContainerID, "", func() error { return cmdDel(args) }) Expect(err).NotTo(HaveOccurred()) + link, err = netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().Promisc != 0).To(Equal(*beforeConf.Promisc)) + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -217,28 +235,28 @@ var _ = Describe("tuning plugin", func() { 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 - } - ] - } -}`) + "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", @@ -271,6 +289,10 @@ var _ = Describe("tuning plugin", func() { args.ContainerID, "", func() error { return cmdDel(args) }) Expect(err).NotTo(HaveOccurred()) + link, err = netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().Promisc != 0).To(Equal(*beforeConf.Promisc)) + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -278,24 +300,24 @@ var _ = Describe("tuning plugin", func() { It("configures and deconfigures mtu with ADD/DEL", func() { conf := []byte(`{ - "name": "test", - "type": "iplink", - "cniVersion": "0.3.1", - "mtu": 1454, - "prevResult": { - "interfaces": [ - {"name": "dummy0", "sandbox":"netns"} - ], - "ips": [ - { - "version": "4", - "address": "10.0.0.2/24", - "gateway": "10.0.0.1", - "interface": 0 - } - ] - } -}`) + "name": "test", + "type": "iplink", + "cniVersion": "0.3.1", + "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", @@ -328,6 +350,10 @@ var _ = Describe("tuning plugin", func() { args.ContainerID, "", func() error { return cmdDel(args) }) Expect(err).NotTo(HaveOccurred()) + link, err = netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().MTU).To(Equal(beforeConf.Mtu)) + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -335,28 +361,28 @@ var _ = Describe("tuning plugin", func() { 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 - } - ] - } -}`) + "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", @@ -389,6 +415,10 @@ var _ = Describe("tuning plugin", func() { args.ContainerID, "", func() error { return cmdDel(args) }) Expect(err).NotTo(HaveOccurred()) + link, err = netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().MTU).To(Equal(beforeConf.Mtu)) + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -396,24 +426,24 @@ var _ = Describe("tuning plugin", func() { It("configures and deconfigures mac address (from conf file) with ADD/DEL", func() { conf := []byte(`{ - "name": "test", - "type": "iplink", - "cniVersion": "0.3.1", - "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 - } - ] - } -}`) + "name": "test", + "type": "iplink", + "cniVersion": "0.3.1", + "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", @@ -448,6 +478,10 @@ var _ = Describe("tuning plugin", func() { args.ContainerID, "", func() error { return cmdDel(args) }) Expect(err).NotTo(HaveOccurred()) + link, err = netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().HardwareAddr.String()).To(Equal(beforeConf.Mac)) + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -455,28 +489,28 @@ var _ = Describe("tuning plugin", func() { 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 - } - ] - } -}`) + "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", @@ -511,6 +545,10 @@ var _ = Describe("tuning plugin", func() { args.ContainerID, "", func() error { return cmdDel(args) }) Expect(err).NotTo(HaveOccurred()) + link, err = netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().HardwareAddr.String()).To(Equal(beforeConf.Mac)) + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -518,23 +556,23 @@ var _ = Describe("tuning plugin", func() { It("configures and deconfigures mac address (from CNI_ARGS) with ADD/DEL", func() { conf := []byte(`{ - "name": "test", - "type": "iplink", - "cniVersion": "0.3.1", - "prevResult": { - "interfaces": [ - {"name": "dummy0", "sandbox":"netns"} - ], - "ips": [ - { - "version": "4", - "address": "10.0.0.2/24", - "gateway": "10.0.0.1", - "interface": 0 - } - ] - } -}`) + "name": "test", + "type": "iplink", + "cniVersion": "0.3.1", + "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", @@ -571,6 +609,10 @@ var _ = Describe("tuning plugin", func() { args.ContainerID, "", func() error { return cmdDel(args) }) Expect(err).NotTo(HaveOccurred()) + link, err = netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().HardwareAddr.String()).To(Equal(beforeConf.Mac)) + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -578,24 +620,24 @@ var _ = Describe("tuning plugin", func() { It("configures and deconfigures promiscuous mode with CNI 0.4.0 ADD/DEL", func() { conf := []byte(`{ - "name": "test", - "type": "iplink", - "cniVersion": "0.4.0", - "promisc": true, - "prevResult": { - "interfaces": [ - {"name": "dummy0", "sandbox":"netns"} - ], - "ips": [ - { - "version": "4", - "address": "10.0.0.2/24", - "gateway": "10.0.0.1", - "interface": 0 - } - ] - } -}`) + "name": "test", + "type": "iplink", + "cniVersion": "0.4.0", + "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", @@ -643,6 +685,10 @@ var _ = Describe("tuning plugin", func() { args.ContainerID, "", func() error { return cmdDel(args) }) Expect(err).NotTo(HaveOccurred()) + link, err = netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().Promisc != 0).To(Equal(*beforeConf.Promisc)) + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -650,24 +696,24 @@ var _ = Describe("tuning plugin", func() { It("configures and deconfigures mtu with CNI 0.4.0 ADD/DEL", func() { conf := []byte(`{ - "name": "test", - "type": "iplink", - "cniVersion": "0.4.0", - "mtu": 1454, - "prevResult": { - "interfaces": [ - {"name": "dummy0", "sandbox":"netns"} - ], - "ips": [ - { - "version": "4", - "address": "10.0.0.2/24", - "gateway": "10.0.0.1", - "interface": 0 - } - ] - } -}`) + "name": "test", + "type": "iplink", + "cniVersion": "0.4.0", + "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", @@ -715,6 +761,10 @@ var _ = Describe("tuning plugin", func() { args.ContainerID, "", func() error { return cmdDel(args) }) Expect(err).NotTo(HaveOccurred()) + link, err = netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().MTU).To(Equal(beforeConf.Mtu)) + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -722,24 +772,24 @@ var _ = Describe("tuning plugin", func() { It("configures and deconfigures mac address (from conf file) with CNI v4.0 ADD/DEL", func() { conf := []byte(`{ - "name": "test", - "type": "iplink", - "cniVersion": "0.4.0", - "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 - } - ] - } -}`) + "name": "test", + "type": "iplink", + "cniVersion": "0.4.0", + "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", @@ -789,6 +839,10 @@ var _ = Describe("tuning plugin", func() { args.ContainerID, "", func() error { return cmdDel(args) }) Expect(err).NotTo(HaveOccurred()) + link, err = netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().HardwareAddr.String()).To(Equal(beforeConf.Mac)) + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -796,23 +850,23 @@ var _ = Describe("tuning plugin", func() { It("configures and deconfigures mac address (from CNI_ARGS) with CNI v4 ADD/DEL", func() { conf := []byte(`{ - "name": "test", - "type": "iplink", - "cniVersion": "0.4.0", - "prevResult": { - "interfaces": [ - {"name": "dummy0", "sandbox":"netns"} - ], - "ips": [ - { - "version": "4", - "address": "10.0.0.2/24", - "gateway": "10.0.0.1", - "interface": 0 - } - ] - } -}`) + "name": "test", + "type": "iplink", + "cniVersion": "0.4.0", + "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", @@ -863,6 +917,10 @@ var _ = Describe("tuning plugin", func() { args.ContainerID, "", func() error { return cmdDel(args) }) Expect(err).NotTo(HaveOccurred()) + link, err = netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().HardwareAddr.String()).To(Equal(beforeConf.Mac)) + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -870,13 +928,79 @@ var _ = Describe("tuning plugin", func() { 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()) + + link, err = netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().HardwareAddr.String()).To(Equal(beforeConf.Mac)) + + return nil + }) + Expect(err).NotTo(HaveOccurred()) + }) + + It("configures and deconfigures mac address, promisc mode and MTU (from conf file) with custom dataDir", func() { + conf := []byte(`{ "name": "test", "type": "iplink", - "cniVersion": "0.3.1", - "capabilities": {"mac": true}, - "RuntimeConfig": { - "mac": "c2:11:22:33:44:55" - }, + "cniVersion": "0.4.0", + "mac": "c2:11:22:33:44:77", + "promisc": true, + "mtu": 4000, + "dataDir": "/tmp/tuning-test", "prevResult": { "interfaces": [ {"name": "dummy0", "sandbox":"netns"} @@ -917,17 +1041,41 @@ var _ = Describe("tuning plugin", func() { link, err := netlink.LinkByName(IFNAME) Expect(err).NotTo(HaveOccurred()) - hw, err := net.ParseMAC("c2:11:22:33:44:55") + hw, err := net.ParseMAC("c2:11:22:33:44:77") Expect(err).NotTo(HaveOccurred()) Expect(link.Attrs().HardwareAddr).To(Equal(hw)) + Expect(link.Attrs().Promisc).To(Equal(1)) + Expect(link.Attrs().MTU).To(Equal(4000)) + + Expect("/tmp/tuning-test/dummy/dummy0.json").Should(BeAnExistingFile()) + + n := &TuningConf{} + err = json.Unmarshal([]byte(conf), &n) + Expect(err).NotTo(HaveOccurred()) + + cniVersion := "0.4.0" + _, confString, err := buildOneConfig("testConfig", cniVersion, n, r) + Expect(err).NotTo(HaveOccurred()) + + args.StdinData = confString + + err = testutils.CmdCheckWithArgs(args, func() error { + return cmdCheck(args) + }) + Expect(err).NotTo(HaveOccurred()) err = testutils.CmdDel(originalNS.Path(), args.ContainerID, "", func() error { return cmdDel(args) }) Expect(err).NotTo(HaveOccurred()) + link, err = netlink.LinkByName(IFNAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().HardwareAddr.String()).To(Equal(beforeConf.Mac)) + Expect(link.Attrs().MTU).To(Equal(beforeConf.Mtu)) + Expect(link.Attrs().Promisc != 0).To(Equal(*beforeConf.Promisc)) + return nil }) Expect(err).NotTo(HaveOccurred()) }) - })