VLAN ACL change detection to be able to warm reload - #4733
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4733 +/- ##
==========================================
+ Coverage 91.42% 91.47% +0.05%
==========================================
Files 46 46
Lines 8923 8980 +57
==========================================
+ Hits 8157 8214 +57
Misses 766 766 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Thanks for the contribution, it appears that this patch has some test failures at the moment that need to be addressed. If I look at this test failure: It looks like this test was expecting a cold restart, but now with your changes a warm reload happens so the test fails. I think you'll need to update this test (and perhaps others) to account for this behavioural change. |
|
Hi @gizmoguy, I've revisited this PR and fixed the failing test cases. Could you please review it? |
|
Hi @hieunt79, I've been testing your patch and it seems to cover most scenarios and work well. I've found one case that doesn't seem to work currently, and that is the case where all port ACLs are removed from a port, e.g start faucet with this configuration where we have 2 ports, both with ACLs: vlans:
office:
vid: 100
description: "office network"
acls:
block-ping:
- rule:
dl_type: 0x800 # IPv4
ip_proto: 1 # ICMP
actions:
allow: False
dps:
sw1:
dp_id: 0x1
hardware: "Open vSwitch"
interfaces:
1:
name: "host1"
native_vlan: office
acls_in:
- block-ping
2:
name: "host2"
native_vlan: office
acls_in:
- block-pingand then remove the ACL from one of the ports and reload faucet, e.g: vlans:
office:
vid: 100
description: "office network"
acls:
block-ping:
- rule:
dl_type: 0x800 # IPv4
ip_proto: 1 # ICMP
actions:
allow: False
dps:
sw1:
dp_id: 0x1
hardware: "Open vSwitch"
interfaces:
1:
name: "host1"
native_vlan: office
acls_in:
- block-ping
2:
name: "host2"
native_vlan: officeWe will see faucet do the warm reload and correctly detect the change in configuration: However, the ACL flow rules do not get deleted from the datapath (unless you restart faucet to trigger a cold reload): I also tested the same scenario for vlan ACLs and in that case everything worked fine, so it's just the port ACL case that seems to be broken currently. |
99f1e18 to
f3b63b3
Compare
|
Hi @gizmoguy, thanks for pointing out the issue. The generated flows are correct: However, if deletes and addmod:
by_kind["delete"] = remove_overlap_ofmsgs(deletes, addmod)To fix this, I added a new I have also added a test case (FaucetConfigReloadPortAclRemoveTest) for this scenario. The latest commit passes both unit and integration tests. |
|
Hi @hieunt79, thanks for digging into that edge case and adding a new test case, I understand better what is happening now. I now see that to change an ACL on a VLAN or port, this patch will delete all the flow rules for the vlan/port and re-add the new flow rules from the new configuration. This approach is essentially what a cold-start does, except it does it for a whole datapath. Here's what I am thinking is a better approach for implementing the warm start for ACL changes (which is similar to how we handle warm reloads for meter changes), that will truly be a warm start (i.e we only delete flow rules we are no longer using and add new flow that are missing):
It should be possible to implement warm reload for VLAN ACLs in the same way, but I do note we are missing Let me know if you have any questions or if you find a problem in my design that I haven't considered that makes it difficult to implement or inefficient. |
Changes to a VLAN's VIPs, router membership, or ACLs currently force a cold restart -- full datapath reconnection and a flow-table wipe. This is unnecessarily disruptive for deployments that update these dynamically (provisioning new tenant networks, IPAM-driven VLAN changes, dynamic router membership, ACL rule edits). The warm-restart path (del_vlan + dp_init + add_vlan) already handles VLAN-level changes incrementally, but two guards in dp.py were short-circuiting to cold start. Those guards are removed and the missing flow cleanup is added so warm restart is correct for VIP- and router-related state. VID replacement (a deleted + added VLAN pair on a DP whose ports cover the new VLAN) keeps its cold-start escalation -- per-port classification flows genuinely need rebuilding. For ACL changes the existing cold_start_port path emits a default goto-vlan add at the same flowmodkey as its preceding bulk delete, which valve_flowreorder.remove_overlap_ofmsgs strips, leaving stale per-port ACL flows on the datapath. cold_start_port is replaced with a diff: capture the addmods that acl_manager.add_port / add_vlan would produce for the old config, mirror them as flowdels, emit them alongside the new addmods. Unchanged-rule pairs share a flowmodkey and are cancelled by remove_overlap_ofmsgs before reaching the wire; only changed rules cross the channel. The mirroring approach reuses the priority/cookie scheme that put the existing flows there, so flowmodkeys align by construction -- without needing per-ACL priority offsets or new acl_manager methods. ValveTable.flowdel grows a cookie parameter so the addmods-to-flowdels conversion can propagate the rule cookie; without that the overlap check silently fails (different cookies = different flowmodkeys) and the granular path emits more ofmsgs than cold_start_port did. The default goto-vlan transition (removing the last ACL from a port, or adding the first to a previously-bare port) falls out of the diff for free and fixes the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733. VLAN ACL changes get the same treatment via a new changed_acl_vlans set in dp.py that catches VLANs whose only change is an ACL ref or an edit to a referenced ACL's rules. VLANs that change in any other way still take the heavy del_vlans + add_vlans reinstall. The integration test FaucetConfigReloadPortAclRemoveTest is brought over from faucetsdn#4733 verbatim, with hieunt79 attributed via Co-Authored-By below. Co-Authored-By: hieunt79 <44926706+hieunt79@users.noreply.github.com>
Changes to a VLAN's VIPs, router membership, or ACLs currently force a cold restart -- full datapath reconnection and a flow-table wipe. This is unnecessarily disruptive for deployments that update these dynamically (provisioning new tenant networks, IPAM-driven VLAN changes, dynamic router membership, ACL rule edits). The warm-restart path (del_vlan + dp_init + add_vlan) already handles VLAN-level changes incrementally, but two guards in dp.py were short-circuiting to cold start. Those guards are removed and the missing flow cleanup is added so warm restart is correct for VIP- and router-related state. VID replacement (a deleted + added VLAN pair on a DP whose ports cover the new VLAN) keeps its cold-start escalation -- per-port classification flows genuinely need rebuilding. For ACL changes the existing cold_start_port path emits a default goto-vlan add at the same flowmodkey as its preceding bulk delete, which valve_flowreorder.remove_overlap_ofmsgs strips, leaving stale per-port ACL flows on the datapath. cold_start_port is replaced with a diff: capture the addmods that acl_manager.add_port / add_vlan would produce for the old config, mirror them as flowdels, emit them alongside the new addmods. Unchanged-rule pairs share a flowmodkey and are cancelled by remove_overlap_ofmsgs before reaching the wire; only changed rules cross the channel. The mirroring approach reuses the priority/cookie scheme that put the existing flows there, so flowmodkeys align by construction -- without needing per-ACL priority offsets or new acl_manager methods. ValveTable.flowdel grows a cookie parameter so the addmods-to-flowdels conversion can propagate the rule cookie; without that the overlap check silently fails (different cookies = different flowmodkeys) and the granular path emits more ofmsgs than cold_start_port did. The default goto-vlan transition (removing the last ACL from a port, or adding the first to a previously-bare port) falls out of the diff for free and fixes the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733. VLAN ACL changes get the same treatment via a new changed_acl_vlans set in dp.py that catches VLANs whose only change is an ACL ref or an edit to a referenced ACL's rules. VLANs that change in any other way still take the heavy del_vlans + add_vlans reinstall. The integration test FaucetConfigReloadPortAclRemoveTest is brought over from faucetsdn#4733 verbatim, with hieunt79 attributed via Co-Authored-By below. Co-Authored-By: hieunt79 <44926706+hieunt79@users.noreply.github.com>
Changes to a VLAN's VIPs, router membership, or ACLs currently force a cold restart -- full datapath reconnection and a flow-table wipe. This is unnecessarily disruptive for deployments that update these dynamically (provisioning new tenant networks, IPAM-driven VLAN changes, dynamic router membership, ACL rule edits). The warm-restart path (del_vlan + dp_init + add_vlan) already handles VLAN-level changes incrementally, but two guards in dp.py were short-circuiting to cold start. Those guards are removed and the missing flow cleanup is added so warm restart is correct for VIP- and router-related state. VID replacement (a deleted + added VLAN pair on a DP whose ports cover the new VLAN) keeps its cold-start escalation -- per-port classification flows genuinely need rebuilding. For ACL changes the existing cold_start_port path emits a default goto-vlan add at the same flowmodkey as its preceding bulk delete, which valve_flowreorder.remove_overlap_ofmsgs strips, leaving stale per-port ACL flows on the datapath. cold_start_port is replaced with a diff: capture the addmods that acl_manager.add_port / add_vlan would produce for the old config, mirror them as flowdels, emit them alongside the new addmods. Unchanged-rule pairs share a flowmodkey and are cancelled by remove_overlap_ofmsgs before reaching the wire; only changed rules cross the channel. The mirroring approach reuses the priority/cookie scheme that put the existing flows there, so flowmodkeys align by construction -- without needing per-ACL priority offsets or new acl_manager methods. ValveTable.flowdel grows a cookie parameter so the addmods-to-flowdels conversion can propagate the rule cookie; without that the overlap check silently fails (different cookies = different flowmodkeys) and the granular path emits more ofmsgs than cold_start_port did. The default goto-vlan transition (removing the last ACL from a port, or adding the first to a previously-bare port) falls out of the diff for free and fixes the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733. VLAN ACL changes get the same treatment via a new changed_acl_vlans set in dp.py that catches VLANs whose only change is an ACL ref or an edit to a referenced ACL's rules. VLANs that change in any other way still take the heavy del_vlans + add_vlans reinstall. The integration test FaucetConfigReloadPortAclRemoveTest is brought over from faucetsdn#4733 verbatim, with hieunt79 attributed via Co-Authored-By below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Changes to a VLAN's VIPs, router membership, or ACLs currently force a cold restart -- full datapath reconnection and a flow-table wipe. This is unnecessarily disruptive for deployments that update these dynamically (provisioning new tenant networks, IPAM-driven VLAN changes, dynamic router membership, ACL rule edits). The warm-restart path (del_vlan + dp_init + add_vlan) already handles VLAN-level changes incrementally, but two guards in dp.py were short-circuiting to cold start. Those guards are removed and the missing flow cleanup is added so warm restart is correct for VIP- and router-related state. VID replacement (a deleted + added VLAN pair on a DP whose ports cover the new VLAN) keeps its cold-start escalation -- per-port classification flows genuinely need rebuilding. For ACL changes the existing cold_start_port path emits a default goto-vlan add at the same flowmodkey as its preceding bulk delete, which valve_flowreorder.remove_overlap_ofmsgs strips, leaving stale per-port ACL flows on the datapath. cold_start_port is replaced with a diff: capture the addmods that acl_manager.add_port / add_vlan would produce for the old config, mirror them as flowdels, emit them alongside the new addmods. Each old flowdel carries the rule's specific match, so the existing flows on the OF table are removed exactly. The default goto-vlan transition (removing the last ACL from a port, or adding the first to a previously-bare port) falls out of the diff for free, fixing the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733. ValveTable.flowdel grows a cookie parameter so the addmods-to-flowdels conversion can propagate the rule cookie -- without it the remove_overlap_ofmsgs python-level cancellation cannot align del+add keys even when the underlying matches are content-equal. _flowmodkey in valve_of also gets a small fix: it now compares match contents via tuple(sorted(match.items())) instead of relying on OFPMatch identity, since os_ken's OFPMatch returns NotImplemented from __eq__ and two semantically-identical matches don't compare equal. Together these let the granular path's unchanged-rule del+add pairs cancel when there's no real change, instead of needlessly churning flows on the wire. VLAN ACL changes get the same treatment via a new changed_acl_vlans set in dp.py that catches VLANs whose only change is an ACL ref or an edit to a referenced ACL's rules. VLANs that change in any other way still take the heavy del_vlans + add_vlans reinstall. The integration test FaucetConfigReloadPortAclRemoveTest is brought over from faucetsdn#4733 verbatim, with hieunt79 attributed via Co-Authored-By below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Changes to a VLAN's VIPs, router membership, or ACLs currently force a cold restart -- full datapath reconnection and a flow-table wipe. This is unnecessarily disruptive for deployments that update these dynamically (provisioning new tenant networks, IPAM-driven VLAN changes, dynamic router membership, ACL rule edits). The warm-restart path (del_vlan + dp_init + add_vlan) already handles VLAN-level changes incrementally, but two guards in dp.py were short-circuiting to cold start. Those guards are removed and the missing flow cleanup is added so warm restart is correct for VIP- and router-related state. VID replacement (a deleted + added VLAN pair on a DP whose ports cover the new VLAN) keeps its cold-start escalation -- per-port classification flows genuinely need rebuilding. For ACL changes the existing cold_start_port path emits a default goto-vlan add at the same flowmodkey as its preceding bulk delete, which valve_flowreorder.remove_overlap_ofmsgs strips, leaving stale per-port ACL flows on the datapath. cold_start_port is replaced with a diff: capture the addmods that acl_manager.add_port / add_vlan would produce for the old config, mirror them as flowdels, emit them alongside the new addmods. Each old flowdel carries the rule's specific match, so the existing flows on the OF table are removed exactly. The default goto-vlan transition (removing the last ACL from a port, or adding the first to a previously-bare port) falls out of the diff for free, fixing the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733. ValveTable.flowdel grows a cookie parameter so the addmods-to-flowdels conversion can propagate the rule cookie -- without it the remove_overlap_ofmsgs python-level cancellation cannot align del+add keys even when the underlying matches are content-equal. _flowmodkey in valve_of also gets a small fix: it now compares match contents via tuple(sorted(match.items())) instead of relying on OFPMatch identity, since os_ken's OFPMatch returns NotImplemented from __eq__ and two semantically-identical matches don't compare equal. Together these let the granular path's unchanged-rule del+add pairs cancel when there's no real change, instead of needlessly churning flows on the wire. VLAN ACL changes get the same treatment via a new changed_acl_vlans set in dp.py that catches VLANs whose only change is an ACL ref or an edit to a referenced ACL's rules. VLANs that change in any other way still take the heavy del_vlans + add_vlans reinstall. The integration test FaucetConfigReloadPortAclRemoveTest is brought over from faucetsdn#4733 verbatim, with hieunt79 attributed via Co-Authored-By below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Changes to a VLAN's VIPs, router membership, or ACLs currently force a cold restart -- full datapath reconnection and a flow-table wipe. This is unnecessarily disruptive for deployments that update these dynamically (provisioning new tenant networks, IPAM-driven VLAN changes, dynamic router membership, ACL rule edits). The warm-restart path (del_vlan + dp_init + add_vlan) already handles VLAN-level changes incrementally, but two guards in dp.py were short-circuiting to cold start. Those guards are removed and the missing flow cleanup is added so warm restart is correct for VIP- and router-related state. VID replacement (a deleted + added VLAN pair on a DP whose ports cover the new VLAN) keeps its cold-start escalation -- per-port classification flows genuinely need rebuilding. For ACL changes the existing cold_start_port path emits a default goto-vlan add at the same flowmodkey as its preceding bulk delete, which valve_flowreorder.remove_overlap_ofmsgs strips, leaving stale per-port ACL flows on the datapath. cold_start_port is replaced with a diff: capture the addmods that acl_manager.add_port / add_vlan would produce for the old config, mirror them as flowdels, emit them alongside the new addmods. Each old flowdel carries the rule's specific match, so the existing flows on the OF table are removed exactly. The default goto-vlan transition (removing the last ACL from a port, or adding the first to a previously-bare port) falls out of the diff for free, fixing the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733. ValveTable.flowdel grows a cookie parameter so the addmods-to-flowdels conversion can propagate the rule cookie -- without it the remove_overlap_ofmsgs python-level cancellation cannot align del+add keys even when the underlying matches are content-equal. _flowmodkey in valve_of also gets a small fix: it now compares match contents via tuple(sorted(match.items())) instead of relying on OFPMatch identity, since os_ken's OFPMatch returns NotImplemented from __eq__ and two semantically-identical matches don't compare equal. Together these let the granular path's unchanged-rule del+add pairs cancel when there's no real change, instead of needlessly churning flows on the wire. VLAN ACL changes get the same treatment via a new changed_acl_vlans set in dp.py that catches VLANs whose only change is an ACL ref or an edit to a referenced ACL's rules. VLANs that change in any other way still take the heavy del_vlans + add_vlans reinstall. The integration test FaucetConfigReloadPortAclRemoveTest is brought over from faucetsdn#4733 verbatim, with hieunt79 attributed via Co-Authored-By below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Changes to a VLAN's VIPs, router membership, or ACLs currently force a cold restart -- full datapath reconnection and a flow-table wipe. This is unnecessarily disruptive for deployments that update these dynamically (provisioning new tenant networks, IPAM-driven VLAN changes, dynamic router membership, ACL rule edits). The warm-restart path (del_vlan + dp_init + add_vlan) already handles VLAN-level changes incrementally, but two guards in dp.py were short-circuiting to cold start. Those guards are removed and the missing flow cleanup is added so warm restart is correct for VIP- and router-related state. VID replacement (a deleted + added VLAN pair on a DP whose ports cover the new VLAN) keeps its cold-start escalation -- per-port classification flows genuinely need rebuilding. For ACL changes the existing cold_start_port path emits a default goto-vlan add at the same flowmodkey as its preceding bulk delete, which valve_flowreorder.remove_overlap_ofmsgs strips, leaving stale per-port ACL flows on the datapath. cold_start_port is replaced with a diff: capture the addmods that acl_manager.add_port / add_vlan would produce for the old config, mirror them as flowdels, emit them alongside the new addmods. Each old flowdel carries the rule's specific match, so the existing flows on the OF table are removed exactly. The default goto-vlan transition (removing the last ACL from a port, or adding the first to a previously-bare port) falls out of the diff for free, fixing the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733. ValveTable.flowdel grows a cookie parameter so the addmods-to-flowdels conversion can propagate the rule cookie -- without it the remove_overlap_ofmsgs python-level cancellation cannot align del+add keys even when the underlying matches are content-equal. _flowmodkey in valve_of also gets a small fix: it now compares match contents via tuple(sorted(match.items())) instead of relying on OFPMatch identity, since os_ken's OFPMatch returns NotImplemented from __eq__ and two semantically-identical matches don't compare equal. Together these let the granular path's unchanged-rule del+add pairs cancel when there's no real change, instead of needlessly churning flows on the wire. VLAN ACL changes get the same treatment via a new changed_acl_vlans set in dp.py that catches VLANs whose only change is an ACL ref or an edit to a referenced ACL's rules. VLANs that change in any other way still take the heavy del_vlans + add_vlans reinstall. The integration test FaucetConfigReloadPortAclRemoveTest is brought over from faucetsdn#4733 verbatim, with hieunt79 attributed via Co-Authored-By below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Changes to a VLAN's VIPs, router membership, or ACLs currently force a cold restart -- full datapath reconnection and a flow-table wipe. This is unnecessarily disruptive for deployments that update these dynamically (provisioning new tenant networks, IPAM-driven VLAN changes, dynamic router membership, ACL rule edits). VLAN/VIP and router warm restart -------------------------------- The warm-restart path (del_vlan + dp_init + add_vlan) already handles VLAN-level changes incrementally, but two guards in dp.py were short- circuiting to cold start. Those guards are removed and the missing flow cleanup is added so warm restart is correct for VIP- and router- related state. VID replacement (a deleted + added VLAN pair on a DP whose ports cover the new VLAN) keeps its cold-start escalation -- per-port classification flows genuinely need rebuilding. Granular ACL warm reload ------------------------ For ACL changes the existing cold_start_port path emits a default goto-vlan add at the same flowmodkey as its preceding bulk delete, which valve_flowreorder.remove_overlap_ofmsgs strips, leaving stale per-port ACL flows on the datapath (the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733). cold_start_port is replaced with a per-port/per-VLAN diff. Before dp_init swaps acl_manager, _apply_config_changes snapshots the addmods that the OLD acl_manager would emit for each affected port and VLAN. After dp_init, it asks the NEW acl_manager for the same and runs the two through valve_acl.diff_addmods, which compares them by (match, cookie, priority, table_id) and emits only the rule-level delta: a flowdel for each rule present only in old, a flowmod for each rule present only in new, nothing for rules unchanged across the reload. A 1-rule edit in a VLAN with hundreds of ACL rules costs O(k) wire ops, not O(N). addmods_to_flowdels uses OFPFC_DELETE_STRICT so a flowdel for a less- specific rule (e.g. a default-allow with no match fields) does not wildcard-delete more specific rules that share its match prefix. valve_table.flowdel grows a cookie kwarg so the addmods-to-flowdels conversion can carry the rule cookie through to the python-level diff key (cookie_mask=0 means OF still ignores it on the wire). _flowmodkey in valve_of canonicalizes match contents via frozenset(match.items()) instead of relying on OFPMatch identity, since os_ken's OFPMatch returns NotImplemented from __eq__ and two semantically-identical matches don't compare equal. VLAN ACL changes get the same treatment via a new changed_acl_vlans set in dp.py that catches VLANs whose only change is an ACL ref or an edit to a referenced ACL's rules (covers acls_in and acls_out). VLANs that change in any other way still take the heavy del_vlans + add_vlans reinstall; an assert in get_config_changes guarantees the two paths stay disjoint so ACL flows are never double-written. Tests ----- Unit coverage in test_valve_config.py exercises: removing the only ACL from a port, adding an ACL to a previously-bare port, the cookie/ priority/table_id alignment that diff_addmods relies on, granular port-ACL reload (asserts exactly 1 del + 1 add for a 1-of-4 rule edit and zero ofmsgs for the unchanged rules -- the cost-scales-with-k property), combined ACL+config VLAN changes, VLAN egress ACL changes, removed-rule cleanup in vlan_acl_table (symmetric stale-flow check), and a VIP change on a DP whose single VLAN owns every port (warm, not cold). Integration coverage in mininet_tests.py adds FaucetVIPChangeWarmStartTest (VIP edit on an all-ports VLAN), FaucetConfigReloadVlanAclChangeTest (granular VLAN ACL warm reload with all other flows untouched), and FaucetConfigReloadPortAclRemoveTest (brought over from faucetsdn#4733 verbatim, with hieunt79 attributed via Co-Authored-By below). The existing test_vlan_acl_update flips from cold_start=True to cold_start=False to match the new warm path. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
VLAN/VIP, router, and ACL config changes now warm-start instead of cold. The warm path (del_vlan + dp_init + add_vlan) already handled the VLAN-level changes; two guards in dp.py were short-circuiting to cold start, and ACL-only changes still went through cold_start_port which left stale flows on the wire. VLAN/VIP and router: - Replace router cold-start guard with finer checks (BGP changes and router add/remove with no routing tables stay cold) - Replace VIP cold-start guard with sibling-VLAN expansion to keep proactive-learn FIB entries consistent - Separate added_vlans from changed_vlans so new VLANs skip the unnecessary del_vlans() - Move changed-VLAN deletion before dp_init() so old managers clean up old select_packets flows - Add pipeline.remove_select(); route manager del_vlan() now cleans select_packets flows alongside FIB flows - Keep cold-start escalation for VID replacement when affected ports cover the DP ACL: - Replace cold_start_port with diff-at-source: snapshot the addmods the OLD acl_manager would emit before dp_init, ask the NEW one for the same after, emit only the rule-level delta. Cost scales with k (rules changed), not N (rules total) - Use OFPFC_DELETE_STRICT for ACL flowdels so a less-specific rule doesn't wildcard-delete more specific rules sharing its prefix - New changed_acl_vlans set in dp.py for VLANs whose only change is an ACL ref or referenced ACL's contents (covers acls_in + acls_out) - valve_table.flowdel grows a cookie kwarg; _flowmodkey in valve_of canonicalizes match contents via frozenset(items()) instead of OFPMatch identity - Fixes the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733 FaucetConfigReloadPortAclRemoveTest brought over from faucetsdn#4733 verbatim, with hieunt79 attributed below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
VLAN/VIP, router, and ACL config changes now warm-start instead of cold. The warm path (del_vlan + dp_init + add_vlan) already handled the VLAN-level changes; two guards in dp.py were short-circuiting to cold start, and ACL-only changes still went through cold_start_port which left stale flows on the wire. VLAN/VIP and router: - Replace router cold-start guard with finer checks (BGP changes and router add/remove with no routing tables stay cold) - Replace VIP cold-start guard with sibling-VLAN expansion to keep proactive-learn FIB entries consistent - Separate added_vlans from changed_vlans so new VLANs skip the unnecessary del_vlans() - Move changed-VLAN deletion before dp_init() so old managers clean up old select_packets flows - Add pipeline.remove_select(); route manager del_vlan() now cleans select_packets flows alongside FIB flows - Keep cold-start escalation for VID replacement when affected ports cover the DP ACL: - Replace cold_start_port with diff-at-source: snapshot the addmods the OLD acl_manager would emit before dp_init, ask the NEW one for the same after, emit only the rule-level delta. Cost scales with k (rules changed), not N (rules total) - Use OFPFC_DELETE_STRICT for ACL flowdels so a less-specific rule doesn't wildcard-delete more specific rules sharing its prefix - New changed_acl_vlans set in dp.py for VLANs whose only change is an ACL ref or referenced ACL's contents (covers acls_in + acls_out) - valve_table.flowdel grows a cookie kwarg; _flowmodkey in valve_of canonicalizes match contents via frozenset(items()) instead of OFPMatch identity - Fixes the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733 FaucetConfigReloadPortAclRemoveTest brought over from faucetsdn#4733 verbatim, with hieunt79 attributed below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
VLAN/VIP, router, and ACL config changes now warm-start instead of cold. The warm path (del_vlan + dp_init + add_vlan) already handled the VLAN-level changes; two guards in dp.py were short-circuiting to cold start, and ACL-only changes still went through cold_start_port which left stale flows on the wire. VLAN/VIP and router: - Replace router cold-start guard with finer checks (BGP changes and router add/remove with no routing tables stay cold) - Replace VIP cold-start guard with sibling-VLAN expansion to keep proactive-learn FIB entries consistent - Separate added_vlans from changed_vlans so new VLANs skip the unnecessary del_vlans() - Move changed-VLAN deletion before dp_init() so old managers clean up old select_packets flows - Add pipeline.remove_select(); route manager del_vlan() now cleans select_packets flows alongside FIB flows - Keep cold-start escalation for VID replacement when affected ports cover the DP ACL: - Replace cold_start_port with diff-at-source: snapshot the addmods the OLD acl_manager would emit before dp_init, ask the NEW one for the same after, emit only the rule-level delta. Cost scales with k (rules changed), not N (rules total) - Use OFPFC_DELETE_STRICT for ACL flowdels so a less-specific rule doesn't wildcard-delete more specific rules sharing its prefix - New changed_acl_vlans set in dp.py for VLANs whose only change is an ACL ref or referenced ACL's contents (covers acls_in + acls_out) - valve_table.flowdel grows a cookie kwarg; _flowmodkey in valve_of canonicalizes match contents via frozenset(items()) instead of OFPMatch identity - Fixes the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733 FaucetConfigReloadPortAclRemoveTest brought over from faucetsdn#4733 verbatim, with hieunt79 attributed below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
VLAN/VIP, router, and ACL config changes now warm-start instead of cold. The warm path (del_vlan + dp_init + add_vlan) already handled the VLAN-level changes; two guards in dp.py were short-circuiting to cold start, and ACL-only changes still went through cold_start_port which left stale flows on the wire. VLAN/VIP and router: - Replace router cold-start guard with finer checks (BGP changes and router add/remove with no routing tables stay cold) - Replace VIP cold-start guard with sibling-VLAN expansion to keep proactive-learn FIB entries consistent - Separate added_vlans from changed_vlans so new VLANs skip the unnecessary del_vlans() - Move changed-VLAN deletion before dp_init() so old managers clean up old select_packets flows - Add pipeline.remove_select(); route manager del_vlan() now cleans select_packets flows alongside FIB flows - Keep cold-start escalation for VID replacement when affected ports cover the DP ACL: - Replace cold_start_port with diff-at-source: snapshot the addmods the OLD acl_manager would emit before dp_init, ask the NEW one for the same after, emit only the rule-level delta. Cost scales with k (rules changed), not N (rules total) - Use OFPFC_DELETE_STRICT for ACL flowdels so a less-specific rule doesn't wildcard-delete more specific rules sharing its prefix - New changed_acl_vlans set in dp.py for VLANs whose only change is an ACL ref or referenced ACL's contents (covers acls_in + acls_out) - valve_table.flowdel grows a cookie kwarg; _flowmodkey in valve_of canonicalizes match contents via frozenset(items()) instead of OFPMatch identity - Fixes the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733 FaucetConfigReloadPortAclRemoveTest brought over from faucetsdn#4733 verbatim, with hieunt79 attributed below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
VLAN/VIP, router, and ACL config changes now warm-start instead of cold. The warm path (del_vlan + dp_init + add_vlan) already handled the VLAN-level changes; two guards in dp.py were short-circuiting to cold start, and ACL-only changes still went through cold_start_port which left stale flows on the wire. VLAN/VIP and router: - Replace router cold-start guard with finer checks (BGP changes and router add/remove with no routing tables stay cold) - Replace VIP cold-start guard with sibling-VLAN expansion to keep proactive-learn FIB entries consistent - Separate added_vlans from changed_vlans so new VLANs skip the unnecessary del_vlans() - Move changed-VLAN deletion before dp_init() so old managers clean up old select_packets flows - Add pipeline.remove_select(); route manager del_vlan() now cleans select_packets flows alongside FIB flows - Keep cold-start escalation for VID replacement when affected ports cover the DP ACL: - Replace cold_start_port with diff-at-source: snapshot the addmods the OLD acl_manager would emit before dp_init, ask the NEW one for the same after, emit only the rule-level delta. Cost scales with k (rules changed), not N (rules total) - Use OFPFC_DELETE_STRICT for ACL flowdels so a less-specific rule doesn't wildcard-delete more specific rules sharing its prefix - New changed_acl_vlans set in dp.py for VLANs whose only change is an ACL ref or referenced ACL's contents (covers acls_in + acls_out) - valve_table.flowdel grows a cookie kwarg; _flowmodkey in valve_of canonicalizes match contents via frozenset(items()) instead of OFPMatch identity - Fixes the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733 FaucetConfigReloadPortAclRemoveTest brought over from faucetsdn#4733 verbatim, with hieunt79 attributed below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
VLAN/VIP, router, and ACL config changes now warm-start instead of cold. The warm path (del_vlan + dp_init + add_vlan) already handled the VLAN-level changes; two guards in dp.py were short-circuiting to cold start, and ACL-only changes still went through cold_start_port which left stale flows on the wire. VLAN/VIP and router: - Replace router cold-start guard with finer checks (BGP changes and router add/remove with no routing tables stay cold) - Replace VIP cold-start guard with sibling-VLAN expansion to keep proactive-learn FIB entries consistent - Separate added_vlans from changed_vlans so new VLANs skip the unnecessary del_vlans() - Move changed-VLAN deletion before dp_init() so old managers clean up old select_packets flows - Add pipeline.remove_select(); route manager del_vlan() now cleans select_packets flows alongside FIB flows - Keep cold-start escalation for VID replacement when affected ports cover the DP ACL: - Replace cold_start_port with diff-at-source: snapshot the addmods the OLD acl_manager would emit before dp_init, ask the NEW one for the same after, emit only the rule-level delta. Cost scales with k (rules changed), not N (rules total) - Use OFPFC_DELETE_STRICT for ACL flowdels so a less-specific rule doesn't wildcard-delete more specific rules sharing its prefix - New changed_acl_vlans set in dp.py for VLANs whose only change is an ACL ref or referenced ACL's contents (covers acls_in + acls_out) - valve_table.flowdel grows a cookie kwarg; _flowmodkey in valve_of canonicalizes match contents via frozenset(items()) instead of OFPMatch identity - Fixes the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733 FaucetConfigReloadPortAclRemoveTest brought over from faucetsdn#4733 verbatim, with hieunt79 attributed below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
VLAN/VIP, router, and ACL config changes now warm-start instead of cold. The warm path (del_vlan + dp_init + add_vlan) already handled the VLAN-level changes; two guards in dp.py were short-circuiting to cold start, and ACL-only changes still went through cold_start_port which left stale flows on the wire. VLAN/VIP and router: - Replace router cold-start guard with finer checks (BGP changes and router add/remove with no routing tables stay cold) - Replace VIP cold-start guard with sibling-VLAN expansion to keep proactive-learn FIB entries consistent - Separate added_vlans from changed_vlans so new VLANs skip the unnecessary del_vlans() - Move changed-VLAN deletion before dp_init() so old managers clean up old select_packets flows - Add pipeline.remove_select(); route manager del_vlan() now cleans select_packets flows alongside FIB flows - Keep cold-start escalation for VID replacement when affected ports cover the DP ACL: - Replace cold_start_port with diff-at-source: snapshot the addmods the OLD acl_manager would emit before dp_init, ask the NEW one for the same after, emit only the rule-level delta. Cost scales with k (rules changed), not N (rules total) - Use OFPFC_DELETE_STRICT for ACL flowdels so a less-specific rule doesn't wildcard-delete more specific rules sharing its prefix - New changed_acl_vlans set in dp.py for VLANs whose only change is an ACL ref or referenced ACL's contents (covers acls_in + acls_out) - valve_table.flowdel grows a cookie kwarg; _flowmodkey in valve_of canonicalizes match contents via frozenset(items()) instead of OFPMatch identity - Fixes the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733 FaucetConfigReloadPortAclRemoveTest brought over from faucetsdn#4733 verbatim, with hieunt79 attributed below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
VLAN/VIP, router, and ACL config changes now warm-start instead of cold. The warm path (del_vlan + dp_init + add_vlan) already handled the VLAN-level changes; two guards in dp.py were short-circuiting to cold start, and ACL-only changes still went through cold_start_port which left stale flows on the wire. VLAN/VIP and router: - Replace router cold-start guard with finer checks (BGP changes and router add/remove with no routing tables stay cold) - Replace VIP cold-start guard with sibling-VLAN expansion to keep proactive-learn FIB entries consistent - Separate added_vlans from changed_vlans so new VLANs skip the unnecessary del_vlans() - Move changed-VLAN deletion before dp_init() so old managers clean up old select_packets flows - Add pipeline.remove_select(); route manager del_vlan() now cleans select_packets flows alongside FIB flows - Keep cold-start escalation for VID replacement when affected ports cover the DP ACL: - Replace cold_start_port with diff-at-source: snapshot the addmods the OLD acl_manager would emit before dp_init, ask the NEW one for the same after, emit only the rule-level delta. Cost scales with k (rules changed), not N (rules total) - Use OFPFC_DELETE_STRICT for ACL flowdels so a less-specific rule doesn't wildcard-delete more specific rules sharing its prefix - New changed_acl_vlans set in dp.py for VLANs whose only change is an ACL ref or referenced ACL's contents (covers acls_in + acls_out) - valve_table.flowdel grows a cookie kwarg; _flowmodkey in valve_of canonicalizes match contents via frozenset(items()) instead of OFPMatch identity - Fixes the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733 FaucetConfigReloadPortAclRemoveTest brought over from faucetsdn#4733 verbatim, with hieunt79 attributed below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
VLAN/VIP, router, and ACL config changes now warm-start instead of cold. The warm path (del_vlan + dp_init + add_vlan) already handled the VLAN-level changes; two guards in dp.py were short-circuiting to cold start, and ACL-only changes still went through cold_start_port which left stale flows on the wire. VLAN/VIP and router: - Replace router cold-start guard with finer checks (BGP changes and router add/remove with no routing tables stay cold) - Replace VIP cold-start guard with sibling-VLAN expansion to keep proactive-learn FIB entries consistent - Separate added_vlans from changed_vlans so new VLANs skip the unnecessary del_vlans() - Move changed-VLAN deletion before dp_init() so old managers clean up old select_packets flows - Add pipeline.remove_select(); route manager del_vlan() now cleans select_packets flows alongside FIB flows - Keep cold-start escalation for VID replacement when affected ports cover the DP ACL: - Replace cold_start_port with diff-at-source: snapshot the addmods the OLD acl_manager would emit before dp_init, ask the NEW one for the same after, emit only the rule-level delta. Cost scales with k (rules changed), not N (rules total) - Use OFPFC_DELETE_STRICT for ACL flowdels so a less-specific rule doesn't wildcard-delete more specific rules sharing its prefix - New changed_acl_vlans set in dp.py for VLANs whose only change is an ACL ref or referenced ACL's contents (covers acls_in + acls_out) - valve_table.flowdel grows a cookie kwarg; _flowmodkey in valve_of canonicalizes match contents via frozenset(items()) instead of OFPMatch identity - Fixes the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733 FaucetConfigReloadPortAclRemoveTest brought over from faucetsdn#4733 verbatim, with hieunt79 attributed below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
VLAN/VIP, router, and ACL config changes now warm-start instead of cold. The warm path (del_vlan + dp_init + add_vlan) already handled the VLAN-level changes; two guards in dp.py were short-circuiting to cold start, and ACL-only changes still went through cold_start_port which left stale flows on the wire. VLAN/VIP and router: - Replace router cold-start guard with finer checks (BGP changes and router add/remove with no routing tables stay cold) - Replace VIP cold-start guard with sibling-VLAN expansion to keep proactive-learn FIB entries consistent - Separate added_vlans from changed_vlans so new VLANs skip the unnecessary del_vlans() - Move changed-VLAN deletion before dp_init() so old managers clean up old select_packets flows - Add pipeline.remove_select(); route manager del_vlan() now cleans select_packets flows alongside FIB flows - Keep cold-start escalation for VID replacement when affected ports cover the DP ACL: - Replace cold_start_port with diff-at-source: snapshot the addmods the OLD acl_manager would emit before dp_init, ask the NEW one for the same after, emit only the rule-level delta. Cost scales with k (rules changed), not N (rules total) - Use OFPFC_DELETE_STRICT for ACL flowdels so a less-specific rule doesn't wildcard-delete more specific rules sharing its prefix - New changed_acl_vlans set in dp.py for VLANs whose only change is an ACL ref or referenced ACL's contents (covers acls_in + acls_out) - valve_table.flowdel grows a cookie kwarg; _flowmodkey in valve_of canonicalizes match contents via frozenset(items()) instead of OFPMatch identity - Fixes the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733 FaucetConfigReloadPortAclRemoveTest brought over from faucetsdn#4733 verbatim, with hieunt79 attributed below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
VLAN/VIP, router, and ACL config changes now warm-start instead of cold. The warm path (del_vlan + dp_init + add_vlan) already handled the VLAN-level changes; two guards in dp.py were short-circuiting to cold start, and ACL-only changes still went through cold_start_port which left stale flows on the wire. VLAN/VIP and router: - Replace router cold-start guard with finer checks (BGP changes and router add/remove with no routing tables stay cold) - Replace VIP cold-start guard with sibling-VLAN expansion to keep proactive-learn FIB entries consistent - Separate added_vlans from changed_vlans so new VLANs skip the unnecessary del_vlans() - Move changed-VLAN deletion before dp_init() so old managers clean up old select_packets flows - Add pipeline.remove_select(); route manager del_vlan() now cleans select_packets flows alongside FIB flows - Keep cold-start escalation for VID replacement when affected ports cover the DP ACL: - Replace cold_start_port with diff-at-source: snapshot the addmods the OLD acl_manager would emit before dp_init, ask the NEW one for the same after, emit only the rule-level delta. Cost scales with k (rules changed), not N (rules total) - Use OFPFC_DELETE_STRICT for ACL flowdels so a less-specific rule doesn't wildcard-delete more specific rules sharing its prefix - New changed_acl_vlans set in dp.py for VLANs whose only change is an ACL ref or referenced ACL's contents (covers acls_in + acls_out) - valve_table.flowdel grows a cookie kwarg; _flowmodkey in valve_of canonicalizes match contents via frozenset(items()) instead of OFPMatch identity - Fixes the stale block-ping flow gizmoguy reproduced reviewing faucetsdn#4733 FaucetConfigReloadPortAclRemoveTest brought over from faucetsdn#4733 verbatim, with hieunt79 attributed below. Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Adopts the per-ACL design @gizmoguy proposed in his 2026-05-01 review of faucetsdn#4733: for each port/VLAN whose only change is acls_in, iterate the old and new ACL lists and call del/add per-ACL with a cold-start priority decrement. remove_overlap_ofmsgs in valve_flowreorder cancels unchanged del+add pairs at flow-emit, so unchanged ACL rules don't churn on the wire. Inserting an ACL mid-list shifts subsequent priorities -- those re-emit (acceptable per gizmoguy's fallback in the linked review). dp.py - _acl_ref_changes returns (old_acls, new_acls) or None - _get_port_config_changes' changed_acl_ports becomes a dict port_num -> (old_acls, new_acls) - _get_vlan_config_changes returns a new changed_acl_vlans dict vid -> (old_acls, new_acls); ACL-only VLAN changes are no longer folded into changed_vlans so they warm-reload instead of cold valve.py _apply_config_changes - Per-ACL del+add loop replaces the prior cold_start_port handling for changed_acl_ports - New per-VLAN ACL loop using add_vlan_acl / del_vlan_acl - Empty<->non-empty port transitions need the wildcard rule flipped, so fall back to cold_start_port valve_acl.py - add_port_acl / del_port_acl get a priority kwarg defaulting to self.auth_priority so dot1x callers are unchanged - build_acl_port_of_msgs derives allow/force_port_vlan instructions from the pipeline (matching cold-start build_acl_ofmsgs), so rules with force_port_vlan: 1 land in the right table; dot1x ACLs never carry force_port_vlan: 1 so its behavior is preserved - New add_vlan_acl / del_vlan_acl symmetric to the port helpers (the methods gizmoguy noted were missing for per-ACL VLAN reload) Tests - FaucetConfigReloadVlanAclChangeTest and FaucetConfigReloadPortAclRemoveTest come from @hieunt79's faucetsdn#4733 (the latter exercises the bug gizmoguy reproduced reviewing faucetsdn#4733: removing one ACL from a port that has multiple ACLs must leave the others installed) - test_vlan_acl_update now expects warm reload (was cold) - ValveChangeVLANACLTestCase.test_change_vlan_acl now expects warm Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Adopts the per-ACL design @gizmoguy proposed in his 2026-05-01 review of faucetsdn#4733: for each port/VLAN whose only change is acls_in, iterate the old and new ACL lists and call del/add per-ACL with a cold-start priority decrement. remove_overlap_ofmsgs in valve_flowreorder cancels unchanged del+add pairs at flow-emit, so unchanged ACL rules don't churn on the wire. Inserting an ACL mid-list shifts subsequent priorities -- those re-emit (acceptable per gizmoguy's fallback in the linked review). dp.py - _acl_ref_changes returns (old_acls, new_acls) or None - _get_port_config_changes' changed_acl_ports becomes a dict port_num -> (old_acls, new_acls) - _get_vlan_config_changes returns a new changed_acl_vlans dict vid -> (old_acls, new_acls); ACL-only VLAN changes are no longer folded into changed_vlans so they warm-reload instead of cold valve.py _apply_config_changes - Per-ACL del+add loop replaces the prior cold_start_port handling for changed_acl_ports - New per-VLAN ACL loop using add_vlan_acl / del_vlan_acl - Empty<->non-empty port transitions need the wildcard rule flipped, so fall back to cold_start_port valve_acl.py - add_port_acl / del_port_acl get a priority kwarg defaulting to self.auth_priority so dot1x callers are unchanged - build_acl_port_of_msgs derives allow/force_port_vlan instructions from the pipeline (matching cold-start build_acl_ofmsgs), so rules with force_port_vlan: 1 land in the right table; dot1x ACLs never carry force_port_vlan: 1 so its behavior is preserved - New add_vlan_acl / del_vlan_acl symmetric to the port helpers (the methods gizmoguy noted were missing for per-ACL VLAN reload) Tests - FaucetConfigReloadVlanAclChangeTest and FaucetConfigReloadPortAclRemoveTest come from @hieunt79's faucetsdn#4733 (the latter exercises the bug gizmoguy reproduced reviewing faucetsdn#4733: removing one ACL from a port that has multiple ACLs must leave the others installed) - test_vlan_acl_update now expects warm reload (was cold) - ValveChangeVLANACLTestCase.test_change_vlan_acl now expects warm Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Adopts the per-ACL design @gizmoguy proposed in his 2026-05-01 review of faucetsdn#4733: for each port/VLAN whose only change is acls_in, iterate the old and new ACL lists and call del/add per-ACL with a cold-start priority decrement. remove_overlap_ofmsgs in valve_flowreorder cancels unchanged del+add pairs at flow-emit, so unchanged ACL rules don't churn on the wire. Inserting an ACL mid-list shifts subsequent priorities -- those re-emit (acceptable per gizmoguy's fallback in the linked review). dp.py - _acl_ref_changes returns (old_acls, new_acls) or None - _get_port_config_changes' changed_acl_ports becomes a dict port_num -> (old_acls, new_acls) - _get_vlan_config_changes returns a new changed_acl_vlans dict vid -> (old_acls, new_acls); ACL-only VLAN changes are no longer folded into changed_vlans so they warm-reload instead of cold valve.py _apply_config_changes - Per-ACL del+add loop replaces the prior cold_start_port handling for changed_acl_ports - New per-VLAN ACL loop using add_vlan_acl / del_vlan_acl - Empty<->non-empty port transitions need the wildcard rule flipped, so fall back to cold_start_port valve_acl.py - add_port_acl / del_port_acl get a priority kwarg defaulting to self.auth_priority so dot1x callers are unchanged - build_acl_port_of_msgs derives allow/force_port_vlan instructions from the pipeline (matching cold-start build_acl_ofmsgs), so rules with force_port_vlan: 1 land in the right table; dot1x ACLs never carry force_port_vlan: 1 so its behavior is preserved - New add_vlan_acl / del_vlan_acl symmetric to the port helpers (the methods gizmoguy noted were missing for per-ACL VLAN reload) Tests - FaucetConfigReloadVlanAclChangeTest and FaucetConfigReloadPortAclRemoveTest come from @hieunt79's faucetsdn#4733 (the latter exercises the bug gizmoguy reproduced reviewing faucetsdn#4733: removing one ACL from a port that has multiple ACLs must leave the others installed) - test_vlan_acl_update now expects warm reload (was cold) - ValveChangeVLANACLTestCase.test_change_vlan_acl now expects warm Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Adopts the per-ACL design @gizmoguy proposed in his 2026-05-01 review of faucetsdn#4733: for each port/VLAN whose only change is acls_in, iterate the old and new ACL lists and call del/add per-ACL with a cold-start priority decrement. remove_overlap_ofmsgs in valve_flowreorder cancels unchanged del+add pairs at flow-emit, so unchanged ACL rules don't churn on the wire. Inserting an ACL mid-list shifts subsequent priorities -- those re-emit (acceptable per gizmoguy's fallback in the linked review). dp.py - _acl_ref_changes returns (old_acls, new_acls) or None - _get_port_config_changes' changed_acl_ports becomes a dict port_num -> (old_acls, new_acls) - _get_vlan_config_changes returns a new changed_acl_vlans dict vid -> (old_acls, new_acls); ACL-only VLAN changes are no longer folded into changed_vlans so they warm-reload instead of cold valve.py _apply_config_changes - Per-ACL del+add loop replaces the prior cold_start_port handling for changed_acl_ports - New per-VLAN ACL loop using add_vlan_acl / del_vlan_acl - Empty<->non-empty port transitions need the wildcard rule flipped, so fall back to cold_start_port valve_acl.py - add_port_acl / del_port_acl get a priority kwarg defaulting to self.auth_priority so dot1x callers are unchanged - build_acl_port_of_msgs derives allow/force_port_vlan instructions from the pipeline (matching cold-start build_acl_ofmsgs), so rules with force_port_vlan: 1 land in the right table; dot1x ACLs never carry force_port_vlan: 1 so its behavior is preserved - New add_vlan_acl / del_vlan_acl symmetric to the port helpers (the methods gizmoguy noted were missing for per-ACL VLAN reload) Tests - FaucetConfigReloadVlanAclChangeTest and FaucetConfigReloadPortAclRemoveTest come from @hieunt79's faucetsdn#4733 (the latter exercises the bug gizmoguy reproduced reviewing faucetsdn#4733: removing one ACL from a port that has multiple ACLs must leave the others installed) - test_vlan_acl_update now expects warm reload (was cold) - ValveChangeVLANACLTestCase.test_change_vlan_acl now expects warm Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Adopts the per-ACL design @gizmoguy proposed in his 2026-05-01 review of faucetsdn#4733: for each port/VLAN whose only change is acls_in, iterate the old and new ACL lists and call del/add per-ACL with a cold-start priority decrement. remove_overlap_ofmsgs in valve_flowreorder cancels unchanged del+add pairs at flow-emit, so unchanged ACL rules don't churn on the wire. Inserting an ACL mid-list shifts subsequent priorities -- those re-emit (acceptable per gizmoguy's fallback in the linked review). dp.py - _acl_ref_changes returns (old_acls, new_acls) or None - _get_port_config_changes' changed_acl_ports becomes a dict port_num -> (old_acls, new_acls) - _get_vlan_config_changes returns a new changed_acl_vlans dict vid -> (old_acls, new_acls); ACL-only VLAN changes are no longer folded into changed_vlans so they warm-reload instead of cold valve.py _apply_config_changes - Per-ACL del+add loop replaces the prior cold_start_port handling for changed_acl_ports - New per-VLAN ACL loop using add_vlan_acl / del_vlan_acl - Empty<->non-empty port transitions need the wildcard rule flipped, so fall back to cold_start_port valve_acl.py - add_port_acl / del_port_acl get a priority kwarg defaulting to self.auth_priority so dot1x callers are unchanged - build_acl_port_of_msgs derives allow/force_port_vlan instructions from the pipeline (matching cold-start build_acl_ofmsgs), so rules with force_port_vlan: 1 land in the right table; dot1x ACLs never carry force_port_vlan: 1 so its behavior is preserved - New add_vlan_acl / del_vlan_acl symmetric to the port helpers (the methods gizmoguy noted were missing for per-ACL VLAN reload) - del_port's flowdel is now priority-less so its flowmodkey differs from the acl_priority wildcard that add_port emits for a port with no acls_in; without this, remove_overlap_ofmsgs cancels the delete and old ACL flows stay on the switch (the @hieunt79 fix from faucetsdn#4733) Tests - FaucetConfigReloadVlanAclChangeTest and FaucetConfigReloadPortAclRemoveTest come from @hieunt79's faucetsdn#4733 (the latter exercises the bug gizmoguy reproduced reviewing faucetsdn#4733: removing one ACL from a port that has multiple ACLs must leave the others installed) - FaucetConfigReloadPortAclRemoveAllTest covers removing the last ACL from a port; without the del_port fix above this hits the remove_overlap_ofmsgs cancellation and the old flow stays stale - test_vlan_acl_update now expects warm reload (was cold) - ValveChangeVLANACLTestCase.test_change_vlan_acl now expects warm Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Adopts the per-ACL design @gizmoguy proposed in his 2026-05-01 review of faucetsdn#4733: for each port/VLAN whose only change is acls_in, iterate the old and new ACL lists and call del/add per-ACL with a cold-start priority decrement. remove_overlap_ofmsgs in valve_flowreorder cancels unchanged del+add pairs at flow-emit, so unchanged ACL rules don't churn on the wire. Inserting an ACL mid-list shifts subsequent priorities -- those re-emit (acceptable per gizmoguy's fallback in the linked review). dp.py - _acl_ref_changes returns (old_acls, new_acls) or None - _get_port_config_changes' changed_acl_ports becomes a dict port_num -> (old_acls, new_acls) - _get_vlan_config_changes returns a new changed_acl_vlans dict vid -> (old_acls, new_acls); ACL-only VLAN changes are no longer folded into changed_vlans so they warm-reload instead of cold valve.py _apply_config_changes - Per-ACL del+add loop replaces the prior cold_start_port handling for changed_acl_ports - New per-VLAN ACL loop using add_vlan_acl / del_vlan_acl - Empty<->non-empty port transitions need the wildcard rule flipped, so fall back to cold_start_port valve_acl.py - add_port_acl / del_port_acl get a priority kwarg defaulting to self.auth_priority so dot1x callers are unchanged - build_acl_port_of_msgs derives allow/force_port_vlan instructions from the pipeline (matching cold-start build_acl_ofmsgs), so rules with force_port_vlan: 1 land in the right table; dot1x ACLs never carry force_port_vlan: 1 so its behavior is preserved - New add_vlan_acl / del_vlan_acl symmetric to the port helpers (the methods gizmoguy noted were missing for per-ACL VLAN reload) - del_port's flowdel is now priority-less so its flowmodkey differs from the acl_priority wildcard that add_port emits for a port with no acls_in; without this, remove_overlap_ofmsgs cancels the delete and old ACL flows stay on the switch (the @hieunt79 fix from faucetsdn#4733) Tests - FaucetConfigReloadVlanAclChangeTest and FaucetConfigReloadPortAclRemoveTest come from @hieunt79's faucetsdn#4733 (the latter exercises the bug gizmoguy reproduced reviewing faucetsdn#4733: removing one ACL from a port that has multiple ACLs must leave the others installed) - FaucetConfigReloadPortAclRemoveAllTest covers removing the last ACL from a port; without the del_port fix above this hits the remove_overlap_ofmsgs cancellation and the old flow stays stale - test_vlan_acl_update now expects warm reload (was cold) - ValveChangeVLANACLTestCase.test_change_vlan_acl now expects warm Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Adopts the per-ACL design @gizmoguy proposed in his 2026-05-01 review of faucetsdn#4733: for each port/VLAN whose only change is acls_in, iterate the old and new ACL lists and call del/add per-ACL with a cold-start priority decrement. remove_overlap_ofmsgs in valve_flowreorder cancels unchanged del+add pairs at flow-emit, so unchanged ACL rules don't churn on the wire. Inserting an ACL mid-list shifts subsequent priorities -- those re-emit (acceptable per gizmoguy's fallback in the linked review). dp.py - _acl_ref_changes returns (old_acls, new_acls) or None - _get_port_config_changes' changed_acl_ports becomes a dict port_num -> (old_acls, new_acls) - _get_vlan_config_changes returns a new changed_acl_vlans dict vid -> (old_acls, new_acls); ACL-only VLAN changes are no longer folded into changed_vlans so they warm-reload instead of cold valve.py _apply_config_changes - Per-ACL del+add loop replaces the prior cold_start_port handling for changed_acl_ports - New per-VLAN ACL loop using add_vlan_acl / del_vlan_acl - Empty<->non-empty port transitions need the wildcard rule flipped, so fall back to cold_start_port valve_acl.py - add_port_acl / del_port_acl get a priority kwarg defaulting to self.auth_priority so dot1x callers are unchanged - build_acl_port_of_msgs derives allow/force_port_vlan instructions from the pipeline (matching cold-start build_acl_ofmsgs), so rules with force_port_vlan: 1 land in the right table; dot1x ACLs never carry force_port_vlan: 1 so its behavior is preserved - New add_vlan_acl / del_vlan_acl symmetric to the port helpers (the methods gizmoguy noted were missing for per-ACL VLAN reload) - del_port's flowdel is now priority-less so its flowmodkey differs from the acl_priority wildcard that add_port emits for a port with no acls_in; without this, remove_overlap_ofmsgs cancels the delete and old ACL flows stay on the switch (the @hieunt79 fix from faucetsdn#4733) Tests - FaucetConfigReloadVlanAclChangeTest and FaucetConfigReloadPortAclRemoveTest come from @hieunt79's faucetsdn#4733 (the latter exercises the bug gizmoguy reproduced reviewing faucetsdn#4733: removing one ACL from a port that has multiple ACLs must leave the others installed) - FaucetConfigReloadPortAclRemoveAllTest covers removing the last ACL from a port; without the del_port fix above this hits the remove_overlap_ofmsgs cancellation and the old flow stays stale - test_vlan_acl_update now expects warm reload (was cold) - ValveChangeVLANACLTestCase.test_change_vlan_acl now expects warm Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Adopts the per-ACL design @gizmoguy proposed in his 2026-05-01 review of faucetsdn#4733: for each port/VLAN whose only change is acls_in, iterate the old and new ACL lists and call del/add per-ACL with a cold-start priority decrement. remove_overlap_ofmsgs in valve_flowreorder cancels unchanged del+add pairs at flow-emit, so unchanged ACL rules don't churn on the wire. Inserting an ACL mid-list shifts subsequent priorities -- those re-emit (acceptable per gizmoguy's fallback in the linked review). dp.py - _acl_ref_changes returns (old_acls, new_acls) or None - _get_port_config_changes' changed_acl_ports becomes a dict port_num -> (old_acls, new_acls) - _get_vlan_config_changes returns a new changed_acl_vlans dict vid -> (old_acls, new_acls); ACL-only VLAN changes are no longer folded into changed_vlans so they warm-reload instead of cold valve.py _apply_config_changes - Per-ACL del+add loop replaces the prior cold_start_port handling for changed_acl_ports - New per-VLAN ACL loop using add_vlan_acl / del_vlan_acl - Empty<->non-empty port transitions need the wildcard rule flipped, so fall back to cold_start_port valve_acl.py - add_port_acl / del_port_acl get a priority kwarg defaulting to self.auth_priority so dot1x callers are unchanged - build_acl_port_of_msgs derives allow/force_port_vlan instructions from the pipeline (matching cold-start build_acl_ofmsgs), so rules with force_port_vlan: 1 land in the right table; dot1x ACLs never carry force_port_vlan: 1 so its behavior is preserved - New add_vlan_acl / del_vlan_acl symmetric to the port helpers (the methods gizmoguy noted were missing for per-ACL VLAN reload) - del_port's flowdel is now priority-less so its flowmodkey differs from the acl_priority wildcard that add_port emits for a port with no acls_in; without this, remove_overlap_ofmsgs cancels the delete and old ACL flows stay on the switch (the @hieunt79 fix from faucetsdn#4733) Tests - FaucetConfigReloadVlanAclChangeTest and FaucetConfigReloadPortAclRemoveTest come from @hieunt79's faucetsdn#4733 (the latter exercises the bug gizmoguy reproduced reviewing faucetsdn#4733: removing one ACL from a port that has multiple ACLs must leave the others installed) - FaucetConfigReloadPortAclRemoveAllTest covers removing the last ACL from a port; without the del_port fix above this hits the remove_overlap_ofmsgs cancellation and the old flow stays stale. Both ports share the same ACL so removing it from one port doesn't change the overall pipeline match set (which would otherwise force cold-start for table reconfiguration) - ValveRemoveAllPortACLsTestCase covers the same scenario at unit level - test_vlan_acl_update now expects warm reload (was cold) - ValveChangeVLANACLTestCase.test_change_vlan_acl now expects warm Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Adopts the per-ACL design @gizmoguy proposed in his 2026-05-01 review of faucetsdn#4733: for each port/VLAN whose only change is acls_in, iterate the old and new ACL lists and call del/add per-ACL with a cold-start priority decrement. remove_overlap_ofmsgs in valve_flowreorder cancels unchanged del+add pairs at flow-emit, so unchanged ACL rules don't churn on the wire. Inserting an ACL mid-list shifts subsequent priorities -- those re-emit (acceptable per gizmoguy's fallback in the linked review). dp.py - _get_vlan_config_changes returns a new changed_acl_vlans set; ACL-only VLAN changes are no longer folded into changed_vlans so they warm-reload instead of cold valve.py _apply_config_changes - Snapshot the old acls_in lists before dp_init swaps self.dp - Per-ACL del+add loop replaces the prior cold_start_port handling for changed_acl_ports, and adds the equivalent for changed_acl_vlans - Empty<->non-empty port transitions need the wildcard rule flipped, so fall back to cold_start_port valve_acl.py - add_port_acl / del_port_acl get a priority kwarg defaulting to self.auth_priority so dot1x callers are unchanged - build_acl_port_of_msgs derives allow/force_port_vlan instructions from the pipeline (matching cold-start build_acl_ofmsgs), so rules with force_port_vlan: 1 land in the right table; dot1x ACLs never carry force_port_vlan: 1 so its behavior is preserved - New add_vlan_acl / del_vlan_acl symmetric to the port helpers (the methods gizmoguy noted were missing for per-ACL VLAN reload) - del_port's flowdel is now priority-less so its flowmodkey differs from the acl_priority wildcard that add_port emits for a port with no acls_in; without this, remove_overlap_ofmsgs cancels the delete and old ACL flows stay on the switch (the @hieunt79 fix from faucetsdn#4733) Tests - FaucetConfigReloadVlanAclChangeTest and FaucetConfigReloadPortAclRemoveTest come from @hieunt79's faucetsdn#4733 (the latter exercises the bug gizmoguy reproduced reviewing faucetsdn#4733: removing one ACL from a port that has multiple ACLs must leave the others installed) - FaucetConfigReloadPortAclRemoveAllTest covers removing the last ACL from a port; without the del_port fix above this hits the remove_overlap_ofmsgs cancellation and the old flow stays stale. Both ports share the same ACL so removing it from one port doesn't change the overall pipeline match set (which would otherwise force cold-start for table reconfiguration) - ValveRemoveAllPortACLsTestCase covers the same scenario at unit level - test_vlan_acl_update now expects warm reload (was cold) - ValveChangeVLANACLTestCase.test_change_vlan_acl now expects warm Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Adopts the per-ACL design @gizmoguy proposed in his 2026-05-01 review of faucetsdn#4733: for each port/VLAN whose only change is acls_in, iterate the old and new ACL lists and call del/add per-ACL with a cold-start priority decrement. remove_overlap_ofmsgs in valve_flowreorder cancels unchanged del+add pairs at flow-emit, so unchanged ACL rules don't churn on the wire. Inserting an ACL mid-list shifts subsequent priorities -- those re-emit (acceptable per gizmoguy's fallback in the linked review). dp.py - _get_vlan_config_changes returns a new changed_acl_vlans set; ACL-only VLAN changes are no longer folded into changed_vlans so they warm-reload instead of cold valve.py _apply_config_changes - Snapshot the old acls_in lists before dp_init swaps self.dp - Per-ACL del+add loop replaces the prior cold_start_port handling for changed_acl_ports, and adds the equivalent for changed_acl_vlans - Empty<->non-empty port transitions need the wildcard rule flipped, so fall back to cold_start_port valve_acl.py - add_port_acl / del_port_acl get a priority kwarg defaulting to self.auth_priority so dot1x callers are unchanged - build_acl_port_of_msgs derives allow/force_port_vlan instructions from the pipeline (matching cold-start build_acl_ofmsgs), so rules with force_port_vlan: 1 land in the right table; dot1x ACLs never carry force_port_vlan: 1 so its behavior is preserved - New add_vlan_acl / del_vlan_acl symmetric to the port helpers (the methods gizmoguy noted were missing for per-ACL VLAN reload) - del_port's flowdel is now priority-less so its flowmodkey differs from the acl_priority wildcard that add_port emits for a port with no acls_in; without this, remove_overlap_ofmsgs cancels the delete and old ACL flows stay on the switch (the @hieunt79 fix from faucetsdn#4733) Tests - FaucetConfigReloadVlanAclChangeTest and FaucetConfigReloadPortAclRemoveTest come from @hieunt79's faucetsdn#4733 (the latter exercises the bug gizmoguy reproduced reviewing faucetsdn#4733: removing one ACL from a port that has multiple ACLs must leave the others installed) - FaucetConfigReloadPortAclRemoveAllTest covers removing the last ACL from a port; without the del_port fix above this hits the remove_overlap_ofmsgs cancellation and the old flow stays stale. Both ports share the same ACL so removing it from one port doesn't change the overall pipeline match set (which would otherwise force cold-start for table reconfiguration) - ValveRemoveAllPortACLsTestCase covers the same scenario at unit level - test_vlan_acl_update now expects warm reload (was cold) - ValveChangeVLANACLTestCase.test_change_vlan_acl now expects warm Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Adopts the per-ACL design @gizmoguy proposed in his 2026-05-01 review of faucetsdn#4733: for each port/VLAN whose only change is acls_in, iterate the old and new ACL lists and call del/add per-ACL with a cold-start priority decrement. remove_overlap_ofmsgs in valve_flowreorder cancels unchanged del+add pairs at flow-emit, so unchanged ACL rules don't churn on the wire. Inserting an ACL mid-list shifts subsequent priorities -- those re-emit (acceptable per gizmoguy's fallback in the linked review). dp.py - _get_vlan_config_changes returns a new changed_acl_vlans set; ACL-only VLAN changes are no longer folded into changed_vlans so they warm-reload instead of cold valve.py _apply_config_changes - Snapshot the old acls_in lists before dp_init swaps self.dp - Per-ACL del+add loop replaces the prior cold_start_port handling for changed_acl_ports, and adds the equivalent for changed_acl_vlans - Empty<->non-empty port transitions need the wildcard rule flipped, so fall back to cold_start_port valve_acl.py - add_port_acl / del_port_acl get a priority kwarg defaulting to self.auth_priority so dot1x callers are unchanged - build_acl_port_of_msgs derives allow/force_port_vlan instructions from the pipeline (matching cold-start build_acl_ofmsgs), so rules with force_port_vlan: 1 land in the right table; dot1x ACLs never carry force_port_vlan: 1 so its behavior is preserved - New add_vlan_acl / del_vlan_acl symmetric to the port helpers (the methods gizmoguy noted were missing for per-ACL VLAN reload) - del_port's flowdel is now priority-less so its flowmodkey differs from the acl_priority wildcard that add_port emits for a port with no acls_in; without this, remove_overlap_ofmsgs cancels the delete and old ACL flows stay on the switch (the @hieunt79 fix from faucetsdn#4733) Tests - FaucetConfigReloadVlanAclChangeTest and FaucetConfigReloadPortAclRemoveTest come from @hieunt79's faucetsdn#4733 (the latter exercises the bug gizmoguy reproduced reviewing faucetsdn#4733: removing one ACL from a port that has multiple ACLs must leave the others installed) - FaucetConfigReloadPortAclRemoveAllTest covers removing the last ACL from a port; without the del_port fix above this hits the remove_overlap_ofmsgs cancellation and the old flow stays stale. Both ports share the same ACL so removing it from one port doesn't change the overall pipeline match set (which would otherwise force cold-start for table reconfiguration) - ValveRemoveAllPortACLsTestCase covers the same scenario at unit level - test_vlan_acl_update now expects warm reload (was cold) - ValveChangeVLANACLTestCase.test_change_vlan_acl now expects warm Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
Adopts the per-ACL design @gizmoguy proposed in his 2026-05-01 review of faucetsdn#4733: for each port/VLAN whose only change is acls_in, iterate the old and new ACL lists and call del/add per-ACL with a cold-start priority decrement. remove_overlap_ofmsgs in valve_flowreorder cancels unchanged del+add pairs at flow-emit, so unchanged ACL rules don't churn on the wire. Inserting an ACL mid-list shifts subsequent priorities -- those re-emit (acceptable per gizmoguy's fallback in the linked review). dp.py - _get_vlan_config_changes returns a new changed_acl_vlans set; ACL-only VLAN changes are no longer folded into changed_vlans so they warm-reload instead of cold valve.py _apply_config_changes - Snapshot the old acls_in lists before dp_init swaps self.dp - Per-ACL del+add loop replaces the prior cold_start_port handling for changed_acl_ports, and adds the equivalent for changed_acl_vlans - Empty<->non-empty port transitions need the wildcard rule flipped, so fall back to cold_start_port valve_acl.py - add_port_acl / del_port_acl get a priority kwarg defaulting to self.auth_priority so dot1x callers are unchanged - build_acl_port_of_msgs derives allow/force_port_vlan instructions from the pipeline (matching cold-start build_acl_ofmsgs), so rules with force_port_vlan: 1 land in the right table; dot1x ACLs never carry force_port_vlan: 1 so its behavior is preserved - New add_vlan_acl / del_vlan_acl symmetric to the port helpers (the methods gizmoguy noted were missing for per-ACL VLAN reload) - del_port's flowdel is now priority-less so its flowmodkey differs from the acl_priority wildcard that add_port emits for a port with no acls_in; without this, remove_overlap_ofmsgs cancels the delete and old ACL flows stay on the switch (the @hieunt79 fix from faucetsdn#4733) Tests - FaucetConfigReloadVlanAclChangeTest and FaucetConfigReloadPortAclRemoveTest come from @hieunt79's faucetsdn#4733 (the latter exercises the bug gizmoguy reproduced reviewing faucetsdn#4733: removing one ACL from a port that has multiple ACLs must leave the others installed) - FaucetConfigReloadPortAclRemoveAllTest covers removing the last ACL from a port; without the del_port fix above this hits the remove_overlap_ofmsgs cancellation and the old flow stays stale. Both ports share the same ACL so removing it from one port doesn't change the overall pipeline match set (which would otherwise force cold-start for table reconfiguration) - ValveRemoveAllPortACLsTestCase covers the same scenario at unit level - test_vlan_acl_update now expects warm reload (was cold) - ValveChangeVLANACLTestCase.test_change_vlan_acl now expects warm Co-Authored-By: hieunt79 <nguyenhieu264996@gmail.com>
|
Hi @hieunt79, thanks for the hard work on this. I had a go at fixing some edge cases I found in this patch and submitted my own separate patch (#4819) which addresses these issues. I've credited your contribution on this issue by adding you as a co-author of the patch. Please leave any comments and/or feedback on my PR if you find any issues with it and include any relevant faucet configuration files that are showing incorrect behaviour. |
|
Hi @gizmoguy, thanks for resolving this issue. Could you please correct my email in these commits? I made a typo, correct is nguyenhieu26496@gmail.com |
|
@hieunt79 email should be updated now |
I want to perform a warm reload when the VLAN ACL changes, so I made the following updates: