Skip to content

Commit

Permalink
Merge pull request #45 from fliqqs/rfc7777
Browse files Browse the repository at this point in the history
RFC 7777 Support
  • Loading branch information
rwestphal authored Feb 12, 2025
2 parents d0b5e4f + 0107f96 commit 58261bf
Show file tree
Hide file tree
Showing 13 changed files with 220 additions and 68 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ Holo supports the following Internet Standards:
* RFC 7684 - OSPFv2 Prefix/Link Attribute Advertisement
* RFC 7166 - Supporting Authentication Trailer for OSPFv3
* RFC 7770 - Extensions to OSPF for Advertising Optional Router Capabilities
* RFC 7777 - Advertising Node Administrative Tags in OSPF
* RFC 8362 - OSPFv3 Link State Advertisement (LSA) Extensibility
* RFC 8405 - Shortest Path First (SPF) Back-Off Delay Algorithm for Link-State IGPs
* RFC 8476 - Signaling Maximum SID Depth (MSD) Using OSPF
Expand Down Expand Up @@ -236,7 +237,7 @@ Holo supports the following Internet Standards:
| ietf-mpls-ldp@2022-03-14 | 86.96% | 92.31% | 100.00% | 100.00% | [92.38%](https://holo-routing.github.io/ietf-yang-coverage/ietf-mpls-ldp@2022-03-14.html) |
| ietf-mpls@2020-12-18 | 0.00% | 57.14% | - | - | [35.29%](https://holo-routing.github.io/ietf-yang-coverage/ietf-mpls@2020-12-18.html) |
| ietf-ospf-sr-mpls@2024-06-19 | 23.08% | 51.82% | - | - | [50.63%](https://holo-routing.github.io/ietf-yang-coverage/ietf-ospf-sr-mpls@2024-06-19.html) |
| ietf-ospf@2022-10-19 | 75.00% | 63.50% | 100.00% | 41.94% | [62.85%](https://holo-routing.github.io/ietf-yang-coverage/ietf-ospf@2022-10-19.html) |
| ietf-ospf@2022-10-19 | 75.82% | 64.25% | 100.00% | 41.94% | [63.58%](https://holo-routing.github.io/ietf-yang-coverage/ietf-ospf@2022-10-19.html) |
| ietf-ospfv3-extended-lsa@2024-06-07 | 50.00% | 85.28% | - | - | [84.85%](https://holo-routing.github.io/ietf-yang-coverage/ietf-ospfv3-extended-lsa@2024-06-07.html) |
| ietf-rip@2020-02-20 | 27.91% | 93.33% | 100.00% | - | [55.41%](https://holo-routing.github.io/ietf-yang-coverage/ietf-rip@2020-02-20.html) |
| ietf-routing-policy@2021-10-11 | 100.00% | 0.00% | - | - | [98.11%](https://holo-routing.github.io/ietf-yang-coverage/ietf-routing-policy@2021-10-11.html) |
Expand Down
1 change: 1 addition & 0 deletions holo-ospf/src/lsdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ pub enum LsaOriginateEvent {
change: BierCfgEvent,
},
HostnameChange,
NodeTagsChange,
}

#[derive(Debug)]
Expand Down
36 changes: 35 additions & 1 deletion holo-ospf/src/northbound/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// SPDX-License-Identifier: MIT
//

use std::collections::{BTreeMap, HashSet};
use std::collections::{BTreeMap, BTreeSet, HashSet};
use std::net::Ipv4Addr;
use std::sync::LazyLock as Lazy;

Expand Down Expand Up @@ -38,6 +38,7 @@ use crate::{gr, southbound, spf, sr};
#[derive(Debug, EnumAsInner)]
pub enum ListEntry<V: Version> {
None,
NodeTag(u32),
Area(AreaIndex),
AreaRange(AreaIndex, V::IpNetwork),
Interface(AreaIndex, InterfaceIndex),
Expand Down Expand Up @@ -74,6 +75,7 @@ pub enum Event {
UpdateSummaries,
ReinstallRoutes,
BierEnableChange(bool),
NodeTagsChange,
}

pub static VALIDATION_CALLBACKS_OSPFV2: Lazy<ValidationCallbacks> =
Expand Down Expand Up @@ -101,6 +103,7 @@ pub struct InstanceCfg {
pub spf_hold_down: u32,
pub spf_time_to_learn: u32,
pub stub_router: bool,
pub node_tags: BTreeSet<u32>,
pub extended_lsa: bool,
pub sr_enabled: bool,
pub instance_id: u8,
Expand Down Expand Up @@ -362,6 +365,27 @@ where
let event_queue = args.event_queue;
event_queue.insert(Event::StubRouterChange);
})
.path(ospf::node_tags::node_tag::PATH)
.create_apply(|instance, args| {
let node_tag = args.dnode.get_u32_relative("tag").unwrap();
instance.config.node_tags.insert(node_tag);

let event_queue = args.event_queue;
event_queue.insert(Event::NodeTagsChange);

})
.delete_apply(|instance, args| {
let node_tag = args.list_entry.into_node_tag().unwrap();
instance.config.node_tags.remove(&node_tag);

let event_queue = args.event_queue;
event_queue.insert(Event::NodeTagsChange);

})
.lookup(|_instance, _list_entry, dnode| {
let node_tag = dnode.get_u32_relative("tag").unwrap();
ListEntry::NodeTag(node_tag)
})
.path(ospf::extended_lsa_support::PATH)
.modify_apply(|instance, args| {
let extended_lsa = args.dnode.get_bool();
Expand Down Expand Up @@ -1583,6 +1607,15 @@ where
}
}
}
Event::NodeTagsChange => {
if let Some((instance, arenas)) = self.as_up() {
let _ = V::lsa_orig_event(
&instance,
arenas,
LsaOriginateEvent::NodeTagsChange,
);
}
}
}
}
}
Expand Down Expand Up @@ -1631,6 +1664,7 @@ impl Default for InstanceCfg {
spf_hold_down,
spf_time_to_learn,
stub_router: false,
node_tags: Default::default(),
extended_lsa,
sr_enabled,
instance_id,
Expand Down
54 changes: 53 additions & 1 deletion holo-ospf/src/northbound/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::lsdb::{LsaEntry, LsaLogEntry, LsaLogId};
use crate::neighbor::Neighbor;
use crate::packet::lsa::{LsaBodyVersion, LsaHdrVersion};
use crate::packet::tlv::{
GrReason, SidLabelRangeTlv, SrLocalBlockTlv, UnknownTlv,
GrReason, NodeAdminTagTlv, SidLabelRangeTlv, SrLocalBlockTlv, UnknownTlv,
};
use crate::route::{Nexthop, RouteNet};
use crate::spf::SpfLogEntry;
Expand Down Expand Up @@ -67,6 +67,8 @@ pub enum ListEntry<'a, V: Version> {
Msd(u8, u8),
Srgb(&'a SidLabelRangeTlv),
Srlb(&'a SrLocalBlockTlv),
NodeAdminTagTlv(&'a NodeAdminTagTlv),
NodeAdminTag(&'a u32),
UnknownTlv(&'a UnknownTlv),
Flag(&'static str),
FlagU32(u32),
Expand Down Expand Up @@ -1096,6 +1098,32 @@ 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::node_tag_tlvs::node_tag_tlv::PATH)
.get_iterate(|_instance, args| {
let lse: &LsaEntry<Ospfv2> = args.parent_list_entry.as_area_lsa().unwrap();
let lsa = &lse.data;
if let Some(lsa_body) = lsa.body.as_opaque_area()
&& let Some(lsa_body) = lsa_body.as_router_info()
{
let iter = lsa_body.node_tags.iter().map(ListEntry::NodeAdminTagTlv);
Some(Box::new(iter))
} else {
None
}
})
.path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv2::body::opaque::ri_opaque::node_tag_tlvs::node_tag_tlv::node_tag::PATH)
.get_iterate(|_instance, args| {
let tlv = args.parent_list_entry.as_node_admin_tag_tlv().unwrap();
let iter = tlv.tags.iter().map(ListEntry::NodeAdminTag);
Some(Box::new(iter))
})
.get_object(|_instance, args| {
use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv2::body::opaque::ri_opaque::node_tag_tlvs::node_tag_tlv::node_tag::NodeTag;
let tag = args.list_entry.as_node_admin_tag().unwrap();
Box::new(NodeTag {
tag: Some(**tag),
})
})
.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;
Expand Down Expand Up @@ -2309,6 +2337,30 @@ 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::node_tag_tlvs::node_tag_tlv::PATH)
.get_iterate(|_instance, args| {
let lse: &LsaEntry<Ospfv3> = args.parent_list_entry.as_area_lsa().unwrap();
let lsa = &lse.data;
if let Some(lsa_body) = lsa.body.as_router_info() {
let iter = lsa_body.node_tags.iter().map(ListEntry::NodeAdminTagTlv);
Some(Box::new(iter))
} else {
None
}
})
.path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::router_information::node_tag_tlvs::node_tag_tlv::node_tag::PATH)
.get_iterate(|_instance, args| {
let tlv = args.parent_list_entry.as_node_admin_tag_tlv().unwrap();
let iter = tlv.tags.iter().map(ListEntry::NodeAdminTag);
Some(Box::new(iter))
})
.get_object(|_instance, args| {
use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::router_information::node_tag_tlvs::node_tag_tlv::node_tag::NodeTag;
let tag = args.list_entry.as_node_admin_tag().unwrap();
Box::new(NodeTag {
tag: Some(**tag),
})
})
.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;
Expand Down
14 changes: 11 additions & 3 deletions holo-ospf/src/ospfv2/lsdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ use crate::packet::lsa::{
Lsa, LsaHdrVersion, LsaKey, LsaScope, LsaTypeVersion,
};
use crate::packet::tlv::{
DynamicHostnameTlv, PrefixSidFlags, RouterInfoCaps, RouterInfoCapsTlv,
SidLabelRangeTlv, SrAlgoTlv, SrLocalBlockTlv,
DynamicHostnameTlv, NodeAdminTagTlv, PrefixSidFlags, RouterInfoCaps,
RouterInfoCapsTlv, SidLabelRangeTlv, SrAlgoTlv, SrLocalBlockTlv,
};
use crate::route::{SummaryNet, SummaryRtr};
use crate::version::Ospfv2;
Expand Down Expand Up @@ -239,7 +239,8 @@ impl LsdbVersion<Self> for Ospfv2 {
}
}
}
LsaOriginateEvent::HostnameChange => {
LsaOriginateEvent::HostnameChange
| LsaOriginateEvent::NodeTagsChange => {
// (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 @@ -603,6 +604,12 @@ fn lsa_orig_router_info(
}
}

// Fill in node tags.
let mut node_tags = vec![];
if !instance.config.node_tags.is_empty() {
node_tags.push(NodeAdminTagTlv::new(instance.config.node_tags.clone()));
}

// (Re)originate Router Information LSA.
let mut info_caps = RouterInfoCaps::STUB_ROUTER;
if instance.config.gr.helper_enabled {
Expand All @@ -621,6 +628,7 @@ fn lsa_orig_router_info(
.hostname
.as_ref()
.map(|hostname| DynamicHostnameTlv::new(hostname.to_string())),
node_tags,
unknown_tlvs: vec![],
}));
instance.tx.protocol_input.lsa_orig_check(
Expand Down
17 changes: 14 additions & 3 deletions holo-ospf/src/ospfv2/packet/lsa_opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ use crate::packet::error::{DecodeError, DecodeResult};
use crate::packet::lsa::{AdjSidVersion, PrefixSidVersion};
use crate::packet::tlv::{
AdjSidFlags, DynamicHostnameTlv, GrReasonTlv, GracePeriodTlv, MsdTlv,
PrefixSidFlags, RouterFuncCapsTlv, RouterInfoCapsTlv, RouterInfoTlvType,
SidLabelRangeTlv, SrAlgoTlv, SrLocalBlockTlv, SrmsPrefTlv, TLV_HDR_SIZE,
UnknownTlv, tlv_encode_end, tlv_encode_start, tlv_wire_len,
NodeAdminTagTlv, PrefixSidFlags, RouterFuncCapsTlv, RouterInfoCapsTlv,
RouterInfoTlvType, SidLabelRangeTlv, SrAlgoTlv, SrLocalBlockTlv,
SrmsPrefTlv, TLV_HDR_SIZE, UnknownTlv, tlv_encode_end, tlv_encode_start,
tlv_wire_len,
};

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

Expand Down Expand Up @@ -551,6 +554,11 @@ impl LsaRouterInfo {
DynamicHostnameTlv::decode(tlv_len, &mut buf_tlv)?;
router_info.info_hostname.get_or_insert(hostname);
}
Some(RouterInfoTlvType::NodeAdminTag) => {
let node_tag =
NodeAdminTagTlv::decode(tlv_len, &mut buf_tlv)?;
router_info.node_tags.push(node_tag);
}
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 @@ -594,6 +602,9 @@ impl LsaRouterInfo {
if let Some(info_hostname) = &self.info_hostname {
info_hostname.encode(buf);
}
for node_tag in &self.node_tags {
node_tag.encode(buf);
}
if let Some(sr_algo) = &self.sr_algo {
sr_algo.encode(buf);
}
Expand Down
14 changes: 11 additions & 3 deletions holo-ospf/src/ospfv3/lsdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ use crate::packet::lsa::{
};
use crate::packet::tlv::{
BierEncapId, BierEncapSubSubTlv, BierSubSubTlv, BierSubTlv,
DynamicHostnameTlv, PrefixSidFlags, RouterInfoCaps, RouterInfoCapsTlv,
SidLabelRangeTlv, SrAlgoTlv, SrLocalBlockTlv,
DynamicHostnameTlv, NodeAdminTagTlv, PrefixSidFlags, RouterInfoCaps,
RouterInfoCapsTlv, SidLabelRangeTlv, SrAlgoTlv, SrLocalBlockTlv,
};
use crate::route::{SummaryNet, SummaryNetFlags, SummaryRtr};
use crate::version::Ospfv3;
Expand Down Expand Up @@ -282,7 +282,8 @@ impl LsdbVersion<Self> for Ospfv3 {
}
}
}
LsaOriginateEvent::HostnameChange => {
LsaOriginateEvent::HostnameChange
| LsaOriginateEvent::NodeTagsChange => {
// (Re)originate Router-Info-LSA(s) in all areas.
for area in arenas.areas.iter() {
lsa_orig_router_info(area, instance);
Expand Down Expand Up @@ -1063,6 +1064,7 @@ fn lsa_orig_router_info(
let mut sr_algo = None;
let mut srgb = vec![];
let mut srlb = vec![];
let mut node_tags = vec![];
if instance.config.sr_enabled {
// Fill in supported SR algorithms.
sr_algo = Some(SrAlgoTlv::new([IgpAlgoType::Spf].into()));
Expand All @@ -1082,6 +1084,11 @@ fn lsa_orig_router_info(
}
}

// Fill in node tags.
if !instance.config.node_tags.is_empty() {
node_tags.push(NodeAdminTagTlv::new(instance.config.node_tags.clone()));
}

// (Re)originate Router Information LSA.
let scope = LsaScopeCode::Area;
let mut info_caps = RouterInfoCaps::STUB_ROUTER;
Expand All @@ -1102,6 +1109,7 @@ fn lsa_orig_router_info(
.hostname
.as_ref()
.map(|hostname| DynamicHostnameTlv::new(hostname.to_string())),
node_tags,
unknown_tlvs: vec![],
});
instance
Expand Down
13 changes: 12 additions & 1 deletion holo-ospf/src/ospfv3/packet/lsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::packet::lsa::{
};
use crate::packet::tlv::{
AdjSidFlags, BierSubTlv, DynamicHostnameTlv, GrReason, GrReasonTlv,
GracePeriodTlv, MsdTlv, PrefixSidFlags, RouterFuncCapsTlv,
GracePeriodTlv, MsdTlv, NodeAdminTagTlv, PrefixSidFlags, RouterFuncCapsTlv,
RouterInfoCapsTlv, RouterInfoTlvType, SidLabelRangeTlv, SrAlgoTlv,
SrLocalBlockTlv, SrmsPrefTlv, TLV_HDR_SIZE, UnknownTlv, tlv_encode_end,
tlv_encode_start, tlv_wire_len,
Expand Down Expand Up @@ -957,6 +957,9 @@ pub struct LsaRouterInfo {
#[serde(skip)]
pub info_hostname: Option<DynamicHostnameTlv>,
#[new(default)]
#[serde(skip)]
pub node_tags: Vec<NodeAdminTagTlv>,
#[new(default)]
pub unknown_tlvs: Vec<UnknownTlv>,
}

Expand Down Expand Up @@ -2565,6 +2568,11 @@ impl LsaRouterInfo {
DynamicHostnameTlv::decode(tlv_len, &mut buf_tlv)?;
router_info.info_hostname.get_or_insert(hostname);
}
Some(RouterInfoTlvType::NodeAdminTag) => {
let node_tag =
NodeAdminTagTlv::decode(tlv_len, &mut buf_tlv)?;
router_info.node_tags.push(node_tag);
}
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 @@ -2608,6 +2616,9 @@ impl LsaRouterInfo {
if let Some(info_hostname) = &self.info_hostname {
info_hostname.encode(buf);
}
for node_tag in &self.node_tags {
node_tag.encode(buf);
}
if let Some(sr_algo) = &self.sr_algo {
sr_algo.encode(buf);
}
Expand Down
Loading

0 comments on commit 58261bf

Please sign in to comment.