From b2d9801b25efab3666d4eb96760462ae0d2002fd Mon Sep 17 00:00:00 2001 From: Eugene Yakubovich Date: Tue, 5 May 2015 13:35:20 -0700 Subject: [PATCH] Do not use netns as ID or for entropy ContainerID is now required so use that or generate random bytes. Fixes #5 --- pkg/ip/link.go | 74 +++++++++++++++++++++++---------- plugins/ipam/host-local/main.go | 6 +-- plugins/main/bridge/bridge.go | 2 +- plugins/main/ipvlan/ipvlan.go | 6 ++- plugins/main/macvlan/macvlan.go | 6 ++- plugins/main/veth/veth.go | 8 ++-- scripts/docker-run.sh | 4 +- scripts/exec-plugins.sh | 17 +++++--- scripts/priv-net-run.sh | 16 +++---- 9 files changed, 90 insertions(+), 49 deletions(-) diff --git a/pkg/ip/link.go b/pkg/ip/link.go index 59865cf8..c99f4f3c 100644 --- a/pkg/ip/link.go +++ b/pkg/ip/link.go @@ -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,33 +39,50 @@ 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) - return - } - - contVeth, err = netlink.LinkByName(contVethName) - if err != nil { - err = fmt.Errorf("failed to lookup %q: %v", contVethName, err) return } @@ -74,6 +91,17 @@ func SetupVeth(entropy, contVethName string, mtu int, hostNS *os.File) (hostVeth return } + hostVeth, err = netlink.LinkByName(hostVethName) + if err != nil { + err = fmt.Errorf("failed to lookup %q: %v", hostVethName, err) + return + } + + if err = netlink.LinkSetUp(hostVeth); err != nil { + err = fmt.Errorf("failed to set %q up: %v", contVethName, err) + return + } + if err = netlink.LinkSetNsFd(hostVeth, int(hostNS.Fd())); err != nil { err = fmt.Errorf("failed to move veth to host netns: %v", err) return diff --git a/plugins/ipam/host-local/main.go b/plugins/ipam/host-local/main.go index b76d6ce4..0df177bf 100644 --- a/plugins/ipam/host-local/main.go +++ b/plugins/ipam/host-local/main.go @@ -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) } diff --git a/plugins/main/bridge/bridge.go b/plugins/main/bridge/bridge.go index 92576799..d3d572f0 100644 --- a/plugins/main/bridge/bridge.go +++ b/plugins/main/bridge/bridge.go @@ -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 } diff --git a/plugins/main/ipvlan/ipvlan.go b/plugins/main/ipvlan/ipvlan.go index e505acec..2a5a8970 100644 --- a/plugins/main/ipvlan/ipvlan.go +++ b/plugins/main/ipvlan/ipvlan.go @@ -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 } diff --git a/plugins/main/macvlan/macvlan.go b/plugins/main/macvlan/macvlan.go index 7ddfab8f..874abc5c 100644 --- a/plugins/main/macvlan/macvlan.go +++ b/plugins/main/macvlan/macvlan.go @@ -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 } diff --git a/plugins/main/veth/veth.go b/plugins/main/veth/veth.go index 2e1783e1..aef901b8 100644 --- a/plugins/main/veth/veth.go +++ b/plugins/main/veth/veth.go @@ -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 diff --git a/scripts/docker-run.sh b/scripts/docker-run.sh index f969b8b2..6271dd28 100755 --- a/scripts/docker-run.sh +++ b/scripts/docker-run.sh @@ -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 diff --git a/scripts/exec-plugins.sh b/scripts/exec-plugins.sh index 26453bda..64ce1bc1 100755 --- a/scripts/exec-plugins.sh +++ b/scripts/exec-plugins.sh @@ -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 diff --git a/scripts/priv-net-run.sh b/scripts/priv-net-run.sh index 1d9fb537..3d1c1ecc 100755 --- a/scripts/priv-net-run.sh +++ b/scripts/priv-net-run.sh @@ -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 $@