Skip to content

[ZTP] Re-assert front panel port config after ZTP profile removal - #6

Merged
gord1306 merged 1 commit into
202311.X_4630_10g_prodfrom
fix/ztp-reassert-port-config-after-teardown
Aug 11, 2026
Merged

[ZTP] Re-assert front panel port config after ZTP profile removal#6
gord1306 merged 1 commit into
202311.X_4630_10g_prodfrom
fix/ztp-reassert-port-config-after-teardown

Conversation

@gord1306

@gord1306 gord1306 commented Aug 10, 2026

Copy link
Copy Markdown

Why I did it

When ZTP completes, ztp-profile.sh remove deletes ZTP|mode from CONFIG_DB and then restarts interfaces-config:

287|             sonic-db-cli CONFIG_DB DEL "ZTP|mode" > /dev/null
292|         systemctl restart interfaces-config

interfaces-config regenerates /etc/network/interfaces from interfaces.j2, whose ZTP in-band block is gated on ZTP['mode'] being defined:

35| {% if (ZTP_DHCP_DISABLED is not defined) and (ZTP is defined) and (ZTP['mode'] is defined) %}
50| {% if ZTP['mode']['inband'] == 'true' %}
54| auto {{ port }}
56| {% if PORT_DATA['PORT_TABLE:'+port]['value']['oper_status'] == 'up' %}
58| iface {{ port }} inet dhcp

With that table gone the block is no longer rendered, so the regenerated file contains no Ethernet stanza at all. interfaces-config.sh:70 then runs systemctl restart networking, which performs ifdown -a followed by ifup -a. ifupdown2 tears down every front panel port it had adopted for ZTP in-band DHCP, and ifup -a does not bring them back because they are no longer listed. The netdev is left administratively down with its MTU reset to the kernel default, while CONFIG_DB, APPL_DB and the ASIC all continue to report the port as up.

portmgrd only acts on CONFIG_DB events and keeps no desired state: portmgr.cpp:336 erases the event once applied, and the 1 s tick in portmgrd.cpp:58 calls Consumer::drain(), which returns immediately when m_toSync is empty. It therefore never notices nor corrects the drift, and the port stays down until something writes CONFIG_DB — which is why a manual config interface shutdown/startup recovers it.

Anything running on the Linux netdev, LLDP and DHCP in particular, stops working on the affected port while show interfaces status keeps reporting up/up, since that command reads APPL_DB.

Which ports are affected depends on which ones happened to be oper up when interfaces-config.sh:34 sampled APPL_DB with redis-dump, so the failure can look intermittent. Note that waiting for all ports to come up before that sample would make it worse rather than better: it would turn an intermittent single port failure into a deterministic all ports failure.

How I did it

Re-assert the front panel port configuration after the interfaces-config restart.

Writing any field of CONFIG_DB PORT|<port> back with its current value produces a keyspace event, and SubscriberStateTable::pops() delivers the entire hash to the consumer:

// sonic-swss-common  common/subscriberstatetable.cpp
if (!m_table.get(key, kfvFieldsValues(kco)))   // whole hash, not just the changed field

so portmgrd re-applies both mtu and admin_status even though only admin_status is written. The write is idempotent and does not flap a port that is already up.

interfaces-config.service and networking.service are both Type=oneshot and neither restart uses --no-block, so ifdown/ifup have completed by the time the loop runs.

How to verify it

On a unit doing inband ZTP, after ZTP reaches "ZTP successfully completed" and the profile has been removed:

ip -o link show | grep Ethernet | grep -c 'state UP'
grep -cE '^auto Ethernet|^iface Ethernet' /etc/network/interfaces
show interfaces status

The second command returns 0, confirming the ZTP stanzas are gone and the removal path has run. Without this change the first command also drops to 0 while show interfaces status still reports every port as up. With the change the front panel ports that have carrier stay up, and show interfaces status agrees with ip link.

Measured on a 54 port unit: the loop issues 108 portmgrd re-applications (mtu and admin_status for each port) and completes in 1.8 seconds.

Notes

  • This is a remediation rather than a root fix. The port is still torn down briefly before being restored; the change stops that from becoming permanent. Preventing the teardown itself would mean keeping front panel ports out of ifupdown2's scope, which is a much larger change.
  • The config-fallback sub-path already performs config reload, which re-applies everything, so the loop is redundant but harmless there.
  • No automated test coverage: tests/test_ztp_engine.py does not exercise ztp-profile.sh.

When ZTP completes, ztp-profile.sh remove deletes ZTP|mode from CONFIG_DB and
then restarts interfaces-config. interfaces-config regenerates
/etc/network/interfaces from interfaces.j2, whose ZTP in-band block is gated on
ZTP['mode'] being defined. With that table gone the block is no longer rendered
and the regenerated file contains no Ethernet stanza at all.

interfaces-config.sh then runs "systemctl restart networking", which performs
"ifdown -a" followed by "ifup -a". ifupdown2 tears down every front panel port
it had adopted for ZTP in-band DHCP, and ifup -a does not bring them back
because they are no longer listed. The netdev is left administratively down with
its MTU reset to the kernel default of 1500, while CONFIG_DB, APPL_DB and the
ASIC all continue to report the port as up.

portmgrd only acts on CONFIG_DB events and keeps no desired state, so it never
notices nor corrects the drift. The port stays down until something writes
CONFIG_DB, which is why a manual config interface shutdown/startup recovers it.

Anything running on the Linux netdev, LLDP and DHCP in particular, stops working
on the affected port while "show interfaces status" keeps reporting up/up, since
that command reads APPL_DB. Which ports are affected depends on which ones
happened to be oper up when interfaces-config sampled APPL_DB with redis-dump,
so the failure can look intermittent.

Re-assert the front panel port configuration after the interfaces-config
restart. Writing any field of CONFIG_DB PORT|<port> back with its current value
produces a keyspace event, and SubscriberStateTable delivers the entire hash to
the consumer, so portmgrd re-applies both mtu and admin_status. The write is
idempotent and does not flap a port that is already up.

Measured on a 54 port platform: the loop issues 108 portmgrd re-applications,
mtu and admin_status for each port, and completes in 1.8 seconds.

interfaces-config.service and networking.service are both Type=oneshot and
neither restart uses --no-block, so ifdown/ifup have completed by the time the
loop runs.

Signed-off-by: gord_chen <gord_chen@edge-core.com>
@gord1306
gord1306 force-pushed the fix/ztp-reassert-port-config-after-teardown branch from a0f6f27 to dd82ca1 Compare August 11, 2026 02:47
@gord1306
gord1306 requested review from chenkelly and linarnan August 11, 2026 02:56
@gord1306
gord1306 merged commit 89fd507 into 202311.X_4630_10g_prod Aug 11, 2026
1 check passed
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.

1 participant