Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ bazel_dep(name = "platforms", version = "1.1.0")

# S-CORE process rules
bazel_dep(name = "score_bazel_platforms", version = "1.1.0")
bazel_dep(name = "score_docs_as_code", version = "8.1.1")
bazel_dep(name = "score_docs_as_code", version = "8.1.2")
bazel_dep(name = "score_tooling", version = "2.2.0")
bazel_dep(name = "score_rust_policies", version = "0.0.5")
bazel_dep(name = "score_process_description", version = "2.1.2")
Expand Down
4 changes: 2 additions & 2 deletions MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/components/mw_log/detailed_design/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ The backend composition and recorder relationships are shown below:
:maxdepth: 1

file_output_backend
syslog_backend
datarouter_backend/index


Expand Down
1 change: 1 addition & 0 deletions docs/components/mw_log/detailed_design/syslog_backend.md
4 changes: 3 additions & 1 deletion docs/components/mw_log/requirements/requirements.rst
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ System Backend

.. comp_req:: Forward to System Logger
:id: comp_req__log__forward_to_system_logger
:version: 1
:version: 2
:reqtype: Functional
:security: NO
:safety: QM
Expand All @@ -144,6 +144,8 @@ System Backend

Note: Under QNX, slogger2 shall be used.

Note: Under Linux, syslog(3) shall be used.

.. comp_req:: System Backend Activation
:id: comp_req__log__system_backend_activation
:version: 1
Expand Down
127 changes: 127 additions & 0 deletions docs/features/logging/architecture/DR-002-dlt-network-transport.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
..
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

DLT Network Transport Evolution
================================

.. dec_rec:: DLT Network Transport Evolution
:id: dec_rec__logging__dlt_transport_evolution
:status: proposed
:version: 1
:context: See below.
:decision: TBA

Today the remote/DLT path is split across two processes, as described in
:doc:`index` and :doc:`../../../components/datarouter/index`:

- `mw::log` (application side) serialises log records and writes
them into a shared-memory buffer.
- `datarouter` (a separate process) reads that buffer, constructs the
DLT protocol headers, and transmits the resulting UDP/IPv4 multicast
packets using the standard BSD Socket API over the platform's default
network stack, shared with all other networked services.

A second, feature-flagged client backend (`shm_dma_enabled`)
would allow forwarding of records through a GTL client into a
DMA-capable shared-memory region instead of the DataRouter
ring buffer, handing them to a DLT-aware daemon/plugin on the receiving
side. This is not the default today, and it does not by itself change
how that receiving daemon talks to the network stack, so the properties
below still apply regardless of which client backend feeds it.

This works, but has three structural properties worth revisiting:

- Every message crosses two IPC hops before it reaches the wire:
one between `mw::log` and `datarouter`, and a second one from
`datarouter` into the network stack itself, since the socket API
it uses is, on this class of platforms, implemented over IPC to a
separate network-stack process rather than executing inline. Each
hop also implies copying the message (application buffer into shared
memory, shared memory into a new buffer with headers prepended, and
again into the network stack's own send buffers). It is this
combination of copies and context switches across both hops, not a
single IPC call, that drives CPU load.
- Where that network-stack process is a single-threaded resource
manager (e.g. QNX's `io-pkt`), it serialises *all* socket traffic
on the system through one queue. This is a separate overhead from
the copies above: it is contention/scheduling cost, so a burst of
log and trace traffic can add latency for every other socket user of
that same instance, and vice versa. Newer, multithreaded stack
implementations (e.g. `io-sock`) reduce this specific contention,
but do not by themselves remove the two IPC hops and copies above.
- log and trace traffic shares the same network stack and send queue as
other service traffic (E.g. Someip communication), so there is no
structural isolation between the two; any queuing or scheduling
behaviour of one can influence the other.

**Way Forward:**

Part 1: A GTL-based client backend as the remote-logging path.

Part 2: Provide a compile-time seam to select between the DLTv1 wire
format and the DLTv2 wire format, analogous to the existing
build-flag pattern for Part 1, rather than replacing one with the
other. Payload serialisation (verbose/non-verbose argument
encoding) is identical between DLTv1 and DLTv2 and does not need a
seam. The concrete DLTv2 protocol implementation behind
this seam is closed-source and maintained outside this repository;
this repository only needs to own the seam/interface, not the DLTv2
implementation itself.

Part 3: Move the DLT header-construction
and transmission stage (i.e. the network-writing responsibility
on the daemon receiving GTL records) into a module that is loaded
directly by the network stack, running on a second, dedicated
network-stack instance used exclusively for log and trace traffic:

- Removes the second IPC hop (and its associated copy) between the
router logic and the network stack for the transmit path.
- Allows direct use of the network stack's native buffer/interface APIs
instead of the generic socket API, removing at least one further
copy and enabling zero-copy transmission where supported by the
driver.
- Structurally isolates log and trace traffic from other network traffic,
since it no longer shares a network-stack instance, queue, or
scheduling domain with it.
- Enables transport-level controls (e.g. egress traffic shaping) to be
applied specifically to the log and trace traffic instance without
affecting other traffic.

.. uml:: _assets/dlt_plugin.puml

Out of scope / unaffected:

- The `mw::log` application-facing logging APIs are unaffected; only
the backend/transport selected underneath it changes.
- The DLT payload serialisation (verbose/non-verbose argument encoding)
is unaffected, since it is identical between DLTv1 and DLTv2.
- The DLTv2 protocol implementation is out of scope: this repository only
provides the compile-time seam to select it (Part 2); the
implementation behind that seam is closed-source and lives in a
separate, non-public `repository <https://github.com/comasso>`_.
- Freedom-from-interference (FFI) guarantees is unaffected and already
provided by the existing mw::log infrastructure.

**Trade-offs**

- Both halves of this evolution targets DMA/zero-copy where the
target hardware happens to support it. Each target platform
needs to be verified and configured individually; where
DMA/zero-copy isn't available, the transport still works,
just without the associated performance benefit.
- Introduces a second network-stack instance that must be configured,
operated, and kept isolated from the default one.
- Requires a feasibility phase to confirm the target network stack
supports loadable modules with the required capabilities for the
supported target platforms.
146 changes: 146 additions & 0 deletions docs/features/logging/architecture/_assets/dlt_plugin.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
' *******************************************************************************
' Copyright (c) 2026 Contributors to the Eclipse Foundation
'
' See the NOTICE file(s) distributed with this work for additional
' information regarding copyright ownership.
'
' This program and the accompanying materials are made available under the
' terms of the Apache License Version 2.0 which is available at
' https://www.apache.org/licenses/LICENSE-2.0
'
' SPDX-License-Identifier: Apache-2.0
' *******************************************************************************

@startuml dlt_plugin
title DLT Daemon functionality as a \nPlugin / Loadable Shared Module (a second dedicated Network Stack instance)

skinparam componentStyle rectangle
skinparam nodesep 40
skinparam ranksep 60
skinparam linetype ortho

interface "mw::diag" as mwdiag
component "DLT Diagnostics\nComponent" as dltdiag <<QM>>
dltdiag --> mwdiag

note top of dltdiag
Independent component registered with the
Diagnostic Manager.
end note

package "client" <<ASIL>> {
component "mw::log" as mwlog <<FFI>>
component "GTL" as gtl <<FFI>>

mwlog -r-> gtl
}

note bottom of mwlog
Forwards records to GTL via an owned
DltTraceBackend/ITraceLibrary client.
end note

file "Client\nConfiguration" as clientconfig
clientconfig -d-> mwlog

'interface name left blank to avoid overlaps and instead highlighted via note below
interface " " as shmpayload
interface " " as shmmeta
interface " " as shmctrl
interface " " as ctrlchannel

note top of shmpayload #Wheat : shm\n(payload)
note top of shmmeta #Wheat : shm\n(metadata)
note bottom of shmctrl #Wheat : shm\n(control block)
note top of ctrlchannel #Wheat :DLT QNX\nControl Channel

gtl -r-> shmpayload: R/W
gtl -r-> shmmeta: R/W
mwlog -r-> shmctrl: R/W
dltdiag --> ctrlchannel

package "Network Stack (log_and_trace instance)" <<QM>> as networkstackinstance {
package "DLT Plugin" {
component "GTL Backend" as gtlbackend
component "Core" as core
component "Statistics\nModule" as stats
component "DLT Router" as router
interface "DLT Wire Format\n(compile-time seam)" as wireformat
component "DLT File\nWriter" as filewriter
component "DLT Network\nWriter" as netwriter
component "Network Stack\nNative APIs" as fbsdapi
component "devs-network-driver.so" as driver
component "gPTP\nLogger Time" as gptp <<optional>>
}
}

package "DLT Wire Format Implementations" as wireformatpkg {
component "DLTv2 \n(closed-source)" as dltv2wire <<external>> #OrangeRed
component "DLTv1 \n(this repository)" as dltv1wire
}

' Optional/experimental time-sync path
package "mw::time" as mwtime <<optional>> {
component "shm\n(logger time)" as shmloggertime <<optional>>
}

dltv2wire -[hidden]r-> dltv1wire

shmpayload -r-> gtlbackend : R/O
shmmeta -r-> gtlbackend : R/O

shmctrl <-r-> core : R/W
ctrlchannel -u-> core

gtlbackend -d-> core
core -d-> router
core -l-> stats
router -d-> filewriter
router -d-> netwriter

wireformat -u-> filewriter
wireformat -u-> netwriter

wireformatpkg ..|> wireformat

note left of wireformat
Compile-time build-flag selection between
DLTv1 and DLTv2 wire formats.
end note

filewriter -d-> fbsdapi
netwriter -d-> fbsdapi
fbsdapi -d-> driver

file "Global\nConfiguration" as globalconfig
core <-d- globalconfig

file "Router\nConfiguration" as routerconfig
routerconfig -d-> router

database "filesystem\n(devb-*, fs-qnx6.so)" as fsdb
filewriter -d-> fsdb

' Optional time-sync path
fbsdapi <-r- gptp
driver <-r- gptp
gptp <-r- mwtime
mwlog -r-> shmloggertime

legend bottom
|= Acronym |= Meaning |
| DLT | Diagnostics Log and Trace |
| GTL | Generic Trace Library |
| QM | Quality Managed (non-ASIL) |
| ASIL | Automotive Safety Integrity Level |
| FFI | Freedom From Interference |
| shm | Shared Memory |
| R/O | Read-Only |
| R/W | Read/Write |
| gPTP | generalized Precision Time Protocol |
| mw::log | Middleware Logging (client-side logging API) |
| mw::diag | Middleware Diagnostics |
| mw::time | Middleware Time (time synchronisation) |
end legend

@enduml
1 change: 1 addition & 0 deletions docs/features/logging/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ capture the safety and security constraints that any backend implementation must
architecture/index.rst
architecture/chklst_arc_inspection.rst
architecture/DR-001-logging.rst
architecture/DR-002-dlt-network-transport.rst
safety_planning/index.rst
16 changes: 16 additions & 0 deletions score/mw/log/backend/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,22 @@ cc_library(
alwayslink = True,
)

# Plugin: Linux syslog(3) System Logging
# Automatically included on Linux (HGY aarch64 / x86 host) builds.
cc_library(
name = "syslog",
srcs = ["syslog_registrant.cpp"],
features = COMPILER_WARNING_FEATURES,
tags = ["FFI"],
target_compatible_with = ["@platforms//os:linux"],
visibility = ["//visibility:public"], # platform_only
deps = [
"//score/mw/log/detail/syslog:syslog_recorder_factory",
"@score_baselibs//score/mw/log:minimal",
],
alwayslink = True,
)

# Plugin: Custom user-provided Logging backend
# Opt-in. Build with --@score_logging//score/mw/log/flags:KCustom_Logging=True
# and --@score_logging//score/mw/log/flags:custom_recorder_impl=//your:target.
Expand Down
Loading
Loading