Skip to content

Commit

Permalink
This commit has the following changes
Browse files Browse the repository at this point in the history
 + windows cni plugins are added
   (*) hostgw
   (*) overlay vxlan
 + windows netconf unit test
 + Fix appveyor config to run the test
 + Vendor commit for
    (*) github.com/Microsoft/hcsshim
    (*) golang.org/x/sys
 + Build Release support for windows plugins
  • Loading branch information
rakelkar authored and madhanrm committed Jun 10, 2018
1 parent 2b8b1ac commit ed18059
Show file tree
Hide file tree
Showing 332 changed files with 79,255 additions and 23,183 deletions.
4 changes: 2 additions & 2 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ environment:
install:
- echo %PATH%
- echo %GOPATH%
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
- go version
- go env

- ps: $webClient = New-Object System.Net.WebClient; $InstallPath="c:" ; $webClient.DownloadFile("https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/gcc.zip", "$InstallPath\gcc.zip"); Expand-Archive $InstallPath\gcc.zip -DestinationPath $InstallPath\gcc -Force; $webClient.DownloadFile("https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/runtime.zip", "$InstallPath\runtime.zip"); Expand-Archive $InstallPath\runtime.zip -DestinationPath $InstallPath\gcc -Force; $webClient.DownloadFile("https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/binutils.zip","$InstallPath\binutils.zip"); Expand-Archive $InstallPath\binutils.zip -DestinationPath $InstallPath\gcc -Force;
- set PATH=%GOPATH%\bin;c:\go\bin;c:\gcc\bin;%PATH%
build: off

test_script:
Expand Down
26 changes: 25 additions & 1 deletion Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ Some CNI network plugins, maintained by the containernetworking team. For more i
* `macvlan`: Creates a new MAC address, forwards all traffic to that to the container
* `ptp`: Creates a veth pair.
* `vlan`: Allocates a vlan device.

#### Windows: windows specific
* `l2bridge`: Creates a bridge, adds the host and the container to it.
* `overlay`: Creates an overlay interface to the container
### IPAM: IP address allocation
* `dhcp`: Runs a daemon on the host to make DHCP requests on behalf of the container
* `host-local`: maintains a local database of allocated IPs
Expand Down
14 changes: 11 additions & 3 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,20 @@ export GO="${GO:-go}"

mkdir -p "${PWD}/bin"

echo "Building plugins"
echo "Building plugins ${GOOS}"
PLUGINS="plugins/meta/* plugins/main/* plugins/ipam/* plugins/sample"
for d in $PLUGINS; do
if [ -d "$d" ]; then
plugin="$(basename "$d")"
echo " $plugin"
$GO build -o "${PWD}/bin/$plugin" "$@" "$REPO_PATH"/$d
if [ $plugin == "windows" ]
then
if [ "$GOARCH" == "amd64" ]
then
GOOS=windows . $d/build.sh
fi
else
echo " $plugin"
$GO build -o "${PWD}/bin/$plugin" "$@" "$REPO_PATH"/$d
fi
fi
done
149 changes: 149 additions & 0 deletions pkg/hns/endpoint_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// +build windows

// Copyright 2017 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 hns

import (
"fmt"
"log"
"net"
"strings"

"github.com/Microsoft/hcsshim"
"github.com/containernetworking/cni/pkg/types/current"
)

// ConstructEndpointName constructs enpointId which is used to identify an endpoint from HNS
// There is a special consideration for netNs name here, which is required for Windows Server 1709
// containerID is the Id of the container on which the endpoint is worked on
func ConstructEndpointName(containerID string, netNs string, networkName string) string {
if netNs != "" {
splits := strings.Split(netNs, ":")
if len(splits) == 2 {
containerID = splits[1]
}
}
epName := containerID + "_" + networkName
return epName
}

// DeprovisionEndpoint removes an endpoint from the container by sending a Detach request to HNS
// For shared endpoint, ContainerDetach is used
// for removing the endpoint completely, HotDetachEndpoint is used
func DeprovisionEndpoint(epName string, netns string, containerID string) error {
hnsEndpoint, err := hcsshim.GetHNSEndpointByName(epName)
if err != nil {
log.Printf("[win-cni] Failed to find endpoint %v, err:%v", epName, err)
return err
}

if netns != "none" {
// Shared endpoint removal. Do not remove the endpoint.
err := hnsEndpoint.ContainerDetach(containerID)
if err != nil {
log.Printf("[win-cni] Failed to detach the container endpoint %v, err:%v", epName, err)
}
return nil
}

err = hcsshim.HotDetachEndpoint(containerID, hnsEndpoint.Id)
if err != nil {
log.Printf("[win-cni] Failed to detach endpoint %v, err:%v", epName, err)
// Do not consider this as failure, else this would leak endpoints
}

_, err = hnsEndpoint.Delete()
if err != nil {
log.Printf("[win-cni] Failed to delete endpoint %v, err:%v", epName, err)
// Do not return error
}

return nil
}

type EndpointMakerFunc func() (*hcsshim.HNSEndpoint, error)

// ProvisionEndpoint provisions an endpoint to a container specified by containerID.
// If an endpoint already exists, the endpoint is reused.
// This call is idempotent
func ProvisionEndpoint(epName string, expectedNetworkId string, containerID string, makeEndpoint EndpointMakerFunc) (*hcsshim.HNSEndpoint, error) {
// check if endpoint already exists
createEndpoint := true
hnsEndpoint, err := hcsshim.GetHNSEndpointByName(epName)
if hnsEndpoint != nil && hnsEndpoint.VirtualNetwork == expectedNetworkId {
log.Printf("[win-cni] Found existing endpoint %v", epName)
createEndpoint = false
}

if createEndpoint {
if hnsEndpoint != nil {
_, err = hnsEndpoint.Delete()
if err != nil {
log.Printf("[win-cni] Failed to delete stale endpoint %v, err:%v", epName, err)
}
}

if hnsEndpoint, err = makeEndpoint(); err != nil {
return nil, err
}

if hnsEndpoint, err = hnsEndpoint.Create(); err != nil {
return nil, err
}

}

// hot attach
if err = hcsshim.HotAttachEndpoint(containerID, hnsEndpoint.Id); err != nil {
return nil, err
}

return hnsEndpoint, nil
}

// ConstructResult constructs the CNI result for the endpoint
func ConstructResult(hnsNetwork *hcsshim.HNSNetwork, hnsEndpoint *hcsshim.HNSEndpoint) (*current.Result, error) {
resultInterface := &current.Interface{
Name: hnsEndpoint.Name,
Mac: hnsEndpoint.MacAddress,
}
_, ipSubnet, err := net.ParseCIDR(hnsNetwork.Subnets[0].AddressPrefix)
if err != nil {
return nil, err
}

var ipVersion string
if ipv4 := hnsEndpoint.IPAddress.To4(); ipv4 != nil {
ipVersion = "4"
} else if ipv6 := hnsEndpoint.IPAddress.To16(); ipv6 != nil {
ipVersion = "6"
} else {
return nil, fmt.Errorf("[win-cni] The IPAddress of hnsEndpoint isn't a valid ipv4 or ipv6 Address.")
}

resultIPConfig := &current.IPConfig{
Version: ipVersion,
Address: net.IPNet{
IP: hnsEndpoint.IPAddress,
Mask: ipSubnet.Mask},
Gateway: net.ParseIP(hnsEndpoint.GatewayAddress),
}
result := &current.Result{}
result.Interfaces = []*current.Interface{resultInterface}
result.IPs = []*current.IPConfig{resultIPConfig}

return result, nil
}
142 changes: 142 additions & 0 deletions pkg/hns/netconf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright 2017 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 hns

import (
"encoding/json"
"github.com/containernetworking/cni/pkg/types"
"strings"
)

// NetConf is the CNI spec
type NetConf struct {
types.NetConf
AdditionalArgs []policyArgument `json:"AdditionalArgs,omitempty"`
}

type policyArgument struct {
Name string
Value map[string]interface{}
}

// MarshalPolicies converts the Endpoint policies in AdditionalArgs
// to HNS specific policies as Json raw bytes
func (n *NetConf) MarshalPolicies() []json.RawMessage {
if n.AdditionalArgs == nil {
n.AdditionalArgs = []policyArgument{}
}

var result []json.RawMessage
for _, policyArg := range n.AdditionalArgs {
if !strings.EqualFold(policyArg.Name, "EndpointPolicy") {
continue
}
if data, err := json.Marshal(policyArg.Value); err == nil {
result = append(result, data)
}
}

return result
}

// ApplyOutboundNatPolicy applies NAT Policy in VFP using HNS
// Simultaneously an exception is added for the network that has to be Nat'd
func (n *NetConf) ApplyOutboundNatPolicy(nwToNat string) {
if n.AdditionalArgs == nil {
n.AdditionalArgs = []policyArgument{}
}

for _, policy := range n.AdditionalArgs {
if !strings.EqualFold(policy.Name, "EndpointPolicy") {
continue
}

pv := policy.Value
if !hasKey(pv, "Type") {
continue
}

if !strings.EqualFold(pv["Type"].(string), "OutBoundNAT") {
continue
}

if !hasKey(pv, "ExceptionList") {
// add the exception since there weren't any
pv["ExceptionList"] = []interface{}{nwToNat}
return
}

nets := pv["ExceptionList"].([]interface{})
for _, net := range nets {
if net.(string) == nwToNat {
// found it - do nothing
return
}
}

// its not in the list of exceptions, add it and we're done
pv["ExceptionList"] = append(nets, nwToNat)
return
}

// didn't find the policy, add it
natEntry := policyArgument{
Name: "EndpointPolicy",
Value: map[string]interface{}{
"Type": "OutBoundNAT",
"ExceptionList": []interface{}{
nwToNat,
},
},
}

n.AdditionalArgs = append(n.AdditionalArgs, natEntry)
}

// ApplyDefaultPAPolicy is used to configure a endpoint PA policy in HNS
func (n *NetConf) ApplyDefaultPAPolicy(paAddress string) {
if n.AdditionalArgs == nil {
n.AdditionalArgs = []policyArgument{}
}

// if its already present, leave untouched
for _, policy := range n.AdditionalArgs {
if policy.Name == "EndpointPolicy" {
if hasKey(policy.Value, "PA") {
// found it, don't override
return
}
}
}

// did not find, add it now
paPolicyData := map[string]interface{}{
"Type": "PA",
"PA": paAddress,
}
paPolicy := &policyArgument{
Name: "EndpointPolicy",
Value: paPolicyData,
}

n.AdditionalArgs = append(n.AdditionalArgs, *paPolicy)

return
}

func hasKey(m map[string]interface{}, k string) bool {
_, ok := m[k]
return ok
}
Loading

0 comments on commit ed18059

Please sign in to comment.