Skip to content
This repository has been archived by the owner on Jun 20, 2024. It is now read-only.

Allow CNI caller to supply blank netns; upgrade cni library to version 0.5.0 #2850

Merged
merged 4 commits into from
Mar 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,6 @@
[submodule "vendor/github.com/hashicorp/go-cleanhttp"]
path = vendor/github.com/hashicorp/go-cleanhttp
url = http://github.com/hashicorp/go-cleanhttp
[submodule "vendor/github.com/appc/cni"]
path = vendor/github.com/appc/cni
url = https://github.com/appc/cni
[submodule "vendor/github.com/coreos/go-iptables"]
path = vendor/github.com/coreos/go-iptables
url = https://github.com/coreos/go-iptables
Expand Down Expand Up @@ -124,3 +121,6 @@
[submodule "vendor/github.com/weaveworks/common"]
path = vendor/github.com/weaveworks/common
url = https://github.com/weaveworks/common
[submodule "vendor/github.com/containernetworking/cni"]
path = vendor/github.com/containernetworking/cni
url = https://github.com/containernetworking/cni
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ ifeq ($(BUILD_IN_CONTAINER),true)
# It bind-mounts the source into the container and passes all important variables
exes $(EXES) tests lint: $(BUILD_UPTODATE)
git submodule update --init
# Containernetworking has another copy of vishvananda/netlink which leads to duplicate definitions
-@rm -r vendor/github.com/containernetworking/cni/vendor
@mkdir -p $(shell pwd)/.pkg
$(SUDO) docker run $(RM) $(RUN_FLAGS) \
-v $(shell pwd):/go/src/github.com/weaveworks/weave \
Expand Down
30 changes: 18 additions & 12 deletions plugin/ipam/cni.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,24 @@ import (
"fmt"
"net"

"github.com/appc/cni/pkg/skel"
"github.com/appc/cni/pkg/types"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/current"
)

func (i *Ipam) CmdAdd(args *skel.CmdArgs) error {
var conf types.NetConf
if err := json.Unmarshal(args.StdinData, &conf); err != nil {
return fmt.Errorf("failed to load netconf: %v", err)
}
result, err := i.Allocate(args)
if err != nil {
return err
}
return result.Print()
return types.PrintResult(result, conf.CNIVersion)
}

func (i *Ipam) Allocate(args *skel.CmdArgs) (*types.Result, error) {
func (i *Ipam) Allocate(args *skel.CmdArgs) (types.Result, error) {
// extract the things we care about
conf, err := loadIPAMConf(args.StdinData)
if err != nil {
Expand Down Expand Up @@ -46,12 +51,13 @@ func (i *Ipam) Allocate(args *skel.CmdArgs) (*types.Result, error) {
if err != nil {
return nil, err
}
result := &types.Result{
IP4: &types.IPConfig{
IP: *ipnet,
result := &current.Result{
IPs: []*current.IPConfig{{
Version: "4",
Address: *ipnet,
Gateway: conf.Gateway,
Routes: conf.Routes,
},
}},
Routes: conf.Routes,
}
return result, nil
}
Expand All @@ -65,9 +71,9 @@ func (i *Ipam) Release(args *skel.CmdArgs) error {
}

type ipamConf struct {
Subnet string `json:"subnet,omitempty"`
Gateway net.IP `json:"gateway,omitempty"`
Routes []types.Route `json:"routes"`
Subnet string `json:"subnet,omitempty"`
Gateway net.IP `json:"gateway,omitempty"`
Routes []*types.Route `json:"routes"`
}

type netConf struct {
Expand Down
56 changes: 37 additions & 19 deletions plugin/net/cni.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import (
"encoding/json"
"fmt"
"net"
"strings"
"syscall"

"github.com/appc/cni/pkg/ipam"
"github.com/appc/cni/pkg/skel"
"github.com/appc/cni/pkg/types"
"github.com/containernetworking/cni/pkg/ipam"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/current"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
weaveapi "github.com/weaveworks/weave/api"
Expand Down Expand Up @@ -40,17 +42,23 @@ func loadNetConf(bytes []byte) (*NetConf, error) {
return n, nil
}

func (c *CNIPlugin) getIP(ipamType string, args *skel.CmdArgs) (result *types.Result, err error) {
func (c *CNIPlugin) getIP(ipamType string, args *skel.CmdArgs) (newResult *current.Result, err error) {
var result types.Result
// Default IPAM is Weave's own
if ipamType == "" {
result, err = ipamplugin.NewIpam(c.weave).Allocate(args)
} else {
result, err = ipam.ExecAdd(ipamType, args.StdinData)
}
if err == nil && result.IP4 == nil {
if err != nil {
return nil, err
}
newResult, err = current.NewResultFromResult(result)
// Check if ipam returned no results without error
if err == nil && len(newResult.IPs) == 0 {
return nil, fmt.Errorf("IPAM plugin failed to allocate IP address")
}
return result, err
return newResult, err
}

func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
Expand All @@ -70,28 +78,31 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
if err != nil {
return fmt.Errorf("unable to allocate IP address: %s", err)
}
// Only expecting one address
ip := result.IPs[0]

This comment was marked as abuse.

This comment was marked as abuse.


// If config says nothing about routes or gateway, default one will be via the bridge
if result.IP4.Routes == nil && result.IP4.Gateway == nil {
bridgeIP, err := weavenet.FindBridgeIP(conf.BrName, &result.IP4.IP)
if len(result.Routes) == 0 && ip.Gateway == nil {
bridgeIP, err := weavenet.FindBridgeIP(conf.BrName, &ip.Address)
if err == weavenet.ErrBridgeNoIP {
bridgeArgs := *args
bridgeArgs.ContainerID = "weave:expose"
bridgeIPResult, err := c.getIP(conf.IPAM.Type, &bridgeArgs)
if err != nil {
return fmt.Errorf("unable to allocate IP address for bridge: %s", err)
}
if err := assignBridgeIP(conf.BrName, bridgeIPResult.IP4.IP); err != nil {
bridgeCIDR := bridgeIPResult.IPs[0].Address
if err := assignBridgeIP(conf.BrName, bridgeCIDR); err != nil {
return fmt.Errorf("unable to assign IP address to bridge: %s", err)
}
if err := weavenet.ExposeNAT(bridgeIPResult.IP4.IP); err != nil {
if err := weavenet.ExposeNAT(bridgeCIDR); err != nil {
return fmt.Errorf("unable to create NAT rules: %s", err)
}
bridgeIP = bridgeIPResult.IP4.IP.IP
bridgeIP = bridgeCIDR.IP
} else if err != nil {
return err
}
result.IP4.Gateway = bridgeIP
result.IPs[0].Gateway = bridgeIP
}

ns, err := netns.GetFromPath(args.Netns)
Expand All @@ -110,20 +121,20 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
id = fmt.Sprintf("%x", data)
}

if err := weavenet.AttachContainer(args.Netns, id, args.IfName, conf.BrName, conf.MTU, false, []*net.IPNet{&result.IP4.IP}, false); err != nil {
if err := weavenet.AttachContainer(args.Netns, id, args.IfName, conf.BrName, conf.MTU, false, []*net.IPNet{&ip.Address}, false); err != nil {
return err
}
if err := weavenet.WithNetNSLinkUnsafe(ns, args.IfName, func(link netlink.Link) error {
return setupRoutes(link, args.IfName, result.IP4.IP, result.IP4.Gateway, result.IP4.Routes)
return setupRoutes(link, args.IfName, ip.Address, ip.Gateway, result.Routes)
}); err != nil {
return fmt.Errorf("error setting up routes: %s", err)
}

result.DNS = conf.DNS
return result.Print()
return types.PrintResult(result, conf.CNIVersion)
}

func setupRoutes(link netlink.Link, name string, ipnet net.IPNet, gw net.IP, routes []types.Route) error {
func setupRoutes(link netlink.Link, name string, ipnet net.IPNet, gw net.IP, routes []*types.Route) error {
var err error
if routes == nil { // If config says nothing about routes, add a default one
if !ipnet.Contains(gw) {
Expand All @@ -133,7 +144,7 @@ func setupRoutes(link netlink.Link, name string, ipnet net.IPNet, gw net.IP, rou
return err
}
}
routes = []types.Route{{Dst: zeroNetwork}}
routes = []*types.Route{{Dst: zeroNetwork}}
}
for _, r := range routes {
if r.GW != nil {
Expand Down Expand Up @@ -170,8 +181,11 @@ func (c *CNIPlugin) CmdDel(args *skel.CmdArgs) error {
return err
}

if _, err = weavenet.WithNetNS(args.Netns, "del-iface", args.IfName); err != nil {
return fmt.Errorf("error removing interface %q: %s", args.IfName, err)
// As of CNI 0.3 spec, runtimes can send blank if they just want the address deallocated
if args.Netns != "" {
if _, err = weavenet.WithNetNS(args.Netns, "del-iface", args.IfName); err != nil {
return fmt.Errorf("error removing interface %q: %s", args.IfName, err)
}
}

// Default IPAM is Weave's own
Expand All @@ -180,6 +194,10 @@ func (c *CNIPlugin) CmdDel(args *skel.CmdArgs) error {
} else {
err = ipam.ExecDel(conf.IPAM.Type, args.StdinData)
}
// Hack - don't know how we should detect this situation properly
if args.Netns == "" && strings.Contains(err.Error(), "no addresses") {
err = nil
}
if err != nil {
return fmt.Errorf("unable to release IP address: %s", err)
}
Expand Down
7 changes: 4 additions & 3 deletions prog/weaveutil/cni.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package main
import (
"os"

cni "github.com/appc/cni/pkg/skel"
cni "github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/version"

weaveapi "github.com/weaveworks/weave/api"
"github.com/weaveworks/weave/common"
Expand All @@ -14,13 +15,13 @@ import (
func cniNet(args []string) error {
weave := weaveapi.NewClient(os.Getenv("WEAVE_HTTP_ADDR"), common.Log)
n := netplugin.NewCNIPlugin(weave)
cni.PluginMain(n.CmdAdd, n.CmdDel)
cni.PluginMain(n.CmdAdd, n.CmdDel, version.PluginSupports("0.1.0", "0.2.0", "0.3.0"))
return nil
}

func cniIPAM(args []string) error {
weave := weaveapi.NewClient(os.Getenv("WEAVE_HTTP_ADDR"), common.Log)
i := ipamplugin.NewIpam(weave)
cni.PluginMain(i.CmdAdd, i.CmdDel)
cni.PluginMain(i.CmdAdd, i.CmdDel, version.PluginSupports("0.1.0", "0.2.0", "0.3.0"))
return nil
}
3 changes: 2 additions & 1 deletion test/830_cni_plugin_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ start_suite "Test CNI plugin"
cni_connect() {
pid=$(container_pid $1 $2)
id=$(docker_on $1 inspect -f '{{.Id}}' $2)
run_on $1 sudo CNI_VERSION=1 CNI_COMMAND=ADD CNI_CONTAINERID=$id CNI_IFNAME=eth0 \
run_on $1 sudo CNI_COMMAND=ADD CNI_CONTAINERID=$id CNI_IFNAME=eth0 \
CNI_NETNS=/proc/$pid/ns/net CNI_PATH=/opt/cni/bin /opt/cni/bin/weave-net
}

Expand All @@ -30,6 +30,7 @@ EOF

cni_connect $HOST1 c2 <<EOF
{
"cniVersion": "0.3.0",
"name": "weave",
"type": "weave-net",
"ipam": {
Expand Down
1 change: 0 additions & 1 deletion vendor/github.com/appc/cni
Submodule cni deleted from 8bb41b
1 change: 1 addition & 0 deletions vendor/github.com/containernetworking/cni
Submodule cni added at 4ce9b0