Skip to content

Add more parsing to tc module #75

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,21 @@ crate directly.
changed netlink attribute. To capture the netlink raw bytes, you may use
tcpdump/wireshark again the `nlmon` interface. For example:

* The integration test(play with linux kernel netlink interface) should be
placed into `rtnetlink` crate. Current(netlink-packet-route) crate should
only unit test case only.

```bash
modprobe nlmon
ip link add nl0 type nlmon
ip link set nl0 up
tcpdump -i nl0 -w netlink_capture_file.cap
# Then use wireshark to open this `netlink_capture_file.cap`
# Find out the packet you are interested,
# right click -> "Copy" -> "...as Hex Dump".
# You may use https://github.com/cathay4t/hex_to_rust to convert this
# hexdump to rust u8 array
```
* The integration test(play with linux kernel netlink interface) should be
placed into `rtnetlink` crate. Current(netlink-packet-route) crate should
only unit test case only.


* For certain netlink message which cannot captured by nlmon, please use
Rust Debug and explain every bits in comment.
Expand Down
4 changes: 4 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
* Only tc has unparsed `Vec<u8>` left.
* Still has many flags not converted into `Vec<enum>`.
* Many place holders in `link::InfoData`.
* Missing unit test cases.
2 changes: 1 addition & 1 deletion src/link/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub struct LinkHeader {
/// Link index.
pub index: u32,
/// Link type. It should be set to one of the `ARPHRD_*`
/// constants. The most common value is [ALinkLayerType::ETHER] for
/// constants. The most common value is [LinkLayerType::Ether] for
/// Ethernet.
/// The LinkLayerType has `From<u16>` and `From<LinkLayerType> for u16`
/// implemented.
Expand Down
2 changes: 0 additions & 2 deletions src/route/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ const RTM_F_OFFLOAD: u32 = 0x4000;
const RTM_F_TRAP: u32 = 0x8000;
const RTM_F_OFFLOAD_FAILED: u32 = 0x20000000;

/// Flags that can be set in a `RTM_GETROUTE`
/// ([`RouteNetlinkMessage::GetRoute`]) message.
#[derive(Clone, Eq, PartialEq, Debug, Copy)]
#[non_exhaustive]
pub enum RouteFlag {
Expand Down
4 changes: 2 additions & 2 deletions src/route/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ impl<'a, T: AsRef<[u8]> + ?Sized> RouteMessageBuffer<&'a T> {
/// messages headers.
#[derive(Debug, PartialEq, Eq, Clone, Default)]
pub struct RouteHeader {
/// Address family of the route: either [AddressFamily::Ipv4] for IPv4,
/// or [AddressFamily::Ipv6] for IPv6.
/// Address family of the route: either [AddressFamily::Inet] for IPv4,
/// or [AddressFamily::Inet6] for IPv6.
pub address_family: AddressFamily,
/// Prefix length of the destination subnet.
pub destination_prefix_length: u8,
Expand Down
2 changes: 1 addition & 1 deletion src/rule/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub enum RuleAttribute {
Source(IpAddr),
/// input interface name
Iifname(String),
/// The priority number of another rule for [RuleAction::Goto]
/// The priority number of another rule for [super::RuleAction::Goto]
Goto(u32),
Priority(u32),
FwMark(u32),
Expand Down
2 changes: 0 additions & 2 deletions src/rule/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ const FIB_RULE_IIF_DETACHED: u32 = 0x00000008;
const FIB_RULE_DEV_DETACHED: u32 = FIB_RULE_IIF_DETACHED;
const FIB_RULE_OIF_DETACHED: u32 = 0x00000010;

/// Flags that can be set in a `RTM_GETROUTE`
/// ([`RuleNetlinkMessage::GetRule`]) message.
#[derive(Clone, Eq, PartialEq, Debug, Copy)]
#[non_exhaustive]
pub enum RuleFlag {
Expand Down
70 changes: 67 additions & 3 deletions src/tc/actions/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ where
pub struct TcActionGeneric {
pub index: u32,
pub capab: u32,
pub action: i32,
pub action: TcActionType,
pub refcnt: i32,
pub bindcnt: i32,
}
Expand All @@ -267,7 +267,7 @@ impl Emitable for TcActionGeneric {
let mut packet = TcActionGenericBuffer::new(buffer);
packet.set_index(self.index);
packet.set_capab(self.capab);
packet.set_action(self.action);
packet.set_action(self.action.into());
packet.set_refcnt(self.refcnt);
packet.set_bindcnt(self.bindcnt);
}
Expand All @@ -278,9 +278,73 @@ impl<T: AsRef<[u8]>> Parseable<TcActionGenericBuffer<T>> for TcActionGeneric {
Ok(Self {
index: buf.index(),
capab: buf.capab(),
action: buf.action(),
action: buf.action().into(),
refcnt: buf.refcnt(),
bindcnt: buf.bindcnt(),
})
}
}

const TC_ACT_UNSPEC: i32 = -1;
const TC_ACT_OK: i32 = 0;
const TC_ACT_RECLASSIFY: i32 = 1;
const TC_ACT_SHOT: i32 = 2;
const TC_ACT_PIPE: i32 = 3;
const TC_ACT_STOLEN: i32 = 4;
const TC_ACT_QUEUED: i32 = 5;
const TC_ACT_REPEAT: i32 = 6;
const TC_ACT_REDIRECT: i32 = 7;
const TC_ACT_TRAP: i32 = 8;

#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
#[non_exhaustive]
pub enum TcActionType {
#[default]
Unspec,
Ok,
Reclassify,
Shot,
Pipe,
Stolen,
Queued,
Repeat,
Redirect,
Trap,
Other(i32),
}

impl From<i32> for TcActionType {
fn from(d: i32) -> Self {
match d {
TC_ACT_UNSPEC => Self::Unspec,
TC_ACT_OK => Self::Ok,
TC_ACT_RECLASSIFY => Self::Reclassify,
TC_ACT_SHOT => Self::Shot,
TC_ACT_PIPE => Self::Pipe,
TC_ACT_STOLEN => Self::Stolen,
TC_ACT_QUEUED => Self::Queued,
TC_ACT_REPEAT => Self::Repeat,
TC_ACT_REDIRECT => Self::Redirect,
TC_ACT_TRAP => Self::Trap,
_ => Self::Other(d),
}
}
}

impl From<TcActionType> for i32 {
fn from(v: TcActionType) -> i32 {
match v {
TcActionType::Unspec => TC_ACT_UNSPEC,
TcActionType::Ok => TC_ACT_OK,
TcActionType::Reclassify => TC_ACT_RECLASSIFY,
TcActionType::Shot => TC_ACT_SHOT,
TcActionType::Pipe => TC_ACT_PIPE,
TcActionType::Stolen => TC_ACT_STOLEN,
TcActionType::Queued => TC_ACT_QUEUED,
TcActionType::Repeat => TC_ACT_REPEAT,
TcActionType::Redirect => TC_ACT_REDIRECT,
TcActionType::Trap => TC_ACT_TRAP,
TcActionType::Other(d) => d,
}
}
}
46 changes: 43 additions & 3 deletions src/tc/actions/mirror.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const TC_MIRRED_BUF_LEN: usize = TcActionGeneric::BUF_LEN + 8;
#[non_exhaustive]
pub struct TcMirror {
pub generic: TcActionGeneric,
pub eaction: i32,
pub eaction: TcMirrorActionType,
pub ifindex: u32,
}

Expand All @@ -97,7 +97,7 @@ impl Emitable for TcMirror {
fn emit(&self, buffer: &mut [u8]) {
let mut packet = TcMirrorBuffer::new(buffer);
self.generic.emit(packet.generic_mut());
packet.set_eaction(self.eaction);
packet.set_eaction(self.eaction.into());
packet.set_ifindex(self.ifindex);
}
}
Expand All @@ -110,8 +110,48 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<TcMirrorBuffer<&'a T>>
generic: TcActionGeneric::parse(&TcActionGenericBuffer::new(
buf.generic(),
))?,
eaction: buf.eaction(),
eaction: buf.eaction().into(),
ifindex: buf.ifindex(),
})
}
}

const TCA_EGRESS_REDIR: i32 = 1;
const TCA_EGRESS_MIRROR: i32 = 2;
const TCA_INGRESS_REDIR: i32 = 3;
const TCA_INGRESS_MIRROR: i32 = 4;

#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
#[non_exhaustive]
pub enum TcMirrorActionType {
#[default]
EgressRedir,
EgressMirror,
IngressRedir,
IngressMirror,
Other(i32),
}

impl From<i32> for TcMirrorActionType {
fn from(d: i32) -> Self {
match d {
TCA_EGRESS_REDIR => Self::EgressRedir,
TCA_EGRESS_MIRROR => Self::EgressMirror,
TCA_INGRESS_REDIR => Self::IngressRedir,
TCA_INGRESS_MIRROR => Self::IngressMirror,
_ => Self::Other(d),
}
}
}

impl From<TcMirrorActionType> for i32 {
fn from(v: TcMirrorActionType) -> i32 {
match v {
TcMirrorActionType::EgressRedir => TCA_EGRESS_REDIR,
TcMirrorActionType::EgressMirror => TCA_EGRESS_MIRROR,
TcMirrorActionType::IngressRedir => TCA_INGRESS_REDIR,
TcMirrorActionType::IngressMirror => TCA_INGRESS_MIRROR,
TcMirrorActionType::Other(d) => d,
}
}
}
7 changes: 5 additions & 2 deletions src/tc/actions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
mod action;
mod mirror;
mod nat;
pub(crate) mod nat_flag;

pub use self::action::{
TcAction, TcActionAttribute, TcActionGeneric, TcActionGenericBuffer,
TcActionOption,
TcActionOption, TcActionType,
};
pub use self::mirror::{
TcActionMirror, TcActionMirrorOption, TcMirror, TcMirrorBuffer,
TcActionMirror, TcActionMirrorOption, TcMirror, TcMirrorActionType,
TcMirrorBuffer,
};
pub use self::nat::{TcActionNat, TcActionNatOption, TcNat, TcNatBuffer};
pub use self::nat_flag::TcNatFlag;
22 changes: 8 additions & 14 deletions src/tc/actions/nat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use netlink_packet_utils::{
DecodeError,
};

use super::{TcActionGeneric, TcActionGenericBuffer};
use super::{
nat_flag::VecTcNatFlag, TcActionGeneric, TcActionGenericBuffer, TcNatFlag,
};

const TCA_NAT_PARMS: u16 = 1;
const TCA_NAT_TM: u16 = 2;
Expand Down Expand Up @@ -73,16 +75,15 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
}

const TC_NAT_BUF_LEN: usize = TcActionGeneric::BUF_LEN + 16;
const TCA_NAT_FLAG_EGRESS: u32 = 1;

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub struct TcNat {
pub generic: TcActionGeneric,
pub old_addr: Ipv4Addr,
pub new_addr: Ipv4Addr,
pub mask: Ipv4Addr,
pub flags: u32, // TODO(Gris Ge): should a Vec<enum TcNatFlag>
pub flags: Vec<TcNatFlag>,
}

impl Default for TcNat {
Expand All @@ -92,7 +93,7 @@ impl Default for TcNat {
old_addr: Ipv4Addr::UNSPECIFIED,
new_addr: Ipv4Addr::UNSPECIFIED,
mask: Ipv4Addr::UNSPECIFIED,
flags: 0,
flags: vec![],
}
}
}
Expand All @@ -105,13 +106,6 @@ buffer!(TcNatBuffer(TC_NAT_BUF_LEN) {
flags: (u32, (TcActionGeneric::BUF_LEN+12)..TC_NAT_BUF_LEN),
});

impl TcNat {
pub fn egress(mut self) -> Self {
self.flags = TCA_NAT_FLAG_EGRESS;
self
}
}

impl Emitable for TcNat {
fn buffer_len(&self) -> usize {
TC_NAT_BUF_LEN
Expand All @@ -127,7 +121,7 @@ impl Emitable for TcNat {
.new_addr_mut()
.copy_from_slice(&self.new_addr.octets());
packet.mask_mut().copy_from_slice(&self.mask.octets());
packet.set_flags(self.flags);
packet.set_flags(u32::from(&VecTcNatFlag(self.flags.to_vec())));
}
}

Expand All @@ -140,7 +134,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<TcNatBuffer<&'a T>> for TcNat {
old_addr: parse_ipv4(buf.old_addr())?,
new_addr: parse_ipv4(buf.new_addr())?,
mask: parse_ipv4(buf.mask())?,
flags: buf.flags(),
flags: VecTcNatFlag::from(buf.flags()).0,
})
}
}
Expand Down
Loading