diff --git a/holo-ospf/src/bier.rs b/holo-ospf/src/bier.rs new file mode 100644 index 00000000..3b01dd8e --- /dev/null +++ b/holo-ospf/src/bier.rs @@ -0,0 +1,57 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use holo_utils::bier::{BierInfo, Bsl, UnderlayProtocolType}; +use holo_utils::ip::IpNetworkKind; + +use crate::instance::InstanceUpView; +use crate::packet::tlv::BierSubSubTlv; +use crate::route::RouteNet; +use crate::spf::SpfIntraAreaNetwork; +use crate::version::Version; + +pub(crate) fn bier_route_add( + instance: &InstanceUpView<'_, V>, + new_route: &mut RouteNet, + stub: &SpfIntraAreaNetwork<'_, V>, +) where + V: Version, +{ + let bier_cfg = &instance.shared.bier_config; + + // 1. Does the BFR match a locally configured BIER sub-domain? + stub.bier.iter().for_each(|tlv| { + if instance.config.bier.mt_id == tlv.mt_id + && let Some(sd_cfg) = bier_cfg + .sd_cfg + .get(&(tlv.sub_domain_id, stub.prefix.address_family())) + && sd_cfg.underlay_protocol == UnderlayProtocolType::Ospf + { + // 2. Register entry in BIRT for each supported bitstring length by the BFR prefix + // TODO: Use BAR and IPA + + // TODO: Sanity check on bitstring lengths upon LSA reception + + let bfr_bss: Vec = tlv + .subtlvs + .iter() + .filter_map(|stlv| match stlv { + BierSubSubTlv::BierEncapSubSubTlv(encap) => { + Bsl::try_from(encap.bs_len).ok() + } + }) + .collect(); + + if !bfr_bss.is_empty() { + new_route.bier_info = Some(BierInfo { + bfr_bss, + sd_id: tlv.sub_domain_id, + bfr_id: tlv.bfr_id, + }) + } + } + }); +} diff --git a/holo-ospf/src/events.rs b/holo-ospf/src/events.rs index 4562b086..09af5c8b 100644 --- a/holo-ospf/src/events.rs +++ b/holo-ospf/src/events.rs @@ -11,7 +11,7 @@ use std::sync::Arc; use chrono::Utc; use holo_utils::bfd; -use holo_utils::ibus::SrCfgEvent; +use holo_utils::ibus::{BierCfgEvent, SrCfgEvent}; use crate::area::{Area, AreaType}; use crate::collections::{ @@ -1429,6 +1429,27 @@ where Ok(()) } +// ===== BIER configuration change event ===== + +pub(crate) fn process_bier_cfg_change( + instance: &mut Instance, + change: BierCfgEvent, +) -> Result<(), Error> +where + V: Version, +{ + if let Some((instance, arenas)) = instance.as_up() + && instance.config.bier.enabled + { + V::lsa_orig_event( + &instance, + arenas, + LsaOriginateEvent::BierCfgChange { change }, + )?; + } + Ok(()) +} + // ===== BFD state update event ===== pub(crate) fn process_bfd_state_update( diff --git a/holo-ospf/src/instance.rs b/holo-ospf/src/instance.rs index c715fb2b..3a516637 100644 --- a/holo-ospf/src/instance.rs +++ b/holo-ospf/src/instance.rs @@ -780,10 +780,17 @@ where IbusMsg::SrCfgUpd(sr_config) => { instance.shared.sr_config = sr_config; } + // BIER configuration update. + IbusMsg::BierCfgUpd(bier_config) => { + instance.shared.bier_config = bier_config.clone(); + } // SR configuration event. IbusMsg::SrCfgEvent(event) => { events::process_sr_cfg_change(instance, event)? } + IbusMsg::BierCfgEvent(event) => { + events::process_bier_cfg_change(instance, event)? + } // Ignore other events. _ => {} } diff --git a/holo-ospf/src/lib.rs b/holo-ospf/src/lib.rs index 27144378..2198ab38 100644 --- a/holo-ospf/src/lib.rs +++ b/holo-ospf/src/lib.rs @@ -12,6 +12,7 @@ #![feature(btree_extract_if, hash_extract_if, ip, let_chains)] pub mod area; +pub mod bier; pub mod collections; pub mod debug; pub mod error; diff --git a/holo-ospf/src/lsdb.rs b/holo-ospf/src/lsdb.rs index c78ad41f..24a106dc 100644 --- a/holo-ospf/src/lsdb.rs +++ b/holo-ospf/src/lsdb.rs @@ -13,7 +13,7 @@ use std::time::Instant; use bitflags::bitflags; use chrono::Utc; use derive_new::new; -use holo_utils::ibus::SrCfgEvent; +use holo_utils::ibus::{BierCfgEvent, SrCfgEvent}; use holo_utils::task::TimeoutTask; use holo_utils::UnboundedSender; use serde::{Deserialize, Serialize}; @@ -124,6 +124,10 @@ pub enum LsaOriginateEvent { area_id: AreaId, iface_id: InterfaceId, }, + BierEnableChange, + BierCfgChange { + change: BierCfgEvent, + }, } #[derive(Debug)] diff --git a/holo-ospf/src/northbound/configuration.rs b/holo-ospf/src/northbound/configuration.rs index 641e05b3..36e09b53 100644 --- a/holo-ospf/src/northbound/configuration.rs +++ b/holo-ospf/src/northbound/configuration.rs @@ -72,6 +72,7 @@ pub enum Event { RerunSpf, UpdateSummaries, ReinstallRoutes, + BierEnableChange(bool), } pub static VALIDATION_CALLBACKS_OSPFV2: Lazy = @@ -102,6 +103,15 @@ pub struct InstanceCfg { pub extended_lsa: bool, pub sr_enabled: bool, pub instance_id: u8, + pub bier: BierOspfCfg, +} + +#[derive(Debug)] +pub struct BierOspfCfg { + pub mt_id: u8, + pub enabled: bool, + pub advertise: bool, + pub receive: bool, } #[derive(Debug)] @@ -778,6 +788,35 @@ where let mtu_ignore = args.dnode.get_bool(); iface.config.mtu_ignore = mtu_ignore; }) + .path(ospf::bier::mt_id::PATH) + .modify_apply(|instance, args| { + let mt_id = args.dnode.get_u8(); + instance.config.bier.mt_id = mt_id; + + // TODO: should reoriginate LSA + }) + .delete_apply(|instance, _args| { + let mt_id = 0; + instance.config.bier.mt_id = mt_id; + }) + .path(ospf::bier::bier::enable::PATH) + .modify_apply(|instance, args| { + let enable = args.dnode.get_bool(); + instance.config.bier.enabled = enable; + + let event_queue = args.event_queue; + event_queue.insert(Event::BierEnableChange(enable)); + }) + .path(ospf::bier::bier::advertise::PATH) + .modify_apply(|instance, args| { + let advertise = args.dnode.get_bool(); + instance.config.bier.advertise = advertise; + }) + .path(ospf::bier::bier::receive::PATH) + .modify_apply(|instance, args| { + let receive = args.dnode.get_bool(); + instance.config.bier.receive = receive; + }) .build() } @@ -1471,6 +1510,22 @@ where } } } + Event::BierEnableChange(bier_enabled) => { + if let Some((instance, _arenas)) = self.as_up() { + // (Re)originate LSAs that might have been affected. + instance + .tx + .protocol_input + .lsa_orig_event(LsaOriginateEvent::BierEnableChange); + + // Purge BIRT if bier disabled or re-install routes if enabled + if bier_enabled { + self.process_event(Event::ReinstallRoutes).await; + } else { + let _ = instance.tx.ibus.send(IbusMsg::BierPurge); + } + } + } Event::RerunSpf => { if let Some((instance, _)) = self.as_up() { instance @@ -1559,6 +1614,21 @@ impl Default for InstanceCfg { extended_lsa, sr_enabled, instance_id, + bier: Default::default(), + } + } +} + +impl Default for BierOspfCfg { + fn default() -> Self { + let enabled = ospf::bier::bier::enable::DFLT; + let advertise = ospf::bier::bier::advertise::DFLT; + let receive = ospf::bier::bier::receive::DFLT; + Self { + mt_id: 0, + enabled, + advertise, + receive, } } } diff --git a/holo-ospf/src/ospfv2/spf.rs b/holo-ospf/src/ospfv2/spf.rs index e350dc8c..c73a28e5 100644 --- a/holo-ospf/src/ospfv2/spf.rs +++ b/holo-ospf/src/ospfv2/spf.rs @@ -491,6 +491,8 @@ impl SpfVersion for Ospfv2 { prefix_options: Default::default(), metric: 0, prefix_sids, + // FIXME: BIER not supported yet for OSPFv2 + bier: Default::default(), }); } VertexLsa::Router(lsa) => { @@ -523,6 +525,8 @@ impl SpfVersion for Ospfv2 { prefix_options: Default::default(), metric, prefix_sids, + // FIXME: BIER not supported yet for OSPFv2 + bier: Default::default(), } }), ) diff --git a/holo-ospf/src/ospfv3/lsdb.rs b/holo-ospf/src/ospfv3/lsdb.rs index 192a3e45..f715e295 100644 --- a/holo-ospf/src/ospfv3/lsdb.rs +++ b/holo-ospf/src/ospfv3/lsdb.rs @@ -7,7 +7,8 @@ use std::collections::{hash_map, BTreeMap, HashMap}; use std::net::{IpAddr, Ipv4Addr}; -use holo_utils::ibus::SrCfgEvent; +use holo_utils::bier::{BierEncapsulationType, BierInBiftId, BiftId}; +use holo_utils::ibus::{BierCfgEvent, SrCfgEvent}; use holo_utils::ip::{AddressFamily, IpNetworkKind}; use holo_utils::mpls::Label; use holo_utils::sr::{IgpAlgoType, Sid, SidLastHopBehavior}; @@ -35,8 +36,9 @@ use crate::packet::lsa::{ Lsa, LsaHdrVersion, LsaKey, LsaScope, LsaTypeVersion, PrefixSidVersion, }; use crate::packet::tlv::{ - PrefixSidFlags, RouterInfoCaps, RouterInfoCapsTlv, SidLabelRangeTlv, - SrAlgoTlv, SrLocalBlockTlv, + BierEncapId, BierEncapSubSubTlv, BierSubSubTlv, BierSubTlv, PrefixSidFlags, + RouterInfoCaps, RouterInfoCapsTlv, SidLabelRangeTlv, SrAlgoTlv, + SrLocalBlockTlv, }; use crate::route::{SummaryNet, SummaryNetFlags, SummaryRtr}; use crate::version::Ospfv3; @@ -279,6 +281,23 @@ impl LsdbVersion for Ospfv3 { } } } + LsaOriginateEvent::BierEnableChange => { + // Reoriginate Intra-area-prefix-LSA(s) in all areas. + for area in arenas.areas.iter() { + lsa_orig_intra_area_prefix(area, instance, arenas); + } + } + LsaOriginateEvent::BierCfgChange { change } => match change { + BierCfgEvent::EncapUpdate(af) + | BierCfgEvent::SubDomainUpdate(af) => { + if af == instance.state.af { + for area in arenas.areas.iter() { + // Reoriginate Intra-area-prefix-LSA(s) in all areas. + lsa_orig_intra_area_prefix(area, instance, arenas); + } + } + } + }, }; Ok(()) @@ -717,6 +736,7 @@ fn lsa_orig_intra_area_prefix( arenas: &InstanceArenas, ) { let sr_config = &instance.shared.sr_config; + let bier_config = &instance.shared.bier_config; let lsdb_id = LsdbId::Area(area.id); let extended_lsa = instance.config.extended_lsa; let adv_rtr = instance.state.router_id; @@ -817,6 +837,60 @@ fn lsa_orig_intra_area_prefix( } } + // Add BIER Sub-TLV(s) if BIER is enabled and allowed to advertise + if instance.config.bier.enabled && instance.config.bier.advertise { + bier_config + .sd_cfg + .iter() + // Search for subdomain configuration(s) for current prefix + .filter(|((_, af), sd_cfg)| { + af == &AddressFamily::Ipv6 && sd_cfg.bfr_prefix == prefix + }) + .for_each(|((sd_id, _), sd_cfg)| { + // BIER prefix has configured encap ? + let bier_encaps = sd_cfg + .encap + .iter() + .filter_map(|((bsl, encap_type), encap)| { + match encap_type { + BierEncapsulationType::Mpls => { + // TODO: where is the label defined? + Some(BierEncapId::Mpls(Label::new(0))) + } + _ => match encap.in_bift_id { + BierInBiftId::Base(id) => Some(id), + BierInBiftId::Encoding(true) => Some(0), + _ => None, + } + .map(|id| { + BierEncapId::NonMpls(BiftId::new(id)) + }), + } + .map(|id| { + BierSubSubTlv::BierEncapSubSubTlv( + BierEncapSubSubTlv::new( + encap.max_si, + id, + (*bsl).into(), + ), + ) + }) + }) + .collect::>(); + + let bier = BierSubTlv::new( + *sd_id, + sd_cfg.mt_id, + sd_cfg.bfr_id, + sd_cfg.bar, + sd_cfg.ipa, + bier_encaps, + ); + + entry.bier.push(bier); + }); + } + prefixes.push(entry); } let ref_lsa = LsaKey::new( diff --git a/holo-ospf/src/ospfv3/packet/lsa.rs b/holo-ospf/src/ospfv3/packet/lsa.rs index 0d780f9c..5e45a7e2 100644 --- a/holo-ospf/src/ospfv3/packet/lsa.rs +++ b/holo-ospf/src/ospfv3/packet/lsa.rs @@ -30,10 +30,10 @@ use crate::packet::lsa::{ PrefixSidVersion, }; use crate::packet::tlv::{ - tlv_encode_end, tlv_encode_start, tlv_wire_len, AdjSidFlags, GrReason, - 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, BierSubTlv, + GrReason, GrReasonTlv, GracePeriodTlv, MsdTlv, PrefixSidFlags, + RouterFuncCapsTlv, RouterInfoCapsTlv, RouterInfoTlvType, SidLabelRangeTlv, + SrAlgoTlv, SrLocalBlockTlv, SrmsPrefTlv, UnknownTlv, TLV_HDR_SIZE, }; use crate::version::Ospfv3; @@ -188,6 +188,7 @@ pub enum ExtLsaSubTlv { LanAdjSid = 6, SidLabel = 7, LinkMsd = 9, + Bier = 42, } // OSPFv3 Extended-LSA Sub-TLVs. @@ -242,6 +243,7 @@ pub struct ExtLsaSubTlvs { pub route_tag: Option, pub prefix_sids: BTreeMap, pub adj_sids: Vec, + pub bier: Vec, pub unknown: Vec, } @@ -886,6 +888,8 @@ pub struct LsaIntraAreaPrefixEntry { #[new(default)] pub prefix_sids: BTreeMap, #[new(default)] + pub bier: Vec, + #[new(default)] pub unknown_stlvs: Vec, } @@ -2368,6 +2372,7 @@ impl LsaIntraAreaPrefix { // Parse Sub-TLVs. let stlvs = ExtLsaSubTlvs::decode(&mut buf_tlv)?; prefix.prefix_sids = stlvs.prefix_sids; + prefix.bier = stlvs.bier; prefix.unknown_stlvs = stlvs.unknown; iap.prefixes.push(prefix); @@ -2449,6 +2454,7 @@ impl LsaIntraAreaPrefixEntry { fn sub_tlvs(&self) -> ExtLsaSubTlvs { ExtLsaSubTlvs { prefix_sids: self.prefix_sids.clone(), + bier: self.bier.clone(), ..Default::default() } } @@ -2732,6 +2738,10 @@ impl ExtLsaSubTlvs { AdjSid::new(flags, weight, nbr_router_id, sid); stlvs.adj_sids.push(adj_sid); } + Some(ExtLsaSubTlv::Bier) => { + let bier = BierSubTlv::decode(tlv_len, &mut buf_value)?; + stlvs.bier.push(bier); + } _ => { // Save unknown Sub-TLV. let value = buf_value.copy_to_bytes(tlv_len as usize); @@ -2790,6 +2800,9 @@ impl ExtLsaSubTlvs { } tlv_encode_end(buf, start_pos); } + for bier in &self.bier { + BierSubTlv::encode(bier, buf, ExtLsaSubTlv::Bier); + } } } diff --git a/holo-ospf/src/ospfv3/spf.rs b/holo-ospf/src/ospfv3/spf.rs index ae935184..4dd1cf5d 100644 --- a/holo-ospf/src/ospfv3/spf.rs +++ b/holo-ospf/src/ospfv3/spf.rs @@ -473,6 +473,7 @@ impl SpfVersion for Ospfv3 { prefix_options: prefix.options, metric: prefix.metric, prefix_sids: prefix.prefix_sids, + bier: prefix.bier, }) }) } diff --git a/holo-ospf/src/packet/tlv.rs b/holo-ospf/src/packet/tlv.rs index 0a74b687..cc70f1f1 100644 --- a/holo-ospf/src/packet/tlv.rs +++ b/holo-ospf/src/packet/tlv.rs @@ -9,6 +9,7 @@ use std::collections::{BTreeMap, BTreeSet}; use bitflags::bitflags; use bytes::{Buf, BufMut, Bytes, BytesMut}; use derive_new::new; +use holo_utils::bier::BiftId; use holo_utils::bytes::{BytesExt, BytesMutExt}; use holo_utils::mpls::Label; use holo_utils::sr::{IgpAlgoType, Sid}; @@ -267,6 +268,100 @@ pub enum GrReason { ControlProcessorSwitchover = 3, } +// +// BIER Sub-TLV. +// +// Encoding format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Type | Length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Sub-domain-ID | MT-ID | BFR-id | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | BAR | IPA | Reserved | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Sub-TLVs (variable) | +// +- -+ +// | | +// +#[derive(Clone, Debug, Eq, new, PartialEq)] +#[derive(Deserialize, Serialize)] +pub struct BierSubTlv { + pub sub_domain_id: u8, + pub mt_id: u8, + pub bfr_id: u16, + pub bar: u8, + pub ipa: u8, + pub subtlvs: Vec, +} + +#[derive(Clone, Debug, Eq, new, PartialEq)] +#[derive(Deserialize, Serialize)] +pub enum BierSubSubTlv { + BierEncapSubSubTlv(BierEncapSubSubTlv), +} + +// +// Bier MPLS Encapsulation Sub-Tlv +// +// Encoding format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Type | Length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Max SI | Label | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |BS Len | Reserved | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Bier Non-MPLS Encapsulation Sub-Tlv +// +// Encoding format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Type | Length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Max SI | BIFT-id | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |BS Len | Reserved | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +#[derive(Clone, Debug, Eq, new, PartialEq)] +#[derive(Deserialize, Serialize)] +pub struct BierEncapSubSubTlv { + pub max_si: u8, + pub id: BierEncapId, + pub bs_len: u8, +} + +#[derive(Clone, Debug, Eq, new, PartialEq)] +#[derive(Deserialize, Serialize)] +pub enum BierEncapId { + Mpls(Label), + NonMpls(BiftId), +} + +impl BierEncapId { + fn get(self) -> u32 { + match self { + Self::Mpls(label) => label.get(), + Self::NonMpls(bift_id) => bift_id.get(), + } + } +} + +#[derive(FromPrimitive, ToPrimitive)] +pub enum BierSubTlvType { + MplsEncap = 41, + NonMplsEncap = 42, +} + #[derive(Clone, Debug, Eq, new, PartialEq)] #[derive(Deserialize, Serialize)] pub struct UnknownTlv { @@ -275,6 +370,100 @@ pub struct UnknownTlv { pub value: Bytes, } +// ===== impl BierSubTlv ===== + +impl BierSubTlv { + pub(crate) fn decode(_tlv_len: u16, buf: &mut Bytes) -> DecodeResult { + let sub_domain_id = buf.get_u8(); + let mt_id = buf.get_u8(); + let bfr_id = buf.get_u16(); + let bar = buf.get_u8(); + let ipa = buf.get_u8(); + let _reserved = buf.get_u16(); + let mut subtlvs: Vec = Vec::new(); + + while buf.remaining() >= TLV_HDR_SIZE as usize { + // Parse Sub-TLV type. + let stlv_type = buf.get_u16(); + + // Parse and validate Sub-TLV length. + let stlv_len = buf.get_u16(); + let stlv_wlen = tlv_wire_len(stlv_len); + if stlv_wlen as usize > buf.remaining() { + return Err(DecodeError::InvalidTlvLength(stlv_len)); + } + + // Parse Sub-TLV value. + let mut buf_stlv = buf.copy_to_bytes(stlv_wlen as usize); + match BierSubTlvType::from_u16(stlv_type) { + Some(stlv_type) => { + match stlv_type { + BierSubTlvType::MplsEncap + | BierSubTlvType::NonMplsEncap => { + let max_si = buf_stlv.get_u8(); + let id = buf_stlv.get_u24(); + let bs_len = (buf_stlv.get_u8() & 0xf0) >> 4; + + let id = match stlv_type { + BierSubTlvType::MplsEncap => { + BierEncapId::Mpls(Label::new(id)) + } + BierSubTlvType::NonMplsEncap => { + BierEncapId::NonMpls(BiftId::new(id)) + } + }; + subtlvs.push(BierSubSubTlv::BierEncapSubSubTlv( + BierEncapSubSubTlv { max_si, id, bs_len }, + )); + } + }; + } + None => { + // Ignore unknown Sub-TLV + continue; + } + } + } + + Ok(BierSubTlv { + sub_domain_id, + mt_id, + bfr_id, + bar, + ipa, + subtlvs, + }) + } + + pub(crate) fn encode( + &self, + buf: &mut BytesMut, + stlv_type: impl ToPrimitive, + ) { + let start_pos = tlv_encode_start(buf, stlv_type); + buf.put_u8(self.sub_domain_id); + buf.put_u8(self.mt_id); + buf.put_u16(self.bfr_id); + buf.put_u8(self.bar); + buf.put_u8(self.ipa); + buf.put_u16(0); + for subtlv in &self.subtlvs { + match subtlv { + BierSubSubTlv::BierEncapSubSubTlv(encap) => { + let start_pos = + tlv_encode_start(buf, BierSubTlvType::NonMplsEncap); + buf.put_u8(encap.max_si); + buf.put_u24(encap.id.clone().get()); + buf.put_u8((encap.bs_len << 4) & 0xf0); + buf.put_u24(0); + tlv_encode_end(buf, start_pos); + } + } + } + tlv_encode_end(buf, start_pos); + } +} + // ===== impl RouterInfoCapsTlv ===== impl RouterInfoCapsTlv { diff --git a/holo-ospf/src/route.rs b/holo-ospf/src/route.rs index 99bd9ef0..f541086b 100644 --- a/holo-ospf/src/route.rs +++ b/holo-ospf/src/route.rs @@ -10,6 +10,7 @@ use std::net::Ipv4Addr; use bitflags::bitflags; use derive_new::new; +use holo_utils::bier::BierInfo; use holo_utils::ip::IpAddrKind; use holo_utils::mpls::Label; use holo_utils::southbound::OspfRouteType; @@ -25,7 +26,7 @@ use crate::northbound::configuration::InstanceCfg; use crate::packet::lsa::{LsaKey, LsaRouterFlagsVersion}; use crate::spf::{SpfPartialComputation, VertexLsaVersion}; use crate::version::Version; -use crate::{southbound, sr}; +use crate::{bier, southbound, sr}; // Network routing table entry. #[derive(Clone, Debug, Eq, PartialEq)] @@ -41,6 +42,7 @@ pub struct RouteNet { pub sr_label: Option