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  }