github.com/cilium/cilium@v1.16.2/pkg/policy/rule_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  	"fmt"
     9  	stdlog "log"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/cilium/proxy/pkg/policy/api/kafka"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"k8s.io/apimachinery/pkg/util/intstr"
    17  
    18  	"github.com/cilium/cilium/api/v1/models"
    19  	"github.com/cilium/cilium/pkg/identity"
    20  	"github.com/cilium/cilium/pkg/labels"
    21  	"github.com/cilium/cilium/pkg/policy/api"
    22  	"github.com/cilium/cilium/pkg/u8proto"
    23  )
    24  
    25  func TestL4Policy(t *testing.T) {
    26  	td := newTestData()
    27  
    28  	toBar := &SearchContext{To: labels.ParseSelectLabelArray("bar")}
    29  	fromBar := &SearchContext{From: labels.ParseSelectLabelArray("bar")}
    30  	toFoo := &SearchContext{To: labels.ParseSelectLabelArray("foo")}
    31  	fromFoo := &SearchContext{From: labels.ParseSelectLabelArray("foo")}
    32  
    33  	rule1 := &rule{
    34  		Rule: api.Rule{
    35  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
    36  			Ingress: []api.IngressRule{
    37  				{
    38  					ToPorts: []api.PortRule{{
    39  						Ports: []api.PortProtocol{
    40  							{Port: "80", Protocol: api.ProtoTCP},
    41  							{Port: "8080", Protocol: api.ProtoTCP},
    42  						},
    43  						Rules: &api.L7Rules{
    44  							HTTP: []api.PortRuleHTTP{
    45  								{Method: "GET", Path: "/"},
    46  							},
    47  						},
    48  					}},
    49  				},
    50  			},
    51  			Egress: []api.EgressRule{
    52  				{
    53  					ToPorts: []api.PortRule{{
    54  						Ports: []api.PortProtocol{
    55  							{Port: "3000", Protocol: api.ProtoAny},
    56  						},
    57  					}},
    58  				},
    59  			},
    60  		},
    61  	}
    62  
    63  	l7rules := api.L7Rules{
    64  		HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}},
    65  	}
    66  	l7map := L7DataMap{
    67  		td.wildcardCachedSelector: &PerSelectorPolicy{
    68  			L7Rules:    l7rules,
    69  			isRedirect: true,
    70  		},
    71  	}
    72  
    73  	expected := NewL4Policy(0)
    74  	expected.Ingress.PortRules.Upsert("80", 0, "TCP", &L4Filter{
    75  		Port: 80, Protocol: api.ProtoTCP, U8Proto: 6,
    76  		wildcard: td.wildcardCachedSelector,
    77  		L7Parser: "http", PerSelectorPolicies: l7map, Ingress: true,
    78  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}},
    79  	})
    80  	expected.Ingress.PortRules.Upsert("8080", 0, "TCP", &L4Filter{
    81  		Port: 8080, Protocol: api.ProtoTCP, U8Proto: 6,
    82  		wildcard: td.wildcardCachedSelector,
    83  		L7Parser: "http", PerSelectorPolicies: l7map, Ingress: true,
    84  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}},
    85  	})
    86  
    87  	expected.Egress.PortRules.Upsert("3000", 0, "TCP", &L4Filter{
    88  		Port: 3000, Protocol: api.ProtoTCP, U8Proto: 6, Ingress: false,
    89  		wildcard: td.wildcardCachedSelector,
    90  		PerSelectorPolicies: L7DataMap{
    91  			td.wildcardCachedSelector: nil,
    92  		},
    93  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}},
    94  	})
    95  	expected.Egress.PortRules.Upsert("3000", 0, "UDP", &L4Filter{
    96  		Port: 3000, Protocol: api.ProtoUDP, U8Proto: 17, Ingress: false,
    97  		wildcard: td.wildcardCachedSelector,
    98  		PerSelectorPolicies: L7DataMap{
    99  			td.wildcardCachedSelector: nil,
   100  		},
   101  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}},
   102  	})
   103  	expected.Egress.PortRules.Upsert("3000", 0, "SCTP", &L4Filter{
   104  		Port: 3000, Protocol: api.ProtoSCTP, U8Proto: 132, Ingress: false,
   105  		wildcard: td.wildcardCachedSelector,
   106  		PerSelectorPolicies: L7DataMap{
   107  			td.wildcardCachedSelector: nil,
   108  		},
   109  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}},
   110  	})
   111  
   112  	ingressState := traceState{}
   113  	egressState := traceState{}
   114  	res := NewL4Policy(0)
   115  	var err error
   116  	res.Ingress.PortRules, err =
   117  		rule1.resolveIngressPolicy(td.testPolicyContext, toBar, &ingressState, NewL4PolicyMap(), nil, nil)
   118  	require.NoError(t, err)
   119  	require.NotNil(t, res.Ingress)
   120  
   121  	res.Egress.PortRules, err =
   122  		rule1.resolveEgressPolicy(td.testPolicyContext, fromBar, &egressState, NewL4PolicyMap(), nil, nil)
   123  	require.NoError(t, err)
   124  	require.NotNil(t, res.Egress)
   125  
   126  	require.Equal(t, &expected, &res)
   127  	require.Equal(t, 1, ingressState.selectedRules)
   128  	require.Equal(t, 1, ingressState.matchedRules)
   129  
   130  	require.Equal(t, 1, egressState.selectedRules)
   131  	require.Equal(t, 1, egressState.matchedRules)
   132  	res.Detach(td.sc)
   133  	expected.Detach(td.sc)
   134  
   135  	// Foo isn't selected in the rule1's policy.
   136  	ingressState = traceState{}
   137  	egressState = traceState{}
   138  
   139  	res1, err := rule1.resolveIngressPolicy(td.testPolicyContext, toFoo, &ingressState, NewL4PolicyMap(), nil, nil)
   140  	require.NoError(t, err)
   141  	res2, err := rule1.resolveEgressPolicy(td.testPolicyContext, fromFoo, &ingressState, NewL4PolicyMap(), nil, nil)
   142  	require.NoError(t, err)
   143  
   144  	require.Nil(t, res1)
   145  	require.Nil(t, res2)
   146  	require.Equal(t, 0, ingressState.selectedRules)
   147  	require.Equal(t, 0, ingressState.matchedRules)
   148  	require.Equal(t, 0, egressState.selectedRules)
   149  	require.Equal(t, 0, egressState.matchedRules)
   150  
   151  	// This rule actually overlaps with the existing ingress "http" rule,
   152  	// so we'd expect it to merge.
   153  	rule2 := &rule{
   154  		Rule: api.Rule{
   155  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
   156  			Ingress: []api.IngressRule{
   157  				{
   158  					// Note that this allows all on 80, so the result should wildcard HTTP
   159  					ToPorts: []api.PortRule{{
   160  						Ports: []api.PortProtocol{
   161  							{Port: "80", Protocol: api.ProtoTCP},
   162  						},
   163  					}},
   164  				},
   165  				{
   166  					ToPorts: []api.PortRule{{
   167  						Ports: []api.PortProtocol{
   168  							{Port: "80", Protocol: api.ProtoTCP},
   169  						},
   170  						Rules: &api.L7Rules{
   171  							HTTP: []api.PortRuleHTTP{
   172  								{Method: "GET", Path: "/"},
   173  							},
   174  						},
   175  					}},
   176  				},
   177  			},
   178  			Egress: []api.EgressRule{
   179  				{
   180  					ToPorts: []api.PortRule{{
   181  						Ports: []api.PortProtocol{
   182  							{Port: "3000", Protocol: api.ProtoAny},
   183  						},
   184  					}},
   185  				},
   186  			},
   187  		},
   188  	}
   189  
   190  	expected = NewL4Policy(0)
   191  	expected.Ingress.PortRules.Upsert("80", 0, "TCP", &L4Filter{
   192  		Port:     80,
   193  		Protocol: api.ProtoTCP,
   194  		U8Proto:  6,
   195  		wildcard: td.wildcardCachedSelector,
   196  		L7Parser: ParserTypeHTTP,
   197  		PerSelectorPolicies: L7DataMap{
   198  			td.wildcardCachedSelector: &PerSelectorPolicy{
   199  				L7Rules: api.L7Rules{
   200  					HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}, {}},
   201  				},
   202  				isRedirect: true,
   203  			},
   204  		},
   205  		Ingress:    true,
   206  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}},
   207  	})
   208  	expected.Egress.PortRules.Upsert("3000", 0, "TCP", &L4Filter{
   209  		Port: 3000, Protocol: api.ProtoTCP, U8Proto: 6, Ingress: false,
   210  		wildcard: td.wildcardCachedSelector,
   211  		PerSelectorPolicies: L7DataMap{
   212  			td.wildcardCachedSelector: nil,
   213  		},
   214  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}},
   215  	})
   216  	expected.Egress.PortRules.Upsert("3000", 0, "UDP", &L4Filter{
   217  		Port: 3000, Protocol: api.ProtoUDP, U8Proto: 17, Ingress: false,
   218  		wildcard: td.wildcardCachedSelector,
   219  		PerSelectorPolicies: L7DataMap{
   220  			td.wildcardCachedSelector: nil,
   221  		},
   222  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}},
   223  	})
   224  	expected.Egress.PortRules.Upsert("3000", 0, "SCTP", &L4Filter{
   225  		Port: 3000, Protocol: api.ProtoSCTP, U8Proto: 132, Ingress: false,
   226  		wildcard: td.wildcardCachedSelector,
   227  		PerSelectorPolicies: L7DataMap{
   228  			td.wildcardCachedSelector: nil,
   229  		},
   230  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}},
   231  	})
   232  
   233  	ingressState = traceState{}
   234  	egressState = traceState{}
   235  	res = NewL4Policy(0)
   236  
   237  	buffer := new(bytes.Buffer)
   238  	ctx := SearchContext{To: labels.ParseSelectLabelArray("bar"), Trace: TRACE_VERBOSE}
   239  	ctx.Logging = stdlog.New(buffer, "", 0)
   240  
   241  	res.Ingress.PortRules, err = rule2.resolveIngressPolicy(td.testPolicyContext, &ctx, &ingressState, NewL4PolicyMap(), nil, nil)
   242  	require.NoError(t, err)
   243  	require.NotNil(t, res.Ingress)
   244  
   245  	t.Log(buffer)
   246  
   247  	res.Egress.PortRules, err = rule2.resolveEgressPolicy(td.testPolicyContext, fromBar, &egressState, NewL4PolicyMap(), nil, nil)
   248  	require.NoError(t, err)
   249  	require.NotNil(t, res.Egress)
   250  
   251  	require.Equal(t, 1, res.Ingress.PortRules.Len())
   252  	require.Equal(t, &expected, &res)
   253  	require.Equal(t, 1, ingressState.selectedRules)
   254  	require.Equal(t, 1, ingressState.matchedRules)
   255  
   256  	require.Equal(t, 1, egressState.selectedRules)
   257  	require.Equal(t, 1, egressState.matchedRules)
   258  	res.Detach(td.sc)
   259  	expected.Detach(td.sc)
   260  
   261  	ingressState = traceState{}
   262  	egressState = traceState{}
   263  
   264  	res1, err = rule2.resolveIngressPolicy(td.testPolicyContext, toFoo, &ingressState, NewL4PolicyMap(), nil, nil)
   265  	require.NoError(t, err)
   266  	require.Nil(t, res1)
   267  
   268  	res2, err = rule2.resolveEgressPolicy(td.testPolicyContext, fromFoo, &egressState, NewL4PolicyMap(), nil, nil)
   269  	require.NoError(t, err)
   270  	require.Nil(t, res2)
   271  
   272  	require.Equal(t, 0, ingressState.selectedRules)
   273  	require.Equal(t, 0, ingressState.matchedRules)
   274  
   275  	require.Equal(t, 0, egressState.selectedRules)
   276  	require.Equal(t, 0, egressState.matchedRules)
   277  }
   278  
   279  func TestMergeL4PolicyIngress(t *testing.T) {
   280  	td := newTestData()
   281  	toBar := &SearchContext{To: labels.ParseSelectLabelArray("bar")}
   282  	//toFoo := &SearchContext{To: labels.ParseSelectLabelArray("foo")}
   283  
   284  	rule1 := &rule{
   285  		Rule: api.Rule{
   286  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
   287  			Ingress: []api.IngressRule{
   288  				{
   289  					IngressCommonRule: api.IngressCommonRule{
   290  						FromEndpoints: []api.EndpointSelector{fooSelector},
   291  					},
   292  					ToPorts: []api.PortRule{{
   293  						Ports: []api.PortProtocol{
   294  							{Port: "80", Protocol: api.ProtoTCP},
   295  						},
   296  					}},
   297  				},
   298  				{
   299  					IngressCommonRule: api.IngressCommonRule{
   300  						FromEndpoints: []api.EndpointSelector{bazSelector},
   301  					},
   302  					ToPorts: []api.PortRule{{
   303  						Ports: []api.PortProtocol{
   304  							{Port: "80", Protocol: api.ProtoTCP},
   305  						},
   306  					}},
   307  				},
   308  			},
   309  		},
   310  	}
   311  
   312  	mergedES := L7DataMap{
   313  		td.cachedFooSelector: nil,
   314  		td.cachedBazSelector: nil,
   315  	}
   316  	expected := NewL4PolicyMapWithValues(map[string]*L4Filter{"80/TCP": {
   317  		Port: 80, Protocol: api.ProtoTCP, U8Proto: 6,
   318  		L7Parser: ParserTypeNone, PerSelectorPolicies: mergedES, Ingress: true,
   319  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{
   320  			td.cachedFooSelector: {nil},
   321  			td.cachedBazSelector: {nil},
   322  		},
   323  	}})
   324  
   325  	state := traceState{}
   326  	res, err := rule1.resolveIngressPolicy(td.testPolicyContext, toBar, &state, NewL4PolicyMap(), nil, nil)
   327  	require.NoError(t, err)
   328  	require.NotNil(t, res)
   329  	require.Equal(t, expected, res)
   330  	require.Equal(t, 1, state.selectedRules)
   331  	require.Equal(t, 1, state.matchedRules)
   332  	res.Detach(td.sc)
   333  	expected.Detach(td.sc)
   334  }
   335  
   336  func TestMergeL4PolicyEgress(t *testing.T) {
   337  	td := newTestData()
   338  
   339  	buffer := new(bytes.Buffer)
   340  	fromBar := &SearchContext{
   341  		From:    labels.ParseSelectLabelArray("bar"),
   342  		Logging: stdlog.New(buffer, "", 0),
   343  		Trace:   TRACE_VERBOSE,
   344  	}
   345  
   346  	// bar can access foo with TCP on port 80, and baz with TCP on port 80.
   347  	rule1 := &rule{
   348  		Rule: api.Rule{
   349  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
   350  			Egress: []api.EgressRule{
   351  				{
   352  					EgressCommonRule: api.EgressCommonRule{
   353  						ToEndpoints: []api.EndpointSelector{fooSelector},
   354  					},
   355  					ToPorts: []api.PortRule{{
   356  						Ports: []api.PortProtocol{
   357  							{Port: "80", Protocol: api.ProtoTCP},
   358  						},
   359  					}},
   360  				},
   361  				{
   362  					EgressCommonRule: api.EgressCommonRule{
   363  						ToEndpoints: []api.EndpointSelector{bazSelector},
   364  					},
   365  					ToPorts: []api.PortRule{{
   366  						Ports: []api.PortProtocol{
   367  							{Port: "80", Protocol: api.ProtoTCP},
   368  						},
   369  					}},
   370  				},
   371  			},
   372  		},
   373  	}
   374  
   375  	mergedES := L7DataMap{
   376  		td.cachedFooSelector: nil,
   377  		td.cachedBazSelector: nil,
   378  	}
   379  	expected := NewL4PolicyMapWithValues(map[string]*L4Filter{"80/TCP": {
   380  		Port: 80, Protocol: api.ProtoTCP, U8Proto: 6,
   381  		L7Parser: ParserTypeNone, PerSelectorPolicies: mergedES, Ingress: false,
   382  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{
   383  			td.cachedFooSelector: {nil},
   384  			td.cachedBazSelector: {nil},
   385  		},
   386  	}})
   387  
   388  	state := traceState{}
   389  	res, err := rule1.resolveEgressPolicy(td.testPolicyContext, fromBar, &state, NewL4PolicyMap(), nil, nil)
   390  
   391  	t.Log(buffer)
   392  
   393  	require.NoError(t, err)
   394  	require.NotNil(t, res)
   395  	require.Equal(t, expected, res)
   396  	require.Equal(t, 1, state.selectedRules)
   397  	require.Equal(t, 1, state.matchedRules)
   398  	res.Detach(td.sc)
   399  	expected.Detach(td.sc)
   400  }
   401  
   402  func TestMergeL7PolicyIngress(t *testing.T) {
   403  	td := newTestData()
   404  	toBar := &SearchContext{To: labels.ParseSelectLabelArray("bar")}
   405  	toFoo := &SearchContext{To: labels.ParseSelectLabelArray("foo")}
   406  
   407  	fooSelectorSlice := []api.EndpointSelector{
   408  		fooSelector,
   409  	}
   410  	rule1 := &rule{
   411  		Rule: api.Rule{
   412  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
   413  			Ingress: []api.IngressRule{
   414  				{
   415  					// Note that this allows all on 80, so the result should wildcard HTTP
   416  					ToPorts: []api.PortRule{{
   417  						Ports: []api.PortProtocol{
   418  							{Port: "80", Protocol: api.ProtoTCP},
   419  						},
   420  					}},
   421  				},
   422  				{
   423  					ToPorts: []api.PortRule{{
   424  						Ports: []api.PortProtocol{
   425  							{Port: "80", Protocol: api.ProtoTCP},
   426  						},
   427  						Rules: &api.L7Rules{
   428  							HTTP: []api.PortRuleHTTP{
   429  								{Method: "GET", Path: "/"},
   430  							},
   431  						},
   432  					}},
   433  				},
   434  				{
   435  					IngressCommonRule: api.IngressCommonRule{
   436  						FromEndpoints: fooSelectorSlice,
   437  					},
   438  					ToPorts: []api.PortRule{{
   439  						Ports: []api.PortProtocol{
   440  							{Port: "80", Protocol: api.ProtoTCP},
   441  						},
   442  						Rules: &api.L7Rules{
   443  							HTTP: []api.PortRuleHTTP{
   444  								{Method: "GET", Path: "/"},
   445  							},
   446  						},
   447  					}},
   448  				},
   449  			},
   450  		},
   451  	}
   452  
   453  	expected := NewL4PolicyMapWithValues(map[string]*L4Filter{"80/TCP": {
   454  		Port:     80,
   455  		Protocol: api.ProtoTCP,
   456  		U8Proto:  6,
   457  		wildcard: td.wildcardCachedSelector,
   458  		L7Parser: ParserTypeHTTP,
   459  		PerSelectorPolicies: L7DataMap{
   460  			td.wildcardCachedSelector: &PerSelectorPolicy{
   461  				L7Rules: api.L7Rules{
   462  					HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}, {}},
   463  				},
   464  				isRedirect: true,
   465  			},
   466  			td.cachedFooSelector: &PerSelectorPolicy{
   467  				L7Rules: api.L7Rules{
   468  					HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}},
   469  				},
   470  				isRedirect: true,
   471  			},
   472  		},
   473  		Ingress: true,
   474  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{
   475  			td.cachedFooSelector:      {nil},
   476  			td.wildcardCachedSelector: {nil},
   477  		},
   478  	}})
   479  
   480  	state := traceState{}
   481  	res, err := rule1.resolveIngressPolicy(td.testPolicyContext, toBar, &state, NewL4PolicyMap(), nil, nil)
   482  	require.NoError(t, err)
   483  	require.NotNil(t, res)
   484  	require.EqualValues(t, expected, res)
   485  	require.Equal(t, 1, state.selectedRules)
   486  	require.Equal(t, 1, state.matchedRules)
   487  	res.Detach(td.sc)
   488  	expected.Detach(td.sc)
   489  
   490  	state = traceState{}
   491  	res, err = rule1.resolveIngressPolicy(td.testPolicyContext, toFoo, &state, NewL4PolicyMap(), nil, nil)
   492  	require.NoError(t, err)
   493  	require.Nil(t, res)
   494  	require.Equal(t, 0, state.selectedRules)
   495  	require.Equal(t, 0, state.matchedRules)
   496  
   497  	rule2 := &rule{
   498  		Rule: api.Rule{
   499  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
   500  			Ingress: []api.IngressRule{
   501  				{
   502  					ToPorts: []api.PortRule{{
   503  						Ports: []api.PortProtocol{
   504  							{Port: "80", Protocol: api.ProtoTCP},
   505  						},
   506  						Rules: &api.L7Rules{
   507  							Kafka: []kafka.PortRule{
   508  								{Topic: "foo"},
   509  							},
   510  						},
   511  					}},
   512  				},
   513  				{
   514  					IngressCommonRule: api.IngressCommonRule{
   515  						FromEndpoints: fooSelectorSlice,
   516  					},
   517  					ToPorts: []api.PortRule{{
   518  						Ports: []api.PortProtocol{
   519  							{Port: "80", Protocol: api.ProtoTCP},
   520  						},
   521  						Rules: &api.L7Rules{
   522  							Kafka: []kafka.PortRule{
   523  								{Topic: "foo"},
   524  							},
   525  						},
   526  					}},
   527  				},
   528  			},
   529  		},
   530  	}
   531  
   532  	l7rules := api.L7Rules{
   533  		Kafka: []kafka.PortRule{{Topic: "foo"}},
   534  	}
   535  	l7map := L7DataMap{
   536  		td.wildcardCachedSelector: &PerSelectorPolicy{
   537  			L7Rules:    l7rules,
   538  			isRedirect: true,
   539  		},
   540  		td.cachedFooSelector: &PerSelectorPolicy{
   541  			L7Rules:    l7rules,
   542  			isRedirect: true,
   543  		},
   544  	}
   545  
   546  	expected = NewL4PolicyMapWithValues(map[string]*L4Filter{"80/TCP": {
   547  		Port: 80, Protocol: api.ProtoTCP, U8Proto: 6,
   548  		wildcard: td.wildcardCachedSelector,
   549  		L7Parser: "kafka", PerSelectorPolicies: l7map, Ingress: true,
   550  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{
   551  			td.cachedFooSelector:      {nil},
   552  			td.wildcardCachedSelector: {nil},
   553  		},
   554  	}})
   555  
   556  	state = traceState{}
   557  	res, err = rule2.resolveIngressPolicy(td.testPolicyContext, toBar, &state, NewL4PolicyMap(), nil, nil)
   558  	require.NoError(t, err)
   559  	require.NotNil(t, res)
   560  	require.EqualValues(t, expected, res)
   561  	require.Equal(t, 1, state.selectedRules)
   562  	require.Equal(t, 1, state.matchedRules)
   563  	res.Detach(td.sc)
   564  	expected.Detach(td.sc)
   565  
   566  	state = traceState{}
   567  	res, err = rule2.resolveIngressPolicy(td.testPolicyContext, toFoo, &state, NewL4PolicyMap(), nil, nil)
   568  	require.NoError(t, err)
   569  	require.Nil(t, res)
   570  	require.Equal(t, 0, state.selectedRules)
   571  	require.Equal(t, 0, state.matchedRules)
   572  
   573  	// Resolve rule1's policy, then try to add rule2.
   574  	res, err = rule1.resolveIngressPolicy(td.testPolicyContext, toBar, &state, NewL4PolicyMap(), nil, nil)
   575  	require.NoError(t, err)
   576  	require.NotNil(t, res)
   577  
   578  	state = traceState{}
   579  	_, err = rule2.resolveIngressPolicy(td.testPolicyContext, toBar, &state, res, nil, nil)
   580  
   581  	require.NotNil(t, err)
   582  	res.Detach(td.sc)
   583  
   584  	// Similar to 'rule2', but with different topics for the l3-dependent
   585  	// rule and the l4-only rule.
   586  	rule3 := &rule{
   587  		Rule: api.Rule{
   588  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
   589  			Ingress: []api.IngressRule{
   590  				{
   591  					IngressCommonRule: api.IngressCommonRule{
   592  						FromEndpoints: fooSelectorSlice,
   593  					},
   594  					ToPorts: []api.PortRule{{
   595  						Ports: []api.PortProtocol{
   596  							{Port: "80", Protocol: api.ProtoTCP},
   597  						},
   598  						Rules: &api.L7Rules{
   599  							Kafka: []kafka.PortRule{
   600  								{Topic: "foo"},
   601  							},
   602  						},
   603  					}},
   604  				},
   605  				{
   606  					IngressCommonRule: api.IngressCommonRule{
   607  						FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector},
   608  					},
   609  					ToPorts: []api.PortRule{{
   610  						Ports: []api.PortProtocol{
   611  							{Port: "80", Protocol: api.ProtoTCP},
   612  						},
   613  						Rules: &api.L7Rules{
   614  							Kafka: []kafka.PortRule{
   615  								{Topic: "bar"},
   616  							},
   617  						},
   618  					}},
   619  				},
   620  			},
   621  		},
   622  	}
   623  
   624  	fooRules := api.L7Rules{
   625  		Kafka: []kafka.PortRule{{Topic: "foo"}},
   626  	}
   627  
   628  	barRules := api.L7Rules{
   629  		Kafka: []kafka.PortRule{{Topic: "bar"}},
   630  	}
   631  
   632  	// The L3-dependent L7 rules are not merged together.
   633  	l7map = L7DataMap{
   634  		td.cachedFooSelector: &PerSelectorPolicy{
   635  			L7Rules:    fooRules,
   636  			isRedirect: true,
   637  		},
   638  		td.wildcardCachedSelector: &PerSelectorPolicy{
   639  			L7Rules:    barRules,
   640  			isRedirect: true,
   641  		},
   642  	}
   643  	expected = NewL4PolicyMapWithValues(map[string]*L4Filter{"80/TCP": {
   644  		Port: 80, Protocol: api.ProtoTCP, U8Proto: 6,
   645  		wildcard: td.wildcardCachedSelector,
   646  		L7Parser: "kafka", PerSelectorPolicies: l7map, Ingress: true,
   647  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{
   648  			td.cachedFooSelector:      {nil},
   649  			td.wildcardCachedSelector: {nil},
   650  		},
   651  	}})
   652  
   653  	state = traceState{}
   654  	res, err = rule3.resolveIngressPolicy(td.testPolicyContext, toBar, &state, NewL4PolicyMap(), nil, nil)
   655  	require.NoError(t, err)
   656  	require.NotNil(t, res)
   657  	require.EqualValues(t, expected, res)
   658  	require.Equal(t, 1, state.selectedRules)
   659  	require.Equal(t, 1, state.matchedRules)
   660  	res.Detach(td.sc)
   661  	expected.Detach(td.sc)
   662  }
   663  
   664  func TestMergeL7PolicyEgress(t *testing.T) {
   665  	td := newTestData()
   666  	fromBar := &SearchContext{From: labels.ParseSelectLabelArray("bar")}
   667  	fromFoo := &SearchContext{From: labels.ParseSelectLabelArray("foo")}
   668  
   669  	fooSelector := []api.EndpointSelector{
   670  		api.NewESFromLabels(labels.ParseSelectLabel("foo")),
   671  	}
   672  
   673  	rule1 := &rule{
   674  		Rule: api.Rule{
   675  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
   676  			Egress: []api.EgressRule{
   677  				{
   678  					// Note that this allows all on 80, so the result should wildcard HTTP
   679  					ToPorts: []api.PortRule{{
   680  						Ports: []api.PortProtocol{
   681  							{Port: "80", Protocol: api.ProtoTCP},
   682  						},
   683  					}},
   684  				},
   685  				{
   686  					ToPorts: []api.PortRule{{
   687  						Ports: []api.PortProtocol{
   688  							{Port: "80", Protocol: api.ProtoTCP},
   689  						},
   690  						Rules: &api.L7Rules{
   691  							HTTP: []api.PortRuleHTTP{
   692  								{Method: "GET", Path: "/public"},
   693  							},
   694  						},
   695  					}},
   696  				},
   697  				{
   698  					EgressCommonRule: api.EgressCommonRule{
   699  						ToEndpoints: fooSelector,
   700  					},
   701  					ToPorts: []api.PortRule{{
   702  						Ports: []api.PortProtocol{
   703  							{Port: "80", Protocol: api.ProtoTCP},
   704  						},
   705  						Rules: &api.L7Rules{
   706  							HTTP: []api.PortRuleHTTP{
   707  								{Method: "GET", Path: "/private"},
   708  							},
   709  						},
   710  					}},
   711  				},
   712  			},
   713  		},
   714  	}
   715  
   716  	expected := NewL4PolicyMapWithValues(map[string]*L4Filter{"80/TCP": {
   717  		Port: 80, Protocol: api.ProtoTCP, U8Proto: 6,
   718  		wildcard: td.wildcardCachedSelector,
   719  		L7Parser: ParserTypeHTTP,
   720  		PerSelectorPolicies: L7DataMap{
   721  			td.wildcardCachedSelector: &PerSelectorPolicy{
   722  				L7Rules: api.L7Rules{
   723  					HTTP: []api.PortRuleHTTP{{Path: "/public", Method: "GET"}, {}},
   724  				},
   725  				isRedirect: true,
   726  			},
   727  			td.cachedFooSelector: &PerSelectorPolicy{
   728  				L7Rules: api.L7Rules{
   729  					HTTP: []api.PortRuleHTTP{{Path: "/private", Method: "GET"}},
   730  				},
   731  				isRedirect: true,
   732  			},
   733  		},
   734  		Ingress: false,
   735  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{
   736  			td.wildcardCachedSelector: {nil},
   737  			td.cachedFooSelector:      {nil},
   738  		},
   739  	}})
   740  
   741  	state := traceState{}
   742  	res, err := rule1.resolveEgressPolicy(td.testPolicyContext, fromBar, &state, NewL4PolicyMap(), nil, nil)
   743  	require.NoError(t, err)
   744  	require.NotNil(t, res)
   745  	require.EqualValues(t, expected, res)
   746  	require.Equal(t, 1, state.selectedRules)
   747  	require.Equal(t, 1, state.matchedRules)
   748  	res.Detach(td.sc)
   749  	expected.Detach(td.sc)
   750  
   751  	state = traceState{}
   752  	res, err = rule1.resolveEgressPolicy(td.testPolicyContext, fromFoo, &state, NewL4PolicyMap(), nil, nil)
   753  	require.NoError(t, err)
   754  	require.Nil(t, res)
   755  	require.Equal(t, 0, state.selectedRules)
   756  	require.Equal(t, 0, state.matchedRules)
   757  
   758  	rule2 := &rule{
   759  		Rule: api.Rule{
   760  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
   761  			Egress: []api.EgressRule{
   762  				{
   763  					// Note that this allows all on 9092, so the result should wildcard Kafka
   764  					ToPorts: []api.PortRule{{
   765  						Ports: []api.PortProtocol{
   766  							{Port: "9092", Protocol: api.ProtoTCP},
   767  						},
   768  					}},
   769  				},
   770  				{
   771  					ToPorts: []api.PortRule{{
   772  						Ports: []api.PortProtocol{
   773  							{Port: "9092", Protocol: api.ProtoTCP},
   774  						},
   775  						Rules: &api.L7Rules{
   776  							Kafka: []kafka.PortRule{
   777  								{Topic: "foo"},
   778  							},
   779  						},
   780  					}},
   781  				},
   782  				{
   783  					EgressCommonRule: api.EgressCommonRule{
   784  						ToEndpoints: fooSelector,
   785  					},
   786  					ToPorts: []api.PortRule{{
   787  						Ports: []api.PortProtocol{
   788  							{Port: "9092", Protocol: api.ProtoTCP},
   789  						},
   790  						Rules: &api.L7Rules{
   791  							Kafka: []kafka.PortRule{
   792  								{Topic: "foo"},
   793  							},
   794  						},
   795  					}},
   796  				},
   797  			},
   798  		},
   799  	}
   800  
   801  	expected = NewL4PolicyMapWithValues(map[string]*L4Filter{"9092/TCP": {
   802  		Port: 9092, Protocol: api.ProtoTCP, U8Proto: 6,
   803  		wildcard: td.wildcardCachedSelector,
   804  		L7Parser: ParserTypeKafka,
   805  		PerSelectorPolicies: L7DataMap{
   806  			td.wildcardCachedSelector: &PerSelectorPolicy{
   807  				L7Rules: api.L7Rules{
   808  					Kafka: []kafka.PortRule{{Topic: "foo"}, {}},
   809  				},
   810  				isRedirect: true,
   811  			},
   812  			td.cachedFooSelector: &PerSelectorPolicy{
   813  				L7Rules: api.L7Rules{
   814  					Kafka: []kafka.PortRule{{Topic: "foo"}},
   815  				},
   816  				isRedirect: true,
   817  			},
   818  		},
   819  		Ingress: false,
   820  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{
   821  			td.cachedFooSelector:      {nil},
   822  			td.wildcardCachedSelector: {nil},
   823  		},
   824  	}})
   825  
   826  	state = traceState{}
   827  	res, err = rule2.resolveEgressPolicy(td.testPolicyContext, fromBar, &state, NewL4PolicyMap(), nil, nil)
   828  	require.NoError(t, err)
   829  	require.NotNil(t, res)
   830  	require.EqualValues(t, expected, res)
   831  	require.Equal(t, 1, state.selectedRules)
   832  	require.Equal(t, 1, state.matchedRules)
   833  	res.Detach(td.sc)
   834  	expected.Detach(td.sc)
   835  
   836  	state = traceState{}
   837  	res, err = rule2.resolveEgressPolicy(td.testPolicyContext, fromFoo, &state, NewL4PolicyMap(), nil, nil)
   838  	require.NoError(t, err)
   839  	require.Nil(t, res)
   840  	require.Equal(t, 0, state.selectedRules)
   841  	require.Equal(t, 0, state.matchedRules)
   842  
   843  	// Resolve rule1's policy, then try to add rule2.
   844  	res, err = rule1.resolveEgressPolicy(td.testPolicyContext, fromBar, &state, NewL4PolicyMap(), nil, nil)
   845  	require.NoError(t, err)
   846  	require.NotNil(t, res)
   847  	res.Detach(td.sc)
   848  
   849  	// Similar to 'rule2', but with different topics for the l3-dependent
   850  	// rule and the l4-only rule.
   851  	rule3 := &rule{
   852  		Rule: api.Rule{
   853  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
   854  			Egress: []api.EgressRule{
   855  				{
   856  					EgressCommonRule: api.EgressCommonRule{
   857  						ToEndpoints: fooSelector,
   858  					},
   859  					ToPorts: []api.PortRule{{
   860  						Ports: []api.PortProtocol{
   861  							{Port: "80", Protocol: api.ProtoTCP},
   862  						},
   863  						Rules: &api.L7Rules{
   864  							Kafka: []kafka.PortRule{
   865  								{Topic: "foo"},
   866  							},
   867  						},
   868  					}},
   869  				},
   870  				{
   871  					ToPorts: []api.PortRule{{
   872  						Ports: []api.PortProtocol{
   873  							{Port: "80", Protocol: api.ProtoTCP},
   874  						},
   875  						Rules: &api.L7Rules{
   876  							Kafka: []kafka.PortRule{
   877  								{Topic: "bar"},
   878  							},
   879  						},
   880  					}},
   881  				},
   882  			},
   883  		},
   884  	}
   885  
   886  	fooRules := api.L7Rules{
   887  		Kafka: []kafka.PortRule{{Topic: "foo"}},
   888  	}
   889  	barRules := api.L7Rules{
   890  		Kafka: []kafka.PortRule{{Topic: "bar"}},
   891  	}
   892  
   893  	// The l3-dependent l7 rules are not merged together.
   894  	l7map := L7DataMap{
   895  		td.cachedFooSelector: &PerSelectorPolicy{
   896  			L7Rules:    fooRules,
   897  			isRedirect: true,
   898  		},
   899  		td.wildcardCachedSelector: &PerSelectorPolicy{
   900  			L7Rules:    barRules,
   901  			isRedirect: true,
   902  		},
   903  	}
   904  	expected = NewL4PolicyMapWithValues(map[string]*L4Filter{"80/TCP": {
   905  		Port: 80, Protocol: api.ProtoTCP, U8Proto: 6,
   906  		wildcard: td.wildcardCachedSelector,
   907  		L7Parser: "kafka", PerSelectorPolicies: l7map, Ingress: false,
   908  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{
   909  			td.cachedFooSelector:      {nil},
   910  			td.wildcardCachedSelector: {nil},
   911  		},
   912  	}})
   913  
   914  	state = traceState{}
   915  	res, err = rule3.resolveEgressPolicy(td.testPolicyContext, fromBar, &state, NewL4PolicyMap(), nil, nil)
   916  	require.NoError(t, err)
   917  	require.NotNil(t, res)
   918  	require.EqualValues(t, expected, res)
   919  	require.Equal(t, 1, state.selectedRules)
   920  	require.Equal(t, 1, state.matchedRules)
   921  	res.Detach(td.sc)
   922  	expected.Detach(td.sc)
   923  }
   924  
   925  func TestRuleWithNoEndpointSelector(t *testing.T) {
   926  	apiRule1 := api.Rule{
   927  		Ingress: []api.IngressRule{
   928  			{
   929  				IngressCommonRule: api.IngressCommonRule{
   930  					FromCIDR: []api.CIDR{
   931  						"10.0.1.0/24",
   932  						"192.168.2.0",
   933  						"10.0.3.1",
   934  						"2001:db8::1/48",
   935  						"2001:db9::",
   936  					},
   937  				},
   938  			},
   939  		},
   940  		Egress: []api.EgressRule{
   941  			{
   942  				EgressCommonRule: api.EgressCommonRule{
   943  					ToCIDR: []api.CIDR{
   944  						"10.1.0.0/16",
   945  						"2001:dbf::/64",
   946  					},
   947  				},
   948  			}, {
   949  				EgressCommonRule: api.EgressCommonRule{
   950  					ToCIDRSet: []api.CIDRRule{{Cidr: api.CIDR("10.0.0.0/8"), ExceptCIDRs: []api.CIDR{"10.96.0.0/12"}}},
   951  				},
   952  			},
   953  		},
   954  	}
   955  
   956  	err := apiRule1.Sanitize()
   957  	require.NotNil(t, err)
   958  }
   959  
   960  func TestL3Policy(t *testing.T) {
   961  	apiRule1 := api.Rule{
   962  		EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
   963  
   964  		Ingress: []api.IngressRule{
   965  			{
   966  				IngressCommonRule: api.IngressCommonRule{
   967  					FromCIDR: []api.CIDR{
   968  						"10.0.1.0/24",
   969  						"192.168.2.0",
   970  						"10.0.3.1",
   971  						"2001:db8::1/48",
   972  						"2001:db9::",
   973  					},
   974  				},
   975  			},
   976  		},
   977  		Egress: []api.EgressRule{
   978  			{
   979  				EgressCommonRule: api.EgressCommonRule{
   980  					ToCIDR: []api.CIDR{
   981  						"10.1.0.0/16",
   982  						"2001:dbf::/64",
   983  					},
   984  				},
   985  			}, {
   986  				EgressCommonRule: api.EgressCommonRule{
   987  					ToCIDRSet: []api.CIDRRule{{Cidr: api.CIDR("10.0.0.0/8"), ExceptCIDRs: []api.CIDR{"10.96.0.0/12"}}},
   988  				},
   989  			},
   990  		},
   991  	}
   992  
   993  	err := apiRule1.Sanitize()
   994  	require.NoError(t, err)
   995  
   996  	rule1 := &rule{Rule: apiRule1}
   997  	err = rule1.Sanitize()
   998  	require.NoError(t, err)
   999  
  1000  	// Must be parsable, make sure Validate fails when not.
  1001  	err = (&api.Rule{
  1002  		EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1003  		Ingress: []api.IngressRule{{
  1004  			IngressCommonRule: api.IngressCommonRule{
  1005  				FromCIDR: []api.CIDR{"10.0.1..0/24"},
  1006  			},
  1007  		}},
  1008  	}).Sanitize()
  1009  	require.NotNil(t, err)
  1010  
  1011  	// Test CIDRRule with no provided CIDR or ExceptionCIDR.
  1012  	// Should fail as CIDR is required.
  1013  	err = (&api.Rule{
  1014  		EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1015  		Ingress: []api.IngressRule{{
  1016  			IngressCommonRule: api.IngressCommonRule{
  1017  				FromCIDRSet: []api.CIDRRule{{Cidr: "", ExceptCIDRs: nil}},
  1018  			},
  1019  		}},
  1020  	}).Sanitize()
  1021  	require.NotNil(t, err)
  1022  
  1023  	// Test CIDRRule with only CIDR provided; should not fail, as ExceptionCIDR
  1024  	// is optional.
  1025  	err = (&api.Rule{
  1026  		EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1027  		Ingress: []api.IngressRule{{
  1028  			IngressCommonRule: api.IngressCommonRule{
  1029  				FromCIDRSet: []api.CIDRRule{{Cidr: "10.0.1.0/24", ExceptCIDRs: nil}},
  1030  			},
  1031  		}},
  1032  	}).Sanitize()
  1033  	require.NoError(t, err)
  1034  
  1035  	// Cannot provide just an IP to a CIDRRule; Cidr must be of format
  1036  	// <IP>/<prefix>.
  1037  	err = (&api.Rule{
  1038  		EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1039  		Ingress: []api.IngressRule{{
  1040  			IngressCommonRule: api.IngressCommonRule{
  1041  				FromCIDRSet: []api.CIDRRule{{Cidr: "10.0.1.32", ExceptCIDRs: nil}},
  1042  			},
  1043  		}},
  1044  	}).Sanitize()
  1045  	require.NotNil(t, err)
  1046  
  1047  	// Cannot exclude a range that is not part of the CIDR.
  1048  	err = (&api.Rule{
  1049  		EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1050  		Ingress: []api.IngressRule{{
  1051  			IngressCommonRule: api.IngressCommonRule{
  1052  				FromCIDRSet: []api.CIDRRule{{Cidr: "10.0.0.0/10", ExceptCIDRs: []api.CIDR{"10.64.0.0/11"}}},
  1053  			},
  1054  		}},
  1055  	}).Sanitize()
  1056  	require.NotNil(t, err)
  1057  
  1058  	// Must have a contiguous mask, make sure Validate fails when not.
  1059  	err = (&api.Rule{
  1060  		EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1061  		Ingress: []api.IngressRule{{
  1062  			IngressCommonRule: api.IngressCommonRule{
  1063  				FromCIDR: []api.CIDR{"10.0.1.0/128.0.0.128"},
  1064  			},
  1065  		}},
  1066  	}).Sanitize()
  1067  	require.NotNil(t, err)
  1068  
  1069  	// Prefix length must be in range for the address, make sure
  1070  	// Validate fails if given prefix length is out of range.
  1071  	err = (&api.Rule{
  1072  		EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1073  		Ingress: []api.IngressRule{{
  1074  			IngressCommonRule: api.IngressCommonRule{
  1075  				FromCIDR: []api.CIDR{"10.0.1.0/34"},
  1076  			},
  1077  		}},
  1078  	}).Sanitize()
  1079  	require.NotNil(t, err)
  1080  }
  1081  
  1082  func TestICMPPolicy(t *testing.T) {
  1083  	td := newTestData()
  1084  	var err error
  1085  	toBar := &SearchContext{To: labels.ParseSelectLabelArray("bar")}
  1086  	fromBar := &SearchContext{From: labels.ParseSelectLabelArray("bar")}
  1087  
  1088  	// A rule for ICMP
  1089  	icmpV4Type := intstr.FromInt(8)
  1090  	rule1 := &rule{
  1091  		Rule: api.Rule{
  1092  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1093  			Ingress: []api.IngressRule{
  1094  				{
  1095  					ICMPs: api.ICMPRules{{
  1096  						Fields: []api.ICMPField{{
  1097  							Type: &icmpV4Type,
  1098  						}},
  1099  					}},
  1100  				},
  1101  			},
  1102  			Egress: []api.EgressRule{
  1103  				{
  1104  					ICMPs: api.ICMPRules{{
  1105  						Fields: []api.ICMPField{{
  1106  							Type: &icmpV4Type,
  1107  						}},
  1108  					}},
  1109  				},
  1110  			},
  1111  		},
  1112  	}
  1113  
  1114  	expected := NewL4Policy(0)
  1115  	expected.Ingress.PortRules.Upsert("8", 0, "ICMP", &L4Filter{
  1116  		Port:     8,
  1117  		Protocol: api.ProtoICMP,
  1118  		U8Proto:  u8proto.ProtoIDs["icmp"],
  1119  		Ingress:  true,
  1120  		wildcard: td.wildcardCachedSelector,
  1121  		PerSelectorPolicies: L7DataMap{
  1122  			td.wildcardCachedSelector: nil,
  1123  		},
  1124  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}},
  1125  	})
  1126  	expected.Egress.PortRules.Upsert("8", 0, "ICMP", &L4Filter{
  1127  		Port:     8,
  1128  		Protocol: api.ProtoICMP,
  1129  		U8Proto:  u8proto.ProtoIDs["icmp"],
  1130  		Ingress:  false,
  1131  		wildcard: td.wildcardCachedSelector,
  1132  		PerSelectorPolicies: L7DataMap{
  1133  			td.wildcardCachedSelector: nil,
  1134  		},
  1135  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}},
  1136  	})
  1137  
  1138  	ingressState := traceState{}
  1139  	egressState := traceState{}
  1140  	res := NewL4Policy(0)
  1141  	res.Ingress.PortRules, err =
  1142  		rule1.resolveIngressPolicy(td.testPolicyContext, toBar, &ingressState, NewL4PolicyMap(), nil, nil)
  1143  	require.NoError(t, err)
  1144  	require.NotNil(t, res.Ingress)
  1145  
  1146  	res.Egress.PortRules, err =
  1147  		rule1.resolveEgressPolicy(td.testPolicyContext, fromBar, &egressState, NewL4PolicyMap(), nil, nil)
  1148  	require.NoError(t, err)
  1149  	require.NotNil(t, res.Egress)
  1150  
  1151  	require.Equal(t, &expected, &res)
  1152  	require.Equal(t, 1, ingressState.selectedRules)
  1153  	require.Equal(t, 1, ingressState.matchedRules)
  1154  	require.Equal(t, 1, egressState.selectedRules)
  1155  	require.Equal(t, 1, egressState.matchedRules)
  1156  
  1157  	res.Detach(td.sc)
  1158  	expected.Detach(td.sc)
  1159  
  1160  	// A rule for Ports and ICMP
  1161  	rule2 := &rule{
  1162  		Rule: api.Rule{
  1163  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1164  			Ingress: []api.IngressRule{
  1165  				{
  1166  					ToPorts: []api.PortRule{{
  1167  						Ports: []api.PortProtocol{
  1168  							{Port: "80", Protocol: api.ProtoTCP},
  1169  						},
  1170  					}},
  1171  					ICMPs: api.ICMPRules{{
  1172  						Fields: []api.ICMPField{{
  1173  							Type: &icmpV4Type,
  1174  						}},
  1175  					}},
  1176  				},
  1177  			},
  1178  		},
  1179  	}
  1180  
  1181  	expected = NewL4Policy(0)
  1182  	expected.Ingress.PortRules.Upsert("80", 0, "TCP", &L4Filter{
  1183  		Port:     80,
  1184  		Protocol: api.ProtoTCP,
  1185  		U8Proto:  u8proto.ProtoIDs["tcp"],
  1186  		Ingress:  true,
  1187  		wildcard: td.wildcardCachedSelector,
  1188  		PerSelectorPolicies: L7DataMap{
  1189  			td.wildcardCachedSelector: nil,
  1190  		},
  1191  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}},
  1192  	})
  1193  	expected.Ingress.PortRules.Upsert("8", 0, "ICMP", &L4Filter{
  1194  		Port:     8,
  1195  		Protocol: api.ProtoICMP,
  1196  		U8Proto:  u8proto.ProtoIDs["icmp"],
  1197  		Ingress:  true,
  1198  		wildcard: td.wildcardCachedSelector,
  1199  		PerSelectorPolicies: L7DataMap{
  1200  			td.wildcardCachedSelector: nil,
  1201  		},
  1202  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}},
  1203  	})
  1204  
  1205  	ingressState = traceState{}
  1206  	res = NewL4Policy(0)
  1207  	res.Ingress.PortRules, err =
  1208  		rule2.resolveIngressPolicy(td.testPolicyContext, toBar, &ingressState, NewL4PolicyMap(), nil, nil)
  1209  	require.NoError(t, err)
  1210  	require.NotNil(t, res.Ingress)
  1211  
  1212  	require.Equal(t, &expected, &res)
  1213  	require.Equal(t, 1, ingressState.selectedRules)
  1214  	require.Equal(t, 1, ingressState.matchedRules)
  1215  
  1216  	res.Detach(td.sc)
  1217  	expected.Detach(td.sc)
  1218  
  1219  	// A rule for ICMPv6
  1220  	icmpV6Type := intstr.FromInt(128)
  1221  	rule3 := &rule{
  1222  		Rule: api.Rule{
  1223  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1224  			Ingress: []api.IngressRule{
  1225  				{
  1226  					ICMPs: api.ICMPRules{{
  1227  						Fields: []api.ICMPField{{
  1228  							Family: "IPv6",
  1229  							Type:   &icmpV6Type,
  1230  						}},
  1231  					}},
  1232  				},
  1233  			},
  1234  		},
  1235  	}
  1236  
  1237  	expected = NewL4Policy(0)
  1238  	expected.Ingress.PortRules.Upsert("128", 0, "ICMPV6", &L4Filter{
  1239  		Port:     128,
  1240  		Protocol: api.ProtoICMPv6,
  1241  		U8Proto:  u8proto.ProtoIDs["icmpv6"],
  1242  		Ingress:  true,
  1243  		wildcard: td.wildcardCachedSelector,
  1244  		PerSelectorPolicies: L7DataMap{
  1245  			td.wildcardCachedSelector: nil,
  1246  		},
  1247  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}},
  1248  	})
  1249  
  1250  	ingressState = traceState{}
  1251  	res = NewL4Policy(0)
  1252  	res.Ingress.PortRules, err =
  1253  		rule3.resolveIngressPolicy(td.testPolicyContext, toBar, &ingressState, NewL4PolicyMap(), nil, nil)
  1254  	require.NoError(t, err)
  1255  	require.NotNil(t, res.Ingress)
  1256  
  1257  	require.Equal(t, &expected, &res)
  1258  	require.Equal(t, 1, ingressState.selectedRules)
  1259  	require.Equal(t, 1, ingressState.matchedRules)
  1260  }
  1261  
  1262  // Tests the restrictions of combining certain label-based L3 and L4 policies.
  1263  // This ensures that the user is informed of policy combinations that are not
  1264  // implemented in the datapath.
  1265  func TestEgressRuleRestrictions(t *testing.T) {
  1266  	fooSelector := []api.EndpointSelector{
  1267  		api.NewESFromLabels(labels.ParseSelectLabel("foo")),
  1268  	}
  1269  
  1270  	// Cannot combine ToEndpoints and ToCIDR
  1271  	apiRule1 := api.Rule{
  1272  		EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1273  		Egress: []api.EgressRule{
  1274  			{
  1275  				EgressCommonRule: api.EgressCommonRule{
  1276  					ToCIDR: []api.CIDR{
  1277  						"10.1.0.0/16",
  1278  						"2001:dbf::/64",
  1279  					},
  1280  					ToEndpoints: fooSelector,
  1281  				},
  1282  			},
  1283  		},
  1284  	}
  1285  
  1286  	err := apiRule1.Sanitize()
  1287  	require.NotNil(t, err)
  1288  }
  1289  
  1290  func TestPolicyEntityValidationEgress(t *testing.T) {
  1291  	r := api.Rule{
  1292  		EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1293  		Egress: []api.EgressRule{
  1294  			{
  1295  				EgressCommonRule: api.EgressCommonRule{
  1296  					ToEntities: []api.Entity{api.EntityWorld},
  1297  				},
  1298  			},
  1299  		},
  1300  	}
  1301  	require.Nil(t, r.Sanitize())
  1302  	require.Equal(t, 1, len(r.Egress[0].ToEntities))
  1303  
  1304  	r.Egress[0].ToEntities = []api.Entity{api.EntityHost}
  1305  	require.Nil(t, r.Sanitize())
  1306  	require.Equal(t, 1, len(r.Egress[0].ToEntities))
  1307  
  1308  	r.Egress[0].ToEntities = []api.Entity{"trololo"}
  1309  	require.NotNil(t, r.Sanitize())
  1310  }
  1311  
  1312  func TestPolicyEntityValidationIngress(t *testing.T) {
  1313  	r := api.Rule{
  1314  		EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1315  		Ingress: []api.IngressRule{
  1316  			{
  1317  				IngressCommonRule: api.IngressCommonRule{
  1318  					FromEntities: []api.Entity{api.EntityWorld},
  1319  				},
  1320  			},
  1321  		},
  1322  	}
  1323  	require.Nil(t, r.Sanitize())
  1324  	require.Equal(t, 1, len(r.Ingress[0].FromEntities))
  1325  
  1326  	r.Ingress[0].FromEntities = []api.Entity{api.EntityHost}
  1327  	require.Nil(t, r.Sanitize())
  1328  	require.Equal(t, 1, len(r.Ingress[0].FromEntities))
  1329  
  1330  	r.Ingress[0].FromEntities = []api.Entity{"trololo"}
  1331  	require.NotNil(t, r.Sanitize())
  1332  }
  1333  
  1334  func TestPolicyEntityValidationEntitySelectorsFill(t *testing.T) {
  1335  	r := api.Rule{
  1336  		EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1337  		Ingress: []api.IngressRule{
  1338  			{
  1339  				IngressCommonRule: api.IngressCommonRule{
  1340  					FromEntities: []api.Entity{api.EntityWorld, api.EntityHost},
  1341  				},
  1342  			},
  1343  		},
  1344  		Egress: []api.EgressRule{
  1345  			{
  1346  				EgressCommonRule: api.EgressCommonRule{
  1347  					ToEntities: []api.Entity{api.EntityWorld, api.EntityHost},
  1348  				},
  1349  			},
  1350  		},
  1351  	}
  1352  	require.Nil(t, r.Sanitize())
  1353  	require.Equal(t, 2, len(r.Ingress[0].FromEntities))
  1354  	require.Equal(t, 2, len(r.Egress[0].ToEntities))
  1355  }
  1356  
  1357  func TestL3RuleLabels(t *testing.T) {
  1358  	td := newTestData()
  1359  	ruleLabels := map[string]labels.LabelArray{
  1360  		"rule0": labels.ParseLabelArray("name=apiRule0"),
  1361  		"rule1": labels.ParseLabelArray("name=apiRule1"),
  1362  		"rule2": labels.ParseLabelArray("name=apiRule2"),
  1363  	}
  1364  
  1365  	rules := map[string]api.Rule{
  1366  		"rule0": {
  1367  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1368  			Labels:           ruleLabels["rule0"],
  1369  			Ingress:          []api.IngressRule{},
  1370  			Egress:           []api.EgressRule{},
  1371  		},
  1372  		"rule1": {
  1373  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1374  			Labels:           ruleLabels["rule1"],
  1375  			Ingress: []api.IngressRule{
  1376  				{
  1377  					IngressCommonRule: api.IngressCommonRule{
  1378  						FromCIDR: []api.CIDR{"10.0.1.0/32"},
  1379  					},
  1380  				},
  1381  			},
  1382  			Egress: []api.EgressRule{
  1383  				{
  1384  					EgressCommonRule: api.EgressCommonRule{
  1385  						ToCIDR: []api.CIDR{"10.1.0.0/32"},
  1386  					},
  1387  				},
  1388  			},
  1389  		},
  1390  		"rule2": {
  1391  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1392  			Labels:           ruleLabels["rule2"],
  1393  			Ingress: []api.IngressRule{
  1394  				{
  1395  					IngressCommonRule: api.IngressCommonRule{
  1396  						FromCIDR: []api.CIDR{"10.0.2.0/32"},
  1397  					},
  1398  				},
  1399  			},
  1400  			Egress: []api.EgressRule{
  1401  				{
  1402  					EgressCommonRule: api.EgressCommonRule{
  1403  						ToCIDR: []api.CIDR{"10.2.0.0/32"},
  1404  					},
  1405  				},
  1406  			},
  1407  		},
  1408  	}
  1409  
  1410  	testCases := []struct {
  1411  		description           string                           // the description to print in asserts
  1412  		rulesToApply          []string                         // the rules from the rules map to resolve, in order
  1413  		expectedIngressLabels map[string]labels.LabelArrayList // the slice of LabelArray we should see, per CIDR prefix
  1414  		expectedEgressLabels  map[string]labels.LabelArrayList // the slice of LabelArray we should see, per CIDR prefix
  1415  
  1416  	}{
  1417  		{
  1418  			description:           "Empty rule that matches. Should not apply labels",
  1419  			rulesToApply:          []string{"rule0"},
  1420  			expectedIngressLabels: nil,
  1421  			expectedEgressLabels:  nil,
  1422  		}, {
  1423  			description:           "A rule that matches. Should apply labels",
  1424  			rulesToApply:          []string{"rule1"},
  1425  			expectedIngressLabels: map[string]labels.LabelArrayList{"10.0.1.0/32": {ruleLabels["rule1"]}},
  1426  			expectedEgressLabels:  map[string]labels.LabelArrayList{"10.1.0.0/32": {ruleLabels["rule1"]}},
  1427  		}, {
  1428  			description:  "Multiple matching rules. Should apply labels from all that have rule entries",
  1429  			rulesToApply: []string{"rule0", "rule1", "rule2"},
  1430  			expectedIngressLabels: map[string]labels.LabelArrayList{
  1431  				"10.0.1.0/32": {ruleLabels["rule1"]},
  1432  				"10.0.2.0/32": {ruleLabels["rule2"]}},
  1433  			expectedEgressLabels: map[string]labels.LabelArrayList{
  1434  				"10.1.0.0/32": {ruleLabels["rule1"]},
  1435  				"10.2.0.0/32": {ruleLabels["rule2"]}},
  1436  		}}
  1437  
  1438  	// endpoint selector for all tests
  1439  	toBar := &SearchContext{To: labels.ParseSelectLabelArray("bar"), Trace: TRACE_VERBOSE}
  1440  	fromBar := &SearchContext{From: labels.ParseSelectLabelArray("bar"), Trace: TRACE_VERBOSE}
  1441  
  1442  	for _, test := range testCases {
  1443  		finalPolicy := NewL4Policy(0)
  1444  		for _, r := range test.rulesToApply {
  1445  			apiRule := rules[r]
  1446  			err := apiRule.Sanitize()
  1447  			require.NoError(t, err, "Cannot sanitize Rule: %+v", apiRule)
  1448  
  1449  			rule := &rule{Rule: apiRule}
  1450  
  1451  			_, err = rule.resolveIngressPolicy(td.testPolicyContext, toBar, &traceState{}, finalPolicy.Ingress.PortRules, nil, nil)
  1452  			require.NoError(t, err)
  1453  			_, err = rule.resolveEgressPolicy(td.testPolicyContext, fromBar, &traceState{}, finalPolicy.Egress.PortRules, nil, nil)
  1454  			require.NoError(t, err)
  1455  		}
  1456  		// For debugging the test:
  1457  		//require.EqualValues(t, NewL4PolicyMap(), finalPolicy.Ingress)
  1458  
  1459  		type expectedResult map[string]labels.LabelArrayList
  1460  		mapDirectionalResultsToExpectedOutput := map[*L4Filter]expectedResult{
  1461  			finalPolicy.Ingress.PortRules.ExactLookup("0", 0, "ANY"): test.expectedIngressLabels,
  1462  			finalPolicy.Egress.PortRules.ExactLookup("0", 0, "ANY"):  test.expectedEgressLabels,
  1463  		}
  1464  		for filter, exp := range mapDirectionalResultsToExpectedOutput {
  1465  			if len(exp) > 0 {
  1466  				for cidr, rule := range exp {
  1467  					matches := false
  1468  					for _, origin := range filter.RuleOrigin {
  1469  						if origin.Equals(rule) {
  1470  							matches = true
  1471  							break
  1472  						}
  1473  					}
  1474  					require.True(t, matches, fmt.Sprintf("%s: expected filter %+v to be derived from rule %s", test.description, filter, rule))
  1475  
  1476  					matches = false
  1477  					for sel := range filter.PerSelectorPolicies {
  1478  						cidrLabels := labels.ParseLabelArray("cidr:" + cidr)
  1479  						t.Logf("Testing %+v", cidrLabels)
  1480  						if matches = sel.(*identitySelector).source.(*labelIdentitySelector).xxxMatches(cidrLabels); matches {
  1481  							break
  1482  						}
  1483  					}
  1484  					require.True(t, matches, fmt.Sprintf("%s: expected cidr %s to match filter %+v", test.description, cidr, filter))
  1485  				}
  1486  			}
  1487  		}
  1488  	}
  1489  }
  1490  
  1491  func TestL4RuleLabels(t *testing.T) {
  1492  	td := newTestData()
  1493  	ruleLabels := map[string]labels.LabelArray{
  1494  		"rule0": labels.ParseLabelArray("name=apiRule0"),
  1495  		"rule1": labels.ParseLabelArray("name=apiRule1"),
  1496  		"rule2": labels.ParseLabelArray("name=apiRule2"),
  1497  	}
  1498  
  1499  	rules := map[string]api.Rule{
  1500  		"rule0": {
  1501  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1502  			Labels:           ruleLabels["rule0"],
  1503  			Ingress:          []api.IngressRule{},
  1504  			Egress:           []api.EgressRule{},
  1505  		},
  1506  
  1507  		"rule1": {
  1508  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1509  			Labels:           ruleLabels["rule1"],
  1510  			Ingress: []api.IngressRule{
  1511  				{
  1512  					ToPorts: []api.PortRule{{
  1513  						Ports: []api.PortProtocol{{Port: "1010", Protocol: api.ProtoTCP}},
  1514  					}},
  1515  				},
  1516  			},
  1517  			Egress: []api.EgressRule{
  1518  				{
  1519  					ToPorts: []api.PortRule{{
  1520  						Ports: []api.PortProtocol{{Port: "1100", Protocol: api.ProtoTCP}},
  1521  					}},
  1522  				},
  1523  			},
  1524  		},
  1525  		"rule2": {
  1526  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  1527  			Labels:           ruleLabels["rule2"],
  1528  			Ingress: []api.IngressRule{
  1529  				{
  1530  					ToPorts: []api.PortRule{{
  1531  						Ports: []api.PortProtocol{{Port: "1020", Protocol: api.ProtoTCP}},
  1532  					}},
  1533  				},
  1534  			},
  1535  			Egress: []api.EgressRule{
  1536  				{
  1537  					ToPorts: []api.PortRule{{
  1538  						Ports: []api.PortProtocol{{Port: "1200", Protocol: api.ProtoTCP}},
  1539  					}},
  1540  				},
  1541  			},
  1542  		},
  1543  	}
  1544  
  1545  	testCases := []struct {
  1546  		description           string                           // the description to print in asserts
  1547  		rulesToApply          []string                         // the rules from the rules map to resolve, in order
  1548  		expectedIngressLabels map[string]labels.LabelArrayList // the slice of LabelArray we should see, in order
  1549  		expectedEgressLabels  map[string]labels.LabelArrayList // the slice of LabelArray we should see, in order
  1550  
  1551  	}{
  1552  		{
  1553  			description:           "Empty rule that matches. Should not apply labels",
  1554  			rulesToApply:          []string{"rule0"},
  1555  			expectedIngressLabels: map[string]labels.LabelArrayList{},
  1556  			expectedEgressLabels:  map[string]labels.LabelArrayList{},
  1557  		},
  1558  		{
  1559  			description:           "A rule that matches. Should apply labels",
  1560  			rulesToApply:          []string{"rule1"},
  1561  			expectedIngressLabels: map[string]labels.LabelArrayList{"1010/TCP": {ruleLabels["rule1"]}},
  1562  			expectedEgressLabels:  map[string]labels.LabelArrayList{"1100/TCP": {ruleLabels["rule1"]}},
  1563  		}, {
  1564  			description:  "Multiple matching rules. Should apply labels from all that have rule entries",
  1565  			rulesToApply: []string{"rule0", "rule1", "rule2"},
  1566  			expectedIngressLabels: map[string]labels.LabelArrayList{
  1567  				"1010/TCP": {ruleLabels["rule1"]},
  1568  				"1020/TCP": {ruleLabels["rule2"]}},
  1569  			expectedEgressLabels: map[string]labels.LabelArrayList{
  1570  				"1100/TCP": {ruleLabels["rule1"]},
  1571  				"1200/TCP": {ruleLabels["rule2"]}},
  1572  		}}
  1573  
  1574  	// endpoint selector for all tests
  1575  	toBar := &SearchContext{To: labels.ParseSelectLabelArray("bar")}
  1576  	fromBar := &SearchContext{From: labels.ParseSelectLabelArray("bar")}
  1577  
  1578  	for _, test := range testCases {
  1579  		finalPolicy := NewL4Policy(0)
  1580  		for _, r := range test.rulesToApply {
  1581  			apiRule := rules[r]
  1582  			err := apiRule.Sanitize()
  1583  			require.NoError(t, err, "Cannot sanitize api.Rule: %+v", apiRule)
  1584  
  1585  			rule := &rule{Rule: apiRule}
  1586  
  1587  			rule.resolveIngressPolicy(td.testPolicyContext, toBar, &traceState{}, finalPolicy.Ingress.PortRules, nil, nil)
  1588  			rule.resolveEgressPolicy(td.testPolicyContext, fromBar, &traceState{}, finalPolicy.Egress.PortRules, nil, nil)
  1589  		}
  1590  
  1591  		require.Equal(t, len(test.expectedIngressLabels), finalPolicy.Ingress.PortRules.Len(), fmt.Sprintf(test.description))
  1592  		for portProto := range test.expectedIngressLabels {
  1593  			portProtoSlice := strings.Split(portProto, "/")
  1594  			out := finalPolicy.Ingress.PortRules.ExactLookup(portProtoSlice[0], 0, portProtoSlice[1])
  1595  			require.NotNil(t, out, test.description)
  1596  			require.Equal(t, 1, len(out.RuleOrigin), fmt.Sprintf(test.description))
  1597  			require.EqualValues(t, test.expectedIngressLabels[portProto], out.RuleOrigin[out.wildcard], fmt.Sprintf(test.description))
  1598  		}
  1599  
  1600  		require.Equal(t, len(test.expectedEgressLabels), finalPolicy.Egress.PortRules.Len(), fmt.Sprintf(test.description))
  1601  		for portProto := range test.expectedEgressLabels {
  1602  			portProtoSlice := strings.Split(portProto, "/")
  1603  			out := finalPolicy.Egress.PortRules.ExactLookup(portProtoSlice[0], 0, portProtoSlice[1])
  1604  			require.NotNil(t, out, test.description)
  1605  
  1606  			require.Equal(t, 1, len(out.RuleOrigin), fmt.Sprintf(test.description))
  1607  			require.EqualValues(t, test.expectedEgressLabels[portProto], out.RuleOrigin[out.wildcard], fmt.Sprintf(test.description))
  1608  		}
  1609  		finalPolicy.Detach(td.sc)
  1610  	}
  1611  }
  1612  
  1613  var (
  1614  	labelsA = labels.LabelArray{
  1615  		labels.NewLabel("id", "a", labels.LabelSourceK8s),
  1616  	}
  1617  
  1618  	endpointSelectorA = api.NewESFromLabels(labels.ParseSelectLabel("id=a"))
  1619  
  1620  	labelsB = labels.LabelArray{
  1621  		labels.NewLabel("id1", "b", labels.LabelSourceK8s),
  1622  		labels.NewLabel("id2", "t", labels.LabelSourceK8s),
  1623  	}
  1624  
  1625  	labelsC = labels.LabelArray{
  1626  		labels.NewLabel("id", "t", labels.LabelSourceK8s),
  1627  	}
  1628  
  1629  	endpointSelectorC = api.NewESFromLabels(labels.ParseSelectLabel("id=t"))
  1630  
  1631  	ctxAToB = SearchContext{From: labelsA, To: labelsB, Trace: TRACE_VERBOSE}
  1632  	ctxAToC = SearchContext{From: labelsA, To: labelsC, Trace: TRACE_VERBOSE}
  1633  )
  1634  
  1635  func expectResult(t *testing.T, expected, obtained api.Decision, buffer *bytes.Buffer) {
  1636  	if obtained != expected {
  1637  		t.Errorf("Unexpected result: obtained=%v, expected=%v", obtained, expected)
  1638  		t.Log(buffer)
  1639  	}
  1640  }
  1641  
  1642  func checkIngress(t *testing.T, repo *Repository, ctx *SearchContext, verdict api.Decision) {
  1643  	repo.Mutex.RLock()
  1644  	defer repo.Mutex.RUnlock()
  1645  
  1646  	buffer := new(bytes.Buffer)
  1647  	ctx.Logging = stdlog.New(buffer, "", 0)
  1648  	expectResult(t, verdict, repo.AllowsIngressRLocked(ctx), buffer)
  1649  }
  1650  
  1651  func checkEgress(t *testing.T, repo *Repository, ctx *SearchContext, verdict api.Decision) {
  1652  	repo.Mutex.RLock()
  1653  	defer repo.Mutex.RUnlock()
  1654  
  1655  	buffer := new(bytes.Buffer)
  1656  	ctx.Logging = stdlog.New(buffer, "", 0)
  1657  	expectResult(t, verdict, repo.AllowsEgressRLocked(ctx), buffer)
  1658  }
  1659  func TestIngressAllowAll(t *testing.T) {
  1660  	td := newTestData()
  1661  	repo := td.repo
  1662  	repo.MustAddList(api.Rules{
  1663  		&api.Rule{
  1664  			EndpointSelector: endpointSelectorC,
  1665  			Ingress: []api.IngressRule{
  1666  				{
  1667  					// Allow all L3&L4 ingress rule
  1668  					IngressCommonRule: api.IngressCommonRule{
  1669  						FromEndpoints: []api.EndpointSelector{
  1670  							api.WildcardEndpointSelector,
  1671  						},
  1672  					},
  1673  				},
  1674  			},
  1675  		},
  1676  	})
  1677  
  1678  	checkIngress(t, repo, &ctxAToB, api.Denied)
  1679  	checkIngress(t, repo, &ctxAToC, api.Allowed)
  1680  
  1681  	ctxAToC80 := ctxAToC
  1682  	ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}
  1683  	checkIngress(t, repo, &ctxAToC80, api.Allowed)
  1684  
  1685  	ctxAToC90 := ctxAToC
  1686  	ctxAToC90.DPorts = []*models.Port{{Name: "port-90", Protocol: models.PortProtocolTCP}}
  1687  	checkIngress(t, repo, &ctxAToC90, api.Allowed)
  1688  }
  1689  
  1690  func TestIngressAllowAllL4Overlap(t *testing.T) {
  1691  	td := newTestData()
  1692  	repo := td.repo
  1693  	repo.MustAddList(api.Rules{
  1694  		&api.Rule{
  1695  			EndpointSelector: endpointSelectorC,
  1696  			Ingress: []api.IngressRule{
  1697  				{
  1698  					// Allow all L3&L4 ingress rule
  1699  					IngressCommonRule: api.IngressCommonRule{
  1700  						FromEndpoints: []api.EndpointSelector{
  1701  							api.WildcardEndpointSelector,
  1702  						},
  1703  					},
  1704  				},
  1705  				{
  1706  					// This rule is a subset of the above
  1707  					// rule and should *NOT* restrict to
  1708  					// port 80 only
  1709  					ToPorts: []api.PortRule{{
  1710  						Ports: []api.PortProtocol{
  1711  							{Port: "80", Protocol: api.ProtoTCP},
  1712  						},
  1713  					}},
  1714  				},
  1715  			},
  1716  		},
  1717  	})
  1718  
  1719  	ctxAToC80 := ctxAToC
  1720  	ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}
  1721  	checkIngress(t, repo, &ctxAToC80, api.Allowed)
  1722  
  1723  	ctxAToC90 := ctxAToC
  1724  	ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
  1725  	checkIngress(t, repo, &ctxAToC90, api.Allowed)
  1726  }
  1727  
  1728  func TestIngressAllowAllL4OverlapNamedPort(t *testing.T) {
  1729  	td := newTestData()
  1730  	repo := td.repo
  1731  	repo.MustAddList(api.Rules{
  1732  		&api.Rule{
  1733  			EndpointSelector: endpointSelectorC,
  1734  			Ingress: []api.IngressRule{
  1735  				{
  1736  					// Allow all L3&L4 ingress rule
  1737  					IngressCommonRule: api.IngressCommonRule{
  1738  						FromEndpoints: []api.EndpointSelector{
  1739  							api.WildcardEndpointSelector,
  1740  						},
  1741  					},
  1742  				},
  1743  				{
  1744  					// This rule is a subset of the above
  1745  					// rule and should *NOT* restrict to
  1746  					// port 80 only
  1747  					ToPorts: []api.PortRule{{
  1748  						Ports: []api.PortProtocol{
  1749  							{Port: "port-80", Protocol: api.ProtoTCP},
  1750  						},
  1751  					}},
  1752  				},
  1753  			},
  1754  		},
  1755  	})
  1756  
  1757  	ctxAToC80 := ctxAToC
  1758  	ctxAToC80.DPorts = []*models.Port{{Name: "port-80", Protocol: models.PortProtocolTCP}}
  1759  	checkIngress(t, repo, &ctxAToC80, api.Allowed)
  1760  
  1761  	ctxAToC90 := ctxAToC
  1762  	ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
  1763  	checkIngress(t, repo, &ctxAToC90, api.Allowed)
  1764  }
  1765  
  1766  func TestIngressL4AllowAll(t *testing.T) {
  1767  	td := newTestData()
  1768  	repo := td.repo
  1769  	repo.MustAddList(api.Rules{
  1770  		&api.Rule{
  1771  			EndpointSelector: endpointSelectorC,
  1772  			Ingress: []api.IngressRule{
  1773  				{
  1774  					ToPorts: []api.PortRule{{
  1775  						Ports: []api.PortProtocol{
  1776  							{Port: "80", Protocol: api.ProtoTCP},
  1777  						},
  1778  					}},
  1779  				},
  1780  			},
  1781  		},
  1782  	})
  1783  
  1784  	ctxAToC80 := ctxAToC
  1785  	ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}
  1786  	checkIngress(t, repo, &ctxAToC80, api.Allowed)
  1787  
  1788  	ctxAToC90 := ctxAToC
  1789  	ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
  1790  	checkIngress(t, repo, &ctxAToC90, api.Denied)
  1791  
  1792  	ctxAToCNamed90 := ctxAToC
  1793  	ctxAToCNamed90.DPorts = []*models.Port{{Name: "port-90", Protocol: models.PortProtocolTCP}}
  1794  	checkIngress(t, repo, &ctxAToCNamed90, api.Denied)
  1795  
  1796  	l4IngressPolicy, err := repo.ResolveL4IngressPolicy(&ctxAToC80)
  1797  	require.NoError(t, err)
  1798  
  1799  	filter := l4IngressPolicy.ExactLookup("80", 0, "TCP")
  1800  	require.NotNil(t, filter)
  1801  	require.Equal(t, uint16(80), filter.Port)
  1802  	require.True(t, filter.Ingress)
  1803  
  1804  	require.Equal(t, 1, len(filter.PerSelectorPolicies))
  1805  	require.Nil(t, filter.PerSelectorPolicies[td.wildcardCachedSelector])
  1806  	l4IngressPolicy.Detach(repo.GetSelectorCache())
  1807  }
  1808  
  1809  func TestIngressL4AllowAllNamedPort(t *testing.T) {
  1810  	td := newTestData()
  1811  	repo := td.repo
  1812  	repo.MustAddList(api.Rules{
  1813  		&api.Rule{
  1814  			EndpointSelector: endpointSelectorC,
  1815  			Ingress: []api.IngressRule{
  1816  				{
  1817  					ToPorts: []api.PortRule{{
  1818  						Ports: []api.PortProtocol{
  1819  							{Port: "port-80", Protocol: api.ProtoTCP},
  1820  						},
  1821  					}},
  1822  				},
  1823  			},
  1824  		},
  1825  	})
  1826  
  1827  	ctxAToCNamed80 := ctxAToC
  1828  	ctxAToCNamed80.DPorts = []*models.Port{{Name: "port-80", Protocol: models.PortProtocolTCP}}
  1829  	checkIngress(t, repo, &ctxAToCNamed80, api.Allowed)
  1830  
  1831  	ctxAToC80 := ctxAToC
  1832  	ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}
  1833  	checkIngress(t, repo, &ctxAToC80, api.Denied)
  1834  
  1835  	ctxAToC90 := ctxAToC
  1836  	ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
  1837  	checkIngress(t, repo, &ctxAToC90, api.Denied)
  1838  
  1839  	ctxAToCNamed90 := ctxAToC
  1840  	ctxAToCNamed90.DPorts = []*models.Port{{Name: "port-90", Protocol: models.PortProtocolTCP}}
  1841  	checkIngress(t, repo, &ctxAToCNamed90, api.Denied)
  1842  
  1843  	l4IngressPolicy, err := repo.ResolveL4IngressPolicy(&ctxAToCNamed80)
  1844  	require.NoError(t, err)
  1845  
  1846  	filter := l4IngressPolicy.ExactLookup("port-80", 0, "TCP")
  1847  	require.NotNil(t, filter)
  1848  	require.Equal(t, uint16(0), filter.Port)
  1849  	require.Equal(t, "port-80", filter.PortName)
  1850  	require.True(t, filter.Ingress)
  1851  
  1852  	require.Equal(t, 1, len(filter.PerSelectorPolicies))
  1853  	require.Nil(t, filter.PerSelectorPolicies[td.wildcardCachedSelector])
  1854  	l4IngressPolicy.Detach(repo.GetSelectorCache())
  1855  }
  1856  
  1857  func TestEgressAllowAll(t *testing.T) {
  1858  	td := newTestData()
  1859  	repo := td.repo
  1860  	repo.MustAddList(api.Rules{
  1861  		&api.Rule{
  1862  			EndpointSelector: endpointSelectorA,
  1863  			Egress: []api.EgressRule{
  1864  				{
  1865  					EgressCommonRule: api.EgressCommonRule{
  1866  						ToEndpoints: []api.EndpointSelector{
  1867  							api.WildcardEndpointSelector,
  1868  						},
  1869  					},
  1870  				},
  1871  			},
  1872  		},
  1873  	})
  1874  
  1875  	checkEgress(t, repo, &ctxAToB, api.Allowed)
  1876  	checkEgress(t, repo, &ctxAToC, api.Allowed)
  1877  
  1878  	ctxAToC80 := ctxAToC
  1879  	ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}
  1880  	checkEgress(t, repo, &ctxAToC80, api.Allowed)
  1881  
  1882  	ctxAToC90 := ctxAToC
  1883  	ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
  1884  	checkEgress(t, repo, &ctxAToC90, api.Allowed)
  1885  }
  1886  
  1887  func TestEgressL4AllowAll(t *testing.T) {
  1888  	td := newTestData()
  1889  	repo := td.repo
  1890  	repo.MustAddList(api.Rules{
  1891  		&api.Rule{
  1892  			EndpointSelector: endpointSelectorA,
  1893  			Egress: []api.EgressRule{
  1894  				{
  1895  					ToPorts: []api.PortRule{{
  1896  						Ports: []api.PortProtocol{
  1897  							{Port: "80", Protocol: api.ProtoTCP},
  1898  						},
  1899  					}},
  1900  				},
  1901  			},
  1902  		},
  1903  	})
  1904  
  1905  	ctxAToC80 := ctxAToC
  1906  	ctxAToC80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}
  1907  	checkEgress(t, repo, &ctxAToC80, api.Allowed)
  1908  
  1909  	ctxAToC90 := ctxAToC
  1910  	ctxAToC90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
  1911  	checkEgress(t, repo, &ctxAToC90, api.Denied)
  1912  
  1913  	buffer := new(bytes.Buffer)
  1914  	ctx := SearchContext{From: labelsA, Trace: TRACE_VERBOSE}
  1915  	ctx.Logging = stdlog.New(buffer, "", 0)
  1916  
  1917  	l4EgressPolicy, err := repo.ResolveL4EgressPolicy(&ctx)
  1918  	require.NoError(t, err)
  1919  
  1920  	t.Log(buffer)
  1921  
  1922  	filter := l4EgressPolicy.ExactLookup("80", 0, "TCP")
  1923  	require.NotNil(t, filter)
  1924  	require.Equal(t, uint16(80), filter.Port)
  1925  	require.Equal(t, false, filter.Ingress)
  1926  
  1927  	require.Equal(t, 1, len(filter.PerSelectorPolicies))
  1928  	require.Nil(t, filter.PerSelectorPolicies[td.wildcardCachedSelector])
  1929  	l4EgressPolicy.Detach(repo.GetSelectorCache())
  1930  }
  1931  
  1932  func TestEgressL4AllowWorld(t *testing.T) {
  1933  	td := newTestData()
  1934  	repo := td.repo
  1935  	repo.MustAddList(api.Rules{
  1936  		&api.Rule{
  1937  			EndpointSelector: endpointSelectorA,
  1938  			Egress: []api.EgressRule{
  1939  				{
  1940  					EgressCommonRule: api.EgressCommonRule{
  1941  						ToEntities: []api.Entity{api.EntityWorld},
  1942  					},
  1943  					ToPorts: []api.PortRule{{
  1944  						Ports: []api.PortProtocol{
  1945  							{Port: "80", Protocol: api.ProtoTCP},
  1946  						},
  1947  					}},
  1948  				},
  1949  			},
  1950  		},
  1951  	})
  1952  
  1953  	worldLabel := labels.ParseSelectLabelArray("reserved:world")
  1954  	ctxAToWorld80 := SearchContext{From: labelsA, To: worldLabel, Trace: TRACE_VERBOSE}
  1955  	ctxAToWorld80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}
  1956  	checkEgress(t, repo, &ctxAToWorld80, api.Allowed)
  1957  
  1958  	ctxAToWorld90 := ctxAToWorld80
  1959  	ctxAToWorld90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
  1960  	checkEgress(t, repo, &ctxAToWorld90, api.Denied)
  1961  
  1962  	// Pod to pod must be denied on port 80 and 90, only world was whitelisted
  1963  	fooLabel := labels.ParseSelectLabelArray("k8s:app=foo")
  1964  	ctxAToFoo := SearchContext{From: labelsA, To: fooLabel, Trace: TRACE_VERBOSE,
  1965  		DPorts: []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}}
  1966  	checkEgress(t, repo, &ctxAToFoo, api.Denied)
  1967  	ctxAToFoo90 := ctxAToFoo
  1968  	ctxAToFoo90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
  1969  	checkEgress(t, repo, &ctxAToFoo90, api.Denied)
  1970  
  1971  	buffer := new(bytes.Buffer)
  1972  	ctx := SearchContext{From: labelsA, Trace: TRACE_VERBOSE}
  1973  	ctx.Logging = stdlog.New(buffer, "", 0)
  1974  
  1975  	l4EgressPolicy, err := repo.ResolveL4EgressPolicy(&ctx)
  1976  	require.NoError(t, err)
  1977  
  1978  	t.Log(buffer)
  1979  
  1980  	filter := l4EgressPolicy.ExactLookup("80", 0, "TCP")
  1981  	require.NotNil(t, filter)
  1982  	require.Equal(t, uint16(80), filter.Port)
  1983  	require.Equal(t, false, filter.Ingress)
  1984  
  1985  	require.Equal(t, 3, len(filter.PerSelectorPolicies))
  1986  	l4EgressPolicy.Detach(repo.GetSelectorCache())
  1987  }
  1988  
  1989  func TestEgressL4AllowAllEntity(t *testing.T) {
  1990  	td := newTestData()
  1991  	repo := td.repo
  1992  	repo.MustAddList(api.Rules{
  1993  		&api.Rule{
  1994  			EndpointSelector: endpointSelectorA,
  1995  			Egress: []api.EgressRule{
  1996  				{
  1997  					EgressCommonRule: api.EgressCommonRule{
  1998  						ToEntities: []api.Entity{api.EntityAll},
  1999  					},
  2000  					ToPorts: []api.PortRule{{
  2001  						Ports: []api.PortProtocol{
  2002  							{Port: "80", Protocol: api.ProtoTCP},
  2003  						},
  2004  					}},
  2005  				},
  2006  			},
  2007  		},
  2008  	})
  2009  
  2010  	worldLabel := labels.ParseSelectLabelArray("reserved:world")
  2011  	ctxAToWorld80 := SearchContext{From: labelsA, To: worldLabel, Trace: TRACE_VERBOSE}
  2012  	ctxAToWorld80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}
  2013  	checkEgress(t, repo, &ctxAToWorld80, api.Allowed)
  2014  
  2015  	ctxAToWorld90 := ctxAToWorld80
  2016  	ctxAToWorld90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
  2017  	checkEgress(t, repo, &ctxAToWorld90, api.Denied)
  2018  
  2019  	// Pod to pod must be allowed on port 80, denied on port 90 (all identity)
  2020  	fooLabel := labels.ParseSelectLabelArray("k8s:app=foo")
  2021  	ctxAToFoo := SearchContext{From: labelsA, To: fooLabel, Trace: TRACE_VERBOSE,
  2022  		DPorts: []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}}
  2023  	checkEgress(t, repo, &ctxAToFoo, api.Allowed)
  2024  	ctxAToFoo90 := ctxAToFoo
  2025  	ctxAToFoo90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
  2026  	checkEgress(t, repo, &ctxAToFoo90, api.Denied)
  2027  
  2028  	buffer := new(bytes.Buffer)
  2029  	ctx := SearchContext{From: labelsA, Trace: TRACE_VERBOSE}
  2030  	ctx.Logging = stdlog.New(buffer, "", 0)
  2031  
  2032  	l4EgressPolicy, err := repo.ResolveL4EgressPolicy(&ctx)
  2033  	require.NoError(t, err)
  2034  
  2035  	t.Log(buffer)
  2036  
  2037  	filter := l4EgressPolicy.ExactLookup("80", 0, "TCP")
  2038  	require.NotNil(t, filter)
  2039  	require.Equal(t, uint16(80), filter.Port)
  2040  	require.Equal(t, false, filter.Ingress)
  2041  
  2042  	require.Equal(t, 1, len(filter.PerSelectorPolicies))
  2043  	l4EgressPolicy.Detach(repo.GetSelectorCache())
  2044  }
  2045  
  2046  func TestEgressL3AllowWorld(t *testing.T) {
  2047  	td := newTestData()
  2048  	repo := td.repo
  2049  	repo.MustAddList(api.Rules{
  2050  		&api.Rule{
  2051  			EndpointSelector: endpointSelectorA,
  2052  			Egress: []api.EgressRule{
  2053  				{
  2054  					EgressCommonRule: api.EgressCommonRule{
  2055  						ToEntities: []api.Entity{api.EntityWorld},
  2056  					},
  2057  				},
  2058  			},
  2059  		},
  2060  	})
  2061  
  2062  	worldLabel := labels.ParseSelectLabelArray("reserved:world")
  2063  	ctxAToWorld80 := SearchContext{From: labelsA, To: worldLabel, Trace: TRACE_VERBOSE}
  2064  	ctxAToWorld80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}
  2065  	checkEgress(t, repo, &ctxAToWorld80, api.Allowed)
  2066  
  2067  	ctxAToWorld90 := ctxAToWorld80
  2068  	ctxAToWorld90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
  2069  	checkEgress(t, repo, &ctxAToWorld90, api.Allowed)
  2070  
  2071  	// Pod to pod must be denied on port 80 and 90, only world was whitelisted
  2072  	fooLabel := labels.ParseSelectLabelArray("k8s:app=foo")
  2073  	ctxAToFoo := SearchContext{From: labelsA, To: fooLabel, Trace: TRACE_VERBOSE,
  2074  		DPorts: []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}}
  2075  	checkEgress(t, repo, &ctxAToFoo, api.Denied)
  2076  	ctxAToFoo90 := ctxAToFoo
  2077  	ctxAToFoo90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
  2078  	checkEgress(t, repo, &ctxAToFoo90, api.Denied)
  2079  
  2080  	buffer := new(bytes.Buffer)
  2081  	ctx := SearchContext{From: labelsA, Trace: TRACE_VERBOSE}
  2082  	ctx.Logging = stdlog.New(buffer, "", 0)
  2083  }
  2084  
  2085  func TestEgressL3AllowAllEntity(t *testing.T) {
  2086  	td := newTestData()
  2087  	repo := td.repo
  2088  	repo.MustAddList(api.Rules{
  2089  		&api.Rule{
  2090  			EndpointSelector: endpointSelectorA,
  2091  			Egress: []api.EgressRule{
  2092  				{
  2093  					EgressCommonRule: api.EgressCommonRule{
  2094  						ToEntities: []api.Entity{api.EntityAll},
  2095  					},
  2096  				},
  2097  			},
  2098  		},
  2099  	})
  2100  
  2101  	worldLabel := labels.ParseSelectLabelArray("reserved:world")
  2102  	ctxAToWorld80 := SearchContext{From: labelsA, To: worldLabel, Trace: TRACE_VERBOSE}
  2103  	ctxAToWorld80.DPorts = []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}
  2104  	checkEgress(t, repo, &ctxAToWorld80, api.Allowed)
  2105  
  2106  	ctxAToWorld90 := ctxAToWorld80
  2107  	ctxAToWorld90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
  2108  	checkEgress(t, repo, &ctxAToWorld90, api.Allowed)
  2109  
  2110  	// Pod to pod must be allowed on both port 80 and 90 (L3 only rule)
  2111  	fooLabel := labels.ParseSelectLabelArray("k8s:app=foo")
  2112  	ctxAToFoo := SearchContext{From: labelsA, To: fooLabel, Trace: TRACE_VERBOSE,
  2113  		DPorts: []*models.Port{{Port: 80, Protocol: models.PortProtocolTCP}}}
  2114  	checkEgress(t, repo, &ctxAToFoo, api.Allowed)
  2115  	ctxAToFoo90 := ctxAToFoo
  2116  	ctxAToFoo90.DPorts = []*models.Port{{Port: 90, Protocol: models.PortProtocolTCP}}
  2117  	checkEgress(t, repo, &ctxAToFoo90, api.Allowed)
  2118  
  2119  	buffer := new(bytes.Buffer)
  2120  	ctx := SearchContext{From: labelsA, Trace: TRACE_VERBOSE}
  2121  	ctx.Logging = stdlog.New(buffer, "", 0)
  2122  }
  2123  
  2124  func TestL4WildcardMerge(t *testing.T) {
  2125  
  2126  	// First, test implicit case.
  2127  	//
  2128  	// Test the case where if we have rules that select the same endpoint on the
  2129  	// same port-protocol tuple with one that is L4-only, and the other applying
  2130  	// at L4 and L7, that the L4-only rule shadows the L4-L7 rule. This is because
  2131  	// L4-only rule implicitly allows all traffic at L7, so the L7-related
  2132  	// parts of the L4-L7 rule are useless.
  2133  	td := newTestData()
  2134  	repo := td.repo
  2135  	repo.MustAddList(api.Rules{&api.Rule{
  2136  		EndpointSelector: endpointSelectorA,
  2137  		Ingress: []api.IngressRule{
  2138  			{
  2139  				IngressCommonRule: api.IngressCommonRule{
  2140  					FromEndpoints: []api.EndpointSelector{endpointSelectorC},
  2141  				},
  2142  				ToPorts: []api.PortRule{{
  2143  					Ports: []api.PortProtocol{
  2144  						{Port: "80", Protocol: api.ProtoTCP},
  2145  					},
  2146  					Rules: &api.L7Rules{
  2147  						HTTP: []api.PortRuleHTTP{
  2148  							{Method: "GET", Path: "/"},
  2149  						},
  2150  					},
  2151  				}},
  2152  			},
  2153  			{
  2154  				ToPorts: []api.PortRule{{
  2155  					Ports: []api.PortProtocol{
  2156  						{Port: "80", Protocol: api.ProtoTCP},
  2157  					},
  2158  				}},
  2159  			},
  2160  			{
  2161  				IngressCommonRule: api.IngressCommonRule{
  2162  					FromEndpoints: []api.EndpointSelector{endpointSelectorC},
  2163  				},
  2164  				ToPorts: []api.PortRule{{
  2165  					Ports: []api.PortProtocol{
  2166  						{Port: "7000", Protocol: api.ProtoTCP},
  2167  					},
  2168  					Rules: &api.L7Rules{
  2169  						L7Proto: "testparser",
  2170  						L7: []api.PortRuleL7{
  2171  							{"Key": "Value"},
  2172  						},
  2173  					},
  2174  				}},
  2175  			},
  2176  			{
  2177  				IngressCommonRule: api.IngressCommonRule{
  2178  					FromEndpoints: []api.EndpointSelector{endpointSelectorC},
  2179  				},
  2180  				ToPorts: []api.PortRule{{
  2181  					Ports: []api.PortProtocol{
  2182  						{Port: "7000", Protocol: api.ProtoTCP},
  2183  					},
  2184  				}},
  2185  			},
  2186  		},
  2187  	}})
  2188  
  2189  	expected := &L4Filter{
  2190  		Port: 80, Protocol: api.ProtoTCP, U8Proto: 6,
  2191  		wildcard: td.wildcardCachedSelector,
  2192  		L7Parser: "http",
  2193  		PerSelectorPolicies: L7DataMap{
  2194  			td.wildcardCachedSelector: nil,
  2195  			td.cachedSelectorC: &PerSelectorPolicy{
  2196  				L7Rules: api.L7Rules{
  2197  					HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}},
  2198  				},
  2199  				isRedirect: true,
  2200  			},
  2201  		},
  2202  		Ingress: true,
  2203  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{
  2204  			td.cachedSelectorC:        {nil},
  2205  			td.wildcardCachedSelector: {nil},
  2206  		},
  2207  	}
  2208  
  2209  	buffer := new(bytes.Buffer)
  2210  	ctx := SearchContext{To: labelsA, Trace: TRACE_VERBOSE}
  2211  	ctx.Logging = stdlog.New(buffer, "", 0)
  2212  
  2213  	l4IngressPolicy, err := repo.ResolveL4IngressPolicy(&ctx)
  2214  	require.NoError(t, err)
  2215  
  2216  	t.Log(buffer)
  2217  
  2218  	filter := l4IngressPolicy.ExactLookup("80", 0, "TCP")
  2219  	require.NotNil(t, filter)
  2220  	require.Equal(t, uint16(80), filter.Port)
  2221  	require.True(t, filter.Ingress)
  2222  
  2223  	require.Equal(t, 2, len(filter.PerSelectorPolicies))
  2224  	require.NotNil(t, filter.PerSelectorPolicies[td.cachedSelectorC])
  2225  	require.Nil(t, filter.PerSelectorPolicies[td.wildcardCachedSelector])
  2226  	require.EqualValues(t, expected, filter)
  2227  	require.Equal(t, ParserTypeHTTP, filter.L7Parser)
  2228  
  2229  	expectedL7 := &L4Filter{
  2230  		Port: 7000, Protocol: api.ProtoTCP, U8Proto: 6,
  2231  		L7Parser: "testparser",
  2232  		PerSelectorPolicies: L7DataMap{
  2233  			td.cachedSelectorC: &PerSelectorPolicy{
  2234  				L7Rules: api.L7Rules{
  2235  					L7Proto: "testparser",
  2236  					L7:      []api.PortRuleL7{{"Key": "Value"}, {}},
  2237  				},
  2238  				isRedirect: true,
  2239  			},
  2240  		},
  2241  		Ingress:    true,
  2242  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.cachedSelectorC: {nil}},
  2243  	}
  2244  
  2245  	filterL7 := l4IngressPolicy.ExactLookup("7000", 0, "TCP")
  2246  	require.NotNil(t, filterL7)
  2247  	require.Equal(t, uint16(7000), filterL7.Port)
  2248  	require.True(t, filterL7.Ingress)
  2249  
  2250  	require.Equal(t, 1, len(filterL7.PerSelectorPolicies))
  2251  	require.NotNil(t, filterL7.PerSelectorPolicies[td.cachedSelectorC])
  2252  	require.Nil(t, filterL7.PerSelectorPolicies[td.wildcardCachedSelector])
  2253  	require.EqualValues(t, expectedL7, filterL7)
  2254  	require.Equal(t, L7ParserType("testparser"), filterL7.L7Parser)
  2255  
  2256  	l4IngressPolicy.Detach(repo.GetSelectorCache())
  2257  
  2258  	// Test the reverse order as well; ensure that we check both conditions
  2259  	// for if L4-only policy is in the L4Filter for the same port-protocol tuple,
  2260  	// and L7 metadata exists in the L4Filter we are adding; expect to resolve
  2261  	// to L4-only policy without any L7-metadata.
  2262  	repo = td.resetRepo()
  2263  	repo.MustAddList(api.Rules{&api.Rule{
  2264  		EndpointSelector: endpointSelectorA,
  2265  		Ingress: []api.IngressRule{
  2266  			{
  2267  				IngressCommonRule: api.IngressCommonRule{
  2268  					FromEndpoints: []api.EndpointSelector{endpointSelectorC},
  2269  				},
  2270  				ToPorts: []api.PortRule{{
  2271  					Ports: []api.PortProtocol{
  2272  						{Port: "7000", Protocol: api.ProtoTCP},
  2273  					},
  2274  				}},
  2275  			},
  2276  			{
  2277  				IngressCommonRule: api.IngressCommonRule{
  2278  					FromEndpoints: []api.EndpointSelector{endpointSelectorC},
  2279  				},
  2280  				ToPorts: []api.PortRule{{
  2281  					Ports: []api.PortProtocol{
  2282  						{Port: "7000", Protocol: api.ProtoTCP},
  2283  					},
  2284  					Rules: &api.L7Rules{
  2285  						L7Proto: "testparser",
  2286  						L7: []api.PortRuleL7{
  2287  							{"Key": "Value"},
  2288  						},
  2289  					},
  2290  				}},
  2291  			},
  2292  			{
  2293  				ToPorts: []api.PortRule{{
  2294  					Ports: []api.PortProtocol{
  2295  						{Port: "80", Protocol: api.ProtoTCP},
  2296  					},
  2297  				}},
  2298  			},
  2299  			{
  2300  				IngressCommonRule: api.IngressCommonRule{
  2301  					FromEndpoints: []api.EndpointSelector{endpointSelectorC},
  2302  				},
  2303  				ToPorts: []api.PortRule{{
  2304  					Ports: []api.PortProtocol{
  2305  						{Port: "80", Protocol: api.ProtoTCP},
  2306  					},
  2307  					Rules: &api.L7Rules{
  2308  						HTTP: []api.PortRuleHTTP{
  2309  							{Method: "GET", Path: "/"},
  2310  						},
  2311  					},
  2312  				}},
  2313  			},
  2314  		},
  2315  	}})
  2316  
  2317  	buffer = new(bytes.Buffer)
  2318  	ctx = SearchContext{To: labelsA, Trace: TRACE_VERBOSE}
  2319  	ctx.Logging = stdlog.New(buffer, "", 0)
  2320  
  2321  	l4IngressPolicy, err = repo.ResolveL4IngressPolicy(&ctx)
  2322  	require.NoError(t, err)
  2323  
  2324  	t.Log(buffer)
  2325  
  2326  	filter = l4IngressPolicy.ExactLookup("80", 0, "TCP")
  2327  	require.NotNil(t, filter)
  2328  	require.Equal(t, uint16(80), filter.Port)
  2329  	require.True(t, filter.Ingress)
  2330  
  2331  	require.Equal(t, 2, len(filter.PerSelectorPolicies))
  2332  	require.Nil(t, filter.PerSelectorPolicies[td.wildcardCachedSelector])
  2333  	require.NotNil(t, filter.PerSelectorPolicies[td.cachedSelectorC])
  2334  	require.EqualValues(t, expected, filter)
  2335  	require.Equal(t, ParserTypeHTTP, filter.L7Parser)
  2336  
  2337  	filterL7 = l4IngressPolicy.ExactLookup("7000", 0, "TCP")
  2338  	require.NotNil(t, filterL7)
  2339  	require.Equal(t, uint16(7000), filterL7.Port)
  2340  	require.True(t, filterL7.Ingress)
  2341  
  2342  	require.Equal(t, 1, len(filterL7.PerSelectorPolicies))
  2343  	require.NotNil(t, filterL7.PerSelectorPolicies[td.cachedSelectorC])
  2344  	require.Nil(t, filterL7.PerSelectorPolicies[td.wildcardCachedSelector])
  2345  	require.EqualValues(t, expectedL7, filterL7)
  2346  	require.Equal(t, L7ParserType("testparser"), filterL7.L7Parser)
  2347  
  2348  	// Second, test the expeicit allow at L3.
  2349  	repo = td.resetRepo()
  2350  	repo.MustAddList(api.Rules{&api.Rule{
  2351  		EndpointSelector: endpointSelectorA,
  2352  		Ingress: []api.IngressRule{
  2353  			{
  2354  				IngressCommonRule: api.IngressCommonRule{
  2355  					FromEndpoints: []api.EndpointSelector{endpointSelectorC},
  2356  				},
  2357  				ToPorts: []api.PortRule{{
  2358  					Ports: []api.PortProtocol{
  2359  						{Port: "80", Protocol: api.ProtoTCP},
  2360  					},
  2361  					Rules: &api.L7Rules{
  2362  						HTTP: []api.PortRuleHTTP{
  2363  							{Method: "GET", Path: "/"},
  2364  						},
  2365  					},
  2366  				}},
  2367  			},
  2368  			{
  2369  				IngressCommonRule: api.IngressCommonRule{
  2370  					FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector},
  2371  				},
  2372  				ToPorts: []api.PortRule{{
  2373  					Ports: []api.PortProtocol{
  2374  						{Port: "80", Protocol: api.ProtoTCP},
  2375  					},
  2376  				}},
  2377  			},
  2378  		},
  2379  	}})
  2380  
  2381  	buffer = new(bytes.Buffer)
  2382  	ctx = SearchContext{To: labelsA, Trace: TRACE_VERBOSE}
  2383  	ctx.Logging = stdlog.New(buffer, "", 0)
  2384  
  2385  	l4IngressPolicy, err = repo.ResolveL4IngressPolicy(&ctx)
  2386  	require.NoError(t, err)
  2387  
  2388  	t.Log(buffer)
  2389  
  2390  	filter = l4IngressPolicy.ExactLookup("80", 0, "TCP")
  2391  	require.NotNil(t, filter)
  2392  	require.Equal(t, uint16(80), filter.Port)
  2393  	require.True(t, filter.Ingress)
  2394  
  2395  	require.Equal(t, ParserTypeHTTP, filter.L7Parser)
  2396  	require.Equal(t, 2, len(filter.PerSelectorPolicies))
  2397  	require.EqualValues(t, expected, filter)
  2398  
  2399  	// Test the reverse order as well; ensure that we check both conditions
  2400  	// for if L4-only policy is in the L4Filter for the same port-protocol tuple,
  2401  	// and L7 metadata exists in the L4Filter we are adding; expect to resolve
  2402  	// to L4-only policy without any L7-metadata.
  2403  	repo = td.resetRepo()
  2404  	repo.MustAddList(api.Rules{&api.Rule{
  2405  		EndpointSelector: endpointSelectorA,
  2406  		Ingress: []api.IngressRule{
  2407  			{
  2408  				IngressCommonRule: api.IngressCommonRule{
  2409  					FromEndpoints: []api.EndpointSelector{api.WildcardEndpointSelector},
  2410  				},
  2411  				ToPorts: []api.PortRule{{
  2412  					Ports: []api.PortProtocol{
  2413  						{Port: "80", Protocol: api.ProtoTCP},
  2414  					},
  2415  				}},
  2416  			},
  2417  			{
  2418  				IngressCommonRule: api.IngressCommonRule{
  2419  					FromEndpoints: []api.EndpointSelector{endpointSelectorC},
  2420  				},
  2421  				ToPorts: []api.PortRule{{
  2422  					Ports: []api.PortProtocol{
  2423  						{Port: "80", Protocol: api.ProtoTCP},
  2424  					},
  2425  					Rules: &api.L7Rules{
  2426  						HTTP: []api.PortRuleHTTP{
  2427  							{Method: "GET", Path: "/"},
  2428  						},
  2429  					},
  2430  				}},
  2431  			},
  2432  		},
  2433  	}})
  2434  
  2435  	buffer = new(bytes.Buffer)
  2436  	ctx = SearchContext{To: labelsA, Trace: TRACE_VERBOSE}
  2437  	ctx.Logging = stdlog.New(buffer, "", 0)
  2438  
  2439  	l4IngressPolicy, err = repo.ResolveL4IngressPolicy(&ctx)
  2440  	require.NoError(t, err)
  2441  
  2442  	t.Log(buffer)
  2443  
  2444  	filter = l4IngressPolicy.ExactLookup("80", 0, "TCP")
  2445  	require.NotNil(t, filter)
  2446  	require.Equal(t, uint16(80), filter.Port)
  2447  	require.True(t, filter.Ingress)
  2448  
  2449  	require.Equal(t, ParserTypeHTTP, filter.L7Parser)
  2450  	require.Equal(t, 2, len(filter.PerSelectorPolicies))
  2451  	require.EqualValues(t, expected, filter)
  2452  }
  2453  
  2454  func TestL3L4L7Merge(t *testing.T) {
  2455  
  2456  	// First rule allows ingress from all endpoints to port 80 only on
  2457  	// GET to "/". However, second rule allows all traffic on port 80 only to a
  2458  	// specific endpoint. When these rules are merged, it equates to allowing
  2459  	// all traffic from port 80 from any endpoint.
  2460  	//
  2461  	// TODO: This comment can't be correct, the resulting policy
  2462  	// should allow all on port 80 only from endpoint C, traffic
  2463  	// from all other endpoints should still only allow only GET
  2464  	// on "/".
  2465  	td := newTestData()
  2466  	repo := td.repo
  2467  	repo.MustAddList(api.Rules{&api.Rule{
  2468  		EndpointSelector: endpointSelectorA,
  2469  		Ingress: []api.IngressRule{
  2470  			{
  2471  				ToPorts: []api.PortRule{{
  2472  					Ports: []api.PortProtocol{
  2473  						{Port: "80", Protocol: api.ProtoTCP},
  2474  					},
  2475  					Rules: &api.L7Rules{
  2476  						HTTP: []api.PortRuleHTTP{
  2477  							{Method: "GET", Path: "/"},
  2478  						},
  2479  					},
  2480  				}},
  2481  			},
  2482  			{
  2483  				IngressCommonRule: api.IngressCommonRule{
  2484  					FromEndpoints: []api.EndpointSelector{endpointSelectorC},
  2485  				},
  2486  				ToPorts: []api.PortRule{{
  2487  					Ports: []api.PortProtocol{
  2488  						{Port: "80", Protocol: api.ProtoTCP},
  2489  					},
  2490  				}},
  2491  			},
  2492  		},
  2493  	}})
  2494  
  2495  	buffer := new(bytes.Buffer)
  2496  	ctx := SearchContext{To: labelsA, Trace: TRACE_VERBOSE}
  2497  	ctx.Logging = stdlog.New(buffer, "", 0)
  2498  
  2499  	l4IngressPolicy, err := repo.ResolveL4IngressPolicy(&ctx)
  2500  	require.NoError(t, err)
  2501  
  2502  	t.Log(buffer)
  2503  
  2504  	filter := l4IngressPolicy.ExactLookup("80", 0, "TCP")
  2505  	require.NotNil(t, filter)
  2506  	require.Equal(t, uint16(80), filter.Port)
  2507  	require.True(t, filter.Ingress)
  2508  
  2509  	require.Equal(t, 2, len(filter.PerSelectorPolicies))
  2510  	require.NotNil(t, filter.PerSelectorPolicies[td.wildcardCachedSelector])
  2511  	require.Nil(t, filter.PerSelectorPolicies[td.cachedSelectorC])
  2512  
  2513  	require.Equal(t, ParserTypeHTTP, filter.L7Parser)
  2514  	require.Equal(t, 2, len(filter.PerSelectorPolicies))
  2515  	require.Equal(t, &L4Filter{
  2516  		Port: 80, Protocol: api.ProtoTCP, U8Proto: 6,
  2517  		wildcard: td.wildcardCachedSelector,
  2518  		L7Parser: "http",
  2519  		PerSelectorPolicies: L7DataMap{
  2520  			td.cachedSelectorC: nil,
  2521  			td.wildcardCachedSelector: &PerSelectorPolicy{
  2522  				L7Rules: api.L7Rules{
  2523  					HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}},
  2524  				},
  2525  				isRedirect: true,
  2526  			},
  2527  		},
  2528  		Ingress: true,
  2529  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{
  2530  			td.cachedSelectorC:        {nil},
  2531  			td.wildcardCachedSelector: {nil},
  2532  		},
  2533  	}, filter)
  2534  
  2535  	repo = td.resetRepo()
  2536  	repo.MustAddList(api.Rules{&api.Rule{
  2537  		EndpointSelector: endpointSelectorA,
  2538  		Ingress: []api.IngressRule{
  2539  			{
  2540  				IngressCommonRule: api.IngressCommonRule{
  2541  					FromEndpoints: []api.EndpointSelector{endpointSelectorC},
  2542  				},
  2543  				ToPorts: []api.PortRule{{
  2544  					Ports: []api.PortProtocol{
  2545  						{Port: "80", Protocol: api.ProtoTCP},
  2546  					},
  2547  				}},
  2548  			},
  2549  			{
  2550  				ToPorts: []api.PortRule{{
  2551  					Ports: []api.PortProtocol{
  2552  						{Port: "80", Protocol: api.ProtoTCP},
  2553  					},
  2554  					Rules: &api.L7Rules{
  2555  						HTTP: []api.PortRuleHTTP{
  2556  							{Method: "GET", Path: "/"},
  2557  						},
  2558  					},
  2559  				}},
  2560  			},
  2561  		},
  2562  	}})
  2563  
  2564  	buffer = new(bytes.Buffer)
  2565  	ctx = SearchContext{To: labelsA, Trace: TRACE_VERBOSE}
  2566  	ctx.Logging = stdlog.New(buffer, "", 0)
  2567  
  2568  	l4IngressPolicy, err = repo.ResolveL4IngressPolicy(&ctx)
  2569  	require.NoError(t, err)
  2570  
  2571  	t.Log(buffer)
  2572  
  2573  	filter = l4IngressPolicy.ExactLookup("80", 0, "TCP")
  2574  	require.NotNil(t, filter)
  2575  	require.Equal(t, uint16(80), filter.Port)
  2576  	require.True(t, filter.Ingress)
  2577  
  2578  	require.Equal(t, ParserTypeHTTP, filter.L7Parser)
  2579  	require.Equal(t, 2, len(filter.PerSelectorPolicies))
  2580  	require.NotNil(t, filter.PerSelectorPolicies[td.wildcardCachedSelector])
  2581  	require.Nil(t, filter.PerSelectorPolicies[td.cachedSelectorC])
  2582  	require.Equal(t, &L4Filter{
  2583  		Port: 80, Protocol: api.ProtoTCP, U8Proto: 6,
  2584  		wildcard: td.wildcardCachedSelector,
  2585  		L7Parser: "http",
  2586  		PerSelectorPolicies: L7DataMap{
  2587  			td.cachedSelectorC: nil,
  2588  			td.wildcardCachedSelector: &PerSelectorPolicy{
  2589  				L7Rules: api.L7Rules{
  2590  					HTTP: []api.PortRuleHTTP{{Path: "/", Method: "GET"}},
  2591  				},
  2592  				isRedirect: true,
  2593  			},
  2594  		},
  2595  		Ingress: true,
  2596  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{
  2597  			td.cachedSelectorC:        {nil},
  2598  			td.wildcardCachedSelector: {nil},
  2599  		},
  2600  	}, filter)
  2601  
  2602  }
  2603  
  2604  func TestMatches(t *testing.T) {
  2605  	td := newTestData()
  2606  	repo := td.repo
  2607  	repo.MustAddList(api.Rules{
  2608  		&api.Rule{
  2609  			EndpointSelector: endpointSelectorA,
  2610  			Ingress: []api.IngressRule{
  2611  				{
  2612  					IngressCommonRule: api.IngressCommonRule{
  2613  						FromEndpoints: []api.EndpointSelector{endpointSelectorC},
  2614  					},
  2615  				},
  2616  			},
  2617  		},
  2618  		&api.Rule{
  2619  			NodeSelector: endpointSelectorA,
  2620  			Ingress: []api.IngressRule{
  2621  				{
  2622  					IngressCommonRule: api.IngressCommonRule{
  2623  						FromEndpoints: []api.EndpointSelector{endpointSelectorC},
  2624  					},
  2625  				},
  2626  			},
  2627  		},
  2628  	})
  2629  
  2630  	epRule := repo.rules[ruleKey{idx: 0}]
  2631  	hostRule := repo.rules[ruleKey{idx: 1}]
  2632  
  2633  	selectedEpLabels := labels.ParseSelectLabel("id=a")
  2634  	selectedIdentity := identity.NewIdentity(54321, labels.Labels{selectedEpLabels.Key: selectedEpLabels})
  2635  	td.addIdentity(selectedIdentity)
  2636  
  2637  	notSelectedEpLabels := labels.ParseSelectLabel("id=b")
  2638  	notSelectedIdentity := identity.NewIdentity(9876, labels.Labels{notSelectedEpLabels.Key: notSelectedEpLabels})
  2639  	td.addIdentity(notSelectedIdentity)
  2640  
  2641  	hostLabels := labels.Labels{selectedEpLabels.Key: selectedEpLabels}
  2642  	hostLabels.MergeLabels(labels.LabelHost)
  2643  	hostIdentity := identity.NewIdentity(identity.ReservedIdentityHost, hostLabels)
  2644  	td.addIdentity(hostIdentity)
  2645  
  2646  	// notSelectedEndpoint is not selected by rule, so we it shouldn't be added
  2647  	// to EndpointsSelected.
  2648  	require.Equal(t, false, epRule.matchesSubject(notSelectedIdentity))
  2649  
  2650  	// selectedEndpoint is selected by rule, so we it should be added to
  2651  	// EndpointsSelected.
  2652  	require.True(t, epRule.matchesSubject(selectedIdentity))
  2653  
  2654  	// Test again to check for caching working correctly.
  2655  	require.True(t, epRule.matchesSubject(selectedIdentity))
  2656  
  2657  	// Possible scenario where an endpoint is deleted, and soon after another
  2658  	// endpoint is added with the same ID, but with a different identity. Matching
  2659  	// needs to handle this case correctly.
  2660  	require.Equal(t, false, epRule.matchesSubject(notSelectedIdentity))
  2661  
  2662  	// host endpoint is not selected by rule, so we it shouldn't be added to EndpointsSelected.
  2663  	require.Equal(t, false, epRule.matchesSubject(hostIdentity))
  2664  
  2665  	// selectedEndpoint is not selected by rule, so we it shouldn't be added to EndpointsSelected.
  2666  	require.Equal(t, false, hostRule.matchesSubject(selectedIdentity))
  2667  
  2668  	// host endpoint is selected by rule, but host labels are mutable, so don't cache them
  2669  	require.True(t, hostRule.matchesSubject(hostIdentity))
  2670  
  2671  	// Assert that mutable host identities are handled
  2672  	// First, add an additional label, ensure that match succeeds
  2673  	hostLabels.MergeLabels(labels.NewLabelsFromModel([]string{"foo=bar"}))
  2674  	hostIdentity = identity.NewIdentity(identity.ReservedIdentityHost, hostLabels)
  2675  	td.addIdentity(hostIdentity)
  2676  	require.True(t, hostRule.matchesSubject(hostIdentity))
  2677  
  2678  	// Then, change host to id=c, which is not selected, and ensure match is correct
  2679  	hostIdentity = identity.NewIdentity(identity.ReservedIdentityHost, labels.NewLabelsFromModel([]string{"id=c"}))
  2680  	td.addIdentity(hostIdentity)
  2681  	require.False(t, hostRule.matchesSubject(hostIdentity))
  2682  }
  2683  
  2684  func BenchmarkRuleString(b *testing.B) {
  2685  	r := &rule{
  2686  		Rule: api.Rule{
  2687  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  2688  			Ingress: []api.IngressRule{
  2689  				{
  2690  					ToPorts: []api.PortRule{{
  2691  						Ports: []api.PortProtocol{
  2692  							{Port: "80", Protocol: api.ProtoTCP},
  2693  							{Port: "8080", Protocol: api.ProtoTCP},
  2694  						},
  2695  						Rules: &api.L7Rules{
  2696  							HTTP: []api.PortRuleHTTP{
  2697  								{Method: "GET", Path: "/"},
  2698  							},
  2699  						},
  2700  					}},
  2701  				},
  2702  			},
  2703  			Egress: []api.EgressRule{
  2704  				{
  2705  					ToPorts: []api.PortRule{{
  2706  						Ports: []api.PortProtocol{
  2707  							{Port: "3000", Protocol: api.ProtoAny},
  2708  						},
  2709  					}},
  2710  				},
  2711  			},
  2712  		},
  2713  	}
  2714  	b.ReportAllocs()
  2715  	b.ResetTimer()
  2716  	for i := 0; i < b.N; i++ {
  2717  		_ = r.String()
  2718  	}
  2719  }
  2720  
  2721  // Test merging of L7 rules when the same rules apply to multiple selectors.
  2722  // This was added to prevent regression of a bug where the merging of l7 rules for "foo"
  2723  // also affected the rules for "baz".
  2724  func TestMergeL7PolicyEgressWithMultipleSelectors(t *testing.T) {
  2725  	td := newTestData()
  2726  	fromBar := &SearchContext{From: labels.ParseSelectLabelArray("bar")}
  2727  	fromFoo := &SearchContext{From: labels.ParseSelectLabelArray("foo")}
  2728  
  2729  	fooSelector := []api.EndpointSelector{
  2730  		api.NewESFromLabels(labels.ParseSelectLabel("foo")),
  2731  	}
  2732  	foobazSelector := []api.EndpointSelector{
  2733  		api.NewESFromLabels(labels.ParseSelectLabel("foo")),
  2734  		api.NewESFromLabels(labels.ParseSelectLabel("baz")),
  2735  	}
  2736  
  2737  	rule1 := &rule{
  2738  		Rule: api.Rule{
  2739  			EndpointSelector: api.NewESFromLabels(labels.ParseSelectLabel("bar")),
  2740  			Egress: []api.EgressRule{
  2741  				{
  2742  					EgressCommonRule: api.EgressCommonRule{
  2743  						ToEndpoints: fooSelector,
  2744  					},
  2745  					// Note that this allows all on 80, so the result should wildcard HTTP to "foo"
  2746  					ToPorts: []api.PortRule{{
  2747  						Ports: []api.PortProtocol{
  2748  							{Port: "80", Protocol: api.ProtoTCP},
  2749  						},
  2750  					}},
  2751  				},
  2752  				{
  2753  					EgressCommonRule: api.EgressCommonRule{
  2754  						ToEndpoints: foobazSelector,
  2755  					},
  2756  					ToPorts: []api.PortRule{{
  2757  						Ports: []api.PortProtocol{
  2758  							{Port: "80", Protocol: api.ProtoTCP},
  2759  						},
  2760  						Rules: &api.L7Rules{
  2761  							HTTP: []api.PortRuleHTTP{
  2762  								{Method: "GET"},
  2763  							},
  2764  						},
  2765  					}},
  2766  				},
  2767  			},
  2768  		},
  2769  	}
  2770  
  2771  	expected := NewL4PolicyMapWithValues(map[string]*L4Filter{"80/TCP": {
  2772  		Port: 80, Protocol: api.ProtoTCP, U8Proto: 6,
  2773  		L7Parser: ParserTypeHTTP,
  2774  		PerSelectorPolicies: L7DataMap{
  2775  			td.cachedFooSelector: &PerSelectorPolicy{
  2776  				L7Rules: api.L7Rules{
  2777  					HTTP: []api.PortRuleHTTP{{Method: "GET"}, {}},
  2778  				},
  2779  				isRedirect: true,
  2780  			},
  2781  			td.cachedBazSelector: &PerSelectorPolicy{
  2782  				L7Rules: api.L7Rules{
  2783  					HTTP: []api.PortRuleHTTP{{Method: "GET"}},
  2784  				},
  2785  				isRedirect: true,
  2786  			},
  2787  		},
  2788  		Ingress: false,
  2789  		RuleOrigin: map[CachedSelector]labels.LabelArrayList{
  2790  			td.cachedBazSelector: {nil},
  2791  			td.cachedFooSelector: {nil},
  2792  		},
  2793  	}})
  2794  
  2795  	state := traceState{}
  2796  	res, err := rule1.resolveEgressPolicy(td.testPolicyContext, fromBar, &state, NewL4PolicyMap(), nil, nil)
  2797  	require.NoError(t, err)
  2798  	require.NotNil(t, res)
  2799  	require.EqualValues(t, expected, res)
  2800  	require.Equal(t, 1, state.selectedRules)
  2801  	require.Equal(t, 1, state.matchedRules)
  2802  	res.Detach(td.sc)
  2803  	expected.Detach(td.sc)
  2804  
  2805  	state = traceState{}
  2806  	res, err = rule1.resolveEgressPolicy(td.testPolicyContext, fromFoo, &state, NewL4PolicyMap(), nil, nil)
  2807  	require.NoError(t, err)
  2808  	require.Nil(t, res)
  2809  	require.Equal(t, 0, state.selectedRules)
  2810  	require.Equal(t, 0, state.matchedRules)
  2811  }
  2812  
  2813  func TestMergeListenerReference(t *testing.T) {
  2814  	// No listener remains a no listener
  2815  	ps := &PerSelectorPolicy{}
  2816  	err := ps.mergeListenerReference(ps)
  2817  	require.NoError(t, err)
  2818  	require.Equal(t, "", ps.Listener)
  2819  	require.Equal(t, uint16(0), ps.Priority)
  2820  
  2821  	// Listener reference remains when the other has none
  2822  	ps0 := &PerSelectorPolicy{Listener: "listener0"}
  2823  	err = ps0.mergeListenerReference(ps)
  2824  	require.NoError(t, err)
  2825  	require.Equal(t, "listener0", ps0.Listener)
  2826  	require.Equal(t, uint16(0), ps0.Priority)
  2827  
  2828  	// Listener reference is propagated when there is none to begin with
  2829  	err = ps.mergeListenerReference(ps0)
  2830  	require.NoError(t, err)
  2831  	require.Equal(t, "listener0", ps.Listener)
  2832  	require.Equal(t, uint16(0), ps.Priority)
  2833  
  2834  	// A listener is not changed when there is no change
  2835  	err = ps0.mergeListenerReference(ps0)
  2836  	require.NoError(t, err)
  2837  	require.Equal(t, "listener0", ps0.Listener)
  2838  	require.Equal(t, uint16(0), ps0.Priority)
  2839  
  2840  	// Cannot merge two different listeners with the default (zero) priority
  2841  	ps0a := &PerSelectorPolicy{Listener: "listener0a"}
  2842  	err = ps0.mergeListenerReference(ps0a)
  2843  	require.NotNil(t, err)
  2844  
  2845  	err = ps0a.mergeListenerReference(ps0)
  2846  	require.NotNil(t, err)
  2847  
  2848  	// Listener with a defined (non-zero) priority takes precedence over
  2849  	// a listener with an undefined (zero) priority
  2850  	ps1 := &PerSelectorPolicy{Listener: "listener1", Priority: 1}
  2851  	err = ps1.mergeListenerReference(ps0)
  2852  	require.NoError(t, err)
  2853  	require.Equal(t, "listener1", ps1.Listener)
  2854  	require.Equal(t, uint16(1), ps1.Priority)
  2855  
  2856  	err = ps0.mergeListenerReference(ps1)
  2857  	require.NoError(t, err)
  2858  	require.Equal(t, "listener1", ps0.Listener)
  2859  	require.Equal(t, uint16(1), ps0.Priority)
  2860  
  2861  	// Listener with the lower priority value takes precedence
  2862  	ps2 := &PerSelectorPolicy{Listener: "listener2", Priority: 2}
  2863  	err = ps1.mergeListenerReference(ps2)
  2864  	require.NoError(t, err)
  2865  	require.Equal(t, "listener1", ps1.Listener)
  2866  	require.Equal(t, uint16(1), ps1.Priority)
  2867  
  2868  	err = ps2.mergeListenerReference(ps1)
  2869  	require.NoError(t, err)
  2870  	require.Equal(t, "listener1", ps2.Listener)
  2871  	require.Equal(t, uint16(1), ps2.Priority)
  2872  
  2873  	// Cannot merge two different listeners with the same priority
  2874  	ps12 := &PerSelectorPolicy{Listener: "listener1", Priority: 2}
  2875  	ps2 = &PerSelectorPolicy{Listener: "listener2", Priority: 2}
  2876  	err = ps12.mergeListenerReference(ps2)
  2877  	require.NotNil(t, err)
  2878  	err = ps2.mergeListenerReference(ps12)
  2879  	require.NotNil(t, err)
  2880  
  2881  	// Lower priority is propagated also when the listeners are the same
  2882  	ps23 := &PerSelectorPolicy{Listener: "listener2", Priority: 3}
  2883  	err = ps2.mergeListenerReference(ps23)
  2884  	require.NoError(t, err)
  2885  	require.Equal(t, "listener2", ps2.Listener)
  2886  	require.Equal(t, uint16(2), ps2.Priority)
  2887  
  2888  	err = ps23.mergeListenerReference(ps2)
  2889  	require.NoError(t, err)
  2890  	require.Equal(t, "listener2", ps23.Listener)
  2891  	require.Equal(t, uint16(2), ps23.Priority)
  2892  }