Skip to content

Commit

Permalink
Map CNI config 'type' to correct HCN NetworkType constant. (#99)
Browse files Browse the repository at this point in the history
* CNI: Map CNI config 'type' to HCN Network Type.

This patch switches the internal structures from internal constants
into the string network type constants in the `hcsshim/hcn`, as well
as adding a mechanism for automatically mapping the CNI config 'type'
value to said constants before making any HCN requests.

Signed-off-by: Nashwan Azhari <[email protected]>

* Testing: map binary names to HCN types.

Signed-off-by: Nashwan Azhari <[email protected]>

---------

Signed-off-by: Nashwan Azhari <[email protected]>
  • Loading branch information
aznashwan authored Jan 16, 2025
1 parent a0463d8 commit 1181792
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 42 deletions.
51 changes: 48 additions & 3 deletions cni/cni.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,25 @@ const (
// Supported CNI versions.
var VersionsSupported = []string{"0.2.0", "0.3.0", "0.4.0", "1.0.0"}

// Aliases for the Windows CNI plugin binary names:
const (
NatPluginName = "nat"
SdnBridgePluginName = "sdnbridge"
SdnOverlayPluginName = "sdnoverlay"
// SdnTunnelPluginName = "sdntunnel"
)

// NOTE(aznashwan): this mapping between the names of binary releases of the WinCNI
// plugins and the underlying HCN network types is required for
// backwards-compatibility with callers which rely on the old plugin naming schemes.
// See: https://github.com/microsoft/windows-container-networking/issues/57
var CniPluginNameToHcnTypeMap map[string]hcn.NetworkType = map[string]hcn.NetworkType{
NatPluginName: hcn.NAT,
SdnBridgePluginName: hcn.L2Bridge,
SdnOverlayPluginName: hcn.Overlay,
// SdnTunnelPluginName: network.L2Tunnel,
}

type KVP struct {
Name string `json:"name"`
Value json.RawMessage `json:"value"`
Expand Down Expand Up @@ -67,8 +86,8 @@ type IpamConfig struct {
// Defined as per https://github.com/containernetworking/cni/blob/master/SPEC.md
type NetworkConfig struct {
CniVersion string `json:"cniVersion"`
Name string `json:"name"` // Name is the Network Name. We would also use this as the Type of HNS Network
Type string `json:"type"` // As per SPEC, Type is Name of the Binary
Name string `json:"name"` // Name is the Network Name.
Type hcn.NetworkType `json:"type"` // As per SPEC, Type is Name of the Binary
Ipam IpamConfig `json:"ipam"`
DNS cniTypes.DNS `json:"dns"`
OptionalFlags OptionalFlags `json:"optionalFlags"`
Expand Down Expand Up @@ -180,6 +199,12 @@ func ParseNetworkConfig(b []byte) (*NetworkConfig, error) {
return nil, err
}

hcnType, err := MapCniTypeToHcnType(config.Type)
if err != nil {
return nil, err
}
config.Type = hcnType

return &config, nil
}

Expand Down Expand Up @@ -252,7 +277,7 @@ func (config *NetworkConfig) GetNetworkInfo(podNamespace string) (ninfo *network
ninfo = &network.NetworkInfo{
ID: config.Name,
Name: config.Name,
Type: network.NetworkType(config.Type),
Type: config.Type,
Subnets: subnets,
InterfaceName: "",
DNS: dnsSettings,
Expand Down Expand Up @@ -494,3 +519,23 @@ func GetInterface(endpoint *network.EndpointInfo) Interface {
Sandbox: "",
}
}

// Maps the given CNI network config "type" field into the correct HNS network type.
func MapCniTypeToHcnType(typeArg hcn.NetworkType) (hcn.NetworkType, error) {
var mappedType *hcn.NetworkType = nil
for binaryName, netType := range CniPluginNameToHcnTypeMap {
if string(typeArg) == binaryName || typeArg == netType {
mappedType = &netType
break
}
}

if mappedType == nil {
return hcn.NetworkType(""), fmt.Errorf("Unsupported CNI config 'type' %q. Options are the keys/values from: %v", typeArg, CniPluginNameToHcnTypeMap)
}
if *mappedType != typeArg {
logrus.Warnf("Provided CNI config 'type' %q will be mapped to %q", typeArg, *mappedType)
}

return *mappedType, nil
}
2 changes: 1 addition & 1 deletion common/core/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func (plugin *netPlugin) Add(args *cniSkel.CmdArgs) (resultError error) {
return err
}

if nwConfig.Type != network.L2Bridge {
if nwConfig.Type != hcn.L2Bridge {
logrus.Errorf("[cni-net] Dual stack can only be specified with l2bridge network: [%v].", nwConfig.Type)
return errors.New("Dual stack specified with non l2bridge network")
}
Expand Down
14 changes: 2 additions & 12 deletions network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,6 @@ import (
"github.com/Microsoft/hcsshim/hcn"
)

type NetworkType string

const (
NAT NetworkType = "NAT"
Overlay NetworkType = "Overlay"
Transparent NetworkType = "Transparent"
L2Tunnel NetworkType = "L2Tunnel"
L2Bridge NetworkType = "L2Bridge"
)

type DNSInfo struct {
Nameservers []string
Domain string
Expand All @@ -32,7 +22,7 @@ type DNSInfo struct {
type NetworkInfo struct {
ID string
Name string
Type NetworkType
Type hcn.NetworkType
InterfaceName string
Subnets []SubnetInfo
DNS DNSInfo
Expand Down Expand Up @@ -99,7 +89,7 @@ func GetNetworkInfoFromHostComputeNetwork(hcnNetwork *hcn.HostComputeNetwork) *N
return &NetworkInfo{
ID: hcnNetwork.Id,
Name: hcnNetwork.Name,
Type: NetworkType(hcnNetwork.Type),
Type: hcnNetwork.Type,
// Note: HostComputeNetwork has NetAdapterNameNetworkPolicySetting instead of a NetworkAdapterName/InterfaceName field.
InterfaceName: GetNetAdapterNameNetworkPolicySetting(hcnNetwork.Policies),
Subnets: subnets,
Expand Down
9 changes: 5 additions & 4 deletions plugins/nat/nat_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@ import (
"testing"

"github.com/Microsoft/hcsshim/hcn"
"github.com/Microsoft/windows-container-networking/cni"
util "github.com/Microsoft/windows-container-networking/test/utilities"
)

var testDualStack bool
var imageToUse string

func CreateNatTestNetwork() *hcn.HostComputeNetwork {
func CreateNatTestNetwork(t *testing.T) *hcn.HostComputeNetwork {
ipams := util.GetDefaultIpams()
return util.CreateTestNetwork("natNet", "Nat", ipams, false)
return util.CreateTestNetwork(t, "natNet", cni.NatPluginName, ipams, false)
}

func TestNatCmdAdd(t *testing.T) {
// t.Skip("Nat test is disabled for now.")
testDualStack = (os.Getenv("TestDualStack") == "1")
imageToUse = os.Getenv("ImageToUse")
testNetwork := CreateNatTestNetwork()
pt := util.MakeTestStruct(t, testNetwork, "nat", false, false, "", testDualStack, imageToUse)
testNetwork := CreateNatTestNetwork(t)
pt := util.MakeTestStruct(t, testNetwork, false, false, "", testDualStack, imageToUse)
pt.RunAll(t)
}
9 changes: 5 additions & 4 deletions plugins/sdnbridge/sdnbridge_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"testing"

"github.com/Microsoft/hcsshim/hcn"
"github.com/Microsoft/windows-container-networking/cni"
util "github.com/Microsoft/windows-container-networking/test/utilities"

"os"
Expand All @@ -12,20 +13,20 @@ import (
var testDualStack bool
var imageToUse string

func CreateBridgeTestNetwork() *hcn.HostComputeNetwork {
func CreateBridgeTestNetwork(t *testing.T) *hcn.HostComputeNetwork {
ipams := util.GetDefaultIpams()
if testDualStack {
ipams = append(ipams, util.GetDefaultIpv6Ipams()...)
}
return util.CreateTestNetwork("bridgeNet", "L2Bridge", ipams, true)
return util.CreateTestNetwork(t, "bridgeNet", cni.SdnBridgePluginName, ipams, true)
}

func TestBridgeCmdAdd(t *testing.T) {
// t.Skip("Bridge test is disabled for now.")
testDualStack = (os.Getenv("TestDualStack") == "1")
imageToUse = os.Getenv("ImageToUse")
testNetwork := CreateBridgeTestNetwork()
pt := util.MakeTestStruct(t, testNetwork, "L2Bridge", true, true, "", testDualStack, imageToUse)
testNetwork := CreateBridgeTestNetwork(t)
pt := util.MakeTestStruct(t, testNetwork, true, true, "", testDualStack, imageToUse)
pt.Ipv6Url = os.Getenv("Ipv6UrlToUse")
pt.RunAll(t)
}
9 changes: 5 additions & 4 deletions plugins/sdnoverlay/sdnoverlay_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"

"github.com/Microsoft/hcsshim/hcn"
"github.com/Microsoft/windows-container-networking/cni"
util "github.com/Microsoft/windows-container-networking/test/utilities"
)

Expand All @@ -28,17 +29,17 @@ func GetVsidPol() []json.RawMessage {
return []json.RawMessage{vsidPolRaw}
}

func CreateOverlayTestNetwork() *hcn.HostComputeNetwork {
func CreateOverlayTestNetwork(t *testing.T) *hcn.HostComputeNetwork {
ipams := util.GetDefaultIpams()
ipams[0].Subnets[0].Policies = GetVsidPol()
return util.CreateTestNetwork("overlayNet", "Overlay", ipams, true)
return util.CreateTestNetwork(t, "overlayNet", cni.SdnOverlayPluginName, ipams, true)
}

func TestOverlayCmdAdd(t *testing.T) {
// t.Skip("Overlay test is disabled for now.")
testDualStack = (os.Getenv("TestDualStack") == "1")
imageToUse = os.Getenv("ImageToUse")
testNetwork := CreateOverlayTestNetwork()
pt := util.MakeTestStruct(t, testNetwork, "Overlay", true, false, "", testDualStack, imageToUse)
testNetwork := CreateOverlayTestNetwork(t)
pt := util.MakeTestStruct(t, testNetwork, true, false, "", testDualStack, imageToUse)
pt.RunAll(t)
}
61 changes: 47 additions & 14 deletions test/utilities/connectivity_testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,32 +88,52 @@ func CreateNetConfIpam(cidr string) cni.IpamConfig {
return testIpam
}

func CreateNetworkConf(cniVersion string, name string, pluginType string,
dns *cniTypes.DNS, addArgs []cni.KVP, gatewayPrefix string) *cni.NetworkConfig {
func CreateNetworkConf(t *testing.T, cniVersion string, name string, pluginType hcn.NetworkType,
dns *cniTypes.DNS, addArgs []cni.KVP, gatewayPrefix string) (*cni.NetworkConfig, error) {

mappedType, err := cni.MapCniTypeToHcnType(pluginType)
if err != nil {
return nil, err
}

if pluginType != mappedType {
t.Logf("WARN: supplied network plugin type %q was mapped to HCN network type %q", pluginType, mappedType)
}

netConf := cni.NetworkConfig{
CniVersion: cniVersion,
Name: name,
Ipam: CreateNetConfIpam(gatewayPrefix),
Type: pluginType,
Type: mappedType,
DNS: *dns,
AdditionalArgs: addArgs,
}
return &netConf
return &netConf, nil
}

func CreateDualStackNetworkConf(
t *testing.T,
cniVersion string,
name string,
pluginType string,
pluginType hcn.NetworkType,
dns *cniTypes.DNS,
addArgs []cni.KVP,
gatewayPrefixv4 string,
gatewayPrefixv6 string) *cni.NetworkConfig {
gatewayPrefixv6 string) (*cni.NetworkConfig, error) {

mappedType, err := cni.MapCniTypeToHcnType(pluginType)
if err != nil {
return nil, err
}

if pluginType != mappedType {
t.Logf("WARN: supplied network plugin type %q was mapped to HCN network type %q", pluginType, mappedType)
}

netConf := cni.NetworkConfig{
CniVersion: cniVersion,
Name: name,
Type: pluginType,
Type: mappedType,
DNS: *dns,
AdditionalArgs: addArgs,
}
Expand All @@ -139,7 +159,7 @@ func CreateDualStackNetworkConf(

netConf.AdditionalRoutes = append(netConf.AdditionalRoutes, testRoute)

return &netConf
return &netConf, nil
}

func GetDefaultIpams() []hcn.Ipam {
Expand Down Expand Up @@ -289,14 +309,24 @@ func CreateGatewayEp(t *testing.T, networkId string, ipAddress string, ipv6Adres
return nil
}

func CreateTestNetwork(name string, netType string, ipams []hcn.Ipam, tryGetNetAdapter bool) *hcn.HostComputeNetwork {
func CreateTestNetwork(t *testing.T, name string, netType string, ipams []hcn.Ipam, tryGetNetAdapter bool) *hcn.HostComputeNetwork {
hcnNetType := hcn.NetworkType(netType)
mappedType, err := cni.MapCniTypeToHcnType(hcnNetType)
if err != nil {
t.Errorf("Failed to map testing network type %q to HCN network type: %v", netType, err)
}

if mappedType != hcnNetType {
t.Logf("WARN: testing network type %q was mapped to HCN network type %q", netType, mappedType)
}

network := &hcn.HostComputeNetwork{
SchemaVersion: hcn.SchemaVersion{
Major: 2,
Minor: 0,
},
Name: name,
Type: hcn.NetworkType(netType),
Type: mappedType,
Ipams: ipams,
}

Expand All @@ -312,7 +342,6 @@ func CreateTestNetwork(name string, netType string, ipams []hcn.Ipam, tryGetNetA
func MakeTestStruct(
t *testing.T,
testNetwork *hcn.HostComputeNetwork,
pluginType string,
epPols bool,
needGW bool,
cid string,
Expand Down Expand Up @@ -352,11 +381,15 @@ func MakeTestStruct(
var netConf *cni.NetworkConfig

if !testDualStack {
netConf = CreateNetworkConf(defaultCniVersion, testNetwork.Name, pluginType, dns, addArgs, netConfPrefix)
if netConf, err = CreateNetworkConf(t, defaultCniVersion, testNetwork.Name, testNetwork.Type, dns, addArgs, netConfPrefix); err != nil {
t.Errorf("Failed to create testing network config: %v", err)
return nil
}
} else {

netConfPrefixv6 := "fd00::101/64"
netConf = CreateDualStackNetworkConf(defaultCniVersion, testNetwork.Name, pluginType, dns, addArgs, netConfPrefix, netConfPrefixv6)
if netConf, err = CreateDualStackNetworkConf(t, defaultCniVersion, testNetwork.Name, testNetwork.Type, dns, addArgs, netConfPrefix, netConfPrefixv6); err != nil {
return nil
}

}
netJson, _ := json.Marshal(netConf)
Expand Down

0 comments on commit 1181792

Please sign in to comment.