Skip to content

Fixes and improvements for Linux#25

Open
BjoernAtBosch wants to merge 10 commits into
eclipse-score:mainfrom
etas-contrib:bjoernatbosch_get_it_running
Open

Fixes and improvements for Linux#25
BjoernAtBosch wants to merge 10 commits into
eclipse-score:mainfrom
etas-contrib:bjoernatbosch_get_it_running

Conversation

@BjoernAtBosch

@BjoernAtBosch BjoernAtBosch commented May 21, 2026

Copy link
Copy Markdown
Contributor

This PR fixes some issues discovered in Linux (closes #36):

  • Fix reception of PTP frames: Previous filtering mechanism in raw_socket.cpp wasn't working under Linux
  • Add (temporary) cmdline parsing to allow configuration of Ethernet interface to be used
  • Use kernel sw timestamps as fallback if hw timestamps are not supported
  • Extend logging

@github-actions

github-actions Bot commented May 21, 2026

Copy link
Copy Markdown

License Check Results

🚀 The license check job ran with the Bazel command:

bazel run //:license-check

Status: ⚠️ Needs Review

Click to expand output
[License Check Output]
Extracting Bazel installation...
Starting local Bazel server (8.6.0) and connecting to it...
INFO: Invocation ID: 68c96304-5f9f-4d3b-8420-8d2353089aea
Computing main repo mapping: 
WARNING: /home/runner/work/time/time/MODULE.bazel:13:7: The attribute 'compatibility_level' in module() is a no-op and will be removed in a future Bazel release. Please remove it from your MODULE.bazel file.
Computing main repo mapping: 
Computing main repo mapping: 
Computing main repo mapping: 
Computing main repo mapping: 
Loading: 
Loading: 3 packages loaded
Loading: 3 packages loaded
    currently loading: 
Loading: 3 packages loaded
    currently loading: 
Loading: 3 packages loaded
    currently loading: 
Analyzing: target //:license-check (4 packages loaded, 0 targets configured)
Analyzing: target //:license-check (4 packages loaded, 0 targets configured)

Analyzing: target //:license-check (61 packages loaded, 10 targets configured)

Analyzing: target //:license-check (141 packages loaded, 1065 targets configured)

Analyzing: target //:license-check (153 packages loaded, 6128 targets configured)

Analyzing: target //:license-check (153 packages loaded, 9185 targets configured)

Analyzing: target //:license-check (154 packages loaded, 9205 targets configured)

Analyzing: target //:license-check (165 packages loaded, 9284 targets configured)

Analyzing: target //:license-check (165 packages loaded, 9284 targets configured)

Analyzing: target //:license-check (166 packages loaded, 9284 targets configured)

Analyzing: target //:license-check (168 packages loaded, 11172 targets configured)

INFO: Analyzed target //:license-check (170 packages loaded, 11422 targets configured).
[11 / 14] checking cached actions
[12 / 16] JavaToolchainCompileClasses external/rules_java+/toolchains/platformclasspath_classes; 0s disk-cache, processwrapper-sandbox ... (2 actions running)
INFO: From Generating Dash formatted dependency file ...:
INFO: Successfully converted 2 packages from Cargo.lock to bazel-out/k8-fastbuild/bin/formatted.txt
[14 / 16] JavaToolchainCompileBootClasspath external/rules_java+/toolchains/platformclasspath.jar; 0s disk-cache, processwrapper-sandbox
INFO: Found 1 target...
Target //:license.check.license_check up-to-date:
  bazel-bin/license.check.license_check
  bazel-bin/license.check.license_check.jar
INFO: Elapsed time: 38.402s, Critical Path: 2.29s
INFO: 16 processes: 12 internal, 3 processwrapper-sandbox, 1 worker.
INFO: Build completed successfully, 16 total actions
INFO: Running command line: bazel-bin/license.check.license_check ./formatted.txt <args omitted>
usage: org.eclipse.dash.licenses.cli.Main [-batch <int>] [-cd <url>]
       [-confidence <int>] [-ef <url>] [-excludeSources <sources>] [-help] [-lic
       <url>] [-project <shortname>] [-repo <url>] [-review] [-summary <file>]
       [-timeout <seconds>] [-token <token>]

@github-actions

Copy link
Copy Markdown

The created documentation from the pull request is available at: docu-html

@BjoernAtBosch BjoernAtBosch force-pushed the bjoernatbosch_get_it_running branch from f201317 to 949c02a Compare July 8, 2026 13:58
@BjoernAtBosch BjoernAtBosch deployed to workflow-approval July 8, 2026 13:58 — with GitHub Actions Active
@BjoernAtBosch BjoernAtBosch temporarily deployed to workflow-approval July 8, 2026 13:58 — with GitHub Actions Inactive
@BjoernAtBosch BjoernAtBosch changed the title Try to get it running in Linux Fixes and improvements for Linux Jul 8, 2026
@BjoernAtBosch BjoernAtBosch marked this pull request as ready for review July 8, 2026 14:05
@BjoernAtBosch BjoernAtBosch requested review from LudwigWeise, gordon9901, lavrovvalera and ryan-steel and removed request for gordon9901 July 8, 2026 14:05
Close();

const int fd = sys_->socket_call(AF_PACKET, SOCK_RAW, htons(ETH_P_1588));
const int fd = sys_->socket_call(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

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.

The BPF filter only checks EtherType at offset 12 == 0x88F7, but VLAN-tagged frames have 0x8100 there — the inner 0x88F7 is at offset 16. Those frames are silently dropped before reaching frame_codec, which already handles them correctly. If VLAN-tagged PTP traffic is not expected in the target environment this is fine,

@BjoernAtBosch BjoernAtBosch Jul 10, 2026

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.

With the previous configuration, I wasn't able to receive gPTP frames in the time_slave. That's the reason to change it. Any gPTP frame should not be VLAN tagged - see my reply to Valery's comment.

Comment thread score/time_slave/src/application/time_slave.cpp

for (++iter; iter != args.cend(); ++iter)
{
if (*iter == "-h" || *iter == "--help")

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.

Returning kInitFailure for --help is problematic — in an automotive lifecycle framework this can trigger watchdog restarts or fault reports. --help is intentional, not an error. Consider exit(0) directly after printing usage, or a separate return code.

@BjoernAtBosch BjoernAtBosch Jul 9, 2026

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.

I can change that, but not sure if returning a 0 (zero) is the right thing. Documentation of the Initialize function tells:

If non-zero returned, application will exit with exit
code returned from Initialize and Run method won't be called.

That's not an issue. That is what we want in case help was requested. But:

NOTE: In case non-zero is returned, the whole group where this
application belongs to will not leave the machine state Init and
thus, all the applications of such group will never be promoted to
the machine state Running. This could lead to the whole ECU not being
able to startup at all which will result in continuous general rejects.

Could it cause issues if we return a zero here from the terminated process (signalling success)? Normally, I'd expect that it should not because the process is expected to be running ...

I mean, this is a bit artificial because in a correctly configured system the time_slave shouldn't be called with -h or --help.

{

constexpr int kRxTimeoutMs = 100; // poll timeout; keeps RxLoop responsive to shutdown
constexpr int kRxTimeoutMs = 500; // poll timeout; keeps RxLoop responsive to shutdown

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.

kRxTimeoutMs raised from 100 → 500 ms with no explanation in the commit message. Worst-case shutdown latency for RxLoop is now 5× longer. Please document the reason (CPU load? NIC behaviour?) so the timing impact can be assessed.

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.

My intention was to reduce checking load and 0.5 sec isn't a long period. But we can switch back to the previous value if preferred.

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.

Understood. Worth noting though that gPTP Sync messages arrive every ~125 ms, so a 500 ms poll wait could span 4 Sync cycles. Not a bug, just something to keep in mind.

<< " [options]\n"
"Options:\n"
" -h, --help Print this message and exit.\n"
" -i, --interface <iface> Define the ethernet interface to be used (default is \""

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.

Do we have more options, which are needed for the slave? I would assume, yes
shall we specify then the config file and make it mandatory to be run?

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.

My intention was to solve the issue first that the interface name differs between QNX and Linux. Furthermore it is quite likely that the user wants to use another interface.
Further options could be added as needed.

auto iter = args.cbegin();
const auto& app_name = *iter;

for (++iter; iter != args.cend(); ++iter)

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.

Do we have already and command parses solutions in the base libs already?

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.

Seems not: Neither lifecycle mgm has nor I found some in baselibs.

// (outer EtherType is 0x8100, not 0x88F7). The BPF filter runs in-kernel before delivery
// to userspace, so non-PTP frames are dropped with zero overhead in the application.
static const ::sock_filter kPtpBpfCode[] = {
BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 12), // load EtherType

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.

Can we change the "12" to some not -magic number?

static const ::sock_filter kPtpBpfCode[] = {
BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 12), // load EtherType
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETH_P_1588, 1, 0), // == 0x88F7 → PASS
BPF_STMT(BPF_RET | BPF_K, 0U), // FAIL: drop

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.

the same here and on the line below

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.

Do you mean the 1 and the 0 in line 122? That's just the jump width to the filter instruction to be executed next ...

{

constexpr int kRxTimeoutMs = 100; // poll timeout; keeps RxLoop responsive to shutdown
constexpr int kRxTimeoutMs = 500; // poll timeout; keeps RxLoop responsive to shutdown

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.

why was it encreased? any justifications?

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.

See reply to gordon9901's comment.

if (*iter == "-h" || *iter == "--help")
{
PrintUsage(app_name);
return false;

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.

I would believe, it shall return true here

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.

But would it terminate then? Typical behavior if querying help of a cmd is to print usage and terminate.

{
const auto& args = context.get_arguments();
auto iter = args.cbegin();
const auto& app_name = *iter;

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.

shall we check if args. are empty before resolving the iterator?
ApplicationContxt might not be == to the classical C argv*

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.

Current impl is. It stores all C args in the vector. It has a separate private variable m_app_path to store the app path, but no public getter :-O


void RawSocketImpl::Close()
{
const int fd = fd_.exchange(-1, std::memory_order_acq_rel);

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.

Shall we drop here the PACKET_DROP_MEMBERSHIP for symmetry?

}

// BPF filter: pass only frames with EtherType 0x88F7 (PTP/gPTP).
// ETH_P_ALL is used for socket/bind because ETH_P_1588 misses VLAN-tagged PTP frames

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.

the filter above, if I'm correct, handles the non tagged frames only.
to address vlan youwould need additioanl instructions.

but in general, I would believe the ptp frames shall not be vlan tagged, so the fileter is correct.
jsut the comments shall be adjusted

@BjoernAtBosch BjoernAtBosch Jul 10, 2026

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.

but in general, I would believe the ptp frames shall not be vlan tagged, so the fileter is correct.

Yes, gPTP specification (IEEE Std 802.1AS-2011) states in section 11.3.3: "A frame that carries an IEEE 802.1AS message shall not have a VLAN tag nor a priority tag."

Will adjust comment ...

Comment thread score/time_slave/src/application/time_slave.cpp
// ETH_P_ALL is used for socket/bind because ETH_P_1588 misses VLAN-tagged PTP frames
// (outer EtherType is 0x8100, not 0x88F7). The BPF filter runs in-kernel before delivery
// to userspace, so non-PTP frames are dropped with zero overhead in the application.
static const ::sock_filter kPtpBpfCode[] = {

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.

kPtpBpfCode value (not type, qnx one is obviously qnx-specific) is identical to kPtp1588FilterInsns defined in gptp/platform/qnx/qnx_raw_shim.cpp - can we combine these somewhere common?

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.

Don't know if that makes sense as this raw_socket impl is Linux-specific

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.

The socket is, but the EtherType for PTP/gPTP is the same across platforms no?

@BjoernAtBosch BjoernAtBosch Jul 10, 2026

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.

Ah - got it now. But no, they are not exactly the same. Furthermore, these setting are quite driver-specific, so I'd like to keep it as is for now.

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.

Ok - both filter instructions do the same. (Wasn't aware how the filter is exactly working - that part was fixed by AI). But still - I think this is quite OS specific, so I'd keep those separatly

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

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

Improvement: Linux support

4 participants