forked from containernetworking/plugins
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Patch for containernetworking#85 + Windows cni plugins are added (*) win-bridge (hostgw) (*) win-overlay (vxlan) + Windows netconf unit test + Fix appveyor config to run the test + Build release support for windows plugins Address comments From: - containernetworking#85 - rakelkar@0049c64
- Loading branch information
Showing
22 changed files
with
1,214 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
// 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" | ||
"net" | ||
"strings" | ||
|
||
"github.com/Microsoft/hcsshim" | ||
"github.com/containernetworking/cni/pkg/types/current" | ||
"github.com/juju/errors" | ||
) | ||
|
||
const ( | ||
pauseContainerNetNS = "none" | ||
) | ||
|
||
// GetSandboxContainerID returns the sandbox ID of this pod | ||
func GetSandboxContainerID(containerID string, netNs string) string { | ||
if len(netNs) != 0 && netNs != pauseContainerNetNS { | ||
splits := strings.SplitN(netNs, ":", 2) | ||
if len(splits) == 2 { | ||
containerID = splits[1] | ||
} | ||
} | ||
|
||
return containerID | ||
} | ||
|
||
// 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 { | ||
return GetSandboxContainerID(containerID, netNs) + "_" + networkName | ||
} | ||
|
||
// 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 { | ||
if len(netns) == 0 { | ||
return nil | ||
} | ||
|
||
hnsEndpoint, err := hcsshim.GetHNSEndpointByName(epName) | ||
if err != nil { | ||
return errors.Annotatef(err, "failed to find HNSEndpoint %s", epName) | ||
} | ||
|
||
if netns != pauseContainerNetNS { | ||
// Shared endpoint removal. Do not remove the endpoint. | ||
hnsEndpoint.ContainerDetach(containerID) | ||
return nil | ||
} | ||
|
||
// Do not consider this as failure, else this would leak endpoints | ||
hcsshim.HotDetachEndpoint(containerID, hnsEndpoint.Id) | ||
|
||
// Do not return error | ||
hnsEndpoint.Delete() | ||
|
||
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 { | ||
createEndpoint = false | ||
} | ||
|
||
if createEndpoint { | ||
if hnsEndpoint != nil { | ||
if _, err = hnsEndpoint.Delete(); err != nil { | ||
return nil, errors.Annotate(err, "failed to delete the stale HNSEndpoint") | ||
} | ||
} | ||
|
||
if hnsEndpoint, err = makeEndpoint(); err != nil { | ||
return nil, errors.Annotate(err, "failed to make a new HNSEndpoint") | ||
} | ||
|
||
if hnsEndpoint, err = hnsEndpoint.Create(); err != nil { | ||
return nil, errors.Annotate(err, "failed to create the new HNSEndpoint") | ||
} | ||
|
||
} | ||
|
||
// hot attach | ||
if err := hcsshim.HotAttachEndpoint(containerID, hnsEndpoint.Id); err != nil { | ||
if hcsshim.ErrComputeSystemDoesNotExist == err { | ||
return hnsEndpoint, 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 := ¤t.Interface{ | ||
Name: hnsEndpoint.Name, | ||
Mac: hnsEndpoint.MacAddress, | ||
} | ||
_, ipSubnet, err := net.ParseCIDR(hnsNetwork.Subnets[0].AddressPrefix) | ||
if err != nil { | ||
return nil, errors.Annotatef(err, "failed to parse CIDR from %s", hnsNetwork.Subnets[0].AddressPrefix) | ||
} | ||
|
||
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("IPAddress of HNSEndpoint %s isn't a valid ipv4 or ipv6 Address", hnsEndpoint.Name) | ||
} | ||
|
||
resultIPConfig := ¤t.IPConfig{ | ||
Version: ipVersion, | ||
Address: net.IPNet{ | ||
IP: hnsEndpoint.IPAddress, | ||
Mask: ipSubnet.Mask}, | ||
Gateway: net.ParseIP(hnsEndpoint.GatewayAddress), | ||
} | ||
result := ¤t.Result{} | ||
result.Interfaces = []*current.Interface{resultInterface} | ||
result.IPs = []*current.IPConfig{resultIPConfig} | ||
|
||
return result, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
// 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" | ||
"strings" | ||
|
||
"bytes" | ||
"github.com/buger/jsonparser" | ||
"github.com/containernetworking/cni/pkg/types" | ||
) | ||
|
||
// NetConf is the CNI spec | ||
type NetConf struct { | ||
types.NetConf | ||
|
||
Policies []policy `json:"policies,omitempty"` | ||
} | ||
|
||
type policy struct { | ||
Name string `json:"name"` | ||
Value json.RawMessage `json:"value"` | ||
} | ||
|
||
// MarshalPolicies converts the Endpoint policies in Policies | ||
// to HNS specific policies as Json raw bytes | ||
func (n *NetConf) MarshalPolicies() []json.RawMessage { | ||
if n.Policies == nil { | ||
n.Policies = make([]policy, 0) | ||
} | ||
|
||
result := make([]json.RawMessage, 0, len(n.Policies)) | ||
for _, p := range n.Policies { | ||
if !strings.EqualFold(p.Name, "EndpointPolicy") { | ||
continue | ||
} | ||
|
||
result = append(result, p.Value) | ||
} | ||
|
||
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.Policies == nil { | ||
n.Policies = make([]policy, 0) | ||
} | ||
|
||
nwToNatBytes := []byte(nwToNat) | ||
|
||
for i, p := range n.Policies { | ||
if !strings.EqualFold(p.Name, "EndpointPolicy") { | ||
continue | ||
} | ||
|
||
typeValue, err := jsonparser.GetUnsafeString(p.Value, "Type") | ||
if err != nil || len(typeValue) == 0 { | ||
continue | ||
} | ||
|
||
if !strings.EqualFold(typeValue, "OutBoundNAT") { | ||
continue | ||
} | ||
|
||
exceptionListValue, dt, _, _ := jsonparser.Get(p.Value, "ExceptionList") | ||
// OutBoundNAT must with ExceptionList, so don't need to judge jsonparser.NotExist | ||
if dt == jsonparser.Array { | ||
buf := bytes.Buffer{} | ||
buf.WriteString(`{"Type": "OutBoundNAT", "ExceptionList": [`) | ||
|
||
jsonparser.ArrayEach(exceptionListValue, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { | ||
if dataType == jsonparser.String && len(value) != 0 { | ||
if bytes.Compare(value, nwToNatBytes) != 0 { | ||
buf.WriteByte('"') | ||
buf.Write(value) | ||
buf.WriteByte('"') | ||
buf.WriteByte(',') | ||
} | ||
} | ||
}) | ||
|
||
buf.WriteString(`"` + nwToNat + `"]}`) | ||
|
||
n.Policies[i] = policy{ | ||
Name: "EndpointPolicy", | ||
Value: buf.Bytes(), | ||
} | ||
} else { | ||
n.Policies[i] = policy{ | ||
Name: "EndpointPolicy", | ||
Value: []byte(`{"Type": "OutBoundNAT", "ExceptionList": ["` + nwToNat + `"]}`), | ||
} | ||
} | ||
|
||
return | ||
} | ||
|
||
// didn't find the policyArg, add it | ||
n.Policies = append(n.Policies, policy{ | ||
Name: "EndpointPolicy", | ||
Value: []byte(`{"Type": "OutBoundNAT", "ExceptionList": ["` + nwToNat + `"]}`), | ||
}) | ||
} | ||
|
||
// ApplyDefaultPAPolicy is used to configure a endpoint PA policy in HNS | ||
func (n *NetConf) ApplyDefaultPAPolicy(paAddress string) { | ||
if n.Policies == nil { | ||
n.Policies = make([]policy, 0) | ||
} | ||
|
||
// if its already present, leave untouched | ||
for i, p := range n.Policies { | ||
if !strings.EqualFold(p.Name, "EndpointPolicy") { | ||
continue | ||
} | ||
|
||
paValue, dt, _, _ := jsonparser.Get(p.Value, "PA") | ||
if dt == jsonparser.NotExist { | ||
continue | ||
} else if dt == jsonparser.String && len(paValue) != 0 { | ||
// found it, don't override | ||
return | ||
} | ||
|
||
n.Policies[i] = policy{ | ||
Name: "EndpointPolicy", | ||
Value: []byte(`{"Type": "PA", "PA": "` + paAddress + `"}`), | ||
} | ||
return | ||
} | ||
|
||
// didn't find the policyArg, add it | ||
n.Policies = append(n.Policies, policy{ | ||
Name: "EndpointPolicy", | ||
Value: []byte(`{"Type": "PA", "PA": "` + paAddress + `"}`), | ||
}) | ||
} |
Oops, something went wrong.