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 }