k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/proxy/ipvs/proxier_test.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  /*
     5  Copyright 2017 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 ipvs
    21  
    22  import (
    23  	"bytes"
    24  	"context"
    25  	"fmt"
    26  	"net"
    27  	"reflect"
    28  	"sort"
    29  	"strings"
    30  	"testing"
    31  	"time"
    32  
    33  	"github.com/stretchr/testify/assert"
    34  	v1 "k8s.io/api/core/v1"
    35  	discovery "k8s.io/api/discovery/v1"
    36  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    37  	"k8s.io/apimachinery/pkg/types"
    38  	"k8s.io/apimachinery/pkg/util/intstr"
    39  	"k8s.io/apimachinery/pkg/util/sets"
    40  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    41  	featuregatetesting "k8s.io/component-base/featuregate/testing"
    42  	"k8s.io/component-base/metrics/testutil"
    43  	"k8s.io/kubernetes/pkg/features"
    44  	"k8s.io/kubernetes/pkg/proxy"
    45  	kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
    46  	"k8s.io/kubernetes/pkg/proxy/conntrack"
    47  	"k8s.io/kubernetes/pkg/proxy/healthcheck"
    48  	utilipset "k8s.io/kubernetes/pkg/proxy/ipvs/ipset"
    49  	ipsettest "k8s.io/kubernetes/pkg/proxy/ipvs/ipset/testing"
    50  	netlinktest "k8s.io/kubernetes/pkg/proxy/ipvs/testing"
    51  	utilipvs "k8s.io/kubernetes/pkg/proxy/ipvs/util"
    52  	ipvstest "k8s.io/kubernetes/pkg/proxy/ipvs/util/testing"
    53  	"k8s.io/kubernetes/pkg/proxy/metrics"
    54  	proxyutil "k8s.io/kubernetes/pkg/proxy/util"
    55  	proxyutiltest "k8s.io/kubernetes/pkg/proxy/util/testing"
    56  	"k8s.io/kubernetes/pkg/util/async"
    57  	utiliptables "k8s.io/kubernetes/pkg/util/iptables"
    58  	iptablestest "k8s.io/kubernetes/pkg/util/iptables/testing"
    59  	"k8s.io/kubernetes/test/utils/ktesting"
    60  	netutils "k8s.io/utils/net"
    61  	"k8s.io/utils/ptr"
    62  )
    63  
    64  const testHostname = "test-hostname"
    65  
    66  // fakeIpvs implements utilipvs.Interface
    67  type fakeIpvs struct {
    68  	ipvsErr   string
    69  	vsCreated bool
    70  }
    71  
    72  func (f *fakeIpvs) Flush() error {
    73  	return nil
    74  }
    75  func (f *fakeIpvs) AddVirtualServer(*utilipvs.VirtualServer) error {
    76  	if f.ipvsErr == "AddVirtualServer" {
    77  		return fmt.Errorf("oops")
    78  	}
    79  	f.vsCreated = true
    80  	return nil
    81  }
    82  func (f *fakeIpvs) UpdateVirtualServer(*utilipvs.VirtualServer) error {
    83  	return nil
    84  }
    85  func (f *fakeIpvs) DeleteVirtualServer(*utilipvs.VirtualServer) error {
    86  	if f.ipvsErr == "DeleteVirtualServer" {
    87  		return fmt.Errorf("oops")
    88  	}
    89  	return nil
    90  }
    91  func (f *fakeIpvs) GetVirtualServer(*utilipvs.VirtualServer) (*utilipvs.VirtualServer, error) {
    92  	return nil, nil
    93  }
    94  func (f *fakeIpvs) GetVirtualServers() ([]*utilipvs.VirtualServer, error) {
    95  	if f.ipvsErr == "GetVirtualServers" {
    96  		return nil, fmt.Errorf("oops")
    97  	}
    98  	if f.vsCreated {
    99  		vs := []*utilipvs.VirtualServer{{}}
   100  		return vs, nil
   101  	}
   102  	return nil, nil
   103  }
   104  func (f *fakeIpvs) AddRealServer(*utilipvs.VirtualServer, *utilipvs.RealServer) error {
   105  	return nil
   106  }
   107  func (f *fakeIpvs) GetRealServers(*utilipvs.VirtualServer) ([]*utilipvs.RealServer, error) {
   108  	return nil, nil
   109  }
   110  func (f *fakeIpvs) DeleteRealServer(*utilipvs.VirtualServer, *utilipvs.RealServer) error {
   111  	return nil
   112  }
   113  func (f *fakeIpvs) UpdateRealServer(*utilipvs.VirtualServer, *utilipvs.RealServer) error {
   114  	return nil
   115  }
   116  func (f *fakeIpvs) ConfigureTimeouts(time.Duration, time.Duration, time.Duration) error {
   117  	return nil
   118  }
   119  
   120  // fakeIPSetVersioner implements IPSetVersioner.
   121  type fakeIPSetVersioner struct {
   122  	version string
   123  	err     error
   124  }
   125  
   126  func (fake *fakeIPSetVersioner) GetVersion() (string, error) {
   127  	return fake.version, fake.err
   128  }
   129  
   130  func NewFakeProxier(ctx context.Context, ipt utiliptables.Interface, ipvs utilipvs.Interface, ipset utilipset.Interface, nodeIPs []string, excludeCIDRs []*net.IPNet, ipFamily v1.IPFamily) *Proxier {
   131  
   132  	netlinkHandle := netlinktest.NewFakeNetlinkHandle(ipFamily == v1.IPv6Protocol)
   133  	netlinkHandle.SetLocalAddresses("eth0", nodeIPs...)
   134  
   135  	// initialize ipsetList with all sets we needed
   136  	ipsetList := make(map[string]*IPSet)
   137  	for _, is := range ipsetInfo {
   138  		ipsetList[is.name] = NewIPSet(ipset, is.name, is.setType, false, is.comment)
   139  	}
   140  	p := &Proxier{
   141  		svcPortMap:            make(proxy.ServicePortMap),
   142  		serviceChanges:        proxy.NewServiceChangeTracker(newServiceInfo, ipFamily, nil, nil),
   143  		endpointsMap:          make(proxy.EndpointsMap),
   144  		endpointsChanges:      proxy.NewEndpointsChangeTracker(testHostname, nil, ipFamily, nil, nil),
   145  		excludeCIDRs:          excludeCIDRs,
   146  		iptables:              ipt,
   147  		ipvs:                  ipvs,
   148  		ipset:                 ipset,
   149  		conntrack:             conntrack.NewFake(),
   150  		strictARP:             false,
   151  		localDetector:         proxyutil.NewNoOpLocalDetector(),
   152  		hostname:              testHostname,
   153  		serviceHealthServer:   healthcheck.NewFakeServiceHealthServer(),
   154  		ipvsScheduler:         defaultScheduler,
   155  		iptablesData:          bytes.NewBuffer(nil),
   156  		filterChainsData:      bytes.NewBuffer(nil),
   157  		natChains:             proxyutil.NewLineBuffer(),
   158  		natRules:              proxyutil.NewLineBuffer(),
   159  		filterChains:          proxyutil.NewLineBuffer(),
   160  		filterRules:           proxyutil.NewLineBuffer(),
   161  		netlinkHandle:         netlinkHandle,
   162  		ipsetList:             ipsetList,
   163  		nodePortAddresses:     proxyutil.NewNodePortAddresses(ipFamily, nil),
   164  		networkInterfacer:     proxyutiltest.NewFakeNetwork(),
   165  		gracefuldeleteManager: NewGracefulTerminationManager(ipvs),
   166  		ipFamily:              ipFamily,
   167  	}
   168  	p.setInitialized(true)
   169  	p.syncRunner = async.NewBoundedFrequencyRunner("test-sync-runner", p.syncProxyRules, 0, time.Minute, 1)
   170  	return p
   171  }
   172  
   173  func makeNSN(namespace, name string) types.NamespacedName {
   174  	return types.NamespacedName{Namespace: namespace, Name: name}
   175  }
   176  
   177  func makeServiceMap(proxier *Proxier, allServices ...*v1.Service) {
   178  	for i := range allServices {
   179  		proxier.OnServiceAdd(allServices[i])
   180  	}
   181  
   182  	proxier.mu.Lock()
   183  	defer proxier.mu.Unlock()
   184  	proxier.servicesSynced = true
   185  }
   186  
   187  func makeEndpointSliceMap(proxier *Proxier, allEpSlices ...*discovery.EndpointSlice) {
   188  	for i := range allEpSlices {
   189  		proxier.OnEndpointSliceAdd(allEpSlices[i])
   190  	}
   191  	proxier.mu.Lock()
   192  	defer proxier.mu.Unlock()
   193  	proxier.endpointSlicesSynced = true
   194  }
   195  
   196  func makeTestService(namespace, name string, svcFunc func(*v1.Service)) *v1.Service {
   197  	svc := &v1.Service{
   198  		ObjectMeta: metav1.ObjectMeta{
   199  			Name:        name,
   200  			Namespace:   namespace,
   201  			Annotations: map[string]string{},
   202  		},
   203  		Spec:   v1.ServiceSpec{},
   204  		Status: v1.ServiceStatus{},
   205  	}
   206  	svcFunc(svc)
   207  	return svc
   208  }
   209  
   210  func populateEndpointSlices(proxier *Proxier, allEndpointSlices ...*discovery.EndpointSlice) {
   211  	for i := range allEndpointSlices {
   212  		proxier.OnEndpointSliceAdd(allEndpointSlices[i])
   213  	}
   214  }
   215  
   216  func makeTestEndpointSlice(namespace, name string, sliceNum int, epsFunc func(*discovery.EndpointSlice)) *discovery.EndpointSlice {
   217  	eps := &discovery.EndpointSlice{
   218  		ObjectMeta: metav1.ObjectMeta{
   219  			Name:      fmt.Sprintf("%s-%d", name, sliceNum),
   220  			Namespace: namespace,
   221  			Labels:    map[string]string{discovery.LabelServiceName: name},
   222  		},
   223  	}
   224  	epsFunc(eps)
   225  	return eps
   226  }
   227  
   228  func TestCleanupLeftovers(t *testing.T) {
   229  	_, ctx := ktesting.NewTestContext(t)
   230  	ipt := iptablestest.NewFake()
   231  	ipvs := ipvstest.NewFake()
   232  	ipset := ipsettest.NewFake(testIPSetVersion)
   233  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
   234  	svcIP := "10.20.30.41"
   235  	svcPort := 80
   236  	svcNodePort := 3001
   237  	svcPortName := proxy.ServicePortName{
   238  		NamespacedName: makeNSN("ns1", "svc1"),
   239  		Port:           "p80",
   240  	}
   241  
   242  	makeServiceMap(fp,
   243  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
   244  			svc.Spec.Type = "NodePort"
   245  			svc.Spec.ClusterIP = svcIP
   246  			svc.Spec.Ports = []v1.ServicePort{{
   247  				Name:     svcPortName.Port,
   248  				Port:     int32(svcPort),
   249  				Protocol: v1.ProtocolTCP,
   250  				NodePort: int32(svcNodePort),
   251  			}}
   252  		}),
   253  	)
   254  	epIP := "10.180.0.1"
   255  	populateEndpointSlices(fp,
   256  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
   257  			eps.AddressType = discovery.AddressTypeIPv4
   258  			eps.Endpoints = []discovery.Endpoint{{
   259  				Addresses: []string{epIP},
   260  			}}
   261  			eps.Ports = []discovery.EndpointPort{{
   262  				Name:     ptr.To(svcPortName.Port),
   263  				Port:     ptr.To(int32(svcPort)),
   264  				Protocol: ptr.To(v1.ProtocolTCP),
   265  			}}
   266  		}),
   267  	)
   268  
   269  	fp.syncProxyRules()
   270  
   271  	// test cleanup left over
   272  	if CleanupLeftovers(ctx, ipvs, ipt, ipset) {
   273  		t.Errorf("Cleanup leftovers failed")
   274  	}
   275  }
   276  
   277  func TestCanUseIPVSProxier(t *testing.T) {
   278  	_, ctx := ktesting.NewTestContext(t)
   279  	testCases := []struct {
   280  		name         string
   281  		scheduler    string
   282  		ipsetVersion string
   283  		ipsetErr     error
   284  		ipvsErr      string
   285  		ok           bool
   286  	}{
   287  		{
   288  			name:         "happy days",
   289  			ipsetVersion: MinIPSetCheckVersion,
   290  			ok:           true,
   291  		},
   292  		{
   293  			name:         "ipset error",
   294  			scheduler:    "",
   295  			ipsetVersion: MinIPSetCheckVersion,
   296  			ipsetErr:     fmt.Errorf("oops"),
   297  			ok:           false,
   298  		},
   299  		{
   300  			name:         "ipset version too low",
   301  			scheduler:    "rr",
   302  			ipsetVersion: "4.3.0",
   303  			ok:           false,
   304  		},
   305  		{
   306  			name:         "GetVirtualServers fail",
   307  			ipsetVersion: MinIPSetCheckVersion,
   308  			ipvsErr:      "GetVirtualServers",
   309  			ok:           false,
   310  		},
   311  		{
   312  			name:         "AddVirtualServer fail",
   313  			ipsetVersion: MinIPSetCheckVersion,
   314  			ipvsErr:      "AddVirtualServer",
   315  			ok:           false,
   316  		},
   317  		{
   318  			name:         "DeleteVirtualServer fail",
   319  			ipsetVersion: MinIPSetCheckVersion,
   320  			ipvsErr:      "DeleteVirtualServer",
   321  			ok:           false,
   322  		},
   323  	}
   324  
   325  	for _, tc := range testCases {
   326  		ipvs := &fakeIpvs{tc.ipvsErr, false}
   327  		versioner := &fakeIPSetVersioner{version: tc.ipsetVersion, err: tc.ipsetErr}
   328  		err := CanUseIPVSProxier(ctx, ipvs, versioner, tc.scheduler)
   329  		if (err == nil) != tc.ok {
   330  			t.Errorf("Case [%s], expect %v, got err: %v", tc.name, tc.ok, err)
   331  		}
   332  	}
   333  }
   334  
   335  func TestGetNodeIPs(t *testing.T) {
   336  	testCases := []struct {
   337  		isIPv6       bool
   338  		devAddresses map[string][]string
   339  		expectIPs    []string
   340  	}{
   341  		// case 0
   342  		{
   343  			devAddresses: map[string][]string{"eth0": {"1.2.3.4"}, "lo": {"127.0.0.1"}},
   344  			expectIPs:    []string{"1.2.3.4"},
   345  		},
   346  		// case 1
   347  		{
   348  			devAddresses: map[string][]string{"lo": {"127.0.0.1"}},
   349  			expectIPs:    []string{},
   350  		},
   351  		// case 2
   352  		{
   353  			devAddresses: map[string][]string{},
   354  			expectIPs:    []string{},
   355  		},
   356  		// case 3
   357  		{
   358  			devAddresses: map[string][]string{"encap0": {"10.20.30.40", "fe80::200:ff:fe01:1"}, "lo": {"127.0.0.1", "::1"}, "docker0": {"172.17.0.1"}},
   359  			expectIPs:    []string{"10.20.30.40", "172.17.0.1"},
   360  		},
   361  		// case 4
   362  		{
   363  			devAddresses: map[string][]string{"encaps9": {"10.20.30.40"}, "lo": {"127.0.0.1", "::1"}, "encap7": {"1000::", "10.20.30.31"}},
   364  			expectIPs:    []string{"10.20.30.40", "10.20.30.31"},
   365  		},
   366  		// case 5
   367  		{
   368  			devAddresses: map[string][]string{"kube-ipvs0": {"2000::", "1.2.3.4"}, "lo": {"127.0.0.1", "::1"}, "encap7": {"1000::", "10.20.30.31"}},
   369  			expectIPs:    []string{"10.20.30.31"},
   370  		},
   371  		// case 6
   372  		{
   373  			devAddresses: map[string][]string{"kube-ipvs0": {"1.2.3.4", "2.3.4.5"}, "lo": {"127.0.0.1", "::1"}},
   374  			expectIPs:    []string{},
   375  		},
   376  		// case 7
   377  		{
   378  			devAddresses: map[string][]string{"kube-ipvs0": {"1.2.3.4", "2.3.4.5"}},
   379  			expectIPs:    []string{},
   380  		},
   381  		// case 8
   382  		{
   383  			devAddresses: map[string][]string{"kube-ipvs0": {"1.2.3.4", "2.3.4.5"}, "eth5": {"3.4.5.6"}, "lo": {"127.0.0.1", "::1"}},
   384  			expectIPs:    []string{"3.4.5.6"},
   385  		},
   386  		// case 9
   387  		{
   388  			devAddresses: map[string][]string{"ipvs0": {"1.2.3.4"}, "lo": {"127.0.0.1", "::1"}, "encap7": {"10.20.30.31"}},
   389  			expectIPs:    []string{"10.20.30.31", "1.2.3.4"},
   390  		},
   391  		// case 10
   392  		{
   393  			isIPv6:       true,
   394  			devAddresses: map[string][]string{"ipvs0": {"1.2.3.4", "1000::"}, "lo": {"127.0.0.1", "::1"}, "encap7": {"10.20.30.31", "2000::", "fe80::200:ff:fe01:1"}},
   395  			expectIPs:    []string{"1000::", "2000::"},
   396  		},
   397  		// case 11
   398  		{
   399  			isIPv6:       true,
   400  			devAddresses: map[string][]string{"ipvs0": {"1.2.3.4", "1000::"}, "lo": {"127.0.0.1", "::1"}, "encap7": {"10.20.30.31", "2000::", "fe80::200:ff:fe01:1"}, "kube-ipvs0": {"1.2.3.4", "2.3.4.5", "2000::"}},
   401  			expectIPs:    []string{"1000::"},
   402  		},
   403  	}
   404  
   405  	for i, tc := range testCases {
   406  		fake := netlinktest.NewFakeNetlinkHandle(tc.isIPv6)
   407  		for dev, addresses := range testCases[i].devAddresses {
   408  			fake.SetLocalAddresses(dev, addresses...)
   409  		}
   410  		ips, err := fake.GetAllLocalAddresses()
   411  		if err != nil {
   412  			t.Errorf("Unexpected error: %v", err)
   413  		}
   414  		devIps, err := fake.GetLocalAddresses("kube-ipvs0")
   415  		if err != nil {
   416  			t.Errorf("Unexpected error: %v", err)
   417  		}
   418  		ips = ips.Difference(devIps)
   419  		if !ips.Equal(sets.New(tc.expectIPs...)) {
   420  			t.Errorf("case[%d], unexpected mismatch, expected: %v, got: %v", i, tc.expectIPs, ips)
   421  		}
   422  	}
   423  }
   424  
   425  func TestNodePortIPv4(t *testing.T) {
   426  	tests := []struct {
   427  		name                   string
   428  		services               []*v1.Service
   429  		endpoints              []*discovery.EndpointSlice
   430  		nodeIPs                []string
   431  		nodePortAddresses      []string
   432  		expectedIPVS           *ipvstest.FakeIPVS
   433  		expectedIPSets         netlinktest.ExpectedIPSet
   434  		expectedIptablesChains netlinktest.ExpectedIptablesChain
   435  	}{
   436  		{
   437  			name: "1 service with node port, has 2 endpoints",
   438  			services: []*v1.Service{
   439  				makeTestService("ns1", "svc1", func(svc *v1.Service) {
   440  					svc.Spec.Type = "NodePort"
   441  					svc.Spec.ClusterIP = "10.20.30.41"
   442  					svc.Spec.Ports = []v1.ServicePort{{
   443  						Name:     "p80",
   444  						Port:     int32(80),
   445  						Protocol: v1.ProtocolTCP,
   446  						NodePort: int32(3001),
   447  					}}
   448  				}),
   449  			},
   450  			endpoints: []*discovery.EndpointSlice{
   451  				makeTestEndpointSlice("ns1", "svc1", 1, func(eps *discovery.EndpointSlice) {
   452  					eps.AddressType = discovery.AddressTypeIPv4
   453  					eps.Endpoints = []discovery.Endpoint{{
   454  						Addresses: []string{"10.180.0.1"},
   455  					}}
   456  					eps.Ports = []discovery.EndpointPort{{
   457  						Name:     ptr.To("p80"),
   458  						Port:     ptr.To[int32](80),
   459  						Protocol: ptr.To(v1.ProtocolTCP),
   460  					}}
   461  				}),
   462  				makeTestEndpointSlice("ns1", "svc1", 2, func(eps *discovery.EndpointSlice) {
   463  					eps.AddressType = discovery.AddressTypeIPv6
   464  					eps.Endpoints = []discovery.Endpoint{{
   465  						Addresses: []string{"1002:ab8::2:10"},
   466  					}}
   467  					eps.Ports = []discovery.EndpointPort{{
   468  						Name:     ptr.To("p80"),
   469  						Port:     ptr.To[int32](80),
   470  						Protocol: ptr.To(v1.ProtocolTCP),
   471  					}}
   472  				}),
   473  			},
   474  			nodeIPs:           []string{"100.101.102.103", "2001:db8::1:1"},
   475  			nodePortAddresses: []string{},
   476  			expectedIPVS: &ipvstest.FakeIPVS{
   477  				Services: map[ipvstest.ServiceKey]*utilipvs.VirtualServer{
   478  					{
   479  						IP:       "10.20.30.41",
   480  						Port:     80,
   481  						Protocol: "TCP",
   482  					}: {
   483  						Address:   netutils.ParseIPSloppy("10.20.30.41"),
   484  						Protocol:  "TCP",
   485  						Port:      uint16(80),
   486  						Scheduler: "rr",
   487  					},
   488  					{
   489  						IP:       "100.101.102.103",
   490  						Port:     3001,
   491  						Protocol: "TCP",
   492  					}: {
   493  						Address:   netutils.ParseIPSloppy("100.101.102.103"),
   494  						Protocol:  "TCP",
   495  						Port:      uint16(3001),
   496  						Scheduler: "rr",
   497  					},
   498  				},
   499  				Destinations: map[ipvstest.ServiceKey][]*utilipvs.RealServer{
   500  					{
   501  						IP:       "10.20.30.41",
   502  						Port:     80,
   503  						Protocol: "TCP",
   504  					}: {
   505  						{
   506  							Address: netutils.ParseIPSloppy("10.180.0.1"),
   507  							Port:    uint16(80),
   508  							Weight:  1,
   509  						},
   510  					},
   511  					{
   512  						IP:       "100.101.102.103",
   513  						Port:     3001,
   514  						Protocol: "TCP",
   515  					}: {
   516  						{
   517  							Address: netutils.ParseIPSloppy("10.180.0.1"),
   518  							Port:    uint16(80),
   519  							Weight:  1,
   520  						},
   521  					},
   522  				},
   523  			},
   524  		},
   525  		{
   526  			name: "1 UDP service with node port, has endpoints",
   527  			services: []*v1.Service{
   528  				makeTestService("ns1", "svc1", func(svc *v1.Service) {
   529  					svc.Spec.Type = "NodePort"
   530  					svc.Spec.ClusterIP = "10.20.30.41"
   531  					svc.Spec.Ports = []v1.ServicePort{{
   532  						Name:     "p80",
   533  						Port:     int32(80),
   534  						Protocol: v1.ProtocolUDP,
   535  						NodePort: int32(3001),
   536  					}}
   537  				}),
   538  			},
   539  			endpoints: []*discovery.EndpointSlice{
   540  				makeTestEndpointSlice("ns1", "svc1", 1, func(eps *discovery.EndpointSlice) {
   541  					eps.AddressType = discovery.AddressTypeIPv4
   542  					eps.Endpoints = []discovery.Endpoint{{
   543  						Addresses: []string{"10.180.0.1"},
   544  					}}
   545  					eps.Ports = []discovery.EndpointPort{{
   546  						Name:     ptr.To("p80"),
   547  						Port:     ptr.To[int32](80),
   548  						Protocol: ptr.To(v1.ProtocolUDP),
   549  					}}
   550  				}),
   551  			},
   552  			nodeIPs:           []string{"100.101.102.103"},
   553  			nodePortAddresses: []string{"0.0.0.0/0"},
   554  			expectedIPVS: &ipvstest.FakeIPVS{
   555  				Services: map[ipvstest.ServiceKey]*utilipvs.VirtualServer{
   556  					{
   557  						IP:       "10.20.30.41",
   558  						Port:     80,
   559  						Protocol: "UDP",
   560  					}: {
   561  						Address:   netutils.ParseIPSloppy("10.20.30.41"),
   562  						Protocol:  "UDP",
   563  						Port:      uint16(80),
   564  						Scheduler: "rr",
   565  					},
   566  					{
   567  						IP:       "100.101.102.103",
   568  						Port:     3001,
   569  						Protocol: "UDP",
   570  					}: {
   571  						Address:   netutils.ParseIPSloppy("100.101.102.103"),
   572  						Protocol:  "UDP",
   573  						Port:      uint16(3001),
   574  						Scheduler: "rr",
   575  					},
   576  				},
   577  				Destinations: map[ipvstest.ServiceKey][]*utilipvs.RealServer{
   578  					{
   579  						IP:       "10.20.30.41",
   580  						Port:     80,
   581  						Protocol: "UDP",
   582  					}: {
   583  						{
   584  							Address: netutils.ParseIPSloppy("10.180.0.1"),
   585  							Port:    uint16(80),
   586  							Weight:  1,
   587  						},
   588  					},
   589  					{
   590  						IP:       "100.101.102.103",
   591  						Port:     3001,
   592  						Protocol: "UDP",
   593  					}: {
   594  						{
   595  							Address: netutils.ParseIPSloppy("10.180.0.1"),
   596  							Port:    uint16(80),
   597  							Weight:  1,
   598  						},
   599  					},
   600  				},
   601  			},
   602  			expectedIPSets: netlinktest.ExpectedIPSet{
   603  				kubeNodePortSetUDP: {{
   604  					Port:     3001,
   605  					Protocol: strings.ToLower(string(v1.ProtocolUDP)),
   606  					SetType:  utilipset.BitmapPort,
   607  				}},
   608  			},
   609  			expectedIptablesChains: netlinktest.ExpectedIptablesChain{
   610  				string(kubeNodePortChain): {{
   611  					JumpChain: string(kubeMarkMasqChain), MatchSet: kubeNodePortSetUDP,
   612  				}, {
   613  					JumpChain: "ACCEPT", MatchSet: kubeHealthCheckNodePortSet,
   614  				}},
   615  				string(kubeServicesChain): {{
   616  					JumpChain: "RETURN", SourceAddress: "127.0.0.0/8",
   617  				}, {
   618  					JumpChain: string(kubeMarkMasqChain), MatchSet: kubeClusterIPSet,
   619  				}, {
   620  					JumpChain: string(kubeNodePortChain), MatchSet: "",
   621  				}, {
   622  					JumpChain: "ACCEPT", MatchSet: kubeClusterIPSet,
   623  				}},
   624  			},
   625  		},
   626  		{
   627  			name: "service has node port but no endpoints",
   628  			services: []*v1.Service{
   629  				makeTestService("ns1", "svc1", func(svc *v1.Service) {
   630  					svc.Spec.Type = "NodePort"
   631  					svc.Spec.ClusterIP = "10.20.30.41"
   632  					svc.Spec.Ports = []v1.ServicePort{{
   633  						Name:     "p80",
   634  						Port:     int32(80),
   635  						Protocol: v1.ProtocolTCP,
   636  						NodePort: int32(3001),
   637  					}}
   638  				}),
   639  			},
   640  			endpoints:         []*discovery.EndpointSlice{},
   641  			nodeIPs:           []string{"100.101.102.103"},
   642  			nodePortAddresses: []string{},
   643  			expectedIPVS: &ipvstest.FakeIPVS{
   644  				Services: map[ipvstest.ServiceKey]*utilipvs.VirtualServer{
   645  					{
   646  						IP:       "10.20.30.41",
   647  						Port:     80,
   648  						Protocol: "TCP",
   649  					}: {
   650  						Address:   netutils.ParseIPSloppy("10.20.30.41"),
   651  						Protocol:  "TCP",
   652  						Port:      uint16(80),
   653  						Scheduler: "rr",
   654  					},
   655  					{
   656  						IP:       "100.101.102.103",
   657  						Port:     3001,
   658  						Protocol: "TCP",
   659  					}: {
   660  						Address:   netutils.ParseIPSloppy("100.101.102.103"),
   661  						Protocol:  "TCP",
   662  						Port:      uint16(3001),
   663  						Scheduler: "rr",
   664  					},
   665  				},
   666  				Destinations: map[ipvstest.ServiceKey][]*utilipvs.RealServer{
   667  					{
   668  						IP:       "10.20.30.41",
   669  						Port:     80,
   670  						Protocol: "TCP",
   671  					}: {}, // no real servers corresponding to no endpoints
   672  					{
   673  						IP:       "100.101.102.103",
   674  						Port:     3001,
   675  						Protocol: "TCP",
   676  					}: {}, // no real servers corresponding to no endpoints
   677  				},
   678  			},
   679  		},
   680  		{
   681  			name: "node port service with protocol sctp on a node with multiple nodeIPs",
   682  			services: []*v1.Service{
   683  				makeTestService("ns1", "svc1", func(svc *v1.Service) {
   684  					svc.Spec.Type = "NodePort"
   685  					svc.Spec.ClusterIP = "10.20.30.41"
   686  					svc.Spec.Ports = []v1.ServicePort{{
   687  						Name:     "p80",
   688  						Port:     int32(80),
   689  						Protocol: v1.ProtocolSCTP,
   690  						NodePort: int32(3001),
   691  					}}
   692  				}),
   693  			},
   694  			endpoints: []*discovery.EndpointSlice{
   695  				makeTestEndpointSlice("ns1", "svc1", 1, func(eps *discovery.EndpointSlice) {
   696  					eps.AddressType = discovery.AddressTypeIPv4
   697  					eps.Endpoints = []discovery.Endpoint{{
   698  						Addresses: []string{"10.180.0.1"},
   699  					}}
   700  					eps.Ports = []discovery.EndpointPort{{
   701  						Name:     ptr.To("p80"),
   702  						Port:     ptr.To[int32](80),
   703  						Protocol: ptr.To(v1.ProtocolSCTP),
   704  					}}
   705  				}),
   706  			},
   707  			nodeIPs: []string{
   708  				"100.101.102.103",
   709  				"100.101.102.104",
   710  				"100.101.102.105",
   711  				"2001:db8::1:1",
   712  				"2001:db8::1:2",
   713  				"2001:db8::1:3",
   714  			},
   715  			nodePortAddresses: []string{},
   716  			expectedIPVS: &ipvstest.FakeIPVS{
   717  				Services: map[ipvstest.ServiceKey]*utilipvs.VirtualServer{
   718  					{
   719  						IP:       "10.20.30.41",
   720  						Port:     80,
   721  						Protocol: "SCTP",
   722  					}: {
   723  						Address:   netutils.ParseIPSloppy("10.20.30.41"),
   724  						Protocol:  "SCTP",
   725  						Port:      uint16(80),
   726  						Scheduler: "rr",
   727  					},
   728  					{
   729  						IP:       "100.101.102.103",
   730  						Port:     3001,
   731  						Protocol: "SCTP",
   732  					}: {
   733  						Address:   netutils.ParseIPSloppy("100.101.102.103"),
   734  						Protocol:  "SCTP",
   735  						Port:      uint16(3001),
   736  						Scheduler: "rr",
   737  					},
   738  					{
   739  						IP:       "100.101.102.104",
   740  						Port:     3001,
   741  						Protocol: "SCTP",
   742  					}: {
   743  						Address:   netutils.ParseIPSloppy("100.101.102.104"),
   744  						Protocol:  "SCTP",
   745  						Port:      uint16(3001),
   746  						Scheduler: "rr",
   747  					},
   748  					{
   749  						IP:       "100.101.102.105",
   750  						Port:     3001,
   751  						Protocol: "SCTP",
   752  					}: {
   753  						Address:   netutils.ParseIPSloppy("100.101.102.105"),
   754  						Protocol:  "SCTP",
   755  						Port:      uint16(3001),
   756  						Scheduler: "rr",
   757  					},
   758  				},
   759  				Destinations: map[ipvstest.ServiceKey][]*utilipvs.RealServer{
   760  					{
   761  						IP:       "10.20.30.41",
   762  						Port:     80,
   763  						Protocol: "SCTP",
   764  					}: {
   765  						{
   766  							Address: netutils.ParseIPSloppy("10.180.0.1"),
   767  							Port:    uint16(80),
   768  							Weight:  1,
   769  						},
   770  					},
   771  					{
   772  						IP:       "100.101.102.103",
   773  						Port:     3001,
   774  						Protocol: "SCTP",
   775  					}: {
   776  						{
   777  							Address: netutils.ParseIPSloppy("10.180.0.1"),
   778  							Port:    uint16(80),
   779  							Weight:  1,
   780  						},
   781  					},
   782  					{
   783  						IP:       "100.101.102.104",
   784  						Port:     3001,
   785  						Protocol: "SCTP",
   786  					}: {
   787  						{
   788  							Address: netutils.ParseIPSloppy("10.180.0.1"),
   789  							Port:    uint16(80),
   790  							Weight:  1,
   791  						},
   792  					},
   793  					{
   794  						IP:       "100.101.102.105",
   795  						Port:     3001,
   796  						Protocol: "SCTP",
   797  					}: {
   798  						{
   799  							Address: netutils.ParseIPSloppy("10.180.0.1"),
   800  							Port:    uint16(80),
   801  							Weight:  1,
   802  						},
   803  					},
   804  				},
   805  			},
   806  			expectedIPSets: netlinktest.ExpectedIPSet{
   807  				kubeNodePortSetSCTP: {
   808  					{
   809  						IP:       "100.101.102.103",
   810  						Port:     3001,
   811  						Protocol: strings.ToLower(string(v1.ProtocolSCTP)),
   812  						SetType:  utilipset.HashIPPort,
   813  					},
   814  					{
   815  						IP:       "100.101.102.104",
   816  						Port:     3001,
   817  						Protocol: strings.ToLower(string(v1.ProtocolSCTP)),
   818  						SetType:  utilipset.HashIPPort,
   819  					},
   820  					{
   821  						IP:       "100.101.102.105",
   822  						Port:     3001,
   823  						Protocol: strings.ToLower(string(v1.ProtocolSCTP)),
   824  						SetType:  utilipset.HashIPPort,
   825  					},
   826  				},
   827  			},
   828  		},
   829  		{
   830  			name: "node port service with protocol sctp and externalTrafficPolicy local",
   831  			services: []*v1.Service{
   832  				makeTestService("ns1", "svc1", func(svc *v1.Service) {
   833  					svc.Spec.Type = "NodePort"
   834  					svc.Spec.ClusterIP = "10.20.30.41"
   835  					svc.Spec.Ports = []v1.ServicePort{{
   836  						Name:     "p80",
   837  						Port:     int32(80),
   838  						Protocol: v1.ProtocolSCTP,
   839  						NodePort: int32(3001),
   840  					}}
   841  					svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
   842  				}),
   843  			},
   844  			endpoints: []*discovery.EndpointSlice{
   845  				makeTestEndpointSlice("ns1", "svc1", 1, func(eps *discovery.EndpointSlice) {
   846  					eps.AddressType = discovery.AddressTypeIPv4
   847  					eps.Endpoints = []discovery.Endpoint{{
   848  						Addresses: []string{"10.180.0.1"},
   849  						NodeName:  ptr.To(testHostname),
   850  					}, {
   851  						Addresses: []string{"10.180.1.1"},
   852  						NodeName:  ptr.To("otherHost"),
   853  					}}
   854  					eps.Ports = []discovery.EndpointPort{{
   855  						Name:     ptr.To("p80"),
   856  						Port:     ptr.To[int32](80),
   857  						Protocol: ptr.To(v1.ProtocolSCTP),
   858  					}}
   859  				}),
   860  			},
   861  			nodeIPs:           []string{"100.101.102.103"},
   862  			nodePortAddresses: []string{},
   863  			expectedIPVS: &ipvstest.FakeIPVS{
   864  				Services: map[ipvstest.ServiceKey]*utilipvs.VirtualServer{
   865  					{
   866  						IP:       "10.20.30.41",
   867  						Port:     80,
   868  						Protocol: "SCTP",
   869  					}: {
   870  						Address:   netutils.ParseIPSloppy("10.20.30.41"),
   871  						Protocol:  "SCTP",
   872  						Port:      uint16(80),
   873  						Scheduler: "rr",
   874  					},
   875  					{
   876  						IP:       "100.101.102.103",
   877  						Port:     3001,
   878  						Protocol: "SCTP",
   879  					}: {
   880  						Address:   netutils.ParseIPSloppy("100.101.102.103"),
   881  						Protocol:  "SCTP",
   882  						Port:      uint16(3001),
   883  						Scheduler: "rr",
   884  					},
   885  				},
   886  				Destinations: map[ipvstest.ServiceKey][]*utilipvs.RealServer{
   887  					{
   888  						IP:       "10.20.30.41",
   889  						Port:     80,
   890  						Protocol: "SCTP",
   891  					}: {
   892  						{
   893  							Address: netutils.ParseIPSloppy("10.180.0.1"),
   894  							Port:    uint16(80),
   895  							Weight:  1,
   896  						},
   897  						{
   898  							Address: netutils.ParseIPSloppy("10.180.1.1"),
   899  							Port:    uint16(80),
   900  							Weight:  1,
   901  						},
   902  					},
   903  					{
   904  						IP:       "100.101.102.103",
   905  						Port:     3001,
   906  						Protocol: "SCTP",
   907  					}: {
   908  						{
   909  							Address: netutils.ParseIPSloppy("10.180.0.1"),
   910  							Port:    uint16(80),
   911  							Weight:  1,
   912  						},
   913  					},
   914  				},
   915  			},
   916  			expectedIPSets: netlinktest.ExpectedIPSet{
   917  				kubeNodePortSetSCTP: {
   918  					{
   919  						IP:       "100.101.102.103",
   920  						Port:     3001,
   921  						Protocol: strings.ToLower(string(v1.ProtocolSCTP)),
   922  						SetType:  utilipset.HashIPPort,
   923  					},
   924  				},
   925  				kubeNodePortLocalSetSCTP: {
   926  					{
   927  						IP:       "100.101.102.103",
   928  						Port:     3001,
   929  						Protocol: strings.ToLower(string(v1.ProtocolSCTP)),
   930  						SetType:  utilipset.HashIPPort,
   931  					},
   932  				},
   933  			},
   934  			expectedIptablesChains: netlinktest.ExpectedIptablesChain{
   935  				string(kubeNodePortChain): {{
   936  					JumpChain: "RETURN", MatchSet: kubeNodePortLocalSetSCTP,
   937  				}, {
   938  					JumpChain: string(kubeMarkMasqChain), MatchSet: kubeNodePortSetSCTP,
   939  				}, {
   940  					JumpChain: "ACCEPT", MatchSet: kubeHealthCheckNodePortSet,
   941  				}},
   942  			},
   943  		},
   944  	}
   945  
   946  	for _, test := range tests {
   947  		t.Run(test.name, func(t *testing.T) {
   948  			_, ctx := ktesting.NewTestContext(t)
   949  			ipt := iptablestest.NewFake()
   950  			ipvs := ipvstest.NewFake()
   951  			ipset := ipsettest.NewFake(testIPSetVersion)
   952  			fp := NewFakeProxier(ctx, ipt, ipvs, ipset, test.nodeIPs, nil, v1.IPv4Protocol)
   953  			fp.nodePortAddresses = proxyutil.NewNodePortAddresses(v1.IPv4Protocol, test.nodePortAddresses)
   954  
   955  			makeServiceMap(fp, test.services...)
   956  			populateEndpointSlices(fp, test.endpoints...)
   957  
   958  			fp.syncProxyRules()
   959  
   960  			if !reflect.DeepEqual(ipvs, test.expectedIPVS) {
   961  				t.Logf("actual ipvs state: %+v", ipvs)
   962  				t.Logf("expected ipvs state: %+v", test.expectedIPVS)
   963  				t.Errorf("unexpected IPVS state")
   964  			}
   965  
   966  			if test.expectedIPSets != nil {
   967  				checkIPSet(t, fp, test.expectedIPSets)
   968  			}
   969  
   970  			if test.expectedIptablesChains != nil {
   971  				checkIptables(t, ipt, test.expectedIptablesChains)
   972  			}
   973  		})
   974  	}
   975  }
   976  
   977  func TestNodePortIPv6(t *testing.T) {
   978  	tests := []struct {
   979  		name                   string
   980  		services               []*v1.Service
   981  		endpoints              []*discovery.EndpointSlice
   982  		nodeIPs                []string
   983  		nodePortAddresses      []string
   984  		expectedIPVS           *ipvstest.FakeIPVS
   985  		expectedIPSets         netlinktest.ExpectedIPSet
   986  		expectedIptablesChains netlinktest.ExpectedIptablesChain
   987  	}{
   988  		{
   989  			name: "1 service with node port, has 2 endpoints",
   990  			services: []*v1.Service{
   991  				makeTestService("ns1", "svc1", func(svc *v1.Service) {
   992  					svc.Spec.Type = "NodePort"
   993  					svc.Spec.ClusterIP = "2020::1"
   994  					svc.Spec.Ports = []v1.ServicePort{{
   995  						Name:     "p80",
   996  						Port:     int32(80),
   997  						Protocol: v1.ProtocolTCP,
   998  						NodePort: int32(3001),
   999  					}}
  1000  				}),
  1001  			},
  1002  			endpoints: []*discovery.EndpointSlice{
  1003  				makeTestEndpointSlice("ns1", "svc1", 1, func(eps *discovery.EndpointSlice) {
  1004  					eps.AddressType = discovery.AddressTypeIPv4
  1005  					eps.Endpoints = []discovery.Endpoint{{
  1006  						Addresses: []string{"10.180.0.1"},
  1007  					}}
  1008  					eps.Ports = []discovery.EndpointPort{{
  1009  						Name:     ptr.To("p80"),
  1010  						Port:     ptr.To[int32](80),
  1011  						Protocol: ptr.To(v1.ProtocolTCP),
  1012  					}}
  1013  				}),
  1014  				makeTestEndpointSlice("ns1", "svc1", 2, func(eps *discovery.EndpointSlice) {
  1015  					eps.AddressType = discovery.AddressTypeIPv6
  1016  					eps.Endpoints = []discovery.Endpoint{{
  1017  						Addresses: []string{"1002:ab8::2:10"},
  1018  					}}
  1019  					eps.Ports = []discovery.EndpointPort{{
  1020  						Name:     ptr.To("p80"),
  1021  						Port:     ptr.To[int32](80),
  1022  						Protocol: ptr.To(v1.ProtocolTCP),
  1023  					}}
  1024  				}),
  1025  			},
  1026  			nodeIPs:           []string{"100.101.102.103", "2001:db8::1:1"},
  1027  			nodePortAddresses: []string{},
  1028  			expectedIPVS: &ipvstest.FakeIPVS{
  1029  				Services: map[ipvstest.ServiceKey]*utilipvs.VirtualServer{
  1030  					{
  1031  						IP:       "2001:db8::1:1",
  1032  						Port:     3001,
  1033  						Protocol: "TCP",
  1034  					}: {
  1035  						Address:   netutils.ParseIPSloppy("2001:db8::1:1"),
  1036  						Protocol:  "TCP",
  1037  						Port:      uint16(3001),
  1038  						Scheduler: "rr",
  1039  					},
  1040  					{
  1041  						IP:       "2020::1",
  1042  						Port:     80,
  1043  						Protocol: "TCP",
  1044  					}: {
  1045  						Address:   netutils.ParseIPSloppy("2020::1"),
  1046  						Protocol:  "TCP",
  1047  						Port:      uint16(80),
  1048  						Scheduler: "rr",
  1049  					},
  1050  				},
  1051  				Destinations: map[ipvstest.ServiceKey][]*utilipvs.RealServer{
  1052  					{
  1053  						IP:       "2001:db8::1:1",
  1054  						Port:     3001,
  1055  						Protocol: "TCP",
  1056  					}: {
  1057  						{
  1058  							Address: netutils.ParseIPSloppy("1002:ab8::2:10"),
  1059  							Port:    uint16(80),
  1060  							Weight:  1,
  1061  						},
  1062  					},
  1063  
  1064  					{
  1065  						IP:       "2020::1",
  1066  						Port:     80,
  1067  						Protocol: "TCP",
  1068  					}: {
  1069  						{
  1070  							Address: netutils.ParseIPSloppy("1002:ab8::2:10"),
  1071  							Port:    uint16(80),
  1072  							Weight:  1,
  1073  						},
  1074  					},
  1075  				},
  1076  			},
  1077  		},
  1078  
  1079  		{
  1080  			name: "1 UDP service with node port, has endpoints (no action on IPv6 Proxier)",
  1081  			services: []*v1.Service{
  1082  				makeTestService("ns1", "svc1", func(svc *v1.Service) {
  1083  					svc.Spec.Type = "NodePort"
  1084  					svc.Spec.ClusterIP = "10.20.30.41"
  1085  					svc.Spec.Ports = []v1.ServicePort{{
  1086  						Name:     "p80",
  1087  						Port:     int32(80),
  1088  						Protocol: v1.ProtocolUDP,
  1089  						NodePort: int32(3001),
  1090  					}}
  1091  				}),
  1092  			},
  1093  			endpoints: []*discovery.EndpointSlice{
  1094  				makeTestEndpointSlice("ns1", "svc1", 1, func(eps *discovery.EndpointSlice) {
  1095  					eps.AddressType = discovery.AddressTypeIPv6
  1096  					eps.Endpoints = []discovery.Endpoint{{
  1097  						Addresses: []string{"10.180.0.1"},
  1098  					}}
  1099  					eps.Ports = []discovery.EndpointPort{{
  1100  						Name:     ptr.To("p80"),
  1101  						Port:     ptr.To[int32](80),
  1102  						Protocol: ptr.To(v1.ProtocolUDP),
  1103  					}}
  1104  				}),
  1105  			},
  1106  			nodeIPs:           []string{"100.101.102.103"},
  1107  			nodePortAddresses: []string{"0.0.0.0/0"},
  1108  			/*since this is a node with only IPv4, proxier should not do anything */
  1109  			expectedIPVS: &ipvstest.FakeIPVS{
  1110  				Services:     map[ipvstest.ServiceKey]*utilipvs.VirtualServer{},
  1111  				Destinations: map[ipvstest.ServiceKey][]*utilipvs.RealServer{},
  1112  			},
  1113  			expectedIPSets:         nil,
  1114  			expectedIptablesChains: nil,
  1115  		},
  1116  
  1117  		{
  1118  			name: "service has node port but no endpoints",
  1119  			services: []*v1.Service{
  1120  				makeTestService("ns1", "svc1", func(svc *v1.Service) {
  1121  					svc.Spec.Type = "NodePort"
  1122  					svc.Spec.ClusterIP = "2020::1"
  1123  					svc.Spec.Ports = []v1.ServicePort{{
  1124  						Name:     "p80",
  1125  						Port:     int32(80),
  1126  						Protocol: v1.ProtocolTCP,
  1127  						NodePort: int32(3001),
  1128  					}}
  1129  				}),
  1130  			},
  1131  			endpoints:         []*discovery.EndpointSlice{},
  1132  			nodeIPs:           []string{"100.101.102.103", "2001:db8::1:1"},
  1133  			nodePortAddresses: []string{},
  1134  			expectedIPVS: &ipvstest.FakeIPVS{
  1135  				Services: map[ipvstest.ServiceKey]*utilipvs.VirtualServer{
  1136  					{
  1137  						IP:       "2001:db8::1:1",
  1138  						Port:     3001,
  1139  						Protocol: "TCP",
  1140  					}: {
  1141  						Address:   netutils.ParseIPSloppy("2001:db8::1:1"),
  1142  						Protocol:  "TCP",
  1143  						Port:      uint16(3001),
  1144  						Scheduler: "rr",
  1145  					},
  1146  					{
  1147  						IP:       "2020::1",
  1148  						Port:     80,
  1149  						Protocol: "TCP",
  1150  					}: {
  1151  						Address:   netutils.ParseIPSloppy("2020::1"),
  1152  						Protocol:  "TCP",
  1153  						Port:      uint16(80),
  1154  						Scheduler: "rr",
  1155  					},
  1156  				},
  1157  				Destinations: map[ipvstest.ServiceKey][]*utilipvs.RealServer{
  1158  					{
  1159  						IP:       "2020::1",
  1160  						Port:     80,
  1161  						Protocol: "TCP",
  1162  					}: {}, // no real servers corresponding to no endpoints
  1163  					{
  1164  						IP:       "2001:db8::1:1",
  1165  						Port:     3001,
  1166  						Protocol: "TCP",
  1167  					}: {}, // no real servers corresponding to no endpoints
  1168  				},
  1169  			},
  1170  		},
  1171  
  1172  		{
  1173  			name: "node port service with protocol sctp on a node with multiple nodeIPs",
  1174  			services: []*v1.Service{
  1175  				makeTestService("ns1", "svc1", func(svc *v1.Service) {
  1176  					svc.Spec.Type = "NodePort"
  1177  					svc.Spec.ClusterIP = "2020::1"
  1178  					svc.Spec.Ports = []v1.ServicePort{{
  1179  						Name:     "p80",
  1180  						Port:     int32(80),
  1181  						Protocol: v1.ProtocolSCTP,
  1182  						NodePort: int32(3001),
  1183  					}}
  1184  				}),
  1185  			},
  1186  			endpoints: []*discovery.EndpointSlice{
  1187  				makeTestEndpointSlice("ns1", "svc1", 1, func(eps *discovery.EndpointSlice) {
  1188  					eps.AddressType = discovery.AddressTypeIPv6
  1189  					eps.Endpoints = []discovery.Endpoint{{
  1190  						Addresses: []string{"2001::1"},
  1191  					}}
  1192  					eps.Ports = []discovery.EndpointPort{{
  1193  						Name:     ptr.To("p80"),
  1194  						Port:     ptr.To[int32](80),
  1195  						Protocol: ptr.To(v1.ProtocolSCTP),
  1196  					}}
  1197  				}),
  1198  			},
  1199  			nodeIPs:           []string{"2001:db8::1:1", "2001:db8::1:2"},
  1200  			nodePortAddresses: []string{},
  1201  			expectedIPVS: &ipvstest.FakeIPVS{
  1202  				Services: map[ipvstest.ServiceKey]*utilipvs.VirtualServer{
  1203  					{
  1204  						IP:       "2001:db8::1:1",
  1205  						Port:     3001,
  1206  						Protocol: "SCTP",
  1207  					}: {
  1208  						Address:   netutils.ParseIPSloppy("2001:db8::1:1"),
  1209  						Protocol:  "SCTP",
  1210  						Port:      uint16(3001),
  1211  						Scheduler: "rr",
  1212  					},
  1213  					{
  1214  						IP:       "2001:db8::1:2",
  1215  						Port:     3001,
  1216  						Protocol: "SCTP",
  1217  					}: {
  1218  						Address:   netutils.ParseIPSloppy("2001:db8::1:2"),
  1219  						Protocol:  "SCTP",
  1220  						Port:      uint16(3001),
  1221  						Scheduler: "rr",
  1222  					},
  1223  					{
  1224  						IP:       "2020::1",
  1225  						Port:     80,
  1226  						Protocol: "SCTP",
  1227  					}: {
  1228  						Address:   netutils.ParseIPSloppy("2020::1"),
  1229  						Protocol:  "SCTP",
  1230  						Port:      uint16(80),
  1231  						Scheduler: "rr",
  1232  					},
  1233  				},
  1234  				Destinations: map[ipvstest.ServiceKey][]*utilipvs.RealServer{
  1235  					{
  1236  						IP:       "2001:db8::1:1",
  1237  						Port:     3001,
  1238  						Protocol: "SCTP",
  1239  					}: {
  1240  						{
  1241  							Address: netutils.ParseIPSloppy("2001::1"),
  1242  							Port:    uint16(80),
  1243  							Weight:  1,
  1244  						},
  1245  					},
  1246  					{
  1247  						IP:       "2001:db8::1:2",
  1248  						Port:     3001,
  1249  						Protocol: "SCTP",
  1250  					}: {
  1251  						{
  1252  							Address: netutils.ParseIPSloppy("2001::1"),
  1253  							Port:    uint16(80),
  1254  							Weight:  1,
  1255  						},
  1256  					},
  1257  					{
  1258  						IP:       "2020::1",
  1259  						Port:     80,
  1260  						Protocol: "SCTP",
  1261  					}: {
  1262  						{
  1263  							Address: netutils.ParseIPSloppy("2001::1"),
  1264  							Port:    uint16(80),
  1265  							Weight:  1,
  1266  						},
  1267  					},
  1268  				},
  1269  			},
  1270  			expectedIPSets: netlinktest.ExpectedIPSet{
  1271  				kubeNodePortSetSCTP: {
  1272  					{
  1273  						IP:       "2001:db8::1:1",
  1274  						Port:     3001,
  1275  						Protocol: strings.ToLower(string(v1.ProtocolSCTP)),
  1276  						SetType:  utilipset.HashIPPort,
  1277  					},
  1278  					{
  1279  						IP:       "2001:db8::1:2",
  1280  						Port:     3001,
  1281  						Protocol: strings.ToLower(string(v1.ProtocolSCTP)),
  1282  						SetType:  utilipset.HashIPPort,
  1283  					},
  1284  				},
  1285  			},
  1286  		},
  1287  	}
  1288  
  1289  	for _, test := range tests {
  1290  		t.Run(test.name, func(t *testing.T) {
  1291  			_, ctx := ktesting.NewTestContext(t)
  1292  			ipt := iptablestest.NewFake()
  1293  			ipvs := ipvstest.NewFake()
  1294  			ipset := ipsettest.NewFake(testIPSetVersion)
  1295  			fp := NewFakeProxier(ctx, ipt, ipvs, ipset, test.nodeIPs, nil, v1.IPv6Protocol)
  1296  			fp.nodePortAddresses = proxyutil.NewNodePortAddresses(v1.IPv6Protocol, test.nodePortAddresses)
  1297  
  1298  			makeServiceMap(fp, test.services...)
  1299  			populateEndpointSlices(fp, test.endpoints...)
  1300  
  1301  			fp.syncProxyRules()
  1302  
  1303  			if !reflect.DeepEqual(ipvs, test.expectedIPVS) {
  1304  				t.Logf("actual ipvs state: %+v", ipvs)
  1305  				t.Logf("expected ipvs state: %+v", test.expectedIPVS)
  1306  				t.Errorf("unexpected IPVS state")
  1307  			}
  1308  
  1309  			if test.expectedIPSets != nil {
  1310  				checkIPSet(t, fp, test.expectedIPSets)
  1311  			}
  1312  
  1313  			if test.expectedIptablesChains != nil {
  1314  				checkIptables(t, ipt, test.expectedIptablesChains)
  1315  			}
  1316  		})
  1317  	}
  1318  }
  1319  
  1320  func Test_syncEndpoint_updateWeightsOnRestart(t *testing.T) {
  1321  	_, ctx := ktesting.NewTestContext(t)
  1322  	ipt := iptablestest.NewFake()
  1323  	ipvs := ipvstest.NewFake()
  1324  	ipset := ipsettest.NewFake(testIPSetVersion)
  1325  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  1326  
  1327  	svc1 := makeTestService("ns1", "svc1", func(svc *v1.Service) {
  1328  		svc.Spec.ClusterIP = "10.20.30.41"
  1329  		svc.Spec.Ports = []v1.ServicePort{{
  1330  			Name:     "p80",
  1331  			Port:     int32(80),
  1332  			Protocol: v1.ProtocolTCP,
  1333  		}}
  1334  	})
  1335  	epSlice1 := makeTestEndpointSlice("ns1", "svc1", 1, func(eps *discovery.EndpointSlice) {
  1336  		eps.AddressType = discovery.AddressTypeIPv4
  1337  		eps.Endpoints = []discovery.Endpoint{{
  1338  			Addresses: []string{"10.180.0.1"},
  1339  		}}
  1340  		eps.Ports = []discovery.EndpointPort{{
  1341  			Name:     ptr.To("p80"),
  1342  			Port:     ptr.To[int32](80),
  1343  			Protocol: ptr.To(v1.ProtocolTCP),
  1344  		}}
  1345  	})
  1346  
  1347  	// sync proxy rules to get to the desired initial state
  1348  	makeServiceMap(fp, svc1)
  1349  	makeEndpointSliceMap(fp, epSlice1)
  1350  	fp.syncProxyRules()
  1351  
  1352  	serv := &utilipvs.VirtualServer{
  1353  		Address:   netutils.ParseIPSloppy("10.20.30.41"),
  1354  		Port:      uint16(80),
  1355  		Protocol:  string(v1.ProtocolTCP),
  1356  		Scheduler: fp.ipvsScheduler,
  1357  	}
  1358  
  1359  	vs, err := fp.ipvs.GetVirtualServer(serv)
  1360  	if err != nil {
  1361  		t.Errorf("failed to get virtual server, err: %v", err)
  1362  	}
  1363  
  1364  	rss, err := fp.ipvs.GetRealServers(vs)
  1365  	if err != nil {
  1366  		t.Errorf("failed to get real servers, err: %v", err)
  1367  	}
  1368  	for _, rs := range rss {
  1369  		rs.Weight = 0
  1370  		if err = fp.ipvs.UpdateRealServer(vs, rs); err != nil {
  1371  			t.Errorf("failed to update real server: %v, err: %v", rs, err)
  1372  		}
  1373  	}
  1374  
  1375  	// simulate a restart by enabling initial sync logic.
  1376  	fp.initialSync = true
  1377  	err = fp.syncEndpoint(proxy.ServicePortName{
  1378  		NamespacedName: types.NamespacedName{
  1379  			Name:      "svc1",
  1380  			Namespace: "ns1",
  1381  		},
  1382  		Port:     "80",
  1383  		Protocol: v1.ProtocolTCP,
  1384  	}, true, vs)
  1385  	if err != nil {
  1386  		t.Errorf("failed to sync endpoint, err: %v", err)
  1387  	}
  1388  
  1389  	rss, err = fp.ipvs.GetRealServers(vs)
  1390  	if err != nil {
  1391  		t.Errorf("failed to get real server, err: %v", err)
  1392  	}
  1393  	for _, rs := range rss {
  1394  		if rs.Weight != 1 {
  1395  			t.Logf("unexpected realserver weight: %d, expected weight: 1", rs.Weight)
  1396  			t.Errorf("unexpected realserver state")
  1397  		}
  1398  	}
  1399  }
  1400  
  1401  func TestIPv4Proxier(t *testing.T) {
  1402  	tests := []struct {
  1403  		name         string
  1404  		services     []*v1.Service
  1405  		endpoints    []*discovery.EndpointSlice
  1406  		expectedIPVS *ipvstest.FakeIPVS
  1407  	}{
  1408  		{
  1409  			name: "2 services with Cluster IP, each with endpoints",
  1410  			services: []*v1.Service{
  1411  				makeTestService("ns1", "svc1", func(svc *v1.Service) {
  1412  					svc.Spec.ClusterIP = "10.20.30.41"
  1413  					svc.Spec.Ports = []v1.ServicePort{{
  1414  						Name:     "p80",
  1415  						Port:     int32(80),
  1416  						Protocol: v1.ProtocolTCP,
  1417  					}}
  1418  				}),
  1419  				makeTestService("ns2", "svc2", func(svc *v1.Service) {
  1420  					svc.Spec.ClusterIP = "1002:ab8::2:1"
  1421  					svc.Spec.Ports = []v1.ServicePort{{
  1422  						Name:     "p8080",
  1423  						Port:     int32(8080),
  1424  						Protocol: v1.ProtocolTCP,
  1425  					}}
  1426  				}),
  1427  			},
  1428  			endpoints: []*discovery.EndpointSlice{
  1429  				makeTestEndpointSlice("ns1", "svc1", 1, func(eps *discovery.EndpointSlice) {
  1430  					eps.AddressType = discovery.AddressTypeIPv4
  1431  					eps.Endpoints = []discovery.Endpoint{{
  1432  						Addresses: []string{"10.180.0.1"},
  1433  					}}
  1434  					eps.Ports = []discovery.EndpointPort{{
  1435  						Name:     ptr.To("p80"),
  1436  						Port:     ptr.To[int32](80),
  1437  						Protocol: ptr.To(v1.ProtocolTCP),
  1438  					}}
  1439  				}),
  1440  				makeTestEndpointSlice("ns2", "svc2", 1, func(eps *discovery.EndpointSlice) {
  1441  					eps.AddressType = discovery.AddressTypeIPv6
  1442  					eps.Endpoints = []discovery.Endpoint{{
  1443  						Addresses: []string{"1009:ab8::5:6"},
  1444  					}}
  1445  					eps.Ports = []discovery.EndpointPort{{
  1446  						Name:     ptr.To("p8080"),
  1447  						Port:     ptr.To[int32](8080),
  1448  						Protocol: ptr.To(v1.ProtocolTCP),
  1449  					}}
  1450  				}),
  1451  			},
  1452  			expectedIPVS: &ipvstest.FakeIPVS{
  1453  				Services: map[ipvstest.ServiceKey]*utilipvs.VirtualServer{
  1454  					{
  1455  						IP:       "10.20.30.41",
  1456  						Port:     80,
  1457  						Protocol: "TCP",
  1458  					}: {
  1459  						Address:   netutils.ParseIPSloppy("10.20.30.41"),
  1460  						Protocol:  "TCP",
  1461  						Port:      uint16(80),
  1462  						Scheduler: "rr",
  1463  					},
  1464  				},
  1465  				Destinations: map[ipvstest.ServiceKey][]*utilipvs.RealServer{
  1466  					{
  1467  						IP:       "10.20.30.41",
  1468  						Port:     80,
  1469  						Protocol: "TCP",
  1470  					}: {
  1471  						{
  1472  							Address: netutils.ParseIPSloppy("10.180.0.1"),
  1473  							Port:    uint16(80),
  1474  							Weight:  1,
  1475  						},
  1476  					},
  1477  				},
  1478  			},
  1479  		},
  1480  		{
  1481  			name: "cluster IP service with no endpoints",
  1482  			services: []*v1.Service{
  1483  				makeTestService("ns1", "svc1", func(svc *v1.Service) {
  1484  					svc.Spec.ClusterIP = "10.20.30.41"
  1485  					svc.Spec.Ports = []v1.ServicePort{{
  1486  						Name:     "p80",
  1487  						Port:     int32(80),
  1488  						Protocol: v1.ProtocolTCP,
  1489  					}}
  1490  				}),
  1491  			},
  1492  			endpoints: []*discovery.EndpointSlice{},
  1493  			expectedIPVS: &ipvstest.FakeIPVS{
  1494  				Services: map[ipvstest.ServiceKey]*utilipvs.VirtualServer{
  1495  					{
  1496  						IP:       "10.20.30.41",
  1497  						Port:     80,
  1498  						Protocol: "TCP",
  1499  					}: {
  1500  						Address:   netutils.ParseIPSloppy("10.20.30.41"),
  1501  						Protocol:  "TCP",
  1502  						Port:      uint16(80),
  1503  						Scheduler: "rr",
  1504  					},
  1505  				},
  1506  				Destinations: map[ipvstest.ServiceKey][]*utilipvs.RealServer{
  1507  					{
  1508  						IP:       "10.20.30.41",
  1509  						Port:     80,
  1510  						Protocol: "TCP",
  1511  					}: {},
  1512  				},
  1513  			},
  1514  		},
  1515  	}
  1516  
  1517  	for _, test := range tests {
  1518  		t.Run(test.name, func(t *testing.T) {
  1519  			_, ctx := ktesting.NewTestContext(t)
  1520  			ipt := iptablestest.NewFake()
  1521  			ipvs := ipvstest.NewFake()
  1522  			ipset := ipsettest.NewFake(testIPSetVersion)
  1523  			fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  1524  
  1525  			makeServiceMap(fp, test.services...)
  1526  			populateEndpointSlices(fp, test.endpoints...)
  1527  
  1528  			fp.syncProxyRules()
  1529  
  1530  			if !reflect.DeepEqual(ipvs, test.expectedIPVS) {
  1531  				t.Logf("actual ipvs state: %v", ipvs)
  1532  				t.Logf("expected ipvs state: %v", test.expectedIPVS)
  1533  				t.Errorf("unexpected IPVS state")
  1534  			}
  1535  		})
  1536  	}
  1537  }
  1538  
  1539  func TestIPv6Proxier(t *testing.T) {
  1540  	tests := []struct {
  1541  		name         string
  1542  		services     []*v1.Service
  1543  		endpoints    []*discovery.EndpointSlice
  1544  		expectedIPVS *ipvstest.FakeIPVS
  1545  	}{
  1546  		{
  1547  			name: "2 services with Cluster IP, each with endpoints",
  1548  			services: []*v1.Service{
  1549  				makeTestService("ns1", "svc1", func(svc *v1.Service) {
  1550  					svc.Spec.ClusterIP = "10.20.30.41"
  1551  					svc.Spec.Ports = []v1.ServicePort{{
  1552  						Name:     "p80",
  1553  						Port:     int32(80),
  1554  						Protocol: v1.ProtocolTCP,
  1555  					}}
  1556  				}),
  1557  				makeTestService("ns2", "svc2", func(svc *v1.Service) {
  1558  					svc.Spec.ClusterIP = "1002:ab8::2:1"
  1559  					svc.Spec.Ports = []v1.ServicePort{{
  1560  						Name:     "p8080",
  1561  						Port:     int32(8080),
  1562  						Protocol: v1.ProtocolTCP,
  1563  					}}
  1564  				}),
  1565  			},
  1566  			endpoints: []*discovery.EndpointSlice{
  1567  				makeTestEndpointSlice("ns1", "svc1", 1, func(eps *discovery.EndpointSlice) {
  1568  					eps.AddressType = discovery.AddressTypeIPv4
  1569  					eps.Endpoints = []discovery.Endpoint{{
  1570  						Addresses: []string{"10.180.0.1"},
  1571  					}}
  1572  					eps.Ports = []discovery.EndpointPort{{
  1573  						Name:     ptr.To("p80"),
  1574  						Port:     ptr.To[int32](80),
  1575  						Protocol: ptr.To(v1.ProtocolTCP),
  1576  					}}
  1577  				}),
  1578  				makeTestEndpointSlice("ns2", "svc2", 1, func(eps *discovery.EndpointSlice) {
  1579  					eps.AddressType = discovery.AddressTypeIPv6
  1580  					eps.Endpoints = []discovery.Endpoint{{
  1581  						Addresses: []string{"1009:ab8::5:6"},
  1582  					}}
  1583  					eps.Ports = []discovery.EndpointPort{{
  1584  						Name:     ptr.To("p8080"),
  1585  						Port:     ptr.To[int32](8080),
  1586  						Protocol: ptr.To(v1.ProtocolTCP),
  1587  					}}
  1588  				}),
  1589  			},
  1590  			expectedIPVS: &ipvstest.FakeIPVS{
  1591  				Services: map[ipvstest.ServiceKey]*utilipvs.VirtualServer{
  1592  					{
  1593  						IP:       "1002:ab8::2:1",
  1594  						Port:     8080,
  1595  						Protocol: "TCP",
  1596  					}: {
  1597  						Address:   netutils.ParseIPSloppy("1002:ab8::2:1"),
  1598  						Protocol:  "TCP",
  1599  						Port:      uint16(8080),
  1600  						Scheduler: "rr",
  1601  					},
  1602  				},
  1603  				Destinations: map[ipvstest.ServiceKey][]*utilipvs.RealServer{
  1604  					{
  1605  						IP:       "1002:ab8::2:1",
  1606  						Port:     8080,
  1607  						Protocol: "TCP",
  1608  					}: {
  1609  						{
  1610  							Address: netutils.ParseIPSloppy("1009:ab8::5:6"),
  1611  							Port:    uint16(8080),
  1612  							Weight:  1,
  1613  						},
  1614  					},
  1615  				},
  1616  			},
  1617  		},
  1618  		{
  1619  			name: "cluster IP service with no endpoints",
  1620  			services: []*v1.Service{
  1621  				makeTestService("ns1", "svc1", func(svc *v1.Service) {
  1622  					svc.Spec.ClusterIP = "2001::1"
  1623  					svc.Spec.Ports = []v1.ServicePort{{
  1624  						Name:     "p80",
  1625  						Port:     int32(80),
  1626  						Protocol: v1.ProtocolTCP,
  1627  					}}
  1628  				}),
  1629  			},
  1630  			endpoints: []*discovery.EndpointSlice{},
  1631  			expectedIPVS: &ipvstest.FakeIPVS{
  1632  				Services: map[ipvstest.ServiceKey]*utilipvs.VirtualServer{
  1633  					{
  1634  						IP:       "2001::1",
  1635  						Port:     80,
  1636  						Protocol: "TCP",
  1637  					}: {
  1638  						Address:   netutils.ParseIPSloppy("2001::1"),
  1639  						Protocol:  "TCP",
  1640  						Port:      uint16(80),
  1641  						Scheduler: "rr",
  1642  					},
  1643  				},
  1644  				Destinations: map[ipvstest.ServiceKey][]*utilipvs.RealServer{
  1645  					{
  1646  						IP:       "2001::1",
  1647  						Port:     80,
  1648  						Protocol: "TCP",
  1649  					}: {},
  1650  				},
  1651  			},
  1652  		},
  1653  	}
  1654  
  1655  	for _, test := range tests {
  1656  		t.Run(test.name, func(t *testing.T) {
  1657  			_, ctx := ktesting.NewTestContext(t)
  1658  			ipt := iptablestest.NewFake()
  1659  			ipvs := ipvstest.NewFake()
  1660  			ipset := ipsettest.NewFake(testIPSetVersion)
  1661  			fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv6Protocol)
  1662  
  1663  			makeServiceMap(fp, test.services...)
  1664  			populateEndpointSlices(fp, test.endpoints...)
  1665  
  1666  			fp.syncProxyRules()
  1667  
  1668  			if !reflect.DeepEqual(ipvs, test.expectedIPVS) {
  1669  				t.Logf("actual ipvs state: %v", ipvs)
  1670  				t.Logf("expected ipvs state: %v", test.expectedIPVS)
  1671  				t.Errorf("unexpected IPVS state")
  1672  			}
  1673  		})
  1674  	}
  1675  }
  1676  
  1677  func TestMasqueradeRule(t *testing.T) {
  1678  	for _, testcase := range []bool{false, true} {
  1679  		_, ctx := ktesting.NewTestContext(t)
  1680  		ipt := iptablestest.NewFake().SetHasRandomFully(testcase)
  1681  		ipvs := ipvstest.NewFake()
  1682  		ipset := ipsettest.NewFake(testIPSetVersion)
  1683  		fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  1684  		makeServiceMap(fp)
  1685  		fp.syncProxyRules()
  1686  
  1687  		buf := bytes.NewBuffer(nil)
  1688  		_ = ipt.SaveInto(utiliptables.TableNAT, buf)
  1689  		natRules := strings.Split(buf.String(), "\n")
  1690  		var hasMasqueradeJump, hasMasqRandomFully bool
  1691  		for _, line := range natRules {
  1692  			rule, _ := iptablestest.ParseRule(line, false)
  1693  			if rule != nil && rule.Chain == kubePostroutingChain && rule.Jump != nil && rule.Jump.Value == "MASQUERADE" {
  1694  				hasMasqueradeJump = true
  1695  				if rule.RandomFully != nil {
  1696  					hasMasqRandomFully = true
  1697  				}
  1698  				break
  1699  			}
  1700  		}
  1701  
  1702  		if !hasMasqueradeJump {
  1703  			t.Errorf("Failed to find -j MASQUERADE in %s chain", kubePostroutingChain)
  1704  		}
  1705  		if hasMasqRandomFully != testcase {
  1706  			probs := map[bool]string{false: "found", true: "did not find"}
  1707  			t.Errorf("%s --random-fully in -j MASQUERADE rule in %s chain for HasRandomFully()=%v", probs[testcase], kubePostroutingChain, testcase)
  1708  		}
  1709  	}
  1710  }
  1711  
  1712  func TestExternalIPsNoEndpoint(t *testing.T) {
  1713  	_, ctx := ktesting.NewTestContext(t)
  1714  	ipt := iptablestest.NewFake()
  1715  	ipvs := ipvstest.NewFake()
  1716  	ipset := ipsettest.NewFake(testIPSetVersion)
  1717  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  1718  	svcIP := "10.20.30.41"
  1719  	svcPort := 80
  1720  	svcExternalIPs := "50.60.70.81"
  1721  	svcPortName := proxy.ServicePortName{
  1722  		NamespacedName: makeNSN("ns1", "svc1"),
  1723  		Port:           "p80",
  1724  	}
  1725  
  1726  	makeServiceMap(fp,
  1727  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
  1728  			svc.Spec.Type = "ClusterIP"
  1729  			svc.Spec.ClusterIP = svcIP
  1730  			svc.Spec.ExternalIPs = []string{svcExternalIPs}
  1731  			svc.Spec.Ports = []v1.ServicePort{{
  1732  				Name:       svcPortName.Port,
  1733  				Port:       int32(svcPort),
  1734  				Protocol:   v1.ProtocolTCP,
  1735  				TargetPort: intstr.FromInt32(int32(svcPort)),
  1736  			}}
  1737  		}),
  1738  	)
  1739  	fp.syncProxyRules()
  1740  
  1741  	// check ipvs service and destinations
  1742  	services, err := ipvs.GetVirtualServers()
  1743  	if err != nil {
  1744  		t.Errorf("Failed to get ipvs services, err: %v", err)
  1745  	}
  1746  	if len(services) != 2 {
  1747  		t.Errorf("Expect 2 ipvs services, got %d", len(services))
  1748  	}
  1749  	found := false
  1750  	for _, svc := range services {
  1751  		if svc.Address.String() == svcExternalIPs && svc.Port == uint16(svcPort) && svc.Protocol == string(v1.ProtocolTCP) {
  1752  			found = true
  1753  			destinations, _ := ipvs.GetRealServers(svc)
  1754  			if len(destinations) != 0 {
  1755  				t.Errorf("Unexpected %d destinations, expect 0 destinations", len(destinations))
  1756  			}
  1757  			break
  1758  		}
  1759  	}
  1760  	if !found {
  1761  		t.Errorf("Expect external ip type service, got none")
  1762  	}
  1763  }
  1764  
  1765  func TestExternalIPs(t *testing.T) {
  1766  	_, ctx := ktesting.NewTestContext(t)
  1767  	ipt := iptablestest.NewFake()
  1768  	ipvs := ipvstest.NewFake()
  1769  	ipset := ipsettest.NewFake(testIPSetVersion)
  1770  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  1771  	svcIP := "10.20.30.41"
  1772  	svcPort := 80
  1773  	svcExternalIPs := sets.New[string]("50.60.70.81", "2012::51", "127.0.0.1")
  1774  	svcPortName := proxy.ServicePortName{
  1775  		NamespacedName: makeNSN("ns1", "svc1"),
  1776  		Port:           "p80",
  1777  	}
  1778  
  1779  	makeServiceMap(fp,
  1780  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
  1781  			svc.Spec.Type = "ClusterIP"
  1782  			svc.Spec.ClusterIP = svcIP
  1783  			svc.Spec.ExternalIPs = svcExternalIPs.UnsortedList()
  1784  			svc.Spec.Ports = []v1.ServicePort{{
  1785  				Name:       svcPortName.Port,
  1786  				Port:       int32(svcPort),
  1787  				Protocol:   v1.ProtocolTCP,
  1788  				TargetPort: intstr.FromInt32(int32(svcPort)),
  1789  			}}
  1790  		}),
  1791  	)
  1792  
  1793  	epIP := "10.180.0.1"
  1794  	populateEndpointSlices(fp,
  1795  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
  1796  			eps.AddressType = discovery.AddressTypeIPv4
  1797  			eps.Endpoints = []discovery.Endpoint{{
  1798  				Addresses: []string{epIP},
  1799  			}}
  1800  			eps.Ports = []discovery.EndpointPort{{
  1801  				Name:     ptr.To(svcPortName.Port),
  1802  				Port:     ptr.To(int32(svcPort)),
  1803  				Protocol: ptr.To(v1.ProtocolUDP),
  1804  			}}
  1805  		}),
  1806  	)
  1807  
  1808  	fp.syncProxyRules()
  1809  
  1810  	// check ipvs service and destinations
  1811  	services, err := ipvs.GetVirtualServers()
  1812  	if err != nil {
  1813  		t.Errorf("Failed to get ipvs services, err: %v", err)
  1814  	}
  1815  	if len(services) != 3 { // ipvs filters out by ipfamily
  1816  		t.Errorf("Expect 3 ipvs services, got %d", len(services))
  1817  	}
  1818  	found := false
  1819  	for _, svc := range services {
  1820  		if svcExternalIPs.Has(svc.Address.String()) && svc.Port == uint16(svcPort) && svc.Protocol == string(v1.ProtocolTCP) {
  1821  			found = true
  1822  			destinations, _ := ipvs.GetRealServers(svc)
  1823  			for _, dest := range destinations {
  1824  				if dest.Address.String() != epIP || dest.Port != uint16(svcPort) {
  1825  					t.Errorf("service Endpoint mismatch ipvs service destination")
  1826  				}
  1827  			}
  1828  			break
  1829  		}
  1830  	}
  1831  	if !found {
  1832  		t.Errorf("Expect external ip type service, got none")
  1833  	}
  1834  }
  1835  
  1836  func TestOnlyLocalExternalIPs(t *testing.T) {
  1837  	_, ctx := ktesting.NewTestContext(t)
  1838  	ipt := iptablestest.NewFake()
  1839  	ipvs := ipvstest.NewFake()
  1840  	ipset := ipsettest.NewFake(testIPSetVersion)
  1841  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  1842  	svcIP := "10.20.30.41"
  1843  	svcPort := 80
  1844  	svcExternalIPs := sets.New[string]("50.60.70.81", "2012::51", "127.0.0.1")
  1845  	svcPortName := proxy.ServicePortName{
  1846  		NamespacedName: makeNSN("ns1", "svc1"),
  1847  		Port:           "p80",
  1848  	}
  1849  
  1850  	makeServiceMap(fp,
  1851  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
  1852  			svc.Spec.Type = "NodePort"
  1853  			svc.Spec.ClusterIP = svcIP
  1854  			svc.Spec.ExternalIPs = svcExternalIPs.UnsortedList()
  1855  			svc.Spec.Ports = []v1.ServicePort{{
  1856  				Name:       svcPortName.Port,
  1857  				Port:       int32(svcPort),
  1858  				Protocol:   v1.ProtocolTCP,
  1859  				TargetPort: intstr.FromInt32(int32(svcPort)),
  1860  			}}
  1861  			svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
  1862  		}),
  1863  	)
  1864  	epIP := "10.180.0.1"
  1865  	epIP1 := "10.180.1.1"
  1866  	thisHostname := testHostname
  1867  	otherHostname := "other-hostname"
  1868  	populateEndpointSlices(fp,
  1869  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
  1870  			eps.AddressType = discovery.AddressTypeIPv4
  1871  			eps.Endpoints = []discovery.Endpoint{{
  1872  				Addresses: []string{epIP},
  1873  				NodeName:  ptr.To(thisHostname),
  1874  			},
  1875  				{
  1876  					Addresses: []string{epIP1},
  1877  					NodeName:  ptr.To(otherHostname),
  1878  				}}
  1879  			eps.Ports = []discovery.EndpointPort{{
  1880  				Name:     ptr.To(svcPortName.Port),
  1881  				Port:     ptr.To(int32(svcPort)),
  1882  				Protocol: ptr.To(v1.ProtocolTCP),
  1883  			}}
  1884  		}),
  1885  	)
  1886  
  1887  	fp.syncProxyRules()
  1888  
  1889  	// check ipvs service and destinations
  1890  	services, err := ipvs.GetVirtualServers()
  1891  	if err != nil {
  1892  		t.Errorf("Failed to get ipvs services, err: %v", err)
  1893  	}
  1894  	if len(services) != 3 { // ipvs filters out by IPFamily
  1895  		t.Errorf("Expect 3 ipvs services, got %d", len(services))
  1896  	}
  1897  	found := false
  1898  	for _, svc := range services {
  1899  		if svcExternalIPs.Has(svc.Address.String()) && svc.Port == uint16(svcPort) && svc.Protocol == string(v1.ProtocolTCP) {
  1900  			found = true
  1901  			destinations, _ := ipvs.GetRealServers(svc)
  1902  			if len(destinations) != 1 {
  1903  				t.Errorf("Expect only 1 local endpoint. but got %v", len(destinations))
  1904  			}
  1905  			for _, dest := range destinations {
  1906  				if dest.Address.String() != epIP || dest.Port != uint16(svcPort) {
  1907  					t.Errorf("service Endpoint mismatch ipvs service destination")
  1908  				}
  1909  			}
  1910  			break
  1911  		}
  1912  	}
  1913  	if !found {
  1914  		t.Errorf("Expect external ip type service, got none")
  1915  	}
  1916  }
  1917  
  1918  func TestLoadBalancer(t *testing.T) {
  1919  	ipt, fp := buildFakeProxier(t)
  1920  	svcIP := "10.20.30.41"
  1921  	svcPort := 80
  1922  	svcNodePort := 3001
  1923  	svcLBIP := "1.2.3.4"
  1924  	svcPortName := proxy.ServicePortName{
  1925  		NamespacedName: makeNSN("ns1", "svc1"),
  1926  		Port:           "p80",
  1927  	}
  1928  
  1929  	makeServiceMap(fp,
  1930  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
  1931  			svc.Spec.Type = "LoadBalancer"
  1932  			svc.Spec.ClusterIP = svcIP
  1933  			svc.Spec.Ports = []v1.ServicePort{{
  1934  				Name:     svcPortName.Port,
  1935  				Port:     int32(svcPort),
  1936  				Protocol: v1.ProtocolTCP,
  1937  				NodePort: int32(svcNodePort),
  1938  			}}
  1939  			svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
  1940  				IP: svcLBIP,
  1941  			}}
  1942  		}),
  1943  	)
  1944  
  1945  	epIP := "10.180.0.1"
  1946  	populateEndpointSlices(fp,
  1947  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
  1948  			eps.AddressType = discovery.AddressTypeIPv4
  1949  			eps.Endpoints = []discovery.Endpoint{{
  1950  				Addresses: []string{epIP},
  1951  			}}
  1952  			eps.Ports = []discovery.EndpointPort{{
  1953  				Name:     ptr.To(svcPortName.Port),
  1954  				Port:     ptr.To(int32(svcPort)),
  1955  				Protocol: ptr.To(v1.ProtocolUDP),
  1956  			}}
  1957  		}),
  1958  	)
  1959  
  1960  	fp.syncProxyRules()
  1961  
  1962  	// Expect 2 services and 1 destination
  1963  	epVS := &netlinktest.ExpectedVirtualServer{
  1964  		VSNum: 2, IP: svcLBIP, Port: uint16(svcNodePort), Protocol: string(v1.ProtocolTCP),
  1965  		RS: []netlinktest.ExpectedRealServer{{
  1966  			IP: epIP, Port: uint16(svcPort),
  1967  		}}}
  1968  	checkIPVS(t, fp, epVS)
  1969  
  1970  	// check ipSet rules
  1971  	epIPSet := netlinktest.ExpectedIPSet{
  1972  		kubeLoadBalancerSet: {{
  1973  			IP:       svcLBIP,
  1974  			Port:     svcPort,
  1975  			Protocol: strings.ToLower(string(v1.ProtocolTCP)),
  1976  			SetType:  utilipset.HashIPPort,
  1977  		}},
  1978  	}
  1979  	checkIPSet(t, fp, epIPSet)
  1980  
  1981  	// Check iptables chain and rules
  1982  	epIpt := netlinktest.ExpectedIptablesChain{
  1983  		string(kubeServicesChain): {{
  1984  			JumpChain: "RETURN", SourceAddress: "127.0.0.0/8",
  1985  		}, {
  1986  			JumpChain: string(kubeLoadBalancerChain), MatchSet: kubeLoadBalancerSet,
  1987  		}, {
  1988  			JumpChain: string(kubeMarkMasqChain), MatchSet: kubeClusterIPSet,
  1989  		}, {
  1990  			JumpChain: string(kubeNodePortChain), MatchSet: "",
  1991  		}, {
  1992  			JumpChain: "ACCEPT", MatchSet: kubeClusterIPSet,
  1993  		}, {
  1994  			JumpChain: "ACCEPT", MatchSet: kubeLoadBalancerSet,
  1995  		}},
  1996  		string(kubeLoadBalancerSet): {{
  1997  			JumpChain: string(kubeMarkMasqChain), MatchSet: "",
  1998  		}},
  1999  	}
  2000  	checkIptables(t, ipt, epIpt)
  2001  }
  2002  
  2003  func TestOnlyLocalNodePorts(t *testing.T) {
  2004  	nodeIP := netutils.ParseIPSloppy("100.101.102.103")
  2005  	ipt, fp := buildFakeProxier(t)
  2006  
  2007  	svcIP := "10.20.30.41"
  2008  	svcPort := 80
  2009  	svcNodePort := 3001
  2010  	svcPortName := proxy.ServicePortName{
  2011  		NamespacedName: makeNSN("ns1", "svc1"),
  2012  		Port:           "p80",
  2013  	}
  2014  
  2015  	makeServiceMap(fp,
  2016  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
  2017  			svc.Spec.Type = "NodePort"
  2018  			svc.Spec.ClusterIP = svcIP
  2019  			svc.Spec.Ports = []v1.ServicePort{{
  2020  				Name:     svcPortName.Port,
  2021  				Port:     int32(svcPort),
  2022  				Protocol: v1.ProtocolTCP,
  2023  				NodePort: int32(svcNodePort),
  2024  			}}
  2025  			svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
  2026  		}),
  2027  	)
  2028  
  2029  	epIP := "10.180.0.1"
  2030  	epIP1 := "10.180.1.1"
  2031  
  2032  	populateEndpointSlices(fp,
  2033  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
  2034  			eps.AddressType = discovery.AddressTypeIPv4
  2035  			eps.Endpoints = []discovery.Endpoint{{
  2036  				Addresses: []string{epIP},
  2037  				NodeName:  ptr.To(testHostname),
  2038  			}, {
  2039  				Addresses: []string{epIP1},
  2040  				NodeName:  ptr.To("other-hostname"),
  2041  			}}
  2042  			eps.Ports = []discovery.EndpointPort{{
  2043  				Name:     ptr.To(svcPortName.Port),
  2044  				Port:     ptr.To(int32(svcPort)),
  2045  				Protocol: ptr.To(v1.ProtocolTCP),
  2046  			}}
  2047  		}),
  2048  	)
  2049  
  2050  	itf := net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0}
  2051  	addrs := []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("100.101.102.103"), Mask: net.CIDRMask(24, 32)}}
  2052  	itf1 := net.Interface{Index: 1, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0}
  2053  	addrs1 := []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("2001:db8::"), Mask: net.CIDRMask(64, 128)}}
  2054  	fp.networkInterfacer.(*proxyutiltest.FakeNetwork).AddInterfaceAddr(&itf, addrs)
  2055  	fp.networkInterfacer.(*proxyutiltest.FakeNetwork).AddInterfaceAddr(&itf1, addrs1)
  2056  	fp.nodePortAddresses = proxyutil.NewNodePortAddresses(v1.IPv4Protocol, []string{"100.101.102.0/24"})
  2057  
  2058  	fp.syncProxyRules()
  2059  
  2060  	// Expect 2 services and 1 destination
  2061  	epVS := &netlinktest.ExpectedVirtualServer{
  2062  		VSNum: 2, IP: nodeIP.String(), Port: uint16(svcNodePort), Protocol: string(v1.ProtocolTCP),
  2063  		RS: []netlinktest.ExpectedRealServer{{
  2064  			IP: epIP, Port: uint16(svcPort),
  2065  		}}}
  2066  	checkIPVS(t, fp, epVS)
  2067  
  2068  	// check ipSet rules
  2069  	epEntry := &utilipset.Entry{
  2070  		Port:     svcNodePort,
  2071  		Protocol: strings.ToLower(string(v1.ProtocolTCP)),
  2072  		SetType:  utilipset.BitmapPort,
  2073  	}
  2074  	epIPSet := netlinktest.ExpectedIPSet{
  2075  		kubeNodePortSetTCP:      {epEntry},
  2076  		kubeNodePortLocalSetTCP: {epEntry},
  2077  	}
  2078  	checkIPSet(t, fp, epIPSet)
  2079  
  2080  	// Check iptables chain and rules
  2081  	epIpt := netlinktest.ExpectedIptablesChain{
  2082  		string(kubeServicesChain): {{
  2083  			JumpChain: "RETURN", SourceAddress: "127.0.0.0/8",
  2084  		}, {
  2085  			JumpChain: string(kubeMarkMasqChain), MatchSet: kubeClusterIPSet,
  2086  		}, {
  2087  			JumpChain: string(kubeNodePortChain), MatchSet: "",
  2088  		}, {
  2089  			JumpChain: "ACCEPT", MatchSet: kubeClusterIPSet,
  2090  		}},
  2091  		string(kubeNodePortChain): {{
  2092  			JumpChain: "RETURN", MatchSet: kubeNodePortLocalSetTCP,
  2093  		}, {
  2094  			JumpChain: string(kubeMarkMasqChain), MatchSet: kubeNodePortSetTCP,
  2095  		}, {
  2096  			JumpChain: "ACCEPT", MatchSet: kubeHealthCheckNodePortSet,
  2097  		}},
  2098  	}
  2099  	checkIptables(t, ipt, epIpt)
  2100  }
  2101  
  2102  func TestHealthCheckNodePort(t *testing.T) {
  2103  	ipt, fp := buildFakeProxier(t)
  2104  
  2105  	svcIP := "10.20.30.41"
  2106  	svcPort := 80
  2107  	svcNodePort := 3000
  2108  	svcPortName := proxy.ServicePortName{
  2109  		NamespacedName: makeNSN("ns1", "svc1"),
  2110  		Port:           "p80",
  2111  	}
  2112  
  2113  	sampleSvc := makeTestService(svcPortName.Namespace, "", func(svc *v1.Service) {
  2114  		svc.Spec.Type = "LoadBalancer"
  2115  		svc.Spec.ClusterIP = svcIP
  2116  		svc.Spec.Ports = []v1.ServicePort{{
  2117  			Name:     svcPortName.Port,
  2118  			Port:     int32(svcPort),
  2119  			Protocol: v1.ProtocolTCP,
  2120  			NodePort: int32(svcNodePort),
  2121  		}}
  2122  		svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
  2123  	})
  2124  
  2125  	svc1, svc2, invalidSvc3 := *sampleSvc, *sampleSvc, *sampleSvc
  2126  	svc1.Name, svc1.Spec.HealthCheckNodePort = "valid-svc1", 30000
  2127  	svc2.Name, svc2.Spec.HealthCheckNodePort = "valid-svc2", 30001
  2128  	// make svc3 invalid by setting external traffic policy to cluster
  2129  	invalidSvc3.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyCluster
  2130  	invalidSvc3.Name, invalidSvc3.Spec.HealthCheckNodePort = "invalid-svc3", 30002
  2131  
  2132  	makeServiceMap(fp,
  2133  		&svc1,
  2134  		&svc2,
  2135  		&invalidSvc3,
  2136  	)
  2137  
  2138  	itf := net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0}
  2139  	addrs := []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("100.101.102.103"), Mask: net.CIDRMask(24, 32)}}
  2140  	itf1 := net.Interface{Index: 1, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0}
  2141  	addrs1 := []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("2001:db8::"), Mask: net.CIDRMask(64, 128)}}
  2142  	fp.networkInterfacer.(*proxyutiltest.FakeNetwork).AddInterfaceAddr(&itf, addrs)
  2143  	fp.networkInterfacer.(*proxyutiltest.FakeNetwork).AddInterfaceAddr(&itf1, addrs1)
  2144  	fp.nodePortAddresses = proxyutil.NewNodePortAddresses(v1.IPv4Protocol, []string{"100.101.102.0/24"})
  2145  
  2146  	fp.syncProxyRules()
  2147  
  2148  	// check ipSet rules
  2149  	makeTCPEntry := func(port int) *utilipset.Entry {
  2150  		return &utilipset.Entry{
  2151  			Port:     port,
  2152  			Protocol: strings.ToLower(string(v1.ProtocolTCP)),
  2153  			SetType:  utilipset.BitmapPort,
  2154  		}
  2155  	}
  2156  	epIPSet := netlinktest.ExpectedIPSet{
  2157  		// healthcheck node port set should only contain valid HC node ports
  2158  		kubeHealthCheckNodePortSet: {makeTCPEntry(30000), makeTCPEntry(30001)},
  2159  	}
  2160  	checkIPSet(t, fp, epIPSet)
  2161  
  2162  	// Check iptables chain and rules
  2163  	epIpt := netlinktest.ExpectedIptablesChain{
  2164  		string(kubeNodePortChain): {{
  2165  			JumpChain: "RETURN", MatchSet: kubeNodePortLocalSetTCP,
  2166  		}, {
  2167  			JumpChain: string(kubeMarkMasqChain), MatchSet: kubeNodePortSetTCP,
  2168  		}, {
  2169  			JumpChain: "ACCEPT", MatchSet: kubeHealthCheckNodePortSet,
  2170  		}},
  2171  	}
  2172  	checkIptables(t, ipt, epIpt)
  2173  }
  2174  
  2175  func TestLoadBalancerSourceRanges(t *testing.T) {
  2176  	ipt, fp := buildFakeProxier(t)
  2177  
  2178  	svcIP := "10.20.30.41"
  2179  	svcPort := 80
  2180  	svcLBIP := "1.2.3.4"
  2181  	svcLBSource := "10.0.0.0/8"
  2182  	svcPortName := proxy.ServicePortName{
  2183  		NamespacedName: makeNSN("ns1", "svc1"),
  2184  		Port:           "p80",
  2185  	}
  2186  	epIP := "10.180.0.1"
  2187  
  2188  	makeServiceMap(fp,
  2189  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
  2190  			svc.Spec.Type = "LoadBalancer"
  2191  			svc.Spec.ClusterIP = svcIP
  2192  			svc.Spec.Ports = []v1.ServicePort{{
  2193  				Name:     svcPortName.Port,
  2194  				Port:     int32(svcPort),
  2195  				Protocol: v1.ProtocolTCP,
  2196  			}}
  2197  			svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
  2198  				IP: svcLBIP,
  2199  			}}
  2200  			svc.Spec.LoadBalancerSourceRanges = []string{
  2201  				svcLBSource,
  2202  			}
  2203  		}),
  2204  	)
  2205  	populateEndpointSlices(fp,
  2206  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
  2207  			eps.AddressType = discovery.AddressTypeIPv4
  2208  			eps.Endpoints = []discovery.Endpoint{{
  2209  				Addresses: []string{epIP},
  2210  			}}
  2211  			eps.Ports = []discovery.EndpointPort{{
  2212  				Name:     ptr.To(svcPortName.Port),
  2213  				Port:     ptr.To(int32(svcPort)),
  2214  				Protocol: ptr.To(v1.ProtocolTCP),
  2215  			}}
  2216  		}),
  2217  	)
  2218  
  2219  	fp.syncProxyRules()
  2220  
  2221  	// Check ipvs service and destinations
  2222  	epVS := &netlinktest.ExpectedVirtualServer{
  2223  		VSNum: 2, IP: svcLBIP, Port: uint16(svcPort), Protocol: string(v1.ProtocolTCP),
  2224  		RS: []netlinktest.ExpectedRealServer{{
  2225  			IP: epIP, Port: uint16(svcPort),
  2226  		}}}
  2227  	checkIPVS(t, fp, epVS)
  2228  
  2229  	// Check ipset entry
  2230  	epIPSet := netlinktest.ExpectedIPSet{
  2231  		kubeLoadBalancerSet: {{
  2232  			IP:       svcLBIP,
  2233  			Port:     svcPort,
  2234  			Protocol: strings.ToLower(string(v1.ProtocolTCP)),
  2235  			SetType:  utilipset.HashIPPort,
  2236  		}},
  2237  		kubeLoadBalancerFWSet: {{
  2238  			IP:       svcLBIP,
  2239  			Port:     svcPort,
  2240  			Protocol: strings.ToLower(string(v1.ProtocolTCP)),
  2241  			SetType:  utilipset.HashIPPort,
  2242  		}},
  2243  		kubeLoadBalancerSourceCIDRSet: {{
  2244  			IP:       svcLBIP,
  2245  			Port:     svcPort,
  2246  			Protocol: strings.ToLower(string(v1.ProtocolTCP)),
  2247  			Net:      svcLBSource,
  2248  			SetType:  utilipset.HashIPPortNet,
  2249  		}},
  2250  	}
  2251  	checkIPSet(t, fp, epIPSet)
  2252  
  2253  	// Check iptables chain and rules
  2254  	epIpt := netlinktest.ExpectedIptablesChain{
  2255  		string(kubeServicesChain): {{
  2256  			JumpChain: "RETURN", SourceAddress: "127.0.0.0/8",
  2257  		}, {
  2258  			JumpChain: string(kubeLoadBalancerChain), MatchSet: kubeLoadBalancerSet,
  2259  		}, {
  2260  			JumpChain: string(kubeMarkMasqChain), MatchSet: kubeClusterIPSet,
  2261  		}, {
  2262  			JumpChain: string(kubeNodePortChain), MatchSet: "",
  2263  		}, {
  2264  			JumpChain: "ACCEPT", MatchSet: kubeClusterIPSet,
  2265  		}, {
  2266  			JumpChain: "ACCEPT", MatchSet: kubeLoadBalancerSet,
  2267  		}},
  2268  		string(kubeProxyFirewallChain): {{
  2269  			JumpChain: string(kubeSourceRangesFirewallChain), MatchSet: kubeLoadBalancerFWSet,
  2270  		}},
  2271  		string(kubeSourceRangesFirewallChain): {{
  2272  			JumpChain: "RETURN", MatchSet: kubeLoadBalancerSourceCIDRSet,
  2273  		}, {
  2274  			JumpChain: "DROP", MatchSet: "",
  2275  		}},
  2276  	}
  2277  	checkIptables(t, ipt, epIpt)
  2278  }
  2279  
  2280  func TestAcceptIPVSTraffic(t *testing.T) {
  2281  	ipt, fp := buildFakeProxier(t)
  2282  
  2283  	ingressIP := "1.2.3.4"
  2284  	externalIP := []string{"5.6.7.8"}
  2285  	svcInfos := []struct {
  2286  		svcType v1.ServiceType
  2287  		svcIP   string
  2288  		svcName string
  2289  		epIP    string
  2290  	}{
  2291  		{v1.ServiceTypeClusterIP, "10.20.30.40", "svc1", "10.180.0.1"},
  2292  		{v1.ServiceTypeLoadBalancer, "10.20.30.41", "svc2", "10.180.0.2"},
  2293  		{v1.ServiceTypeNodePort, "10.20.30.42", "svc3", "10.180.0.3"},
  2294  	}
  2295  
  2296  	for _, svcInfo := range svcInfos {
  2297  		makeServiceMap(fp,
  2298  			makeTestService("ns1", svcInfo.svcName, func(svc *v1.Service) {
  2299  				svc.Spec.Type = svcInfo.svcType
  2300  				svc.Spec.ClusterIP = svcInfo.svcIP
  2301  				svc.Spec.Ports = []v1.ServicePort{{
  2302  					Name:     "p80",
  2303  					Port:     80,
  2304  					Protocol: v1.ProtocolTCP,
  2305  					NodePort: 80,
  2306  				}}
  2307  				if svcInfo.svcType == v1.ServiceTypeLoadBalancer {
  2308  					svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
  2309  						IP: ingressIP,
  2310  					}}
  2311  				}
  2312  				if svcInfo.svcType == v1.ServiceTypeClusterIP {
  2313  					svc.Spec.ExternalIPs = externalIP
  2314  				}
  2315  			}),
  2316  		)
  2317  
  2318  		populateEndpointSlices(fp,
  2319  			makeTestEndpointSlice("ns1", "p80", 1, func(eps *discovery.EndpointSlice) {
  2320  				eps.Endpoints = []discovery.Endpoint{{
  2321  					Addresses: []string{svcInfo.epIP},
  2322  				}}
  2323  				eps.Ports = []discovery.EndpointPort{{
  2324  					Name:     ptr.To("p80"),
  2325  					Port:     ptr.To[int32](80),
  2326  					Protocol: ptr.To(v1.ProtocolUDP),
  2327  				}}
  2328  			}),
  2329  		)
  2330  	}
  2331  	fp.syncProxyRules()
  2332  
  2333  	// Check iptables chain and rules
  2334  	epIpt := netlinktest.ExpectedIptablesChain{
  2335  		string(kubeServicesChain): {
  2336  			{JumpChain: "RETURN", SourceAddress: "127.0.0.0/8"},
  2337  			{JumpChain: string(kubeLoadBalancerChain), MatchSet: kubeLoadBalancerSet},
  2338  			{JumpChain: string(kubeMarkMasqChain), MatchSet: kubeClusterIPSet},
  2339  			{JumpChain: string(kubeMarkMasqChain), MatchSet: kubeExternalIPSet},
  2340  			{JumpChain: "ACCEPT", MatchSet: kubeExternalIPSet}, // With externalTrafficOnlyArgs
  2341  			{JumpChain: "ACCEPT", MatchSet: kubeExternalIPSet}, // With dstLocalOnlyArgs
  2342  			{JumpChain: string(kubeNodePortChain), MatchSet: ""},
  2343  			{JumpChain: "ACCEPT", MatchSet: kubeClusterIPSet},
  2344  			{JumpChain: "ACCEPT", MatchSet: kubeLoadBalancerSet},
  2345  		},
  2346  	}
  2347  	checkIptables(t, ipt, epIpt)
  2348  }
  2349  
  2350  func TestOnlyLocalLoadBalancing(t *testing.T) {
  2351  	ipt, fp := buildFakeProxier(t)
  2352  
  2353  	svcIP := "10.20.30.41"
  2354  	svcPort := 80
  2355  	svcNodePort := 3001
  2356  	svcLBIP := "1.2.3.4"
  2357  	svcPortName := proxy.ServicePortName{
  2358  		NamespacedName: makeNSN("ns1", "svc1"),
  2359  		Port:           "p80",
  2360  	}
  2361  
  2362  	makeServiceMap(fp,
  2363  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
  2364  			svc.Spec.Type = "LoadBalancer"
  2365  			svc.Spec.ClusterIP = svcIP
  2366  			svc.Spec.Ports = []v1.ServicePort{{
  2367  				Name:     svcPortName.Port,
  2368  				Port:     int32(svcPort),
  2369  				Protocol: v1.ProtocolTCP,
  2370  				NodePort: int32(svcNodePort),
  2371  			}}
  2372  			svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
  2373  				IP: svcLBIP,
  2374  			}}
  2375  			svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
  2376  		}),
  2377  	)
  2378  
  2379  	epIP := "10.180.0.1"
  2380  	epIP1 := "10.180.1.1"
  2381  
  2382  	populateEndpointSlices(fp,
  2383  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
  2384  			eps.AddressType = discovery.AddressTypeIPv4
  2385  			eps.Endpoints = []discovery.Endpoint{
  2386  				{ // **local** endpoint address, should be added as RS
  2387  					Addresses: []string{epIP},
  2388  					NodeName:  ptr.To(testHostname),
  2389  				},
  2390  				{ // **remote** endpoint address, should not be added as RS
  2391  					Addresses: []string{epIP1},
  2392  					NodeName:  ptr.To("other-hostname"),
  2393  				}}
  2394  			eps.Ports = []discovery.EndpointPort{{
  2395  				Name:     ptr.To(svcPortName.Port),
  2396  				Port:     ptr.To(int32(svcPort)),
  2397  				Protocol: ptr.To(v1.ProtocolTCP),
  2398  			}}
  2399  		}),
  2400  	)
  2401  
  2402  	fp.syncProxyRules()
  2403  
  2404  	// Expect 2 services and 1 destination
  2405  	epVS := &netlinktest.ExpectedVirtualServer{
  2406  		VSNum: 2, IP: svcLBIP, Port: uint16(svcPort), Protocol: string(v1.ProtocolTCP),
  2407  		RS: []netlinktest.ExpectedRealServer{{
  2408  			IP: epIP, Port: uint16(svcPort),
  2409  		}}}
  2410  	checkIPVS(t, fp, epVS)
  2411  
  2412  	// check ipSet rules
  2413  	epIPSet := netlinktest.ExpectedIPSet{
  2414  		kubeLoadBalancerSet: {{
  2415  			IP:       svcLBIP,
  2416  			Port:     svcPort,
  2417  			Protocol: strings.ToLower(string(v1.ProtocolTCP)),
  2418  			SetType:  utilipset.HashIPPort,
  2419  		}},
  2420  		kubeLoadBalancerLocalSet: {{
  2421  			IP:       svcLBIP,
  2422  			Port:     svcPort,
  2423  			Protocol: strings.ToLower(string(v1.ProtocolTCP)),
  2424  			SetType:  utilipset.HashIPPort,
  2425  		}},
  2426  	}
  2427  	checkIPSet(t, fp, epIPSet)
  2428  
  2429  	// Check iptables chain and rules
  2430  	epIpt := netlinktest.ExpectedIptablesChain{
  2431  		string(kubeServicesChain): {{
  2432  			JumpChain: "RETURN", SourceAddress: "127.0.0.0/8",
  2433  		}, {
  2434  			JumpChain: string(kubeLoadBalancerChain), MatchSet: kubeLoadBalancerSet,
  2435  		}, {
  2436  			JumpChain: string(kubeMarkMasqChain), MatchSet: kubeClusterIPSet,
  2437  		}, {
  2438  			JumpChain: string(kubeNodePortChain), MatchSet: "",
  2439  		}, {
  2440  			JumpChain: "ACCEPT", MatchSet: kubeClusterIPSet,
  2441  		}, {
  2442  			JumpChain: "ACCEPT", MatchSet: kubeLoadBalancerSet,
  2443  		}},
  2444  		string(kubeLoadBalancerChain): {{
  2445  			JumpChain: "RETURN", MatchSet: kubeLoadBalancerLocalSet,
  2446  		}, {
  2447  			JumpChain: string(kubeMarkMasqChain), MatchSet: "",
  2448  		}},
  2449  	}
  2450  	checkIptables(t, ipt, epIpt)
  2451  }
  2452  
  2453  func addTestPort(array []v1.ServicePort, name string, protocol v1.Protocol, port, nodeport int32, targetPort int) []v1.ServicePort {
  2454  	svcPort := v1.ServicePort{
  2455  		Name:       name,
  2456  		Protocol:   protocol,
  2457  		Port:       port,
  2458  		NodePort:   nodeport,
  2459  		TargetPort: intstr.FromInt32(int32(targetPort)),
  2460  	}
  2461  	return append(array, svcPort)
  2462  }
  2463  
  2464  func TestBuildServiceMapAddRemove(t *testing.T) {
  2465  	_, ctx := ktesting.NewTestContext(t)
  2466  	ipt := iptablestest.NewFake()
  2467  	ipvs := ipvstest.NewFake()
  2468  	ipset := ipsettest.NewFake(testIPSetVersion)
  2469  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  2470  
  2471  	services := []*v1.Service{
  2472  		makeTestService("somewhere-else", "cluster-ip", func(svc *v1.Service) {
  2473  			svc.Spec.Type = v1.ServiceTypeClusterIP
  2474  			svc.Spec.ClusterIP = "172.16.55.4"
  2475  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "something", "UDP", 1234, 4321, 0)
  2476  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "somethingelse", "UDP", 1235, 5321, 0)
  2477  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "somesctp", "SCTP", 1236, 6321, 0)
  2478  		}),
  2479  		makeTestService("somewhere-else", "node-port", func(svc *v1.Service) {
  2480  			svc.Spec.Type = v1.ServiceTypeNodePort
  2481  			svc.Spec.ClusterIP = "172.16.55.10"
  2482  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "blahblah", "UDP", 345, 678, 0)
  2483  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "moreblahblah", "TCP", 344, 677, 0)
  2484  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "sctpblah", "SCTP", 343, 676, 0)
  2485  		}),
  2486  		makeTestService("somewhere", "load-balancer", func(svc *v1.Service) {
  2487  			svc.Spec.Type = v1.ServiceTypeLoadBalancer
  2488  			svc.Spec.ClusterIP = "172.16.55.11"
  2489  			svc.Spec.LoadBalancerIP = "5.6.7.8"
  2490  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "foobar", "UDP", 8675, 30061, 7000)
  2491  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "baz", "UDP", 8676, 30062, 7001)
  2492  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "sctpfoo", "SCTP", 8677, 30063, 7002)
  2493  			svc.Status.LoadBalancer = v1.LoadBalancerStatus{
  2494  				Ingress: []v1.LoadBalancerIngress{
  2495  					{IP: "10.1.2.4"},
  2496  				},
  2497  			}
  2498  		}),
  2499  		makeTestService("somewhere", "only-local-load-balancer", func(svc *v1.Service) {
  2500  			svc.Spec.Type = v1.ServiceTypeLoadBalancer
  2501  			svc.Spec.ClusterIP = "172.16.55.12"
  2502  			svc.Spec.LoadBalancerIP = "5.6.7.8"
  2503  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "foobar2", "UDP", 8677, 30063, 7002)
  2504  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "baz", "UDP", 8678, 30064, 7003)
  2505  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "sctpbaz", "SCTP", 8679, 30065, 7004)
  2506  			svc.Status.LoadBalancer = v1.LoadBalancerStatus{
  2507  				Ingress: []v1.LoadBalancerIngress{
  2508  					{IP: "10.1.2.3"},
  2509  				},
  2510  			}
  2511  			svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
  2512  			svc.Spec.HealthCheckNodePort = 345
  2513  		}),
  2514  	}
  2515  
  2516  	for i := range services {
  2517  		fp.OnServiceAdd(services[i])
  2518  	}
  2519  	result := fp.svcPortMap.Update(fp.serviceChanges)
  2520  	if len(fp.svcPortMap) != 12 {
  2521  		t.Errorf("expected service map length 12, got %v", fp.svcPortMap)
  2522  	}
  2523  
  2524  	if len(result.DeletedUDPClusterIPs) != 0 {
  2525  		// Services only added, so nothing stale yet
  2526  		t.Errorf("expected stale UDP services length 0, got %d", len(result.DeletedUDPClusterIPs))
  2527  	}
  2528  
  2529  	// The only-local-loadbalancer ones get added
  2530  	healthCheckNodePorts := fp.svcPortMap.HealthCheckNodePorts()
  2531  	if len(healthCheckNodePorts) != 1 {
  2532  		t.Errorf("expected 1 healthcheck port, got %v", healthCheckNodePorts)
  2533  	} else {
  2534  		nsn := makeNSN("somewhere", "only-local-load-balancer")
  2535  		if port, found := healthCheckNodePorts[nsn]; !found || port != 345 {
  2536  			t.Errorf("expected healthcheck port [%q]=345: got %v", nsn, healthCheckNodePorts)
  2537  		}
  2538  	}
  2539  
  2540  	// Remove some stuff
  2541  	// oneService is a modification of services[0] with removed first port.
  2542  	oneService := makeTestService("somewhere-else", "cluster-ip", func(svc *v1.Service) {
  2543  		svc.Spec.Type = v1.ServiceTypeClusterIP
  2544  		svc.Spec.ClusterIP = "172.16.55.4"
  2545  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "somethingelse", "UDP", 1235, 5321, 0)
  2546  	})
  2547  
  2548  	fp.OnServiceUpdate(services[0], oneService)
  2549  	fp.OnServiceDelete(services[1])
  2550  	fp.OnServiceDelete(services[2])
  2551  	fp.OnServiceDelete(services[3])
  2552  
  2553  	result = fp.svcPortMap.Update(fp.serviceChanges)
  2554  	if len(fp.svcPortMap) != 1 {
  2555  		t.Errorf("expected service map length 1, got %v", fp.svcPortMap)
  2556  	}
  2557  
  2558  	// All services but one were deleted. While you'd expect only the ClusterIPs
  2559  	// from the three deleted services here, we still have the ClusterIP for
  2560  	// the not-deleted service, because one of it's ServicePorts was deleted.
  2561  	expectedStaleUDPServices := []string{"172.16.55.10", "172.16.55.4", "172.16.55.11", "172.16.55.12"}
  2562  	if len(result.DeletedUDPClusterIPs) != len(expectedStaleUDPServices) {
  2563  		t.Errorf("expected stale UDP services length %d, got %v", len(expectedStaleUDPServices), result.DeletedUDPClusterIPs.UnsortedList())
  2564  	}
  2565  	for _, ip := range expectedStaleUDPServices {
  2566  		if !result.DeletedUDPClusterIPs.Has(ip) {
  2567  			t.Errorf("expected stale UDP service service %s", ip)
  2568  		}
  2569  	}
  2570  
  2571  	healthCheckNodePorts = fp.svcPortMap.HealthCheckNodePorts()
  2572  	if len(healthCheckNodePorts) != 0 {
  2573  		t.Errorf("expected 0 healthcheck ports, got %v", healthCheckNodePorts)
  2574  	}
  2575  }
  2576  
  2577  func TestBuildServiceMapServiceHeadless(t *testing.T) {
  2578  	_, ctx := ktesting.NewTestContext(t)
  2579  	ipt := iptablestest.NewFake()
  2580  	ipvs := ipvstest.NewFake()
  2581  	ipset := ipsettest.NewFake(testIPSetVersion)
  2582  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  2583  
  2584  	makeServiceMap(fp,
  2585  		makeTestService("somewhere-else", "headless", func(svc *v1.Service) {
  2586  			svc.Spec.Type = v1.ServiceTypeClusterIP
  2587  			svc.Spec.ClusterIP = v1.ClusterIPNone
  2588  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "rpc", "UDP", 1234, 0, 0)
  2589  		}),
  2590  		makeTestService("somewhere-else", "headless-without-port", func(svc *v1.Service) {
  2591  			svc.Spec.Type = v1.ServiceTypeClusterIP
  2592  			svc.Spec.ClusterIP = v1.ClusterIPNone
  2593  		}),
  2594  		makeTestService("somewhere-else", "headless-sctp", func(svc *v1.Service) {
  2595  			svc.Spec.Type = v1.ServiceTypeClusterIP
  2596  			svc.Spec.ClusterIP = v1.ClusterIPNone
  2597  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "sip", "SCTP", 1235, 0, 0)
  2598  		}),
  2599  	)
  2600  
  2601  	// Headless service should be ignored
  2602  	result := fp.svcPortMap.Update(fp.serviceChanges)
  2603  	if len(fp.svcPortMap) != 0 {
  2604  		t.Errorf("expected service map length 0, got %d", len(fp.svcPortMap))
  2605  	}
  2606  
  2607  	if len(result.DeletedUDPClusterIPs) != 0 {
  2608  		t.Errorf("expected stale UDP services length 0, got %d", len(result.DeletedUDPClusterIPs))
  2609  	}
  2610  
  2611  	// No proxied services, so no healthchecks
  2612  	healthCheckNodePorts := fp.svcPortMap.HealthCheckNodePorts()
  2613  	if len(healthCheckNodePorts) != 0 {
  2614  		t.Errorf("expected healthcheck ports length 0, got %d", len(healthCheckNodePorts))
  2615  	}
  2616  }
  2617  
  2618  func TestBuildServiceMapServiceTypeExternalName(t *testing.T) {
  2619  	_, ctx := ktesting.NewTestContext(t)
  2620  	ipt := iptablestest.NewFake()
  2621  	ipvs := ipvstest.NewFake()
  2622  	ipset := ipsettest.NewFake(testIPSetVersion)
  2623  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  2624  
  2625  	makeServiceMap(fp,
  2626  		makeTestService("somewhere-else", "external-name", func(svc *v1.Service) {
  2627  			svc.Spec.Type = v1.ServiceTypeExternalName
  2628  			svc.Spec.ClusterIP = "172.16.55.4" // Should be ignored
  2629  			svc.Spec.ExternalName = "foo2.bar.com"
  2630  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "blah", "UDP", 1235, 5321, 0)
  2631  		}),
  2632  	)
  2633  
  2634  	result := fp.svcPortMap.Update(fp.serviceChanges)
  2635  	if len(fp.svcPortMap) != 0 {
  2636  		t.Errorf("expected service map length 0, got %v", fp.svcPortMap)
  2637  	}
  2638  	if len(result.DeletedUDPClusterIPs) != 0 {
  2639  		t.Errorf("expected stale UDP services length 0, got %v", result.DeletedUDPClusterIPs)
  2640  	}
  2641  
  2642  	// No proxied services, so no healthchecks
  2643  	healthCheckNodePorts := fp.svcPortMap.HealthCheckNodePorts()
  2644  	if len(healthCheckNodePorts) != 0 {
  2645  		t.Errorf("expected healthcheck ports length 0, got %v", healthCheckNodePorts)
  2646  	}
  2647  }
  2648  
  2649  func TestBuildServiceMapServiceUpdate(t *testing.T) {
  2650  	_, ctx := ktesting.NewTestContext(t)
  2651  	ipt := iptablestest.NewFake()
  2652  	ipvs := ipvstest.NewFake()
  2653  	ipset := ipsettest.NewFake(testIPSetVersion)
  2654  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  2655  
  2656  	servicev1 := makeTestService("somewhere", "some-service", func(svc *v1.Service) {
  2657  		svc.Spec.Type = v1.ServiceTypeClusterIP
  2658  		svc.Spec.ClusterIP = "172.16.55.4"
  2659  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "something", "UDP", 1234, 4321, 0)
  2660  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "somethingelse", "TCP", 1235, 5321, 0)
  2661  	})
  2662  	servicev2 := makeTestService("somewhere", "some-service", func(svc *v1.Service) {
  2663  		svc.Spec.Type = v1.ServiceTypeLoadBalancer
  2664  		svc.Spec.ClusterIP = "172.16.55.4"
  2665  		svc.Spec.LoadBalancerIP = "5.6.7.8"
  2666  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "something", "UDP", 1234, 4321, 7002)
  2667  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "somethingelse", "TCP", 1235, 5321, 7003)
  2668  		svc.Status.LoadBalancer = v1.LoadBalancerStatus{
  2669  			Ingress: []v1.LoadBalancerIngress{
  2670  				{IP: "10.1.2.3"},
  2671  			},
  2672  		}
  2673  		svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
  2674  		svc.Spec.HealthCheckNodePort = 345
  2675  	})
  2676  
  2677  	fp.OnServiceAdd(servicev1)
  2678  
  2679  	result := fp.svcPortMap.Update(fp.serviceChanges)
  2680  	if len(fp.svcPortMap) != 2 {
  2681  		t.Errorf("expected service map length 2, got %v", fp.svcPortMap)
  2682  	}
  2683  	if len(result.DeletedUDPClusterIPs) != 0 {
  2684  		// Services only added, so nothing stale yet
  2685  		t.Errorf("expected stale UDP services length 0, got %d", len(result.DeletedUDPClusterIPs))
  2686  	}
  2687  
  2688  	healthCheckNodePorts := fp.svcPortMap.HealthCheckNodePorts()
  2689  	if len(healthCheckNodePorts) != 0 {
  2690  		t.Errorf("expected healthcheck ports length 0, got %v", healthCheckNodePorts)
  2691  	}
  2692  
  2693  	// Change service to load-balancer
  2694  	fp.OnServiceUpdate(servicev1, servicev2)
  2695  	result = fp.svcPortMap.Update(fp.serviceChanges)
  2696  	if len(fp.svcPortMap) != 2 {
  2697  		t.Errorf("expected service map length 2, got %v", fp.svcPortMap)
  2698  	}
  2699  	if len(result.DeletedUDPClusterIPs) != 0 {
  2700  		t.Errorf("expected stale UDP services length 0, got %v", result.DeletedUDPClusterIPs.UnsortedList())
  2701  	}
  2702  
  2703  	healthCheckNodePorts = fp.svcPortMap.HealthCheckNodePorts()
  2704  	if len(healthCheckNodePorts) != 1 {
  2705  		t.Errorf("expected healthcheck ports length 1, got %v", healthCheckNodePorts)
  2706  	}
  2707  
  2708  	// No change; make sure the service map stays the same and there are
  2709  	// no health-check changes
  2710  	fp.OnServiceUpdate(servicev2, servicev2)
  2711  	result = fp.svcPortMap.Update(fp.serviceChanges)
  2712  	if len(fp.svcPortMap) != 2 {
  2713  		t.Errorf("expected service map length 2, got %v", fp.svcPortMap)
  2714  	}
  2715  	if len(result.DeletedUDPClusterIPs) != 0 {
  2716  		t.Errorf("expected stale UDP services length 0, got %v", result.DeletedUDPClusterIPs.UnsortedList())
  2717  	}
  2718  
  2719  	healthCheckNodePorts = fp.svcPortMap.HealthCheckNodePorts()
  2720  	if len(healthCheckNodePorts) != 1 {
  2721  		t.Errorf("expected healthcheck ports length 1, got %v", healthCheckNodePorts)
  2722  	}
  2723  
  2724  	// And back to ClusterIP
  2725  	fp.OnServiceUpdate(servicev2, servicev1)
  2726  	result = fp.svcPortMap.Update(fp.serviceChanges)
  2727  	if len(fp.svcPortMap) != 2 {
  2728  		t.Errorf("expected service map length 2, got %v", fp.svcPortMap)
  2729  	}
  2730  	if len(result.DeletedUDPClusterIPs) != 0 {
  2731  		// Services only added, so nothing stale yet
  2732  		t.Errorf("expected stale UDP services length 0, got %d", len(result.DeletedUDPClusterIPs))
  2733  	}
  2734  
  2735  	healthCheckNodePorts = fp.svcPortMap.HealthCheckNodePorts()
  2736  	if len(healthCheckNodePorts) != 0 {
  2737  		t.Errorf("expected healthcheck ports length 0, got %v", healthCheckNodePorts)
  2738  	}
  2739  }
  2740  
  2741  func TestSessionAffinity(t *testing.T) {
  2742  	_, ctx := ktesting.NewTestContext(t)
  2743  	ipt := iptablestest.NewFake()
  2744  	ipvs := ipvstest.NewFake()
  2745  	ipset := ipsettest.NewFake(testIPSetVersion)
  2746  	nodeIP := "100.101.102.103"
  2747  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, []string{nodeIP}, nil, v1.IPv4Protocol)
  2748  	svcIP := "10.20.30.41"
  2749  	svcPort := 80
  2750  	svcNodePort := 3001
  2751  	svcExternalIPs := "50.60.70.81"
  2752  	svcPortName := proxy.ServicePortName{
  2753  		NamespacedName: makeNSN("ns1", "svc1"),
  2754  		Port:           "p80",
  2755  	}
  2756  
  2757  	makeServiceMap(fp,
  2758  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
  2759  			svc.Spec.Type = "NodePort"
  2760  			svc.Spec.ClusterIP = svcIP
  2761  			svc.Spec.ExternalIPs = []string{svcExternalIPs}
  2762  			svc.Spec.SessionAffinity = v1.ServiceAffinityClientIP
  2763  			svc.Spec.SessionAffinityConfig = &v1.SessionAffinityConfig{
  2764  				ClientIP: &v1.ClientIPConfig{
  2765  					TimeoutSeconds: ptr.To[int32](v1.DefaultClientIPServiceAffinitySeconds),
  2766  				},
  2767  			}
  2768  			svc.Spec.Ports = []v1.ServicePort{{
  2769  				Name:     svcPortName.Port,
  2770  				Port:     int32(svcPort),
  2771  				Protocol: v1.ProtocolTCP,
  2772  				NodePort: int32(svcNodePort),
  2773  			}}
  2774  		}),
  2775  	)
  2776  	fp.syncProxyRules()
  2777  
  2778  	// check ipvs service and destinations
  2779  	services, err := ipvs.GetVirtualServers()
  2780  	if err != nil {
  2781  		t.Errorf("Failed to get ipvs services, err: %v", err)
  2782  	}
  2783  	for _, svc := range services {
  2784  		if svc.Timeout != uint32(v1.DefaultClientIPServiceAffinitySeconds) {
  2785  			t.Errorf("Unexpected mismatch ipvs service session affinity timeout: %d, expected: %d", svc.Timeout, v1.DefaultClientIPServiceAffinitySeconds)
  2786  		}
  2787  	}
  2788  }
  2789  
  2790  func makeServicePortName(ns, name, port string, protocol v1.Protocol) proxy.ServicePortName {
  2791  	return proxy.ServicePortName{
  2792  		NamespacedName: makeNSN(ns, name),
  2793  		Port:           port,
  2794  		Protocol:       protocol,
  2795  	}
  2796  }
  2797  
  2798  func Test_updateEndpointsMap(t *testing.T) {
  2799  	emptyEndpointSlices := []*discovery.EndpointSlice{
  2800  		makeTestEndpointSlice("ns1", "ep1", 1, func(*discovery.EndpointSlice) {}),
  2801  	}
  2802  	subset1 := func(eps *discovery.EndpointSlice) {
  2803  		eps.AddressType = discovery.AddressTypeIPv4
  2804  		eps.Endpoints = []discovery.Endpoint{{
  2805  			Addresses: []string{"1.1.1.1"},
  2806  		}}
  2807  		eps.Ports = []discovery.EndpointPort{{
  2808  			Name:     ptr.To("p11"),
  2809  			Port:     ptr.To[int32](11),
  2810  			Protocol: ptr.To(v1.ProtocolUDP),
  2811  		}}
  2812  	}
  2813  	subset2 := func(eps *discovery.EndpointSlice) {
  2814  		eps.AddressType = discovery.AddressTypeIPv4
  2815  		eps.Endpoints = []discovery.Endpoint{{
  2816  			Addresses: []string{"1.1.1.2"},
  2817  		}}
  2818  		eps.Ports = []discovery.EndpointPort{{
  2819  			Name:     ptr.To("p12"),
  2820  			Port:     ptr.To[int32](12),
  2821  			Protocol: ptr.To(v1.ProtocolUDP),
  2822  		}}
  2823  	}
  2824  	namedPortLocal := []*discovery.EndpointSlice{
  2825  		makeTestEndpointSlice("ns1", "ep1", 1,
  2826  			func(eps *discovery.EndpointSlice) {
  2827  				eps.AddressType = discovery.AddressTypeIPv4
  2828  				eps.Endpoints = []discovery.Endpoint{{
  2829  					Addresses: []string{"1.1.1.1"},
  2830  					NodeName:  ptr.To(testHostname),
  2831  				}}
  2832  				eps.Ports = []discovery.EndpointPort{{
  2833  					Name:     ptr.To("p11"),
  2834  					Port:     ptr.To[int32](11),
  2835  					Protocol: ptr.To(v1.ProtocolUDP),
  2836  				}}
  2837  			}),
  2838  	}
  2839  	namedPort := []*discovery.EndpointSlice{
  2840  		makeTestEndpointSlice("ns1", "ep1", 1, subset1),
  2841  	}
  2842  	namedPortRenamed := []*discovery.EndpointSlice{
  2843  		makeTestEndpointSlice("ns1", "ep1", 1,
  2844  			func(eps *discovery.EndpointSlice) {
  2845  				eps.AddressType = discovery.AddressTypeIPv4
  2846  				eps.Endpoints = []discovery.Endpoint{{
  2847  					Addresses: []string{"1.1.1.1"},
  2848  				}}
  2849  				eps.Ports = []discovery.EndpointPort{{
  2850  					Name:     ptr.To("p11-2"),
  2851  					Port:     ptr.To[int32](11),
  2852  					Protocol: ptr.To(v1.ProtocolUDP),
  2853  				}}
  2854  			}),
  2855  	}
  2856  	namedPortRenumbered := []*discovery.EndpointSlice{
  2857  		makeTestEndpointSlice("ns1", "ep1", 1,
  2858  			func(eps *discovery.EndpointSlice) {
  2859  				eps.AddressType = discovery.AddressTypeIPv4
  2860  				eps.Endpoints = []discovery.Endpoint{{
  2861  					Addresses: []string{"1.1.1.1"},
  2862  				}}
  2863  				eps.Ports = []discovery.EndpointPort{{
  2864  					Name:     ptr.To("p11"),
  2865  					Port:     ptr.To[int32](22),
  2866  					Protocol: ptr.To(v1.ProtocolUDP),
  2867  				}}
  2868  			}),
  2869  	}
  2870  	namedPortsLocalNoLocal := []*discovery.EndpointSlice{
  2871  		makeTestEndpointSlice("ns1", "ep1", 1,
  2872  			func(eps *discovery.EndpointSlice) {
  2873  				eps.AddressType = discovery.AddressTypeIPv4
  2874  				eps.Endpoints = []discovery.Endpoint{{
  2875  					Addresses: []string{"1.1.1.1"},
  2876  				}, {
  2877  					Addresses: []string{"1.1.1.2"},
  2878  					NodeName:  ptr.To(testHostname),
  2879  				}}
  2880  				eps.Ports = []discovery.EndpointPort{{
  2881  					Name:     ptr.To("p11"),
  2882  					Port:     ptr.To[int32](11),
  2883  					Protocol: ptr.To(v1.ProtocolUDP),
  2884  				}, {
  2885  					Name:     ptr.To("p12"),
  2886  					Port:     ptr.To[int32](12),
  2887  					Protocol: ptr.To(v1.ProtocolUDP),
  2888  				}}
  2889  			}),
  2890  	}
  2891  	multipleSubsets := []*discovery.EndpointSlice{
  2892  		makeTestEndpointSlice("ns1", "ep1", 1, subset1),
  2893  		makeTestEndpointSlice("ns1", "ep1", 2, subset2),
  2894  	}
  2895  	subsetLocal := func(eps *discovery.EndpointSlice) {
  2896  		eps.AddressType = discovery.AddressTypeIPv4
  2897  		eps.Endpoints = []discovery.Endpoint{{
  2898  			Addresses: []string{"1.1.1.2"},
  2899  			NodeName:  ptr.To(testHostname),
  2900  		}}
  2901  		eps.Ports = []discovery.EndpointPort{{
  2902  			Name:     ptr.To("p12"),
  2903  			Port:     ptr.To[int32](12),
  2904  			Protocol: ptr.To(v1.ProtocolUDP),
  2905  		}}
  2906  	}
  2907  	multipleSubsetsWithLocal := []*discovery.EndpointSlice{
  2908  		makeTestEndpointSlice("ns1", "ep1", 1, subset1),
  2909  		makeTestEndpointSlice("ns1", "ep1", 2, subsetLocal),
  2910  	}
  2911  	subsetMultiplePortsLocal := func(eps *discovery.EndpointSlice) {
  2912  		eps.AddressType = discovery.AddressTypeIPv4
  2913  		eps.Endpoints = []discovery.Endpoint{{
  2914  			Addresses: []string{"1.1.1.1"},
  2915  			NodeName:  ptr.To(testHostname),
  2916  		}}
  2917  		eps.Ports = []discovery.EndpointPort{{
  2918  			Name:     ptr.To("p11"),
  2919  			Port:     ptr.To[int32](11),
  2920  			Protocol: ptr.To(v1.ProtocolUDP),
  2921  		}, {
  2922  			Name:     ptr.To("p12"),
  2923  			Port:     ptr.To[int32](12),
  2924  			Protocol: ptr.To(v1.ProtocolUDP),
  2925  		}}
  2926  	}
  2927  	subset3 := func(eps *discovery.EndpointSlice) {
  2928  		eps.AddressType = discovery.AddressTypeIPv4
  2929  		eps.Endpoints = []discovery.Endpoint{{
  2930  			Addresses: []string{"1.1.1.3"},
  2931  		}}
  2932  		eps.Ports = []discovery.EndpointPort{{
  2933  			Name:     ptr.To("p13"),
  2934  			Port:     ptr.To[int32](13),
  2935  			Protocol: ptr.To(v1.ProtocolUDP),
  2936  		}}
  2937  	}
  2938  	multipleSubsetsMultiplePortsLocal := []*discovery.EndpointSlice{
  2939  		makeTestEndpointSlice("ns1", "ep1", 1, subsetMultiplePortsLocal),
  2940  		makeTestEndpointSlice("ns1", "ep1", 2, subset3),
  2941  	}
  2942  	subsetMultipleIPsPorts1 := func(eps *discovery.EndpointSlice) {
  2943  		eps.AddressType = discovery.AddressTypeIPv4
  2944  		eps.Endpoints = []discovery.Endpoint{{
  2945  			Addresses: []string{"1.1.1.1"},
  2946  		}, {
  2947  			Addresses: []string{"1.1.1.2"},
  2948  			NodeName:  ptr.To(testHostname),
  2949  		}}
  2950  		eps.Ports = []discovery.EndpointPort{{
  2951  			Name:     ptr.To("p11"),
  2952  			Port:     ptr.To[int32](11),
  2953  			Protocol: ptr.To(v1.ProtocolUDP),
  2954  		}, {
  2955  			Name:     ptr.To("p12"),
  2956  			Port:     ptr.To[int32](12),
  2957  			Protocol: ptr.To(v1.ProtocolUDP),
  2958  		}}
  2959  	}
  2960  	subsetMultipleIPsPorts2 := func(eps *discovery.EndpointSlice) {
  2961  		eps.AddressType = discovery.AddressTypeIPv4
  2962  		eps.Endpoints = []discovery.Endpoint{{
  2963  			Addresses: []string{"1.1.1.3"},
  2964  		}, {
  2965  			Addresses: []string{"1.1.1.4"},
  2966  			NodeName:  ptr.To(testHostname),
  2967  		}}
  2968  		eps.Ports = []discovery.EndpointPort{{
  2969  			Name:     ptr.To("p13"),
  2970  			Port:     ptr.To[int32](13),
  2971  			Protocol: ptr.To(v1.ProtocolUDP),
  2972  		}, {
  2973  			Name:     ptr.To("p14"),
  2974  			Port:     ptr.To[int32](14),
  2975  			Protocol: ptr.To(v1.ProtocolUDP),
  2976  		}}
  2977  	}
  2978  	subsetMultipleIPsPorts3 := func(eps *discovery.EndpointSlice) {
  2979  		eps.AddressType = discovery.AddressTypeIPv4
  2980  		eps.Endpoints = []discovery.Endpoint{{
  2981  			Addresses: []string{"2.2.2.1"},
  2982  		}, {
  2983  			Addresses: []string{"2.2.2.2"},
  2984  			NodeName:  ptr.To(testHostname),
  2985  		}}
  2986  		eps.Ports = []discovery.EndpointPort{{
  2987  			Name:     ptr.To("p21"),
  2988  			Port:     ptr.To[int32](21),
  2989  			Protocol: ptr.To(v1.ProtocolUDP),
  2990  		}, {
  2991  			Name:     ptr.To("p22"),
  2992  			Port:     ptr.To[int32](22),
  2993  			Protocol: ptr.To(v1.ProtocolUDP),
  2994  		}}
  2995  	}
  2996  	multipleSubsetsIPsPorts := []*discovery.EndpointSlice{
  2997  		makeTestEndpointSlice("ns1", "ep1", 1, subsetMultipleIPsPorts1),
  2998  		makeTestEndpointSlice("ns1", "ep1", 2, subsetMultipleIPsPorts2),
  2999  		makeTestEndpointSlice("ns2", "ep2", 1, subsetMultipleIPsPorts3),
  3000  	}
  3001  	complexSubset1 := func(eps *discovery.EndpointSlice) {
  3002  		eps.AddressType = discovery.AddressTypeIPv4
  3003  		eps.Endpoints = []discovery.Endpoint{{
  3004  			Addresses: []string{"2.2.2.2"},
  3005  			NodeName:  ptr.To(testHostname),
  3006  		}, {
  3007  			Addresses: []string{"2.2.2.22"},
  3008  			NodeName:  ptr.To(testHostname),
  3009  		}}
  3010  		eps.Ports = []discovery.EndpointPort{{
  3011  			Name:     ptr.To("p22"),
  3012  			Port:     ptr.To[int32](22),
  3013  			Protocol: ptr.To(v1.ProtocolUDP),
  3014  		}}
  3015  	}
  3016  	complexSubset2 := func(eps *discovery.EndpointSlice) {
  3017  		eps.AddressType = discovery.AddressTypeIPv4
  3018  		eps.Endpoints = []discovery.Endpoint{{
  3019  			Addresses: []string{"2.2.2.3"},
  3020  			NodeName:  ptr.To(testHostname),
  3021  		}}
  3022  		eps.Ports = []discovery.EndpointPort{{
  3023  			Name:     ptr.To("p23"),
  3024  			Port:     ptr.To[int32](23),
  3025  			Protocol: ptr.To(v1.ProtocolUDP),
  3026  		}}
  3027  	}
  3028  	complexSubset3 := func(eps *discovery.EndpointSlice) {
  3029  		eps.AddressType = discovery.AddressTypeIPv4
  3030  		eps.Endpoints = []discovery.Endpoint{{
  3031  			Addresses: []string{"4.4.4.4"},
  3032  			NodeName:  ptr.To(testHostname),
  3033  		}, {
  3034  			Addresses: []string{"4.4.4.5"},
  3035  			NodeName:  ptr.To(testHostname),
  3036  		}}
  3037  		eps.Ports = []discovery.EndpointPort{{
  3038  			Name:     ptr.To("p44"),
  3039  			Port:     ptr.To[int32](44),
  3040  			Protocol: ptr.To(v1.ProtocolUDP),
  3041  		}}
  3042  	}
  3043  	complexSubset4 := func(eps *discovery.EndpointSlice) {
  3044  		eps.AddressType = discovery.AddressTypeIPv4
  3045  		eps.Endpoints = []discovery.Endpoint{{
  3046  			Addresses: []string{"4.4.4.6"},
  3047  			NodeName:  ptr.To(testHostname),
  3048  		}}
  3049  		eps.Ports = []discovery.EndpointPort{{
  3050  			Name:     ptr.To("p45"),
  3051  			Port:     ptr.To[int32](45),
  3052  			Protocol: ptr.To(v1.ProtocolUDP),
  3053  		}}
  3054  	}
  3055  	complexSubset5 := func(eps *discovery.EndpointSlice) {
  3056  		eps.AddressType = discovery.AddressTypeIPv4
  3057  		eps.Endpoints = []discovery.Endpoint{{
  3058  			Addresses: []string{"1.1.1.1"},
  3059  		}, {
  3060  			Addresses: []string{"1.1.1.11"},
  3061  		}}
  3062  		eps.Ports = []discovery.EndpointPort{{
  3063  			Name:     ptr.To("p11"),
  3064  			Port:     ptr.To[int32](11),
  3065  			Protocol: ptr.To(v1.ProtocolUDP),
  3066  		}}
  3067  	}
  3068  	complexSubset6 := func(eps *discovery.EndpointSlice) {
  3069  		eps.AddressType = discovery.AddressTypeIPv4
  3070  		eps.Endpoints = []discovery.Endpoint{{
  3071  			Addresses: []string{"1.1.1.2"},
  3072  		}}
  3073  		eps.Ports = []discovery.EndpointPort{{
  3074  			Name:     ptr.To("p12"),
  3075  			Port:     ptr.To[int32](12),
  3076  			Protocol: ptr.To(v1.ProtocolUDP),
  3077  		}, {
  3078  			Name:     ptr.To("p122"),
  3079  			Port:     ptr.To[int32](122),
  3080  			Protocol: ptr.To(v1.ProtocolUDP),
  3081  		}}
  3082  	}
  3083  	complexSubset7 := func(eps *discovery.EndpointSlice) {
  3084  		eps.AddressType = discovery.AddressTypeIPv4
  3085  		eps.Endpoints = []discovery.Endpoint{{
  3086  			Addresses: []string{"3.3.3.3"},
  3087  		}}
  3088  		eps.Ports = []discovery.EndpointPort{{
  3089  			Name:     ptr.To("p33"),
  3090  			Port:     ptr.To[int32](33),
  3091  			Protocol: ptr.To(v1.ProtocolUDP),
  3092  		}}
  3093  	}
  3094  	complexSubset8 := func(eps *discovery.EndpointSlice) {
  3095  		eps.AddressType = discovery.AddressTypeIPv4
  3096  		eps.Endpoints = []discovery.Endpoint{{
  3097  			Addresses: []string{"4.4.4.4"},
  3098  			NodeName:  ptr.To(testHostname),
  3099  		}}
  3100  		eps.Ports = []discovery.EndpointPort{{
  3101  			Name:     ptr.To("p44"),
  3102  			Port:     ptr.To[int32](44),
  3103  			Protocol: ptr.To(v1.ProtocolUDP),
  3104  		}}
  3105  	}
  3106  	complexBefore := []*discovery.EndpointSlice{
  3107  		makeTestEndpointSlice("ns1", "ep1", 1, subset1),
  3108  		nil,
  3109  		makeTestEndpointSlice("ns2", "ep2", 1, complexSubset1),
  3110  		makeTestEndpointSlice("ns2", "ep2", 2, complexSubset2),
  3111  		nil,
  3112  		makeTestEndpointSlice("ns4", "ep4", 1, complexSubset3),
  3113  		makeTestEndpointSlice("ns4", "ep4", 2, complexSubset4),
  3114  	}
  3115  	complexAfter := []*discovery.EndpointSlice{
  3116  		makeTestEndpointSlice("ns1", "ep1", 1, complexSubset5),
  3117  		makeTestEndpointSlice("ns1", "ep1", 2, complexSubset6),
  3118  		nil,
  3119  		nil,
  3120  		makeTestEndpointSlice("ns3", "ep3", 1, complexSubset7),
  3121  		makeTestEndpointSlice("ns4", "ep4", 1, complexSubset8),
  3122  		nil,
  3123  	}
  3124  
  3125  	testCases := []struct {
  3126  		// previousEndpoints and currentEndpoints are used to call appropriate
  3127  		// handlers OnEndpoints* (based on whether corresponding values are nil
  3128  		// or non-nil) and must be of equal length.
  3129  		name                           string
  3130  		previousEndpoints              []*discovery.EndpointSlice
  3131  		currentEndpoints               []*discovery.EndpointSlice
  3132  		oldEndpoints                   map[proxy.ServicePortName][]endpointExpectation
  3133  		expectedResult                 map[proxy.ServicePortName][]endpointExpectation
  3134  		expectedDeletedUDPEndpoints    []proxy.ServiceEndpoint
  3135  		expectedNewlyActiveUDPServices map[proxy.ServicePortName]bool
  3136  		expectedReadyEndpoints         map[types.NamespacedName]int
  3137  	}{{
  3138  		// Case[0]: nothing
  3139  		name:                           "nothing",
  3140  		oldEndpoints:                   map[proxy.ServicePortName][]endpointExpectation{},
  3141  		expectedResult:                 map[proxy.ServicePortName][]endpointExpectation{},
  3142  		expectedDeletedUDPEndpoints:    []proxy.ServiceEndpoint{},
  3143  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{},
  3144  		expectedReadyEndpoints:         map[types.NamespacedName]int{},
  3145  	}, {
  3146  		// Case[1]: no change, named port, local
  3147  		name:              "no change, named port, local",
  3148  		previousEndpoints: namedPortLocal,
  3149  		currentEndpoints:  namedPortLocal,
  3150  		oldEndpoints: map[proxy.ServicePortName][]endpointExpectation{
  3151  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3152  				{endpoint: "1.1.1.1:11", isLocal: true},
  3153  			},
  3154  		},
  3155  		expectedResult: map[proxy.ServicePortName][]endpointExpectation{
  3156  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3157  				{endpoint: "1.1.1.1:11", isLocal: true},
  3158  			},
  3159  		},
  3160  		expectedDeletedUDPEndpoints:    []proxy.ServiceEndpoint{},
  3161  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{},
  3162  		expectedReadyEndpoints: map[types.NamespacedName]int{
  3163  			makeNSN("ns1", "ep1"): 1,
  3164  		},
  3165  	}, {
  3166  		// Case[2]: no change, multiple subsets
  3167  		name:              "no change, multiple subsets",
  3168  		previousEndpoints: multipleSubsets,
  3169  		currentEndpoints:  multipleSubsets,
  3170  		oldEndpoints: map[proxy.ServicePortName][]endpointExpectation{
  3171  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3172  				{endpoint: "1.1.1.1:11", isLocal: false},
  3173  			},
  3174  			makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  3175  				{endpoint: "1.1.1.2:12", isLocal: false},
  3176  			},
  3177  		},
  3178  		expectedResult: map[proxy.ServicePortName][]endpointExpectation{
  3179  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3180  				{endpoint: "1.1.1.1:11", isLocal: false},
  3181  			},
  3182  			makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  3183  				{endpoint: "1.1.1.2:12", isLocal: false},
  3184  			},
  3185  		},
  3186  		expectedDeletedUDPEndpoints:    []proxy.ServiceEndpoint{},
  3187  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{},
  3188  		expectedReadyEndpoints:         map[types.NamespacedName]int{},
  3189  	}, {
  3190  		// Case[3]: no change, multiple subsets, multiple ports, local
  3191  		name:              "no change, multiple subsets, multiple ports, local",
  3192  		previousEndpoints: multipleSubsetsMultiplePortsLocal,
  3193  		currentEndpoints:  multipleSubsetsMultiplePortsLocal,
  3194  		oldEndpoints: map[proxy.ServicePortName][]endpointExpectation{
  3195  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3196  				{endpoint: "1.1.1.1:11", isLocal: true},
  3197  			},
  3198  			makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  3199  				{endpoint: "1.1.1.1:12", isLocal: true},
  3200  			},
  3201  			makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): {
  3202  				{endpoint: "1.1.1.3:13", isLocal: false},
  3203  			},
  3204  		},
  3205  		expectedResult: map[proxy.ServicePortName][]endpointExpectation{
  3206  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3207  				{endpoint: "1.1.1.1:11", isLocal: true},
  3208  			},
  3209  			makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  3210  				{endpoint: "1.1.1.1:12", isLocal: true},
  3211  			},
  3212  			makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): {
  3213  				{endpoint: "1.1.1.3:13", isLocal: false},
  3214  			},
  3215  		},
  3216  		expectedDeletedUDPEndpoints:    []proxy.ServiceEndpoint{},
  3217  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{},
  3218  		expectedReadyEndpoints: map[types.NamespacedName]int{
  3219  			makeNSN("ns1", "ep1"): 1,
  3220  		},
  3221  	}, {
  3222  		// Case[4]: no change, multiple endpoints, subsets, IPs, and ports
  3223  		name:              "no change, multiple endpoints, subsets, IPs, and ports",
  3224  		previousEndpoints: multipleSubsetsIPsPorts,
  3225  		currentEndpoints:  multipleSubsetsIPsPorts,
  3226  		oldEndpoints: map[proxy.ServicePortName][]endpointExpectation{
  3227  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3228  				{endpoint: "1.1.1.1:11", isLocal: false},
  3229  				{endpoint: "1.1.1.2:11", isLocal: true},
  3230  			},
  3231  			makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  3232  				{endpoint: "1.1.1.1:12", isLocal: false},
  3233  				{endpoint: "1.1.1.2:12", isLocal: true},
  3234  			},
  3235  			makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): {
  3236  				{endpoint: "1.1.1.3:13", isLocal: false},
  3237  				{endpoint: "1.1.1.4:13", isLocal: true},
  3238  			},
  3239  			makeServicePortName("ns1", "ep1", "p14", v1.ProtocolUDP): {
  3240  				{endpoint: "1.1.1.3:14", isLocal: false},
  3241  				{endpoint: "1.1.1.4:14", isLocal: true},
  3242  			},
  3243  			makeServicePortName("ns2", "ep2", "p21", v1.ProtocolUDP): {
  3244  				{endpoint: "2.2.2.1:21", isLocal: false},
  3245  				{endpoint: "2.2.2.2:21", isLocal: true},
  3246  			},
  3247  			makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): {
  3248  				{endpoint: "2.2.2.1:22", isLocal: false},
  3249  				{endpoint: "2.2.2.2:22", isLocal: true},
  3250  			},
  3251  		},
  3252  		expectedResult: map[proxy.ServicePortName][]endpointExpectation{
  3253  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3254  				{endpoint: "1.1.1.1:11", isLocal: false},
  3255  				{endpoint: "1.1.1.2:11", isLocal: true},
  3256  			},
  3257  			makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  3258  				{endpoint: "1.1.1.1:12", isLocal: false},
  3259  				{endpoint: "1.1.1.2:12", isLocal: true},
  3260  			},
  3261  			makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): {
  3262  				{endpoint: "1.1.1.3:13", isLocal: false},
  3263  				{endpoint: "1.1.1.4:13", isLocal: true},
  3264  			},
  3265  			makeServicePortName("ns1", "ep1", "p14", v1.ProtocolUDP): {
  3266  				{endpoint: "1.1.1.3:14", isLocal: false},
  3267  				{endpoint: "1.1.1.4:14", isLocal: true},
  3268  			},
  3269  			makeServicePortName("ns2", "ep2", "p21", v1.ProtocolUDP): {
  3270  				{endpoint: "2.2.2.1:21", isLocal: false},
  3271  				{endpoint: "2.2.2.2:21", isLocal: true},
  3272  			},
  3273  			makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): {
  3274  				{endpoint: "2.2.2.1:22", isLocal: false},
  3275  				{endpoint: "2.2.2.2:22", isLocal: true},
  3276  			},
  3277  		},
  3278  		expectedDeletedUDPEndpoints:    []proxy.ServiceEndpoint{},
  3279  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{},
  3280  		expectedReadyEndpoints: map[types.NamespacedName]int{
  3281  			makeNSN("ns1", "ep1"): 2,
  3282  			makeNSN("ns2", "ep2"): 1,
  3283  		},
  3284  	}, {
  3285  		// Case[5]: add an Endpoints
  3286  		name:              "add an Endpoints",
  3287  		previousEndpoints: []*discovery.EndpointSlice{nil},
  3288  		currentEndpoints:  namedPortLocal,
  3289  		oldEndpoints:      map[proxy.ServicePortName][]endpointExpectation{},
  3290  		expectedResult: map[proxy.ServicePortName][]endpointExpectation{
  3291  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3292  				{endpoint: "1.1.1.1:11", isLocal: true},
  3293  			},
  3294  		},
  3295  		expectedDeletedUDPEndpoints: []proxy.ServiceEndpoint{},
  3296  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{
  3297  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): true,
  3298  		},
  3299  		expectedReadyEndpoints: map[types.NamespacedName]int{
  3300  			makeNSN("ns1", "ep1"): 1,
  3301  		},
  3302  	}, {
  3303  		// Case[6]: remove an Endpoints
  3304  		name:              "remove an Endpoints",
  3305  		previousEndpoints: namedPortLocal,
  3306  		currentEndpoints:  []*discovery.EndpointSlice{nil},
  3307  		oldEndpoints: map[proxy.ServicePortName][]endpointExpectation{
  3308  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3309  				{endpoint: "1.1.1.1:11", isLocal: true},
  3310  			},
  3311  		},
  3312  		expectedResult: map[proxy.ServicePortName][]endpointExpectation{},
  3313  		expectedDeletedUDPEndpoints: []proxy.ServiceEndpoint{{
  3314  			Endpoint:        "1.1.1.1:11",
  3315  			ServicePortName: makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP),
  3316  		}},
  3317  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{},
  3318  		expectedReadyEndpoints:         map[types.NamespacedName]int{},
  3319  	}, {
  3320  		// Case[7]: add an IP and port
  3321  		name:              "add an IP and port",
  3322  		previousEndpoints: namedPort,
  3323  		currentEndpoints:  namedPortsLocalNoLocal,
  3324  		oldEndpoints: map[proxy.ServicePortName][]endpointExpectation{
  3325  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3326  				{endpoint: "1.1.1.1:11", isLocal: false},
  3327  			},
  3328  		},
  3329  		expectedResult: map[proxy.ServicePortName][]endpointExpectation{
  3330  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3331  				{endpoint: "1.1.1.1:11", isLocal: false},
  3332  				{endpoint: "1.1.1.2:11", isLocal: true},
  3333  			},
  3334  			makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  3335  				{endpoint: "1.1.1.1:12", isLocal: false},
  3336  				{endpoint: "1.1.1.2:12", isLocal: true},
  3337  			},
  3338  		},
  3339  		expectedDeletedUDPEndpoints: []proxy.ServiceEndpoint{},
  3340  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{
  3341  			makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): true,
  3342  		},
  3343  		expectedReadyEndpoints: map[types.NamespacedName]int{
  3344  			makeNSN("ns1", "ep1"): 1,
  3345  		},
  3346  	}, {
  3347  		// Case[8]: remove an IP and port
  3348  		name:              "remove an IP and port",
  3349  		previousEndpoints: namedPortsLocalNoLocal,
  3350  		currentEndpoints:  namedPort,
  3351  		oldEndpoints: map[proxy.ServicePortName][]endpointExpectation{
  3352  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3353  				{endpoint: "1.1.1.1:11", isLocal: false},
  3354  				{endpoint: "1.1.1.2:11", isLocal: true},
  3355  			},
  3356  			makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  3357  				{endpoint: "1.1.1.1:12", isLocal: false},
  3358  				{endpoint: "1.1.1.2:12", isLocal: true},
  3359  			},
  3360  		},
  3361  		expectedResult: map[proxy.ServicePortName][]endpointExpectation{
  3362  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3363  				{endpoint: "1.1.1.1:11", isLocal: false},
  3364  			},
  3365  		},
  3366  		expectedDeletedUDPEndpoints: []proxy.ServiceEndpoint{{
  3367  			Endpoint:        "1.1.1.2:11",
  3368  			ServicePortName: makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP),
  3369  		}, {
  3370  			Endpoint:        "1.1.1.1:12",
  3371  			ServicePortName: makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP),
  3372  		}, {
  3373  			Endpoint:        "1.1.1.2:12",
  3374  			ServicePortName: makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP),
  3375  		}},
  3376  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{},
  3377  		expectedReadyEndpoints:         map[types.NamespacedName]int{},
  3378  	}, {
  3379  		// Case[9]: add a subset
  3380  		name:              "add a subset",
  3381  		previousEndpoints: []*discovery.EndpointSlice{namedPort[0], nil},
  3382  		currentEndpoints:  multipleSubsetsWithLocal,
  3383  		oldEndpoints: map[proxy.ServicePortName][]endpointExpectation{
  3384  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3385  				{endpoint: "1.1.1.1:11", isLocal: false},
  3386  			},
  3387  		},
  3388  		expectedResult: map[proxy.ServicePortName][]endpointExpectation{
  3389  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3390  				{endpoint: "1.1.1.1:11", isLocal: false},
  3391  			},
  3392  			makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  3393  				{endpoint: "1.1.1.2:12", isLocal: true},
  3394  			},
  3395  		},
  3396  		expectedDeletedUDPEndpoints: []proxy.ServiceEndpoint{},
  3397  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{
  3398  			makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): true,
  3399  		},
  3400  		expectedReadyEndpoints: map[types.NamespacedName]int{
  3401  			makeNSN("ns1", "ep1"): 1,
  3402  		},
  3403  	}, {
  3404  		// Case[10]: remove a subset
  3405  		name:              "remove a subset",
  3406  		previousEndpoints: multipleSubsets,
  3407  		currentEndpoints:  []*discovery.EndpointSlice{namedPort[0], nil},
  3408  		oldEndpoints: map[proxy.ServicePortName][]endpointExpectation{
  3409  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3410  				{endpoint: "1.1.1.1:11", isLocal: false},
  3411  			},
  3412  			makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  3413  				{endpoint: "1.1.1.2:12", isLocal: false},
  3414  			},
  3415  		},
  3416  		expectedResult: map[proxy.ServicePortName][]endpointExpectation{
  3417  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3418  				{endpoint: "1.1.1.1:11", isLocal: false},
  3419  			},
  3420  		},
  3421  		expectedDeletedUDPEndpoints: []proxy.ServiceEndpoint{{
  3422  			Endpoint:        "1.1.1.2:12",
  3423  			ServicePortName: makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP),
  3424  		}},
  3425  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{},
  3426  		expectedReadyEndpoints:         map[types.NamespacedName]int{},
  3427  	}, {
  3428  		// Case[11]: rename a port
  3429  		name:              "rename a port",
  3430  		previousEndpoints: namedPort,
  3431  		currentEndpoints:  namedPortRenamed,
  3432  		oldEndpoints: map[proxy.ServicePortName][]endpointExpectation{
  3433  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3434  				{endpoint: "1.1.1.1:11", isLocal: false},
  3435  			},
  3436  		},
  3437  		expectedResult: map[proxy.ServicePortName][]endpointExpectation{
  3438  			makeServicePortName("ns1", "ep1", "p11-2", v1.ProtocolUDP): {
  3439  				{endpoint: "1.1.1.1:11", isLocal: false},
  3440  			},
  3441  		},
  3442  		expectedDeletedUDPEndpoints: []proxy.ServiceEndpoint{{
  3443  			Endpoint:        "1.1.1.1:11",
  3444  			ServicePortName: makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP),
  3445  		}},
  3446  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{
  3447  			makeServicePortName("ns1", "ep1", "p11-2", v1.ProtocolUDP): true,
  3448  		},
  3449  		expectedReadyEndpoints: map[types.NamespacedName]int{},
  3450  	}, {
  3451  		// Case[12]: renumber a port
  3452  		name:              "renumber a port",
  3453  		previousEndpoints: namedPort,
  3454  		currentEndpoints:  namedPortRenumbered,
  3455  		oldEndpoints: map[proxy.ServicePortName][]endpointExpectation{
  3456  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3457  				{endpoint: "1.1.1.1:11", isLocal: false},
  3458  			},
  3459  		},
  3460  		expectedResult: map[proxy.ServicePortName][]endpointExpectation{
  3461  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3462  				{endpoint: "1.1.1.1:22", isLocal: false},
  3463  			},
  3464  		},
  3465  		expectedDeletedUDPEndpoints: []proxy.ServiceEndpoint{{
  3466  			Endpoint:        "1.1.1.1:11",
  3467  			ServicePortName: makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP),
  3468  		}},
  3469  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{},
  3470  		expectedReadyEndpoints:         map[types.NamespacedName]int{},
  3471  	}, {
  3472  		// Case[13]: complex add and remove
  3473  		name:              "complex add and remove",
  3474  		previousEndpoints: complexBefore,
  3475  		currentEndpoints:  complexAfter,
  3476  		oldEndpoints: map[proxy.ServicePortName][]endpointExpectation{
  3477  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3478  				{endpoint: "1.1.1.1:11", isLocal: false},
  3479  			},
  3480  			makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): {
  3481  				{endpoint: "2.2.2.22:22", isLocal: true},
  3482  				{endpoint: "2.2.2.2:22", isLocal: true},
  3483  			},
  3484  			makeServicePortName("ns2", "ep2", "p23", v1.ProtocolUDP): {
  3485  				{endpoint: "2.2.2.3:23", isLocal: true},
  3486  			},
  3487  			makeServicePortName("ns4", "ep4", "p44", v1.ProtocolUDP): {
  3488  				{endpoint: "4.4.4.4:44", isLocal: true},
  3489  				{endpoint: "4.4.4.5:44", isLocal: true},
  3490  			},
  3491  			makeServicePortName("ns4", "ep4", "p45", v1.ProtocolUDP): {
  3492  				{endpoint: "4.4.4.6:45", isLocal: true},
  3493  			},
  3494  		},
  3495  		expectedResult: map[proxy.ServicePortName][]endpointExpectation{
  3496  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3497  				{endpoint: "1.1.1.11:11", isLocal: false},
  3498  				{endpoint: "1.1.1.1:11", isLocal: false},
  3499  			},
  3500  			makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  3501  				{endpoint: "1.1.1.2:12", isLocal: false},
  3502  			},
  3503  			makeServicePortName("ns1", "ep1", "p122", v1.ProtocolUDP): {
  3504  				{endpoint: "1.1.1.2:122", isLocal: false},
  3505  			},
  3506  			makeServicePortName("ns3", "ep3", "p33", v1.ProtocolUDP): {
  3507  				{endpoint: "3.3.3.3:33", isLocal: false},
  3508  			},
  3509  			makeServicePortName("ns4", "ep4", "p44", v1.ProtocolUDP): {
  3510  				{endpoint: "4.4.4.4:44", isLocal: true},
  3511  			},
  3512  		},
  3513  		expectedDeletedUDPEndpoints: []proxy.ServiceEndpoint{{
  3514  			Endpoint:        "2.2.2.2:22",
  3515  			ServicePortName: makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP),
  3516  		}, {
  3517  			Endpoint:        "2.2.2.22:22",
  3518  			ServicePortName: makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP),
  3519  		}, {
  3520  			Endpoint:        "2.2.2.3:23",
  3521  			ServicePortName: makeServicePortName("ns2", "ep2", "p23", v1.ProtocolUDP),
  3522  		}, {
  3523  			Endpoint:        "4.4.4.5:44",
  3524  			ServicePortName: makeServicePortName("ns4", "ep4", "p44", v1.ProtocolUDP),
  3525  		}, {
  3526  			Endpoint:        "4.4.4.6:45",
  3527  			ServicePortName: makeServicePortName("ns4", "ep4", "p45", v1.ProtocolUDP),
  3528  		}},
  3529  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{
  3530  			makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP):  true,
  3531  			makeServicePortName("ns1", "ep1", "p122", v1.ProtocolUDP): true,
  3532  			makeServicePortName("ns3", "ep3", "p33", v1.ProtocolUDP):  true,
  3533  		},
  3534  		expectedReadyEndpoints: map[types.NamespacedName]int{
  3535  			makeNSN("ns4", "ep4"): 1,
  3536  		},
  3537  	}, {
  3538  		// Case[14]: change from 0 endpoint address to 1 named port
  3539  		name:              "change from 0 endpoint address to 1 named port",
  3540  		previousEndpoints: emptyEndpointSlices,
  3541  		currentEndpoints:  namedPort,
  3542  		oldEndpoints:      map[proxy.ServicePortName][]endpointExpectation{},
  3543  		expectedResult: map[proxy.ServicePortName][]endpointExpectation{
  3544  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  3545  				{endpoint: "1.1.1.1:11", isLocal: false},
  3546  			},
  3547  		},
  3548  		expectedDeletedUDPEndpoints: []proxy.ServiceEndpoint{},
  3549  		expectedNewlyActiveUDPServices: map[proxy.ServicePortName]bool{
  3550  			makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): true,
  3551  		},
  3552  		expectedReadyEndpoints: map[types.NamespacedName]int{},
  3553  	},
  3554  	}
  3555  
  3556  	for tci, tc := range testCases {
  3557  		t.Run(tc.name, func(t *testing.T) {
  3558  			_, ctx := ktesting.NewTestContext(t)
  3559  			ipt := iptablestest.NewFake()
  3560  			ipvs := ipvstest.NewFake()
  3561  			ipset := ipsettest.NewFake(testIPSetVersion)
  3562  			fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  3563  			fp.hostname = testHostname
  3564  
  3565  			// First check that after adding all previous versions of endpoints,
  3566  			// the fp.oldEndpoints is as we expect.
  3567  			for i := range tc.previousEndpoints {
  3568  				if tc.previousEndpoints[i] != nil {
  3569  					fp.OnEndpointSliceAdd(tc.previousEndpoints[i])
  3570  				}
  3571  			}
  3572  			fp.endpointsMap.Update(fp.endpointsChanges)
  3573  			checkEndpointExpectations(t, tci, fp.endpointsMap, tc.oldEndpoints)
  3574  
  3575  			// Now let's call appropriate handlers to get to state we want to be.
  3576  			if len(tc.previousEndpoints) != len(tc.currentEndpoints) {
  3577  				t.Fatalf("[%d] different lengths of previous and current endpoints", tci)
  3578  			}
  3579  
  3580  			for i := range tc.previousEndpoints {
  3581  				prev, curr := tc.previousEndpoints[i], tc.currentEndpoints[i]
  3582  				switch {
  3583  				case prev == nil:
  3584  					fp.OnEndpointSliceAdd(curr)
  3585  				case curr == nil:
  3586  					fp.OnEndpointSliceDelete(prev)
  3587  				default:
  3588  					fp.OnEndpointSliceUpdate(prev, curr)
  3589  				}
  3590  			}
  3591  			result := fp.endpointsMap.Update(fp.endpointsChanges)
  3592  			newMap := fp.endpointsMap
  3593  			checkEndpointExpectations(t, tci, newMap, tc.expectedResult)
  3594  			if len(result.DeletedUDPEndpoints) != len(tc.expectedDeletedUDPEndpoints) {
  3595  				t.Errorf("[%d] expected %d staleEndpoints, got %d: %v", tci, len(tc.expectedDeletedUDPEndpoints), len(result.DeletedUDPEndpoints), result.DeletedUDPEndpoints)
  3596  			}
  3597  			for _, x := range tc.expectedDeletedUDPEndpoints {
  3598  				found := false
  3599  				for _, stale := range result.DeletedUDPEndpoints {
  3600  					if stale == x {
  3601  						found = true
  3602  						break
  3603  					}
  3604  				}
  3605  				if !found {
  3606  					t.Errorf("[%d] expected staleEndpoints[%v], but didn't find it: %v", tci, x, result.DeletedUDPEndpoints)
  3607  				}
  3608  			}
  3609  			if len(result.NewlyActiveUDPServices) != len(tc.expectedNewlyActiveUDPServices) {
  3610  				t.Errorf("[%d] expected %d staleServiceNames, got %d: %v", tci, len(tc.expectedNewlyActiveUDPServices), len(result.NewlyActiveUDPServices), result.NewlyActiveUDPServices)
  3611  			}
  3612  			for svcName := range tc.expectedNewlyActiveUDPServices {
  3613  				found := false
  3614  				for _, stale := range result.NewlyActiveUDPServices {
  3615  					if stale == svcName {
  3616  						found = true
  3617  						break
  3618  					}
  3619  				}
  3620  				if !found {
  3621  					t.Errorf("[%d] expected staleServiceNames[%v], but didn't find it: %v", tci, svcName, result.NewlyActiveUDPServices)
  3622  				}
  3623  			}
  3624  			localReadyEndpoints := fp.endpointsMap.LocalReadyEndpoints()
  3625  			if !reflect.DeepEqual(localReadyEndpoints, tc.expectedReadyEndpoints) {
  3626  				t.Errorf("[%d] expected healthchecks %v, got %v", tci, tc.expectedReadyEndpoints, localReadyEndpoints)
  3627  			}
  3628  		})
  3629  	}
  3630  }
  3631  
  3632  type endpointExpectation struct {
  3633  	endpoint string
  3634  	isLocal  bool
  3635  }
  3636  
  3637  func checkEndpointExpectations(t *testing.T, tci int, newMap proxy.EndpointsMap, expected map[proxy.ServicePortName][]endpointExpectation) {
  3638  	if len(newMap) != len(expected) {
  3639  		t.Errorf("[%d] expected %d results, got %d: %v", tci, len(expected), len(newMap), newMap)
  3640  	}
  3641  	for x := range expected {
  3642  		if len(newMap[x]) != len(expected[x]) {
  3643  			t.Errorf("[%d] expected %d endpoints for %v, got %d", tci, len(expected[x]), x, len(newMap[x]))
  3644  		} else {
  3645  			for i := range expected[x] {
  3646  				newEp := newMap[x][i]
  3647  				if newEp.String() != expected[x][i].endpoint ||
  3648  					newEp.IsLocal() != expected[x][i].isLocal {
  3649  					t.Errorf("[%d] expected new[%v][%d] to be %v, got %v", tci, x, i, expected[x][i], newEp)
  3650  				}
  3651  			}
  3652  		}
  3653  	}
  3654  }
  3655  
  3656  func Test_syncService(t *testing.T) {
  3657  	testCases := []struct {
  3658  		oldVirtualServer  *utilipvs.VirtualServer
  3659  		svcName           string
  3660  		newVirtualServer  *utilipvs.VirtualServer
  3661  		bindAddr          bool
  3662  		alreadyBoundAddrs sets.Set[string]
  3663  	}{
  3664  		{
  3665  			// case 0, old virtual server is same as new virtual server
  3666  			oldVirtualServer: &utilipvs.VirtualServer{
  3667  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3668  				Protocol:  string(v1.ProtocolTCP),
  3669  				Port:      80,
  3670  				Scheduler: "rr",
  3671  				Flags:     utilipvs.FlagHashed,
  3672  			},
  3673  			svcName: "foo",
  3674  			newVirtualServer: &utilipvs.VirtualServer{
  3675  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3676  				Protocol:  string(v1.ProtocolTCP),
  3677  				Port:      80,
  3678  				Scheduler: "rr",
  3679  				Flags:     utilipvs.FlagHashed,
  3680  			},
  3681  			bindAddr:          false,
  3682  			alreadyBoundAddrs: nil,
  3683  		},
  3684  		{
  3685  			// case 1, old virtual server is different from new virtual server
  3686  			oldVirtualServer: &utilipvs.VirtualServer{
  3687  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3688  				Protocol:  string(v1.ProtocolTCP),
  3689  				Port:      8080,
  3690  				Scheduler: "rr",
  3691  				Flags:     utilipvs.FlagHashed,
  3692  			},
  3693  			svcName: "bar",
  3694  			newVirtualServer: &utilipvs.VirtualServer{
  3695  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3696  				Protocol:  string(v1.ProtocolTCP),
  3697  				Port:      8080,
  3698  				Scheduler: "rr",
  3699  				Flags:     utilipvs.FlagPersistent,
  3700  			},
  3701  			bindAddr:          false,
  3702  			alreadyBoundAddrs: nil,
  3703  		},
  3704  		{
  3705  			// case 2, old virtual server is different from new virtual server
  3706  			oldVirtualServer: &utilipvs.VirtualServer{
  3707  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3708  				Protocol:  string(v1.ProtocolTCP),
  3709  				Port:      8080,
  3710  				Scheduler: "rr",
  3711  				Flags:     utilipvs.FlagHashed,
  3712  			},
  3713  			svcName: "bar",
  3714  			newVirtualServer: &utilipvs.VirtualServer{
  3715  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3716  				Protocol:  string(v1.ProtocolTCP),
  3717  				Port:      8080,
  3718  				Scheduler: "wlc",
  3719  				Flags:     utilipvs.FlagHashed,
  3720  			},
  3721  			bindAddr:          false,
  3722  			alreadyBoundAddrs: nil,
  3723  		},
  3724  		{
  3725  			// case 3, old virtual server is nil, and create new virtual server
  3726  			oldVirtualServer: nil,
  3727  			svcName:          "baz",
  3728  			newVirtualServer: &utilipvs.VirtualServer{
  3729  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3730  				Protocol:  string(v1.ProtocolUDP),
  3731  				Port:      53,
  3732  				Scheduler: "rr",
  3733  				Flags:     utilipvs.FlagHashed,
  3734  			},
  3735  			bindAddr:          true,
  3736  			alreadyBoundAddrs: nil,
  3737  		},
  3738  		{
  3739  			// case 4, SCTP, old virtual server is same as new virtual server
  3740  			oldVirtualServer: &utilipvs.VirtualServer{
  3741  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3742  				Protocol:  string(v1.ProtocolSCTP),
  3743  				Port:      80,
  3744  				Scheduler: "rr",
  3745  				Flags:     utilipvs.FlagHashed,
  3746  			},
  3747  			svcName: "foo",
  3748  			newVirtualServer: &utilipvs.VirtualServer{
  3749  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3750  				Protocol:  string(v1.ProtocolSCTP),
  3751  				Port:      80,
  3752  				Scheduler: "rr",
  3753  				Flags:     utilipvs.FlagHashed,
  3754  			},
  3755  			bindAddr:          false,
  3756  			alreadyBoundAddrs: nil,
  3757  		},
  3758  		{
  3759  			// case 5, old virtual server is different from new virtual server
  3760  			oldVirtualServer: &utilipvs.VirtualServer{
  3761  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3762  				Protocol:  string(v1.ProtocolSCTP),
  3763  				Port:      8080,
  3764  				Scheduler: "rr",
  3765  				Flags:     utilipvs.FlagHashed,
  3766  			},
  3767  			svcName: "bar",
  3768  			newVirtualServer: &utilipvs.VirtualServer{
  3769  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3770  				Protocol:  string(v1.ProtocolSCTP),
  3771  				Port:      8080,
  3772  				Scheduler: "rr",
  3773  				Flags:     utilipvs.FlagPersistent,
  3774  			},
  3775  			bindAddr:          false,
  3776  			alreadyBoundAddrs: nil,
  3777  		},
  3778  		{
  3779  			// case 6, old virtual server is different from new virtual server
  3780  			oldVirtualServer: &utilipvs.VirtualServer{
  3781  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3782  				Protocol:  string(v1.ProtocolSCTP),
  3783  				Port:      8080,
  3784  				Scheduler: "rr",
  3785  				Flags:     utilipvs.FlagHashed,
  3786  			},
  3787  			svcName: "bar",
  3788  			newVirtualServer: &utilipvs.VirtualServer{
  3789  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3790  				Protocol:  string(v1.ProtocolSCTP),
  3791  				Port:      8080,
  3792  				Scheduler: "wlc",
  3793  				Flags:     utilipvs.FlagHashed,
  3794  			},
  3795  			bindAddr:          false,
  3796  			alreadyBoundAddrs: nil,
  3797  		},
  3798  		{
  3799  			// case 7, old virtual server is nil, and create new virtual server
  3800  			oldVirtualServer: nil,
  3801  			svcName:          "baz",
  3802  			newVirtualServer: &utilipvs.VirtualServer{
  3803  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3804  				Protocol:  string(v1.ProtocolSCTP),
  3805  				Port:      53,
  3806  				Scheduler: "rr",
  3807  				Flags:     utilipvs.FlagHashed,
  3808  			},
  3809  			bindAddr:          true,
  3810  			alreadyBoundAddrs: sets.New[string](),
  3811  		},
  3812  		{
  3813  			// case 8, virtual server address already binded, skip sync
  3814  			oldVirtualServer: &utilipvs.VirtualServer{
  3815  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3816  				Protocol:  string(v1.ProtocolSCTP),
  3817  				Port:      53,
  3818  				Scheduler: "rr",
  3819  				Flags:     utilipvs.FlagHashed,
  3820  			},
  3821  			svcName: "baz",
  3822  			newVirtualServer: &utilipvs.VirtualServer{
  3823  				Address:   netutils.ParseIPSloppy("1.2.3.4"),
  3824  				Protocol:  string(v1.ProtocolSCTP),
  3825  				Port:      53,
  3826  				Scheduler: "rr",
  3827  				Flags:     utilipvs.FlagHashed,
  3828  			},
  3829  			bindAddr:          true,
  3830  			alreadyBoundAddrs: sets.New("1.2.3.4"),
  3831  		},
  3832  	}
  3833  
  3834  	for i := range testCases {
  3835  		_, ctx := ktesting.NewTestContext(t)
  3836  		ipt := iptablestest.NewFake()
  3837  		ipvs := ipvstest.NewFake()
  3838  		ipset := ipsettest.NewFake(testIPSetVersion)
  3839  		proxier := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  3840  
  3841  		proxier.netlinkHandle.EnsureDummyDevice(defaultDummyDevice)
  3842  		if testCases[i].oldVirtualServer != nil {
  3843  			if err := proxier.ipvs.AddVirtualServer(testCases[i].oldVirtualServer); err != nil {
  3844  				t.Errorf("Case [%d], unexpected add IPVS virtual server error: %v", i, err)
  3845  			}
  3846  		}
  3847  		if err := proxier.syncService(testCases[i].svcName, testCases[i].newVirtualServer, testCases[i].bindAddr, testCases[i].alreadyBoundAddrs); err != nil {
  3848  			t.Errorf("Case [%d], unexpected sync IPVS virtual server error: %v", i, err)
  3849  		}
  3850  		// check
  3851  		list, err := proxier.ipvs.GetVirtualServers()
  3852  		if err != nil {
  3853  			t.Errorf("Case [%d], unexpected list IPVS virtual server error: %v", i, err)
  3854  		}
  3855  		if len(list) != 1 {
  3856  			t.Errorf("Case [%d], expect %d virtual servers, got %d", i, 1, len(list))
  3857  			continue
  3858  		}
  3859  		if !list[0].Equal(testCases[i].newVirtualServer) {
  3860  			t.Errorf("Case [%d], unexpected mismatch, expect: %#v, got: %#v", i, testCases[i].newVirtualServer, list[0])
  3861  		}
  3862  	}
  3863  }
  3864  
  3865  func buildFakeProxier(t *testing.T) (*iptablestest.FakeIPTables, *Proxier) {
  3866  	_, ctx := ktesting.NewTestContext(t)
  3867  	ipt := iptablestest.NewFake()
  3868  	ipvs := ipvstest.NewFake()
  3869  	ipset := ipsettest.NewFake(testIPSetVersion)
  3870  	return ipt, NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  3871  }
  3872  
  3873  func getRules(ipt *iptablestest.FakeIPTables, chain utiliptables.Chain) []*iptablestest.Rule {
  3874  	var rules []*iptablestest.Rule
  3875  
  3876  	buf := bytes.NewBuffer(nil)
  3877  	_ = ipt.SaveInto(utiliptables.TableNAT, buf)
  3878  	_ = ipt.SaveInto(utiliptables.TableFilter, buf)
  3879  	lines := strings.Split(buf.String(), "\n")
  3880  	for _, l := range lines {
  3881  		if !strings.HasPrefix(l, "-A ") {
  3882  			continue
  3883  		}
  3884  		rule, _ := iptablestest.ParseRule(l, false)
  3885  		if rule != nil && rule.Chain == chain {
  3886  			rules = append(rules, rule)
  3887  		}
  3888  	}
  3889  	return rules
  3890  }
  3891  
  3892  // checkIptables to check expected iptables chain and rules. The got rules must have same number and order as the
  3893  // expected rules.
  3894  func checkIptables(t *testing.T, ipt *iptablestest.FakeIPTables, epIpt netlinktest.ExpectedIptablesChain) {
  3895  	for epChain, epRules := range epIpt {
  3896  		rules := getRules(ipt, utiliptables.Chain(epChain))
  3897  		if len(rules) != len(epRules) {
  3898  			t.Errorf("Expected %d iptables rule in chain %s, got %d", len(epRules), epChain, len(rules))
  3899  			continue
  3900  		}
  3901  		for i, epRule := range epRules {
  3902  			rule := rules[i]
  3903  			if rule.Jump == nil || rule.Jump.Value != epRule.JumpChain {
  3904  				t.Errorf("Expected MatchSet=%s JumpChain=%s, got %s", epRule.MatchSet, epRule.JumpChain, rule.Raw)
  3905  			}
  3906  			if (epRule.MatchSet == "" && rule.MatchSet != nil) || (epRule.MatchSet != "" && (rule.MatchSet == nil || rule.MatchSet.Value != epRule.MatchSet)) {
  3907  				t.Errorf("Expected MatchSet=%s JumpChain=%s, got %s", epRule.MatchSet, epRule.JumpChain, rule.Raw)
  3908  			}
  3909  		}
  3910  	}
  3911  }
  3912  
  3913  // checkIPSet to check expected ipset and entries
  3914  func checkIPSet(t *testing.T, fp *Proxier, ipSet netlinktest.ExpectedIPSet) {
  3915  	for set, entries := range ipSet {
  3916  		ents, err := fp.ipset.ListEntries(set)
  3917  		if err != nil || len(ents) != len(entries) {
  3918  			t.Errorf("Check ipset entries failed for ipset: %q, expect %d, got %d", set, len(entries), len(ents))
  3919  			continue
  3920  		}
  3921  		expectedEntries := []string{}
  3922  		for _, entry := range entries {
  3923  			expectedEntries = append(expectedEntries, entry.String())
  3924  		}
  3925  		sort.Strings(ents)
  3926  		sort.Strings(expectedEntries)
  3927  		if !reflect.DeepEqual(ents, expectedEntries) {
  3928  			t.Errorf("Check ipset entries failed for ipset: %q", set)
  3929  		}
  3930  	}
  3931  }
  3932  
  3933  // checkIPVS to check expected ipvs service and destination
  3934  func checkIPVS(t *testing.T, fp *Proxier, vs *netlinktest.ExpectedVirtualServer) {
  3935  	t.Helper()
  3936  	services, err := fp.ipvs.GetVirtualServers()
  3937  	if err != nil {
  3938  		t.Errorf("Failed to get ipvs services, err: %v", err)
  3939  	}
  3940  	if len(services) != vs.VSNum {
  3941  		t.Errorf("Expect %d ipvs services, got %d", vs.VSNum, len(services))
  3942  	}
  3943  	for _, svc := range services {
  3944  		if svc.Address.String() == vs.IP && svc.Port == vs.Port && svc.Protocol == vs.Protocol {
  3945  			destinations, _ := fp.ipvs.GetRealServers(svc)
  3946  			if len(destinations) != len(vs.RS) {
  3947  				t.Errorf("Expected %d destinations, got %d destinations", len(vs.RS), len(destinations))
  3948  			}
  3949  			if len(vs.RS) == 1 {
  3950  				if destinations[0].Address.String() != vs.RS[0].IP || destinations[0].Port != vs.RS[0].Port {
  3951  					t.Errorf("Unexpected mismatch destinations")
  3952  				}
  3953  			}
  3954  		}
  3955  	}
  3956  }
  3957  
  3958  func TestCleanLegacyService(t *testing.T) {
  3959  	_, ctx := ktesting.NewTestContext(t)
  3960  	ipt := iptablestest.NewFake()
  3961  	ipvs := ipvstest.NewFake()
  3962  	ipset := ipsettest.NewFake(testIPSetVersion)
  3963  	excludeCIDRs, _ := netutils.ParseCIDRs([]string{"3.3.3.0/24", "4.4.4.0/24"})
  3964  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, excludeCIDRs, v1.IPv4Protocol)
  3965  
  3966  	// All ipvs services that were processed in the latest sync loop.
  3967  	activeServices := sets.New("ipvs0", "ipvs1")
  3968  	// All ipvs services in the system.
  3969  	currentServices := map[string]*utilipvs.VirtualServer{
  3970  		// Created by kube-proxy.
  3971  		"ipvs0": {
  3972  			Address:   netutils.ParseIPSloppy("1.1.1.1"),
  3973  			Protocol:  string(v1.ProtocolUDP),
  3974  			Port:      53,
  3975  			Scheduler: "rr",
  3976  			Flags:     utilipvs.FlagHashed,
  3977  		},
  3978  		// Created by kube-proxy.
  3979  		"ipvs1": {
  3980  			Address:   netutils.ParseIPSloppy("2.2.2.2"),
  3981  			Protocol:  string(v1.ProtocolUDP),
  3982  			Port:      54,
  3983  			Scheduler: "rr",
  3984  			Flags:     utilipvs.FlagHashed,
  3985  		},
  3986  		// Created by an external party.
  3987  		"ipvs2": {
  3988  			Address:   netutils.ParseIPSloppy("3.3.3.3"),
  3989  			Protocol:  string(v1.ProtocolUDP),
  3990  			Port:      55,
  3991  			Scheduler: "rr",
  3992  			Flags:     utilipvs.FlagHashed,
  3993  		},
  3994  		// Created by an external party.
  3995  		"ipvs3": {
  3996  			Address:   netutils.ParseIPSloppy("4.4.4.4"),
  3997  			Protocol:  string(v1.ProtocolUDP),
  3998  			Port:      56,
  3999  			Scheduler: "rr",
  4000  			Flags:     utilipvs.FlagHashed,
  4001  		},
  4002  		// Created by an external party.
  4003  		"ipvs4": {
  4004  			Address:   netutils.ParseIPSloppy("5.5.5.5"),
  4005  			Protocol:  string(v1.ProtocolUDP),
  4006  			Port:      57,
  4007  			Scheduler: "rr",
  4008  			Flags:     utilipvs.FlagHashed,
  4009  		},
  4010  		// Created by kube-proxy, but now stale.
  4011  		"ipvs5": {
  4012  			Address:   netutils.ParseIPSloppy("6.6.6.6"),
  4013  			Protocol:  string(v1.ProtocolUDP),
  4014  			Port:      58,
  4015  			Scheduler: "rr",
  4016  			Flags:     utilipvs.FlagHashed,
  4017  		},
  4018  	}
  4019  	for v := range currentServices {
  4020  		fp.ipvs.AddVirtualServer(currentServices[v])
  4021  	}
  4022  
  4023  	fp.cleanLegacyService(activeServices, currentServices)
  4024  	// ipvs4 and ipvs5 should have been cleaned.
  4025  	remainingVirtualServers, _ := fp.ipvs.GetVirtualServers()
  4026  	if len(remainingVirtualServers) != 4 {
  4027  		t.Errorf("Expected number of remaining IPVS services after cleanup to be %v. Got %v", 4, len(remainingVirtualServers))
  4028  	}
  4029  	for _, vs := range remainingVirtualServers {
  4030  		// Checking that ipvs4 and ipvs5 were removed.
  4031  		if vs.Port == 57 {
  4032  			t.Errorf("Expected ipvs4 to be removed after cleanup. It still remains")
  4033  		}
  4034  		if vs.Port == 58 {
  4035  			t.Errorf("Expected ipvs5 to be removed after cleanup. It still remains")
  4036  		}
  4037  	}
  4038  }
  4039  
  4040  func TestCleanLegacyServiceWithRealServers(t *testing.T) {
  4041  	_, ctx := ktesting.NewTestContext(t)
  4042  	ipt := iptablestest.NewFake()
  4043  	ipvs := ipvstest.NewFake()
  4044  	ipset := ipsettest.NewFake(testIPSetVersion)
  4045  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  4046  
  4047  	// all deleted expect ipvs2
  4048  	activeServices := sets.New("ipvs2")
  4049  	// All ipvs services in the system.
  4050  	currentServices := map[string]*utilipvs.VirtualServer{
  4051  		"ipvs0": { // deleted with real servers
  4052  			Address:   netutils.ParseIPSloppy("1.1.1.1"),
  4053  			Protocol:  string(v1.ProtocolUDP),
  4054  			Port:      53,
  4055  			Scheduler: "rr",
  4056  			Flags:     utilipvs.FlagHashed,
  4057  		},
  4058  		"ipvs1": { // deleted no real server
  4059  			Address:   netutils.ParseIPSloppy("2.2.2.2"),
  4060  			Protocol:  string(v1.ProtocolUDP),
  4061  			Port:      54,
  4062  			Scheduler: "rr",
  4063  			Flags:     utilipvs.FlagHashed,
  4064  		},
  4065  		"ipvs2": { // not deleted
  4066  			Address:   netutils.ParseIPSloppy("3.3.3.3"),
  4067  			Protocol:  string(v1.ProtocolUDP),
  4068  			Port:      54,
  4069  			Scheduler: "rr",
  4070  			Flags:     utilipvs.FlagHashed,
  4071  		},
  4072  	}
  4073  
  4074  	// "ipvs0" has a real server, but it should still be deleted since the Service is deleted
  4075  	realServers := map[*utilipvs.VirtualServer]*utilipvs.RealServer{
  4076  		{
  4077  			Address:   netutils.ParseIPSloppy("1.1.1.1"),
  4078  			Protocol:  string(v1.ProtocolUDP),
  4079  			Port:      53,
  4080  			Scheduler: "rr",
  4081  			Flags:     utilipvs.FlagHashed,
  4082  		}: {
  4083  			Address: netutils.ParseIPSloppy("10.180.0.1"),
  4084  			Port:    uint16(53),
  4085  			Weight:  1,
  4086  		},
  4087  	}
  4088  
  4089  	for v := range currentServices {
  4090  		fp.ipvs.AddVirtualServer(currentServices[v])
  4091  	}
  4092  
  4093  	for v, r := range realServers {
  4094  		fp.ipvs.AddRealServer(v, r)
  4095  	}
  4096  
  4097  	fp.cleanLegacyService(activeServices, currentServices)
  4098  	remainingVirtualServers, _ := fp.ipvs.GetVirtualServers()
  4099  	if len(remainingVirtualServers) != 1 {
  4100  		t.Errorf("Expected number of remaining IPVS services after cleanup to be %v. Got %v", 1, len(remainingVirtualServers))
  4101  	}
  4102  
  4103  	if remainingVirtualServers[0] != currentServices["ipvs2"] {
  4104  		t.Logf("actual virtual server: %v", remainingVirtualServers[0])
  4105  		t.Logf("expected virtual server: %v", currentServices["ipvs0"])
  4106  		t.Errorf("unexpected IPVS service")
  4107  	}
  4108  }
  4109  
  4110  func TestCleanLegacyRealServersExcludeCIDRs(t *testing.T) {
  4111  	_, ctx := ktesting.NewTestContext(t)
  4112  	ipt := iptablestest.NewFake()
  4113  	ipvs := ipvstest.NewFake()
  4114  	ipset := ipsettest.NewFake(testIPSetVersion)
  4115  	gtm := NewGracefulTerminationManager(ipvs)
  4116  	excludeCIDRs, _ := netutils.ParseCIDRs([]string{"4.4.4.4/32"})
  4117  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, excludeCIDRs, v1.IPv4Protocol)
  4118  	fp.gracefuldeleteManager = gtm
  4119  
  4120  	vs := &utilipvs.VirtualServer{
  4121  		Address:   netutils.ParseIPSloppy("4.4.4.4"),
  4122  		Protocol:  string(v1.ProtocolUDP),
  4123  		Port:      56,
  4124  		Scheduler: "rr",
  4125  		Flags:     utilipvs.FlagHashed,
  4126  	}
  4127  
  4128  	fp.ipvs.AddVirtualServer(vs)
  4129  
  4130  	rss := []*utilipvs.RealServer{
  4131  		{
  4132  			Address:      netutils.ParseIPSloppy("10.10.10.10"),
  4133  			Port:         56,
  4134  			ActiveConn:   0,
  4135  			InactiveConn: 0,
  4136  		},
  4137  		{
  4138  			Address:      netutils.ParseIPSloppy("11.11.11.11"),
  4139  			Port:         56,
  4140  			ActiveConn:   0,
  4141  			InactiveConn: 0,
  4142  		},
  4143  	}
  4144  	for _, rs := range rss {
  4145  		fp.ipvs.AddRealServer(vs, rs)
  4146  	}
  4147  
  4148  	fp.netlinkHandle.EnsureDummyDevice(defaultDummyDevice)
  4149  
  4150  	fp.netlinkHandle.EnsureAddressBind("4.4.4.4", defaultDummyDevice)
  4151  
  4152  	fp.cleanLegacyService(nil, map[string]*utilipvs.VirtualServer{"ipvs0": vs})
  4153  
  4154  	fp.gracefuldeleteManager.tryDeleteRs()
  4155  
  4156  	remainingRealServers, _ := fp.ipvs.GetRealServers(vs)
  4157  
  4158  	if len(remainingRealServers) != 2 {
  4159  		t.Errorf("Expected number of remaining IPVS real servers after cleanup should be %v. Got %v", 2, len(remainingRealServers))
  4160  	}
  4161  }
  4162  
  4163  func TestCleanLegacyService6(t *testing.T) {
  4164  	_, ctx := ktesting.NewTestContext(t)
  4165  	ipt := iptablestest.NewFake()
  4166  	ipvs := ipvstest.NewFake()
  4167  	ipset := ipsettest.NewFake(testIPSetVersion)
  4168  	excludeCIDRs, _ := netutils.ParseCIDRs([]string{"3000::/64", "4000::/64"})
  4169  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, excludeCIDRs, v1.IPv6Protocol)
  4170  	fp.nodeIP = netutils.ParseIPSloppy("::1")
  4171  
  4172  	// All ipvs services that were processed in the latest sync loop.
  4173  	activeServices := sets.New("ipvs0", "ipvs1")
  4174  	// All ipvs services in the system.
  4175  	currentServices := map[string]*utilipvs.VirtualServer{
  4176  		// Created by kube-proxy.
  4177  		"ipvs0": {
  4178  			Address:   netutils.ParseIPSloppy("1000::1"),
  4179  			Protocol:  string(v1.ProtocolUDP),
  4180  			Port:      53,
  4181  			Scheduler: "rr",
  4182  			Flags:     utilipvs.FlagHashed,
  4183  		},
  4184  		// Created by kube-proxy.
  4185  		"ipvs1": {
  4186  			Address:   netutils.ParseIPSloppy("1000::2"),
  4187  			Protocol:  string(v1.ProtocolUDP),
  4188  			Port:      54,
  4189  			Scheduler: "rr",
  4190  			Flags:     utilipvs.FlagHashed,
  4191  		},
  4192  		// Created by an external party.
  4193  		"ipvs2": {
  4194  			Address:   netutils.ParseIPSloppy("3000::1"),
  4195  			Protocol:  string(v1.ProtocolUDP),
  4196  			Port:      55,
  4197  			Scheduler: "rr",
  4198  			Flags:     utilipvs.FlagHashed,
  4199  		},
  4200  		// Created by an external party.
  4201  		"ipvs3": {
  4202  			Address:   netutils.ParseIPSloppy("4000::1"),
  4203  			Protocol:  string(v1.ProtocolUDP),
  4204  			Port:      56,
  4205  			Scheduler: "rr",
  4206  			Flags:     utilipvs.FlagHashed,
  4207  		},
  4208  		// Created by an external party.
  4209  		"ipvs4": {
  4210  			Address:   netutils.ParseIPSloppy("5000::1"),
  4211  			Protocol:  string(v1.ProtocolUDP),
  4212  			Port:      57,
  4213  			Scheduler: "rr",
  4214  			Flags:     utilipvs.FlagHashed,
  4215  		},
  4216  		// Created by kube-proxy, but now stale.
  4217  		"ipvs5": {
  4218  			Address:   netutils.ParseIPSloppy("1000::6"),
  4219  			Protocol:  string(v1.ProtocolUDP),
  4220  			Port:      58,
  4221  			Scheduler: "rr",
  4222  			Flags:     utilipvs.FlagHashed,
  4223  		},
  4224  	}
  4225  	for v := range currentServices {
  4226  		fp.ipvs.AddVirtualServer(currentServices[v])
  4227  	}
  4228  
  4229  	fp.cleanLegacyService(activeServices, currentServices)
  4230  	// ipvs4 and ipvs5 should have been cleaned.
  4231  	remainingVirtualServers, _ := fp.ipvs.GetVirtualServers()
  4232  	if len(remainingVirtualServers) != 4 {
  4233  		t.Errorf("Expected number of remaining IPVS services after cleanup to be %v. Got %v", 4, len(remainingVirtualServers))
  4234  	}
  4235  	for _, vs := range remainingVirtualServers {
  4236  		// Checking that ipvs4 and ipvs5 were removed.
  4237  		if vs.Port == 57 {
  4238  			t.Errorf("Expected ipvs4 to be removed after cleanup. It still remains")
  4239  		}
  4240  		if vs.Port == 58 {
  4241  			t.Errorf("Expected ipvs5 to be removed after cleanup. It still remains")
  4242  		}
  4243  	}
  4244  }
  4245  
  4246  func TestMultiPortServiceBindAddr(t *testing.T) {
  4247  	_, ctx := ktesting.NewTestContext(t)
  4248  	ipt := iptablestest.NewFake()
  4249  	ipvs := ipvstest.NewFake()
  4250  	ipset := ipsettest.NewFake(testIPSetVersion)
  4251  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  4252  
  4253  	service1 := makeTestService("ns1", "svc1", func(svc *v1.Service) {
  4254  		svc.Spec.Type = v1.ServiceTypeClusterIP
  4255  		svc.Spec.ClusterIP = "172.16.55.4"
  4256  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port1", "TCP", 1234, 0, 0)
  4257  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port2", "TCP", 1235, 0, 0)
  4258  	})
  4259  	service2 := makeTestService("ns1", "svc1", func(svc *v1.Service) {
  4260  		svc.Spec.Type = v1.ServiceTypeClusterIP
  4261  		svc.Spec.ClusterIP = "172.16.55.4"
  4262  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port1", "TCP", 1234, 0, 0)
  4263  	})
  4264  	service3 := makeTestService("ns1", "svc1", func(svc *v1.Service) {
  4265  		svc.Spec.Type = v1.ServiceTypeClusterIP
  4266  		svc.Spec.ClusterIP = "172.16.55.4"
  4267  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port1", "TCP", 1234, 0, 0)
  4268  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port2", "TCP", 1235, 0, 0)
  4269  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port3", "UDP", 1236, 0, 0)
  4270  	})
  4271  
  4272  	fp.servicesSynced = true
  4273  
  4274  	// first, add multi-port service1
  4275  	fp.OnServiceAdd(service1)
  4276  	fp.syncProxyRules()
  4277  	remainingAddrs, _ := fp.netlinkHandle.ListBindAddress(defaultDummyDevice)
  4278  	// should only remain address "172.16.55.4"
  4279  	if len(remainingAddrs) != 1 {
  4280  		t.Errorf("Expected number of remaining bound addrs after cleanup to be %v. Got %v", 1, len(remainingAddrs))
  4281  	}
  4282  	if remainingAddrs[0] != "172.16.55.4" {
  4283  		t.Errorf("Expected remaining address should be %s, got %s", "172.16.55.4", remainingAddrs[0])
  4284  	}
  4285  
  4286  	// update multi-port service1 to single-port service2
  4287  	fp.OnServiceUpdate(service1, service2)
  4288  	fp.syncProxyRules()
  4289  	remainingAddrs, _ = fp.netlinkHandle.ListBindAddress(defaultDummyDevice)
  4290  	// should still only remain address "172.16.55.4"
  4291  	if len(remainingAddrs) != 1 {
  4292  		t.Errorf("Expected number of remaining bound addrs after cleanup to be %v. Got %v", 1, len(remainingAddrs))
  4293  	} else if remainingAddrs[0] != "172.16.55.4" {
  4294  		t.Errorf("Expected remaining address should be %s, got %s", "172.16.55.4", remainingAddrs[0])
  4295  	}
  4296  
  4297  	// update single-port service2 to multi-port service3
  4298  	fp.OnServiceUpdate(service2, service3)
  4299  	fp.syncProxyRules()
  4300  	remainingAddrs, _ = fp.netlinkHandle.ListBindAddress(defaultDummyDevice)
  4301  	// should still only remain address "172.16.55.4"
  4302  	if len(remainingAddrs) != 1 {
  4303  		t.Errorf("Expected number of remaining bound addrs after cleanup to be %v. Got %v", 1, len(remainingAddrs))
  4304  	} else if remainingAddrs[0] != "172.16.55.4" {
  4305  		t.Errorf("Expected remaining address should be %s, got %s", "172.16.55.4", remainingAddrs[0])
  4306  	}
  4307  
  4308  	// delete multi-port service3
  4309  	fp.OnServiceDelete(service3)
  4310  	fp.syncProxyRules()
  4311  	remainingAddrs, _ = fp.netlinkHandle.ListBindAddress(defaultDummyDevice)
  4312  	// all addresses should be unbound
  4313  	if len(remainingAddrs) != 0 {
  4314  		t.Errorf("Expected number of remaining bound addrs after cleanup to be %v. Got %v", 0, len(remainingAddrs))
  4315  	}
  4316  }
  4317  
  4318  func Test_getFirstColumn(t *testing.T) {
  4319  	testCases := []struct {
  4320  		name        string
  4321  		fileContent string
  4322  		want        []string
  4323  		wantErr     bool
  4324  	}{
  4325  		{
  4326  			name: "valid content",
  4327  			fileContent: `libiscsi_tcp 28672 1 iscsi_tcp, Live 0xffffffffc07ae000
  4328  libiscsi 57344 3 ib_iser,iscsi_tcp,libiscsi_tcp, Live 0xffffffffc079a000
  4329  raid10 57344 0 - Live 0xffffffffc0597000`,
  4330  			want:    []string{"libiscsi_tcp", "libiscsi", "raid10"},
  4331  			wantErr: false,
  4332  		},
  4333  	}
  4334  	for _, test := range testCases {
  4335  		t.Run(test.name, func(t *testing.T) {
  4336  			got, err := getFirstColumn(strings.NewReader(test.fileContent))
  4337  			if (err != nil) != test.wantErr {
  4338  				t.Errorf("getFirstColumn() error = %v, wantErr %v", err, test.wantErr)
  4339  				return
  4340  			}
  4341  			if !reflect.DeepEqual(got, test.want) {
  4342  				t.Errorf("getFirstColumn() = %v, want %v", got, test.want)
  4343  			}
  4344  		})
  4345  	}
  4346  }
  4347  
  4348  // The majority of EndpointSlice specific tests are not ipvs specific and focus on
  4349  // the shared EndpointsChangeTracker and EndpointSliceCache. This test ensures that the
  4350  // ipvs proxier supports translating EndpointSlices to ipvs output.
  4351  func TestEndpointSliceE2E(t *testing.T) {
  4352  	_, ctx := ktesting.NewTestContext(t)
  4353  	ipt := iptablestest.NewFake()
  4354  	ipvs := ipvstest.NewFake()
  4355  	ipset := ipsettest.NewFake(testIPSetVersion)
  4356  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  4357  	fp.servicesSynced = true
  4358  	fp.endpointSlicesSynced = true
  4359  
  4360  	// Add initial service
  4361  	serviceName := "svc1"
  4362  	namespaceName := "ns1"
  4363  	fp.OnServiceAdd(&v1.Service{
  4364  		ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespaceName},
  4365  		Spec: v1.ServiceSpec{
  4366  			ClusterIP: "172.20.1.1",
  4367  			Selector:  map[string]string{"foo": "bar"},
  4368  			Ports:     []v1.ServicePort{{Name: "", TargetPort: intstr.FromInt32(80), Protocol: v1.ProtocolTCP}},
  4369  		},
  4370  	})
  4371  
  4372  	// Add initial endpoint slice
  4373  	endpointSlice := &discovery.EndpointSlice{
  4374  		ObjectMeta: metav1.ObjectMeta{
  4375  			Name:      fmt.Sprintf("%s-1", serviceName),
  4376  			Namespace: namespaceName,
  4377  			Labels:    map[string]string{discovery.LabelServiceName: serviceName},
  4378  		},
  4379  		Ports: []discovery.EndpointPort{{
  4380  			Name:     ptr.To(""),
  4381  			Port:     ptr.To[int32](80),
  4382  			Protocol: ptr.To(v1.ProtocolTCP),
  4383  		}},
  4384  		AddressType: discovery.AddressTypeIPv4,
  4385  		Endpoints: []discovery.Endpoint{{
  4386  			Addresses:  []string{"10.0.1.1"},
  4387  			Conditions: discovery.EndpointConditions{Ready: ptr.To(true)},
  4388  			NodeName:   ptr.To(testHostname),
  4389  		}, {
  4390  			Addresses:  []string{"10.0.1.2"},
  4391  			Conditions: discovery.EndpointConditions{Ready: ptr.To(true)},
  4392  			NodeName:   ptr.To("node2"),
  4393  		}, {
  4394  			Addresses:  []string{"10.0.1.3"},
  4395  			Conditions: discovery.EndpointConditions{Ready: ptr.To(true)},
  4396  			NodeName:   ptr.To("node3"),
  4397  		}, { // not ready endpoints should be ignored
  4398  			Addresses:  []string{"10.0.1.4"},
  4399  			Conditions: discovery.EndpointConditions{Ready: ptr.To(false)},
  4400  			NodeName:   ptr.To("node3"),
  4401  		}},
  4402  	}
  4403  
  4404  	fp.OnEndpointSliceAdd(endpointSlice)
  4405  	fp.syncProxyRules()
  4406  
  4407  	// Ensure that Proxier updates ipvs appropriately after EndpointSlice update
  4408  	assert.NotNil(t, fp.ipsetList["KUBE-LOOP-BACK"])
  4409  	activeEntries1 := fp.ipsetList["KUBE-LOOP-BACK"].activeEntries
  4410  	assert.Equal(t, 1, activeEntries1.Len(), "Expected 1 active entry in KUBE-LOOP-BACK")
  4411  	assert.Equal(t, true, activeEntries1.Has("10.0.1.1,tcp:80,10.0.1.1"), "Expected activeEntries to reference first (local) pod")
  4412  	virtualServers1, vsErr1 := ipvs.GetVirtualServers()
  4413  	assert.Nil(t, vsErr1, "Expected no error getting virtual servers")
  4414  	assert.Len(t, virtualServers1, 1, "Expected 1 virtual server")
  4415  	realServers1, rsErr1 := ipvs.GetRealServers(virtualServers1[0])
  4416  	assert.Nil(t, rsErr1, "Expected no error getting real servers")
  4417  	assert.Len(t, realServers1, 3, "Expected 3 real servers")
  4418  	assert.Equal(t, realServers1[0].String(), "10.0.1.1:80")
  4419  	assert.Equal(t, realServers1[1].String(), "10.0.1.2:80")
  4420  	assert.Equal(t, realServers1[2].String(), "10.0.1.3:80")
  4421  
  4422  	fp.OnEndpointSliceDelete(endpointSlice)
  4423  	fp.syncProxyRules()
  4424  
  4425  	// Ensure that Proxier updates ipvs appropriately after EndpointSlice delete
  4426  	assert.NotNil(t, fp.ipsetList["KUBE-LOOP-BACK"])
  4427  	activeEntries2 := fp.ipsetList["KUBE-LOOP-BACK"].activeEntries
  4428  	assert.Equal(t, 0, activeEntries2.Len(), "Expected 0 active entries in KUBE-LOOP-BACK")
  4429  	virtualServers2, vsErr2 := ipvs.GetVirtualServers()
  4430  	assert.Nil(t, vsErr2, "Expected no error getting virtual servers")
  4431  	assert.Len(t, virtualServers2, 1, "Expected 1 virtual server")
  4432  	realServers2, rsErr2 := ipvs.GetRealServers(virtualServers2[0])
  4433  	assert.Nil(t, rsErr2, "Expected no error getting real servers")
  4434  	assert.Len(t, realServers2, 0, "Expected 0 real servers")
  4435  }
  4436  
  4437  func TestHealthCheckNodePortE2E(t *testing.T) {
  4438  	_, ctx := ktesting.NewTestContext(t)
  4439  	ipt := iptablestest.NewFake()
  4440  	ipvs := ipvstest.NewFake()
  4441  	ipset := ipsettest.NewFake(testIPSetVersion)
  4442  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  4443  	fp.servicesSynced = true
  4444  	fp.endpointSlicesSynced = true
  4445  
  4446  	// Add initial service
  4447  	serviceName := "svc1"
  4448  	namespaceName := "ns1"
  4449  
  4450  	svc := v1.Service{
  4451  		ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespaceName},
  4452  		Spec: v1.ServiceSpec{
  4453  			ClusterIP:             "172.20.1.1",
  4454  			Selector:              map[string]string{"foo": "bar"},
  4455  			Ports:                 []v1.ServicePort{{Name: "", TargetPort: intstr.FromInt32(80), Protocol: v1.ProtocolTCP}},
  4456  			Type:                  "LoadBalancer",
  4457  			HealthCheckNodePort:   30000,
  4458  			ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyLocal,
  4459  		},
  4460  	}
  4461  	fp.OnServiceAdd(&svc)
  4462  	fp.syncProxyRules()
  4463  
  4464  	// Ensure that Proxier updates ipvs appropriately after service's being created
  4465  	assert.NotNil(t, fp.ipsetList["KUBE-HEALTH-CHECK-NODE-PORT"])
  4466  	activeEntries1 := fp.ipsetList["KUBE-HEALTH-CHECK-NODE-PORT"].activeEntries
  4467  	assert.Equal(t, 1, activeEntries1.Len(), "Expected 1 active entry in KUBE-HEALTH-CHECK-NODE-PORT")
  4468  	assert.Equal(t, true, activeEntries1.Has("30000"), "Expected activeEntries to reference hc node port in spec")
  4469  
  4470  	// Update health check node port in the spec
  4471  	newSvc := svc
  4472  	newSvc.Spec.HealthCheckNodePort = 30001
  4473  	fp.OnServiceUpdate(&svc, &newSvc)
  4474  	fp.syncProxyRules()
  4475  
  4476  	// Ensure that Proxier updates ipvs appropriately after service's being updated
  4477  	assert.NotNil(t, fp.ipsetList["KUBE-HEALTH-CHECK-NODE-PORT"])
  4478  	activeEntries2 := fp.ipsetList["KUBE-HEALTH-CHECK-NODE-PORT"].activeEntries
  4479  	assert.Equal(t, 1, activeEntries2.Len(), "Expected 1 active entry in KUBE-HEALTH-CHECK-NODE-PORT")
  4480  	assert.Equal(t, true, activeEntries2.Has("30001"), "Expected activeEntries to reference updated hc node port in spec")
  4481  
  4482  	fp.OnServiceDelete(&svc)
  4483  	fp.syncProxyRules()
  4484  
  4485  	// Ensure that Proxier updates ipvs appropriately after EndpointSlice delete
  4486  	assert.NotNil(t, fp.ipsetList["KUBE-HEALTH-CHECK-NODE-PORT"])
  4487  	activeEntries3 := fp.ipsetList["KUBE-HEALTH-CHECK-NODE-PORT"].activeEntries
  4488  	assert.Equal(t, 0, activeEntries3.Len(), "Expected 0 active entries in KUBE-HEALTH-CHECK-NODE-PORT")
  4489  }
  4490  
  4491  // Test_HealthCheckNodePortWhenTerminating tests that health check node ports are not enabled when all local endpoints are terminating
  4492  func Test_HealthCheckNodePortWhenTerminating(t *testing.T) {
  4493  	_, ctx := ktesting.NewTestContext(t)
  4494  	ipt := iptablestest.NewFake()
  4495  	ipvs := ipvstest.NewFake()
  4496  	ipset := ipsettest.NewFake(testIPSetVersion)
  4497  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  4498  	fp.servicesSynced = true
  4499  	// fp.endpointsSynced = true
  4500  	fp.endpointSlicesSynced = true
  4501  
  4502  	serviceName := "svc1"
  4503  	namespaceName := "ns1"
  4504  
  4505  	fp.OnServiceAdd(&v1.Service{
  4506  		ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespaceName},
  4507  		Spec: v1.ServiceSpec{
  4508  			ClusterIP: "172.20.1.1",
  4509  			Selector:  map[string]string{"foo": "bar"},
  4510  			Ports:     []v1.ServicePort{{Name: "", TargetPort: intstr.FromInt32(80), Protocol: v1.ProtocolTCP}},
  4511  		},
  4512  	})
  4513  
  4514  	endpointSlice := &discovery.EndpointSlice{
  4515  		ObjectMeta: metav1.ObjectMeta{
  4516  			Name:      fmt.Sprintf("%s-1", serviceName),
  4517  			Namespace: namespaceName,
  4518  			Labels:    map[string]string{discovery.LabelServiceName: serviceName},
  4519  		},
  4520  		Ports: []discovery.EndpointPort{{
  4521  			Name:     ptr.To(""),
  4522  			Port:     ptr.To[int32](80),
  4523  			Protocol: ptr.To(v1.ProtocolTCP),
  4524  		}},
  4525  		AddressType: discovery.AddressTypeIPv4,
  4526  		Endpoints: []discovery.Endpoint{{
  4527  			Addresses:  []string{"10.0.1.1"},
  4528  			Conditions: discovery.EndpointConditions{Ready: ptr.To(true)},
  4529  			NodeName:   ptr.To(testHostname),
  4530  		}, {
  4531  			Addresses:  []string{"10.0.1.2"},
  4532  			Conditions: discovery.EndpointConditions{Ready: ptr.To(true)},
  4533  			NodeName:   ptr.To(testHostname),
  4534  		}, {
  4535  			Addresses:  []string{"10.0.1.3"},
  4536  			Conditions: discovery.EndpointConditions{Ready: ptr.To(true)},
  4537  		}, { // not ready endpoints should be ignored
  4538  			Addresses:  []string{"10.0.1.4"},
  4539  			Conditions: discovery.EndpointConditions{Ready: ptr.To(false)},
  4540  			NodeName:   ptr.To(testHostname),
  4541  		}},
  4542  	}
  4543  
  4544  	fp.OnEndpointSliceAdd(endpointSlice)
  4545  	_ = fp.endpointsMap.Update(fp.endpointsChanges)
  4546  	localReadyEndpoints := fp.endpointsMap.LocalReadyEndpoints()
  4547  	if len(localReadyEndpoints) != 1 {
  4548  		t.Errorf("unexpected number of health check node ports, expected 1 but got: %d", len(localReadyEndpoints))
  4549  	}
  4550  
  4551  	// set all endpoints to terminating
  4552  	endpointSliceTerminating := &discovery.EndpointSlice{
  4553  		ObjectMeta: metav1.ObjectMeta{
  4554  			Name:      fmt.Sprintf("%s-1", serviceName),
  4555  			Namespace: namespaceName,
  4556  			Labels:    map[string]string{discovery.LabelServiceName: serviceName},
  4557  		},
  4558  		Ports: []discovery.EndpointPort{{
  4559  			Name:     ptr.To(""),
  4560  			Port:     ptr.To[int32](80),
  4561  			Protocol: ptr.To(v1.ProtocolTCP),
  4562  		}},
  4563  		AddressType: discovery.AddressTypeIPv4,
  4564  		Endpoints: []discovery.Endpoint{{
  4565  			Addresses: []string{"10.0.1.1"},
  4566  			Conditions: discovery.EndpointConditions{
  4567  				Ready:       ptr.To(false),
  4568  				Serving:     ptr.To(true),
  4569  				Terminating: ptr.To(false),
  4570  			},
  4571  			NodeName: ptr.To(testHostname),
  4572  		}, {
  4573  			Addresses: []string{"10.0.1.2"},
  4574  			Conditions: discovery.EndpointConditions{
  4575  				Ready:       ptr.To(false),
  4576  				Serving:     ptr.To(true),
  4577  				Terminating: ptr.To(true),
  4578  			},
  4579  			NodeName: ptr.To(testHostname),
  4580  		}, {
  4581  			Addresses: []string{"10.0.1.3"},
  4582  			Conditions: discovery.EndpointConditions{
  4583  				Ready:       ptr.To(false),
  4584  				Serving:     ptr.To(true),
  4585  				Terminating: ptr.To(true),
  4586  			},
  4587  			NodeName: ptr.To(testHostname),
  4588  		}, { // not ready endpoints should be ignored
  4589  			Addresses: []string{"10.0.1.4"},
  4590  			Conditions: discovery.EndpointConditions{
  4591  				Ready:       ptr.To(false),
  4592  				Serving:     ptr.To(false),
  4593  				Terminating: ptr.To(true),
  4594  			},
  4595  			NodeName: ptr.To(testHostname),
  4596  		}},
  4597  	}
  4598  
  4599  	fp.OnEndpointSliceUpdate(endpointSlice, endpointSliceTerminating)
  4600  	_ = fp.endpointsMap.Update(fp.endpointsChanges)
  4601  	localReadyEndpoints = fp.endpointsMap.LocalReadyEndpoints()
  4602  	if len(localReadyEndpoints) != 0 {
  4603  		t.Errorf("unexpected number of health check node ports, expected 0 but got: %d", len(localReadyEndpoints))
  4604  	}
  4605  }
  4606  
  4607  func TestFilterCIDRs(t *testing.T) {
  4608  	var cidrList []string
  4609  	var cidrs []string
  4610  	var expected []string
  4611  	cidrs = filterCIDRs(true, []string{})
  4612  	if len(cidrs) > 0 {
  4613  		t.Errorf("An empty list produces a non-empty return %v", cidrs)
  4614  	}
  4615  
  4616  	cidrList = []string{"1000::/64", "10.0.0.0/16", "11.0.0.0/16", "2000::/64"}
  4617  	expected = []string{"1000::/64", "2000::/64"}
  4618  	cidrs = filterCIDRs(true, cidrList)
  4619  	if !reflect.DeepEqual(cidrs, expected) {
  4620  		t.Errorf("cidrs %v is not expected %v", cidrs, expected)
  4621  	}
  4622  
  4623  	expected = []string{"10.0.0.0/16", "11.0.0.0/16"}
  4624  	cidrs = filterCIDRs(false, cidrList)
  4625  	if !reflect.DeepEqual(cidrs, expected) {
  4626  		t.Errorf("cidrs %v is not expected %v", cidrs, expected)
  4627  	}
  4628  
  4629  	cidrList = []string{"1000::/64", "2000::/64"}
  4630  	expected = []string{}
  4631  	cidrs = filterCIDRs(false, cidrList)
  4632  	if len(cidrs) > 0 {
  4633  		t.Errorf("cidrs %v is not expected %v", cidrs, expected)
  4634  	}
  4635  }
  4636  
  4637  func TestCreateAndLinkKubeChain(t *testing.T) {
  4638  	_, ctx := ktesting.NewTestContext(t)
  4639  	ipt := iptablestest.NewFake()
  4640  	ipvs := ipvstest.NewFake()
  4641  	ipset := ipsettest.NewFake(testIPSetVersion)
  4642  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  4643  	fp.createAndLinkKubeChain()
  4644  	expectedNATChains := `:KUBE-SERVICES - [0:0]
  4645  :KUBE-POSTROUTING - [0:0]
  4646  :KUBE-NODE-PORT - [0:0]
  4647  :KUBE-LOAD-BALANCER - [0:0]
  4648  :KUBE-MARK-MASQ - [0:0]
  4649  `
  4650  	expectedFilterChains := `:KUBE-FORWARD - [0:0]
  4651  :KUBE-NODE-PORT - [0:0]
  4652  :KUBE-PROXY-FIREWALL - [0:0]
  4653  :KUBE-SOURCE-RANGES-FIREWALL - [0:0]
  4654  :KUBE-IPVS-FILTER - [0:0]
  4655  :KUBE-IPVS-OUT-FILTER - [0:0]
  4656  `
  4657  	assert.Equal(t, expectedNATChains, fp.natChains.String())
  4658  	assert.Equal(t, expectedFilterChains, fp.filterChains.String())
  4659  }
  4660  
  4661  // This test ensures that the iptables proxier supports translating Endpoints to
  4662  // iptables output when internalTrafficPolicy is specified
  4663  func TestTestInternalTrafficPolicyE2E(t *testing.T) {
  4664  	type endpoint struct {
  4665  		ip       string
  4666  		hostname string
  4667  	}
  4668  
  4669  	testCases := []struct {
  4670  		name                     string
  4671  		internalTrafficPolicy    *v1.ServiceInternalTrafficPolicy
  4672  		endpoints                []endpoint
  4673  		expectVirtualServer      bool
  4674  		expectLocalEntries       bool
  4675  		expectLocalRealServerNum int
  4676  		expectLocalRealServers   []string
  4677  	}{
  4678  		{
  4679  			name:                  "internalTrafficPolicy is cluster with non-zero local endpoints",
  4680  			internalTrafficPolicy: ptr.To(v1.ServiceInternalTrafficPolicyCluster),
  4681  			endpoints: []endpoint{
  4682  				{"10.0.1.1", testHostname},
  4683  				{"10.0.1.2", "host1"},
  4684  				{"10.0.1.3", "host2"},
  4685  			},
  4686  			expectVirtualServer:      true,
  4687  			expectLocalEntries:       true,
  4688  			expectLocalRealServerNum: 3,
  4689  			expectLocalRealServers: []string{
  4690  				"10.0.1.1:80",
  4691  				"10.0.1.2:80",
  4692  				"10.0.1.3:80",
  4693  			},
  4694  		},
  4695  		{
  4696  			name:                  "internalTrafficPolicy is cluster with zero local endpoints",
  4697  			internalTrafficPolicy: ptr.To(v1.ServiceInternalTrafficPolicyCluster),
  4698  			endpoints: []endpoint{
  4699  				{"10.0.1.1", "host0"},
  4700  				{"10.0.1.2", "host1"},
  4701  				{"10.0.1.3", "host2"},
  4702  			},
  4703  			expectVirtualServer:      false,
  4704  			expectLocalEntries:       false,
  4705  			expectLocalRealServerNum: 3,
  4706  			expectLocalRealServers: []string{
  4707  				"10.0.1.1:80",
  4708  				"10.0.1.2:80",
  4709  				"10.0.1.3:80",
  4710  			},
  4711  		},
  4712  		{
  4713  			name:                  "internalTrafficPolicy is local with non-zero local endpoints",
  4714  			internalTrafficPolicy: ptr.To(v1.ServiceInternalTrafficPolicyLocal),
  4715  			endpoints: []endpoint{
  4716  				{"10.0.1.1", testHostname},
  4717  				{"10.0.1.2", "host1"},
  4718  				{"10.0.1.3", "host2"},
  4719  			},
  4720  			expectVirtualServer:      true,
  4721  			expectLocalEntries:       true,
  4722  			expectLocalRealServerNum: 1,
  4723  			expectLocalRealServers: []string{
  4724  				"10.0.1.1:80",
  4725  			},
  4726  		},
  4727  		{
  4728  			name:                  "internalTrafficPolicy is local with zero local endpoints",
  4729  			internalTrafficPolicy: ptr.To(v1.ServiceInternalTrafficPolicyLocal),
  4730  			endpoints: []endpoint{
  4731  				{"10.0.1.1", "host0"},
  4732  				{"10.0.1.2", "host1"},
  4733  				{"10.0.1.3", "host2"},
  4734  			},
  4735  			expectVirtualServer:      false,
  4736  			expectLocalEntries:       false,
  4737  			expectLocalRealServerNum: 0,
  4738  			expectLocalRealServers:   []string{},
  4739  		},
  4740  	}
  4741  	for _, tc := range testCases {
  4742  		_, ctx := ktesting.NewTestContext(t)
  4743  		ipt := iptablestest.NewFake()
  4744  		ipvs := ipvstest.NewFake()
  4745  		ipset := ipsettest.NewFake(testIPSetVersion)
  4746  		fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  4747  		fp.servicesSynced = true
  4748  		// fp.endpointsSynced = true
  4749  		fp.endpointSlicesSynced = true
  4750  
  4751  		// Add initial service
  4752  		serviceName := "svc1"
  4753  		namespaceName := "ns1"
  4754  
  4755  		svc := &v1.Service{
  4756  			ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespaceName},
  4757  			Spec: v1.ServiceSpec{
  4758  				ClusterIP: "172.20.1.1",
  4759  				Selector:  map[string]string{"foo": "bar"},
  4760  				Ports:     []v1.ServicePort{{Name: "", TargetPort: intstr.FromInt32(80), Protocol: v1.ProtocolTCP}},
  4761  			},
  4762  		}
  4763  		if tc.internalTrafficPolicy != nil {
  4764  			svc.Spec.InternalTrafficPolicy = tc.internalTrafficPolicy
  4765  		}
  4766  
  4767  		fp.OnServiceAdd(svc)
  4768  
  4769  		// Add initial endpoint slice
  4770  		endpointSlice := &discovery.EndpointSlice{
  4771  			ObjectMeta: metav1.ObjectMeta{
  4772  				Name:      fmt.Sprintf("%s-1", serviceName),
  4773  				Namespace: namespaceName,
  4774  				Labels:    map[string]string{discovery.LabelServiceName: serviceName},
  4775  			},
  4776  			Ports: []discovery.EndpointPort{{
  4777  				Name:     ptr.To(""),
  4778  				Port:     ptr.To[int32](80),
  4779  				Protocol: ptr.To(v1.ProtocolTCP),
  4780  			}},
  4781  			AddressType: discovery.AddressTypeIPv4,
  4782  		}
  4783  
  4784  		for _, ep := range tc.endpoints {
  4785  			endpointSlice.Endpoints = append(endpointSlice.Endpoints, discovery.Endpoint{
  4786  				Addresses:  []string{ep.ip},
  4787  				Conditions: discovery.EndpointConditions{Ready: ptr.To(true)},
  4788  				NodeName:   ptr.To(ep.hostname),
  4789  			})
  4790  		}
  4791  
  4792  		fp.OnEndpointSliceAdd(endpointSlice)
  4793  		fp.syncProxyRules()
  4794  
  4795  		// Ensure that Proxier updates ipvs appropriately after EndpointSlice update
  4796  		assert.NotNil(t, fp.ipsetList["KUBE-LOOP-BACK"])
  4797  
  4798  		activeEntries1 := fp.ipsetList["KUBE-LOOP-BACK"].activeEntries
  4799  
  4800  		if tc.expectLocalEntries {
  4801  			assert.Equal(t, 1, activeEntries1.Len(), "Expected 1 active entry in KUBE-LOOP-BACK")
  4802  		} else {
  4803  			assert.Equal(t, 0, activeEntries1.Len(), "Expected no active entry in KUBE-LOOP-BACK")
  4804  		}
  4805  
  4806  		if tc.expectVirtualServer {
  4807  			virtualServers1, vsErr1 := ipvs.GetVirtualServers()
  4808  			assert.Nil(t, vsErr1, "Expected no error getting virtual servers")
  4809  
  4810  			assert.Len(t, virtualServers1, 1, "Expected 1 virtual server")
  4811  			realServers1, rsErr1 := ipvs.GetRealServers(virtualServers1[0])
  4812  			assert.Nil(t, rsErr1, "Expected no error getting real servers")
  4813  
  4814  			assert.Len(t, realServers1, tc.expectLocalRealServerNum, fmt.Sprintf("Expected %d real servers", tc.expectLocalRealServerNum))
  4815  			for i := 0; i < tc.expectLocalRealServerNum; i++ {
  4816  				assert.Equal(t, realServers1[i].String(), tc.expectLocalRealServers[i])
  4817  			}
  4818  		}
  4819  
  4820  		fp.OnEndpointSliceDelete(endpointSlice)
  4821  		fp.syncProxyRules()
  4822  
  4823  		// Ensure that Proxier updates ipvs appropriately after EndpointSlice delete
  4824  		assert.NotNil(t, fp.ipsetList["KUBE-LOOP-BACK"])
  4825  		activeEntries3 := fp.ipsetList["KUBE-LOOP-BACK"].activeEntries
  4826  		assert.Equal(t, 0, activeEntries3.Len(), "Expected 0 active entries in KUBE-LOOP-BACK")
  4827  		virtualServers2, vsErr2 := ipvs.GetVirtualServers()
  4828  		assert.Nil(t, vsErr2, "Expected no error getting virtual servers")
  4829  		assert.Len(t, virtualServers2, 1, "Expected 1 virtual server")
  4830  		realServers2, rsErr2 := ipvs.GetRealServers(virtualServers2[0])
  4831  		assert.Nil(t, rsErr2, "Expected no error getting real servers")
  4832  		assert.Len(t, realServers2, 0, "Expected 0 real servers")
  4833  	}
  4834  }
  4835  
  4836  // Test_EndpointSliceReadyAndTerminatingCluster tests that when there are ready and ready + terminating
  4837  // endpoints and the traffic policy is "Cluster", only the ready endpoints are used.
  4838  func Test_EndpointSliceReadyAndTerminatingCluster(t *testing.T) {
  4839  	_, ctx := ktesting.NewTestContext(t)
  4840  	ipt := iptablestest.NewFake()
  4841  	ipvs := ipvstest.NewFake()
  4842  	ipset := ipsettest.NewFake(testIPSetVersion)
  4843  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  4844  	fp.servicesSynced = true
  4845  	// fp.endpointsSynced = true
  4846  	fp.endpointSlicesSynced = true
  4847  
  4848  	serviceName := "svc1"
  4849  	// Add initial service
  4850  	namespaceName := "ns1"
  4851  	fp.OnServiceAdd(&v1.Service{
  4852  		ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespaceName},
  4853  		Spec: v1.ServiceSpec{
  4854  			ClusterIP:             "172.20.1.1",
  4855  			Selector:              map[string]string{"foo": "bar"},
  4856  			Type:                  v1.ServiceTypeNodePort,
  4857  			ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyCluster,
  4858  			InternalTrafficPolicy: ptr.To(v1.ServiceInternalTrafficPolicyCluster),
  4859  			ExternalIPs: []string{
  4860  				"1.2.3.4",
  4861  			},
  4862  			Ports: []v1.ServicePort{
  4863  				{
  4864  					Name:       "",
  4865  					Port:       80,
  4866  					TargetPort: intstr.FromInt32(80),
  4867  					Protocol:   v1.ProtocolTCP,
  4868  				},
  4869  			},
  4870  		},
  4871  	})
  4872  
  4873  	// Add initial endpoint slice
  4874  	endpointSlice := &discovery.EndpointSlice{
  4875  		ObjectMeta: metav1.ObjectMeta{
  4876  			Name:      fmt.Sprintf("%s-1", serviceName),
  4877  			Namespace: namespaceName,
  4878  			Labels:    map[string]string{discovery.LabelServiceName: serviceName},
  4879  		},
  4880  		Ports: []discovery.EndpointPort{{
  4881  			Name:     ptr.To(""),
  4882  			Port:     ptr.To[int32](80),
  4883  			Protocol: ptr.To(v1.ProtocolTCP),
  4884  		}},
  4885  		AddressType: discovery.AddressTypeIPv4,
  4886  		Endpoints: []discovery.Endpoint{
  4887  			{
  4888  				Addresses: []string{"10.0.1.1"},
  4889  				Conditions: discovery.EndpointConditions{
  4890  					Ready:       ptr.To(true),
  4891  					Serving:     ptr.To(true),
  4892  					Terminating: ptr.To(false),
  4893  				},
  4894  				NodeName: ptr.To(testHostname),
  4895  			},
  4896  			{
  4897  				Addresses: []string{"10.0.1.2"},
  4898  				Conditions: discovery.EndpointConditions{
  4899  					Ready:       ptr.To(true),
  4900  					Serving:     ptr.To(true),
  4901  					Terminating: ptr.To(false),
  4902  				},
  4903  				NodeName: ptr.To(testHostname),
  4904  			},
  4905  			{
  4906  				Addresses: []string{"10.0.1.3"},
  4907  				Conditions: discovery.EndpointConditions{
  4908  					Ready:       ptr.To(false),
  4909  					Serving:     ptr.To(true),
  4910  					Terminating: ptr.To(true),
  4911  				},
  4912  				NodeName: ptr.To(testHostname),
  4913  			},
  4914  			{
  4915  				Addresses: []string{"10.0.1.4"},
  4916  				Conditions: discovery.EndpointConditions{
  4917  					Ready:       ptr.To(false),
  4918  					Serving:     ptr.To(false),
  4919  					Terminating: ptr.To(true),
  4920  				},
  4921  				NodeName: ptr.To(testHostname),
  4922  			},
  4923  			{
  4924  				Addresses: []string{"10.0.1.5"},
  4925  				Conditions: discovery.EndpointConditions{
  4926  					Ready:       ptr.To(true),
  4927  					Serving:     ptr.To(true),
  4928  					Terminating: ptr.To(false),
  4929  				},
  4930  				NodeName: ptr.To("another-host"),
  4931  			},
  4932  		},
  4933  	}
  4934  
  4935  	fp.OnEndpointSliceAdd(endpointSlice)
  4936  	fp.syncProxyRules()
  4937  
  4938  	// Ensure that Proxier updates ipvs appropriately after EndpointSlice update
  4939  	assert.NotNil(t, fp.ipsetList["KUBE-LOOP-BACK"])
  4940  	activeEntries1 := fp.ipsetList["KUBE-LOOP-BACK"].activeEntries
  4941  	assert.Equal(t, 4, activeEntries1.Len(), "Expected 4 active entry in KUBE-LOOP-BACK")
  4942  	assert.Equal(t, true, activeEntries1.Has("10.0.1.1,tcp:80,10.0.1.1"), "Expected activeEntries to reference first pod")
  4943  	assert.Equal(t, true, activeEntries1.Has("10.0.1.2,tcp:80,10.0.1.2"), "Expected activeEntries to reference second pod")
  4944  	assert.Equal(t, true, activeEntries1.Has("10.0.1.3,tcp:80,10.0.1.3"), "Expected activeEntries to reference third pod")
  4945  	assert.Equal(t, true, activeEntries1.Has("10.0.1.4,tcp:80,10.0.1.4"), "Expected activeEntries to reference fourth pod")
  4946  
  4947  	virtualServers, vsErr := ipvs.GetVirtualServers()
  4948  	assert.Nil(t, vsErr, "Expected no error getting virtual servers")
  4949  	assert.Len(t, virtualServers, 2, "Expected 2 virtual server")
  4950  
  4951  	var clusterIPServer, externalIPServer *utilipvs.VirtualServer
  4952  	for _, virtualServer := range virtualServers {
  4953  		if virtualServer.Address.String() == "172.20.1.1" {
  4954  			clusterIPServer = virtualServer
  4955  		}
  4956  
  4957  		if virtualServer.Address.String() == "1.2.3.4" {
  4958  			externalIPServer = virtualServer
  4959  		}
  4960  	}
  4961  
  4962  	// clusterIP should route to cluster-wide ready endpoints
  4963  	realServers1, rsErr1 := ipvs.GetRealServers(clusterIPServer)
  4964  	assert.Nil(t, rsErr1, "Expected no error getting real servers")
  4965  	assert.Len(t, realServers1, 3, "Expected 3 real servers")
  4966  	assert.Equal(t, realServers1[0].String(), "10.0.1.1:80")
  4967  	assert.Equal(t, realServers1[1].String(), "10.0.1.2:80")
  4968  	assert.Equal(t, realServers1[2].String(), "10.0.1.5:80")
  4969  
  4970  	// externalIP should route to cluster-wide ready endpoints
  4971  	realServers2, rsErr2 := ipvs.GetRealServers(externalIPServer)
  4972  	assert.Nil(t, rsErr2, "Expected no error getting real servers")
  4973  	assert.Len(t, realServers2, 3, "Expected 3 real servers")
  4974  	assert.Equal(t, realServers2[0].String(), "10.0.1.1:80")
  4975  	assert.Equal(t, realServers2[1].String(), "10.0.1.2:80")
  4976  	assert.Equal(t, realServers1[2].String(), "10.0.1.5:80")
  4977  
  4978  	fp.OnEndpointSliceDelete(endpointSlice)
  4979  	fp.syncProxyRules()
  4980  
  4981  	// Ensure that Proxier updates ipvs appropriately after EndpointSlice delete
  4982  	assert.NotNil(t, fp.ipsetList["KUBE-LOOP-BACK"])
  4983  	activeEntries2 := fp.ipsetList["KUBE-LOOP-BACK"].activeEntries
  4984  	assert.Equal(t, 0, activeEntries2.Len(), "Expected 0 active entries in KUBE-LOOP-BACK")
  4985  
  4986  	virtualServers, vsErr = ipvs.GetVirtualServers()
  4987  	assert.Nil(t, vsErr, "Expected no error getting virtual servers")
  4988  	assert.Len(t, virtualServers, 2, "Expected 2 virtual server")
  4989  
  4990  	for _, virtualServer := range virtualServers {
  4991  		if virtualServer.Address.String() == "172.20.1.1" {
  4992  			clusterIPServer = virtualServer
  4993  		}
  4994  
  4995  		if virtualServer.Address.String() == "1.2.3.4" {
  4996  			externalIPServer = virtualServer
  4997  		}
  4998  	}
  4999  
  5000  	realServers1, rsErr1 = ipvs.GetRealServers(clusterIPServer)
  5001  	assert.Nil(t, rsErr1, "Expected no error getting real servers")
  5002  	assert.Len(t, realServers1, 0, "Expected 0 real servers")
  5003  
  5004  	realServers2, rsErr2 = ipvs.GetRealServers(externalIPServer)
  5005  	assert.Nil(t, rsErr2, "Expected no error getting real servers")
  5006  	assert.Len(t, realServers2, 0, "Expected 0 real servers")
  5007  }
  5008  
  5009  // Test_EndpointSliceReadyAndTerminatingLocal tests that when there are local ready and ready + terminating
  5010  // endpoints, only the ready endpoints are used.
  5011  func Test_EndpointSliceReadyAndTerminatingLocal(t *testing.T) {
  5012  	_, ctx := ktesting.NewTestContext(t)
  5013  	ipt := iptablestest.NewFake()
  5014  	ipvs := ipvstest.NewFake()
  5015  	ipset := ipsettest.NewFake(testIPSetVersion)
  5016  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  5017  	fp.servicesSynced = true
  5018  	// fp.endpointsSynced = true
  5019  	fp.endpointSlicesSynced = true
  5020  
  5021  	serviceName := "svc1"
  5022  	// Add initial service
  5023  	namespaceName := "ns1"
  5024  	fp.OnServiceAdd(&v1.Service{
  5025  		ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespaceName},
  5026  		Spec: v1.ServiceSpec{
  5027  			ClusterIP:             "172.20.1.1",
  5028  			Selector:              map[string]string{"foo": "bar"},
  5029  			Type:                  v1.ServiceTypeNodePort,
  5030  			ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyLocal,
  5031  			InternalTrafficPolicy: ptr.To(v1.ServiceInternalTrafficPolicyCluster),
  5032  			ExternalIPs: []string{
  5033  				"1.2.3.4",
  5034  			},
  5035  			Ports: []v1.ServicePort{
  5036  				{
  5037  					Name:       "",
  5038  					Port:       80,
  5039  					TargetPort: intstr.FromInt32(80),
  5040  					Protocol:   v1.ProtocolTCP,
  5041  				},
  5042  			},
  5043  		},
  5044  	})
  5045  
  5046  	// Add initial endpoint slice
  5047  	endpointSlice := &discovery.EndpointSlice{
  5048  		ObjectMeta: metav1.ObjectMeta{
  5049  			Name:      fmt.Sprintf("%s-1", serviceName),
  5050  			Namespace: namespaceName,
  5051  			Labels:    map[string]string{discovery.LabelServiceName: serviceName},
  5052  		},
  5053  		Ports: []discovery.EndpointPort{{
  5054  			Name:     ptr.To(""),
  5055  			Port:     ptr.To[int32](80),
  5056  			Protocol: ptr.To(v1.ProtocolTCP),
  5057  		}},
  5058  		AddressType: discovery.AddressTypeIPv4,
  5059  		Endpoints: []discovery.Endpoint{
  5060  			{
  5061  				Addresses: []string{"10.0.1.1"},
  5062  				Conditions: discovery.EndpointConditions{
  5063  					Ready:       ptr.To(true),
  5064  					Serving:     ptr.To(true),
  5065  					Terminating: ptr.To(false),
  5066  				},
  5067  				NodeName: ptr.To(testHostname),
  5068  			},
  5069  			{
  5070  				Addresses: []string{"10.0.1.2"},
  5071  				Conditions: discovery.EndpointConditions{
  5072  					Ready:       ptr.To(true),
  5073  					Serving:     ptr.To(true),
  5074  					Terminating: ptr.To(false),
  5075  				},
  5076  				NodeName: ptr.To(testHostname),
  5077  			},
  5078  			{
  5079  				Addresses: []string{"10.0.1.3"},
  5080  				Conditions: discovery.EndpointConditions{
  5081  					Ready:       ptr.To(false),
  5082  					Serving:     ptr.To(true),
  5083  					Terminating: ptr.To(true),
  5084  				},
  5085  				NodeName: ptr.To(testHostname),
  5086  			},
  5087  			{
  5088  				Addresses: []string{"10.0.1.4"},
  5089  				Conditions: discovery.EndpointConditions{
  5090  					Ready:       ptr.To(false),
  5091  					Serving:     ptr.To(false),
  5092  					Terminating: ptr.To(true),
  5093  				},
  5094  				NodeName: ptr.To(testHostname),
  5095  			},
  5096  			{
  5097  				Addresses: []string{"10.0.1.5"},
  5098  				Conditions: discovery.EndpointConditions{
  5099  					Ready:       ptr.To(true),
  5100  					Serving:     ptr.To(true),
  5101  					Terminating: ptr.To(false),
  5102  				},
  5103  				NodeName: ptr.To("another-host"),
  5104  			},
  5105  		},
  5106  	}
  5107  
  5108  	fp.OnEndpointSliceAdd(endpointSlice)
  5109  	fp.syncProxyRules()
  5110  
  5111  	// Ensure that Proxier updates ipvs appropriately after EndpointSlice update
  5112  	assert.NotNil(t, fp.ipsetList["KUBE-LOOP-BACK"])
  5113  	activeEntries1 := fp.ipsetList["KUBE-LOOP-BACK"].activeEntries
  5114  	assert.Equal(t, 4, activeEntries1.Len(), "Expected 3 active entry in KUBE-LOOP-BACK")
  5115  	assert.Equal(t, true, activeEntries1.Has("10.0.1.1,tcp:80,10.0.1.1"), "Expected activeEntries to reference first (local) pod")
  5116  	assert.Equal(t, true, activeEntries1.Has("10.0.1.2,tcp:80,10.0.1.2"), "Expected activeEntries to reference second (local) pod")
  5117  	assert.Equal(t, true, activeEntries1.Has("10.0.1.3,tcp:80,10.0.1.3"), "Expected activeEntries to reference second (local) pod")
  5118  	assert.Equal(t, true, activeEntries1.Has("10.0.1.4,tcp:80,10.0.1.4"), "Expected activeEntries to reference second (local) pod")
  5119  
  5120  	virtualServers, vsErr := ipvs.GetVirtualServers()
  5121  	assert.Nil(t, vsErr, "Expected no error getting virtual servers")
  5122  	assert.Len(t, virtualServers, 2, "Expected 2 virtual server")
  5123  
  5124  	var clusterIPServer, externalIPServer *utilipvs.VirtualServer
  5125  	for _, virtualServer := range virtualServers {
  5126  		if virtualServer.Address.String() == "172.20.1.1" {
  5127  			clusterIPServer = virtualServer
  5128  		}
  5129  
  5130  		if virtualServer.Address.String() == "1.2.3.4" {
  5131  			externalIPServer = virtualServer
  5132  		}
  5133  	}
  5134  
  5135  	// clusterIP should route to cluster-wide ready endpoints
  5136  	realServers1, rsErr1 := ipvs.GetRealServers(clusterIPServer)
  5137  	assert.Nil(t, rsErr1, "Expected no error getting real servers")
  5138  	assert.Len(t, realServers1, 3, "Expected 3 real servers")
  5139  	assert.Equal(t, realServers1[0].String(), "10.0.1.1:80")
  5140  	assert.Equal(t, realServers1[1].String(), "10.0.1.2:80")
  5141  	assert.Equal(t, realServers1[2].String(), "10.0.1.5:80")
  5142  
  5143  	// externalIP should route to local ready + non-terminating endpoints if they exist
  5144  	realServers2, rsErr2 := ipvs.GetRealServers(externalIPServer)
  5145  	assert.Nil(t, rsErr2, "Expected no error getting real servers")
  5146  	assert.Len(t, realServers2, 2, "Expected 2 real servers")
  5147  	assert.Equal(t, realServers2[0].String(), "10.0.1.1:80")
  5148  	assert.Equal(t, realServers2[1].String(), "10.0.1.2:80")
  5149  
  5150  	fp.OnEndpointSliceDelete(endpointSlice)
  5151  	fp.syncProxyRules()
  5152  
  5153  	// Ensure that Proxier updates ipvs appropriately after EndpointSlice delete
  5154  	assert.NotNil(t, fp.ipsetList["KUBE-LOOP-BACK"])
  5155  	activeEntries2 := fp.ipsetList["KUBE-LOOP-BACK"].activeEntries
  5156  	assert.Equal(t, 0, activeEntries2.Len(), "Expected 0 active entries in KUBE-LOOP-BACK")
  5157  
  5158  	virtualServers, vsErr = ipvs.GetVirtualServers()
  5159  	assert.Nil(t, vsErr, "Expected no error getting virtual servers")
  5160  	assert.Len(t, virtualServers, 2, "Expected 2 virtual server")
  5161  
  5162  	for _, virtualServer := range virtualServers {
  5163  		if virtualServer.Address.String() == "172.20.1.1" {
  5164  			clusterIPServer = virtualServer
  5165  		}
  5166  
  5167  		if virtualServer.Address.String() == "1.2.3.4" {
  5168  			externalIPServer = virtualServer
  5169  		}
  5170  	}
  5171  
  5172  	realServers1, rsErr1 = ipvs.GetRealServers(clusterIPServer)
  5173  	assert.Nil(t, rsErr1, "Expected no error getting real servers")
  5174  	assert.Len(t, realServers1, 0, "Expected 0 real servers")
  5175  
  5176  	realServers2, rsErr2 = ipvs.GetRealServers(externalIPServer)
  5177  	assert.Nil(t, rsErr2, "Expected no error getting real servers")
  5178  	assert.Len(t, realServers2, 0, "Expected 0 real servers")
  5179  }
  5180  
  5181  // Test_EndpointSliceOnlyReadyTerminatingCluster tests that when there are only ready terminating
  5182  // endpoints and the traffic policy is "Cluster",  we fall back to terminating endpoints.
  5183  func Test_EndpointSliceOnlyReadyAndTerminatingCluster(t *testing.T) {
  5184  	_, ctx := ktesting.NewTestContext(t)
  5185  	ipt := iptablestest.NewFake()
  5186  	ipvs := ipvstest.NewFake()
  5187  	ipset := ipsettest.NewFake(testIPSetVersion)
  5188  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  5189  	fp.servicesSynced = true
  5190  	// fp.endpointsSynced = true
  5191  	fp.endpointSlicesSynced = true
  5192  
  5193  	// Add initial service
  5194  	serviceName := "svc1"
  5195  	namespaceName := "ns1"
  5196  	fp.OnServiceAdd(&v1.Service{
  5197  		ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespaceName},
  5198  		Spec: v1.ServiceSpec{
  5199  			ClusterIP:             "172.20.1.1",
  5200  			Selector:              map[string]string{"foo": "bar"},
  5201  			Type:                  v1.ServiceTypeNodePort,
  5202  			ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyCluster,
  5203  			InternalTrafficPolicy: ptr.To(v1.ServiceInternalTrafficPolicyCluster),
  5204  			ExternalIPs: []string{
  5205  				"1.2.3.4",
  5206  			},
  5207  			Ports: []v1.ServicePort{
  5208  				{
  5209  					Name:       "",
  5210  					Port:       80,
  5211  					TargetPort: intstr.FromInt32(80),
  5212  					Protocol:   v1.ProtocolTCP,
  5213  				},
  5214  			},
  5215  		},
  5216  	})
  5217  
  5218  	// Add initial endpoint slice
  5219  	endpointSlice := &discovery.EndpointSlice{
  5220  		ObjectMeta: metav1.ObjectMeta{
  5221  			Name:      fmt.Sprintf("%s-1", serviceName),
  5222  			Namespace: namespaceName,
  5223  			Labels:    map[string]string{discovery.LabelServiceName: serviceName},
  5224  		},
  5225  		Ports: []discovery.EndpointPort{{
  5226  			Name:     ptr.To(""),
  5227  			Port:     ptr.To[int32](80),
  5228  			Protocol: ptr.To(v1.ProtocolTCP),
  5229  		}},
  5230  		AddressType: discovery.AddressTypeIPv4,
  5231  		Endpoints: []discovery.Endpoint{
  5232  			{
  5233  				Addresses: []string{"10.0.1.1"},
  5234  				Conditions: discovery.EndpointConditions{
  5235  					Ready:       ptr.To(false),
  5236  					Serving:     ptr.To(true),
  5237  					Terminating: ptr.To(true),
  5238  				},
  5239  				NodeName: ptr.To(testHostname),
  5240  			},
  5241  			{
  5242  				Addresses: []string{"10.0.1.2"},
  5243  				Conditions: discovery.EndpointConditions{
  5244  					Ready:       ptr.To(false),
  5245  					Serving:     ptr.To(true),
  5246  					Terminating: ptr.To(true),
  5247  				},
  5248  				NodeName: ptr.To(testHostname),
  5249  			},
  5250  			{
  5251  				Addresses: []string{"10.0.1.3"},
  5252  				Conditions: discovery.EndpointConditions{
  5253  					Ready:       ptr.To(false),
  5254  					Serving:     ptr.To(false),
  5255  					Terminating: ptr.To(true),
  5256  				},
  5257  				NodeName: ptr.To(testHostname),
  5258  			},
  5259  			{
  5260  				Addresses: []string{"10.0.1.4"},
  5261  				Conditions: discovery.EndpointConditions{
  5262  					Ready:       ptr.To(false),
  5263  					Serving:     ptr.To(true),
  5264  					Terminating: ptr.To(true),
  5265  				},
  5266  				NodeName: ptr.To("another-host"),
  5267  			},
  5268  			{
  5269  				Addresses: []string{"10.0.1.5"},
  5270  				Conditions: discovery.EndpointConditions{
  5271  					Ready:       ptr.To(false),
  5272  					Serving:     ptr.To(false),
  5273  					Terminating: ptr.To(false),
  5274  				},
  5275  				NodeName: ptr.To("another-host"),
  5276  			},
  5277  		},
  5278  	}
  5279  
  5280  	fp.OnEndpointSliceAdd(endpointSlice)
  5281  	fp.syncProxyRules()
  5282  
  5283  	// Ensure that Proxier updates ipvs appropriately after EndpointSlice update
  5284  	assert.NotNil(t, fp.ipsetList["KUBE-LOOP-BACK"])
  5285  	activeEntries1 := fp.ipsetList["KUBE-LOOP-BACK"].activeEntries
  5286  	assert.Equal(t, 3, activeEntries1.Len(), "Expected 3 active entry in KUBE-LOOP-BACK")
  5287  	assert.Equal(t, true, activeEntries1.Has("10.0.1.1,tcp:80,10.0.1.1"), "Expected activeEntries to reference first (local) pod")
  5288  	assert.Equal(t, true, activeEntries1.Has("10.0.1.2,tcp:80,10.0.1.2"), "Expected activeEntries to reference second (local) pod")
  5289  	assert.Equal(t, true, activeEntries1.Has("10.0.1.3,tcp:80,10.0.1.3"), "Expected activeEntries to reference second (local) pod")
  5290  
  5291  	virtualServers, vsErr := ipvs.GetVirtualServers()
  5292  	assert.Nil(t, vsErr, "Expected no error getting virtual servers")
  5293  	assert.Len(t, virtualServers, 2, "Expected 2 virtual server")
  5294  
  5295  	var clusterIPServer, externalIPServer *utilipvs.VirtualServer
  5296  	for _, virtualServer := range virtualServers {
  5297  		if virtualServer.Address.String() == "172.20.1.1" {
  5298  			clusterIPServer = virtualServer
  5299  		}
  5300  
  5301  		if virtualServer.Address.String() == "1.2.3.4" {
  5302  			externalIPServer = virtualServer
  5303  		}
  5304  	}
  5305  
  5306  	// clusterIP should fall back to cluster-wide ready + terminating endpoints
  5307  	realServers1, rsErr1 := ipvs.GetRealServers(clusterIPServer)
  5308  	assert.Nil(t, rsErr1, "Expected no error getting real servers")
  5309  	assert.Len(t, realServers1, 3, "Expected 1 real servers")
  5310  	assert.Equal(t, realServers1[0].String(), "10.0.1.1:80")
  5311  	assert.Equal(t, realServers1[1].String(), "10.0.1.2:80")
  5312  	assert.Equal(t, realServers1[2].String(), "10.0.1.4:80")
  5313  
  5314  	// externalIP should fall back to ready + terminating endpoints
  5315  	realServers2, rsErr2 := ipvs.GetRealServers(externalIPServer)
  5316  	assert.Nil(t, rsErr2, "Expected no error getting real servers")
  5317  	assert.Len(t, realServers2, 3, "Expected 2 real servers")
  5318  	assert.Equal(t, realServers2[0].String(), "10.0.1.1:80")
  5319  	assert.Equal(t, realServers2[1].String(), "10.0.1.2:80")
  5320  	assert.Equal(t, realServers2[2].String(), "10.0.1.4:80")
  5321  
  5322  	fp.OnEndpointSliceDelete(endpointSlice)
  5323  	fp.syncProxyRules()
  5324  
  5325  	// Ensure that Proxier updates ipvs appropriately after EndpointSlice delete
  5326  	assert.NotNil(t, fp.ipsetList["KUBE-LOOP-BACK"])
  5327  	activeEntries2 := fp.ipsetList["KUBE-LOOP-BACK"].activeEntries
  5328  	assert.Equal(t, 0, activeEntries2.Len(), "Expected 0 active entries in KUBE-LOOP-BACK")
  5329  
  5330  	virtualServers, vsErr = ipvs.GetVirtualServers()
  5331  	assert.Nil(t, vsErr, "Expected no error getting virtual servers")
  5332  	assert.Len(t, virtualServers, 2, "Expected 2 virtual server")
  5333  
  5334  	for _, virtualServer := range virtualServers {
  5335  		if virtualServer.Address.String() == "172.20.1.1" {
  5336  			clusterIPServer = virtualServer
  5337  		}
  5338  
  5339  		if virtualServer.Address.String() == "1.2.3.4" {
  5340  			externalIPServer = virtualServer
  5341  		}
  5342  	}
  5343  
  5344  	realServers1, rsErr1 = ipvs.GetRealServers(clusterIPServer)
  5345  	assert.Nil(t, rsErr1, "Expected no error getting real servers")
  5346  	assert.Len(t, realServers1, 0, "Expected 0 real servers")
  5347  
  5348  	realServers2, rsErr2 = ipvs.GetRealServers(externalIPServer)
  5349  	assert.Nil(t, rsErr2, "Expected no error getting real servers")
  5350  	assert.Len(t, realServers2, 0, "Expected 0 real servers")
  5351  }
  5352  
  5353  // Test_EndpointSliceOnlyReadyTerminatingLocal tests that when there are only local ready terminating
  5354  // endpoints, we fall back to those endpoints.
  5355  func Test_EndpointSliceOnlyReadyAndTerminatingLocal(t *testing.T) {
  5356  	_, ctx := ktesting.NewTestContext(t)
  5357  	ipt := iptablestest.NewFake()
  5358  	ipvs := ipvstest.NewFake()
  5359  	ipset := ipsettest.NewFake(testIPSetVersion)
  5360  	fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, v1.IPv4Protocol)
  5361  	fp.servicesSynced = true
  5362  	// fp.endpointsSynced = true
  5363  	fp.endpointSlicesSynced = true
  5364  
  5365  	// Add initial service
  5366  	serviceName := "svc1"
  5367  	namespaceName := "ns1"
  5368  	fp.OnServiceAdd(&v1.Service{
  5369  		ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespaceName},
  5370  		Spec: v1.ServiceSpec{
  5371  			ClusterIP:             "172.20.1.1",
  5372  			Selector:              map[string]string{"foo": "bar"},
  5373  			Type:                  v1.ServiceTypeNodePort,
  5374  			ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyLocal,
  5375  			InternalTrafficPolicy: ptr.To(v1.ServiceInternalTrafficPolicyCluster),
  5376  			ExternalIPs: []string{
  5377  				"1.2.3.4",
  5378  			},
  5379  			Ports: []v1.ServicePort{
  5380  				{
  5381  					Name:       "",
  5382  					Port:       80,
  5383  					TargetPort: intstr.FromInt32(80),
  5384  					Protocol:   v1.ProtocolTCP,
  5385  				},
  5386  			},
  5387  		},
  5388  	})
  5389  
  5390  	// Add initial endpoint slice
  5391  	endpointSlice := &discovery.EndpointSlice{
  5392  		ObjectMeta: metav1.ObjectMeta{
  5393  			Name:      fmt.Sprintf("%s-1", serviceName),
  5394  			Namespace: namespaceName,
  5395  			Labels:    map[string]string{discovery.LabelServiceName: serviceName},
  5396  		},
  5397  		Ports: []discovery.EndpointPort{{
  5398  			Name:     ptr.To(""),
  5399  			Port:     ptr.To[int32](80),
  5400  			Protocol: ptr.To(v1.ProtocolTCP),
  5401  		}},
  5402  		AddressType: discovery.AddressTypeIPv4,
  5403  		Endpoints: []discovery.Endpoint{
  5404  			{
  5405  				Addresses: []string{"10.0.1.1"},
  5406  				Conditions: discovery.EndpointConditions{
  5407  					Ready:       ptr.To(false),
  5408  					Serving:     ptr.To(true),
  5409  					Terminating: ptr.To(true),
  5410  				},
  5411  				NodeName: ptr.To(testHostname),
  5412  			},
  5413  			{
  5414  				Addresses: []string{"10.0.1.2"},
  5415  				Conditions: discovery.EndpointConditions{
  5416  					Ready:       ptr.To(false),
  5417  					Serving:     ptr.To(true),
  5418  					Terminating: ptr.To(true),
  5419  				},
  5420  				NodeName: ptr.To(testHostname),
  5421  			},
  5422  			{
  5423  				Addresses: []string{"10.0.1.3"},
  5424  				Conditions: discovery.EndpointConditions{
  5425  					Ready:       ptr.To(false),
  5426  					Serving:     ptr.To(false),
  5427  					Terminating: ptr.To(true),
  5428  				},
  5429  				NodeName: ptr.To(testHostname),
  5430  			},
  5431  			{
  5432  				Addresses: []string{"10.0.1.4"},
  5433  				Conditions: discovery.EndpointConditions{
  5434  					Ready:       ptr.To(false),
  5435  					Serving:     ptr.To(true),
  5436  					Terminating: ptr.To(true),
  5437  				},
  5438  				NodeName: ptr.To("another-host"),
  5439  			},
  5440  			{
  5441  				Addresses: []string{"10.0.1.5"},
  5442  				Conditions: discovery.EndpointConditions{
  5443  					Ready:       ptr.To(true),
  5444  					Serving:     ptr.To(true),
  5445  					Terminating: ptr.To(false),
  5446  				},
  5447  				NodeName: ptr.To("another-host"),
  5448  			},
  5449  		},
  5450  	}
  5451  
  5452  	fp.OnEndpointSliceAdd(endpointSlice)
  5453  	fp.syncProxyRules()
  5454  
  5455  	// Ensure that Proxier updates ipvs appropriately after EndpointSlice update
  5456  	assert.NotNil(t, fp.ipsetList["KUBE-LOOP-BACK"])
  5457  	activeEntries1 := fp.ipsetList["KUBE-LOOP-BACK"].activeEntries
  5458  	assert.Equal(t, 3, activeEntries1.Len(), "Expected 3 active entry in KUBE-LOOP-BACK")
  5459  	assert.Equal(t, true, activeEntries1.Has("10.0.1.1,tcp:80,10.0.1.1"), "Expected activeEntries to reference first (local) pod")
  5460  	assert.Equal(t, true, activeEntries1.Has("10.0.1.2,tcp:80,10.0.1.2"), "Expected activeEntries to reference second (local) pod")
  5461  	assert.Equal(t, true, activeEntries1.Has("10.0.1.3,tcp:80,10.0.1.3"), "Expected activeEntries to reference second (local) pod")
  5462  
  5463  	virtualServers, vsErr := ipvs.GetVirtualServers()
  5464  	assert.Nil(t, vsErr, "Expected no error getting virtual servers")
  5465  	assert.Len(t, virtualServers, 2, "Expected 2 virtual server")
  5466  
  5467  	var clusterIPServer, externalIPServer *utilipvs.VirtualServer
  5468  	for _, virtualServer := range virtualServers {
  5469  		if virtualServer.Address.String() == "172.20.1.1" {
  5470  			clusterIPServer = virtualServer
  5471  		}
  5472  
  5473  		if virtualServer.Address.String() == "1.2.3.4" {
  5474  			externalIPServer = virtualServer
  5475  		}
  5476  	}
  5477  
  5478  	// clusterIP should route to cluster-wide Ready endpoints
  5479  	realServers1, rsErr1 := ipvs.GetRealServers(clusterIPServer)
  5480  	assert.Nil(t, rsErr1, "Expected no error getting real servers")
  5481  	assert.Len(t, realServers1, 1, "Expected 1 real servers")
  5482  	assert.Equal(t, realServers1[0].String(), "10.0.1.5:80")
  5483  
  5484  	// externalIP should fall back to local ready + terminating endpoints
  5485  	realServers2, rsErr2 := ipvs.GetRealServers(externalIPServer)
  5486  	assert.Nil(t, rsErr2, "Expected no error getting real servers")
  5487  	assert.Len(t, realServers2, 2, "Expected 2 real servers")
  5488  	assert.Equal(t, realServers2[0].String(), "10.0.1.1:80")
  5489  	assert.Equal(t, realServers2[1].String(), "10.0.1.2:80")
  5490  
  5491  	fp.OnEndpointSliceDelete(endpointSlice)
  5492  	fp.syncProxyRules()
  5493  
  5494  	// Ensure that Proxier updates ipvs appropriately after EndpointSlice delete
  5495  	assert.NotNil(t, fp.ipsetList["KUBE-LOOP-BACK"])
  5496  	activeEntries2 := fp.ipsetList["KUBE-LOOP-BACK"].activeEntries
  5497  	assert.Equal(t, 0, activeEntries2.Len(), "Expected 0 active entries in KUBE-LOOP-BACK")
  5498  
  5499  	virtualServers, vsErr = ipvs.GetVirtualServers()
  5500  	assert.Nil(t, vsErr, "Expected no error getting virtual servers")
  5501  	assert.Len(t, virtualServers, 2, "Expected 2 virtual server")
  5502  
  5503  	for _, virtualServer := range virtualServers {
  5504  		if virtualServer.Address.String() == "172.20.1.1" {
  5505  			clusterIPServer = virtualServer
  5506  		}
  5507  
  5508  		if virtualServer.Address.String() == "1.2.3.4" {
  5509  			externalIPServer = virtualServer
  5510  		}
  5511  	}
  5512  
  5513  	realServers1, rsErr1 = ipvs.GetRealServers(clusterIPServer)
  5514  	assert.Nil(t, rsErr1, "Expected no error getting real servers")
  5515  	assert.Len(t, realServers1, 0, "Expected 0 real servers")
  5516  
  5517  	realServers2, rsErr2 = ipvs.GetRealServers(externalIPServer)
  5518  	assert.Nil(t, rsErr2, "Expected no error getting real servers")
  5519  	assert.Len(t, realServers2, 0, "Expected 0 real servers")
  5520  }
  5521  
  5522  func TestIpIsValidForSet(t *testing.T) {
  5523  	testCases := []struct {
  5524  		isIPv6 bool
  5525  		ip     string
  5526  		res    bool
  5527  	}{
  5528  		{
  5529  			false,
  5530  			"127.0.0.1",
  5531  			false,
  5532  		},
  5533  		{
  5534  			false,
  5535  			"127.0.0.0",
  5536  			false,
  5537  		},
  5538  		{
  5539  			false,
  5540  			"127.6.7.8",
  5541  			false,
  5542  		},
  5543  		{
  5544  			false,
  5545  			"8.8.8.8",
  5546  			true,
  5547  		},
  5548  		{
  5549  			false,
  5550  			"192.168.0.1",
  5551  			true,
  5552  		},
  5553  		{
  5554  			false,
  5555  			"169.254.0.0",
  5556  			true,
  5557  		},
  5558  		{
  5559  			false,
  5560  			"::ffff:169.254.0.0", // IPv6 mapped IPv4
  5561  			true,
  5562  		},
  5563  		{
  5564  			false,
  5565  			"1000::",
  5566  			false,
  5567  		},
  5568  		// IPv6
  5569  		{
  5570  			true,
  5571  			"::1",
  5572  			false,
  5573  		},
  5574  		{
  5575  			true,
  5576  			"1000::",
  5577  			true,
  5578  		},
  5579  		{
  5580  			true,
  5581  			"fe80::200:ff:fe01:1",
  5582  			false,
  5583  		},
  5584  		{
  5585  			true,
  5586  			"8.8.8.8",
  5587  			false,
  5588  		},
  5589  		{
  5590  			true,
  5591  			"::ffff:8.8.8.8",
  5592  			false,
  5593  		},
  5594  	}
  5595  
  5596  	for _, tc := range testCases {
  5597  		v := &netlinkHandle{}
  5598  		v.isIPv6 = tc.isIPv6
  5599  		ip := netutils.ParseIPSloppy(tc.ip)
  5600  		if ip == nil {
  5601  			t.Errorf("Parse error: %s", tc.ip)
  5602  		}
  5603  		if v.isValidForSet(ip) != tc.res {
  5604  			if tc.isIPv6 {
  5605  				t.Errorf("IPv6: %s", tc.ip)
  5606  			} else {
  5607  				t.Errorf("IPv4: %s", tc.ip)
  5608  			}
  5609  		}
  5610  	}
  5611  }
  5612  
  5613  func TestNoEndpointsMetric(t *testing.T) {
  5614  	type endpoint struct {
  5615  		ip       string
  5616  		hostname string
  5617  	}
  5618  
  5619  	metrics.RegisterMetrics(kubeproxyconfig.ProxyModeIPVS)
  5620  
  5621  	testCases := []struct {
  5622  		name                                                string
  5623  		internalTrafficPolicy                               *v1.ServiceInternalTrafficPolicy
  5624  		externalTrafficPolicy                               v1.ServiceExternalTrafficPolicy
  5625  		endpoints                                           []endpoint
  5626  		expectedSyncProxyRulesNoLocalEndpointsTotalInternal int
  5627  		expectedSyncProxyRulesNoLocalEndpointsTotalExternal int
  5628  	}{
  5629  		{
  5630  			name:                  "internalTrafficPolicy is set and there are local endpoints",
  5631  			internalTrafficPolicy: ptr.To(v1.ServiceInternalTrafficPolicyLocal),
  5632  			endpoints: []endpoint{
  5633  				{"10.0.1.1", testHostname},
  5634  				{"10.0.1.2", "host1"},
  5635  				{"10.0.1.3", "host2"},
  5636  			},
  5637  		},
  5638  		{
  5639  			name:                  "externalTrafficPolicy is set and there are local endpoints",
  5640  			externalTrafficPolicy: v1.ServiceExternalTrafficPolicyLocal,
  5641  			endpoints: []endpoint{
  5642  				{"10.0.1.1", testHostname},
  5643  				{"10.0.1.2", "host1"},
  5644  				{"10.0.1.3", "host2"},
  5645  			},
  5646  		},
  5647  		{
  5648  			name:                  "both policies are set and there are local endpoints",
  5649  			internalTrafficPolicy: ptr.To(v1.ServiceInternalTrafficPolicyLocal),
  5650  			externalTrafficPolicy: v1.ServiceExternalTrafficPolicyLocal,
  5651  			endpoints: []endpoint{
  5652  				{"10.0.1.1", testHostname},
  5653  				{"10.0.1.2", "host1"},
  5654  				{"10.0.1.3", "host2"},
  5655  			},
  5656  		},
  5657  		{
  5658  			name:                  "internalTrafficPolicy is set and there are no local endpoints",
  5659  			internalTrafficPolicy: ptr.To(v1.ServiceInternalTrafficPolicyLocal),
  5660  			endpoints: []endpoint{
  5661  				{"10.0.1.1", "host0"},
  5662  				{"10.0.1.2", "host1"},
  5663  				{"10.0.1.3", "host2"},
  5664  			},
  5665  			expectedSyncProxyRulesNoLocalEndpointsTotalInternal: 1,
  5666  		},
  5667  		{
  5668  			name:                  "externalTrafficPolicy is set and there are no local endpoints",
  5669  			externalTrafficPolicy: v1.ServiceExternalTrafficPolicyLocal,
  5670  			endpoints: []endpoint{
  5671  				{"10.0.1.1", "host0"},
  5672  				{"10.0.1.2", "host1"},
  5673  				{"10.0.1.3", "host2"},
  5674  			},
  5675  			expectedSyncProxyRulesNoLocalEndpointsTotalExternal: 1,
  5676  		},
  5677  		{
  5678  			name:                  "Both policies are set and there are no local endpoints",
  5679  			internalTrafficPolicy: ptr.To(v1.ServiceInternalTrafficPolicyLocal),
  5680  			externalTrafficPolicy: v1.ServiceExternalTrafficPolicyLocal,
  5681  			endpoints: []endpoint{
  5682  				{"10.0.1.1", "host0"},
  5683  				{"10.0.1.2", "host1"},
  5684  				{"10.0.1.3", "host2"},
  5685  			},
  5686  			expectedSyncProxyRulesNoLocalEndpointsTotalInternal: 1,
  5687  			expectedSyncProxyRulesNoLocalEndpointsTotalExternal: 1,
  5688  		},
  5689  		{
  5690  			name:                  "Both policies are set and there are no endpoints at all",
  5691  			internalTrafficPolicy: ptr.To(v1.ServiceInternalTrafficPolicyLocal),
  5692  			externalTrafficPolicy: v1.ServiceExternalTrafficPolicyLocal,
  5693  			endpoints:             []endpoint{},
  5694  			expectedSyncProxyRulesNoLocalEndpointsTotalInternal: 0,
  5695  			expectedSyncProxyRulesNoLocalEndpointsTotalExternal: 0,
  5696  		},
  5697  	}
  5698  	for _, tc := range testCases {
  5699  		_, ctx := ktesting.NewTestContext(t)
  5700  		ipt := iptablestest.NewFake()
  5701  		ipvs := ipvstest.NewFake()
  5702  		ipset := ipsettest.NewFake(testIPSetVersion)
  5703  		fp := NewFakeProxier(ctx, ipt, ipvs, ipset, []string{"10.0.0.1"}, nil, v1.IPv4Protocol)
  5704  		fp.servicesSynced = true
  5705  		// fp.endpointsSynced = true
  5706  		fp.endpointSlicesSynced = true
  5707  
  5708  		// Add initial service
  5709  		serviceName := "svc1"
  5710  		namespaceName := "ns1"
  5711  
  5712  		svc := &v1.Service{
  5713  			ObjectMeta: metav1.ObjectMeta{Name: serviceName, Namespace: namespaceName},
  5714  			Spec: v1.ServiceSpec{
  5715  				ClusterIP: "172.20.1.1",
  5716  				Selector:  map[string]string{"foo": "bar"},
  5717  				Ports:     []v1.ServicePort{{Name: "p80", Port: 80, TargetPort: intstr.FromInt32(80), Protocol: v1.ProtocolTCP, NodePort: 30000}},
  5718  			},
  5719  		}
  5720  		if tc.internalTrafficPolicy != nil {
  5721  			svc.Spec.InternalTrafficPolicy = tc.internalTrafficPolicy
  5722  		}
  5723  		if tc.externalTrafficPolicy != "" {
  5724  			svc.Spec.Type = v1.ServiceTypeNodePort
  5725  			svc.Spec.ExternalTrafficPolicy = tc.externalTrafficPolicy
  5726  		}
  5727  
  5728  		fp.OnServiceAdd(svc)
  5729  
  5730  		// Add initial endpoint slice
  5731  		endpointSlice := &discovery.EndpointSlice{
  5732  			ObjectMeta: metav1.ObjectMeta{
  5733  				Name:      fmt.Sprintf("%s-1", serviceName),
  5734  				Namespace: namespaceName,
  5735  				Labels:    map[string]string{discovery.LabelServiceName: serviceName},
  5736  			},
  5737  			Ports: []discovery.EndpointPort{{
  5738  				Name:     ptr.To("p80"),
  5739  				Port:     ptr.To[int32](80),
  5740  				Protocol: ptr.To(v1.ProtocolTCP),
  5741  			}},
  5742  			AddressType: discovery.AddressTypeIPv4,
  5743  		}
  5744  
  5745  		for _, ep := range tc.endpoints {
  5746  			endpointSlice.Endpoints = append(endpointSlice.Endpoints, discovery.Endpoint{
  5747  				Addresses:  []string{ep.ip},
  5748  				Conditions: discovery.EndpointConditions{Ready: ptr.To(true)},
  5749  				NodeName:   ptr.To(ep.hostname),
  5750  			})
  5751  		}
  5752  
  5753  		fp.OnEndpointSliceAdd(endpointSlice)
  5754  		fp.syncProxyRules()
  5755  
  5756  		syncProxyRulesNoLocalEndpointsTotalInternal, err := testutil.GetGaugeMetricValue(metrics.SyncProxyRulesNoLocalEndpointsTotal.WithLabelValues("internal"))
  5757  		if err != nil {
  5758  			t.Errorf("failed to get %s value(internal), err: %v", metrics.SyncProxyRulesNoLocalEndpointsTotal.Name, err)
  5759  		}
  5760  
  5761  		if tc.expectedSyncProxyRulesNoLocalEndpointsTotalInternal != int(syncProxyRulesNoLocalEndpointsTotalInternal) {
  5762  			t.Errorf("sync_proxy_rules_no_endpoints_total metric mismatch(internal): got=%d, expected %d", int(syncProxyRulesNoLocalEndpointsTotalInternal), tc.expectedSyncProxyRulesNoLocalEndpointsTotalInternal)
  5763  		}
  5764  
  5765  		syncProxyRulesNoLocalEndpointsTotalExternal, err := testutil.GetGaugeMetricValue(metrics.SyncProxyRulesNoLocalEndpointsTotal.WithLabelValues("external"))
  5766  		if err != nil {
  5767  			t.Errorf("failed to get %s value(external), err: %v", metrics.SyncProxyRulesNoLocalEndpointsTotal.Name, err)
  5768  		}
  5769  
  5770  		if tc.expectedSyncProxyRulesNoLocalEndpointsTotalExternal != int(syncProxyRulesNoLocalEndpointsTotalExternal) {
  5771  			t.Errorf("sync_proxy_rules_no_endpoints_total metric mismatch(external): got=%d, expected %d", int(syncProxyRulesNoLocalEndpointsTotalExternal), tc.expectedSyncProxyRulesNoLocalEndpointsTotalExternal)
  5772  		}
  5773  	}
  5774  }
  5775  
  5776  func TestDismissLocalhostRuleExist(t *testing.T) {
  5777  	tests := []struct {
  5778  		name     string
  5779  		ipFamily v1.IPFamily
  5780  		src      string
  5781  	}{
  5782  		{
  5783  			name:     "ipv4 rule",
  5784  			ipFamily: v1.IPv4Protocol,
  5785  			src:      "127.0.0.0/8",
  5786  		},
  5787  		{
  5788  			name:     "ipv6 rule",
  5789  			ipFamily: v1.IPv6Protocol,
  5790  			src:      "::1/128",
  5791  		},
  5792  	}
  5793  	for _, test := range tests {
  5794  		t.Run(test.name, func(t *testing.T) {
  5795  			_, ctx := ktesting.NewTestContext(t)
  5796  			ipt := iptablestest.NewFake()
  5797  			if test.ipFamily == v1.IPv6Protocol {
  5798  				ipt = iptablestest.NewIPv6Fake()
  5799  			}
  5800  			ipvs := ipvstest.NewFake()
  5801  			ipset := ipsettest.NewFake(testIPSetVersion)
  5802  			fp := NewFakeProxier(ctx, ipt, ipvs, ipset, nil, nil, test.ipFamily)
  5803  
  5804  			fp.syncProxyRules()
  5805  
  5806  			rules := getRules(ipt, kubeServicesChain)
  5807  			if len(rules) <= 0 {
  5808  				t.Errorf("skip loop back ip in kubeservice chain not exist")
  5809  				return
  5810  			}
  5811  			if !rules[0].Jump.Matches("RETURN") || !rules[0].SourceAddress.Matches(test.src) {
  5812  				t.Errorf("rules not match, expect jump: %s, got: %s; expect source address: %s, got: %s", "RETURN", rules[0].Jump.String(), test.src, rules[0].SourceAddress.String())
  5813  			}
  5814  		})
  5815  	}
  5816  }
  5817  
  5818  func TestLoadBalancerIngressRouteTypeProxy(t *testing.T) {
  5819  	testCases := []struct {
  5820  		name             string
  5821  		ipModeEnabled    bool
  5822  		svcIP            string
  5823  		svcLBIP          string
  5824  		ipMode           *v1.LoadBalancerIPMode
  5825  		expectedServices int
  5826  	}{
  5827  		/* LoadBalancerIPMode disabled */
  5828  		{
  5829  			name:             "LoadBalancerIPMode disabled, ipMode Proxy",
  5830  			ipModeEnabled:    false,
  5831  			svcIP:            "10.20.30.41",
  5832  			svcLBIP:          "1.2.3.4",
  5833  			ipMode:           ptr.To(v1.LoadBalancerIPModeProxy),
  5834  			expectedServices: 2,
  5835  		},
  5836  		{
  5837  			name:             "LoadBalancerIPMode disabled, ipMode VIP",
  5838  			ipModeEnabled:    false,
  5839  			svcIP:            "10.20.30.42",
  5840  			svcLBIP:          "1.2.3.5",
  5841  			ipMode:           ptr.To(v1.LoadBalancerIPModeVIP),
  5842  			expectedServices: 2,
  5843  		},
  5844  		{
  5845  			name:             "LoadBalancerIPMode disabled, ipMode nil",
  5846  			ipModeEnabled:    false,
  5847  			svcIP:            "10.20.30.43",
  5848  			svcLBIP:          "1.2.3.6",
  5849  			ipMode:           nil,
  5850  			expectedServices: 2,
  5851  		},
  5852  		/* LoadBalancerIPMode enabled */
  5853  		{
  5854  			name:             "LoadBalancerIPMode enabled, ipMode Proxy",
  5855  			ipModeEnabled:    true,
  5856  			svcIP:            "10.20.30.41",
  5857  			svcLBIP:          "1.2.3.4",
  5858  			ipMode:           ptr.To(v1.LoadBalancerIPModeProxy),
  5859  			expectedServices: 1,
  5860  		},
  5861  		{
  5862  			name:             "LoadBalancerIPMode enabled, ipMode VIP",
  5863  			ipModeEnabled:    true,
  5864  			svcIP:            "10.20.30.42",
  5865  			svcLBIP:          "1.2.3.5",
  5866  			ipMode:           ptr.To(v1.LoadBalancerIPModeVIP),
  5867  			expectedServices: 2,
  5868  		},
  5869  		{
  5870  			name:             "LoadBalancerIPMode enabled, ipMode nil",
  5871  			ipModeEnabled:    true,
  5872  			svcIP:            "10.20.30.43",
  5873  			svcLBIP:          "1.2.3.6",
  5874  			ipMode:           nil,
  5875  			expectedServices: 2,
  5876  		},
  5877  	}
  5878  
  5879  	svcPort := 80
  5880  	svcNodePort := 3001
  5881  	svcPortName := proxy.ServicePortName{
  5882  		NamespacedName: makeNSN("ns1", "svc1"),
  5883  		Port:           "p80",
  5884  	}
  5885  
  5886  	for _, testCase := range testCases {
  5887  		t.Run(testCase.name, func(t *testing.T) {
  5888  			featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.LoadBalancerIPMode, testCase.ipModeEnabled)
  5889  			_, fp := buildFakeProxier(t)
  5890  			makeServiceMap(fp,
  5891  				makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
  5892  					svc.Spec.Type = "LoadBalancer"
  5893  					svc.Spec.ClusterIP = testCase.svcIP
  5894  					svc.Spec.Ports = []v1.ServicePort{{
  5895  						Name:     svcPortName.Port,
  5896  						Port:     int32(svcPort),
  5897  						Protocol: v1.ProtocolTCP,
  5898  						NodePort: int32(svcNodePort),
  5899  					}}
  5900  					svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
  5901  						IP:     testCase.svcLBIP,
  5902  						IPMode: testCase.ipMode,
  5903  					}}
  5904  				}),
  5905  			)
  5906  
  5907  			makeEndpointSliceMap(fp,
  5908  				makeTestEndpointSlice("ns1", "svc1", 1, func(eps *discovery.EndpointSlice) {
  5909  					eps.AddressType = discovery.AddressTypeIPv4
  5910  					eps.Endpoints = []discovery.Endpoint{{
  5911  						Addresses: []string{"10.180.0.1"},
  5912  					}}
  5913  					eps.Ports = []discovery.EndpointPort{{
  5914  						Name:     ptr.To("p80"),
  5915  						Port:     ptr.To[int32](80),
  5916  						Protocol: ptr.To(v1.ProtocolTCP),
  5917  					}}
  5918  				}),
  5919  			)
  5920  
  5921  			fp.syncProxyRules()
  5922  
  5923  			services, err := fp.ipvs.GetVirtualServers()
  5924  			if err != nil {
  5925  				t.Errorf("Failed to get ipvs services, err: %v", err)
  5926  			}
  5927  			if len(services) != testCase.expectedServices {
  5928  				t.Errorf("Expected %d ipvs services, got %d", testCase.expectedServices, len(services))
  5929  			}
  5930  		})
  5931  	}
  5932  }