github.com/cilium/cilium@v1.16.2/pkg/policy/distillery_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package policy
     5  
     6  import (
     7  	"bytes"
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	stdlog "log"
    12  	"net/netip"
    13  	"strings"
    14  	"sync"
    15  	"testing"
    16  
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  	"golang.org/x/exp/maps"
    20  
    21  	"github.com/cilium/cilium/api/v1/models"
    22  	"github.com/cilium/cilium/pkg/container/bitlpm"
    23  	"github.com/cilium/cilium/pkg/identity"
    24  	"github.com/cilium/cilium/pkg/labels"
    25  	"github.com/cilium/cilium/pkg/option"
    26  	"github.com/cilium/cilium/pkg/policy/api"
    27  	"github.com/cilium/cilium/pkg/policy/trafficdirection"
    28  	"github.com/cilium/cilium/pkg/policy/types"
    29  	"github.com/cilium/cilium/pkg/testutils"
    30  	"github.com/cilium/cilium/pkg/u8proto"
    31  )
    32  
    33  var (
    34  	ep1 = testutils.NewTestEndpoint()
    35  	ep2 = testutils.NewTestEndpoint()
    36  )
    37  
    38  func localIdentity(n uint32) identity.NumericIdentity {
    39  	return identity.NumericIdentity(n) | identity.IdentityScopeLocal
    40  
    41  }
    42  func TestCacheManagement(t *testing.T) {
    43  	repo := NewPolicyRepository(nil, nil, nil)
    44  	cache := repo.policyCache
    45  	identity := ep1.GetSecurityIdentity()
    46  	require.Equal(t, identity, ep2.GetSecurityIdentity())
    47  
    48  	// Nonsense delete of entry that isn't yet inserted
    49  	deleted := cache.delete(identity)
    50  	require.Equal(t, false, deleted)
    51  
    52  	// Insert identity twice. Should be the same policy.
    53  	policy1 := cache.insert(identity)
    54  	policy2 := cache.insert(identity)
    55  	require.Equal(t, policy2, policy1)
    56  
    57  	// Despite two insert calls, there is no reference tracking; any delete
    58  	// will clear the cache.
    59  	cacheCleared := cache.delete(identity)
    60  	require.True(t, cacheCleared)
    61  	cacheCleared = cache.delete(identity)
    62  	require.Equal(t, false, cacheCleared)
    63  
    64  	// Insert two distinct identities, then delete one. Other should still
    65  	// be there.
    66  	ep3 := testutils.NewTestEndpoint()
    67  	ep3.SetIdentity(1234, true)
    68  	identity3 := ep3.GetSecurityIdentity()
    69  	require.NotEqual(t, identity, identity3)
    70  	policy1 = cache.insert(identity)
    71  	policy3 := cache.insert(identity3)
    72  	require.NotEqual(t, policy3, policy1)
    73  	_ = cache.delete(identity)
    74  	policy3 = cache.lookupOrCreate(identity3, false)
    75  	require.NotNil(t, policy3)
    76  }
    77  
    78  func TestCachePopulation(t *testing.T) {
    79  	repo := NewPolicyRepository(nil, nil, nil)
    80  	repo.revision.Store(42)
    81  	cache := repo.policyCache
    82  
    83  	identity1 := ep1.GetSecurityIdentity()
    84  	require.Equal(t, identity1, ep2.GetSecurityIdentity())
    85  	policy1 := cache.insert(identity1)
    86  
    87  	// Calculate the policy and observe that it's cached
    88  	updated, err := cache.updateSelectorPolicy(identity1)
    89  	require.NoError(t, err)
    90  	require.True(t, updated)
    91  	updated, err = cache.updateSelectorPolicy(identity1)
    92  	require.NoError(t, err)
    93  	require.Equal(t, false, updated)
    94  	policy2 := cache.insert(identity1)
    95  	idp1 := policy1.(*cachedSelectorPolicy).getPolicy()
    96  	idp2 := policy2.(*cachedSelectorPolicy).getPolicy()
    97  	require.Equal(t, idp2, idp1)
    98  
    99  	// Remove the identity and observe that it is no longer available
   100  	cacheCleared := cache.delete(identity1)
   101  	require.True(t, cacheCleared)
   102  	updated, err = cache.updateSelectorPolicy(identity1)
   103  	require.Error(t, err)
   104  
   105  	// Attempt to update policy for non-cached endpoint and observe failure
   106  	ep3 := testutils.NewTestEndpoint()
   107  	ep3.SetIdentity(1234, true)
   108  	_, err = cache.updateSelectorPolicy(ep3.GetSecurityIdentity())
   109  	require.Error(t, err)
   110  	require.Equal(t, false, updated)
   111  
   112  	// Insert endpoint with different identity and observe that the cache
   113  	// is different from ep1, ep2
   114  	policy1 = cache.insert(identity1)
   115  	idp1 = policy1.(*cachedSelectorPolicy).getPolicy()
   116  	require.NotNil(t, idp1)
   117  	identity3 := ep3.GetSecurityIdentity()
   118  	policy3 := cache.insert(identity3)
   119  	require.NotEqual(t, policy1, policy3)
   120  	updated, err = cache.updateSelectorPolicy(identity3)
   121  	require.NoError(t, err)
   122  	require.True(t, updated)
   123  	idp3 := policy3.(*cachedSelectorPolicy).getPolicy()
   124  	require.NotEqual(t, idp1, idp3)
   125  
   126  	// If there's an error during policy resolution, update should fail
   127  	//repo.err = fmt.Errorf("not implemented!")
   128  	//repo.revision++
   129  	//_, err = cache.updateSelectorPolicy(identity3)
   130  	//require.Error(t, err)
   131  }
   132  
   133  // Distillery integration tests
   134  func key(id uint32, port uint16, hdr uint8, dir uint8) Key {
   135  	mask := uint16(0xffff)
   136  	if port == 0 {
   137  		mask = 0
   138  	}
   139  	return keyWithPortMask(id, port, mask, hdr, dir)
   140  }
   141  
   142  // keyWithPortMask returns a key with a specific port mask.
   143  // Note: This method inverts the portMask on the key for the caller.
   144  func keyWithPortMask(id uint32, port, portMask uint16, hdr uint8, dir uint8) Key {
   145  	return types.Key{
   146  		Identity:         id,
   147  		DestPort:         port,
   148  		InvertedPortMask: ^portMask,
   149  		Nexthdr:          hdr,
   150  		TrafficDirection: dir,
   151  	}
   152  }
   153  
   154  var (
   155  	// Identity, labels, selectors for an endpoint named "foo"
   156  	identityFoo = uint32(100)
   157  	labelsFoo   = labels.ParseSelectLabelArray("foo", "blue")
   158  	selectFoo_  = api.NewESFromLabels(labels.ParseSelectLabel("foo"))
   159  	allowFooL3_ = selectFoo_
   160  	denyFooL3__ = selectFoo_
   161  
   162  	// Identity, labels, selectors for an endpoint named "bar"
   163  	identityBar = uint32(200)
   164  	labelsBar   = labels.ParseSelectLabelArray("bar", "blue")
   165  	selectBar_  = api.NewESFromLabels(labels.ParseSelectLabel("bar"))
   166  	allowBarL3_ = selectBar_
   167  
   168  	// API rule sections for composability
   169  	// L4 rule sections
   170  	allowAllL4_ []api.PortRule
   171  	allowPort80 = []api.PortRule{{
   172  		Ports: []api.PortProtocol{
   173  			{Port: "80", Protocol: api.ProtoTCP},
   174  		},
   175  	}}
   176  	allowNamedPort80 = []api.PortRule{{
   177  		Ports: []api.PortProtocol{
   178  			{Port: "port-80", Protocol: api.ProtoTCP},
   179  		},
   180  	}}
   181  	denyAllL4_ []api.PortDenyRule
   182  	denyPort80 = []api.PortDenyRule{{
   183  		Ports: []api.PortProtocol{
   184  			{Port: "80", Protocol: api.ProtoTCP},
   185  		},
   186  	}}
   187  	// L7 rule sections
   188  	allowHTTPRoot = &api.L7Rules{
   189  		HTTP: []api.PortRuleHTTP{
   190  			{Method: "GET", Path: "/"},
   191  		},
   192  	}
   193  	// API rule definitions for default-deny, L3, L3L4, L3L4L7, L4, L4L7
   194  	lbls____NoAllow = labels.ParseLabelArray("no-allow")
   195  	rule____NoAllow = api.NewRule().
   196  			WithLabels(lbls____NoAllow).
   197  			WithIngressRules([]api.IngressRule{{}})
   198  	lblsL3____Allow = labels.ParseLabelArray("l3-allow")
   199  	ruleL3____Allow = api.NewRule().
   200  			WithLabels(lblsL3____Allow).
   201  			WithIngressRules([]api.IngressRule{{
   202  			IngressCommonRule: api.IngressCommonRule{
   203  				FromEndpoints: []api.EndpointSelector{allowFooL3_},
   204  			},
   205  			ToPorts: allowAllL4_,
   206  		}})
   207  	lblsL3L4__Allow = labels.ParseLabelArray("l3l4-allow")
   208  	ruleL3L4__Allow = api.NewRule().
   209  			WithLabels(lblsL3L4__Allow).
   210  			WithIngressRules([]api.IngressRule{{
   211  			IngressCommonRule: api.IngressCommonRule{
   212  				FromEndpoints: []api.EndpointSelector{allowFooL3_},
   213  			},
   214  			ToPorts: allowPort80,
   215  		}})
   216  	ruleL3npL4__Allow = api.NewRule().
   217  				WithLabels(lblsL3L4__Allow).
   218  				WithIngressRules([]api.IngressRule{{
   219  			IngressCommonRule: api.IngressCommonRule{
   220  				FromEndpoints: []api.EndpointSelector{allowFooL3_},
   221  			},
   222  			ToPorts: allowNamedPort80,
   223  		}})
   224  	lblsL3L4L7Allow = labels.ParseLabelArray("l3l4l7-allow")
   225  	ruleL3L4L7Allow = api.NewRule().
   226  			WithLabels(lblsL3L4L7Allow).
   227  			WithIngressRules([]api.IngressRule{{
   228  			IngressCommonRule: api.IngressCommonRule{
   229  				FromEndpoints: []api.EndpointSelector{allowFooL3_},
   230  			},
   231  			ToPorts: combineL4L7(allowPort80, allowHTTPRoot),
   232  		}})
   233  	ruleL3npL4L7Allow = api.NewRule().
   234  				WithLabels(lblsL3L4L7Allow).
   235  				WithIngressRules([]api.IngressRule{{
   236  			IngressCommonRule: api.IngressCommonRule{
   237  				FromEndpoints: []api.EndpointSelector{allowFooL3_},
   238  			},
   239  			ToPorts: combineL4L7(allowNamedPort80, allowHTTPRoot),
   240  		}})
   241  	lbls__L4__Allow = labels.ParseLabelArray("l4-allow")
   242  	rule__L4__Allow = api.NewRule().
   243  			WithLabels(lbls__L4__Allow).
   244  			WithIngressRules([]api.IngressRule{{
   245  			ToPorts: allowPort80,
   246  		}})
   247  	rule__L4__AllowAuth = api.NewRule().
   248  				WithLabels(lbls__L4__Allow).
   249  				WithIngressRules([]api.IngressRule{{
   250  			ToPorts: allowPort80,
   251  			Authentication: &api.Authentication{
   252  				Mode: api.AuthenticationModeRequired,
   253  			},
   254  		}})
   255  	rule__npL4__Allow = api.NewRule().
   256  				WithLabels(lbls__L4__Allow).
   257  				WithIngressRules([]api.IngressRule{{
   258  			ToPorts: allowNamedPort80,
   259  		}})
   260  	lbls__L4L7Allow = labels.ParseLabelArray("l4l7-allow")
   261  	rule__L4L7Allow = api.NewRule().
   262  			WithLabels(lbls__L4L7Allow).
   263  			WithIngressRules([]api.IngressRule{{
   264  			ToPorts: combineL4L7(allowPort80, allowHTTPRoot),
   265  		}})
   266  	rule__npL4L7Allow = api.NewRule().
   267  				WithLabels(lbls__L4L7Allow).
   268  				WithIngressRules([]api.IngressRule{{
   269  			ToPorts: combineL4L7(allowNamedPort80, allowHTTPRoot),
   270  		}})
   271  	lblsL3__AllowFoo = labels.ParseLabelArray("l3-allow-foo")
   272  	ruleL3__AllowFoo = api.NewRule().
   273  				WithLabels(lblsL3__AllowFoo).
   274  				WithIngressRules([]api.IngressRule{{
   275  			IngressCommonRule: api.IngressCommonRule{
   276  				FromEndpoints: []api.EndpointSelector{allowFooL3_},
   277  			},
   278  		}})
   279  	lblsL3__AllowBar = labels.ParseLabelArray("l3-allow-bar")
   280  	ruleL3__AllowBar = api.NewRule().
   281  				WithLabels(lblsL3__AllowBar).
   282  				WithIngressRules([]api.IngressRule{{
   283  			IngressCommonRule: api.IngressCommonRule{
   284  				FromEndpoints: []api.EndpointSelector{allowBarL3_},
   285  			},
   286  		}})
   287  	lblsL3L4AllowBar     = labels.ParseLabelArray("l3l4-allow-bar")
   288  	ruleL3L4AllowBarAuth = api.NewRule().
   289  				WithLabels(lblsL3L4AllowBar).
   290  				WithIngressRules([]api.IngressRule{{
   291  			ToPorts: allowPort80,
   292  			IngressCommonRule: api.IngressCommonRule{
   293  				FromEndpoints: []api.EndpointSelector{allowBarL3_},
   294  			},
   295  			Authentication: &api.Authentication{
   296  				Mode: api.AuthenticationModeAlwaysFail,
   297  			},
   298  		}})
   299  	ruleL3__AllowBarAuth = api.NewRule().
   300  				WithLabels(lblsL3__AllowBar).
   301  				WithIngressRules([]api.IngressRule{{
   302  			IngressCommonRule: api.IngressCommonRule{
   303  				FromEndpoints: []api.EndpointSelector{allowBarL3_},
   304  			},
   305  			Authentication: &api.Authentication{
   306  				Mode: api.AuthenticationModeAlwaysFail,
   307  			},
   308  		}})
   309  	lbls____AllowAll = labels.ParseLabelArray("allow-all")
   310  	rule____AllowAll = api.NewRule().
   311  				WithLabels(lbls____AllowAll).
   312  				WithIngressRules([]api.IngressRule{{
   313  			IngressCommonRule: api.IngressCommonRule{
   314  				FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector},
   315  			},
   316  		}})
   317  	rule____AllowAllAuth = api.NewRule().
   318  				WithLabels(lbls____AllowAll).
   319  				WithIngressRules([]api.IngressRule{{
   320  			IngressCommonRule: api.IngressCommonRule{
   321  				FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector},
   322  			},
   323  			Authentication: &api.Authentication{
   324  				Mode: api.AuthenticationModeRequired,
   325  			},
   326  		}})
   327  	lblsAllowAllIngress = labels.LabelArray{
   328  		labels.NewLabel(LabelKeyPolicyDerivedFrom, LabelAllowAnyIngress, labels.LabelSourceReserved),
   329  	}
   330  
   331  	lbls_____NoDeny = labels.ParseLabelArray("deny")
   332  	rule_____NoDeny = api.NewRule().
   333  			WithLabels(lbls_____NoDeny).
   334  			WithIngressRules([]api.IngressRule{{}})
   335  
   336  	lblsL3_____Deny = labels.ParseLabelArray("l3-deny")
   337  	ruleL3_____Deny = api.NewRule().
   338  			WithLabels(lblsL3_____Deny).
   339  			WithIngressDenyRules([]api.IngressDenyRule{{
   340  			IngressCommonRule: api.IngressCommonRule{
   341  				FromEndpoints: []api.EndpointSelector{denyFooL3__},
   342  			},
   343  			ToPorts: denyAllL4_,
   344  		}})
   345  
   346  	lbls__L4___Deny = labels.ParseLabelArray("l4-deny")
   347  	rule__L4___Deny = api.NewRule().
   348  			WithLabels(lbls__L4___Deny).
   349  			WithIngressDenyRules([]api.IngressDenyRule{{
   350  			ToPorts: denyPort80,
   351  		}})
   352  
   353  	lblsL3L4___Deny = labels.ParseLabelArray("l3l4-deny")
   354  	ruleL3L4___Deny = api.NewRule().
   355  			WithLabels(lblsL3L4___Deny).
   356  			WithIngressDenyRules([]api.IngressDenyRule{{
   357  			IngressCommonRule: api.IngressCommonRule{
   358  				FromEndpoints: []api.EndpointSelector{denyFooL3__},
   359  			},
   360  			ToPorts: denyPort80,
   361  		}})
   362  
   363  	// Misc other bpf key fields for convenience / readability.
   364  	dirIngress = trafficdirection.Ingress.Uint8()
   365  	dirEgress  = trafficdirection.Egress.Uint8()
   366  	// Desired map keys for L3, L3-dependent L4, L4
   367  	mapKeyAllowFoo__ = key(identityFoo, 0, 0, dirIngress)
   368  	mapKeyAllowBar__ = key(identityBar, 0, 0, dirIngress)
   369  	mapKeyAllowBarL4 = key(identityBar, 80, 6, dirIngress)
   370  	mapKeyAllowFooL4 = key(identityFoo, 80, 6, dirIngress)
   371  	mapKeyDeny_Foo__ = mapKeyAllowFoo__
   372  	mapKeyDeny_FooL4 = mapKeyAllowFooL4
   373  	mapKeyAllow___L4 = key(0, 80, 6, dirIngress)
   374  	mapKeyDeny____L4 = mapKeyAllow___L4
   375  	mapKeyAllowAll__ = key(0, 0, 0, dirIngress)
   376  	mapKeyAllowAllE_ = key(0, 0, 0, dirEgress)
   377  	// Desired map entries for no L7 redirect / redirect to Proxy
   378  	mapEntryL7None_ = func(lbls ...labels.LabelArray) MapStateEntry {
   379  		return NewMapStateEntry(nil, labels.LabelArrayList(lbls).Sort(), 0, "", 0, false, DefaultAuthType, AuthTypeDisabled).WithOwners()
   380  	}
   381  	mapEntryL7Auth_ = func(at AuthType, lbls ...labels.LabelArray) MapStateEntry {
   382  		return NewMapStateEntry(nil, labels.LabelArrayList(lbls).Sort(), 0, "", 0, false, ExplicitAuthType, at).WithOwners()
   383  	}
   384  	mapEntryL7Deny_ = func(lbls ...labels.LabelArray) MapStateEntry {
   385  		return NewMapStateEntry(nil, labels.LabelArrayList(lbls).Sort(), 0, "", 0, true, DefaultAuthType, AuthTypeDisabled).WithOwners()
   386  	}
   387  	mapEntryL7Proxy = func(lbls ...labels.LabelArray) MapStateEntry {
   388  		entry := NewMapStateEntry(nil, labels.LabelArrayList(lbls).Sort(), 1, "", 0, false, DefaultAuthType, AuthTypeDisabled).WithOwners()
   389  		entry.ProxyPort = 1
   390  		return entry
   391  	}
   392  )
   393  
   394  // combineL4L7 returns a new PortRule that refers to the specified l4 ports and
   395  // l7 rules.
   396  func combineL4L7(l4 []api.PortRule, l7 *api.L7Rules) []api.PortRule {
   397  	result := make([]api.PortRule, 0, len(l4))
   398  	for _, pr := range l4 {
   399  		result = append(result, api.PortRule{
   400  			Ports: pr.Ports,
   401  			Rules: l7,
   402  		})
   403  	}
   404  	return result
   405  }
   406  
   407  // policyDistillery is a convenience wrapper around the existing policy engine,
   408  // allowing simple direct evaluation of L3 and L4 state into "MapState".
   409  type policyDistillery struct {
   410  	*Repository
   411  	log io.Writer
   412  }
   413  
   414  func newPolicyDistillery(selectorCache *SelectorCache) *policyDistillery {
   415  	ret := &policyDistillery{
   416  		Repository: NewPolicyRepository(nil, nil, nil),
   417  	}
   418  	ret.selectorCache = selectorCache
   419  	return ret
   420  }
   421  
   422  func (d *policyDistillery) WithLogBuffer(w io.Writer) *policyDistillery {
   423  	return &policyDistillery{
   424  		Repository: d.Repository,
   425  		log:        w,
   426  	}
   427  }
   428  
   429  // distillPolicy distills the policy repository into a set of bpf map state
   430  // entries for an endpoint with the specified labels.
   431  func (d *policyDistillery) distillPolicy(owner PolicyOwner, epLabels labels.LabelArray, identity *identity.Identity) (MapState, error) {
   432  	sp := d.Repository.GetPolicyCache().insert(identity)
   433  	d.Repository.GetPolicyCache().UpdatePolicy(identity)
   434  	epp := sp.Consume(DummyOwner{})
   435  	if epp == nil {
   436  		return nil, errors.New("policy distillation failure")
   437  	}
   438  
   439  	// Remove the allow-all egress entry that's generated by default. This is
   440  	// because this test suite doesn't have a notion of traffic direction, so
   441  	// the extra egress allow-all is technically correct, but omitted from the
   442  	// expected output that's asserted against for the sake of brevity.
   443  	epp.policyMapState.Delete(mapKeyAllowAllE_)
   444  
   445  	return epp.policyMapState, nil
   446  }
   447  
   448  // Perm calls f with each permutation of a.
   449  func Perm[X any](a []X, f func([]X)) {
   450  	perm(a, f, 0)
   451  }
   452  
   453  // Permute the values at index i to len(a)-1.
   454  func perm[X any](a []X, f func([]X), i int) {
   455  	if i > len(a) {
   456  		f(a)
   457  		return
   458  	}
   459  	perm(a, f, i+1)
   460  	for j := i + 1; j < len(a); j++ {
   461  		a[i], a[j] = a[j], a[i]
   462  		perm(a, f, i+1)
   463  		a[i], a[j] = a[j], a[i]
   464  	}
   465  }
   466  
   467  func Test_Perm(t *testing.T) {
   468  	var res []string
   469  	expected := []string{
   470  		"abc",
   471  		"acb",
   472  		"bac",
   473  		"bca",
   474  		"cba",
   475  		"cab",
   476  	}
   477  	Perm([]rune("abc"), func(x []rune) { res = append(res, string(x)) })
   478  	assert.Equal(t, res, expected, "invalid permutations")
   479  }
   480  
   481  func Test_MergeL3(t *testing.T) {
   482  	// Cache policy enforcement value from when test was ran to avoid pollution
   483  	// across tests.
   484  	oldPolicyEnable := GetPolicyEnabled()
   485  	defer SetPolicyEnabled(oldPolicyEnable)
   486  
   487  	SetPolicyEnabled(option.DefaultEnforcement)
   488  
   489  	identityCache := identity.IdentityMap{
   490  		identity.NumericIdentity(identityFoo): labelsFoo,
   491  		identity.NumericIdentity(identityBar): labelsBar,
   492  	}
   493  	selectorCache := testNewSelectorCache(identityCache)
   494  
   495  	type authResult map[identity.NumericIdentity]AuthTypes
   496  	tests := []struct {
   497  		test   int
   498  		rules  api.Rules
   499  		result MapState
   500  		auths  authResult
   501  	}{
   502  		{
   503  			0,
   504  			api.Rules{ruleL3__AllowFoo, ruleL3__AllowBar},
   505  			NewMapState(map[Key]MapStateEntry{
   506  				mapKeyAllowFoo__: mapEntryL7None_(lblsL3__AllowFoo),
   507  				mapKeyAllowBar__: mapEntryL7None_(lblsL3__AllowBar),
   508  			}),
   509  			authResult{
   510  				identity.NumericIdentity(identityBar): AuthTypes{},
   511  				identity.NumericIdentity(identityFoo): AuthTypes{},
   512  			},
   513  		},
   514  		{
   515  			1,
   516  			api.Rules{ruleL3__AllowFoo, ruleL3L4__Allow},
   517  			NewMapState(map[Key]MapStateEntry{
   518  				mapKeyAllowFoo__: mapEntryL7None_(lblsL3__AllowFoo),
   519  				mapKeyAllowFooL4: mapEntryL7None_(lblsL3L4__Allow),
   520  			}),
   521  			authResult{
   522  				identity.NumericIdentity(identityBar): AuthTypes{},
   523  				identity.NumericIdentity(identityFoo): AuthTypes{},
   524  			},
   525  		},
   526  		{
   527  			2,
   528  			api.Rules{ruleL3__AllowFoo, ruleL3__AllowBarAuth},
   529  			NewMapState(map[Key]MapStateEntry{
   530  				mapKeyAllowFoo__: mapEntryL7None_(lblsL3__AllowFoo),
   531  				mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeAlwaysFail, lblsL3__AllowBar),
   532  			}),
   533  			authResult{
   534  				identity.NumericIdentity(identityBar): AuthTypes{AuthTypeAlwaysFail: struct{}{}},
   535  				identity.NumericIdentity(identityFoo): AuthTypes{},
   536  			},
   537  		},
   538  		{
   539  			3,
   540  			api.Rules{ruleL3__AllowFoo, ruleL3__AllowBarAuth, rule__L4__AllowAuth},
   541  			NewMapState(map[Key]MapStateEntry{
   542  				mapKeyAllow___L4: mapEntryL7Auth_(AuthTypeSpire, lbls__L4__Allow),
   543  				mapKeyAllowFoo__: mapEntryL7None_(lblsL3__AllowFoo),
   544  				mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeAlwaysFail, lblsL3__AllowBar),
   545  			}),
   546  			authResult{
   547  				identity.NumericIdentity(identityBar): AuthTypes{AuthTypeAlwaysFail: struct{}{}, AuthTypeSpire: struct{}{}},
   548  				identity.NumericIdentity(identityFoo): AuthTypes{AuthTypeSpire: struct{}{}},
   549  			},
   550  		},
   551  		{
   552  			4,
   553  			api.Rules{rule____AllowAll, ruleL3__AllowBarAuth},
   554  			NewMapState(map[Key]MapStateEntry{
   555  				mapKeyAllowAll__: mapEntryL7None_(lbls____AllowAll),
   556  				mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeAlwaysFail, lblsL3__AllowBar),
   557  			}),
   558  			authResult{
   559  				identity.NumericIdentity(identityBar): AuthTypes{AuthTypeAlwaysFail: struct{}{}},
   560  				identity.NumericIdentity(identityFoo): AuthTypes{},
   561  			},
   562  		},
   563  		{
   564  			5,
   565  			api.Rules{rule____AllowAllAuth, ruleL3__AllowBar},
   566  			NewMapState(map[Key]MapStateEntry{
   567  				mapKeyAllowAll__: mapEntryL7Auth_(AuthTypeSpire, lbls____AllowAll),
   568  				mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeSpire, lblsL3__AllowBar),
   569  			}),
   570  			authResult{
   571  				identity.NumericIdentity(identityBar): AuthTypes{AuthTypeSpire: struct{}{}},
   572  				identity.NumericIdentity(identityFoo): AuthTypes{AuthTypeSpire: struct{}{}},
   573  			},
   574  		},
   575  		{
   576  			6,
   577  			api.Rules{rule____AllowAllAuth, rule__L4__Allow},
   578  			NewMapState(map[Key]MapStateEntry{
   579  				mapKeyAllowAll__: mapEntryL7Auth_(AuthTypeSpire, lbls____AllowAll),
   580  				mapKeyAllow___L4: mapEntryL7Auth_(AuthTypeSpire, lbls__L4__Allow),
   581  			}),
   582  			authResult{
   583  				identity.NumericIdentity(identityBar): AuthTypes{AuthTypeSpire: struct{}{}},
   584  				identity.NumericIdentity(identityFoo): AuthTypes{AuthTypeSpire: struct{}{}},
   585  			},
   586  		},
   587  		{
   588  			7,
   589  			api.Rules{rule____AllowAllAuth, ruleL3__AllowBar, rule__L4__Allow},
   590  			NewMapState(map[Key]MapStateEntry{
   591  				mapKeyAllowAll__: mapEntryL7Auth_(AuthTypeSpire, lbls____AllowAll),
   592  				mapKeyAllow___L4: mapEntryL7Auth_(AuthTypeSpire, lbls__L4__Allow),
   593  				mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeSpire, lblsL3__AllowBar),
   594  			}),
   595  			authResult{
   596  				identity.NumericIdentity(identityBar): AuthTypes{AuthTypeSpire: struct{}{}},
   597  				identity.NumericIdentity(identityFoo): AuthTypes{AuthTypeSpire: struct{}{}},
   598  			},
   599  		},
   600  		{
   601  			8,
   602  			api.Rules{rule____AllowAll, ruleL3__AllowBar, rule__L4__Allow},
   603  			NewMapState(map[Key]MapStateEntry{
   604  				mapKeyAllowAll__: mapEntryL7Auth_(AuthTypeDisabled, lbls____AllowAll),
   605  				mapKeyAllow___L4: mapEntryL7Auth_(AuthTypeDisabled, lbls__L4__Allow),
   606  				mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeDisabled, lblsL3__AllowBar),
   607  			}),
   608  			authResult{
   609  				identity.NumericIdentity(identityBar): AuthTypes{},
   610  				identity.NumericIdentity(identityFoo): AuthTypes{},
   611  			},
   612  		},
   613  		{
   614  			9,
   615  			api.Rules{rule____AllowAll, rule__L4__Allow, ruleL3__AllowBarAuth},
   616  			NewMapState(map[Key]MapStateEntry{
   617  				mapKeyAllowAll__: mapEntryL7Auth_(AuthTypeDisabled, lbls____AllowAll),
   618  				mapKeyAllow___L4: mapEntryL7Auth_(AuthTypeDisabled, lbls__L4__Allow),
   619  				mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeAlwaysFail, lblsL3__AllowBar),
   620  				mapKeyAllowBarL4: mapEntryL7Auth_(AuthTypeAlwaysFail, lbls__L4__Allow, lblsL3__AllowBar),
   621  			}),
   622  			authResult{
   623  				identity.NumericIdentity(identityBar): AuthTypes{AuthTypeAlwaysFail: struct{}{}},
   624  				identity.NumericIdentity(identityFoo): AuthTypes{},
   625  			},
   626  		},
   627  		{
   628  			10, // Same as 9, but the L3L4 entry is created by an explicit rule.
   629  			api.Rules{rule____AllowAll, rule__L4__Allow, ruleL3__AllowBarAuth, ruleL3L4AllowBarAuth},
   630  			NewMapState(map[Key]MapStateEntry{
   631  				mapKeyAllowAll__: mapEntryL7Auth_(AuthTypeDisabled, lbls____AllowAll),
   632  				mapKeyAllow___L4: mapEntryL7Auth_(AuthTypeDisabled, lbls__L4__Allow),
   633  				mapKeyAllowBar__: mapEntryL7Auth_(AuthTypeAlwaysFail, lblsL3__AllowBar),
   634  				mapKeyAllowBarL4: mapEntryL7Auth_(AuthTypeAlwaysFail, lblsL3L4AllowBar, lbls__L4__Allow, lblsL3__AllowBar),
   635  			}),
   636  			authResult{
   637  				identity.NumericIdentity(identityBar): AuthTypes{AuthTypeAlwaysFail: struct{}{}},
   638  				identity.NumericIdentity(identityFoo): AuthTypes{},
   639  			},
   640  		},
   641  	}
   642  
   643  	identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(identityFoo), labelsFoo)
   644  	for _, tt := range tests {
   645  		for i, r := range tt.rules {
   646  			tt.rules[i] = r.WithEndpointSelector(selectFoo_)
   647  		}
   648  
   649  		round := 0
   650  		Perm(tt.rules, func(rules []*api.Rule) {
   651  			round++
   652  
   653  			repo := newPolicyDistillery(selectorCache)
   654  			_, _ = repo.MustAddList(rules)
   655  
   656  			t.Run(fmt.Sprintf("permutation_%d-%d", tt.test, round), func(t *testing.T) {
   657  				logBuffer := new(bytes.Buffer)
   658  				repo = repo.WithLogBuffer(logBuffer)
   659  				mapstate, err := repo.distillPolicy(DummyOwner{}, labelsFoo, identity)
   660  				if err != nil {
   661  					t.Errorf("Policy resolution failure: %s", err)
   662  				}
   663  				if equal := assert.True(t, mapstate.Equals(tt.result), mapstate.Diff(tt.result)); !equal {
   664  					t.Logf("Rules:\n%s\n\n", api.Rules(rules).String())
   665  					t.Logf("Policy Trace: \n%s\n", logBuffer.String())
   666  					t.Errorf("Policy obtained didn't match expected for endpoint %s:\nObtained: %v\nExpected: %v", labelsFoo, mapstate, tt.result)
   667  				}
   668  				for remoteID, expectedAuthTypes := range tt.auths {
   669  					authTypes := repo.GetAuthTypes(identity.ID, remoteID)
   670  					if !maps.Equal(authTypes, expectedAuthTypes) {
   671  						t.Errorf("Incorrect AuthTypes result for remote ID %d: obtained %v, expected %v", remoteID, authTypes, expectedAuthTypes)
   672  					}
   673  				}
   674  			})
   675  		})
   676  	}
   677  }
   678  
   679  // The following variables names are derived from the following google sheet
   680  // https://docs.google.com/spreadsheets/d/1WANIoZGB48nryylQjjOw6lKjI80eVgPShrdMTMalLEw/edit?usp=sharing
   681  
   682  const (
   683  	L3L4KeyL3 = iota
   684  	L3L4KeyL4
   685  	L3L4KeyL7
   686  	L3L4KeyDeny
   687  	L4KeyL3
   688  	L4KeyL4
   689  	L4KeyL7
   690  	L4KeyDeny
   691  	L3KeyL3
   692  	L3KeyL4
   693  	L3KeyL7
   694  	L3KeyDeny
   695  	Total
   696  )
   697  
   698  // fieldsSet is the representation of the values set in the cells M8-P8, Q8-T8
   699  // and U8-X8.
   700  type fieldsSet struct {
   701  	L3   *bool
   702  	L4   *bool
   703  	L7   *bool
   704  	Deny *bool
   705  }
   706  
   707  // generatedBPFKey is the representation of the values set in the cells [M:P]6,
   708  // [Q:T]6 and [U:X]6.
   709  type generatedBPFKey struct {
   710  	L3L4Key fieldsSet
   711  	L4Key   fieldsSet
   712  	L3Key   fieldsSet
   713  }
   714  
   715  func parseFieldBool(s string) *bool {
   716  	switch s {
   717  	case "X":
   718  		return nil
   719  	case "0":
   720  		return func() *bool { a := false; return &a }()
   721  	case "1":
   722  		return func() *bool { a := true; return &a }()
   723  	default:
   724  		panic("Unknown value")
   725  	}
   726  }
   727  
   728  func parseTable(test string) generatedBPFKey {
   729  	// Remove all consecutive white space characters and return the charts that
   730  	// need want to parse.
   731  	fields := strings.Fields(test)
   732  	if len(fields) != Total {
   733  		panic("Wrong number of expected results")
   734  	}
   735  	return generatedBPFKey{
   736  		L3L4Key: fieldsSet{
   737  			L3:   parseFieldBool(fields[L3L4KeyL3]),
   738  			L4:   parseFieldBool(fields[L3L4KeyL4]),
   739  			L7:   parseFieldBool(fields[L3L4KeyL7]),
   740  			Deny: parseFieldBool(fields[L3L4KeyDeny]),
   741  		},
   742  		L4Key: fieldsSet{
   743  			L3:   parseFieldBool(fields[L4KeyL3]),
   744  			L4:   parseFieldBool(fields[L4KeyL4]),
   745  			L7:   parseFieldBool(fields[L4KeyL7]),
   746  			Deny: parseFieldBool(fields[L4KeyDeny]),
   747  		},
   748  		L3Key: fieldsSet{
   749  			L3:   parseFieldBool(fields[L3KeyL3]),
   750  			L4:   parseFieldBool(fields[L3KeyL4]),
   751  			L7:   parseFieldBool(fields[L3KeyL7]),
   752  			Deny: parseFieldBool(fields[L3KeyDeny]),
   753  		},
   754  	}
   755  }
   756  
   757  // testCaseToMapState generates the expected MapState logic. This function is
   758  // an implementation of the expected behavior. Any relation between this
   759  // function and non unit-test code should be seen as coincidental.
   760  // The algorithm represented in this function should be the source of truth
   761  // of our expectations when enforcing multiple types of policies.
   762  func testCaseToMapState(t generatedBPFKey) MapState {
   763  	m := newMapState(nil)
   764  
   765  	if t.L3Key.L3 != nil {
   766  		if t.L3Key.Deny != nil && *t.L3Key.Deny {
   767  			m.denies.Upsert(mapKeyDeny_Foo__, mapEntryL7Deny_())
   768  		} else {
   769  			// If L7 is not set or if it explicitly set but it's false
   770  			if t.L3Key.L7 == nil || !*t.L3Key.L7 {
   771  				m.allows.Upsert(mapKeyAllowFoo__, mapEntryL7None_())
   772  			}
   773  			// there's no "else" because we don't support L3L7 policies, i.e.,
   774  			// a L4 port needs to be specified.
   775  		}
   776  	}
   777  	if t.L4Key.L3 != nil {
   778  		if t.L4Key.Deny != nil && *t.L4Key.Deny {
   779  			m.denies.Upsert(mapKeyDeny____L4, mapEntryL7Deny_())
   780  		} else {
   781  			// If L7 is not set or if it explicitly set but it's false
   782  			if t.L4Key.L7 == nil || !*t.L4Key.L7 {
   783  				m.allows.Upsert(mapKeyAllow___L4, mapEntryL7None_())
   784  			} else {
   785  				// L7 is set and it's true then we should expected a mapEntry
   786  				// with L7 redirection.
   787  				m.allows.Upsert(mapKeyAllow___L4, mapEntryL7Proxy())
   788  			}
   789  		}
   790  	}
   791  	if t.L3L4Key.L3 != nil {
   792  		if t.L3L4Key.Deny != nil && *t.L3L4Key.Deny {
   793  			m.denies.Upsert(mapKeyDeny_FooL4, mapEntryL7Deny_())
   794  		} else {
   795  			// If L7 is not set or if it explicitly set but it's false
   796  			if t.L3L4Key.L7 == nil || !*t.L3L4Key.L7 {
   797  				m.allows.Upsert(mapKeyAllowFooL4, mapEntryL7None_())
   798  			} else {
   799  				// L7 is set and it's true then we should expected a mapEntry
   800  				// with L7 redirection only if we haven't set it already
   801  				// for an existing L4-only.
   802  				if t.L4Key.L7 == nil || !*t.L4Key.L7 {
   803  					m.allows.Upsert(mapKeyAllowFooL4, mapEntryL7Proxy())
   804  				}
   805  			}
   806  		}
   807  	}
   808  
   809  	// Add dependency deny-L3->deny-L3L4 if allow-L4 exists
   810  	denyL3, denyL3exists := m.denies.Lookup(mapKeyDeny_Foo__)
   811  	denyL3L4, denyL3L4exists := m.denies.Lookup(mapKeyDeny_FooL4)
   812  	allowL4, allowL4exists := m.allows.Lookup(mapKeyAllow___L4)
   813  	if allowL4exists && !allowL4.IsDeny && denyL3exists && denyL3.IsDeny && denyL3L4exists && denyL3L4.IsDeny {
   814  		m.AddDependent(mapKeyDeny_Foo__, mapKeyDeny_FooL4, ChangeState{})
   815  	}
   816  	return m
   817  }
   818  
   819  func generateMapStates() []MapState {
   820  	rawTestTable := []string{
   821  		"X	X	X	X	X	X	X	X	X	X	X	X", // 0
   822  		"X	X	X	X	X	X	X	X	1	0	0	0",
   823  		"X	X	X	X	0	1	0	0	X	X	X	X",
   824  		"X	X	X	X	0	1	0	0	1	0	0	0",
   825  		"1	1	0	0	X	X	X	X	X	X	X	X",
   826  		"1	1	0	0	X	X	X	X	1	0	0	0", // 5
   827  		"X	X	X	X	0	1	0	0	X	X	X	X",
   828  		"X	X	X	X	0	1	0	0	1	0	0	0",
   829  		"X	X	X	X	0	1	1	0	X	X	X	X",
   830  		"X	X	X	X	0	1	1	0	1	0	0	0",
   831  		"X	X	X	X	0	1	1	0	X	X	X	X", // 10
   832  		"X	X	X	X	0	1	1	0	1	0	0	0",
   833  		"1	1	1	0	0	1	1	0	X	X	X	X",
   834  		"1	1	1	0	0	1	1	0	1	0	0	0",
   835  		"1	1	1	0	0	1	1	0	X	X	X	X",
   836  		"1	1	1	0	0	1	1	0	1	0	0	0", // 15
   837  		"1	1	1	0	X	X	X	X	X	X	X	X",
   838  		"1	1	1	0	X	X	X	X	1	0	0	0",
   839  		"1	1	1	0	0	1	0	0	X	X	X	X",
   840  		"1	1	1	0	0	1	0	0	1	0	0	0",
   841  		"1	1	1	0	X	X	X	X	X	X	X	X", // 20
   842  		"1	1	1	0	X	X	X	X	1	0	0	0",
   843  		"1	1	1	0	0	1	0	0	X	X	X	X",
   844  		"1	1	1	0	0	1	0	0	1	0	0	0",
   845  		"1	1	1	0	0	1	1	0	X	X	X	X",
   846  		"1	1	1	0	0	1	1	0	1	0	0	0", // 25
   847  		"1	1	1	0	0	1	1	0	X	X	X	X",
   848  		"1	1	1	0	0	1	1	0	1	0	0	0",
   849  		"1	1	1	0	0	1	1	0	X	X	X	X",
   850  		"1	1	1	0	0	1	1	0	1	0	0	0",
   851  		"1	1	1	0	0	1	1	0	X	X	X	X", // 30
   852  		"1	1	1	0	0	1	1	0	1	0	0	0",
   853  
   854  		"X	X	X	X	X	X	X	X	1	0	0	1", // 32
   855  		"X	X	X	X	X	X	X	X	1	0	0	1",
   856  		"1	1	0	1	0	1	0	0	1	0	0	1",
   857  		"1	1	0	1	0	1	0	0	1	0	0	1",
   858  		"X	X	X	X	X	X	X	X	1	0	0	1",
   859  		"X	X	X	X	X	X	X	X	1	0	0	1",
   860  		"1	1	0	1	0	1	0	0	1	0	0	1",
   861  		"1	1	0	1	0	1	0	0	1	0	0	1",
   862  		"1	1	0	1	0	1	1	0	1	0	0	1",
   863  		"1	1	0	1	0	1	1	0	1	0	0	1",
   864  		"1	1	0	1	0	1	1	0	1	0	0	1",
   865  		"1	1	0	1	0	1	1	0	1	0	0	1",
   866  		"1	1	0	1	0	1	1	0	1	0	0	1",
   867  		"1	1	0	1	0	1	1	0	1	0	0	1",
   868  		"1	1	0	1	0	1	1	0	1	0	0	1",
   869  		"1	1	0	1	0	1	1	0	1	0	0	1",
   870  		"X	X	X	X	X	X	X	X	1	0	0	1",
   871  		"X	X	X	X	X	X	X	X	1	0	0	1",
   872  		"1	1	0	1	0	1	0	0	1	0	0	1",
   873  		"1	1	0	1	0	1	0	0	1	0	0	1",
   874  		"X	X	X	X	X	X	X	X	1	0	0	1",
   875  		"X	X	X	X	X	X	X	X	1	0	0	1",
   876  		"1	1	0	1	0	1	0	0	1	0	0	1",
   877  		"1	1	0	1	0	1	0	0	1	0	0	1",
   878  		"1	1	0	1	0	1	1	0	1	0	0	1",
   879  		"1	1	0	1	0	1	1	0	1	0	0	1",
   880  		"1	1	0	1	0	1	1	0	1	0	0	1",
   881  		"1	1	0	1	0	1	1	0	1	0	0	1",
   882  		"1	1	0	1	0	1	1	0	1	0	0	1",
   883  		"1	1	0	1	0	1	1	0	1	0	0	1",
   884  		"1	1	0	1	0	1	1	0	1	0	0	1",
   885  		"1	1	0	1	0	1	1	0	1	0	0	1",
   886  
   887  		"X	X	X	X	0	1	0	1	X	X	X	X", // 64
   888  		"X	X	X	X	0	1	0	1	1	0	0	0",
   889  		"X	X	X	X	0	1	0	1	X	X	X	X",
   890  		"X	X	X	X	0	1	0	1	1	0	0	0",
   891  		"X	X	X	X	0	1	0	1	X	X	X	X",
   892  		"X	X	X	X	0	1	0	1	1	0	0	0",
   893  		"X	X	X	X	0	1	0	1	X	X	X	X",
   894  		"X	X	X	X	0	1	0	1	1	0	0	0",
   895  		"X	X	X	X	0	1	0	1	X	X	X	X",
   896  		"X	X	X	X	0	1	0	1	1	0	0	0",
   897  		"X	X	X	X	0	1	0	1	X	X	X	X",
   898  		"X	X	X	X	0	1	0	1	1	0	0	0",
   899  		"X	X	X	X	0	1	0	1	X	X	X	X",
   900  		"X	X	X	X	0	1	0	1	1	0	0	0",
   901  		"X	X	X	X	0	1	0	1	X	X	X	X",
   902  		"X	X	X	X	0	1	0	1	1	0	0	0",
   903  		"X	X	X	X	0	1	0	1	X	X	X	X",
   904  		"X	X	X	X	0	1	0	1	1	0	0	0",
   905  		"X	X	X	X	0	1	0	1	X	X	X	X",
   906  		"X	X	X	X	0	1	0	1	1	0	0	0",
   907  		"X	X	X	X	0	1	0	1	X	X	X	X",
   908  		"X	X	X	X	0	1	0	1	1	0	0	0",
   909  		"X	X	X	X	0	1	0	1	X	X	X	X",
   910  		"X	X	X	X	0	1	0	1	1	0	0	0",
   911  		"X	X	X	X	0	1	0	1	X	X	X	X",
   912  		"X	X	X	X	0	1	0	1	1	0	0	0",
   913  		"X	X	X	X	0	1	0	1	X	X	X	X",
   914  		"X	X	X	X	0	1	0	1	1	0	0	0",
   915  		"X	X	X	X	0	1	0	1	X	X	X	X",
   916  		"X	X	X	X	0	1	0	1	1	0	0	0",
   917  		"X	X	X	X	0	1	0	1	X	X	X	X",
   918  		"X	X	X	X	0	1	0	1	1	0	0	0",
   919  
   920  		"X	X	X	X	0	1	0	1	1	0	0	1", // 96
   921  		"X	X	X	X	0	1	0	1	1	0	0	1",
   922  		"X	X	X	X	0	1	0	1	1	0	0	1",
   923  		"X	X	X	X	0	1	0	1	1	0	0	1",
   924  		"X	X	X	X	0	1	0	1	1	0	0	1",
   925  		"X	X	X	X	0	1	0	1	1	0	0	1",
   926  		"X	X	X	X	0	1	0	1	1	0	0	1",
   927  		"X	X	X	X	0	1	0	1	1	0	0	1",
   928  		"X	X	X	X	0	1	0	1	1	0	0	1",
   929  		"X	X	X	X	0	1	0	1	1	0	0	1",
   930  		"X	X	X	X	0	1	0	1	1	0	0	1",
   931  		"X	X	X	X	0	1	0	1	1	0	0	1",
   932  		"X	X	X	X	0	1	0	1	1	0	0	1",
   933  		"X	X	X	X	0	1	0	1	1	0	0	1",
   934  		"X	X	X	X	0	1	0	1	1	0	0	1",
   935  		"X	X	X	X	0	1	0	1	1	0	0	1",
   936  		"X	X	X	X	0	1	0	1	1	0	0	1",
   937  		"X	X	X	X	0	1	0	1	1	0	0	1",
   938  		"X	X	X	X	0	1	0	1	1	0	0	1",
   939  		"X	X	X	X	0	1	0	1	1	0	0	1",
   940  		"X	X	X	X	0	1	0	1	1	0	0	1",
   941  		"X	X	X	X	0	1	0	1	1	0	0	1",
   942  		"X	X	X	X	0	1	0	1	1	0	0	1",
   943  		"X	X	X	X	0	1	0	1	1	0	0	1",
   944  		"X	X	X	X	0	1	0	1	1	0	0	1",
   945  		"X	X	X	X	0	1	0	1	1	0	0	1",
   946  		"X	X	X	X	0	1	0	1	1	0	0	1",
   947  		"X	X	X	X	0	1	0	1	1	0	0	1",
   948  		"X	X	X	X	0	1	0	1	1	0	0	1",
   949  		"X	X	X	X	0	1	0	1	1	0	0	1",
   950  		"X	X	X	X	0	1	0	1	1	0	0	1",
   951  		"X	X	X	X	0	1	0	1	1	0	0	1",
   952  
   953  		"1	1	0	1	X	X	X	X	X	X	X	X", // 128
   954  		"1	1	0	1	X	X	X	X	1	0	0	0",
   955  		"1	1	0	1	0	1	0	0	X	X	X	X",
   956  		"1	1	0	1	0	1	0	0	1	0	0	0",
   957  		"1	1	0	1	X	X	X	X	X	X	X	X",
   958  		"1	1	0	1	X	X	X	X	1	0	0	0",
   959  		"1	1	0	1	0	1	0	0	X	X	X	X",
   960  		"1	1	0	1	0	1	0	0	1	0	0	0",
   961  		"1	1	0	1	0	1	1	0	X	X	X	X",
   962  		"1	1	0	1	0	1	1	0	1	0	0	0",
   963  		"1	1	0	1	0	1	1	0	X	X	X	X",
   964  		"1	1	0	1	0	1	1	0	1	0	0	0",
   965  		"1	1	0	1	0	1	1	0	X	X	X	X",
   966  		"1	1	0	1	0	1	1	0	1	0	0	0",
   967  		"1	1	0	1	0	1	1	0	X	X	X	X",
   968  		"1	1	0	1	0	1	1	0	1	0	0	0",
   969  		"1	1	0	1	X	X	X	X	X	X	X	X",
   970  		"1	1	0	1	X	X	X	X	1	0	0	0",
   971  		"1	1	0	1	0	1	0	0	X	X	X	X",
   972  		"1	1	0	1	0	1	0	0	1	0	0	0",
   973  		"1	1	0	1	X	X	X	X	X	X	X	X",
   974  		"1	1	0	1	X	X	X	X	1	0	0	0",
   975  		"1	1	0	1	0	1	0	0	X	X	X	X",
   976  		"1	1	0	1	0	1	0	0	1	0	0	0",
   977  		"1	1	0	1	0	1	1	0	X	X	X	X",
   978  		"1	1	0	1	0	1	1	0	1	0	0	0",
   979  		"1	1	0	1	0	1	1	0	X	X	X	X",
   980  		"1	1	0	1	0	1	1	0	1	0	0	0",
   981  		"1	1	0	1	0	1	1	0	X	X	X	X",
   982  		"1	1	0	1	0	1	1	0	1	0	0	0",
   983  		"1	1	0	1	0	1	1	0	X	X	X	X",
   984  		"1	1	0	1	0	1	1	0	1	0	0	0",
   985  
   986  		"X	X	X	X	X	X	X	X	1	0	0	1", // 160
   987  		"X	X	X	X	X	X	X	X	1	0	0	1",
   988  		"1	1	0	1	0	1	0	0	1	0	0	1",
   989  		"1	1	0	1	0	1	0	0	1	0	0	1",
   990  		"X	X	X	X	X	X	X	X	1	0	0	1",
   991  		"X	X	X	X	X	X	X	X	1	0	0	1",
   992  		"1	1	0	1	0	1	0	0	1	0	0	1",
   993  		"1	1	0	1	0	1	0	0	1	0	0	1",
   994  		"1	1	0	1	0	1	1	0	1	0	0	1",
   995  		"1	1	0	1	0	1	1	0	1	0	0	1",
   996  		"1	1	0	1	0	1	1	0	1	0	0	1",
   997  		"1	1	0	1	0	1	1	0	1	0	0	1",
   998  		"1	1	0	1	0	1	1	0	1	0	0	1",
   999  		"1	1	0	1	0	1	1	0	1	0	0	1",
  1000  		"1	1	0	1	0	1	1	0	1	0	0	1",
  1001  		"1	1	0	1	0	1	1	0	1	0	0	1",
  1002  		"X	X	X	X	X	X	X	X	1	0	0	1",
  1003  		"X	X	X	X	X	X	X	X	1	0	0	1",
  1004  		"1	1	0	1	0	1	0	0	1	0	0	1",
  1005  		"1	1	0	1	0	1	0	0	1	0	0	1",
  1006  		"X	X	X	X	X	X	X	X	1	0	0	1",
  1007  		"X	X	X	X	X	X	X	X	1	0	0	1",
  1008  		"1	1	0	1	0	1	0	0	1	0	0	1",
  1009  		"1	1	0	1	0	1	0	0	1	0	0	1",
  1010  		"1	1	0	1	0	1	1	0	1	0	0	1",
  1011  		"1	1	0	1	0	1	1	0	1	0	0	1",
  1012  		"1	1	0	1	0	1	1	0	1	0	0	1",
  1013  		"1	1	0	1	0	1	1	0	1	0	0	1",
  1014  		"1	1	0	1	0	1	1	0	1	0	0	1",
  1015  		"1	1	0	1	0	1	1	0	1	0	0	1",
  1016  		"1	1	0	1	0	1	1	0	1	0	0	1",
  1017  		"1	1	0	1	0	1	1	0	1	0	0	1",
  1018  
  1019  		"X	X	X	X	0	1	0	1	X	X	X	X", // 192
  1020  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1021  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1022  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1023  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1024  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1025  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1026  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1027  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1028  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1029  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1030  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1031  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1032  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1033  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1034  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1035  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1036  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1037  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1038  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1039  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1040  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1041  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1042  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1043  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1044  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1045  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1046  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1047  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1048  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1049  		"X	X	X	X	0	1	0	1	X	X	X	X",
  1050  		"X	X	X	X	0	1	0	1	1	0	0	0",
  1051  
  1052  		"X	X	X	X	1	1	0	1	1	0	0	1", // 224
  1053  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1054  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1055  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1056  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1057  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1058  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1059  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1060  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1061  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1062  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1063  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1064  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1065  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1066  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1067  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1068  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1069  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1070  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1071  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1072  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1073  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1074  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1075  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1076  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1077  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1078  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1079  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1080  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1081  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1082  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1083  		"X	X	X	X	1	1	0	1	1	0	0	1",
  1084  	}
  1085  	mapStates := make([]MapState, 0, len(rawTestTable))
  1086  	for _, rawTest := range rawTestTable {
  1087  		testCase := parseTable(rawTest)
  1088  		mapState := testCaseToMapState(testCase)
  1089  		mapStates = append(mapStates, mapState)
  1090  	}
  1091  
  1092  	return mapStates
  1093  }
  1094  
  1095  func generateRule(testCase int) api.Rules {
  1096  	rulesIdx := api.Rules{
  1097  		ruleL3____Allow,
  1098  		rule__L4__Allow,
  1099  		ruleL3L4__Allow,
  1100  		rule__L4L7Allow,
  1101  		ruleL3L4L7Allow,
  1102  		// denyIdx
  1103  		ruleL3_____Deny,
  1104  		rule__L4___Deny,
  1105  		ruleL3L4___Deny,
  1106  	}
  1107  	rules := make(api.Rules, 0, len(rulesIdx))
  1108  	for i := len(rulesIdx) - 1; i >= 0; i-- {
  1109  		if ((testCase >> i) & 0x1) != 0 {
  1110  			rules = append(rules, rulesIdx[i])
  1111  		} else {
  1112  			if i >= 5 { // denyIdx
  1113  				rules = append(rules, rule_____NoDeny)
  1114  			} else {
  1115  				rules = append(rules, rule____NoAllow)
  1116  			}
  1117  		}
  1118  	}
  1119  	return rules
  1120  }
  1121  
  1122  func Test_MergeRules(t *testing.T) {
  1123  	// Cache policy enforcement value from when test was ran to avoid pollution
  1124  	// across tests.
  1125  	oldPolicyEnable := GetPolicyEnabled()
  1126  	defer SetPolicyEnabled(oldPolicyEnable)
  1127  
  1128  	SetPolicyEnabled(option.DefaultEnforcement)
  1129  
  1130  	identityCache := identity.IdentityMap{
  1131  		identity.NumericIdentity(identityFoo): labelsFoo,
  1132  	}
  1133  	selectorCache := testNewSelectorCache(identityCache)
  1134  	identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(identityFoo), labelsFoo)
  1135  
  1136  	tests := []struct {
  1137  		test     int
  1138  		rules    api.Rules
  1139  		expected MapState
  1140  	}{
  1141  		// The following table is derived from the Google Doc here:
  1142  		// https://docs.google.com/spreadsheets/d/1WANIoZGB48nryylQjjOw6lKjI80eVgPShrdMTMalLEw/edit?usp=sharing
  1143  		//
  1144  		//  Rule 0                   | Rule 1         | Rule 2         | Rule 3         | Rule 4         | Rule 5         | Rule 6         | Rule 7         | Desired BPF map state
  1145  		{0, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(nil)},
  1146  		{1, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1147  		{2, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})},
  1148  		{3, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1149  		{4, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3L4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7None_(lblsL3L4__Allow)})},
  1150  		{5, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3L4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7None_(lblsL3L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1151  		{6, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3L4__Allow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})},                                                     // identical L3L4 entry suppressed
  1152  		{7, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3L4__Allow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed
  1153  		{8, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})},
  1154  		{9, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1155  		{10, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, rule____NoAllow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})},
  1156  		{11, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, rule____NoAllow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1157  		{12, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, ruleL3L4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})},                                                                      // L3L4 entry suppressed to allow L4-only entry to redirect
  1158  		{13, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, ruleL3L4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},                  // L3L4 entry suppressed to allow L4-only entry to redirect
  1159  		{14, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, ruleL3L4__Allow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})},                                                     // L3L4 entry suppressed to allow L4-only entry to redirect
  1160  		{15, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__L4L7Allow, ruleL3L4__Allow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // L3L4 entry suppressed to allow L4-only entry to redirect
  1161  		{16, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow)})},
  1162  		{17, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1163  		{18, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, rule____NoAllow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})},
  1164  		{19, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, rule____NoAllow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1165  		{20, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, ruleL3L4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow)})},
  1166  		{21, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, ruleL3L4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1167  		{22, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, ruleL3L4__Allow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})},
  1168  		{23, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule____NoAllow, ruleL3L4__Allow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1169  		{24, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})},                                                                      // identical L3L4 entry suppressed
  1170  		{25, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},                  // identical L3L4 entry suppressed
  1171  		{26, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, rule____NoAllow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})},                                                     // identical L3L4 entry suppressed
  1172  		{27, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, rule____NoAllow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed
  1173  		{28, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, ruleL3L4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})},                                                                      // identical L3L4 entry suppressed
  1174  		{29, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, ruleL3L4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},                  // identical L3L4 entry suppressed
  1175  		{30, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, ruleL3L4__Allow, rule__L4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})},                                                     // identical L3L4 entry suppressed
  1176  		{31, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3L4L7Allow, rule__L4L7Allow, ruleL3L4__Allow, rule__L4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed
  1177  	}
  1178  
  1179  	expectedMapState := generateMapStates()
  1180  	// Add the auto generated test cases for the deny policies
  1181  	generatedIdx := 32
  1182  	for i := generatedIdx; i < 256; i++ {
  1183  		tests = append(tests,
  1184  			struct {
  1185  				test     int
  1186  				rules    api.Rules
  1187  				expected MapState
  1188  			}{
  1189  				test:     i,
  1190  				rules:    generateRule(i),
  1191  				expected: expectedMapState[i],
  1192  			})
  1193  	}
  1194  
  1195  	for i, tt := range tests {
  1196  		repo := newPolicyDistillery(selectorCache)
  1197  		generatedRule := generateRule(tt.test)
  1198  		for _, r := range tt.rules {
  1199  			if r != nil {
  1200  				rule := r.WithEndpointSelector(selectFoo_)
  1201  				_, _ = repo.MustAddList(api.Rules{rule})
  1202  			}
  1203  		}
  1204  		t.Run(fmt.Sprintf("permutation_%d", tt.test), func(t *testing.T) {
  1205  			logBuffer := new(bytes.Buffer)
  1206  			repo = repo.WithLogBuffer(logBuffer)
  1207  			mapstate, err := repo.distillPolicy(DummyOwner{}, labelsFoo, identity)
  1208  			if err != nil {
  1209  				t.Errorf("Policy resolution failure: %s", err)
  1210  			}
  1211  			// Ignore generated rules as they lap LabelArrayList which would
  1212  			// make the tests fail.
  1213  			if i < generatedIdx {
  1214  				if equal := assert.True(t, mapstate.Equals(tt.expected), mapstate.Diff(tt.expected)); !equal {
  1215  					require.EqualExportedValuesf(t, tt.expected, mapstate, "Policy obtained didn't match expected for endpoint %s", labelsFoo)
  1216  					t.Logf("Rules:\n%s\n\n", tt.rules.String())
  1217  					t.Logf("Policy Trace: \n%s\n", logBuffer.String())
  1218  					t.Errorf("Policy obtained didn't match expected for endpoint %s", labelsFoo)
  1219  				}
  1220  			}
  1221  			// It is extremely difficult to derive the "DerivedFromRules" field.
  1222  			// Since this field is only used for debuggability purposes we can
  1223  			// ignore it and test only for the MapState that we are expecting
  1224  			// to be plumbed into the datapath.
  1225  			mapstate.ForEach(func(k Key, v MapStateEntry) bool {
  1226  				if v.DerivedFromRules == nil || len(v.DerivedFromRules) == 0 {
  1227  					return true
  1228  				}
  1229  				v.DerivedFromRules = labels.LabelArrayList(nil).Sort()
  1230  				mapstate.Insert(k, v)
  1231  				return true
  1232  			})
  1233  			if equal := assert.EqualExportedValues(t, expectedMapState[tt.test], mapstate); !equal {
  1234  				t.Logf("Rules:\n%s\n\n", tt.rules.String())
  1235  				t.Logf("Policy Trace: \n%s\n", logBuffer.String())
  1236  				t.Error("Policy obtained didn't match expected for endpoint")
  1237  			}
  1238  			if equal := assert.ElementsMatch(t, tt.rules, generatedRule); !equal {
  1239  				t.Logf("Rules:\n%s\n\n", tt.rules.String())
  1240  				t.Logf("Policy Trace: \n%s\n", logBuffer.String())
  1241  				t.Error("Generated rules didn't match manual rules")
  1242  			}
  1243  		})
  1244  	}
  1245  }
  1246  
  1247  func Test_MergeRulesWithNamedPorts(t *testing.T) {
  1248  	// Cache policy enforcement value from when test was ran to avoid pollution
  1249  	// across tests.
  1250  	oldPolicyEnable := GetPolicyEnabled()
  1251  	defer SetPolicyEnabled(oldPolicyEnable)
  1252  
  1253  	SetPolicyEnabled(option.DefaultEnforcement)
  1254  
  1255  	identityCache := identity.IdentityMap{
  1256  		identity.NumericIdentity(identityFoo): labelsFoo,
  1257  	}
  1258  	selectorCache := testNewSelectorCache(identityCache)
  1259  	identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(identityFoo), labelsFoo)
  1260  
  1261  	tests := []struct {
  1262  		test     int
  1263  		rules    api.Rules
  1264  		expected MapState
  1265  	}{
  1266  		// The following table is derived from the Google Doc here:
  1267  		// https://docs.google.com/spreadsheets/d/1WANIoZGB48nryylQjjOw6lKjI80eVgPShrdMTMalLEw/edit?usp=sharing
  1268  		//
  1269  		//  Rule 0                   | Rule 1         | Rule 2         | Rule 3         | Rule 4         | Rule 5         | Rule 6         | Rule 7         | Desired BPF map state
  1270  		{0, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(nil)},
  1271  		{1, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1272  		{2, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})},
  1273  		{3, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1274  		{4, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3npL4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7None_(lblsL3L4__Allow)})},
  1275  		{5, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3npL4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7None_(lblsL3L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1276  		{6, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3npL4__Allow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})},                                                     // identical L3L4 entry suppressed
  1277  		{7, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule____NoAllow, ruleL3npL4__Allow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed
  1278  		{8, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})},
  1279  		{9, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1280  		{10, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, rule____NoAllow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})},
  1281  		{11, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, rule____NoAllow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1282  		{12, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, ruleL3npL4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})},                                                                        // L3L4 entry suppressed to allow L4-only entry to redirect
  1283  		{13, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, ruleL3npL4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},                    // L3L4 entry suppressed to allow L4-only entry to redirect
  1284  		{14, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, ruleL3npL4__Allow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})},                                                     // L3L4 entry suppressed to allow L4-only entry to redirect
  1285  		{15, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, rule____NoAllow, rule__npL4L7Allow, ruleL3npL4__Allow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // L3L4 entry suppressed to allow L4-only entry to redirect
  1286  		{16, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow)})},
  1287  		{17, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1288  		{18, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, rule____NoAllow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})},
  1289  		{19, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, rule____NoAllow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1290  		{20, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, ruleL3npL4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow)})},
  1291  		{21, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, ruleL3npL4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1292  		{22, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, ruleL3npL4__Allow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow)})},
  1293  		{23, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule____NoAllow, ruleL3npL4__Allow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllowFooL4: mapEntryL7Proxy(lblsL3L4L7Allow, lblsL3L4__Allow), mapKeyAllow___L4: mapEntryL7None_(lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},
  1294  		{24, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, rule____NoAllow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})},                                                                          // identical L3L4 entry suppressed
  1295  		{25, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, rule____NoAllow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},                      // identical L3L4 entry suppressed
  1296  		{26, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, rule____NoAllow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})},                                                       // identical L3L4 entry suppressed
  1297  		{27, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, rule____NoAllow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},   // identical L3L4 entry suppressed
  1298  		{28, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, ruleL3npL4__Allow, rule____NoAllow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow)})},                                                                        // identical L3L4 entry suppressed
  1299  		{29, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, ruleL3npL4__Allow, rule____NoAllow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})},                    // identical L3L4 entry suppressed
  1300  		{30, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, ruleL3npL4__Allow, rule__npL4__Allow, rule____NoAllow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow)})},                                                     // identical L3L4 entry suppressed
  1301  		{31, api.Rules{rule_____NoDeny, rule_____NoDeny, rule_____NoDeny, ruleL3npL4L7Allow, rule__npL4L7Allow, ruleL3npL4__Allow, rule__npL4__Allow, ruleL3____Allow}, newMapState(map[Key]MapStateEntry{mapKeyAllow___L4: mapEntryL7Proxy(lbls__L4L7Allow, lbls__L4__Allow), mapKeyAllowFoo__: mapEntryL7None_(lblsL3____Allow)})}, // identical L3L4 entry suppressed
  1302  	}
  1303  	for _, tt := range tests {
  1304  		repo := newPolicyDistillery(selectorCache)
  1305  		for _, r := range tt.rules {
  1306  			if r != nil {
  1307  				rule := r.WithEndpointSelector(selectFoo_)
  1308  				_, _ = repo.MustAddList(api.Rules{rule})
  1309  			}
  1310  		}
  1311  		t.Run(fmt.Sprintf("permutation_%d", tt.test), func(t *testing.T) {
  1312  			logBuffer := new(bytes.Buffer)
  1313  			repo = repo.WithLogBuffer(logBuffer)
  1314  			mapstate, err := repo.distillPolicy(DummyOwner{}, labelsFoo, identity)
  1315  			if err != nil {
  1316  				t.Errorf("Policy resolution failure: %s", err)
  1317  			}
  1318  			require.Truef(t, mapstate.Equals(tt.expected),
  1319  				"Policy obtained didn't match expected for endpoint %s:\n%s", labelsFoo, mapstate.Diff(tt.expected))
  1320  		})
  1321  	}
  1322  }
  1323  
  1324  func Test_AllowAll(t *testing.T) {
  1325  	// Cache policy enforcement value from when test was ran to avoid pollution
  1326  	// across tests.
  1327  	oldPolicyEnable := GetPolicyEnabled()
  1328  	defer SetPolicyEnabled(oldPolicyEnable)
  1329  
  1330  	SetPolicyEnabled(option.DefaultEnforcement)
  1331  
  1332  	identityCache := identity.IdentityMap{
  1333  		identity.NumericIdentity(identityFoo): labelsFoo,
  1334  		identity.NumericIdentity(identityBar): labelsBar,
  1335  	}
  1336  	selectorCache := testNewSelectorCache(identityCache)
  1337  	identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(identityFoo), labelsFoo)
  1338  
  1339  	tests := []struct {
  1340  		test     int
  1341  		selector api.EndpointSelector
  1342  		rules    api.Rules
  1343  		expected MapState
  1344  	}{
  1345  		{0, api.EndpointSelectorNone, api.Rules{rule____AllowAll}, NewMapState(map[Key]MapStateEntry{mapKeyAllowAll__: mapEntryL7None_(lblsAllowAllIngress)})},
  1346  		{1, api.WildcardEndpointSelector, api.Rules{rule____AllowAll}, NewMapState(map[Key]MapStateEntry{mapKeyAllowAll__: mapEntryL7None_(lbls____AllowAll)})},
  1347  	}
  1348  
  1349  	for _, tt := range tests {
  1350  		repo := newPolicyDistillery(selectorCache)
  1351  		for _, r := range tt.rules {
  1352  			if r != nil {
  1353  				rule := r.WithEndpointSelector(tt.selector)
  1354  				_, _ = repo.MustAddList(api.Rules{rule})
  1355  			}
  1356  		}
  1357  		t.Run(fmt.Sprintf("permutation_%d", tt.test), func(t *testing.T) {
  1358  			logBuffer := new(bytes.Buffer)
  1359  			repo = repo.WithLogBuffer(logBuffer)
  1360  			mapstate, err := repo.distillPolicy(DummyOwner{}, labelsFoo, identity)
  1361  			if err != nil {
  1362  				t.Errorf("Policy resolution failure: %s", err)
  1363  			}
  1364  			if equal := assert.True(t, mapstate.Equals(tt.expected), mapstate.Diff(tt.expected)); !equal {
  1365  				t.Logf("Rules:\n%s\n\n", tt.rules.String())
  1366  				t.Logf("Policy Trace: \n%s\n", logBuffer.String())
  1367  				t.Errorf("Policy obtained didn't match expected for endpoint %s", labelsFoo)
  1368  			}
  1369  		})
  1370  	}
  1371  }
  1372  
  1373  var (
  1374  	ruleAllowAllIngress = api.NewRule().WithIngressRules([]api.IngressRule{{
  1375  		IngressCommonRule: api.IngressCommonRule{
  1376  			FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector},
  1377  		}}}).WithEndpointSelector(api.WildcardEndpointSelector)
  1378  	ruleL3DenyWorld = api.NewRule().WithIngressDenyRules([]api.IngressDenyRule{{
  1379  		IngressCommonRule: api.IngressCommonRule{
  1380  			FromEntities: api.EntitySlice{api.EntityWorld},
  1381  		},
  1382  	}}).WithEgressDenyRules([]api.EgressDenyRule{{
  1383  		EgressCommonRule: api.EgressCommonRule{
  1384  			ToEntities: api.EntitySlice{api.EntityWorld},
  1385  		},
  1386  	}}).WithEndpointSelector(api.WildcardEndpointSelector)
  1387  
  1388  	cpyRule                   = *ruleL3DenyWorld
  1389  	ruleL3DenyWorldWithLabels = (&cpyRule).WithLabels(labels.LabelWorld.LabelArray())
  1390  	worldReservedID           = identity.ReservedIdentityWorld.Uint32()
  1391  	mapKeyL3WorldIngress      = key(worldReservedID, 0, 0, trafficdirection.Ingress.Uint8())
  1392  	mapKeyL3WorldEgress       = key(worldReservedID, 0, 0, trafficdirection.Egress.Uint8())
  1393  	mapEntryDeny              = MapStateEntry{
  1394  		ProxyPort:        0,
  1395  		DerivedFromRules: labels.LabelArrayList{nil},
  1396  		IsDeny:           true,
  1397  		owners:           map[MapStateOwner]struct{}{},
  1398  	}
  1399  	mapEntryAllow = MapStateEntry{
  1400  		ProxyPort:        0,
  1401  		DerivedFromRules: labels.LabelArrayList{nil},
  1402  		owners:           map[MapStateOwner]struct{}{},
  1403  	}
  1404  	worldLabelArrayList         = labels.LabelArrayList{labels.LabelWorld.LabelArray()}
  1405  	mapEntryWorldDenyWithLabels = MapStateEntry{
  1406  		ProxyPort:        0,
  1407  		DerivedFromRules: worldLabelArrayList,
  1408  		IsDeny:           true,
  1409  		owners:           map[MapStateOwner]struct{}{},
  1410  	}
  1411  
  1412  	worldIPIdentity = localIdentity(16324)
  1413  	worldIPCIDR     = api.CIDR("192.0.2.3/32")
  1414  	lblWorldIP      = labels.ParseSelectLabelArray(fmt.Sprintf("%s:%s", labels.LabelSourceCIDR, worldIPCIDR))
  1415  	hostIPv4        = api.CIDR("172.19.0.1/32")
  1416  	hostIPv6        = api.CIDR("fc00:c111::3/64")
  1417  	lblHostIPv4CIDR = labels.GetCIDRLabels(netip.MustParsePrefix(string(hostIPv4)))
  1418  	lblHostIPv6CIDR = labels.GetCIDRLabels(netip.MustParsePrefix(string(hostIPv6)))
  1419  
  1420  	ruleL3AllowWorldIP = api.NewRule().WithIngressRules([]api.IngressRule{{
  1421  		IngressCommonRule: api.IngressCommonRule{
  1422  			FromCIDR: api.CIDRSlice{worldIPCIDR},
  1423  		},
  1424  	}}).WithEgressRules([]api.EgressRule{{
  1425  		EgressCommonRule: api.EgressCommonRule{
  1426  			ToCIDR: api.CIDRSlice{worldIPCIDR},
  1427  		},
  1428  	}}).WithEndpointSelector(api.WildcardEndpointSelector)
  1429  
  1430  	worldSubnetIdentity = localIdentity(16325)
  1431  	worldSubnet         = api.CIDR("192.0.2.0/24")
  1432  	worldSubnetRule     = api.CIDRRule{
  1433  		Cidr: worldSubnet,
  1434  	}
  1435  	lblWorldSubnet   = labels.GetCIDRLabels(netip.MustParsePrefix(string(worldSubnet)))
  1436  	ruleL3DenySubnet = api.NewRule().WithIngressDenyRules([]api.IngressDenyRule{{
  1437  		IngressCommonRule: api.IngressCommonRule{
  1438  			FromCIDRSet: api.CIDRRuleSlice{worldSubnetRule},
  1439  		},
  1440  	}}).WithEgressDenyRules([]api.EgressDenyRule{{
  1441  		EgressCommonRule: api.EgressCommonRule{
  1442  			ToCIDRSet: api.CIDRRuleSlice{worldSubnetRule},
  1443  		},
  1444  	}}).WithEndpointSelector(api.WildcardEndpointSelector)
  1445  	mapKeyL3SubnetIngress = key(worldSubnetIdentity.Uint32(), 0, 0, trafficdirection.Ingress.Uint8())
  1446  	mapKeyL3SubnetEgress  = key(worldSubnetIdentity.Uint32(), 0, 0, trafficdirection.Egress.Uint8())
  1447  
  1448  	ruleL3DenySmallerSubnet = api.NewRule().WithIngressDenyRules([]api.IngressDenyRule{{
  1449  		IngressCommonRule: api.IngressCommonRule{
  1450  			FromCIDRSet: api.CIDRRuleSlice{api.CIDRRule{Cidr: worldIPCIDR}},
  1451  		},
  1452  	}}).WithEgressDenyRules([]api.EgressDenyRule{{
  1453  		EgressCommonRule: api.EgressCommonRule{
  1454  			ToCIDRSet: api.CIDRRuleSlice{api.CIDRRule{Cidr: worldIPCIDR}},
  1455  		},
  1456  	}}).WithEndpointSelector(api.WildcardEndpointSelector)
  1457  
  1458  	ruleL3AllowLargerSubnet = api.NewRule().WithIngressRules([]api.IngressRule{{
  1459  		IngressCommonRule: api.IngressCommonRule{
  1460  			FromCIDRSet: api.CIDRRuleSlice{api.CIDRRule{Cidr: worldSubnet}},
  1461  		},
  1462  	}}).WithEgressRules([]api.EgressRule{{
  1463  		EgressCommonRule: api.EgressCommonRule{
  1464  			ToCIDRSet: api.CIDRRuleSlice{api.CIDRRule{Cidr: worldSubnet}},
  1465  		},
  1466  	}}).WithEndpointSelector(api.WildcardEndpointSelector)
  1467  
  1468  	mapKeyL3WorldIPIngress = key(worldIPIdentity.Uint32(), 0, 0, trafficdirection.Ingress.Uint8())
  1469  	mapKeyL3WorldIPEgress  = key(worldIPIdentity.Uint32(), 0, 0, trafficdirection.Egress.Uint8())
  1470  
  1471  	ruleL3AllowHostEgress = api.NewRule().WithEgressRules([]api.EgressRule{{
  1472  		EgressCommonRule: api.EgressCommonRule{
  1473  			ToCIDRSet: api.CIDRRuleSlice{api.CIDRRule{Cidr: hostIPv4}, api.CIDRRule{Cidr: hostIPv6}},
  1474  		},
  1475  	}}).WithEndpointSelector(api.WildcardEndpointSelector)
  1476  
  1477  	mapKeyL3UnknownIngress = key(identity.IdentityUnknown.Uint32(), 0, 0, trafficdirection.Ingress.Uint8())
  1478  	derivedFrom            = labels.LabelArrayList{
  1479  		labels.LabelArray{
  1480  			labels.NewLabel(LabelKeyPolicyDerivedFrom, LabelAllowAnyIngress, labels.LabelSourceReserved),
  1481  		},
  1482  	}
  1483  	mapEntryL3UnknownIngress          = NewMapStateEntry(nil, derivedFrom, 0, "", 0, false, ExplicitAuthType, AuthTypeDisabled)
  1484  	mapKeyL3HostEgress                = key(identity.ReservedIdentityHost.Uint32(), 0, 0, trafficdirection.Egress.Uint8())
  1485  	ruleL3L4Port8080ProtoAnyDenyWorld = api.NewRule().WithIngressDenyRules([]api.IngressDenyRule{
  1486  		{
  1487  			ToPorts: api.PortDenyRules{
  1488  				api.PortDenyRule{
  1489  					Ports: []api.PortProtocol{
  1490  						{
  1491  							Port:     "8080",
  1492  							Protocol: api.ProtoAny,
  1493  						},
  1494  					},
  1495  				},
  1496  			},
  1497  			IngressCommonRule: api.IngressCommonRule{
  1498  				FromEntities: api.EntitySlice{api.EntityWorld},
  1499  			},
  1500  		},
  1501  	}).WithEgressDenyRules([]api.EgressDenyRule{
  1502  		{
  1503  			ToPorts: api.PortDenyRules{
  1504  				api.PortDenyRule{
  1505  					Ports: []api.PortProtocol{
  1506  						{
  1507  							Port:     "8080",
  1508  							Protocol: api.ProtoAny,
  1509  						},
  1510  					},
  1511  				},
  1512  			},
  1513  			EgressCommonRule: api.EgressCommonRule{
  1514  				ToEntities: api.EntitySlice{api.EntityWorld},
  1515  			},
  1516  		},
  1517  	}).WithEndpointSelector(api.WildcardEndpointSelector)
  1518  	mapKeyL3L4Port8080ProtoTCPWorldIngress  = key(worldReservedID, 8080, 6, trafficdirection.Ingress.Uint8())
  1519  	mapKeyL3L4Port8080ProtoTCPWorldEgress   = key(worldReservedID, 8080, 6, trafficdirection.Egress.Uint8())
  1520  	mapKeyL3L4Port8080ProtoUDPWorldIngress  = key(worldReservedID, 8080, 17, trafficdirection.Ingress.Uint8())
  1521  	mapKeyL3L4Port8080ProtoUDPWorldEgress   = key(worldReservedID, 8080, 17, trafficdirection.Egress.Uint8())
  1522  	mapKeyL3L4Port8080ProtoSCTPWorldIngress = key(worldReservedID, 8080, 132, trafficdirection.Ingress.Uint8())
  1523  	mapKeyL3L4Port8080ProtoSCTPWorldEgress  = key(worldReservedID, 8080, 132, trafficdirection.Egress.Uint8())
  1524  
  1525  	mapKeyL3L4Port8080ProtoTCPWorldSNIngress  = key(worldSubnetIdentity.Uint32(), 8080, 6, trafficdirection.Ingress.Uint8())
  1526  	mapKeyL3L4Port8080ProtoTCPWorldSNEgress   = key(worldSubnetIdentity.Uint32(), 8080, 6, trafficdirection.Egress.Uint8())
  1527  	mapKeyL3L4Port8080ProtoUDPWorldSNIngress  = key(worldSubnetIdentity.Uint32(), 8080, 17, trafficdirection.Ingress.Uint8())
  1528  	mapKeyL3L4Port8080ProtoUDPWorldSNEgress   = key(worldSubnetIdentity.Uint32(), 8080, 17, trafficdirection.Egress.Uint8())
  1529  	mapKeyL3L4Port8080ProtoSCTPWorldSNIngress = key(worldSubnetIdentity.Uint32(), 8080, 132, trafficdirection.Ingress.Uint8())
  1530  	mapKeyL3L4Port8080ProtoSCTPWorldSNEgress  = key(worldSubnetIdentity.Uint32(), 8080, 132, trafficdirection.Egress.Uint8())
  1531  
  1532  	mapKeyL3L4Port8080ProtoTCPWorldIPIngress  = key(worldIPIdentity.Uint32(), 8080, 6, trafficdirection.Ingress.Uint8())
  1533  	mapKeyL3L4Port8080ProtoTCPWorldIPEgress   = key(worldIPIdentity.Uint32(), 8080, 6, trafficdirection.Egress.Uint8())
  1534  	mapKeyL3L4Port8080ProtoUDPWorldIPIngress  = key(worldIPIdentity.Uint32(), 8080, 17, trafficdirection.Ingress.Uint8())
  1535  	mapKeyL3L4Port8080ProtoUDPWorldIPEgress   = key(worldIPIdentity.Uint32(), 8080, 17, trafficdirection.Egress.Uint8())
  1536  	mapKeyL3L4Port8080ProtoSCTPWorldIPIngress = key(worldIPIdentity.Uint32(), 8080, 132, trafficdirection.Ingress.Uint8())
  1537  	mapKeyL3L4Port8080ProtoSCTPWorldIPEgress  = key(worldIPIdentity.Uint32(), 8080, 132, trafficdirection.Egress.Uint8())
  1538  
  1539  	ruleL3AllowWorldSubnet = api.NewRule().WithIngressRules([]api.IngressRule{{
  1540  		ToPorts: api.PortRules{
  1541  			api.PortRule{
  1542  				Ports: []api.PortProtocol{
  1543  					{
  1544  						Port:     "8080",
  1545  						Protocol: api.ProtoAny,
  1546  					},
  1547  				},
  1548  			},
  1549  		},
  1550  		IngressCommonRule: api.IngressCommonRule{
  1551  			FromCIDR: api.CIDRSlice{worldSubnet},
  1552  		},
  1553  	}}).WithEgressRules([]api.EgressRule{{
  1554  		ToPorts: api.PortRules{
  1555  			api.PortRule{
  1556  				Ports: []api.PortProtocol{
  1557  					{
  1558  						Port:     "8080",
  1559  						Protocol: api.ProtoAny,
  1560  					},
  1561  				},
  1562  			},
  1563  		},
  1564  		EgressCommonRule: api.EgressCommonRule{
  1565  			ToCIDR: api.CIDRSlice{worldSubnet},
  1566  		},
  1567  	}}).WithEndpointSelector(api.WildcardEndpointSelector)
  1568  
  1569  	ruleL3DenyWorldIP = api.NewRule().WithIngressDenyRules([]api.IngressDenyRule{{
  1570  		IngressCommonRule: api.IngressCommonRule{
  1571  			FromCIDR: api.CIDRSlice{worldIPCIDR},
  1572  		},
  1573  	}}).WithEgressDenyRules([]api.EgressDenyRule{{
  1574  		EgressCommonRule: api.EgressCommonRule{
  1575  			ToCIDR: api.CIDRSlice{worldIPCIDR},
  1576  		},
  1577  	}}).WithEndpointSelector(api.WildcardEndpointSelector)
  1578  	mapKeyAnyIngress                        = key(0, 0, 0, trafficdirection.Ingress.Uint8())
  1579  	mapKeyL4AnyPortProtoWorldIPIngress      = key(worldIPIdentity.Uint32(), 0, 0, trafficdirection.Ingress.Uint8())
  1580  	mapKeyL4AnyPortProtoWorldIPEgress       = key(worldIPIdentity.Uint32(), 0, 0, trafficdirection.Egress.Uint8())
  1581  	mapKeyL4Port8080ProtoTCPWorldIPIngress  = key(worldIPIdentity.Uint32(), 8080, 6, trafficdirection.Ingress.Uint8())
  1582  	mapKeyL4Port8080ProtoTCPWorldIPEgress   = key(worldIPIdentity.Uint32(), 8080, 6, trafficdirection.Egress.Uint8())
  1583  	mapKeyL4Port8080ProtoUDPWorldIPIngress  = key(worldIPIdentity.Uint32(), 8080, 17, trafficdirection.Ingress.Uint8())
  1584  	mapKeyL4Port8080ProtoUDPWorldIPEgress   = key(worldIPIdentity.Uint32(), 8080, 17, trafficdirection.Egress.Uint8())
  1585  	mapKeyL4Port8080ProtoSCTPWorldIPIngress = key(worldIPIdentity.Uint32(), 8080, 132, trafficdirection.Ingress.Uint8())
  1586  	mapKeyL4Port8080ProtoSCTPWorldIPEgress  = key(worldIPIdentity.Uint32(), 8080, 132, trafficdirection.Egress.Uint8())
  1587  	mapEntryL4WorldIPDependentsIngressDeny  = MapStateEntry{
  1588  		ProxyPort:        0,
  1589  		IsDeny:           true,
  1590  		DerivedFromRules: labels.LabelArrayList{nil},
  1591  		owners:           map[MapStateOwner]struct{}{},
  1592  		dependents: Keys{
  1593  			mapKeyL4Port8080ProtoTCPWorldIPIngress:  struct{}{},
  1594  			mapKeyL4Port8080ProtoUDPWorldIPIngress:  struct{}{},
  1595  			mapKeyL4Port8080ProtoSCTPWorldIPIngress: struct{}{},
  1596  		},
  1597  	}
  1598  	mapEntryL4WorldIPDependentsEgressDeny = MapStateEntry{
  1599  		ProxyPort:        0,
  1600  		IsDeny:           true,
  1601  		DerivedFromRules: labels.LabelArrayList{nil},
  1602  		owners:           map[MapStateOwner]struct{}{},
  1603  		dependents: Keys{
  1604  			mapKeyL4Port8080ProtoTCPWorldIPEgress:  struct{}{},
  1605  			mapKeyL4Port8080ProtoUDPWorldIPEgress:  struct{}{},
  1606  			mapKeyL4Port8080ProtoSCTPWorldIPEgress: struct{}{},
  1607  		},
  1608  	}
  1609  
  1610  	ruleL3AllowWorldSubnetNamedPort = api.NewRule().WithIngressRules([]api.IngressRule{{
  1611  		ToPorts: api.PortRules{
  1612  			api.PortRule{
  1613  				Ports: []api.PortProtocol{
  1614  					{
  1615  						Port:     "http",
  1616  						Protocol: api.ProtoTCP,
  1617  					},
  1618  				},
  1619  			},
  1620  		},
  1621  		IngressCommonRule: api.IngressCommonRule{
  1622  			FromCIDR: api.CIDRSlice{worldSubnet},
  1623  		},
  1624  	}}).WithEndpointSelector(api.WildcardEndpointSelector)
  1625  	mapKeyL3L4NamedPortHTTPProtoTCPWorldSubNetIngress = key(worldSubnetIdentity.Uint32(), 80, 6, trafficdirection.Ingress.Uint8())
  1626  	mapKeyL3L4NamedPortHTTPProtoTCPWorldIPIngress     = key(worldIPIdentity.Uint32(), 80, 6, trafficdirection.Ingress.Uint8())
  1627  
  1628  	ruleL3AllowWorldSubnetPortRange = api.NewRule().WithIngressRules([]api.IngressRule{{
  1629  		ToPorts: api.PortRules{
  1630  			api.PortRule{
  1631  				Ports: []api.PortProtocol{
  1632  					{
  1633  						Port:     "64",
  1634  						EndPort:  127,
  1635  						Protocol: api.ProtoTCP,
  1636  					},
  1637  					{
  1638  						Port:     "5",
  1639  						EndPort:  10,
  1640  						Protocol: api.ProtoTCP,
  1641  					},
  1642  				},
  1643  			},
  1644  		},
  1645  		IngressCommonRule: api.IngressCommonRule{
  1646  			FromCIDR: api.CIDRSlice{worldSubnet},
  1647  		},
  1648  	}}).WithEndpointSelector(api.WildcardEndpointSelector)
  1649  	mapKeyL3L4Port64To127ProtoTCPWorldSubNetIngress = keyWithPortMask(worldSubnetIdentity.Uint32(), 64, 0xffc0, 6, trafficdirection.Ingress.Uint8())
  1650  	mapKeyL3L4Port5ProtoTCPWorldSubNetIngress       = key(worldSubnetIdentity.Uint32(), 5, 6, trafficdirection.Ingress.Uint8())
  1651  	mapKeyL3L4Port6To7ProtoTCPWorldSubNetIngress    = keyWithPortMask(worldSubnetIdentity.Uint32(), 6, 0xfffe, 6, trafficdirection.Ingress.Uint8())
  1652  	mapKeyL3L4Port8To9ProtoTCPWorldSubNetIngress    = keyWithPortMask(worldSubnetIdentity.Uint32(), 8, 0xfffe, 6, trafficdirection.Ingress.Uint8())
  1653  	mapKeyL3L4Port10ProtoTCPWorldSubNetIngress      = key(worldSubnetIdentity.Uint32(), 10, 6, trafficdirection.Ingress.Uint8())
  1654  	mapKeyL3L4Port64To127ProtoTCPWorldIPIngress     = keyWithPortMask(worldIPIdentity.Uint32(), 64, 0xffc0, 6, trafficdirection.Ingress.Uint8())
  1655  	mapKeyL3L4Port5ProtoTCPWorldIPIngress           = key(worldIPIdentity.Uint32(), 5, 6, trafficdirection.Ingress.Uint8())
  1656  	mapKeyL3L4Port6To7ProtoTCPWorldIPIngress        = keyWithPortMask(worldIPIdentity.Uint32(), 6, 0xfffe, 6, trafficdirection.Ingress.Uint8())
  1657  	mapKeyL3L4Port8To9ProtoTCPWorldIPIngress        = keyWithPortMask(worldIPIdentity.Uint32(), 8, 0xfffe, 6, trafficdirection.Ingress.Uint8())
  1658  	mapKeyL3L4Port10ProtoTCPWorldIPIngress          = key(worldIPIdentity.Uint32(), 10, 6, trafficdirection.Ingress.Uint8())
  1659  )
  1660  
  1661  func Test_EnsureDeniesPrecedeAllows(t *testing.T) {
  1662  	// Cache policy enforcement value from when test was ran to avoid pollution
  1663  	// across tests.
  1664  	oldPolicyEnable := GetPolicyEnabled()
  1665  	defer SetPolicyEnabled(oldPolicyEnable)
  1666  
  1667  	SetPolicyEnabled(option.DefaultEnforcement)
  1668  
  1669  	identityCache := identity.IdentityMap{
  1670  		identity.NumericIdentity(identityFoo): labelsFoo,
  1671  		identity.ReservedIdentityWorld:        labels.LabelWorld.LabelArray(),
  1672  		worldIPIdentity:                       lblWorldIP,                  // "192.0.2.3/32"
  1673  		worldSubnetIdentity:                   lblWorldSubnet.LabelArray(), // "192.0.2.0/24"
  1674  	}
  1675  	selectorCache := testNewSelectorCache(identityCache)
  1676  	identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(identityFoo), labelsFoo)
  1677  
  1678  	tests := []struct {
  1679  		test     string
  1680  		rules    api.Rules
  1681  		expected MapState
  1682  	}{
  1683  		{"deny_world_no_labels", api.Rules{ruleAllowAllIngress, ruleL3DenyWorld, ruleL3AllowWorldIP}, newMapState(map[Key]MapStateEntry{
  1684  			mapKeyAnyIngress:       mapEntryAllow,
  1685  			mapKeyL3WorldIngress:   mapEntryDeny,
  1686  			mapKeyL3WorldEgress:    mapEntryDeny,
  1687  			mapKeyL3SubnetIngress:  mapEntryDeny,
  1688  			mapKeyL3SubnetEgress:   mapEntryDeny,
  1689  			mapKeyL3WorldIPIngress: mapEntryDeny,
  1690  			mapKeyL3WorldIPEgress:  mapEntryDeny,
  1691  		})}, {"deny_world_with_labels", api.Rules{ruleAllowAllIngress, ruleL3DenyWorldWithLabels, ruleL3AllowWorldIP}, newMapState(map[Key]MapStateEntry{
  1692  			mapKeyAnyIngress:       mapEntryAllow,
  1693  			mapKeyL3WorldIngress:   mapEntryWorldDenyWithLabels,
  1694  			mapKeyL3WorldEgress:    mapEntryWorldDenyWithLabels,
  1695  			mapKeyL3SubnetIngress:  mapEntryDeny,
  1696  			mapKeyL3SubnetEgress:   mapEntryDeny,
  1697  			mapKeyL3WorldIPIngress: mapEntryDeny,
  1698  			mapKeyL3WorldIPEgress:  mapEntryDeny,
  1699  		})}, {"deny_one_ip_with_a_larger_subnet", api.Rules{ruleAllowAllIngress, ruleL3DenySubnet, ruleL3AllowWorldIP}, newMapState(map[Key]MapStateEntry{
  1700  			mapKeyAnyIngress:       mapEntryAllow,
  1701  			mapKeyL3SubnetIngress:  mapEntryDeny,
  1702  			mapKeyL3SubnetEgress:   mapEntryDeny,
  1703  			mapKeyL3WorldIPIngress: mapEntryDeny,
  1704  			mapKeyL3WorldIPEgress:  mapEntryDeny,
  1705  		})}, {"deny_part_of_a_subnet_with_an_ip", api.Rules{ruleAllowAllIngress, ruleL3DenySmallerSubnet, ruleL3AllowLargerSubnet}, newMapState(map[Key]MapStateEntry{
  1706  			mapKeyAnyIngress:       mapEntryAllow,
  1707  			mapKeyL3WorldIPIngress: mapEntryDeny,
  1708  			mapKeyL3WorldIPEgress:  mapEntryDeny,
  1709  			mapKeyL3SubnetIngress:  mapEntryAllow,
  1710  			mapKeyL3SubnetEgress:   mapEntryAllow,
  1711  		})}, {"broad_cidr_deny_is_a_portproto_subset_of_a_specific_cidr_allow", api.Rules{ruleAllowAllIngress, ruleL3L4Port8080ProtoAnyDenyWorld, ruleL3AllowWorldIP}, newMapState(map[Key]MapStateEntry{
  1712  			mapKeyAnyIngress:                          mapEntryAllow,
  1713  			mapKeyL3L4Port8080ProtoTCPWorldIngress:    mapEntryDeny,
  1714  			mapKeyL3L4Port8080ProtoTCPWorldEgress:     mapEntryDeny,
  1715  			mapKeyL3L4Port8080ProtoUDPWorldIngress:    mapEntryDeny,
  1716  			mapKeyL3L4Port8080ProtoUDPWorldEgress:     mapEntryDeny,
  1717  			mapKeyL3L4Port8080ProtoSCTPWorldIngress:   mapEntryDeny,
  1718  			mapKeyL3L4Port8080ProtoSCTPWorldEgress:    mapEntryDeny,
  1719  			mapKeyL3L4Port8080ProtoTCPWorldSNIngress:  mapEntryDeny,
  1720  			mapKeyL3L4Port8080ProtoTCPWorldSNEgress:   mapEntryDeny,
  1721  			mapKeyL3L4Port8080ProtoUDPWorldSNIngress:  mapEntryDeny,
  1722  			mapKeyL3L4Port8080ProtoUDPWorldSNEgress:   mapEntryDeny,
  1723  			mapKeyL3L4Port8080ProtoSCTPWorldSNIngress: mapEntryDeny,
  1724  			mapKeyL3L4Port8080ProtoSCTPWorldSNEgress:  mapEntryDeny,
  1725  			mapKeyL3L4Port8080ProtoTCPWorldIPIngress:  mapEntryDeny,
  1726  			mapKeyL3L4Port8080ProtoTCPWorldIPEgress:   mapEntryDeny,
  1727  			mapKeyL3L4Port8080ProtoUDPWorldIPIngress:  mapEntryDeny,
  1728  			mapKeyL3L4Port8080ProtoUDPWorldIPEgress:   mapEntryDeny,
  1729  			mapKeyL3L4Port8080ProtoSCTPWorldIPIngress: mapEntryDeny,
  1730  			mapKeyL3L4Port8080ProtoSCTPWorldIPEgress:  mapEntryDeny,
  1731  			mapKeyL3WorldIPIngress:                    mapEntryAllow,
  1732  			mapKeyL3WorldIPEgress:                     mapEntryAllow,
  1733  		})}, {"broad_cidr_allow_is_a_portproto_subset_of_a_specific_cidr_deny", api.Rules{ruleAllowAllIngress, ruleL3AllowWorldSubnet, ruleL3DenyWorldIP}, newMapState(map[Key]MapStateEntry{
  1734  			mapKeyAnyIngress:                          mapEntryAllow,
  1735  			mapKeyL3L4Port8080ProtoTCPWorldSNIngress:  mapEntryAllow,
  1736  			mapKeyL3L4Port8080ProtoTCPWorldSNEgress:   mapEntryAllow,
  1737  			mapKeyL3L4Port8080ProtoUDPWorldSNIngress:  mapEntryAllow,
  1738  			mapKeyL3L4Port8080ProtoUDPWorldSNEgress:   mapEntryAllow,
  1739  			mapKeyL3L4Port8080ProtoSCTPWorldSNIngress: mapEntryAllow,
  1740  			mapKeyL3L4Port8080ProtoSCTPWorldSNEgress:  mapEntryAllow,
  1741  			mapKeyL4AnyPortProtoWorldIPIngress:        mapEntryL4WorldIPDependentsIngressDeny,
  1742  			mapKeyL4AnyPortProtoWorldIPEgress:         mapEntryL4WorldIPDependentsEgressDeny,
  1743  			mapKeyL4Port8080ProtoTCPWorldIPIngress:    mapEntryDeny,
  1744  			mapKeyL4Port8080ProtoTCPWorldIPEgress:     mapEntryDeny,
  1745  			mapKeyL4Port8080ProtoUDPWorldIPIngress:    mapEntryDeny,
  1746  			mapKeyL4Port8080ProtoUDPWorldIPEgress:     mapEntryDeny,
  1747  			mapKeyL4Port8080ProtoSCTPWorldIPIngress:   mapEntryDeny,
  1748  			mapKeyL4Port8080ProtoSCTPWorldIPEgress:    mapEntryDeny,
  1749  		})}, {"named_port_world_subnet", api.Rules{ruleAllowAllIngress, ruleL3AllowWorldSubnetNamedPort}, newMapState(map[Key]MapStateEntry{
  1750  			mapKeyAnyIngress: mapEntryAllow,
  1751  			mapKeyL3L4NamedPortHTTPProtoTCPWorldSubNetIngress: mapEntryAllow,
  1752  			mapKeyL3L4NamedPortHTTPProtoTCPWorldIPIngress:     mapEntryAllow,
  1753  		})}, {"port_range_world_subnet", api.Rules{ruleAllowAllIngress, ruleL3AllowWorldSubnetPortRange}, newMapState(map[Key]MapStateEntry{
  1754  			mapKeyAnyIngress: mapEntryAllow,
  1755  			mapKeyL3L4Port64To127ProtoTCPWorldSubNetIngress: mapEntryAllow,
  1756  			mapKeyL3L4Port5ProtoTCPWorldSubNetIngress:       mapEntryAllow,
  1757  			mapKeyL3L4Port6To7ProtoTCPWorldSubNetIngress:    mapEntryAllow,
  1758  			mapKeyL3L4Port8To9ProtoTCPWorldSubNetIngress:    mapEntryAllow,
  1759  			mapKeyL3L4Port10ProtoTCPWorldSubNetIngress:      mapEntryAllow,
  1760  			mapKeyL3L4Port64To127ProtoTCPWorldIPIngress:     mapEntryAllow,
  1761  			mapKeyL3L4Port5ProtoTCPWorldIPIngress:           mapEntryAllow,
  1762  			mapKeyL3L4Port6To7ProtoTCPWorldIPIngress:        mapEntryAllow,
  1763  			mapKeyL3L4Port8To9ProtoTCPWorldIPIngress:        mapEntryAllow,
  1764  			mapKeyL3L4Port10ProtoTCPWorldIPIngress:          mapEntryAllow,
  1765  		})},
  1766  	}
  1767  	// Do not test in dualstack mode
  1768  	defer func(ipv4, ipv6 bool) {
  1769  		option.Config.EnableIPv4 = ipv4
  1770  		option.Config.EnableIPv6 = ipv6
  1771  	}(option.Config.EnableIPv4, option.Config.EnableIPv6)
  1772  	option.Config.EnableIPv4 = true
  1773  	option.Config.EnableIPv6 = false
  1774  	for _, tt := range tests {
  1775  		repo := newPolicyDistillery(selectorCache)
  1776  		for _, rule := range tt.rules {
  1777  			if rule != nil {
  1778  				_, _ = repo.MustAddList(api.Rules{rule})
  1779  			}
  1780  		}
  1781  		t.Run(tt.test, func(t *testing.T) {
  1782  			logBuffer := new(bytes.Buffer)
  1783  			repo = repo.WithLogBuffer(logBuffer)
  1784  			mapstate, err := repo.distillPolicy(DummyOwner{}, labelsFoo, identity)
  1785  			if err != nil {
  1786  				t.Errorf("Policy resolution failure: %s", err)
  1787  			}
  1788  			if equal := assert.True(t, mapstate.Equals(tt.expected), mapstate.Diff(tt.expected)); !equal {
  1789  				t.Logf("Policy Trace: \n%s\n", logBuffer.String())
  1790  				t.Errorf("Policy test, %q, obtained didn't match expected for endpoint %s", tt.test, labelsFoo)
  1791  			}
  1792  		})
  1793  	}
  1794  }
  1795  
  1796  func Test_EnsureEntitiesSelectableByCIDR(t *testing.T) {
  1797  	// Cache policy enforcement value from when test was ran to avoid pollution
  1798  	// across tests.
  1799  	oldPolicyEnable := GetPolicyEnabled()
  1800  	defer SetPolicyEnabled(oldPolicyEnable)
  1801  
  1802  	SetPolicyEnabled(option.DefaultEnforcement)
  1803  	hostLabel := labels.NewFrom(labels.LabelHost)
  1804  	hostLabel.MergeLabels(lblHostIPv4CIDR)
  1805  	hostLabel.MergeLabels(lblHostIPv6CIDR)
  1806  	identityCache := identity.IdentityMap{
  1807  		identity.NumericIdentity(identityFoo): labelsFoo,
  1808  		identity.ReservedIdentityHost:         hostLabel.LabelArray(),
  1809  	}
  1810  	selectorCache := testNewSelectorCache(identityCache)
  1811  	identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(identityFoo), labelsFoo)
  1812  
  1813  	tests := []struct {
  1814  		test     string
  1815  		rules    api.Rules
  1816  		expected MapState
  1817  	}{
  1818  		{"host_cidr_select", api.Rules{ruleL3AllowHostEgress}, newMapState(map[Key]MapStateEntry{
  1819  			mapKeyL3UnknownIngress: mapEntryL3UnknownIngress,
  1820  			mapKeyL3HostEgress:     mapEntryAllow,
  1821  		})},
  1822  	}
  1823  
  1824  	for _, tt := range tests {
  1825  		repo := newPolicyDistillery(selectorCache)
  1826  		for _, rule := range tt.rules {
  1827  			if rule != nil {
  1828  				_, _ = repo.MustAddList(api.Rules{rule})
  1829  			}
  1830  		}
  1831  		t.Run(tt.test, func(t *testing.T) {
  1832  			logBuffer := new(bytes.Buffer)
  1833  			repo = repo.WithLogBuffer(logBuffer)
  1834  			mapstate, err := repo.distillPolicy(DummyOwner{}, labelsFoo, identity)
  1835  			if err != nil {
  1836  				t.Errorf("Policy resolution failure: %s", err)
  1837  			}
  1838  			if equal := assert.True(t, mapstate.Equals(tt.expected), mapstate.Diff(tt.expected)); !equal {
  1839  				t.Logf("Policy Trace: \n%s\n", logBuffer.String())
  1840  				t.Errorf("Policy test, %q, obtained didn't match expected for endpoint %s", tt.test, labelsFoo)
  1841  			}
  1842  		})
  1843  	}
  1844  }
  1845  
  1846  func mapStateAllowsKey(ms *mapState, key Key) bool {
  1847  	var ok bool
  1848  	ms.denies.trie.Ancestors(key.PrefixLength(), key,
  1849  		func(_ uint, _ bitlpm.Key[types.Key], idMap map[identity.NumericIdentity]MapStateEntry) bool {
  1850  			if _, exists := idMap[identity.NumericIdentity(key.Identity)]; exists {
  1851  				ok = true
  1852  			}
  1853  			return true
  1854  		})
  1855  	if ok {
  1856  		return false
  1857  	}
  1858  	ms.allows.trie.Ancestors(key.PrefixLength(), key,
  1859  		func(_ uint, _ bitlpm.Key[types.Key], idMap map[identity.NumericIdentity]MapStateEntry) bool {
  1860  
  1861  			if _, exists := idMap[identity.NumericIdentity(key.Identity)]; exists {
  1862  				ok = true
  1863  			}
  1864  			return true
  1865  		})
  1866  	return ok
  1867  }
  1868  
  1869  func TestEgressPortRangePrecedence(t *testing.T) {
  1870  	td := newTestData()
  1871  	identityCache := identity.IdentityMap{
  1872  		identity.NumericIdentity(100): labelsA,
  1873  	}
  1874  	td.sc.UpdateIdentities(identityCache, nil, &sync.WaitGroup{})
  1875  	identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(100), labelsA)
  1876  
  1877  	type portRange struct {
  1878  		startPort, endPort uint16
  1879  		isAllow            bool
  1880  	}
  1881  	tests := []struct {
  1882  		name       string
  1883  		rules      []portRange
  1884  		rangeTests []portRange
  1885  	}{
  1886  		{
  1887  			name: "deny range (1-1024) covers port allow (80)",
  1888  			rules: []portRange{
  1889  				{80, 0, true},
  1890  				{1, 1024, false},
  1891  			},
  1892  			rangeTests: []portRange{
  1893  				{79, 81, false},
  1894  				{1023, 1025, false},
  1895  			},
  1896  		},
  1897  		{
  1898  			name: "deny port (80) in broader allow range (1-1024)",
  1899  			rules: []portRange{
  1900  				{80, 0, false},
  1901  				{1, 1024, true},
  1902  			},
  1903  			rangeTests: []portRange{
  1904  				{1, 2, true},
  1905  				{79, 0, true},
  1906  				{80, 0, false},
  1907  				{81, 0, true},
  1908  				{1023, 1024, true},
  1909  				{1025, 1026, false},
  1910  			},
  1911  		},
  1912  		{
  1913  			name: "wildcard deny (*) covers broad allow range (1-1024)",
  1914  			rules: []portRange{
  1915  				{0, 0, false},
  1916  				{1, 1024, true},
  1917  			},
  1918  			rangeTests: []portRange{
  1919  				{1, 2, false},
  1920  				{1023, 1025, false},
  1921  			},
  1922  		},
  1923  		{
  1924  			name: "wildcard allow (*) has an deny range hole (1-1024)",
  1925  			rules: []portRange{
  1926  				{0, 0, true},
  1927  				{1, 1024, false},
  1928  			},
  1929  			rangeTests: []portRange{
  1930  				{1, 2, false},
  1931  				{1023, 1024, false},
  1932  				{1025, 1026, true},
  1933  				{65534, 0, true},
  1934  			},
  1935  		},
  1936  		{
  1937  			name: "two allow ranges (80-90, 90-100) with overlapping deny (85-95)",
  1938  			rules: []portRange{
  1939  				{80, 90, true},
  1940  				{85, 95, false},
  1941  				{90, 100, true},
  1942  			},
  1943  			rangeTests: []portRange{
  1944  				{79, 0, false},
  1945  				{80, 84, true},
  1946  				{85, 95, false},
  1947  				{96, 100, true},
  1948  				{101, 0, true},
  1949  			},
  1950  		},
  1951  	}
  1952  
  1953  	for _, tt := range tests {
  1954  		t.Run(tt.name, func(t *testing.T) {
  1955  			tr := &rule{
  1956  				Rule: api.Rule{
  1957  					EndpointSelector: endpointSelectorA,
  1958  				},
  1959  			}
  1960  			for _, rul := range tt.rules {
  1961  				pp := api.PortProtocol{
  1962  					Port:     fmt.Sprintf("%d", rul.startPort),
  1963  					EndPort:  int32(rul.endPort),
  1964  					Protocol: api.ProtoTCP,
  1965  				}
  1966  				if rul.isAllow {
  1967  					tr.Rule.Egress = append(tr.Rule.Egress, api.EgressRule{
  1968  						EgressCommonRule: api.EgressCommonRule{
  1969  							ToEndpoints: []api.EndpointSelector{endpointSelectorA},
  1970  						},
  1971  						ToPorts: []api.PortRule{{
  1972  							Ports: []api.PortProtocol{pp},
  1973  						}},
  1974  					})
  1975  				} else {
  1976  					tr.Rule.EgressDeny = append(tr.Rule.EgressDeny, api.EgressDenyRule{
  1977  						EgressCommonRule: api.EgressCommonRule{
  1978  							ToEndpoints: []api.EndpointSelector{endpointSelectorA},
  1979  						},
  1980  						ToPorts: []api.PortDenyRule{{
  1981  							Ports: []api.PortProtocol{pp},
  1982  						}},
  1983  					})
  1984  				}
  1985  			}
  1986  			buffer := new(bytes.Buffer)
  1987  			ctxFromA := SearchContext{From: labelsA, Trace: TRACE_VERBOSE}
  1988  			ctxFromA.Logging = stdlog.New(buffer, "", 0)
  1989  			defer t.Log(buffer)
  1990  
  1991  			require.NoError(t, tr.Sanitize())
  1992  			state := traceState{}
  1993  			res, err := tr.resolveEgressPolicy(td.testPolicyContext, &ctxFromA, &state, NewL4PolicyMap(), nil, nil)
  1994  			require.NoError(t, err)
  1995  			require.NotNil(t, res)
  1996  
  1997  			repo := newPolicyDistillery(td.sc)
  1998  			repo.MustAddList(api.Rules{&tr.Rule})
  1999  			repo = repo.WithLogBuffer(buffer)
  2000  			ms, err := repo.distillPolicy(DummyOwner{}, labelsA, identity)
  2001  
  2002  			require.NoError(t, err)
  2003  			require.NotNil(t, ms)
  2004  			mapStateP, ok := ms.(*mapState)
  2005  			require.True(t, ok, "failed type coercion")
  2006  
  2007  			for _, rt := range tt.rangeTests {
  2008  				for i := rt.startPort; i <= rt.endPort; i++ {
  2009  					ctxFromA.DPorts = []*models.Port{{Port: i, Protocol: models.PortProtocolTCP}}
  2010  					key := Key{
  2011  						Identity:         identity.ID.Uint32(),
  2012  						DestPort:         i,
  2013  						Nexthdr:          uint8(u8proto.TCP),
  2014  						TrafficDirection: trafficdirection.Egress.Uint8(),
  2015  					}
  2016  					if rt.isAllow {
  2017  						// IngressCoversContext just checks the "From" labels of the search context.
  2018  						require.Equalf(t, api.Allowed.String(), res.IngressCoversContext(&ctxFromA).String(), "Requesting port %d", i)
  2019  
  2020  						require.Truef(t, mapStateAllowsKey(mapStateP, key), "key (%v) not allowed", key)
  2021  					} else {
  2022  						// IngressCoversContext just checks the "From" labels of the search context.
  2023  						require.Equalf(t, api.Denied.String(), res.IngressCoversContext(&ctxFromA).String(), "Requesting port %d", i)
  2024  						require.Falsef(t, mapStateAllowsKey(mapStateP, key), "key (%v) allowed", key)
  2025  
  2026  					}
  2027  				}
  2028  			}
  2029  
  2030  		})
  2031  	}
  2032  }