Skip to content
Open
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ This repo contains plugins meant for testing/development of latest windows featu
* `nat`
* `sdnbridge`

## Usage
[Container networking on windows.](https://docs.microsoft.com/en-us/virtualization/windowscontainers/container-networking/architecture) Following windows networking definitions, this plugin works to create the endpoint from parameters defined in the cni.conf, and a attach it to the namespace referred to by CNI_NETNS. There are two assumptions the plugins makes to perform this:
1. The user has already created a network which endpoints can be created under.
2. The namespace has been already been created.
For 2, the container is typically created with a reference to the namespace and it is expected that the container runtime performs this creation step. These plugins strictly work within the V2 windows container networking flow. Endpoint Policies should be in the [V2 schema format](https://docs.microsoft.com/en-us/windows-server/networking/technologies/hcn/hcn-top).


## Releases
Currently you must build the binaries yourself (see below)

Expand Down Expand Up @@ -38,6 +45,12 @@ Currently there are two groups of end-to-end tests shared by all the plugins
* Properties Verification - tests an add command and verifies that the resulting state is as expected. I.e. we attach an endpoint that endpoint has policy x,y,z etc.
* Connectivity Testing - creates a container and makes a CNI call for it and verifies that the container has connectivity for pod-to-pod, host-to-pod, pod-to-host, and pod-to-internet

## Errors
66 - General failure in the plugin: indicates an error occured in the plugin with no extra information
71 - Port Already Exists: indicates the port specified in a policy, (usually port mapping), is in use, likely by another endpoint. To fix this error, free the port desired or change the port you wish to use.
81 - Network Not Found: The network specified in the CNI config was not found. The expectation is that the network has been created before invoking the plugin to create an endpoint for a container. Create the network to use the plugin.


## Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a
Expand Down
8 changes: 2 additions & 6 deletions cni/cni.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,9 @@ func CallPlugin(plugin PluginApi, cmd string, args *cniSkel.CmdArgs, config *Net
config.Ipam.Type = savedType

if err != nil {
res := cniTypes.Error{
Code: 66,
Msg: "failure in cni",
Details: err.Error(),
}
res := ResolveError(err)
res.Print()
return nil, err
return nil, res
}

// Read back the result.
Expand Down
54 changes: 54 additions & 0 deletions cni/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright Microsoft Corp.
// All rights reserved.

package cni

import (
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/hcn"
cniTypes "github.com/containernetworking/cni/pkg/types"
)

func ResolveError(err error) *cniTypes.Error {
if err == nil {
return nil
}
logrus.Debugf("[cni-net] Error detected, resolving error, %v", err)
if hcn.IsNotFoundError(err) {
switch err.(type) {
case hcn.NetworkNotFoundError:
return newNetworkNotFoundError(err)
}
}

if hcn.IsPortAlreadyExistsError(err) {
return newPortAlreadyExistsError(err)
}

return newGenericError(err)

}

func newGenericError(err error) *cniTypes.Error {
return &cniTypes.Error{
Code: 66,
Msg: "failure in cni",
Details: err.Error(),
}
}

func newPortAlreadyExistsError(err error) *cniTypes.Error {
return &cniTypes.Error{
Code: 71,
Msg: "Port specified is already in use. This indicates that an endpoint already exists with the port mapping requested. Delete the endpoint or change the port",
Details: err.Error(),
}
}

func newNetworkNotFoundError(err error) *cniTypes.Error {
return &cniTypes.Error{
Code: 81,
Msg: "Network not found. The network specified in the CNI config was not found and the endpoint can not be created. Please create the network to proceed.",
Details: err.Error(),
}
}
65 changes: 29 additions & 36 deletions common/core/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/Microsoft/windows-container-networking/network"
"github.com/sirupsen/logrus"
"os"

"github.com/Microsoft/hcsshim/hcn"
"github.com/containernetworking/cni/pkg/invoke"
cniSkel "github.com/containernetworking/cni/pkg/skel"
Expand Down Expand Up @@ -94,44 +93,45 @@ func (plugin *netPlugin) Add(args *cniSkel.CmdArgs) (resultError error) {
logrus.Debugf("[cni-net] Processing ADD command with args {ContainerID:%v Netns:%v IfName:%v Args:%v Path:%v}.",
args.ContainerID, args.Netns, args.IfName, args.Args, args.Path)

defer func() {resultError = cni.ResolveError(resultError)}()
podConfig, err := cni.ParseCniArgs(args.Args)
k8sNamespace := ""
if err == nil {
k8sNamespace = string(podConfig.K8S_POD_NAMESPACE)
}

// Parse network configuration from stdin.
cniConfig, err := cni.ParseNetworkConfig(args.StdinData)
cniConfig, resultError := cni.ParseNetworkConfig(args.StdinData)
if err != nil {
logrus.Errorf("[cni-net] Failed to parse network configuration, err:%v.", err)
return err
return
}

logrus.Debugf("[cni-net] Read network configuration %+v.", cniConfig)

// Convert cniConfig to NetworkInfo
// We don't set namespace, setting namespace is not valid for EP creation
networkInfo := cniConfig.GetNetworkInfo(k8sNamespace)
epInfo, err := cniConfig.GetEndpointInfo(networkInfo, args.ContainerID, "")

if err != nil {
return err
epInfo, resultError := cniConfig.GetEndpointInfo(networkInfo, args.ContainerID, "")
if resultError != nil {
return
}

// Check for missing namespace
if args.Netns == "" {
logrus.Errorf("[cni-net] Missing Namespace, cannot add, endpoint : [%v].", epInfo)
return errors.New("cannot create endpoint without a namespace")
resultError = errors.New("cannot create endpoint without a namespace")
return
}

nwConfig, err := getOrCreateNetwork(plugin, networkInfo, cniConfig)
if err != nil {
return err
nwConfig, resultError := getNetwork(plugin, networkInfo, cniConfig)
if resultError != nil {
return
}

hnsEndpoint, err := plugin.nm.GetEndpointByName(epInfo.Name)
if hnsEndpoint != nil {
logrus.Infof("[cni-net] Endpoint %+v already exists for network %v.", hnsEndpoint, nwConfig.ID)
logrus.Infof("[cni-net] Endpoint %v already exists for network %v.", hnsEndpoint, nwConfig.ID)
// Endpoint exists
// Validate for duplication
if hnsEndpoint.NetworkID == nwConfig.ID {
Expand All @@ -142,7 +142,8 @@ func (plugin *netPlugin) Add(args *cniSkel.CmdArgs) (resultError error) {
res := cni.GetCurrResult(nwConfig, hnsEndpoint, args.IfName)
result, err := res.GetAsVersion(cniConfig.CniVersion)
if err != nil {
return err
resultError = err
return
}

result.Print()
Expand All @@ -154,10 +155,10 @@ func (plugin *netPlugin) Add(args *cniSkel.CmdArgs) (resultError error) {

// If Ipam was provided, allocate a pool and obtain V4 address
if cniConfig.Ipam.Type != "" {
err = allocateIpam(networkInfo, epInfo, cniConfig, cniConfig.OptionalFlags.ForceBridgeGateway)
if err != nil {
// Error was logged by allocateIpam.
return err
resultError = allocateIpam(networkInfo, epInfo, cniConfig, cniConfig.OptionalFlags.ForceBridgeGateway)
if resultError != nil {
// ResultError was logged by allocateIpam.
return
}
defer func() {
if resultError != nil {
Expand All @@ -166,7 +167,7 @@ func (plugin *netPlugin) Add(args *cniSkel.CmdArgs) (resultError error) {
err := deallocateIpam(cniConfig)
os.Setenv("CNI_COMMAND", "ADD")
if err != nil {
logrus.Debugf("[cni-net] failed during ADD command for clean-up delegate delete call, %v", err)
logrus.Debugf("[cni-net] failed during ADD command for clean-up delegate delete call, %v", resultError)
}
}
}()
Expand All @@ -175,17 +176,17 @@ func (plugin *netPlugin) Add(args *cniSkel.CmdArgs) (resultError error) {
// Apply the Network Policy for Endpoint
epInfo.Policies = append(epInfo.Policies, networkInfo.Policies...)

epInfo, err = plugin.nm.CreateEndpoint(nwConfig.ID, epInfo, args.Netns)
if err != nil {
logrus.Errorf("[cni-net] Failed to create endpoint, error : %v.", err)
return err
epInfo, resultError = plugin.nm.CreateEndpoint(nwConfig.ID, epInfo, args.Netns)
if resultError != nil {
logrus.Errorf("[cni-net] Failed to create endpoint, resultError : %v.", resultError)
return
}

// Convert result to the requested CNI version.
res := cni.GetCurrResult(nwConfig, epInfo, args.IfName)
result, err := res.GetAsVersion(cniConfig.CniVersion)
if err != nil {
return err
result, resultError := res.GetAsVersion(cniConfig.CniVersion)
if resultError != nil {
return
}

// result := cni.GetResult020(nwConfig, epInfo)
Expand Down Expand Up @@ -248,23 +249,15 @@ func deallocateIpam(cniConfig *cni.NetworkConfig) error {
// getOrCreateNetwork
// TODO: Require network to be created beforehand and make it an error of the network is not found.
// Once that is done, remove this function.
func getOrCreateNetwork(
func getNetwork(
plugin *netPlugin,
networkInfo *network.NetworkInfo,
cniConfig *cni.NetworkConfig) (*network.NetworkInfo, error) {
// Check whether the network already exists.
nwConfig, err := plugin.nm.GetNetworkByName(cniConfig.Name)
if err != nil {
// Network does not exist.
logrus.Infof("[cni-net] Creating network.")

nwConfig, err = plugin.nm.CreateNetwork(networkInfo)
if err != nil {
logrus.Errorf("[cni-net] Failed to create network, err:%v.", err)
return nil, err
}

logrus.Debugf("[cni-net] Created network %v with subnet %v.", nwConfig.ID, cniConfig.Ipam.Subnet)
logrus.Errorf("[cni-net] Failed to find network [%v], err:%v.", cniConfig.Name, err)
return nil, err
} else {
// Network already exists.
logrus.Debugf("[cni-net] Found network %v with subnet %v.", nwConfig.ID, nwConfig.Subnets)
Expand Down
11 changes: 6 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@ module github.com/Microsoft/windows-container-networking
go 1.12

require (
github.com/Microsoft/go-winio v0.4.14
github.com/Microsoft/hcsshim v0.8.7-0.20190916181005-bd9b25532450
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5
github.com/Microsoft/hcsshim v0.8.8-0.20200225064221-b400e4ffeccc
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50 // indirect
github.com/containerd/go-runc v0.0.0-20190226155025-7d11b49dc076
github.com/containernetworking/cni v0.0.0-20190403160241-0471e018e593
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/hashicorp/go-multierror v1.0.0 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/linuxkit/virtsock v0.0.0-20180830132707-8e79449dea07 // indirect
github.com/microsoft/hcsshim v0.8.6 // indirect
github.com/opencontainers/runtime-spec v0.0.0-20190408193819-a1b50f621a48 // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/opencontainers/runtime-tools v0.0.0-20190313075039-7125f1d443b0
github.com/opencontainers/selinux v1.2.1 // indirect
github.com/pkg/errors v0.8.1
github.com/sirupsen/logrus v1.4.1
github.com/sirupsen/logrus v1.4.2
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 // indirect
github.com/xeipuuv/gojsonschema v1.1.0 // indirect
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6
golang.org/x/sync v0.0.0-20190423024810-112230192c58
)
Loading