From edc460a6a09350a46df09471f5739d85428a0d37 Mon Sep 17 00:00:00 2001 From: nrybowski Date: Fri, 5 Apr 2024 05:58:13 +0200 Subject: [PATCH 01/13] Add basic support for BIER TLVs in OSPFv3 - Add YANG augmentations from draft-ietf-bier-bier-yang-07 OSPF-side - Partial implementation of draft-ietf-bier-ospfv3-extensions-07 Signed-off-by: Nicolas Rybowski --- holo-ospf/src/instance.rs | 3 + holo-ospf/src/northbound/configuration.rs | 48 ++++++++ holo-ospf/src/ospfv3/lsdb.rs | 13 ++- holo-ospf/src/ospfv3/packet/lsa.rs | 14 ++- holo-ospf/src/packet/tlv.rs | 108 ++++++++++++++++++ .../modules/augmentations/holo-ospf.yang | 51 +++++++++ 6 files changed, 235 insertions(+), 2 deletions(-) diff --git a/holo-ospf/src/instance.rs b/holo-ospf/src/instance.rs index c715fb2b..70bddc6b 100644 --- a/holo-ospf/src/instance.rs +++ b/holo-ospf/src/instance.rs @@ -780,6 +780,9 @@ where IbusMsg::SrCfgUpd(sr_config) => { instance.shared.sr_config = sr_config; } + IbusMsg::BierCfgUpd(bier_config) => { + instance.shared.bier_config = bier_config.clone(); + } // SR configuration event. IbusMsg::SrCfgEvent(event) => { events::process_sr_cfg_change(instance, event)? diff --git a/holo-ospf/src/northbound/configuration.rs b/holo-ospf/src/northbound/configuration.rs index 641e05b3..0817b309 100644 --- a/holo-ospf/src/northbound/configuration.rs +++ b/holo-ospf/src/northbound/configuration.rs @@ -102,6 +102,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: u16, + pub enabled: bool, + pub advertise: bool, + pub receive: bool, } #[derive(Debug)] @@ -778,6 +787,30 @@ where let mtu_ignore = args.dnode.get_bool(); iface.config.mtu_ignore = mtu_ignore; }) + .path(ospf::bier_ospf_cfg::mt_id::PATH) + .modify_apply(|instance, args| { + let mt_id = args.dnode.get_u16(); + instance.config.bier.mt_id = mt_id; + }) + .delete_apply(|instance, _args| { + let mt_id = 0; + instance.config.bier.mt_id = mt_id; + }) + .path(ospf::bier_ospf_cfg::bier::enable::PATH) + .modify_apply(|instance, args| { + let enable = args.dnode.get_bool(); + instance.config.bier.enabled = enable; + }) + .path(ospf::bier_ospf_cfg::bier::advertise::PATH) + .modify_apply(|instance, args| { + let advertise = args.dnode.get_bool(); + instance.config.bier.advertise = advertise; + }) + .path(ospf::bier_ospf_cfg::bier::receive::PATH) + .modify_apply(|instance, args| { + let receive = args.dnode.get_bool(); + instance.config.bier.receive = receive; + }) .build() } @@ -1559,6 +1592,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_ospf_cfg::bier::enable::DFLT; + let advertise = ospf::bier_ospf_cfg::bier::advertise::DFLT; + let receive = ospf::bier_ospf_cfg::bier::receive::DFLT; + Self { + mt_id: 0, + enabled, + advertise, + receive, } } } diff --git a/holo-ospf/src/ospfv3/lsdb.rs b/holo-ospf/src/ospfv3/lsdb.rs index 192a3e45..433fabef 100644 --- a/holo-ospf/src/ospfv3/lsdb.rs +++ b/holo-ospf/src/ospfv3/lsdb.rs @@ -36,7 +36,7 @@ use crate::packet::lsa::{ }; use crate::packet::tlv::{ PrefixSidFlags, RouterInfoCaps, RouterInfoCapsTlv, SidLabelRangeTlv, - SrAlgoTlv, SrLocalBlockTlv, + SrAlgoTlv, SrLocalBlockTlv, BierSubTlv, }; use crate::route::{SummaryNet, SummaryNetFlags, SummaryRtr}; use crate::version::Ospfv3; @@ -717,6 +717,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 +818,16 @@ fn lsa_orig_intra_area_prefix( } } + // Add BIER Sub-TLV(s) + if instance.config.bier.enabled { + bier_config.sd_cfg.iter().for_each(|((sd_id, addr_family), sd_cfg)|{ + if addr_family == &AddressFamily::Ipv6 && sd_cfg.bfr_prefix == prefix { + let bier = BierSubTlv::new(*sd_id, sd_cfg.mt_id, sd_cfg.bfr_id, sd_cfg.bar, sd_cfg.ipa); + 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..30c0de9a 100644 --- a/holo-ospf/src/ospfv3/packet/lsa.rs +++ b/holo-ospf/src/ospfv3/packet/lsa.rs @@ -33,7 +33,7 @@ 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, + SrLocalBlockTlv, SrmsPrefTlv, UnknownTlv, TLV_HDR_SIZE, BierSubTlv, }; 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, } @@ -2449,6 +2453,7 @@ impl LsaIntraAreaPrefixEntry { fn sub_tlvs(&self) -> ExtLsaSubTlvs { ExtLsaSubTlvs { prefix_sids: self.prefix_sids.clone(), + bier: self.bier.clone(), ..Default::default() } } @@ -2732,6 +2737,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 +2799,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/packet/tlv.rs b/holo-ospf/src/packet/tlv.rs index 0a74b687..23337d28 100644 --- a/holo-ospf/src/packet/tlv.rs +++ b/holo-ospf/src/packet/tlv.rs @@ -267,6 +267,57 @@ 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, +} + +// +// 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 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +#[derive(Clone, Debug, Eq, new, PartialEq)] +#[derive(Deserialize, Serialize)] +pub struct BierMplsEncapSubTlv { + pub max_si: u8, + pub label: Label, + pub bs_len: u8, +} + #[derive(Clone, Debug, Eq, new, PartialEq)] #[derive(Deserialize, Serialize)] pub struct UnknownTlv { @@ -275,6 +326,63 @@ 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(); + + 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)); + } + + // TODO + // Parse Sub-TLV value. + /*let mut buf_stlv = buf.copy_to_bytes(stlv_wlen as usize); + match stlv_type { + SUBTLV_BIER_MPLS_ENCAP => { + }, + _ => { + // Ignore unknown Sub-TLV + } + }*/ + + } + + Ok(BierSubTlv { + sub_domain_id, + mt_id, + bfr_id, + bar, + ipa, + }) + } + + 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); + // TODO: encode sub-tlvs + tlv_encode_end(buf, start_pos); + } +} + // ===== impl RouterInfoCapsTlv ===== impl RouterInfoCapsTlv { diff --git a/holo-yang/modules/augmentations/holo-ospf.yang b/holo-yang/modules/augmentations/holo-ospf.yang index d417654e..5c2ca285 100644 --- a/holo-yang/modules/augmentations/holo-ospf.yang +++ b/holo-yang/modules/augmentations/holo-ospf.yang @@ -66,6 +66,41 @@ module holo-ospf { "Describes the reason for the router restart."; } + /* + * Groupings. + */ + grouping bier-protocol-extensions{ + description + "Defines protocol extensions."; + leaf mt-id{ + type uint16 ; + description + "Multi-topology associated with bier sub-domain."; + } + container bier { + leaf enable { + type boolean; + default false; + description + "Enables bier protocol extensions."; + } + leaf advertise { + type boolean; + default true; + description + "Enable to advertise the parameters associated with bier."; + } + leaf receive { + type boolean; + default true; + description + "Enable to receive the parameters associated with bier."; + } + description + "BIER global config."; + } + } + /* * Augmentations. */ @@ -175,6 +210,22 @@ module holo-ospf { } } + augment "/rt:routing/rt:control-plane-protocols/" + + "rt:control-plane-protocol/ospf:ospf" { + when "../rt:type = 'ospf:ospfv2' or + ../rt:type = 'ospf:ospfv3'" { + description + "This augments the ospf routing protocol when used"; + } + description + "This augments ospf protocol configuration with bier."; + container bier-ospf-cfg{ + uses bier-protocol-extensions; + description + "Control of bier advertisement and reception."; + } + } + /* * Notifications. */ From 6e259c9c1cf5936a7ef386aabba0bb9b45e5c0eb Mon Sep 17 00:00:00 2001 From: nrybowski Date: Tue, 6 Aug 2024 10:26:07 +0200 Subject: [PATCH 02/13] bier: Add encpasulation sub-sub-tlv for OSPFv3 Signed-off-by: Nicolas Rybowski --- holo-ospf/src/ospfv3/lsdb.rs | 66 ++++++++++++++++-- holo-ospf/src/ospfv3/packet/lsa.rs | 8 +-- holo-ospf/src/packet/tlv.rs | 107 +++++++++++++++++++++++++---- holo-utils/src/bier.rs | 47 +++++++++++++ 4 files changed, 204 insertions(+), 24 deletions(-) diff --git a/holo-ospf/src/ospfv3/lsdb.rs b/holo-ospf/src/ospfv3/lsdb.rs index 433fabef..c7ab8d49 100644 --- a/holo-ospf/src/ospfv3/lsdb.rs +++ b/holo-ospf/src/ospfv3/lsdb.rs @@ -7,6 +7,7 @@ use std::collections::{hash_map, BTreeMap, HashMap}; use std::net::{IpAddr, Ipv4Addr}; +use holo_utils::bier::{BierEncapsulationType, BierInBiftId, BiftId}; use holo_utils::ibus::SrCfgEvent; use holo_utils::ip::{AddressFamily, IpNetworkKind}; use holo_utils::mpls::Label; @@ -35,8 +36,9 @@ use crate::packet::lsa::{ Lsa, LsaHdrVersion, LsaKey, LsaScope, LsaTypeVersion, PrefixSidVersion, }; use crate::packet::tlv::{ - PrefixSidFlags, RouterInfoCaps, RouterInfoCapsTlv, SidLabelRangeTlv, - SrAlgoTlv, SrLocalBlockTlv, BierSubTlv, + BierEncapId, BierEncapSubSubTlv, BierSubSubTlv, BierSubTlv, PrefixSidFlags, + RouterInfoCaps, RouterInfoCapsTlv, SidLabelRangeTlv, SrAlgoTlv, + SrLocalBlockTlv, }; use crate::route::{SummaryNet, SummaryNetFlags, SummaryRtr}; use crate::version::Ospfv3; @@ -820,12 +822,62 @@ fn lsa_orig_intra_area_prefix( // Add BIER Sub-TLV(s) if instance.config.bier.enabled { - bier_config.sd_cfg.iter().for_each(|((sd_id, addr_family), sd_cfg)|{ - if addr_family == &AddressFamily::Ipv6 && sd_cfg.bfr_prefix == prefix { - let bier = BierSubTlv::new(*sd_id, sd_cfg.mt_id, sd_cfg.bfr_id, sd_cfg.bar, sd_cfg.ipa); + 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)| { + if let Some(id) = match encap_type { + BierEncapsulationType::Mpls => { + // TODO: where is the label defined? + Some(BierEncapId::Mpls(Label::new(0))) + } + _ => { + if let Some(id) = match encap.in_bift_id { + BierInBiftId::Base(id) => Some(id), + BierInBiftId::Encoding(true) => Some(0), + _ => None, + } { + Some(BierEncapId::NonMpls(BiftId::new( + id, + ))) + } else { + None + } + } + } { + Some(BierSubSubTlv::BierEncapSubSubTlv( + BierEncapSubSubTlv::new( + encap.max_si, + id, + (*bsl).into(), + ), + )) + } else { + None + } + }) + .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); diff --git a/holo-ospf/src/ospfv3/packet/lsa.rs b/holo-ospf/src/ospfv3/packet/lsa.rs index 30c0de9a..f204d563 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, BierSubTlv, + 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; diff --git a/holo-ospf/src/packet/tlv.rs b/holo-ospf/src/packet/tlv.rs index 23337d28..f9914652 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}; @@ -293,6 +294,13 @@ pub struct BierSubTlv { 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), } // @@ -310,14 +318,50 @@ pub struct BierSubTlv { // |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 BierMplsEncapSubTlv { +pub struct BierEncapSubSubTlv { pub max_si: u8, - pub label: Label, + 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 { @@ -336,10 +380,11 @@ impl BierSubTlv { 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(); + let stlv_type = buf.get_u16(); // Parse and validate Sub-TLV length. let stlv_len = buf.get_u16(); @@ -348,17 +393,36 @@ impl BierSubTlv { return Err(DecodeError::InvalidTlvLength(stlv_len)); } - // TODO // Parse Sub-TLV value. - /*let mut buf_stlv = buf.copy_to_bytes(stlv_wlen as usize); - match stlv_type { - SUBTLV_BIER_MPLS_ENCAP => { - }, - _ => { + 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 { @@ -367,10 +431,15 @@ impl BierSubTlv { bfr_id, bar, ipa, + subtlvs, }) } - pub(crate) fn encode(&self, buf: &mut BytesMut, stlv_type: impl ToPrimitive) { + 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); @@ -378,8 +447,20 @@ impl BierSubTlv { buf.put_u8(self.bar); buf.put_u8(self.ipa); buf.put_u16(0); - // TODO: encode sub-tlvs tlv_encode_end(buf, start_pos); + 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); + tlv_encode_end(buf, start_pos); + } + _ => {} + } + } } } diff --git a/holo-utils/src/bier.rs b/holo-utils/src/bier.rs index 3d6c2d4b..4ae33fac 100644 --- a/holo-utils/src/bier.rs +++ b/holo-utils/src/bier.rs @@ -17,6 +17,22 @@ use crate::ip::AddressFamily; pub type SubDomainId = u8; pub type BfrId = u16; +#[derive(Clone, Debug, Default, Eq, PartialEq)] +#[derive(Deserialize, Serialize)] +pub struct BiftId(u32); + +impl BiftId { + pub const VALUE_MASK: u32 = 0x000FFFFF; + + pub fn new(bift_id: u32) -> Self { + Self(bift_id) + } + + pub fn get(&self) -> u32 { + self.0 & Self::VALUE_MASK + } +} + #[derive(Clone, Debug, Default)] #[derive(Deserialize, Serialize)] pub struct BierCfg { @@ -125,6 +141,37 @@ impl TryFromYang for Bsl { } } +impl Into for Bsl { + // Mapping defined in RFC8296, Section 2.1.2 + fn into(self) -> u8 { + match self { + Self::_64 => 1, + Self::_128 => 2, + Self::_256 => 3, + Self::_512 => 4, + Self::_1024 => 5, + Self::_2048 => 6, + Self::_4096 => 7, + } + } +} + +impl TryFrom for Bsl { + type Error = &'static str; + fn try_from(value: u8) -> Result { + match value { + 1 => Ok(Self::_64), + 2 => Ok(Self::_128), + 3 => Ok(Self::_256), + 4 => Ok(Self::_512), + 5 => Ok(Self::_1024), + 6 => Ok(Self::_2048), + 7 => Ok(Self::_4096), + _ => Err("Not Supported"), + } + } +} + impl TryFromYang for BierEncapsulationType { fn try_from_yang(value: &str) -> Option { match value { From 15342feb1b925c3d869a1faa5eadba5ff4d492b1 Mon Sep 17 00:00:00 2001 From: nrybowski Date: Thu, 8 Aug 2024 09:52:12 +0200 Subject: [PATCH 03/13] bier: Fix wrong encapsulation Sub-TLV encoding Signed-off-by: Nicolas Rybowski --- holo-ospf/src/packet/tlv.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/holo-ospf/src/packet/tlv.rs b/holo-ospf/src/packet/tlv.rs index f9914652..7e741810 100644 --- a/holo-ospf/src/packet/tlv.rs +++ b/holo-ospf/src/packet/tlv.rs @@ -447,7 +447,6 @@ impl BierSubTlv { buf.put_u8(self.bar); buf.put_u8(self.ipa); buf.put_u16(0); - tlv_encode_end(buf, start_pos); for subtlv in &self.subtlvs { match subtlv { BierSubSubTlv::BierEncapSubSubTlv(encap) => { @@ -455,12 +454,14 @@ impl BierSubTlv { 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); + buf.put_u8((encap.bs_len << 4) & 0xf0); + buf.put_u24(0); tlv_encode_end(buf, start_pos); } _ => {} } } + tlv_encode_end(buf, start_pos); } } From 32768acba1f845e63b84910b500ff147734b8ebe Mon Sep 17 00:00:00 2001 From: nrybowski Date: Thu, 8 Aug 2024 10:02:00 +0200 Subject: [PATCH 04/13] bier: Fix wrong type for mt-id in OSPF YANG configuration for BIER Signed-off-by: Nicolas Rybowski --- holo-ospf/src/northbound/configuration.rs | 4 ++-- holo-yang/modules/augmentations/holo-ospf.yang | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/holo-ospf/src/northbound/configuration.rs b/holo-ospf/src/northbound/configuration.rs index 0817b309..bb3253b9 100644 --- a/holo-ospf/src/northbound/configuration.rs +++ b/holo-ospf/src/northbound/configuration.rs @@ -107,7 +107,7 @@ pub struct InstanceCfg { #[derive(Debug)] pub struct BierOspfCfg { - pub mt_id: u16, + pub mt_id: u8, pub enabled: bool, pub advertise: bool, pub receive: bool, @@ -789,7 +789,7 @@ where }) .path(ospf::bier_ospf_cfg::mt_id::PATH) .modify_apply(|instance, args| { - let mt_id = args.dnode.get_u16(); + let mt_id = args.dnode.get_u8(); instance.config.bier.mt_id = mt_id; }) .delete_apply(|instance, _args| { diff --git a/holo-yang/modules/augmentations/holo-ospf.yang b/holo-yang/modules/augmentations/holo-ospf.yang index 5c2ca285..a149ad96 100644 --- a/holo-yang/modules/augmentations/holo-ospf.yang +++ b/holo-yang/modules/augmentations/holo-ospf.yang @@ -73,7 +73,7 @@ module holo-ospf { description "Defines protocol extensions."; leaf mt-id{ - type uint16 ; + type uint8 ; description "Multi-topology associated with bier sub-domain."; } From b040b4824b31d9c7cbfd325c312cc2837b662042 Mon Sep 17 00:00:00 2001 From: nrybowski Date: Thu, 8 Aug 2024 10:05:21 +0200 Subject: [PATCH 05/13] bier: Update BIRT from OSPFv3 Signed-off-by: Nicolas Rybowski --- holo-ospf/src/ospfv2/spf.rs | 4 + holo-ospf/src/ospfv3/lsdb.rs | 36 +++-- holo-ospf/src/ospfv3/packet/lsa.rs | 1 + holo-ospf/src/ospfv3/spf.rs | 1 + holo-ospf/src/packet/tlv.rs | 1 - holo-ospf/src/route.rs | 46 ++++++- holo-ospf/src/southbound/tx.rs | 17 ++- holo-ospf/src/spf.rs | 3 +- holo-ospf/tests/packet/ospfv3.rs | 2 + holo-routing/src/ibus.rs | 3 + holo-routing/src/lib.rs | 5 +- holo-routing/src/northbound/mod.rs | 1 + holo-routing/src/northbound/state.rs | 57 +++++++- holo-routing/src/rib.rs | 31 ++++- holo-utils/src/bier.rs | 126 ++++++++++++++---- holo-utils/src/ibus.rs | 8 +- holo-utils/src/southbound.rs | 9 ++ .../modules/augmentations/holo-routing.yang | 70 ++++++++++ holo-yang/src/lib.rs | 3 + 19 files changed, 365 insertions(+), 59 deletions(-) create mode 100644 holo-yang/modules/augmentations/holo-routing.yang 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 c7ab8d49..4c644412 100644 --- a/holo-ospf/src/ospfv3/lsdb.rs +++ b/holo-ospf/src/ospfv3/lsdb.rs @@ -820,8 +820,8 @@ fn lsa_orig_intra_area_prefix( } } - // Add BIER Sub-TLV(s) - if instance.config.bier.enabled { + // 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() @@ -835,35 +835,29 @@ fn lsa_orig_intra_area_prefix( .encap .iter() .filter_map(|((bsl, encap_type), encap)| { - if let Some(id) = match encap_type { + match encap_type { BierEncapsulationType::Mpls => { // TODO: where is the label defined? Some(BierEncapId::Mpls(Label::new(0))) } - _ => { - if let Some(id) = match encap.in_bift_id { - BierInBiftId::Base(id) => Some(id), - BierInBiftId::Encoding(true) => Some(0), - _ => None, - } { - Some(BierEncapId::NonMpls(BiftId::new( - id, - ))) - } else { - None - } + _ => match encap.in_bift_id { + BierInBiftId::Base(id) => Some(id), + BierInBiftId::Encoding(true) => Some(0), + _ => None, } - } { - Some(BierSubSubTlv::BierEncapSubSubTlv( + .map(|id| { + BierEncapId::NonMpls(BiftId::new(id)) + }), + } + .map(|id| { + BierSubSubTlv::BierEncapSubSubTlv( BierEncapSubSubTlv::new( encap.max_si, id, (*bsl).into(), ), - )) - } else { - None - } + ) + }) }) .collect::>(); diff --git a/holo-ospf/src/ospfv3/packet/lsa.rs b/holo-ospf/src/ospfv3/packet/lsa.rs index f204d563..5e45a7e2 100644 --- a/holo-ospf/src/ospfv3/packet/lsa.rs +++ b/holo-ospf/src/ospfv3/packet/lsa.rs @@ -2372,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); 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 7e741810..cc70f1f1 100644 --- a/holo-ospf/src/packet/tlv.rs +++ b/holo-ospf/src/packet/tlv.rs @@ -458,7 +458,6 @@ impl BierSubTlv { buf.put_u24(0); tlv_encode_end(buf, start_pos); } - _ => {} } } tlv_encode_end(buf, start_pos); diff --git a/holo-ospf/src/route.rs b/holo-ospf/src/route.rs index 99bd9ef0..17b70f3c 100644 --- a/holo-ospf/src/route.rs +++ b/holo-ospf/src/route.rs @@ -10,7 +10,8 @@ use std::net::Ipv4Addr; use bitflags::bitflags; use derive_new::new; -use holo_utils::ip::IpAddrKind; +use holo_utils::bier::{BierInfo, Bsl, UnderlayProtocolType}; +use holo_utils::ip::{IpAddrKind, IpNetworkKind}; use holo_utils::mpls::Label; use holo_utils::southbound::OspfRouteType; use holo_utils::sr::IgpAlgoType; @@ -23,6 +24,7 @@ use crate::interface::Interface; use crate::lsdb::{LsaEntry, LSA_INFINITY}; use crate::northbound::configuration::InstanceCfg; use crate::packet::lsa::{LsaKey, LsaRouterFlagsVersion}; +use crate::packet::tlv::BierSubSubTlv; use crate::spf::{SpfPartialComputation, VertexLsaVersion}; use crate::version::Version; use crate::{southbound, sr}; @@ -41,6 +43,7 @@ pub struct RouteNet { pub sr_label: Option