summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2023-03-30 23:29:58 -0700
committerJakub Kicinski <kuba@kernel.org>2023-03-30 23:30:18 -0700
commitdee1efb301f4c380f454bc84c2258b3d594c9615 (patch)
tree36f9bc892d5c61025457cd0bfe68d80c3f2ef464
parent709d0b880ceae9503ce4282fcfaf4cb59c6dd267 (diff)
parentf3d07b02b2b8eba5b0e168405614e15cd6617a43 (diff)
Merge branch 'tools-ynl-fill-in-some-gaps-of-ethtool-spec'
Stanislav Fomichev says: ==================== tools: ynl: fill in some gaps of ethtool spec I was trying to fill in the spec while exploring ethtool API for some related work. I don't think I'll have the patience to fill in the rest, so decided to share whatever I currently have. Patches 1-2 add the be16 + spec. Patches 3-4 implement an ethtool-like python tool to test the spec. Patches 3-4 are there because it felt more fun do the tool instead of writing the actual tests; feel free to drop it; sharing mostly to show that the spec is not a complete nonsense. The spec is not 100% complete, see patch 2 for what's missing. I was hoping to finish the stats-get message, but I'm too dump to implement bitmask marshaling (multi-attr). ==================== Link: https://lore.kernel.org/r/20230329221655.708489-1-sdf@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--Documentation/netlink/specs/ethtool.yaml1296
-rwxr-xr-xtools/net/ynl/ethtool424
-rw-r--r--tools/net/ynl/lib/nlspec.py10
-rw-r--r--tools/net/ynl/lib/ynl.py58
4 files changed, 1752 insertions, 36 deletions
diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml
index 6d8ae3d9a680..129f413ea349 100644
--- a/Documentation/netlink/specs/ethtool.yaml
+++ b/Documentation/netlink/specs/ethtool.yaml
@@ -6,6 +6,12 @@ protocol: genetlink-legacy
doc: Partial family for Ethtool Netlink.
+definitions:
+ -
+ name: udp-tunnel-type
+ type: enum
+ entries: [ vxlan, geneve, vxlan-gpe ]
+
attribute-sets:
-
name: header
@@ -38,6 +44,7 @@ attribute-sets:
-
name: bit
type: nest
+ multi-attr: true
nested-attributes: bitset-bit
-
name: bitset
@@ -54,6 +61,22 @@ attribute-sets:
nested-attributes: bitset-bits
-
+ name: u64-array
+ attributes:
+ -
+ name: u64
+ type: nest
+ multi-attr: true
+ nested-attributes: u64
+ -
+ name: s32-array
+ attributes:
+ -
+ name: s32
+ type: nest
+ multi-attr: true
+ nested-attributes: s32
+ -
name: string
attributes:
-
@@ -234,6 +257,657 @@ attribute-sets:
name: stats
type: nest
nested-attributes: mm-stat
+ -
+ name: linkinfo
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: port
+ type: u8
+ -
+ name: phyaddr
+ type: u8
+ -
+ name: tp-mdix
+ type: u8
+ -
+ name: tp-mdix-ctrl
+ type: u8
+ -
+ name: transceiver
+ type: u8
+ -
+ name: linkmodes
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: autoneg
+ type: u8
+ -
+ name: ours
+ type: nest
+ nested-attributes: bitset
+ -
+ name: peer
+ type: nest
+ nested-attributes: bitset
+ -
+ name: speed
+ type: u32
+ -
+ name: duplex
+ type: u8
+ -
+ name: master-slave-cfg
+ type: u8
+ -
+ name: master-slave-state
+ type: u8
+ -
+ name: master-slave-lanes
+ type: u32
+ -
+ name: rate-matching
+ type: u8
+ -
+ name: linkstate
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: link
+ type: u8
+ -
+ name: sqi
+ type: u32
+ -
+ name: sqi-max
+ type: u32
+ -
+ name: ext-state
+ type: u8
+ -
+ name: ext-substate
+ type: u8
+ -
+ name: down-cnt
+ type: u32
+ -
+ name: debug
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: msgmask
+ type: nest
+ nested-attributes: bitset
+ -
+ name: wol
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: modes
+ type: nest
+ nested-attributes: bitset
+ -
+ name: sopass
+ type: binary
+ -
+ name: features
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: hw
+ type: nest
+ nested-attributes: bitset
+ -
+ name: wanted
+ type: nest
+ nested-attributes: bitset
+ -
+ name: active
+ type: nest
+ nested-attributes: bitset
+ -
+ name: nochange
+ type: nest
+ nested-attributes: bitset
+ -
+ name: channels
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: rx-max
+ type: u32
+ -
+ name: tx-max
+ type: u32
+ -
+ name: other-max
+ type: u32
+ -
+ name: combined-max
+ type: u32
+ -
+ name: rx-count
+ type: u32
+ -
+ name: tx-count
+ type: u32
+ -
+ name: other-count
+ type: u32
+ -
+ name: combined-count
+ type: u32
+
+ -
+ name: coalesce
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: rx-usecs
+ type: u32
+ -
+ name: rx-max-frames
+ type: u32
+ -
+ name: rx-usecs-irq
+ type: u32
+ -
+ name: rx-max-frames-irq
+ type: u32
+ -
+ name: tx-usecs
+ type: u32
+ -
+ name: tx-max-frames
+ type: u32
+ -
+ name: tx-usecs-irq
+ type: u32
+ -
+ name: tx-max-frames-irq
+ type: u32
+ -
+ name: stats-block-usecs
+ type: u32
+ -
+ name: use-adaptive-rx
+ type: u8
+ -
+ name: use-adaptive-tx
+ type: u8
+ -
+ name: pkt-rate-low
+ type: u32
+ -
+ name: rx-usecs-low
+ type: u32
+ -
+ name: rx-max-frames-low
+ type: u32
+ -
+ name: tx-usecs-low
+ type: u32
+ -
+ name: tx-max-frames-low
+ type: u32
+ -
+ name: pkt-rate-high
+ type: u32
+ -
+ name: rx-usecs-high
+ type: u32
+ -
+ name: rx-max-frames-high
+ type: u32
+ -
+ name: tx-usecs-high
+ type: u32
+ -
+ name: tx-max-frames-high
+ type: u32
+ -
+ name: rate-sample-interval
+ type: u32
+ -
+ name: use-cqe-mode-tx
+ type: u8
+ -
+ name: use-cqe-mode-rx
+ type: u8
+ -
+ name: tx-aggr-max-bytes
+ type: u32
+ -
+ name: tx-aggr-max-frames
+ type: u32
+ -
+ name: tx-aggr-time-usecs
+ type: u32
+ -
+ name: pause-stat
+ attributes:
+ -
+ name: pad
+ type: u32
+ -
+ name: tx-frames
+ type: u64
+ -
+ name: rx-frames
+ type: u64
+ -
+ name: pause
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: autoneg
+ type: u8
+ -
+ name: rx
+ type: u8
+ -
+ name: tx
+ type: u8
+ -
+ name: stats
+ type: nest
+ nested-attributes: pause-stat
+ -
+ name: stats-src
+ type: u32
+ -
+ name: eee
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: modes-ours
+ type: nest
+ nested-attributes: bitset
+ -
+ name: modes-peer
+ type: nest
+ nested-attributes: bitset
+ -
+ name: active
+ type: u8
+ -
+ name: enabled
+ type: u8
+ -
+ name: tx-lpi-enabled
+ type: u8
+ -
+ name: tx-lpi-timer
+ type: u32
+ -
+ name: tsinfo
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: timestamping
+ type: nest
+ nested-attributes: bitset
+ -
+ name: tx-types
+ type: nest
+ nested-attributes: bitset
+ -
+ name: rx-filters
+ type: nest
+ nested-attributes: bitset
+ -
+ name: phc-index
+ type: u32
+ -
+ name: cable-test-nft-nest-result
+ attributes:
+ -
+ name: pair
+ type: u8
+ -
+ name: code
+ type: u8
+ -
+ name: cable-test-nft-nest-fault-length
+ attributes:
+ -
+ name: pair
+ type: u8
+ -
+ name: cm
+ type: u32
+ -
+ name: cable-test-nft-nest
+ attributes:
+ -
+ name: result
+ type: nest
+ nested-attributes: cable-test-nft-nest-result
+ -
+ name: fault-length
+ type: nest
+ nested-attributes: cable-test-nft-nest-fault-length
+ -
+ name: cable-test
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: status
+ type: u8
+ -
+ name: nest
+ type: nest
+ nested-attributes: cable-test-nft-nest
+ -
+ name: cable-test-tdr-cfg
+ attributes:
+ -
+ name: first
+ type: u32
+ -
+ name: last
+ type: u32
+ -
+ name: step
+ type: u32
+ -
+ name: pari
+ type: u8
+ -
+ name: cable-test-tdr
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: cfg
+ type: nest
+ nested-attributes: cable-test-tdr-cfg
+ -
+ name: tunnel-info-udp-entry
+ attributes:
+ -
+ name: port
+ type: u16
+ byte-order: big-endian
+ -
+ name: type
+ type: u32
+ enum: udp-tunnel-type
+ -
+ name: tunnel-info-udp-table
+ attributes:
+ -
+ name: size
+ type: u32
+ -
+ name: types
+ type: nest
+ nested-attributes: bitset
+ -
+ name: udp-ports
+ type: nest
+ nested-attributes: tunnel-info-udp-entry
+ -
+ name: tunnel-info
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: udp-ports
+ type: nest
+ nested-attributes: tunnel-info-udp-table
+ -
+ name: fec-stat
+ attributes:
+ -
+ name: pad
+ type: u8
+ -
+ name: corrected
+ type: nest
+ nested-attributes: u64-array
+ -
+ name: uncorr
+ type: nest
+ nested-attributes: u64-array
+ -
+ name: corr-bits
+ type: nest
+ nested-attributes: u64-array
+ -
+ name: fec
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: modes
+ type: nest
+ nested-attributes: bitset
+ -
+ name: auto
+ type: u8
+ -
+ name: active
+ type: u32
+ -
+ name: stats
+ type: nest
+ nested-attributes: fec-stat
+ -
+ name: module-eeprom
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: offset
+ type: u32
+ -
+ name: length
+ type: u32
+ -
+ name: page
+ type: u8
+ -
+ name: bank
+ type: u8
+ -
+ name: i2c-address
+ type: u8
+ -
+ name: data
+ type: binary
+ -
+ name: stats-grp
+ attributes:
+ -
+ name: pad
+ type: u32
+ -
+ name: id
+ type: u32
+ -
+ name: ss-id
+ type: u32
+ -
+ name: stat
+ type: nest
+ nested-attributes: u64
+ -
+ name: hist-rx
+ type: nest
+ nested-attributes: u64
+ -
+ name: hist-tx
+ type: nest
+ nested-attributes: u64
+ -
+ name: hist-bkt-low
+ type: u32
+ -
+ name: hist-bkt-hi
+ type: u32
+ -
+ name: hist-bkt-val
+ type: u64
+ -
+ name: stats
+ attributes:
+ -
+ name: pad
+ type: u32
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: groups
+ type: nest
+ nested-attributes: bitset
+ -
+ name: grp
+ type: nest
+ nested-attributes: stats-grp
+ -
+ name: src
+ type: u32
+ -
+ name: phc-vclocks
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: num
+ type: u32
+ -
+ name: index
+ type: nest
+ nested-attributes: s32-array
+ -
+ name: module
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: power-mode-policy
+ type: u8
+ -
+ name: power-mode
+ type: u8
+ -
+ name: pse
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: admin-state
+ type: u32
+ -
+ name: admin-control
+ type: u32
+ -
+ name: pw-d-status
+ type: u32
+ -
+ name: rss
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: context
+ type: u32
+ -
+ name: hfunc
+ type: u32
+ -
+ name: indir
+ type: binary
+ -
+ name: hkey
+ type: binary
+ -
+ name: plca
+ attributes:
+ -
+ name: header
+ type: nest
+ nested-attributes: header
+ -
+ name: version
+ type: u16
+ -
+ name: enabled
+ type: u8
+ -
+ name: status
+ type: u8
+ -
+ name: node-cnt
+ type: u32
+ -
+ name: node-id
+ type: u32
+ -
+ name: to-tmr
+ type: u32
+ -
+ name: burst-cnt
+ type: u32
+ -
+ name: burst-tmr
+ type: u32
operations:
enum-model: directional
@@ -255,9 +929,188 @@ operations:
- header
- stringsets
dump: *strset-get-op
+ -
+ name: linkinfo-get
+ doc: Get link info.
- # TODO: fill in the requests in between
+ attribute-set: linkinfo
+ do: &linkinfo-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes: &linkinfo
+ - header
+ - port
+ - phyaddr
+ - tp-mdix
+ - tp-mdix-ctrl
+ - transceiver
+ dump: *linkinfo-get-op
+ -
+ name: linkinfo-set
+ doc: Set link info.
+
+ attribute-set: linkinfo
+
+ do:
+ request:
+ attributes: *linkinfo
+ -
+ name: linkinfo-ntf
+ doc: Notification for change in link info.
+ notify: linkinfo-get
+ -
+ name: linkmodes-get
+ doc: Get link modes.
+
+ attribute-set: linkmodes
+
+ do: &linkmodes-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes: &linkmodes
+ - header
+ - autoneg
+ - ours
+ - peer
+ - speed
+ - duplex
+ - master-slave-cfg
+ - master-slave-state
+ - master-slave-lanes
+ - rate-matching
+ dump: *linkmodes-get-op
+ -
+ name: linkmodes-set
+ doc: Set link modes.
+
+ attribute-set: linkmodes
+
+ do:
+ request:
+ attributes: *linkmodes
+ -
+ name: linkmodes-ntf
+ doc: Notification for change in link modes.
+ notify: linkmodes-get
+ -
+ name: linkstate-get
+ doc: Get link state.
+
+ attribute-set: linkstate
+
+ do: &linkstate-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes:
+ - header
+ - link
+ - sqi
+ - sqi-max
+ - ext-state
+ - ext-substate
+ - down-cnt
+ dump: *linkstate-get-op
+ -
+ name: debug-get
+ doc: Get debug message mask.
+
+ attribute-set: debug
+
+ do: &debug-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes: &debug
+ - header
+ - msgmask
+ dump: *debug-get-op
+ -
+ name: debug-set
+ doc: Set debug message mask.
+
+ attribute-set: debug
+
+ do:
+ request:
+ attributes: *debug
+ -
+ name: debug-ntf
+ doc: Notification for change in debug message mask.
+ notify: debug-get
+ -
+ name: wol-get
+ doc: Get WOL params.
+
+ attribute-set: wol
+
+ do: &wol-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes: &wol
+ - header
+ - modes
+ - sopass
+ dump: *wol-get-op
+ -
+ name: wol-set
+ doc: Set WOL params.
+
+ attribute-set: wol
+
+ do:
+ request:
+ attributes: *wol
+ -
+ name: wol-ntf
+ doc: Notification for change in WOL params.
+ notify: wol-get
+ -
+ name: features-get
+ doc: Get features.
+
+ attribute-set: features
+
+ do: &feature-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes: &feature
+ - header
+ # User-changeable features.
+ - hw
+ # User-requested features.
+ - wanted
+ # Currently active features.
+ - active
+ # Unchangeable features.
+ - nochange
+ dump: *feature-get-op
+ -
+ name: features-set
+ doc: Set features.
+
+ attribute-set: features
+
+ do: &feature-set-op
+ request:
+ attributes: *feature
+ reply:
+ attributes: *feature
+ -
+ name: features-ntf
+ doc: Notification for change in features.
+ notify: features-get
-
name: privflags-get
doc: Get device private flags.
@@ -266,12 +1119,10 @@ operations:
do: &privflag-get-op
request:
- value: 13
attributes:
- header
reply:
- value: 14
- attributes:
+ attributes: &privflag
- header
- flags
dump: *privflag-get-op
@@ -283,9 +1134,7 @@ operations:
do:
request:
- attributes:
- - header
- - flags
+ attributes: *privflag
-
name: privflags-ntf
doc: Notification for change in device private flags.
@@ -302,7 +1151,7 @@ operations:
attributes:
- header
reply:
- attributes:
+ attributes: &ring
- header
- rx-max
- rx-mini-max
@@ -328,24 +1177,431 @@ operations:
do:
request:
+ attributes: *ring
+ -
+ name: rings-ntf
+ doc: Notification for change in ring params.
+ notify: rings-get
+ -
+ name: channels-get
+ doc: Get channel params.
+
+ attribute-set: channels
+
+ do: &channel-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes: &channel
+ - header
+ - rx-max
+ - tx-max
+ - other-max
+ - combined-max
+ - rx-count
+ - tx-count
+ - other-count
+ - combined-count
+ dump: *channel-get-op
+ -
+ name: channels-set
+ doc: Set channel params.
+
+ attribute-set: channels
+
+ do:
+ request:
+ attributes: *channel
+ -
+ name: channels-ntf
+ doc: Notification for change in channel params.
+ notify: channels-get
+ -
+ name: coalesce-get
+ doc: Get coalesce params.
+
+ attribute-set: coalesce
+
+ do: &coalesce-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes: &coalesce
+ - header
+ - rx-usecs
+ - rx-max-frames
+ - rx-usecs-irq
+ - rx-max-frames-irq
+ - tx-usecs
+ - tx-max-frames
+ - tx-usecs-irq
+ - tx-max-frames-irq
+ - stats-block-usecs
+ - use-adaptive-rx
+ - use-adaptive-tx
+ - pkt-rate-low
+ - rx-usecs-low
+ - rx-max-frames-low
+ - tx-usecs-low
+ - tx-max-frames-low
+ - pkt-rate-high
+ - rx-usecs-high
+ - rx-max-frames-high
+ - tx-usecs-high
+ - tx-max-frames-high
+ - rate-sample-interval
+ - use-cqe-mode-tx
+ - use-cqe-mode-rx
+ - tx-aggr-max-bytes
+ - tx-aggr-max-frames
+ - tx-aggr-time-usecs
+ dump: *coalesce-get-op
+ -
+ name: coalesce-set
+ doc: Set coalesce params.
+
+ attribute-set: coalesce
+
+ do:
+ request:
+ attributes: *coalesce
+ -
+ name: coalesce-ntf
+ doc: Notification for change in coalesce params.
+ notify: coalesce-get
+ -
+ name: pause-get
+ doc: Get pause params.
+
+ attribute-set: pause
+
+ do: &pause-get-op
+ request:
attributes:
- header
+ reply:
+ attributes: &pause
+ - header
+ - autoneg
- rx
- - rx-mini
- - rx-jumbo
- tx
- - rx-buf-len
- - tcp-data-split
- - cqe-size
- - tx-push
- - rx-push
+ - stats
+ - stats-src
+ dump: *pause-get-op
-
- name: rings-ntf
- doc: Notification for change in ring params.
- notify: rings-get
+ name: pause-set
+ doc: Set pause params.
+
+ attribute-set: pause
+
+ do:
+ request:
+ attributes: *pause
+ -
+ name: pause-ntf
+ doc: Notification for change in pause params.
+ notify: pause-get
+ -
+ name: eee-get
+ doc: Get eee params.
+
+ attribute-set: eee
+
+ do: &eee-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes: &eee
+ - header
+ - modes-ours
+ - modes-peer
+ - active
+ - enabled
+ - tx-lpi-enabled
+ - tx-lpi-timer
+ dump: *eee-get-op
+ -
+ name: eee-set
+ doc: Set eee params.
+
+ attribute-set: eee
+
+ do:
+ request:
+ attributes: *eee
+ -
+ name: eee-ntf
+ doc: Notification for change in eee params.
+ notify: eee-get
+ -
+ name: tsinfo-get
+ doc: Get tsinfo params.
+
+ attribute-set: tsinfo
+
+ do: &tsinfo-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes:
+ - header
+ - timestamping
+ - tx-types
+ - rx-filters
+ - phc-index
+ dump: *tsinfo-get-op
+ -
+ name: cable-test-act
+ doc: Cable test.
+
+ attribute-set: cable-test
+
+ do:
+ request:
+ attributes:
+ - header
+ reply:
+ attributes:
+ - header
+ - cable-test-nft-nest
+ -
+ name: cable-test-tdr-act
+ doc: Cable test TDR.
+
+ attribute-set: cable-test-tdr
+
+ do:
+ request:
+ attributes:
+ - header
+ reply:
+ attributes:
+ - header
+ - cable-test-tdr-cfg
+ -
+ name: tunnel-info-get
+ doc: Get tsinfo params.
+
+ attribute-set: tunnel-info
+
+ do: &tunnel-info-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes:
+ - header
+ - udp-ports
+ dump: *tunnel-info-get-op
+ -
+ name: fec-get
+ doc: Get FEC params.
- # TODO: fill in the requests in between
+ attribute-set: fec
+ do: &fec-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes: &fec
+ - header
+ - modes
+ - auto
+ - active
+ - stats
+ dump: *fec-get-op
+ -
+ name: fec-set
+ doc: Set FEC params.
+
+ attribute-set: fec
+
+ do:
+ request:
+ attributes: *fec
+ -
+ name: fec-ntf
+ doc: Notification for change in FEC params.
+ notify: fec-get
+ -
+ name: module-eeprom-get
+ doc: Get module EEPROM params.
+
+ attribute-set: module-eeprom
+
+ do: &module-eeprom-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes:
+ - header
+ - offset
+ - length
+ - page
+ - bank
+ - i2c-address
+ - data
+ dump: *module-eeprom-get-op
+ -
+ name: stats-get
+ doc: Get statistics.
+
+ attribute-set: stats
+
+ do: &stats-get-op
+ request:
+ attributes:
+ - header
+ - groups
+ reply:
+ attributes:
+ - header
+ - groups
+ - grp
+ - src
+ dump: *stats-get-op
+ -
+ name: phc-vclocks-get
+ doc: Get PHC VCLOCKs.
+
+ attribute-set: phc-vclocks
+
+ do: &phc-vclocks-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes:
+ - header
+ - num
+ dump: *phc-vclocks-get-op
+ -
+ name: module-get
+ doc: Get module params.
+
+ attribute-set: module
+
+ do: &module-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes: &module
+ - header
+ - power-mode-policy
+ - power-mode
+ dump: *module-get-op
+ -
+ name: module-set
+ doc: Set module params.
+
+ attribute-set: module
+
+ do:
+ request:
+ attributes: *module
+ -
+ name: module-ntf
+ doc: Notification for change in module params.
+ notify: module-get
+ -
+ name: pse-get
+ doc: Get Power Sourcing Equipment params.
+
+ attribute-set: pse
+
+ do: &pse-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes: &pse
+ - header
+ - admin-state
+ - admin-control
+ - pw-d-status
+ dump: *pse-get-op
+ -
+ name: pse-set
+ doc: Set Power Sourcing Equipment params.
+
+ attribute-set: pse
+
+ do:
+ request:
+ attributes: *pse
+ -
+ name: rss-get
+ doc: Get RSS params.
+
+ attribute-set: rss
+
+ do: &rss-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes:
+ - header
+ - context
+ - hfunc
+ - indir
+ - hkey
+ dump: *rss-get-op
+ -
+ name: plca-get
+ doc: Get PLCA params.
+
+ attribute-set: plca
+
+ do: &plca-get-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes: &plca
+ - header
+ - version
+ - enabled
+ - status
+ - node-cnt
+ - node-id
+ - to-tmr
+ - burst-cnt
+ - burst-tmr
+ dump: *plca-get-op
+ -
+ name: plca-set
+ doc: Set PLCA params.
+
+ attribute-set: plca
+
+ do:
+ request:
+ attributes: *plca
+ -
+ name: plca-get-status
+ doc: Get PLCA status params.
+
+ attribute-set: plca
+
+ do: &plca-get-status-op
+ request:
+ attributes:
+ - header
+ reply:
+ attributes: *plca
+ dump: *plca-get-status-op
+ -
+ name: plca-ntf
+ doc: Notification for change in PLCA params.
+ notify: plca-get
-
name: mm-get
doc: Get MAC Merge configuration and state
@@ -354,11 +1610,9 @@ operations:
do: &mm-get-op
request:
- value: 42
attributes:
- header
reply:
- value: 42
attributes:
- header
- pmac-enabled
diff --git a/tools/net/ynl/ethtool b/tools/net/ynl/ethtool
new file mode 100755
index 000000000000..5fb1d670693a
--- /dev/null
+++ b/tools/net/ynl/ethtool
@@ -0,0 +1,424 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+
+import argparse
+import json
+import pprint
+import sys
+import re
+
+from lib import YnlFamily
+
+def args_to_req(ynl, op_name, args, req):
+ """
+ Verify and convert command-line arguments to the ynl-compatible request.
+ """
+ valid_attrs = ynl.operation_do_attributes(op_name)
+ valid_attrs.remove('header') # not user-provided
+
+ if len(args) == 0:
+ print(f'no attributes, expected: {valid_attrs}')
+ sys.exit(1)
+
+ i = 0
+ while i < len(args):
+ attr = args[i]
+ if i + 1 >= len(args):
+ print(f'expected value for \'{attr}\'')
+ sys.exit(1)
+
+ if attr not in valid_attrs:
+ print(f'invalid attribute \'{attr}\', expected: {valid_attrs}')
+ sys.exit(1)
+
+ val = args[i+1]
+ i += 2
+
+ req[attr] = val
+
+def print_field(reply, *desc):
+ """
+ Pretty-print a set of fields from the reply. desc specifies the
+ fields and the optional type (bool/yn).
+ """
+ if len(desc) == 0:
+ return print_field(reply, *zip(reply.keys(), reply.keys()))
+
+ for spec in desc:
+ try:
+ field, name, tp = spec
+ except:
+ field, name = spec
+ tp = 'int'
+
+ value = reply.get(field, None)
+ if tp == 'yn':
+ value = 'yes' if value else 'no'
+ elif tp == 'bool' or isinstance(value, bool):
+ value = 'on' if value else 'off'
+ else:
+ value = 'n/a' if value is None else value
+
+ print(f'{name}: {value}')
+
+def print_speed(name, value):
+ """
+ Print out the speed-like strings from the value dict.
+ """
+ speed_re = re.compile(r'[0-9]+base[^/]+/.+')
+ speed = [ k for k, v in value.items() if v and speed_re.match(k) ]
+ print(f'{name}: {" ".join(speed)}')
+
+def doit(ynl, args, op_name):
+ """
+ Prepare request header, parse arguments and doit.
+ """
+ req = {
+ 'header': {
+ 'dev-name': args.device,
+ },
+ }
+
+ args_to_req(ynl, op_name, args.args, req)
+ ynl.do(op_name, req)
+
+def dumpit(ynl, args, op_name, extra = {}):
+ """
+ Prepare request header, parse arguments and dumpit (filtering out the
+ devices we're not interested in).
+ """
+ reply = ynl.dump(op_name, { 'header': {} } | extra)
+ if not reply:
+ return {}
+
+ for msg in reply:
+ if msg['header']['dev-name'] == args.device:
+ if args.json:
+ pprint.PrettyPrinter().pprint(msg)
+ sys.exit(0)
+ msg.pop('header', None)
+ return msg
+
+ print(f"Not supported for device {args.device}")
+ sys.exit(1)
+
+def bits_to_dict(attr):
+ """
+ Convert ynl-formatted bitmask to a dict of bit=value.
+ """
+ ret = {}
+ if 'bits' not in attr:
+ return dict()
+ if 'bit' not in attr['bits']:
+ return dict()
+ for bit in attr['bits']['bit']:
+ if bit['name'] == '':
+ continue
+ name = bit['name']
+ value = bit.get('value', False)
+ ret[name] = value
+ return ret
+
+def main():
+ parser = argparse.ArgumentParser(description='ethtool wannabe')
+ parser.add_argument('--json', action=argparse.BooleanOptionalAction)
+ parser.add_argument('--show-priv-flags', action=argparse.BooleanOptionalAction)
+ parser.add_argument('--set-priv-flags', action=argparse.BooleanOptionalAction)
+ parser.add_argument('--show-eee', action=argparse.BooleanOptionalAction)
+ parser.add_argument('--set-eee', action=argparse.BooleanOptionalAction)
+ parser.add_argument('-a', '--show-pause', action=argparse.BooleanOptionalAction)
+ parser.add_argument('-A', '--set-pause', action=argparse.BooleanOptionalAction)
+ parser.add_argument('-c', '--show-coalesce', action=argparse.BooleanOptionalAction)
+ parser.add_argument('-C', '--set-coalesce', action=argparse.BooleanOptionalAction)
+ parser.add_argument('-g', '--show-ring', action=argparse.BooleanOptionalAction)
+ parser.add_argument('-G', '--set-ring', action=argparse.BooleanOptionalAction)
+ parser.add_argument('-k', '--show-features', action=argparse.BooleanOptionalAction)
+ parser.add_argument('-K', '--set-features', action=argparse.BooleanOptionalAction)
+ parser.add_argument('-l', '--show-channels', action=argparse.BooleanOptionalAction)
+ parser.add_argument('-L', '--set-channels', action=argparse.BooleanOptionalAction)
+ parser.add_argument('-T', '--show-time-stamping', action=argparse.BooleanOptionalAction)
+ parser.add_argument('-S', '--statistics', action=argparse.BooleanOptionalAction)
+ # TODO: --show-tunnels tunnel-info-get
+ # TODO: --show-module module-get
+ # TODO: --get-plca-cfg plca-get
+ # TODO: --get-plca-status plca-get-status
+ # TODO: --show-mm mm-get
+ # TODO: --show-fec fec-get
+ # TODO: --dump-module-eerpom module-eeprom-get
+ # TODO: pse-get
+ # TODO: rss-get
+ parser.add_argument('device', metavar='device', type=str)
+ parser.add_argument('args', metavar='args', type=str, nargs='*')
+ global args
+ args = parser.parse_args()
+
+ spec = '/usr/local/google/home/sdf/src/linux/Documentation/netlink/specs/ethtool.yaml'
+ schema = '/usr/local/google/home/sdf/src/linux/Documentation/netlink/genetlink-legacy.yaml'
+
+ ynl = YnlFamily(spec, schema)
+
+ if args.set_priv_flags:
+ # TODO: parse the bitmask
+ print("not implemented")
+ return
+
+ if args.set_eee:
+ return doit(ynl, args, 'eee-set')
+
+ if args.set_pause:
+ return doit(ynl, args, 'pause-set')
+
+ if args.set_coalesce:
+ return doit(ynl, args, 'coalesce-set')
+
+ if args.set_features:
+ # TODO: parse the bitmask
+ print("not implemented")
+ return
+
+ if args.set_channels:
+ return doit(ynl, args, 'channels-set')
+
+ if args.set_ring:
+ return doit(ynl, args, 'rings-set')
+
+ if args.show_priv_flags:
+ flags = bits_to_dict(dumpit(ynl, args, 'privflags-get')['flags'])
+ print_field(flags)
+ return
+
+ if args.show_eee:
+ eee = dumpit(ynl, args, 'eee-get')
+ ours = bits_to_dict(eee['modes-ours'])
+ peer = bits_to_dict(eee['modes-peer'])
+
+ if 'enabled' in eee:
+ status = 'enabled' if eee['enabled'] else 'disabled'
+ if 'active' in eee and eee['active']:
+ status = status + ' - active'
+ else:
+ status = status + ' - inactive'
+ else:
+ status = 'not supported'
+
+ print(f'EEE status: {status}')
+ print_field(eee, ('tx-lpi-timer', 'Tx LPI'))
+ print_speed('Advertised EEE link modes', ours)
+ print_speed('Link partner advertised EEE link modes', peer)
+
+ return
+
+ if args.show_pause:
+ print_field(dumpit(ynl, args, 'pause-get'),
+ ('autoneg', 'Autonegotiate', 'bool'),
+ ('rx', 'RX', 'bool'),
+ ('tx', 'TX', 'bool'))
+ return
+
+ if args.show_coalesce:
+ print_field(dumpit(ynl, args, 'coalesce-get'))
+ return
+
+ if args.show_features:
+ reply = dumpit(ynl, args, 'features-get')
+ available = bits_to_dict(reply['hw'])
+ requested = bits_to_dict(reply['wanted']).keys()
+ active = bits_to_dict(reply['active']).keys()
+ never_changed = bits_to_dict(reply['nochange']).keys()
+
+ for f in sorted(available):
+ value = "off"
+ if f in active:
+ value = "on"
+
+ fixed = ""
+ if f not in available or f in never_changed:
+ fixed = " [fixed]"
+
+ req = ""
+ if f in requested:
+ if f in active:
+ req = " [requested on]"
+ else:
+ req = " [requested off]"
+
+ print(f'{f}: {value}{fixed}{req}')
+
+ return
+
+ if args.show_channels:
+ reply = dumpit(ynl, args, 'channels-get')
+ print(f'Channel parameters for {args.device}:')
+
+ print(f'Pre-set maximums:')
+ print_field(reply,
+ ('rx-max', 'RX'),
+ ('tx-max', 'TX'),
+ ('other-max', 'Other'),
+ ('combined-max', 'Combined'))
+
+ print(f'Current hardware settings:')
+ print_field(reply,
+ ('rx-count', 'RX'),
+ ('tx-count', 'TX'),
+ ('other-count', 'Other'),
+ ('combined-count', 'Combined'))
+
+ return
+
+ if args.show_ring:
+ reply = dumpit(ynl, args, 'channels-get')
+
+ print(f'Ring parameters for {args.device}:')
+
+ print(f'Pre-set maximums:')
+ print_field(reply,
+ ('rx-max', 'RX'),
+ ('rx-mini-max', 'RX Mini'),
+ ('rx-jumbo-max', 'RX Jumbo'),
+ ('tx-max', 'TX'))
+
+ print(f'Current hardware settings:')
+ print_field(reply,
+ ('rx', 'RX'),
+ ('rx-mini', 'RX Mini'),
+ ('rx-jumbo', 'RX Jumbo'),
+ ('tx', 'TX'))
+
+ print_field(reply,
+ ('rx-buf-len', 'RX Buf Len'),
+ ('cqe-size', 'CQE Size'),
+ ('tx-push', 'TX Push', 'bool'))
+
+ return
+
+ if args.statistics:
+ print(f'NIC statistics:')
+
+ # TODO: pass id?
+ strset = dumpit(ynl, args, 'strset-get')
+ pprint.PrettyPrinter().pprint(strset)
+
+ req = {
+ 'groups': {
+ 'size': 1,
+ 'bits': {
+ 'bit':
+ # TODO: support passing the bitmask
+ #[
+ #{ 'name': 'eth-phy', 'value': True },
+ { 'name': 'eth-mac', 'value': True },
+ #{ 'name': 'eth-ctrl', 'value': True },
+ #{ 'name': 'rmon', 'value': True },
+ #],
+ },
+ },
+ }
+
+ rsp = dumpit(ynl, args, 'stats-get', req)
+ pprint.PrettyPrinter().pprint(rsp)
+ return
+
+ if args.show_time_stamping:
+ tsinfo = dumpit(ynl, args, 'tsinfo-get')
+
+ print(f'Time stamping parameters for {args.device}:')
+
+ print('Capabilities:')
+ [print(f'\t{v}') for v in bits_to_dict(tsinfo['timestamping'])]
+
+ print(f'PTP Hardware Clock: {tsinfo["phc-index"]}')
+
+ print('Hardware Transmit Timestamp Modes:')
+ [print(f'\t{v}') for v in bits_to_dict(tsinfo['tx-types'])]
+
+ print('Hardware Receive Filter Modes:')
+ [print(f'\t{v}') for v in bits_to_dict(tsinfo['rx-filters'])]
+ return
+
+ print(f'Settings for {args.device}:')
+ linkmodes = dumpit(ynl, args, 'linkmodes-get')
+ ours = bits_to_dict(linkmodes['ours'])
+
+ supported_ports = ('TP', 'AUI', 'BNC', 'MII', 'FIBRE', 'Backplane')
+ ports = [ p for p in supported_ports if ours.get(p, False)]
+ print(f'Supported ports: [ {" ".join(ports)} ]')
+
+ print_speed('Supported link modes', ours)
+
+ print_field(ours, ('Pause', 'Supported pause frame use', 'yn'))
+ print_field(ours, ('Autoneg', 'Supports auto-negotiation', 'yn'))
+
+ supported_fec = ('None', 'PS', 'BASER', 'LLRS')
+ fec = [ p for p in supported_fec if ours.get(p, False)]
+ fec_str = " ".join(fec)
+ if len(fec) == 0:
+ fec_str = "Not reported"
+
+ print(f'Supported FEC modes: {fec_str}')
+
+ speed = 'Unknown!'
+ if linkmodes['speed'] > 0 and linkmodes['speed'] < 0xffffffff:
+ speed = f'{linkmodes["speed"]}Mb/s'
+ print(f'Speed: {speed}')
+
+ duplex_modes = {
+ 0: 'Half',
+ 1: 'Full',
+ }
+ duplex = duplex_modes.get(linkmodes["duplex"], None)
+ if not duplex:
+ duplex = f'Unknown! ({linkmodes["duplex"]})'
+ print(f'Duplex: {duplex}')
+
+ autoneg = "off"
+ if linkmodes.get("autoneg", 0) != 0:
+ autoneg = "on"
+ print(f'Auto-negotiation: {autoneg}')
+
+ ports = {
+ 0: 'Twisted Pair',
+ 1: 'AUI',
+ 2: 'MII',
+ 3: 'FIBRE',
+ 4: 'BNC',
+ 5: 'Directly Attached Copper',
+ 0xef: 'None',
+ }
+ linkinfo = dumpit(ynl, args, 'linkinfo-get')
+ print(f'Port: {ports.get(linkinfo["port"], "Other")}')
+
+ print_field(linkinfo, ('phyaddr', 'PHYAD'))
+
+ transceiver = {
+ 0: 'Internal',
+ 1: 'External',
+ }
+ print(f'Transceiver: {transceiver.get(linkinfo["transceiver"], "Unknown")}')
+
+ mdix_ctrl = {
+ 1: 'off',
+ 2: 'on',
+ }
+ mdix = mdix_ctrl.get(linkinfo['tp-mdix-ctrl'], None)
+ if mdix:
+ mdix = mdix + ' (forced)'
+ else:
+ mdix = mdix_ctrl.get(linkinfo['tp-mdix'], 'Unknown (auto)')
+ print(f'MDI-X: {mdix}')
+
+ debug = dumpit(ynl, args, 'debug-get')
+ msgmask = bits_to_dict(debug.get("msgmask", [])).keys()
+ print(f'Current message level: {" ".join(msgmask)}')
+
+ linkstate = dumpit(ynl, args, 'linkstate-get')
+ detected_states = {
+ 0: 'no',
+ 1: 'yes',
+ }
+ # TODO: wol-get
+ detected = detected_states.get(linkstate['link'], 'unknown')
+ print(f'Link detected: {detected}')
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py
index 06a906d74f0e..a0241add3839 100644
--- a/tools/net/ynl/lib/nlspec.py
+++ b/tools/net/ynl/lib/nlspec.py
@@ -163,6 +163,7 @@ class SpecAttr(SpecElement):
self.is_multi = yaml.get('multi-attr', False)
self.struct_name = yaml.get('struct')
self.sub_type = yaml.get('sub-type')
+ self.byte_order = yaml.get('byte-order')
class SpecAttrSet(SpecElement):
@@ -443,6 +444,15 @@ class SpecFamily(SpecElement):
self.msgs[op.name] = op
+ def find_operation(self, name):
+ """
+ For a given operation name, find and return operation spec.
+ """
+ for op in self.yaml['operations']['list']:
+ if name == op['name']:
+ return op
+ return None
+
def resolve(self):
self.resolve_up(super())
diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py
index ec40918152e1..7690e0b0cb3f 100644
--- a/tools/net/ynl/lib/ynl.py
+++ b/tools/net/ynl/lib/ynl.py
@@ -67,6 +67,14 @@ class Netlink:
NLMSGERR_ATTR_MISS_NEST = 6
+class NlError(Exception):
+ def __init__(self, nl_msg):
+ self.nl_msg = nl_msg
+
+ def __str__(self):
+ return f"Netlink error: {os.strerror(-self.nl_msg.error)}\n{self.nl_msg}"
+
+
class NlAttr:
type_formats = { 'u8' : ('B', 1), 's8' : ('b', 1),
'u16': ('H', 2), 's16': ('h', 2),
@@ -80,17 +88,25 @@ class NlAttr:
self.full_len = (self.payload_len + 3) & ~3
self.raw = raw[offset + 4:offset + self.payload_len]
+ def format_byte_order(byte_order):
+ if byte_order:
+ return ">" if byte_order == "big-endian" else "<"
+ return ""
+
def as_u8(self):
return struct.unpack("B", self.raw)[0]
- def as_u16(self):
- return struct.unpack("H", self.raw)[0]
+ def as_u16(self, byte_order=None):
+ endian = NlAttr.format_byte_order(byte_order)
+ return struct.unpack(f"{endian}H", self.raw)[0]
- def as_u32(self):
- return struct.unpack("I", self.raw)[0]
+ def as_u32(self, byte_order=None):
+ endian = NlAttr.format_byte_order(byte_order)
+ return struct.unpack(f"{endian}I", self.raw)[0]
- def as_u64(self):
- return struct.unpack("Q", self.raw)[0]
+ def as_u64(self, byte_order=None):
+ endian = NlAttr.format_byte_order(byte_order)
+ return struct.unpack(f"{endian}Q", self.raw)[0]
def as_strz(self):
return self.raw.decode('ascii')[:-1]
@@ -365,11 +381,14 @@ class YnlFamily(SpecFamily):
elif attr["type"] == 'u8':
attr_payload = struct.pack("B", int(value))
elif attr["type"] == 'u16':
- attr_payload = struct.pack("H", int(value))
+ endian = NlAttr.format_byte_order(attr.byte_order)
+ attr_payload = struct.pack(f"{endian}H", int(value))
elif attr["type"] == 'u32':
- attr_payload = struct.pack("I", int(value))
+ endian = NlAttr.format_byte_order(attr.byte_order)
+ attr_payload = struct.pack(f"{endian}I", int(value))
elif attr["type"] == 'u64':
- attr_payload = struct.pack("Q", int(value))
+ endian = NlAttr.format_byte_order(attr.byte_order)
+ attr_payload = struct.pack(f"{endian}Q", int(value))
elif attr["type"] == 'string':
attr_payload = str(value).encode('ascii') + b'\x00'
elif attr["type"] == 'binary':
@@ -415,11 +434,11 @@ class YnlFamily(SpecFamily):
elif attr_spec['type'] == 'u8':
decoded = attr.as_u8()
elif attr_spec['type'] == 'u16':
- decoded = attr.as_u16()
+ decoded = attr.as_u16(attr_spec.byte_order)
elif attr_spec['type'] == 'u32':
- decoded = attr.as_u32()
+ decoded = attr.as_u32(attr_spec.byte_order)
elif attr_spec['type'] == 'u64':
- decoded = attr.as_u64()
+ decoded = attr.as_u64(attr_spec.byte_order)
elif attr_spec["type"] == 'string':
decoded = attr.as_strz()
elif attr_spec["type"] == 'binary':
@@ -508,6 +527,17 @@ class YnlFamily(SpecFamily):
self.handle_ntf(nl_msg, gm)
+ def operation_do_attributes(self, name):
+ """
+ For a given operation name, find and return a supported
+ set of attributes (as a dict).
+ """
+ op = self.find_operation(name)
+ if not op:
+ return None
+
+ return op['do']['request']['attributes'].copy()
+
def _op(self, method, vals, dump=False):
op = self.ops[method]
@@ -540,9 +570,7 @@ class YnlFamily(SpecFamily):
self._decode_extack(msg, op.attr_set, nl_msg.extack)
if nl_msg.error:
- print("Netlink error:", os.strerror(-nl_msg.error))
- print(nl_msg)
- return
+ raise NlError(nl_msg)
if nl_msg.done:
if nl_msg.extack:
print("Netlink warning:")