Skip to content

Commit 4d2ab22

Browse files
committed
More tests
1 parent 01298cc commit 4d2ab22

File tree

5 files changed

+149
-16
lines changed

5 files changed

+149
-16
lines changed

src/net/vxlan.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,16 @@ impl Vni {
3636
Self(vni)
3737
}
3838

39-
pub const MAX: u32 = (1 << 24) - 1;
40-
pub const MIN: u32 = 1;
39+
/// The largest legal VXLAN VNI
40+
pub const MAX: Self = Self((1 << 24) - 1);
41+
/// The smallest legal VXLAN VNI
42+
pub const MIN: Self = Self(1);
4143
}
4244

4345
impl TryFrom<u32> for Vni {
4446
type Error = DecodeError;
4547

46-
/// Creates a new `Vni` value from a `u32`.
48+
/// Creates a new `Vni` value from an `u32`.
4749
///
4850
/// # Errors
4951
/// Returns an error if the VNI is zero or greater than or equal to 2^24.
@@ -81,14 +83,19 @@ mod tests {
8183
assert!(Vni::new(0).is_err());
8284
}
8385

86+
#[test]
87+
fn min_vni_is_valid() {
88+
assert!(Vni::new(Vni::MIN.0).is_ok());
89+
}
90+
8491
#[test]
8592
fn max_vni_is_valid() {
86-
assert!(Vni::new(Vni::MAX).is_ok());
93+
assert!(Vni::new(Vni::MAX.0).is_ok());
8794
}
8895

8996
#[test]
9097
fn vni_greater_than_max_is_invalid() {
91-
assert!(Vni::new(Vni::MAX + 1).is_err());
98+
assert!(Vni::new(Vni::MAX.0 + 1).is_err());
9299
}
93100

94101
#[test]

src/tc/filters/cls_flower.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use crate::net::mpls;
2222
use crate::net::{ethernet, icmpv4, icmpv6};
2323
use crate::tc::filters::flower;
2424
use crate::tc::filters::flower::encap;
25+
use crate::tc::flower::encap::OptionsList;
2526
use crate::tc::{TcAction, TcFlowerOptionFlags, TcHandle};
2627
use crate::{EncKeyId, IpProtocol};
2728

@@ -501,8 +502,28 @@ impl Nla for TcFilterFlowerOption {
501502
Self::KeyEncIpTosMask(_) => TCA_FLOWER_KEY_ENC_IP_TOS_MASK,
502503
Self::KeyEncIpTtl(_) => TCA_FLOWER_KEY_ENC_IP_TTL,
503504
Self::KeyEncIpTtlMask(_) => TCA_FLOWER_KEY_ENC_IP_TTL_MASK,
504-
Self::KeyEncOpts(_) => TCA_FLOWER_KEY_ENC_OPTS,
505-
Self::KeyEncOptsMask(_) => TCA_FLOWER_KEY_ENC_OPTS_MASK,
505+
// NOTE: iproute2 is just not consistent with the use of the NLAF_NESTED flag
506+
// for encap options.
507+
Self::KeyEncOpts(OptionsList(opts)) => {
508+
TCA_FLOWER_KEY_ENC_OPTS
509+
| match opts {
510+
encap::Options::Geneve(_) => 0,
511+
encap::Options::Vxlan(_) => NLA_F_NESTED,
512+
encap::Options::Erspan(_) => 0,
513+
encap::Options::Gtp(_) => 0,
514+
encap::Options::Other(_) => 0,
515+
}
516+
}
517+
Self::KeyEncOptsMask(OptionsList(opts)) => {
518+
TCA_FLOWER_KEY_ENC_OPTS_MASK
519+
| match opts {
520+
encap::Options::Geneve(_) => 0,
521+
encap::Options::Vxlan(_) => NLA_F_NESTED,
522+
encap::Options::Erspan(_) => 0,
523+
encap::Options::Gtp(_) => 0,
524+
encap::Options::Other(_) => 0,
525+
}
526+
}
506527
Self::InHwCount(_) => TCA_FLOWER_IN_HW_COUNT,
507528
Self::KeyPortSrcMin(_) => TCA_FLOWER_KEY_PORT_SRC_MIN,
508529
Self::KeyPortSrcMax(_) => TCA_FLOWER_KEY_PORT_SRC_MAX,

src/tc/filters/flower/encap/geneve.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,16 +311,38 @@ mod tests {
311311

312312
#[test]
313313
fn options_parse_back_data() {
314-
let example = Options::Data(Data::new(vec![0x12345678, 0x9abcdef0]));
314+
let example = Options::Data(Data::new(vec![0x1234_5678, 0x9abc_def0]));
315315
let mut buffer = vec![0; example.buffer_len()];
316316
example.emit(&mut buffer);
317317
let parsed =
318318
Options::parse(&NlaBuffer::new_checked(&buffer).unwrap()).unwrap();
319319
assert_eq!(example, parsed);
320320
}
321321

322+
/// Setup
323+
///
324+
/// Create a scratch network interface and add a qdisc to it.
325+
///
326+
/// ```bash
327+
/// ip link add dev dummy type dummy
328+
/// tc qdisc add dev dummy clsact
329+
/// ```
330+
///
331+
/// Then capture the netlink request for
332+
///
333+
/// ```bash
334+
/// tc filter add dev vtep ingress protocol ip \
335+
/// flower \
336+
/// geneve_opts 1:1:abcdef01
337+
/// ```
338+
///
339+
/// # Modifications
340+
///
341+
/// * Removed cooked header (16 bytes)
342+
/// * Removed rtnetlink header (16 bytes)
322343
const RAW_CAP: &str = "000000003900000000000000f2ffffff080000000b000100666c6f776572000054000200200054001c0001000600010000010000050002000100000008000300abcdef01200055001c00010006000100ffff000005000200ff00000008000300ffffffff08001600000000000600080008000000";
323344

345+
/// Returns the message we expected to parse from [`RAW_CAP`].
324346
fn expected_message() -> TcMessage {
325347
TcMessage {
326348
header: TcHeader {
@@ -339,12 +361,12 @@ mod tests {
339361
Flower(KeyEncOpts(OptionsList(Geneve(vec![
340362
Options::Class(Class::new(1)),
341363
Options::Type(Type::new(1)),
342-
Options::Data(Data::new(vec![0xabcdef01])),
364+
Options::Data(Data::new(vec![0xabcd_ef01])),
343365
])))),
344366
Flower(KeyEncOptsMask(OptionsList(Geneve(vec![
345367
Options::Class(Class::new(65535)),
346368
Options::Type(Type::new(255)),
347-
Options::Data(Data::new(vec![4294967295])),
369+
Options::Data(Data::new(vec![0xffff_ffff])),
348370
])))),
349371
Flower(TcFilterFlowerOption::Flags(
350372
TcFlowerOptionFlags::empty(),

src/tc/filters/flower/encap/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use anyhow::Context;
2-
use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer, NlasIterator};
2+
use netlink_packet_utils::nla::{DefaultNla, Nla, NLA_F_NESTED, NlaBuffer, NlasIterator};
33
use netlink_packet_utils::{DecodeError, Emitable, Parseable};
44

55
use crate::tc::filters::cls_flower::TCA_FLOWER_KEY_ENC_OPTS;
@@ -18,7 +18,7 @@ const TCA_FLOWER_KEY_ENC_OPTS_GTP: u16 = 4;
1818
#[derive(Debug, PartialEq, Eq, Clone)]
1919
#[repr(transparent)]
2020
#[must_use]
21-
pub struct OptionsList(Options);
21+
pub struct OptionsList(pub(crate) Options);
2222

2323
impl OptionsList {
2424
pub fn new(options: Options) -> Self {
@@ -84,7 +84,7 @@ impl Nla for Options {
8484
fn kind(&self) -> u16 {
8585
match self {
8686
Self::Geneve(_) => TCA_FLOWER_KEY_ENC_OPTS_GENEVE,
87-
Self::Vxlan(_) => TCA_FLOWER_KEY_ENC_OPTS_VXLAN,
87+
Self::Vxlan(_) => TCA_FLOWER_KEY_ENC_OPTS_VXLAN | NLA_F_NESTED,
8888
Self::Erspan(_) => TCA_FLOWER_KEY_ENC_OPTS_ERSPAN,
8989
Self::Gtp(_) => TCA_FLOWER_KEY_ENC_OPTS_GTP,
9090
Self::Other(nla) => nla.kind(),

src/tc/filters/flower/encap/vxlan.rs

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer};
33
use netlink_packet_utils::parsers::parse_u32;
44
use netlink_packet_utils::{DecodeError, Parseable};
55

6-
const TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GPB: u16 = 1; /* u32 */
6+
const TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GPB: u16 = 1;
77

88
#[derive(Debug, PartialEq, Eq, Clone)]
99
#[non_exhaustive]
@@ -92,6 +92,16 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Gpb {
9292
mod tests {
9393
use netlink_packet_utils::Emitable;
9494

95+
use crate::net::ethernet::Ethertype;
96+
use crate::tc::flower::encap::{OptionsList, vxlan};
97+
use crate::tc::TcFilterFlowerOption::{
98+
KeyEncOpts, KeyEncOptsMask, KeyEthType,
99+
};
100+
use crate::tc::TcOption::Flower;
101+
use crate::tc::{TcAttribute, TcFilterFlowerOption, TcFlowerOptionFlags, TcHandle, TcHeader, TcMessage, TcMessageBuffer};
102+
use crate::AddressFamily;
103+
use crate::tc::flower::encap::Options::Vxlan;
104+
95105
use super::*;
96106

97107
#[test]
@@ -106,7 +116,7 @@ mod tests {
106116

107117
#[test]
108118
fn parse_back_gpb_example() {
109-
let example = Gpb::new(0x12345678);
119+
let example = Gpb::new(0x12_34_56_78);
110120
let mut buffer = vec![0; example.buffer_len()];
111121
example.emit(&mut buffer);
112122
let parsed =
@@ -126,11 +136,84 @@ mod tests {
126136

127137
#[test]
128138
fn parse_back_options_example() {
129-
let example = Options::Gpb(Gpb::new(0x12345678));
139+
let example = Options::Gpb(Gpb::new(0x12_34_56_78));
130140
let mut buffer = vec![0; example.buffer_len()];
131141
example.emit(&mut buffer);
132142
let parsed =
133143
Options::parse(&NlaBuffer::new_checked(&buffer).unwrap()).unwrap();
134144
assert_eq!(example, parsed);
135145
}
146+
147+
/// Setup
148+
///
149+
/// Create a scratch network interface and add a qdisc to it.
150+
///
151+
/// ```bash
152+
/// ip link add dev dummy type dummy
153+
/// tc qdisc add dev dummy clsact
154+
/// ```
155+
///
156+
/// Then capture the netlink request for
157+
///
158+
/// ```bash
159+
/// tc filter add dev vtep ingress protocol ip \
160+
/// flower \
161+
/// vxlan_opts 112
162+
/// ```
163+
///
164+
/// # Modifications
165+
///
166+
/// * Removed cooked header (16 bytes)
167+
/// * Removed rtnetlink header (16 bytes)
168+
const RAW_CAP: &str = "000000003900000000000000f2ffffff080000000b000100666c6f776572000034000200100054800c0002800800010070000000100055800c00028008000100ffffffff08001600000000000600080008000000";
169+
170+
/// Returns the message we expected to parse from [`RAW_CAP`].
171+
fn expected_message() -> TcMessage {
172+
TcMessage {
173+
header: TcHeader {
174+
family: AddressFamily::Unspec,
175+
index: 57,
176+
handle: TcHandle { major: 0, minor: 0 },
177+
parent: TcHandle {
178+
major: 65535,
179+
minor: 65522,
180+
},
181+
info: 8,
182+
},
183+
attributes: vec![
184+
TcAttribute::Kind("flower".to_string()),
185+
TcAttribute::Options(vec![
186+
Flower(KeyEncOpts(OptionsList(Vxlan(vec![
187+
Options::Gpb(Gpb::new(112))
188+
])))),
189+
Flower(KeyEncOptsMask(OptionsList(Vxlan(vec![
190+
Options::Gpb(Gpb::new(0xff_ff_ff_ff))
191+
])))),
192+
Flower(TcFilterFlowerOption::Flags(
193+
TcFlowerOptionFlags::empty(),
194+
)),
195+
Flower(KeyEthType(Ethertype::IPv4)),
196+
]),
197+
],
198+
}
199+
}
200+
201+
#[test]
202+
fn captured_parses_as_expected() {
203+
let raw_cap = hex::decode(RAW_CAP).unwrap();
204+
let expected = expected_message();
205+
let parsed =
206+
TcMessage::parse(&TcMessageBuffer::new_checked(&raw_cap).unwrap())
207+
.unwrap();
208+
assert_eq!(expected, parsed);
209+
}
210+
211+
#[test]
212+
fn expected_emits_as_captured() {
213+
let raw_cap = hex::decode(RAW_CAP).unwrap();
214+
let expected = expected_message();
215+
let mut buffer = vec![0; expected.buffer_len()];
216+
expected.emit(&mut buffer);
217+
assert_eq!(raw_cap, buffer);
218+
}
136219
}

0 commit comments

Comments
 (0)