Skip to content

Commit c514c3a

Browse files
committed
link: Add initial support of IFLA_DPLL_PIN
It require real hardware to test capture, hence no real unit test case. Signed-off-by: Gris Ge <cnfourt@gmail.com>
1 parent a596b46 commit c514c3a

6 files changed

Lines changed: 124 additions & 2 deletions

File tree

src/link/attribute.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use super::{
2424
af_spec::VecAfSpecUnspec,
2525
buffer_tool::expand_buffer_if_small,
2626
devlink_port::DevlinkPort,
27+
dpll_pin::DpllPin,
2728
ext_mask::VecLinkExtentMask,
2829
link_info::VecLinkInfo,
2930
proto_info::VecLinkProtoInfoInet6,
@@ -104,7 +105,7 @@ const IFLA_ALLMULTI: u16 = 61;
104105
const IFLA_DEVLINK_PORT: u16 = 62;
105106
const IFLA_GSO_IPV4_MAX_SIZE: u16 = 63;
106107
const IFLA_GRO_IPV4_MAX_SIZE: u16 = 64;
107-
// const IFLA_DPLL_PIN: u16 = 65;
108+
const IFLA_DPLL_PIN: u16 = 65;
108109
// const IFLA_MAX_PACING_OFFLOAD_HORIZON: u16 = 66;
109110
const IFLA_NETNS_IMMUTABLE: u16 = 67;
110111
// const IFLA_HEADROOM: u16 = 68;
@@ -183,6 +184,7 @@ pub enum LinkAttribute {
183184
GroIpv4MaxSize(u32),
184185
NetnsImmutable(bool),
185186
DevlinkPort(Vec<DevlinkPort>),
187+
DpllPin(Vec<DpllPin>),
186188
Other(DefaultNla),
187189
}
188190

@@ -256,6 +258,7 @@ impl Nla for LinkAttribute {
256258
Self::AfSpecUnspec(nlas) => nlas.as_slice().buffer_len(),
257259
Self::AfSpecBridge(nlas) => nlas.as_slice().buffer_len(),
258260
Self::DevlinkPort(nlas) => nlas.as_slice().buffer_len(),
261+
Self::DpllPin(nlas) => nlas.as_slice().buffer_len(),
259262
Self::ProtoInfoUnknown(attr) => attr.value_len(),
260263
Self::Wireless(v) => v.buffer_len(),
261264
Self::Other(attr) => attr.value_len(),
@@ -339,6 +342,7 @@ impl Nla for LinkAttribute {
339342
Self::AfSpecUnspec(nlas) => nlas.as_slice().emit(buffer),
340343
Self::AfSpecBridge(nlas) => nlas.as_slice().emit(buffer),
341344
Self::DevlinkPort(nlas) => nlas.as_slice().emit(buffer),
345+
Self::DpllPin(nlas) => nlas.as_slice().emit(buffer),
342346
Self::Wireless(v) => v.emit(buffer),
343347
Self::ProtoInfoUnknown(attr) | Self::Other(attr) => {
344348
attr.emit_value(buffer)
@@ -411,6 +415,7 @@ impl Nla for LinkAttribute {
411415
Self::GroIpv4MaxSize(_) => IFLA_GRO_IPV4_MAX_SIZE,
412416
Self::NetnsImmutable(_) => IFLA_NETNS_IMMUTABLE,
413417
Self::DevlinkPort(_) => IFLA_DEVLINK_PORT | NLA_F_NESTED,
418+
Self::DpllPin(_) => IFLA_DPLL_PIN | NLA_F_NESTED,
414419
Self::Other(attr) => attr.kind(),
415420
}
416421
}
@@ -781,6 +786,16 @@ impl<'a, T: AsRef<[u8]> + ?Sized>
781786
}
782787
Self::DevlinkPort(nlas)
783788
}
789+
IFLA_DPLL_PIN => {
790+
let err = "invalid IFLA_DPLL_PIN value";
791+
let mut nlas = vec![];
792+
for nla in NlasIterator::new(payload) {
793+
let nla = &nla.context(err)?;
794+
let parsed = DpllPin::parse(nla).context(err)?;
795+
nlas.push(parsed);
796+
}
797+
Self::DpllPin(nlas)
798+
}
784799
kind => Self::Other(
785800
DefaultNla::parse(buf)
786801
.context(format!("unknown NLA type {kind}"))?,

src/link/dpll_pin.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
// TODO: If you have hardware to simulate DPLL pins, please add unit tests for
4+
// this module.
5+
6+
use netlink_packet_core::{
7+
emit_u32, parse_u32, DecodeError, DefaultNla, ErrorContext, Nla, NlaBuffer,
8+
Parseable,
9+
};
10+
11+
const DPLL_A_PIN_ID: u16 = 1;
12+
13+
#[derive(Debug, PartialEq, Eq, Clone)]
14+
#[non_exhaustive]
15+
pub enum DpllPin {
16+
/// The unique pin identifier within the DPLL subsystem.
17+
PinId(u32),
18+
Other(DefaultNla),
19+
}
20+
21+
impl Nla for DpllPin {
22+
fn value_len(&self) -> usize {
23+
match self {
24+
Self::PinId(_) => 4,
25+
Self::Other(nla) => nla.value_len(),
26+
}
27+
}
28+
29+
fn emit_value(&self, buffer: &mut [u8]) {
30+
match self {
31+
Self::PinId(v) => emit_u32(buffer, *v).unwrap(),
32+
Self::Other(nla) => nla.emit_value(buffer),
33+
}
34+
}
35+
36+
fn kind(&self) -> u16 {
37+
match self {
38+
Self::PinId(_) => DPLL_A_PIN_ID,
39+
Self::Other(nla) => nla.kind(),
40+
}
41+
}
42+
}
43+
44+
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for DpllPin {
45+
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
46+
let payload = buf.value();
47+
Ok(match buf.kind() {
48+
DPLL_A_PIN_ID => Self::PinId(
49+
parse_u32(payload).context("invalid DPLL_A_PIN_ID value")?,
50+
),
51+
_ => {
52+
Self::Other(DefaultNla::parse(buf).context(format!(
53+
"unknown DPLL_A_PIN type {}",
54+
buf.kind()
55+
))?)
56+
}
57+
})
58+
}
59+
}

src/link/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod attribute;
55
mod buffer_tool;
66
mod devlink_port;
77
mod down_reason;
8+
mod dpll_pin;
89
mod event;
910
pub(crate) mod ext_mask;
1011
mod header;
@@ -39,6 +40,7 @@ pub use self::{
3940
attribute::LinkAttribute,
4041
devlink_port::DevlinkPort,
4142
down_reason::LinkProtocolDownReason,
43+
dpll_pin::DpllPin,
4244
event::LinkEvent,
4345
ext_mask::LinkExtentMask,
4446
header::{LinkHeader, LinkMessageBuffer},

src/link/tests/bridge.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1218,7 +1218,7 @@ fn test_bridge_netns_immutable() {
12181218
port: 0,
12191219
}),
12201220
LinkAttribute::DevlinkPort(vec![]),
1221-
LinkAttribute::Other(DefaultNla::new(32833, vec![])),
1221+
LinkAttribute::DpllPin(vec![]),
12221222
],
12231223
};
12241224

src/link/tests/dpll_pin.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use netlink_packet_core::{Emitable, NlaBuffer, Parseable};
4+
5+
use crate::link::dpll_pin::DpllPin;
6+
7+
// A nested IFLA_DPLL_PIN containing a single DPLL_A_PIN_ID = 42
8+
// 8 bytes total: 4-byte NLA header + 4-byte u32 value
9+
static DPLL_PIN_ID: [u8; 8] = [
10+
0x08, 0x00, // length = 8
11+
0x01, 0x00, // type = 1 = DPLL_A_PIN_ID
12+
0x2a, 0x00, 0x00, 0x00, // value = 42 (little-endian)
13+
];
14+
15+
#[test]
16+
fn parse_dpll_pin_id() {
17+
let nla = NlaBuffer::new_checked(&DPLL_PIN_ID[..]).unwrap();
18+
let parsed = DpllPin::parse(&nla).unwrap();
19+
assert_eq!(parsed, DpllPin::PinId(42));
20+
}
21+
22+
#[test]
23+
fn emit_dpll_pin_id() {
24+
let nla = DpllPin::PinId(42);
25+
assert_eq!(nla.buffer_len(), 8);
26+
27+
let mut buf = vec![0u8; 8];
28+
nla.emit(&mut buf);
29+
assert_eq!(&buf[..], &DPLL_PIN_ID[..]);
30+
}
31+
32+
#[test]
33+
fn parse_unknown_dpll_pin_attr() {
34+
// An NLA with type=99 (unknown), value = [0xde, 0xad]
35+
let raw: [u8; 8] = [
36+
0x06, 0x00, // length = 6
37+
0x63, 0x00, // type = 99 (unknown)
38+
0xde, 0xad, // value bytes
39+
0x00, 0x00, // padding
40+
];
41+
let nla = NlaBuffer::new_checked(&raw[..]).unwrap();
42+
let parsed = DpllPin::parse(&nla).unwrap();
43+
assert!(matches!(parsed, DpllPin::Other(_)));
44+
}

src/link/tests/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ mod bond;
77
#[cfg(test)]
88
mod bridge;
99
#[cfg(test)]
10+
mod dpll_pin;
11+
#[cfg(test)]
1012
mod geneve;
1113
#[cfg(test)]
1214
mod gre;

0 commit comments

Comments
 (0)