Skip to content

PTP capable interface detection without ethtool (New)#2695

Open
tomli380576 wants to merge 13 commits into
mainfrom
ethtool-native-ptp-detection
Open

PTP capable interface detection without ethtool (New)#2695
tomli380576 wants to merge 13 commits into
mainfrom
ethtool-native-ptp-detection

Conversation

@tomli380576

@tomli380576 tomli380576 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Description

This PR implements a new module inside checkbox-support that can check whether an interface like enp1s1 supports PTP without relying on ethtool. More functions like getting interface speeds natively are planned as well so a new directory ethtool is added in checkbox support.

This runs on ubuntu 16.04 too, albeit we don't have anything that supports PTP on 16.04.

Resolved issues

Ideally we stop parsing ethtool's text output to avoid problems like #2677 in the future.

Documentation

The comments in the code will point to the exact structs and macros we are re-implementing, but the basic idea is to copy this function from ethtool where we send the SIOCETHTOOL ioctl with an empty ethtool_ts_info that only has .cmd = ETHTOOL_GET_TS_INFO set, wait for the kernel to fill in the data, then read phc_index. If phc_index == -1, that means the interface doesn't support PTP; if phc_index >= 0, the interface supports PTP and a /dev/ptp{phc_index} device is expected to exist.

Padding

There was 1 interesting footgun caught by copilot about struct padding. The ifreq struct in the kernel looks like this:

struct ifreq {
    union {
        char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
    } ifr_ifrn;

    union {
        struct sockaddr ifru_addr;
        struct sockaddr ifru_dstaddr;
        struct sockaddr ifru_broadaddr;
        struct sockaddr ifru_netmask;
        struct sockaddr ifru_hwaddr;
        short ifru_flags;
        int ifru_ivalue;
        int ifru_mtu;
        struct ifmap ifru_map;
        char ifru_slave[IFNAMSIZ]; /* Just fits the size */
        char ifru_newname[IFNAMSIZ];
        void * ifru_data;
        struct if_settings ifru_settings;
    } ifr_ifru;
};

where the ifr_ifru field is a union. This needs extra care because it actually has differently-sized union members. The largest one is struct ifmap, which looks like:

struct ifmap {
    unsigned long mem_start;
    unsigned long mem_end;
    unsigned short base_addr;
    unsigned char irq;
    unsigned char dma;
    unsigned char port;
    /* 3 bytes spare */
};

thus giving us the size of sizeof(long)*2 + sizeof(short) + sizeof(char)*3 + 3 = 24 bytes. However long and short are not types with a fixed size, so this struct is included in the python version as well just to compute the padding size without doing brittle sizeof calculations.

Tests

Unit tests

@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.23529% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.10%. Comparing base (e003781) to head (ab06bb9).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
...eckbox-support/checkbox_support/ethtool/ts_info.py 96.61% 2 Missing ⚠️
...ort/checkbox_support/ethtool/tests/test_ts_info.py 99.09% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2695      +/-   ##
==========================================
+ Coverage   59.97%   60.10%   +0.13%     
==========================================
  Files         487      489       +2     
  Lines       48918    49088     +170     
  Branches     8757     8793      +36     
==========================================
+ Hits        29339    29506     +167     
- Misses      18654    18655       +1     
- Partials      925      927       +2     
Flag Coverage Δ
checkbox-support 71.05% <98.23%> (+1.11%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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

This PR adds a new checkbox-support helper module that detects whether a network interface is PTP-capable by querying ETHTOOL_GET_TS_INFO via ioctl, avoiding parsing ethtool CLI output (and issues like the ethtool v6.19+ field rename).

Changes:

  • Add a new checkbox_support.ethtool.ts_info module that issues SIOCETHTOOL/ETHTOOL_GET_TS_INFO and interprets phc_index.
  • Add helper logic to filter for “physical ethernet” interfaces via /sys/class/net/... checks.
  • Provide a high-level is_ptp_capable() API that maps phc_index to /dev/ptpX.

Reviewed changes

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

File Description
checkbox-support/checkbox_support/ethtool/ts_info.py New ioctl-based implementation to retrieve timestamping/PHC information and determine PTP capability.
checkbox-support/checkbox_support/ethtool/__init__.py Package marker for the new ethtool helper module.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread checkbox-support/checkbox_support/ethtool/ts_info.py
Comment thread checkbox-support/checkbox_support/ethtool/ts_info.py Outdated
Comment thread checkbox-support/checkbox_support/ethtool/ts_info.py
@tomli380576
tomli380576 marked this pull request as ready for review July 16, 2026 07:46
@tomli380576
tomli380576 requested a review from Copilot July 16, 2026 07:55

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

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

Comment thread checkbox-support/checkbox_support/ethtool/ts_info.py Outdated
Comment thread checkbox-support/checkbox_support/ethtool/ts_info.py Outdated
Comment thread checkbox-support/checkbox_support/ethtool/ts_info.py
Comment thread checkbox-support/checkbox_support/ethtool/ts_info.py Outdated
@tomli380576
tomli380576 marked this pull request as draft July 16, 2026 08:25

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

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

Comment thread checkbox-support/checkbox_support/ethtool/ts_info.py Outdated
Comment thread checkbox-support/checkbox_support/ethtool/ts_info.py Outdated
@tomli380576
tomli380576 marked this pull request as ready for review July 16, 2026 08:58
@tomli380576 tomli380576 changed the title Native PTP capable interface detection without using ethtool (New) PTP capable interface detection without ethtool (New) Jul 16, 2026
@tomli380576
tomli380576 marked this pull request as draft July 17, 2026 02:45
@tomli380576
tomli380576 marked this pull request as ready for review July 17, 2026 03:17

@fernando79513 fernando79513 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks a lot for the contribution!

The code looks fine. I don't get all the specifics of the ethtool structs but the utility looks ok.

I have a couple of more general questions:

Have you tested it on an actual device with PTP?

I get that calling directly the kernel witout relying on ehtool gives us more control about the test, but it also puts on us the "burden" of mantaining it every time there is a change in the kernel. Also users may be relying on the ethtool binary, so I think there is some value on testing it indirectly.
I'm okay with this solution for this very specific case, but as a general practice trying to "re-write" this kind of tools may cause us more work than adapting to the changes in the long run.

Comment on lines +118 to +126
# check for ARPHRD_ETHER
if not (sys_class_net_interface / "type").read_text().strip() == "1":
return False
# skip everything not associated with a physical device
if not (sys_class_net_interface / "device").exists():
return False
# wifi interfaces (16.04+)
if (sys_class_net_interface / "phy80211").exists():
return False

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think you can add here some extra debugging messages.

Suggested change
# check for ARPHRD_ETHER
if not (sys_class_net_interface / "type").read_text().strip() == "1":
return False
# skip everything not associated with a physical device
if not (sys_class_net_interface / "device").exists():
return False
# wifi interfaces (16.04+)
if (sys_class_net_interface / "phy80211").exists():
return False
# check for ARPHRD_ETHER
if not (sys_class_net_interface / "type").read_text().strip() == "1":
print("interface {} is not ARPHRD_ETHER".format(interface))
return False
# skip everything not associated with a physical device
if not (sys_class_net_interface / "device").exists():
print("interface {} is not a physical device".format(interface))
return False
# wifi interfaces (16.04+)
if (sys_class_net_interface / "phy80211").exists():
print("interface {} is a wifi device".format(interface))
return False

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.

3 participants