-
Notifications
You must be signed in to change notification settings - Fork 72
[vpp][acl] do not count policy denies as interface drops #280
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
Open
lolyu
wants to merge
1
commit into
sonic-net:master
Choose a base branch
from
lolyu:acl_policy_drop_not_if_drop
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+173
−1
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
166 changes: 166 additions & 0 deletions
166
vppbld/patches/0019-acl-do-not-count-policy-denies-as-interface-drops.patch
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,166 @@ | ||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||
| From: Longxiang Lyu <lolv@microsoft.com> | ||
| Date: Tue, 1 Sep 2026 12:30:00 +0000 | ||
| Subject: [PATCH] acl: do not count policy denies as interface drops | ||
|
|
||
| An ACL deny is an intentional forwarding decision, but VPP terminates it | ||
| at the generic "error-drop" node, and error-drop charges every packet it | ||
| frees to the ingress interface's drop counter. That counter is exported | ||
| as /if/drops, which saivpp maps to SAI_PORT_STAT_IF_IN_DISCARDS and SONiC | ||
| renders as RX_DRP. | ||
|
|
||
| The result is that a port doing exactly what it was configured to do | ||
| looks broken. On a dual-ToR the standby mux ports carry a deny ACL, so a | ||
| healthy standby port reports something like | ||
|
|
||
| Ethernet16 RX_OK 5,769 RX_DRP 5,706 | ||
|
|
||
| i.e. a ~99% discard rate that will page an operator. Real hardware does | ||
| not behave this way: an ACL deny increments the ACL rule counter, not | ||
| ifInDiscards. RFC 1213 defines ifInDiscards as packets discarded despite | ||
| "no errors ... to prevent their being deliverable", which is a resource | ||
| condition, not a policy decision. | ||
|
|
||
| Add a VNET_BUFFER_F_POLICY_DROP buffer flag. The ACL plugin sets it when | ||
| a packet is denied by the policy itself, and interface_drop_punt() then | ||
| excludes those packets from the interface drop/punt counter. Everything | ||
| else is unchanged: the per-node "ACL deny packets" error counter, the | ||
| per-ACE counters behind "show acl-plugin acl", packet tracing and buffer | ||
| freeing all behave exactly as before, so the drops remain fully visible | ||
| to an operator via "show errors". | ||
|
|
||
| A deny forced by session-table exhaustion carries ACL_TOO_MANY_SESSIONS | ||
| rather than ACL_DROP and is deliberately left unflagged: that one is a | ||
| genuine resource discard and belongs in the interface counter. | ||
|
|
||
| Signed-off-by: Longxiang Lyu <lolv@microsoft.com> | ||
| --- | ||
| diff --git a/src/plugins/acl/dataplane_node.c b/src/plugins/acl/dataplane_node.c | ||
| index 471228726..9465c8d64 100644 | ||
| --- a/src/plugins/acl/dataplane_node.c | ||
| +++ b/src/plugins/acl/dataplane_node.c | ||
| @@ -548,6 +548,17 @@ acl_fa_inner_node_fn (vlib_main_t * vm, | ||
| vnet_feature_next_u16 (&next[0], b[0]); | ||
| /* if the action is not deny - then use that next */ | ||
| next[0] = action ? next[0] : 0; | ||
| + | ||
| + /* | ||
| + * A deny that came from the policy itself is an intentional | ||
| + * drop, so tell error-drop not to charge it to the interface | ||
| + * drop counter. A deny forced by session table exhaustion | ||
| + * carries ACL_TOO_MANY_SESSIONS instead and is deliberately | ||
| + * left unflagged: that one is a genuine resource discard. | ||
| + */ | ||
| + if (PREDICT_FALSE (0 == action) | ||
| + && b[0]->error == error_node->errors[ACL_FA_ERROR_ACL_DROP]) | ||
| + b[0]->flags |= VNET_BUFFER_F_POLICY_DROP; | ||
| } | ||
|
|
||
| if (node_trace_on) // PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE)) | ||
| diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h | ||
| --- a/src/vnet/buffer.h | ||
| +++ b/src/vnet/buffer.h | ||
| @@ -33,15 +33,24 @@ | ||
| _ (16, IS_DVR, "dvr", 1) \ | ||
| _ (17, QOS_DATA_VALID, "qos-data-valid", 0) \ | ||
| _ (18, GSO, "gso", 0) \ | ||
| - _ (19, AVAIL1, "avail1", 1) \ | ||
| - _ (20, AVAIL2, "avail2", 1) \ | ||
| - _ (21, AVAIL3, "avail3", 1) \ | ||
| - _ (22, AVAIL4, "avail4", 1) \ | ||
| - _ (23, AVAIL5, "avail5", 1) \ | ||
| - _ (24, AVAIL6, "avail6", 1) \ | ||
| - _ (25, AVAIL7, "avail7", 1) \ | ||
| - _ (26, AVAIL8, "avail8", 1) \ | ||
| - _ (27, AVAIL9, "avail9", 1) | ||
| + _ (19, POLICY_DROP, "policy-drop", 1) \ | ||
| + _ (20, AVAIL1, "avail1", 1) \ | ||
| + _ (21, AVAIL2, "avail2", 1) \ | ||
| + _ (22, AVAIL3, "avail3", 1) \ | ||
| + _ (23, AVAIL4, "avail4", 1) \ | ||
| + _ (24, AVAIL5, "avail5", 1) \ | ||
| + _ (25, AVAIL6, "avail6", 1) \ | ||
| + _ (26, AVAIL7, "avail7", 1) \ | ||
| + _ (27, AVAIL8, "avail8", 1) | ||
| + | ||
| +/* | ||
| + * VNET_BUFFER_F_POLICY_DROP marks a buffer that is being dropped on purpose | ||
| + * by a forwarding policy (today: an ACL deny). error-drop still counts the | ||
| + * per-node error and frees the buffer as usual, but does not charge the | ||
| + * drop to the ingress interface's drop counter: a policy deny is not an | ||
| + * interface discard. Drops caused by a lack of resources must NOT set this | ||
| + * flag - those are genuine discards and belong in the interface counter. | ||
| + */ | ||
|
|
||
| /* | ||
| * Please allocate the FIRST available bit, redefine | ||
| @@ -52,7 +61,7 @@ | ||
| #define VNET_BUFFER_FLAGS_ALL_AVAIL \ | ||
| (VNET_BUFFER_F_AVAIL1 | VNET_BUFFER_F_AVAIL2 | VNET_BUFFER_F_AVAIL3 | \ | ||
| VNET_BUFFER_F_AVAIL4 | VNET_BUFFER_F_AVAIL5 | VNET_BUFFER_F_AVAIL6 | \ | ||
| - VNET_BUFFER_F_AVAIL7 | VNET_BUFFER_F_AVAIL8 | VNET_BUFFER_F_AVAIL9) | ||
| + VNET_BUFFER_F_AVAIL7 | VNET_BUFFER_F_AVAIL8) | ||
|
|
||
| #define VNET_BUFFER_FLAGS_VLAN_BITS \ | ||
| (VNET_BUFFER_F_VLAN_1_DEEP | VNET_BUFFER_F_VLAN_2_DEEP) | ||
| diff --git a/src/vnet/interface_output.c b/src/vnet/interface_output.c | ||
| --- a/src/vnet/interface_output.c | ||
| +++ b/src/vnet/interface_output.c | ||
| @@ -1040,6 +1040,37 @@ | ||
| count = clib_count_equal_u32 (sw_if_index, n_left); | ||
| n_left -= count; | ||
|
|
||
| + /* | ||
| + * Walk the block once to (a) discount intentional policy drops, which | ||
| + * must not look like interface discards, and (b) for packets whose RX | ||
| + * sw_if_index was rewritten (e.g. by bond-input), also charge the | ||
| + * original member interface. | ||
| + */ | ||
| + { | ||
| + u32 n_policy = 0; | ||
| + | ||
| + for (u32 j = 0; j < count; j++) | ||
| + { | ||
| + vlib_buffer_t *ob = bufs[off + j]; | ||
| + u32 orig; | ||
| + | ||
| + if (ob->flags & VNET_BUFFER_F_POLICY_DROP) | ||
| + { | ||
| + n_policy++; | ||
| + continue; | ||
| + } | ||
| + | ||
| + orig = vnet_buffer2 (ob)->orig_rx_sw_if_index; | ||
| + if (orig && orig != sw_if_index[0]) | ||
| + vlib_increment_simple_counter (cm, thread_index, orig, 1); | ||
| + } | ||
| + | ||
| + count -= n_policy; | ||
| + } | ||
| + | ||
| + if (0 == count) | ||
| + continue; | ||
| + | ||
| vlib_increment_simple_counter (cm, thread_index, sw_if_index[0], count); | ||
|
|
||
| /* Increment super-interface drop/punt counters for | ||
| @@ -1048,19 +1079,6 @@ | ||
| if (sw_if0->sup_sw_if_index != sw_if_index[0]) | ||
| vlib_increment_simple_counter | ||
| (cm, thread_index, sw_if0->sup_sw_if_index, count); | ||
| - | ||
| - /* Also count against the original member interface if the | ||
| - RX sw_if_index was rewritten (e.g. by bond-input). */ | ||
| - { | ||
| - u32 orig_off = frame->n_vectors - n_left - count; | ||
| - for (u32 j = 0; j < count; j++) | ||
| - { | ||
| - vlib_buffer_t *ob = bufs[orig_off + j]; | ||
| - u32 orig = vnet_buffer2 (ob)->orig_rx_sw_if_index; | ||
| - if (orig && orig != sw_if_index[0]) | ||
| - vlib_increment_simple_counter (cm, thread_index, orig, 1); | ||
| - } | ||
| - } | ||
| } | ||
|
|
||
| vnet_interface_main_t *im = &vnm->interface_main; | ||
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
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.
Uh oh!
There was an error while loading. Please reload this page.
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.
As far as I understand the original code, it added the count for regular interfaces and then down below also added same count for a super interface (like a bond) if it exists. Are we double counting by adding this code for sub-interfaces?
Also, since we skip this code if this is a policy drop, is the intention here to do this for sub-interfaces only when this is not a policy drop?
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.
Good question, and the diff is genuinely misleading here — sorry. That loop isn't new; I moved it.
It comes from patch
0008-bond-drop-stats-track-original-member-interface.patch. You can see it already present in the tree with only 0008 applied:The diff shows it as
+at the top and-at the bottom because I merged it into my new loop, so the block is walked once instead of twice. Net effect on non-policy traffic: identical work, one pass.On the double-counting concern specifically — these are two different mechanisms, and neither is about sub-interfaces in the same sense:
sup_sw_if_indexEthernet0.100→Ethernet0)orig_rx_sw_if_indexBondEthernet0→Ethernet0)orig_rx_sw_if_indexis written in exactly one place —src/vnet/bonding/node.c, wherebond-inputrewritessw_if_index[VLIB_RX]from the member to the bond — and is explicitly zeroed otherwise. It's also guarded byorig && orig != sw_if_index[0], so it can never charge the same interface twice.The offsets are equivalent too: the original computed
orig_off = frame->n_vectors - n_left - countaftern_left -= count, which is the same value as myoff = frame->n_vectors - n_leftcomputed before the decrement.Yes — intentional, and it applies to all three counters, not just this one:
countcountcontinueIf the bond member were still charged for a policy drop, a mux port that happened to be a LAG member would keep reporting
RX_DRPand the fix wouldn't work there. Suppressing it in one place and not the others would be the inconsistent option.