netlink_packet_route/rtnl/tc/
message.rs1use anyhow::Context;
4use netlink_packet_utils::{
5 nla::{DefaultNla, NlasIterator},
6 parsers::{parse_string, parse_u8},
7 traits::{Emitable, Parseable, ParseableParametrized},
8 DecodeError,
9};
10
11use crate::{
12 constants::*,
13 nlas::tc::{Nla, Stats, Stats2, StatsBuffer, TcOpt},
14 TcMessageBuffer, TC_HEADER_LEN,
15};
16
17#[derive(Debug, PartialEq, Eq, Clone, Default)]
18#[non_exhaustive]
19pub struct TcMessage {
20 pub header: TcHeader,
21 pub nlas: Vec<Nla>,
22}
23
24impl TcMessage {
25 pub fn into_parts(self) -> (TcHeader, Vec<Nla>) {
26 (self.header, self.nlas)
27 }
28
29 pub fn from_parts(header: TcHeader, nlas: Vec<Nla>) -> Self {
30 TcMessage { header, nlas }
31 }
32
33 pub fn with_index(index: i32) -> Self {
35 Self {
36 header: TcHeader {
37 index,
38 ..Default::default()
39 },
40 nlas: Vec::new(),
41 }
42 }
43}
44
45#[derive(Debug, PartialEq, Eq, Clone, Default)]
46pub struct TcHeader {
47 pub family: u8,
48 pub index: i32,
50 pub handle: u32,
52 pub parent: u32,
54 pub info: u32,
55}
56
57impl Emitable for TcHeader {
58 fn buffer_len(&self) -> usize {
59 TC_HEADER_LEN
60 }
61
62 fn emit(&self, buffer: &mut [u8]) {
63 let mut packet = TcMessageBuffer::new(buffer);
64 packet.set_family(self.family);
65 packet.set_index(self.index);
66 packet.set_handle(self.handle);
67 packet.set_parent(self.parent);
68 packet.set_info(self.info);
69 }
70}
71
72impl Emitable for TcMessage {
73 fn buffer_len(&self) -> usize {
74 self.header.buffer_len() + self.nlas.as_slice().buffer_len()
75 }
76
77 fn emit(&self, buffer: &mut [u8]) {
78 self.header.emit(buffer);
79 self.nlas
80 .as_slice()
81 .emit(&mut buffer[self.header.buffer_len()..]);
82 }
83}
84
85impl<T: AsRef<[u8]>> Parseable<TcMessageBuffer<T>> for TcHeader {
86 fn parse(buf: &TcMessageBuffer<T>) -> Result<Self, DecodeError> {
87 Ok(Self {
88 family: buf.family(),
89 index: buf.index(),
90 handle: buf.handle(),
91 parent: buf.parent(),
92 info: buf.info(),
93 })
94 }
95}
96
97impl<'a, T: AsRef<[u8]> + 'a> Parseable<TcMessageBuffer<&'a T>> for TcMessage {
98 fn parse(buf: &TcMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
99 Ok(Self {
100 header: TcHeader::parse(buf)
101 .context("failed to parse tc message header")?,
102 nlas: Vec::<Nla>::parse(buf)
103 .context("failed to parse tc message NLAs")?,
104 })
105 }
106}
107
108impl<'a, T: AsRef<[u8]> + 'a> Parseable<TcMessageBuffer<&'a T>> for Vec<Nla> {
109 fn parse(buf: &TcMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
110 let mut nlas = vec![];
111 let mut kind = String::new();
112
113 for nla_buf in buf.nlas() {
114 let buf = nla_buf.context("invalid tc nla")?;
115 let payload = buf.value();
116 let nla = match buf.kind() {
117 TCA_UNSPEC => Nla::Unspec(payload.to_vec()),
118 TCA_KIND => {
119 kind = parse_string(payload).context("invalid TCA_KIND")?;
120 Nla::Kind(kind.clone())
121 }
122 TCA_OPTIONS => {
123 let mut nlas = vec![];
124 for nla in NlasIterator::new(payload) {
125 let nla = nla.context("invalid TCA_OPTIONS")?;
126 nlas.push(
127 TcOpt::parse_with_param(&nla, &kind)
128 .context("failed to parse TCA_OPTIONS")?,
129 )
130 }
131 Nla::Options(nlas)
132 }
133 TCA_STATS => Nla::Stats(
134 Stats::parse(
135 &StatsBuffer::new_checked(payload)
136 .context("invalid TCA_STATS")?,
137 )
138 .context("failed to parse TCA_STATS")?,
139 ),
140 TCA_XSTATS => Nla::XStats(payload.to_vec()),
141 TCA_RATE => Nla::Rate(payload.to_vec()),
142 TCA_FCNT => Nla::Fcnt(payload.to_vec()),
143 TCA_STATS2 => {
144 let mut nlas = vec![];
145 for nla in NlasIterator::new(payload) {
146 let nla = nla.context("invalid TCA_STATS2")?;
147 nlas.push(
148 Stats2::parse(&nla)
149 .context("failed to parse TCA_STATS2")?,
150 );
151 }
152 Nla::Stats2(nlas)
153 }
154 TCA_STAB => Nla::Stab(payload.to_vec()),
155 TCA_CHAIN => Nla::Chain(payload.to_vec()),
156 TCA_HW_OFFLOAD => Nla::HwOffload(
157 parse_u8(payload)
158 .context("failed to parse TCA_HW_OFFLOAD")?,
159 ),
160 _ => Nla::Other(
161 DefaultNla::parse(&buf)
162 .context("failed to parse tc nla")?,
163 ),
164 };
165
166 nlas.push(nla);
167 }
168 Ok(nlas)
169 }
170}