{
"ImportPath": "github.com/containernetworking/cni/pkg/invoke",
"Comment": "v0.5.0",
- "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4"
+ "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f"
},
{
"ImportPath": "github.com/containernetworking/cni/pkg/ip",
"Comment": "v0.5.0",
- "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4"
+ "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f"
},
{
"ImportPath": "github.com/containernetworking/cni/pkg/ipam",
"Comment": "v0.5.0",
- "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4"
+ "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f"
},
{
"ImportPath": "github.com/containernetworking/cni/pkg/ns",
"Comment": "v0.5.0",
- "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4"
+ "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f"
},
{
"ImportPath": "github.com/containernetworking/cni/pkg/skel",
"Comment": "v0.5.0",
- "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4"
+ "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f"
},
{
"ImportPath": "github.com/containernetworking/cni/pkg/testutils",
"Comment": "v0.5.0",
- "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4"
+ "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f"
},
{
"ImportPath": "github.com/containernetworking/cni/pkg/types",
"Comment": "v0.5.0",
- "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4"
+ "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f"
},
{
"ImportPath": "github.com/containernetworking/cni/pkg/types/020",
"Comment": "v0.5.0",
- "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4"
+ "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f"
},
{
"ImportPath": "github.com/containernetworking/cni/pkg/types/current",
"Comment": "v0.5.0",
- "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4"
+ "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f"
+ },
+ {
+ "ImportPath": "github.com/containernetworking/cni/pkg/utils",
+ "Comment": "v0.5.0",
+ "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f"
},
{
"ImportPath": "github.com/containernetworking/cni/pkg/utils/hwaddr",
"Comment": "v0.5.0",
- "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4"
+ "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f"
+ },
+ {
+ "ImportPath": "github.com/containernetworking/cni/pkg/utils/sysctl",
+ "Comment": "v0.5.0",
+ "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f"
},
{
"ImportPath": "github.com/containernetworking/cni/pkg/version",
"Comment": "v0.5.0",
- "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4"
+ "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f"
},
{
"ImportPath": "github.com/coreos/go-iptables/iptables",
VersionDecoder: versionDecoder,
}
pluginPath = "/some/plugin/path"
- netconf = []byte(`{ "some": "stdin", "cniVersion": "0.3.0" }`)
+ netconf = []byte(`{ "some": "stdin", "cniVersion": "0.3.1" }`)
cniargs = &fakes.CNIArgs{}
cniargs.AsEnvCall.Returns.Env = []string{"SOME=ENV"}
})
"CNI_PATH=/some/bin/path",
"CNI_IFNAME=some-eth0",
}
- stdin = []byte(`{"some":"stdin-json", "cniVersion": "0.3.0"}`)
+ stdin = []byte(`{"some":"stdin-json", "cniVersion": "0.3.1"}`)
execer = &invoke.RawExec{}
})
import (
"crypto/rand"
+ "errors"
"fmt"
"net"
"os"
"github.com/vishvananda/netlink"
)
+var (
+ ErrLinkNotFound = errors.New("link not found")
+)
+
func makeVethPair(name, peer string, mtu int) (netlink.Link, error) {
veth := &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{
return err
}
-// SetupVeth sets up a virtual ethernet link.
-// Should be in container netns, and will switch back to hostNS to set the host
-// veth end up.
-func SetupVeth(contVethName string, mtu int, hostNS ns.NetNS) (hostVeth, contVeth netlink.Link, err error) {
- var hostVethName string
- hostVethName, contVeth, err = makeVeth(contVethName, mtu)
+func ifaceFromNetlinkLink(l netlink.Link) net.Interface {
+ a := l.Attrs()
+ return net.Interface{
+ Index: a.Index,
+ MTU: a.MTU,
+ Name: a.Name,
+ HardwareAddr: a.HardwareAddr,
+ Flags: a.Flags,
+ }
+}
+
+// SetupVeth sets up a pair of virtual ethernet devices.
+// Call SetupVeth from inside the container netns. It will create both veth
+// devices and move the host-side veth into the provided hostNS namespace.
+// On success, SetupVeth returns (hostVeth, containerVeth, nil)
+func SetupVeth(contVethName string, mtu int, hostNS ns.NetNS) (net.Interface, net.Interface, error) {
+ hostVethName, contVeth, err := makeVeth(contVethName, mtu)
if err != nil {
- return
+ return net.Interface{}, net.Interface{}, err
}
if err = netlink.LinkSetUp(contVeth); err != nil {
- err = fmt.Errorf("failed to set %q up: %v", contVethName, err)
- return
+ return net.Interface{}, net.Interface{}, fmt.Errorf("failed to set %q up: %v", contVethName, err)
}
- hostVeth, err = netlink.LinkByName(hostVethName)
+ hostVeth, err := netlink.LinkByName(hostVethName)
if err != nil {
- err = fmt.Errorf("failed to lookup %q: %v", hostVethName, err)
- return
+ return net.Interface{}, net.Interface{}, fmt.Errorf("failed to lookup %q: %v", hostVethName, err)
}
if err = netlink.LinkSetNsFd(hostVeth, int(hostNS.Fd())); err != nil {
- err = fmt.Errorf("failed to move veth to host netns: %v", err)
- return
+ return net.Interface{}, net.Interface{}, fmt.Errorf("failed to move veth to host netns: %v", err)
}
err = hostNS.Do(func(_ ns.NetNS) error {
}
return nil
})
- return
+ if err != nil {
+ return net.Interface{}, net.Interface{}, err
+ }
+ return ifaceFromNetlinkLink(hostVeth), ifaceFromNetlinkLink(contVeth), nil
}
// DelLinkByName removes an interface link.
func DelLinkByNameAddr(ifName string, family int) (*net.IPNet, error) {
iface, err := netlink.LinkByName(ifName)
if err != nil {
+ if err != nil && err.Error() == "Link not found" {
+ return nil, ErrLinkNotFound
+ }
return nil, fmt.Errorf("failed to lookup %q: %v", ifName, err)
}
hostNetNS ns.NetNS
containerNetNS ns.NetNS
ifaceCounter int = 0
- hostVeth netlink.Link
- containerVeth netlink.Link
+ hostVeth net.Interface
+ containerVeth net.Interface
hostVethName string
containerVethName string
}
Expect(err).NotTo(HaveOccurred())
- hostVethName = hostVeth.Attrs().Name
- containerVethName = containerVeth.Attrs().Name
+ hostVethName = hostVeth.Name
+ containerVethName = containerVeth.Name
return nil
})
containerVethFromName, err := netlink.LinkByName(containerVethName)
Expect(err).NotTo(HaveOccurred())
- Expect(containerVethFromName.Attrs().Index).To(Equal(containerVeth.Attrs().Index))
+ Expect(containerVethFromName.Attrs().Index).To(Equal(containerVeth.Index))
return nil
})
hostVethFromName, err := netlink.LinkByName(hostVethName)
Expect(err).NotTo(HaveOccurred())
- Expect(hostVethFromName.Attrs().Index).To(Equal(hostVeth.Attrs().Index))
+ Expect(hostVethFromName.Attrs().Index).To(Equal(hostVeth.Index))
return nil
})
})
})
+ Context("deleting an non-existent device", func() {
+ It("returns known error", func() {
+ _ = containerNetNS.Do(func(ns.NetNS) error {
+ defer GinkgoRecover()
+
+ // This string should match the expected error codes in the cmdDel functions of some of the plugins
+ _, err := ip.DelLinkByNameAddr("THIS_DONT_EXIST", netlink.FAMILY_V4)
+ Expect(err).To(Equal(ip.ErrLinkNotFound))
+
+ return nil
+ })
+ })
+ })
+
Context("when there is no name available for the host-side", func() {
BeforeEach(func() {
//adding different interface to container ns
hostVeth, _, err := ip.SetupVeth(containerVethName, mtu, hostNetNS)
Expect(err).NotTo(HaveOccurred())
- hostVethName = hostVeth.Attrs().Name
+ hostVethName = hostVeth.Name
return nil
})
"github.com/containernetworking/cni/pkg/types"
)
-const implementedSpecVersion string = "0.2.0"
+const ImplementedSpecVersion string = "0.2.0"
-var SupportedVersions = []string{"", "0.1.0", implementedSpecVersion}
+var SupportedVersions = []string{"", "0.1.0", ImplementedSpecVersion}
// Compatibility types for CNI version 0.1.0 and 0.2.0
func GetResult(r types.Result) (*Result, error) {
// We expect version 0.1.0/0.2.0 results
- result020, err := r.GetAsVersion(implementedSpecVersion)
+ result020, err := r.GetAsVersion(ImplementedSpecVersion)
if err != nil {
return nil, err
}
// Result is what gets returned from the plugin (via stdout) to the caller
type Result struct {
- IP4 *IPConfig `json:"ip4,omitempty"`
- IP6 *IPConfig `json:"ip6,omitempty"`
- DNS types.DNS `json:"dns,omitempty"`
+ CNIVersion string `json:"cniVersion,omitempty"`
+ IP4 *IPConfig `json:"ip4,omitempty"`
+ IP6 *IPConfig `json:"ip6,omitempty"`
+ DNS types.DNS `json:"dns,omitempty"`
}
func (r *Result) Version() string {
- return implementedSpecVersion
+ return ImplementedSpecVersion
}
func (r *Result) GetAsVersion(version string) (types.Result, error) {
for _, supportedVersion := range SupportedVersions {
if version == supportedVersion {
+ r.CNIVersion = version
return r, nil
}
}
"github.com/containernetworking/cni/pkg/types/020"
)
-const implementedSpecVersion string = "0.3.0"
+const ImplementedSpecVersion string = "0.3.1"
-var SupportedVersions = []string{implementedSpecVersion}
+var SupportedVersions = []string{"0.3.0", ImplementedSpecVersion}
func NewResult(data []byte) (types.Result, error) {
result := &Result{}
}
func GetResult(r types.Result) (*Result, error) {
- resultCurrent, err := r.GetAsVersion(implementedSpecVersion)
+ resultCurrent, err := r.GetAsVersion(ImplementedSpecVersion)
if err != nil {
return nil, err
}
}
newResult := &Result{
- DNS: oldResult.DNS,
- Routes: []*types.Route{},
+ CNIVersion: ImplementedSpecVersion,
+ DNS: oldResult.DNS,
+ Routes: []*types.Route{},
}
if oldResult.IP4 != nil {
if !ok {
return nil, fmt.Errorf("failed to convert result")
}
+ newResult.CNIVersion = ImplementedSpecVersion
return newResult, nil
}
}
}
}
- return nil, fmt.Errorf("unsupported CNI result version %q", version)
+ return nil, fmt.Errorf("unsupported CNI result22 version %q", version)
}
// Result is what gets returned from the plugin (via stdout) to the caller
type Result struct {
+ CNIVersion string `json:"cniVersion,omitempty"`
Interfaces []*Interface `json:"interfaces,omitempty"`
IPs []*IPConfig `json:"ips,omitempty"`
Routes []*types.Route `json:"routes,omitempty"`
// Convert to the older 0.2.0 CNI spec Result type
func (r *Result) convertTo020() (*types020.Result, error) {
oldResult := &types020.Result{
- DNS: r.DNS,
+ CNIVersion: types020.ImplementedSpecVersion,
+ DNS: r.DNS,
}
for _, ip := range r.IPs {
}
func (r *Result) Version() string {
- return implementedSpecVersion
+ return ImplementedSpecVersion
}
func (r *Result) GetAsVersion(version string) (types.Result, error) {
switch version {
- case implementedSpecVersion:
+ case "0.3.0", ImplementedSpecVersion:
+ r.CNIVersion = version
return r, nil
case types020.SupportedVersions[0], types020.SupportedVersions[1], types020.SupportedVersions[2]:
return r.convertTo020()
}
- return nil, fmt.Errorf("cannot convert version 0.3.0 to %q", version)
+ return nil, fmt.Errorf("cannot convert version 0.3.x to %q", version)
}
func (r *Result) Print() error {
--- /dev/null
+// Copyright 2016 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package sysctl
+
+import (
+ "fmt"
+ "io/ioutil"
+ "path/filepath"
+ "strings"
+)
+
+// Sysctl provides a method to set/get values from /proc/sys - in linux systems
+// new interface to set/get values of variables formerly handled by sysctl syscall
+// If optional `params` have only one string value - this function will
+// set this value into corresponding sysctl variable
+func Sysctl(name string, params ...string) (string, error) {
+ if len(params) > 1 {
+ return "", fmt.Errorf("unexcepted additional parameters")
+ } else if len(params) == 1 {
+ return setSysctl(name, params[0])
+ }
+ return getSysctl(name)
+}
+
+func getSysctl(name string) (string, error) {
+ fullName := filepath.Join("/proc/sys", strings.Replace(name, ".", "/", -1))
+ fullName = filepath.Clean(fullName)
+ data, err := ioutil.ReadFile(fullName)
+ if err != nil {
+ return "", err
+ }
+
+ return string(data[:len(data)-1]), nil
+}
+
+func setSysctl(name, value string) (string, error) {
+ fullName := filepath.Join("/proc/sys", strings.Replace(name, ".", "/", -1))
+ fullName = filepath.Clean(fullName)
+ if err := ioutil.WriteFile(fullName, []byte(value), 0644); err != nil {
+ return "", err
+ }
+
+ return getSysctl(name)
+}
--- /dev/null
+// Copyright 2016 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package utils
+
+import (
+ "crypto/sha512"
+ "fmt"
+)
+
+const (
+ maxChainLength = 28
+ chainPrefix = "CNI-"
+ prefixLength = len(chainPrefix)
+)
+
+// Generates a chain name to be used with iptables.
+// Ensures that the generated chain name is exactly
+// maxChainLength chars in length
+func FormatChainName(name string, id string) string {
+ chainBytes := sha512.Sum512([]byte(name + id))
+ chain := fmt.Sprintf("%s%x", chainPrefix, chainBytes)
+ return chain[:maxChainLength]
+}
+
+// FormatComment returns a comment used for easier
+// rule identification within iptables.
+func FormatComment(name string, id string) string {
+ return fmt.Sprintf("name: %q id: %q", name, id)
+}
--- /dev/null
+// Copyright 2016 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package utils_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+
+ "testing"
+)
+
+func TestUtils(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Utils Suite")
+}
--- /dev/null
+// Copyright 2016 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package utils
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("Utils", func() {
+ It("must format a short name", func() {
+ chain := FormatChainName("test", "1234")
+ Expect(len(chain)).To(Equal(maxChainLength))
+ Expect(chain).To(Equal("CNI-2bbe0c48b91a7d1b8a6753a8"))
+ })
+
+ It("must truncate a long name", func() {
+ chain := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
+ Expect(len(chain)).To(Equal(maxChainLength))
+ Expect(chain).To(Equal("CNI-374f33fe84ab0ed84dcdebe3"))
+ })
+
+ It("must be predictable", func() {
+ chain1 := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
+ chain2 := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
+ Expect(len(chain1)).To(Equal(maxChainLength))
+ Expect(len(chain2)).To(Equal(maxChainLength))
+ Expect(chain1).To(Equal(chain2))
+ })
+
+ It("must change when a character changes", func() {
+ chain1 := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
+ chain2 := FormatChainName("testalongnamethatdoesnotmakesense", "1235")
+ Expect(len(chain1)).To(Equal(maxChainLength))
+ Expect(len(chain2)).To(Equal(maxChainLength))
+ Expect(chain1).To(Equal("CNI-374f33fe84ab0ed84dcdebe3"))
+ Expect(chain1).NotTo(Equal(chain2))
+ })
+})
// Current reports the version of the CNI spec implemented by this library
func Current() string {
- return "0.3.0"
+ return "0.3.1"
}
// Legacy PluginInfo describes a plugin that is backwards compatible with the
// Any future CNI spec versions which meet this definition should be added to
// this list.
var Legacy = PluginSupports("0.1.0", "0.2.0")
-var All = PluginSupports("0.1.0", "0.2.0", "0.3.0")
+var All = PluginSupports("0.1.0", "0.2.0", "0.3.0", "0.3.1")
var resultFactories = []struct {
supportedVersions []string