use std::net::{Ipv4Addr, Ipv6Addr};
use super::{
builder::MessageBuilder,
connection::Connection,
error::Result,
interface_ref::InterfaceRef,
message::{NLM_F_ACK, NLM_F_REQUEST, NlMsgType},
mpls::MplsEncap,
protocol::Route,
srv6::Srv6Encap,
types::route::{RouteProtocol, RouteScope, RouteType, RtMsg, RtaAttr, rt_table},
};
const NLM_F_CREATE: u16 = 0x400;
const NLM_F_EXCL: u16 = 0x200;
const AF_INET: u8 = 2;
const AF_INET6: u8 = 10;
mod rtax {
pub const MTU: u16 = 2;
pub const WINDOW: u16 = 3;
pub const RTT: u16 = 4;
pub const RTTVAR: u16 = 5;
pub const SSTHRESH: u16 = 6;
pub const CWND: u16 = 7;
pub const ADVMSS: u16 = 8;
pub const REORDERING: u16 = 9;
pub const HOPLIMIT: u16 = 10;
pub const INITCWND: u16 = 11;
pub const FEATURES: u16 = 12;
pub const RTO_MIN: u16 = 13;
pub const INITRWND: u16 = 14;
pub const QUICKACK: u16 = 15;
}
pub mod rtnh_flags {
pub const DEAD: u8 = 1;
pub const PERVASIVE: u8 = 2;
pub const ONLINK: u8 = 4;
pub const OFFLOAD: u8 = 8;
pub const LINKDOWN: u8 = 16;
pub const UNRESOLVED: u8 = 32;
pub const TRAP: u8 = 64;
}
#[derive(Debug, Clone, Default)]
pub struct ResolvedRouteInterfaces {
pub oif: Option<u32>,
pub multipath: Vec<Option<u32>>,
}
pub trait RouteConfig: Send + Sync {
fn device_ref(&self) -> Option<&InterfaceRef>;
fn multipath_device_refs(&self) -> Vec<Option<&InterfaceRef>>;
fn family(&self) -> u8;
fn write_add(&self, builder: &mut MessageBuilder, interfaces: &ResolvedRouteInterfaces);
fn write_delete(&self, builder: &mut MessageBuilder);
}
#[derive(Debug, Clone, Default)]
pub struct RouteMetrics {
pub mtu: Option<u32>,
pub advmss: Option<u32>,
pub window: Option<u32>,
pub rtt: Option<u32>,
pub rttvar: Option<u32>,
pub ssthresh: Option<u32>,
pub cwnd: Option<u32>,
pub initcwnd: Option<u32>,
pub initrwnd: Option<u32>,
pub hoplimit: Option<u32>,
pub rto_min: Option<u32>,
pub quickack: Option<u32>,
pub reordering: Option<u32>,
pub features: Option<u32>,
}
impl RouteMetrics {
pub fn new() -> Self {
Self::default()
}
pub fn mtu(mut self, mtu: u32) -> Self {
self.mtu = Some(mtu);
self
}
pub fn advmss(mut self, advmss: u32) -> Self {
self.advmss = Some(advmss);
self
}
pub fn window(mut self, window: u32) -> Self {
self.window = Some(window);
self
}
pub fn initcwnd(mut self, initcwnd: u32) -> Self {
self.initcwnd = Some(initcwnd);
self
}
pub fn initrwnd(mut self, initrwnd: u32) -> Self {
self.initrwnd = Some(initrwnd);
self
}
pub fn hoplimit(mut self, hoplimit: u32) -> Self {
self.hoplimit = Some(hoplimit);
self
}
pub fn rto_min(mut self, rto_min: u32) -> Self {
self.rto_min = Some(rto_min);
self
}
pub fn quickack(mut self, quickack: u32) -> Self {
self.quickack = Some(quickack);
self
}
pub fn has_any(&self) -> bool {
self.mtu.is_some()
|| self.advmss.is_some()
|| self.window.is_some()
|| self.rtt.is_some()
|| self.rttvar.is_some()
|| self.ssthresh.is_some()
|| self.cwnd.is_some()
|| self.initcwnd.is_some()
|| self.initrwnd.is_some()
|| self.hoplimit.is_some()
|| self.rto_min.is_some()
|| self.quickack.is_some()
|| self.reordering.is_some()
|| self.features.is_some()
}
fn write_to(&self, builder: &mut MessageBuilder) {
let metrics = builder.nest_start(RtaAttr::Metrics as u16);
if let Some(v) = self.mtu {
builder.append_attr_u32(rtax::MTU, v);
}
if let Some(v) = self.advmss {
builder.append_attr_u32(rtax::ADVMSS, v);
}
if let Some(v) = self.window {
builder.append_attr_u32(rtax::WINDOW, v);
}
if let Some(v) = self.rtt {
builder.append_attr_u32(rtax::RTT, v);
}
if let Some(v) = self.rttvar {
builder.append_attr_u32(rtax::RTTVAR, v);
}
if let Some(v) = self.ssthresh {
builder.append_attr_u32(rtax::SSTHRESH, v);
}
if let Some(v) = self.cwnd {
builder.append_attr_u32(rtax::CWND, v);
}
if let Some(v) = self.initcwnd {
builder.append_attr_u32(rtax::INITCWND, v);
}
if let Some(v) = self.initrwnd {
builder.append_attr_u32(rtax::INITRWND, v);
}
if let Some(v) = self.hoplimit {
builder.append_attr_u32(rtax::HOPLIMIT, v);
}
if let Some(v) = self.rto_min {
builder.append_attr_u32(rtax::RTO_MIN, v);
}
if let Some(v) = self.quickack {
builder.append_attr_u32(rtax::QUICKACK, v);
}
if let Some(v) = self.reordering {
builder.append_attr_u32(rtax::REORDERING, v);
}
if let Some(v) = self.features {
builder.append_attr_u32(rtax::FEATURES, v);
}
builder.nest_end(metrics);
}
}
#[derive(Debug, Clone)]
pub struct NextHop {
gateway_v4: Option<Ipv4Addr>,
gateway_v6: Option<Ipv6Addr>,
dev: Option<InterfaceRef>,
weight: u8,
flags: u8,
}
impl NextHop {
pub fn new() -> Self {
Self {
gateway_v4: None,
gateway_v6: None,
dev: None,
weight: 1,
flags: 0,
}
}
pub fn gateway_v4(mut self, addr: Ipv4Addr) -> Self {
self.gateway_v4 = Some(addr);
self.gateway_v6 = None;
self
}
pub fn gateway_v6(mut self, addr: Ipv6Addr) -> Self {
self.gateway_v6 = Some(addr);
self.gateway_v4 = None;
self
}
pub fn dev(mut self, dev: impl Into<String>) -> Self {
self.dev = Some(InterfaceRef::Name(dev.into()));
self
}
pub fn dev_index(mut self, ifindex: u32) -> Self {
self.dev = Some(InterfaceRef::Index(ifindex));
self
}
pub fn device_ref(&self) -> Option<&InterfaceRef> {
self.dev.as_ref()
}
pub fn weight(mut self, weight: u8) -> Self {
self.weight = weight.max(1);
self
}
pub fn onlink(mut self) -> Self {
self.flags |= rtnh_flags::ONLINK;
self
}
}
impl Default for NextHop {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct Ipv4Route {
destination: Ipv4Addr,
prefix_len: u8,
gateway: Option<Ipv4Addr>,
prefsrc: Option<Ipv4Addr>,
dev: Option<InterfaceRef>,
route_type: RouteType,
protocol: RouteProtocol,
scope: Option<RouteScope>,
table: u32,
priority: Option<u32>,
metrics: Option<RouteMetrics>,
mark: Option<u32>,
multipath: Option<Vec<NextHop>>,
nexthop_id: Option<u32>,
mpls_encap: Option<MplsEncap>,
srv6_encap: Option<Srv6Encap>,
}
impl Ipv4Route {
pub fn new(destination: impl Into<String>, prefix_len: u8) -> Self {
let dest_str = destination.into();
let dest = dest_str.parse().unwrap_or(Ipv4Addr::UNSPECIFIED);
Self {
destination: dest,
prefix_len,
gateway: None,
prefsrc: None,
dev: None,
route_type: RouteType::Unicast,
protocol: RouteProtocol::Boot,
scope: None,
table: rt_table::MAIN as u32,
priority: None,
metrics: None,
mark: None,
multipath: None,
nexthop_id: None,
mpls_encap: None,
srv6_encap: None,
}
}
pub fn from_addr(destination: Ipv4Addr, prefix_len: u8) -> Self {
Self {
destination,
prefix_len,
gateway: None,
prefsrc: None,
dev: None,
route_type: RouteType::Unicast,
protocol: RouteProtocol::Boot,
scope: None,
table: rt_table::MAIN as u32,
priority: None,
metrics: None,
mark: None,
multipath: None,
nexthop_id: None,
mpls_encap: None,
srv6_encap: None,
}
}
pub fn gateway(mut self, gateway: Ipv4Addr) -> Self {
self.gateway = Some(gateway);
self.multipath = None;
self
}
pub fn prefsrc(mut self, src: Ipv4Addr) -> Self {
self.prefsrc = Some(src);
self
}
pub fn dev(mut self, dev: impl Into<String>) -> Self {
self.dev = Some(InterfaceRef::Name(dev.into()));
self
}
pub fn dev_index(mut self, ifindex: u32) -> Self {
self.dev = Some(InterfaceRef::Index(ifindex));
self
}
pub fn route_type(mut self, rtype: RouteType) -> Self {
self.route_type = rtype;
self
}
pub fn protocol(mut self, protocol: RouteProtocol) -> Self {
self.protocol = protocol;
self
}
pub fn scope(mut self, scope: RouteScope) -> Self {
self.scope = Some(scope);
self
}
pub fn table(mut self, table: u32) -> Self {
self.table = table;
self
}
pub fn priority(mut self, priority: u32) -> Self {
self.priority = Some(priority);
self
}
pub fn metric(self, metric: u32) -> Self {
self.priority(metric)
}
pub fn metrics(mut self, metrics: RouteMetrics) -> Self {
self.metrics = Some(metrics);
self
}
pub fn mark(mut self, mark: u32) -> Self {
self.mark = Some(mark);
self
}
pub fn multipath(mut self, nexthops: Vec<NextHop>) -> Self {
self.multipath = Some(nexthops);
self.gateway = None;
self.nexthop_id = None;
self
}
pub fn nexthop_group(mut self, group_id: u32) -> Self {
self.nexthop_id = Some(group_id);
self.gateway = None;
self.multipath = None;
self
}
pub fn mpls_encap(mut self, encap: MplsEncap) -> Self {
self.mpls_encap = Some(encap);
self
}
pub fn srv6_encap(mut self, encap: Srv6Encap) -> Self {
self.srv6_encap = Some(encap);
self
}
fn determine_scope(&self) -> RouteScope {
if let Some(scope) = self.scope {
return scope;
}
match self.route_type {
RouteType::Local | RouteType::Nat => RouteScope::Host,
RouteType::Broadcast | RouteType::Multicast | RouteType::Anycast => RouteScope::Link,
RouteType::Unicast | RouteType::Unspec => {
if self.gateway.is_some() || self.multipath.is_some() || self.nexthop_id.is_some() {
RouteScope::Universe
} else {
RouteScope::Link
}
}
_ => RouteScope::Universe,
}
}
}
impl RouteConfig for Ipv4Route {
fn device_ref(&self) -> Option<&InterfaceRef> {
self.dev.as_ref()
}
fn multipath_device_refs(&self) -> Vec<Option<&InterfaceRef>> {
match &self.multipath {
Some(nexthops) => nexthops.iter().map(|nh| nh.device_ref()).collect(),
None => Vec::new(),
}
}
fn family(&self) -> u8 {
AF_INET
}
fn write_add(&self, builder: &mut MessageBuilder, interfaces: &ResolvedRouteInterfaces) {
let table_u8 = if self.table > 255 {
rt_table::UNSPEC
} else {
self.table as u8
};
let scope = self.determine_scope();
let rtmsg = RtMsg::new()
.with_family(AF_INET)
.with_dst_len(self.prefix_len)
.with_table(table_u8)
.with_protocol(self.protocol as u8)
.with_scope(scope as u8)
.with_type(self.route_type as u8);
builder.append(&rtmsg);
if self.prefix_len > 0 {
builder.append_attr(RtaAttr::Dst as u16, &self.destination.octets());
}
if let Some(gw) = self.gateway {
builder.append_attr(RtaAttr::Gateway as u16, &gw.octets());
}
if let Some(src) = self.prefsrc {
builder.append_attr(RtaAttr::Prefsrc as u16, &src.octets());
}
if let Some(ifindex) = interfaces.oif {
builder.append_attr_u32(RtaAttr::Oif as u16, ifindex);
}
if self.table > 255 {
builder.append_attr_u32(RtaAttr::Table as u16, self.table);
}
if let Some(prio) = self.priority {
builder.append_attr_u32(RtaAttr::Priority as u16, prio);
}
if let Some(mark) = self.mark {
builder.append_attr_u32(RtaAttr::Mark as u16, mark);
}
if let Some(ref metrics) = self.metrics
&& metrics.has_any()
{
metrics.write_to(builder);
}
if let Some(ref nexthops) = self.multipath {
write_multipath_v4(builder, nexthops, &interfaces.multipath);
}
if let Some(nh_id) = self.nexthop_id {
builder.append_attr_u32(RtaAttr::NhId as u16, nh_id);
}
if let Some(ref encap) = self.mpls_encap {
encap.write_to(builder);
}
if let Some(ref encap) = self.srv6_encap {
encap.write_to(builder);
}
}
fn write_delete(&self, builder: &mut MessageBuilder) {
let table_u8 = if self.table > 255 {
rt_table::UNSPEC
} else {
self.table as u8
};
let rtmsg = RtMsg::new()
.with_family(AF_INET)
.with_dst_len(self.prefix_len)
.with_table(table_u8);
builder.append(&rtmsg);
if self.prefix_len > 0 {
builder.append_attr(RtaAttr::Dst as u16, &self.destination.octets());
}
if self.table > 255 {
builder.append_attr_u32(RtaAttr::Table as u16, self.table);
}
}
}
#[derive(Debug, Clone)]
pub struct Ipv6Route {
destination: Ipv6Addr,
prefix_len: u8,
gateway: Option<Ipv6Addr>,
prefsrc: Option<Ipv6Addr>,
dev: Option<InterfaceRef>,
route_type: RouteType,
protocol: RouteProtocol,
scope: Option<RouteScope>,
table: u32,
priority: Option<u32>,
metrics: Option<RouteMetrics>,
mark: Option<u32>,
multipath: Option<Vec<NextHop>>,
pref: Option<u8>,
nexthop_id: Option<u32>,
mpls_encap: Option<MplsEncap>,
srv6_encap: Option<Srv6Encap>,
}
impl Ipv6Route {
pub fn new(destination: impl Into<String>, prefix_len: u8) -> Self {
let dest_str = destination.into();
let dest = dest_str.parse().unwrap_or(Ipv6Addr::UNSPECIFIED);
Self {
destination: dest,
prefix_len,
gateway: None,
prefsrc: None,
dev: None,
route_type: RouteType::Unicast,
protocol: RouteProtocol::Boot,
scope: None,
table: rt_table::MAIN as u32,
priority: None,
metrics: None,
mark: None,
multipath: None,
pref: None,
nexthop_id: None,
mpls_encap: None,
srv6_encap: None,
}
}
pub fn from_addr(destination: Ipv6Addr, prefix_len: u8) -> Self {
Self {
destination,
prefix_len,
gateway: None,
prefsrc: None,
dev: None,
route_type: RouteType::Unicast,
protocol: RouteProtocol::Boot,
scope: None,
table: rt_table::MAIN as u32,
priority: None,
metrics: None,
mark: None,
multipath: None,
pref: None,
nexthop_id: None,
mpls_encap: None,
srv6_encap: None,
}
}
pub fn gateway(mut self, gateway: Ipv6Addr) -> Self {
self.gateway = Some(gateway);
self.multipath = None;
self
}
pub fn prefsrc(mut self, src: Ipv6Addr) -> Self {
self.prefsrc = Some(src);
self
}
pub fn dev(mut self, dev: impl Into<String>) -> Self {
self.dev = Some(InterfaceRef::Name(dev.into()));
self
}
pub fn dev_index(mut self, ifindex: u32) -> Self {
self.dev = Some(InterfaceRef::Index(ifindex));
self
}
pub fn route_type(mut self, rtype: RouteType) -> Self {
self.route_type = rtype;
self
}
pub fn protocol(mut self, protocol: RouteProtocol) -> Self {
self.protocol = protocol;
self
}
pub fn scope(mut self, scope: RouteScope) -> Self {
self.scope = Some(scope);
self
}
pub fn table(mut self, table: u32) -> Self {
self.table = table;
self
}
pub fn priority(mut self, priority: u32) -> Self {
self.priority = Some(priority);
self
}
pub fn metric(self, metric: u32) -> Self {
self.priority(metric)
}
pub fn metrics(mut self, metrics: RouteMetrics) -> Self {
self.metrics = Some(metrics);
self
}
pub fn mark(mut self, mark: u32) -> Self {
self.mark = Some(mark);
self
}
pub fn multipath(mut self, nexthops: Vec<NextHop>) -> Self {
self.multipath = Some(nexthops);
self.gateway = None;
self.nexthop_id = None;
self
}
pub fn pref(mut self, pref: u8) -> Self {
self.pref = Some(pref);
self
}
pub fn nexthop_group(mut self, group_id: u32) -> Self {
self.nexthop_id = Some(group_id);
self.gateway = None;
self.multipath = None;
self
}
pub fn mpls_encap(mut self, encap: MplsEncap) -> Self {
self.mpls_encap = Some(encap);
self
}
pub fn srv6_encap(mut self, encap: Srv6Encap) -> Self {
self.srv6_encap = Some(encap);
self
}
fn determine_scope(&self) -> RouteScope {
if let Some(scope) = self.scope {
return scope;
}
match self.route_type {
RouteType::Local => RouteScope::Host,
RouteType::Unicast | RouteType::Unspec => {
if self.gateway.is_some() || self.multipath.is_some() || self.nexthop_id.is_some() {
RouteScope::Universe
} else {
RouteScope::Link
}
}
_ => RouteScope::Universe,
}
}
}
impl RouteConfig for Ipv6Route {
fn device_ref(&self) -> Option<&InterfaceRef> {
self.dev.as_ref()
}
fn multipath_device_refs(&self) -> Vec<Option<&InterfaceRef>> {
match &self.multipath {
Some(nexthops) => nexthops.iter().map(|nh| nh.device_ref()).collect(),
None => Vec::new(),
}
}
fn family(&self) -> u8 {
AF_INET6
}
fn write_add(&self, builder: &mut MessageBuilder, interfaces: &ResolvedRouteInterfaces) {
let table_u8 = if self.table > 255 {
rt_table::UNSPEC
} else {
self.table as u8
};
let scope = self.determine_scope();
let rtmsg = RtMsg::new()
.with_family(AF_INET6)
.with_dst_len(self.prefix_len)
.with_table(table_u8)
.with_protocol(self.protocol as u8)
.with_scope(scope as u8)
.with_type(self.route_type as u8);
builder.append(&rtmsg);
if self.prefix_len > 0 {
builder.append_attr(RtaAttr::Dst as u16, &self.destination.octets());
}
if let Some(gw) = self.gateway {
builder.append_attr(RtaAttr::Gateway as u16, &gw.octets());
}
if let Some(src) = self.prefsrc {
builder.append_attr(RtaAttr::Prefsrc as u16, &src.octets());
}
if let Some(ifindex) = interfaces.oif {
builder.append_attr_u32(RtaAttr::Oif as u16, ifindex);
}
if self.table > 255 {
builder.append_attr_u32(RtaAttr::Table as u16, self.table);
}
if let Some(prio) = self.priority {
builder.append_attr_u32(RtaAttr::Priority as u16, prio);
}
if let Some(mark) = self.mark {
builder.append_attr_u32(RtaAttr::Mark as u16, mark);
}
if let Some(pref) = self.pref {
builder.append_attr_u8(RtaAttr::Pref as u16, pref);
}
if let Some(ref metrics) = self.metrics
&& metrics.has_any()
{
metrics.write_to(builder);
}
if let Some(ref nexthops) = self.multipath {
write_multipath_v6(builder, nexthops, &interfaces.multipath);
}
if let Some(nh_id) = self.nexthop_id {
builder.append_attr_u32(RtaAttr::NhId as u16, nh_id);
}
if let Some(ref encap) = self.mpls_encap {
encap.write_to(builder);
}
if let Some(ref encap) = self.srv6_encap {
encap.write_to(builder);
}
}
fn write_delete(&self, builder: &mut MessageBuilder) {
let table_u8 = if self.table > 255 {
rt_table::UNSPEC
} else {
self.table as u8
};
let rtmsg = RtMsg::new()
.with_family(AF_INET6)
.with_dst_len(self.prefix_len)
.with_table(table_u8);
builder.append(&rtmsg);
if self.prefix_len > 0 {
builder.append_attr(RtaAttr::Dst as u16, &self.destination.octets());
}
if self.table > 255 {
builder.append_attr_u32(RtaAttr::Table as u16, self.table);
}
}
}
fn write_multipath_v4(
builder: &mut MessageBuilder,
nexthops: &[NextHop],
resolved_indices: &[Option<u32>],
) {
let mut mp_data = Vec::new();
for (i, nh) in nexthops.iter().enumerate() {
let ifindex = resolved_indices.get(i).copied().flatten().unwrap_or(0);
let mut nh_len: u16 = 8; if nh.gateway_v4.is_some() {
nh_len += 8; }
mp_data.extend_from_slice(&nh_len.to_ne_bytes());
mp_data.push(nh.flags);
mp_data.push(nh.weight.saturating_sub(1)); mp_data.extend_from_slice(&ifindex.to_ne_bytes());
if let Some(gw) = nh.gateway_v4 {
let nla_len: u16 = 4 + 4; mp_data.extend_from_slice(&nla_len.to_ne_bytes());
mp_data.extend_from_slice(&(RtaAttr::Gateway as u16).to_ne_bytes());
mp_data.extend_from_slice(&gw.octets());
}
}
builder.append_attr(RtaAttr::Multipath as u16, &mp_data);
}
fn write_multipath_v6(
builder: &mut MessageBuilder,
nexthops: &[NextHop],
resolved_indices: &[Option<u32>],
) {
let mut mp_data = Vec::new();
for (i, nh) in nexthops.iter().enumerate() {
let ifindex = resolved_indices.get(i).copied().flatten().unwrap_or(0);
let mut nh_len: u16 = 8;
if nh.gateway_v6.is_some() {
nh_len += 4 + 16; }
mp_data.extend_from_slice(&nh_len.to_ne_bytes());
mp_data.push(nh.flags);
mp_data.push(nh.weight.saturating_sub(1));
mp_data.extend_from_slice(&ifindex.to_ne_bytes());
if let Some(gw) = nh.gateway_v6 {
let nla_len: u16 = 4 + 16;
mp_data.extend_from_slice(&nla_len.to_ne_bytes());
mp_data.extend_from_slice(&(RtaAttr::Gateway as u16).to_ne_bytes());
mp_data.extend_from_slice(&gw.octets());
}
}
builder.append_attr(RtaAttr::Multipath as u16, &mp_data);
}
const NLM_F_REPLACE: u16 = 0x100;
impl Connection<Route> {
async fn resolve_route_interfaces<R: RouteConfig>(
&self,
config: &R,
) -> Result<ResolvedRouteInterfaces> {
let oif = match config.device_ref() {
Some(iface) => Some(self.resolve_interface(iface).await?),
None => None,
};
let mp_refs = config.multipath_device_refs();
let mut multipath = Vec::with_capacity(mp_refs.len());
for iface_opt in mp_refs {
match iface_opt {
Some(iface) => multipath.push(Some(self.resolve_interface(iface).await?)),
None => multipath.push(None),
}
}
Ok(ResolvedRouteInterfaces { oif, multipath })
}
pub async fn add_route<R: RouteConfig>(&self, config: R) -> Result<()> {
let interfaces = self.resolve_route_interfaces(&config).await?;
let mut builder = MessageBuilder::new(
NlMsgType::RTM_NEWROUTE,
NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL,
);
config.write_add(&mut builder, &interfaces);
self.send_ack(builder)
.await
.map_err(|e| e.with_context("add_route"))
}
pub async fn del_route<R: RouteConfig>(&self, config: R) -> Result<()> {
let mut builder = MessageBuilder::new(NlMsgType::RTM_DELROUTE, NLM_F_REQUEST | NLM_F_ACK);
config.write_delete(&mut builder);
self.send_ack(builder)
.await
.map_err(|e| e.with_context("del_route"))
}
#[tracing::instrument(level = "debug", skip_all, fields(method = "del_route_v4"))]
pub async fn del_route_v4(&self, destination: &str, prefix_len: u8) -> Result<()> {
let route = Ipv4Route::new(destination, prefix_len);
self.del_route(route).await
}
#[tracing::instrument(level = "debug", skip_all, fields(method = "del_route_v6"))]
pub async fn del_route_v6(&self, destination: &str, prefix_len: u8) -> Result<()> {
let route = Ipv6Route::new(destination, prefix_len);
self.del_route(route).await
}
pub async fn replace_route<R: RouteConfig>(&self, config: R) -> Result<()> {
let interfaces = self.resolve_route_interfaces(&config).await?;
let mut builder = MessageBuilder::new(
NlMsgType::RTM_NEWROUTE,
NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_REPLACE,
);
config.write_add(&mut builder, &interfaces);
self.send_ack(builder)
.await
.map_err(|e| e.with_context("replace_route"))
}
}