Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

policy: Track policy rule labels from which map entries are derived from #10512

Merged
merged 4 commits into from Mar 18, 2020

Conversation

gandro
Copy link
Member

@gandro gandro commented Mar 9, 2020

This PR allows us to track the policies for which a certain policy map entry has been created.

It is implemented by copying over the DerivedFromRules from the merged ingress/egress filters to the user-space representation of the policy map state. These entries are then moved over into the realizedPolicy of each endpoint when the policy maps are synced.

Since the order of the DerivedFromRules rules is not deterministic, we create a sorted copy of each LabelArrayList. Default entries such as AllowAnyIngress, AllowAnyEgress and AllowLocalHostIngress are annotated with artificial labels (of label source reserved).


Note to reviewer: This is the successor PR to #10293 - but with proper test coverage this time and hopefully addresses the feedback given in the other PR. Review per commit.


This change is Reviewable

@gandro gandro added pending-review sig/policy Impacts whether traffic is allowed or denied based on user-defined policies. release-note/misc This PR makes changes that have no direct user impact. labels Mar 9, 2020
@gandro gandro requested review from a team as code owners March 9, 2020 14:19
@gandro gandro requested a review from a team March 9, 2020 14:19
@maintainer-s-little-helper maintainer-s-little-helper bot added this to In progress in 1.8.0 Mar 9, 2020
pkg/policy/mapstate.go Show resolved Hide resolved
pkg/policy/distillery_test.go Show resolved Hide resolved
pkg/policy/distillery_test.go Show resolved Hide resolved
pkg/policy/distillery_test.go Show resolved Hide resolved
pkg/policy/distillery_test.go Show resolved Hide resolved
pkg/policy/distillery_test.go Show resolved Hide resolved
pkg/policy/distillery_test.go Show resolved Hide resolved
pkg/policy/distillery_test.go Show resolved Hide resolved
pkg/policy/distillery_test.go Show resolved Hide resolved
pkg/policy/distillery_test.go Show resolved Hide resolved
@gandro gandro force-pushed the pr/gandro/track-source-policy-for-map-entry branch from 83a6de7 to b50f082 Compare March 9, 2020 14:20
@gandro
Copy link
Member Author

gandro commented Mar 9, 2020

test-me-please

@coveralls
Copy link

coveralls commented Mar 9, 2020

Coverage Status

Coverage increased (+0.004%) to 45.713% when pulling 2442d14 on pr/gandro/track-source-policy-for-map-entry into a5c0488 on master.

pkg/labels/array_test.go Show resolved Hide resolved
pkg/policy/mapstate.go Show resolved Hide resolved
pkg/policy/l4.go Outdated Show resolved Hide resolved
pkg/policy/l4.go Outdated
@@ -358,12 +356,13 @@ func (l4 *L4Filter) IdentitySelectionUpdated(selector CachedSelector, selections
// that we could not push updates on a stale policy.
l4Policy := (*L4Policy)(atomic.LoadPointer(&l4.policy))
if l4Policy != nil {
derivedFrom := l4.DerivedFromRules.DeepCopy().Sort()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to:

  1. DeepCopy()?
  2. Sort the rules?

Can't both of these be avoided if we simply insert the labels by order when l4.DerivedFromRules is created / appended?

Copy link
Member Author

@gandro gandro Mar 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They need to be sorted because the insert is not deterministic (see commit message) and we need to be able to have them sorted so we can compare them here:

return e.ProxyPort == o.ProxyPort && e.DerivedFromRules.Equals(o.DerivedFromRules)

They need to be copied to avoid accidentally sorting the original array. As an added bonus, sorting them also makes the unit tests much easier to read.

Edit: I think I slightly misread your comment. Ideally yes, we would have them sorted properly when we insert a new rule. However, given that the insert order is not deterministic, I think it's cheaper to do the sorting here instead of trying to use a heap or something.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But here we are doing a DeepCopy of the full array plus sorting it. Which operation will be performed more frequently? This one or when we insert a new label into o.DerivedFromRules?

Copy link
Member Author

@gandro gandro Mar 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding of the policy code is still somewhat limited, so I might be wrong. But it is my understanding that inserting a new label is much more frequent, as it is called for each rule of each policy applicable to the endpoint when the endpoint is regenerated. While this code here is only called once for each endpoint regeneration.

Edit: Note that the MapStateEntry.DerivedFromRules is never modified after the entry is created here. Only L4Filter.DerivedFromRules is being modified when multiple rules are being merged.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm not mistaken (/cc @jrajahalme) IdentitySelectionUpdated() can be invoked any time any new identity appears anywhere in the cluster. In large-scale clusters with constant churn, this may happen quite frequently.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, that's a good pointer. That's a case then where we indeed should probably sort L4Filter.DerivedFromRules once we are certain that there are no rules which can be added to the L4Filter anymore. I will have to look a bit more deeply where that place would be.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joestringer is correct, typically policy computations are less frequent than map state generation due to identities being created either for new endpoints or newly resolved DNS names.

@gandro L4Filter.attach() is called once when the merging is over to "attach" the computed policy to the filter. Sorting in the beginning of this function is likely the right thing to do:

func (l4 *L4Filter) attach(ctx PolicyContext, l4Policy *L4Policy) {
    // sort here
    ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you all for the feedback, I think that helped me quite understand the code quite a bit better! I have pushed a new version where we sort the labels in L4Filter.attach. This also allows me to avoid having to create a copy, since this call seems to happen after any modifications to the DerivedFromRules.

@gandro gandro force-pushed the pr/gandro/track-source-policy-for-map-entry branch from b50f082 to b883a53 Compare March 10, 2020 12:22
`Equals` is more idiomatic than `Same` and consistent with Label.Equals.

Signed-off-by: Sebastian Wicki <sebastian@isovalent.com>
These functions are used to create canonical representations of the
LabelArrayList that can be used to check if two LabelArrayList contain
the same set of labels.

Signed-off-by: Sebastian Wicki <sebastian@isovalent.com>
This commit allows us to track the policies for which a certain policy
map entry has been created.

It is implemented by copying over the `DerivedFromRules` from the
merged ingress/egress filters to the user-space representation of
the policy map state. These entries are then moved over into the
`realizedPolicy` of each endpoint when the policy maps are synced.

Since the order of the `DerivedFromRules` rules is not deterministic,
sort each LabelArrayList when the computed policy is attached.
Default entries such as `AllowAnyIngress`, `AllowAnyEgress` and
`AllowLocalHostIngress` are annotated with artificial labels (of label
 source `reserved`).

Signed-off-by: Sebastian Wicki <sebastian@isovalent.com>
This function allows callers to get the list of policies which caused a
certain policy map entry to be added for a given endpoint.

Signed-off-by: Sebastian Wicki <sebastian@isovalent.com>
@gandro gandro force-pushed the pr/gandro/track-source-policy-for-map-entry branch from b883a53 to 2442d14 Compare March 16, 2020 09:05
@gandro
Copy link
Member Author

gandro commented Mar 16, 2020

test-me-please

Edit: Hit https://github.com/cilium/cilium/projects/97#card-33577672

@gandro gandro requested a review from aanm March 17, 2020 10:15
@gandro
Copy link
Member Author

gandro commented Mar 17, 2020

test-me-please

@aanm aanm merged commit a62c369 into master Mar 18, 2020
1.8.0 automation moved this from In progress to Merged Mar 18, 2020
@aanm aanm deleted the pr/gandro/track-source-policy-for-map-entry branch March 18, 2020 09:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release-note/misc This PR makes changes that have no direct user impact. sig/policy Impacts whether traffic is allowed or denied based on user-defined policies.
Projects
No open projects
1.8.0
  
Merged
Development

Successfully merging this pull request may close these issues.

None yet

6 participants