etherip-xdp 0.2.0

EtherIP implementation using XDP for Linux, in Rust.
Documentation
use futures::TryStreamExt;

use std::net::Ipv6Addr;

use crate::interface::InterfaceId;

#[allow(dead_code)]
pub struct RouteManager {
    handle: rtnetlink::RouteHandle,
}

impl RouteManager {
    pub(crate) fn new(handle: &super::RtnetlinkConnection) -> Self {
        Self {
            handle: handle.handle.route(),
        }
    }

    pub async fn get_v6(
        &self,
        dst: std::net::Ipv6Addr,
        prefix_len: u8,
    ) -> Result<Vec<(InterfaceId, std::net::Ipv6Addr)>, std::io::Error> {
        let mut routes = Vec::new();
        let req = self.handle.get(rtnetlink::IpVersion::V6);
        let response = req.execute();
        futures::pin_mut!(response);
        while let Some(response) = response
            .try_next()
            .await
            .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?
        {
            let mut if_index = 0;
            let mut gateway = Ipv6Addr::UNSPECIFIED;
            let mut found = false;
            if response.header.address_family != netlink_packet_route::AddressFamily::Inet6 {
                continue;
            }
            if response.header.destination_prefix_length != prefix_len {
                continue;
            }
            for route in response.attributes.iter() {
                if let netlink_packet_route::route::RouteAttribute::Oif(ifidx) = route {
                    if_index = *ifidx;
                }
                if let netlink_packet_route::route::RouteAttribute::Gateway(addr) = route {
                    gateway = match addr {
                        netlink_packet_route::route::RouteAddress::Inet6(addr) => *addr,
                        _ => Ipv6Addr::UNSPECIFIED,
                    };
                }
                if let netlink_packet_route::route::RouteAttribute::Destination(addr) = route {
                    if let netlink_packet_route::route::RouteAddress::Inet6(addr) = addr {
                        if addr == &dst {
                            found = true;
                        }
                    }
                }
            }

            if prefix_len == 0 && response.header.destination_prefix_length == 0 {
                found = true;
            }

            if found {
                routes.push((InterfaceId::new(if_index), gateway));
            }
        }
        Ok(routes)
    }
}