github.com/imran-kn/cilium-fork@v1.6.9/pkg/policy/l4.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 "encoding/json" 20 "fmt" 21 "sort" 22 "strconv" 23 "sync/atomic" 24 "unsafe" 25 26 "github.com/cilium/cilium/api/v1/models" 27 "github.com/cilium/cilium/pkg/identity" 28 "github.com/cilium/cilium/pkg/labels" 29 "github.com/cilium/cilium/pkg/lock" 30 "github.com/cilium/cilium/pkg/logging/logfields" 31 "github.com/cilium/cilium/pkg/policy/api" 32 "github.com/cilium/cilium/pkg/policy/trafficdirection" 33 "github.com/cilium/cilium/pkg/u8proto" 34 35 "github.com/sirupsen/logrus" 36 ) 37 38 // L7DataMap contains a map of L7 rules per endpoint where key is a CachedSelector 39 type L7DataMap map[CachedSelector]api.L7Rules 40 41 func (l7 L7DataMap) MarshalJSON() ([]byte, error) { 42 if len(l7) == 0 { 43 return []byte("[]"), nil 44 } 45 46 /* First, create a sorted slice of the selectors so we can get 47 * consistent JSON output */ 48 selectors := make(CachedSelectorSlice, 0, len(l7)) 49 for cs := range l7 { 50 selectors = append(selectors, cs) 51 } 52 sort.Sort(selectors) 53 54 /* Now we can iterate the slice and generate JSON entries. */ 55 var err error 56 buffer := bytes.NewBufferString("[") 57 for _, cs := range selectors { 58 buffer.WriteString("{\"") 59 buffer.WriteString(cs.String()) 60 buffer.WriteString("\":") 61 b, err := json.Marshal(l7[cs]) 62 if err == nil { 63 buffer.Write(b) 64 } else { 65 buffer.WriteString("\"L7DataMap error: ") 66 buffer.WriteString(err.Error()) 67 buffer.WriteString("\"") 68 } 69 buffer.WriteString("},") 70 } 71 buffer.Truncate(buffer.Len() - 1) // Drop the final "," 72 buffer.WriteString("]") 73 74 return buffer.Bytes(), err 75 } 76 77 // L7ParserType is the type used to indicate what L7 parser to use. 78 // Consts are defined for all well known L7 parsers. 79 // Unknown string values are created for key-value pair policies, which 80 // are then transparently used in redirect configuration. 81 type L7ParserType string 82 83 func (l7 L7ParserType) String() string { 84 return (string)(l7) 85 } 86 87 const ( 88 // ParserTypeNone represents the case where no parser type is provided. 89 ParserTypeNone L7ParserType = "" 90 // ParserTypeHTTP specifies a HTTP parser type 91 ParserTypeHTTP L7ParserType = "http" 92 // ParserTypeKafka specifies a Kafka parser type 93 ParserTypeKafka L7ParserType = "kafka" 94 // ParserTypeDNS specifies a DNS parser type 95 ParserTypeDNS L7ParserType = "dns" 96 ) 97 98 // L4Filter represents the policy (allowed remote sources / destinations of 99 // traffic) that applies at a specific L4 port/protocol combination (including 100 // all ports and protocols), at either ingress or egress. The policy here is 101 // specified in terms of selectors that are mapped to security identities via 102 // the selector cache. 103 type L4Filter struct { 104 // Port is the destination port to allow. Port 0 indicates that all traffic 105 // is allowed at L4. 106 Port int `json:"port"` 107 // Protocol is the L4 protocol to allow or NONE 108 Protocol api.L4Proto `json:"protocol"` 109 // U8Proto is the Protocol in numeric format, or 0 for NONE 110 U8Proto u8proto.U8proto `json:"-"` 111 // allowsAllAtL3 indicates whether this filter allows all traffic at L3. 112 // This can be determined by checking whether 'Endpoints' contains 113 // 'wildcardCachedSelector', but caching this information instead is 114 // much more performant. 115 allowsAllAtL3 bool 116 // CachedSelectors limits the labels for allowing traffic (to / from). 117 // This includes selectors for destinations affected by entity-based 118 // and CIDR-based policy. 119 // Holds references to the CachedSelectors, which must be released! 120 CachedSelectors CachedSelectorSlice `json:"-"` 121 // L7Parser specifies the L7 protocol parser (optional). If specified as 122 // an empty string, then means that no L7 proxy redirect is performed. 123 L7Parser L7ParserType `json:"-"` 124 // L7RulesPerEp is a list of L7 rules per endpoint passed to the L7 proxy (optional) 125 L7RulesPerEp L7DataMap `json:"l7-rules,omitempty"` 126 // Ingress is true if filter applies at ingress; false if it applies at egress. 127 Ingress bool `json:"-"` 128 // The rule labels of this Filter 129 DerivedFromRules labels.LabelArrayList `json:"-"` 130 131 // This reference is circular, but it is cleaned up at Detach() 132 policy unsafe.Pointer // *L4Policy 133 } 134 135 // AllowsAllAtL3 returns whether this L4Filter applies to all endpoints at L3. 136 func (l4 *L4Filter) AllowsAllAtL3() bool { 137 return l4.allowsAllAtL3 138 } 139 140 // HasL3DependentL7Rules returns true if this L4Filter is created from rules 141 // that require an L3 match as well as specific L7 rules. 142 func (l4 *L4Filter) HasL3DependentL7Rules() bool { 143 switch len(l4.L7RulesPerEp) { 144 case 0: 145 // No L7 rules. 146 return false 147 case 1: 148 // loop to get access to the first and only key in the map 149 for cs := range l4.L7RulesPerEp { 150 // If L3 is wildcarded, this filter corresponds to L4-only rule(s). 151 return !cs.IsWildcard() 152 } 153 } 154 return true 155 } 156 157 // ToKeys converts filter into a list of Keys. 158 func (l4 *L4Filter) ToKeys(direction trafficdirection.TrafficDirection) []Key { 159 keysToAdd := []Key{} 160 port := uint16(l4.Port) 161 proto := uint8(l4.U8Proto) 162 163 if l4.AllowsAllAtL3() { 164 if l4.Port == 0 { 165 // Allow-all 166 log.WithFields(logrus.Fields{ 167 logfields.TrafficDirection: direction, 168 }).Debug("ToKeys: allow all") 169 170 keyToAdd := Key{ 171 DestPort: 0, 172 Nexthdr: 0, 173 TrafficDirection: direction.Uint8(), 174 } 175 keysToAdd = append(keysToAdd, keyToAdd) 176 } else { 177 // L4 allow 178 log.WithFields(logrus.Fields{ 179 logfields.Port: port, 180 logfields.Protocol: proto, 181 logfields.TrafficDirection: direction, 182 }).Debug("ToKeys: L4 allow all") 183 184 keyToAdd := Key{ 185 Identity: 0, 186 // NOTE: Port is in host byte-order! 187 DestPort: port, 188 Nexthdr: proto, 189 TrafficDirection: direction.Uint8(), 190 } 191 keysToAdd = append(keysToAdd, keyToAdd) 192 } 193 if !l4.HasL3DependentL7Rules() { 194 return keysToAdd 195 } // else we need to calculate all L3-dependent L4 peers below. 196 } 197 198 for _, cs := range l4.CachedSelectors { 199 identities := cs.GetSelections() 200 log.WithFields(logrus.Fields{ 201 logfields.TrafficDirection: direction, 202 logfields.EndpointSelector: cs, 203 logfields.PolicyID: identities, 204 }).Debug("ToKeys: Allowed remote IDs") 205 for _, id := range identities { 206 srcID := id.Uint32() 207 keyToAdd := Key{ 208 Identity: srcID, 209 // NOTE: Port is in host byte-order! 210 DestPort: port, 211 Nexthdr: proto, 212 TrafficDirection: direction.Uint8(), 213 } 214 keysToAdd = append(keysToAdd, keyToAdd) 215 } 216 } 217 218 return keysToAdd 219 } 220 221 // IdentitySelectionUpdated implements CachedSelectionUser interface 222 // This call is made while holding name manager and selector cache 223 // locks, must beware of deadlocking! 224 // 225 // The caller is responsible for making sure the same identity is not 226 // present in both 'added' and 'deleted'. 227 func (l4 *L4Filter) IdentitySelectionUpdated(selector CachedSelector, selections, added, deleted []identity.NumericIdentity) { 228 log.WithFields(logrus.Fields{ 229 logfields.EndpointSelector: selector, 230 logfields.PolicyID: selections, 231 logfields.AddedPolicyID: added, 232 logfields.DeletedPolicyID: deleted, 233 }).Debug("identities selected by L4Filter updated") 234 235 // Skip updates on filter that wildcards L3. 236 // This logic mirrors the one in ToKeys(). 237 if l4.AllowsAllAtL3() && !l4.HasL3DependentL7Rules() { 238 return 239 } 240 241 // Push endpoint policy changes. 242 // 243 // `l4.policy` is set to nil when the filter is detached so 244 // that we could not push updates on a stale policy. 245 l4Policy := (*L4Policy)(atomic.LoadPointer(&l4.policy)) 246 if l4Policy != nil { 247 direction := trafficdirection.Egress 248 if l4.Ingress { 249 direction = trafficdirection.Ingress 250 } 251 l4Policy.AccumulateMapChanges(added, deleted, uint16(l4.Port), uint8(l4.U8Proto), direction) 252 } 253 } 254 255 func (l4 *L4Filter) cacheIdentitySelector(sel api.EndpointSelector, selectorCache *SelectorCache) CachedSelector { 256 cs, added := selectorCache.AddIdentitySelector(l4, sel) 257 if added { 258 l4.CachedSelectors = append(l4.CachedSelectors, cs) 259 } 260 return cs 261 } 262 263 func (l4 *L4Filter) cacheIdentitySelectors(selectors api.EndpointSelectorSlice, selectorCache *SelectorCache) { 264 for _, sel := range selectors { 265 l4.cacheIdentitySelector(sel, selectorCache) 266 } 267 } 268 269 func (l4 *L4Filter) cacheFQDNSelectors(selectors api.FQDNSelectorSlice, selectorCache *SelectorCache) { 270 for _, fqdnSel := range selectors { 271 l4.cacheFQDNSelector(fqdnSel, selectorCache) 272 } 273 } 274 275 func (l4 *L4Filter) cacheFQDNSelector(sel api.FQDNSelector, selectorCache *SelectorCache) CachedSelector { 276 cs, added := selectorCache.AddFQDNSelector(l4, sel) 277 if added { 278 l4.CachedSelectors = append(l4.CachedSelectors, cs) 279 } 280 return cs 281 } 282 283 // GetRelevantRulesForKafka returns the relevant rules based on the remote numeric identity. 284 func (l7 L7DataMap) GetRelevantRulesForKafka(nid identity.NumericIdentity) []api.PortRuleKafka { 285 var rules []api.PortRuleKafka 286 287 for cs, r := range l7 { 288 if cs.IsWildcard() || cs.Selects(nid) { 289 rules = append(rules, r.Kafka...) 290 } 291 } 292 return rules 293 } 294 295 func (l7 L7DataMap) addRulesForEndpoints(rules api.L7Rules, endpoints []CachedSelector) { 296 if rules.Len() == 0 { 297 return 298 } 299 300 for _, epsel := range endpoints { 301 l7[epsel] = rules 302 } 303 } 304 305 // createL4Filter creates a filter for L4 policy that applies to the specified 306 // endpoints and port/protocol, with reference to the original rules that the 307 // filter is derived from. This filter may be associated with a series of L7 308 // rules via the `rule` parameter. 309 // Not called with an empty peerEndpoints. 310 func createL4Filter(peerEndpoints api.EndpointSelectorSlice, rule api.PortRule, port api.PortProtocol, 311 protocol api.L4Proto, ruleLabels labels.LabelArray, ingress bool, selectorCache *SelectorCache, fqdns api.FQDNSelectorSlice) *L4Filter { 312 313 // already validated via PortRule.Validate() 314 p, _ := strconv.ParseUint(port.Port, 0, 16) 315 // already validated via L4Proto.Validate() 316 u8p, _ := u8proto.ParseProtocol(string(protocol)) 317 318 l4 := &L4Filter{ 319 Port: int(p), 320 Protocol: protocol, 321 U8Proto: u8p, 322 L7RulesPerEp: make(L7DataMap), 323 DerivedFromRules: labels.LabelArrayList{ruleLabels}, 324 Ingress: ingress, 325 } 326 327 if peerEndpoints.SelectsAllEndpoints() { 328 l4.cacheIdentitySelector(api.WildcardEndpointSelector, selectorCache) 329 l4.allowsAllAtL3 = true 330 } else { 331 l4.CachedSelectors = make(CachedSelectorSlice, 0, len(peerEndpoints)) 332 l4.cacheIdentitySelectors(peerEndpoints, selectorCache) 333 l4.cacheFQDNSelectors(fqdns, selectorCache) 334 } 335 336 if protocol == api.ProtoTCP && rule.Rules != nil { 337 switch { 338 case len(rule.Rules.HTTP) > 0: 339 l4.L7Parser = ParserTypeHTTP 340 case len(rule.Rules.Kafka) > 0: 341 l4.L7Parser = ParserTypeKafka 342 case rule.Rules.L7Proto != "": 343 l4.L7Parser = (L7ParserType)(rule.Rules.L7Proto) 344 } 345 if !rule.Rules.IsEmpty() { 346 l4.L7RulesPerEp.addRulesForEndpoints(*rule.Rules, l4.CachedSelectors) 347 } 348 } 349 350 // we need this to redirect DNS UDP (or ANY, which is more useful) 351 if !rule.Rules.IsEmpty() && len(rule.Rules.DNS) > 0 { 352 l4.L7Parser = ParserTypeDNS 353 l4.L7RulesPerEp.addRulesForEndpoints(*rule.Rules, l4.CachedSelectors) 354 } 355 356 return l4 357 } 358 359 // detach releases the references held in the L4Filter and must be called before 360 // the filter is left to be garbage collected. 361 func (l4 *L4Filter) detach(selectorCache *SelectorCache) { 362 selectorCache.RemoveSelectors(l4.CachedSelectors, l4) 363 l4.attach(nil) 364 } 365 366 func (l4 *L4Filter) attach(l4Policy *L4Policy) { 367 atomic.StorePointer(&l4.policy, unsafe.Pointer(l4Policy)) 368 } 369 370 // createL4IngressFilter creates a filter for L4 policy that applies to the 371 // specified endpoints and port/protocol for ingress traffic, with reference 372 // to the original rules that the filter is derived from. This filter may be 373 // associated with a series of L7 rules via the `rule` parameter. 374 // 375 // hostWildcardL7 determines if L7 traffic from Host should be 376 // wildcarded (in the relevant daemon mode). 377 func createL4IngressFilter(fromEndpoints api.EndpointSelectorSlice, hostWildcardL7 bool, rule api.PortRule, port api.PortProtocol, 378 protocol api.L4Proto, ruleLabels labels.LabelArray, selectorCache *SelectorCache) *L4Filter { 379 380 filter := createL4Filter(fromEndpoints, rule, port, protocol, ruleLabels, true, selectorCache, nil) 381 382 // If the filter would apply L7 rules for the Host, when we should accept everything from host, 383 // then wildcard Host at L7. 384 if !rule.Rules.IsEmpty() && hostWildcardL7 { 385 for _, cs := range filter.CachedSelectors { 386 if cs.Selects(identity.ReservedIdentityHost) { 387 hostSelector := api.ReservedEndpointSelectors[labels.IDNameHost] 388 hcs := filter.cacheIdentitySelector(hostSelector, selectorCache) 389 filter.L7RulesPerEp[hcs] = api.L7Rules{} 390 } 391 } 392 } 393 394 return filter 395 } 396 397 // createL4EgressFilter creates a filter for L4 policy that applies to the 398 // specified endpoints and port/protocol for egress traffic, with reference 399 // to the original rules that the filter is derived from. This filter may be 400 // associated with a series of L7 rules via the `rule` parameter. 401 func createL4EgressFilter(toEndpoints api.EndpointSelectorSlice, rule api.PortRule, port api.PortProtocol, 402 protocol api.L4Proto, ruleLabels labels.LabelArray, selectorCache *SelectorCache, fqdns api.FQDNSelectorSlice) *L4Filter { 403 404 return createL4Filter(toEndpoints, rule, port, protocol, ruleLabels, false, selectorCache, fqdns) 405 } 406 407 // IsRedirect returns true if the L4 filter contains a port redirection 408 func (l4 *L4Filter) IsRedirect() bool { 409 return l4.L7Parser != ParserTypeNone 410 } 411 412 // IsEnvoyRedirect returns true if the L4 filter contains a port redirected to Envoy 413 func (l4 *L4Filter) IsEnvoyRedirect() bool { 414 return l4.IsRedirect() && l4.L7Parser != ParserTypeKafka && l4.L7Parser != ParserTypeDNS 415 } 416 417 // IsProxylibRedirect returns true if the L4 filter contains a port redirected to Proxylib (via Envoy) 418 func (l4 *L4Filter) IsProxylibRedirect() bool { 419 return l4.IsEnvoyRedirect() && l4.L7Parser != ParserTypeHTTP 420 } 421 422 // MarshalIndent returns the `L4Filter` in indented JSON string. 423 func (l4 *L4Filter) MarshalIndent() string { 424 b, err := json.MarshalIndent(l4, "", " ") 425 if err != nil { 426 b = []byte("\"L4Filter error: " + err.Error() + "\"") 427 } 428 return string(b) 429 } 430 431 // String returns the `L4Filter` in a human-readable string. 432 func (l4 *L4Filter) String() string { 433 b, err := json.Marshal(l4) 434 if err != nil { 435 return err.Error() 436 } 437 return string(b) 438 } 439 440 // Note: Only used for policy tracing 441 func (l4 *L4Filter) matchesLabels(labels labels.LabelArray) bool { 442 if l4.AllowsAllAtL3() { 443 return true 444 } else if len(labels) == 0 { 445 return false 446 } 447 448 for _, sel := range l4.CachedSelectors { 449 // slow, but OK for tracing 450 if idSel, ok := sel.(*labelIdentitySelector); ok && idSel.xxxMatches(labels) { 451 return true 452 } 453 } 454 455 return false 456 } 457 458 // L4PolicyMap is a list of L4 filters indexable by protocol/port 459 // key format: "port/proto" 460 type L4PolicyMap map[string]*L4Filter 461 462 // Detach removes the cached selectors held by L4PolicyMap from the 463 // selectorCache, allowing the map to be garbage collected when there 464 // are no more references to it. 465 func (l4 L4PolicyMap) Detach(selectorCache *SelectorCache) { 466 for _, f := range l4 { 467 f.detach(selectorCache) 468 } 469 } 470 471 // Attach makes all the L4Filters to point back to the L4Policy that contains them. 472 func (l4 L4PolicyMap) Attach(l4Policy *L4Policy) { 473 for _, f := range l4 { 474 f.attach(l4Policy) 475 } 476 } 477 478 // HasRedirect returns true if at least one L4 filter contains a port 479 // redirection 480 func (l4 L4PolicyMap) HasRedirect() bool { 481 for _, f := range l4 { 482 if f.IsRedirect() { 483 return true 484 } 485 } 486 return false 487 } 488 489 // HasEnvoyRedirect returns true if at least one L4 filter contains a port 490 // redirection that is forwarded to Envoy 491 func (l4 L4PolicyMap) HasEnvoyRedirect() bool { 492 for _, f := range l4 { 493 if f.IsEnvoyRedirect() { 494 return true 495 } 496 } 497 return false 498 } 499 500 // HasProxylibRedirect returns true if at least one L4 filter contains a port 501 // redirection that is forwarded to Proxylib (via Envoy) 502 func (l4 L4PolicyMap) HasProxylibRedirect() bool { 503 for _, f := range l4 { 504 if f.IsProxylibRedirect() { 505 return true 506 } 507 } 508 return false 509 } 510 511 // containsAllL3L4 checks if the L4PolicyMap contains all L4 ports in `ports`. 512 // For L4Filters that specify ToEndpoints or FromEndpoints, uses `labels` to 513 // determine whether the policy allows L4 communication between the corresponding 514 // endpoints. 515 // Returns api.Denied in the following conditions: 516 // * If a single port is not present in the `L4PolicyMap` and is not allowed 517 // by the distilled L3 policy 518 // * If a port is present in the `L4PolicyMap`, but it applies ToEndpoints or 519 // FromEndpoints constraints that require labels not present in `labels`. 520 // Otherwise, returns api.Allowed. 521 // 522 // Note: Only used for policy tracing 523 func (l4 L4PolicyMap) containsAllL3L4(labels labels.LabelArray, ports []*models.Port) api.Decision { 524 if len(l4) == 0 { 525 return api.Allowed 526 } 527 528 // Check L3-only filters first. 529 filter, match := l4[api.PortProtocolAny] 530 if match && filter.matchesLabels(labels) { 531 return api.Allowed 532 } 533 534 for _, l4Ctx := range ports { 535 lwrProtocol := l4Ctx.Protocol 536 switch lwrProtocol { 537 case "", models.PortProtocolANY: 538 tcpPort := fmt.Sprintf("%d/TCP", l4Ctx.Port) 539 tcpFilter, tcpmatch := l4[tcpPort] 540 if tcpmatch { 541 tcpmatch = tcpFilter.matchesLabels(labels) 542 } 543 udpPort := fmt.Sprintf("%d/UDP", l4Ctx.Port) 544 udpFilter, udpmatch := l4[udpPort] 545 if udpmatch { 546 udpmatch = udpFilter.matchesLabels(labels) 547 } 548 if !tcpmatch && !udpmatch { 549 return api.Denied 550 } 551 default: 552 port := fmt.Sprintf("%d/%s", l4Ctx.Port, lwrProtocol) 553 filter, match := l4[port] 554 if !match || !filter.matchesLabels(labels) { 555 return api.Denied 556 } 557 } 558 } 559 return api.Allowed 560 } 561 562 type L4Policy struct { 563 Ingress L4PolicyMap 564 Egress L4PolicyMap 565 566 // Revision is the repository revision used to generate this policy. 567 Revision uint64 568 569 // Endpoint policies using this L4Policy 570 // These are circular references, cleaned up in Detach() 571 mutex lock.RWMutex 572 users map[*EndpointPolicy]struct{} 573 } 574 575 // NewL4Policy creates a new L4Policy 576 func NewL4Policy(revision uint64) *L4Policy { 577 return &L4Policy{ 578 Ingress: L4PolicyMap{}, 579 Egress: L4PolicyMap{}, 580 Revision: revision, 581 users: make(map[*EndpointPolicy]struct{}), 582 } 583 } 584 585 // insertUser adds a user to the L4Policy so that incremental 586 // updates of the L4Policy may be forwarded to the users of it. 587 func (l4 *L4Policy) insertUser(user *EndpointPolicy) { 588 l4.mutex.Lock() 589 590 // 'users' is set to nil when the policy is detached. This 591 // happens to the old policy when it is being replaced with a 592 // new one, or when the last endpoint using this policy is 593 // removed. 594 // In the case of an policy update it is possible that an 595 // endpoint has started regeneration before the policy was 596 // updated, and that the policy was updated before the said 597 // endpoint reached this point. In this case the endpoint's 598 // policy is going to be recomputed soon after and we do 599 // nothing here. 600 if l4.users != nil { 601 l4.users[user] = struct{}{} 602 } 603 604 l4.mutex.Unlock() 605 } 606 607 // AccumulateMapChanges distributes the given changes to the registered users. 608 // 609 // The caller is responsible for making sure the same identity is not 610 // present in both 'adds' and 'deletes'. 611 func (l4 *L4Policy) AccumulateMapChanges(adds, deletes []identity.NumericIdentity, 612 port uint16, proto uint8, direction trafficdirection.TrafficDirection) { 613 l4.mutex.RLock() 614 for epPolicy := range l4.users { 615 epPolicy.PolicyMapChanges.AccumulateMapChanges(adds, deletes, port, proto, direction) 616 } 617 l4.mutex.RUnlock() 618 } 619 620 // Detach makes the L4Policy ready for garbage collection, removing 621 // circular pointer references. 622 // Note that the L4Policy itself is not modified in any way, so that it may still 623 // be used concurrently. 624 func (l4 *L4Policy) Detach(selectorCache *SelectorCache) { 625 l4.Ingress.Detach(selectorCache) 626 l4.Egress.Detach(selectorCache) 627 628 l4.mutex.Lock() 629 l4.users = nil 630 l4.mutex.Unlock() 631 } 632 633 // Attach makes all the L4Filters to point back to the L4Policy that contains them. 634 // This is done before the L4Policy is exposed to concurrent access. 635 func (l4 *L4Policy) Attach() { 636 l4.Ingress.Attach(l4) 637 l4.Egress.Attach(l4) 638 } 639 640 // IngressCoversContext checks if the receiver's ingress L4Policy contains 641 // all `dPorts` and `labels`. 642 // 643 // Note: Only used for policy tracing 644 func (l4 *L4PolicyMap) IngressCoversContext(ctx *SearchContext) api.Decision { 645 return l4.containsAllL3L4(ctx.From, ctx.DPorts) 646 } 647 648 // EgressCoversContext checks if the receiver's egress L4Policy contains 649 // all `dPorts` and `labels`. 650 // 651 // Note: Only used for policy tracing 652 func (l4 *L4PolicyMap) EgressCoversContext(ctx *SearchContext) api.Decision { 653 return l4.containsAllL3L4(ctx.To, ctx.DPorts) 654 } 655 656 // HasRedirect returns true if the L4 policy contains at least one port redirection 657 func (l4 *L4Policy) HasRedirect() bool { 658 return l4 != nil && (l4.Ingress.HasRedirect() || l4.Egress.HasRedirect()) 659 } 660 661 // HasEnvoyRedirect returns true if the L4 policy contains at least one port redirection to Envoy 662 func (l4 *L4Policy) HasEnvoyRedirect() bool { 663 return l4 != nil && (l4.Ingress.HasEnvoyRedirect() || l4.Egress.HasEnvoyRedirect()) 664 } 665 666 // HasProxylibRedirect returns true if the L4 policy contains at least one port redirection to Proxylib 667 func (l4 *L4Policy) HasProxylibRedirect() bool { 668 return l4 != nil && (l4.Ingress.HasProxylibRedirect() || l4.Egress.HasProxylibRedirect()) 669 } 670 671 // RequiresConntrack returns true if if the L4 configuration requires 672 // connection tracking to be enabled. 673 func (l4 *L4Policy) RequiresConntrack() bool { 674 return l4 != nil && (len(l4.Ingress) > 0 || len(l4.Egress) > 0) 675 } 676 677 func (l4 *L4Policy) GetModel() *models.L4Policy { 678 if l4 == nil { 679 return nil 680 } 681 682 ingress := []*models.PolicyRule{} 683 for _, v := range l4.Ingress { 684 ingress = append(ingress, &models.PolicyRule{ 685 Rule: v.MarshalIndent(), 686 DerivedFromRules: v.DerivedFromRules.GetModel(), 687 }) 688 } 689 690 egress := []*models.PolicyRule{} 691 for _, v := range l4.Egress { 692 egress = append(egress, &models.PolicyRule{ 693 Rule: v.MarshalIndent(), 694 DerivedFromRules: v.DerivedFromRules.GetModel(), 695 }) 696 } 697 698 return &models.L4Policy{ 699 Ingress: ingress, 700 Egress: egress, 701 } 702 }