-
Notifications
You must be signed in to change notification settings - Fork 34
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
optimize filter sampling logic when filtering not enabled #488
Conversation
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #488 +/- ##
==========================================
+ Coverage 29.72% 29.85% +0.12%
==========================================
Files 48 48
Lines 4797 4797
==========================================
+ Hits 1426 1432 +6
+ Misses 3261 3256 -5
+ Partials 110 109 -1
Flags with carried forward coverage won't be shown. Click here to find out more. |
9d72433
to
03a957d
Compare
/ok-to-test |
Thanks, I think it fixes most of the regression but there are still a case not covered: if users previously had a filter and have global sampling, they would still see a performance regression. |
New image: It will expire after two weeks. To deploy this build, run from the operator repo, assuming the operator is running: USER=netobserv VERSION=8201443 make set-agent-image |
if u enable filtering that should by itself optimize things I think we can defer this till we better know how the filter smapling will be used we might need to have default value also in case its not set ? |
@msherif1234
The regression that remains is without using filter sampling, let's say someone was filtering for only TCP traffic and applied a global sampling, this too would be concerned with a performance regression |
@msherif1234 here's my suggestion to fix this entirely: msherif1234#1 |
/ok-to-test |
03a957d
to
35857aa
Compare
/ok-to-test |
/ok-to-test |
New image: It will expire after two weeks. To deploy this build, run from the operator repo, assuming the operator is running: USER=netobserv VERSION=c2e2b27 make set-agent-image |
1 similar comment
New image: It will expire after two weeks. To deploy this build, run from the operator repo, assuming the operator is running: USER=netobserv VERSION=c2e2b27 make set-agent-image |
bpf/utils.h
Outdated
@@ -211,7 +218,7 @@ static inline bool check_and_do_flow_filtering(flow_id *id, u16 flags, u32 drop_ | |||
// we have no matching rules so we update global counter for flows that are not matched by any rule | |||
increase_counter(FILTER_NOMATCH); | |||
// we have accept rule but no match so we can't let mismatched flows in the hashmap table. | |||
if (action == ACCEPT || action == MAX_FILTER_ACTIONS) { | |||
if (action == ACCEPT) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I see why you removed this, I think it fixes an issue but introduces a new one. In case of no CIDR match, action is neither ACCEPT nor REJECT and previously we would view that as a DROP; now you change that to be a KEEP. I think neither of those options are valid, we need to inspect the filters to decide whether it should return DROP or KEEP.
If users have defined any ACCEPT rules, then a no-match should return DROP
If users have defined any REJECT rules, then a no-match should return KEEP
... and if users have defined a mix of ACCEPT and REJECT, I think it just doesn't make sense because we don't know what to say when no rule is matched?
So at the end of the day, I think it's an API issue: we shouldn't allow to set ACCEPT/REJECT action per rule, it should be a single setting for all rules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should be the one define what is the default behavior when no CIDR match happens which is when we get the special action value, in that case I feel keeping the default as before to disallow is more accurate , nothing wrong with the API IMO, we just need to define what is the nomatch action behavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't agree: if we keep as it is today, then there's a whole range of things you can't express, e.g:
Filter: { 1.2.3.4/32: REJECT }
You would expect a flow like that to be kept: src=6.6.6.6, dst=8.8.8.8
But here it would be dropped because action == MAX_FILTER_ACTIONS
(or you need to add extra rules for working that around, but I see that as an unexpected behaviour)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah u need to add Allow 0.0.0.0/0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you add Allow 0.0.0.0/0, you fall into another problem: since the src_ip is checked before the dst_ip, this global-allow will take precedence on a flow like src=6.6.6.6, dst=1.2.3.4
even though there is the reject rule for that IP that in theory should take precedence.
Maybe then you need to always run both lookups for source and dest, and not check dest only when src has no match.
I think we should be more clear on what to expect with this feature, I've started a doc for acceptance criteria: https://docs.google.com/document/d/1YUVcpCdYxRACRVrqEOwir6upMyla5RvvUsZmgP4WvIs/edit?tab=t.0 - I think there's already a couple of issues - things that are not covered
35857aa
to
dd9ccbd
Compare
/ok-to-test |
I understand but my point is when filtering is on u see same perf impact regardless if u hvae sampoling action or not its not worth optimizing this case IMO |
New image: It will expire after two weeks. To deploy this build, run from the operator repo, assuming the operator is running: USER=netobserv VERSION=ec4a937 make set-agent-image |
So we would be introducing a perf regression on purpose, just so it aligns with a case that has worse performance? I'm not sure to agree with that argument... And the optimization is not super complicated. |
it seems overkill to customize for special case IMO what if people endup using sampling all the time when they filter they might complain why filtering with smapling has different cpu than with sampling , idk seems too much IMO but not totally against it regardless if its easy or hard to do |
I don't think that people doing filtering + global sampling are a corner case to ignore. Doing simple filtering with global sampling is precisely meant to reduce resource consumption - the new filtered sampling is a nice feature to fine-tune what you sample, but we can't assume everybody will use that. |
/ok-to-test |
New image: It will expire after two weeks. To deploy this build, run from the operator repo, assuming the operator is running: USER=netobserv VERSION=ae7ce55 make set-agent-image |
Signed-off-by: Mohamed Mahmoud <[email protected]>
ab3250c
to
1342023
Compare
/ok-to-test |
New image: It will expire after two weeks. To deploy this build, run from the operator repo, assuming the operator is running: USER=netobserv VERSION=06d8a9e make set-agent-image |
I am fine proceeding with the suggested optimization tell we better know how users will endup using this since u have a ready PR we can get mine in then u can followup with ur change WDYT ? |
It's possible that flow ids found in the additional map don't match any id from the main flow map, for different reasons. This is especially visible when filtering for drops, as in this case all flows are produced only by the drop hook. In these cases, we must be able to reconstruct the flows from the user space. 3 things were particularly missing: end/start time and eth_protocol. So, they are added back into the additional map. Also, in user space, need to iterate separately over the two maps, to not miss any orphan flow.
@msherif1234 can you review this commit ec403e4 ? |
for _, id := range ids { | ||
countAdditional++ | ||
if err := m.objects.AdditionalFlowMetrics.LookupAndDelete(&id, &additionalMetrics); err != nil { | ||
log.WithError(err).WithField("flowId", id).Warnf("couldn't lookup/delete additional metrics entry") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why the error handling here is different than the other map in fact this more identical to old code so it should be similar no ? specially the check for i===0
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you mean, for the switch to legacy mode? I can add that yes. I assumed if there's a need for switching to legacy, it would be done already before entering in that block.. but for sure, there's the case of drops=true which generates 0 regular flow, so ok I can add that for that case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -106,6 +106,9 @@ typedef struct flow_metrics_t { | |||
const struct flow_metrics_t *unused2 __attribute__((unused)); | |||
|
|||
typedef struct additional_metrics_t { | |||
u64 start_mono_time_ts; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we really need this for all features or only the drop case if drop case only we might bundle this in the drop struct ? WDYT ? might be cleaner to have it for all and more future proof just in case not sure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes I think it's safer to do it for all. It's actually a good thing that the drop=true filter revealed this issue, because it certainly can happen also in other situations, even if that's exceptional. There certainly can be some race condition that makes flows "orphan" in the additional map, without counterpart in main flow map, so we need to fetch &delete them separately if we don't want to risk having them in maps forever. And those "orphan" flows need the timestamp & eth_protocol to be correctly processed
/ok-to-test |
Ok |
/lgtm |
@msherif1234: you cannot LGTM your own PR. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
/lgtm |
New image: It will expire after two weeks. To deploy this build, run from the operator repo, assuming the operator is running: USER=netobserv VERSION=81f89c0 make set-agent-image |
} | ||
filter_sampling = sampling; | ||
do_sampling = 1; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What should do_sampling
be set to if filter is enabled? It is currently left unchanged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do_sampling is just bool either 0 or 1 sampling rate is what prandom uses
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prior to this code change, do_sampling
was always set to 0 or 1 in this function. Now it can be left unchanged if is_filter_enabled()
is true. There are a few places in other parts of the code that does something depending on the state of do_sampling
. See: https://github.com/search?q=repo%3Anetobserv/netobserv-ebpf-agent%20do_sampling&type=code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stleerh I think all code paths are covered to set a value on do_sampling:
- if filters aren't enabled (line 85), do_sampling is set to either 0 or 1
- if filters are enabled (line 118), do_sampling is also set to either 0 or 1
The execution between line 85 and 118 are just IP/TCP headers extraction, they won't involve checking do_sampling, so that should be fine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I didn't see that line 85 is not the same as line 118.
/lgtm
do_sampling = 1; | ||
if (skip) { | ||
return TC_ACT_OK; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is related to the same question on what do_sampling
should be set to since this is part of the same function.
/label qe-approved |
Description
optimize logic when filtering not enabled to avoid doing packet parsing when its not needed
Dependencies
n/a
Checklist
If you are not familiar with our processes or don't know what to answer in the list below, let us know in a comment: the maintainers will take care of that.