github.com/imran-kn/cilium-fork@v1.6.9/pkg/policy/rule.go (about) 1 // Copyright 2016-2019 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package policy 16 17 import ( 18 "bytes" 19 "fmt" 20 21 "github.com/cilium/cilium/pkg/identity" 22 "github.com/cilium/cilium/pkg/labels" 23 "github.com/cilium/cilium/pkg/lock" 24 "github.com/cilium/cilium/pkg/option" 25 "github.com/cilium/cilium/pkg/policy/api" 26 27 v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 ) 29 30 type rule struct { 31 api.Rule 32 33 metadata *ruleMetadata 34 } 35 36 type ruleMetadata struct { 37 // mutex protects all fields in this type. 38 Mutex lock.RWMutex 39 40 // IdentitySelected is a cache that maps from an identity to whether 41 // this rule selects that identity. 42 IdentitySelected map[identity.NumericIdentity]bool 43 } 44 45 func newRuleMetadata() *ruleMetadata { 46 return &ruleMetadata{ 47 IdentitySelected: make(map[identity.NumericIdentity]bool), 48 } 49 } 50 51 func (m *ruleMetadata) delete(identity *identity.Identity) { 52 m.Mutex.Lock() 53 defer m.Mutex.Unlock() 54 delete(m.IdentitySelected, identity.ID) 55 } 56 57 func (r *rule) String() string { 58 return fmt.Sprintf("%v", r.EndpointSelector) 59 } 60 61 func (l4 *L4Filter) mergeCachedSelectors(from *L4Filter, selectorCache *SelectorCache) { 62 for _, cs := range from.CachedSelectors { 63 if l4.CachedSelectors.Insert(cs) { 64 // Update selector owner to the existingFilter 65 selectorCache.ChangeUser(cs, from, l4) 66 } else { 67 // selector was already in existingFilter.CachedSelectors, release 68 selectorCache.RemoveSelector(cs, from) 69 } 70 } 71 from.CachedSelectors = nil 72 } 73 74 func mergePortProto(ctx *SearchContext, existingFilter, filterToMerge *L4Filter, selectorCache *SelectorCache) error { 75 // Handle cases where filter we are merging new rule with, new rule itself 76 // allows all traffic on L3, or both rules allow all traffic on L3. 77 if existingFilter.AllowsAllAtL3() { 78 // Case 1: existing filter selects all endpoints, which means that this filter 79 // can now simply select all endpoints. 80 // 81 // Release references held by filterToMerge.CachedSelectors 82 if !filterToMerge.HasL3DependentL7Rules() { 83 selectorCache.RemoveSelectors(filterToMerge.CachedSelectors, filterToMerge) 84 filterToMerge.CachedSelectors = nil 85 } 86 } else { 87 // Case 2: Merge selectors from filterToMerge to the existingFilter. 88 if filterToMerge.AllowsAllAtL3() { 89 // Allowing all, release selectors from existingFilter 90 if !existingFilter.HasL3DependentL7Rules() { 91 selectorCache.RemoveSelectors(existingFilter.CachedSelectors, existingFilter) 92 existingFilter.CachedSelectors = nil 93 } 94 existingFilter.allowsAllAtL3 = true 95 } 96 } 97 existingFilter.mergeCachedSelectors(filterToMerge, selectorCache) 98 99 // Merge the L7-related data from the arguments provided to this function 100 // with the existing L7-related data already in the filter. 101 if filterToMerge.L7Parser != ParserTypeNone { 102 if existingFilter.L7Parser == ParserTypeNone { 103 existingFilter.L7Parser = filterToMerge.L7Parser 104 } else if filterToMerge.L7Parser != existingFilter.L7Parser { 105 ctx.PolicyTrace(" Merge conflict: mismatching parsers %s/%s\n", filterToMerge.L7Parser, existingFilter.L7Parser) 106 return fmt.Errorf("cannot merge conflicting L7 parsers (%s/%s)", filterToMerge.L7Parser, existingFilter.L7Parser) 107 } 108 } 109 110 for cs, newL7Rules := range filterToMerge.L7RulesPerEp { 111 if l7Rules, ok := existingFilter.L7RulesPerEp[cs]; ok { 112 switch { 113 case len(newL7Rules.HTTP) > 0: 114 if len(l7Rules.Kafka) > 0 || len(l7Rules.DNS) > 0 || l7Rules.L7Proto != "" { 115 ctx.PolicyTrace(" Merge conflict: mismatching L7 rule types.\n") 116 return fmt.Errorf("cannot merge conflicting L7 rule types") 117 } 118 119 for _, newRule := range newL7Rules.HTTP { 120 if !newRule.Exists(l7Rules) { 121 l7Rules.HTTP = append(l7Rules.HTTP, newRule) 122 } 123 } 124 case len(newL7Rules.Kafka) > 0: 125 if len(l7Rules.HTTP) > 0 || len(l7Rules.DNS) > 0 || l7Rules.L7Proto != "" { 126 ctx.PolicyTrace(" Merge conflict: mismatching L7 rule types.\n") 127 return fmt.Errorf("cannot merge conflicting L7 rule types") 128 } 129 130 for _, newRule := range newL7Rules.Kafka { 131 if !newRule.Exists(l7Rules) { 132 l7Rules.Kafka = append(l7Rules.Kafka, newRule) 133 } 134 } 135 case newL7Rules.L7Proto != "": 136 if len(l7Rules.Kafka) > 0 || len(l7Rules.HTTP) > 0 || len(l7Rules.DNS) > 0 || (l7Rules.L7Proto != "" && l7Rules.L7Proto != newL7Rules.L7Proto) { 137 ctx.PolicyTrace(" Merge conflict: mismatching L7 rule types.\n") 138 return fmt.Errorf("cannot merge conflicting L7 rule types") 139 } 140 if l7Rules.L7Proto == "" { 141 l7Rules.L7Proto = newL7Rules.L7Proto 142 } 143 144 for _, newRule := range newL7Rules.L7 { 145 if !newRule.Exists(l7Rules) { 146 l7Rules.L7 = append(l7Rules.L7, newRule) 147 } 148 } 149 case len(newL7Rules.DNS) > 0: 150 if len(l7Rules.HTTP) > 0 || len(l7Rules.Kafka) > 0 || len(l7Rules.L7) > 0 { 151 ctx.PolicyTrace(" Merge conflict: mismatching L7 rule types.\n") 152 return fmt.Errorf("cannot merge conflicting L7 rule types") 153 } 154 155 for _, newRule := range newL7Rules.DNS { 156 if !newRule.Exists(l7Rules) { 157 l7Rules.DNS = append(l7Rules.DNS, newRule) 158 } 159 } 160 161 default: 162 ctx.PolicyTrace(" No L7 rules to merge.\n") 163 } 164 existingFilter.L7RulesPerEp[cs] = l7Rules 165 } else { 166 existingFilter.L7RulesPerEp[cs] = newL7Rules 167 } 168 } 169 return nil 170 } 171 172 // mergeIngressPortProto merges all rules which share the same port & protocol that 173 // select a given set of endpoints. It updates the L4Filter mapped to by the specified 174 // port and protocol with the contents of the provided PortRule. If the rule 175 // being merged has conflicting L7 rules with those already in the provided 176 // L4PolicyMap for the specified port-protocol tuple, it returns an error. 177 // 178 // If any rules contain L7 rules that select Host and we should accept 179 // all traffic from host (hostWildcardL7 == true) the L7 rules will be 180 // translated into L7 wildcards (ie, traffic will be forwarded to the 181 // proxy for endpoints matching those labels, but the proxy will allow 182 // all such traffic). 183 func mergeIngressPortProto(ctx *SearchContext, endpoints api.EndpointSelectorSlice, hostWildcardL7 bool, r api.PortRule, p api.PortProtocol, 184 proto api.L4Proto, ruleLabels labels.LabelArray, resMap L4PolicyMap, selectorCache *SelectorCache) (int, error) { 185 186 key := p.Port + "/" + string(proto) 187 existingFilter, ok := resMap[key] 188 if !ok { 189 resMap[key] = createL4IngressFilter(endpoints, hostWildcardL7, r, p, proto, ruleLabels, selectorCache) 190 return 1, nil 191 } 192 193 // Create a new L4Filter based off of the arguments provided to this function 194 // for merging with the filter which is already in the policy map. 195 filterToMerge := createL4IngressFilter(endpoints, hostWildcardL7, r, p, proto, ruleLabels, selectorCache) 196 197 if err := mergePortProto(ctx, existingFilter, filterToMerge, selectorCache); err != nil { 198 filterToMerge.detach(selectorCache) 199 return 0, err 200 } 201 existingFilter.DerivedFromRules = append(existingFilter.DerivedFromRules, ruleLabels) 202 resMap[key] = existingFilter 203 204 return 1, nil 205 } 206 207 func traceL3(ctx *SearchContext, peerEndpoints api.EndpointSelectorSlice, direction string) { 208 var result bytes.Buffer 209 210 // Requirements will be cloned into every selector, only trace them once. 211 if len(peerEndpoints[0].MatchExpressions) > 0 { 212 sel := peerEndpoints[0] 213 result.WriteString(" Enforcing requirements ") 214 result.WriteString(fmt.Sprintf("%+v", sel.MatchExpressions)) 215 result.WriteString("\n") 216 } 217 // EndpointSelector 218 for _, sel := range peerEndpoints { 219 if len(sel.MatchLabels) > 0 { 220 result.WriteString(" Allows ") 221 result.WriteString(direction) 222 result.WriteString(" labels ") 223 result.WriteString(sel.String()) 224 result.WriteString("\n") 225 } 226 } 227 ctx.PolicyTrace(result.String()) 228 } 229 230 // portRulesCoverContext determines whether L4 portions of rules cover the 231 // specified port models. 232 // 233 // Returns true if the list of ports is 0, or the rules match the ports. 234 func rulePortsCoverSearchContext(ports []api.PortProtocol, ctx *SearchContext) bool { 235 if len(ctx.DPorts) == 0 { 236 return true 237 } 238 for _, p := range ports { 239 for _, dp := range ctx.DPorts { 240 tracePort := api.PortProtocol{ 241 Port: fmt.Sprintf("%d", dp.Port), 242 Protocol: api.L4Proto(dp.Protocol), 243 } 244 if p.Covers(tracePort) { 245 return true 246 } 247 } 248 } 249 return false 250 } 251 252 func mergeIngress(ctx *SearchContext, fromEndpoints api.EndpointSelectorSlice, toPorts []api.PortRule, ruleLabels labels.LabelArray, resMap L4PolicyMap, selectorCache *SelectorCache) (int, error) { 253 found := 0 254 255 if ctx.From != nil && len(fromEndpoints) > 0 { 256 if ctx.TraceEnabled() { 257 traceL3(ctx, fromEndpoints, "from") 258 } 259 if !fromEndpoints.Matches(ctx.From) { 260 ctx.PolicyTrace(" No label match for %s", ctx.From) 261 return 0, nil 262 } 263 ctx.PolicyTrace(" Found all required labels") 264 } 265 266 // Daemon options may induce L3 allows for host/world. In this case, if 267 // we find any L7 rules matching host/world then we need to turn any L7 268 // restrictions on these endpoints into L7 allow-all so that the 269 // traffic is always allowed, but is also always redirected through the 270 // proxy 271 hostWildcardL7 := option.Config.AlwaysAllowLocalhost() 272 273 var ( 274 cnt int 275 err error 276 ) 277 278 // L3-only rule (with requirements folded into fromEndpoints). 279 if len(toPorts) == 0 && len(fromEndpoints) > 0 { 280 cnt, err = mergeIngressPortProto(ctx, fromEndpoints, hostWildcardL7, api.PortRule{}, api.PortProtocol{Port: "0", Protocol: api.ProtoAny}, api.ProtoAny, ruleLabels, resMap, selectorCache) 281 if err != nil { 282 return found, err 283 } 284 } 285 286 found += cnt 287 288 for _, r := range toPorts { 289 // For L4 Policy, an empty slice of EndpointSelector indicates that the 290 // rule allows all at L3 - explicitly specify this by creating a slice 291 // with the WildcardEndpointSelector. 292 if len(fromEndpoints) == 0 { 293 fromEndpoints = api.EndpointSelectorSlice{api.WildcardEndpointSelector} 294 } 295 296 ctx.PolicyTrace(" Allows port %v\n", r.Ports) 297 if !rulePortsCoverSearchContext(r.Ports, ctx) { 298 ctx.PolicyTrace(" No port match found\n") 299 continue 300 } 301 if r.Rules != nil && r.Rules.L7Proto != "" { 302 ctx.PolicyTrace(" l7proto: \"%s\"\n", r.Rules.L7Proto) 303 } 304 if !r.Rules.IsEmpty() { 305 for _, l7 := range r.Rules.HTTP { 306 ctx.PolicyTrace(" %+v\n", l7) 307 } 308 for _, l7 := range r.Rules.Kafka { 309 ctx.PolicyTrace(" %+v\n", l7) 310 } 311 for _, l7 := range r.Rules.L7 { 312 ctx.PolicyTrace(" %+v\n", l7) 313 } 314 } 315 316 for _, p := range r.Ports { 317 if p.Protocol != api.ProtoAny { 318 cnt, err := mergeIngressPortProto(ctx, fromEndpoints, hostWildcardL7, r, p, p.Protocol, ruleLabels, resMap, selectorCache) 319 if err != nil { 320 return found, err 321 } 322 found += cnt 323 } else { 324 cnt, err := mergeIngressPortProto(ctx, fromEndpoints, hostWildcardL7, r, p, api.ProtoTCP, ruleLabels, resMap, selectorCache) 325 if err != nil { 326 return found, err 327 } 328 found += cnt 329 330 cnt, err = mergeIngressPortProto(ctx, fromEndpoints, hostWildcardL7, r, p, api.ProtoUDP, ruleLabels, resMap, selectorCache) 331 if err != nil { 332 return found, err 333 } 334 found += cnt 335 } 336 } 337 } 338 339 return found, nil 340 } 341 342 func (state *traceState) selectRule(ctx *SearchContext, r *rule) { 343 ctx.PolicyTrace("* Rule %s: selected\n", r) 344 state.selectedRules++ 345 } 346 347 func (state *traceState) unSelectRule(ctx *SearchContext, labels labels.LabelArray, r *rule) { 348 ctx.PolicyTraceVerbose(" Rule %s: did not select %+v\n", r, labels) 349 } 350 351 // resolveIngressPolicy analyzes the rule against the given SearchContext, and 352 // merges it with any prior-generated policy within the provided L4Policy. 353 // Requirements based off of all Ingress requirements (set in FromRequires) in 354 // other rules are stored in the specified slice of LabelSelectorRequirement. 355 // These requirements are dynamically inserted into a copy of the receiver rule, 356 // as requirements form conjunctions across all rules. 357 func (r *rule) resolveIngressPolicy(ctx *SearchContext, state *traceState, result L4PolicyMap, requirements []v1.LabelSelectorRequirement, selectorCache *SelectorCache) (L4PolicyMap, error) { 358 if !ctx.rulesSelect { 359 if !r.EndpointSelector.Matches(ctx.To) { 360 state.unSelectRule(ctx, ctx.To, r) 361 return nil, nil 362 } 363 } 364 365 state.selectRule(ctx, r) 366 found := 0 367 368 if len(r.Ingress) == 0 { 369 ctx.PolicyTrace(" No ingress rules\n") 370 } 371 for _, ingressRule := range r.Ingress { 372 fromEndpoints := ingressRule.GetSourceEndpointSelectorsWithRequirements(requirements) 373 cnt, err := mergeIngress(ctx, fromEndpoints, ingressRule.ToPorts, r.Rule.Labels.DeepCopy(), result, selectorCache) 374 if err != nil { 375 return nil, err 376 } 377 if cnt > 0 { 378 found += cnt 379 } 380 } 381 382 if found > 0 { 383 return result, nil 384 } 385 386 return nil, nil 387 } 388 389 // ********************** CIDR POLICY ********************** 390 391 // mergeCIDR inserts all of the CIDRs in ipRules to resMap. Returns the number 392 // of CIDRs added to resMap. 393 func mergeCIDR(ctx *SearchContext, dir string, ipRules []api.CIDR, ruleLabels labels.LabelArray, resMap *CIDRPolicyMap) int { 394 found := 0 395 396 for _, r := range ipRules { 397 strCIDR := string(r) 398 ctx.PolicyTrace(" Allows %s IP %s\n", dir, strCIDR) 399 400 found += resMap.Insert(strCIDR, ruleLabels) 401 } 402 403 return found 404 } 405 406 // resolveCIDRPolicy inserts the CIDRs from the specified rule into result if 407 // the rule corresponds to the current SearchContext. It returns the resultant 408 // CIDRPolicy containing the added ingress and egress CIDRs. If no CIDRs are 409 // added to result, a nil CIDRPolicy is returned. 410 func (r *rule) resolveCIDRPolicy(ctx *SearchContext, state *traceState, result *CIDRPolicy) *CIDRPolicy { 411 // Don't select rule if it doesn't apply to the given context. 412 if !ctx.rulesSelect { 413 if !r.EndpointSelector.Matches(ctx.To) { 414 state.unSelectRule(ctx, ctx.To, r) 415 return nil 416 } 417 } 418 419 state.selectRule(ctx, r) 420 found := 0 421 422 for _, ingressRule := range r.Ingress { 423 // TODO (ianvernon): GH-1658 424 var allCIDRs []api.CIDR 425 allCIDRs = append(allCIDRs, ingressRule.FromCIDR...) 426 allCIDRs = append(allCIDRs, api.ComputeResultantCIDRSet(ingressRule.FromCIDRSet)...) 427 428 // CIDR + L4 rules are handled via mergeIngress(), 429 // skip them here. 430 if len(allCIDRs) > 0 && len(ingressRule.ToPorts) > 0 { 431 continue 432 } 433 434 if cnt := mergeCIDR(ctx, "Ingress", allCIDRs, r.Labels, &result.Ingress); cnt > 0 { 435 found += cnt 436 } 437 } 438 439 // CIDR egress policy is used for visibility of desired state in 440 // the API and for determining which prefix lengths are available, 441 // however it does not determine the actual CIDRs in the BPF maps 442 // for allowing traffic by CIDR! 443 for _, egressRule := range r.Egress { 444 var allCIDRs []api.CIDR 445 allCIDRs = append(allCIDRs, egressRule.ToCIDR...) 446 allCIDRs = append(allCIDRs, api.ComputeResultantCIDRSet(egressRule.ToCIDRSet)...) 447 448 // Unlike the Ingress policy which only counts L3 policy in 449 // this function, we count the CIDR+L4 policy in the 450 // desired egress CIDR policy here as well. This ensures 451 // proper computation of IPcache prefix lengths. 452 if cnt := mergeCIDR(ctx, "Egress", allCIDRs, r.Labels, &result.Egress); cnt > 0 { 453 found += cnt 454 } 455 } 456 457 if found > 0 { 458 return result 459 } 460 461 ctx.PolicyTrace(" No L3 rules\n") 462 return nil 463 } 464 465 func (r *rule) matches(securityIdentity *identity.Identity) bool { 466 r.metadata.Mutex.Lock() 467 defer r.metadata.Mutex.Unlock() 468 var ruleMatches bool 469 470 if ruleMatches, cached := r.metadata.IdentitySelected[securityIdentity.ID]; cached { 471 return ruleMatches 472 } 473 // Fall back to costly matching. 474 if ruleMatches = r.EndpointSelector.Matches(securityIdentity.LabelArray); ruleMatches { 475 // Update cache so we don't have to do costly matching again. 476 r.metadata.IdentitySelected[securityIdentity.ID] = true 477 } else { 478 r.metadata.IdentitySelected[securityIdentity.ID] = false 479 } 480 481 return ruleMatches 482 } 483 484 // ****************** EGRESS POLICY ****************** 485 486 func mergeEgress(ctx *SearchContext, toEndpoints api.EndpointSelectorSlice, toPorts []api.PortRule, ruleLabels labels.LabelArray, resMap L4PolicyMap, selectorCache *SelectorCache, fqdns api.FQDNSelectorSlice) (int, error) { 487 found := 0 488 489 if ctx.To != nil && len(toEndpoints) > 0 { 490 if ctx.TraceEnabled() { 491 traceL3(ctx, toEndpoints, "to") 492 } 493 if !toEndpoints.Matches(ctx.To) { 494 ctx.PolicyTrace(" No label match for %s", ctx.To) 495 return 0, nil 496 } 497 ctx.PolicyTrace(" Found all required labels") 498 } 499 500 var ( 501 cnt int 502 err error 503 ) 504 505 // L3-only rule (with requirements folded into toEndpoints). 506 if len(toPorts) == 0 && len(toEndpoints) > 0 { 507 cnt, err = mergeEgressPortProto(ctx, toEndpoints, api.PortRule{}, api.PortProtocol{Port: "0", Protocol: api.ProtoAny}, api.ProtoAny, ruleLabels, resMap, selectorCache, fqdns) 508 if err != nil { 509 return found, err 510 } 511 } 512 513 found += cnt 514 515 for _, r := range toPorts { 516 // For L4 Policy, an empty slice of EndpointSelector indicates that the 517 // rule allows all at L3 - explicitly specify this by creating a slice 518 // with the WildcardEndpointSelector. 519 if len(toEndpoints) == 0 { 520 toEndpoints = api.EndpointSelectorSlice{api.WildcardEndpointSelector} 521 } 522 ctx.PolicyTrace(" Allows port %v\n", r.Ports) 523 if r.Rules != nil && r.Rules.L7Proto != "" { 524 ctx.PolicyTrace(" l7proto: \"%s\"\n", r.Rules.L7Proto) 525 } 526 if !r.Rules.IsEmpty() { 527 for _, l7 := range r.Rules.HTTP { 528 ctx.PolicyTrace(" %+v\n", l7) 529 } 530 for _, l7 := range r.Rules.Kafka { 531 ctx.PolicyTrace(" %+v\n", l7) 532 } 533 for _, l7 := range r.Rules.L7 { 534 ctx.PolicyTrace(" %+v\n", l7) 535 } 536 } 537 538 for _, p := range r.Ports { 539 if p.Protocol != api.ProtoAny { 540 cnt, err := mergeEgressPortProto(ctx, toEndpoints, r, p, p.Protocol, ruleLabels, resMap, selectorCache, fqdns) 541 if err != nil { 542 return found, err 543 } 544 found += cnt 545 } else { 546 cnt, err := mergeEgressPortProto(ctx, toEndpoints, r, p, api.ProtoTCP, ruleLabels, resMap, selectorCache, fqdns) 547 if err != nil { 548 return found, err 549 } 550 found += cnt 551 552 cnt, err = mergeEgressPortProto(ctx, toEndpoints, r, p, api.ProtoUDP, ruleLabels, resMap, selectorCache, fqdns) 553 if err != nil { 554 return found, err 555 } 556 found += cnt 557 } 558 } 559 } 560 561 return found, nil 562 } 563 564 // mergeEgressPortProto merges all rules which share the same port & protocol that 565 // select a given set of endpoints. It updates the L4Filter mapped to by the specified 566 // port and protocol with the contents of the provided PortRule. If the rule 567 // being merged has conflicting L7 rules with those already in the provided 568 // L4PolicyMap for the specified port-protocol tuple, it returns an error. 569 func mergeEgressPortProto(ctx *SearchContext, endpoints api.EndpointSelectorSlice, r api.PortRule, p api.PortProtocol, 570 proto api.L4Proto, ruleLabels labels.LabelArray, resMap L4PolicyMap, selectorCache *SelectorCache, fqdns api.FQDNSelectorSlice) (int, error) { 571 572 key := p.Port + "/" + string(proto) 573 existingFilter, ok := resMap[key] 574 if !ok { 575 resMap[key] = createL4EgressFilter(endpoints, r, p, proto, ruleLabels, selectorCache, fqdns) 576 return 1, nil 577 } 578 579 // Create a new L4Filter based off of the arguments provided to this function 580 // for merging with the filter which is already in the policy map. 581 filterToMerge := createL4EgressFilter(endpoints, r, p, proto, ruleLabels, selectorCache, fqdns) 582 583 if err := mergePortProto(ctx, existingFilter, filterToMerge, selectorCache); err != nil { 584 filterToMerge.detach(selectorCache) 585 return 0, err 586 } 587 existingFilter.DerivedFromRules = append(existingFilter.DerivedFromRules, ruleLabels) 588 resMap[key] = existingFilter 589 return 1, nil 590 } 591 592 func (r *rule) resolveEgressPolicy(ctx *SearchContext, state *traceState, result L4PolicyMap, requirements []v1.LabelSelectorRequirement, selectorCache *SelectorCache) (L4PolicyMap, error) { 593 if !ctx.rulesSelect { 594 if !r.EndpointSelector.Matches(ctx.From) { 595 state.unSelectRule(ctx, ctx.From, r) 596 return nil, nil 597 } 598 } 599 600 state.selectRule(ctx, r) 601 found := 0 602 603 if len(r.Egress) == 0 { 604 ctx.PolicyTrace(" No L4 rules\n") 605 } 606 for _, egressRule := range r.Egress { 607 toEndpoints := egressRule.GetDestinationEndpointSelectorsWithRequirements(requirements) 608 cnt, err := mergeEgress(ctx, toEndpoints, egressRule.ToPorts, r.Rule.Labels.DeepCopy(), result, selectorCache, egressRule.ToFQDNs) 609 if err != nil { 610 return nil, err 611 } 612 if cnt > 0 { 613 found += cnt 614 } 615 } 616 617 if found > 0 { 618 return result, nil 619 } 620 621 return nil, nil 622 }