-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add more inversion of control The library now depends on the caller to retrieve netlink messages and pass it to `netlink-tc`. `netlink-tc` accepts `Vec<NetlinkMessage<RtnlMessage>>` which can be fetched using `netlink-packet-route`. The message is then parsed and processed as earlier. * Remove dependency to make netlink calls to retrieve `TcMsg` Pass a new `RtNetlinkMessage` which encapsulates `TcMsg` and `LinkMsg`. The netlink is already parsed and passed as a parameter rather than making a netlink call here and then parsing. * Add examples for fetching qdiscs, classes, links * Scope down errors; refactor imports * Add `ParseOptions` builder This enables caller to decide how to handle unknown or unimplemented attributes and options. Default behavior is to ignore such branches.
- Loading branch information
Showing
13 changed files
with
856 additions
and
1,209 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
use netlink_packet_core::{ | ||
NetlinkHeader, NetlinkMessage, NetlinkPayload, NLM_F_DUMP, NLM_F_REQUEST, | ||
}; | ||
use netlink_packet_route::{LinkMessage, RtnlMessage, TcHeader, TcMessage}; | ||
use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr}; | ||
use netlink_tc::ParseOptions; | ||
|
||
fn socket() -> Socket { | ||
let socket = Socket::new(NETLINK_ROUTE).unwrap(); | ||
socket.connect(&SocketAddr::new(0, 0)).unwrap(); | ||
socket | ||
} | ||
|
||
fn receive_netlink_messages(message: RtnlMessage) -> Vec<NetlinkMessage<RtnlMessage>> { | ||
let socket = socket(); | ||
send_request(&socket, message); | ||
|
||
let mut receive_buffer = vec![0; 4096]; | ||
let mut offset = 0; | ||
|
||
let mut messages = Vec::new(); | ||
while let Ok(size) = socket.recv(&mut &mut receive_buffer[..], 0) { | ||
loop { | ||
let bytes = &receive_buffer[offset..]; | ||
let rx_packet = <NetlinkMessage<RtnlMessage>>::deserialize(bytes).unwrap(); | ||
messages.push(rx_packet.clone()); | ||
let payload = rx_packet.payload; | ||
if let NetlinkPayload::Error(err) = payload { | ||
panic!("Netlink error: {:?}", err); | ||
} | ||
if let NetlinkPayload::Done(_) = payload { | ||
return messages; | ||
} | ||
|
||
offset += rx_packet.header.length as usize; | ||
if offset == size || rx_packet.header.length == 0 { | ||
offset = 0; | ||
break; | ||
} | ||
} | ||
} | ||
|
||
messages | ||
} | ||
|
||
fn get_qdiscs() -> Vec<NetlinkMessage<RtnlMessage>> { | ||
receive_netlink_messages(RtnlMessage::GetQueueDiscipline(TcMessage::default())) | ||
} | ||
|
||
fn get_classes(index: i32) -> Vec<NetlinkMessage<RtnlMessage>> { | ||
let header = TcHeader { | ||
index, | ||
..Default::default() | ||
}; | ||
let mut message = TcMessage::default(); | ||
message.header = header; | ||
receive_netlink_messages(RtnlMessage::GetTrafficClass(message)) | ||
} | ||
|
||
fn get_links() -> Vec<NetlinkMessage<RtnlMessage>> { | ||
receive_netlink_messages(RtnlMessage::GetLink(LinkMessage::default())) | ||
} | ||
|
||
fn send_request(socket: &Socket, message: RtnlMessage) { | ||
let mut nl_hdr = NetlinkHeader::default(); | ||
nl_hdr.flags = NLM_F_REQUEST | NLM_F_DUMP; | ||
|
||
let mut packet = NetlinkMessage::new(nl_hdr, NetlinkPayload::from(message)); | ||
packet.finalize(); | ||
|
||
let mut buf = vec![0; packet.header.length as usize]; | ||
packet.serialize(&mut buf[..]); | ||
|
||
socket.send(&buf[..], 0).unwrap(); | ||
} | ||
|
||
fn main() { | ||
let messages = get_qdiscs(); | ||
let qdiscs = ParseOptions::new() | ||
.fail_on_unknown_netlink_message(false) | ||
.fail_on_unknown_attribute(false) | ||
.fail_on_unknown_option(false) | ||
.tc(messages) | ||
.unwrap(); | ||
println!("length: {}, qdiscs: {:#?}", qdiscs.len(), qdiscs); | ||
|
||
let messages = get_links(); | ||
let links = ParseOptions::new() | ||
.fail_on_unknown_netlink_message(false) | ||
.fail_on_unknown_attribute(false) | ||
.fail_on_unknown_option(false) | ||
.links(messages) | ||
.unwrap(); | ||
println!("length: {}, links: {:#?}", links.len(), links); | ||
|
||
let mut messages = Vec::new(); | ||
for link in links { | ||
let classes = get_classes(link.index as i32); | ||
messages.extend(classes); | ||
} | ||
let classes = ParseOptions::new() | ||
.fail_on_unknown_netlink_message(false) | ||
.fail_on_unknown_attribute(false) | ||
.fail_on_unknown_option(false) | ||
.tc(messages) | ||
.unwrap(); | ||
println!("length: {}, classes: {:#?}", classes.len(), classes); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,7 @@ | ||
use std::error; | ||
|
||
use bincode::ErrorKind; | ||
use thiserror::Error; | ||
|
||
#[derive(Debug, Error)] | ||
pub enum NetlinkError { | ||
#[error("Failed to create socket: {0}")] | ||
Socket(#[from] Box<dyn error::Error>), | ||
|
||
#[error("Failed to send message: {0}")] | ||
Send(String), | ||
|
||
#[error("Netlink error: {0}")] | ||
Netlink(String), | ||
|
||
#[error("Failed to decode netlink message: {0}")] | ||
NetlinkDecode(String), | ||
} | ||
|
||
#[derive(Debug, Error)] | ||
pub enum LinkError { | ||
#[error("rust-netlink error: {0}")] | ||
Netlink(#[from] NetlinkError), | ||
|
||
#[error("Missing attribute: {0}")] | ||
MissingAttribute(String), | ||
} | ||
|
||
#[derive(Debug, Error)] | ||
pub enum TcError { | ||
#[error("rust-netlink error: {0}")] | ||
Netlink(#[from] NetlinkError), | ||
|
||
#[error("Failed to retrieve links: {0}")] | ||
Link(#[from] LinkError), | ||
|
||
#[error("Failed to decode field: {0}")] | ||
Decode(String), | ||
|
||
#[error("Failed to unmarshal struct: {0}")] | ||
UnmarshalStruct(#[from] Box<ErrorKind>), | ||
|
||
#[error("Failed to unmarshal structs: {0}")] | ||
UnmarshalStructs(String), | ||
|
||
#[error("Inavalid attribute: {0}")] | ||
InvalidAttribute(String), | ||
|
||
#[error("Attribute not implemented: {0}")] | ||
UnimplementedAttribute(String), | ||
pub enum Error { | ||
#[error("Failed to parse: {0}")] | ||
Parse(String), | ||
} |
Oops, something went wrong.