Do not use netns as ID or for entropy
authorEugene Yakubovich <eugene.yakubovich@coreos.com>
Tue, 5 May 2015 20:35:20 +0000 (13:35 -0700)
committerEugene Yakubovich <eugene.yakubovich@coreos.com>
Fri, 8 May 2015 22:02:23 +0000 (15:02 -0700)
ContainerID is now required so use that
or generate random bytes.

Fixes #5

pkg/ip/link.go
plugins/ipam/host-local/main.go
plugins/main/bridge/bridge.go
plugins/main/ipvlan/ipvlan.go
plugins/main/macvlan/macvlan.go
plugins/main/veth/veth.go
scripts/docker-run.sh
scripts/exec-plugins.sh
scripts/priv-net-run.sh

index 59865cf..c99f4f3 100644 (file)
@@ -15,7 +15,7 @@
 package ip
 
 import (
-       "crypto/sha512"
+       "crypto/rand"
        "fmt"
        "net"
        "os"
@@ -23,7 +23,7 @@ import (
        "github.com/appc/cni/Godeps/_workspace/src/github.com/vishvananda/netlink"
 )
 
-func makeVeth(name, peer string, mtu int) (netlink.Link, error) {
+func makeVethPair(name, peer string, mtu int) (netlink.Link, error) {
        veth := &netlink.Veth{
                LinkAttrs: netlink.LinkAttrs{
                        Name:  name,
@@ -39,37 +39,65 @@ func makeVeth(name, peer string, mtu int) (netlink.Link, error) {
        return veth, nil
 }
 
+func makeVeth(name string, mtu int) (peerName string, veth netlink.Link, err error) {
+       for i := 0; i < 10; i++ {
+               peerName, err = RandomVethName()
+               if err != nil {
+                       return
+               }
+
+               veth, err = makeVethPair(name, peerName, mtu)
+               switch {
+               case err == nil:
+                       return
+
+               case os.IsExist(err):
+                       continue
+
+               default:
+                       err = fmt.Errorf("failed to make veth pair: %v", err)
+                       return
+               }
+       }
+
+       // should really never be hit
+       err = fmt.Errorf("failed to find a unique veth name")
+       return
+}
+
 // RandomVethName returns string "veth" with random prefix (hashed from entropy)
-func RandomVethName(entropy string) string {
-       h := sha512.New()
-       h.Write([]byte(entropy))
-       return fmt.Sprintf("veth%x", h.Sum(nil)[:5])
+func RandomVethName() (string, error) {
+       entropy := make([]byte, 4)
+       _, err := rand.Reader.Read(entropy)
+       if err != nil {
+               return "", fmt.Errorf("failed to generate random veth name: %v", err)
+       }
+
+       // NetworkManager (recent versions) will ignore veth devices that start with "veth"
+       return fmt.Sprintf("veth%x", entropy), nil
 }
 
 // SetupVeth sets up a virtual ethernet link.
 // Should be in container netns.
-// TODO(eyakubovich): get rid of entropy and ask kernel to pick name via pattern
-func SetupVeth(entropy, contVethName string, mtu int, hostNS *os.File) (hostVeth, contVeth netlink.Link, err error) {
-       // NetworkManager (recent versions) will ignore veth devices that start with "veth"
-       hostVethName := RandomVethName(entropy)
-       hostVeth, err = makeVeth(hostVethName, contVethName, mtu)
+func SetupVeth(contVethName string, mtu int, hostNS *os.File) (hostVeth, contVeth netlink.Link, err error) {
+       var hostVethName string
+       hostVethName, contVeth, err = makeVeth(contVethName, mtu)
        if err != nil {
-               err = fmt.Errorf("failed to make veth pair: %v", err)
                return
        }
 
-       if err = netlink.LinkSetUp(hostVeth); err != nil {
-               err = fmt.Errorf("failed to set %q up: %v", hostVethName, err)
+       if err = netlink.LinkSetUp(contVeth); err != nil {
+               err = fmt.Errorf("failed to set %q up: %v", contVethName, err)
                return
        }
 
-       contVeth, err = netlink.LinkByName(contVethName)
+       hostVeth, err = netlink.LinkByName(hostVethName)
        if err != nil {
-               err = fmt.Errorf("failed to lookup %q: %v", contVethName, err)
+               err = fmt.Errorf("failed to lookup %q: %v", hostVethName, err)
                return
        }
 
-       if err = netlink.LinkSetUp(contVeth); err != nil {
+       if err = netlink.LinkSetUp(hostVeth); err != nil {
                err = fmt.Errorf("failed to set %q up: %v", contVethName, err)
                return
        }
index b76d6ce..0df177b 100644 (file)
@@ -48,9 +48,9 @@ func cmdAdd(args *skel.CmdArgs) error {
 
        switch ipamConf.Type {
        case "host-local":
-               ipConf, err = allocator.Get(args.Netns)
+               ipConf, err = allocator.Get(args.ContainerID)
        case "host-local-ptp":
-               ipConf, err = allocator.GetPtP(args.Netns)
+               ipConf, err = allocator.GetPtP(args.ContainerID)
        default:
                return errors.New("Unsupported IPAM plugin type")
        }
@@ -81,5 +81,5 @@ func cmdDel(args *skel.CmdArgs) error {
                return err
        }
 
-       return allocator.Release(args.Netns)
+       return allocator.Release(args.ContainerID)
 }
index 9257679..d3d572f 100644 (file)
@@ -130,7 +130,7 @@ func setupVeth(netns string, br *netlink.Bridge, ifName string, mtu int, pr *plu
 
        err := ns.WithNetNSPath(netns, func(hostNS *os.File) error {
                // create the veth pair in the container and move host end into host netns
-               hostVeth, _, err := ip.SetupVeth(netns, ifName, mtu, hostNS)
+               hostVeth, _, err := ip.SetupVeth(ifName, mtu, hostNS)
                if err != nil {
                        return err
                }
index e505ace..2a5a897 100644 (file)
@@ -107,7 +107,11 @@ func cmdAdd(args *skel.CmdArgs) error {
        }
        defer netns.Close()
 
-       tmpName := ip.RandomVethName(args.Netns)
+       tmpName, err := ip.RandomVethName()
+       if err != nil {
+               return err
+       }
+
        if err = createIpvlan(n, tmpName, netns); err != nil {
                return err
        }
index 7ddfab8..874abc5 100644 (file)
@@ -111,7 +111,11 @@ func cmdAdd(args *skel.CmdArgs) error {
        }
        defer netns.Close()
 
-       tmpName := ip.RandomVethName(args.Netns)
+       tmpName, err := ip.RandomVethName()
+       if err != nil {
+               return err
+       }
+
        if err = createMacvlan(n, tmpName, netns); err != nil {
                return err
        }
index 2e1783e..aef901b 100644 (file)
@@ -47,9 +47,7 @@ type NetConf struct {
 func setupContainerVeth(netns, ifName string, mtu int, pr *plugin.Result) (string, error) {
        var hostVethName string
        err := ns.WithNetNSPath(netns, func(hostNS *os.File) error {
-               entropy := netns + ifName
-
-               hostVeth, _, err := ip.SetupVeth(entropy, ifName, mtu, hostNS)
+               hostVeth, _, err := ip.SetupVeth(ifName, mtu, hostNS)
                if err != nil {
                        return err
                }
@@ -116,7 +114,7 @@ func cmdAdd(args *skel.CmdArgs) error {
        }
 
        if conf.IPMasq {
-               h := sha512.Sum512([]byte(args.Netns))
+               h := sha512.Sum512([]byte(args.ContainerID))
                chain := fmt.Sprintf("CNI-%s-%x", conf.Name, h[:8])
                if err = ip.SetupIPMasq(&result.IP4.IP, chain); err != nil {
                        return err
@@ -143,7 +141,7 @@ func cmdDel(args *skel.CmdArgs) error {
        }
 
        if conf.IPMasq {
-               h := sha512.Sum512([]byte(args.Netns))
+               h := sha512.Sum512([]byte(args.ContainerID))
                chain := fmt.Sprintf("CNI-%s-%x", conf.Name, h[:8])
                if err = ip.TeardownIPMasq(ipn, chain); err != nil {
                        return err
index f969b8b..6271dd2 100755 (executable)
@@ -9,10 +9,10 @@ contid=$(docker run -d --net=none busybox:latest /bin/sleep 10000000)
 pid=$(docker inspect -f '{{ .State.Pid }}' $contid)
 netnspath=/proc/$pid/ns/net
 
-./exec-plugins.sh add $netnspath
+./exec-plugins.sh add $contid $netnspath
 
 function cleanup() {
-       ./exec-plugins.sh del $netnspath
+       ./exec-plugins.sh del $contid $netnspath
        docker kill $contid >/dev/null
 }
 trap cleanup EXIT
index 26453bd..64ce1bc 100755 (executable)
@@ -1,29 +1,36 @@
-#!/bin/bash -e
+#!/bin/bash
 
 NETCONFPATH=${NETCONFPATH-/etc/cni/net.d}
 
 function exec_plugins() {
        i=0
-       netns=$2
+       contid=$2
+       netns=$3
        export CNI_COMMAND=$(echo $1 | tr '[:lower:]' '[:upper:]')
        export PATH=$CNI_PATH:$PATH
+       export CNI_CONTAINERID=$contid
        export CNI_NETNS=$netns
 
        for netconf in $(echo $NETCONFPATH/*.conf | sort); do
+               name=$(jq -r '.name' <$netconf)
                plugin=$(jq -r '.type' <$netconf)
                export CNI_IFNAME=$(printf eth%d $i)
 
                $plugin <$netconf >/dev/null
+               if [ $? -ne 0 ]; then
+                       echo "${name} : error executing $CNI_COMMAND"
+                       exit 1
+               fi
 
                let "i=i+1"
        done
 }
 
-if [ $# -ne 2 ]; then
-       echo "Usage: $0 add|del NETNS-PATH"
+if [ $# -ne 3 ]; then
+       echo "Usage: $0 add|del CONTAINER-ID NETNS-PATH"
        echo "  Adds or deletes the container specified by NETNS-PATH to the networks"
        echo "  specified in \$NETCONFPATH directory"
        exit 1
 fi
 
-exec_plugins $1 $2
+exec_plugins $1 $2 $3
index 1d9fb53..3d1c1ec 100755 (executable)
@@ -3,18 +3,18 @@
 # Run a command in a private network namespace
 # set up by CNI plugins
 
-netnsname=$(printf '%x%x' $RANDOM $RANDOM)
-netnspath=/var/run/netns/$netnsname
+contid=$(printf '%x%x%x%x' $RANDOM $RANDOM $RANDOM $RANDOM)
+netnspath=/var/run/netns/$contid
 
-ip netns add $netnsname
-ip netns exec $netnsname ip link set lo up
-./exec-plugins.sh add $netnspath
+ip netns add $contid
+ip netns exec $contid ip link set lo up
+./exec-plugins.sh add $contid $netnspath
 
 
 function cleanup() {
-       ./exec-plugins.sh del $netnspath
-       ip netns delete $netnsname
+       ./exec-plugins.sh del $contid $netnspath
+       ip netns delete $contid
 }
 trap cleanup EXIT
 
-ip netns exec $netnsname $@
+ip netns exec $contid $@