use netlink_packet_core::{DefaultNla, Emitable, NlaBuffer, Parseable};
use crate::{
tc::{
actions::{
message::{
TcActionMessage, TcActionMessageAttribute,
TcActionMessageAttribute::{
Actions, Flags, RootCount, RootExtWarnMsg, RootTimeDelta,
},
TcActionMessageFlags, TcActionMessageFlagsWithSelector,
},
TcActionMessageBuffer, TcActionMessageHeader,
},
TcAction,
TcActionAttribute::{Cookie, Index, Kind},
},
AddressFamily,
};
mod mirror {
use netlink_packet_core::{DefaultNla, Parseable};
use crate::{
tc::{
actions::{
message::{
TcActionMessage,
TcActionMessageAttribute::{Actions, RootCount},
},
TcActionMessageBuffer, TcActionMessageHeader,
},
TcAction,
TcActionAttribute::{InHwCount, Kind, Options, Other, Stats},
TcActionGeneric,
TcActionMirrorOption::{Parms, Tm},
TcActionOption::Mirror,
TcActionType::{Pipe, Stolen},
TcMirror,
TcMirrorActionType::{EgressRedir, IngressMirror},
TcStats2::{Basic, BasicHw, Queue},
TcStatsBasic, TcStatsQueue, Tcf,
},
AddressFamily,
};
mod message {
pub(super) const CREATE1: &[u8] = &[
0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x01, 0x00, 0x34, 0x00, 0x01,
0x00, 0x0b, 0x00, 0x01, 0x00, 0x6d, 0x69, 0x72, 0x72, 0x65, 0x64,
0x00, 0x00, 0x24, 0x00, 0x02, 0x80, 0x20, 0x00, 0x02, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00,
];
pub(super) const CREATE2: &[u8] = &[
0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x01, 0x00, 0x34, 0x00, 0x01,
0x00, 0x0b, 0x00, 0x01, 0x00, 0x6d, 0x69, 0x72, 0x72, 0x65, 0x64,
0x00, 0x00, 0x24, 0x00, 0x02, 0x80, 0x20, 0x00, 0x02, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00,
];
pub(super) const LIST: &[u8] = &[
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00,
0x00, 0x64, 0x01, 0x01, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x0b, 0x00,
0x01, 0x00, 0x6d, 0x69, 0x72, 0x72, 0x65, 0x64, 0x00, 0x00, 0x44,
0x00, 0x04, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x14, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0c, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48,
0x00, 0x02, 0x00, 0x20, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x24, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x01, 0x00, 0x0b, 0x00,
0x01, 0x00, 0x6d, 0x69, 0x72, 0x72, 0x65, 0x64, 0x00, 0x00, 0x44,
0x00, 0x04, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x14, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0c, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48,
0x00, 0x02, 0x00, 0x20, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x24, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
];
}
#[test]
fn parse_message1_create() {
let expected = TcActionMessage {
header: TcActionMessageHeader {
family: AddressFamily::Unspec,
},
attributes: vec![Actions(vec![TcAction {
tab: 1,
attributes: vec![
Kind("mirred".into()),
Options(vec![Mirror(Parms(TcMirror {
generic: TcActionGeneric {
index: 1,
capab: 0,
action: Stolen,
refcnt: 0,
bindcnt: 0,
},
eaction: EgressRedir,
ifindex: 1,
}))]),
],
}])],
};
let parsed = TcActionMessage::parse(
&TcActionMessageBuffer::new_checked(&message::CREATE1).unwrap(),
)
.unwrap();
assert_eq!(parsed, expected);
}
#[test]
fn parse_message2_create() {
let expected = TcActionMessage {
header: TcActionMessageHeader {
family: AddressFamily::Unspec,
},
attributes: vec![Actions(vec![TcAction {
tab: 1,
attributes: vec![
Kind("mirred".into()),
Options(vec![Mirror(Parms(TcMirror {
generic: TcActionGeneric {
index: 2,
capab: 0,
action: Pipe,
refcnt: 0,
bindcnt: 0,
},
eaction: IngressMirror,
ifindex: 1,
}))]),
],
}])],
};
let buf = message::CREATE2;
let parsed = TcActionMessage::parse(
&TcActionMessageBuffer::new_checked(&buf).unwrap(),
)
.unwrap();
assert_eq!(parsed, expected);
}
#[test]
#[allow(clippy::too_many_lines)]
fn parse_message3_list() {
let expected = TcActionMessage {
header: TcActionMessageHeader {
family: AddressFamily::Unspec,
},
attributes: vec![
RootCount(2),
Actions(vec![
TcAction {
tab: 0,
attributes: vec![
Kind("mirred".into()),
Stats(vec![
Basic(TcStatsBasic {
bytes: 0,
packets: 0,
}),
BasicHw(TcStatsBasic {
bytes: 0,
packets: 0,
}),
Queue(TcStatsQueue {
qlen: 0,
backlog: 0,
drops: 0,
requeues: 0,
overlimits: 0,
}),
]),
Other(DefaultNla::new(
9,
vec![0, 0, 0, 0, 3, 0, 0, 0],
)),
InHwCount(0),
Options(vec![
Mirror(Parms(TcMirror {
generic: TcActionGeneric {
index: 1,
capab: 0,
action: Stolen,
refcnt: 1,
bindcnt: 0,
},
eaction: EgressRedir,
ifindex: 1,
})),
Mirror(Tm(Tcf {
install: 0,
lastuse: 0,
expires: 0,
firstuse: 0,
})),
]),
],
},
TcAction {
tab: 1,
attributes: vec![
Kind("mirred".into()),
Stats(vec![
Basic(TcStatsBasic {
bytes: 0,
packets: 0,
}),
BasicHw(TcStatsBasic {
bytes: 0,
packets: 0,
}),
Queue(TcStatsQueue {
qlen: 0,
backlog: 0,
drops: 0,
requeues: 0,
overlimits: 0,
}),
]),
Other(DefaultNla::new(
9,
vec![0, 0, 0, 0, 3, 0, 0, 0],
)),
InHwCount(0),
Options(vec![
Mirror(Parms(TcMirror {
generic: TcActionGeneric {
index: 2,
capab: 0,
action: Pipe,
refcnt: 1,
bindcnt: 0,
},
eaction: IngressMirror,
ifindex: 1,
})),
Mirror(Tm(Tcf {
install: 0,
lastuse: 0,
expires: 0,
firstuse: 0,
})),
]),
],
},
]),
],
};
let parsed = TcActionMessage::parse(
&TcActionMessageBuffer::new_checked(&message::LIST).unwrap(),
)
.unwrap();
assert_eq!(parsed, expected);
}
}
#[test]
fn tc_action_message_attribute_parse_back_blank_actions() {
let orig = Actions(vec![]);
let mut buffer = vec![0; orig.buffer_len()];
orig.emit(&mut buffer);
let parsed = TcActionMessageAttribute::parse(
&NlaBuffer::new_checked(buffer.as_slice()).unwrap(),
)
.unwrap();
assert_eq!(orig, parsed);
}
#[test]
fn tc_action_message_attribute_parse_back_example_action() {
let orig = Actions(vec![TcAction {
tab: 9999,
attributes: vec![Kind("example".into())],
}]);
let mut buffer = vec![0; orig.buffer_len()];
orig.emit(&mut buffer);
let parsed = TcActionMessageAttribute::parse(
&NlaBuffer::new_checked(buffer.as_slice()).unwrap(),
)
.unwrap();
assert_eq!(orig, parsed);
}
#[test]
fn tc_action_message_attribute_parse_back_multiple_example_action() {
let orig = Actions(vec![
TcAction {
tab: 1111,
attributes: vec![Kind("example1".into())],
},
TcAction {
tab: 2222,
attributes: vec![
Kind("example2".into()),
Index(42),
Cookie(vec![1, 2, 3, 4, 5, 6]),
],
},
]);
let mut buffer = vec![0; orig.buffer_len()];
orig.emit(&mut buffer);
let parsed = TcActionMessageAttribute::parse(
&NlaBuffer::new_checked(buffer.as_slice()).unwrap(),
)
.unwrap();
assert_eq!(orig, parsed);
}
#[test]
fn tc_action_message_flags_parse_back_default() {
let orig = TcActionMessageFlagsWithSelector::default();
let mut buffer = vec![0; orig.buffer_len()];
orig.emit(&mut buffer);
let parsed = TcActionMessageFlagsWithSelector::parse(
&NlaBuffer::new_checked(buffer.as_slice()).unwrap(),
)
.unwrap();
assert_eq!(orig, parsed);
}
#[test]
fn tc_action_message_flags_parse_back_example_value() {
let orig = TcActionMessageFlagsWithSelector {
flags: TcActionMessageFlags::LargeDump
| TcActionMessageFlags::TerseDump,
selector: TcActionMessageFlags::LargeDump,
};
let mut buffer = vec![0; orig.buffer_len()];
orig.emit(&mut buffer);
let parsed = TcActionMessageFlagsWithSelector::parse(
&NlaBuffer::new_checked(buffer.as_slice()).unwrap(),
)
.unwrap();
assert_eq!(orig, parsed);
}
#[test]
fn tc_action_message_parse_back_default() {
let orig = TcActionMessage::default();
let mut buffer = vec![0; orig.buffer_len()];
orig.emit(&mut buffer);
let parsed = TcActionMessage::parse(
&TcActionMessageBuffer::new_checked(buffer.as_slice()).unwrap(),
)
.unwrap();
assert_eq!(orig, parsed);
}
#[test]
fn tc_action_message_parse_back_example_value() {
let orig = TcActionMessage {
header: TcActionMessageHeader {
family: AddressFamily::Alg,
},
attributes: vec![
Flags(TcActionMessageFlagsWithSelector {
flags: TcActionMessageFlags::LargeDump,
selector: TcActionMessageFlags::LargeDump,
}),
RootCount(42),
RootTimeDelta(43),
RootExtWarnMsg("hello".to_string()),
TcActionMessageAttribute::Other(DefaultNla::new(
99,
vec![1, 2, 3, 4],
)),
],
};
let mut buffer = vec![0; orig.buffer_len()];
orig.emit(&mut buffer);
let parsed = TcActionMessage::parse(
&TcActionMessageBuffer::new_checked(buffer.as_slice()).unwrap(),
)
.unwrap();
assert_eq!(orig, parsed);
}