fix(uavcan): warn while the dynamic node ID allocation table is full (#28243)

centralized::Storage never evicts, so a node ID spent on a board that is
gone stays spent. Once all of them are, every board the table has not
seen before is refused a node ID through a UAVCAN_TRACE that compiles to
nothing here - silent on the bus and on the console, so a full table
reads as a dead node.

Boards already in the table still get their cached ID and join fine, so
the bus looks healthy. A test station cycling boards through one flight
controller fills the table and stops allocating for good.

PX4_ERR every 5 s while full: the table does not empty itself, so this
is a fault someone has to clear, not a one-time notice.
This commit is contained in:
Jacob Dahl
2026-08-14 17:20:16 -06:00
committed by GitHub
parent 7daace6411
commit a3d5fb11bb
3 changed files with 34 additions and 0 deletions
+4
View File
@@ -759,6 +759,10 @@ UavcanNode::Run()
_servers->setArmed(actuator_armed.armed || actuator_armed.prearmed);
}
if (_servers != nullptr) {
_servers->warn_if_node_id_allocation_table_full();
}
#ifdef CONFIG_MODULES_NFS_MOUNT
if (_servers != nullptr) {
+24
View File
@@ -154,6 +154,30 @@ int UavcanServers::init()
return 0;
}
void UavcanServers::warn_if_node_id_allocation_table_full()
{
/*
The table never evicts an entry, so a node ID spent on a board that is no longer present stays spent. Once
all of them are, every board the table has not seen before is refused a node ID, and the refusal is silent
on the bus and here - the node just never appears, which reads as a dead node rather than a full table.
Keep saying so: the table does not empty itself, so this is a fault someone has to clear.
*/
if (_server_instance.getNumAllocations() < uavcan::NodeID::MaxRecommendedForRegularNodes) {
return;
}
const hrt_abstime now = hrt_absolute_time();
if (_node_id_table_full_warned != 0 && now - _node_id_table_full_warned < NODE_ID_TABLE_FULL_WARN_INTERVAL) {
return;
}
_node_id_table_full_warned = now;
PX4_ERR("dynamic node ID table is full (%u/%u): no new node can join, delete %s and reboot",
static_cast<unsigned>(_server_instance.getNumAllocations()),
static_cast<unsigned>(uavcan::NodeID::MaxRecommendedForRegularNodes), UAVCAN_NODE_DB_PATH);
}
#ifdef CONFIG_MODULES_NFS_MOUNT
void UavcanServers::check_nfs()
{
+6
View File
@@ -71,6 +71,8 @@ public:
int init();
void warn_if_node_id_allocation_table_full();
#ifdef CONFIG_MODULES_NFS_MOUNT
void check_nfs();
#endif
@@ -86,6 +88,8 @@ public:
private:
static constexpr hrt_abstime NODE_ID_TABLE_FULL_WARN_INTERVAL{5_s};
void unpackFwFromROMFS(const char *sd_path, const char *romfs_path);
void migrateFWFromRoot(const char *sd_path, const char *sd_root_path);
int copyFw(const char *dst, const char *src);
@@ -100,5 +104,7 @@ private:
uavcan::NodeInfoRetriever &_node_info_retriever;
hrt_abstime _node_id_table_full_warned{0};
uORB::Subscription _nfs_up_sub{ORB_ID(nfs_up)};
};