Skip to content

Address racey SAI PHY Serdes object causing bad syncd setup - #1945

Open
justin-wong-ce wants to merge 11 commits into
sonic-net:masterfrom
justin-wong-ce:port-phy-retry
Open

Address racey SAI PHY Serdes object causing bad syncd setup#1945
justin-wong-ce wants to merge 11 commits into
sonic-net:masterfrom
justin-wong-ce:port-phy-retry

Conversation

@justin-wong-ce

@justin-wong-ce justin-wong-ce commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Description of PR

Summary:
Mitigate a race condition in Port PHY Serdes initialization (syncd) where the SAI is still busy with the object from its creation when syncd's intialization attempts to read attributes from the object for syncd's own setup.

This race condition will cause a failing SAI call that is needed for initializing syncd, causing polls to the Port PHY Serdes object to fail continuously later on. The chances of this happening is around ~2.5% per config reload / reboot.

Do this by allowing 5 retries with 10ms wait intervals in between tries. The retry will only trigger when the failure reason is SAI_STATUS_OBJECT_IN_USE.

Fixes #1946

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Documentation update
  • Test improvement

Approach

What is the motivation for this PR?

Fix syslog ERRs that logs continuously when this scenario occurs.

Work item tracking
  • Microsoft ADO (number only):

How did you do it?

Added multiple attempts for interacing with Port PHY Serdes object over SAI during setup.

How did you verify/test it?

Continuous syslog ERRs no longer occur. The retry logic can be seen working in the syslogs as well. The most retry attempts observed is 1.

Any platform specific information?

Broadcom.

Documentation

Mitigate a race condition in Port PHY Serdes initialization (syncd)
where the SAI is still busy with the object from its creation when syncd's
intialization attempts to read attributes from the object for syncd's
own setup.

Do this by allowing 3 retries with 10ms wait intervals in between tries.
The retry will only trigger when the failure reason is
SAI_STATUS_OBJECT_IN_USE.

Signed-off-by: Justin Wong <jvwong@arista.com>
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Signed-off-by: Justin Wong <jvwong@arista.com>
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Comment thread syncd/FlexCounter.cpp
port_rid = attr.value.oid;
return true;
}
sai_status_t status = Base::m_vendorSai->get(Base::m_objectType, port_serdes_rid, 1, &attr);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey Justin - the fix is a bit of "by-chance".

Also supposedly,

  1. flex counter should not fail syncd init
  2. flex counter should work after the objects gets created

so I wonder if we have looked deeper into the failure/race and see what might be happening?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above, the race condition is from the SAI not being able to handle the Port PHY Serdes object creation and accessing of its attribute in extremely quick succession.

Either the SAI needs to be able to delay a request and not return SAI_STATUS_OBJECT_IN_USE, or Sonic (syncd initialization for this case) needs to be able to handle SAI_STATUS_OBJECT_IN_USE properly.

the fix is a bit of "by-chance"

I can change the fix such that it will retry until SAI does not return the SAI_STATUS_OBJECT_IN_USE, rather than just 3 times - this will remove the chance element.

I think it is reasonable to retry when the SAI returns SAI_STATUS_OBJECT_IN_USE since the object is busy and not available for read.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please let me know what you think of the latest changes

@r12f r12f Jun 18, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if we just simply skip the failed round and retry in the next pulling interval?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

retrying 3 times is not going to guarantee the fix anyway.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error is occuring during the initialization stage and this code that is being edited is for the initialization of Port PHY Serdes.
This will print the following ERR syslog once - during syncd's intialization:

30979 2026 Jun  7 20:56:03.499522 qspf201 ERR syncd#syncd: :- initAttrData: PORT_PHY_SERDES_ATTR: port_serdes_rid:0xb005700000000 has no serdes count attribute information
30980 2026 Jun  7 20:56:03.499522 qspf201 WARNING syncd#syncd: :- collectData: PORT_PHY_SERDES_ATTR: Failed to initialize attribute SAI_PORT_SERDES_ATTR_TX_FIR_TAPS_LIST for RID:0xb005700000000, skipping object

If SAI_STATUS_OBJECT_IN_USE is returned here and we don't retry, this will result missing info (maps) that is used to do other initalization steps later on, as it is treated as a failure.

If the info is missing, it will cause polling to fail all the time.
The following ERR syslog will print at every single poll interval:

26929 2026 Jun  7 20:55:59.007758 qspf201 ERR syncd#syncd: [none] SAI_API_PORT:brcm_sai_get_port_serdes_attribute_cmn:18248 Port 11 hardware lane count get failed with error -17.

26930 2026 Jun  7 20:55:59.007758 qspf201 ERR syncd#syncd: :- updatePortSerdesTapsCountMap: PORT_PHY_SERDES_ATTR: Failed to get port serdes count attr SAI_PORT_SERDES_ATTR_TX_FIR_COUNT for port_serdes RID:0xb005700000000, status:-17

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@justin-wong-ce i see you have removed the retry loop, I dont think this is a right approach.
We should not retry without an upper bound. If we believe a retry of 3 times with a 10ms is not enough we can increase this to 5 retries but we should not leave it unbounded.
@r12f fyi.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@r12f please advise whether if we can go forward with 5 retries

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to check, is it that because flexcounter is running in its own thread and starts as part of syncd initialization, it could be that flexcounter is starting to get port stats before SAI initialization (triggered from the sync main thread) completes? If so, should the flexcounter thread start instead be delayed until after SAI initialization?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and no - the situaiton with the Port PHY Serdes objects are a bit special.

The Port PHY Serdes objects are first initialized like any other counter during syncd's initialization. There are no problems up to this part.

After a port configuration update, the configuration for these objects also change.

Since these objects only support CREATE, the objects have to be re-created to be reconfigured. What happens in the code is it will re-create these objects, then proceed to read from the objects from SAI so it can instantiate some variables in FlexCounter.cpp for polling - these reads usually happens on the next poll on these objects (which may or may not be the 1st poll).

The time between is not sufficient in some cases since the reconfiguration happens late into initialization or sometimes when polling has already started.
Althought its a rare occurence, it still needs to be accounted for.

Comment thread syncd/FlexCounter.cpp Fixed
Comment thread syncd/FlexCounter.cpp Fixed
Signed-off-by: Justin Wong <jvwong@arista.com>
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Signed-off-by: Justin Wong <jvwong@arista.com>
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Signed-off-by: Justin Wong <jvwong@arista.com>
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Signed-off-by: Justin Wong <jvwong@arista.com>
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@mssonicbld

Copy link
Copy Markdown
Collaborator

Hi, there are workflow run(s) waiting for approval, you may be first-time contributor. I will notify maintainers to help approve once PR is approved. Thanks!

---Powered by SONiC BuildBot

@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@justin-wong-ce

Copy link
Copy Markdown
Contributor Author

Note: I am aware of the cherry-pick conflict to 202511. I have a local branch that addresses this conflict ready and will make a direct backport when this PR is approved.

flexCounter->removeCounter(testPortSerdesOid);
}

TEST_F(TestPortPhySerdesAttr, RetryOnObjectInUseThenSucceed)
Signed-off-by: Justin Wong <jvwong@arista.com>
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Comment thread syncd/FlexCounter.cpp Outdated
@tjchadaga
tjchadaga requested a review from prgeor July 14, 2026 08:03
@tjchadaga

Copy link
Copy Markdown
Contributor

@justin-wong-ce - are these failure logs only seen on a specific platform?

@justin-wong-ce

Copy link
Copy Markdown
Contributor Author

@justin-wong-ce - are these failure logs only seen on a specific platform?

I do not have access to other platforms - I can only test on Broadcom.

I cannot say for sure if it happens on other platforms so I only noted Broadcom in the PR description.

@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Signed-off-by: Justin Wong <jvwong@arista.com>
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@justin-wong-ce

Copy link
Copy Markdown
Contributor Author

Restarting CI due to failure from:

The process '/usr/bin/python' failed with exit code 1
BuildTrixie • amd64 • [Auto] Generate build coverage properties

ENOENT: no such file or directory, open '/__w/1/s/.diff-coverage/codecoverageProperties.json'
BuildTrixie • amd64 • [Auto] Update build coverage properties
Bash exited with code '100'.
Test • vstest • Install dependencies

@justin-wong-ce

Copy link
Copy Markdown
Contributor Author

/azpw retry

@mssonicbld

Copy link
Copy Markdown
Collaborator

Retrying failed(or canceled) jobs...

@mssonicbld

Copy link
Copy Markdown
Collaborator

Retrying failed(or canceled) stages in build 1164893:

✅Stage Test:

  • Job vstest: retried.

@r12f

r12f commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

hi @tjchadaga - do you mind to help check this PR?

@rookie-who

Copy link
Copy Markdown

Hi — this PR is flagged for cherry-pick to the 202605 branch (Request for 202605 Branch). To move forward with the cherry-pick, could you please:

  1. Test this change on the 202605 branch and add the test results to the PR description
  2. Add the label Tested for 202605 branch once testing is complete

This helps us track readiness and ensures we don't cherry-pick untested changes. Thanks!

Comment by @vaibhavhd via automated tooling

@mssonicbld

Copy link
Copy Markdown
Collaborator

This PR has backport request label(s) for branch(es): 202511,202605, but is missing required test information. Please make sure you tick the tested branch(es) in the Tested branch section and provide test evidence (e.g., 202511: <test result>) in the Test result section as well in your PR description.

---Powered by SONiC BuildBot

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Mitigates a race during syncd Port PHY Serdes flex-counter initialization where immediate SAI get calls can fail with SAI_STATUS_OBJECT_IN_USE, leaving syncd in a degraded state that later causes continuous polling errors.

Changes:

  • Add retry-with-delay logic (10ms backoff) for key SAI get operations used to initialize Port PHY Serdes collection (port RID lookup, hardware lane count query, and tap/count attribute reads).
  • Add unit tests that validate both “eventual success after transient OBJECT_IN_USE” and “failure after retry exhaustion” behaviors.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
syncd/FlexCounter.cpp Adds OBJECT_IN_USE retry handling during Port PHY Serdes attribute initialization to avoid permanent bad state caused by transient SAI busy responses.
unittest/syncd/TestPortPhySerdesAttr.cpp Adds tests covering retry success and exhaustion scenarios for the Port PHY Serdes initialization path.

Comment on lines +361 to +362
* and results in a good syncd state such that RX_VGA entries appears in
* PORT_PHY_ATTR_TABLE after retries.
Comment thread syncd/FlexCounter.cpp
Comment on lines +2234 to +2236
for (uint32_t tries = 1; tries <= 5; tries++)
{
port_rid = attr.value.oid;
return true;
}
sai_status_t status = Base::m_vendorSai->get(Base::m_objectType, port_serdes_rid, 1, &attr);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to update the description after applying changes from #1945 (comment)

Comment thread syncd/FlexCounter.cpp
// SAI object is busy - retry in 10ms
SWSS_LOG_WARN("PORT_PHY_SERDES_ATTR: SAI object in use, retry getting port RID for port serdes RID:0x%" PRIx64 "...",
port_serdes_rid);
std::this_thread::sleep_for(chrono::milliseconds(10));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@justin-wong-ce this is risky to sleep assuming we have say 256 ports which will result in 256 * 10 * 5 = 12.8 secs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 2.5% chance is the probability of it happening to 1 port on a config-reload or reboot. Of course yes, there is the chance of it happening to all ports at the same time and I agree this is not an optimal solution.

Comment thread syncd/FlexCounter.cpp

if (status == SAI_STATUS_SUCCESS)
break;
else if (status == SAI_STATUS_OBJECT_IN_USE && tries < 5)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@justin-wong-ce I think we need to understand who else is modifying the serdes object to keep it busy in BRCM SDK. Adding a busy retry only mitigates the problem to some extent but there could be other race condition in future where these retries may not be sufficient. Do you know how else is modifying the serdes object?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To my knowledge, there is just not enough time between creating the object and reading from it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Port phy serdes objects are first created in intialization.

Then some time later, a reconfiguration can happen. This can be during intialization or during polling.
To apply the new config, the object has to be recreated.

There is a chance a poll will happen too quickly after the object is created.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK, there is no mechanism to partially delay the polling only on the Port PHY Serdes objects, or on object creation. However, I am also not familiar with the orchagent code.

If there is a way to:

  1. stop polling on certain objects when destroy object
  2. when an object isc reated, check the object is ready for polling before turning on polling

^then we should use this approach, this will be the ideal fix.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SAI Port PHY Serdes object causing syslog ERRs when polling