github.com/cilium/cilium@v1.16.2/pkg/loadbalancer/loadbalancer_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package loadbalancer 5 6 import ( 7 "testing" 8 9 cmtypes "github.com/cilium/cilium/pkg/clustermesh/types" 10 ) 11 12 func TestL4Addr_Equals(t *testing.T) { 13 type args struct { 14 o *L4Addr 15 } 16 tests := []struct { 17 name string 18 fields *L4Addr 19 args args 20 want bool 21 }{ 22 { 23 name: "both equal", 24 fields: &L4Addr{ 25 Protocol: NONE, 26 Port: 1, 27 }, 28 args: args{ 29 o: &L4Addr{ 30 Protocol: NONE, 31 Port: 1, 32 }, 33 }, 34 want: true, 35 }, 36 { 37 name: "both different", 38 fields: &L4Addr{ 39 Protocol: NONE, 40 Port: 0, 41 }, 42 args: args{ 43 o: &L4Addr{ 44 Protocol: NONE, 45 Port: 1, 46 }, 47 }, 48 want: false, 49 }, 50 { 51 name: "both nil", 52 args: args{}, 53 want: true, 54 }, 55 { 56 name: "other nil", 57 fields: &L4Addr{ 58 Protocol: NONE, 59 Port: 1, 60 }, 61 args: args{}, 62 want: false, 63 }, 64 } 65 for _, tt := range tests { 66 t.Run(tt.name, func(t *testing.T) { 67 l := tt.fields 68 if got := l.DeepEqual(tt.args.o); got != tt.want { 69 t.Errorf("L4Addr.DeepEqual() = %v, want %v", got, tt.want) 70 } 71 }) 72 } 73 } 74 75 func TestL3n4AddrID_Equals(t *testing.T) { 76 type args struct { 77 o *L3n4AddrID 78 } 79 tests := []struct { 80 name string 81 fields *L3n4AddrID 82 args args 83 want bool 84 }{ 85 { 86 name: "both equal", 87 fields: &L3n4AddrID{ 88 L3n4Addr: L3n4Addr{ 89 L4Addr: L4Addr{ 90 Protocol: NONE, 91 Port: 1, 92 }, 93 AddrCluster: cmtypes.MustParseAddrCluster("1.1.1.1"), 94 }, 95 ID: 1, 96 }, 97 args: args{ 98 o: &L3n4AddrID{ 99 L3n4Addr: L3n4Addr{ 100 L4Addr: L4Addr{ 101 Protocol: NONE, 102 Port: 1, 103 }, 104 AddrCluster: cmtypes.MustParseAddrCluster("1.1.1.1"), 105 }, 106 ID: 1, 107 }, 108 }, 109 want: true, 110 }, 111 { 112 name: "IDs different", 113 fields: &L3n4AddrID{ 114 L3n4Addr: L3n4Addr{ 115 L4Addr: L4Addr{ 116 Protocol: NONE, 117 Port: 1, 118 }, 119 AddrCluster: cmtypes.MustParseAddrCluster("1.1.1.1"), 120 }, 121 ID: 1, 122 }, 123 args: args{ 124 o: &L3n4AddrID{ 125 L3n4Addr: L3n4Addr{ 126 L4Addr: L4Addr{ 127 Protocol: NONE, 128 Port: 1, 129 }, 130 AddrCluster: cmtypes.MustParseAddrCluster("1.1.1.1"), 131 }, 132 ID: 2, 133 }, 134 }, 135 want: false, 136 }, 137 { 138 name: "IPs different", 139 fields: &L3n4AddrID{ 140 L3n4Addr: L3n4Addr{ 141 L4Addr: L4Addr{ 142 Protocol: NONE, 143 Port: 1, 144 }, 145 AddrCluster: cmtypes.MustParseAddrCluster("2.2.2.2"), 146 }, 147 ID: 1, 148 }, 149 args: args{ 150 o: &L3n4AddrID{ 151 L3n4Addr: L3n4Addr{ 152 L4Addr: L4Addr{ 153 Protocol: NONE, 154 Port: 1, 155 }, 156 AddrCluster: cmtypes.MustParseAddrCluster("1.1.1.1"), 157 }, 158 ID: 1, 159 }, 160 }, 161 want: false, 162 }, 163 { 164 name: "Ports different", 165 fields: &L3n4AddrID{ 166 L3n4Addr: L3n4Addr{ 167 L4Addr: L4Addr{ 168 Protocol: NONE, 169 Port: 2, 170 }, 171 AddrCluster: cmtypes.MustParseAddrCluster("1.1.1.1"), 172 }, 173 ID: 1, 174 }, 175 args: args{ 176 o: &L3n4AddrID{ 177 L3n4Addr: L3n4Addr{ 178 L4Addr: L4Addr{ 179 Protocol: NONE, 180 Port: 1, 181 }, 182 AddrCluster: cmtypes.MustParseAddrCluster("1.1.1.1"), 183 }, 184 ID: 1, 185 }, 186 }, 187 want: false, 188 }, 189 { 190 name: "both nil", 191 args: args{}, 192 want: true, 193 }, 194 } 195 for _, tt := range tests { 196 t.Run(tt.name, func(t *testing.T) { 197 f := tt.fields 198 if got := f.DeepEqual(tt.args.o); got != tt.want { 199 t.Errorf("L3n4AddrID.Equals() = %v, want %v", got, tt.want) 200 } 201 }) 202 } 203 } 204 205 func TestL3n4AddrID_Strings(t *testing.T) { 206 tests := []struct { 207 name string 208 fields *L3n4AddrID 209 string string 210 stringWithProtocol string 211 }{ 212 { 213 name: "IPv4 no protocol", 214 fields: &L3n4AddrID{ 215 L3n4Addr: L3n4Addr{ 216 L4Addr: L4Addr{ 217 Protocol: NONE, 218 Port: 9876, 219 }, 220 AddrCluster: cmtypes.MustParseAddrCluster("1.1.1.1"), 221 }, 222 ID: 1, 223 }, 224 string: "1.1.1.1:9876", 225 stringWithProtocol: "1.1.1.1:9876/NONE", 226 }, 227 { 228 name: "IPv4 TCP", 229 fields: &L3n4AddrID{ 230 L3n4Addr: L3n4Addr{ 231 L4Addr: L4Addr{ 232 Protocol: TCP, 233 Port: 9876, 234 }, 235 AddrCluster: cmtypes.MustParseAddrCluster("2.2.2.2"), 236 Scope: ScopeExternal, 237 }, 238 ID: 1, 239 }, 240 string: "2.2.2.2:9876", 241 stringWithProtocol: "2.2.2.2:9876/TCP", 242 }, 243 { 244 name: "IPv4 UDP", 245 fields: &L3n4AddrID{ 246 L3n4Addr: L3n4Addr{ 247 L4Addr: L4Addr{ 248 Protocol: UDP, 249 Port: 9876, 250 }, 251 AddrCluster: cmtypes.MustParseAddrCluster("3.3.3.3"), 252 Scope: ScopeInternal, 253 }, 254 ID: 1, 255 }, 256 string: "3.3.3.3:9876/i", 257 stringWithProtocol: "3.3.3.3:9876/UDP/i", 258 }, 259 { 260 name: "IPv4 SCTP", 261 fields: &L3n4AddrID{ 262 L3n4Addr: L3n4Addr{ 263 L4Addr: L4Addr{ 264 Protocol: SCTP, 265 Port: 9876, 266 }, 267 AddrCluster: cmtypes.MustParseAddrCluster("4.4.4.4"), 268 }, 269 ID: 1, 270 }, 271 string: "4.4.4.4:9876", 272 stringWithProtocol: "4.4.4.4:9876/SCTP", 273 }, 274 { 275 name: "IPv6 no protocol", 276 fields: &L3n4AddrID{ 277 L3n4Addr: L3n4Addr{ 278 L4Addr: L4Addr{ 279 Protocol: NONE, 280 Port: 9876, 281 }, 282 AddrCluster: cmtypes.MustParseAddrCluster("1020:3040:5060:7080:90a0:b0c0:d0e0:f000"), 283 }, 284 ID: 1, 285 }, 286 string: "[1020:3040:5060:7080:90a0:b0c0:d0e0:f000]:9876", 287 stringWithProtocol: "[1020:3040:5060:7080:90a0:b0c0:d0e0:f000]:9876/NONE", 288 }, 289 { 290 name: "IPv6 TCP", 291 fields: &L3n4AddrID{ 292 L3n4Addr: L3n4Addr{ 293 L4Addr: L4Addr{ 294 Protocol: TCP, 295 Port: 9876, 296 }, 297 AddrCluster: cmtypes.MustParseAddrCluster("1020:3040:5060:7080:90a0:b0c0:d0e0:f000"), 298 Scope: ScopeExternal, 299 }, 300 ID: 1, 301 }, 302 string: "[1020:3040:5060:7080:90a0:b0c0:d0e0:f000]:9876", 303 stringWithProtocol: "[1020:3040:5060:7080:90a0:b0c0:d0e0:f000]:9876/TCP", 304 }, 305 { 306 name: "IPv6 UDP", 307 fields: &L3n4AddrID{ 308 L3n4Addr: L3n4Addr{ 309 L4Addr: L4Addr{ 310 Protocol: UDP, 311 Port: 9876, 312 }, 313 AddrCluster: cmtypes.MustParseAddrCluster("1020:3040:5060:7080:90a0:b0c0:d0e0:f000"), 314 Scope: ScopeInternal, 315 }, 316 ID: 1, 317 }, 318 string: "[1020:3040:5060:7080:90a0:b0c0:d0e0:f000]:9876/i", 319 stringWithProtocol: "[1020:3040:5060:7080:90a0:b0c0:d0e0:f000]:9876/UDP/i", 320 }, 321 { 322 name: "IPv6 SCTP", 323 fields: &L3n4AddrID{ 324 L3n4Addr: L3n4Addr{ 325 L4Addr: L4Addr{ 326 Protocol: SCTP, 327 Port: 9876, 328 }, 329 AddrCluster: cmtypes.MustParseAddrCluster("1020:3040:5060:7080:90a0:b0c0:d0e0:f000"), 330 }, 331 ID: 1, 332 }, 333 string: "[1020:3040:5060:7080:90a0:b0c0:d0e0:f000]:9876", 334 stringWithProtocol: "[1020:3040:5060:7080:90a0:b0c0:d0e0:f000]:9876/SCTP", 335 }, 336 } 337 338 for _, tt := range tests { 339 t.Run(tt.name, func(t *testing.T) { 340 f := tt.fields 341 string := f.String() 342 if string != tt.string { 343 t.Errorf("L3n4AddrID.String() = %s, want %s", string, tt.string) 344 } 345 strWithProtocol := f.StringWithProtocol() 346 if strWithProtocol != tt.stringWithProtocol { 347 t.Errorf("L3n4AddrID.StringWithProtocol() = %s, want %s", strWithProtocol, tt.stringWithProtocol) 348 } 349 }) 350 } 351 } 352 353 func TestNewSvcFlag(t *testing.T) { 354 type args struct { 355 svcType SVCType 356 svcExtLocal bool 357 svcIntLocal bool 358 svcRoutable bool 359 svcL7LB bool 360 } 361 tests := []struct { 362 name string 363 args args 364 want ServiceFlags 365 }{ 366 { 367 args: args{ 368 svcType: SVCTypeClusterIP, 369 svcExtLocal: false, 370 svcIntLocal: false, 371 svcRoutable: true, 372 }, 373 want: serviceFlagNone | serviceFlagRoutable, 374 }, 375 { 376 args: args{ 377 svcType: SVCTypeNodePort, 378 svcExtLocal: false, 379 svcIntLocal: false, 380 svcRoutable: true, 381 }, 382 want: serviceFlagNodePort | serviceFlagRoutable, 383 }, 384 { 385 args: args{ 386 svcType: SVCTypeExternalIPs, 387 svcExtLocal: false, 388 svcIntLocal: false, 389 svcRoutable: true, 390 }, 391 want: serviceFlagExternalIPs | serviceFlagRoutable, 392 }, 393 { 394 // Impossible combination, ClusterIP can't have externalTrafficPolicy=Local. 395 args: args{ 396 svcType: SVCTypeClusterIP, 397 svcExtLocal: true, 398 svcIntLocal: false, 399 svcRoutable: true, 400 }, 401 want: serviceFlagNone | serviceFlagExtLocalScope | serviceFlagRoutable, 402 }, 403 { 404 args: args{ 405 svcType: SVCTypeNodePort, 406 svcExtLocal: true, 407 svcIntLocal: false, 408 svcRoutable: true, 409 }, 410 want: serviceFlagNodePort | serviceFlagExtLocalScope | serviceFlagTwoScopes | serviceFlagRoutable, 411 }, 412 { 413 args: args{ 414 svcType: SVCTypeExternalIPs, 415 svcExtLocal: true, 416 svcIntLocal: false, 417 svcRoutable: true, 418 }, 419 want: serviceFlagExternalIPs | serviceFlagExtLocalScope | serviceFlagTwoScopes | serviceFlagRoutable, 420 }, 421 { 422 args: args{ 423 svcType: SVCTypeClusterIP, 424 svcExtLocal: false, 425 svcIntLocal: true, 426 svcRoutable: true, 427 }, 428 want: serviceFlagNone | serviceFlagIntLocalScope | serviceFlagRoutable, 429 }, 430 { 431 args: args{ 432 svcType: SVCTypeNodePort, 433 svcExtLocal: false, 434 svcIntLocal: true, 435 svcRoutable: true, 436 }, 437 want: serviceFlagNodePort | serviceFlagIntLocalScope | serviceFlagTwoScopes | serviceFlagRoutable, 438 }, 439 { 440 args: args{ 441 svcType: SVCTypeExternalIPs, 442 svcExtLocal: false, 443 svcIntLocal: true, 444 svcRoutable: true, 445 }, 446 want: serviceFlagExternalIPs | serviceFlagIntLocalScope | serviceFlagTwoScopes | serviceFlagRoutable, 447 }, 448 { 449 // Impossible combination, ClusterIP can't have externalTrafficPolicy=Local. 450 args: args{ 451 svcType: SVCTypeClusterIP, 452 svcExtLocal: true, 453 svcIntLocal: true, 454 svcRoutable: true, 455 }, 456 want: serviceFlagNone | serviceFlagExtLocalScope | serviceFlagIntLocalScope | serviceFlagRoutable, 457 }, 458 { 459 args: args{ 460 svcType: SVCTypeNodePort, 461 svcExtLocal: true, 462 svcIntLocal: true, 463 svcRoutable: true, 464 }, 465 want: serviceFlagNodePort | serviceFlagExtLocalScope | serviceFlagIntLocalScope | serviceFlagRoutable, 466 }, 467 { 468 args: args{ 469 svcType: SVCTypeExternalIPs, 470 svcExtLocal: true, 471 svcIntLocal: true, 472 svcRoutable: true, 473 }, 474 want: serviceFlagExternalIPs | serviceFlagExtLocalScope | serviceFlagIntLocalScope | serviceFlagRoutable, 475 }, 476 { 477 args: args{ 478 svcType: SVCTypeExternalIPs, 479 svcExtLocal: true, 480 svcIntLocal: false, 481 svcRoutable: false, 482 }, 483 want: serviceFlagExternalIPs | serviceFlagExtLocalScope | serviceFlagTwoScopes, 484 }, 485 { 486 args: args{ 487 svcType: SVCTypeExternalIPs, 488 svcExtLocal: false, 489 svcIntLocal: true, 490 svcRoutable: false, 491 }, 492 want: serviceFlagExternalIPs | serviceFlagIntLocalScope | serviceFlagTwoScopes, 493 }, 494 { 495 args: args{ 496 svcType: SVCTypeExternalIPs, 497 svcExtLocal: true, 498 svcIntLocal: true, 499 svcRoutable: false, 500 }, 501 want: serviceFlagExternalIPs | serviceFlagExtLocalScope | serviceFlagIntLocalScope, 502 }, 503 { 504 args: args{ 505 svcType: SVCTypeLocalRedirect, 506 svcExtLocal: false, 507 svcIntLocal: false, 508 svcRoutable: true, 509 }, 510 want: serviceFlagLocalRedirect | serviceFlagRoutable, 511 }, 512 { 513 args: args{ 514 svcType: SVCTypeClusterIP, 515 svcL7LB: true, 516 }, 517 want: serviceFlagL7LoadBalancer, 518 }, 519 } 520 for _, tt := range tests { 521 t.Run(tt.name, func(t *testing.T) { 522 p := &SvcFlagParam{ 523 SvcExtLocal: tt.args.svcExtLocal, 524 SvcIntLocal: tt.args.svcIntLocal, 525 SessionAffinity: false, 526 IsRoutable: tt.args.svcRoutable, 527 SvcType: tt.args.svcType, 528 L7LoadBalancer: tt.args.svcL7LB, 529 } 530 if got := NewSvcFlag(p); got != tt.want { 531 t.Errorf("NewSvcFlag() = %v, want %v", got, tt.want) 532 } 533 }) 534 } 535 } 536 537 func TestServiceFlags_String(t *testing.T) { 538 tests := []struct { 539 name string 540 s ServiceFlags 541 want string 542 }{ 543 { 544 name: "Test-1", 545 s: serviceFlagExternalIPs | serviceFlagRoutable, 546 want: "ExternalIPs", 547 }, 548 { 549 name: "Test-2", 550 s: serviceFlagNone | serviceFlagRoutable, 551 want: "ClusterIP", 552 }, 553 { 554 name: "Test-3", 555 s: serviceFlagNodePort | serviceFlagExtLocalScope | serviceFlagRoutable, 556 want: "NodePort, Local", 557 }, 558 { 559 name: "Test-4", 560 s: serviceFlagExternalIPs | serviceFlagExtLocalScope | serviceFlagRoutable, 561 want: "ExternalIPs, Local", 562 }, 563 { 564 name: "Test-5", 565 s: serviceFlagLoadBalancer | serviceFlagRoutable, 566 want: "LoadBalancer", 567 }, 568 { 569 name: "Test-6", 570 s: serviceFlagLoadBalancer, 571 want: "LoadBalancer, non-routable", 572 }, 573 { 574 name: "Test-7", 575 s: serviceFlagNodePort | serviceFlagIntLocalScope | serviceFlagRoutable, 576 want: "NodePort, InternalLocal", 577 }, 578 { 579 name: "Test-8", 580 s: serviceFlagExternalIPs | serviceFlagIntLocalScope | serviceFlagRoutable, 581 want: "ExternalIPs, InternalLocal", 582 }, 583 { 584 name: "Test-9", 585 s: serviceFlagNodePort | serviceFlagExtLocalScope | serviceFlagIntLocalScope | serviceFlagRoutable, 586 want: "NodePort, Local, InternalLocal", 587 }, 588 { 589 name: "Test-10", 590 s: serviceFlagExternalIPs | serviceFlagExtLocalScope | serviceFlagIntLocalScope | serviceFlagRoutable, 591 want: "ExternalIPs, Local, InternalLocal", 592 }, 593 } 594 for _, tt := range tests { 595 t.Run(tt.name, func(t *testing.T) { 596 if got := tt.s.String(); got != tt.want { 597 t.Errorf("String() = %v, want %v", got, tt.want) 598 } 599 }) 600 } 601 } 602 603 func benchmarkHash(b *testing.B, addr *L3n4Addr) { 604 b.ReportAllocs() 605 b.ResetTimer() 606 for i := 0; i < b.N; i++ { 607 addr.Hash() 608 } 609 } 610 611 func BenchmarkL3n4Addr_Hash_IPv4(b *testing.B) { 612 addr := NewL3n4Addr(TCP, cmtypes.MustParseAddrCluster("1.2.3.4"), 8080, ScopeInternal) 613 benchmarkHash(b, addr) 614 } 615 616 func BenchmarkL3n4Addr_Hash_IPv6_Short(b *testing.B) { 617 addr := NewL3n4Addr(TCP, cmtypes.MustParseAddrCluster("fd00::1:36c6"), 8080, ScopeInternal) 618 benchmarkHash(b, addr) 619 } 620 621 func BenchmarkL3n4Addr_Hash_IPv6_Long(b *testing.B) { 622 addr := NewL3n4Addr(TCP, cmtypes.MustParseAddrCluster("2001:0db8:85a3::8a2e:0370:7334"), 8080, ScopeInternal) 623 benchmarkHash(b, addr) 624 } 625 626 func BenchmarkL3n4Addr_Hash_IPv6_Max(b *testing.B) { 627 addr := NewL3n4Addr(TCP, cmtypes.MustParseAddrCluster("1020:3040:5060:7080:90a0:b0c0:d0e0:f000"), 30303, 100) 628 benchmarkHash(b, addr) 629 } 630 631 func benchmarkString(b *testing.B, addr *L3n4Addr) { 632 b.ReportAllocs() 633 b.ResetTimer() 634 var length int 635 for i := 0; i < b.N; i++ { 636 length += len(addr.String()) 637 } 638 } 639 640 func BenchmarkL3n4Addr_String_IPv4(b *testing.B) { 641 addr := NewL3n4Addr(TCP, cmtypes.MustParseAddrCluster("192.168.123.210"), 8080, ScopeInternal) 642 benchmarkString(b, addr) 643 } 644 645 func BenchmarkL3n4Addr_String_IPv6_Max(b *testing.B) { 646 addr := NewL3n4Addr(TCP, cmtypes.MustParseAddrCluster("1020:3040:5060:7080:90a0:b0c0:d0e0:f000"), 30303, 100) 647 benchmarkString(b, addr) 648 } 649 650 func benchmarkStringWithProtocol(b *testing.B, addr *L3n4Addr) { 651 b.ReportAllocs() 652 b.ResetTimer() 653 for i := 0; i < b.N; i++ { 654 addr.StringWithProtocol() 655 } 656 } 657 658 func BenchmarkL3n4Addr_StringWithProtocol_IPv4(b *testing.B) { 659 addr := NewL3n4Addr(TCP, cmtypes.MustParseAddrCluster("192.168.123.210"), 8080, ScopeInternal) 660 benchmarkStringWithProtocol(b, addr) 661 } 662 663 func BenchmarkL3n4Addr_StringWithProtocol_IPv6_Max(b *testing.B) { 664 addr := NewL3n4Addr(TCP, cmtypes.MustParseAddrCluster("1020:3040:5060:7080:90a0:b0c0:d0e0:f000"), 30303, 100) 665 benchmarkStringWithProtocol(b, addr) 666 }