github.com/cilium/cilium@v1.16.2/pkg/maps/ctmap/ctmap_privileged_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package ctmap 5 6 import ( 7 "math/rand/v2" 8 "net/netip" 9 "testing" 10 11 "github.com/cilium/ebpf/rlimit" 12 "github.com/cilium/fake" 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 mapsexp "golang.org/x/exp/maps" 16 17 "github.com/cilium/cilium/pkg/bpf" 18 "github.com/cilium/cilium/pkg/maps/nat" 19 "github.com/cilium/cilium/pkg/option" 20 "github.com/cilium/cilium/pkg/testutils" 21 "github.com/cilium/cilium/pkg/tuple" 22 "github.com/cilium/cilium/pkg/types" 23 "github.com/cilium/cilium/pkg/u8proto" 24 ) 25 26 func init() { 27 InitMapInfo(true, true, true) 28 } 29 30 func setupCTMap(tb testing.TB) { 31 testutils.PrivilegedTest(tb) 32 33 bpf.CheckOrMountFS("") 34 err := rlimit.RemoveMemlock() 35 require.Nil(tb, err) 36 } 37 38 func BenchmarkMapBatchLookup(b *testing.B) { 39 m := newMap(MapNameTCP4Global+"_test", mapTypeIPv4TCPGlobal) 40 err := m.OpenOrCreate() 41 assert.NoError(b, m.Map.Unpin()) 42 assert.NoError(b, err) 43 44 _ = populateFakeDataCTMap4(b, m, option.CTMapEntriesGlobalTCPDefault) 45 46 b.ReportAllocs() 47 b.ResetTimer() 48 for i := 0; i < b.N; i++ { 49 count, err := m.Count() 50 assert.NoError(b, err) 51 assert.Greater(b, count, option.CTMapEntriesGlobalAnyDefault) 52 } 53 } 54 55 func Benchmark_MapUpdate(b *testing.B) { 56 setupCTMap(b) 57 58 m := newMap(MapNameTCP4Global+"_test", mapTypeIPv4TCPGlobal) 59 err := m.OpenOrCreate() 60 defer m.Map.Unpin() 61 require.Nil(b, err) 62 63 key := &CtKey4{ 64 tuple.TupleKey4{ 65 DestAddr: types.IPv4{0xa, 0x10, 0xc5, 0xf0}, 66 SourceAddr: types.IPv4{0xa, 0x10, 0x9d, 0xb3}, 67 DestPort: 0, 68 SourcePort: 0, 69 NextHeader: u8proto.TCP, 70 Flags: tuple.TUPLE_F_OUT, 71 }, 72 } 73 value := &CtEntry{ 74 Packets: 4 + 4, 75 Bytes: 216 + 216, 76 Lifetime: 37459, 77 Flags: SeenNonSyn | RxClosing, 78 RevNAT: 0, 79 TxFlagsSeen: 0x02, 80 RxFlagsSeen: 0x14, 81 SourceSecurityID: 40653, 82 LastTxReport: 15856, 83 LastRxReport: 15856, 84 } 85 86 require.Equal(b, true, b.N < 0xFFFF*0xFFFF) 87 for i := 0; i < b.N; i++ { 88 key.DestPort = uint16(i % 0xFFFF) 89 key.SourcePort = uint16(i / 0xFFFF) 90 err := m.Map.Update(key, value) 91 require.Nil(b, err) 92 } 93 94 a1 := make([]CtKey, 1) 95 a2 := make([]*CtEntry, 1) 96 97 // Also account the cost of casting from MapKey to TupleKey 98 cb := func(k bpf.MapKey, v bpf.MapValue) { 99 key := k.(CtKey) 100 value := v.(*CtEntry) 101 a1[0] = key 102 a2[0] = value 103 } 104 105 b.ResetTimer() 106 err = m.DumpWithCallback(cb) 107 require.Nil(b, err) 108 t := m.Flush() 109 require.Equal(b, b.N, t) 110 } 111 112 // TestCtGcIcmp tests whether ICMP NAT entries are removed upon a removal of 113 // their CT entry (GH#12625). 114 func TestCtGcIcmp(t *testing.T) { 115 setupCTMap(t) 116 117 // Init maps 118 natMap := nat.NewMap("cilium_nat_any4_test", nat.IPv4, 1000) 119 err := natMap.OpenOrCreate() 120 require.Nil(t, err) 121 defer natMap.Map.Unpin() 122 123 ctMapName := MapNameAny4Global + "_test" 124 mapInfo[mapTypeIPv4AnyGlobal] = mapAttributes{ 125 natMap: natMap, natMapLock: mapInfo[mapTypeIPv4AnyGlobal].natMapLock, 126 } 127 128 ctMap := newMap(ctMapName, mapTypeIPv4AnyGlobal) 129 err = ctMap.OpenOrCreate() 130 require.Nil(t, err) 131 defer ctMap.Map.Unpin() 132 133 // Create the following entries and check that they get GC-ed: 134 // - CT: ICMP OUT 192.168.61.11:38193 -> 192.168.61.12:0 <..> 135 // - NAT: ICMP IN 192.168.61.12:0 -> 192.168.61.11:38193 XLATE_DST <..> 136 // ICMP OUT 192.168.61.11:38193 -> 192.168.61.12:0 XLATE_SRC <..> 137 138 ctKey := &CtKey4Global{ 139 tuple.TupleKey4Global{ 140 TupleKey4: tuple.TupleKey4{ 141 SourceAddr: types.IPv4{192, 168, 61, 12}, 142 DestAddr: types.IPv4{192, 168, 61, 11}, 143 SourcePort: 0x3195, 144 DestPort: 0, 145 NextHeader: u8proto.ICMP, 146 Flags: tuple.TUPLE_F_OUT, 147 }, 148 }, 149 } 150 ctVal := &CtEntry{ 151 Packets: 1, 152 Bytes: 216, 153 Lifetime: 37459, 154 } 155 err = ctMap.Map.Update(ctKey, ctVal) 156 require.Nil(t, err) 157 158 natKey := &nat.NatKey4{ 159 TupleKey4Global: tuple.TupleKey4Global{ 160 TupleKey4: tuple.TupleKey4{ 161 DestAddr: types.IPv4{192, 168, 61, 12}, 162 SourceAddr: types.IPv4{192, 168, 61, 11}, 163 DestPort: 0, 164 SourcePort: 0x3195, 165 NextHeader: u8proto.ICMP, 166 Flags: tuple.TUPLE_F_OUT, 167 }, 168 }, 169 } 170 natVal := &nat.NatEntry4{ 171 Created: 37400, 172 NeedsCT: 1, 173 Addr: types.IPv4{192, 168, 61, 11}, 174 Port: 0x3195, 175 } 176 err = natMap.Map.Update(natKey, natVal) 177 require.Nil(t, err) 178 natKey = &nat.NatKey4{ 179 TupleKey4Global: tuple.TupleKey4Global{ 180 TupleKey4: tuple.TupleKey4{ 181 SourceAddr: types.IPv4{192, 168, 61, 12}, 182 DestAddr: types.IPv4{192, 168, 61, 11}, 183 SourcePort: 0, 184 DestPort: 0x3195, 185 NextHeader: u8proto.ICMP, 186 Flags: tuple.TUPLE_F_IN, 187 }, 188 }, 189 } 190 natVal = &nat.NatEntry4{ 191 Created: 37400, 192 NeedsCT: 1, 193 Addr: types.IPv4{192, 168, 61, 11}, 194 Port: 0x3195, 195 } 196 err = natMap.Map.Update(natKey, natVal) 197 require.Nil(t, err) 198 199 buf := make(map[string][]string) 200 err = ctMap.Map.Dump(buf) 201 require.Nil(t, err) 202 require.Equal(t, 1, len(buf)) 203 204 buf = make(map[string][]string) 205 err = natMap.Map.Dump(buf) 206 require.Nil(t, err) 207 require.Equal(t, 2, len(buf)) 208 209 // GC and check whether NAT entries have been collected 210 filter := &GCFilter{ 211 RemoveExpired: true, 212 Time: 39000, 213 } 214 stats := doGC4(ctMap, filter) 215 require.Equal(t, uint32(0), stats.aliveEntries) 216 require.Equal(t, uint32(1), stats.deleted) 217 218 buf = make(map[string][]string) 219 err = natMap.Map.Dump(buf) 220 require.Nil(t, err) 221 require.Equal(t, 0, len(buf)) 222 } 223 224 // TestCtGcTcp tests whether TCP SNAT entries are removed upon a removal of 225 // their CT entry. 226 func TestCtGcTcp(t *testing.T) { 227 setupCTMap(t) 228 // Init maps 229 natMap := nat.NewMap("cilium_nat_any4_test", nat.IPv4, 1000) 230 err := natMap.OpenOrCreate() 231 require.Nil(t, err) 232 defer natMap.Map.Unpin() 233 234 ctMapName := MapNameTCP4Global + "_test" 235 mapInfo[mapTypeIPv4TCPGlobal] = mapAttributes{ 236 natMap: natMap, natMapLock: mapInfo[mapTypeIPv4TCPGlobal].natMapLock, 237 } 238 239 ctMap := newMap(ctMapName, mapTypeIPv4TCPGlobal) 240 err = ctMap.OpenOrCreate() 241 require.Nil(t, err) 242 defer ctMap.Map.Unpin() 243 244 // Create the following entries and check that they get GC-ed: 245 // - CT: TCP OUT 192.168.61.11:38193 -> 192.168.61.12:80 <..> 246 // - NAT: TCP OUT 192.168.61.11:38193 -> 192.168.61.12:80 XLATE_SRC 192.168.61.11:38194 247 // TCP IN 192.168.61.12:80 -> 192.168.61.11:38194 XLATE_DST 192.168.61.11:38193 248 249 ctKey := &CtKey4Global{ 250 tuple.TupleKey4Global{ 251 TupleKey4: tuple.TupleKey4{ 252 SourceAddr: types.IPv4{192, 168, 61, 12}, 253 DestAddr: types.IPv4{192, 168, 61, 11}, 254 SourcePort: 0x3195, 255 DestPort: 0x50, 256 NextHeader: u8proto.TCP, 257 Flags: tuple.TUPLE_F_OUT, 258 }, 259 }, 260 } 261 ctVal := &CtEntry{ 262 Packets: 1, 263 Bytes: 216, 264 Lifetime: 37459, 265 } 266 err = ctMap.Map.Update(ctKey, ctVal) 267 require.Nil(t, err) 268 269 natKey := &nat.NatKey4{ 270 TupleKey4Global: tuple.TupleKey4Global{ 271 TupleKey4: tuple.TupleKey4{ 272 DestAddr: types.IPv4{192, 168, 61, 12}, 273 SourceAddr: types.IPv4{192, 168, 61, 11}, 274 DestPort: 0x50, 275 SourcePort: 0x3195, 276 NextHeader: u8proto.TCP, 277 Flags: tuple.TUPLE_F_OUT, 278 }, 279 }, 280 } 281 natVal := &nat.NatEntry4{ 282 Created: 37400, 283 NeedsCT: 1, 284 Addr: types.IPv4{192, 168, 61, 11}, 285 Port: 0x3295, 286 } 287 err = natMap.Map.Update(natKey, natVal) 288 require.Nil(t, err) 289 natKey = &nat.NatKey4{ 290 TupleKey4Global: tuple.TupleKey4Global{ 291 TupleKey4: tuple.TupleKey4{ 292 SourceAddr: types.IPv4{192, 168, 61, 12}, 293 DestAddr: types.IPv4{192, 168, 61, 11}, 294 SourcePort: 0x50, 295 DestPort: 0x3295, 296 NextHeader: u8proto.TCP, 297 Flags: tuple.TUPLE_F_IN, 298 }, 299 }, 300 } 301 natVal = &nat.NatEntry4{ 302 Created: 37400, 303 NeedsCT: 1, 304 Addr: types.IPv4{192, 168, 61, 11}, 305 Port: 0x3195, 306 } 307 err = natMap.Map.Update(natKey, natVal) 308 require.Nil(t, err) 309 310 buf := make(map[string][]string) 311 err = ctMap.Map.Dump(buf) 312 require.Nil(t, err) 313 require.Equal(t, 1, len(buf)) 314 315 buf = make(map[string][]string) 316 err = natMap.Map.Dump(buf) 317 require.Nil(t, err) 318 require.Equal(t, 2, len(buf)) 319 320 // GC and check whether NAT entries have been collected 321 filter := &GCFilter{ 322 RemoveExpired: true, 323 Time: 39000, 324 } 325 stats := doGC4(ctMap, filter) 326 require.Equal(t, uint32(0), stats.aliveEntries) 327 require.Equal(t, uint32(1), stats.deleted) 328 329 buf = make(map[string][]string) 330 err = natMap.Map.Dump(buf) 331 require.Nil(t, err) 332 require.Equal(t, 0, len(buf)) 333 } 334 335 // TestCtGcDsr tests whether DSR NAT entries are removed upon a removal of 336 // their CT entry (== CT_EGRESS). 337 func TestCtGcDsr(t *testing.T) { 338 setupCTMap(t) 339 340 // Init maps 341 natMap := nat.NewMap("cilium_nat_any4_test", nat.IPv4, 1000) 342 err := natMap.OpenOrCreate() 343 require.Nil(t, err) 344 defer natMap.Map.Unpin() 345 346 ctMapName := MapNameTCP4Global + "_test" 347 mapInfo[mapTypeIPv4TCPGlobal] = mapAttributes{ 348 natMap: natMap, natMapLock: mapInfo[mapTypeIPv4TCPGlobal].natMapLock, 349 } 350 351 ctMap := newMap(ctMapName, mapTypeIPv4TCPGlobal) 352 err = ctMap.OpenOrCreate() 353 require.Nil(t, err) 354 defer ctMap.Map.Unpin() 355 356 // Create the following entries and check that they get GC-ed: 357 // - CT: TCP OUT 1.1.1.1:1111 -> 192.168.61.11:8080 <..> 358 // - NAT: TCP OUT 192.168.61.11:8080 -> 1.1.1.1:1111 XLATE_SRC 2.2.2.2:80 359 360 ctKey := &CtKey4Global{ 361 tuple.TupleKey4Global{ 362 TupleKey4: tuple.TupleKey4{ 363 SourceAddr: types.IPv4{192, 168, 61, 11}, 364 DestAddr: types.IPv4{1, 1, 1, 1}, 365 SourcePort: 0x5704, 366 DestPort: 0x901f, 367 NextHeader: u8proto.TCP, 368 Flags: tuple.TUPLE_F_OUT, 369 }, 370 }, 371 } 372 ctVal := &CtEntry{ 373 Packets: 1, 374 Bytes: 216, 375 Lifetime: 37459, 376 Flags: DSRInternal, 377 } 378 err = ctMap.Map.Update(ctKey, ctVal) 379 require.Nil(t, err) 380 381 natKey := &nat.NatKey4{ 382 TupleKey4Global: tuple.TupleKey4Global{ 383 TupleKey4: tuple.TupleKey4{ 384 DestAddr: types.IPv4{1, 1, 1, 1}, 385 SourceAddr: types.IPv4{192, 168, 61, 11}, 386 DestPort: 0x5704, 387 SourcePort: 0x901f, 388 NextHeader: u8proto.TCP, 389 Flags: tuple.TUPLE_F_OUT, 390 }, 391 }, 392 } 393 natVal := &nat.NatEntry4{ 394 Created: 37400, 395 Addr: types.IPv4{2, 2, 2, 2}, 396 Port: 0x50, 397 } 398 err = natMap.Map.Update(natKey, natVal) 399 require.Nil(t, err) 400 401 buf := make(map[string][]string) 402 err = ctMap.Map.Dump(buf) 403 require.Nil(t, err) 404 require.Equal(t, 1, len(buf)) 405 406 buf = make(map[string][]string) 407 err = natMap.Map.Dump(buf) 408 require.Nil(t, err) 409 require.Equal(t, 1, len(buf)) 410 411 // GC and check whether NAT entry has been collected 412 filter := &GCFilter{ 413 RemoveExpired: true, 414 Time: 39000, 415 } 416 stats := doGC4(ctMap, filter) 417 require.Equal(t, uint32(0), stats.aliveEntries) 418 require.Equal(t, uint32(1), stats.deleted) 419 420 buf = make(map[string][]string) 421 err = natMap.Map.Dump(buf) 422 require.Nil(t, err) 423 require.Equal(t, 0, len(buf)) 424 } 425 426 // TestOrphanNat checks whether dangling NAT entries are GC'd (GH#12686) 427 func TestOrphanNatGC(t *testing.T) { 428 setupCTMap(t) 429 430 // Init maps 431 natMap := nat.NewMap("cilium_nat_any4_test", nat.IPv4, 1000) 432 err := natMap.OpenOrCreate() 433 require.Nil(t, err) 434 defer natMap.Map.Unpin() 435 436 ctMapAnyName := MapNameAny4Global + "_test" 437 mapInfo[mapTypeIPv4AnyGlobal] = mapAttributes{ 438 natMap: natMap, natMapLock: mapInfo[mapTypeIPv4AnyGlobal].natMapLock, 439 } 440 ctMapAny := newMap(ctMapAnyName, mapTypeIPv4AnyGlobal) 441 err = ctMapAny.OpenOrCreate() 442 require.Nil(t, err) 443 defer ctMapAny.Map.Unpin() 444 445 ctMapTCPName := MapNameTCP4Global + "_test" 446 mapInfo[mapTypeIPv4TCPGlobal] = mapAttributes{ 447 natMap: natMap, natMapLock: mapInfo[mapTypeIPv4TCPGlobal].natMapLock, 448 } 449 ctMapTCP := newMap(ctMapTCPName, mapTypeIPv4TCPGlobal) 450 err = ctMapTCP.OpenOrCreate() 451 require.Nil(t, err) 452 defer ctMapTCP.Map.Unpin() 453 454 // Create the following entries and check that SNAT entries are NOT GC-ed 455 // (as we have the CT entry which they belong to): 456 // 457 // - Host local traffic (no SNAT): 458 // CT: UDP OUT 10.23.32.45:54864 -> 10.23.53.48:8472 459 // NAT: UDP IN 10.23.53.48:8472 -> 10.23.32.45:54865 XLATE_DST 10.23.32.45:54864 460 // UDP OUT 10.23.32.45:54864 -> 10.23.53.48:8472 XLATE_SRC 10.23.32.45:54865 461 // 462 // The example above covers other SNAT cases. E.g. (not used in unit tests below, just 463 // to show for completion): 464 // 465 // - NodePort request from outside (subject to NodePort SNAT): 466 // CT: TCP OUT 192.168.61.1:63000 -> 10.0.1.99:80 467 // NAT: TCP IN 10.0.1.99:80 -> 10.0.0.134:63000 XLATE_DST 192.168.61.1:63000 468 // NAT: TCP OUT 192.168.61.1:63000 -> 10.0.1.99:80 XLATE_SRC 10.0.0.134:63000 469 // 470 // - Local endpoint request to outside (subject to BPF-masq): 471 // CT: TCP OUT 10.0.1.99:34520 -> 1.1.1.1:80 472 // NAT: TCP IN 1.1.1.1:80 -> 10.0.2.15:34520 XLATE_DST 10.0.1.99:34520 473 // TCP OUT 10.0.1.99:34520 -> 1.1.1.1:80 XLATE_SRC 10.0.2.15:34520 474 475 ctKey := &CtKey4Global{ 476 TupleKey4Global: tuple.TupleKey4Global{ 477 TupleKey4: tuple.TupleKey4{ 478 DestAddr: types.IPv4{10, 23, 32, 45}, 479 SourceAddr: types.IPv4{10, 23, 53, 48}, 480 SourcePort: 0x50d6, 481 DestPort: 0x1821, 482 NextHeader: u8proto.UDP, 483 Flags: tuple.TUPLE_F_OUT, 484 }, 485 }, 486 } 487 ctVal := &CtEntry{ 488 Packets: 1, 489 Bytes: 216, 490 Lifetime: 37459, 491 } 492 err = ctMapAny.Map.Update(ctKey, ctVal) 493 require.Nil(t, err) 494 495 natKey := &nat.NatKey4{ 496 TupleKey4Global: tuple.TupleKey4Global{ 497 TupleKey4: tuple.TupleKey4{ 498 SourceAddr: types.IPv4{10, 23, 32, 45}, 499 DestAddr: types.IPv4{10, 23, 53, 48}, 500 SourcePort: 0x50d6, 501 DestPort: 0x1821, 502 NextHeader: u8proto.UDP, 503 Flags: tuple.TUPLE_F_OUT, 504 }, 505 }, 506 } 507 natVal := &nat.NatEntry4{ 508 Created: 37400, 509 NeedsCT: 1, 510 Addr: types.IPv4{10, 23, 32, 45}, 511 Port: 0x51d6, 512 } 513 err = natMap.Map.Update(natKey, natVal) 514 require.Nil(t, err) 515 natKey = &nat.NatKey4{ 516 TupleKey4Global: tuple.TupleKey4Global{ 517 TupleKey4: tuple.TupleKey4{ 518 DestAddr: types.IPv4{10, 23, 32, 45}, 519 SourceAddr: types.IPv4{10, 23, 53, 48}, 520 DestPort: 0x51d6, 521 SourcePort: 0x1821, 522 NextHeader: u8proto.UDP, 523 Flags: tuple.TUPLE_F_IN, 524 }, 525 }, 526 } 527 natVal = &nat.NatEntry4{ 528 Created: 37400, 529 NeedsCT: 1, 530 Addr: types.IPv4{10, 23, 32, 45}, 531 Port: 0x50d6, 532 } 533 err = natMap.Map.Update(natKey, natVal) 534 require.Nil(t, err) 535 536 stats := PurgeOrphanNATEntries(ctMapTCP, ctMapAny) 537 require.Equal(t, uint32(1), stats.IngressAlive) 538 require.Equal(t, uint32(0), stats.IngressDeleted) 539 require.Equal(t, uint32(1), stats.EgressAlive) 540 require.Equal(t, uint32(0), stats.EgressDeleted) 541 // Check that both entries haven't removed 542 buf := make(map[string][]string) 543 err = natMap.Map.Dump(buf) 544 require.Nil(t, err) 545 require.Equal(t, 2, len(buf)) 546 547 // Now remove the CT entry which should remove both NAT entries 548 err = ctMapAny.Map.Delete(ctKey) 549 require.Nil(t, err) 550 stats = PurgeOrphanNATEntries(ctMapTCP, ctMapAny) 551 require.Equal(t, uint32(1), stats.IngressDeleted) 552 require.Equal(t, uint32(0), stats.IngressAlive) 553 require.Equal(t, uint32(1), stats.EgressDeleted) 554 require.Equal(t, uint32(0), stats.EgressAlive) 555 // Check that both orphan NAT entries have been removed 556 buf = make(map[string][]string) 557 err = natMap.Map.Dump(buf) 558 require.Nil(t, err) 559 require.Equal(t, 0, len(buf)) 560 561 // Create only CT_INGRESS NAT entry which should be removed 562 err = natMap.Map.Update(natKey, natVal) 563 require.Nil(t, err) 564 565 stats = PurgeOrphanNATEntries(ctMapTCP, ctMapAny) 566 require.Equal(t, uint32(1), stats.IngressDeleted) 567 require.Equal(t, uint32(0), stats.EgressDeleted) 568 buf = make(map[string][]string) 569 err = natMap.Map.Dump(buf) 570 require.Nil(t, err) 571 require.Equal(t, 0, len(buf)) 572 573 // Test DSR (new, tracked by nodeport.h) 574 // 575 // Create the following entries and check that SNAT entries are NOT GC-ed 576 // (as we have the CT entry which they belong to): 577 // 578 // CT: TCP OUT 10.0.2.10:50000 -> 10.20.30.40:1234 579 // NAT: TCP OUT 10.20.30.40:1234 -> 10.0.2.10:50000 XLATE_SRC 10.0.2.20:40000 580 581 ctKey = &CtKey4Global{ 582 TupleKey4Global: tuple.TupleKey4Global{ 583 TupleKey4: tuple.TupleKey4{ 584 DestAddr: types.IPv4{10, 0, 2, 10}, 585 SourceAddr: types.IPv4{10, 20, 30, 40}, 586 SourcePort: 0x50c3, 587 DestPort: 0xd204, 588 NextHeader: u8proto.TCP, 589 Flags: tuple.TUPLE_F_OUT, 590 }, 591 }, 592 } 593 ctVal = &CtEntry{ 594 Packets: 1, 595 Bytes: 216, 596 Lifetime: 37459, 597 Flags: DSRInternal, 598 } 599 err = ctMapTCP.Map.Update(ctKey, ctVal) 600 require.Nil(t, err) 601 602 natKey = &nat.NatKey4{ 603 TupleKey4Global: tuple.TupleKey4Global{ 604 TupleKey4: tuple.TupleKey4{ 605 SourceAddr: types.IPv4{10, 20, 30, 40}, 606 DestAddr: types.IPv4{10, 0, 2, 10}, 607 SourcePort: 0xd204, 608 DestPort: 0x50c3, 609 NextHeader: u8proto.TCP, 610 Flags: tuple.TUPLE_F_OUT, 611 }, 612 }, 613 } 614 natVal = &nat.NatEntry4{ 615 Created: 37400, 616 Addr: types.IPv4{10, 0, 2, 20}, 617 Port: 0x409c, 618 } 619 err = natMap.Map.Update(natKey, natVal) 620 require.Nil(t, err) 621 622 stats = PurgeOrphanNATEntries(ctMapTCP, ctMapTCP) 623 require.Equal(t, uint32(0), stats.IngressAlive) 624 require.Equal(t, uint32(0), stats.IngressDeleted) 625 require.Equal(t, uint32(1), stats.EgressAlive) 626 require.Equal(t, uint32(0), stats.EgressDeleted) 627 // Check that the entry hasn't been removed 628 buf = make(map[string][]string) 629 err = natMap.Map.Dump(buf) 630 require.Nil(t, err) 631 require.Equal(t, 1, len(buf)) 632 633 // Now remove the CT entry which should remove the NAT entry 634 err = ctMapTCP.Map.Delete(ctKey) 635 require.Nil(t, err) 636 stats = PurgeOrphanNATEntries(ctMapTCP, ctMapTCP) 637 require.Equal(t, uint32(0), stats.IngressAlive) 638 require.Equal(t, uint32(0), stats.IngressDeleted) 639 require.Equal(t, uint32(0), stats.EgressAlive) 640 require.Equal(t, uint32(1), stats.EgressDeleted) 641 // Check that the orphan NAT entry has been removed 642 buf = make(map[string][]string) 643 err = natMap.Map.Dump(buf) 644 require.Nil(t, err) 645 require.Equal(t, 0, len(buf)) 646 647 // When a connection is re-opened and switches from DSR to local-backend, 648 // its CT entry gets re-created but uses the same CT tuple as key. 649 // 650 // Validate that we clean up the stale DSR NAT entry in such a case. 651 ctVal.Flags = 0 652 653 err = ctMapTCP.Map.Update(ctKey, ctVal) 654 require.Nil(t, err) 655 656 err = natMap.Map.Update(natKey, natVal) 657 require.Nil(t, err) 658 659 stats = PurgeOrphanNATEntries(ctMapTCP, ctMapTCP) 660 require.Equal(t, uint32(0), stats.IngressAlive) 661 require.Equal(t, uint32(0), stats.IngressDeleted) 662 require.Equal(t, uint32(0), stats.EgressAlive) 663 require.Equal(t, uint32(1), stats.EgressDeleted) 664 // Check that the orphan NAT entry has been removed 665 buf = make(map[string][]string) 666 err = natMap.Map.Dump(buf) 667 require.Nil(t, err) 668 require.Equal(t, 0, len(buf)) 669 670 // Let's check IPv6 671 672 natMapV6 := nat.NewMap("cilium_nat_any6_test", nat.IPv6, 1000) 673 err = natMapV6.OpenOrCreate() 674 require.Nil(t, err) 675 defer natMapV6.Map.Unpin() 676 677 ctMapAnyName = MapNameAny6Global + "_test" 678 mapInfo[mapTypeIPv6AnyGlobal] = mapAttributes{ 679 natMap: natMapV6, natMapLock: mapInfo[mapTypeIPv6AnyGlobal].natMapLock, 680 } 681 ctMapAnyV6 := newMap(ctMapAnyName, mapTypeIPv6AnyGlobal) 682 err = ctMapAnyV6.OpenOrCreate() 683 require.Nil(t, err) 684 defer ctMapAnyV6.Map.Unpin() 685 686 ctMapTCPName = MapNameTCP6Global + "_test" 687 mapInfo[mapTypeIPv6TCPGlobal] = mapAttributes{ 688 natMap: natMapV6, natMapLock: mapInfo[mapTypeIPv6TCPGlobal].natMapLock, 689 } 690 ctMapTCPV6 := newMap(ctMapTCPName, mapTypeIPv6TCPGlobal) 691 err = ctMapTCP.OpenOrCreate() 692 require.Nil(t, err) 693 defer ctMapTCPV6.Map.Unpin() 694 695 natKeyV6 := &nat.NatKey6{ 696 TupleKey6Global: tuple.TupleKey6Global{ 697 TupleKey6: tuple.TupleKey6{ 698 SourceAddr: types.IPv6{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 699 DestAddr: types.IPv6{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 700 SourcePort: 0x50d6, 701 DestPort: 0x1821, 702 NextHeader: u8proto.UDP, 703 Flags: tuple.TUPLE_F_IN, 704 }, 705 }, 706 } 707 natValV6 := &nat.NatEntry6{ 708 Created: 37400, 709 NeedsCT: 1, 710 Addr: types.IPv6{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, 711 Port: 0x51d6, 712 } 713 err = natMapV6.Map.Update(natKeyV6, natValV6) 714 require.Nil(t, err) 715 716 stats = PurgeOrphanNATEntries(ctMapTCPV6, ctMapAnyV6) 717 require.Equal(t, uint32(1), stats.IngressDeleted) 718 require.Equal(t, uint32(0), stats.EgressDeleted) 719 buf = make(map[string][]string) 720 err = natMap.Map.Dump(buf) 721 require.Nil(t, err) 722 require.Equal(t, 0, len(buf)) 723 } 724 725 // TestCount checks whether the CT map batch lookup dumps the count of the 726 // entire map. 727 func TestCount(t *testing.T) { 728 testutils.PrivilegedTest(t) 729 730 // Set the max size of the map explicitly so we can provide enough buffer 731 // for the LRU map to avoid eviction that makes the assertions within this 732 // test indeterministic and consequently cause flakes. 733 prev := option.Config.CTMapEntriesGlobalTCP 734 defer func() { option.Config.CTMapEntriesGlobalTCP = prev }() 735 option.Config.CTMapEntriesGlobalTCP = 524288 736 size := 8192 // choose a reasonbly large map that does not make test time too long. 737 738 m := newMap(MapNameTCP4Global+"_test", mapTypeIPv4TCPGlobal) 739 err := m.OpenOrCreate() 740 assert.NoError(t, err) 741 assert.NoError(t, m.Map.Unpin()) 742 743 cache := populateFakeDataCTMap4(t, m, size) 744 initial := len(cache) 745 746 batchCount, err := m.Count() 747 assert.Equal(t, initial, batchCount) 748 assert.NoError(t, err) 749 750 for _, k := range mapsexp.Keys(cache)[:size/4] { 751 if err := m.Delete(k); err != nil { 752 t.Fatal(err) 753 } 754 delete(cache, k) 755 756 batchCount, err := m.Count() 757 assert.Equal(t, len(cache), batchCount) 758 assert.NoError(t, err) 759 } 760 761 batchCount, err = m.Count() 762 assert.Equal(t, len(cache), batchCount) 763 assert.NoError(t, err) 764 765 var count int 766 assert.NoError(t, m.DumpWithCallback(func(_ bpf.MapKey, _ bpf.MapValue) { count++ })) 767 assert.Equal(t, count, batchCount) 768 assert.Equal(t, len(cache), batchCount) 769 } 770 771 func populateFakeDataCTMap4(tb testing.TB, m CtMap, size int) map[*CtKey4Global]struct{} { 772 tb.Helper() 773 774 protos := []int{int(u8proto.ANY), int(u8proto.ICMP), int(u8proto.TCP), int(u8proto.UDP), int(u8proto.ICMPv6), int(u8proto.SCTP)} 775 flags := []int{tuple.TUPLE_F_IN, tuple.TUPLE_F_OUT, tuple.TUPLE_F_RELATED, tuple.TUPLE_F_SERVICE} 776 genKey := func() *CtKey4Global { 777 return &CtKey4Global{ 778 TupleKey4Global: tuple.TupleKey4Global{ 779 TupleKey4: tuple.TupleKey4{ 780 DestAddr: netip.MustParseAddr(fake.IP(fake.WithIPv4())).As4(), 781 SourceAddr: netip.MustParseAddr(fake.IP(fake.WithIPv4())).As4(), 782 DestPort: uint16(fake.Port()), 783 SourcePort: uint16(fake.Port()), 784 NextHeader: u8proto.U8proto(protos[rand.IntN(len(protos))]), 785 Flags: uint8(flags[rand.IntN(len(flags))]), 786 }, 787 }, 788 } 789 } 790 value := &CtEntry{ 791 Packets: 4 + 4, 792 Bytes: 216 + 216, 793 Lifetime: 37459, 794 Flags: SeenNonSyn | RxClosing, 795 RevNAT: 0, 796 TxFlagsSeen: 0x02, 797 RxFlagsSeen: 0x14, 798 SourceSecurityID: 40653, 799 LastTxReport: 15856, 800 LastRxReport: 15856, 801 } 802 803 cache := make(map[*CtKey4Global]struct{}, size) 804 for len(cache) < size { 805 key := genKey() 806 if _, needGenerate := cache[key]; needGenerate { 807 continue 808 } 809 if err := m.Update(key, value); err != nil { 810 tb.Fatal(err) 811 } 812 cache[key] = struct{}{} 813 } 814 815 return cache 816 }