use netlink_bindings::{
rt_link,
tc::{Request, TcPrioQopt, Tcmsg},
};
use netlink_socket2::NetlinkSocket;
const TC_H_ROOT: u32 = 0xffffffff;
#[cfg_attr(not(feature = "async"), maybe_async::must_be_sync)]
#[cfg_attr(feature = "tokio", tokio::main(flavor = "current_thread"))]
#[cfg_attr(feature = "smol", macro_rules_attribute::apply(smol_macros::main))]
async fn main() {
let ifname = std::env::args().skip(1).next().unwrap_or("wg0".to_string());
let mut sock = NetlinkSocket::new();
let ifi = link_get_ifindex(&mut sock, &ifname).await;
let qdisc_handle = 0xbeef << 16;
tc_prio_add(&mut sock, ifi, qdisc_handle).await;
tc_prio_show(&mut sock, ifi, qdisc_handle).await;
tc_prio_del(&mut sock, ifi, qdisc_handle).await;
}
#[cfg_attr(not(feature = "async"), maybe_async::must_be_sync)]
async fn tc_prio_add(sock: &mut NetlinkSocket, ifi: i32, handle: u32) {
let header = Tcmsg {
family: 0,
ifindex: ifi,
handle: handle,
parent: TC_H_ROOT,
..Default::default()
};
let mut req = Request::new()
.set_create()
.set_excl()
.op_newqdisc_do(&header);
let priomap: [u8; 16] = [7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let tc_prio_opt = TcPrioQopt {
bands: 8,
priomap: priomap,
};
req.encode().nested_options_prio(&tc_prio_opt);
let mut iter = sock.request(&req).await.unwrap();
iter.recv_ack().await.unwrap();
println!("tc prio add on ifi {} OK", ifi);
}
#[cfg_attr(not(feature = "async"), maybe_async::must_be_sync)]
async fn tc_prio_show(sock: &mut NetlinkSocket, ifi: i32, qdisc_handle: u32) {
let header = Tcmsg {
family: 0,
ifindex: ifi,
handle: qdisc_handle,
parent: TC_H_ROOT,
info: 0,
..Default::default()
};
let req = Request::new().op_getqdisc_dump(&header);
let mut iter = sock.request(&req).await.unwrap();
while let Some(res) = iter.recv().await {
let (header, attrs) = res.unwrap();
if header.ifindex == ifi && header.handle == qdisc_handle {
println!("{:#?}", (header, attrs));
println!("tc prio show on ifi {} OK", ifi);
return;
}
}
panic!("No qdisc found");
}
#[cfg_attr(not(feature = "async"), maybe_async::must_be_sync)]
async fn tc_prio_del(sock: &mut NetlinkSocket, ifi: i32, qdisc_handle: u32) {
let req = Request::new().op_delqdisc_do(&Tcmsg {
family: 0,
ifindex: ifi,
handle: qdisc_handle,
parent: TC_H_ROOT,
info: 0,
..Default::default()
});
let mut iter = sock.request(&req).await.unwrap();
iter.recv_ack().await.unwrap();
println!("tc prio del on ifi {} OK", ifi);
}
#[cfg_attr(not(feature = "async"), maybe_async::must_be_sync)]
pub async fn link_get_ifindex(sock: &mut NetlinkSocket, ifname: &str) -> i32 {
let mut request = rt_link::Request::new().op_getlink_do(&Default::default());
request.encode().push_ifname_bytes(ifname.as_bytes());
let mut iter = sock.request(&request).await.unwrap();
let (header, _attrs) = iter.recv_one().await.unwrap();
header.ifi_index
}