Skip to content

Commit

Permalink
Add basic support for BIER TLVs in OSPFv3
Browse files Browse the repository at this point in the history
- 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 <[email protected]>
  • Loading branch information
nrybowski committed Aug 2, 2024
1 parent 9806948 commit 6f96f18
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 2 deletions.
3 changes: 3 additions & 0 deletions holo-ospf/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?
Expand Down
48 changes: 48 additions & 0 deletions holo-ospf/src/northbound/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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()
}

Expand Down Expand Up @@ -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,
}
}
}
Expand Down
13 changes: 12 additions & 1 deletion holo-ospf/src/ospfv3/lsdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -717,6 +717,7 @@ fn lsa_orig_intra_area_prefix(
arenas: &InstanceArenas<Ospfv3>,
) {
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;
Expand Down Expand Up @@ -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(
Expand Down
14 changes: 13 additions & 1 deletion holo-ospf/src/ospfv3/packet/lsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -188,6 +188,7 @@ pub enum ExtLsaSubTlv {
LanAdjSid = 6,
SidLabel = 7,
LinkMsd = 9,
Bier = 42,
}

// OSPFv3 Extended-LSA Sub-TLVs.
Expand Down Expand Up @@ -242,6 +243,7 @@ pub struct ExtLsaSubTlvs {
pub route_tag: Option<u32>,
pub prefix_sids: BTreeMap<IgpAlgoType, PrefixSid>,
pub adj_sids: Vec<AdjSid>,
pub bier: Vec<BierSubTlv>,
pub unknown: Vec<UnknownTlv>,
}

Expand Down Expand Up @@ -886,6 +888,8 @@ pub struct LsaIntraAreaPrefixEntry {
#[new(default)]
pub prefix_sids: BTreeMap<IgpAlgoType, PrefixSid>,
#[new(default)]
pub bier: Vec<BierSubTlv>,
#[new(default)]
pub unknown_stlvs: Vec<UnknownTlv>,
}

Expand Down Expand Up @@ -2449,6 +2453,7 @@ impl LsaIntraAreaPrefixEntry {
fn sub_tlvs(&self) -> ExtLsaSubTlvs {
ExtLsaSubTlvs {
prefix_sids: self.prefix_sids.clone(),
bier: self.bier.clone(),
..Default::default()
}
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -2790,6 +2799,9 @@ impl ExtLsaSubTlvs {
}
tlv_encode_end(buf, start_pos);
}
for bier in &self.bier {
BierSubTlv::encode(bier, buf, ExtLsaSubTlv::Bier);
}
}
}

Expand Down
108 changes: 108 additions & 0 deletions holo-ospf/src/packet/tlv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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<Self> {
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 {
Expand Down
51 changes: 51 additions & 0 deletions holo-yang/modules/augmentations/holo-ospf.yang
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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.
*/
Expand Down

0 comments on commit 6f96f18

Please sign in to comment.