Merge: CNB97: ethtool: update ethtool core to upstream v6.15.

MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/6775

JIRA: https://issues.redhat.com/browse/RHEL-89014

Update ethtool upto kernel v6.15.

Brew: [https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=67396250](https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=67705537)

Depends: !6842

Signed-off-by: Mohammad Heib <mheib@redhat.com>

New features:

- Include a new readable timestamping string, **'option-rx-filter'**, which will appear when using the -T option.
- add support for writing firmware blocks using EPL (Extended Payload).
- Make timestamping hardware PTP provider selectable.
- add support for configuring hds-thresh
- Add support for 200Gbps per lane link modes.

Omitted-fix: 6db9d3a536cd netdevsim: don't assume core pre-populates HDS params on GET

* The targeted code was dropped during the update, so this fix is irrelevant.

Omitted-fix: 19f72d95ae31 Docs/zh_CN: Translate index.rst to Simplified Chinese

* Changes are not relevant for networking.

Omitted-fix: 869413825088 selftests: drv-net: wait for iperf client to stop sending

* [mschmidt] This is just for selftests. It appeared too late. We can't afford to block this MR any further.

Approved-by: Antoine Tenart <atenart@redhat.com>
Approved-by: Michal Schmidt <mschmidt@redhat.com>
Approved-by: Corinna Vinschen <vinschen@redhat.com>
Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com>

Merged-by: Augusto Caringi <acaringi@redhat.com>
This commit is contained in:
Augusto Caringi 2025-07-28 12:55:39 -03:00
commit c18e5c4e54
75 changed files with 5696 additions and 1152 deletions

View File

@ -106,6 +106,9 @@ properties:
name-prefix:
description: For enum the prefix of the values, optional.
type: string
enum-cnt-name:
description: Name of the render-max counter enum entry.
type: string
# End genetlink-c
attribute-sets:

View File

@ -117,6 +117,9 @@ properties:
name-prefix:
description: For enum the prefix of the values, optional.
type: string
enum-cnt-name:
description: Name of the render-max counter enum entry.
type: string
# End genetlink-c
# Start genetlink-legacy
members:

View File

@ -5,6 +5,10 @@ name: ethtool
protocol: genetlink-legacy
doc: Partial family for Ethtool Netlink.
uapi-header: linux/ethtool_netlink_generated.h
c-family-name: ethtool-genl-name
c-version-name: ethtool-genl-version
definitions:
-
@ -12,43 +16,101 @@ definitions:
enum-name:
type: enum
entries: [ vxlan, geneve, vxlan-gpe ]
enum-cnt-name: __ethtool-udp-tunnel-type-cnt
render-max: true
-
name: stringset
type: enum
entries: []
header: linux/ethtool.h # skip rendering, no actual definition
-
name: header-flags
type: flags
entries: [ compact-bitsets, omit-reply, stats ]
name-prefix: ethtool-flag-
doc: common ethtool header flags
entries:
-
name: compact-bitsets
doc: use compact bitsets in reply
-
name: omit-reply
doc: provide optional reply for SET or ACT requests
-
name: stats
doc: request statistics, if supported by the driver
-
name: module-fw-flash-status
type: enum
entries: [ started, in_progress, completed, error ]
doc: plug-in module firmware flashing status
header: linux/ethtool.h
entries:
-
name: started
doc: The firmware flashing process has started.
-
name: in_progress
doc: The firmware flashing process is in progress.
-
name: completed
doc: The firmware flashing process was completed successfully.
-
name: error
doc: The firmware flashing process was stopped due to an error.
-
name: c33-pse-ext-state
enum-name:
doc: "groups of PSE extended states functions. IEEE 802.3-2022 33.2.4.4 Variables"
type: enum
name-prefix: ethtool-c33-pse-ext-state-
header: linux/ethtool.h
entries:
- none
- error-condition
- mr-mps-valid
- mr-pse-enable
- option-detect-ted
- option-vport-lim
- ovld-detected
- power-not-available
- short-detected
-
name: none
doc: none
-
name: error-condition
doc: Group of error_condition states
-
name: mr-mps-valid
doc: Group of mr_mps_valid states
-
name: mr-pse-enable
doc: Group of mr_pse_enable states
-
name: option-detect-ted
doc: Group of option_detect_ted states
-
name: option-vport-lim
doc: Group of option_vport_lim states
-
name: ovld-detected
doc: Group of ovld_detected states
-
name: power-not-available
doc: Group of power_not_available states
-
name: short-detected
doc: Group of short_detected states
-
name: phy-upstream-type
enum-name:
enum-name: phy-upstream
header: linux/ethtool.h
type: enum
name-prefix: phy-upstream
entries: [ mac, phy ]
-
name: tcp-data-split
type: enum
entries: [ unknown, disabled, enabled ]
attribute-sets:
-
name: header
attr-cnt-name: __ethtool-a-header-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: dev-index
type: u32
@ -65,7 +127,12 @@ attribute-sets:
-
name: bitset-bit
attr-cnt-name: __ethtool-a-bitset-bit-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: index
type: u32
@ -77,7 +144,12 @@ attribute-sets:
type: flag
-
name: bitset-bits
attr-cnt-name: __ethtool-a-bitset-bits-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: bit
type: nest
@ -85,7 +157,12 @@ attribute-sets:
nested-attributes: bitset-bit
-
name: bitset
attr-cnt-name: __ethtool-a-bitset-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: nomask
type: flag
@ -96,10 +173,20 @@ attribute-sets:
name: bits
type: nest
nested-attributes: bitset-bits
-
name: value
type: binary
-
name: mask
type: binary
-
name: string
attr-cnt-name: __ethtool-a-string-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: index
type: u32
@ -108,7 +195,16 @@ attribute-sets:
type: string
-
name: strings
attr-cnt-name: __ethtool-a-strings-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: unspec
type: unused
value: 0
-
name: string
type: nest
@ -116,7 +212,12 @@ attribute-sets:
nested-attributes: string
-
name: stringset
attr-cnt-name: __ethtool-a-stringset-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: id
type: u32
@ -130,7 +231,12 @@ attribute-sets:
nested-attributes: strings
-
name: stringsets
attr-cnt-name: __ethtool-a-stringsets-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: stringset
type: nest
@ -138,7 +244,12 @@ attribute-sets:
nested-attributes: stringset
-
name: strset
attr-cnt-name: __ethtool-a-strset-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -153,7 +264,12 @@ attribute-sets:
-
name: privflags
attr-cnt-name: __ethtool-a-privflags-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -165,7 +281,12 @@ attribute-sets:
-
name: rings
attr-cnt-name: __ethtool-a-rings-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -200,6 +321,7 @@ attribute-sets:
-
name: tcp-data-split
type: u8
enum: tcp-data-split
-
name: cqe-size
type: u32
@ -215,34 +337,57 @@ attribute-sets:
-
name: tx-push-buf-len-max
type: u32
-
name: hds-thresh
type: u32
-
name: hds-thresh-max
type: u32
-
name: mm-stat
attr-cnt-name: __ethtool-a-mm-stat-cnt
doc: MAC Merge (802.3)
attributes:
-
name: unspec
type: unused
value: 0
-
name: pad
type: pad
-
name: reassembly-errors
doc: aMACMergeFrameAssErrorCount
type: u64
-
name: smd-errors
doc: aMACMergeFrameSmdErrorCount
type: u64
-
name: reassembly-ok
doc: aMACMergeFrameAssOkCount
type: u64
-
name: rx-frag-count
doc: aMACMergeFragCountRx
type: u64
-
name: tx-frag-count
doc: aMACMergeFragCountTx
type: u64
-
name: hold-count
doc: aMACMergeHoldCount
type: u64
-
name: mm
attr-cnt-name: __ethtool-a-mm-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -280,7 +425,12 @@ attribute-sets:
nested-attributes: mm-stat
-
name: linkinfo
attr-cnt-name: __ethtool-a-linkinfo-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -302,7 +452,12 @@ attribute-sets:
type: u8
-
name: linkmodes
attr-cnt-name: __ethtool-a-linkmodes-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -338,7 +493,12 @@ attribute-sets:
type: u8
-
name: linkstate
attr-cnt-name: __ethtool-a-linkstate-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -363,7 +523,12 @@ attribute-sets:
type: u32
-
name: debug
attr-cnt-name: __ethtool-a-debug-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -374,7 +539,12 @@ attribute-sets:
nested-attributes: bitset
-
name: wol
attr-cnt-name: __ethtool-a-wol-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -388,7 +558,12 @@ attribute-sets:
type: binary
-
name: features
attr-cnt-name: __ethtool-a-features-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -411,7 +586,12 @@ attribute-sets:
nested-attributes: bitset
-
name: channels
attr-cnt-name: __ethtool-a-channels-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -443,7 +623,12 @@ attribute-sets:
-
name: irq-moderation
attr-cnt-name: __ethtool-a-irq-moderation-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: usec
type: u32
@ -455,7 +640,12 @@ attribute-sets:
type: u32
-
name: profile
attr-cnt-name: __ethtool-a-profile-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: irq-moderation
type: nest
@ -463,7 +653,12 @@ attribute-sets:
nested-attributes: irq-moderation
-
name: coalesce
attr-cnt-name: __ethtool-a-coalesce-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -560,7 +755,12 @@ attribute-sets:
-
name: pause-stat
attr-cnt-name: __ethtool-a-pause-stat-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: pad
type: pad
@ -572,7 +772,12 @@ attribute-sets:
type: u64
-
name: pause
attr-cnt-name: __ethtool-a-pause-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -595,7 +800,12 @@ attribute-sets:
type: u32
-
name: eee
attr-cnt-name: __ethtool-a-eee-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -622,7 +832,12 @@ attribute-sets:
type: u32
-
name: ts-stat
attr-cnt-name: __ethtool-a-ts-stat-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: tx-pkts
type: uint
@ -632,9 +847,31 @@ attribute-sets:
-
name: tx-err
type: uint
-
name: tx-onestep-pkts-unconfirmed
type: uint
-
name: ts-hwtstamp-provider
attr-cnt-name: __ethtool-a-ts-hwtstamp-provider-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: index
type: u32
-
name: qualifier
type: u32
-
name: tsinfo
attr-cnt-name: __ethtool-a-tsinfo-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -658,21 +895,38 @@ attribute-sets:
name: stats
type: nest
nested-attributes: ts-stat
-
name: hwtstamp-provider
type: nest
nested-attributes: ts-hwtstamp-provider
-
name: cable-result
attr-cnt-name: __ethtool-a-cable-result-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: pair
doc: ETHTOOL_A_CABLE_PAIR
type: u8
-
name: code
doc: ETHTOOL_A_CABLE_RESULT_CODE
type: u8
-
name: src
doc: ETHTOOL_A_CABLE_INF_SRC
type: u32
-
name: cable-fault-length
attr-cnt-name: __ethtool-a-cable-fault-length-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: pair
type: u8
@ -684,7 +938,12 @@ attribute-sets:
type: u32
-
name: cable-nest
attr-cnt-name: __ethtool-a-cable-nest-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: result
type: nest
@ -695,20 +954,31 @@ attribute-sets:
nested-attributes: cable-fault-length
-
name: cable-test
attr-cnt-name: __ethtool-a-cable-test-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
nested-attributes: header
-
name: cable-test-ntf
attr-cnt-name: __ethtool-a-cable-test-ntf-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
nested-attributes: header
-
name: status
doc: _STARTED/_COMPLETE
type: u8
-
name: nest
@ -716,7 +986,12 @@ attribute-sets:
nested-attributes: cable-nest
-
name: cable-test-tdr-cfg
attr-cnt-name: __ethtool-a-cable-test-tdr-cfg-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: first
type: u32
@ -731,7 +1006,12 @@ attribute-sets:
type: u8
-
name: cable-test-tdr-ntf
attr-cnt-name: __ethtool-a-cable-test-tdr-ntf-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -745,7 +1025,12 @@ attribute-sets:
nested-attributes: cable-nest
-
name: cable-test-tdr
attr-cnt-name: __ethtool-a-cable-test-tdr-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -756,7 +1041,12 @@ attribute-sets:
nested-attributes: cable-test-tdr-cfg
-
name: tunnel-udp-entry
attr-cnt-name: __ethtool-a-tunnel-udp-entry-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: port
type: u16
@ -767,7 +1057,12 @@ attribute-sets:
enum: udp-tunnel-type
-
name: tunnel-udp-table
attr-cnt-name: __ethtool-a-tunnel-udp-table-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: size
type: u32
@ -782,14 +1077,24 @@ attribute-sets:
nested-attributes: tunnel-udp-entry
-
name: tunnel-udp
attr-cnt-name: __ethtool-a-tunnel-udp-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: table
type: nest
nested-attributes: tunnel-udp-table
-
name: tunnel-info
attr-cnt-name: __ethtool-a-tunnel-info-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -800,7 +1105,12 @@ attribute-sets:
nested-attributes: tunnel-udp
-
name: fec-stat
attr-cnt-name: __ethtool-a-fec-stat-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: pad
type: pad
@ -818,7 +1128,12 @@ attribute-sets:
sub-type: u64
-
name: fec
attr-cnt-name: __ethtool-a-fec-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -839,7 +1154,12 @@ attribute-sets:
nested-attributes: fec-stat
-
name: module-eeprom
attr-cnt-name: __ethtool-a-module-eeprom-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -864,7 +1184,12 @@ attribute-sets:
type: binary
-
name: stats-grp
attr-cnt-name: __ethtool-a-stats-grp-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: pad
type: pad
@ -907,7 +1232,12 @@ attribute-sets:
name: hist-val
-
name: stats
attr-cnt-name: __ethtool-a-stats-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: pad
type: pad
@ -928,7 +1258,12 @@ attribute-sets:
type: u32
-
name: phc-vclocks
attr-cnt-name: __ethtool-a-phc-vclocks-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -942,7 +1277,12 @@ attribute-sets:
sub-type: s32
-
name: module
attr-cnt-name: __ethtool-a-module-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -955,7 +1295,13 @@ attribute-sets:
type: u8
-
name: c33-pse-pw-limit
attr-cnt-name: __ethtool-a-c33-pse-pw-limit-cnt
attr-max-name: __ethtool-a-c33-pse-pw-limit-max
attributes:
-
name: unspec
type: unused
value: 0
-
name: min
type: u32
@ -964,7 +1310,12 @@ attribute-sets:
type: u32
-
name: pse
attr-cnt-name: __ethtool-a-pse-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -1022,7 +1373,12 @@ attribute-sets:
nested-attributes: c33-pse-pw-limit
-
name: rss
attr-cnt-name: __ethtool-a-rss-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -1048,7 +1404,12 @@ attribute-sets:
type: u32
-
name: plca
attr-cnt-name: __ethtool-a-plca-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -1079,7 +1440,12 @@ attribute-sets:
type: u32
-
name: module-fw-flash
attr-cnt-name: __ethtool-a-module-fw-flash-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -1105,7 +1471,12 @@ attribute-sets:
type: uint
-
name: phy
attr-cnt-name: __ethtool-a-phy-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
@ -1132,6 +1503,34 @@ attribute-sets:
-
name: downstream-sfp-name
type: string
-
name: tsconfig
attr-cnt-name: __ethtool-a-tsconfig-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: header
type: nest
nested-attributes: header
-
name: hwtstamp-provider
type: nest
nested-attributes: ts-hwtstamp-provider
-
name: tx-types
type: nest
nested-attributes: bitset
-
name: rx-filters
type: nest
nested-attributes: bitset
-
name: hwtstamp-flags
type: nest
nested-attributes: bitset
operations:
enum-model: directional
@ -1393,6 +1792,8 @@ operations:
- rx-push
- tx-push-buf-len
- tx-push-buf-len-max
- hds-thresh
- hds-thresh-max
dump: *ring-get-op
-
name: rings-set
@ -1573,6 +1974,7 @@ operations:
request:
attributes:
- header
- hwtstamp-provider
reply:
attributes:
- header
@ -1581,6 +1983,7 @@ operations:
- rx-filters
- phc-index
- stats
- hwtstamp-provider
dump: *tsinfo-get-op
-
name: cable-test-act
@ -1951,3 +2354,36 @@ operations:
- upstream-sfp-name
- downstream-sfp-name
dump: *phy-get-op
-
name: phy-ntf
doc: Notification for change in PHY devices.
notify: phy-get
-
name: tsconfig-get
doc: Get hwtstamp config.
attribute-set: tsconfig
do: &tsconfig-get-op
request:
attributes:
- header
reply:
attributes: &tsconfig
- header
- hwtstamp-provider
- tx-types
- rx-filters
- hwtstamp-flags
dump: *tsconfig-get-op
-
name: tsconfig-set
doc: Set hwtstamp config.
attribute-set: tsconfig
do:
request:
attributes: *tsconfig
reply:
attributes: *tsconfig

View File

@ -0,0 +1,17 @@
.. SPDX-License-Identifier: GPL-2.0
======================
Networking Diagnostics
======================
.. toctree::
:maxdepth: 2
twisted_pair_layer1_diagnostics.rst
.. only:: subproject and html
Indices
=======
* :ref:`genindex`

View File

@ -0,0 +1,784 @@
.. SPDX-License-Identifier: GPL-2.0
Diagnostic Concept for Investigating Twisted Pair Ethernet Variants at OSI Layer 1
==================================================================================
Introduction
------------
This documentation is designed for two primary audiences:
1. **Users and System Administrators**: For those dealing with real-world
Ethernet issues, this guide provides a practical, step-by-step
troubleshooting flow to help identify and resolve common problems in Twisted
Pair Ethernet at OSI Layer 1. If you're facing unstable links, speed drops,
or mysterious network issues, jump right into the step-by-step guide and
follow it through to find your solution.
2. **Kernel Developers**: For developers working with network drivers and PHY
support, this documentation outlines the diagnostic process and highlights
areas where the Linux kernels diagnostic interfaces could be extended or
improved. By understanding the diagnostic flow, developers can better
prioritize future enhancements.
Step-by-Step Diagnostic Guide from Linux (General Ethernet)
-----------------------------------------------------------
This diagnostic guide covers common Ethernet troubleshooting scenarios,
focusing on **link stability and detection** across different Ethernet
environments, including **Single-Pair Ethernet (SPE)** and **Multi-Pair
Ethernet (MPE)**, as well as power delivery technologies like **PoDL** (Power
over Data Line) and **PoE** (Clause 33 PSE).
The guide is designed to help users diagnose physical layer (Layer 1) issues on
systems running **Linux kernel version 6.11 or newer**, utilizing **ethtool
version 6.10 or later** and **iproute2 version 6.4.0 or later**.
In this guide, we assume that users may have **limited or no access to the link
partner** and will focus on diagnosing issues locally.
Diagnostic Scenarios
~~~~~~~~~~~~~~~~~~~~
- **Link is up and stable, but no data transfer**: If the link is stable but
there are issues with data transmission, refer to the **OSI Layer 2
Troubleshooting Guide**.
- **Link is unstable**: Link resets, speed drops, or other fluctuations
indicate potential issues at the hardware or physical layer.
- **No link detected**: The interface is up, but no link is established.
Verify Interface Status
~~~~~~~~~~~~~~~~~~~~~~~
Begin by verifying the status of the Ethernet interface to check if it is
administratively up. Unlike `ethtool`, which provides information on the link
and PHY status, it does not show the **administrative state** of the interface.
To check this, you should use the `ip` command, which describes the interface
state within the angle brackets `"<>"` in its output.
For example, in the output `<NO-CARRIER,BROADCAST,MULTICAST,UP>`, the important
keywords are:
- **UP**: The interface is in the administrative "UP" state.
- **NO-CARRIER**: The interface is administratively up, but no physical link is
detected.
If the output shows `<BROADCAST,MULTICAST>`, this indicates the interface is in
the administrative "DOWN" state.
- **Command:** `ip link show dev <interface>`
- **Expected Output:**
.. code-block:: bash
4: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 ...
link/ether 88:14:2b:00:96:f2 brd ff:ff:ff:ff:ff:ff
- **Interpreting the Output:**
- **Administrative UP State**:
- If the output contains **"UP"**, the interface is administratively up,
and the system is trying to establish a physical link.
- If you also see **"NO-CARRIER"**, it means the physical link has not been
detected, indicating potential Layer 1 issues like a cable fault,
misconfiguration, or no connection at the link partner. In this case,
proceed to the **Inspect Link Status and PHY Configuration** section.
- **Administrative DOWN State**:
- If the output lacks **"UP"** and shows only states like
**"<BROADCAST,MULTICAST>"**, it means the interface is administratively
down. In this case, bring the interface up using the following command:
.. code-block:: bash
ip link set dev <interface> up
- **Next Steps**:
- If the interface is **administratively up** but shows **NO-CARRIER**,
proceed to the **Inspect Link Status and PHY Configuration** section to
troubleshoot potential physical layer issues.
- If the interface was **administratively down** and you have brought it up,
ensure to **repeat this verification step** to confirm the new state of the
interface before proceeding
- **If the interface is up and the link is detected**:
- If the output shows **"UP"** and there is **no `NO-CARRIER`**, the
interface is administratively up, and the physical link has been
successfully established. If everything is working as expected, the Layer
1 diagnostics are complete, and no further action is needed.
- If the interface is up and the link is detected but **no data is being
transferred**, the issue is likely beyond Layer 1, and you should proceed
with diagnosing the higher layers of the OSI model. This may involve
checking Layer 2 configurations (such as VLANs or MAC address issues),
Layer 3 settings (like IP addresses, routing, or ARP), or Layer 4 and
above (firewalls, services, etc.).
- If the **link is unstable** or **frequently resetting or dropping**, this
may indicate a physical layer issue such as a faulty cable, interference,
or power delivery problems. In this case, proceed with the next step in
this guide.
Inspect Link Status and PHY Configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use `ethtool -I` to check the link status, PHY configuration, supported link
modes, and additional statistics such as the **Link Down Events** counter. This
step is essential for diagnosing Layer 1 problems such as speed mismatches,
duplex issues, and link instability.
For both **Single-Pair Ethernet (SPE)** and **Multi-Pair Ethernet (MPE)**
devices, you will use this step to gather key details about the link. **SPE**
links generally support a single speed and mode without autonegotiation (with
the exception of **10BaseT1L**), while **MPE** devices typically support
multiple link modes and autonegotiation.
- **Command:** `ethtool -I <interface>`
- **Example Output for SPE Interface (Non-autonegotiation)**:
.. code-block:: bash
Settings for spe4:
Supported ports: [ TP ]
Supported link modes: 100baseT1/Full
Supported pause frame use: No
Supports auto-negotiation: No
Supported FEC modes: Not reported
Advertised link modes: Not applicable
Advertised pause frame use: No
Advertised auto-negotiation: No
Advertised FEC modes: Not reported
Speed: 100Mb/s
Duplex: Full
Auto-negotiation: off
master-slave cfg: forced slave
master-slave status: slave
Port: Twisted Pair
PHYAD: 6
Transceiver: external
MDI-X: Unknown
Supports Wake-on: d
Wake-on: d
Link detected: yes
SQI: 7/7
Link Down Events: 2
- **Example Output for MPE Interface (Autonegotiation)**:
.. code-block:: bash
Settings for eth1:
Supported ports: [ TP MII ]
Supported link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
Supported pause frame use: Symmetric Receive-only
Supports auto-negotiation: Yes
Supported FEC modes: Not reported
Advertised link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
Advertised pause frame use: Symmetric Receive-only
Advertised auto-negotiation: Yes
Advertised FEC modes: Not reported
Link partner advertised link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
Link partner advertised pause frame use: Symmetric Receive-only
Link partner advertised auto-negotiation: Yes
Link partner advertised FEC modes: Not reported
Speed: 100Mb/s
Duplex: Full
Auto-negotiation: on
Port: Twisted Pair
PHYAD: 10
Transceiver: internal
MDI-X: Unknown
Supports Wake-on: pg
Wake-on: p
Link detected: yes
Link Down Events: 1
- **Next Steps**:
- Record the output provided by `ethtool`, particularly noting the
**master-slave status**, **speed**, **duplex**, and other relevant fields.
This information will be useful for further analysis or troubleshooting.
Once the **ethtool** output has been collected and stored, move on to the
next diagnostic step.
Check Power Delivery (PoDL or PoE)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If it is known that **PoDL** or **PoE** is **not implemented** on the system,
or the **PSE** (Power Sourcing Equipment) is managed by proprietary user-space
software or external tools, you can skip this step. In such cases, verify power
delivery through alternative methods, such as checking hardware indicators
(LEDs), using multimeters, or consulting vendor-specific software for
monitoring power status.
If **PoDL** or **PoE** is implemented and managed directly by Linux, follow
these steps to ensure power is being delivered correctly:
- **Command:** `ethtool --show-pse <interface>`
- **Expected Output Examples**:
1. **PSE Not Supported**:
If no PSE is attached or the interface does not support PSE, the following
output is expected:
.. code-block:: bash
netlink error: No PSE is attached
netlink error: Operation not supported
2. **PoDL (Single-Pair Ethernet)**:
When PoDL is implemented, you might see the following attributes:
.. code-block:: bash
PSE attributes for eth1:
PoDL PSE Admin State: enabled
PoDL PSE Power Detection Status: delivering power
3. **PoE (Clause 33 PSE)**:
For standard PoE, the output may look like this:
.. code-block:: bash
PSE attributes for eth1:
Clause 33 PSE Admin State: enabled
Clause 33 PSE Power Detection Status: delivering power
Clause 33 PSE Available Power Limit: 18000
- **Adjust Power Limit (if needed)**:
- Sometimes, the available power limit may not be sufficient for the link
partner. You can increase the power limit as needed.
- **Command:** `ethtool --set-pse <interface> c33-pse-avail-pw-limit <limit>`
Example:
.. code-block:: bash
ethtool --set-pse eth1 c33-pse-avail-pw-limit 18000
ethtool --show-pse eth1
**Expected Output** after adjusting the power limit:
.. code-block:: bash
Clause 33 PSE Available Power Limit: 18000
- **Next Steps**:
- **PoE or PoDL Not Used**: If **PoE** or **PoDL** is not implemented or used
on the system, proceed to the next diagnostic step, as power delivery is
not relevant for this setup.
- **PoE or PoDL Controlled Externally**: If **PoE** or **PoDL** is used but
is not managed by the Linux kernel's **PSE-PD** framework (i.e., it is
controlled by proprietary user-space software or external tools), this part
is out of scope for this documentation. Please consult vendor-specific
documentation or external tools for monitoring and managing power delivery.
- **PSE Admin State Disabled**:
- If the `PSE Admin State:` is **disabled**, enable it by running one of
the following commands:
.. code-block:: bash
ethtool --set-pse <devname> podl-pse-admin-control enable
or, for Clause 33 PSE (PoE):
ethtool --set-pse <devname> c33-pse-admin-control enable
- After enabling the PSE Admin State, return to the start of the **Check
Power Delivery (PoDL or PoE)** step to recheck the power delivery status.
- **Power Not Delivered**: If the `Power Detection Status` shows something
other than "delivering power" (e.g., `over current`), troubleshoot the
**PSE**. Check for potential issues such as a short circuit in the cable,
insufficient power delivery, or a fault in the PSE itself.
- **Power Delivered but No Link**: If power is being delivered but no link is
established, proceed with further diagnostics by performing **Cable
Diagnostics** or reviewing the **Inspect Link Status and PHY
Configuration** steps to identify any underlying issues with the physical
link or settings.
Cable Diagnostics
~~~~~~~~~~~~~~~~~
Use `ethtool` to test for physical layer issues such as cable faults. The test
results can vary depending on the cable's condition, the technology in use, and
the state of the link partner. The results from the cable test will help in
diagnosing issues like open circuits, shorts, impedance mismatches, and
noise-related problems.
- **Command:** `ethtool --cable-test <interface>`
The following are the typical outputs for **Single-Pair Ethernet (SPE)** and
**Multi-Pair Ethernet (MPE)**:
- **For Single-Pair Ethernet (SPE)**:
- **Expected Output (SPE)**:
.. code-block:: bash
Cable test completed for device eth1.
Pair A, fault length: 25.00m
Pair A code Open Circuit
This indicates an open circuit or cable fault at the reported distance, but
results can be influenced by the link partner's state. Refer to the
**"Troubleshooting Based on Cable Test Results"** section for further
interpretation of these results.
- **For Multi-Pair Ethernet (MPE)**:
- **Expected Output (MPE)**:
.. code-block:: bash
Cable test completed for device eth0.
Pair A code OK
Pair B code OK
Pair C code Open Circuit
Here, Pair C is reported as having an open circuit, while Pairs A and B are
functioning correctly. However, if autonegotiation is in use on Pairs A and
B, the cable test may be disrupted. Refer to the **"Troubleshooting Based on
Cable Test Results"** section for a detailed explanation of these issues and
how to resolve them.
For detailed descriptions of the different possible cable test results, please
refer to the **"Troubleshooting Based on Cable Test Results"** section.
Troubleshooting Based on Cable Test Results
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
After running the cable test, the results can help identify specific issues in
the physical connection. However, it is important to note that **cable testing
results heavily depend on the capabilities and characteristics of both the
local hardware and the link partner**. The accuracy and reliability of the
results can vary significantly between different hardware implementations.
In some cases, this can introduce **blind spots** in the current cable testing
implementation, where certain results may not accurately reflect the actual
physical state of the cable. For example:
- An **Open Circuit** result might not only indicate a damaged or disconnected
cable but also occur if the cable is properly attached to a powered-down link
partner.
- Some PHYs may report a **Short within Pair** if the link partner is in
**forced slave mode**, even though there is no actual short in the cable.
To help users interpret the results more effectively, it could be beneficial to
extend the **kernel UAPI** (User API) to provide additional context or
**possible variants** of issues based on the hardwares characteristics. Since
these quirks are often hardware-specific, the **kernel driver** would be an
ideal source of such information. By providing flags or hints related to
potential false positives for each test result, users would have a better
understanding of what to verify and where to investigate further.
Until such improvements are made, users should be aware of these limitations
and manually verify cable issues as needed. Physical inspections may help
resolve uncertainties related to false positive results.
The results can be one of the following:
- **OK**:
- The cable is functioning correctly, and no issues were detected.
- **Next Steps**: If you are still experiencing issues, it might be related
to higher-layer problems, such as duplex mismatches or speed negotiation,
which are not physical-layer issues.
- **Special Case for `BaseT1` (1000/100/10BaseT1)**: In `BaseT1` systems, an
"OK" result typically also means that the link is up and likely in **slave
mode**, since cable tests usually only pass in this mode. For some
**10BaseT1L** PHYs, an "OK" result may occur even if the cable is too long
for the PHY's configured range (for example, when the range is configured
for short-distance mode).
- **Open Circuit**:
- An **Open Circuit** result typically indicates that the cable is damaged or
disconnected at the reported fault length. Consider these possibilities:
- If the link partner is in **admin down** state or powered off, you might
still get an "Open Circuit" result even if the cable is functional.
- **Next Steps**: Inspect the cable at the fault length for visible damage
or loose connections. Verify the link partner is powered on and in the
correct mode.
- **Short within Pair**:
- A **Short within Pair** indicates an unintended connection within the same
pair of wires, typically caused by physical damage to the cable.
- **Next Steps**: Replace or repair the cable and check for any physical
damage or improperly crimped connectors.
- **Short to Another Pair**:
- A **Short to Another Pair** means the wires from different pairs are
shorted, which could occur due to physical damage or incorrect wiring.
- **Next Steps**: Replace or repair the damaged cable. Inspect the cable for
incorrect terminations or pinched wiring.
- **Impedance Mismatch**:
- **Impedance Mismatch** indicates a reflection caused by an impedance
discontinuity in the cable. This can happen when a part of the cable has
abnormal impedance (e.g., when different cable types are spliced together
or when there is a defect in the cable).
- **Next Steps**: Check the cable quality and ensure consistent impedance
throughout its length. Replace any sections of the cable that do not meet
specifications.
- **Noise**:
- **Noise** means that the Time Domain Reflectometry (TDR) test could not
complete due to excessive noise on the cable, which can be caused by
interference from electromagnetic sources.
- **Next Steps**: Identify and eliminate sources of electromagnetic
interference (EMI) near the cable. Consider using shielded cables or
rerouting the cable away from noise sources.
- **Resolution Not Possible**:
- **Resolution Not Possible** means that the TDR test could not detect the
issue due to the resolution limitations of the test or because the fault is
beyond the distance that the test can measure.
- **Next Steps**: Inspect the cable manually if possible, or use alternative
diagnostic tools that can handle greater distances or higher resolution.
- **Unknown**:
- An **Unknown** result may occur when the test cannot classify the fault or
when a specific issue is outside the scope of the tool's detection
capabilities.
- **Next Steps**: Re-run the test, verify the link partner's state, and inspect
the cable manually if necessary.
Verify Link Partner PHY Configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If the cable test passes but the link is still not functioning correctly, its
essential to verify the configuration of the link partners PHY. Mismatches in
speed, duplex settings, or master-slave roles can cause connection issues.
Autonegotiation Mismatch
^^^^^^^^^^^^^^^^^^^^^^^^
- If both link partners support autonegotiation, ensure that autonegotiation is
enabled on both sides and that all supported link modes are advertised. A
mismatch can lead to connectivity problems or sub optimal performance.
- **Quick Fix:** Reset autonegotiation to the default settings, which will
advertise all default link modes:
.. code-block:: bash
ethtool -s <interface> autoneg on
- **Command to check configuration:** `ethtool <interface>`
- **Expected Output:** Ensure that both sides advertise compatible link modes.
If autonegotiation is off, verify that both link partners are configured for
the same speed and duplex.
The following example shows a case where the local PHY advertises fewer link
modes than it supports. This will reduce the number of overlapping link modes
with the link partner. In the worst case, there will be no common link modes,
and the link will not be created:
.. code-block:: bash
Settings for eth0:
Supported link modes: 1000baseT/Full, 100baseT/Full
Advertised link modes: 1000baseT/Full
Speed: 1000Mb/s
Duplex: Full
Auto-negotiation: on
Combined Mode Mismatch (Autonegotiation on One Side, Forced on the Other)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- One possible issue occurs when one side is using **autonegotiation** (as in
most modern systems), and the other side is set to a **forced link mode**
(e.g., older hardware with single-speed hubs). In such cases, modern PHYs
will attempt to detect the forced mode on the other side. If the link is
established, you may notice:
- **No or empty "Link partner advertised link modes"**.
- **"Link partner advertised auto-negotiation:"** will be **"no"** or not
present.
- This type of detection does not always work reliably:
- Typically, the modern PHY will default to **Half Duplex**, even if the link
partner is actually configured for **Full Duplex**.
- Some PHYs may not work reliably if the link partner switches from one
forced mode to another. In this case, only a down/up cycle may help.
- **Next Steps**: Set both sides to the same fixed speed and duplex mode to
avoid potential detection issues.
.. code-block:: bash
ethtool -s <interface> speed 1000 duplex full autoneg off
Master/Slave Role Mismatch (BaseT1 and 1000BaseT PHYs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- In **BaseT1** systems (e.g., 1000BaseT1, 100BaseT1), link establishment
requires that one device is configured as **master** and the other as
**slave**. A mismatch in this master-slave configuration can prevent the link
from being established. However, **1000BaseT** also supports configurable
master/slave roles and can face similar issues.
- **Role Preference in 1000BaseT**: The **1000BaseT** specification allows link
partners to negotiate master-slave roles or role preferences during
autonegotiation. Some PHYs have hardware limitations or bugs that prevent
them from functioning properly in certain roles. In such cases, drivers may
force these PHYs into a specific role (e.g., **forced master** or **forced
slave**) or try a weaker option by setting preferences. If both link partners
have the same issue and are forced into the same mode (e.g., both forced into
master mode), they will not be able to establish a link.
- **Next Steps**: Ensure that one side is configured as **master** and the
other as **slave** to avoid this issue, particularly when hardware
limitations are involved, or try the weaker **preferred** option instead of
**forced**. Check for any driver-related restrictions or forced modes.
- **Command to force master/slave mode**:
.. code-block:: bash
ethtool -s <interface> master-slave forced-master
or:
.. code-block:: bash
ethtool -s <interface> master-slave forced-master speed 1000 duplex full autoneg off
- **Check the current master/slave status**:
.. code-block:: bash
ethtool <interface>
Example Output:
.. code-block:: bash
master-slave cfg: forced-master
master-slave status: master
- **Hardware Bugs and Driver Forcing**: If a known hardware issue forces the
PHY into a specific mode, its essential to check the driver source code or
hardware documentation for details. Ensure that the roles are compatible
across both link partners, and if both PHYs are forced into the same mode,
adjust one side accordingly to resolve the mismatch.
Monitor Link Resets and Speed Drops
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If the link is unstable, showing frequent resets or speed drops, this may
indicate issues with the cable, PHY configuration, or environmental factors.
While there is still no completely unified way in Linux to directly monitor
downshift events or link speed changes via user space tools, both the Linux
kernel logs and `ethtool` can provide valuable insights, especially if the
driver supports reporting such events.
- **Monitor Kernel Logs for Link Resets and Speed Drops**:
- The Linux kernel will print link status changes, including downshift
events, in the system logs. These messages typically include speed changes,
duplex mode, and downshifted link speed (if the driver supports it).
- **Command to monitor kernel logs in real-time:**
.. code-block:: bash
dmesg -w | grep "Link is Up\|Link is Down"
- Example Output (if a downshift occurs):
.. code-block:: bash
eth0: Link is Up - 100Mbps/Full (downshifted) - flow control rx/tx
eth0: Link is Down
This indicates that the link has been established but has downshifted from
a higher speed.
- **Note**: Not all drivers or PHYs support downshift reporting, so you may
not see this information for all devices.
- **Monitor Link Down Events Using `ethtool`**:
- Starting with the latest kernel and `ethtool` versions, you can track
**Link Down Events** using the `ethtool -I` command. This will provide
counters for link drops, helping to diagnose link instability issues if
supported by the driver.
- **Command to monitor link down events:**
.. code-block:: bash
ethtool -I <interface>
- Example Output (if supported):
.. code-block:: bash
PSE attributes for eth1:
Link Down Events: 5
This indicates that the link has dropped 5 times. Frequent link down events
may indicate cable or environmental issues that require further
investigation.
- **Check Link Status and Speed**:
- Even though downshift counts or events are not easily tracked, you can
still use `ethtool` to manually check the current link speed and status.
- **Command:** `ethtool <interface>`
- **Expected Output:**
.. code-block:: bash
Speed: 1000Mb/s
Duplex: Full
Auto-negotiation: on
Link detected: yes
Any inconsistencies in the expected speed or duplex setting could indicate
an issue.
- **Disable Energy-Efficient Ethernet (EEE) for Diagnostics**:
- **EEE** (Energy-Efficient Ethernet) can be a source of link instability due
to transitions in and out of low-power states. For diagnostic purposes, it
may be useful to **temporarily** disable EEE to determine if it is
contributing to link instability. This is **not a generic recommendation**
for disabling power management.
- **Next Steps**: Disable EEE and monitor if the link becomes stable. If
disabling EEE resolves the issue, report the bug so that the driver can be
fixed.
- **Command:**
.. code-block:: bash
ethtool --set-eee <interface> eee off
- **Important**: If disabling EEE resolves the instability, the issue should
be reported to the maintainers as a bug, and the driver should be corrected
to handle EEE properly without causing instability. Disabling EEE
permanently should not be seen as a solution.
- **Monitor Error Counters**:
- Use `ethtool -S <interface> --all-groups` to retrieve standardized interface
statistics if the driver supports the unified interface:
- **Command:** `ethtool -S <interface> --all-groups`
- **Example Output (if supported)**:
.. code-block:: bash
phydev-RxFrames: 100391
phydev-RxErrors: 0
phydev-TxFrames: 9
phydev-TxErrors: 0
- If the unified interface is not supported, use `ethtool -S <interface>` to
retrieve MAC and PHY counters. Note that non-standardized PHY counter names
vary by driver and must be interpreted accordingly:
- **Command:** `ethtool -S <interface>`
- **Example Output (if supported)**:
.. code-block:: bash
rx_crc_errors: 123
tx_errors: 45
rx_frame_errors: 78
- **Note**: If no meaningful error counters are available or if counters are
not supported, you may need to rely on physical inspections (e.g., cable
condition) or kernel log messages (e.g., link up/down events) to further
diagnose the issue.
- **Compare Counters**:
- Compare the egress and ingress frame counts reported by the PHY and MAC.
- A small difference may occur due to sampling rate differences between the
MAC and PHY drivers, or if the PHY and MAC are not always fully
synchronized in their UP or DOWN states.
- Significant discrepancies indicate potential issues in the data path
between the MAC and PHY.
When All Else Fails...
~~~~~~~~~~~~~~~~~~~~~~
So you've checked the cables, monitored the logs, disabled EEE, and still...
nothing? Dont worry, youre not alone. Sometimes, Ethernet gremlins just dont
want to cooperate.
But before you throw in the towel (or the Ethernet cable), take a deep breath.
Its always possible that:
1. Your PHY has a unique, undocumented personality.
2. The problem is lying dormant, waiting for just the right moment to magically
resolve itself (hey, it happens!).
3. Or, it could be that the ultimate solution simply hasnt been invented yet.
If none of the above bring you comfort, theres one final step: contribute! If
you've uncovered new or unusual issues, or have creative diagnostic methods,
feel free to share your findings and extend this documentation. Together, we
can hunt down every elusive network issue - one twisted pair at a time.
Remember: sometimes the solution is just a reboot away, but if not, its time to
dig deeper - or report that bug!

View File

@ -236,6 +236,9 @@ Userspace to kernel:
``ETHTOOL_MSG_MM_GET`` get MAC merge layer state
``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters
``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` flash transceiver module firmware
``ETHTOOL_MSG_PHY_GET`` get Ethernet PHY information
``ETHTOOL_MSG_TSCONFIG_GET`` get hw timestamping configuration
``ETHTOOL_MSG_TSCONFIG_SET`` set hw timestamping configuration
===================================== =================================
Kernel to userspace:
@ -283,6 +286,10 @@ Kernel to userspace:
``ETHTOOL_MSG_PLCA_NTF`` PLCA RS parameters
``ETHTOOL_MSG_MM_GET_REPLY`` MAC merge layer status
``ETHTOOL_MSG_MODULE_FW_FLASH_NTF`` transceiver module flash updates
``ETHTOOL_MSG_PHY_GET_REPLY`` Ethernet PHY information
``ETHTOOL_MSG_PHY_NTF`` Ethernet PHY information change
``ETHTOOL_MSG_TSCONFIG_GET_REPLY`` hw timestamping configuration
``ETHTOOL_MSG_TSCONFIG_SET_REPLY`` new hw timestamping configuration
======================================== =================================
``GET`` requests are sent by userspace applications to retrieve device
@ -892,6 +899,10 @@ Kernel response contents:
``ETHTOOL_A_RINGS_RX_PUSH`` u8 flag of RX Push mode
``ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN`` u32 size of TX push buffer
``ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX`` u32 max size of TX push buffer
``ETHTOOL_A_RINGS_HDS_THRESH`` u32 threshold of
header / data split
``ETHTOOL_A_RINGS_HDS_THRESH_MAX`` u32 max threshold of
header / data split
======================================= ====== ===========================
``ETHTOOL_A_RINGS_TCP_DATA_SPLIT`` indicates whether the device is usable with
@ -934,10 +945,12 @@ Request contents:
``ETHTOOL_A_RINGS_RX_JUMBO`` u32 size of RX jumbo ring
``ETHTOOL_A_RINGS_TX`` u32 size of TX ring
``ETHTOOL_A_RINGS_RX_BUF_LEN`` u32 size of buffers on the ring
``ETHTOOL_A_RINGS_TCP_DATA_SPLIT`` u8 TCP header / data split
``ETHTOOL_A_RINGS_CQE_SIZE`` u32 Size of TX/RX CQE
``ETHTOOL_A_RINGS_TX_PUSH`` u8 flag of TX Push mode
``ETHTOOL_A_RINGS_RX_PUSH`` u8 flag of RX Push mode
``ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN`` u32 size of TX push buffer
``ETHTOOL_A_RINGS_HDS_THRESH`` u32 threshold of header / data split
==================================== ====== ===========================
Kernel checks that requested ring sizes do not exceed limits reported by
@ -954,6 +967,10 @@ A bigger CQE can have more receive buffer pointers, and in turn the NIC can
transfer a bigger frame from wire. Based on the NIC hardware, the overall
completion queue size can be adjusted in the driver if CQE size is modified.
``ETHTOOL_A_RINGS_HDS_THRESH`` specifies the threshold value of
header / data split feature. If a received packet size is larger than this
threshold value, header and data will be split.
CHANNELS_GET
============
@ -1242,9 +1259,10 @@ Gets timestamping information like ``ETHTOOL_GET_TS_INFO`` ioctl request.
Request contents:
===================================== ====== ==========================
``ETHTOOL_A_TSINFO_HEADER`` nested request header
===================================== ====== ==========================
======================================== ====== ============================
``ETHTOOL_A_TSINFO_HEADER`` nested request header
``ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER`` nested PTP hw clock provider
======================================== ====== ============================
Kernel response contents:
@ -1263,11 +1281,17 @@ would be empty (no bit set).
Additional hardware timestamping statistics response contents:
===================================== ====== ===================================
``ETHTOOL_A_TS_STAT_TX_PKTS`` uint Packets with Tx HW timestamps
``ETHTOOL_A_TS_STAT_TX_LOST`` uint Tx HW timestamp not arrived count
``ETHTOOL_A_TS_STAT_TX_ERR`` uint HW error request Tx timestamp count
===================================== ====== ===================================
================================================== ====== =====================
``ETHTOOL_A_TS_STAT_TX_PKTS`` uint Packets with Tx
HW timestamps
``ETHTOOL_A_TS_STAT_TX_LOST`` uint Tx HW timestamp
not arrived count
``ETHTOOL_A_TS_STAT_TX_ERR`` uint HW error request
Tx timestamp count
``ETHTOOL_A_TS_STAT_TX_ONESTEP_PKTS_UNCONFIRMED`` uint Packets with one-step
HW TX timestamps with
unconfirmed delivery
================================================== ====== =====================
CABLE_TEST
==========
@ -1608,6 +1632,7 @@ the ``ETHTOOL_A_STATS_GROUPS`` bitset. Currently defined values are:
ETHTOOL_STATS_ETH_PHY eth-phy Basic IEEE 802.3 PHY statistics (30.3.2.1.*)
ETHTOOL_STATS_ETH_CTRL eth-ctrl Basic IEEE 802.3 MAC Ctrl statistics (30.3.3.*)
ETHTOOL_STATS_RMON rmon RMON (RFC 2819) statistics
ETHTOOL_STATS_PHY phy Additional PHY statistics, not defined by IEEE
====================== ======== ===============================================
Each group should have a corresponding ``ETHTOOL_A_STATS_GRP`` in the reply.
@ -1909,7 +1934,7 @@ ETHTOOL_A_RSS_INDIR attribute returns RSS indirection table where each byte
indicates queue number.
ETHTOOL_A_RSS_INPUT_XFRM attribute is a bitmap indicating the type of
transformation applied to the input protocol fields before given to the RSS
hfunc. Current supported option is symmetric-xor.
hfunc. Current supported options are symmetric-xor and symmetric-or-xor.
PLCA_GET_CFG
============
@ -2240,6 +2265,75 @@ Kernel response contents:
When ``ETHTOOL_A_PHY_UPSTREAM_TYPE`` is PHY_UPSTREAM_PHY, the PHY's parent is
another PHY.
TSCONFIG_GET
============
Retrieves the information about the current hardware timestamping source and
configuration.
It is similar to the deprecated ``SIOCGHWTSTAMP`` ioctl request.
Request contents:
==================================== ====== ==========================
``ETHTOOL_A_TSCONFIG_HEADER`` nested request header
==================================== ====== ==========================
Kernel response contents:
======================================== ====== ============================
``ETHTOOL_A_TSCONFIG_HEADER`` nested request header
``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider
``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type
``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter
``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags
======================================== ====== ============================
When set the ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` attribute identifies the
source of the hw timestamping provider. It is composed by
``ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX`` attribute which describe the index of
the PTP device and ``ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER`` which describe
the qualifier of the timestamp.
When set the ``ETHTOOL_A_TSCONFIG_TX_TYPES``, ``ETHTOOL_A_TSCONFIG_RX_FILTERS``
and the ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` attributes identify the Tx
type, the Rx filter and the flags configured for the current hw timestamping
provider. The attributes are propagated to the driver through the following
structure:
.. kernel-doc:: include/linux/net_tstamp.h
:identifiers: kernel_hwtstamp_config
TSCONFIG_SET
============
Set the information about the current hardware timestamping source and
configuration.
It is similar to the deprecated ``SIOCSHWTSTAMP`` ioctl request.
Request contents:
======================================== ====== ============================
``ETHTOOL_A_TSCONFIG_HEADER`` nested request header
``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider
``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type
``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter
``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags
======================================== ====== ============================
Kernel response contents:
======================================== ====== ============================
``ETHTOOL_A_TSCONFIG_HEADER`` nested request header
``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider
``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type
``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter
``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags
======================================== ====== ============================
For a description of each attribute, see ``TSCONFIG_GET``.
Request translation
===================
@ -2348,4 +2442,6 @@ are netlink only.
n/a ``ETHTOOL_MSG_MM_SET``
n/a ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT``
n/a ``ETHTOOL_MSG_PHY_GET``
``SIOCGHWTSTAMP`` ``ETHTOOL_MSG_TSCONFIG_GET``
``SIOCSHWTSTAMP`` ``ETHTOOL_MSG_TSCONFIG_SET``
=================================== =====================================

View File

@ -13,6 +13,7 @@ Contents:
can
can_ucan_protocol
device_drivers/index
diagnostic/index
dsa/index
devlink/index
caif/index

View File

@ -49,14 +49,21 @@ destination address) and TCP/UDP (source port, destination port) tuples
are swapped, the computed hash is the same. This is beneficial in some
applications that monitor TCP/IP flows (IDS, firewalls, ...etc) and need
both directions of the flow to land on the same Rx queue (and CPU). The
"Symmetric-XOR" is a type of RSS algorithms that achieves this hash
symmetry by XORing the input source and destination fields of the IP
and/or L4 protocols. This, however, results in reduced input entropy and
could potentially be exploited. Specifically, the algorithm XORs the input
"Symmetric-XOR" and "Symmetric-OR-XOR" are types of RSS algorithms that
achieve this hash symmetry by XOR/ORing the input source and destination
fields of the IP and/or L4 protocols. This, however, results in reduced
input entropy and could potentially be exploited.
Specifically, the "Symmetric-XOR" algorithm XORs the input
as follows::
# (SRC_IP ^ DST_IP, SRC_IP ^ DST_IP, SRC_PORT ^ DST_PORT, SRC_PORT ^ DST_PORT)
The "Symmetric-OR-XOR" algorithm, on the other hand, transforms the input as
follows::
# (SRC_IP | DST_IP, SRC_IP ^ DST_IP, SRC_PORT | DST_PORT, SRC_PORT ^ DST_PORT)
The result is then fed to the underlying RSS algorithm.
Some advanced NICs allow steering packets to queues based on

View File

@ -266,6 +266,23 @@ SOF_TIMESTAMPING_OPT_TX_SWHW:
two separate messages will be looped to the socket's error queue,
each containing just one timestamp.
SOF_TIMESTAMPING_OPT_RX_FILTER:
Filter out spurious receive timestamps: report a receive timestamp
only if the matching timestamp generation flag is enabled.
Receive timestamps are generated early in the ingress path, before a
packet's destination socket is known. If any socket enables receive
timestamps, packets for all socket will receive timestamped packets.
Including those that request timestamp reporting with
SOF_TIMESTAMPING_SOFTWARE and/or SOF_TIMESTAMPING_RAW_HARDWARE, but
do not request receive timestamp generation. This can happen when
requesting transmit timestamps only.
Receiving spurious timestamps is generally benign. A process can
ignore the unexpected non-zero value. But it makes behavior subtly
dependent on other sockets. This flag isolates the socket for more
deterministic behavior.
New applications are encouraged to pass SOF_TIMESTAMPING_OPT_ID to
disambiguate timestamps and SOF_TIMESTAMPING_OPT_TSONLY to operate
regardless of the setting of sysctl net.core.tstamp_allow_data.
@ -492,8 +509,8 @@ implicitly defined. ts[0] holds a software timestamp if set, ts[1]
is again deprecated and ts[2] holds a hardware timestamp if set.
3. Hardware Timestamping configuration: SIOCSHWTSTAMP and SIOCGHWTSTAMP
=======================================================================
3. Hardware Timestamping configuration: ETHTOOL_MSG_TSCONFIG_SET/GET
====================================================================
Hardware time stamping must also be initialized for each device driver
that is expected to do hardware time stamping. The parameter is defined in
@ -506,12 +523,14 @@ include/uapi/linux/net_tstamp.h as::
};
Desired behavior is passed into the kernel and to a specific device by
calling ioctl(SIOCSHWTSTAMP) with a pointer to a struct ifreq whose
ifr_data points to a struct hwtstamp_config. The tx_type and
rx_filter are hints to the driver what it is expected to do. If
the requested fine-grained filtering for incoming packets is not
supported, the driver may time stamp more than just the requested types
of packets.
calling the tsconfig netlink socket ``ETHTOOL_MSG_TSCONFIG_SET``.
The ``ETHTOOL_A_TSCONFIG_TX_TYPES``, ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` and
``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` netlink attributes are then used to set
the struct hwtstamp_config accordingly.
The ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` netlink nested attribute is used
to select the source of the hardware time stamping. It is composed of an index
for the device source and a qualifier for the type of time stamping.
Drivers are free to use a more permissive configuration than the requested
configuration. It is expected that drivers should only implement directly the
@ -530,9 +549,16 @@ Only a processes with admin rights may change the configuration. User
space is responsible to ensure that multiple processes don't interfere
with each other and that the settings are reset.
Any process can read the actual configuration by passing this
structure to ioctl(SIOCGHWTSTAMP) in the same way. However, this has
not been implemented in all drivers.
Any process can read the actual configuration by requesting tsconfig netlink
socket ``ETHTOOL_MSG_TSCONFIG_GET``.
The legacy configuration is the use of the ioctl(SIOCSHWTSTAMP) with a pointer
to a struct ifreq whose ifr_data points to a struct hwtstamp_config.
The tx_type and rx_filter are hints to the driver what it is expected to do.
If the requested fine-grained filtering for incoming packets is not
supported, the driver may time stamp more than just the requested types
of packets. ioctl(SIOCGHWTSTAMP) is used in the same way as the
ioctl(SIOCSHWTSTAMP). However, this has not been implemented in all drivers.
::
@ -577,9 +603,10 @@ not been implemented in all drivers.
--------------------------------------------------------
A driver which supports hardware time stamping must support the
SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with
the actual values as described in the section on SIOCSHWTSTAMP. It
should also support SIOCGHWTSTAMP.
ndo_hwtstamp_set NDO or the legacy SIOCSHWTSTAMP ioctl and update the
supplied struct hwtstamp_config with the actual values as described in
the section on SIOCSHWTSTAMP. It should also support ndo_hwtstamp_get or
the legacy SIOCGHWTSTAMP.
Time stamps for received packets must be stored in the skb. To get a pointer
to the shared time stamp structure of the skb call skb_hwtstamps(). Then

View File

@ -56,7 +56,9 @@ If ``name-prefix`` is specified it replaces the ``$family-$enum``
portion of the entry name.
Boolean ``render-max`` controls creation of the max values
(which are enabled by default for attribute enums).
(which are enabled by default for attribute enums). These max
values are named ``__$pfx-MAX`` and ``$pfx-MAX``. The name
of the first value can be overridden via ``enum-cnt-name`` property.
Attributes
==========

View File

@ -1852,7 +1852,7 @@ static int iavf_set_rxfh(struct net_device *netdev,
static const struct ethtool_ops iavf_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_USE_ADAPTIVE,
.cap_rss_sym_xor_supported = true,
.supported_input_xfrm = RXH_XFRM_SYM_XOR,
.get_drvinfo = iavf_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_ringparam = iavf_get_ringparam,

View File

@ -4770,7 +4770,7 @@ static const struct ethtool_ops ice_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_USE_ADAPTIVE |
ETHTOOL_COALESCE_RX_USECS_HIGH,
.cap_rss_sym_xor_supported = true,
.supported_input_xfrm = RXH_XFRM_SYM_XOR,
.rxfh_per_ctx_key = true,
.get_link_ksettings = ice_get_link_ksettings,
.set_link_ksettings = ice_set_link_ksettings,

View File

@ -59,6 +59,7 @@ const struct ethtool_ops ef100_ethtool_ops = {
.get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
.get_rxfh_key_size = efx_ethtool_get_rxfh_key_size,
.rxfh_per_ctx_key = true,
.cap_rss_rxnfc_adds = true,
.rxfh_priv_size = sizeof(struct efx_rss_context_priv),
.get_rxfh = efx_ethtool_get_rxfh,
.set_rxfh = efx_ethtool_set_rxfh,

View File

@ -263,6 +263,7 @@ const struct ethtool_ops efx_ethtool_ops = {
.get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
.get_rxfh_key_size = efx_ethtool_get_rxfh_key_size,
.rxfh_per_ctx_key = true,
.cap_rss_rxnfc_adds = true,
.rxfh_priv_size = sizeof(struct efx_rss_context_priv),
.get_rxfh = efx_ethtool_get_rxfh,
.set_rxfh = efx_ethtool_set_rxfh,

View File

@ -2,8 +2,8 @@
// Copyright (c) 2020 Facebook
#include <linux/debugfs.h>
#include <linux/ethtool.h>
#include <linux/random.h>
#include <net/netdev_queues.h>
#include "netdevsim.h"
@ -72,6 +72,10 @@ static void nsim_get_ringparam(struct net_device *dev,
struct netdevsim *ns = netdev_priv(dev);
memcpy(ring, &ns->ethtool.ring, sizeof(ns->ethtool.ring));
kernel_ring->hds_thresh_max = NSIM_HDS_THRESHOLD_MAX;
if (kernel_ring->tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_UNKNOWN)
kernel_ring->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_ENABLED;
}
static int nsim_set_ringparam(struct net_device *dev,
@ -161,6 +165,8 @@ static int nsim_get_ts_info(struct net_device *dev,
static const struct ethtool_ops nsim_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_ALL_PARAMS,
.supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT |
ETHTOOL_RING_USE_HDS_THRS,
.get_pause_stats = nsim_get_pause_stats,
.get_pauseparam = nsim_get_pauseparam,
.set_pauseparam = nsim_set_pauseparam,
@ -182,6 +188,7 @@ static void nsim_ethtool_ring_init(struct netdevsim *ns)
ns->ethtool.ring.rx_jumbo_max_pending = 4096;
ns->ethtool.ring.rx_mini_max_pending = 4096;
ns->ethtool.ring.tx_max_pending = 4096;
}
void nsim_ethtool_init(struct netdevsim *ns)

View File

@ -15,6 +15,7 @@
#include <linux/debugfs.h>
#include <linux/etherdevice.h>
#include <linux/ethtool_netlink.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
@ -54,6 +55,7 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct net_device *peer_dev;
unsigned int len = skb->len;
struct netdevsim *peer_ns;
struct netdev_config *cfg;
struct nsim_rq *rq;
int rxq;
@ -71,6 +73,13 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
rxq = rxq % peer_dev->num_rx_queues;
rq = &peer_ns->rq[rxq];
cfg = peer_dev->cfg;
if (skb_is_nonlinear(skb) &&
(cfg->hds_config != ETHTOOL_TCP_DATA_SPLIT_ENABLED ||
(cfg->hds_config == ETHTOOL_TCP_DATA_SPLIT_ENABLED &&
cfg->hds_thresh > len)))
skb_linearize(skb);
skb_tx_timestamp(skb);
if (unlikely(nsim_forward_skb(peer_dev, skb, rq) == NET_RX_DROP))
goto out_drop_cnt;

View File

@ -16,6 +16,7 @@
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/ethtool.h>
#include <linux/ethtool_netlink.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/netdevice.h>
@ -36,6 +37,8 @@
#define NSIM_IPSEC_VALID BIT(31)
#define NSIM_UDP_TUNNEL_N_PORTS 4
#define NSIM_HDS_THRESHOLD_MAX 1024
struct nsim_sa {
struct xfrm_state *xs;
__be32 ipaddr[4];

View File

@ -13,7 +13,7 @@
*/
const char *phy_speed_to_str(int speed)
{
BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 103,
BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 121,
"Enum ethtool_link_mode_bit_indices and phylib are out of sync. "
"If a speed or mode has been added please update phy_speed_to_str "
"and the PHY settings array.\n");
@ -169,6 +169,12 @@ static const struct phy_setting settings[] = {
PHY_SETTING( 800000, FULL, 800000baseDR8_2_Full ),
PHY_SETTING( 800000, FULL, 800000baseSR8_Full ),
PHY_SETTING( 800000, FULL, 800000baseVR8_Full ),
PHY_SETTING( 800000, FULL, 800000baseCR4_Full ),
PHY_SETTING( 800000, FULL, 800000baseKR4_Full ),
PHY_SETTING( 800000, FULL, 800000baseDR4_Full ),
PHY_SETTING( 800000, FULL, 800000baseDR4_2_Full ),
PHY_SETTING( 800000, FULL, 800000baseSR4_Full ),
PHY_SETTING( 800000, FULL, 800000baseVR4_Full ),
/* 400G */
PHY_SETTING( 400000, FULL, 400000baseCR8_Full ),
PHY_SETTING( 400000, FULL, 400000baseKR8_Full ),
@ -180,6 +186,12 @@ static const struct phy_setting settings[] = {
PHY_SETTING( 400000, FULL, 400000baseLR4_ER4_FR4_Full ),
PHY_SETTING( 400000, FULL, 400000baseDR4_Full ),
PHY_SETTING( 400000, FULL, 400000baseSR4_Full ),
PHY_SETTING( 400000, FULL, 400000baseCR2_Full ),
PHY_SETTING( 400000, FULL, 400000baseKR2_Full ),
PHY_SETTING( 400000, FULL, 400000baseDR2_Full ),
PHY_SETTING( 400000, FULL, 400000baseDR2_2_Full ),
PHY_SETTING( 400000, FULL, 400000baseSR2_Full ),
PHY_SETTING( 400000, FULL, 400000baseVR2_Full ),
/* 200G */
PHY_SETTING( 200000, FULL, 200000baseCR4_Full ),
PHY_SETTING( 200000, FULL, 200000baseKR4_Full ),
@ -191,6 +203,12 @@ static const struct phy_setting settings[] = {
PHY_SETTING( 200000, FULL, 200000baseLR2_ER2_FR2_Full ),
PHY_SETTING( 200000, FULL, 200000baseDR2_Full ),
PHY_SETTING( 200000, FULL, 200000baseSR2_Full ),
PHY_SETTING( 200000, FULL, 200000baseCR_Full ),
PHY_SETTING( 200000, FULL, 200000baseKR_Full ),
PHY_SETTING( 200000, FULL, 200000baseDR_Full ),
PHY_SETTING( 200000, FULL, 200000baseDR_2_Full ),
PHY_SETTING( 200000, FULL, 200000baseSR_Full ),
PHY_SETTING( 200000, FULL, 200000baseVR_Full ),
/* 100G */
PHY_SETTING( 100000, FULL, 100000baseCR4_Full ),
PHY_SETTING( 100000, FULL, 100000baseKR4_Full ),

View File

@ -615,6 +615,49 @@ int phy_ethtool_get_stats(struct phy_device *phydev,
}
EXPORT_SYMBOL(phy_ethtool_get_stats);
/**
* __phy_ethtool_get_phy_stats - Retrieve standardized PHY statistics
* @phydev: Pointer to the PHY device
* @phy_stats: Pointer to ethtool_eth_phy_stats structure
* @phydev_stats: Pointer to ethtool_phy_stats structure
*
* Fetches PHY statistics using a kernel-defined interface for consistent
* diagnostics. Unlike phy_ethtool_get_stats(), which allows custom stats,
* this function enforces a standardized format for better interoperability.
*/
void __phy_ethtool_get_phy_stats(struct phy_device *phydev,
struct ethtool_eth_phy_stats *phy_stats,
struct ethtool_phy_stats *phydev_stats)
{
if (!phydev->drv || !phydev->drv->get_phy_stats)
return;
mutex_lock(&phydev->lock);
phydev->drv->get_phy_stats(phydev, phy_stats, phydev_stats);
mutex_unlock(&phydev->lock);
}
/**
* __phy_ethtool_get_link_ext_stats - Retrieve extended link statistics for a PHY
* @phydev: Pointer to the PHY device
* @link_stats: Pointer to the structure to store extended link statistics
*
* Populates the ethtool_link_ext_stats structure with link down event counts
* and additional driver-specific link statistics, if available.
*/
void __phy_ethtool_get_link_ext_stats(struct phy_device *phydev,
struct ethtool_link_ext_stats *link_stats)
{
link_stats->link_down_events = READ_ONCE(phydev->link_down_events);
if (!phydev->drv || !phydev->drv->get_link_stats)
return;
mutex_lock(&phydev->lock);
phydev->drv->get_link_stats(phydev, link_stats);
mutex_unlock(&phydev->lock);
}
/**
* phy_ethtool_get_plca_cfg - Get PLCA RS configuration
* @phydev: the phy_device struct

View File

@ -32,6 +32,7 @@
#include <linux/phy_link_topology.h>
#include <linux/pse-pd/pse.h>
#include <linux/property.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/rtnetlink.h>
#include <linux/sfp.h>
#include <linux/skbuff.h>
@ -1998,6 +1999,15 @@ void phy_detach(struct phy_device *phydev)
phy_suspend(phydev);
if (dev) {
struct hwtstamp_provider *hwprov;
hwprov = rtnl_dereference(dev->hwprov);
/* Disable timestamp if it is the one selected */
if (hwprov && hwprov->phydev == phydev) {
rcu_assign_pointer(dev->hwprov, NULL);
kfree_rcu(hwprov, rcu_head);
}
phydev->attached_dev->phydev = NULL;
phydev->attached_dev = NULL;
phy_link_topo_del_phy(dev, phydev);
@ -3748,6 +3758,8 @@ static const struct ethtool_phy_ops phy_ethtool_phy_ops = {
static const struct phylib_stubs __phylib_stubs = {
.hwtstamp_get = __phy_hwtstamp_get,
.hwtstamp_set = __phy_hwtstamp_set,
.get_phy_stats = __phy_ethtool_get_phy_stats,
.get_link_ext_stats = __phy_ethtool_get_link_ext_stats,
};
static void phylib_register_stubs(void)

View File

@ -80,6 +80,9 @@ enum {
* @cqe_size: Size of TX/RX completion queue event
* @tx_push_buf_len: Size of TX push buffer
* @tx_push_buf_max_len: Maximum allowed size of TX push buffer
* @hds_thresh: Packet size threshold for header data split (HDS)
* @hds_thresh_max: Maximum supported setting for @hds_threshold
*
*/
struct kernel_ethtool_ringparam {
u32 rx_buf_len;
@ -89,6 +92,8 @@ struct kernel_ethtool_ringparam {
u32 cqe_size;
u32 tx_push_buf_len;
u32 tx_push_buf_max_len;
u32 hds_thresh;
u32 hds_thresh_max;
};
/**
@ -99,6 +104,7 @@ struct kernel_ethtool_ringparam {
* @ETHTOOL_RING_USE_RX_PUSH: capture for setting rx_push
* @ETHTOOL_RING_USE_TX_PUSH_BUF_LEN: capture for setting tx_push_buf_len
* @ETHTOOL_RING_USE_TCP_DATA_SPLIT: capture for setting tcp_data_split
* @ETHTOOL_RING_USE_HDS_THRS: capture for setting header-data-split-thresh
*/
enum ethtool_supported_ring_param {
ETHTOOL_RING_USE_RX_BUF_LEN = BIT(0),
@ -107,6 +113,7 @@ enum ethtool_supported_ring_param {
ETHTOOL_RING_USE_RX_PUSH = BIT(3),
ETHTOOL_RING_USE_TX_PUSH_BUF_LEN = BIT(4),
ETHTOOL_RING_USE_TCP_DATA_SPLIT = BIT(5),
ETHTOOL_RING_USE_HDS_THRS = BIT(6),
};
#define __ETH_RSS_HASH_BIT(bit) ((u32)1 << (bit))
@ -205,6 +212,14 @@ static inline u8 *ethtool_rxfh_context_key(struct ethtool_rxfh_context *ctx)
void ethtool_rxfh_context_lost(struct net_device *dev, u32 context_id);
struct link_mode_info {
int speed;
u8 lanes;
u8 duplex;
};
extern const struct link_mode_info link_mode_params[];
/* declare a link mode bitmap */
#define __ETHTOOL_DECLARE_LINK_MODE_MASK(name) \
DECLARE_BITMAP(name, __ETHTOOL_LINK_MODE_MASK_NBITS)
@ -417,6 +432,29 @@ struct ethtool_eth_phy_stats {
);
};
/**
* struct ethtool_phy_stats - PHY-level statistics counters
* @rx_packets: Total successfully received frames
* @rx_bytes: Total successfully received bytes
* @rx_errors: Total received frames with errors (e.g., CRC errors)
* @tx_packets: Total successfully transmitted frames
* @tx_bytes: Total successfully transmitted bytes
* @tx_errors: Total transmitted frames with errors
*
* This structure provides a standardized interface for reporting
* PHY-level statistics counters. It is designed to expose statistics
* commonly provided by PHYs but not explicitly defined in the IEEE
* 802.3 standard.
*/
struct ethtool_phy_stats {
u64 rx_packets;
u64 rx_bytes;
u64 rx_errors;
u64 tx_packets;
u64 tx_bytes;
u64 tx_errors;
};
/* Basic IEEE 802.3 MAC Ctrl statistics (30.3.3.*), not otherwise exposed
* via a more targeted API.
*/
@ -534,6 +572,12 @@ struct ethtool_rmon_stats {
/**
* struct ethtool_ts_stats - HW timestamping statistics
* @pkts: Number of packets successfully timestamped by the hardware.
* @onestep_pkts_unconfirmed: Number of PTP packets with one-step TX
* timestamping that were sent, but for which the
* device offers no confirmation whether they made
* it onto the wire and the timestamp was inserted
* in the originTimestamp or correctionField, or
* not.
* @lost: Number of hardware timestamping requests where the timestamping
* information from the hardware never arrived for submission with
* the skb.
@ -546,6 +590,7 @@ struct ethtool_rmon_stats {
struct ethtool_ts_stats {
struct_group(tx_stats,
u64 pkts;
u64 onestep_pkts_unconfirmed;
u64 lost;
u64 err;
);
@ -716,6 +761,7 @@ struct ethtool_rxfh_param {
* @cmd: command number = %ETHTOOL_GET_TS_INFO
* @so_timestamping: bit mask of the sum of the supported SO_TIMESTAMPING flags
* @phc_index: device index of the associated PHC, or -1 if there is none
* @phc_qualifier: qualifier of the associated PHC
* @tx_types: bit mask of the supported hwtstamp_tx_types enumeration values
* @rx_filters: bit mask of the supported hwtstamp_rx_filters enumeration values
*/
@ -723,22 +769,25 @@ struct kernel_ethtool_ts_info {
u32 cmd;
u32 so_timestamping;
int phc_index;
enum hwtstamp_provider_qualifier phc_qualifier;
enum hwtstamp_tx_types tx_types;
enum hwtstamp_rx_filters rx_filters;
};
/**
* struct ethtool_ops - optional netdev operations
* @supported_input_xfrm: supported types of input xfrm from %RXH_XFRM_*.
* @cap_link_lanes_supported: indicates if the driver supports lanes
* parameter.
* @cap_rss_ctx_supported: indicates if the driver supports RSS
* contexts via legacy API, drivers implementing @create_rxfh_context
* do not have to set this bit.
* @cap_rss_sym_xor_supported: indicates if the driver supports symmetric-xor
* RSS.
* @rxfh_per_ctx_key: device supports setting different RSS key for each
* additional context. Netlink API should report hfunc, key, and input_xfrm
* for every context, not just context 0.
* @cap_rss_rxnfc_adds: device supports nonzero ring_cookie in filters with
* %FLOW_RSS flag; the queue ID from the filter is added to the value from
* the indirection table to determine the delivery queue.
* @rxfh_indir_space: max size of RSS indirection tables, if indirection table
* size as returned by @get_rxfh_indir_size may change during lifetime
* of the device. Leave as 0 if the table size is constant.
@ -751,6 +800,7 @@ struct kernel_ethtool_ts_info {
* @rss_context argument to @create_rxfh_context and friends.
* @supported_coalesce_params: supported types of interrupt coalescing.
* @supported_ring_params: supported ring params.
* @supported_hwtstamp_qualifiers: bitfield of supported hwtstamp qualifier.
* @get_drvinfo: Report driver/device information. Modern drivers no
* longer have to implement this callback. Most fields are
* correctly filled in by the core using system information, or
@ -957,16 +1007,18 @@ struct kernel_ethtool_ts_info {
* of the generic netdev features interface.
*/
struct ethtool_ops {
u32 supported_input_xfrm:8;
u32 cap_link_lanes_supported:1;
u32 cap_rss_ctx_supported:1;
u32 cap_rss_sym_xor_supported:1;
u32 rxfh_per_ctx_key:1;
u32 cap_rss_rxnfc_adds:1;
u32 rxfh_indir_space;
u16 rxfh_key_space;
u16 rxfh_priv_size;
u32 rxfh_max_num_contexts;
u32 supported_coalesce_params;
u32 supported_ring_params;
u32 supported_hwtstamp_qualifiers;
void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
int (*get_regs_len)(struct net_device *);
void (*get_regs)(struct net_device *, struct ethtool_regs *, void *);

View File

@ -12,6 +12,33 @@ enum hwtstamp_source {
HWTSTAMP_SOURCE_PHYLIB,
};
/**
* struct hwtstamp_provider_desc - hwtstamp provider description
*
* @index: index of the hwtstamp provider.
* @qualifier: hwtstamp provider qualifier.
*/
struct hwtstamp_provider_desc {
int index;
enum hwtstamp_provider_qualifier qualifier;
};
/**
* struct hwtstamp_provider - hwtstamp provider object
*
* @rcu_head: RCU callback used to free the struct.
* @source: source of the hwtstamp provider.
* @phydev: pointer of the phydev source in case a PTP coming from phylib
* @desc: hwtstamp provider description.
*/
struct hwtstamp_provider {
struct rcu_head rcu_head;
enum hwtstamp_source source;
struct phy_device *phydev;
struct hwtstamp_provider_desc desc;
};
/**
* struct kernel_hwtstamp_config - Kernel copy of struct hwtstamp_config
*
@ -24,6 +51,7 @@ enum hwtstamp_source {
* copied the ioctl request back to user space
* @source: indication whether timestamps should come from the netdev or from
* an attached phylib PHY
* @qualifier: qualifier of the hwtstamp provider
*
* Prefer using this structure for in-kernel processing of hardware
* timestamping configuration, over the inextensible struct hwtstamp_config
@ -36,6 +64,7 @@ struct kernel_hwtstamp_config {
struct ifreq *ifr;
bool copied_to_user;
enum hwtstamp_source source;
enum hwtstamp_provider_qualifier qualifier;
RH_KABI_RESERVE(1)
RH_KABI_RESERVE(2)

View File

@ -64,6 +64,7 @@ struct dsa_port;
struct ip_tunnel_parm_kern;
struct macsec_context;
struct macsec_ops;
struct netdev_config;
struct netdev_name_node;
struct sd_flow_limit;
struct sfp_bus;
@ -81,6 +82,7 @@ struct xdp_buff;
struct xdp_md;
struct ethtool_netdev_state;
struct phy_link_topology;
struct hwtstamp_provider;
void synchronize_net(void);
void netdev_set_default_ethtool_ops(struct net_device *dev,
@ -2116,6 +2118,7 @@ enum netdev_reg_state {
* @gro_flush_timeout: timeout for GRO layer in NAPI
* @napi_defer_hard_irqs: If not zero, provides a counter that would
* allow to avoid NIC hard IRQ, on busy queues.
* @hwprov: Tracks which PTP performs hardware packet time stamping.
*
* FIXME: cleanup struct net_device such that network protocol info
* moves out.
@ -2487,6 +2490,14 @@ struct net_device {
const struct udp_tunnel_nic_info *udp_tunnel_nic_info;
struct udp_tunnel_nic *udp_tunnel_nic;
/** @cfg: net_device queue-related configuration */
struct netdev_config *cfg;
/**
* @cfg_pending: same as @cfg but when device is being actively
* reconfigured includes any changes to the configuration
* requested by the user, but which may or may not be rejected.
*/
struct netdev_config *cfg_pending;
struct ethtool_netdev_state *ethtool;
/* protected by rtnl_lock */
@ -2528,6 +2539,8 @@ struct net_device {
struct net_shaper_hierarchy *net_shaper_hierarchy;
#endif
struct hwtstamp_provider __rcu *hwprov;
RH_KABI_RESERVE(1)
RH_KABI_RESERVE(2)
RH_KABI_RESERVE(3)
@ -4127,9 +4140,6 @@ int generic_hwtstamp_get_lower(struct net_device *dev,
int generic_hwtstamp_set_lower(struct net_device *dev,
struct kernel_hwtstamp_config *kernel_cfg,
struct netlink_ext_ack *extack);
int dev_set_hwtstamp_phylib(struct net_device *dev,
struct kernel_hwtstamp_config *cfg,
struct netlink_ext_ack *extack);
int dev_ethtool(struct net *net, struct ifreq *ifr, void __user *userdata);
unsigned int dev_get_flags(const struct net_device *);
int __dev_change_flags(struct net_device *dev, unsigned int flags,
@ -4165,6 +4175,7 @@ struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
u8 dev_xdp_prog_count(struct net_device *dev);
u8 dev_xdp_sb_prog_count(struct net_device *dev);
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode);
int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb);

View File

@ -1093,6 +1093,35 @@ struct phy_driver {
int (*cable_test_get_status)(struct phy_device *dev, bool *finished);
/* Get statistics from the PHY using ethtool */
/**
* @get_phy_stats: Retrieve PHY statistics.
* @dev: The PHY device for which the statistics are retrieved.
* @eth_stats: structure where Ethernet PHY stats will be stored.
* @stats: structure where additional PHY-specific stats will be stored.
*
* Retrieves the supported PHY statistics and populates the provided
* structures. The input structures are pre-initialized with
* `ETHTOOL_STAT_NOT_SET`, and the driver must only modify members
* corresponding to supported statistics. Unmodified members will remain
* set to `ETHTOOL_STAT_NOT_SET` and will not be returned to userspace.
*/
void (*get_phy_stats)(struct phy_device *dev,
struct ethtool_eth_phy_stats *eth_stats,
struct ethtool_phy_stats *stats);
/**
* @get_link_stats: Retrieve link statistics.
* @dev: The PHY device for which the statistics are retrieved.
* @link_stats: structure where link-specific stats will be stored.
*
* Retrieves link-related statistics for the given PHY device. The input
* structure is pre-initialized with `ETHTOOL_STAT_NOT_SET`, and the
* driver must only modify members corresponding to supported
* statistics. Unmodified members will remain set to
* `ETHTOOL_STAT_NOT_SET` and will not be returned to userspace.
*/
void (*get_link_stats)(struct phy_device *dev,
struct ethtool_link_ext_stats *link_stats);
/** @get_sset_count: Number of statistic counters */
int (*get_sset_count)(struct phy_device *dev);
/** @get_strings: Names of the statistic counters */
@ -2057,6 +2086,13 @@ int phy_ethtool_get_strings(struct phy_device *phydev, u8 *data);
int phy_ethtool_get_sset_count(struct phy_device *phydev);
int phy_ethtool_get_stats(struct phy_device *phydev,
struct ethtool_stats *stats, u64 *data);
void __phy_ethtool_get_phy_stats(struct phy_device *phydev,
struct ethtool_eth_phy_stats *phy_stats,
struct ethtool_phy_stats *phydev_stats);
void __phy_ethtool_get_link_ext_stats(struct phy_device *phydev,
struct ethtool_link_ext_stats *link_stats);
int phy_ethtool_get_plca_cfg(struct phy_device *phydev,
struct phy_plca_cfg *plca_cfg);
int phy_ethtool_set_plca_cfg(struct phy_device *phydev,

View File

@ -5,6 +5,9 @@
#include <linux/rtnetlink.h>
struct ethtool_eth_phy_stats;
struct ethtool_link_ext_stats;
struct ethtool_phy_stats;
struct kernel_hwtstamp_config;
struct netlink_ext_ack;
struct phy_device;
@ -19,6 +22,11 @@ struct phylib_stubs {
int (*hwtstamp_set)(struct phy_device *phydev,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack);
void (*get_phy_stats)(struct phy_device *phydev,
struct ethtool_eth_phy_stats *phy_stats,
struct ethtool_phy_stats *phydev_stats);
void (*get_link_ext_stats)(struct phy_device *phydev,
struct ethtool_link_ext_stats *link_stats);
};
static inline int phy_hwtstamp_get(struct phy_device *phydev,
@ -50,6 +58,29 @@ static inline int phy_hwtstamp_set(struct phy_device *phydev,
return phylib_stubs->hwtstamp_set(phydev, config, extack);
}
static inline void phy_ethtool_get_phy_stats(struct phy_device *phydev,
struct ethtool_eth_phy_stats *phy_stats,
struct ethtool_phy_stats *phydev_stats)
{
ASSERT_RTNL();
if (!phylib_stubs)
return;
phylib_stubs->get_phy_stats(phydev, phy_stats, phydev_stats);
}
static inline void phy_ethtool_get_link_ext_stats(struct phy_device *phydev,
struct ethtool_link_ext_stats *link_stats)
{
ASSERT_RTNL();
if (!phylib_stubs)
return;
phylib_stubs->get_link_ext_stats(phydev, link_stats);
}
#else
static inline int phy_hwtstamp_get(struct phy_device *phydev,
@ -65,4 +96,15 @@ static inline int phy_hwtstamp_set(struct phy_device *phydev,
return -EOPNOTSUPP;
}
static inline void phy_ethtool_get_phy_stats(struct phy_device *phydev,
struct ethtool_eth_phy_stats *phy_stats,
struct ethtool_phy_stats *phydev_stats)
{
}
static inline void phy_ethtool_get_link_ext_stats(struct phy_device *phydev,
struct ethtool_link_ext_stats *link_stats)
{
}
#endif

View File

@ -6,6 +6,16 @@
#include <linux/rh_kabi.h>
/**
* struct netdev_config - queue-related configuration for a netdev
* @hds_thresh: HDS Threshold value.
* @hds_config: HDS value from userspace.
*/
struct netdev_config {
u32 hds_thresh;
u8 hds_config;
};
/* See the netdev.yaml spec for definition of each statistic */
struct netdev_queue_stats_rx {
u64 bytes;

View File

@ -681,6 +681,8 @@ enum ethtool_link_ext_substate_module {
* @ETH_SS_STATS_ETH_MAC: names of IEEE 802.3 MAC statistics
* @ETH_SS_STATS_ETH_CTRL: names of IEEE 802.3 MAC Control statistics
* @ETH_SS_STATS_RMON: names of RMON statistics
* @ETH_SS_STATS_PHY: names of PHY(dev) statistics
* @ETH_SS_TS_FLAGS: hardware timestamping flags
*
* @ETH_SS_COUNT: number of defined string sets
*/
@ -706,6 +708,8 @@ enum ethtool_stringset {
ETH_SS_STATS_ETH_MAC,
ETH_SS_STATS_ETH_CTRL,
ETH_SS_STATS_RMON,
ETH_SS_STATS_PHY,
ETH_SS_TS_FLAGS,
/* add new constants above here */
ETH_SS_COUNT
@ -2055,6 +2059,24 @@ enum ethtool_link_mode_bit_indices {
ETHTOOL_LINK_MODE_10baseT1S_Half_BIT = 100,
ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT = 101,
ETHTOOL_LINK_MODE_10baseT1BRR_Full_BIT = 102,
ETHTOOL_LINK_MODE_200000baseCR_Full_BIT = 103,
ETHTOOL_LINK_MODE_200000baseKR_Full_BIT = 104,
ETHTOOL_LINK_MODE_200000baseDR_Full_BIT = 105,
ETHTOOL_LINK_MODE_200000baseDR_2_Full_BIT = 106,
ETHTOOL_LINK_MODE_200000baseSR_Full_BIT = 107,
ETHTOOL_LINK_MODE_200000baseVR_Full_BIT = 108,
ETHTOOL_LINK_MODE_400000baseCR2_Full_BIT = 109,
ETHTOOL_LINK_MODE_400000baseKR2_Full_BIT = 110,
ETHTOOL_LINK_MODE_400000baseDR2_Full_BIT = 111,
ETHTOOL_LINK_MODE_400000baseDR2_2_Full_BIT = 112,
ETHTOOL_LINK_MODE_400000baseSR2_Full_BIT = 113,
ETHTOOL_LINK_MODE_400000baseVR2_Full_BIT = 114,
ETHTOOL_LINK_MODE_800000baseCR4_Full_BIT = 115,
ETHTOOL_LINK_MODE_800000baseKR4_Full_BIT = 116,
ETHTOOL_LINK_MODE_800000baseDR4_Full_BIT = 117,
ETHTOOL_LINK_MODE_800000baseDR4_2_Full_BIT = 118,
ETHTOOL_LINK_MODE_800000baseSR4_Full_BIT = 119,
ETHTOOL_LINK_MODE_800000baseVR4_Full_BIT = 120,
/* must be last entry */
__ETHTOOL_LINK_MODE_MASK_NBITS
@ -2267,6 +2289,10 @@ static inline int ethtool_validate_duplex(__u8 duplex)
* be exploited to reduce the RSS queue spread.
*/
#define RXH_XFRM_SYM_XOR (1 << 0)
/* Similar to SYM_XOR, except that one copy of the XOR'ed fields is replaced by
* an OR of the same fields
*/
#define RXH_XFRM_SYM_OR_XOR (1 << 1)
#define RXH_XFRM_NO_CHANGE 0xff
/* L2-L4 network traffic flow types */
@ -2526,12 +2552,19 @@ struct ethtool_link_settings {
__u8 master_slave_state;
__u8 rate_matching;
__u32 reserved[7];
#ifndef __KERNEL__
/* Linux builds with -Wflex-array-member-not-at-end but does
* not use the "link_mode_masks" member. Leave it defined for
* userspace for now, and when userspace wants to start using
* -Wfamnae, we'll need a new solution.
*/
__u32 link_mode_masks[];
/* layout of link_mode_masks fields:
* __u32 map_supported[link_mode_masks_nwords];
* __u32 map_advertising[link_mode_masks_nwords];
* __u32 map_lp_advertising[link_mode_masks_nwords];
*/
#endif
};
/**

View File

@ -10,545 +10,12 @@
#define _UAPI_LINUX_ETHTOOL_NETLINK_H_
#include <linux/ethtool.h>
/* message types - userspace to kernel */
enum {
ETHTOOL_MSG_USER_NONE,
ETHTOOL_MSG_STRSET_GET,
ETHTOOL_MSG_LINKINFO_GET,
ETHTOOL_MSG_LINKINFO_SET,
ETHTOOL_MSG_LINKMODES_GET,
ETHTOOL_MSG_LINKMODES_SET,
ETHTOOL_MSG_LINKSTATE_GET,
ETHTOOL_MSG_DEBUG_GET,
ETHTOOL_MSG_DEBUG_SET,
ETHTOOL_MSG_WOL_GET,
ETHTOOL_MSG_WOL_SET,
ETHTOOL_MSG_FEATURES_GET,
ETHTOOL_MSG_FEATURES_SET,
ETHTOOL_MSG_PRIVFLAGS_GET,
ETHTOOL_MSG_PRIVFLAGS_SET,
ETHTOOL_MSG_RINGS_GET,
ETHTOOL_MSG_RINGS_SET,
ETHTOOL_MSG_CHANNELS_GET,
ETHTOOL_MSG_CHANNELS_SET,
ETHTOOL_MSG_COALESCE_GET,
ETHTOOL_MSG_COALESCE_SET,
ETHTOOL_MSG_PAUSE_GET,
ETHTOOL_MSG_PAUSE_SET,
ETHTOOL_MSG_EEE_GET,
ETHTOOL_MSG_EEE_SET,
ETHTOOL_MSG_TSINFO_GET,
ETHTOOL_MSG_CABLE_TEST_ACT,
ETHTOOL_MSG_CABLE_TEST_TDR_ACT,
ETHTOOL_MSG_TUNNEL_INFO_GET,
ETHTOOL_MSG_FEC_GET,
ETHTOOL_MSG_FEC_SET,
ETHTOOL_MSG_MODULE_EEPROM_GET,
ETHTOOL_MSG_STATS_GET,
ETHTOOL_MSG_PHC_VCLOCKS_GET,
ETHTOOL_MSG_MODULE_GET,
ETHTOOL_MSG_MODULE_SET,
ETHTOOL_MSG_PSE_GET,
ETHTOOL_MSG_PSE_SET,
ETHTOOL_MSG_RSS_GET,
ETHTOOL_MSG_PLCA_GET_CFG,
ETHTOOL_MSG_PLCA_SET_CFG,
ETHTOOL_MSG_PLCA_GET_STATUS,
ETHTOOL_MSG_MM_GET,
ETHTOOL_MSG_MM_SET,
ETHTOOL_MSG_MODULE_FW_FLASH_ACT,
ETHTOOL_MSG_PHY_GET,
/* add new constants above here */
__ETHTOOL_MSG_USER_CNT,
ETHTOOL_MSG_USER_MAX = __ETHTOOL_MSG_USER_CNT - 1
};
/* message types - kernel to userspace */
enum {
ETHTOOL_MSG_KERNEL_NONE,
ETHTOOL_MSG_STRSET_GET_REPLY,
ETHTOOL_MSG_LINKINFO_GET_REPLY,
ETHTOOL_MSG_LINKINFO_NTF,
ETHTOOL_MSG_LINKMODES_GET_REPLY,
ETHTOOL_MSG_LINKMODES_NTF,
ETHTOOL_MSG_LINKSTATE_GET_REPLY,
ETHTOOL_MSG_DEBUG_GET_REPLY,
ETHTOOL_MSG_DEBUG_NTF,
ETHTOOL_MSG_WOL_GET_REPLY,
ETHTOOL_MSG_WOL_NTF,
ETHTOOL_MSG_FEATURES_GET_REPLY,
ETHTOOL_MSG_FEATURES_SET_REPLY,
ETHTOOL_MSG_FEATURES_NTF,
ETHTOOL_MSG_PRIVFLAGS_GET_REPLY,
ETHTOOL_MSG_PRIVFLAGS_NTF,
ETHTOOL_MSG_RINGS_GET_REPLY,
ETHTOOL_MSG_RINGS_NTF,
ETHTOOL_MSG_CHANNELS_GET_REPLY,
ETHTOOL_MSG_CHANNELS_NTF,
ETHTOOL_MSG_COALESCE_GET_REPLY,
ETHTOOL_MSG_COALESCE_NTF,
ETHTOOL_MSG_PAUSE_GET_REPLY,
ETHTOOL_MSG_PAUSE_NTF,
ETHTOOL_MSG_EEE_GET_REPLY,
ETHTOOL_MSG_EEE_NTF,
ETHTOOL_MSG_TSINFO_GET_REPLY,
ETHTOOL_MSG_CABLE_TEST_NTF,
ETHTOOL_MSG_CABLE_TEST_TDR_NTF,
ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY,
ETHTOOL_MSG_FEC_GET_REPLY,
ETHTOOL_MSG_FEC_NTF,
ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY,
ETHTOOL_MSG_STATS_GET_REPLY,
ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY,
ETHTOOL_MSG_MODULE_GET_REPLY,
ETHTOOL_MSG_MODULE_NTF,
ETHTOOL_MSG_PSE_GET_REPLY,
ETHTOOL_MSG_RSS_GET_REPLY,
ETHTOOL_MSG_PLCA_GET_CFG_REPLY,
ETHTOOL_MSG_PLCA_GET_STATUS_REPLY,
ETHTOOL_MSG_PLCA_NTF,
ETHTOOL_MSG_MM_GET_REPLY,
ETHTOOL_MSG_MM_NTF,
ETHTOOL_MSG_MODULE_FW_FLASH_NTF,
ETHTOOL_MSG_PHY_GET_REPLY,
ETHTOOL_MSG_PHY_NTF,
/* add new constants above here */
__ETHTOOL_MSG_KERNEL_CNT,
ETHTOOL_MSG_KERNEL_MAX = __ETHTOOL_MSG_KERNEL_CNT - 1
};
/* request header */
enum ethtool_header_flags {
ETHTOOL_FLAG_COMPACT_BITSETS = 1 << 0, /* use compact bitsets in reply */
ETHTOOL_FLAG_OMIT_REPLY = 1 << 1, /* provide optional reply for SET or ACT requests */
ETHTOOL_FLAG_STATS = 1 << 2, /* request statistics, if supported by the driver */
};
#include <linux/ethtool_netlink_generated.h>
#define ETHTOOL_FLAG_ALL (ETHTOOL_FLAG_COMPACT_BITSETS | \
ETHTOOL_FLAG_OMIT_REPLY | \
ETHTOOL_FLAG_STATS)
enum {
ETHTOOL_A_HEADER_UNSPEC,
ETHTOOL_A_HEADER_DEV_INDEX, /* u32 */
ETHTOOL_A_HEADER_DEV_NAME, /* string */
ETHTOOL_A_HEADER_FLAGS, /* u32 - ETHTOOL_FLAG_* */
ETHTOOL_A_HEADER_PHY_INDEX, /* u32 */
/* add new constants above here */
__ETHTOOL_A_HEADER_CNT,
ETHTOOL_A_HEADER_MAX = __ETHTOOL_A_HEADER_CNT - 1
};
/* bit sets */
enum {
ETHTOOL_A_BITSET_BIT_UNSPEC,
ETHTOOL_A_BITSET_BIT_INDEX, /* u32 */
ETHTOOL_A_BITSET_BIT_NAME, /* string */
ETHTOOL_A_BITSET_BIT_VALUE, /* flag */
/* add new constants above here */
__ETHTOOL_A_BITSET_BIT_CNT,
ETHTOOL_A_BITSET_BIT_MAX = __ETHTOOL_A_BITSET_BIT_CNT - 1
};
enum {
ETHTOOL_A_BITSET_BITS_UNSPEC,
ETHTOOL_A_BITSET_BITS_BIT, /* nest - _A_BITSET_BIT_* */
/* add new constants above here */
__ETHTOOL_A_BITSET_BITS_CNT,
ETHTOOL_A_BITSET_BITS_MAX = __ETHTOOL_A_BITSET_BITS_CNT - 1
};
enum {
ETHTOOL_A_BITSET_UNSPEC,
ETHTOOL_A_BITSET_NOMASK, /* flag */
ETHTOOL_A_BITSET_SIZE, /* u32 */
ETHTOOL_A_BITSET_BITS, /* nest - _A_BITSET_BITS_* */
ETHTOOL_A_BITSET_VALUE, /* binary */
ETHTOOL_A_BITSET_MASK, /* binary */
/* add new constants above here */
__ETHTOOL_A_BITSET_CNT,
ETHTOOL_A_BITSET_MAX = __ETHTOOL_A_BITSET_CNT - 1
};
/* string sets */
enum {
ETHTOOL_A_STRING_UNSPEC,
ETHTOOL_A_STRING_INDEX, /* u32 */
ETHTOOL_A_STRING_VALUE, /* string */
/* add new constants above here */
__ETHTOOL_A_STRING_CNT,
ETHTOOL_A_STRING_MAX = __ETHTOOL_A_STRING_CNT - 1
};
enum {
ETHTOOL_A_STRINGS_UNSPEC,
ETHTOOL_A_STRINGS_STRING, /* nest - _A_STRINGS_* */
/* add new constants above here */
__ETHTOOL_A_STRINGS_CNT,
ETHTOOL_A_STRINGS_MAX = __ETHTOOL_A_STRINGS_CNT - 1
};
enum {
ETHTOOL_A_STRINGSET_UNSPEC,
ETHTOOL_A_STRINGSET_ID, /* u32 */
ETHTOOL_A_STRINGSET_COUNT, /* u32 */
ETHTOOL_A_STRINGSET_STRINGS, /* nest - _A_STRINGS_* */
/* add new constants above here */
__ETHTOOL_A_STRINGSET_CNT,
ETHTOOL_A_STRINGSET_MAX = __ETHTOOL_A_STRINGSET_CNT - 1
};
enum {
ETHTOOL_A_STRINGSETS_UNSPEC,
ETHTOOL_A_STRINGSETS_STRINGSET, /* nest - _A_STRINGSET_* */
/* add new constants above here */
__ETHTOOL_A_STRINGSETS_CNT,
ETHTOOL_A_STRINGSETS_MAX = __ETHTOOL_A_STRINGSETS_CNT - 1
};
/* STRSET */
enum {
ETHTOOL_A_STRSET_UNSPEC,
ETHTOOL_A_STRSET_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_STRSET_STRINGSETS, /* nest - _A_STRINGSETS_* */
ETHTOOL_A_STRSET_COUNTS_ONLY, /* flag */
/* add new constants above here */
__ETHTOOL_A_STRSET_CNT,
ETHTOOL_A_STRSET_MAX = __ETHTOOL_A_STRSET_CNT - 1
};
/* LINKINFO */
enum {
ETHTOOL_A_LINKINFO_UNSPEC,
ETHTOOL_A_LINKINFO_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_LINKINFO_PORT, /* u8 */
ETHTOOL_A_LINKINFO_PHYADDR, /* u8 */
ETHTOOL_A_LINKINFO_TP_MDIX, /* u8 */
ETHTOOL_A_LINKINFO_TP_MDIX_CTRL, /* u8 */
ETHTOOL_A_LINKINFO_TRANSCEIVER, /* u8 */
/* add new constants above here */
__ETHTOOL_A_LINKINFO_CNT,
ETHTOOL_A_LINKINFO_MAX = __ETHTOOL_A_LINKINFO_CNT - 1
};
/* LINKMODES */
enum {
ETHTOOL_A_LINKMODES_UNSPEC,
ETHTOOL_A_LINKMODES_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_LINKMODES_AUTONEG, /* u8 */
ETHTOOL_A_LINKMODES_OURS, /* bitset */
ETHTOOL_A_LINKMODES_PEER, /* bitset */
ETHTOOL_A_LINKMODES_SPEED, /* u32 */
ETHTOOL_A_LINKMODES_DUPLEX, /* u8 */
ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG, /* u8 */
ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE, /* u8 */
ETHTOOL_A_LINKMODES_LANES, /* u32 */
ETHTOOL_A_LINKMODES_RATE_MATCHING, /* u8 */
/* add new constants above here */
__ETHTOOL_A_LINKMODES_CNT,
ETHTOOL_A_LINKMODES_MAX = __ETHTOOL_A_LINKMODES_CNT - 1
};
/* LINKSTATE */
enum {
ETHTOOL_A_LINKSTATE_UNSPEC,
ETHTOOL_A_LINKSTATE_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_LINKSTATE_LINK, /* u8 */
ETHTOOL_A_LINKSTATE_SQI, /* u32 */
ETHTOOL_A_LINKSTATE_SQI_MAX, /* u32 */
ETHTOOL_A_LINKSTATE_EXT_STATE, /* u8 */
ETHTOOL_A_LINKSTATE_EXT_SUBSTATE, /* u8 */
ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT, /* u32 */
/* add new constants above here */
__ETHTOOL_A_LINKSTATE_CNT,
ETHTOOL_A_LINKSTATE_MAX = __ETHTOOL_A_LINKSTATE_CNT - 1
};
/* DEBUG */
enum {
ETHTOOL_A_DEBUG_UNSPEC,
ETHTOOL_A_DEBUG_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_DEBUG_MSGMASK, /* bitset */
/* add new constants above here */
__ETHTOOL_A_DEBUG_CNT,
ETHTOOL_A_DEBUG_MAX = __ETHTOOL_A_DEBUG_CNT - 1
};
/* WOL */
enum {
ETHTOOL_A_WOL_UNSPEC,
ETHTOOL_A_WOL_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_WOL_MODES, /* bitset */
ETHTOOL_A_WOL_SOPASS, /* binary */
/* add new constants above here */
__ETHTOOL_A_WOL_CNT,
ETHTOOL_A_WOL_MAX = __ETHTOOL_A_WOL_CNT - 1
};
/* FEATURES */
enum {
ETHTOOL_A_FEATURES_UNSPEC,
ETHTOOL_A_FEATURES_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_FEATURES_HW, /* bitset */
ETHTOOL_A_FEATURES_WANTED, /* bitset */
ETHTOOL_A_FEATURES_ACTIVE, /* bitset */
ETHTOOL_A_FEATURES_NOCHANGE, /* bitset */
/* add new constants above here */
__ETHTOOL_A_FEATURES_CNT,
ETHTOOL_A_FEATURES_MAX = __ETHTOOL_A_FEATURES_CNT - 1
};
/* PRIVFLAGS */
enum {
ETHTOOL_A_PRIVFLAGS_UNSPEC,
ETHTOOL_A_PRIVFLAGS_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_PRIVFLAGS_FLAGS, /* bitset */
/* add new constants above here */
__ETHTOOL_A_PRIVFLAGS_CNT,
ETHTOOL_A_PRIVFLAGS_MAX = __ETHTOOL_A_PRIVFLAGS_CNT - 1
};
/* RINGS */
enum {
ETHTOOL_TCP_DATA_SPLIT_UNKNOWN = 0,
ETHTOOL_TCP_DATA_SPLIT_DISABLED,
ETHTOOL_TCP_DATA_SPLIT_ENABLED,
};
enum {
ETHTOOL_A_RINGS_UNSPEC,
ETHTOOL_A_RINGS_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_RINGS_RX_MAX, /* u32 */
ETHTOOL_A_RINGS_RX_MINI_MAX, /* u32 */
ETHTOOL_A_RINGS_RX_JUMBO_MAX, /* u32 */
ETHTOOL_A_RINGS_TX_MAX, /* u32 */
ETHTOOL_A_RINGS_RX, /* u32 */
ETHTOOL_A_RINGS_RX_MINI, /* u32 */
ETHTOOL_A_RINGS_RX_JUMBO, /* u32 */
ETHTOOL_A_RINGS_TX, /* u32 */
ETHTOOL_A_RINGS_RX_BUF_LEN, /* u32 */
ETHTOOL_A_RINGS_TCP_DATA_SPLIT, /* u8 */
ETHTOOL_A_RINGS_CQE_SIZE, /* u32 */
ETHTOOL_A_RINGS_TX_PUSH, /* u8 */
ETHTOOL_A_RINGS_RX_PUSH, /* u8 */
ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN, /* u32 */
ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX, /* u32 */
/* add new constants above here */
__ETHTOOL_A_RINGS_CNT,
ETHTOOL_A_RINGS_MAX = (__ETHTOOL_A_RINGS_CNT - 1)
};
/* CHANNELS */
enum {
ETHTOOL_A_CHANNELS_UNSPEC,
ETHTOOL_A_CHANNELS_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_CHANNELS_RX_MAX, /* u32 */
ETHTOOL_A_CHANNELS_TX_MAX, /* u32 */
ETHTOOL_A_CHANNELS_OTHER_MAX, /* u32 */
ETHTOOL_A_CHANNELS_COMBINED_MAX, /* u32 */
ETHTOOL_A_CHANNELS_RX_COUNT, /* u32 */
ETHTOOL_A_CHANNELS_TX_COUNT, /* u32 */
ETHTOOL_A_CHANNELS_OTHER_COUNT, /* u32 */
ETHTOOL_A_CHANNELS_COMBINED_COUNT, /* u32 */
/* add new constants above here */
__ETHTOOL_A_CHANNELS_CNT,
ETHTOOL_A_CHANNELS_MAX = (__ETHTOOL_A_CHANNELS_CNT - 1)
};
/* COALESCE */
enum {
ETHTOOL_A_COALESCE_UNSPEC,
ETHTOOL_A_COALESCE_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_COALESCE_RX_USECS, /* u32 */
ETHTOOL_A_COALESCE_RX_MAX_FRAMES, /* u32 */
ETHTOOL_A_COALESCE_RX_USECS_IRQ, /* u32 */
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ, /* u32 */
ETHTOOL_A_COALESCE_TX_USECS, /* u32 */
ETHTOOL_A_COALESCE_TX_MAX_FRAMES, /* u32 */
ETHTOOL_A_COALESCE_TX_USECS_IRQ, /* u32 */
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ, /* u32 */
ETHTOOL_A_COALESCE_STATS_BLOCK_USECS, /* u32 */
ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX, /* u8 */
ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX, /* u8 */
ETHTOOL_A_COALESCE_PKT_RATE_LOW, /* u32 */
ETHTOOL_A_COALESCE_RX_USECS_LOW, /* u32 */
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW, /* u32 */
ETHTOOL_A_COALESCE_TX_USECS_LOW, /* u32 */
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW, /* u32 */
ETHTOOL_A_COALESCE_PKT_RATE_HIGH, /* u32 */
ETHTOOL_A_COALESCE_RX_USECS_HIGH, /* u32 */
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH, /* u32 */
ETHTOOL_A_COALESCE_TX_USECS_HIGH, /* u32 */
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH, /* u32 */
ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL, /* u32 */
ETHTOOL_A_COALESCE_USE_CQE_MODE_TX, /* u8 */
ETHTOOL_A_COALESCE_USE_CQE_MODE_RX, /* u8 */
ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES, /* u32 */
ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES, /* u32 */
ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS, /* u32 */
/* nest - _A_PROFILE_IRQ_MODERATION */
ETHTOOL_A_COALESCE_RX_PROFILE,
/* nest - _A_PROFILE_IRQ_MODERATION */
ETHTOOL_A_COALESCE_TX_PROFILE,
/* add new constants above here */
__ETHTOOL_A_COALESCE_CNT,
ETHTOOL_A_COALESCE_MAX = (__ETHTOOL_A_COALESCE_CNT - 1)
};
enum {
ETHTOOL_A_PROFILE_UNSPEC,
/* nest, _A_IRQ_MODERATION_* */
ETHTOOL_A_PROFILE_IRQ_MODERATION,
__ETHTOOL_A_PROFILE_CNT,
ETHTOOL_A_PROFILE_MAX = (__ETHTOOL_A_PROFILE_CNT - 1)
};
enum {
ETHTOOL_A_IRQ_MODERATION_UNSPEC,
ETHTOOL_A_IRQ_MODERATION_USEC, /* u32 */
ETHTOOL_A_IRQ_MODERATION_PKTS, /* u32 */
ETHTOOL_A_IRQ_MODERATION_COMPS, /* u32 */
__ETHTOOL_A_IRQ_MODERATION_CNT,
ETHTOOL_A_IRQ_MODERATION_MAX = (__ETHTOOL_A_IRQ_MODERATION_CNT - 1)
};
/* PAUSE */
enum {
ETHTOOL_A_PAUSE_UNSPEC,
ETHTOOL_A_PAUSE_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_PAUSE_AUTONEG, /* u8 */
ETHTOOL_A_PAUSE_RX, /* u8 */
ETHTOOL_A_PAUSE_TX, /* u8 */
ETHTOOL_A_PAUSE_STATS, /* nest - _PAUSE_STAT_* */
ETHTOOL_A_PAUSE_STATS_SRC, /* u32 */
/* add new constants above here */
__ETHTOOL_A_PAUSE_CNT,
ETHTOOL_A_PAUSE_MAX = (__ETHTOOL_A_PAUSE_CNT - 1)
};
enum {
ETHTOOL_A_PAUSE_STAT_UNSPEC,
ETHTOOL_A_PAUSE_STAT_PAD,
ETHTOOL_A_PAUSE_STAT_TX_FRAMES,
ETHTOOL_A_PAUSE_STAT_RX_FRAMES,
/* add new constants above here
* adjust ETHTOOL_PAUSE_STAT_CNT if adding non-stats!
*/
__ETHTOOL_A_PAUSE_STAT_CNT,
ETHTOOL_A_PAUSE_STAT_MAX = (__ETHTOOL_A_PAUSE_STAT_CNT - 1)
};
/* EEE */
enum {
ETHTOOL_A_EEE_UNSPEC,
ETHTOOL_A_EEE_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_EEE_MODES_OURS, /* bitset */
ETHTOOL_A_EEE_MODES_PEER, /* bitset */
ETHTOOL_A_EEE_ACTIVE, /* u8 */
ETHTOOL_A_EEE_ENABLED, /* u8 */
ETHTOOL_A_EEE_TX_LPI_ENABLED, /* u8 */
ETHTOOL_A_EEE_TX_LPI_TIMER, /* u32 */
/* add new constants above here */
__ETHTOOL_A_EEE_CNT,
ETHTOOL_A_EEE_MAX = (__ETHTOOL_A_EEE_CNT - 1)
};
/* TSINFO */
enum {
ETHTOOL_A_TSINFO_UNSPEC,
ETHTOOL_A_TSINFO_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_TSINFO_TIMESTAMPING, /* bitset */
ETHTOOL_A_TSINFO_TX_TYPES, /* bitset */
ETHTOOL_A_TSINFO_RX_FILTERS, /* bitset */
ETHTOOL_A_TSINFO_PHC_INDEX, /* u32 */
ETHTOOL_A_TSINFO_STATS, /* nest - _A_TSINFO_STAT */
/* add new constants above here */
__ETHTOOL_A_TSINFO_CNT,
ETHTOOL_A_TSINFO_MAX = (__ETHTOOL_A_TSINFO_CNT - 1)
};
enum {
ETHTOOL_A_TS_STAT_UNSPEC,
ETHTOOL_A_TS_STAT_TX_PKTS, /* uint */
ETHTOOL_A_TS_STAT_TX_LOST, /* uint */
ETHTOOL_A_TS_STAT_TX_ERR, /* uint */
/* add new constants above here */
__ETHTOOL_A_TS_STAT_CNT,
ETHTOOL_A_TS_STAT_MAX = (__ETHTOOL_A_TS_STAT_CNT - 1)
};
/* PHC VCLOCKS */
enum {
ETHTOOL_A_PHC_VCLOCKS_UNSPEC,
ETHTOOL_A_PHC_VCLOCKS_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_PHC_VCLOCKS_NUM, /* u32 */
ETHTOOL_A_PHC_VCLOCKS_INDEX, /* array, s32 */
/* add new constants above here */
__ETHTOOL_A_PHC_VCLOCKS_CNT,
ETHTOOL_A_PHC_VCLOCKS_MAX = (__ETHTOOL_A_PHC_VCLOCKS_CNT - 1)
};
/* CABLE TEST */
enum {
ETHTOOL_A_CABLE_TEST_UNSPEC,
ETHTOOL_A_CABLE_TEST_HEADER, /* nest - _A_HEADER_* */
/* add new constants above here */
__ETHTOOL_A_CABLE_TEST_CNT,
ETHTOOL_A_CABLE_TEST_MAX = __ETHTOOL_A_CABLE_TEST_CNT - 1
};
/* CABLE TEST NOTIFY */
enum {
ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC,
@ -582,74 +49,12 @@ enum {
ETHTOOL_A_CABLE_INF_SRC_ALCD,
};
enum {
ETHTOOL_A_CABLE_RESULT_UNSPEC,
ETHTOOL_A_CABLE_RESULT_PAIR, /* u8 ETHTOOL_A_CABLE_PAIR_ */
ETHTOOL_A_CABLE_RESULT_CODE, /* u8 ETHTOOL_A_CABLE_RESULT_CODE_ */
ETHTOOL_A_CABLE_RESULT_SRC, /* u32 ETHTOOL_A_CABLE_INF_SRC_ */
__ETHTOOL_A_CABLE_RESULT_CNT,
ETHTOOL_A_CABLE_RESULT_MAX = (__ETHTOOL_A_CABLE_RESULT_CNT - 1)
};
enum {
ETHTOOL_A_CABLE_FAULT_LENGTH_UNSPEC,
ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR, /* u8 ETHTOOL_A_CABLE_PAIR_ */
ETHTOOL_A_CABLE_FAULT_LENGTH_CM, /* u32 */
ETHTOOL_A_CABLE_FAULT_LENGTH_SRC, /* u32 ETHTOOL_A_CABLE_INF_SRC_ */
__ETHTOOL_A_CABLE_FAULT_LENGTH_CNT,
ETHTOOL_A_CABLE_FAULT_LENGTH_MAX = (__ETHTOOL_A_CABLE_FAULT_LENGTH_CNT - 1)
};
enum {
ETHTOOL_A_CABLE_TEST_NTF_STATUS_UNSPEC,
ETHTOOL_A_CABLE_TEST_NTF_STATUS_STARTED,
ETHTOOL_A_CABLE_TEST_NTF_STATUS_COMPLETED
};
enum {
ETHTOOL_A_CABLE_NEST_UNSPEC,
ETHTOOL_A_CABLE_NEST_RESULT, /* nest - ETHTOOL_A_CABLE_RESULT_ */
ETHTOOL_A_CABLE_NEST_FAULT_LENGTH, /* nest - ETHTOOL_A_CABLE_FAULT_LENGTH_ */
__ETHTOOL_A_CABLE_NEST_CNT,
ETHTOOL_A_CABLE_NEST_MAX = (__ETHTOOL_A_CABLE_NEST_CNT - 1)
};
enum {
ETHTOOL_A_CABLE_TEST_NTF_UNSPEC,
ETHTOOL_A_CABLE_TEST_NTF_HEADER, /* nest - ETHTOOL_A_HEADER_* */
ETHTOOL_A_CABLE_TEST_NTF_STATUS, /* u8 - _STARTED/_COMPLETE */
ETHTOOL_A_CABLE_TEST_NTF_NEST, /* nest - of results: */
__ETHTOOL_A_CABLE_TEST_NTF_CNT,
ETHTOOL_A_CABLE_TEST_NTF_MAX = (__ETHTOOL_A_CABLE_TEST_NTF_CNT - 1)
};
/* CABLE TEST TDR */
enum {
ETHTOOL_A_CABLE_TEST_TDR_CFG_UNSPEC,
ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST, /* u32 */
ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST, /* u32 */
ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP, /* u32 */
ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR, /* u8 */
/* add new constants above here */
__ETHTOOL_A_CABLE_TEST_TDR_CFG_CNT,
ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX = __ETHTOOL_A_CABLE_TEST_TDR_CFG_CNT - 1
};
enum {
ETHTOOL_A_CABLE_TEST_TDR_UNSPEC,
ETHTOOL_A_CABLE_TEST_TDR_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_CABLE_TEST_TDR_CFG, /* nest - *_TDR_CFG_* */
/* add new constants above here */
__ETHTOOL_A_CABLE_TEST_TDR_CNT,
ETHTOOL_A_CABLE_TEST_TDR_MAX = __ETHTOOL_A_CABLE_TEST_TDR_CNT - 1
};
/* CABLE TEST TDR NOTIFY */
enum {
@ -689,163 +94,17 @@ enum {
ETHTOOL_A_CABLE_TDR_NEST_MAX = (__ETHTOOL_A_CABLE_TDR_NEST_CNT - 1)
};
enum {
ETHTOOL_A_CABLE_TEST_TDR_NTF_UNSPEC,
ETHTOOL_A_CABLE_TEST_TDR_NTF_HEADER, /* nest - ETHTOOL_A_HEADER_* */
ETHTOOL_A_CABLE_TEST_TDR_NTF_STATUS, /* u8 - _STARTED/_COMPLETE */
ETHTOOL_A_CABLE_TEST_TDR_NTF_NEST, /* nest - of results: */
/* add new constants above here */
__ETHTOOL_A_CABLE_TEST_TDR_NTF_CNT,
ETHTOOL_A_CABLE_TEST_TDR_NTF_MAX = __ETHTOOL_A_CABLE_TEST_TDR_NTF_CNT - 1
};
/* TUNNEL INFO */
enum {
ETHTOOL_UDP_TUNNEL_TYPE_VXLAN,
ETHTOOL_UDP_TUNNEL_TYPE_GENEVE,
ETHTOOL_UDP_TUNNEL_TYPE_VXLAN_GPE,
__ETHTOOL_UDP_TUNNEL_TYPE_CNT
};
enum {
ETHTOOL_A_TUNNEL_UDP_ENTRY_UNSPEC,
ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT, /* be16 */
ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE, /* u32 */
/* add new constants above here */
__ETHTOOL_A_TUNNEL_UDP_ENTRY_CNT,
ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX = (__ETHTOOL_A_TUNNEL_UDP_ENTRY_CNT - 1)
};
enum {
ETHTOOL_A_TUNNEL_UDP_TABLE_UNSPEC,
ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE, /* u32 */
ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES, /* bitset */
ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY, /* nest - _UDP_ENTRY_* */
/* add new constants above here */
__ETHTOOL_A_TUNNEL_UDP_TABLE_CNT,
ETHTOOL_A_TUNNEL_UDP_TABLE_MAX = (__ETHTOOL_A_TUNNEL_UDP_TABLE_CNT - 1)
};
enum {
ETHTOOL_A_TUNNEL_UDP_UNSPEC,
ETHTOOL_A_TUNNEL_UDP_TABLE, /* nest - _UDP_TABLE_* */
/* add new constants above here */
__ETHTOOL_A_TUNNEL_UDP_CNT,
ETHTOOL_A_TUNNEL_UDP_MAX = (__ETHTOOL_A_TUNNEL_UDP_CNT - 1)
};
enum {
ETHTOOL_A_TUNNEL_INFO_UNSPEC,
ETHTOOL_A_TUNNEL_INFO_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_TUNNEL_INFO_UDP_PORTS, /* nest - _UDP_TABLE */
/* add new constants above here */
__ETHTOOL_A_TUNNEL_INFO_CNT,
ETHTOOL_A_TUNNEL_INFO_MAX = (__ETHTOOL_A_TUNNEL_INFO_CNT - 1)
};
/* FEC */
enum {
ETHTOOL_A_FEC_UNSPEC,
ETHTOOL_A_FEC_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_FEC_MODES, /* bitset */
ETHTOOL_A_FEC_AUTO, /* u8 */
ETHTOOL_A_FEC_ACTIVE, /* u32 */
ETHTOOL_A_FEC_STATS, /* nest - _A_FEC_STAT */
__ETHTOOL_A_FEC_CNT,
ETHTOOL_A_FEC_MAX = (__ETHTOOL_A_FEC_CNT - 1)
};
enum {
ETHTOOL_A_FEC_STAT_UNSPEC,
ETHTOOL_A_FEC_STAT_PAD,
ETHTOOL_A_FEC_STAT_CORRECTED, /* array, u64 */
ETHTOOL_A_FEC_STAT_UNCORR, /* array, u64 */
ETHTOOL_A_FEC_STAT_CORR_BITS, /* array, u64 */
/* add new constants above here */
__ETHTOOL_A_FEC_STAT_CNT,
ETHTOOL_A_FEC_STAT_MAX = (__ETHTOOL_A_FEC_STAT_CNT - 1)
};
/* MODULE EEPROM */
enum {
ETHTOOL_A_MODULE_EEPROM_UNSPEC,
ETHTOOL_A_MODULE_EEPROM_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_MODULE_EEPROM_OFFSET, /* u32 */
ETHTOOL_A_MODULE_EEPROM_LENGTH, /* u32 */
ETHTOOL_A_MODULE_EEPROM_PAGE, /* u8 */
ETHTOOL_A_MODULE_EEPROM_BANK, /* u8 */
ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS, /* u8 */
ETHTOOL_A_MODULE_EEPROM_DATA, /* binary */
__ETHTOOL_A_MODULE_EEPROM_CNT,
ETHTOOL_A_MODULE_EEPROM_MAX = (__ETHTOOL_A_MODULE_EEPROM_CNT - 1)
};
/* STATS */
enum {
ETHTOOL_A_STATS_UNSPEC,
ETHTOOL_A_STATS_PAD,
ETHTOOL_A_STATS_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_STATS_GROUPS, /* bitset */
ETHTOOL_A_STATS_GRP, /* nest - _A_STATS_GRP_* */
ETHTOOL_A_STATS_SRC, /* u32 */
/* add new constants above here */
__ETHTOOL_A_STATS_CNT,
ETHTOOL_A_STATS_MAX = (__ETHTOOL_A_STATS_CNT - 1)
};
enum {
ETHTOOL_STATS_ETH_PHY,
ETHTOOL_STATS_ETH_MAC,
ETHTOOL_STATS_ETH_CTRL,
ETHTOOL_STATS_RMON,
ETHTOOL_STATS_PHY,
/* add new constants above here */
__ETHTOOL_STATS_CNT
};
enum {
ETHTOOL_A_STATS_GRP_UNSPEC,
ETHTOOL_A_STATS_GRP_PAD,
ETHTOOL_A_STATS_GRP_ID, /* u32 */
ETHTOOL_A_STATS_GRP_SS_ID, /* u32 */
ETHTOOL_A_STATS_GRP_STAT, /* nest */
ETHTOOL_A_STATS_GRP_HIST_RX, /* nest */
ETHTOOL_A_STATS_GRP_HIST_TX, /* nest */
ETHTOOL_A_STATS_GRP_HIST_BKT_LOW, /* u32 */
ETHTOOL_A_STATS_GRP_HIST_BKT_HI, /* u32 */
ETHTOOL_A_STATS_GRP_HIST_VAL, /* u64 */
/* add new constants above here */
__ETHTOOL_A_STATS_GRP_CNT,
ETHTOOL_A_STATS_GRP_MAX = (__ETHTOOL_A_STATS_GRP_CNT - 1)
};
enum {
/* 30.3.2.1.5 aSymbolErrorDuringCarrier */
ETHTOOL_A_STATS_ETH_PHY_5_SYM_ERR,
@ -935,160 +194,20 @@ enum {
ETHTOOL_A_STATS_RMON_MAX = (__ETHTOOL_A_STATS_RMON_CNT - 1)
};
/* MODULE */
enum {
ETHTOOL_A_MODULE_UNSPEC,
ETHTOOL_A_MODULE_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_MODULE_POWER_MODE_POLICY, /* u8 */
ETHTOOL_A_MODULE_POWER_MODE, /* u8 */
/* Basic packet counters if PHY has separate counters from the MAC */
ETHTOOL_A_STATS_PHY_RX_PKTS,
ETHTOOL_A_STATS_PHY_RX_BYTES,
ETHTOOL_A_STATS_PHY_RX_ERRORS,
ETHTOOL_A_STATS_PHY_TX_PKTS,
ETHTOOL_A_STATS_PHY_TX_BYTES,
ETHTOOL_A_STATS_PHY_TX_ERRORS,
/* add new constants above here */
__ETHTOOL_A_MODULE_CNT,
ETHTOOL_A_MODULE_MAX = (__ETHTOOL_A_MODULE_CNT - 1)
__ETHTOOL_A_STATS_PHY_CNT,
ETHTOOL_A_STATS_PHY_MAX = (__ETHTOOL_A_STATS_PHY_CNT - 1)
};
/* Power Sourcing Equipment */
enum {
ETHTOOL_A_C33_PSE_PW_LIMIT_UNSPEC,
ETHTOOL_A_C33_PSE_PW_LIMIT_MIN, /* u32 */
ETHTOOL_A_C33_PSE_PW_LIMIT_MAX, /* u32 */
};
enum {
ETHTOOL_A_PSE_UNSPEC,
ETHTOOL_A_PSE_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_PODL_PSE_ADMIN_STATE, /* u32 */
ETHTOOL_A_PODL_PSE_ADMIN_CONTROL, /* u32 */
ETHTOOL_A_PODL_PSE_PW_D_STATUS, /* u32 */
ETHTOOL_A_C33_PSE_ADMIN_STATE, /* u32 */
ETHTOOL_A_C33_PSE_ADMIN_CONTROL, /* u32 */
ETHTOOL_A_C33_PSE_PW_D_STATUS, /* u32 */
ETHTOOL_A_C33_PSE_PW_CLASS, /* u32 */
ETHTOOL_A_C33_PSE_ACTUAL_PW, /* u32 */
ETHTOOL_A_C33_PSE_EXT_STATE, /* u32 */
ETHTOOL_A_C33_PSE_EXT_SUBSTATE, /* u32 */
ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT, /* u32 */
ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES, /* nest - _C33_PSE_PW_LIMIT_* */
/* add new constants above here */
__ETHTOOL_A_PSE_CNT,
ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
};
enum {
ETHTOOL_A_RSS_UNSPEC,
ETHTOOL_A_RSS_HEADER,
ETHTOOL_A_RSS_CONTEXT, /* u32 */
ETHTOOL_A_RSS_HFUNC, /* u32 */
ETHTOOL_A_RSS_INDIR, /* binary */
ETHTOOL_A_RSS_HKEY, /* binary */
ETHTOOL_A_RSS_INPUT_XFRM, /* u32 */
ETHTOOL_A_RSS_START_CONTEXT, /* u32 */
__ETHTOOL_A_RSS_CNT,
ETHTOOL_A_RSS_MAX = (__ETHTOOL_A_RSS_CNT - 1),
};
/* PLCA */
enum {
ETHTOOL_A_PLCA_UNSPEC,
ETHTOOL_A_PLCA_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_PLCA_VERSION, /* u16 */
ETHTOOL_A_PLCA_ENABLED, /* u8 */
ETHTOOL_A_PLCA_STATUS, /* u8 */
ETHTOOL_A_PLCA_NODE_CNT, /* u32 */
ETHTOOL_A_PLCA_NODE_ID, /* u32 */
ETHTOOL_A_PLCA_TO_TMR, /* u32 */
ETHTOOL_A_PLCA_BURST_CNT, /* u32 */
ETHTOOL_A_PLCA_BURST_TMR, /* u32 */
/* add new constants above here */
__ETHTOOL_A_PLCA_CNT,
ETHTOOL_A_PLCA_MAX = (__ETHTOOL_A_PLCA_CNT - 1)
};
/* MAC Merge (802.3) */
enum {
ETHTOOL_A_MM_STAT_UNSPEC,
ETHTOOL_A_MM_STAT_PAD,
/* aMACMergeFrameAssErrorCount */
ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS, /* u64 */
/* aMACMergeFrameSmdErrorCount */
ETHTOOL_A_MM_STAT_SMD_ERRORS, /* u64 */
/* aMACMergeFrameAssOkCount */
ETHTOOL_A_MM_STAT_REASSEMBLY_OK, /* u64 */
/* aMACMergeFragCountRx */
ETHTOOL_A_MM_STAT_RX_FRAG_COUNT, /* u64 */
/* aMACMergeFragCountTx */
ETHTOOL_A_MM_STAT_TX_FRAG_COUNT, /* u64 */
/* aMACMergeHoldCount */
ETHTOOL_A_MM_STAT_HOLD_COUNT, /* u64 */
/* add new constants above here */
__ETHTOOL_A_MM_STAT_CNT,
ETHTOOL_A_MM_STAT_MAX = (__ETHTOOL_A_MM_STAT_CNT - 1)
};
enum {
ETHTOOL_A_MM_UNSPEC,
ETHTOOL_A_MM_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_MM_PMAC_ENABLED, /* u8 */
ETHTOOL_A_MM_TX_ENABLED, /* u8 */
ETHTOOL_A_MM_TX_ACTIVE, /* u8 */
ETHTOOL_A_MM_TX_MIN_FRAG_SIZE, /* u32 */
ETHTOOL_A_MM_RX_MIN_FRAG_SIZE, /* u32 */
ETHTOOL_A_MM_VERIFY_ENABLED, /* u8 */
ETHTOOL_A_MM_VERIFY_STATUS, /* u8 */
ETHTOOL_A_MM_VERIFY_TIME, /* u32 */
ETHTOOL_A_MM_MAX_VERIFY_TIME, /* u32 */
ETHTOOL_A_MM_STATS, /* nest - _A_MM_STAT_* */
/* add new constants above here */
__ETHTOOL_A_MM_CNT,
ETHTOOL_A_MM_MAX = (__ETHTOOL_A_MM_CNT - 1)
};
/* MODULE_FW_FLASH */
enum {
ETHTOOL_A_MODULE_FW_FLASH_UNSPEC,
ETHTOOL_A_MODULE_FW_FLASH_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_MODULE_FW_FLASH_FILE_NAME, /* string */
ETHTOOL_A_MODULE_FW_FLASH_PASSWORD, /* u32 */
ETHTOOL_A_MODULE_FW_FLASH_STATUS, /* u32 */
ETHTOOL_A_MODULE_FW_FLASH_STATUS_MSG, /* string */
ETHTOOL_A_MODULE_FW_FLASH_DONE, /* uint */
ETHTOOL_A_MODULE_FW_FLASH_TOTAL, /* uint */
/* add new constants above here */
__ETHTOOL_A_MODULE_FW_FLASH_CNT,
ETHTOOL_A_MODULE_FW_FLASH_MAX = (__ETHTOOL_A_MODULE_FW_FLASH_CNT - 1)
};
enum {
ETHTOOL_A_PHY_UNSPEC,
ETHTOOL_A_PHY_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_PHY_INDEX, /* u32 */
ETHTOOL_A_PHY_DRVNAME, /* string */
ETHTOOL_A_PHY_NAME, /* string */
ETHTOOL_A_PHY_UPSTREAM_TYPE, /* u32 */
ETHTOOL_A_PHY_UPSTREAM_INDEX, /* u32 */
ETHTOOL_A_PHY_UPSTREAM_SFP_NAME, /* string */
ETHTOOL_A_PHY_DOWNSTREAM_SFP_NAME, /* string */
/* add new constants above here */
__ETHTOOL_A_PHY_CNT,
ETHTOOL_A_PHY_MAX = (__ETHTOOL_A_PHY_CNT - 1)
};
/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
#define ETHTOOL_MCGRP_MONITOR_NAME "monitor"
#endif /* _UAPI_LINUX_ETHTOOL_NETLINK_H_ */

View File

@ -0,0 +1,816 @@
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/* Do not edit directly, auto-generated from: */
/* Documentation/netlink/specs/ethtool.yaml */
/* YNL-GEN uapi header */
#ifndef _UAPI_LINUX_ETHTOOL_NETLINK_GENERATED_H
#define _UAPI_LINUX_ETHTOOL_NETLINK_GENERATED_H
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
enum {
ETHTOOL_UDP_TUNNEL_TYPE_VXLAN,
ETHTOOL_UDP_TUNNEL_TYPE_GENEVE,
ETHTOOL_UDP_TUNNEL_TYPE_VXLAN_GPE,
/* private: */
__ETHTOOL_UDP_TUNNEL_TYPE_CNT,
ETHTOOL_UDP_TUNNEL_TYPE_MAX = (__ETHTOOL_UDP_TUNNEL_TYPE_CNT - 1)
};
/**
* enum ethtool_header_flags - common ethtool header flags
* @ETHTOOL_FLAG_COMPACT_BITSETS: use compact bitsets in reply
* @ETHTOOL_FLAG_OMIT_REPLY: provide optional reply for SET or ACT requests
* @ETHTOOL_FLAG_STATS: request statistics, if supported by the driver
*/
enum ethtool_header_flags {
ETHTOOL_FLAG_COMPACT_BITSETS = 1,
ETHTOOL_FLAG_OMIT_REPLY = 2,
ETHTOOL_FLAG_STATS = 4,
};
enum ethtool_tcp_data_split {
ETHTOOL_TCP_DATA_SPLIT_UNKNOWN,
ETHTOOL_TCP_DATA_SPLIT_DISABLED,
ETHTOOL_TCP_DATA_SPLIT_ENABLED,
};
enum {
ETHTOOL_A_HEADER_UNSPEC,
ETHTOOL_A_HEADER_DEV_INDEX,
ETHTOOL_A_HEADER_DEV_NAME,
ETHTOOL_A_HEADER_FLAGS,
ETHTOOL_A_HEADER_PHY_INDEX,
__ETHTOOL_A_HEADER_CNT,
ETHTOOL_A_HEADER_MAX = (__ETHTOOL_A_HEADER_CNT - 1)
};
enum {
ETHTOOL_A_BITSET_BIT_UNSPEC,
ETHTOOL_A_BITSET_BIT_INDEX,
ETHTOOL_A_BITSET_BIT_NAME,
ETHTOOL_A_BITSET_BIT_VALUE,
__ETHTOOL_A_BITSET_BIT_CNT,
ETHTOOL_A_BITSET_BIT_MAX = (__ETHTOOL_A_BITSET_BIT_CNT - 1)
};
enum {
ETHTOOL_A_BITSET_BITS_UNSPEC,
ETHTOOL_A_BITSET_BITS_BIT,
__ETHTOOL_A_BITSET_BITS_CNT,
ETHTOOL_A_BITSET_BITS_MAX = (__ETHTOOL_A_BITSET_BITS_CNT - 1)
};
enum {
ETHTOOL_A_BITSET_UNSPEC,
ETHTOOL_A_BITSET_NOMASK,
ETHTOOL_A_BITSET_SIZE,
ETHTOOL_A_BITSET_BITS,
ETHTOOL_A_BITSET_VALUE,
ETHTOOL_A_BITSET_MASK,
__ETHTOOL_A_BITSET_CNT,
ETHTOOL_A_BITSET_MAX = (__ETHTOOL_A_BITSET_CNT - 1)
};
enum {
ETHTOOL_A_STRING_UNSPEC,
ETHTOOL_A_STRING_INDEX,
ETHTOOL_A_STRING_VALUE,
__ETHTOOL_A_STRING_CNT,
ETHTOOL_A_STRING_MAX = (__ETHTOOL_A_STRING_CNT - 1)
};
enum {
ETHTOOL_A_STRINGS_UNSPEC,
ETHTOOL_A_STRINGS_STRING,
__ETHTOOL_A_STRINGS_CNT,
ETHTOOL_A_STRINGS_MAX = (__ETHTOOL_A_STRINGS_CNT - 1)
};
enum {
ETHTOOL_A_STRINGSET_UNSPEC,
ETHTOOL_A_STRINGSET_ID,
ETHTOOL_A_STRINGSET_COUNT,
ETHTOOL_A_STRINGSET_STRINGS,
__ETHTOOL_A_STRINGSET_CNT,
ETHTOOL_A_STRINGSET_MAX = (__ETHTOOL_A_STRINGSET_CNT - 1)
};
enum {
ETHTOOL_A_STRINGSETS_UNSPEC,
ETHTOOL_A_STRINGSETS_STRINGSET,
__ETHTOOL_A_STRINGSETS_CNT,
ETHTOOL_A_STRINGSETS_MAX = (__ETHTOOL_A_STRINGSETS_CNT - 1)
};
enum {
ETHTOOL_A_STRSET_UNSPEC,
ETHTOOL_A_STRSET_HEADER,
ETHTOOL_A_STRSET_STRINGSETS,
ETHTOOL_A_STRSET_COUNTS_ONLY,
__ETHTOOL_A_STRSET_CNT,
ETHTOOL_A_STRSET_MAX = (__ETHTOOL_A_STRSET_CNT - 1)
};
enum {
ETHTOOL_A_PRIVFLAGS_UNSPEC,
ETHTOOL_A_PRIVFLAGS_HEADER,
ETHTOOL_A_PRIVFLAGS_FLAGS,
__ETHTOOL_A_PRIVFLAGS_CNT,
ETHTOOL_A_PRIVFLAGS_MAX = (__ETHTOOL_A_PRIVFLAGS_CNT - 1)
};
enum {
ETHTOOL_A_RINGS_UNSPEC,
ETHTOOL_A_RINGS_HEADER,
ETHTOOL_A_RINGS_RX_MAX,
ETHTOOL_A_RINGS_RX_MINI_MAX,
ETHTOOL_A_RINGS_RX_JUMBO_MAX,
ETHTOOL_A_RINGS_TX_MAX,
ETHTOOL_A_RINGS_RX,
ETHTOOL_A_RINGS_RX_MINI,
ETHTOOL_A_RINGS_RX_JUMBO,
ETHTOOL_A_RINGS_TX,
ETHTOOL_A_RINGS_RX_BUF_LEN,
ETHTOOL_A_RINGS_TCP_DATA_SPLIT,
ETHTOOL_A_RINGS_CQE_SIZE,
ETHTOOL_A_RINGS_TX_PUSH,
ETHTOOL_A_RINGS_RX_PUSH,
ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN,
ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX,
ETHTOOL_A_RINGS_HDS_THRESH,
ETHTOOL_A_RINGS_HDS_THRESH_MAX,
__ETHTOOL_A_RINGS_CNT,
ETHTOOL_A_RINGS_MAX = (__ETHTOOL_A_RINGS_CNT - 1)
};
enum {
ETHTOOL_A_MM_STAT_UNSPEC,
ETHTOOL_A_MM_STAT_PAD,
ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS,
ETHTOOL_A_MM_STAT_SMD_ERRORS,
ETHTOOL_A_MM_STAT_REASSEMBLY_OK,
ETHTOOL_A_MM_STAT_RX_FRAG_COUNT,
ETHTOOL_A_MM_STAT_TX_FRAG_COUNT,
ETHTOOL_A_MM_STAT_HOLD_COUNT,
__ETHTOOL_A_MM_STAT_CNT,
ETHTOOL_A_MM_STAT_MAX = (__ETHTOOL_A_MM_STAT_CNT - 1)
};
enum {
ETHTOOL_A_MM_UNSPEC,
ETHTOOL_A_MM_HEADER,
ETHTOOL_A_MM_PMAC_ENABLED,
ETHTOOL_A_MM_TX_ENABLED,
ETHTOOL_A_MM_TX_ACTIVE,
ETHTOOL_A_MM_TX_MIN_FRAG_SIZE,
ETHTOOL_A_MM_RX_MIN_FRAG_SIZE,
ETHTOOL_A_MM_VERIFY_ENABLED,
ETHTOOL_A_MM_VERIFY_STATUS,
ETHTOOL_A_MM_VERIFY_TIME,
ETHTOOL_A_MM_MAX_VERIFY_TIME,
ETHTOOL_A_MM_STATS,
__ETHTOOL_A_MM_CNT,
ETHTOOL_A_MM_MAX = (__ETHTOOL_A_MM_CNT - 1)
};
enum {
ETHTOOL_A_LINKINFO_UNSPEC,
ETHTOOL_A_LINKINFO_HEADER,
ETHTOOL_A_LINKINFO_PORT,
ETHTOOL_A_LINKINFO_PHYADDR,
ETHTOOL_A_LINKINFO_TP_MDIX,
ETHTOOL_A_LINKINFO_TP_MDIX_CTRL,
ETHTOOL_A_LINKINFO_TRANSCEIVER,
__ETHTOOL_A_LINKINFO_CNT,
ETHTOOL_A_LINKINFO_MAX = (__ETHTOOL_A_LINKINFO_CNT - 1)
};
enum {
ETHTOOL_A_LINKMODES_UNSPEC,
ETHTOOL_A_LINKMODES_HEADER,
ETHTOOL_A_LINKMODES_AUTONEG,
ETHTOOL_A_LINKMODES_OURS,
ETHTOOL_A_LINKMODES_PEER,
ETHTOOL_A_LINKMODES_SPEED,
ETHTOOL_A_LINKMODES_DUPLEX,
ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG,
ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE,
ETHTOOL_A_LINKMODES_LANES,
ETHTOOL_A_LINKMODES_RATE_MATCHING,
__ETHTOOL_A_LINKMODES_CNT,
ETHTOOL_A_LINKMODES_MAX = (__ETHTOOL_A_LINKMODES_CNT - 1)
};
enum {
ETHTOOL_A_LINKSTATE_UNSPEC,
ETHTOOL_A_LINKSTATE_HEADER,
ETHTOOL_A_LINKSTATE_LINK,
ETHTOOL_A_LINKSTATE_SQI,
ETHTOOL_A_LINKSTATE_SQI_MAX,
ETHTOOL_A_LINKSTATE_EXT_STATE,
ETHTOOL_A_LINKSTATE_EXT_SUBSTATE,
ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT,
__ETHTOOL_A_LINKSTATE_CNT,
ETHTOOL_A_LINKSTATE_MAX = (__ETHTOOL_A_LINKSTATE_CNT - 1)
};
enum {
ETHTOOL_A_DEBUG_UNSPEC,
ETHTOOL_A_DEBUG_HEADER,
ETHTOOL_A_DEBUG_MSGMASK,
__ETHTOOL_A_DEBUG_CNT,
ETHTOOL_A_DEBUG_MAX = (__ETHTOOL_A_DEBUG_CNT - 1)
};
enum {
ETHTOOL_A_WOL_UNSPEC,
ETHTOOL_A_WOL_HEADER,
ETHTOOL_A_WOL_MODES,
ETHTOOL_A_WOL_SOPASS,
__ETHTOOL_A_WOL_CNT,
ETHTOOL_A_WOL_MAX = (__ETHTOOL_A_WOL_CNT - 1)
};
enum {
ETHTOOL_A_FEATURES_UNSPEC,
ETHTOOL_A_FEATURES_HEADER,
ETHTOOL_A_FEATURES_HW,
ETHTOOL_A_FEATURES_WANTED,
ETHTOOL_A_FEATURES_ACTIVE,
ETHTOOL_A_FEATURES_NOCHANGE,
__ETHTOOL_A_FEATURES_CNT,
ETHTOOL_A_FEATURES_MAX = (__ETHTOOL_A_FEATURES_CNT - 1)
};
enum {
ETHTOOL_A_CHANNELS_UNSPEC,
ETHTOOL_A_CHANNELS_HEADER,
ETHTOOL_A_CHANNELS_RX_MAX,
ETHTOOL_A_CHANNELS_TX_MAX,
ETHTOOL_A_CHANNELS_OTHER_MAX,
ETHTOOL_A_CHANNELS_COMBINED_MAX,
ETHTOOL_A_CHANNELS_RX_COUNT,
ETHTOOL_A_CHANNELS_TX_COUNT,
ETHTOOL_A_CHANNELS_OTHER_COUNT,
ETHTOOL_A_CHANNELS_COMBINED_COUNT,
__ETHTOOL_A_CHANNELS_CNT,
ETHTOOL_A_CHANNELS_MAX = (__ETHTOOL_A_CHANNELS_CNT - 1)
};
enum {
ETHTOOL_A_IRQ_MODERATION_UNSPEC,
ETHTOOL_A_IRQ_MODERATION_USEC,
ETHTOOL_A_IRQ_MODERATION_PKTS,
ETHTOOL_A_IRQ_MODERATION_COMPS,
__ETHTOOL_A_IRQ_MODERATION_CNT,
ETHTOOL_A_IRQ_MODERATION_MAX = (__ETHTOOL_A_IRQ_MODERATION_CNT - 1)
};
enum {
ETHTOOL_A_PROFILE_UNSPEC,
ETHTOOL_A_PROFILE_IRQ_MODERATION,
__ETHTOOL_A_PROFILE_CNT,
ETHTOOL_A_PROFILE_MAX = (__ETHTOOL_A_PROFILE_CNT - 1)
};
enum {
ETHTOOL_A_COALESCE_UNSPEC,
ETHTOOL_A_COALESCE_HEADER,
ETHTOOL_A_COALESCE_RX_USECS,
ETHTOOL_A_COALESCE_RX_MAX_FRAMES,
ETHTOOL_A_COALESCE_RX_USECS_IRQ,
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ,
ETHTOOL_A_COALESCE_TX_USECS,
ETHTOOL_A_COALESCE_TX_MAX_FRAMES,
ETHTOOL_A_COALESCE_TX_USECS_IRQ,
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ,
ETHTOOL_A_COALESCE_STATS_BLOCK_USECS,
ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX,
ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX,
ETHTOOL_A_COALESCE_PKT_RATE_LOW,
ETHTOOL_A_COALESCE_RX_USECS_LOW,
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW,
ETHTOOL_A_COALESCE_TX_USECS_LOW,
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW,
ETHTOOL_A_COALESCE_PKT_RATE_HIGH,
ETHTOOL_A_COALESCE_RX_USECS_HIGH,
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH,
ETHTOOL_A_COALESCE_TX_USECS_HIGH,
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH,
ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL,
ETHTOOL_A_COALESCE_USE_CQE_MODE_TX,
ETHTOOL_A_COALESCE_USE_CQE_MODE_RX,
ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES,
ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES,
ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS,
ETHTOOL_A_COALESCE_RX_PROFILE,
ETHTOOL_A_COALESCE_TX_PROFILE,
__ETHTOOL_A_COALESCE_CNT,
ETHTOOL_A_COALESCE_MAX = (__ETHTOOL_A_COALESCE_CNT - 1)
};
enum {
ETHTOOL_A_PAUSE_STAT_UNSPEC,
ETHTOOL_A_PAUSE_STAT_PAD,
ETHTOOL_A_PAUSE_STAT_TX_FRAMES,
ETHTOOL_A_PAUSE_STAT_RX_FRAMES,
__ETHTOOL_A_PAUSE_STAT_CNT,
ETHTOOL_A_PAUSE_STAT_MAX = (__ETHTOOL_A_PAUSE_STAT_CNT - 1)
};
enum {
ETHTOOL_A_PAUSE_UNSPEC,
ETHTOOL_A_PAUSE_HEADER,
ETHTOOL_A_PAUSE_AUTONEG,
ETHTOOL_A_PAUSE_RX,
ETHTOOL_A_PAUSE_TX,
ETHTOOL_A_PAUSE_STATS,
ETHTOOL_A_PAUSE_STATS_SRC,
__ETHTOOL_A_PAUSE_CNT,
ETHTOOL_A_PAUSE_MAX = (__ETHTOOL_A_PAUSE_CNT - 1)
};
enum {
ETHTOOL_A_EEE_UNSPEC,
ETHTOOL_A_EEE_HEADER,
ETHTOOL_A_EEE_MODES_OURS,
ETHTOOL_A_EEE_MODES_PEER,
ETHTOOL_A_EEE_ACTIVE,
ETHTOOL_A_EEE_ENABLED,
ETHTOOL_A_EEE_TX_LPI_ENABLED,
ETHTOOL_A_EEE_TX_LPI_TIMER,
__ETHTOOL_A_EEE_CNT,
ETHTOOL_A_EEE_MAX = (__ETHTOOL_A_EEE_CNT - 1)
};
enum {
ETHTOOL_A_TS_STAT_UNSPEC,
ETHTOOL_A_TS_STAT_TX_PKTS,
ETHTOOL_A_TS_STAT_TX_LOST,
ETHTOOL_A_TS_STAT_TX_ERR,
ETHTOOL_A_TS_STAT_TX_ONESTEP_PKTS_UNCONFIRMED,
__ETHTOOL_A_TS_STAT_CNT,
ETHTOOL_A_TS_STAT_MAX = (__ETHTOOL_A_TS_STAT_CNT - 1)
};
enum {
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_UNSPEC,
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX,
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER,
__ETHTOOL_A_TS_HWTSTAMP_PROVIDER_CNT,
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_MAX = (__ETHTOOL_A_TS_HWTSTAMP_PROVIDER_CNT - 1)
};
enum {
ETHTOOL_A_TSINFO_UNSPEC,
ETHTOOL_A_TSINFO_HEADER,
ETHTOOL_A_TSINFO_TIMESTAMPING,
ETHTOOL_A_TSINFO_TX_TYPES,
ETHTOOL_A_TSINFO_RX_FILTERS,
ETHTOOL_A_TSINFO_PHC_INDEX,
ETHTOOL_A_TSINFO_STATS,
ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER,
__ETHTOOL_A_TSINFO_CNT,
ETHTOOL_A_TSINFO_MAX = (__ETHTOOL_A_TSINFO_CNT - 1)
};
enum {
ETHTOOL_A_CABLE_RESULT_UNSPEC,
ETHTOOL_A_CABLE_RESULT_PAIR,
ETHTOOL_A_CABLE_RESULT_CODE,
ETHTOOL_A_CABLE_RESULT_SRC,
__ETHTOOL_A_CABLE_RESULT_CNT,
ETHTOOL_A_CABLE_RESULT_MAX = (__ETHTOOL_A_CABLE_RESULT_CNT - 1)
};
enum {
ETHTOOL_A_CABLE_FAULT_LENGTH_UNSPEC,
ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR,
ETHTOOL_A_CABLE_FAULT_LENGTH_CM,
ETHTOOL_A_CABLE_FAULT_LENGTH_SRC,
__ETHTOOL_A_CABLE_FAULT_LENGTH_CNT,
ETHTOOL_A_CABLE_FAULT_LENGTH_MAX = (__ETHTOOL_A_CABLE_FAULT_LENGTH_CNT - 1)
};
enum {
ETHTOOL_A_CABLE_NEST_UNSPEC,
ETHTOOL_A_CABLE_NEST_RESULT,
ETHTOOL_A_CABLE_NEST_FAULT_LENGTH,
__ETHTOOL_A_CABLE_NEST_CNT,
ETHTOOL_A_CABLE_NEST_MAX = (__ETHTOOL_A_CABLE_NEST_CNT - 1)
};
enum {
ETHTOOL_A_CABLE_TEST_UNSPEC,
ETHTOOL_A_CABLE_TEST_HEADER,
__ETHTOOL_A_CABLE_TEST_CNT,
ETHTOOL_A_CABLE_TEST_MAX = (__ETHTOOL_A_CABLE_TEST_CNT - 1)
};
enum {
ETHTOOL_A_CABLE_TEST_NTF_UNSPEC,
ETHTOOL_A_CABLE_TEST_NTF_HEADER,
ETHTOOL_A_CABLE_TEST_NTF_STATUS,
ETHTOOL_A_CABLE_TEST_NTF_NEST,
__ETHTOOL_A_CABLE_TEST_NTF_CNT,
ETHTOOL_A_CABLE_TEST_NTF_MAX = (__ETHTOOL_A_CABLE_TEST_NTF_CNT - 1)
};
enum {
ETHTOOL_A_CABLE_TEST_TDR_CFG_UNSPEC,
ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST,
ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST,
ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP,
ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR,
__ETHTOOL_A_CABLE_TEST_TDR_CFG_CNT,
ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX = (__ETHTOOL_A_CABLE_TEST_TDR_CFG_CNT - 1)
};
enum {
ETHTOOL_A_CABLE_TEST_TDR_NTF_UNSPEC,
ETHTOOL_A_CABLE_TEST_TDR_NTF_HEADER,
ETHTOOL_A_CABLE_TEST_TDR_NTF_STATUS,
ETHTOOL_A_CABLE_TEST_TDR_NTF_NEST,
__ETHTOOL_A_CABLE_TEST_TDR_NTF_CNT,
ETHTOOL_A_CABLE_TEST_TDR_NTF_MAX = (__ETHTOOL_A_CABLE_TEST_TDR_NTF_CNT - 1)
};
enum {
ETHTOOL_A_CABLE_TEST_TDR_UNSPEC,
ETHTOOL_A_CABLE_TEST_TDR_HEADER,
ETHTOOL_A_CABLE_TEST_TDR_CFG,
__ETHTOOL_A_CABLE_TEST_TDR_CNT,
ETHTOOL_A_CABLE_TEST_TDR_MAX = (__ETHTOOL_A_CABLE_TEST_TDR_CNT - 1)
};
enum {
ETHTOOL_A_TUNNEL_UDP_ENTRY_UNSPEC,
ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT,
ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE,
__ETHTOOL_A_TUNNEL_UDP_ENTRY_CNT,
ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX = (__ETHTOOL_A_TUNNEL_UDP_ENTRY_CNT - 1)
};
enum {
ETHTOOL_A_TUNNEL_UDP_TABLE_UNSPEC,
ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE,
ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES,
ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY,
__ETHTOOL_A_TUNNEL_UDP_TABLE_CNT,
ETHTOOL_A_TUNNEL_UDP_TABLE_MAX = (__ETHTOOL_A_TUNNEL_UDP_TABLE_CNT - 1)
};
enum {
ETHTOOL_A_TUNNEL_UDP_UNSPEC,
ETHTOOL_A_TUNNEL_UDP_TABLE,
__ETHTOOL_A_TUNNEL_UDP_CNT,
ETHTOOL_A_TUNNEL_UDP_MAX = (__ETHTOOL_A_TUNNEL_UDP_CNT - 1)
};
enum {
ETHTOOL_A_TUNNEL_INFO_UNSPEC,
ETHTOOL_A_TUNNEL_INFO_HEADER,
ETHTOOL_A_TUNNEL_INFO_UDP_PORTS,
__ETHTOOL_A_TUNNEL_INFO_CNT,
ETHTOOL_A_TUNNEL_INFO_MAX = (__ETHTOOL_A_TUNNEL_INFO_CNT - 1)
};
enum {
ETHTOOL_A_FEC_STAT_UNSPEC,
ETHTOOL_A_FEC_STAT_PAD,
ETHTOOL_A_FEC_STAT_CORRECTED,
ETHTOOL_A_FEC_STAT_UNCORR,
ETHTOOL_A_FEC_STAT_CORR_BITS,
__ETHTOOL_A_FEC_STAT_CNT,
ETHTOOL_A_FEC_STAT_MAX = (__ETHTOOL_A_FEC_STAT_CNT - 1)
};
enum {
ETHTOOL_A_FEC_UNSPEC,
ETHTOOL_A_FEC_HEADER,
ETHTOOL_A_FEC_MODES,
ETHTOOL_A_FEC_AUTO,
ETHTOOL_A_FEC_ACTIVE,
ETHTOOL_A_FEC_STATS,
__ETHTOOL_A_FEC_CNT,
ETHTOOL_A_FEC_MAX = (__ETHTOOL_A_FEC_CNT - 1)
};
enum {
ETHTOOL_A_MODULE_EEPROM_UNSPEC,
ETHTOOL_A_MODULE_EEPROM_HEADER,
ETHTOOL_A_MODULE_EEPROM_OFFSET,
ETHTOOL_A_MODULE_EEPROM_LENGTH,
ETHTOOL_A_MODULE_EEPROM_PAGE,
ETHTOOL_A_MODULE_EEPROM_BANK,
ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS,
ETHTOOL_A_MODULE_EEPROM_DATA,
__ETHTOOL_A_MODULE_EEPROM_CNT,
ETHTOOL_A_MODULE_EEPROM_MAX = (__ETHTOOL_A_MODULE_EEPROM_CNT - 1)
};
enum {
ETHTOOL_A_STATS_GRP_UNSPEC,
ETHTOOL_A_STATS_GRP_PAD,
ETHTOOL_A_STATS_GRP_ID,
ETHTOOL_A_STATS_GRP_SS_ID,
ETHTOOL_A_STATS_GRP_STAT,
ETHTOOL_A_STATS_GRP_HIST_RX,
ETHTOOL_A_STATS_GRP_HIST_TX,
ETHTOOL_A_STATS_GRP_HIST_BKT_LOW,
ETHTOOL_A_STATS_GRP_HIST_BKT_HI,
ETHTOOL_A_STATS_GRP_HIST_VAL,
__ETHTOOL_A_STATS_GRP_CNT,
ETHTOOL_A_STATS_GRP_MAX = (__ETHTOOL_A_STATS_GRP_CNT - 1)
};
enum {
ETHTOOL_A_STATS_UNSPEC,
ETHTOOL_A_STATS_PAD,
ETHTOOL_A_STATS_HEADER,
ETHTOOL_A_STATS_GROUPS,
ETHTOOL_A_STATS_GRP,
ETHTOOL_A_STATS_SRC,
__ETHTOOL_A_STATS_CNT,
ETHTOOL_A_STATS_MAX = (__ETHTOOL_A_STATS_CNT - 1)
};
enum {
ETHTOOL_A_PHC_VCLOCKS_UNSPEC,
ETHTOOL_A_PHC_VCLOCKS_HEADER,
ETHTOOL_A_PHC_VCLOCKS_NUM,
ETHTOOL_A_PHC_VCLOCKS_INDEX,
__ETHTOOL_A_PHC_VCLOCKS_CNT,
ETHTOOL_A_PHC_VCLOCKS_MAX = (__ETHTOOL_A_PHC_VCLOCKS_CNT - 1)
};
enum {
ETHTOOL_A_MODULE_UNSPEC,
ETHTOOL_A_MODULE_HEADER,
ETHTOOL_A_MODULE_POWER_MODE_POLICY,
ETHTOOL_A_MODULE_POWER_MODE,
__ETHTOOL_A_MODULE_CNT,
ETHTOOL_A_MODULE_MAX = (__ETHTOOL_A_MODULE_CNT - 1)
};
enum {
ETHTOOL_A_C33_PSE_PW_LIMIT_UNSPEC,
ETHTOOL_A_C33_PSE_PW_LIMIT_MIN,
ETHTOOL_A_C33_PSE_PW_LIMIT_MAX,
__ETHTOOL_A_C33_PSE_PW_LIMIT_CNT,
__ETHTOOL_A_C33_PSE_PW_LIMIT_MAX = (__ETHTOOL_A_C33_PSE_PW_LIMIT_CNT - 1)
};
enum {
ETHTOOL_A_PSE_UNSPEC,
ETHTOOL_A_PSE_HEADER,
ETHTOOL_A_PODL_PSE_ADMIN_STATE,
ETHTOOL_A_PODL_PSE_ADMIN_CONTROL,
ETHTOOL_A_PODL_PSE_PW_D_STATUS,
ETHTOOL_A_C33_PSE_ADMIN_STATE,
ETHTOOL_A_C33_PSE_ADMIN_CONTROL,
ETHTOOL_A_C33_PSE_PW_D_STATUS,
ETHTOOL_A_C33_PSE_PW_CLASS,
ETHTOOL_A_C33_PSE_ACTUAL_PW,
ETHTOOL_A_C33_PSE_EXT_STATE,
ETHTOOL_A_C33_PSE_EXT_SUBSTATE,
ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT,
ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES,
__ETHTOOL_A_PSE_CNT,
ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
};
enum {
ETHTOOL_A_RSS_UNSPEC,
ETHTOOL_A_RSS_HEADER,
ETHTOOL_A_RSS_CONTEXT,
ETHTOOL_A_RSS_HFUNC,
ETHTOOL_A_RSS_INDIR,
ETHTOOL_A_RSS_HKEY,
ETHTOOL_A_RSS_INPUT_XFRM,
ETHTOOL_A_RSS_START_CONTEXT,
__ETHTOOL_A_RSS_CNT,
ETHTOOL_A_RSS_MAX = (__ETHTOOL_A_RSS_CNT - 1)
};
enum {
ETHTOOL_A_PLCA_UNSPEC,
ETHTOOL_A_PLCA_HEADER,
ETHTOOL_A_PLCA_VERSION,
ETHTOOL_A_PLCA_ENABLED,
ETHTOOL_A_PLCA_STATUS,
ETHTOOL_A_PLCA_NODE_CNT,
ETHTOOL_A_PLCA_NODE_ID,
ETHTOOL_A_PLCA_TO_TMR,
ETHTOOL_A_PLCA_BURST_CNT,
ETHTOOL_A_PLCA_BURST_TMR,
__ETHTOOL_A_PLCA_CNT,
ETHTOOL_A_PLCA_MAX = (__ETHTOOL_A_PLCA_CNT - 1)
};
enum {
ETHTOOL_A_MODULE_FW_FLASH_UNSPEC,
ETHTOOL_A_MODULE_FW_FLASH_HEADER,
ETHTOOL_A_MODULE_FW_FLASH_FILE_NAME,
ETHTOOL_A_MODULE_FW_FLASH_PASSWORD,
ETHTOOL_A_MODULE_FW_FLASH_STATUS,
ETHTOOL_A_MODULE_FW_FLASH_STATUS_MSG,
ETHTOOL_A_MODULE_FW_FLASH_DONE,
ETHTOOL_A_MODULE_FW_FLASH_TOTAL,
__ETHTOOL_A_MODULE_FW_FLASH_CNT,
ETHTOOL_A_MODULE_FW_FLASH_MAX = (__ETHTOOL_A_MODULE_FW_FLASH_CNT - 1)
};
enum {
ETHTOOL_A_PHY_UNSPEC,
ETHTOOL_A_PHY_HEADER,
ETHTOOL_A_PHY_INDEX,
ETHTOOL_A_PHY_DRVNAME,
ETHTOOL_A_PHY_NAME,
ETHTOOL_A_PHY_UPSTREAM_TYPE,
ETHTOOL_A_PHY_UPSTREAM_INDEX,
ETHTOOL_A_PHY_UPSTREAM_SFP_NAME,
ETHTOOL_A_PHY_DOWNSTREAM_SFP_NAME,
__ETHTOOL_A_PHY_CNT,
ETHTOOL_A_PHY_MAX = (__ETHTOOL_A_PHY_CNT - 1)
};
enum {
ETHTOOL_A_TSCONFIG_UNSPEC,
ETHTOOL_A_TSCONFIG_HEADER,
ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER,
ETHTOOL_A_TSCONFIG_TX_TYPES,
ETHTOOL_A_TSCONFIG_RX_FILTERS,
ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS,
__ETHTOOL_A_TSCONFIG_CNT,
ETHTOOL_A_TSCONFIG_MAX = (__ETHTOOL_A_TSCONFIG_CNT - 1)
};
enum {
ETHTOOL_MSG_USER_NONE = 0,
ETHTOOL_MSG_STRSET_GET = 1,
ETHTOOL_MSG_LINKINFO_GET,
ETHTOOL_MSG_LINKINFO_SET,
ETHTOOL_MSG_LINKMODES_GET,
ETHTOOL_MSG_LINKMODES_SET,
ETHTOOL_MSG_LINKSTATE_GET,
ETHTOOL_MSG_DEBUG_GET,
ETHTOOL_MSG_DEBUG_SET,
ETHTOOL_MSG_WOL_GET,
ETHTOOL_MSG_WOL_SET,
ETHTOOL_MSG_FEATURES_GET,
ETHTOOL_MSG_FEATURES_SET,
ETHTOOL_MSG_PRIVFLAGS_GET,
ETHTOOL_MSG_PRIVFLAGS_SET,
ETHTOOL_MSG_RINGS_GET,
ETHTOOL_MSG_RINGS_SET,
ETHTOOL_MSG_CHANNELS_GET,
ETHTOOL_MSG_CHANNELS_SET,
ETHTOOL_MSG_COALESCE_GET,
ETHTOOL_MSG_COALESCE_SET,
ETHTOOL_MSG_PAUSE_GET,
ETHTOOL_MSG_PAUSE_SET,
ETHTOOL_MSG_EEE_GET,
ETHTOOL_MSG_EEE_SET,
ETHTOOL_MSG_TSINFO_GET,
ETHTOOL_MSG_CABLE_TEST_ACT,
ETHTOOL_MSG_CABLE_TEST_TDR_ACT,
ETHTOOL_MSG_TUNNEL_INFO_GET,
ETHTOOL_MSG_FEC_GET,
ETHTOOL_MSG_FEC_SET,
ETHTOOL_MSG_MODULE_EEPROM_GET,
ETHTOOL_MSG_STATS_GET,
ETHTOOL_MSG_PHC_VCLOCKS_GET,
ETHTOOL_MSG_MODULE_GET,
ETHTOOL_MSG_MODULE_SET,
ETHTOOL_MSG_PSE_GET,
ETHTOOL_MSG_PSE_SET,
ETHTOOL_MSG_RSS_GET,
ETHTOOL_MSG_PLCA_GET_CFG,
ETHTOOL_MSG_PLCA_SET_CFG,
ETHTOOL_MSG_PLCA_GET_STATUS,
ETHTOOL_MSG_MM_GET,
ETHTOOL_MSG_MM_SET,
ETHTOOL_MSG_MODULE_FW_FLASH_ACT,
ETHTOOL_MSG_PHY_GET,
ETHTOOL_MSG_TSCONFIG_GET,
ETHTOOL_MSG_TSCONFIG_SET,
__ETHTOOL_MSG_USER_CNT,
ETHTOOL_MSG_USER_MAX = (__ETHTOOL_MSG_USER_CNT - 1)
};
enum {
ETHTOOL_MSG_KERNEL_NONE = 0,
ETHTOOL_MSG_STRSET_GET_REPLY = 1,
ETHTOOL_MSG_LINKINFO_GET_REPLY,
ETHTOOL_MSG_LINKINFO_NTF,
ETHTOOL_MSG_LINKMODES_GET_REPLY,
ETHTOOL_MSG_LINKMODES_NTF,
ETHTOOL_MSG_LINKSTATE_GET_REPLY,
ETHTOOL_MSG_DEBUG_GET_REPLY,
ETHTOOL_MSG_DEBUG_NTF,
ETHTOOL_MSG_WOL_GET_REPLY,
ETHTOOL_MSG_WOL_NTF,
ETHTOOL_MSG_FEATURES_GET_REPLY,
ETHTOOL_MSG_FEATURES_SET_REPLY,
ETHTOOL_MSG_FEATURES_NTF,
ETHTOOL_MSG_PRIVFLAGS_GET_REPLY,
ETHTOOL_MSG_PRIVFLAGS_NTF,
ETHTOOL_MSG_RINGS_GET_REPLY,
ETHTOOL_MSG_RINGS_NTF,
ETHTOOL_MSG_CHANNELS_GET_REPLY,
ETHTOOL_MSG_CHANNELS_NTF,
ETHTOOL_MSG_COALESCE_GET_REPLY,
ETHTOOL_MSG_COALESCE_NTF,
ETHTOOL_MSG_PAUSE_GET_REPLY,
ETHTOOL_MSG_PAUSE_NTF,
ETHTOOL_MSG_EEE_GET_REPLY,
ETHTOOL_MSG_EEE_NTF,
ETHTOOL_MSG_TSINFO_GET_REPLY,
ETHTOOL_MSG_CABLE_TEST_NTF,
ETHTOOL_MSG_CABLE_TEST_TDR_NTF,
ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY,
ETHTOOL_MSG_FEC_GET_REPLY,
ETHTOOL_MSG_FEC_NTF,
ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY,
ETHTOOL_MSG_STATS_GET_REPLY,
ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY,
ETHTOOL_MSG_MODULE_GET_REPLY,
ETHTOOL_MSG_MODULE_NTF,
ETHTOOL_MSG_PSE_GET_REPLY,
ETHTOOL_MSG_RSS_GET_REPLY,
ETHTOOL_MSG_PLCA_GET_CFG_REPLY,
ETHTOOL_MSG_PLCA_GET_STATUS_REPLY,
ETHTOOL_MSG_PLCA_NTF,
ETHTOOL_MSG_MM_GET_REPLY,
ETHTOOL_MSG_MM_NTF,
ETHTOOL_MSG_MODULE_FW_FLASH_NTF,
ETHTOOL_MSG_PHY_GET_REPLY,
ETHTOOL_MSG_PHY_NTF,
ETHTOOL_MSG_TSCONFIG_GET_REPLY,
ETHTOOL_MSG_TSCONFIG_SET_REPLY,
__ETHTOOL_MSG_KERNEL_CNT,
ETHTOOL_MSG_KERNEL_MAX = (__ETHTOOL_MSG_KERNEL_CNT - 1)
};
#endif /* _UAPI_LINUX_ETHTOOL_NETLINK_GENERATED_H */

View File

@ -13,6 +13,17 @@
#include <linux/types.h>
#include <linux/socket.h> /* for SO_TIMESTAMPING */
/*
* Possible type of hwtstamp provider. Mainly "precise" the default one
* is for IEEE 1588 quality and "approx" is for NICs DMA point.
*/
enum hwtstamp_provider_qualifier {
HWTSTAMP_PROVIDER_QUALIFIER_PRECISE,
HWTSTAMP_PROVIDER_QUALIFIER_APPROX,
HWTSTAMP_PROVIDER_QUALIFIER_CNT,
};
/* SO_TIMESTAMPING flags */
enum {
SOF_TIMESTAMPING_TX_HARDWARE = (1<<0),
@ -32,8 +43,9 @@ enum {
SOF_TIMESTAMPING_OPT_TX_SWHW = (1<<14),
SOF_TIMESTAMPING_BIND_PHC = (1 << 15),
SOF_TIMESTAMPING_OPT_ID_TCP = (1 << 16),
SOF_TIMESTAMPING_OPT_RX_FILTER = (1 << 17),
SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_ID_TCP,
SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_RX_FILTER,
SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) |
SOF_TIMESTAMPING_LAST
};

View File

@ -91,6 +91,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/ethtool_netlink.h>
#include <linux/skbuff.h>
#include <linux/kthread.h>
#include <linux/bpf.h>
@ -104,6 +105,7 @@
#include <net/dst.h>
#include <net/dst_metadata.h>
#include <net/gro.h>
#include <net/netdev_queues.h>
#include <net/pkt_sched.h>
#include <net/pkt_cls.h>
#include <net/checksum.h>
@ -9426,6 +9428,18 @@ u8 dev_xdp_prog_count(struct net_device *dev)
}
EXPORT_SYMBOL_GPL(dev_xdp_prog_count);
u8 dev_xdp_sb_prog_count(struct net_device *dev)
{
u8 count = 0;
int i;
for (i = 0; i < __MAX_XDP_MODE; i++)
if (dev->xdp_state[i].prog &&
!dev->xdp_state[i].prog->aux->xdp_has_frags)
count++;
return count;
}
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode)
{
struct bpf_prog *prog = dev_xdp_prog(dev, mode);
@ -9454,6 +9468,12 @@ static int dev_xdp_install(struct net_device *dev, enum bpf_xdp_mode mode,
struct netdev_bpf xdp;
int err;
if (dev->cfg->hds_config == ETHTOOL_TCP_DATA_SPLIT_ENABLED &&
prog && !prog->aux->xdp_has_frags) {
NL_SET_ERR_MSG(extack, "unable to install XDP to device using tcp-data-split");
return -EBUSY;
}
memset(&xdp, 0, sizeof(xdp));
xdp.command = mode == XDP_MODE_HW ? XDP_SETUP_PROG_HW : XDP_SETUP_PROG;
xdp.extack = extack;
@ -11156,6 +11176,11 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
if (!dev->ethtool)
goto free_all;
dev->cfg = kzalloc(sizeof(*dev->cfg), GFP_KERNEL_ACCOUNT);
if (!dev->cfg)
goto free_all;
dev->cfg_pending = dev->cfg;
napi_config_sz = array_size(maxqs, sizeof(*dev->napi_config));
dev->napi_config = kvzalloc(napi_config_sz, GFP_KERNEL_ACCOUNT);
if (!dev->napi_config)
@ -11212,6 +11237,8 @@ void free_netdev(struct net_device *dev)
mutex_destroy(&dev->lock);
WARN_ON(dev->cfg != dev->cfg_pending);
kfree(dev->cfg);
kfree(dev->ethtool);
netif_free_tx_queues(dev);
netif_free_rx_queues(dev);

View File

@ -245,6 +245,12 @@ static inline void netdev_set_gro_flush_timeout(struct net_device *netdev,
}
int rps_cpumask_housekeeping(struct cpumask *mask);
int dev_set_hwtstamp_phylib(struct net_device *dev,
struct kernel_hwtstamp_config *cfg,
struct netlink_ext_ack *extack);
int dev_get_hwtstamp_phylib(struct net_device *dev,
struct kernel_hwtstamp_config *cfg);
int net_hwtstamp_validate(const struct kernel_hwtstamp_config *cfg);
/* Best effort check that NAPI is not idle (can't be scheduled to run) */
static inline void napi_assert_will_not_race(const struct napi_struct *napi)

View File

@ -6,6 +6,7 @@
#include <linux/rtnetlink.h>
#include <linux/net_tstamp.h>
#include <linux/phylib_stubs.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/wireless.h>
#include <linux/if_bridge.h>
#include <net/dsa_stubs.h>
@ -184,7 +185,7 @@ static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cm
return err;
}
static int net_hwtstamp_validate(const struct kernel_hwtstamp_config *cfg)
int net_hwtstamp_validate(const struct kernel_hwtstamp_config *cfg)
{
enum hwtstamp_tx_types tx_type;
enum hwtstamp_rx_filters rx_filter;
@ -266,9 +267,24 @@ static int dev_eth_ioctl(struct net_device *dev,
* -EOPNOTSUPP for phylib for now, which is still more accurate than letting
* the netdev handle the GET request.
*/
static int dev_get_hwtstamp_phylib(struct net_device *dev,
struct kernel_hwtstamp_config *cfg)
int dev_get_hwtstamp_phylib(struct net_device *dev,
struct kernel_hwtstamp_config *cfg)
{
struct hwtstamp_provider *hwprov;
hwprov = rtnl_dereference(dev->hwprov);
if (hwprov) {
cfg->qualifier = hwprov->desc.qualifier;
if (hwprov->source == HWTSTAMP_SOURCE_PHYLIB &&
hwprov->phydev)
return phy_hwtstamp_get(hwprov->phydev, cfg);
if (hwprov->source == HWTSTAMP_SOURCE_NETDEV)
return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg);
return -EOPNOTSUPP;
}
if (phy_is_default_hwtstamp(dev->phydev))
return phy_hwtstamp_get(dev->phydev, cfg);
@ -324,11 +340,32 @@ int dev_set_hwtstamp_phylib(struct net_device *dev,
struct netlink_ext_ack *extack)
{
const struct net_device_ops *ops = dev->netdev_ops;
bool phy_ts = phy_is_default_hwtstamp(dev->phydev);
struct kernel_hwtstamp_config old_cfg = {};
struct hwtstamp_provider *hwprov;
struct phy_device *phydev;
bool changed = false;
bool phy_ts;
int err;
hwprov = rtnl_dereference(dev->hwprov);
if (hwprov) {
if (hwprov->source == HWTSTAMP_SOURCE_PHYLIB &&
hwprov->phydev) {
phy_ts = true;
phydev = hwprov->phydev;
} else if (hwprov->source == HWTSTAMP_SOURCE_NETDEV) {
phy_ts = false;
} else {
return -EOPNOTSUPP;
}
cfg->qualifier = hwprov->desc.qualifier;
} else {
phy_ts = phy_is_default_hwtstamp(dev->phydev);
if (phy_ts)
phydev = dev->phydev;
}
cfg->source = phy_ts ? HWTSTAMP_SOURCE_PHYLIB : HWTSTAMP_SOURCE_NETDEV;
if (phy_ts && dev->see_all_hwtstamp_requests) {
@ -350,7 +387,7 @@ int dev_set_hwtstamp_phylib(struct net_device *dev,
changed = kernel_hwtstamp_config_changed(&old_cfg, cfg);
if (phy_ts) {
err = phy_hwtstamp_set(dev->phydev, cfg, extack);
err = phy_hwtstamp_set(phydev, cfg, extack);
if (err) {
if (changed)
ops->ndo_hwtstamp_set(dev, &old_cfg, NULL);
@ -360,7 +397,6 @@ int dev_set_hwtstamp_phylib(struct net_device *dev,
return 0;
}
EXPORT_SYMBOL_GPL(dev_set_hwtstamp_phylib);
static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
{

View File

@ -9,6 +9,7 @@
#include <linux/ptp_classify.h>
#include <linux/skbuff.h>
#include <linux/export.h>
#include <linux/ptp_clock_kernel.h>
static unsigned int classify(const struct sk_buff *skb)
{
@ -21,19 +22,39 @@ static unsigned int classify(const struct sk_buff *skb)
void skb_clone_tx_timestamp(struct sk_buff *skb)
{
struct hwtstamp_provider *hwprov;
struct mii_timestamper *mii_ts;
struct phy_device *phydev;
struct sk_buff *clone;
unsigned int type;
if (!skb->sk || !skb->dev ||
!phy_is_default_hwtstamp(skb->dev->phydev))
if (!skb->sk || !skb->dev)
return;
rcu_read_lock();
hwprov = rcu_dereference(skb->dev->hwprov);
if (hwprov) {
if (hwprov->source != HWTSTAMP_SOURCE_PHYLIB ||
!hwprov->phydev) {
rcu_read_unlock();
return;
}
phydev = hwprov->phydev;
} else {
phydev = skb->dev->phydev;
if (!phy_is_default_hwtstamp(phydev)) {
rcu_read_unlock();
return;
}
}
rcu_read_unlock();
type = classify(skb);
if (type == PTP_CLASS_NONE)
return;
mii_ts = skb->dev->phydev->mii_ts;
mii_ts = phydev->mii_ts;
if (likely(mii_ts->txtstamp)) {
clone = skb_clone_sk(skb);
if (!clone)
@ -45,12 +66,33 @@ EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp);
bool skb_defer_rx_timestamp(struct sk_buff *skb)
{
struct hwtstamp_provider *hwprov;
struct mii_timestamper *mii_ts;
struct phy_device *phydev;
unsigned int type;
if (!skb->dev || !phy_is_default_hwtstamp(skb->dev->phydev))
if (!skb->dev)
return false;
rcu_read_lock();
hwprov = rcu_dereference(skb->dev->hwprov);
if (hwprov) {
if (hwprov->source != HWTSTAMP_SOURCE_PHYLIB ||
!hwprov->phydev) {
rcu_read_unlock();
return false;
}
phydev = hwprov->phydev;
} else {
phydev = skb->dev->phydev;
if (!phy_is_default_hwtstamp(phydev)) {
rcu_read_unlock();
return false;
}
}
rcu_read_unlock();
if (skb_headroom(skb) < ETH_HLEN)
return false;
@ -63,7 +105,7 @@ bool skb_defer_rx_timestamp(struct sk_buff *skb)
if (type == PTP_CLASS_NONE)
return false;
mii_ts = skb->dev->phydev->mii_ts;
mii_ts = phydev->mii_ts;
if (likely(mii_ts->rxtstamp))
return mii_ts->rxtstamp(mii_ts, skb, type);

View File

@ -9,4 +9,4 @@ ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o rss.o \
channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \
tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \
module.o cmis_fw_update.o cmis_cdb.o pse-pd.o plca.o mm.o \
phy.o
phy.o tsconfig.o

View File

@ -425,12 +425,32 @@ static int ethnl_parse_bit(unsigned int *index, bool *val, unsigned int nbits,
return 0;
}
/**
* ethnl_bitmap32_equal() - Compare two bitmaps
* @map1: first bitmap
* @map2: second bitmap
* @nbits: bit size to compare
*
* Return: true if first @nbits are equal, false if not
*/
static bool ethnl_bitmap32_equal(const u32 *map1, const u32 *map2,
unsigned int nbits)
{
if (memcmp(map1, map2, nbits / 32 * sizeof(u32)))
return false;
if (nbits % 32 == 0)
return true;
return !((map1[nbits / 32] ^ map2[nbits / 32]) &
ethnl_lower_bits(nbits % 32));
}
static int
ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
const struct nlattr *attr, struct nlattr **tb,
ethnl_string_array_t names,
struct netlink_ext_ack *extack, bool *mod)
{
u32 *saved_bitmap = NULL;
struct nlattr *bit_attr;
bool no_mask;
int rem;
@ -448,8 +468,20 @@ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
}
no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
if (no_mask)
ethnl_bitmap32_clear(bitmap, 0, nbits, mod);
if (no_mask) {
unsigned int nwords = DIV_ROUND_UP(nbits, 32);
unsigned int nbytes = nwords * sizeof(u32);
bool dummy;
/* The bitmap size is only the size of the map part without
* its mask part.
*/
saved_bitmap = kcalloc(nwords, sizeof(u32), GFP_KERNEL);
if (!saved_bitmap)
return -ENOMEM;
memcpy(saved_bitmap, bitmap, nbytes);
ethnl_bitmap32_clear(bitmap, 0, nbits, &dummy);
}
nla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) {
bool old_val, new_val;
@ -458,22 +490,30 @@ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
if (nla_type(bit_attr) != ETHTOOL_A_BITSET_BITS_BIT) {
NL_SET_ERR_MSG_ATTR(extack, bit_attr,
"only ETHTOOL_A_BITSET_BITS_BIT allowed in ETHTOOL_A_BITSET_BITS");
kfree(saved_bitmap);
return -EINVAL;
}
ret = ethnl_parse_bit(&idx, &new_val, nbits, bit_attr, no_mask,
names, extack);
if (ret < 0)
if (ret < 0) {
kfree(saved_bitmap);
return ret;
}
old_val = bitmap[idx / 32] & ((u32)1 << (idx % 32));
if (new_val != old_val) {
if (new_val)
bitmap[idx / 32] |= ((u32)1 << (idx % 32));
else
bitmap[idx / 32] &= ~((u32)1 << (idx % 32));
*mod = true;
if (!no_mask)
*mod = true;
}
}
if (no_mask && !ethnl_bitmap32_equal(saved_bitmap, bitmap, nbits))
*mod = true;
kfree(saved_bitmap);
return 0;
}

View File

@ -72,8 +72,8 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
dev = req_info.dev;
rtnl_lock();
phydev = ethnl_req_get_phydev(&req_info,
tb[ETHTOOL_A_CABLE_TEST_HEADER],
phydev = ethnl_req_get_phydev(&req_info, tb,
ETHTOOL_A_CABLE_TEST_HEADER,
info->extack);
if (IS_ERR_OR_NULL(phydev)) {
ret = -EOPNOTSUPP;
@ -339,8 +339,8 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
goto out_dev_put;
rtnl_lock();
phydev = ethnl_req_get_phydev(&req_info,
tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
phydev = ethnl_req_get_phydev(&req_info, tb,
ETHTOOL_A_CABLE_TEST_TDR_HEADER,
info->extack);
if (IS_ERR_OR_NULL(phydev)) {
ret = -EOPNOTSUPP;

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#define ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH 120
#define ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH 2048
#define ETHTOOL_CMIS_CDB_CMD_PAGE 0x9F
#define ETHTOOL_CMIS_CDB_PAGE_I2C_ADDR 0x50
@ -23,6 +24,7 @@ enum ethtool_cmis_cdb_cmd_id {
ETHTOOL_CMIS_CDB_CMD_FW_MANAGMENT_FEATURES = 0x0041,
ETHTOOL_CMIS_CDB_CMD_START_FW_DOWNLOAD = 0x0101,
ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_LPL = 0x0103,
ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_EPL = 0x0104,
ETHTOOL_CMIS_CDB_CMD_COMPLETE_FW_DOWNLOAD = 0x0107,
ETHTOOL_CMIS_CDB_CMD_RUN_FW_IMAGE = 0x0109,
ETHTOOL_CMIS_CDB_CMD_COMMIT_FW_IMAGE = 0x010A,
@ -38,6 +40,7 @@ enum ethtool_cmis_cdb_cmd_id {
* @resv1: Added to match the CMIS standard request continuity.
* @resv2: Added to match the CMIS standard request continuity.
* @payload: Payload for the CDB commands.
* @epl: Extended payload for the CDB commands.
*/
struct ethtool_cmis_cdb_request {
__be16 id;
@ -49,6 +52,7 @@ struct ethtool_cmis_cdb_request {
u8 resv2;
u8 payload[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH];
);
u8 *epl; /* Everything above this field checksummed. */
};
#define CDB_F_COMPLETION_VALID BIT(0)
@ -96,13 +100,14 @@ struct ethtool_cmis_cdb_rpl {
u8 payload[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH];
};
u32 ethtool_cmis_get_max_payload_size(u8 num_of_byte_octs);
u32 ethtool_cmis_get_max_lpl_size(u8 num_of_byte_octs);
void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args *args,
enum ethtool_cmis_cdb_cmd_id cmd, u8 *pl,
u8 lpl_len, u16 max_duration,
u8 read_write_len_ext, u16 msleep_pre_rpl,
u8 rpl_exp_len, u8 flags);
enum ethtool_cmis_cdb_cmd_id cmd, u8 *lpl,
u8 lpl_len, u8 *epl, u16 epl_len,
u16 max_duration, u8 read_write_len_ext,
u16 msleep_pre_rpl, u8 rpl_exp_len,
u8 flags);
void ethtool_cmis_cdb_check_completion_flag(u8 cmis_rev, u8 *flags);

View File

@ -11,25 +11,29 @@
* min(i, 15) byte octets where i specifies the allowable additional number of
* byte octets in a READ or a WRITE.
*/
u32 ethtool_cmis_get_max_payload_size(u8 num_of_byte_octs)
u32 ethtool_cmis_get_max_lpl_size(u8 num_of_byte_octs)
{
return 8 * (1 + min_t(u8, num_of_byte_octs, 15));
}
void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args *args,
enum ethtool_cmis_cdb_cmd_id cmd, u8 *pl,
u8 lpl_len, u16 max_duration,
u8 read_write_len_ext, u16 msleep_pre_rpl,
u8 rpl_exp_len, u8 flags)
enum ethtool_cmis_cdb_cmd_id cmd, u8 *lpl,
u8 lpl_len, u8 *epl, u16 epl_len,
u16 max_duration, u8 read_write_len_ext,
u16 msleep_pre_rpl, u8 rpl_exp_len, u8 flags)
{
args->req.id = cpu_to_be16(cmd);
args->req.lpl_len = lpl_len;
if (pl)
memcpy(args->req.payload, pl, args->req.lpl_len);
if (lpl)
memcpy(args->req.payload, lpl, args->req.lpl_len);
if (epl) {
args->req.epl_len = cpu_to_be16(epl_len);
args->req.epl = epl;
}
args->max_duration = max_duration;
args->read_write_len_ext =
ethtool_cmis_get_max_payload_size(read_write_len_ext);
ethtool_cmis_get_max_lpl_size(read_write_len_ext);
args->msleep_pre_rpl = msleep_pre_rpl;
args->rpl_exp_len = rpl_exp_len;
args->flags = flags;
@ -183,7 +187,7 @@ cmis_cdb_validate_password(struct ethtool_cmis_cdb *cdb,
}
ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_QUERY_STATUS,
(u8 *)&qs_pl, sizeof(qs_pl), 0,
(u8 *)&qs_pl, sizeof(qs_pl), NULL, 0, 0,
cdb->read_write_len_ext, 1000,
sizeof(*rpl),
CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
@ -245,8 +249,9 @@ static int cmis_cdb_module_features_get(struct ethtool_cmis_cdb *cdb,
ethtool_cmis_cdb_check_completion_flag(cdb->cmis_rev, &flags);
ethtool_cmis_cdb_compose_args(&args,
ETHTOOL_CMIS_CDB_CMD_MODULE_FEATURES,
NULL, 0, 0, cdb->read_write_len_ext,
1000, sizeof(*rpl), flags);
NULL, 0, NULL, 0, 0,
cdb->read_write_len_ext, 1000,
sizeof(*rpl), flags);
err = ethtool_cmis_cdb_execute_cmd(dev, &args);
if (err < 0) {
@ -346,7 +351,7 @@ ethtool_cmis_module_poll(struct net_device *dev,
struct netlink_ext_ack extack = {};
int err;
ethtool_cmis_page_init(&page_data, 0, offset, sizeof(rpl));
ethtool_cmis_page_init(&page_data, 0, offset, sizeof(*rpl));
page_data.data = (u8 *)rpl;
err = ops->get_module_eeprom_by_page(dev, &page_data, &extack);
@ -546,6 +551,49 @@ __ethtool_cmis_cdb_execute_cmd(struct net_device *dev,
return err;
}
#define CMIS_CDB_EPL_PAGE_START 0xA0
#define CMIS_CDB_EPL_PAGE_END 0xAF
#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_START 128
#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_END 255
static int
ethtool_cmis_cdb_execute_epl_cmd(struct net_device *dev,
struct ethtool_cmis_cdb_cmd_args *args,
struct ethtool_module_eeprom *page_data)
{
u16 epl_len = be16_to_cpu(args->req.epl_len);
u32 bytes_written = 0;
u8 page;
int err;
for (page = CMIS_CDB_EPL_PAGE_START;
page <= CMIS_CDB_EPL_PAGE_END && bytes_written < epl_len; page++) {
u16 offset = CMIS_CDB_EPL_FW_BLOCK_OFFSET_START;
while (offset <= CMIS_CDB_EPL_FW_BLOCK_OFFSET_END &&
bytes_written < epl_len) {
u32 bytes_left = epl_len - bytes_written;
u16 space_left, bytes_to_write;
space_left = CMIS_CDB_EPL_FW_BLOCK_OFFSET_END - offset + 1;
bytes_to_write = min_t(u16, bytes_left,
min_t(u16, space_left,
args->read_write_len_ext));
err = __ethtool_cmis_cdb_execute_cmd(dev, page_data,
page, offset,
bytes_to_write,
args->req.epl + bytes_written);
if (err < 0)
return err;
offset += bytes_to_write;
bytes_written += bytes_to_write;
}
}
return 0;
}
static u8 cmis_cdb_calc_checksum(const void *data, size_t size)
{
const u8 *bytes = (const u8 *)data;
@ -567,7 +615,9 @@ int ethtool_cmis_cdb_execute_cmd(struct net_device *dev,
int err;
args->req.chk_code =
cmis_cdb_calc_checksum(&args->req, sizeof(args->req));
cmis_cdb_calc_checksum(&args->req,
offsetof(struct ethtool_cmis_cdb_request,
epl));
if (args->req.lpl_len > args->read_write_len_ext) {
args->err_msg = "LPL length is longer than CDB read write length extension allows";
@ -589,6 +639,12 @@ int ethtool_cmis_cdb_execute_cmd(struct net_device *dev,
if (err < 0)
return err;
if (args->req.epl_len) {
err = ethtool_cmis_cdb_execute_epl_cmd(dev, args, &page_data);
if (err < 0)
return err;
}
offset = CMIS_CDB_CMD_ID_OFFSET +
offsetof(struct ethtool_cmis_cdb_request, id);
err = __ethtool_cmis_cdb_execute_cmd(dev, &page_data,

View File

@ -9,6 +9,7 @@
struct cmis_fw_update_fw_mng_features {
u8 start_cmd_payload_size;
u8 write_mechanism;
u16 max_duration_start;
u16 max_duration_write;
u16 max_duration_complete;
@ -36,7 +37,9 @@ struct cmis_cdb_fw_mng_features_rpl {
};
enum cmis_cdb_fw_write_mechanism {
CMIS_CDB_FW_WRITE_MECHANISM_NONE = 0x00,
CMIS_CDB_FW_WRITE_MECHANISM_LPL = 0x01,
CMIS_CDB_FW_WRITE_MECHANISM_EPL = 0x10,
CMIS_CDB_FW_WRITE_MECHANISM_BOTH = 0x11,
};
@ -54,7 +57,8 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
ethtool_cmis_cdb_check_completion_flag(cdb->cmis_rev, &flags);
ethtool_cmis_cdb_compose_args(&args,
ETHTOOL_CMIS_CDB_CMD_FW_MANAGMENT_FEATURES,
NULL, 0, cdb->max_completion_time,
NULL, 0, NULL, 0,
cdb->max_completion_time,
cdb->read_write_len_ext, 1000,
sizeof(*rpl), flags);
@ -67,10 +71,9 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
}
rpl = (struct cmis_cdb_fw_mng_features_rpl *)args.req.payload;
if (!(rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ||
rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_BOTH)) {
if (rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_NONE) {
ethnl_module_fw_flash_ntf_err(dev, ntf_params,
"Write LPL is not supported",
"CDB write mechanism is not supported",
NULL);
return -EOPNOTSUPP;
}
@ -82,6 +85,10 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
*/
cdb->read_write_len_ext = rpl->read_write_len_ext;
fw_mng->start_cmd_payload_size = rpl->start_cmd_payload_size;
fw_mng->write_mechanism =
rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ?
CMIS_CDB_FW_WRITE_MECHANISM_LPL :
CMIS_CDB_FW_WRITE_MECHANISM_EPL;
fw_mng->max_duration_start = be16_to_cpu(rpl->max_duration_start);
fw_mng->max_duration_write = be16_to_cpu(rpl->max_duration_write);
fw_mng->max_duration_complete = be16_to_cpu(rpl->max_duration_complete);
@ -122,7 +129,7 @@ cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb,
ethtool_cmis_cdb_compose_args(&args,
ETHTOOL_CMIS_CDB_CMD_START_FW_DOWNLOAD,
(u8 *)&pl, lpl_len,
(u8 *)&pl, lpl_len, NULL, 0,
fw_mng->max_duration_start,
cdb->read_write_len_ext, 1000, 0,
CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
@ -148,9 +155,9 @@ struct cmis_cdb_write_fw_block_lpl_pl {
};
static int
cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb,
struct ethtool_cmis_fw_update_params *fw_update,
struct cmis_fw_update_fw_mng_features *fw_mng)
cmis_fw_update_write_image_lpl(struct ethtool_cmis_cdb *cdb,
struct ethtool_cmis_fw_update_params *fw_update,
struct cmis_fw_update_fw_mng_features *fw_mng)
{
u8 start = fw_mng->start_cmd_payload_size;
u32 offset, max_block_size, max_lpl_len;
@ -158,7 +165,7 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb,
int err;
max_lpl_len = min_t(u32,
ethtool_cmis_get_max_payload_size(cdb->read_write_len_ext),
ethtool_cmis_get_max_lpl_size(cdb->read_write_len_ext),
ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH);
max_block_size =
max_lpl_len - sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl,
@ -183,7 +190,7 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb,
ethtool_cmis_cdb_compose_args(&args,
ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_LPL,
(u8 *)&pl, lpl_len,
(u8 *)&pl, lpl_len, NULL, 0,
fw_mng->max_duration_write,
cdb->read_write_len_ext, 1, 0,
CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
@ -201,6 +208,67 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb,
return 0;
}
struct cmis_cdb_write_fw_block_epl_pl {
u8 fw_block[ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH];
};
static int
cmis_fw_update_write_image_epl(struct ethtool_cmis_cdb *cdb,
struct ethtool_cmis_fw_update_params *fw_update,
struct cmis_fw_update_fw_mng_features *fw_mng)
{
u8 start = fw_mng->start_cmd_payload_size;
u32 image_size = fw_update->fw->size;
u32 offset, lpl_len;
int err;
lpl_len = sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl,
block_address);
for (offset = start; offset < image_size;
offset += ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH) {
struct cmis_cdb_write_fw_block_lpl_pl lpl = {
.block_address = cpu_to_be32(offset - start),
};
struct cmis_cdb_write_fw_block_epl_pl *epl;
struct ethtool_cmis_cdb_cmd_args args = {};
u32 epl_len;
ethnl_module_fw_flash_ntf_in_progress(fw_update->dev,
&fw_update->ntf_params,
offset - start,
image_size);
epl_len = min_t(u32, ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH,
image_size - offset);
epl = kmalloc_array(epl_len, sizeof(u8), GFP_KERNEL);
if (!epl)
return -ENOMEM;
memcpy(epl->fw_block, &fw_update->fw->data[offset], epl_len);
ethtool_cmis_cdb_compose_args(&args,
ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_EPL,
(u8 *)&lpl, lpl_len, (u8 *)epl,
epl_len,
fw_mng->max_duration_write,
cdb->read_write_len_ext, 1, 0,
CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
err = ethtool_cmis_cdb_execute_cmd(fw_update->dev, &args);
kfree(epl);
if (err < 0) {
ethnl_module_fw_flash_ntf_err(fw_update->dev,
&fw_update->ntf_params,
"Write FW block EPL command failed",
args.err_msg);
return err;
}
}
return 0;
}
static int
cmis_fw_update_complete_download(struct ethtool_cmis_cdb *cdb,
struct net_device *dev,
@ -212,7 +280,8 @@ cmis_fw_update_complete_download(struct ethtool_cmis_cdb *cdb,
ethtool_cmis_cdb_compose_args(&args,
ETHTOOL_CMIS_CDB_CMD_COMPLETE_FW_DOWNLOAD,
NULL, 0, fw_mng->max_duration_complete,
NULL, 0, NULL, 0,
fw_mng->max_duration_complete,
cdb->read_write_len_ext, 1000, 0,
CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
@ -236,9 +305,15 @@ cmis_fw_update_download_image(struct ethtool_cmis_cdb *cdb,
if (err < 0)
return err;
err = cmis_fw_update_write_image(cdb, fw_update, fw_mng);
if (err < 0)
return err;
if (fw_mng->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL) {
err = cmis_fw_update_write_image_lpl(cdb, fw_update, fw_mng);
if (err < 0)
return err;
} else {
err = cmis_fw_update_write_image_epl(cdb, fw_update, fw_mng);
if (err < 0)
return err;
}
err = cmis_fw_update_complete_download(cdb, fw_update->dev, fw_mng,
&fw_update->ntf_params);
@ -294,7 +369,7 @@ cmis_fw_update_run_image(struct ethtool_cmis_cdb *cdb, struct net_device *dev,
int err;
ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_RUN_FW_IMAGE,
(u8 *)&pl, sizeof(pl),
(u8 *)&pl, sizeof(pl), NULL, 0,
cdb->max_completion_time,
cdb->read_write_len_ext, 1000, 0,
CDB_F_MODULE_STATE_VALID);
@ -326,7 +401,8 @@ cmis_fw_update_commit_image(struct ethtool_cmis_cdb *cdb,
ethtool_cmis_cdb_compose_args(&args,
ETHTOOL_CMIS_CDB_CMD_COMMIT_FW_IMAGE,
NULL, 0, cdb->max_completion_time,
NULL, 0, NULL, 0,
cdb->max_completion_time,
cdb->read_write_len_ext, 1000, 0,
CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);

View File

@ -5,9 +5,13 @@
#include <linux/phy.h>
#include <linux/rtnetlink.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/phy_link_topology.h>
#include <net/netdev_queues.h>
#include "netlink.h"
#include "common.h"
#include "../core/dev.h"
const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
[NETIF_F_SG_BIT] = "tx-scatter-gather",
@ -210,6 +214,24 @@ const char link_mode_names[][ETH_GSTRING_LEN] = {
__DEFINE_LINK_MODE_NAME(10, T1S, Half),
__DEFINE_LINK_MODE_NAME(10, T1S_P2MP, Half),
__DEFINE_LINK_MODE_NAME(10, T1BRR, Full),
__DEFINE_LINK_MODE_NAME(200000, CR, Full),
__DEFINE_LINK_MODE_NAME(200000, KR, Full),
__DEFINE_LINK_MODE_NAME(200000, DR, Full),
__DEFINE_LINK_MODE_NAME(200000, DR_2, Full),
__DEFINE_LINK_MODE_NAME(200000, SR, Full),
__DEFINE_LINK_MODE_NAME(200000, VR, Full),
__DEFINE_LINK_MODE_NAME(400000, CR2, Full),
__DEFINE_LINK_MODE_NAME(400000, KR2, Full),
__DEFINE_LINK_MODE_NAME(400000, DR2, Full),
__DEFINE_LINK_MODE_NAME(400000, DR2_2, Full),
__DEFINE_LINK_MODE_NAME(400000, SR2, Full),
__DEFINE_LINK_MODE_NAME(400000, VR2, Full),
__DEFINE_LINK_MODE_NAME(800000, CR4, Full),
__DEFINE_LINK_MODE_NAME(800000, KR4, Full),
__DEFINE_LINK_MODE_NAME(800000, DR4, Full),
__DEFINE_LINK_MODE_NAME(800000, DR4_2, Full),
__DEFINE_LINK_MODE_NAME(800000, SR4, Full),
__DEFINE_LINK_MODE_NAME(800000, VR4, Full),
};
static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);
@ -218,8 +240,11 @@ static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);
#define __LINK_MODE_LANES_CR4 4
#define __LINK_MODE_LANES_CR8 8
#define __LINK_MODE_LANES_DR 1
#define __LINK_MODE_LANES_DR_2 1
#define __LINK_MODE_LANES_DR2 2
#define __LINK_MODE_LANES_DR2_2 2
#define __LINK_MODE_LANES_DR4 4
#define __LINK_MODE_LANES_DR4_2 4
#define __LINK_MODE_LANES_DR8 8
#define __LINK_MODE_LANES_KR 1
#define __LINK_MODE_LANES_KR2 2
@ -248,6 +273,9 @@ static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);
#define __LINK_MODE_LANES_T1L 1
#define __LINK_MODE_LANES_T1S 1
#define __LINK_MODE_LANES_T1S_P2MP 1
#define __LINK_MODE_LANES_VR 1
#define __LINK_MODE_LANES_VR2 2
#define __LINK_MODE_LANES_VR4 4
#define __LINK_MODE_LANES_VR8 8
#define __LINK_MODE_LANES_DR8_2 8
#define __LINK_MODE_LANES_T1BRR 1
@ -375,8 +403,27 @@ const struct link_mode_info link_mode_params[] = {
__DEFINE_LINK_MODE_PARAMS(10, T1S, Half),
__DEFINE_LINK_MODE_PARAMS(10, T1S_P2MP, Half),
__DEFINE_LINK_MODE_PARAMS(10, T1BRR, Full),
__DEFINE_LINK_MODE_PARAMS(200000, CR, Full),
__DEFINE_LINK_MODE_PARAMS(200000, KR, Full),
__DEFINE_LINK_MODE_PARAMS(200000, DR, Full),
__DEFINE_LINK_MODE_PARAMS(200000, DR_2, Full),
__DEFINE_LINK_MODE_PARAMS(200000, SR, Full),
__DEFINE_LINK_MODE_PARAMS(200000, VR, Full),
__DEFINE_LINK_MODE_PARAMS(400000, CR2, Full),
__DEFINE_LINK_MODE_PARAMS(400000, KR2, Full),
__DEFINE_LINK_MODE_PARAMS(400000, DR2, Full),
__DEFINE_LINK_MODE_PARAMS(400000, DR2_2, Full),
__DEFINE_LINK_MODE_PARAMS(400000, SR2, Full),
__DEFINE_LINK_MODE_PARAMS(400000, VR2, Full),
__DEFINE_LINK_MODE_PARAMS(800000, CR4, Full),
__DEFINE_LINK_MODE_PARAMS(800000, KR4, Full),
__DEFINE_LINK_MODE_PARAMS(800000, DR4, Full),
__DEFINE_LINK_MODE_PARAMS(800000, DR4_2, Full),
__DEFINE_LINK_MODE_PARAMS(800000, SR4, Full),
__DEFINE_LINK_MODE_PARAMS(800000, VR4, Full),
};
static_assert(ARRAY_SIZE(link_mode_params) == __ETHTOOL_LINK_MODE_MASK_NBITS);
EXPORT_SYMBOL_GPL(link_mode_params);
const char netif_msg_class_names[][ETH_GSTRING_LEN] = {
[NETIF_MSG_DRV_BIT] = "drv",
@ -427,6 +474,7 @@ const char sof_timestamping_names[][ETH_GSTRING_LEN] = {
[const_ilog2(SOF_TIMESTAMPING_OPT_TX_SWHW)] = "option-tx-swhw",
[const_ilog2(SOF_TIMESTAMPING_BIND_PHC)] = "bind-phc",
[const_ilog2(SOF_TIMESTAMPING_OPT_ID_TCP)] = "option-id-tcp",
[const_ilog2(SOF_TIMESTAMPING_OPT_RX_FILTER)] = "option-rx-filter",
};
static_assert(ARRAY_SIZE(sof_timestamping_names) == __SOF_TIMESTAMPING_CNT);
@ -458,6 +506,11 @@ const char ts_rx_filter_names[][ETH_GSTRING_LEN] = {
};
static_assert(ARRAY_SIZE(ts_rx_filter_names) == __HWTSTAMP_FILTER_CNT);
const char ts_flags_names[][ETH_GSTRING_LEN] = {
[const_ilog2(HWTSTAMP_FLAG_BONDED_PHC_INDEX)] = "bonded-phc-index",
};
static_assert(ARRAY_SIZE(ts_flags_names) == __HWTSTAMP_FLAG_CNT);
const char udp_tunnel_type_names[][ETH_GSTRING_LEN] = {
[ETHTOOL_UDP_TUNNEL_TYPE_VXLAN] = "vxlan",
[ETHTOOL_UDP_TUNNEL_TYPE_GENEVE] = "geneve",
@ -537,6 +590,20 @@ static int ethtool_get_rxnfc_rule_count(struct net_device *dev)
return info.rule_cnt;
}
/* Max offset for one RSS context */
static u32 ethtool_get_rss_ctx_max_channel(struct ethtool_rxfh_context *ctx)
{
u32 max_ring = 0;
u32 i, *tbl;
if (WARN_ON_ONCE(!ctx))
return 0;
tbl = ethtool_rxfh_context_indir(ctx);
for (i = 0; i < ctx->indir_size; i++)
max_ring = max(max_ring, tbl[i]);
return max_ring;
}
static int ethtool_get_max_rxnfc_channel(struct net_device *dev, u64 *max)
{
const struct ethtool_ops *ops = dev->ethtool_ops;
@ -573,10 +640,18 @@ static int ethtool_get_max_rxnfc_channel(struct net_device *dev, u64 *max)
if (rule_info.fs.ring_cookie != RX_CLS_FLOW_DISC &&
rule_info.fs.ring_cookie != RX_CLS_FLOW_WAKE &&
!(rule_info.flow_type & FLOW_RSS) &&
!ethtool_get_flow_spec_ring_vf(rule_info.fs.ring_cookie))
max_ring =
max_t(u64, max_ring, rule_info.fs.ring_cookie);
!ethtool_get_flow_spec_ring_vf(rule_info.fs.ring_cookie)) {
u64 ring = rule_info.fs.ring_cookie;
if (rule_info.flow_type & FLOW_RSS) {
struct ethtool_rxfh_context *ctx;
ctx = xa_load(&dev->ethtool->rss_ctx,
rule_info.rss_context);
ring += ethtool_get_rss_ctx_max_channel(ctx);
}
max_ring = max_t(u64, max_ring, ring);
}
}
kvfree(info);
@ -588,6 +663,7 @@ err_free_info:
return err;
}
/* Max offset across all of a device's RSS contexts */
static u32 ethtool_get_max_rss_ctx_channel(struct net_device *dev)
{
struct ethtool_rxfh_context *ctx;
@ -595,13 +671,8 @@ static u32 ethtool_get_max_rss_ctx_channel(struct net_device *dev)
u32 max_ring = 0;
mutex_lock(&dev->ethtool->rss_lock);
xa_for_each(&dev->ethtool->rss_ctx, context, ctx) {
u32 i, *tbl;
tbl = ethtool_rxfh_context_indir(ctx);
for (i = 0; i < ctx->indir_size; i++)
max_ring = max(max_ring, tbl[i]);
}
xa_for_each(&dev->ethtool->rss_ctx, context, ctx)
max_ring = max(max_ring, ethtool_get_rss_ctx_max_channel(ctx));
mutex_unlock(&dev->ethtool->rss_lock);
return max_ring;
@ -610,7 +681,7 @@ static u32 ethtool_get_max_rss_ctx_channel(struct net_device *dev)
static u32 ethtool_get_max_rxfh_channel(struct net_device *dev)
{
struct ethtool_rxfh_param rxfh = {};
u32 dev_size, current_max;
u32 dev_size, current_max = 0;
int ret;
/* While we do track whether RSS context has an indirection
@ -675,6 +746,54 @@ int ethtool_check_max_channel(struct net_device *dev,
return 0;
}
int ethtool_check_rss_ctx_busy(struct net_device *dev, u32 rss_context)
{
const struct ethtool_ops *ops = dev->ethtool_ops;
struct ethtool_rxnfc *info;
int rc, i, rule_cnt;
if (!ops->get_rxnfc)
return 0;
rule_cnt = ethtool_get_rxnfc_rule_count(dev);
if (!rule_cnt)
return 0;
if (rule_cnt < 0)
return -EINVAL;
info = kvzalloc(struct_size(info, rule_locs, rule_cnt), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->cmd = ETHTOOL_GRXCLSRLALL;
info->rule_cnt = rule_cnt;
rc = ops->get_rxnfc(dev, info, info->rule_locs);
if (rc)
goto out_free;
for (i = 0; i < rule_cnt; i++) {
struct ethtool_rxnfc rule_info = {
.cmd = ETHTOOL_GRXCLSRULE,
.fs.location = info->rule_locs[i],
};
rc = ops->get_rxnfc(dev, &rule_info, NULL);
if (rc)
goto out_free;
if (rule_info.fs.flow_type & FLOW_RSS &&
rule_info.rss_context == rss_context) {
rc = -EBUSY;
goto out_free;
}
}
out_free:
kvfree(info);
return rc;
}
int ethtool_check_ops(const struct ethtool_ops *ops)
{
if (WARN_ON(ops->set_coalesce && !ops->supported_coalesce_params))
@ -688,20 +807,114 @@ int ethtool_check_ops(const struct ethtool_ops *ops)
return 0;
}
int __ethtool_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info)
void ethtool_ringparam_get_cfg(struct net_device *dev,
struct ethtool_ringparam *param,
struct kernel_ethtool_ringparam *kparam,
struct netlink_ext_ack *extack)
{
const struct ethtool_ops *ops = dev->ethtool_ops;
struct phy_device *phydev = dev->phydev;
int err = 0;
memset(param, 0, sizeof(*param));
memset(kparam, 0, sizeof(*kparam));
param->cmd = ETHTOOL_GRINGPARAM;
dev->ethtool_ops->get_ringparam(dev, param, kparam, extack);
/* Driver gives us current state, we want to return current config */
kparam->tcp_data_split = dev->cfg->hds_config;
kparam->hds_thresh = dev->cfg->hds_thresh;
}
static void ethtool_init_tsinfo(struct kernel_ethtool_ts_info *info)
{
memset(info, 0, sizeof(*info));
info->cmd = ETHTOOL_GET_TS_INFO;
info->phc_index = -1;
}
if (phy_is_default_hwtstamp(phydev) && phy_has_tsinfo(phydev))
err = phy_ts_info(phydev, info);
else if (ops->get_ts_info)
err = ops->get_ts_info(dev, info);
int ethtool_net_get_ts_info_by_phc(struct net_device *dev,
struct kernel_ethtool_ts_info *info,
struct hwtstamp_provider_desc *hwprov_desc)
{
const struct ethtool_ops *ops = dev->ethtool_ops;
int err;
if (!ops->get_ts_info)
return -ENODEV;
/* Does ptp comes from netdev */
ethtool_init_tsinfo(info);
info->phc_qualifier = hwprov_desc->qualifier;
err = ops->get_ts_info(dev, info);
if (err)
return err;
if (info->phc_index == hwprov_desc->index &&
net_support_hwtstamp_qualifier(dev, hwprov_desc->qualifier))
return 0;
return -ENODEV;
}
struct phy_device *
ethtool_phy_get_ts_info_by_phc(struct net_device *dev,
struct kernel_ethtool_ts_info *info,
struct hwtstamp_provider_desc *hwprov_desc)
{
int err;
/* Only precise qualifier is supported in phydev */
if (hwprov_desc->qualifier != HWTSTAMP_PROVIDER_QUALIFIER_PRECISE)
return ERR_PTR(-ENODEV);
/* Look in the phy topology */
if (dev->link_topo) {
struct phy_device_node *pdn;
unsigned long phy_index;
xa_for_each(&dev->link_topo->phys, phy_index, pdn) {
if (!phy_has_tsinfo(pdn->phy))
continue;
ethtool_init_tsinfo(info);
err = phy_ts_info(pdn->phy, info);
if (err)
return ERR_PTR(err);
if (info->phc_index == hwprov_desc->index)
return pdn->phy;
}
return ERR_PTR(-ENODEV);
}
/* Look on the dev->phydev */
if (phy_has_tsinfo(dev->phydev)) {
ethtool_init_tsinfo(info);
err = phy_ts_info(dev->phydev, info);
if (err)
return ERR_PTR(err);
if (info->phc_index == hwprov_desc->index)
return dev->phydev;
}
return ERR_PTR(-ENODEV);
}
int ethtool_get_ts_info_by_phc(struct net_device *dev,
struct kernel_ethtool_ts_info *info,
struct hwtstamp_provider_desc *hwprov_desc)
{
int err;
err = ethtool_net_get_ts_info_by_phc(dev, info, hwprov_desc);
if (err == -ENODEV) {
struct phy_device *phy;
phy = ethtool_phy_get_ts_info_by_phc(dev, info, hwprov_desc);
if (IS_ERR(phy))
err = PTR_ERR(phy);
else
err = 0;
}
info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_SOFTWARE;
@ -709,6 +922,59 @@ int __ethtool_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info
return err;
}
int __ethtool_get_ts_info(struct net_device *dev,
struct kernel_ethtool_ts_info *info)
{
struct hwtstamp_provider *hwprov;
int err = 0;
rcu_read_lock();
hwprov = rcu_dereference(dev->hwprov);
/* No provider specified, use default behavior */
if (!hwprov) {
const struct ethtool_ops *ops = dev->ethtool_ops;
struct phy_device *phydev = dev->phydev;
ethtool_init_tsinfo(info);
if (phy_is_default_hwtstamp(phydev) &&
phy_has_tsinfo(phydev))
err = phy_ts_info(phydev, info);
else if (ops->get_ts_info)
err = ops->get_ts_info(dev, info);
info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_SOFTWARE;
rcu_read_unlock();
return err;
}
err = ethtool_get_ts_info_by_phc(dev, info, &hwprov->desc);
rcu_read_unlock();
return err;
}
bool net_support_hwtstamp_qualifier(struct net_device *dev,
enum hwtstamp_provider_qualifier qualifier)
{
const struct ethtool_ops *ops = dev->ethtool_ops;
if (!ops)
return false;
/* Return true with precise qualifier and with NIC without
* qualifier description to not break the old behavior.
*/
if (!ops->supported_hwtstamp_qualifiers &&
qualifier == HWTSTAMP_PROVIDER_QUALIFIER_PRECISE)
return true;
if (ops->supported_hwtstamp_qualifiers & BIT(qualifier))
return true;
return false;
}
int ethtool_get_phc_vclocks(struct net_device *dev, int **vclock_index)
{
struct kernel_ethtool_ts_info info = { };

View File

@ -13,14 +13,10 @@
ETHTOOL_LINK_MODE_ ## speed ## base ## type ## _ ## duplex ## _BIT
#define __SOF_TIMESTAMPING_CNT (const_ilog2(SOF_TIMESTAMPING_LAST) + 1)
struct link_mode_info {
int speed;
u8 lanes;
u8 duplex;
};
#define __HWTSTAMP_FLAG_CNT (const_ilog2(HWTSTAMP_FLAG_LAST) + 1)
struct genl_info;
struct hwtstamp_provider_desc;
extern const char
netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN];
@ -31,12 +27,12 @@ tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN];
extern const char
phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
extern const char link_mode_names[][ETH_GSTRING_LEN];
extern const struct link_mode_info link_mode_params[];
extern const char netif_msg_class_names[][ETH_GSTRING_LEN];
extern const char wol_mode_names[][ETH_GSTRING_LEN];
extern const char sof_timestamping_names[][ETH_GSTRING_LEN];
extern const char ts_tx_type_names[][ETH_GSTRING_LEN];
extern const char ts_rx_filter_names[][ETH_GSTRING_LEN];
extern const char ts_flags_names[][ETH_GSTRING_LEN];
extern const char udp_tunnel_type_names[][ETH_GSTRING_LEN];
int __ethtool_get_link(struct net_device *dev);
@ -47,7 +43,26 @@ bool convert_legacy_settings_to_link_ksettings(
int ethtool_check_max_channel(struct net_device *dev,
struct ethtool_channels channels,
struct genl_info *info);
int ethtool_check_rss_ctx_busy(struct net_device *dev, u32 rss_context);
void ethtool_ringparam_get_cfg(struct net_device *dev,
struct ethtool_ringparam *param,
struct kernel_ethtool_ringparam *kparam,
struct netlink_ext_ack *extack);
int __ethtool_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info);
int ethtool_get_ts_info_by_phc(struct net_device *dev,
struct kernel_ethtool_ts_info *info,
struct hwtstamp_provider_desc *hwprov_desc);
int ethtool_net_get_ts_info_by_phc(struct net_device *dev,
struct kernel_ethtool_ts_info *info,
struct hwtstamp_provider_desc *hwprov_desc);
struct phy_device *
ethtool_phy_get_ts_info_by_phc(struct net_device *dev,
struct kernel_ethtool_ts_info *info,
struct hwtstamp_provider_desc *hwprov_desc);
bool net_support_hwtstamp_qualifier(struct net_device *dev,
enum hwtstamp_provider_qualifier qualifier);
extern const struct ethtool_phy_ops *ethtool_phy_ops;
extern const struct ethtool_pse_ops *ethtool_pse_ops;

View File

@ -992,18 +992,31 @@ static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
if (rc)
return rc;
if (ops->get_rxfh) {
if (cmd == ETHTOOL_SRXCLSRLINS && info.fs.flow_type & FLOW_RSS) {
/* Nonzero ring with RSS only makes sense
* if NIC adds them together
*/
if (!ops->cap_rss_rxnfc_adds &&
ethtool_get_flow_spec_ring(info.fs.ring_cookie))
return -EINVAL;
if (info.rss_context &&
!xa_load(&dev->ethtool->rss_ctx, info.rss_context))
return -EINVAL;
}
if (cmd == ETHTOOL_SRXFH && ops->get_rxfh) {
struct ethtool_rxfh_param rxfh = {};
rc = ops->get_rxfh(dev, &rxfh);
if (rc)
return rc;
/* Sanity check: if symmetric-xor is set, then:
/* Sanity check: if symmetric-xor/symmetric-or-xor is set, then:
* 1 - no other fields besides IP src/dst and/or L4 src/dst
* 2 - If src is set, dst must also be set
*/
if ((rxfh.input_xfrm & RXH_XFRM_SYM_XOR) &&
if ((rxfh.input_xfrm & (RXH_XFRM_SYM_XOR | RXH_XFRM_SYM_OR_XOR)) &&
((info.data & ~(RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3)) ||
(!!(info.data & RXH_IP_SRC) ^ !!(info.data & RXH_IP_DST)) ||
@ -1376,11 +1389,11 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
return -EOPNOTSUPP;
/* Check input data transformation capabilities */
if (rxfh.input_xfrm && rxfh.input_xfrm != RXH_XFRM_SYM_XOR &&
rxfh.input_xfrm != RXH_XFRM_SYM_OR_XOR &&
rxfh.input_xfrm != RXH_XFRM_NO_CHANGE)
return -EINVAL;
if (rxfh.input_xfrm != RXH_XFRM_NO_CHANGE &&
(rxfh.input_xfrm & RXH_XFRM_SYM_XOR) &&
!ops->cap_rss_sym_xor_supported)
rxfh.input_xfrm & ~ops->supported_input_xfrm)
return -EOPNOTSUPP;
create = rxfh.rss_context == ETH_RXFH_CONTEXT_ALLOC;
@ -1462,6 +1475,13 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
mutex_lock(&dev->ethtool->rss_lock);
locked = true;
}
if (rxfh.rss_context && rxfh_dev.rss_delete) {
ret = ethtool_check_rss_ctx_busy(dev, rxfh.rss_context);
if (ret)
goto out;
}
if (create) {
if (rxfh_dev.rss_delete) {
ret = -EINVAL;
@ -1505,6 +1525,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
extack);
/* Make sure driver populates defaults */
WARN_ON_ONCE(!ret && !rxfh_dev.key &&
ops->rxfh_per_ctx_key &&
!memchr_inv(ethtool_rxfh_context_key(ctx),
0, ctx->key_size));
} else if (rxfh_dev.rss_delete) {
@ -2045,8 +2066,8 @@ static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
{
struct ethtool_ringparam ringparam, max = { .cmd = ETHTOOL_GRINGPARAM };
struct kernel_ethtool_ringparam kernel_ringparam;
struct ethtool_ringparam ringparam, max;
int ret;
if (!dev->ethtool_ops->set_ringparam || !dev->ethtool_ops->get_ringparam)
@ -2055,7 +2076,7 @@ static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
return -EFAULT;
dev->ethtool_ops->get_ringparam(dev, &max, &kernel_ringparam, NULL);
ethtool_ringparam_get_cfg(dev, &max, &kernel_ringparam, NULL);
/* ensure new ring parameters are within the maximums */
if (ringparam.rx_pending > max.rx_max_pending ||

View File

@ -3,6 +3,7 @@
#include "netlink.h"
#include "common.h"
#include <linux/phy.h>
#include <linux/phylib_stubs.h>
struct linkstate_req_info {
struct ethnl_req_info base;
@ -26,9 +27,8 @@ const struct nla_policy ethnl_linkstate_get_policy[] = {
NLA_POLICY_NESTED(ethnl_header_policy_stats),
};
static int linkstate_get_sqi(struct net_device *dev)
static int linkstate_get_sqi(struct phy_device *phydev)
{
struct phy_device *phydev = dev->phydev;
int ret;
if (!phydev)
@ -46,9 +46,8 @@ static int linkstate_get_sqi(struct net_device *dev)
return ret;
}
static int linkstate_get_sqi_max(struct net_device *dev)
static int linkstate_get_sqi_max(struct phy_device *phydev)
{
struct phy_device *phydev = dev->phydev;
int ret;
if (!phydev)
@ -100,19 +99,28 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
{
struct linkstate_reply_data *data = LINKSTATE_REPDATA(reply_base);
struct net_device *dev = reply_base->dev;
struct nlattr **tb = info->attrs;
struct phy_device *phydev;
int ret;
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_LINKSTATE_HEADER,
info->extack);
if (IS_ERR(phydev)) {
ret = PTR_ERR(phydev);
goto out;
}
ret = ethnl_ops_begin(dev);
if (ret < 0)
return ret;
data->link = __ethtool_get_link(dev);
ret = linkstate_get_sqi(dev);
ret = linkstate_get_sqi(phydev);
if (linkstate_sqi_critical_error(ret))
goto out;
data->sqi = ret;
ret = linkstate_get_sqi_max(dev);
ret = linkstate_get_sqi_max(phydev);
if (linkstate_sqi_critical_error(ret))
goto out;
data->sqi_max = ret;
@ -127,9 +135,9 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
sizeof(data->link_stats) / 8);
if (req_base->flags & ETHTOOL_FLAG_STATS) {
if (dev->phydev)
data->link_stats.link_down_events =
READ_ONCE(dev->phydev->link_down_events);
if (phydev)
phy_ethtool_get_link_ext_stats(phydev,
&data->link_stats);
if (dev->ethtool_ops->get_link_ext_stats)
dev->ethtool_ops->get_link_ext_stats(dev,

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <net/netdev_queues.h>
#include <net/sock.h>
#include <linux/ethtool_netlink.h>
#include <linux/phy_link_topology.h>
@ -90,7 +91,7 @@ int ethnl_ops_begin(struct net_device *dev)
pm_runtime_get_sync(dev->dev.parent);
if (!netif_device_present(dev) ||
dev->reg_state == NETREG_UNREGISTERING) {
dev->reg_state >= NETREG_UNREGISTERING) {
ret = -ENODEV;
goto err;
}
@ -210,7 +211,7 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info,
}
struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
const struct nlattr *header,
struct nlattr **tb, unsigned int header,
struct netlink_ext_ack *extack)
{
struct phy_device *phydev;
@ -224,8 +225,8 @@ struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
return req_info->dev->phydev;
phydev = phy_link_topo_get_phy(req_info->dev, req_info->phy_index);
if (!phydev) {
NL_SET_ERR_MSG_ATTR(extack, header,
if (!phydev && tb) {
NL_SET_ERR_MSG_ATTR(extack, tb[header],
"no phy matching phyindex");
return ERR_PTR(-ENODEV);
}
@ -394,6 +395,8 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
[ETHTOOL_MSG_PLCA_GET_STATUS] = &ethnl_plca_status_request_ops,
[ETHTOOL_MSG_MM_GET] = &ethnl_mm_request_ops,
[ETHTOOL_MSG_MM_SET] = &ethnl_mm_request_ops,
[ETHTOOL_MSG_TSCONFIG_GET] = &ethnl_tsconfig_request_ops,
[ETHTOOL_MSG_TSCONFIG_SET] = &ethnl_tsconfig_request_ops,
};
static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
@ -490,7 +493,7 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info)
ret = ops->prepare_data(req_info, reply_data, info);
rtnl_unlock();
if (ret < 0)
goto err_cleanup;
goto err_dev;
ret = ops->reply_size(req_info, reply_data);
if (ret < 0)
goto err_cleanup;
@ -548,7 +551,7 @@ static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,
ret = ctx->ops->prepare_data(ctx->req_info, ctx->reply_data, info);
rtnl_unlock();
if (ret < 0)
goto out;
goto out_cancel;
ret = ethnl_fill_reply_header(skb, dev, ctx->ops->hdr_attr);
if (ret < 0)
goto out;
@ -557,6 +560,7 @@ static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,
out:
if (ctx->ops->cleanup_data)
ctx->ops->cleanup_data(ctx->reply_data);
out_cancel:
ctx->reply_data->dev = NULL;
if (ret < 0)
genlmsg_cancel(skb, ehdr);
@ -665,6 +669,7 @@ static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)
const struct ethnl_request_ops *ops;
struct ethnl_req_info req_info = {};
const u8 cmd = info->genlhdr->cmd;
struct net_device *dev;
int ret;
ops = ethnl_default_requests[cmd];
@ -686,20 +691,36 @@ static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)
goto out_dev;
}
dev = req_info.dev;
rtnl_lock();
ret = ethnl_ops_begin(req_info.dev);
dev->cfg_pending = kmemdup(dev->cfg, sizeof(*dev->cfg),
GFP_KERNEL_ACCOUNT);
if (!dev->cfg_pending) {
ret = -ENOMEM;
goto out_tie_cfg;
}
ret = ethnl_ops_begin(dev);
if (ret < 0)
goto out_rtnl;
goto out_free_cfg;
ret = ops->set(&req_info, info);
if (ret <= 0)
if (ret < 0)
goto out_ops;
ethtool_notify(req_info.dev, ops->set_ntf_cmd, NULL);
swap(dev->cfg, dev->cfg_pending);
if (!ret)
goto out_ops;
ethtool_notify(dev, ops->set_ntf_cmd, NULL);
ret = 0;
out_ops:
ethnl_ops_complete(req_info.dev);
out_rtnl:
ethnl_ops_complete(dev);
out_free_cfg:
kfree(dev->cfg_pending);
out_tie_cfg:
dev->cfg_pending = dev->cfg;
rtnl_unlock();
out_dev:
ethnl_parse_header_dev_put(&req_info);
@ -760,7 +781,7 @@ static void ethnl_default_notify(struct net_device *dev, unsigned int cmd,
ethnl_init_reply_data(reply_data, ops, dev);
ret = ops->prepare_data(req_info, reply_data, &info);
if (ret < 0)
goto err_cleanup;
goto err_rep;
ret = ops->reply_size(req_info, reply_data);
if (ret < 0)
goto err_cleanup;
@ -795,6 +816,7 @@ err_skb:
err_cleanup:
if (ops->cleanup_data)
ops->cleanup_data(reply_data);
err_rep:
kfree(reply_data);
kfree(req_info);
return;
@ -1074,9 +1096,9 @@ static const struct genl_ops ethtool_genl_ops[] = {
{
.cmd = ETHTOOL_MSG_TSINFO_GET,
.doit = ethnl_default_doit,
.start = ethnl_default_start,
.dumpit = ethnl_default_dumpit,
.done = ethnl_default_done,
.start = ethnl_tsinfo_start,
.dumpit = ethnl_tsinfo_dumpit,
.done = ethnl_tsinfo_done,
.policy = ethnl_tsinfo_get_policy,
.maxattr = ARRAY_SIZE(ethnl_tsinfo_get_policy) - 1,
},
@ -1243,6 +1265,22 @@ static const struct genl_ops ethtool_genl_ops[] = {
.policy = ethnl_phy_get_policy,
.maxattr = ARRAY_SIZE(ethnl_phy_get_policy) - 1,
},
{
.cmd = ETHTOOL_MSG_TSCONFIG_GET,
.doit = ethnl_default_doit,
.start = ethnl_default_start,
.dumpit = ethnl_default_dumpit,
.done = ethnl_default_done,
.policy = ethnl_tsconfig_get_policy,
.maxattr = ARRAY_SIZE(ethnl_tsconfig_get_policy) - 1,
},
{
.cmd = ETHTOOL_MSG_TSCONFIG_SET,
.flags = GENL_UNS_ADMIN_PERM,
.doit = ethnl_default_set_doit,
.policy = ethnl_tsconfig_set_policy,
.maxattr = ARRAY_SIZE(ethnl_tsconfig_set_policy) - 1,
},
};
static const struct genl_multicast_group ethtool_nl_mcgrps[] = {

View File

@ -275,7 +275,8 @@ static inline void ethnl_parse_header_dev_put(struct ethnl_req_info *req_info)
* ethnl_req_get_phydev() - Gets the phy_device targeted by this request,
* if any. Must be called under rntl_lock().
* @req_info: The ethnl request to get the phy from.
* @header: The netlink header, used for error reporting.
* @tb: The netlink attributes array, for error reporting.
* @header: The netlink header index, used for error reporting.
* @extack: The netlink extended ACK, for error reporting.
*
* The caller must hold RTNL, until it's done interacting with the returned
@ -289,7 +290,7 @@ static inline void ethnl_parse_header_dev_put(struct ethnl_req_info *req_info)
* is returned.
*/
struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
const struct nlattr *header,
struct nlattr **tb, unsigned int header,
struct netlink_ext_ack *extack);
/**
@ -435,6 +436,7 @@ extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops;
extern const struct ethnl_request_ops ethnl_plca_status_request_ops;
extern const struct ethnl_request_ops ethnl_mm_request_ops;
extern const struct ethnl_request_ops ethnl_phy_request_ops;
extern const struct ethnl_request_ops ethnl_tsconfig_request_ops;
extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1];
extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1];
@ -455,7 +457,7 @@ extern const struct nla_policy ethnl_features_set_policy[ETHTOOL_A_FEATURES_WANT
extern const struct nla_policy ethnl_privflags_get_policy[ETHTOOL_A_PRIVFLAGS_HEADER + 1];
extern const struct nla_policy ethnl_privflags_set_policy[ETHTOOL_A_PRIVFLAGS_FLAGS + 1];
extern const struct nla_policy ethnl_rings_get_policy[ETHTOOL_A_RINGS_HEADER + 1];
extern const struct nla_policy ethnl_rings_set_policy[ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX + 1];
extern const struct nla_policy ethnl_rings_set_policy[ETHTOOL_A_RINGS_HDS_THRESH_MAX + 1];
extern const struct nla_policy ethnl_channels_get_policy[ETHTOOL_A_CHANNELS_HEADER + 1];
extern const struct nla_policy ethnl_channels_set_policy[ETHTOOL_A_CHANNELS_COMBINED_COUNT + 1];
extern const struct nla_policy ethnl_coalesce_get_policy[ETHTOOL_A_COALESCE_HEADER + 1];
@ -464,7 +466,7 @@ extern const struct nla_policy ethnl_pause_get_policy[ETHTOOL_A_PAUSE_STATS_SRC
extern const struct nla_policy ethnl_pause_set_policy[ETHTOOL_A_PAUSE_TX + 1];
extern const struct nla_policy ethnl_eee_get_policy[ETHTOOL_A_EEE_HEADER + 1];
extern const struct nla_policy ethnl_eee_set_policy[ETHTOOL_A_EEE_TX_LPI_TIMER + 1];
extern const struct nla_policy ethnl_tsinfo_get_policy[ETHTOOL_A_TSINFO_HEADER + 1];
extern const struct nla_policy ethnl_tsinfo_get_policy[ETHTOOL_A_TSINFO_MAX + 1];
extern const struct nla_policy ethnl_cable_test_act_policy[ETHTOOL_A_CABLE_TEST_HEADER + 1];
extern const struct nla_policy ethnl_cable_test_tdr_act_policy[ETHTOOL_A_CABLE_TEST_TDR_CFG + 1];
extern const struct nla_policy ethnl_tunnel_info_get_policy[ETHTOOL_A_TUNNEL_INFO_HEADER + 1];
@ -485,6 +487,8 @@ extern const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1];
extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1];
extern const struct nla_policy ethnl_module_fw_flash_act_policy[ETHTOOL_A_MODULE_FW_FLASH_PASSWORD + 1];
extern const struct nla_policy ethnl_phy_get_policy[ETHTOOL_A_PHY_HEADER + 1];
extern const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFIG_HEADER + 1];
extern const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFIG_MAX + 1];
int ethnl_set_features(struct sk_buff *skb, struct genl_info *info);
int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info);
@ -499,11 +503,15 @@ int ethnl_phy_start(struct netlink_callback *cb);
int ethnl_phy_doit(struct sk_buff *skb, struct genl_info *info);
int ethnl_phy_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
int ethnl_phy_done(struct netlink_callback *cb);
int ethnl_tsinfo_start(struct netlink_callback *cb);
int ethnl_tsinfo_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
int ethnl_tsinfo_done(struct netlink_callback *cb);
extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN];
extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN];
extern const char stats_eth_mac_names[__ETHTOOL_A_STATS_ETH_MAC_CNT][ETH_GSTRING_LEN];
extern const char stats_eth_ctrl_names[__ETHTOOL_A_STATS_ETH_CTRL_CNT][ETH_GSTRING_LEN];
extern const char stats_rmon_names[__ETHTOOL_A_STATS_RMON_CNT][ETH_GSTRING_LEN];
extern const char stats_phy_names[__ETHTOOL_A_STATS_PHY_CNT][ETH_GSTRING_LEN];
#endif /* _NET_ETHTOOL_NETLINK_H */

View File

@ -125,7 +125,7 @@ static int ethnl_phy_parse_request(struct ethnl_req_info *req_base,
struct phy_req_info *req_info = PHY_REQINFO(req_base);
struct phy_device *phydev;
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PHY_HEADER],
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PHY_HEADER,
extack);
if (!phydev)
return 0;

View File

@ -62,7 +62,7 @@ static int plca_get_cfg_prepare_data(const struct ethnl_req_info *req_base,
struct phy_device *phydev;
int ret;
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PLCA_HEADER],
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PLCA_HEADER,
info->extack);
// check that the PHY device is available and connected
if (IS_ERR_OR_NULL(phydev)) {
@ -152,7 +152,7 @@ ethnl_set_plca(struct ethnl_req_info *req_info, struct genl_info *info)
bool mod = false;
int ret;
phydev = ethnl_req_get_phydev(req_info, tb[ETHTOOL_A_PLCA_HEADER],
phydev = ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PLCA_HEADER,
info->extack);
// check that the PHY device is available and connected
if (IS_ERR_OR_NULL(phydev))
@ -211,7 +211,7 @@ static int plca_get_status_prepare_data(const struct ethnl_req_info *req_base,
struct phy_device *phydev;
int ret;
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PLCA_HEADER],
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PLCA_HEADER,
info->extack);
// check that the PHY device is available and connected
if (IS_ERR_OR_NULL(phydev)) {

View File

@ -64,7 +64,7 @@ static int pse_prepare_data(const struct ethnl_req_info *req_base,
if (ret < 0)
return ret;
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PSE_HEADER],
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PSE_HEADER,
info->extack);
if (IS_ERR(phydev))
return -ENODEV;
@ -261,7 +261,7 @@ ethnl_set_pse(struct ethnl_req_info *req_info, struct genl_info *info)
struct phy_device *phydev;
int ret;
phydev = ethnl_req_get_phydev(req_info, tb[ETHTOOL_A_PSE_HEADER],
phydev = ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PSE_HEADER,
info->extack);
ret = ethnl_set_pse_validate(phydev, info);
if (ret)

View File

@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <net/netdev_queues.h>
#include "netlink.h"
#include "common.h"
@ -37,6 +39,10 @@ static int rings_prepare_data(const struct ethnl_req_info *req_base,
ret = ethnl_ops_begin(dev);
if (ret < 0)
return ret;
data->kernel_ringparam.tcp_data_split = dev->cfg->hds_config;
data->kernel_ringparam.hds_thresh = dev->cfg->hds_thresh;
dev->ethtool_ops->get_ringparam(dev, &data->ringparam,
&data->kernel_ringparam, info->extack);
ethnl_ops_complete(dev);
@ -61,7 +67,9 @@ static int rings_reply_size(const struct ethnl_req_info *req_base,
nla_total_size(sizeof(u8)) + /* _RINGS_TX_PUSH */
nla_total_size(sizeof(u8))) + /* _RINGS_RX_PUSH */
nla_total_size(sizeof(u32)) + /* _RINGS_TX_PUSH_BUF_LEN */
nla_total_size(sizeof(u32)); /* _RINGS_TX_PUSH_BUF_LEN_MAX */
nla_total_size(sizeof(u32)) + /* _RINGS_TX_PUSH_BUF_LEN_MAX */
nla_total_size(sizeof(u32)) + /* _RINGS_HDS_THRESH */
nla_total_size(sizeof(u32)); /* _RINGS_HDS_THRESH_MAX*/
}
static int rings_fill_reply(struct sk_buff *skb,
@ -108,7 +116,12 @@ static int rings_fill_reply(struct sk_buff *skb,
(nla_put_u32(skb, ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX,
kr->tx_push_buf_max_len) ||
nla_put_u32(skb, ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN,
kr->tx_push_buf_len))))
kr->tx_push_buf_len))) ||
((supported_ring_params & ETHTOOL_RING_USE_HDS_THRS) &&
(nla_put_u32(skb, ETHTOOL_A_RINGS_HDS_THRESH,
kr->hds_thresh) ||
nla_put_u32(skb, ETHTOOL_A_RINGS_HDS_THRESH_MAX,
kr->hds_thresh_max))))
return -EMSGSIZE;
return 0;
@ -130,6 +143,7 @@ const struct nla_policy ethnl_rings_set_policy[] = {
[ETHTOOL_A_RINGS_TX_PUSH] = NLA_POLICY_MAX(NLA_U8, 1),
[ETHTOOL_A_RINGS_RX_PUSH] = NLA_POLICY_MAX(NLA_U8, 1),
[ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN] = { .type = NLA_U32 },
[ETHTOOL_A_RINGS_HDS_THRESH] = { .type = NLA_U32 },
};
static int
@ -155,6 +169,14 @@ ethnl_set_rings_validate(struct ethnl_req_info *req_info,
return -EOPNOTSUPP;
}
if (tb[ETHTOOL_A_RINGS_HDS_THRESH] &&
!(ops->supported_ring_params & ETHTOOL_RING_USE_HDS_THRS)) {
NL_SET_ERR_MSG_ATTR(info->extack,
tb[ETHTOOL_A_RINGS_HDS_THRESH],
"setting hds-thresh is not supported");
return -EOPNOTSUPP;
}
if (tb[ETHTOOL_A_RINGS_CQE_SIZE] &&
!(ops->supported_ring_params & ETHTOOL_RING_USE_CQE_SIZE)) {
NL_SET_ERR_MSG_ATTR(info->extack,
@ -193,16 +215,16 @@ ethnl_set_rings_validate(struct ethnl_req_info *req_info,
static int
ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
{
struct kernel_ethtool_ringparam kernel_ringparam = {};
struct ethtool_ringparam ringparam = {};
struct kernel_ethtool_ringparam kernel_ringparam;
struct net_device *dev = req_info->dev;
struct ethtool_ringparam ringparam;
struct nlattr **tb = info->attrs;
const struct nlattr *err_attr;
bool mod = false;
int ret;
dev->ethtool_ops->get_ringparam(dev, &ringparam,
&kernel_ringparam, info->extack);
ethtool_ringparam_get_cfg(dev, &ringparam, &kernel_ringparam,
info->extack);
ethnl_update_u32(&ringparam.rx_pending, tb[ETHTOOL_A_RINGS_RX], &mod);
ethnl_update_u32(&ringparam.rx_mini_pending,
@ -222,9 +244,19 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
tb[ETHTOOL_A_RINGS_RX_PUSH], &mod);
ethnl_update_u32(&kernel_ringparam.tx_push_buf_len,
tb[ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN], &mod);
ethnl_update_u32(&kernel_ringparam.hds_thresh,
tb[ETHTOOL_A_RINGS_HDS_THRESH], &mod);
if (!mod)
return 0;
if (kernel_ringparam.tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_ENABLED &&
dev_xdp_sb_prog_count(dev)) {
NL_SET_ERR_MSG_ATTR(info->extack,
tb[ETHTOOL_A_RINGS_TCP_DATA_SPLIT],
"tcp-data-split can not be enabled with single buffer XDP");
return -EINVAL;
}
/* ensure new ring parameters are within limits */
if (ringparam.rx_pending > ringparam.rx_max_pending)
err_attr = tb[ETHTOOL_A_RINGS_RX];
@ -234,6 +266,8 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
err_attr = tb[ETHTOOL_A_RINGS_RX_JUMBO];
else if (ringparam.tx_pending > ringparam.tx_max_pending)
err_attr = tb[ETHTOOL_A_RINGS_TX];
else if (kernel_ringparam.hds_thresh > kernel_ringparam.hds_thresh_max)
err_attr = tb[ETHTOOL_A_RINGS_HDS_THRESH];
else
err_attr = NULL;
if (err_attr) {
@ -250,6 +284,9 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
return -EINVAL;
}
dev->cfg_pending->hds_config = kernel_ringparam.tcp_data_split;
dev->cfg_pending->hds_thresh = kernel_ringparam.hds_thresh;
ret = dev->ethtool_ops->set_ringparam(dev, &ringparam,
&kernel_ringparam, info->extack);
return ret < 0 ? ret : 1;

View File

@ -107,6 +107,8 @@ rss_prepare_ctx(const struct rss_req_info *request, struct net_device *dev,
u32 total_size, indir_bytes;
u8 *rss_config;
data->no_key_fields = !dev->ethtool_ops->rxfh_per_ctx_key;
ctx = xa_load(&dev->ethtool->rss_ctx, request->rss_context);
if (!ctx)
return -ENOENT;
@ -153,7 +155,6 @@ rss_prepare_data(const struct ethnl_req_info *req_base,
if (!ops->cap_rss_ctx_supported && !ops->create_rxfh_context)
return -EOPNOTSUPP;
data->no_key_fields = !ops->rxfh_per_ctx_key;
return rss_prepare_ctx(request, dev, data, info);
}

View File

@ -1,5 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/phy.h>
#include <linux/phylib_stubs.h>
#include "netlink.h"
#include "common.h"
#include "bitset.h"
@ -20,6 +23,7 @@ struct stats_reply_data {
struct ethtool_eth_mac_stats mac_stats;
struct ethtool_eth_ctrl_stats ctrl_stats;
struct ethtool_rmon_stats rmon_stats;
struct ethtool_phy_stats phydev_stats;
);
const struct ethtool_rmon_hist_range *rmon_ranges;
};
@ -32,6 +36,7 @@ const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN] = {
[ETHTOOL_STATS_ETH_MAC] = "eth-mac",
[ETHTOOL_STATS_ETH_CTRL] = "eth-ctrl",
[ETHTOOL_STATS_RMON] = "rmon",
[ETHTOOL_STATS_PHY] = "phydev",
};
const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN] = {
@ -76,6 +81,15 @@ const char stats_rmon_names[__ETHTOOL_A_STATS_RMON_CNT][ETH_GSTRING_LEN] = {
[ETHTOOL_A_STATS_RMON_JABBER] = "etherStatsJabbers",
};
const char stats_phy_names[__ETHTOOL_A_STATS_PHY_CNT][ETH_GSTRING_LEN] = {
[ETHTOOL_A_STATS_PHY_RX_PKTS] = "RxFrames",
[ETHTOOL_A_STATS_PHY_RX_BYTES] = "RxOctets",
[ETHTOOL_A_STATS_PHY_RX_ERRORS] = "RxErrors",
[ETHTOOL_A_STATS_PHY_TX_PKTS] = "TxFrames",
[ETHTOOL_A_STATS_PHY_TX_BYTES] = "TxOctets",
[ETHTOOL_A_STATS_PHY_TX_ERRORS] = "TxErrors",
};
const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_SRC + 1] = {
[ETHTOOL_A_STATS_HEADER] =
NLA_POLICY_NESTED(ethnl_header_policy),
@ -120,8 +134,15 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
struct stats_reply_data *data = STATS_REPDATA(reply_base);
enum ethtool_mac_stats_src src = req_info->src;
struct net_device *dev = reply_base->dev;
struct nlattr **tb = info->attrs;
struct phy_device *phydev;
int ret;
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_STATS_HEADER,
info->extack);
if (IS_ERR(phydev))
return PTR_ERR(phydev);
ret = ethnl_ops_begin(dev);
if (ret < 0)
return ret;
@ -145,6 +166,14 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
data->ctrl_stats.src = src;
data->rmon_stats.src = src;
if ((test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask) ||
test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask)) &&
src == ETHTOOL_MAC_STATS_SRC_AGGREGATE) {
if (phydev)
phy_ethtool_get_phy_stats(phydev, &data->phy_stats,
&data->phydev_stats);
}
if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) &&
dev->ethtool_ops->get_eth_phy_stats)
dev->ethtool_ops->get_eth_phy_stats(dev, &data->phy_stats);
@ -194,6 +223,10 @@ static int stats_reply_size(const struct ethnl_req_info *req_base,
nla_total_size(4)) * /* _A_STATS_GRP_HIST_BKT_HI */
ETHTOOL_RMON_HIST_MAX * 2;
}
if (test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask)) {
n_stats += sizeof(struct ethtool_phy_stats) / sizeof(u64);
n_grps++;
}
len += n_grps * (nla_total_size(0) + /* _A_STATS_GRP */
nla_total_size(4) + /* _A_STATS_GRP_ID */
@ -247,6 +280,25 @@ static int stats_put_phy_stats(struct sk_buff *skb,
return 0;
}
static int stats_put_phydev_stats(struct sk_buff *skb,
const struct stats_reply_data *data)
{
if (stat_put(skb, ETHTOOL_A_STATS_PHY_RX_PKTS,
data->phydev_stats.rx_packets) ||
stat_put(skb, ETHTOOL_A_STATS_PHY_RX_BYTES,
data->phydev_stats.rx_bytes) ||
stat_put(skb, ETHTOOL_A_STATS_PHY_RX_ERRORS,
data->phydev_stats.rx_errors) ||
stat_put(skb, ETHTOOL_A_STATS_PHY_TX_PKTS,
data->phydev_stats.tx_packets) ||
stat_put(skb, ETHTOOL_A_STATS_PHY_TX_BYTES,
data->phydev_stats.tx_bytes) ||
stat_put(skb, ETHTOOL_A_STATS_PHY_TX_ERRORS,
data->phydev_stats.tx_errors))
return -EMSGSIZE;
return 0;
}
static int stats_put_mac_stats(struct sk_buff *skb,
const struct stats_reply_data *data)
{
@ -423,6 +475,9 @@ static int stats_fill_reply(struct sk_buff *skb,
if (!ret && test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask))
ret = stats_put_stats(skb, data, ETHTOOL_STATS_RMON,
ETH_SS_STATS_RMON, stats_put_rmon_stats);
if (!ret && test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask))
ret = stats_put_stats(skb, data, ETHTOOL_STATS_PHY,
ETH_SS_STATS_PHY, stats_put_phydev_stats);
return ret;
}

View File

@ -75,6 +75,11 @@ static const struct strset_info info_template[] = {
.count = __HWTSTAMP_FILTER_CNT,
.strings = ts_rx_filter_names,
},
[ETH_SS_TS_FLAGS] = {
.per_dev = false,
.count = __HWTSTAMP_FLAG_CNT,
.strings = ts_flags_names,
},
[ETH_SS_UDP_TUNNEL_TYPES] = {
.per_dev = false,
.count = __ETHTOOL_UDP_TUNNEL_TYPE_CNT,
@ -105,6 +110,11 @@ static const struct strset_info info_template[] = {
.count = __ETHTOOL_A_STATS_RMON_CNT,
.strings = stats_rmon_names,
},
[ETH_SS_STATS_PHY] = {
.per_dev = false,
.count = __ETHTOOL_A_STATS_PHY_CNT,
.strings = stats_phy_names,
},
};
struct strset_req_info {
@ -299,7 +309,7 @@ static int strset_prepare_data(const struct ethnl_req_info *req_base,
return 0;
}
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_HEADER_FLAGS],
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_HEADER_FLAGS,
info->extack);
/* phydev can be NULL, check for errors only */

20
net/ethtool/ts.h Normal file
View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _NET_ETHTOOL_TS_H
#define _NET_ETHTOOL_TS_H
#include "netlink.h"
static const struct nla_policy
ethnl_ts_hwtst_prov_policy[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_MAX + 1] = {
[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX] = { .type = NLA_U32 },
[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER] =
NLA_POLICY_MAX(NLA_U32, HWTSTAMP_PROVIDER_QUALIFIER_CNT - 1)
};
int ts_parse_hwtst_provider(const struct nlattr *nest,
struct hwtstamp_provider_desc *hwprov_desc,
struct netlink_ext_ack *extack,
bool *mod);
#endif /* _NET_ETHTOOL_TS_H */

457
net/ethtool/tsconfig.c Normal file
View File

@ -0,0 +1,457 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
#include "netlink.h"
#include "common.h"
#include "bitset.h"
#include "../core/dev.h"
#include "ts.h"
struct tsconfig_req_info {
struct ethnl_req_info base;
};
struct tsconfig_reply_data {
struct ethnl_reply_data base;
struct hwtstamp_provider_desc hwprov_desc;
struct {
u32 tx_type;
u32 rx_filter;
u32 flags;
} hwtst_config;
};
#define TSCONFIG_REPDATA(__reply_base) \
container_of(__reply_base, struct tsconfig_reply_data, base)
const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFIG_HEADER + 1] = {
[ETHTOOL_A_TSCONFIG_HEADER] =
NLA_POLICY_NESTED(ethnl_header_policy),
};
static int tsconfig_prepare_data(const struct ethnl_req_info *req_base,
struct ethnl_reply_data *reply_base,
const struct genl_info *info)
{
struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base);
struct hwtstamp_provider *hwprov = NULL;
struct net_device *dev = reply_base->dev;
struct kernel_hwtstamp_config cfg = {};
int ret;
if (!dev->netdev_ops->ndo_hwtstamp_get)
return -EOPNOTSUPP;
ret = ethnl_ops_begin(dev);
if (ret < 0)
return ret;
ret = dev_get_hwtstamp_phylib(dev, &cfg);
if (ret)
goto out;
data->hwtst_config.tx_type = BIT(cfg.tx_type);
data->hwtst_config.rx_filter = BIT(cfg.rx_filter);
data->hwtst_config.flags = cfg.flags;
data->hwprov_desc.index = -1;
hwprov = rtnl_dereference(dev->hwprov);
if (hwprov) {
data->hwprov_desc.index = hwprov->desc.index;
data->hwprov_desc.qualifier = hwprov->desc.qualifier;
} else {
struct kernel_ethtool_ts_info ts_info = {};
ts_info.phc_index = -1;
ret = __ethtool_get_ts_info(dev, &ts_info);
if (ret)
goto out;
if (ts_info.phc_index == -1)
return -ENODEV;
data->hwprov_desc.index = ts_info.phc_index;
data->hwprov_desc.qualifier = ts_info.phc_qualifier;
}
out:
ethnl_ops_complete(dev);
return ret;
}
static int tsconfig_reply_size(const struct ethnl_req_info *req_base,
const struct ethnl_reply_data *reply_base)
{
const struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base);
bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
int len = 0;
int ret;
BUILD_BUG_ON(__HWTSTAMP_TX_CNT > 32);
BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT > 32);
BUILD_BUG_ON(__HWTSTAMP_FLAG_CNT > 32);
if (data->hwtst_config.flags) {
ret = ethnl_bitset32_size(&data->hwtst_config.flags,
NULL, __HWTSTAMP_FLAG_CNT,
ts_flags_names, compact);
if (ret < 0)
return ret;
len += ret; /* _TSCONFIG_HWTSTAMP_FLAGS */
}
if (data->hwtst_config.tx_type) {
ret = ethnl_bitset32_size(&data->hwtst_config.tx_type,
NULL, __HWTSTAMP_TX_CNT,
ts_tx_type_names, compact);
if (ret < 0)
return ret;
len += ret; /* _TSCONFIG_TX_TYPES */
}
if (data->hwtst_config.rx_filter) {
ret = ethnl_bitset32_size(&data->hwtst_config.rx_filter,
NULL, __HWTSTAMP_FILTER_CNT,
ts_rx_filter_names, compact);
if (ret < 0)
return ret;
len += ret; /* _TSCONFIG_RX_FILTERS */
}
if (data->hwprov_desc.index >= 0)
/* _TSCONFIG_HWTSTAMP_PROVIDER */
len += nla_total_size(0) +
2 * nla_total_size(sizeof(u32));
return len;
}
static int tsconfig_fill_reply(struct sk_buff *skb,
const struct ethnl_req_info *req_base,
const struct ethnl_reply_data *reply_base)
{
const struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base);
bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
int ret;
if (data->hwtst_config.flags) {
ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS,
&data->hwtst_config.flags, NULL,
__HWTSTAMP_FLAG_CNT,
ts_flags_names, compact);
if (ret < 0)
return ret;
}
if (data->hwtst_config.tx_type) {
ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSCONFIG_TX_TYPES,
&data->hwtst_config.tx_type, NULL,
__HWTSTAMP_TX_CNT,
ts_tx_type_names, compact);
if (ret < 0)
return ret;
}
if (data->hwtst_config.rx_filter) {
ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSCONFIG_RX_FILTERS,
&data->hwtst_config.rx_filter,
NULL, __HWTSTAMP_FILTER_CNT,
ts_rx_filter_names, compact);
if (ret < 0)
return ret;
}
if (data->hwprov_desc.index >= 0) {
struct nlattr *nest;
nest = nla_nest_start(skb, ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER);
if (!nest)
return -EMSGSIZE;
if (nla_put_u32(skb, ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX,
data->hwprov_desc.index) ||
nla_put_u32(skb,
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER,
data->hwprov_desc.qualifier)) {
nla_nest_cancel(skb, nest);
return -EMSGSIZE;
}
nla_nest_end(skb, nest);
}
return 0;
}
/* TSCONFIG_SET */
const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFIG_MAX + 1] = {
[ETHTOOL_A_TSCONFIG_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER] =
NLA_POLICY_NESTED(ethnl_ts_hwtst_prov_policy),
[ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS] = { .type = NLA_NESTED },
[ETHTOOL_A_TSCONFIG_RX_FILTERS] = { .type = NLA_NESTED },
[ETHTOOL_A_TSCONFIG_TX_TYPES] = { .type = NLA_NESTED },
};
static int tsconfig_send_reply(struct net_device *dev, struct genl_info *info)
{
struct tsconfig_reply_data *reply_data;
struct tsconfig_req_info *req_info;
struct sk_buff *rskb;
void *reply_payload;
int reply_len = 0;
int ret;
req_info = kzalloc(sizeof(*req_info), GFP_KERNEL);
if (!req_info)
return -ENOMEM;
reply_data = kmalloc(sizeof(*reply_data), GFP_KERNEL);
if (!reply_data) {
kfree(req_info);
return -ENOMEM;
}
ASSERT_RTNL();
reply_data->base.dev = dev;
ret = tsconfig_prepare_data(&req_info->base, &reply_data->base, info);
if (ret < 0)
goto err_cleanup;
ret = tsconfig_reply_size(&req_info->base, &reply_data->base);
if (ret < 0)
goto err_cleanup;
reply_len = ret + ethnl_reply_header_size();
rskb = ethnl_reply_init(reply_len, dev, ETHTOOL_MSG_TSCONFIG_SET_REPLY,
ETHTOOL_A_TSCONFIG_HEADER, info, &reply_payload);
if (!rskb)
goto err_cleanup;
ret = tsconfig_fill_reply(rskb, &req_info->base, &reply_data->base);
if (ret < 0)
goto err_cleanup;
genlmsg_end(rskb, reply_payload);
ret = genlmsg_reply(rskb, info);
err_cleanup:
kfree(reply_data);
kfree(req_info);
return ret;
}
static int ethnl_set_tsconfig_validate(struct ethnl_req_info *req_base,
struct genl_info *info)
{
const struct net_device_ops *ops = req_base->dev->netdev_ops;
if (!ops->ndo_hwtstamp_set || !ops->ndo_hwtstamp_get)
return -EOPNOTSUPP;
return 1;
}
static struct hwtstamp_provider *
tsconfig_set_hwprov_from_desc(struct net_device *dev,
struct genl_info *info,
struct hwtstamp_provider_desc *hwprov_desc)
{
struct kernel_ethtool_ts_info ts_info;
struct hwtstamp_provider *hwprov;
struct nlattr **tb = info->attrs;
struct phy_device *phy = NULL;
enum hwtstamp_source source;
int ret;
ret = ethtool_net_get_ts_info_by_phc(dev, &ts_info, hwprov_desc);
if (!ret) {
/* Found */
source = HWTSTAMP_SOURCE_NETDEV;
} else {
phy = ethtool_phy_get_ts_info_by_phc(dev, &ts_info, hwprov_desc);
if (IS_ERR(phy)) {
if (PTR_ERR(phy) == -ENODEV)
NL_SET_ERR_MSG_ATTR(info->extack,
tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER],
"phc not in this net device topology");
return ERR_CAST(phy);
}
source = HWTSTAMP_SOURCE_PHYLIB;
}
hwprov = kzalloc(sizeof(*hwprov), GFP_KERNEL);
if (!hwprov)
return ERR_PTR(-ENOMEM);
hwprov->desc.index = hwprov_desc->index;
hwprov->desc.qualifier = hwprov_desc->qualifier;
hwprov->source = source;
hwprov->phydev = phy;
return hwprov;
}
static int ethnl_set_tsconfig(struct ethnl_req_info *req_base,
struct genl_info *info)
{
struct kernel_hwtstamp_config hwtst_config = {0};
bool hwprov_mod = false, config_mod = false;
struct hwtstamp_provider *hwprov = NULL;
struct net_device *dev = req_base->dev;
struct nlattr **tb = info->attrs;
int ret;
BUILD_BUG_ON(__HWTSTAMP_TX_CNT >= 32);
BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT >= 32);
BUILD_BUG_ON(__HWTSTAMP_FLAG_CNT > 32);
if (!netif_device_present(dev))
return -ENODEV;
if (tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER]) {
struct hwtstamp_provider_desc __hwprov_desc = {.index = -1};
struct hwtstamp_provider *__hwprov;
__hwprov = rtnl_dereference(dev->hwprov);
if (__hwprov) {
__hwprov_desc.index = __hwprov->desc.index;
__hwprov_desc.qualifier = __hwprov->desc.qualifier;
}
ret = ts_parse_hwtst_provider(tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER],
&__hwprov_desc, info->extack,
&hwprov_mod);
if (ret < 0)
return ret;
if (hwprov_mod) {
hwprov = tsconfig_set_hwprov_from_desc(dev, info,
&__hwprov_desc);
if (IS_ERR(hwprov))
return PTR_ERR(hwprov);
}
}
/* Get current hwtstamp config if we are not changing the
* hwtstamp source. It will be zeroed in the other case.
*/
if (!hwprov_mod) {
ret = dev_get_hwtstamp_phylib(dev, &hwtst_config);
if (ret < 0 && ret != -EOPNOTSUPP)
goto err_free_hwprov;
}
/* Get the hwtstamp config from netlink */
if (tb[ETHTOOL_A_TSCONFIG_TX_TYPES]) {
u32 req_tx_type;
req_tx_type = BIT(hwtst_config.tx_type);
ret = ethnl_update_bitset32(&req_tx_type,
__HWTSTAMP_TX_CNT,
tb[ETHTOOL_A_TSCONFIG_TX_TYPES],
ts_tx_type_names, info->extack,
&config_mod);
if (ret < 0)
goto err_free_hwprov;
/* Select only one tx type at a time */
if (ffs(req_tx_type) != fls(req_tx_type)) {
ret = -EINVAL;
goto err_free_hwprov;
}
hwtst_config.tx_type = ffs(req_tx_type) - 1;
}
if (tb[ETHTOOL_A_TSCONFIG_RX_FILTERS]) {
u32 req_rx_filter;
req_rx_filter = BIT(hwtst_config.rx_filter);
ret = ethnl_update_bitset32(&req_rx_filter,
__HWTSTAMP_FILTER_CNT,
tb[ETHTOOL_A_TSCONFIG_RX_FILTERS],
ts_rx_filter_names, info->extack,
&config_mod);
if (ret < 0)
goto err_free_hwprov;
/* Select only one rx filter at a time */
if (ffs(req_rx_filter) != fls(req_rx_filter)) {
ret = -EINVAL;
goto err_free_hwprov;
}
hwtst_config.rx_filter = ffs(req_rx_filter) - 1;
}
if (tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS]) {
ret = ethnl_update_bitset32(&hwtst_config.flags,
__HWTSTAMP_FLAG_CNT,
tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS],
ts_flags_names, info->extack,
&config_mod);
if (ret < 0)
goto err_free_hwprov;
}
ret = net_hwtstamp_validate(&hwtst_config);
if (ret)
goto err_free_hwprov;
if (hwprov_mod) {
struct kernel_hwtstamp_config zero_config = {0};
struct hwtstamp_provider *__hwprov;
/* Disable current time stamping if we try to enable
* another one
*/
ret = dev_set_hwtstamp_phylib(dev, &zero_config, info->extack);
if (ret < 0)
goto err_free_hwprov;
/* Change the selected hwtstamp source */
__hwprov = rcu_replace_pointer_rtnl(dev->hwprov, hwprov);
if (__hwprov)
kfree_rcu(__hwprov, rcu_head);
}
if (config_mod) {
ret = dev_set_hwtstamp_phylib(dev, &hwtst_config,
info->extack);
if (ret < 0)
return ret;
}
if (hwprov_mod || config_mod) {
ret = tsconfig_send_reply(dev, info);
if (ret && ret != -EOPNOTSUPP) {
NL_SET_ERR_MSG(info->extack,
"error while reading the new configuration set");
return ret;
}
}
/* tsconfig has no notification */
return 0;
err_free_hwprov:
kfree(hwprov);
return ret;
}
const struct ethnl_request_ops ethnl_tsconfig_request_ops = {
.request_cmd = ETHTOOL_MSG_TSCONFIG_GET,
.reply_cmd = ETHTOOL_MSG_TSCONFIG_GET_REPLY,
.hdr_attr = ETHTOOL_A_TSCONFIG_HEADER,
.req_info_size = sizeof(struct tsconfig_req_info),
.reply_data_size = sizeof(struct tsconfig_reply_data),
.prepare_data = tsconfig_prepare_data,
.reply_size = tsconfig_reply_size,
.fill_reply = tsconfig_fill_reply,
.set_validate = ethnl_set_tsconfig_validate,
.set = ethnl_set_tsconfig,
};

View File

@ -1,13 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/net_tstamp.h>
#include <linux/phy.h>
#include <linux/phy_link_topology.h>
#include <linux/ptp_clock_kernel.h>
#include "netlink.h"
#include "common.h"
#include "bitset.h"
#include "ts.h"
struct tsinfo_req_info {
struct ethnl_req_info base;
struct hwtstamp_provider_desc hwprov_desc;
};
struct tsinfo_reply_data {
@ -16,34 +21,96 @@ struct tsinfo_reply_data {
struct ethtool_ts_stats stats;
};
#define TSINFO_REQINFO(__req_base) \
container_of(__req_base, struct tsinfo_req_info, base)
#define TSINFO_REPDATA(__reply_base) \
container_of(__reply_base, struct tsinfo_reply_data, base)
#define ETHTOOL_TS_STAT_CNT \
(__ETHTOOL_A_TS_STAT_CNT - (ETHTOOL_A_TS_STAT_UNSPEC + 1))
const struct nla_policy ethnl_tsinfo_get_policy[] = {
const struct nla_policy ethnl_tsinfo_get_policy[ETHTOOL_A_TSINFO_MAX + 1] = {
[ETHTOOL_A_TSINFO_HEADER] =
NLA_POLICY_NESTED(ethnl_header_policy_stats),
[ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER] =
NLA_POLICY_NESTED(ethnl_ts_hwtst_prov_policy),
};
int ts_parse_hwtst_provider(const struct nlattr *nest,
struct hwtstamp_provider_desc *hwprov_desc,
struct netlink_ext_ack *extack,
bool *mod)
{
struct nlattr *tb[ARRAY_SIZE(ethnl_ts_hwtst_prov_policy)];
int ret;
ret = nla_parse_nested(tb,
ARRAY_SIZE(ethnl_ts_hwtst_prov_policy) - 1,
nest,
ethnl_ts_hwtst_prov_policy, extack);
if (ret < 0)
return ret;
if (NL_REQ_ATTR_CHECK(extack, nest, tb,
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX) ||
NL_REQ_ATTR_CHECK(extack, nest, tb,
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER))
return -EINVAL;
ethnl_update_u32(&hwprov_desc->index,
tb[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX],
mod);
ethnl_update_u32(&hwprov_desc->qualifier,
tb[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER],
mod);
return 0;
}
static int
tsinfo_parse_request(struct ethnl_req_info *req_base, struct nlattr **tb,
struct netlink_ext_ack *extack)
{
struct tsinfo_req_info *req = TSINFO_REQINFO(req_base);
bool mod = false;
req->hwprov_desc.index = -1;
if (!tb[ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER])
return 0;
return ts_parse_hwtst_provider(tb[ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER],
&req->hwprov_desc, extack, &mod);
}
static int tsinfo_prepare_data(const struct ethnl_req_info *req_base,
struct ethnl_reply_data *reply_base,
const struct genl_info *info)
{
struct tsinfo_reply_data *data = TSINFO_REPDATA(reply_base);
struct tsinfo_req_info *req = TSINFO_REQINFO(req_base);
struct net_device *dev = reply_base->dev;
int ret;
ret = ethnl_ops_begin(dev);
if (ret < 0)
return ret;
if (req->hwprov_desc.index != -1) {
ret = ethtool_get_ts_info_by_phc(dev, &data->ts_info,
&req->hwprov_desc);
ethnl_ops_complete(dev);
return ret;
}
if (req_base->flags & ETHTOOL_FLAG_STATS) {
ethtool_stats_init((u64 *)&data->stats,
sizeof(data->stats) / sizeof(u64));
if (dev->ethtool_ops->get_ts_stats)
dev->ethtool_ops->get_ts_stats(dev, &data->stats);
}
ret = __ethtool_get_ts_info(dev, &data->ts_info);
ethnl_ops_complete(dev);
@ -87,8 +154,11 @@ static int tsinfo_reply_size(const struct ethnl_req_info *req_base,
return ret;
len += ret; /* _TSINFO_RX_FILTERS */
}
if (ts_info->phc_index >= 0)
if (ts_info->phc_index >= 0) {
len += nla_total_size(sizeof(u32)); /* _TSINFO_PHC_INDEX */
/* _TSINFO_HWTSTAMP_PROVIDER */
len += nla_total_size(0) + 2 * nla_total_size(sizeof(u32));
}
if (req_base->flags & ETHTOOL_FLAG_STATS)
len += nla_total_size(0) + /* _TSINFO_STATS */
nla_total_size_64bit(sizeof(u64)) * ETHTOOL_TS_STAT_CNT;
@ -116,6 +186,8 @@ static int tsinfo_put_stats(struct sk_buff *skb,
if (tsinfo_put_stat(skb, stats->tx_stats.pkts,
ETHTOOL_A_TS_STAT_TX_PKTS) ||
tsinfo_put_stat(skb, stats->tx_stats.onestep_pkts_unconfirmed,
ETHTOOL_A_TS_STAT_TX_ONESTEP_PKTS_UNCONFIRMED) ||
tsinfo_put_stat(skb, stats->tx_stats.lost,
ETHTOOL_A_TS_STAT_TX_LOST) ||
tsinfo_put_stat(skb, stats->tx_stats.err,
@ -163,9 +235,29 @@ static int tsinfo_fill_reply(struct sk_buff *skb,
if (ret < 0)
return ret;
}
if (ts_info->phc_index >= 0 &&
nla_put_u32(skb, ETHTOOL_A_TSINFO_PHC_INDEX, ts_info->phc_index))
return -EMSGSIZE;
if (ts_info->phc_index >= 0) {
struct nlattr *nest;
ret = nla_put_u32(skb, ETHTOOL_A_TSINFO_PHC_INDEX,
ts_info->phc_index);
if (ret)
return -EMSGSIZE;
nest = nla_nest_start(skb, ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER);
if (!nest)
return -EMSGSIZE;
if (nla_put_u32(skb, ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX,
ts_info->phc_index) ||
nla_put_u32(skb,
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER,
ts_info->phc_qualifier)) {
nla_nest_cancel(skb, nest);
return -EMSGSIZE;
}
nla_nest_end(skb, nest);
}
if (req_base->flags & ETHTOOL_FLAG_STATS &&
tsinfo_put_stats(skb, &data->stats))
return -EMSGSIZE;
@ -173,6 +265,264 @@ static int tsinfo_fill_reply(struct sk_buff *skb,
return 0;
}
struct ethnl_tsinfo_dump_ctx {
struct tsinfo_req_info *req_info;
struct tsinfo_reply_data *reply_data;
unsigned long pos_ifindex;
bool netdev_dump_done;
unsigned long pos_phyindex;
enum hwtstamp_provider_qualifier pos_phcqualifier;
};
static void *ethnl_tsinfo_prepare_dump(struct sk_buff *skb,
struct net_device *dev,
struct tsinfo_reply_data *reply_data,
struct netlink_callback *cb)
{
struct ethnl_tsinfo_dump_ctx *ctx = (void *)cb->ctx;
void *ehdr = NULL;
ehdr = ethnl_dump_put(skb, cb,
ETHTOOL_MSG_TSINFO_GET_REPLY);
if (!ehdr)
return ERR_PTR(-EMSGSIZE);
reply_data = ctx->reply_data;
memset(reply_data, 0, sizeof(*reply_data));
reply_data->base.dev = dev;
reply_data->ts_info.cmd = ETHTOOL_GET_TS_INFO;
reply_data->ts_info.phc_index = -1;
return ehdr;
}
static int ethnl_tsinfo_end_dump(struct sk_buff *skb,
struct net_device *dev,
struct tsinfo_req_info *req_info,
struct tsinfo_reply_data *reply_data,
void *ehdr)
{
int ret;
reply_data->ts_info.so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_SOFTWARE;
ret = ethnl_fill_reply_header(skb, dev, ETHTOOL_A_TSINFO_HEADER);
if (ret < 0)
return ret;
ret = tsinfo_fill_reply(skb, &req_info->base, &reply_data->base);
if (ret < 0)
return ret;
reply_data->base.dev = NULL;
genlmsg_end(skb, ehdr);
return ret;
}
static int ethnl_tsinfo_dump_one_phydev(struct sk_buff *skb,
struct net_device *dev,
struct phy_device *phydev,
struct netlink_callback *cb)
{
struct ethnl_tsinfo_dump_ctx *ctx = (void *)cb->ctx;
struct tsinfo_reply_data *reply_data;
struct tsinfo_req_info *req_info;
void *ehdr = NULL;
int ret = 0;
if (!phy_has_tsinfo(phydev))
return -EOPNOTSUPP;
reply_data = ctx->reply_data;
req_info = ctx->req_info;
ehdr = ethnl_tsinfo_prepare_dump(skb, dev, reply_data, cb);
if (IS_ERR(ehdr))
return PTR_ERR(ehdr);
ret = phy_ts_info(phydev, &reply_data->ts_info);
if (ret < 0)
goto err;
ret = ethnl_tsinfo_end_dump(skb, dev, req_info, reply_data, ehdr);
if (ret < 0)
goto err;
return ret;
err:
genlmsg_cancel(skb, ehdr);
return ret;
}
static int ethnl_tsinfo_dump_one_netdev(struct sk_buff *skb,
struct net_device *dev,
struct netlink_callback *cb)
{
struct ethnl_tsinfo_dump_ctx *ctx = (void *)cb->ctx;
const struct ethtool_ops *ops = dev->ethtool_ops;
struct tsinfo_reply_data *reply_data;
struct tsinfo_req_info *req_info;
void *ehdr = NULL;
int ret = 0;
if (!ops->get_ts_info)
return -EOPNOTSUPP;
reply_data = ctx->reply_data;
req_info = ctx->req_info;
for (; ctx->pos_phcqualifier < HWTSTAMP_PROVIDER_QUALIFIER_CNT;
ctx->pos_phcqualifier++) {
if (!net_support_hwtstamp_qualifier(dev,
ctx->pos_phcqualifier))
continue;
ehdr = ethnl_tsinfo_prepare_dump(skb, dev, reply_data, cb);
if (IS_ERR(ehdr)) {
ret = PTR_ERR(ehdr);
goto err;
}
reply_data->ts_info.phc_qualifier = ctx->pos_phcqualifier;
ret = ops->get_ts_info(dev, &reply_data->ts_info);
if (ret < 0)
goto err;
ret = ethnl_tsinfo_end_dump(skb, dev, req_info, reply_data,
ehdr);
if (ret < 0)
goto err;
}
return ret;
err:
genlmsg_cancel(skb, ehdr);
return ret;
}
static int ethnl_tsinfo_dump_one_net_topo(struct sk_buff *skb,
struct net_device *dev,
struct netlink_callback *cb)
{
struct ethnl_tsinfo_dump_ctx *ctx = (void *)cb->ctx;
struct phy_device_node *pdn;
int ret = 0;
if (!ctx->netdev_dump_done) {
ret = ethnl_tsinfo_dump_one_netdev(skb, dev, cb);
if (ret < 0 && ret != -EOPNOTSUPP)
return ret;
ctx->netdev_dump_done = true;
}
if (!dev->link_topo) {
if (phy_has_tsinfo(dev->phydev)) {
ret = ethnl_tsinfo_dump_one_phydev(skb, dev,
dev->phydev, cb);
if (ret < 0 && ret != -EOPNOTSUPP)
return ret;
}
return 0;
}
xa_for_each_start(&dev->link_topo->phys, ctx->pos_phyindex, pdn,
ctx->pos_phyindex) {
if (phy_has_tsinfo(pdn->phy)) {
ret = ethnl_tsinfo_dump_one_phydev(skb, dev,
pdn->phy, cb);
if (ret < 0 && ret != -EOPNOTSUPP)
return ret;
}
}
return ret;
}
int ethnl_tsinfo_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
{
struct ethnl_tsinfo_dump_ctx *ctx = (void *)cb->ctx;
struct net *net = sock_net(skb->sk);
struct net_device *dev;
int ret = 0;
rtnl_lock();
if (ctx->req_info->base.dev) {
ret = ethnl_tsinfo_dump_one_net_topo(skb,
ctx->req_info->base.dev,
cb);
} else {
for_each_netdev_dump(net, dev, ctx->pos_ifindex) {
ret = ethnl_tsinfo_dump_one_net_topo(skb, dev, cb);
if (ret < 0 && ret != -EOPNOTSUPP)
break;
ctx->pos_phyindex = 0;
ctx->netdev_dump_done = false;
ctx->pos_phcqualifier = HWTSTAMP_PROVIDER_QUALIFIER_PRECISE;
}
}
rtnl_unlock();
return ret;
}
int ethnl_tsinfo_start(struct netlink_callback *cb)
{
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
struct ethnl_tsinfo_dump_ctx *ctx = (void *)cb->ctx;
struct nlattr **tb = info->info.attrs;
struct tsinfo_reply_data *reply_data;
struct tsinfo_req_info *req_info;
int ret;
BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));
req_info = kzalloc(sizeof(*req_info), GFP_KERNEL);
if (!req_info)
return -ENOMEM;
reply_data = kzalloc(sizeof(*reply_data), GFP_KERNEL);
if (!reply_data) {
ret = -ENOMEM;
goto free_req_info;
}
ret = ethnl_parse_header_dev_get(&req_info->base,
tb[ETHTOOL_A_TSINFO_HEADER],
sock_net(cb->skb->sk), cb->extack,
false);
if (ret < 0)
goto free_reply_data;
ctx->req_info = req_info;
ctx->reply_data = reply_data;
ctx->pos_ifindex = 0;
ctx->pos_phyindex = 0;
ctx->netdev_dump_done = false;
ctx->pos_phcqualifier = HWTSTAMP_PROVIDER_QUALIFIER_PRECISE;
return 0;
free_reply_data:
kfree(reply_data);
free_req_info:
kfree(req_info);
return ret;
}
int ethnl_tsinfo_done(struct netlink_callback *cb)
{
struct ethnl_tsinfo_dump_ctx *ctx = (void *)cb->ctx;
struct tsinfo_req_info *req_info = ctx->req_info;
ethnl_parse_header_dev_put(&req_info->base);
kfree(ctx->reply_data);
kfree(ctx->req_info);
return 0;
}
const struct ethnl_request_ops ethnl_tsinfo_request_ops = {
.request_cmd = ETHTOOL_MSG_TSINFO_GET,
.reply_cmd = ETHTOOL_MSG_TSINFO_GET_REPLY,
@ -180,6 +530,7 @@ const struct ethnl_request_ops ethnl_tsinfo_request_ops = {
.req_info_size = sizeof(struct tsinfo_req_info),
.reply_data_size = sizeof(struct tsinfo_reply_data),
.parse_request = tsinfo_parse_request,
.prepare_data = tsinfo_prepare_data,
.reply_size = tsinfo_reply_size,
.fill_reply = tsinfo_fill_reply,

View File

@ -2391,6 +2391,7 @@ void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
struct scm_timestamping_internal *tss)
{
int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW);
u32 tsflags = READ_ONCE(sk->sk_tsflags);
bool has_timestamping = false;
if (tss->ts[0].tv_sec || tss->ts[0].tv_nsec) {
@ -2430,14 +2431,18 @@ void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
}
}
if (sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE)
if (tsflags & SOF_TIMESTAMPING_SOFTWARE &&
(tsflags & SOF_TIMESTAMPING_RX_SOFTWARE ||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER)))
has_timestamping = true;
else
tss->ts[0] = (struct timespec64) {0};
}
if (tss->ts[2].tv_sec || tss->ts[2].tv_nsec) {
if (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE)
if (tsflags & SOF_TIMESTAMPING_RAW_HARDWARE &&
(tsflags & SOF_TIMESTAMPING_RX_HARDWARE ||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER)))
has_timestamping = true;
else
tss->ts[2] = (struct timespec64) {0};

View File

@ -901,6 +901,7 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
skb_hwtstamps(skb);
int if_index;
ktime_t hwtstamp;
u32 tsflags;
/* Race occurred between timestamp enabling and packet
receiving. Fill in the current time for now. */
@ -942,11 +943,18 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
}
memset(&tss, 0, sizeof(tss));
if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) &&
tsflags = READ_ONCE(sk->sk_tsflags);
if ((tsflags & SOF_TIMESTAMPING_SOFTWARE &&
(tsflags & SOF_TIMESTAMPING_RX_SOFTWARE ||
skb_is_err_queue(skb) ||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))) &&
ktime_to_timespec64_cond(skb->tstamp, tss.ts + 0))
empty = 0;
if (shhwtstamps &&
(sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
(tsflags & SOF_TIMESTAMPING_RAW_HARDWARE &&
(tsflags & SOF_TIMESTAMPING_RX_HARDWARE ||
skb_is_err_queue(skb) ||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))) &&
!skb_is_swtx_tstamp(skb, false_tstamp)) {
if_index = 0;
if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP_NETDEV)

View File

@ -17,7 +17,8 @@ get_hdr_inc=-D$(1) -include $(UAPI_PATH)/linux/$(2)
CFLAGS_devlink:=$(call get_hdr_inc,_LINUX_DEVLINK_H_,devlink.h)
CFLAGS_dpll:=$(call get_hdr_inc,_LINUX_DPLL_H,dpll.h)
CFLAGS_ethtool:=$(call get_hdr_inc,_LINUX_ETHTOOL_H,ethtool.h) \
$(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_H_,ethtool_netlink.h)
$(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_H_,ethtool_netlink.h) \
$(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_GENERATED_H,ethtool_netlink_generated.h)
CFLAGS_handshake:=$(call get_hdr_inc,_LINUX_HANDSHAKE_H,handshake.h)
CFLAGS_mptcp_pm:=$(call get_hdr_inc,_LINUX_MPTCP_PM_H,mptcp_pm.h)
CFLAGS_net_shaper:=$(call get_hdr_inc,_LINUX_NET_SHAPER_H,net_shaper.h)

View File

@ -3,9 +3,12 @@
import argparse
import json
import pathlib
import pprint
import sys
import time
sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix())
from lib import YnlFamily, Netlink, NlError

View File

@ -3,11 +3,13 @@
import argparse
import json
import pathlib
import pprint
import sys
import re
import os
sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix())
from lib import YnlFamily
def args_to_req(ynl, op_name, args, req):
@ -337,16 +339,24 @@ def main():
print('Capabilities:')
[print(f'\t{v}') for v in bits_to_dict(tsinfo['timestamping'])]
print(f'PTP Hardware Clock: {tsinfo["phc-index"]}')
print(f'PTP Hardware Clock: {tsinfo.get("phc-index", "none")}')
print('Hardware Transmit Timestamp Modes:')
[print(f'\t{v}') for v in bits_to_dict(tsinfo['tx-types'])]
if 'tx-types' in tsinfo:
print('Hardware Transmit Timestamp Modes:')
[print(f'\t{v}') for v in bits_to_dict(tsinfo['tx-types'])]
else:
print('Hardware Transmit Timestamp Modes: none')
print('Hardware Receive Filter Modes:')
[print(f'\t{v}') for v in bits_to_dict(tsinfo['rx-filters'])]
if 'rx-filters' in tsinfo:
print('Hardware Receive Filter Modes:')
[print(f'\t{v}') for v in bits_to_dict(tsinfo['rx-filters'])]
else:
print('Hardware Receive Filter Modes: none')
if 'stats' in tsinfo and tsinfo['stats']:
print('Statistics:')
[print(f'\t{k}: {v}') for k, v in tsinfo['stats'].items()]
print('Statistics:')
[print(f'\t{k}: {v}') for k, v in tsinfo['stats'].items()]
return
print(f'Settings for {args.device}:')

View File

@ -4,12 +4,15 @@
import argparse
import collections
import filecmp
import pathlib
import os
import re
import shutil
import sys
import tempfile
import yaml
sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix())
from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, SpecEnumEntry
@ -793,6 +796,8 @@ class EnumSet(SpecEnumSet):
self.user_type = 'int'
self.value_pfx = yaml.get('name-prefix', f"{family.ident_name}-{yaml['name']}-")
self.header = yaml.get('header', None)
self.enum_cnt_name = yaml.get('enum-cnt-name', None)
super().__init__(family, yaml)
@ -2409,6 +2414,87 @@ def uapi_enum_start(family, cw, obj, ckey='', enum_name='enum-name'):
cw.block_start(line=start_line)
def render_uapi_unified(family, cw, max_by_define, separate_ntf):
max_name = c_upper(family.get('cmd-max-name', f"{family.op_prefix}MAX"))
cnt_name = c_upper(family.get('cmd-cnt-name', f"__{family.op_prefix}MAX"))
max_value = f"({cnt_name} - 1)"
uapi_enum_start(family, cw, family['operations'], 'enum-name')
val = 0
for op in family.msgs.values():
if separate_ntf and ('notify' in op or 'event' in op):
continue
suffix = ','
if op.value != val:
suffix = f" = {op.value},"
val = op.value
cw.p(op.enum_name + suffix)
val += 1
cw.nl()
cw.p(cnt_name + ('' if max_by_define else ','))
if not max_by_define:
cw.p(f"{max_name} = {max_value}")
cw.block_end(line=';')
if max_by_define:
cw.p(f"#define {max_name} {max_value}")
cw.nl()
def render_uapi_directional(family, cw, max_by_define):
max_name = f"{family.op_prefix}USER_MAX"
cnt_name = f"__{family.op_prefix}USER_CNT"
max_value = f"({cnt_name} - 1)"
cw.block_start(line='enum')
cw.p(c_upper(f'{family.name}_MSG_USER_NONE = 0,'))
val = 0
for op in family.msgs.values():
if 'do' in op and 'event' not in op:
suffix = ','
if op.value and op.value != val:
suffix = f" = {op.value},"
val = op.value
cw.p(op.enum_name + suffix)
val += 1
cw.nl()
cw.p(cnt_name + ('' if max_by_define else ','))
if not max_by_define:
cw.p(f"{max_name} = {max_value}")
cw.block_end(line=';')
if max_by_define:
cw.p(f"#define {max_name} {max_value}")
cw.nl()
max_name = f"{family.op_prefix}KERNEL_MAX"
cnt_name = f"__{family.op_prefix}KERNEL_CNT"
max_value = f"({cnt_name} - 1)"
cw.block_start(line='enum')
cw.p(c_upper(f'{family.name}_MSG_KERNEL_NONE = 0,'))
val = 0
for op in family.msgs.values():
if ('do' in op and 'reply' in op['do']) or 'notify' in op or 'event' in op:
enum_name = op.enum_name
if 'event' not in op and 'notify' not in op:
enum_name = f'{enum_name}_REPLY'
suffix = ','
if op.value and op.value != val:
suffix = f" = {op.value},"
val = op.value
cw.p(enum_name + suffix)
val += 1
cw.nl()
cw.p(cnt_name + ('' if max_by_define else ','))
if not max_by_define:
cw.p(f"{max_name} = {max_value}")
cw.block_end(line=';')
if max_by_define:
cw.p(f"#define {max_name} {max_value}")
cw.nl()
def render_uapi(family, cw):
hdr_prot = f"_UAPI_LINUX_{c_upper(family.uapi_header_name)}_H"
cw.p('#ifndef ' + hdr_prot)
@ -2431,6 +2517,9 @@ def render_uapi(family, cw):
if const['type'] == 'enum' or const['type'] == 'flags':
enum = family.consts[const['name']]
if enum.header:
continue
if enum.has_doc():
if enum.has_entry_doc():
cw.p('/**')
@ -2463,9 +2552,12 @@ def render_uapi(family, cw):
max_val = f' = {enum.get_mask()},'
cw.p(max_name + max_val)
else:
cnt_name = enum.enum_cnt_name
max_name = c_upper(name_pfx + 'max')
cw.p('__' + max_name + ',')
cw.p(max_name + ' = (__' + max_name + ' - 1)')
if not cnt_name:
cnt_name = '__' + name_pfx + 'max'
cw.p(c_upper(cnt_name) + ',')
cw.p(max_name + ' = (' + c_upper(cnt_name) + ' - 1)')
cw.block_end(line=';')
cw.nl()
elif const['type'] == 'const':
@ -2506,30 +2598,12 @@ def render_uapi(family, cw):
# Commands
separate_ntf = 'async-prefix' in family['operations']
max_name = c_upper(family.get('cmd-max-name', f"{family.op_prefix}MAX"))
cnt_name = c_upper(family.get('cmd-cnt-name', f"__{family.op_prefix}MAX"))
max_value = f"({cnt_name} - 1)"
uapi_enum_start(family, cw, family['operations'], 'enum-name')
val = 0
for op in family.msgs.values():
if separate_ntf and ('notify' in op or 'event' in op):
continue
suffix = ','
if op.value != val:
suffix = f" = {op.value},"
val = op.value
cw.p(op.enum_name + suffix)
val += 1
cw.nl()
cw.p(cnt_name + ('' if max_by_define else ','))
if not max_by_define:
cw.p(f"{max_name} = {max_value}")
cw.block_end(line=';')
if max_by_define:
cw.p(f"#define {max_name} {max_value}")
cw.nl()
if family.msg_id_model == 'unified':
render_uapi_unified(family, cw, max_by_define, separate_ntf)
elif family.msg_id_model == 'directional':
render_uapi_directional(family, cw, max_by_define)
else:
raise Exception(f'Unsupported message enum-model {family.msg_id_model}')
if separate_ntf:
uapi_enum_start(family, cw, family['operations'], enum_name='async-enum')
@ -2653,13 +2727,6 @@ def main():
os.sys.exit(1)
return
supported_models = ['unified']
if args.mode in ['user', 'kernel']:
supported_models += ['directional']
if parsed.msg_id_model not in supported_models:
print(f'Message enum-model {parsed.msg_id_model} not supported for {args.mode} generation')
os.sys.exit(1)
cw = CodeWriter(BaseNlLib(), args.out_file, overwrite=(not args.cmp_out))
_, spec_kernel = find_kernel_root(args.spec)
@ -2709,12 +2776,17 @@ def main():
else:
cw.p(f'#include "{hdr_file}"')
cw.p('#include "ynl.h"')
headers = [parsed.uapi_header]
headers = []
for definition in parsed['definitions']:
if 'header' in definition:
headers.append(definition['header'])
if args.mode == 'user':
headers.append(parsed.uapi_header)
seen_header = []
for one in headers:
cw.p(f"#include <{one}>")
if one not in seen_header:
cw.p(f"#include <{one}>")
seen_header.append(one)
cw.nl()
if args.mode == "user":

View File

@ -96,7 +96,7 @@ TARGETS_HOTPLUG = cpu-hotplug
TARGETS_HOTPLUG += memory-hotplug
# Networking tests want the net/lib target, include it automatically
ifneq ($(filter net drivers/net,$(TARGETS)),)
ifneq ($(filter net drivers/net drivers/net/hw,$(TARGETS)),)
ifeq ($(filter net/lib,$(TARGETS)),)
INSTALL_DEP_TARGETS := net/lib
endif

View File

@ -7,6 +7,7 @@ TEST_PROGS := \
queues.py \
stats.py \
shaper.py \
hds.py \
# end of TEST_PROGS
include ../../lib.mk

View File

@ -0,0 +1,152 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0
import errno
from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_raises, KsftSkipEx
from lib.py import EthtoolFamily, NlError
from lib.py import NetDrvEnv
from lib.py import defer, ethtool, ip, random
def get_hds(cfg, netnl) -> None:
try:
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
except NlError as e:
raise KsftSkipEx('ring-get not supported by device')
if 'tcp-data-split' not in rings:
raise KsftSkipEx('tcp-data-split not supported by device')
def get_hds_thresh(cfg, netnl) -> None:
try:
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
except NlError as e:
raise KsftSkipEx('ring-get not supported by device')
if 'hds-thresh' not in rings:
raise KsftSkipEx('hds-thresh not supported by device')
def set_hds_enable(cfg, netnl) -> None:
try:
netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'tcp-data-split': 'enabled'})
except NlError as e:
if e.error == errno.EINVAL:
raise KsftSkipEx("disabling of HDS not supported by the device")
elif e.error == errno.EOPNOTSUPP:
raise KsftSkipEx("ring-set not supported by the device")
try:
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
except NlError as e:
raise KsftSkipEx('ring-get not supported by device')
if 'tcp-data-split' not in rings:
raise KsftSkipEx('tcp-data-split not supported by device')
ksft_eq('enabled', rings['tcp-data-split'])
def set_hds_disable(cfg, netnl) -> None:
try:
netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'tcp-data-split': 'disabled'})
except NlError as e:
if e.error == errno.EINVAL:
raise KsftSkipEx("disabling of HDS not supported by the device")
elif e.error == errno.EOPNOTSUPP:
raise KsftSkipEx("ring-set not supported by the device")
try:
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
except NlError as e:
raise KsftSkipEx('ring-get not supported by device')
if 'tcp-data-split' not in rings:
raise KsftSkipEx('tcp-data-split not supported by device')
ksft_eq('disabled', rings['tcp-data-split'])
def set_hds_thresh_zero(cfg, netnl) -> None:
try:
netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': 0})
except NlError as e:
if e.error == errno.EINVAL:
raise KsftSkipEx("hds-thresh-set not supported by the device")
elif e.error == errno.EOPNOTSUPP:
raise KsftSkipEx("ring-set not supported by the device")
try:
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
except NlError as e:
raise KsftSkipEx('ring-get not supported by device')
if 'hds-thresh' not in rings:
raise KsftSkipEx('hds-thresh not supported by device')
ksft_eq(0, rings['hds-thresh'])
def set_hds_thresh_random(cfg, netnl) -> None:
try:
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
except NlError as e:
raise KsftSkipEx('ring-get not supported by device')
if 'hds-thresh' not in rings:
raise KsftSkipEx('hds-thresh not supported by device')
if 'hds-thresh-max' not in rings:
raise KsftSkipEx('hds-thresh-max not defined by device')
if rings['hds-thresh-max'] < 2:
raise KsftSkipEx('hds-thresh-max is too small')
elif rings['hds-thresh-max'] == 2:
hds_thresh = 1
else:
while True:
hds_thresh = random.randint(1, rings['hds-thresh-max'] - 1)
if hds_thresh != rings['hds-thresh']:
break
try:
netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': hds_thresh})
except NlError as e:
if e.error == errno.EINVAL:
raise KsftSkipEx("hds-thresh-set not supported by the device")
elif e.error == errno.EOPNOTSUPP:
raise KsftSkipEx("ring-set not supported by the device")
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
ksft_eq(hds_thresh, rings['hds-thresh'])
def set_hds_thresh_max(cfg, netnl) -> None:
try:
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
except NlError as e:
raise KsftSkipEx('ring-get not supported by device')
if 'hds-thresh' not in rings:
raise KsftSkipEx('hds-thresh not supported by device')
try:
netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': rings['hds-thresh-max']})
except NlError as e:
if e.error == errno.EINVAL:
raise KsftSkipEx("hds-thresh-set not supported by the device")
elif e.error == errno.EOPNOTSUPP:
raise KsftSkipEx("ring-set not supported by the device")
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
ksft_eq(rings['hds-thresh'], rings['hds-thresh-max'])
def set_hds_thresh_gt(cfg, netnl) -> None:
try:
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
except NlError as e:
raise KsftSkipEx('ring-get not supported by device')
if 'hds-thresh' not in rings:
raise KsftSkipEx('hds-thresh not supported by device')
if 'hds-thresh-max' not in rings:
raise KsftSkipEx('hds-thresh-max not defined by device')
hds_gt = rings['hds-thresh-max'] + 1
with ksft_raises(NlError) as e:
netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': hds_gt})
ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
def main() -> None:
with NetDrvEnv(__file__, queue_count=3) as cfg:
ksft_run([get_hds,
get_hds_thresh,
set_hds_disable,
set_hds_enable,
set_hds_thresh_random,
set_hds_thresh_zero,
set_hds_thresh_max,
set_hds_thresh_gt],
args=(cfg, EthtoolFamily()))
ksft_exit()
if __name__ == "__main__":
main()

View File

@ -9,6 +9,8 @@ TEST_PROGS = \
hw_stats_l3.sh \
hw_stats_l3_gre.sh \
loopback.sh \
rss_ctx.py \
rss_input_xfrm.py \
#
TEST_FILES := \
@ -16,6 +18,7 @@ TEST_FILES := \
#
TEST_INCLUDES := \
$(wildcard lib/py/*.py ../lib/py/*.py) \
../../../net/lib.sh \
../../../net/forwarding/lib.sh \
../../../net/forwarding/ipip_lib.sh \

View File

@ -0,0 +1,16 @@
# SPDX-License-Identifier: GPL-2.0
import sys
from pathlib import Path
KSFT_DIR = (Path(__file__).parent / "../../../../..").resolve()
try:
sys.path.append(KSFT_DIR.as_posix())
from net.lib.py import *
from drivers.net.lib.py import *
except ModuleNotFoundError as e:
ksft_pr("Failed importing `net` library from kernel sources")
ksft_pr(str(e))
ktap_result(True, comment="SKIP")
sys.exit(4)

View File

@ -0,0 +1,817 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0
import datetime
import random
import re
from lib.py import ksft_run, ksft_pr, ksft_exit
from lib.py import ksft_eq, ksft_ne, ksft_ge, ksft_in, ksft_lt, ksft_true, ksft_raises
from lib.py import NetDrvEpEnv
from lib.py import EthtoolFamily, NetdevFamily
from lib.py import KsftSkipEx, KsftFailEx
from lib.py import rand_port
from lib.py import ethtool, ip, defer, GenerateTraffic, CmdExitFailure
def _rss_key_str(key):
return ":".join(["{:02x}".format(x) for x in key])
def _rss_key_rand(length):
return [random.randint(0, 255) for _ in range(length)]
def _rss_key_check(cfg, data=None, context=0):
if data is None:
data = get_rss(cfg, context=context)
if 'rss-hash-key' not in data:
return
non_zero = [x for x in data['rss-hash-key'] if x != 0]
ksft_eq(bool(non_zero), True, comment=f"RSS key is all zero {data['rss-hash-key']}")
def get_rss(cfg, context=0):
return ethtool(f"-x {cfg.ifname} context {context}", json=True)[0]
def get_drop_err_sum(cfg):
stats = ip("-s -s link show dev " + cfg.ifname, json=True)[0]
cnt = 0
for key in ['errors', 'dropped', 'over_errors', 'fifo_errors',
'length_errors', 'crc_errors', 'missed_errors',
'frame_errors']:
cnt += stats["stats64"]["rx"][key]
return cnt, stats["stats64"]["tx"]["carrier_changes"]
def ethtool_create(cfg, act, opts):
output = ethtool(f"{act} {cfg.ifname} {opts}").stdout
# Output will be something like: "New RSS context is 1" or
# "Added rule with ID 7", we want the integer from the end
return int(output.split()[-1])
def require_ntuple(cfg):
features = ethtool(f"-k {cfg.ifname}", json=True)[0]
if not features["ntuple-filters"]["active"]:
# ntuple is more of a capability than a config knob, don't bother
# trying to enable it (until some driver actually needs it).
raise KsftSkipEx("Ntuple filters not enabled on the device: " + str(features["ntuple-filters"]))
# Get Rx packet counts for all queues, as a simple list of integers
# if @prev is specified the prev counts will be subtracted
def _get_rx_cnts(cfg, prev=None):
cfg.wait_hw_stats_settle()
data = cfg.netdevnl.qstats_get({"ifindex": cfg.ifindex, "scope": ["queue"]}, dump=True)
data = [x for x in data if x['queue-type'] == "rx"]
max_q = max([x["queue-id"] for x in data])
queue_stats = [0] * (max_q + 1)
for q in data:
queue_stats[q["queue-id"]] = q["rx-packets"]
if prev and q["queue-id"] < len(prev):
queue_stats[q["queue-id"]] -= prev[q["queue-id"]]
return queue_stats
def _send_traffic_check(cfg, port, name, params):
# params is a dict with 3 possible keys:
# - "target": required, which queues we expect to get iperf traffic
# - "empty": optional, which queues should see no traffic at all
# - "noise": optional, which queues we expect to see low traffic;
# used for queues of the main context, since some background
# OS activity may use those queues while we're testing
# the value for each is a list, or some other iterable containing queue ids.
cnts = _get_rx_cnts(cfg)
GenerateTraffic(cfg, port=port).wait_pkts_and_stop(20000)
cnts = _get_rx_cnts(cfg, prev=cnts)
directed = sum(cnts[i] for i in params['target'])
ksft_ge(directed, 20000, f"traffic on {name}: " + str(cnts))
if params.get('noise'):
ksft_lt(sum(cnts[i] for i in params['noise']), directed / 2,
f"traffic on other queues ({name})':" + str(cnts))
if params.get('empty'):
ksft_eq(sum(cnts[i] for i in params['empty']), 0,
f"traffic on inactive queues ({name}): " + str(cnts))
def _ntuple_rule_check(cfg, rule_id, ctx_id):
"""Check that ntuple rule references RSS context ID"""
text = ethtool(f"-n {cfg.ifname} rule {rule_id}").stdout
pattern = f"RSS Context (ID: )?{ctx_id}"
ksft_true(re.search(pattern, text), "RSS context not referenced in ntuple rule")
def test_rss_key_indir(cfg):
"""Test basics like updating the main RSS key and indirection table."""
qcnt = len(_get_rx_cnts(cfg))
if qcnt < 3:
KsftSkipEx("Device has fewer than 3 queues (or doesn't support queue stats)")
data = get_rss(cfg)
want_keys = ['rss-hash-key', 'rss-hash-function', 'rss-indirection-table']
for k in want_keys:
if k not in data:
raise KsftFailEx("ethtool results missing key: " + k)
if not data[k]:
raise KsftFailEx(f"ethtool results empty for '{k}': {data[k]}")
_rss_key_check(cfg, data=data)
key_len = len(data['rss-hash-key'])
# Set the key
key = _rss_key_rand(key_len)
ethtool(f"-X {cfg.ifname} hkey " + _rss_key_str(key))
data = get_rss(cfg)
ksft_eq(key, data['rss-hash-key'])
# Set the indirection table and the key together
key = _rss_key_rand(key_len)
ethtool(f"-X {cfg.ifname} equal 3 hkey " + _rss_key_str(key))
reset_indir = defer(ethtool, f"-X {cfg.ifname} default")
data = get_rss(cfg)
_rss_key_check(cfg, data=data)
ksft_eq(0, min(data['rss-indirection-table']))
ksft_eq(2, max(data['rss-indirection-table']))
# Reset indirection table and set the key
key = _rss_key_rand(key_len)
ethtool(f"-X {cfg.ifname} default hkey " + _rss_key_str(key))
data = get_rss(cfg)
_rss_key_check(cfg, data=data)
ksft_eq(0, min(data['rss-indirection-table']))
ksft_eq(qcnt - 1, max(data['rss-indirection-table']))
# Set the indirection table
ethtool(f"-X {cfg.ifname} equal 2")
data = get_rss(cfg)
ksft_eq(0, min(data['rss-indirection-table']))
ksft_eq(1, max(data['rss-indirection-table']))
# Check we only get traffic on the first 2 queues
cnts = _get_rx_cnts(cfg)
GenerateTraffic(cfg).wait_pkts_and_stop(20000)
cnts = _get_rx_cnts(cfg, prev=cnts)
# 2 queues, 20k packets, must be at least 5k per queue
ksft_ge(cnts[0], 5000, "traffic on main context (1/2): " + str(cnts))
ksft_ge(cnts[1], 5000, "traffic on main context (2/2): " + str(cnts))
# The other queues should be unused
ksft_eq(sum(cnts[2:]), 0, "traffic on unused queues: " + str(cnts))
# Restore, and check traffic gets spread again
reset_indir.exec()
cnts = _get_rx_cnts(cfg)
GenerateTraffic(cfg).wait_pkts_and_stop(20000)
cnts = _get_rx_cnts(cfg, prev=cnts)
# First two queues get less traffic than all the rest
ksft_lt(sum(cnts[:2]), sum(cnts[2:]), "traffic distributed: " + str(cnts))
def test_rss_queue_reconfigure(cfg, main_ctx=True):
"""Make sure queue changes can't override requested RSS config.
By default main RSS table should change to include all queues.
When user sets a specific RSS config the driver should preserve it,
even when queue count changes. Driver should refuse to deactivate
queues used in the user-set RSS config.
"""
if not main_ctx:
require_ntuple(cfg)
# Start with 4 queues, an arbitrary known number.
try:
qcnt = len(_get_rx_cnts(cfg))
ethtool(f"-L {cfg.ifname} combined 4")
defer(ethtool, f"-L {cfg.ifname} combined {qcnt}")
except:
raise KsftSkipEx("Not enough queues for the test or qstat not supported")
if main_ctx:
ctx_id = 0
ctx_ref = ""
else:
ctx_id = ethtool_create(cfg, "-X", "context new")
ctx_ref = f"context {ctx_id}"
defer(ethtool, f"-X {cfg.ifname} {ctx_ref} delete")
# Indirection table should be distributing to all queues.
data = get_rss(cfg, context=ctx_id)
ksft_eq(0, min(data['rss-indirection-table']))
ksft_eq(3, max(data['rss-indirection-table']))
# Increase queues, indirection table should be distributing to all queues.
# It's unclear whether tables of additional contexts should be reset, too.
if main_ctx:
ethtool(f"-L {cfg.ifname} combined 5")
data = get_rss(cfg)
ksft_eq(0, min(data['rss-indirection-table']))
ksft_eq(4, max(data['rss-indirection-table']))
ethtool(f"-L {cfg.ifname} combined 4")
# Configure the table explicitly
port = rand_port()
ethtool(f"-X {cfg.ifname} {ctx_ref} weight 1 0 0 1")
if main_ctx:
other_key = 'empty'
defer(ethtool, f"-X {cfg.ifname} default")
else:
other_key = 'noise'
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id}"
ntuple = ethtool_create(cfg, "-N", flow)
defer(ethtool, f"-N {cfg.ifname} delete {ntuple}")
_send_traffic_check(cfg, port, ctx_ref, { 'target': (0, 3),
other_key: (1, 2) })
# We should be able to increase queues, but table should be left untouched
ethtool(f"-L {cfg.ifname} combined 5")
data = get_rss(cfg, context=ctx_id)
ksft_eq({0, 3}, set(data['rss-indirection-table']))
_send_traffic_check(cfg, port, ctx_ref, { 'target': (0, 3),
other_key: (1, 2, 4) })
# Setting queue count to 3 should fail, queue 3 is used
try:
ethtool(f"-L {cfg.ifname} combined 3")
except CmdExitFailure:
pass
else:
raise Exception(f"Driver didn't prevent us from deactivating a used queue (context {ctx_id})")
if not main_ctx:
ethtool(f"-L {cfg.ifname} combined 4")
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id} action 1"
try:
# this targets queue 4, which doesn't exist
ntuple2 = ethtool_create(cfg, "-N", flow)
defer(ethtool, f"-N {cfg.ifname} delete {ntuple2}")
except CmdExitFailure:
pass
else:
raise Exception(f"Driver didn't prevent us from targeting a nonexistent queue (context {ctx_id})")
# change the table to target queues 0 and 2
ethtool(f"-X {cfg.ifname} {ctx_ref} weight 1 0 1 0")
# ntuple rule therefore targets queues 1 and 3
try:
ntuple2 = ethtool_create(cfg, "-N", flow)
except CmdExitFailure:
ksft_pr("Driver does not support rss + queue offset")
return
defer(ethtool, f"-N {cfg.ifname} delete {ntuple2}")
# should replace existing filter
ksft_eq(ntuple, ntuple2)
_send_traffic_check(cfg, port, ctx_ref, { 'target': (1, 3),
'noise' : (0, 2) })
# Setting queue count to 3 should fail, queue 3 is used
try:
ethtool(f"-L {cfg.ifname} combined 3")
except CmdExitFailure:
pass
else:
raise Exception(f"Driver didn't prevent us from deactivating a used queue (context {ctx_id})")
def test_rss_resize(cfg):
"""Test resizing of the RSS table.
Some devices dynamically increase and decrease the size of the RSS
indirection table based on the number of enabled queues.
When that happens driver must maintain the balance of entries
(preferably duplicating the smaller table).
"""
channels = cfg.ethnl.channels_get({'header': {'dev-index': cfg.ifindex}})
ch_max = channels['combined-max']
qcnt = channels['combined-count']
if ch_max < 2:
raise KsftSkipEx(f"Not enough queues for the test: {ch_max}")
ethtool(f"-L {cfg.ifname} combined 2")
defer(ethtool, f"-L {cfg.ifname} combined {qcnt}")
ethtool(f"-X {cfg.ifname} weight 1 7")
defer(ethtool, f"-X {cfg.ifname} default")
ethtool(f"-L {cfg.ifname} combined {ch_max}")
data = get_rss(cfg)
ksft_eq(0, min(data['rss-indirection-table']))
ksft_eq(1, max(data['rss-indirection-table']))
ksft_eq(7,
data['rss-indirection-table'].count(1) /
data['rss-indirection-table'].count(0),
f"Table imbalance after resize: {data['rss-indirection-table']}")
def test_hitless_key_update(cfg):
"""Test that flows may be rehashed without impacting traffic.
Some workloads may want to rehash the flows in response to an imbalance.
Most effective way to do that is changing the RSS key. Check that changing
the key does not cause link flaps or traffic disruption.
Disrupting traffic for key update is not a bug, but makes the key
update unusable for rehashing under load.
"""
data = get_rss(cfg)
key_len = len(data['rss-hash-key'])
key = _rss_key_rand(key_len)
tgen = GenerateTraffic(cfg)
try:
errors0, carrier0 = get_drop_err_sum(cfg)
t0 = datetime.datetime.now()
ethtool(f"-X {cfg.ifname} hkey " + _rss_key_str(key))
t1 = datetime.datetime.now()
errors1, carrier1 = get_drop_err_sum(cfg)
finally:
tgen.wait_pkts_and_stop(5000)
ksft_lt((t1 - t0).total_seconds(), 0.2)
ksft_eq(errors1 - errors1, 0)
ksft_eq(carrier1 - carrier0, 0)
def test_rss_context_dump(cfg):
"""
Test dumping RSS contexts. This tests mostly exercises the kernel APIs.
"""
# Get a random key of the right size
data = get_rss(cfg)
if 'rss-hash-key' in data:
key_data = _rss_key_rand(len(data['rss-hash-key']))
key = _rss_key_str(key_data)
else:
key_data = []
key = "ba:ad"
ids = []
try:
ids.append(ethtool_create(cfg, "-X", f"context new"))
defer(ethtool, f"-X {cfg.ifname} context {ids[-1]} delete")
ids.append(ethtool_create(cfg, "-X", f"context new weight 1 1"))
defer(ethtool, f"-X {cfg.ifname} context {ids[-1]} delete")
ids.append(ethtool_create(cfg, "-X", f"context new hkey {key}"))
defer(ethtool, f"-X {cfg.ifname} context {ids[-1]} delete")
except CmdExitFailure:
if not ids:
raise KsftSkipEx("Unable to add any contexts")
ksft_pr(f"Added only {len(ids)} out of 3 contexts")
expect_tuples = set([(cfg.ifname, -1)] + [(cfg.ifname, ctx_id) for ctx_id in ids])
# Dump all
ctxs = cfg.ethnl.rss_get({}, dump=True)
tuples = [(c['header']['dev-name'], c.get('context', -1)) for c in ctxs]
ksft_eq(len(tuples), len(set(tuples)), "duplicates in context dump")
ctx_tuples = set([ctx for ctx in tuples if ctx[0] == cfg.ifname])
ksft_eq(expect_tuples, ctx_tuples)
# Sanity-check the results
for data in ctxs:
ksft_ne(set(data['indir']), {0}, "indir table is all zero")
ksft_ne(set(data.get('hkey', [1])), {0}, "key is all zero")
# More specific checks
if len(ids) > 1 and data.get('context') == ids[1]:
ksft_eq(set(data['indir']), {0, 1},
"ctx1 - indir table mismatch")
if len(ids) > 2 and data.get('context') == ids[2]:
ksft_eq(data['hkey'], bytes(key_data), "ctx2 - key mismatch")
# Ifindex filter
ctxs = cfg.ethnl.rss_get({'header': {'dev-name': cfg.ifname}}, dump=True)
tuples = [(c['header']['dev-name'], c.get('context', -1)) for c in ctxs]
ctx_tuples = set(tuples)
ksft_eq(len(tuples), len(ctx_tuples), "duplicates in context dump")
ksft_eq(expect_tuples, ctx_tuples)
# Skip ctx 0
expect_tuples.remove((cfg.ifname, -1))
ctxs = cfg.ethnl.rss_get({'start-context': 1}, dump=True)
tuples = [(c['header']['dev-name'], c.get('context', -1)) for c in ctxs]
ksft_eq(len(tuples), len(set(tuples)), "duplicates in context dump")
ctx_tuples = set([ctx for ctx in tuples if ctx[0] == cfg.ifname])
ksft_eq(expect_tuples, ctx_tuples)
# And finally both with ifindex and skip main
ctxs = cfg.ethnl.rss_get({'header': {'dev-name': cfg.ifname}, 'start-context': 1}, dump=True)
ctx_tuples = set([(c['header']['dev-name'], c.get('context', -1)) for c in ctxs])
ksft_eq(expect_tuples, ctx_tuples)
def test_rss_context(cfg, ctx_cnt=1, create_with_cfg=None):
"""
Test separating traffic into RSS contexts.
The queues will be allocated 2 for each context:
ctx0 ctx1 ctx2 ctx3
[0 1] [2 3] [4 5] [6 7] ...
"""
require_ntuple(cfg)
requested_ctx_cnt = ctx_cnt
# Try to allocate more queues when necessary
qcnt = len(_get_rx_cnts(cfg))
if qcnt < 2 + 2 * ctx_cnt:
try:
ksft_pr(f"Increasing queue count {qcnt} -> {2 + 2 * ctx_cnt}")
ethtool(f"-L {cfg.ifname} combined {2 + 2 * ctx_cnt}")
defer(ethtool, f"-L {cfg.ifname} combined {qcnt}")
except:
raise KsftSkipEx("Not enough queues for the test")
ports = []
# Use queues 0 and 1 for normal traffic
ethtool(f"-X {cfg.ifname} equal 2")
defer(ethtool, f"-X {cfg.ifname} default")
for i in range(ctx_cnt):
want_cfg = f"start {2 + i * 2} equal 2"
create_cfg = want_cfg if create_with_cfg else ""
try:
ctx_id = ethtool_create(cfg, "-X", f"context new {create_cfg}")
defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete")
except CmdExitFailure:
# try to carry on and skip at the end
if i == 0:
raise
ksft_pr(f"Failed to create context {i + 1}, trying to test what we got")
ctx_cnt = i
break
_rss_key_check(cfg, context=ctx_id)
if not create_with_cfg:
ethtool(f"-X {cfg.ifname} context {ctx_id} {want_cfg}")
_rss_key_check(cfg, context=ctx_id)
# Sanity check the context we just created
data = get_rss(cfg, ctx_id)
ksft_eq(min(data['rss-indirection-table']), 2 + i * 2, "Unexpected context cfg: " + str(data))
ksft_eq(max(data['rss-indirection-table']), 2 + i * 2 + 1, "Unexpected context cfg: " + str(data))
ports.append(rand_port())
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {ports[i]} context {ctx_id}"
ntuple = ethtool_create(cfg, "-N", flow)
defer(ethtool, f"-N {cfg.ifname} delete {ntuple}")
_ntuple_rule_check(cfg, ntuple, ctx_id)
for i in range(ctx_cnt):
_send_traffic_check(cfg, ports[i], f"context {i}",
{ 'target': (2+i*2, 3+i*2),
'noise': (0, 1),
'empty': list(range(2, 2+i*2)) + list(range(4+i*2, 2+2*ctx_cnt)) })
if requested_ctx_cnt != ctx_cnt:
raise KsftSkipEx(f"Tested only {ctx_cnt} contexts, wanted {requested_ctx_cnt}")
def test_rss_context4(cfg):
test_rss_context(cfg, 4)
def test_rss_context32(cfg):
test_rss_context(cfg, 32)
def test_rss_context4_create_with_cfg(cfg):
test_rss_context(cfg, 4, create_with_cfg=True)
def test_rss_context_queue_reconfigure(cfg):
test_rss_queue_reconfigure(cfg, main_ctx=False)
def test_rss_context_out_of_order(cfg, ctx_cnt=4):
"""
Test separating traffic into RSS contexts.
Contexts are removed in semi-random order, and steering re-tested
to make sure removal doesn't break steering to surviving contexts.
Test requires 3 contexts to work.
"""
require_ntuple(cfg)
requested_ctx_cnt = ctx_cnt
# Try to allocate more queues when necessary
qcnt = len(_get_rx_cnts(cfg))
if qcnt < 2 + 2 * ctx_cnt:
try:
ksft_pr(f"Increasing queue count {qcnt} -> {2 + 2 * ctx_cnt}")
ethtool(f"-L {cfg.ifname} combined {2 + 2 * ctx_cnt}")
defer(ethtool, f"-L {cfg.ifname} combined {qcnt}")
except:
raise KsftSkipEx("Not enough queues for the test")
ntuple = []
ctx = []
ports = []
def remove_ctx(idx):
ntuple[idx].exec()
ntuple[idx] = None
ctx[idx].exec()
ctx[idx] = None
def check_traffic():
for i in range(ctx_cnt):
if ctx[i]:
expected = {
'target': (2+i*2, 3+i*2),
'noise': (0, 1),
'empty': list(range(2, 2+i*2)) + list(range(4+i*2, 2+2*ctx_cnt))
}
else:
expected = {
'target': (0, 1),
'empty': range(2, 2+2*ctx_cnt)
}
_send_traffic_check(cfg, ports[i], f"context {i}", expected)
# Use queues 0 and 1 for normal traffic
ethtool(f"-X {cfg.ifname} equal 2")
defer(ethtool, f"-X {cfg.ifname} default")
for i in range(ctx_cnt):
ctx_id = ethtool_create(cfg, "-X", f"context new start {2 + i * 2} equal 2")
ctx.append(defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete"))
ports.append(rand_port())
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {ports[i]} context {ctx_id}"
ntuple_id = ethtool_create(cfg, "-N", flow)
ntuple.append(defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}"))
check_traffic()
# Remove middle context
remove_ctx(ctx_cnt // 2)
check_traffic()
# Remove first context
remove_ctx(0)
check_traffic()
# Remove last context
remove_ctx(-1)
check_traffic()
if requested_ctx_cnt != ctx_cnt:
raise KsftSkipEx(f"Tested only {ctx_cnt} contexts, wanted {requested_ctx_cnt}")
def test_rss_context_overlap(cfg, other_ctx=0):
"""
Test contexts overlapping with each other.
Use 4 queues for the main context, but only queues 2 and 3 for context 1.
"""
require_ntuple(cfg)
queue_cnt = len(_get_rx_cnts(cfg))
if queue_cnt < 4:
try:
ksft_pr(f"Increasing queue count {queue_cnt} -> 4")
ethtool(f"-L {cfg.ifname} combined 4")
defer(ethtool, f"-L {cfg.ifname} combined {queue_cnt}")
except:
raise KsftSkipEx("Not enough queues for the test")
if other_ctx == 0:
ethtool(f"-X {cfg.ifname} equal 4")
defer(ethtool, f"-X {cfg.ifname} default")
else:
other_ctx = ethtool_create(cfg, "-X", "context new")
ethtool(f"-X {cfg.ifname} context {other_ctx} equal 4")
defer(ethtool, f"-X {cfg.ifname} context {other_ctx} delete")
ctx_id = ethtool_create(cfg, "-X", "context new")
ethtool(f"-X {cfg.ifname} context {ctx_id} start 2 equal 2")
defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete")
port = rand_port()
if other_ctx:
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {other_ctx}"
ntuple_id = ethtool_create(cfg, "-N", flow)
ntuple = defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
# Test the main context
cnts = _get_rx_cnts(cfg)
GenerateTraffic(cfg, port=port).wait_pkts_and_stop(20000)
cnts = _get_rx_cnts(cfg, prev=cnts)
ksft_ge(sum(cnts[ :4]), 20000, "traffic on main context: " + str(cnts))
ksft_ge(sum(cnts[ :2]), 7000, "traffic on main context (1/2): " + str(cnts))
ksft_ge(sum(cnts[2:4]), 7000, "traffic on main context (2/2): " + str(cnts))
if other_ctx == 0:
ksft_eq(sum(cnts[4: ]), 0, "traffic on other queues: " + str(cnts))
# Now create a rule for context 1 and make sure traffic goes to a subset
if other_ctx:
ntuple.exec()
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id}"
ntuple_id = ethtool_create(cfg, "-N", flow)
defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
cnts = _get_rx_cnts(cfg)
GenerateTraffic(cfg, port=port).wait_pkts_and_stop(20000)
cnts = _get_rx_cnts(cfg, prev=cnts)
directed = sum(cnts[2:4])
ksft_lt(sum(cnts[ :2]), directed / 2, "traffic on main context: " + str(cnts))
ksft_ge(directed, 20000, "traffic on extra context: " + str(cnts))
if other_ctx == 0:
ksft_eq(sum(cnts[4: ]), 0, "traffic on other queues: " + str(cnts))
def test_rss_context_overlap2(cfg):
test_rss_context_overlap(cfg, True)
def test_flow_add_context_missing(cfg):
"""
Test that we are not allowed to add a rule pointing to an RSS context
which was never created.
"""
require_ntuple(cfg)
# Find a context which doesn't exist
for ctx_id in range(1, 100):
try:
get_rss(cfg, context=ctx_id)
except CmdExitFailure:
break
with ksft_raises(CmdExitFailure) as cm:
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port 1234 context {ctx_id}"
ntuple_id = ethtool_create(cfg, "-N", flow)
ethtool(f"-N {cfg.ifname} delete {ntuple_id}")
if cm.exception:
ksft_in('Invalid argument', cm.exception.cmd.stderr)
def test_delete_rss_context_busy(cfg):
"""
Test that deletion returns -EBUSY when an rss context is being used
by an ntuple filter.
"""
require_ntuple(cfg)
# create additional rss context
ctx_id = ethtool_create(cfg, "-X", "context new")
ctx_deleter = defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete")
# utilize context from ntuple filter
port = rand_port()
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id}"
ntuple_id = ethtool_create(cfg, "-N", flow)
defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
# attempt to delete in-use context
try:
ctx_deleter.exec_only()
ctx_deleter.cancel()
raise KsftFailEx(f"deleted context {ctx_id} used by rule {ntuple_id}")
except CmdExitFailure:
pass
def test_rss_ntuple_addition(cfg):
"""
Test that the queue offset (ring_cookie) of an ntuple rule is added
to the queue number read from the indirection table.
"""
require_ntuple(cfg)
queue_cnt = len(_get_rx_cnts(cfg))
if queue_cnt < 4:
try:
ksft_pr(f"Increasing queue count {queue_cnt} -> 4")
ethtool(f"-L {cfg.ifname} combined 4")
defer(ethtool, f"-L {cfg.ifname} combined {queue_cnt}")
except:
raise KsftSkipEx("Not enough queues for the test")
# Use queue 0 for normal traffic
ethtool(f"-X {cfg.ifname} equal 1")
defer(ethtool, f"-X {cfg.ifname} default")
# create additional rss context
ctx_id = ethtool_create(cfg, "-X", "context new equal 2")
defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete")
# utilize context from ntuple filter
port = rand_port()
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id} action 2"
try:
ntuple_id = ethtool_create(cfg, "-N", flow)
except CmdExitFailure:
raise KsftSkipEx("Ntuple filter with RSS and nonzero action not supported")
defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
_send_traffic_check(cfg, port, f"context {ctx_id}", { 'target': (2, 3),
'empty' : (1,),
'noise' : (0,) })
def test_rss_default_context_rule(cfg):
"""
Allocate a port, direct this port to context 0, then create a new RSS
context and steer all TCP traffic to it (context 1). Verify that:
* Traffic to the specific port continues to use queues of the main
context (0/1).
* Traffic to any other TCP port is redirected to the new context
(queues 2/3).
"""
require_ntuple(cfg)
queue_cnt = len(_get_rx_cnts(cfg))
if queue_cnt < 4:
try:
ksft_pr(f"Increasing queue count {queue_cnt} -> 4")
ethtool(f"-L {cfg.ifname} combined 4")
defer(ethtool, f"-L {cfg.ifname} combined {queue_cnt}")
except Exception as exc:
raise KsftSkipEx("Not enough queues for the test") from exc
# Use queues 0 and 1 for the main context
ethtool(f"-X {cfg.ifname} equal 2")
defer(ethtool, f"-X {cfg.ifname} default")
# Create a new RSS context that uses queues 2 and 3
ctx_id = ethtool_create(cfg, "-X", "context new start 2 equal 2")
defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete")
# Generic low-priority rule: redirect all TCP traffic to the new context.
# Give it an explicit higher location number (lower priority).
flow_generic = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} context {ctx_id} loc 1"
ethtool(f"-N {cfg.ifname} {flow_generic}")
defer(ethtool, f"-N {cfg.ifname} delete 1")
# Specific high-priority rule for a random port that should stay on context 0.
# Assign loc 0 so it is evaluated before the generic rule.
port_main = rand_port()
flow_main = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port_main} context 0 loc 0"
ethtool(f"-N {cfg.ifname} {flow_main}")
defer(ethtool, f"-N {cfg.ifname} delete 0")
_ntuple_rule_check(cfg, 1, ctx_id)
# Verify that traffic matching the specific rule still goes to queues 0/1
_send_traffic_check(cfg, port_main, "context 0",
{ 'target': (0, 1),
'empty' : (2, 3) })
# And that traffic for any other port is steered to the new context
port_other = rand_port()
_send_traffic_check(cfg, port_other, f"context {ctx_id}",
{ 'target': (2, 3),
'noise' : (0, 1) })
def main() -> None:
with NetDrvEpEnv(__file__, nsim_test=False) as cfg:
cfg.ethnl = EthtoolFamily()
cfg.netdevnl = NetdevFamily()
ksft_run([test_rss_key_indir, test_rss_queue_reconfigure,
test_rss_resize, test_hitless_key_update,
test_rss_context, test_rss_context4, test_rss_context32,
test_rss_context_dump, test_rss_context_queue_reconfigure,
test_rss_context_overlap, test_rss_context_overlap2,
test_rss_context_out_of_order, test_rss_context4_create_with_cfg,
test_flow_add_context_missing,
test_delete_rss_context_busy, test_rss_ntuple_addition,
test_rss_default_context_rule],
args=(cfg, ))
ksft_exit()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,87 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0
import multiprocessing
import socket
from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_ge, cmd, fd_read_timeout
from lib.py import NetDrvEpEnv
from lib.py import EthtoolFamily, NetdevFamily
from lib.py import KsftSkipEx, KsftFailEx
from lib.py import rand_port
def traffic(cfg, local_port, remote_port, ipver):
af_inet = socket.AF_INET if ipver == "4" else socket.AF_INET6
sock = socket.socket(af_inet, socket.SOCK_DGRAM)
sock.bind(("", local_port))
sock.connect((cfg.remote_addr_v[ipver], remote_port))
tgt = f"{ipver}:[{cfg.addr_v[ipver]}]:{local_port},sourceport={remote_port}"
cmd("echo a | socat - UDP" + tgt, host=cfg.remote)
fd_read_timeout(sock.fileno(), 5)
return sock.getsockopt(socket.SOL_SOCKET, socket.SO_INCOMING_CPU)
def test_rss_input_xfrm(cfg, ipver):
"""
Test symmetric input_xfrm.
If symmetric RSS hash is configured, send traffic twice, swapping the
src/dst UDP ports, and verify that the same queue is receiving the traffic
in both cases (IPs are constant).
"""
if multiprocessing.cpu_count() < 2:
raise KsftSkipEx("Need at least two CPUs to test symmetric RSS hash")
input_xfrm = cfg.ethnl.rss_get(
{'header': {'dev-name': cfg.ifname}}).get('input_xfrm')
# Check for symmetric xor/or-xor
if not input_xfrm or (input_xfrm != 1 and input_xfrm != 2):
raise KsftSkipEx("Symmetric RSS hash not requested")
cpus = set()
successful = 0
for _ in range(100):
try:
port1 = rand_port(socket.SOCK_DGRAM)
port2 = rand_port(socket.SOCK_DGRAM)
cpu1 = traffic(cfg, port1, port2, ipver)
cpu2 = traffic(cfg, port2, port1, ipver)
cpus.update([cpu1, cpu2])
ksft_eq(
cpu1, cpu2, comment=f"Received traffic on different cpus with ports ({port1 = }, {port2 = }) while symmetric hash is configured")
successful += 1
if successful == 10:
break
except:
continue
else:
raise KsftFailEx("Failed to run traffic")
ksft_ge(len(cpus), 2,
comment=f"Received traffic on less than two cpus {cpus = }")
def test_rss_input_xfrm_ipv4(cfg):
cfg.require_ipver("4")
test_rss_input_xfrm(cfg, "4")
def test_rss_input_xfrm_ipv6(cfg):
cfg.require_ipver("6")
test_rss_input_xfrm(cfg, "6")
def main() -> None:
with NetDrvEpEnv(__file__, nsim_test=False) as cfg:
cfg.ethnl = EthtoolFamily()
cfg.netdevnl = NetdevFamily()
ksft_run([test_rss_input_xfrm_ipv4, test_rss_input_xfrm_ipv6],
args=(cfg, ))
ksft_exit()
if __name__ == "__main__":
main()

View File

@ -15,4 +15,5 @@ except ModuleNotFoundError as e:
sys.exit(4)
from .env import *
from .load import *
from .remote import Remote

View File

@ -3,7 +3,7 @@
import os
import shlex
from pathlib import Path
from lib.py import KsftSkipEx
from lib.py import KsftSkipEx, KsftXfailEx
from lib.py import cmd, ip
from lib.py import NetNS, NetdevSimDev
from .remote import Remote
@ -76,7 +76,7 @@ class NetDrvEpEnv:
nsim_v4_pfx = "192.0.2."
nsim_v6_pfx = "2001:db8::"
def __init__(self, src_path):
def __init__(self, src_path, nsim_test=None):
self.env = _load_env_file(src_path)
@ -88,6 +88,8 @@ class NetDrvEpEnv:
self._ns_peer = None
if "NETIF" in self.env:
if nsim_test is True:
raise KsftXfailEx("Test only works on netdevsim")
self.dev = ip("link show dev " + self.env['NETIF'], json=True)[0]
self.v4 = self.env.get("LOCAL_V4")
@ -97,6 +99,9 @@ class NetDrvEpEnv:
kind = self.env["REMOTE_TYPE"]
args = self.env["REMOTE_ARGS"]
else:
if nsim_test is False:
raise KsftXfailEx("Test does not work on netdevsim")
self.create_local()
self.dev = self._ns.nsims[0].dev

View File

@ -0,0 +1,42 @@
# SPDX-License-Identifier: GPL-2.0
import time
from lib.py import ksft_pr, cmd, ip, rand_port, wait_port_listen
class GenerateTraffic:
def __init__(self, env, port=None):
env.require_cmd("iperf3", remote=True)
self.env = env
if port is None:
port = rand_port()
self._iperf_server = cmd(f"iperf3 -s -1 -p {port}", background=True)
wait_port_listen(port)
time.sleep(0.1)
self._iperf_client = cmd(f"iperf3 -c {env.addr} -P 16 -p {port} -t 86400",
background=True, host=env.remote)
# Wait for traffic to ramp up
pkt = ip("-s link show dev " + env.ifname, json=True)[0]["stats64"]["rx"]["packets"]
for _ in range(50):
time.sleep(0.1)
now = ip("-s link show dev " + env.ifname, json=True)[0]["stats64"]["rx"]["packets"]
if now - pkt > 1000:
return
pkt = now
self.stop(verbose=True)
raise Exception("iperf3 traffic did not ramp up")
def stop(self, verbose=None):
self._iperf_client.process(terminate=True)
if verbose:
ksft_pr(">> Client:")
ksft_pr(self._iperf_client.stdout)
ksft_pr(self._iperf_client.stderr)
self._iperf_server.process(terminate=True)
if verbose:
ksft_pr(">> Server:")
ksft_pr(self._iperf_server.stdout)
ksft_pr(self._iperf_server.stderr)

View File

@ -6,11 +6,16 @@ import sys
import time
import traceback
from .consts import KSFT_MAIN_NAME
from .utils import global_defer_queue
KSFT_RESULT = None
KSFT_RESULT_ALL = True
class KsftFailEx(Exception):
pass
class KsftSkipEx(Exception):
pass
@ -38,6 +43,12 @@ def ksft_eq(a, b, comment=""):
_fail("Check failed", a, "!=", b, comment)
def ksft_ne(a, b, comment=""):
global KSFT_RESULT
if a == b:
_fail("Check failed", a, "==", b, comment)
def ksft_true(a, comment=""):
if not a:
_fail("Check failed", a, "does not eval to True", comment)
@ -53,6 +64,11 @@ def ksft_ge(a, b, comment=""):
_fail("Check failed", a, "<", b, comment)
def ksft_lt(a, b, comment=""):
if a >= b:
_fail("Check failed", a, ">=", b, comment)
class ksft_raises:
def __init__(self, expected_type):
self.exception = None
@ -99,6 +115,24 @@ def ktap_result(ok, cnt=1, case="", comment=""):
print(res)
def ksft_flush_defer():
global KSFT_RESULT
i = 0
qlen_start = len(global_defer_queue)
while global_defer_queue:
i += 1
entry = global_defer_queue.pop()
try:
entry.exec_only()
except:
ksft_pr(f"Exception while handling defer / cleanup (callback {i} of {qlen_start})!")
tb = traceback.format_exc()
for line in tb.strip().split('\n'):
ksft_pr("Defer Exception|", line)
KSFT_RESULT = False
def ksft_run(cases=None, globs=None, case_pfx=None, args=()):
cases = cases or []
@ -121,29 +155,31 @@ def ksft_run(cases=None, globs=None, case_pfx=None, args=()):
for case in cases:
KSFT_RESULT = True
cnt += 1
comment = ""
cnt_key = ""
try:
case(*args)
except KsftSkipEx as e:
ktap_result(True, cnt, case, comment="SKIP " + str(e))
totals['skip'] += 1
continue
comment = "SKIP " + str(e)
cnt_key = 'skip'
except KsftXfailEx as e:
ktap_result(True, cnt, case, comment="XFAIL " + str(e))
totals['xfail'] += 1
continue
comment = "XFAIL " + str(e)
cnt_key = 'xfail'
except Exception as e:
tb = traceback.format_exc()
for line in tb.strip().split('\n'):
ksft_pr("Exception|", line)
ktap_result(False, cnt, case)
totals['fail'] += 1
continue
KSFT_RESULT = False
cnt_key = 'fail'
ktap_result(KSFT_RESULT, cnt, case)
if KSFT_RESULT:
totals['pass'] += 1
else:
totals['fail'] += 1
ksft_flush_defer()
if not cnt_key:
cnt_key = 'pass' if KSFT_RESULT else 'fail'
ktap_result(KSFT_RESULT, cnt, case, comment=comment)
totals[cnt_key] += 1
print(
f"# Totals: pass:{totals['pass']} fail:{totals['fail']} xfail:{totals['xfail']} xpass:0 skip:{totals['skip']} error:0"

View File

@ -1,12 +1,27 @@
# SPDX-License-Identifier: GPL-2.0
import errno
import json as _json
import os
import random
import re
import select
import socket
import subprocess
import time
class CmdExitFailure(Exception):
pass
def fd_read_timeout(fd, timeout):
rlist, _, _ = select.select([fd], [], [], timeout)
if rlist:
return os.read(fd, 1024)
else:
raise TimeoutError("Timeout waiting for fd read")
class cmd:
def __init__(self, comm, shell=True, fail=True, ns=None, background=False, host=None, timeout=5):
if ns:
@ -41,7 +56,8 @@ class cmd:
if self.proc.returncode != 0 and fail:
if len(stderr) > 0 and stderr[-1] == "\n":
stderr = stderr[:-1]
raise Exception("Command failed: %s\n%s" % (self.proc.args, stderr))
raise CmdExitFailure("Command failed: %s\nSTDOUT: %s\nSTDERR: %s" %
(self.proc.args, stdout, stderr))
class bkg(cmd):
@ -58,11 +74,45 @@ class bkg(cmd):
def __exit__(self, ex_type, ex_value, ex_tb):
return self.process(terminate=self.terminate, fail=self.check_fail)
global_defer_queue = []
def ip(args, json=None, ns=None, host=None):
cmd_str = "ip "
class defer:
def __init__(self, func, *args, **kwargs):
global global_defer_queue
if not callable(func):
raise Exception("defer created with un-callable object, did you call the function instead of passing its name?")
self.func = func
self.args = args
self.kwargs = kwargs
self._queue = global_defer_queue
self._queue.append(self)
def __enter__(self):
return self
def __exit__(self, ex_type, ex_value, ex_tb):
return self.exec()
def exec_only(self):
self.func(*self.args, **self.kwargs)
def cancel(self):
self._queue.remove(self)
def exec(self):
self.cancel()
self.exec_only()
def tool(name, args, json=None, ns=None, host=None):
cmd_str = name + ' '
if json:
cmd_str += '-j '
cmd_str += '--json '
cmd_str += args
cmd_obj = cmd(cmd_str, ns=ns, host=host)
if json:
@ -70,11 +120,23 @@ def ip(args, json=None, ns=None, host=None):
return cmd_obj
def rand_port():
def ip(args, json=None, ns=None, host=None):
if ns:
args = f'-netns {ns} ' + args
return tool('ip', args, json=json, host=host)
def ethtool(args, json=None, ns=None, host=None):
return tool('ethtool', args, json=json, ns=ns, host=host)
def rand_port(type=socket.SOCK_STREAM):
"""
Get unprivileged port, for now just random, one day we may decide to check if used.
Get a random unprivileged port.
"""
return random.randint(1024, 65535)
with socket.socket(socket.AF_INET6, type) as s:
s.bind(("", 0))
return s.getsockname()[1]
def wait_port_listen(port, proto="tcp", ns=None, host=None, sleep=0.005, deadline=5):

View File

@ -57,6 +57,8 @@ static struct sof_flag sof_flags[] = {
SOF_FLAG(SOF_TIMESTAMPING_SOFTWARE),
SOF_FLAG(SOF_TIMESTAMPING_RX_SOFTWARE),
SOF_FLAG(SOF_TIMESTAMPING_RX_HARDWARE),
SOF_FLAG(SOF_TIMESTAMPING_OPT_RX_FILTER),
SOF_FLAG(SOF_TIMESTAMPING_RAW_HARDWARE),
};
static struct socket_type socket_types[] = {
@ -97,6 +99,22 @@ static struct test_case test_cases[] = {
| SOF_TIMESTAMPING_RX_HARDWARE },
{}
},
{
{ .so_timestamping = SOF_TIMESTAMPING_RAW_HARDWARE
| SOF_TIMESTAMPING_OPT_RX_FILTER },
{}
},
{
{ .so_timestamping = SOF_TIMESTAMPING_SOFTWARE
| SOF_TIMESTAMPING_OPT_RX_FILTER },
{}
},
{
{ .so_timestamping = SOF_TIMESTAMPING_SOFTWARE
| SOF_TIMESTAMPING_RX_SOFTWARE
| SOF_TIMESTAMPING_OPT_RX_FILTER },
{ .swtstamp = true }
},
{
{ .so_timestamping = SOF_TIMESTAMPING_SOFTWARE
| SOF_TIMESTAMPING_RX_SOFTWARE },