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