Skip to content

Commit 2d33edb

Browse files
jreppnowcathay4t
authored andcommitted
add rich representation for VLAN QOS mapping
1 parent b6de604 commit 2d33edb

File tree

2 files changed

+158
-12
lines changed

2 files changed

+158
-12
lines changed

src/rtnl/constants.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,8 @@ pub const IFLA_VLAN_FLAGS: u16 = 2;
476476
pub const IFLA_VLAN_EGRESS_QOS: u16 = 3;
477477
pub const IFLA_VLAN_INGRESS_QOS: u16 = 4;
478478
pub const IFLA_VLAN_PROTOCOL: u16 = 5;
479+
pub const IFLA_VLAN_QOS_UNSPEC: u16 = 0;
480+
pub const IFLA_VLAN_QOS_MAPPING: u16 = 1;
479481
pub const IFLA_VRF_UNSPEC: u16 = 0;
480482
pub const IFLA_VRF_TABLE: u16 = 1;
481483
pub const IFLA_IPVLAN_UNSPEC: u16 = 0;

src/rtnl/link/nlas/link_infos.rs

Lines changed: 156 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -944,8 +944,8 @@ pub enum InfoVlan {
944944
Unspec(Vec<u8>),
945945
Id(u16),
946946
Flags((u32, u32)),
947-
EgressQos(Vec<u8>),
948-
IngressQos(Vec<u8>),
947+
EgressQos(Vec<VlanQosMapping>),
948+
IngressQos(Vec<VlanQosMapping>),
949949
Protocol(u16),
950950
}
951951

@@ -956,10 +956,10 @@ impl Nla for InfoVlan {
956956
match self {
957957
Id(_) | Protocol(_) => 2,
958958
Flags(_) => 8,
959-
Unspec(bytes)
960-
| EgressQos(bytes)
961-
| IngressQos(bytes)
962-
=> bytes.len(),
959+
Unspec(bytes) => bytes.len(),
960+
EgressQos(mappings)
961+
| IngressQos(mappings)
962+
=> mappings.as_slice().buffer_len(),
963963
}
964964
}
965965

@@ -968,10 +968,9 @@ impl Nla for InfoVlan {
968968
use self::InfoVlan::*;
969969
match self {
970970
Unspec(ref bytes)
971-
| EgressQos(ref bytes)
972-
| IngressQos(ref bytes)
973-
=> buffer.copy_from_slice(bytes),
974-
971+
=> buffer.copy_from_slice(bytes),
972+
EgressQos(ref mappings)
973+
| IngressQos(ref mappings) => mappings.as_slice().emit(buffer),
975974
Id(ref value)
976975
| Protocol(ref value)
977976
=> NativeEndian::write_u16(buffer, *value),
@@ -996,6 +995,16 @@ impl Nla for InfoVlan {
996995
}
997996
}
998997

998+
fn parse_mappings(payload: &[u8]) -> Result<Vec<VlanQosMapping>, DecodeError> {
999+
let mut mappings = Vec::new();
1000+
for nla in NlasIterator::new(payload) {
1001+
let nla = nla?;
1002+
let parsed = VlanQosMapping::parse(&nla)?;
1003+
mappings.push(parsed);
1004+
}
1005+
Ok(mappings)
1006+
}
1007+
9991008
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoVlan {
10001009
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
10011010
use self::InfoVlan::*;
@@ -1014,8 +1023,14 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoVlan {
10141023
let mask = parse_u32(&payload[4..]).context(err)?;
10151024
Flags((flags, mask))
10161025
}
1017-
IFLA_VLAN_EGRESS_QOS => EgressQos(payload.to_vec()),
1018-
IFLA_VLAN_INGRESS_QOS => IngressQos(payload.to_vec()),
1026+
IFLA_VLAN_EGRESS_QOS => EgressQos(
1027+
parse_mappings(payload)
1028+
.context("failed to parse IFLA_VLAN_EGRESS_QOS")?,
1029+
),
1030+
IFLA_VLAN_INGRESS_QOS => IngressQos(
1031+
parse_mappings(payload)
1032+
.context("failed to parse IFLA_VLAN_INGRESS_QOS")?,
1033+
),
10191034
IFLA_VLAN_PROTOCOL => Protocol(
10201035
parse_u16_be(payload)
10211036
.context("invalid IFLA_VLAN_PROTOCOL value")?,
@@ -1522,6 +1537,66 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoMacVtap {
15221537
}
15231538
}
15241539

1540+
#[derive(Debug, PartialEq, Eq, Clone)]
1541+
#[non_exhaustive]
1542+
pub enum VlanQosMapping {
1543+
Unspec(Vec<u8>),
1544+
Mapping { from: u32, to: u32 },
1545+
Other(DefaultNla),
1546+
}
1547+
1548+
impl Nla for VlanQosMapping {
1549+
fn value_len(&self) -> usize {
1550+
match self {
1551+
VlanQosMapping::Unspec(bytes) => bytes.len(),
1552+
VlanQosMapping::Mapping { .. } => 8,
1553+
VlanQosMapping::Other(nla) => nla.value_len(),
1554+
}
1555+
}
1556+
1557+
fn kind(&self) -> u16 {
1558+
match self {
1559+
VlanQosMapping::Unspec(_) => IFLA_VLAN_QOS_UNSPEC,
1560+
VlanQosMapping::Mapping { .. } => IFLA_VLAN_QOS_MAPPING,
1561+
VlanQosMapping::Other(nla) => nla.kind(),
1562+
}
1563+
}
1564+
1565+
fn emit_value(&self, buffer: &mut [u8]) {
1566+
use VlanQosMapping::*;
1567+
match self {
1568+
Unspec(payload) => buffer.copy_from_slice(payload),
1569+
Mapping { from, to } => {
1570+
NativeEndian::write_u32(buffer, *from);
1571+
NativeEndian::write_u32(&mut buffer[4..], *to);
1572+
}
1573+
Other(nla) => nla.emit_value(buffer),
1574+
}
1575+
}
1576+
}
1577+
1578+
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
1579+
for VlanQosMapping
1580+
{
1581+
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
1582+
use VlanQosMapping::*;
1583+
let payload = buf.value();
1584+
Ok(match buf.kind() {
1585+
IFLA_VLAN_QOS_UNSPEC => Unspec(payload.to_vec()),
1586+
IFLA_VLAN_QOS_MAPPING => Mapping {
1587+
from: parse_u32(&payload[..4])
1588+
.context("expected u32 from value")?,
1589+
to: parse_u32(&payload[4..])
1590+
.context("expected u32 to value")?,
1591+
},
1592+
kind => Other(
1593+
DefaultNla::parse(buf)
1594+
.context(format!("unknown NLA type {kind}"))?,
1595+
),
1596+
})
1597+
}
1598+
}
1599+
15251600
#[cfg(test)]
15261601
mod tests {
15271602
use super::*;
@@ -2199,4 +2274,73 @@ mod tests {
21992274
nlas.as_slice().emit(&mut vec);
22002275
assert_eq!(&vec[..], &BRIDGE[..]);
22012276
}
2277+
2278+
#[rustfmt::skip]
2279+
static VLAN: [u8; 68] = [
2280+
0x09, 0x00, // length = 9
2281+
0x01, 0x00, // type = 1 = IFLA_INFO_KIND
2282+
0x76, 0x6c, 0x61, 0x6e, 0x00, // V = "vlan\0"
2283+
0x00, 0x00, 0x00, // padding
2284+
0x38, 0x00, // length = 56
2285+
0x02, 0x00, // type = 2 = IFLA_INFO_DATA
2286+
0x06, 0x00, // length - 6
2287+
0x01, 0x00, // type = 1 = IFLA_VLAN_ID
2288+
0x4b, 0x00, // id = 0x4b = 75
2289+
0x00, 0x00, // padding
2290+
0x10, 0x00, // length = 16
2291+
0x03, 0x00, // type = 3 = IFLA_VLAN_EGRESS_QOS_MAPPING
2292+
0x0c, 0x00, // length = 12
2293+
0x01, 0x00, // type = 1 = IFLA_VLAN_QOS_MAPPING
2294+
0x03, 0x00, 0x00, 0x00, // from = 3
2295+
0x04, 0x00, 0x00, 0x00, // to = 4
2296+
0x1c, 0x00, // length = 44
2297+
0x04, 0x00, // type = 4 = IFLA_VLAN_INGRESS_QOS_MAPPING
2298+
0x0c, 0x00, // length = 12
2299+
0x01, 0x00, // type = 1 = IFLA_VLAN_QOS_MAPPING
2300+
0x00, 0x00, 0x00, 0x00, // from = 0
2301+
0x01, 0x00, 0x00, 0x00, // to = 1
2302+
0x0c, 0x00, // length = 12
2303+
0x01, 0x00, // type = 1 = IFLA_VLAN_QOS_MAPPING
2304+
0x01, 0x00, 0x00, 0x00, // from = 1
2305+
0x02, 0x00, 0x00, 0x00, // to = 2
2306+
];
2307+
2308+
lazy_static! {
2309+
static ref VLAN_INFO: Vec<InfoVlan> = vec![
2310+
InfoVlan::Id(75),
2311+
InfoVlan::EgressQos(vec![VlanQosMapping::Mapping {
2312+
from: 3,
2313+
to: 4
2314+
}]),
2315+
InfoVlan::IngressQos(vec![
2316+
VlanQosMapping::Mapping { from: 0, to: 1 },
2317+
VlanQosMapping::Mapping { from: 1, to: 2 }
2318+
]),
2319+
];
2320+
}
2321+
2322+
#[test]
2323+
fn parse_info_vlan() {
2324+
let nla = NlaBuffer::new_checked(&VLAN[..]).unwrap();
2325+
let parsed = VecInfo::parse(&nla).unwrap().0;
2326+
let expected = vec![
2327+
Info::Kind(InfoKind::Vlan),
2328+
Info::Data(InfoData::Vlan(VLAN_INFO.clone())),
2329+
];
2330+
assert_eq!(expected, parsed);
2331+
}
2332+
2333+
#[test]
2334+
fn emit_info_vlan() {
2335+
let nlas = vec![
2336+
Info::Kind(InfoKind::Vlan),
2337+
Info::Data(InfoData::Vlan(VLAN_INFO.clone())),
2338+
];
2339+
2340+
assert_eq!(nlas.as_slice().buffer_len(), VLAN.len());
2341+
2342+
let mut vec = vec![0xff; VLAN.len()];
2343+
nlas.as_slice().emit(&mut vec);
2344+
assert_eq!(&vec[..], &VLAN[..]);
2345+
}
22022346
}

0 commit comments

Comments
 (0)