netlink_packet_route/tc/
options.rs1use netlink_packet_core::{
4 DecodeError, DefaultNla, ErrorContext, Nla, NlaBuffer, NlasIterator,
5 Parseable, ParseableParametrized,
6};
7
8use super::{
9 TcFilterFlower, TcFilterFlowerOption, TcFilterMatchAll,
10 TcFilterMatchAllOption, TcFilterU32, TcFilterU32Option, TcQdiscFqCodel,
11 TcQdiscFqCodelOption, TcQdiscIngress, TcQdiscIngressOption,
12};
13
14#[derive(Debug, PartialEq, Eq, Clone)]
15#[non_exhaustive]
16pub enum TcOption {
17 FqCodel(TcQdiscFqCodelOption),
18 Ingress(TcQdiscIngressOption),
20 Flower(TcFilterFlowerOption),
22 U32(TcFilterU32Option),
23 MatchAll(TcFilterMatchAllOption),
25 Other(DefaultNla),
27}
28
29impl Nla for TcOption {
30 fn value_len(&self) -> usize {
31 match self {
32 Self::FqCodel(u) => u.value_len(),
33 Self::Ingress(u) => u.value_len(),
34 Self::U32(u) => u.value_len(),
35 Self::Flower(u) => u.value_len(),
36 Self::MatchAll(m) => m.value_len(),
37 Self::Other(o) => o.value_len(),
38 }
39 }
40
41 fn emit_value(&self, buffer: &mut [u8]) {
42 match self {
43 Self::FqCodel(u) => u.emit_value(buffer),
44 Self::Ingress(u) => u.emit_value(buffer),
45 Self::Flower(u) => u.emit_value(buffer),
46 Self::U32(u) => u.emit_value(buffer),
47 Self::MatchAll(m) => m.emit_value(buffer),
48 Self::Other(o) => o.emit_value(buffer),
49 }
50 }
51
52 fn kind(&self) -> u16 {
53 match self {
54 Self::FqCodel(u) => u.kind(),
55 Self::Ingress(u) => u.kind(),
56 Self::Flower(u) => u.kind(),
57 Self::U32(u) => u.kind(),
58 Self::MatchAll(m) => m.kind(),
59 Self::Other(o) => o.kind(),
60 }
61 }
62}
63
64impl<'a, T> ParseableParametrized<NlaBuffer<&'a T>, &str> for TcOption
65where
66 T: AsRef<[u8]> + ?Sized,
67{
68 fn parse_with_param(
69 buf: &NlaBuffer<&'a T>,
70 kind: &str,
71 ) -> Result<Self, DecodeError> {
72 Ok(match kind {
73 TcQdiscIngress::KIND => {
74 Self::Ingress(TcQdiscIngressOption::parse(buf).context(
75 "failed to parse ingress TCA_OPTIONS attributes",
76 )?)
77 }
78 TcFilterFlower::KIND => Self::Flower(
79 TcFilterFlowerOption::parse(buf)
80 .context("failed to parse flower TCA_OPTIONS attributes")?,
81 ),
82 TcQdiscFqCodel::KIND => {
83 Self::FqCodel(TcQdiscFqCodelOption::parse(buf).context(
84 "failed to parse fq_codel TCA_OPTIONS attributes",
85 )?)
86 }
87 TcFilterU32::KIND => Self::U32(
88 TcFilterU32Option::parse(buf)
89 .context("failed to parse u32 TCA_OPTIONS attributes")?,
90 ),
91 TcFilterMatchAll::KIND => {
92 Self::MatchAll(TcFilterMatchAllOption::parse(buf).context(
93 "failed to parse matchall TCA_OPTIONS attributes",
94 )?)
95 }
96 _ => Self::Other(DefaultNla::parse(buf)?),
97 })
98 }
99}
100
101pub(crate) struct VecTcOption(pub(crate) Vec<TcOption>);
102
103impl<'a, T> ParseableParametrized<NlaBuffer<&'a T>, &str> for VecTcOption
104where
105 T: AsRef<[u8]> + ?Sized,
106{
107 fn parse_with_param(
108 buf: &NlaBuffer<&'a T>,
109 kind: &str,
110 ) -> Result<VecTcOption, DecodeError> {
111 Ok(match kind {
112 TcFilterU32::KIND
113 | TcFilterMatchAll::KIND
114 | TcFilterFlower::KIND
115 | TcQdiscIngress::KIND
116 | TcQdiscFqCodel::KIND => {
117 let mut nlas = vec![];
118 for nla in NlasIterator::new(buf.value()) {
119 let nla = nla.context(format!(
120 "Invalid TCA_OPTIONS for kind: {kind}",
121 ))?;
122 nlas.push(
123 TcOption::parse_with_param(&nla, kind).context(
124 format!(
125 "Failed to parse TCA_OPTIONS for kind: {kind}",
126 ),
127 )?,
128 )
129 }
130 Self(nlas)
131 }
132 _ => Self(vec![TcOption::Other(DefaultNla::parse(buf)?)]),
137 })
138 }
139}