policy: Pre-parse cached selectors, index by namespace#42008
Merged
jrajahalme merged 11 commits intocilium:mainfrom Dec 2, 2025
Merged
policy: Pre-parse cached selectors, index by namespace#42008jrajahalme merged 11 commits intocilium:mainfrom
jrajahalme merged 11 commits intocilium:mainfrom
Conversation
cbc5dd3 to
cd19f69
Compare
Member
|
/scale-100 |
Member
Author
|
/test |
cd19f69 to
e4260a6
Compare
e4260a6 to
4d9ce46
Compare
Member
Author
|
/test |
squeed
reviewed
Oct 8, 2025
squeed
reviewed
Oct 8, 2025
squeed
reviewed
Oct 8, 2025
Contributor
|
(note: I see at least one "wip" commit message) |
Member
Author
Was a commit squash artefact, will fix :-) |
4d9ce46 to
d18a7c0
Compare
Member
Author
|
/test |
squeed
reviewed
Oct 14, 2025
squeed
reviewed
Oct 14, 2025
Member
Author
|
/test |
ebfc4b8 to
91a39d8
Compare
91a39d8 to
c650f3a
Compare
Member
Author
|
/test |
c650f3a to
6cca148
Compare
Use world label in CIDR selectors instead of a zero-length prefixes. Thus
a CIDR "0.0.0.0/0" selector will translate to a "reserved:world" selector
(in an IPv6 disabled configuration). This makes it possible to remove the
addition of world selectors when wildcard selectors are added.
Do not add extra selectors with "reserved:world" label requirement (or
dual-stack equivalents) when a CIDR selecting all IPv4 or IPv6 addresses
is ingested. Adding the extra world label selector will no longer expand
the set of selected identities, since the world selector has already been
used instead of a zero-length CIDR selector.
The removed logic was also partially based on string matching on forms
that would not match for selectors with a CIDR "1.1.1.1/0" for example,
even though the resulting CIDR selector would be the same
("cidr.0.0.0.0/0").
This change allows CIDR selector parsing to internal
representation to be simplified, as each CIDR selector will map to
exactly one internal EndpointSelector.
Signed-off-by: Jarno Rajahalme <[email protected]>
Add a new LabelMatcher interface with a sole LookupLabel function that uses a pre-parsed *Label as an argument. Implement it in Labels, LabelArray, and in a new K8sSet, that can be used to cast bare sting maps to a LabelMatcher. Use iteration index into LabelArray rather than using a temporary Label. This makes a diffence due to LookupLabel used in some inner loops in policy selector matching. Signed-off-by: Jarno Rajahalme <[email protected]>
Use the cached string and requirements with pre-parsed labels instead of api.EndpointSelector in labelIdentitySelector. labels.LabelArray is changed to add HasLabel(), GetLabel() and LookupLabel() functions that take a pre-parsed Label as an argument instead of a string. This makes CIDR policy resolution in BenchmarkResolveCIDRPolicyRules 70% faster, with 90% less memory used and 95% less allocations. Signed-off-by: Jarno Rajahalme <[email protected]>
Consider selector possibly selecting any namespace if the selector requirement has any operator than "In", "Equals", or "DoubleEquals". For example, if the requirement is "NotIn", then any namespace *not in* the values would be selected. In this kind of cases we skip namespace filtering and perform a full match. Signed-off-by: Jarno Rajahalme <[email protected]>
Store the fqdn identity label into `fqdnSelector` so that it does not need to be re-created on every match operation. Signed-off-by: Jarno Rajahalme <[email protected]>
Refactor scIdentityCache to a struct. Keep scIdentities in a map via a pointer so that it is possible to point to them via a secondary index to be added in the next commit. Signed-off-by: Jarno Rajahalme <[email protected]>
Add a namespace index to identities so that ones with non-matching identities can be trivially skipped when adding or removing selectors to/from the selector cache. Signed-off-by: Jarno Rajahalme <[email protected]>
Index cached selectors by namespace so that ones with non-matching namespaces can be trivially skipped when adding or deleting identities. Signed-off-by: Jarno Rajahalme <[email protected]>
Signed-off-by: Jarno Rajahalme <[email protected]>
898549e to
fcacbe2
Compare
Member
Author
|
Removed part.Map change (last commit), as it triggered consistent |
Member
Author
|
/test |
sayboras
approved these changes
Nov 26, 2025
Member
sayboras
left a comment
There was a problem hiding this comment.
Looks good for cilium/proxy related files
rgo3
approved these changes
Nov 27, 2025
squeed
reviewed
Dec 1, 2025
squeed
reviewed
Dec 1, 2025
Member
Author
|
/test |
squeed
approved these changes
Dec 1, 2025
Keep pre-computed Requirements only in Selector implementations in pkg/policy/types. Use these in places where EndpointSelector was used for matching in production code previously. This simplifies policy/api code, and keeps the faster matching in one place (policy/types.Selector implementations). These same Selectors are now also used internally in SelectorCache for updating the cached selections. Note that the matching interface of api.EndpointSelector has been moved to unit test code. Due to dependency cycle avoidance the unit test matching logic in policy/api can not use the new matching logic in policy/types. For selector matching in production code, create a types.LabelSelector from api.EndpointSelector and use that for matching. Note that for this to work the api.EndpointSelector MUST HAVE the key prefixed with a label source (e.g., "k8s."), otherwise any dot separated prefix will be parsed as the label's source and removed from the label key! API selector types now all have a SelectorKey() method, used for getting a key string before a new Selectors are created from them. This method should be fast, and api.EndpointSelector keeps the internal cachedLabelSelectorString member for this purpose. This cached string is still updated after each modification to api.EndpointSelector. PeerSelector interface used to be a "marker" interface with IsPeerSelector() function that did nothing. Since we added another function (SelectorKey()) to the interface, it is not a pure marker anymore, and IsPeerSelector() function is no longer needed, so remove it. Since also subject selectors can be cached in selector cache, rename PeerSelector interface as APISelector, as it must be implemented by all policy.api types that can be used as types.Selectors. Stop hauling logger to selector matching functions, as they use validated inputs and should never fail. To help avoid breaking this invariant, use logging.DefaultSlogLogger as a "soft panic" to fail Cilium CI if these are hit during CI runs. Signed-off-by: Jarno Rajahalme <[email protected]>
Member
Author
|
Squashed last three commits, added slogloggercheck with reason to use |
Member
Author
|
/test |
tklauser
approved these changes
Dec 2, 2025
tklauser
reviewed
Dec 3, 2025
| value = v.Value | ||
| } | ||
| return | ||
| // Get implements labels.LabelMatcher; label source is ignored |
Member
There was a problem hiding this comment.
nit:
Suggested change
| // Get implements labels.LabelMatcher; label source is ignored | |
| // GetLabel implements labels.LabelMatcher; label source is ignored |
| // Has implements k8sLabels.Labels. | ||
| func (l labelsMatcher) Has(label string) (exists bool) { | ||
| return labels.Labels(l).HasLabelWithKey(label) | ||
| // Has implements labels.LabelMatcher. |
Member
There was a problem hiding this comment.
Suggested change
| // Has implements labels.LabelMatcher. | |
| // HasLabel implements labels.LabelMatcher. |
| // Lookup implements k8sLabels.Labels. | ||
| func (l labelsMatcher) Lookup(label string) (value string, exists bool) { | ||
| v, ok := labels.Labels(l)[label] | ||
| // Lookup implements labels.LabelMatcher |
Member
There was a problem hiding this comment.
Suggested change
| // Lookup implements labels.LabelMatcher | |
| // LookupLabel implements labels.LabelMatcher |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Parse selector requirement keys into labels when inserting into selector cache. Previously the labels of each existing cached selector (and
netip.Prefixfor a CIDR selector) were re-parsed and re-allocated on each match operation, used when new selectors or identities are added to the selector cache. This was essentially an O(n^2) operation on policy ingestion and identity updates.Index cached selectors and identities by namespace so that it is possible to avoid futile matches rather than making the match operation itself fail early for a non-matching namespace. This speeds up namespaced policy ingestion and identity updates.
These changes make CIDR policy resolution in the new BenchmarkResolveCIDRPolicyRules ~4x faster, using 90% less memory and 96% less allocations.