Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ospf dynamic hostname #41

Merged
merged 8 commits into from
Jan 10, 2025
Merged
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ Holo supports the following Internet Standards:
* RFC 5243 - OSPF Database Exchange Summary List Optimization
* RFC 5250 - The OSPF Opaque LSA Option
* RFC 5340 - OSPF for IPv6
* RFC 5642 - Dynamic Hostname Exchange Mechanism for OSPF
* RFC 5709 - OSPFv2 HMAC-SHA Cryptographic Authentication
* RFC 5838 - Support of Address Families in OSPFv3
* RFC 6987 - OSPF Stub Router Advertisement
Expand Down
22 changes: 22 additions & 0 deletions holo-ospf/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1526,3 +1526,25 @@ where

Ok(())
}

// ===== Hostname update event =====

pub(crate) fn process_hostname_update<V>(
instance: &mut Instance<V>,
hostname: Option<String>,
) -> Result<(), Error<V>>
where
V: Version,
{
instance.shared.hostname = hostname;

if let Some((instance, arenas)) = instance.as_up() {
V::lsa_orig_event(
&instance,
arenas,
LsaOriginateEvent::HostnameChange,
)?;
}

Ok(())
}
6 changes: 6 additions & 0 deletions holo-ospf/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ pub struct InstanceState<V: Version> {
pub gr_helper_count: usize,
// Authentication non-decreasing sequence number.
pub auth_seqno: Arc<AtomicU64>,
// Hostname cache.
pub hostnames: BTreeMap<Ipv4Addr, String>,
}

#[derive(Debug, Default)]
Expand Down Expand Up @@ -580,6 +582,7 @@ where
spf_log_next_id: 0,
gr_helper_count: 0,
auth_seqno: Arc::new(V::initial_auth_seqno(boot_count).into()),
hostnames: Default::default(),
}
}
}
Expand Down Expand Up @@ -791,6 +794,9 @@ where
IbusMsg::BierCfgEvent(event) => {
events::process_bier_cfg_change(instance, event)?
}
IbusMsg::HostnameUpdate(hostname) => {
events::process_hostname_update(instance, hostname)?;
}
// Ignore other events.
_ => {}
}
Expand Down
3 changes: 2 additions & 1 deletion holo-ospf/src/lsdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ pub enum LsaOriginateEvent {
BierCfgChange {
change: BierCfgEvent,
},
HostnameChange,
}

#[derive(Debug)]
Expand Down Expand Up @@ -211,7 +212,7 @@ pub trait LsdbVersion<V: Version> {

// Custom LSA installation handling.
fn lsdb_install(
instance: &InstanceUpView<'_, V>,
instance: &mut InstanceUpView<'_, V>,
arenas: &mut InstanceArenas<V>,
lsdb_idx: LsdbIndex,
lsdb_id: LsdbId,
Expand Down
73 changes: 73 additions & 0 deletions holo-ospf/src/northbound/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub enum ListEntry<'a, V: Version> {
LsaLog(&'a LsaLogEntry<V>),
Route(&'a V::IpNetwork, &'a RouteNet<V>),
Nexthop(&'a Nexthop<V::IpAddr>),
Hostname(&'a Ipv4Addr, &'a String),
AsStatsLsaType(&'a LsdbSingleType<V>),
AsLsaType(&'a LsdbSingleType<V>),
AsLsa(&'a LsaEntry<V>),
Expand Down Expand Up @@ -536,6 +537,20 @@ where
raw_data: Some(lsa.raw.as_ref()).ignore_in_testing(),
})
})
.path(ospf::hostnames::hostname::PATH)
.get_iterate(|instance, _args| {
let Some(instance_state) = &instance.state else { return None };
let iter = instance_state.hostnames.iter().map(|(router_id, hostname)| ListEntry::Hostname(router_id, hostname));
Some(Box::new(iter) as _)
})
.get_object(|_instance, args| {
use ospf::hostnames::hostname::Hostname;
let (router_id, hostname) = args.list_entry.as_hostname().unwrap();
Box::new(Hostname {
router_id: Cow::Borrowed(router_id),
hostname: Some(Cow::Borrowed(hostname)),
})
})
.build()
}

Expand Down Expand Up @@ -662,6 +677,21 @@ fn load_callbacks_ospfv2() -> Callbacks<Instance<Ospfv2>> {
functional_flag: Some(*flag),
})
})
.path(ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv2::body::opaque::ri_opaque::dynamic_hostname_tlv::PATH)
.get_object(|_instance, args| {
use ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv2::body::opaque::ri_opaque::dynamic_hostname_tlv::DynamicHostnameTlv;
let lse: &LsaEntry<Ospfv2> = args.list_entry.as_as_lsa().unwrap();
let lsa = &lse.data;
let mut hostname = None;
if let Some(lsa_body) = lsa.body.as_opaque_as()
&& let Some(lsa_body) = lsa_body.as_router_info()
&& let Some(info_hostname) = &lsa_body.info_hostname {
hostname = Some(Cow::Borrowed(info_hostname.get()));
}
Box::new(DynamicHostnameTlv {
hostname,
})
})
.path(ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv2::body::opaque::ri_opaque::maximum_sid_depth_tlv::msd_type::PATH)
.get_iterate(|_instance, args| {
let lse: &LsaEntry<Ospfv2> = args.parent_list_entry.as_as_lsa().unwrap();
Expand Down Expand Up @@ -1066,6 +1096,21 @@ fn load_callbacks_ospfv2() -> Callbacks<Instance<Ospfv2>> {
functional_flag: Some(*flag),
})
})
.path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv2::body::opaque::ri_opaque::dynamic_hostname_tlv::PATH)
.get_object(|_instance, args| {
use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv2::body::opaque::ri_opaque::dynamic_hostname_tlv::DynamicHostnameTlv;
let lse: &LsaEntry<Ospfv2> = args.list_entry.as_area_lsa().unwrap();
let lsa = &lse.data;
let mut hostname = None;
if let Some(lsa_body) = lsa.body.as_opaque_area()
&& let Some(lsa_body) = lsa_body.as_router_info()
&& let Some(info_hostname) = &lsa_body.info_hostname {
hostname = Some(Cow::Borrowed(info_hostname.get()));
}
Box::new(DynamicHostnameTlv {
hostname,
})
})
.path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv2::body::opaque::ri_opaque::maximum_sid_depth_tlv::msd_type::PATH)
.get_iterate(|_instance, args| {
let lse: &LsaEntry<Ospfv2> = args.parent_list_entry.as_area_lsa().unwrap();
Expand Down Expand Up @@ -1783,6 +1828,20 @@ fn load_callbacks_ospfv3() -> Callbacks<Instance<Ospfv3>> {
functional_flag: Some(*flag),
})
})
.path(ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv3::body::router_information::dynamic_hostname_tlv::PATH)
.get_object(|_instance, args| {
use ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv3::body::router_information::dynamic_hostname_tlv::DynamicHostnameTlv;
let lse: &LsaEntry<Ospfv3> = args.list_entry.as_as_lsa().unwrap();
let lsa = &lse.data;
let mut hostname = None;
if let Some(lsa_body) = lsa.body.as_router_info()
&& let Some(info_hostname) = &lsa_body.info_hostname {
hostname = Some(Cow::Borrowed(info_hostname.get()));
}
Box::new(DynamicHostnameTlv {
hostname,
})
})
.path(ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv3::body::router_information::sr_algorithm_tlv::PATH)
.get_object(|_instance, args| {
use ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv3::body::router_information::sr_algorithm_tlv::SrAlgorithmTlv;
Expand Down Expand Up @@ -2250,6 +2309,20 @@ fn load_callbacks_ospfv3() -> Callbacks<Instance<Ospfv3>> {
functional_flag: Some(*flag),
})
})
.path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::router_information::dynamic_hostname_tlv::PATH)
.get_object(|_instance, args| {
use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::router_information::dynamic_hostname_tlv::DynamicHostnameTlv;
let lse: &LsaEntry<Ospfv3> = args.list_entry.as_area_lsa().unwrap();
let lsa = &lse.data;
let mut hostname = None;
if let Some(lsa_body) = lsa.body.as_router_info()
&& let Some(info_hostname) = &lsa_body.info_hostname {
hostname = Some(Cow::Borrowed(info_hostname.get()));
}
Box::new(DynamicHostnameTlv {
hostname,
})
})
.path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::router_information::sr_algorithm_tlv::PATH)
.get_object(|_instance, args| {
use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::router_information::sr_algorithm_tlv::SrAlgorithmTlv;
Expand Down
33 changes: 30 additions & 3 deletions holo-ospf/src/ospfv2/lsdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ use crate::packet::lsa::{
Lsa, LsaHdrVersion, LsaKey, LsaScope, LsaTypeVersion,
};
use crate::packet::tlv::{
PrefixSidFlags, RouterInfoCaps, RouterInfoCapsTlv, SidLabelRangeTlv,
SrAlgoTlv, SrLocalBlockTlv,
DynamicHostnameTlv, PrefixSidFlags, RouterInfoCaps, RouterInfoCapsTlv,
SidLabelRangeTlv, SrAlgoTlv, SrLocalBlockTlv,
};
use crate::route::{SummaryNet, SummaryRtr};
use crate::version::Ospfv2;
Expand Down Expand Up @@ -240,6 +240,12 @@ impl LsdbVersion<Self> for Ospfv2 {
}
}
}
LsaOriginateEvent::HostnameChange => {
// (Re)originate Router Information LSA(s) in all areas.
for area in arenas.areas.iter() {
lsa_orig_router_info(area, instance);
}
}
_ => (),
};

Expand Down Expand Up @@ -321,7 +327,7 @@ impl LsdbVersion<Self> for Ospfv2 {
}

fn lsdb_install(
instance: &InstanceUpView<'_, Self>,
instance: &mut InstanceUpView<'_, Self>,
arenas: &mut InstanceArenas<Self>,
lsdb_idx: LsdbIndex,
_lsdb_id: LsdbId,
Expand All @@ -346,6 +352,22 @@ impl LsdbVersion<Self> for Ospfv2 {
}
}
}

// Update hostname database.
if let LsaBody::OpaqueArea(LsaOpaque::RouterInfo(router_info))
| LsaBody::OpaqueAs(LsaOpaque::RouterInfo(router_info)) = &lsa.body
{
if let Some(hostname_tlv) = router_info.info_hostname.as_ref() {
// Install or update hostname.
instance
.state
.hostnames
.insert(lsa.hdr.adv_rtr, hostname_tlv.hostname.clone());
} else {
// Remove hostname if it exists.
instance.state.hostnames.remove(&lsa.hdr.adv_rtr);
}
}
}
}

Expand Down Expand Up @@ -595,6 +617,11 @@ fn lsa_orig_router_info(
srlb,
msds: None,
srms_pref: None,
info_hostname: instance
.shared
.hostname
.as_ref()
.map(|hostname| DynamicHostnameTlv::new(hostname.to_string())),
unknown_tlvs: vec![],
}));
instance.tx.protocol_input.lsa_orig_check(
Expand Down
18 changes: 14 additions & 4 deletions holo-ospf/src/ospfv2/packet/lsa_opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ use crate::ospfv2::packet::lsa::{LsaRouterLinkType, LsaUnknown};
use crate::packet::error::{DecodeError, DecodeResult};
use crate::packet::lsa::{AdjSidVersion, PrefixSidVersion};
use crate::packet::tlv::{
tlv_encode_end, tlv_encode_start, tlv_wire_len, AdjSidFlags, GrReasonTlv,
GracePeriodTlv, MsdTlv, PrefixSidFlags, RouterFuncCapsTlv,
RouterInfoCapsTlv, RouterInfoTlvType, SidLabelRangeTlv, SrAlgoTlv,
SrLocalBlockTlv, SrmsPrefTlv, UnknownTlv, TLV_HDR_SIZE,
tlv_encode_end, tlv_encode_start, tlv_wire_len, AdjSidFlags,
DynamicHostnameTlv, GrReasonTlv, GracePeriodTlv, MsdTlv, PrefixSidFlags,
RouterFuncCapsTlv, RouterInfoCapsTlv, RouterInfoTlvType, SidLabelRangeTlv,
SrAlgoTlv, SrLocalBlockTlv, SrmsPrefTlv, UnknownTlv, TLV_HDR_SIZE,
};

// OSPFv2 opaque LSA types.
Expand Down Expand Up @@ -122,6 +122,8 @@ pub struct LsaRouterInfo {
pub srlb: Vec<SrLocalBlockTlv>,
pub msds: Option<MsdTlv>,
pub srms_pref: Option<SrmsPrefTlv>,
#[serde(skip)]
pub info_hostname: Option<DynamicHostnameTlv>,
pub unknown_tlvs: Vec<UnknownTlv>,
}

Expand Down Expand Up @@ -544,6 +546,11 @@ impl LsaRouterInfo {
RouterFuncCapsTlv::decode(tlv_len, &mut buf_tlv)?;
router_info.func_caps.get_or_insert(caps);
}
Some(RouterInfoTlvType::DynamicHostname) => {
let hostname =
DynamicHostnameTlv::decode(tlv_len, &mut buf_tlv)?;
router_info.info_hostname.get_or_insert(hostname);
}
Some(RouterInfoTlvType::SrAlgo) => {
let sr_algo = SrAlgoTlv::decode(tlv_len, &mut buf_tlv)?;
router_info.sr_algo.get_or_insert(sr_algo);
Expand Down Expand Up @@ -584,6 +591,9 @@ impl LsaRouterInfo {
if let Some(func_caps) = &self.func_caps {
func_caps.encode(buf);
}
if let Some(info_hostname) = &self.info_hostname {
info_hostname.encode(buf);
}
if let Some(sr_algo) = &self.sr_algo {
sr_algo.encode(buf);
}
Expand Down
35 changes: 31 additions & 4 deletions holo-ospf/src/ospfv3/lsdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ use crate::packet::lsa::{
Lsa, LsaHdrVersion, LsaKey, LsaScope, LsaTypeVersion, PrefixSidVersion,
};
use crate::packet::tlv::{
BierEncapId, BierEncapSubSubTlv, BierSubSubTlv, BierSubTlv, PrefixSidFlags,
RouterInfoCaps, RouterInfoCapsTlv, SidLabelRangeTlv, SrAlgoTlv,
SrLocalBlockTlv,
BierEncapId, BierEncapSubSubTlv, BierSubSubTlv, BierSubTlv,
DynamicHostnameTlv, PrefixSidFlags, RouterInfoCaps, RouterInfoCapsTlv,
SidLabelRangeTlv, SrAlgoTlv, SrLocalBlockTlv,
};
use crate::route::{SummaryNet, SummaryNetFlags, SummaryRtr};
use crate::version::Ospfv3;
Expand Down Expand Up @@ -281,6 +281,12 @@ impl LsdbVersion<Self> for Ospfv3 {
}
}
}
LsaOriginateEvent::HostnameChange => {
// (Re)originate Router-Info-LSA(s) in all areas.
for area in arenas.areas.iter() {
lsa_orig_router_info(area, instance);
}
}
LsaOriginateEvent::BierEnableChange => {
// Reoriginate Intra-area-prefix-LSA(s) in all areas.
for area in arenas.areas.iter() {
Expand Down Expand Up @@ -418,7 +424,7 @@ impl LsdbVersion<Self> for Ospfv3 {
}

fn lsdb_install(
instance: &InstanceUpView<'_, Self>,
instance: &mut InstanceUpView<'_, Self>,
_arenas: &mut InstanceArenas<Self>,
_lsdb_idx: LsdbIndex,
lsdb_id: LsdbId,
Expand All @@ -434,6 +440,22 @@ impl LsdbVersion<Self> for Ospfv3 {
);
}
}

// Check for DynamicHostnameTlv
if lsa.hdr.lsa_type.function_code_normalized()
== Some(LsaFunctionCode::RouterInfo)
{
if let LsaBody::RouterInfo(router_info) = &lsa.body {
if let Some(hostname_tlv) = router_info.info_hostname.as_ref() {
instance
.state
.hostnames
.insert(lsa.hdr.adv_rtr, hostname_tlv.hostname.clone());
} else {
instance.state.hostnames.remove(&lsa.hdr.adv_rtr);
}
}
}
}
}

Expand Down Expand Up @@ -1074,6 +1096,11 @@ fn lsa_orig_router_info(
srlb,
msds: None,
srms_pref: None,
info_hostname: instance
.shared
.hostname
.as_ref()
.map(|hostname| DynamicHostnameTlv::new(hostname.to_string())),
unknown_tlvs: vec![],
});
instance
Expand Down
Loading
Loading