1use netlink_packet_core::{
4 emit_u64, parse_u64, parse_u8, DecodeError, DefaultNla, Emitable,
5 ErrorContext, Nla, NlaBuffer, NlasIterator, Parseable, NLA_F_NESTED,
6};
7
8use crate::{EthtoolAttr, EthtoolHeader};
9
10const ETHTOOL_A_PAUSE_HEADER: u16 = 1;
11const ETHTOOL_A_PAUSE_AUTONEG: u16 = 2;
12const ETHTOOL_A_PAUSE_RX: u16 = 3;
13const ETHTOOL_A_PAUSE_TX: u16 = 4;
14const ETHTOOL_A_PAUSE_STATS: u16 = 5;
15
16const ETHTOOL_A_PAUSE_STAT_TX_FRAMES: u16 = 2;
17const ETHTOOL_A_PAUSE_STAT_RX_FRAMES: u16 = 3;
18
19#[derive(Debug, PartialEq, Eq, Clone)]
20pub enum EthtoolPauseStatAttr {
21 Rx(u64),
22 Tx(u64),
23 Other(DefaultNla),
24}
25
26impl Nla for EthtoolPauseStatAttr {
27 fn value_len(&self) -> usize {
28 match self {
29 Self::Rx(_) | Self::Tx(_) => 8,
30 Self::Other(attr) => attr.value_len(),
31 }
32 }
33
34 fn kind(&self) -> u16 {
35 match self {
36 Self::Rx(_) => ETHTOOL_A_PAUSE_STAT_RX_FRAMES,
37 Self::Tx(_) => ETHTOOL_A_PAUSE_STAT_RX_FRAMES,
38 Self::Other(attr) => attr.kind(),
39 }
40 }
41
42 fn emit_value(&self, buffer: &mut [u8]) {
43 match self {
44 Self::Rx(value) | Self::Tx(value) => {
45 emit_u64(buffer, *value).unwrap()
46 }
47 Self::Other(ref attr) => attr.emit_value(buffer),
48 }
49 }
50}
51
52impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
53 for EthtoolPauseStatAttr
54{
55 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
56 let payload = buf.value();
57 Ok(match buf.kind() {
58 ETHTOOL_A_PAUSE_STAT_TX_FRAMES => Self::Tx(
59 parse_u64(payload)
60 .context("invalid ETHTOOL_A_PAUSE_STAT_TX_FRAMES value")?,
61 ),
62 ETHTOOL_A_PAUSE_STAT_RX_FRAMES => Self::Rx(
63 parse_u64(payload)
64 .context("invalid ETHTOOL_A_PAUSE_STAT_RX_FRAMES value")?,
65 ),
66 _ => Self::Other(
67 DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?,
68 ),
69 })
70 }
71}
72
73#[derive(Debug, PartialEq, Eq, Clone)]
74pub enum EthtoolPauseAttr {
75 Header(Vec<EthtoolHeader>),
76 AutoNeg(bool),
77 Rx(bool),
78 Tx(bool),
79 Stats(Vec<EthtoolPauseStatAttr>),
80 Other(DefaultNla),
81}
82
83impl Nla for EthtoolPauseAttr {
84 fn value_len(&self) -> usize {
85 match self {
86 Self::Header(hdrs) => hdrs.as_slice().buffer_len(),
87 Self::AutoNeg(_) | Self::Rx(_) | Self::Tx(_) => 1,
88 Self::Stats(ref nlas) => nlas.as_slice().buffer_len(),
89 Self::Other(attr) => attr.value_len(),
90 }
91 }
92
93 fn kind(&self) -> u16 {
94 match self {
95 Self::Header(_) => ETHTOOL_A_PAUSE_HEADER | NLA_F_NESTED,
96 Self::AutoNeg(_) => ETHTOOL_A_PAUSE_AUTONEG,
97 Self::Rx(_) => ETHTOOL_A_PAUSE_RX,
98 Self::Tx(_) => ETHTOOL_A_PAUSE_TX,
99 Self::Stats(_) => ETHTOOL_A_PAUSE_STATS | NLA_F_NESTED,
100 Self::Other(attr) => attr.kind(),
101 }
102 }
103
104 fn emit_value(&self, buffer: &mut [u8]) {
105 match self {
106 Self::Header(ref nlas) => nlas.as_slice().emit(buffer),
107 Self::AutoNeg(value) | Self::Rx(value) | Self::Tx(value) => {
108 buffer[0] = *value as u8
109 }
110 Self::Stats(ref nlas) => nlas.as_slice().emit(buffer),
111 Self::Other(ref attr) => attr.emit(buffer),
112 }
113 }
114}
115
116impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
117 for EthtoolPauseAttr
118{
119 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
120 let payload = buf.value();
121 Ok(match buf.kind() {
122 ETHTOOL_A_PAUSE_HEADER => {
123 let mut nlas = Vec::new();
124 let error_msg = "failed to parse pause header attributes";
125 for nla in NlasIterator::new(payload) {
126 let nla = &nla.context(error_msg)?;
127 let parsed =
128 EthtoolHeader::parse(nla).context(error_msg)?;
129 nlas.push(parsed);
130 }
131 Self::Header(nlas)
132 }
133 ETHTOOL_A_PAUSE_AUTONEG => Self::AutoNeg(
134 parse_u8(payload)
135 .context("invalid ETHTOOL_A_PAUSE_AUTONEG value")?
136 == 1,
137 ),
138 ETHTOOL_A_PAUSE_RX => Self::Rx(
139 parse_u8(payload)
140 .context("invalid ETHTOOL_A_PAUSE_RX value")?
141 == 1,
142 ),
143 ETHTOOL_A_PAUSE_TX => Self::Tx(
144 parse_u8(payload)
145 .context("invalid ETHTOOL_A_PAUSE_TX value")?
146 == 1,
147 ),
148 ETHTOOL_A_PAUSE_STATS => {
149 let mut nlas = Vec::new();
150 let error_msg = "failed to parse pause stats attributes";
151 for nla in NlasIterator::new(payload) {
152 let nla = &nla.context(error_msg)?;
153 let parsed =
154 EthtoolPauseStatAttr::parse(nla).context(error_msg)?;
155 nlas.push(parsed);
156 }
157 Self::Stats(nlas)
158 }
159 _ => Self::Other(
160 DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?,
161 ),
162 })
163 }
164}
165
166pub(crate) fn parse_pause_nlas(
167 buffer: &[u8],
168) -> Result<Vec<EthtoolAttr>, DecodeError> {
169 let mut nlas = Vec::new();
170 for nla in NlasIterator::new(buffer) {
171 let error_msg =
172 format!("Failed to parse ethtool pause message attribute {nla:?}");
173 let nla = &nla.context(error_msg.clone())?;
174 let parsed = EthtoolPauseAttr::parse(nla).context(error_msg)?;
175 nlas.push(EthtoolAttr::Pause(parsed));
176 }
177 Ok(nlas)
178}