Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 50 additions & 3 deletions holo-ospf/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//

use std::cmp::Ordering;
use std::collections::btree_map;
use std::collections::btree_map::{self, Entry};
use std::net::Ipv4Addr;
use std::sync::Arc;

Expand All @@ -29,6 +29,7 @@ use crate::lsdb::{
use crate::neighbor::{LastDbDesc, Neighbor, RxmtPacketType, nsm};
use crate::northbound::notification;
use crate::packet::error::DecodeResult;
use crate::packet::lls::ReverseMetricFlags;
use crate::packet::lsa::{
Lsa, LsaBodyVersion, LsaHdrVersion, LsaKey, LsaScope, LsaTypeVersion,
};
Expand Down Expand Up @@ -431,9 +432,55 @@ where
// Examine LLS data block if enabled and present in the packet.
if iface.config.lls_enabled
&& hello.options().l_bit()
&& let Some(_lls) = hello.lls()
&& let Some(lls) = hello.lls()
{
// TODO: Handle LLS data
// Handle Reverse Metric (RFC 9339).
if iface.config.reverse_metric.receive {
// We have to recall the latest configuration we have received.
// If it has not changed, we do not update the metric nor we
// originate a new Router LSA.
// If the Reverse Metric from the neighbor has been updated since
// the last one we received, then we propagate the information.
for (mtid, (flags, metric)) in lls.reverse_metric.iter() {
let entry = iface.state.rms.entry(*mtid);
if let Some((flags, metric)) = match entry {
Entry::Occupied(entry) => {
// Has the RM changed?
let (old_flags, old_metric) = entry.into_mut();
(old_metric != metric || old_flags != flags).then(
|| {
*old_metric = *metric;
*old_flags = *flags;
(*old_flags, *old_metric)
},
)
}
Entry::Vacant(entry) => {
// This is the first time we see the RM.
Some(*entry.insert((*flags, *metric)))
}
} {
// Update metric.
// RFC 9339 Section 6 : "The H and O flags are mutually
// exclusive; the H flag is ignored when the O flag is set."
let higher = flags.contains(ReverseMetricFlags::H);
let offset = flags.contains(ReverseMetricFlags::O);
if offset {
iface.state.cost =
iface.state.cost.saturating_add(metric);
} else if !higher || iface.state.cost < metric {
iface.state.cost = metric;
}

// Trigger Router LSA origination.
instance.tx.protocol_input.lsa_orig_event(
LsaOriginateEvent::InterfaceCostChange {
area_id: area.id,
},
);
}
}
}
}

Ok(())
Expand Down
15 changes: 13 additions & 2 deletions holo-ospf/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use crate::northbound::configuration::InterfaceCfg;
use crate::northbound::notification;
use crate::packet::Packet;
use crate::packet::auth::AuthMethod;
use crate::packet::lls::ReverseMetricFlags;
use crate::packet::lsa::{Lsa, LsaHdrVersion, LsaKey};
use crate::tasks;
use crate::tasks::messages::output::NetTxPacketMsg;
Expand Down Expand Up @@ -97,6 +98,10 @@ pub struct InterfaceState<V: Version> {
pub auth: Option<AuthMethod>,
// Tasks.
pub tasks: InterfaceTasks<V>,
// Dynamic value of the interface cost.
pub cost: u16,
// History of known Reverse Metric received on this interface.
pub rms: BTreeMap<u8, (ReverseMetricFlags, u16)>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -255,12 +260,16 @@ where
) -> Interface<V> {
Debug::<V>::InterfaceCreate(&name).log();

let config = InterfaceCfg::default();
let mut state = InterfaceState::default();
state.cost = config.cost;

Interface {
id,
name,
system: InterfaceSys::default(),
config: InterfaceCfg::default(),
state: InterfaceState::default(),
config,
state,
vlink_key,
}
}
Expand Down Expand Up @@ -1016,6 +1025,8 @@ where
network_lsa_self: None,
auth: None,
tasks: Default::default(),
cost: 0,
rms: Default::default(),
}
}
}
Expand Down
110 changes: 110 additions & 0 deletions holo-ospf/src/northbound/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,15 @@ pub struct RangeCfg {
pub cost: Option<u32>,
}

#[derive(Debug)]
pub struct ReverseMetricCfg {
pub receive: bool,
pub mtid: u8,
pub metric: Option<u16>,
pub higher: bool,
pub offset: bool,
}

#[derive(Debug)]
pub struct InterfaceCfg<V: Version> {
pub instance_id: InheritableConfig<u8>,
Expand All @@ -199,6 +208,7 @@ pub struct InterfaceCfg<V: Version> {
pub bfd_params: bfd::ClientCfg,
pub trace_opts: InterfaceTraceOptions,
pub lls_enabled: bool,
pub reverse_metric: ReverseMetricCfg,
}

#[derive(Debug)]
Expand Down Expand Up @@ -989,6 +999,7 @@ where

let cost = args.dnode.get_u16();
iface.config.cost = cost;
iface.state.cost = cost;

let event_queue = args.event_queue;
event_queue.insert(Event::InterfaceCostChange(area_idx));
Expand Down Expand Up @@ -1232,7 +1243,88 @@ where
let event_queue = args.event_queue;
event_queue.insert(Event::UpdateTraceOptions);
})
.path(ospf::areas::area::interfaces::interface::reverse_metric::enable_receive::PATH)
.modify_apply(|instance, args| {
let (_, iface_idx) =
args.list_entry.into_interface().unwrap();
let iface = &mut instance.arenas.interfaces[iface_idx];

let receive = args.dnode.get_bool();
iface.config.reverse_metric.receive = receive;
})
.path(ospf::areas::area::interfaces::interface::reverse_metric::metric::PATH)
.modify_apply(|instance, args| {
let (area_idx, iface_idx) =
args.list_entry.into_interface().unwrap();
let iface = &mut instance.arenas.interfaces[iface_idx];

let metric = args.dnode.get_u16();
iface.config.reverse_metric.metric = Some(metric);

let event_queue = args.event_queue;
event_queue.insert(Event::InterfaceSyncHelloTx(area_idx, iface_idx));
})
.delete_apply(|instance, args| {
let (area_idx, iface_idx) =
args.list_entry.into_interface().unwrap();
let iface = &mut instance.arenas.interfaces[iface_idx];

iface.config.reverse_metric.metric = None;

let event_queue = args.event_queue;
event_queue.insert(Event::InterfaceSyncHelloTx(area_idx, iface_idx));
})
.path(ospf::areas::area::interfaces::interface::reverse_metric::flags::higher::PATH)
.modify_apply(|instance, args| {
let (area_idx, iface_idx) =
args.list_entry.into_interface().unwrap();
let iface = &mut instance.arenas.interfaces[iface_idx];

let higher = args.dnode.get_bool();
iface.config.reverse_metric.higher = higher;

let event_queue = args.event_queue;
event_queue.insert(Event::InterfaceSyncHelloTx(area_idx, iface_idx));
})
.path(ospf::areas::area::interfaces::interface::reverse_metric::flags::offset::PATH)
.modify_apply(|instance, args| {
let (area_idx, iface_idx) =
args.list_entry.into_interface().unwrap();
let iface = &mut instance.arenas.interfaces[iface_idx];

let offset = args.dnode.get_bool();
iface.config.reverse_metric.offset = offset;

let event_queue = args.event_queue;
event_queue.insert(Event::InterfaceSyncHelloTx(area_idx, iface_idx));
})
.path(ospf::areas::area::interfaces::interface::reverse_metric::mtid::PATH)
.modify_apply(|instance, args| {
let (area_idx, iface_idx) =
args.list_entry.into_interface().unwrap();
let iface = &mut instance.arenas.interfaces[iface_idx];

let mtid = args.dnode.get_u8();
iface.config.reverse_metric.mtid = mtid;

let event_queue = args.event_queue;
event_queue.insert(Event::InterfaceSyncHelloTx(area_idx, iface_idx));
})
.path(ospf::areas::area::reverse_metric::enable_receive::PATH)
.modify_apply(|instance, args| {
let area_idx = args.list_entry.into_area().unwrap();
let receive = args.dnode.get_bool();
instance.arenas.interfaces.iter_mut().filter(|(area, _)| area == &area_idx).for_each(|(_, iface)| {
iface.config.reverse_metric.receive = receive;
});
})
.path(ospf::reverse_metric::enable_receive::PATH)
.modify_apply(|instance, args| {
let receive = args.dnode.get_bool();
instance.arenas.interfaces.iter_mut().for_each(|(_, iface)| {
iface.config.reverse_metric.receive = receive;
});
})
.build()
}

Expand Down Expand Up @@ -2407,6 +2499,23 @@ impl Default for RangeCfg {
}
}

impl Default for ReverseMetricCfg {
fn default() -> Self {
let receive = ospf::areas::area::interfaces::interface::reverse_metric::enable_receive::DFLT;
let metric = None;
let higher = ospf::areas::area::interfaces::interface::reverse_metric::flags::higher::DFLT;
let offset = ospf::areas::area::interfaces::interface::reverse_metric::flags::offset::DFLT;
let mtid = ospf::areas::area::interfaces::interface::reverse_metric::mtid::DFLT;
Self {
receive,
metric,
higher,
offset,
mtid,
}
}
}

impl<V> Default for InterfaceCfg<V>
where
V: Version,
Expand Down Expand Up @@ -2455,6 +2564,7 @@ where
bfd_params: Default::default(),
trace_opts: Default::default(),
lls_enabled,
reverse_metric: Default::default(),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions holo-ospf/src/northbound/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ where
"ietf-ospfv3-extended-lsa",
"holo-ospf",
"holo-ospf-dev",
"holo-ospf-reverse-metric",
]
}

Expand Down
26 changes: 20 additions & 6 deletions holo-ospf/src/ospfv2/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::network::{MulticastAddr, NetworkVersion};
use crate::ospfv2;
use crate::ospfv2::packet::{Hello, PacketHdr};
use crate::packet::auth::AuthMethod;
use crate::packet::lls::{LlsHelloData, ReverseMetricFlags};
use crate::packet::{Packet, PacketType};
use crate::version::Ospfv2;

Expand Down Expand Up @@ -62,12 +63,25 @@ impl InterfaceVersion<Self> for Ospfv2 {
iface.system.primary_addr.unwrap().mask()
};

let lls = if iface.config.lls_enabled {
// TODO: Get LLS configuration
None
} else {
None
};
let advertise_rm = iface.config.reverse_metric.metric.is_some();
let lls = (iface.config.lls_enabled & advertise_rm).then(|| {
let mut lls_data: LlsHelloData = Default::default();

// Handle Reverse Metric (RFC 9339).
if let Some(metric) = iface.config.reverse_metric.metric {
let cfg = &iface.config.reverse_metric;
let mut flags = ReverseMetricFlags::empty();
if cfg.higher {
flags |= ReverseMetricFlags::H;
}
if cfg.offset {
flags |= ReverseMetricFlags::O;
}
lls_data.reverse_metric.insert(cfg.mtid, (flags, metric));
}

lls_data
});

Packet::Hello(Hello {
hdr,
Expand Down
4 changes: 2 additions & 2 deletions holo-ospf/src/ospfv2/lsdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ fn lsa_orig_router(
let non_stub_cost = if instance.config.stub_router {
MAX_LINK_METRIC
} else {
iface.config.cost
iface.state.cost
};

let mut add_stub_links = false;
Expand Down Expand Up @@ -551,7 +551,7 @@ fn lsa_orig_router(
LsaRouterLinkType::StubNetwork,
addr.ip(),
addr.mask(),
iface.config.cost,
iface.state.cost,
)
}),
);
Expand Down
Loading