Skip to content

Commit 37f9c5c

Browse files
ffmanceracathay4t
authored andcommitted
hsr: support HSR interface
The patch is introducing HSR interface support. In addition, it is providing the InfoHsr Nla. This Nla is gathering all the IFLA_HSR_ netlink attributes. Unit test added. Signed-off-by: Fernando Fernandez Mancera <[email protected]>
1 parent 19f1435 commit 37f9c5c

File tree

2 files changed

+222
-0
lines changed

2 files changed

+222
-0
lines changed

src/rtnl/constants.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,16 @@ pub const VETH_INFO_PEER: u16 = 1;
523523
pub const IFLA_XFRM_UNSPEC: u16 = 0;
524524
pub const IFLA_XFRM_LINK: u16 = 1;
525525
pub const IFLA_XFRM_IF_ID: u16 = 2;
526+
pub const IFLA_HSR_UNSPEC: u16 = 0;
527+
pub const IFLA_HSR_SLAVE1: u16 = 1;
528+
pub const IFLA_HSR_SLAVE2: u16 = 2;
529+
pub const IFLA_HSR_MULTICAST_SPEC: u16 = 3;
530+
pub const IFLA_HSR_SUPERVISION_ADDR: u16 = 4;
531+
pub const IFLA_HSR_SEQ_NR: u16 = 5;
532+
pub const IFLA_HSR_VERSION: u16 = 6;
533+
pub const IFLA_HSR_PROTOCOL: u16 = 7;
534+
pub const HSR_PROTOCOL_HSR: u8 = 0;
535+
pub const HSR_PROTOCOL_PRP: u8 = 1;
526536

527537
pub const ARPHRD_NETROM: u16 = 0;
528538
pub const ARPHRD_ETHER: u16 = 1;

src/rtnl/link/nlas/link_infos.rs

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const IPOIB: &str = "ipoib";
4242
const WIREGUARD: &str = "wireguard";
4343
const XFRM: &str = "xfrm";
4444
const MACSEC: &str = "macsec";
45+
const HSR: &str = "hsr";
4546

4647
#[derive(Debug, PartialEq, Eq, Clone)]
4748
#[non_exhaustive]
@@ -337,6 +338,17 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for VecInfo {
337338
}
338339
InfoData::MacSec(v)
339340
}
341+
InfoKind::Hsr => {
342+
let mut v = Vec::new();
343+
let err = "failed to parse IFLA_INFO_DATA (IFLA_INFO_KIND is 'hsr')";
344+
for nla in NlasIterator::new(payload) {
345+
let nla = &nla.context(err)?;
346+
let parsed =
347+
InfoHsr::parse(nla).context(err)?;
348+
v.push(parsed);
349+
}
350+
InfoData::Hsr(v)
351+
}
340352
};
341353
res.push(Info::Data(info_data));
342354
} else {
@@ -383,6 +395,7 @@ pub enum InfoData {
383395
Wireguard(Vec<u8>),
384396
Xfrm(Vec<InfoXfrmTun>),
385397
MacSec(Vec<InfoMacSec>),
398+
Hsr(Vec<InfoHsr>),
386399
Other(Vec<u8>),
387400
}
388401

@@ -403,6 +416,7 @@ impl Nla for InfoData {
403416
Vxlan(ref nlas) => nlas.as_slice().buffer_len(),
404417
Xfrm(ref nlas) => nlas.as_slice().buffer_len(),
405418
MacSec(ref nlas) => nlas.as_slice().buffer_len(),
419+
Hsr(ref nlas) => nlas.as_slice().buffer_len(),
406420
Dummy(ref bytes)
407421
| Tun(ref bytes)
408422
| Nlmon(ref bytes)
@@ -437,6 +451,7 @@ impl Nla for InfoData {
437451
Vxlan(ref nlas) => nlas.as_slice().emit(buffer),
438452
Xfrm(ref nlas) => nlas.as_slice().emit(buffer),
439453
MacSec(ref nlas) => nlas.as_slice().emit(buffer),
454+
Hsr(ref nlas) => nlas.as_slice().emit(buffer),
440455
Dummy(ref bytes)
441456
| Tun(ref bytes)
442457
| Nlmon(ref bytes)
@@ -519,6 +534,7 @@ pub enum InfoKind {
519534
Wireguard,
520535
Xfrm,
521536
MacSec,
537+
Hsr,
522538
Other(String),
523539
}
524540

@@ -551,6 +567,7 @@ impl Nla for InfoKind {
551567
Wireguard => WIREGUARD.len(),
552568
Xfrm => XFRM.len(),
553569
MacSec => MACSEC.len(),
570+
Hsr => HSR.len(),
554571
Other(ref s) => s.len(),
555572
};
556573
len + 1
@@ -584,6 +601,7 @@ impl Nla for InfoKind {
584601
Wireguard => WIREGUARD,
585602
Xfrm => XFRM,
586603
MacSec => MACSEC,
604+
Hsr => HSR,
587605
Other(ref s) => s.as_str(),
588606
};
589607
buffer[..s.len()].copy_from_slice(s.as_bytes());
@@ -633,6 +651,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoKind {
633651
WIREGUARD => Wireguard,
634652
MACSEC => MacSec,
635653
XFRM => Xfrm,
654+
HSR => Hsr,
636655
_ => Other(s),
637656
})
638657
}
@@ -1228,6 +1247,131 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoMacSec {
12281247
}
12291248
}
12301249

1250+
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1251+
#[non_exhaustive]
1252+
pub enum HsrProtocol {
1253+
Hsr,
1254+
Prp,
1255+
Other(u8),
1256+
}
1257+
1258+
impl From<u8> for HsrProtocol {
1259+
fn from(d: u8) -> Self {
1260+
match d {
1261+
HSR_PROTOCOL_HSR => Self::Hsr,
1262+
HSR_PROTOCOL_PRP => Self::Prp,
1263+
_ => Self::Other(d),
1264+
}
1265+
}
1266+
}
1267+
1268+
impl From<HsrProtocol> for u8 {
1269+
fn from(d: HsrProtocol) -> Self {
1270+
match d {
1271+
HsrProtocol::Hsr => HSR_PROTOCOL_HSR,
1272+
HsrProtocol::Prp => HSR_PROTOCOL_PRP,
1273+
HsrProtocol::Other(value) => value,
1274+
}
1275+
}
1276+
}
1277+
1278+
#[derive(Debug, PartialEq, Eq, Clone)]
1279+
#[non_exhaustive]
1280+
pub enum InfoHsr {
1281+
Unspec(Vec<u8>),
1282+
Port1(u32),
1283+
Port2(u32),
1284+
MulticastSpec(u8),
1285+
SupervisionAddr([u8; 6]),
1286+
Version(u8),
1287+
SeqNr(u16),
1288+
Protocol(HsrProtocol),
1289+
Other(DefaultNla),
1290+
}
1291+
1292+
impl Nla for InfoHsr {
1293+
fn value_len(&self) -> usize {
1294+
use self::InfoHsr::*;
1295+
match self {
1296+
Unspec(bytes) => bytes.len(),
1297+
SupervisionAddr(_) => 6,
1298+
Port1(_) | Port2(_) => 4,
1299+
SeqNr(_) => 2,
1300+
MulticastSpec(_) | Version(_) | Protocol(_) => 1,
1301+
Other(nla) => nla.value_len(),
1302+
}
1303+
}
1304+
1305+
fn emit_value(&self, buffer: &mut [u8]) {
1306+
use self::InfoHsr::*;
1307+
match self {
1308+
Unspec(bytes) => buffer.copy_from_slice(bytes.as_slice()),
1309+
Port1(value) | Port2(value) => {
1310+
NativeEndian::write_u32(buffer, *value)
1311+
}
1312+
MulticastSpec(value) | Version(value) => buffer[0] = *value,
1313+
SeqNr(value) => NativeEndian::write_u16(buffer, *value),
1314+
Protocol(value) => buffer[0] = (*value).into(),
1315+
SupervisionAddr(ref value) => buffer.copy_from_slice(&value[..]),
1316+
Other(nla) => nla.emit_value(buffer),
1317+
}
1318+
}
1319+
1320+
fn kind(&self) -> u16 {
1321+
use self::InfoHsr::*;
1322+
match self {
1323+
Unspec(_) => IFLA_HSR_UNSPEC,
1324+
Port1(_) => IFLA_HSR_SLAVE1,
1325+
Port2(_) => IFLA_HSR_SLAVE2,
1326+
MulticastSpec(_) => IFLA_HSR_MULTICAST_SPEC,
1327+
SupervisionAddr(_) => IFLA_HSR_SUPERVISION_ADDR,
1328+
SeqNr(_) => IFLA_HSR_SEQ_NR,
1329+
Version(_) => IFLA_HSR_VERSION,
1330+
Protocol(_) => IFLA_HSR_PROTOCOL,
1331+
Other(nla) => nla.kind(),
1332+
}
1333+
}
1334+
}
1335+
1336+
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoHsr {
1337+
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
1338+
use self::InfoHsr::*;
1339+
let payload = buf.value();
1340+
Ok(match buf.kind() {
1341+
IFLA_HSR_UNSPEC => Unspec(payload.to_vec()),
1342+
IFLA_HSR_SLAVE1 => Port1(
1343+
parse_u32(payload).context("invalid IFLA_HSR_SLAVE1 value")?,
1344+
),
1345+
IFLA_HSR_SLAVE2 => Port2(
1346+
parse_u32(payload).context("invalid IFLA_HSR_SLAVE2 value")?,
1347+
),
1348+
IFLA_HSR_MULTICAST_SPEC => MulticastSpec(
1349+
parse_u8(payload)
1350+
.context("invalid IFLA_HSR_MULTICAST_SPEC value")?,
1351+
),
1352+
IFLA_HSR_SUPERVISION_ADDR => SupervisionAddr(
1353+
parse_mac(payload)
1354+
.context("invalid IFLA_HSR_SUPERVISION_ADDR value")?,
1355+
),
1356+
IFLA_HSR_SEQ_NR => SeqNr(
1357+
parse_u16(payload).context("invalid IFLA_HSR_SEQ_NR value")?,
1358+
),
1359+
IFLA_HSR_VERSION => Version(
1360+
parse_u8(payload).context("invalid IFLA_HSR_VERSION value")?,
1361+
),
1362+
IFLA_HSR_PROTOCOL => Protocol(
1363+
parse_u8(payload)
1364+
.context("invalid IFLA_HSR_PROTOCOL value")?
1365+
.into(),
1366+
),
1367+
kind => Other(
1368+
DefaultNla::parse(buf)
1369+
.context(format!("unknown NLA type {kind}"))?,
1370+
),
1371+
})
1372+
}
1373+
}
1374+
12311375
#[derive(Debug, PartialEq, Eq, Clone)]
12321376
#[non_exhaustive]
12331377
pub enum InfoXfrmTun {
@@ -2674,4 +2818,72 @@ mod tests {
26742818
nlas.as_slice().emit(&mut vec);
26752819
assert_eq!(&vec[..], &MACSEC[..]);
26762820
}
2821+
2822+
#[rustfmt::skip]
2823+
static HSR: [u8; 56] = [
2824+
0x08, 0x00, // L = 8
2825+
0x01, 0x00, // T = 1 (IFLA_INFO_KIND)
2826+
0x68, 0x73, 0x72, 0x00, // V = "hsr"
2827+
2828+
0x30, 0x00, // L = 48
2829+
0x02, 0x00, // T = 2 (IFLA_INFO_DATA)
2830+
2831+
0x08, 0x00, // L = 8
2832+
0x01, 0x00, // T = 1 (IFLA_HSR_SLAVE1)
2833+
0x18, 0x00, 0x00, 0x00, // V = 24
2834+
2835+
0x08, 0x00, // L = 8
2836+
0x02, 0x00, // T = 2 (IFLA_HSR_SLAVE2)
2837+
0x1a, 0x00, 0x00, 0x00, // V = 26
2838+
2839+
0x0a, 0x00, // L = 10
2840+
0x04, 0x00, // T = 4 (IFLA_HSR_SUPERVISION_ADDR)
2841+
0x01, 0x15, 0x4e, 0x00, 0x01, 0x2d, // V = "01:15:4e:00:01:2d"
2842+
0x00, 0x00, // padding
2843+
2844+
0x06, 0x00, // L = 6
2845+
0x05, 0x00, // T = 5 (IFLA_HSR_SEQ_NR)
2846+
0x4b, 0xfc, // V = 64587
2847+
0x00, 0x00, // padding
2848+
2849+
0x05, 0x00, // L = 5
2850+
0x07, 0x00, // T = 7 (IFLA_HSR_PROTOCOL)
2851+
0x01, // V = 1 (HSR_PROTOCOL_PRP)
2852+
0x00, 0x00, 0x00 // padding
2853+
];
2854+
2855+
lazy_static! {
2856+
static ref HSR_INFO: Vec<InfoHsr> = vec![
2857+
InfoHsr::Port1(24),
2858+
InfoHsr::Port2(26),
2859+
InfoHsr::SupervisionAddr([0x01, 0x15, 0x4e, 0x00, 0x01, 0x2d]),
2860+
InfoHsr::SeqNr(64587),
2861+
InfoHsr::Protocol(HsrProtocol::Prp),
2862+
];
2863+
}
2864+
2865+
#[test]
2866+
fn parse_info_hsr() {
2867+
let nla = NlaBuffer::new_checked(&HSR[..]).unwrap();
2868+
let parsed = VecInfo::parse(&nla).unwrap().0;
2869+
let expected = vec![
2870+
Info::Kind(InfoKind::Hsr),
2871+
Info::Data(InfoData::Hsr(HSR_INFO.clone())),
2872+
];
2873+
assert_eq!(expected, parsed);
2874+
}
2875+
2876+
#[test]
2877+
fn emit_info_hsr() {
2878+
let nlas = vec![
2879+
Info::Kind(InfoKind::Hsr),
2880+
Info::Data(InfoData::Hsr(HSR_INFO.clone())),
2881+
];
2882+
2883+
assert_eq!(nlas.as_slice().buffer_len(), HSR.len());
2884+
2885+
let mut vec = vec![0xff; HSR.len()];
2886+
nlas.as_slice().emit(&mut vec);
2887+
assert_eq!(&vec[..], &HSR[..]);
2888+
}
26772889
}

0 commit comments

Comments
 (0)