k8s.io/kubernetes@v1.29.3/pkg/proxy/winkernel/proxier_test.go (about)

     1  //go:build windows
     2  // +build windows
     3  
     4  /*
     5  Copyright 2021 The Kubernetes Authors.
     6  
     7  Licensed under the Apache License, Version 2.0 (the "License");
     8  you may not use this file except in compliance with the License.
     9  You may obtain a copy of the License at
    10  
    11      http://www.apache.org/licenses/LICENSE-2.0
    12  
    13  Unless required by applicable law or agreed to in writing, software
    14  distributed under the License is distributed on an "AS IS" BASIS,
    15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  See the License for the specific language governing permissions and
    17  limitations under the License.
    18  */
    19  
    20  package winkernel
    21  
    22  import (
    23  	"encoding/json"
    24  	"fmt"
    25  	"net"
    26  	"strings"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/Microsoft/hcsshim/hcn"
    31  	v1 "k8s.io/api/core/v1"
    32  	discovery "k8s.io/api/discovery/v1"
    33  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    34  	"k8s.io/apimachinery/pkg/types"
    35  	"k8s.io/apimachinery/pkg/util/intstr"
    36  	"k8s.io/kubernetes/pkg/proxy"
    37  	"k8s.io/kubernetes/pkg/proxy/healthcheck"
    38  	fakehcn "k8s.io/kubernetes/pkg/proxy/winkernel/testing"
    39  	netutils "k8s.io/utils/net"
    40  	"k8s.io/utils/ptr"
    41  )
    42  
    43  const (
    44  	testHostName      = "test-hostname"
    45  	testNetwork       = "TestNetwork"
    46  	ipAddress         = "10.0.0.1"
    47  	prefixLen         = 24
    48  	macAddress        = "00-11-22-33-44-55"
    49  	clusterCIDR       = "192.168.1.0/24"
    50  	destinationPrefix = "192.168.2.0/24"
    51  	providerAddress   = "10.0.0.3"
    52  	guid              = "123ABC"
    53  	endpointGuid1     = "EPID-1"
    54  	loadbalancerGuid1 = "LBID-1"
    55  	endpointLocal     = "EP-LOCAL"
    56  	endpointGw        = "EP-GW"
    57  	epIpAddressGw     = "192.168.2.1"
    58  	epMacAddressGw    = "00-11-22-33-44-66"
    59  )
    60  
    61  func newHnsNetwork(networkInfo *hnsNetworkInfo) *hcn.HostComputeNetwork {
    62  	var policies []hcn.NetworkPolicy
    63  	for _, remoteSubnet := range networkInfo.remoteSubnets {
    64  		policySettings := hcn.RemoteSubnetRoutePolicySetting{
    65  			DestinationPrefix:           remoteSubnet.destinationPrefix,
    66  			IsolationId:                 remoteSubnet.isolationID,
    67  			ProviderAddress:             remoteSubnet.providerAddress,
    68  			DistributedRouterMacAddress: remoteSubnet.drMacAddress,
    69  		}
    70  		settings, _ := json.Marshal(policySettings)
    71  		policy := hcn.NetworkPolicy{
    72  			Type:     hcn.RemoteSubnetRoute,
    73  			Settings: settings,
    74  		}
    75  		policies = append(policies, policy)
    76  	}
    77  
    78  	network := &hcn.HostComputeNetwork{
    79  		Id:       networkInfo.id,
    80  		Name:     networkInfo.name,
    81  		Type:     hcn.NetworkType(networkInfo.networkType),
    82  		Policies: policies,
    83  	}
    84  	return network
    85  }
    86  
    87  func NewFakeProxier(syncPeriod time.Duration, minSyncPeriod time.Duration, clusterCIDR string, hostname string, nodeIP net.IP, networkType string) *Proxier {
    88  	sourceVip := "192.168.1.2"
    89  	var remoteSubnets []*remoteSubnetInfo
    90  	rs := &remoteSubnetInfo{
    91  		destinationPrefix: destinationPrefix,
    92  		isolationID:       4096,
    93  		providerAddress:   providerAddress,
    94  		drMacAddress:      macAddress,
    95  	}
    96  	remoteSubnets = append(remoteSubnets, rs)
    97  	hnsNetworkInfo := &hnsNetworkInfo{
    98  		id:            strings.ToUpper(guid),
    99  		name:          testNetwork,
   100  		networkType:   networkType,
   101  		remoteSubnets: remoteSubnets,
   102  	}
   103  	hnsNetwork := newHnsNetwork(hnsNetworkInfo)
   104  	hcnMock := fakehcn.NewHcnMock(hnsNetwork)
   105  	proxier := &Proxier{
   106  		svcPortMap:          make(proxy.ServicePortMap),
   107  		endpointsMap:        make(proxy.EndpointsMap),
   108  		clusterCIDR:         clusterCIDR,
   109  		hostname:            testHostName,
   110  		nodeIP:              nodeIP,
   111  		serviceHealthServer: healthcheck.NewFakeServiceHealthServer(),
   112  		network:             *hnsNetworkInfo,
   113  		sourceVip:           sourceVip,
   114  		hostMac:             macAddress,
   115  		isDSR:               false,
   116  		hns: &hns{
   117  			hcn: hcnMock,
   118  		},
   119  		hcn:                   hcnMock,
   120  		endPointsRefCount:     make(endPointsReferenceCountMap),
   121  		forwardHealthCheckVip: true,
   122  		mapStaleLoadbalancers: make(map[string]bool),
   123  	}
   124  
   125  	serviceChanges := proxy.NewServiceChangeTracker(proxier.newServiceInfo, v1.IPv4Protocol, nil, proxier.serviceMapChange)
   126  	endpointsChangeTracker := proxy.NewEndpointsChangeTracker(hostname, proxier.newEndpointInfo, v1.IPv4Protocol, nil, proxier.endpointsMapChange)
   127  	proxier.endpointsChanges = endpointsChangeTracker
   128  	proxier.serviceChanges = serviceChanges
   129  
   130  	return proxier
   131  }
   132  
   133  func TestCreateServiceVip(t *testing.T) {
   134  	syncPeriod := 30 * time.Second
   135  	proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)
   136  	if proxier == nil {
   137  		t.Error()
   138  	}
   139  
   140  	svcIP := "10.20.30.41"
   141  	svcPort := 80
   142  	svcNodePort := 3001
   143  	svcExternalIPs := "50.60.70.81"
   144  	svcPortName := proxy.ServicePortName{
   145  		NamespacedName: makeNSN("ns1", "svc1"),
   146  		Port:           "p80",
   147  		Protocol:       v1.ProtocolTCP,
   148  	}
   149  
   150  	makeServiceMap(proxier,
   151  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
   152  			svc.Spec.Type = "NodePort"
   153  			svc.Spec.ClusterIP = svcIP
   154  			svc.Spec.ExternalIPs = []string{svcExternalIPs}
   155  			svc.Spec.SessionAffinity = v1.ServiceAffinityClientIP
   156  			svc.Spec.SessionAffinityConfig = &v1.SessionAffinityConfig{
   157  				ClientIP: &v1.ClientIPConfig{
   158  					TimeoutSeconds: ptr.To[int32](v1.DefaultClientIPServiceAffinitySeconds),
   159  				},
   160  			}
   161  			svc.Spec.Ports = []v1.ServicePort{{
   162  				Name:     svcPortName.Port,
   163  				Port:     int32(svcPort),
   164  				Protocol: v1.ProtocolTCP,
   165  				NodePort: int32(svcNodePort),
   166  			}}
   167  		}),
   168  	)
   169  	proxier.setInitialized(true)
   170  	proxier.syncProxyRules()
   171  
   172  	svc := proxier.svcPortMap[svcPortName]
   173  	svcInfo, ok := svc.(*serviceInfo)
   174  	if !ok {
   175  		t.Errorf("Failed to cast serviceInfo %q", svcPortName.String())
   176  
   177  	} else {
   178  		if svcInfo.remoteEndpoint == nil {
   179  			t.Error()
   180  		}
   181  		if svcInfo.remoteEndpoint.ip != svcIP {
   182  			t.Error()
   183  		}
   184  	}
   185  }
   186  
   187  func TestCreateRemoteEndpointOverlay(t *testing.T) {
   188  	syncPeriod := 30 * time.Second
   189  	proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)
   190  	if proxier == nil {
   191  		t.Error()
   192  	}
   193  
   194  	svcIP := "10.20.30.41"
   195  	svcPort := 80
   196  	svcNodePort := 3001
   197  	svcPortName := proxy.ServicePortName{
   198  		NamespacedName: makeNSN("ns1", "svc1"),
   199  		Port:           "p80",
   200  		Protocol:       v1.ProtocolTCP,
   201  	}
   202  
   203  	makeServiceMap(proxier,
   204  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
   205  			svc.Spec.Type = "NodePort"
   206  			svc.Spec.ClusterIP = svcIP
   207  			svc.Spec.Ports = []v1.ServicePort{{
   208  				Name:     svcPortName.Port,
   209  				Port:     int32(svcPort),
   210  				Protocol: v1.ProtocolTCP,
   211  				NodePort: int32(svcNodePort),
   212  			}}
   213  		}),
   214  	)
   215  	populateEndpointSlices(proxier,
   216  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
   217  			eps.AddressType = discovery.AddressTypeIPv4
   218  			eps.Endpoints = []discovery.Endpoint{{
   219  				Addresses: []string{epIpAddressRemote},
   220  			}}
   221  			eps.Ports = []discovery.EndpointPort{{
   222  				Name:     ptr.To(svcPortName.Port),
   223  				Port:     ptr.To(int32(svcPort)),
   224  				Protocol: ptr.To(v1.ProtocolTCP),
   225  			}}
   226  		}),
   227  	)
   228  
   229  	proxier.setInitialized(true)
   230  	proxier.syncProxyRules()
   231  
   232  	ep := proxier.endpointsMap[svcPortName][0]
   233  	epInfo, ok := ep.(*endpointInfo)
   234  	if !ok {
   235  		t.Errorf("Failed to cast endpointInfo %q", svcPortName.String())
   236  
   237  	} else {
   238  		if epInfo.hnsID != "EPID-3" {
   239  			t.Errorf("%v does not match %v", epInfo.hnsID, endpointGuid1)
   240  		}
   241  	}
   242  
   243  	if *proxier.endPointsRefCount["EPID-3"] <= 0 {
   244  		t.Errorf("RefCount not incremented. Current value: %v", *proxier.endPointsRefCount[endpointGuid1])
   245  	}
   246  
   247  	if *proxier.endPointsRefCount["EPID-3"] != *epInfo.refCount {
   248  		t.Errorf("Global refCount: %v does not match endpoint refCount: %v", *proxier.endPointsRefCount[endpointGuid1], *epInfo.refCount)
   249  	}
   250  }
   251  
   252  func TestCreateRemoteEndpointL2Bridge(t *testing.T) {
   253  	syncPeriod := 30 * time.Second
   254  	proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", netutils.ParseIPSloppy("10.0.0.1"), "L2Bridge")
   255  	if proxier == nil {
   256  		t.Error()
   257  	}
   258  
   259  	svcIP := "10.20.30.41"
   260  	svcPort := 80
   261  	svcNodePort := 3001
   262  	svcPortName := proxy.ServicePortName{
   263  		NamespacedName: makeNSN("ns1", "svc1"),
   264  		Port:           "p80",
   265  		Protocol:       v1.ProtocolTCP,
   266  	}
   267  
   268  	makeServiceMap(proxier,
   269  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
   270  			svc.Spec.Type = "NodePort"
   271  			svc.Spec.ClusterIP = svcIP
   272  			svc.Spec.Ports = []v1.ServicePort{{
   273  				Name:     svcPortName.Port,
   274  				Port:     int32(svcPort),
   275  				Protocol: v1.ProtocolTCP,
   276  				NodePort: int32(svcNodePort),
   277  			}}
   278  		}),
   279  	)
   280  	populateEndpointSlices(proxier,
   281  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
   282  			eps.AddressType = discovery.AddressTypeIPv4
   283  			eps.Endpoints = []discovery.Endpoint{{
   284  				Addresses: []string{epIpAddressRemote},
   285  			}}
   286  			eps.Ports = []discovery.EndpointPort{{
   287  				Name:     ptr.To(svcPortName.Port),
   288  				Port:     ptr.To(int32(svcPort)),
   289  				Protocol: ptr.To(v1.ProtocolTCP),
   290  			}}
   291  		}),
   292  	)
   293  	proxier.setInitialized(true)
   294  	proxier.syncProxyRules()
   295  	ep := proxier.endpointsMap[svcPortName][0]
   296  	epInfo, ok := ep.(*endpointInfo)
   297  	if !ok {
   298  		t.Errorf("Failed to cast endpointInfo %q", svcPortName.String())
   299  
   300  	} else {
   301  		if epInfo.hnsID != endpointGuid1 {
   302  			t.Errorf("%v does not match %v", epInfo.hnsID, endpointGuid1)
   303  		}
   304  	}
   305  
   306  	if *proxier.endPointsRefCount[endpointGuid1] <= 0 {
   307  		t.Errorf("RefCount not incremented. Current value: %v", *proxier.endPointsRefCount[endpointGuid1])
   308  	}
   309  
   310  	if *proxier.endPointsRefCount[endpointGuid1] != *epInfo.refCount {
   311  		t.Errorf("Global refCount: %v does not match endpoint refCount: %v", *proxier.endPointsRefCount[endpointGuid1], *epInfo.refCount)
   312  	}
   313  }
   314  func TestSharedRemoteEndpointDelete(t *testing.T) {
   315  	syncPeriod := 30 * time.Second
   316  	proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", netutils.ParseIPSloppy("10.0.0.1"), "L2Bridge")
   317  	if proxier == nil {
   318  		t.Error()
   319  	}
   320  
   321  	svcIP1 := "10.20.30.41"
   322  	svcPort1 := 80
   323  	svcNodePort1 := 3001
   324  	svcPortName1 := proxy.ServicePortName{
   325  		NamespacedName: makeNSN("ns1", "svc1"),
   326  		Port:           "p80",
   327  		Protocol:       v1.ProtocolTCP,
   328  	}
   329  
   330  	svcIP2 := "10.20.30.42"
   331  	svcPort2 := 80
   332  	svcNodePort2 := 3002
   333  	svcPortName2 := proxy.ServicePortName{
   334  		NamespacedName: makeNSN("ns1", "svc2"),
   335  		Port:           "p80",
   336  		Protocol:       v1.ProtocolTCP,
   337  	}
   338  
   339  	makeServiceMap(proxier,
   340  		makeTestService(svcPortName1.Namespace, svcPortName1.Name, func(svc *v1.Service) {
   341  			svc.Spec.Type = "NodePort"
   342  			svc.Spec.ClusterIP = svcIP1
   343  			svc.Spec.Ports = []v1.ServicePort{{
   344  				Name:     svcPortName1.Port,
   345  				Port:     int32(svcPort1),
   346  				Protocol: v1.ProtocolTCP,
   347  				NodePort: int32(svcNodePort1),
   348  			}}
   349  		}),
   350  		makeTestService(svcPortName2.Namespace, svcPortName2.Name, func(svc *v1.Service) {
   351  			svc.Spec.Type = "NodePort"
   352  			svc.Spec.ClusterIP = svcIP2
   353  			svc.Spec.Ports = []v1.ServicePort{{
   354  				Name:     svcPortName2.Port,
   355  				Port:     int32(svcPort2),
   356  				Protocol: v1.ProtocolTCP,
   357  				NodePort: int32(svcNodePort2),
   358  			}}
   359  		}),
   360  	)
   361  	populateEndpointSlices(proxier,
   362  		makeTestEndpointSlice(svcPortName1.Namespace, svcPortName1.Name, 1, func(eps *discovery.EndpointSlice) {
   363  			eps.AddressType = discovery.AddressTypeIPv4
   364  			eps.Endpoints = []discovery.Endpoint{{
   365  				Addresses: []string{epIpAddressRemote},
   366  			}}
   367  			eps.Ports = []discovery.EndpointPort{{
   368  				Name:     ptr.To(svcPortName1.Port),
   369  				Port:     ptr.To(int32(svcPort1)),
   370  				Protocol: ptr.To(v1.ProtocolTCP),
   371  			}}
   372  		}),
   373  		makeTestEndpointSlice(svcPortName2.Namespace, svcPortName2.Name, 1, func(eps *discovery.EndpointSlice) {
   374  			eps.AddressType = discovery.AddressTypeIPv4
   375  			eps.Endpoints = []discovery.Endpoint{{
   376  				Addresses: []string{epIpAddressRemote},
   377  			}}
   378  			eps.Ports = []discovery.EndpointPort{{
   379  				Name:     ptr.To(svcPortName2.Port),
   380  				Port:     ptr.To(int32(svcPort2)),
   381  				Protocol: ptr.To(v1.ProtocolTCP),
   382  			}}
   383  		}),
   384  	)
   385  	proxier.setInitialized(true)
   386  	proxier.syncProxyRules()
   387  	ep := proxier.endpointsMap[svcPortName1][0]
   388  	epInfo, ok := ep.(*endpointInfo)
   389  	if !ok {
   390  		t.Errorf("Failed to cast endpointInfo %q", svcPortName1.String())
   391  
   392  	} else {
   393  		if epInfo.hnsID != endpointGuid1 {
   394  			t.Errorf("%v does not match %v", epInfo.hnsID, endpointGuid1)
   395  		}
   396  	}
   397  
   398  	if *proxier.endPointsRefCount[endpointGuid1] != 2 {
   399  		t.Errorf("RefCount not incremented. Current value: %v", *proxier.endPointsRefCount[endpointGuid1])
   400  	}
   401  
   402  	if *proxier.endPointsRefCount[endpointGuid1] != *epInfo.refCount {
   403  		t.Errorf("Global refCount: %v does not match endpoint refCount: %v", *proxier.endPointsRefCount[endpointGuid1], *epInfo.refCount)
   404  	}
   405  
   406  	proxier.setInitialized(false)
   407  	deleteServices(proxier,
   408  		makeTestService(svcPortName2.Namespace, svcPortName2.Name, func(svc *v1.Service) {
   409  			svc.Spec.Type = "NodePort"
   410  			svc.Spec.ClusterIP = svcIP2
   411  			svc.Spec.Ports = []v1.ServicePort{{
   412  				Name:     svcPortName2.Port,
   413  				Port:     int32(svcPort2),
   414  				Protocol: v1.ProtocolTCP,
   415  				NodePort: int32(svcNodePort2),
   416  			}}
   417  		}),
   418  	)
   419  
   420  	deleteEndpointSlices(proxier,
   421  		makeTestEndpointSlice(svcPortName2.Namespace, svcPortName2.Name, 1, func(eps *discovery.EndpointSlice) {
   422  			eps.AddressType = discovery.AddressTypeIPv4
   423  			eps.Endpoints = []discovery.Endpoint{{
   424  				Addresses: []string{epIpAddressRemote},
   425  			}}
   426  			eps.Ports = []discovery.EndpointPort{{
   427  				Name:     ptr.To(svcPortName2.Port),
   428  				Port:     ptr.To(int32(svcPort2)),
   429  				Protocol: ptr.To(v1.ProtocolTCP),
   430  			}}
   431  		}),
   432  	)
   433  
   434  	proxier.setInitialized(true)
   435  	proxier.syncProxyRules()
   436  
   437  	ep = proxier.endpointsMap[svcPortName1][0]
   438  	epInfo, ok = ep.(*endpointInfo)
   439  	if !ok {
   440  		t.Errorf("Failed to cast endpointInfo %q", svcPortName1.String())
   441  
   442  	} else {
   443  		if epInfo.hnsID != endpointGuid1 {
   444  			t.Errorf("%v does not match %v", epInfo.hnsID, endpointGuid1)
   445  		}
   446  	}
   447  
   448  	if *epInfo.refCount != 1 {
   449  		t.Errorf("Incorrect Refcount. Current value: %v", *epInfo.refCount)
   450  	}
   451  
   452  	if *proxier.endPointsRefCount[endpointGuid1] != *epInfo.refCount {
   453  		t.Errorf("Global refCount: %v does not match endpoint refCount: %v", *proxier.endPointsRefCount[endpointGuid1], *epInfo.refCount)
   454  	}
   455  }
   456  func TestSharedRemoteEndpointUpdate(t *testing.T) {
   457  	syncPeriod := 30 * time.Second
   458  	proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", netutils.ParseIPSloppy("10.0.0.1"), "L2Bridge")
   459  	if proxier == nil {
   460  		t.Error()
   461  	}
   462  
   463  	svcIP1 := "10.20.30.41"
   464  	svcPort1 := 80
   465  	svcNodePort1 := 3001
   466  	svcPortName1 := proxy.ServicePortName{
   467  		NamespacedName: makeNSN("ns1", "svc1"),
   468  		Port:           "p80",
   469  		Protocol:       v1.ProtocolTCP,
   470  	}
   471  
   472  	svcIP2 := "10.20.30.42"
   473  	svcPort2 := 80
   474  	svcNodePort2 := 3002
   475  	svcPortName2 := proxy.ServicePortName{
   476  		NamespacedName: makeNSN("ns1", "svc2"),
   477  		Port:           "p80",
   478  		Protocol:       v1.ProtocolTCP,
   479  	}
   480  
   481  	makeServiceMap(proxier,
   482  		makeTestService(svcPortName1.Namespace, svcPortName1.Name, func(svc *v1.Service) {
   483  			svc.Spec.Type = "NodePort"
   484  			svc.Spec.ClusterIP = svcIP1
   485  			svc.Spec.Ports = []v1.ServicePort{{
   486  				Name:     svcPortName1.Port,
   487  				Port:     int32(svcPort1),
   488  				Protocol: v1.ProtocolTCP,
   489  				NodePort: int32(svcNodePort1),
   490  			}}
   491  		}),
   492  		makeTestService(svcPortName2.Namespace, svcPortName2.Name, func(svc *v1.Service) {
   493  			svc.Spec.Type = "NodePort"
   494  			svc.Spec.ClusterIP = svcIP2
   495  			svc.Spec.Ports = []v1.ServicePort{{
   496  				Name:     svcPortName2.Port,
   497  				Port:     int32(svcPort2),
   498  				Protocol: v1.ProtocolTCP,
   499  				NodePort: int32(svcNodePort2),
   500  			}}
   501  		}),
   502  	)
   503  
   504  	populateEndpointSlices(proxier,
   505  		makeTestEndpointSlice(svcPortName1.Namespace, svcPortName1.Name, 1, func(eps *discovery.EndpointSlice) {
   506  			eps.AddressType = discovery.AddressTypeIPv4
   507  			eps.Endpoints = []discovery.Endpoint{{
   508  				Addresses: []string{epIpAddressRemote},
   509  			}}
   510  			eps.Ports = []discovery.EndpointPort{{
   511  				Name:     ptr.To(svcPortName1.Port),
   512  				Port:     ptr.To(int32(svcPort1)),
   513  				Protocol: ptr.To(v1.ProtocolTCP),
   514  			}}
   515  		}),
   516  		makeTestEndpointSlice(svcPortName2.Namespace, svcPortName2.Name, 1, func(eps *discovery.EndpointSlice) {
   517  			eps.AddressType = discovery.AddressTypeIPv4
   518  			eps.Endpoints = []discovery.Endpoint{{
   519  				Addresses: []string{epIpAddressRemote},
   520  			}}
   521  			eps.Ports = []discovery.EndpointPort{{
   522  				Name:     ptr.To(svcPortName2.Port),
   523  				Port:     ptr.To(int32(svcPort2)),
   524  				Protocol: ptr.To(v1.ProtocolTCP),
   525  			}}
   526  		}),
   527  	)
   528  
   529  	proxier.setInitialized(true)
   530  	proxier.syncProxyRules()
   531  	ep := proxier.endpointsMap[svcPortName1][0]
   532  	epInfo, ok := ep.(*endpointInfo)
   533  	if !ok {
   534  		t.Errorf("Failed to cast endpointInfo %q", svcPortName1.String())
   535  
   536  	} else {
   537  		if epInfo.hnsID != endpointGuid1 {
   538  			t.Errorf("%v does not match %v", epInfo.hnsID, endpointGuid1)
   539  		}
   540  	}
   541  
   542  	if *proxier.endPointsRefCount[endpointGuid1] != 2 {
   543  		t.Errorf("RefCount not incremented. Current value: %v", *proxier.endPointsRefCount[endpointGuid1])
   544  	}
   545  
   546  	if *proxier.endPointsRefCount[endpointGuid1] != *epInfo.refCount {
   547  		t.Errorf("Global refCount: %v does not match endpoint refCount: %v", *proxier.endPointsRefCount[endpointGuid1], *epInfo.refCount)
   548  	}
   549  
   550  	proxier.setInitialized(false)
   551  
   552  	proxier.OnServiceUpdate(
   553  		makeTestService(svcPortName1.Namespace, svcPortName1.Name, func(svc *v1.Service) {
   554  			svc.Spec.Type = "NodePort"
   555  			svc.Spec.ClusterIP = svcIP1
   556  			svc.Spec.Ports = []v1.ServicePort{{
   557  				Name:     svcPortName1.Port,
   558  				Port:     int32(svcPort1),
   559  				Protocol: v1.ProtocolTCP,
   560  				NodePort: int32(svcNodePort1),
   561  			}}
   562  		}),
   563  		makeTestService(svcPortName1.Namespace, svcPortName1.Name, func(svc *v1.Service) {
   564  			svc.Spec.Type = "NodePort"
   565  			svc.Spec.ClusterIP = svcIP1
   566  			svc.Spec.Ports = []v1.ServicePort{{
   567  				Name:     svcPortName1.Port,
   568  				Port:     int32(svcPort1),
   569  				Protocol: v1.ProtocolTCP,
   570  				NodePort: int32(3003),
   571  			}}
   572  		}))
   573  
   574  	proxier.OnEndpointSliceUpdate(
   575  		makeTestEndpointSlice(svcPortName1.Namespace, svcPortName1.Name, 1, func(eps *discovery.EndpointSlice) {
   576  			eps.AddressType = discovery.AddressTypeIPv4
   577  			eps.Endpoints = []discovery.Endpoint{{
   578  				Addresses: []string{epIpAddressRemote},
   579  			}}
   580  			eps.Ports = []discovery.EndpointPort{{
   581  				Name:     ptr.To(svcPortName1.Port),
   582  				Port:     ptr.To(int32(svcPort1)),
   583  				Protocol: ptr.To(v1.ProtocolTCP),
   584  			}}
   585  		}),
   586  		makeTestEndpointSlice(svcPortName1.Namespace, svcPortName1.Name, 1, func(eps *discovery.EndpointSlice) {
   587  			eps.AddressType = discovery.AddressTypeIPv4
   588  			eps.Endpoints = []discovery.Endpoint{{
   589  				Addresses: []string{epIpAddressRemote},
   590  			}}
   591  			eps.Ports = []discovery.EndpointPort{{
   592  				Name:     ptr.To(svcPortName1.Port),
   593  				Port:     ptr.To(int32(svcPort1)),
   594  				Protocol: ptr.To(v1.ProtocolTCP),
   595  			},
   596  				{
   597  					Name:     ptr.To("p443"),
   598  					Port:     ptr.To[int32](443),
   599  					Protocol: ptr.To(v1.ProtocolTCP),
   600  				}}
   601  		}))
   602  
   603  	proxier.mu.Lock()
   604  	proxier.endpointSlicesSynced = true
   605  	proxier.mu.Unlock()
   606  
   607  	proxier.setInitialized(true)
   608  	proxier.syncProxyRules()
   609  
   610  	ep = proxier.endpointsMap[svcPortName1][0]
   611  	epInfo, ok = ep.(*endpointInfo)
   612  
   613  	if !ok {
   614  		t.Errorf("Failed to cast endpointInfo %q", svcPortName1.String())
   615  
   616  	} else {
   617  		if epInfo.hnsID != endpointGuid1 {
   618  			t.Errorf("%v does not match %v", epInfo.hnsID, endpointGuid1)
   619  		}
   620  	}
   621  
   622  	if *epInfo.refCount != 2 {
   623  		t.Errorf("Incorrect refcount. Current value: %v", *epInfo.refCount)
   624  	}
   625  
   626  	if *proxier.endPointsRefCount[endpointGuid1] != *epInfo.refCount {
   627  		t.Errorf("Global refCount: %v does not match endpoint refCount: %v", *proxier.endPointsRefCount[endpointGuid1], *epInfo.refCount)
   628  	}
   629  }
   630  func TestCreateLoadBalancer(t *testing.T) {
   631  	syncPeriod := 30 * time.Second
   632  	proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)
   633  	if proxier == nil {
   634  		t.Error()
   635  	}
   636  
   637  	svcIP := "10.20.30.41"
   638  	svcPort := 80
   639  	svcNodePort := 3001
   640  	svcPortName := proxy.ServicePortName{
   641  		NamespacedName: makeNSN("ns1", "svc1"),
   642  		Port:           "p80",
   643  		Protocol:       v1.ProtocolTCP,
   644  	}
   645  
   646  	makeServiceMap(proxier,
   647  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
   648  			svc.Spec.Type = "NodePort"
   649  			svc.Spec.ClusterIP = svcIP
   650  			svc.Spec.Ports = []v1.ServicePort{{
   651  				Name:     svcPortName.Port,
   652  				Port:     int32(svcPort),
   653  				Protocol: v1.ProtocolTCP,
   654  				NodePort: int32(svcNodePort),
   655  			}}
   656  		}),
   657  	)
   658  	populateEndpointSlices(proxier,
   659  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
   660  			eps.AddressType = discovery.AddressTypeIPv4
   661  			eps.Endpoints = []discovery.Endpoint{{
   662  				Addresses: []string{epIpAddressRemote},
   663  			}}
   664  			eps.Ports = []discovery.EndpointPort{{
   665  				Name:     ptr.To(svcPortName.Port),
   666  				Port:     ptr.To(int32(svcPort)),
   667  				Protocol: ptr.To(v1.ProtocolTCP),
   668  			}}
   669  		}),
   670  	)
   671  
   672  	proxier.setInitialized(true)
   673  	proxier.syncProxyRules()
   674  
   675  	svc := proxier.svcPortMap[svcPortName]
   676  	svcInfo, ok := svc.(*serviceInfo)
   677  	if !ok {
   678  		t.Errorf("Failed to cast serviceInfo %q", svcPortName.String())
   679  
   680  	} else {
   681  		if svcInfo.hnsID != loadbalancerGuid1 {
   682  			t.Errorf("%v does not match %v", svcInfo.hnsID, loadbalancerGuid1)
   683  		}
   684  	}
   685  }
   686  
   687  func TestCreateDsrLoadBalancer(t *testing.T) {
   688  	syncPeriod := 30 * time.Second
   689  	proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)
   690  	if proxier == nil {
   691  		t.Error()
   692  	}
   693  
   694  	svcIP := "10.20.30.41"
   695  	svcPort := 80
   696  	svcNodePort := 3001
   697  	svcPortName := proxy.ServicePortName{
   698  		NamespacedName: makeNSN("ns1", "svc1"),
   699  		Port:           "p80",
   700  		Protocol:       v1.ProtocolTCP,
   701  	}
   702  	lbIP := "11.21.31.41"
   703  
   704  	makeServiceMap(proxier,
   705  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
   706  			svc.Spec.Type = "NodePort"
   707  			svc.Spec.ClusterIP = svcIP
   708  			svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
   709  			svc.Spec.Ports = []v1.ServicePort{{
   710  				Name:     svcPortName.Port,
   711  				Port:     int32(svcPort),
   712  				Protocol: v1.ProtocolTCP,
   713  				NodePort: int32(svcNodePort),
   714  			}}
   715  			svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
   716  				IP: lbIP,
   717  			}}
   718  		}),
   719  	)
   720  	populateEndpointSlices(proxier,
   721  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
   722  			eps.AddressType = discovery.AddressTypeIPv4
   723  			eps.Endpoints = []discovery.Endpoint{{
   724  				Addresses: []string{epIpAddressRemote},
   725  				NodeName:  ptr.To("testhost"),
   726  			}}
   727  			eps.Ports = []discovery.EndpointPort{{
   728  				Name:     ptr.To(svcPortName.Port),
   729  				Port:     ptr.To(int32(svcPort)),
   730  				Protocol: ptr.To(v1.ProtocolTCP),
   731  			}}
   732  		}),
   733  	)
   734  
   735  	hcn := (proxier.hcn).(*fakehcn.HcnMock)
   736  	proxier.rootHnsEndpointName = endpointGw
   737  	hcn.PopulateQueriedEndpoints(endpointLocal, guid, epIpAddressRemote, macAddress, prefixLen)
   738  	hcn.PopulateQueriedEndpoints(endpointGw, guid, epIpAddressGw, epMacAddressGw, prefixLen)
   739  	proxier.setInitialized(true)
   740  	proxier.syncProxyRules()
   741  
   742  	svc := proxier.svcPortMap[svcPortName]
   743  	svcInfo, ok := svc.(*serviceInfo)
   744  	if !ok {
   745  		t.Errorf("Failed to cast serviceInfo %q", svcPortName.String())
   746  
   747  	} else {
   748  		if svcInfo.hnsID != loadbalancerGuid1 {
   749  			t.Errorf("%v does not match %v", svcInfo.hnsID, loadbalancerGuid1)
   750  		}
   751  		if svcInfo.localTrafficDSR != true {
   752  			t.Errorf("Failed to create DSR loadbalancer with local traffic policy")
   753  		}
   754  		if len(svcInfo.loadBalancerIngressIPs) == 0 {
   755  			t.Errorf("svcInfo does not have any loadBalancerIngressIPs, %+v", svcInfo)
   756  		} else if svcInfo.loadBalancerIngressIPs[0].healthCheckHnsID != "LBID-4" {
   757  			t.Errorf("The Hns Loadbalancer HealthCheck Id %v does not match %v. ServicePortName %q", svcInfo.loadBalancerIngressIPs[0].healthCheckHnsID, loadbalancerGuid1, svcPortName.String())
   758  		}
   759  	}
   760  }
   761  
   762  // TestClusterIPLBInCreateDsrLoadBalancer tests, if the available endpoints are remote,
   763  // syncproxyrules only creates ClusterIP Loadbalancer and no NodePort, External IP or IngressIP
   764  // loadbalancers will be created.
   765  func TestClusterIPLBInCreateDsrLoadBalancer(t *testing.T) {
   766  	syncPeriod := 30 * time.Second
   767  	proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)
   768  
   769  	if proxier == nil {
   770  		t.Error()
   771  	}
   772  
   773  	svcIP := "10.20.30.41"
   774  	svcPort := 80
   775  	svcNodePort := 3001
   776  	svcPortName := proxy.ServicePortName{
   777  		NamespacedName: makeNSN("ns1", "svc1"),
   778  		Port:           "p80",
   779  		Protocol:       v1.ProtocolTCP,
   780  	}
   781  	lbIP := "11.21.31.41"
   782  
   783  	makeServiceMap(proxier,
   784  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
   785  			svc.Spec.Type = "NodePort"
   786  			svc.Spec.ClusterIP = svcIP
   787  			svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
   788  			svc.Spec.Ports = []v1.ServicePort{{
   789  				Name:     svcPortName.Port,
   790  				Port:     int32(svcPort),
   791  				Protocol: v1.ProtocolTCP,
   792  				NodePort: int32(svcNodePort),
   793  			}}
   794  			svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
   795  				IP: lbIP,
   796  			}}
   797  		}),
   798  	)
   799  	populateEndpointSlices(proxier,
   800  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
   801  			eps.AddressType = discovery.AddressTypeIPv4
   802  			eps.Endpoints = []discovery.Endpoint{{
   803  				Addresses: []string{epIpAddressRemote},
   804  				NodeName:  ptr.To("testhost2"), // This will make this endpoint as a remote endpoint
   805  			}}
   806  			eps.Ports = []discovery.EndpointPort{{
   807  				Name:     ptr.To(svcPortName.Port),
   808  				Port:     ptr.To(int32(svcPort)),
   809  				Protocol: ptr.To(v1.ProtocolTCP),
   810  			}}
   811  		}),
   812  	)
   813  
   814  	proxier.setInitialized(true)
   815  	proxier.syncProxyRules()
   816  
   817  	svc := proxier.svcPortMap[svcPortName]
   818  	svcInfo, ok := svc.(*serviceInfo)
   819  	if !ok {
   820  		t.Errorf("Failed to cast serviceInfo %q", svcPortName.String())
   821  
   822  	} else {
   823  		// Checking ClusterIP Loadbalancer is created
   824  		if svcInfo.hnsID != loadbalancerGuid1 {
   825  			t.Errorf("%v does not match %v", svcInfo.hnsID, loadbalancerGuid1)
   826  		}
   827  		// Verifying NodePort Loadbalancer is not created
   828  		if svcInfo.nodePorthnsID != "" {
   829  			t.Errorf("NodePortHnsID %v is not empty.", svcInfo.nodePorthnsID)
   830  		}
   831  		// Verifying ExternalIP Loadbalancer is not created
   832  		for _, externalIP := range svcInfo.externalIPs {
   833  			if externalIP.hnsID != "" {
   834  				t.Errorf("ExternalLBID %v is not empty.", externalIP.hnsID)
   835  			}
   836  		}
   837  		// Verifying IngressIP Loadbalancer is not created
   838  		for _, ingressIP := range svcInfo.loadBalancerIngressIPs {
   839  			if ingressIP.hnsID != "" {
   840  				t.Errorf("IngressLBID %v is not empty.", ingressIP.hnsID)
   841  			}
   842  		}
   843  	}
   844  }
   845  
   846  func TestEndpointSlice(t *testing.T) {
   847  	syncPeriod := 30 * time.Second
   848  	proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)
   849  	if proxier == nil {
   850  		t.Error()
   851  	}
   852  
   853  	proxier.servicesSynced = true
   854  	proxier.endpointSlicesSynced = true
   855  
   856  	svcPortName := proxy.ServicePortName{
   857  		NamespacedName: makeNSN("ns1", "svc1"),
   858  		Port:           "p80",
   859  		Protocol:       v1.ProtocolTCP,
   860  	}
   861  
   862  	proxier.OnServiceAdd(&v1.Service{
   863  		ObjectMeta: metav1.ObjectMeta{Name: svcPortName.Name, Namespace: svcPortName.Namespace},
   864  		Spec: v1.ServiceSpec{
   865  			ClusterIP: "172.20.1.1",
   866  			Selector:  map[string]string{"foo": "bar"},
   867  			Ports:     []v1.ServicePort{{Name: svcPortName.Port, TargetPort: intstr.FromInt32(80), Protocol: v1.ProtocolTCP}},
   868  		},
   869  	})
   870  
   871  	// Add initial endpoint slice
   872  	endpointSlice := &discovery.EndpointSlice{
   873  		ObjectMeta: metav1.ObjectMeta{
   874  			Name:      fmt.Sprintf("%s-1", svcPortName.Name),
   875  			Namespace: svcPortName.Namespace,
   876  			Labels:    map[string]string{discovery.LabelServiceName: svcPortName.Name},
   877  		},
   878  		Ports: []discovery.EndpointPort{{
   879  			Name:     &svcPortName.Port,
   880  			Port:     ptr.To[int32](80),
   881  			Protocol: ptr.To(v1.ProtocolTCP),
   882  		}},
   883  		AddressType: discovery.AddressTypeIPv4,
   884  		Endpoints: []discovery.Endpoint{{
   885  			Addresses:  []string{"192.168.2.3"},
   886  			Conditions: discovery.EndpointConditions{Ready: ptr.To(true)},
   887  			NodeName:   ptr.To("testhost2"),
   888  		}},
   889  	}
   890  
   891  	proxier.OnEndpointSliceAdd(endpointSlice)
   892  	proxier.setInitialized(true)
   893  	proxier.syncProxyRules()
   894  
   895  	svc := proxier.svcPortMap[svcPortName]
   896  	svcInfo, ok := svc.(*serviceInfo)
   897  	if !ok {
   898  		t.Errorf("Failed to cast serviceInfo %q", svcPortName.String())
   899  
   900  	} else {
   901  		if svcInfo.hnsID != loadbalancerGuid1 {
   902  			t.Errorf("The Hns Loadbalancer Id %v does not match %v. ServicePortName %q", svcInfo.hnsID, loadbalancerGuid1, svcPortName.String())
   903  		}
   904  	}
   905  
   906  	ep := proxier.endpointsMap[svcPortName][0]
   907  	epInfo, ok := ep.(*endpointInfo)
   908  	if !ok {
   909  		t.Errorf("Failed to cast endpointInfo %q", svcPortName.String())
   910  
   911  	} else {
   912  		if epInfo.hnsID != "EPID-3" {
   913  			t.Errorf("Hns EndpointId %v does not match %v. ServicePortName %q", epInfo.hnsID, endpointGuid1, svcPortName.String())
   914  		}
   915  	}
   916  }
   917  
   918  func TestNoopEndpointSlice(t *testing.T) {
   919  	p := Proxier{}
   920  	p.OnEndpointSliceAdd(&discovery.EndpointSlice{})
   921  	p.OnEndpointSliceUpdate(&discovery.EndpointSlice{}, &discovery.EndpointSlice{})
   922  	p.OnEndpointSliceDelete(&discovery.EndpointSlice{})
   923  	p.OnEndpointSlicesSynced()
   924  }
   925  
   926  func TestFindRemoteSubnetProviderAddress(t *testing.T) {
   927  	syncPeriod := 30 * time.Second
   928  	proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)
   929  	if proxier == nil {
   930  		t.Error()
   931  	}
   932  
   933  	networkInfo, _ := proxier.hns.getNetworkByName(testNetwork)
   934  	pa := networkInfo.findRemoteSubnetProviderAddress(providerAddress)
   935  
   936  	if pa != providerAddress {
   937  		t.Errorf("%v does not match %v", pa, providerAddress)
   938  	}
   939  
   940  	pa = networkInfo.findRemoteSubnetProviderAddress(epIpAddressRemote)
   941  
   942  	if pa != providerAddress {
   943  		t.Errorf("%v does not match %v", pa, providerAddress)
   944  	}
   945  
   946  	pa = networkInfo.findRemoteSubnetProviderAddress(serviceVip)
   947  
   948  	if len(pa) != 0 {
   949  		t.Errorf("Provider address is not empty as expected")
   950  	}
   951  }
   952  
   953  func makeNSN(namespace, name string) types.NamespacedName {
   954  	return types.NamespacedName{Namespace: namespace, Name: name}
   955  }
   956  
   957  func makeServiceMap(proxier *Proxier, allServices ...*v1.Service) {
   958  	for i := range allServices {
   959  		proxier.OnServiceAdd(allServices[i])
   960  	}
   961  
   962  	proxier.mu.Lock()
   963  	defer proxier.mu.Unlock()
   964  	proxier.servicesSynced = true
   965  }
   966  func deleteServices(proxier *Proxier, allServices ...*v1.Service) {
   967  	for i := range allServices {
   968  		proxier.OnServiceDelete(allServices[i])
   969  	}
   970  
   971  	proxier.mu.Lock()
   972  	defer proxier.mu.Unlock()
   973  	proxier.servicesSynced = true
   974  }
   975  
   976  func makeTestService(namespace, name string, svcFunc func(*v1.Service)) *v1.Service {
   977  	svc := &v1.Service{
   978  		ObjectMeta: metav1.ObjectMeta{
   979  			Name:        name,
   980  			Namespace:   namespace,
   981  			Annotations: map[string]string{},
   982  		},
   983  		Spec:   v1.ServiceSpec{},
   984  		Status: v1.ServiceStatus{},
   985  	}
   986  	svcFunc(svc)
   987  	return svc
   988  }
   989  
   990  func deleteEndpointSlices(proxier *Proxier, allEndpointSlices ...*discovery.EndpointSlice) {
   991  	for i := range allEndpointSlices {
   992  		proxier.OnEndpointSliceDelete(allEndpointSlices[i])
   993  	}
   994  
   995  	proxier.mu.Lock()
   996  	defer proxier.mu.Unlock()
   997  	proxier.endpointSlicesSynced = true
   998  }
   999  
  1000  func populateEndpointSlices(proxier *Proxier, allEndpointSlices ...*discovery.EndpointSlice) {
  1001  	for i := range allEndpointSlices {
  1002  		proxier.OnEndpointSliceAdd(allEndpointSlices[i])
  1003  	}
  1004  }
  1005  
  1006  func makeTestEndpointSlice(namespace, name string, sliceNum int, epsFunc func(*discovery.EndpointSlice)) *discovery.EndpointSlice {
  1007  	eps := &discovery.EndpointSlice{
  1008  		ObjectMeta: metav1.ObjectMeta{
  1009  			Name:      fmt.Sprintf("%s-%d", name, sliceNum),
  1010  			Namespace: namespace,
  1011  			Labels:    map[string]string{discovery.LabelServiceName: name},
  1012  		},
  1013  	}
  1014  	epsFunc(eps)
  1015  	return eps
  1016  }