Skip to content

Allow warm restart for VLAN/VIP, router, and ACL configuration changes - #4799

Closed
courtland wants to merge 1 commit into
faucetsdn:mainfrom
courtland:warm-restart-vlan-vip
Closed

Allow warm restart for VLAN/VIP, router, and ACL configuration changes#4799
courtland wants to merge 1 commit into
faucetsdn:mainfrom
courtland:warm-restart-vlan-vip

Conversation

@courtland

@courtland courtland commented May 1, 2026

Copy link
Copy Markdown

Summary

Changes to a VLAN's VIPs, router configuration, or ACL configuration currently force a cold restart — full datapath reconnection and a flow-table wipe. This is unnecessarily disruptive for deployments that update these dynamically (tenant provisioning, IPAM-driven VIP changes, dynamic router membership, ACL edits).

The warm-restart path (del_vlan + dp_init + add_vlan) already handles VLAN-level changes; two guards in dp.py were short-circuiting to cold, and ACL-only changes still went through cold_start_port which left stale flows on the wire. This PR removes the guards, fixes the cleanup, and replaces the ACL cold-start path with a diff-at-source granular reload that emits only changed rules — cost is O(k) where k = rules changed, regardless of total ACL size.

What warm-starts now (previously cold)

Scenario Before After
Change VIP address on VLAN Cold Warm
Add/remove VIPs on existing VLAN (routing tables exist) Cold Warm
Change router VLAN membership (non-BGP) Cold Warm
Add/remove router (routing tables exist) Cold Warm
Add new VLAN with VIPs (OVS, routing tables exist) Cold Warm
Change a port's acls_in Cold Warm
Change a VLAN's acls_in / acls_out Cold Warm
Edit rules of an ACL referenced by a port or VLAN Cold Warm

What still cold-starts

  • BGP config changes
  • Router add/remove with no existing routing tables
  • VID replacement when affected ports cover the DP
  • Pipeline changes (e.g. first-ever VIP adds ipv4_fib / vip tables)
  • TFM table-size changes (out of scope)
  • All ports changed

Scope rationale

VLAN/VIP and router warm-restart are inseparable: VIP changes must propagate to router-sibling VLANs for FIB consistency, and router membership changes drive the same VLAN reinstall plumbing. ACL warm-restart is technically a separable follow-up but rides the same del_vlan / dp_init / add_vlan infrastructure — absorbing it here (per offline thread with @gizmoguy) obsoletes #4733 in one merge instead of two.

_flowmodkey canonicalises match contents and instructions because OFPMatch and OFPInstruction fall back to identity __eq__. Without canonicalisation the OLD/NEW addmod snapshots wouldn't diff structurally, and an ACL rule whose action flipped (e.g. allow:0 → allow:1, same match) would look unchanged on the wire. The canonicalisation is global rather than a diff-only key so it applies everywhere flowmod equality matters (dedup, overlap-cancellation).

Relation to #4733

This PR now incorporates #4733's goals. Instead of looping per-ACL with del_port_acl / add_port_acl, it snapshots the addmods that add_port / add_vlan would emit and diffs them — the priority/cookie scheme matches what cold-start install put on the table by construction, which the per-ACL helpers don't (they reset priority per-ACL). FaucetConfigReloadPortAclRemoveTest is included verbatim with Co-Authored-By: hieunt79. The stale-block-ping flow @gizmoguy reproduced is fixed.

If merged, #4733 can be closed.

@codecov

codecov Bot commented May 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.29412% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.56%. Comparing base (9bc5528) to head (2c70afc).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
faucet/dp.py 95.45% 4 Missing ⚠️
faucet/valve_acl.py 86.21% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4799      +/-   ##
==========================================
+ Coverage   91.42%   91.56%   +0.15%     
==========================================
  Files          46       46              
  Lines        8923     9054     +131     
==========================================
+ Hits         8157     8290     +133     
+ Misses        766      764       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@courtland
courtland marked this pull request as ready for review May 1, 2026 18:01
@gizmoguy

gizmoguy commented May 7, 2026

Copy link
Copy Markdown
Member

I tested this patch with the case where a single VLAN has its VIP change, e.g starting faucet with this configuration:

vlans:
    office:
        vid: 100
        description: "office network"
        faucet_vips: ["10.0.0.1/24"]
        faucet_mac: "00:00:00:00:00:11"
dps:
    sw1:
        dp_id: 0x1
        hardware: "Open vSwitch"
        interfaces:
            1:
                name: "host1"
                native_vlan: office
            2:
                name: "host2"
                native_vlan: office

and then changing only the VIP and reloading faucet with SIGUP, i.e:

vlans:
    office:
        vid: 100
        description: "office network"
        faucet_vips: ["10.0.0.2/24"]
        faucet_mac: "00:00:00:00:00:11"
dps:
    sw1:
        dp_id: 0x1
        hardware: "Open vSwitch"
        interfaces:
            1:
                name: "host1"
                native_vlan: office
            2:
                name: "host2"
                native_vlan: office

This triggers a cold restart:

May 07 02:26:50 faucet INFO     Reloading configuration
May 07 02:26:50 faucet INFO     configuration /etc/faucet/faucet.yaml changed, analyzing differences
May 07 02:26:50 faucet INFO     Reconfiguring existing datapath DPID 1 (0x1)
May 07 02:26:50 faucet.valve INFO     DPID 1 (0x1) sw1 no ACL changes
May 07 02:26:50 faucet.valve INFO     DPID 1 (0x1) sw1 VLAN 100 changed:   {
      "description": "office network",
      "dot1x_assigned": false,
      "edge_learn_stack_root": true,
      "faucet_mac": "00:00:00:00:00:11",
      "faucet_vips": [
-         "10.0.0.1/24"
?                 ^

+         "10.0.0.2/24"
?                 ^

      ],
      "max_hosts": 256,
      "minimum_ip_size_check": true,
      "proactive_arp_limit": 512,
      "proactive_nd_limit": 512,
      "reserved_internal_vlan": false,
      "targeted_gw_resolution": true,
      "unicast_flood": true,
      "vid": 100
  }
May 07 02:26:50 faucet.valve INFO     DPID 1 (0x1) sw1 VLANs changed: {100}
May 07 02:26:50 faucet.valve INFO     DPID 1 (0x1) sw1 no METERS changes
May 07 02:26:50 faucet.valve INFO     DPID 1 (0x1) sw1 no port changes
May 07 02:26:50 faucet.valve INFO     DPID 1 (0x1) sw1 all ports changed
May 07 02:26:50 faucet.valve INFO     DPID 1 (0x1) sw1 IPv4 routing is active on VLAN office vid:100 untagged: Port 1,Port 2 with VIPs ['10.0.0.2/24']
May 07 02:26:50 faucet.valve INFO     DPID 1 (0x1) sw1 cold starting
May 07 02:26:50 faucet.valve INFO     DPID 1 (0x1) sw1 forcing DP reconnection to ensure ports are synchronized

Is this the expected behaviour? As I read the PR description, this should trigger the Change VIP address on VLAN case which should warm start and does not hit the first-ever VIP case which triggers a cold start.

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>
@courtland
courtland force-pushed the warm-restart-vlan-vip branch from 13af1a1 to 2c70afc Compare May 12, 2026 19:01
@courtland courtland changed the title Allow warm restart for VLAN/VIP and router configuration changes Allow warm restart for VLAN/VIP, router, and ACL configuration changes May 12, 2026
@courtland

Copy link
Copy Markdown
Author

@gizmoguy — yes, single-VLAN-owns-all-ports VIP changes were still cold-restarting in the prior version. The cross-VLAN port-change escalation in _get_port_config_changes was over-promoting to all_ports_changed whenever changed_vlans covered all DP ports — your test config hits it exactly. Our production runs multi-VLAN per DP so we didn't exercise that topology and the original PR missed it. Fixed in this push, ValveChangeVIPSingleVLANAllPortsWarmStartTestCase covers it.

This push also absorbs the warm-ACL-reload work from #4733 — supersession-with-attribution per our offline thread. @hieunt79 is Co-Authored-By with FaucetConfigReloadPortAclRemoveTest included verbatim.

Mechanism deviates slightly from your 2026-05-01 per-ACL del_port_acl / add_port_acl proposal: I snapshot the addmods add_port / add_vlan would emit around dp_init and emit only the delta. Per-ACL helpers restart priority per-ACL while cold-start install decrements across all rules of all ACLs, so reusing them at port granularity produces flows at non-canonical priorities that don't cancel cleanly via remove_overlap_ofmsgs. Snapshotting add_port / add_vlan keeps the priority scheme aligned by construction.

Two supporting fixes — both touching _flowmodkey globally — are documented in the updated description. This closes #4733 on merge.

@courtland

Copy link
Copy Markdown
Author

Closing in favor of opening individual PRs for the various warm reload cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants