use std::mem::size_of;
use std::os::raw::c_int;
use eui48::MacAddress;
use ffi::*;
use ffi::netlink_family::*;
use sys::*;
#[derive(Default, Debug)]
pub struct Link {
pub index: u32,
pub name: String,
pub flags: u32,
pub mac: MacAddress,
pub mtu: u32,
pub xdp: Xdp,
}
#[derive(Default, Debug)]
pub struct Xdp {
pub fd: u32,
pub attached: bool,
pub flags: u32,
pub prog_id: u32,
}
pub fn links() -> Result<Vec<Link>, Error> {
let sock = Socket::new(NETLINK_ROUTE)?;
#[repr(C)]
#[derive(Default, Debug)]
struct Request {
hdr: nlmsghdr,
req: rtgenmsg,
}
let mut req = Request::default();
req.hdr.nlmsg_len = nlmsg_length(size_of::<rtgenmsg>() as u32);
req.hdr.nlmsg_type = RTM_GETLINK;
req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
req.req.rtgen_family = AF_UNSPEC;
sock.send(&mut [as_iovec(&mut req)])?;
sock.recv(|data: &ifinfomsg, mut tail: Attrs| {
let mut link = Link::default();
link.index = data.ifi_index as u32;
link.flags = data.ifi_flags as u32;
while let Some((head, data)) = tail.next::<rtattr>() {
match head.rta_type {
IFLA_IFNAME => link.name = data.string(),
IFLA_ADDRESS => link.mac = MacAddress::new(*data.cast()),
IFLA_MTU => link.mtu = *data.cast(),
IFLA_XDP => link.xdp = xdp(data.attrs()),
_ => (),
}
}
Ok(link)
})
}
fn xdp(mut attrs: Attrs) -> Xdp {
let mut xdp = Xdp::default();
while let Some((head, data)) = attrs.next::<nlattr>() {
match head.nla_type {
IFLA_XDP_FD => xdp.fd = *data.cast::<c_int>() as u32,
IFLA_XDP_ATTACHED => xdp.attached = *data.cast::<u8>() == 1,
IFLA_XDP_FLAGS => xdp.flags = *data.cast(),
IFLA_XDP_PROG_ID => xdp.prog_id = *data.cast(),
_ => ()
}
}
xdp
}