Skip to content

Commit

Permalink
isis: implement TE Router ID TLVs
Browse files Browse the repository at this point in the history
Add support for IPv4/IPv6 Router ID TLVs and corresponding
configuration options for their announcement.

Signed-off-by: Renato Westphal <[email protected]>
  • Loading branch information
rwestphal committed Jan 15, 2025
1 parent 4a2b197 commit 542dd70
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 21 deletions.
4 changes: 4 additions & 0 deletions holo-isis/src/lsdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,8 +306,10 @@ fn lsp_build_tlvs(
ipv4_internal_reach.into_values(),
[],
ext_ipv4_reach.into_values(),
instance.config.ipv4_router_id,
ipv6_addrs,
ipv6_reach.into_values(),
instance.config.ipv6_router_id,
)
}

Expand Down Expand Up @@ -363,8 +365,10 @@ fn lsp_build_tlvs_pseudo(
[],
[],
[],
None,
[],
[],
None,
)
}

Expand Down
37 changes: 37 additions & 0 deletions holo-isis/src/northbound/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//

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

use async_trait::async_trait;
Expand Down Expand Up @@ -81,6 +82,8 @@ pub struct InstanceCfg {
pub metric_type: LevelsCfg<MetricType>,
pub default_metric: LevelsCfg<u32>,
pub auth: LevelsOptCfg<AuthCfg>,
pub ipv4_router_id: Option<Ipv4Addr>,
pub ipv6_router_id: Option<Ipv6Addr>,
pub max_paths: u16,
pub afs: BTreeMap<AddressFamily, AddressFamilyCfg>,
pub spf_initial_delay: u32,
Expand Down Expand Up @@ -403,6 +406,38 @@ fn load_callbacks() -> Callbacks<Instance> {
event_queue.insert(Event::ReoriginateLsps(LevelNumber::L1));
event_queue.insert(Event::ReoriginateLsps(LevelNumber::L2));
})
.path(isis::mpls::te_rid::ipv4_router_id::PATH)
.modify_apply(|instance, args| {
let addr = args.dnode.get_ipv4();
instance.config.ipv4_router_id = Some(addr);

let event_queue = args.event_queue;
event_queue.insert(Event::ReoriginateLsps(LevelNumber::L1));
event_queue.insert(Event::ReoriginateLsps(LevelNumber::L2));
})
.delete_apply(|instance, args| {
instance.config.ipv4_router_id = None;

let event_queue = args.event_queue;
event_queue.insert(Event::ReoriginateLsps(LevelNumber::L1));
event_queue.insert(Event::ReoriginateLsps(LevelNumber::L2));
})
.path(isis::mpls::te_rid::ipv6_router_id::PATH)
.modify_apply(|instance, args| {
let addr = args.dnode.get_ipv6();
instance.config.ipv6_router_id = Some(addr);

let event_queue = args.event_queue;
event_queue.insert(Event::ReoriginateLsps(LevelNumber::L1));
event_queue.insert(Event::ReoriginateLsps(LevelNumber::L2));
})
.delete_apply(|instance, args| {
instance.config.ipv6_router_id = None;

let event_queue = args.event_queue;
event_queue.insert(Event::ReoriginateLsps(LevelNumber::L1));
event_queue.insert(Event::ReoriginateLsps(LevelNumber::L2));
})
.path(isis::spf_control::paths::PATH)
.modify_apply(|instance, args| {
let max_paths = args.dnode.get_u16();
Expand Down Expand Up @@ -1242,6 +1277,8 @@ impl Default for InstanceCfg {
default_metric,
auth: Default::default(),
max_paths,
ipv4_router_id: None,
ipv6_router_id: None,
afs: Default::default(),
spf_initial_delay,
spf_short_delay,
Expand Down
4 changes: 2 additions & 2 deletions holo-isis/src/northbound/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,8 @@ fn load_callbacks() -> Callbacks<Instance> {
sequence: Some(lsp.seqno),
ipv4_addresses: Some(Box::new(ipv4_addresses)),
ipv6_addresses: Some(Box::new(ipv6_addresses)),
ipv4_te_routerid: None,
ipv6_te_routerid: None,
ipv4_te_routerid: lsp.tlvs.ipv4_router_id.as_ref().map(|tlv| Cow::Borrowed(tlv.get())),
ipv6_te_routerid: lsp.tlvs.ipv6_router_id.as_ref().map(|tlv| Cow::Borrowed(tlv.get())),
protocol_supported: Some(Box::new(protocol_supported)),
dynamic_hostname: lsp.tlvs.hostname().map(Cow::Borrowed),
lsp_buffer_size: lsp.tlvs.lsp_buf_size(),
Expand Down
2 changes: 2 additions & 0 deletions holo-isis/src/packet/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@ pub enum TlvType {
ProtocolsSupported = 129,
Ipv4ExternalReach = 130,
Ipv4Addresses = 132,
Ipv4RouterId = 134,
ExtIpv4Reach = 135,
DynamicHostname = 137,
Ipv6RouterId = 140,
Ipv6Addresses = 232,
Ipv6Reach = 236,
}
Expand Down
44 changes: 40 additions & 4 deletions holo-isis/src/packet/pdu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ use crate::packet::error::{DecodeError, DecodeResult};
use crate::packet::tlv::{
AreaAddressesTlv, DynamicHostnameTlv, ExtIpv4Reach, ExtIpv4ReachTlv,
ExtIsReach, ExtIsReachTlv, Ipv4AddressesTlv, Ipv4Reach, Ipv4ReachTlv,
Ipv6AddressesTlv, Ipv6Reach, Ipv6ReachTlv, IsReach, IsReachTlv,
LspBufferSizeTlv, LspEntriesTlv, LspEntry, NeighborsTlv, PaddingTlv,
ProtocolsSupportedTlv, TLV_HDR_SIZE, TLV_MAX_LEN, Tlv, UnknownTlv,
tlv_entries_split, tlv_take_max,
Ipv4RouterIdTlv, Ipv6AddressesTlv, Ipv6Reach, Ipv6ReachTlv,
Ipv6RouterIdTlv, IsReach, IsReachTlv, LspBufferSizeTlv, LspEntriesTlv,
LspEntry, NeighborsTlv, PaddingTlv, ProtocolsSupportedTlv, TLV_HDR_SIZE,
TLV_MAX_LEN, Tlv, UnknownTlv, tlv_entries_split, tlv_take_max,
};
use crate::packet::{AreaAddr, LanId, LevelNumber, LevelType, LspId, SystemId};

Expand Down Expand Up @@ -111,8 +111,10 @@ pub struct LspTlvs {
pub ipv4_internal_reach: Vec<Ipv4ReachTlv>,
pub ipv4_external_reach: Vec<Ipv4ReachTlv>,
pub ext_ipv4_reach: Vec<ExtIpv4ReachTlv>,
pub ipv4_router_id: Option<Ipv4RouterIdTlv>,
pub ipv6_addrs: Vec<Ipv6AddressesTlv>,
pub ipv6_reach: Vec<Ipv6ReachTlv>,
pub ipv6_router_id: Option<Ipv6RouterIdTlv>,
pub unknown: Vec<UnknownTlv>,
}

Expand Down Expand Up @@ -679,6 +681,13 @@ impl Lsp {
let tlv = ExtIpv4ReachTlv::decode(tlv_len, &mut buf_tlv)?;
tlvs.ext_ipv4_reach.push(tlv);
}
Some(TlvType::Ipv4RouterId) => {
if tlvs.ipv4_router_id.is_some() {
continue;
}
let tlv = Ipv4RouterIdTlv::decode(tlv_len, &mut buf_tlv)?;
tlvs.ipv4_router_id = Some(tlv);
}
Some(TlvType::Ipv6Addresses) => {
let tlv = Ipv6AddressesTlv::decode(tlv_len, &mut buf_tlv)?;
tlvs.ipv6_addrs.push(tlv);
Expand All @@ -687,6 +696,13 @@ impl Lsp {
let tlv = Ipv6ReachTlv::decode(tlv_len, &mut buf_tlv)?;
tlvs.ipv6_reach.push(tlv);
}
Some(TlvType::Ipv6RouterId) => {
if tlvs.ipv6_router_id.is_some() {
continue;
}
let tlv = Ipv6RouterIdTlv::decode(tlv_len, &mut buf_tlv)?;
tlvs.ipv6_router_id = Some(tlv);
}
_ => {
// Save unknown top-level TLV.
let value = buf_tlv.copy_to_bytes(tlv_len as usize);
Expand Down Expand Up @@ -754,12 +770,18 @@ impl Lsp {
for tlv in &self.tlvs.ext_ipv4_reach {
tlv.encode(&mut buf);
}
if let Some(tlv) = &self.tlvs.ipv4_router_id {
tlv.encode(&mut buf);
}
for tlv in &self.tlvs.ipv6_addrs {
tlv.encode(&mut buf);
}
for tlv in &self.tlvs.ipv6_reach {
tlv.encode(&mut buf);
}
if let Some(tlv) = &self.tlvs.ipv6_router_id {
tlv.encode(&mut buf);
}

// Compute LSP checksum.
let cksum = Self::checksum(&buf[12..]);
Expand Down Expand Up @@ -868,8 +890,10 @@ impl LspTlvs {
ipv4_internal_reach: impl IntoIterator<Item = Ipv4Reach>,
ipv4_external_reach: impl IntoIterator<Item = Ipv4Reach>,
ext_ipv4_reach: impl IntoIterator<Item = ExtIpv4Reach>,
ipv4_router_id: Option<Ipv4Addr>,
ipv6_addrs: impl IntoIterator<Item = Ipv6Addr>,
ipv6_reach: impl IntoIterator<Item = Ipv6Reach>,
ipv6_router_id: Option<Ipv6Addr>,
) -> Self {
LspTlvs {
protocols_supported: Some(ProtocolsSupportedTlv::from(
Expand All @@ -884,8 +908,10 @@ impl LspTlvs {
ipv4_internal_reach: tlv_entries_split(ipv4_internal_reach),
ipv4_external_reach: tlv_entries_split(ipv4_external_reach),
ext_ipv4_reach: tlv_entries_split(ext_ipv4_reach),
ipv4_router_id: ipv4_router_id.map(Ipv4RouterIdTlv::new),
ipv6_addrs: tlv_entries_split(ipv6_addrs),
ipv6_reach: tlv_entries_split(ipv6_reach),
ipv6_router_id: ipv6_router_id.map(Ipv6RouterIdTlv::new),
unknown: Default::default(),
}
}
Expand All @@ -905,6 +931,14 @@ impl LspTlvs {
if let Some(lsp_buf_size) = &lsp_buf_size {
rem_len -= lsp_buf_size.len();
}
let ipv4_router_id = self.ipv4_router_id.take();
if let Some(ipv4_router_id) = &ipv4_router_id {
rem_len -= ipv4_router_id.len();
}
let ipv6_router_id = self.ipv6_router_id.take();
if let Some(ipv6_router_id) = &ipv6_router_id {
rem_len -= ipv6_router_id.len();
}
let is_reach = tlv_take_max(&mut self.is_reach, &mut rem_len);
let ext_is_reach = tlv_take_max(&mut self.ext_is_reach, &mut rem_len);
let ipv4_addrs = tlv_take_max(&mut self.ipv4_addrs, &mut rem_len);
Expand All @@ -931,8 +965,10 @@ impl LspTlvs {
ipv4_internal_reach,
ipv4_external_reach,
ext_ipv4_reach,
ipv4_router_id,
ipv6_addrs,
ipv6_reach,
ipv6_router_id,
unknown: Default::default(),
})
}
Expand Down
76 changes: 76 additions & 0 deletions holo-isis/src/packet/tlv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,16 @@ pub struct Ipv6ReachSubTlvs {
pub unknown: Vec<UnknownTlv>,
}

#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(new)]
#[derive(Deserialize, Serialize)]
pub struct Ipv4RouterIdTlv(Ipv4Addr);

#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(new)]
#[derive(Deserialize, Serialize)]
pub struct Ipv6RouterIdTlv(Ipv6Addr);

#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(new)]
#[derive(Deserialize, Serialize)]
Expand Down Expand Up @@ -1188,6 +1198,72 @@ where
}
}

// ===== impl Ipv4RouterIdTlv =====

impl Ipv4RouterIdTlv {
const SIZE: usize = 4;

pub(crate) fn decode(tlv_len: u8, buf: &mut Bytes) -> DecodeResult<Self> {
// Validate the TLV length.
if tlv_len as usize != Self::SIZE {
return Err(DecodeError::InvalidTlvLength(tlv_len));
}

let addr = buf.get_ipv4();

Ok(Ipv4RouterIdTlv(addr))
}

pub(crate) fn encode(&self, buf: &mut BytesMut) {
let start_pos = tlv_encode_start(buf, TlvType::Ipv4RouterId);
buf.put_ipv4(&self.0);
tlv_encode_end(buf, start_pos);
}

pub(crate) fn get(&self) -> &Ipv4Addr {
&self.0
}
}

impl Tlv for Ipv4RouterIdTlv {
fn len(&self) -> usize {
TLV_HDR_SIZE + Self::SIZE
}
}

// ===== impl Ipv6RouterIdTlv =====

impl Ipv6RouterIdTlv {
const SIZE: usize = 16;

pub(crate) fn decode(tlv_len: u8, buf: &mut Bytes) -> DecodeResult<Self> {
// Validate the TLV length.
if tlv_len as usize != Self::SIZE {
return Err(DecodeError::InvalidTlvLength(tlv_len));
}

let addr = buf.get_ipv6();

Ok(Ipv6RouterIdTlv(addr))
}

pub(crate) fn encode(&self, buf: &mut BytesMut) {
let start_pos = tlv_encode_start(buf, TlvType::Ipv6RouterId);
buf.put_ipv6(&self.0);
tlv_encode_end(buf, start_pos);
}

pub(crate) fn get(&self) -> &Ipv6Addr {
&self.0
}
}

impl Tlv for Ipv6RouterIdTlv {
fn len(&self) -> usize {
TLV_HDR_SIZE + Self::SIZE
}
}

// ===== blanket implementations =====

impl<T: MultiTlv> Tlv for T {
Expand Down
32 changes: 21 additions & 11 deletions holo-isis/tests/packet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ use holo_isis::packet::pdu::{
use holo_isis::packet::tlv::{
AreaAddressesTlv, DynamicHostnameTlv, ExtIpv4Reach, ExtIpv4ReachTlv,
ExtIsReach, ExtIsReachTlv, Ipv4AddressesTlv, Ipv4Reach, Ipv4ReachTlv,
Ipv6AddressesTlv, Ipv6Reach, Ipv6ReachTlv, IsReach, IsReachTlv,
LspBufferSizeTlv, LspEntriesTlv, LspEntry, NeighborsTlv, PaddingTlv,
ProtocolsSupportedTlv,
Ipv4RouterIdTlv, Ipv6AddressesTlv, Ipv6Reach, Ipv6ReachTlv,
Ipv6RouterIdTlv, IsReach, IsReachTlv, LspBufferSizeTlv, LspEntriesTlv,
LspEntry, NeighborsTlv, PaddingTlv, ProtocolsSupportedTlv,
};
use holo_isis::packet::{
AreaAddr, LanId, LevelNumber, LevelType, LspId, SystemId,
Expand Down Expand Up @@ -521,18 +521,20 @@ static PSNP1: Lazy<(Vec<u8>, Pdu)> = Lazy::new(|| {
static LSP1: Lazy<(Vec<u8>, Pdu)> = Lazy::new(|| {
(
vec![
0x83, 0x1b, 0x01, 0x00, 0x12, 0x01, 0x00, 0x00, 0x00, 0x82, 0x04,
0x83, 0x1b, 0x01, 0x00, 0x12, 0x01, 0x00, 0x00, 0x00, 0x9a, 0x04,
0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0xd0, 0x32, 0x01, 0x81, 0x01, 0xcc, 0x01, 0x04, 0x03,
0x00, 0x04, 0xb7, 0x38, 0x01, 0x81, 0x01, 0xcc, 0x01, 0x04, 0x03,
0x49, 0x00, 0x00, 0x16, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x03, 0x00, 0x00, 0x0a, 0x00, 0x84, 0x04, 0x01, 0x01, 0x01, 0x01,
0x87, 0x11, 0x00, 0x00, 0x00, 0x0a, 0x18, 0x0a, 0x00, 0x01, 0x00,
0x00, 0x00, 0x0a, 0x20, 0x01, 0x01, 0x01, 0x01, 0xe8, 0x10, 0x20,
0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0xec, 0x24, 0x00, 0x00, 0x00, 0x0a, 0x00,
0x80, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00,
0x40, 0x20, 0x01, 0x0d, 0xb8, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0a, 0x20, 0x01, 0x01, 0x01, 0x01, 0x86, 0x04, 0x01,
0x01, 0x01, 0x01, 0xe8, 0x10, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xec,
0x24, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x80, 0x20, 0x01, 0x0d, 0xb8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x40, 0x20, 0x01, 0x0d, 0xb8,
0x10, 0x00, 0x00, 0x00, 0x8c, 0x10, 0x20, 0x01, 0x0d, 0xb8, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
],
Pdu::Lsp(Lsp::new(
LevelNumber::L1,
Expand Down Expand Up @@ -582,6 +584,9 @@ static LSP1: Lazy<(Vec<u8>, Pdu)> = Lazy::new(|| {
},
],
}],
ipv4_router_id: Some(Ipv4RouterIdTlv::new(
Ipv4Addr::from_str("1.1.1.1").unwrap(),
)),
ipv6_addrs: vec![Ipv6AddressesTlv {
list: vec![Ipv6Addr::from_str("2001:db8::1").unwrap()],
}],
Expand All @@ -607,6 +612,9 @@ static LSP1: Lazy<(Vec<u8>, Pdu)> = Lazy::new(|| {
},
],
}],
ipv6_router_id: Some(Ipv6RouterIdTlv::new(
Ipv6Addr::from_str("2001:db8::1").unwrap(),
)),
unknown: vec![],
},
)),
Expand Down Expand Up @@ -704,8 +712,10 @@ static LSP2: Lazy<(Vec<u8>, Pdu)> = Lazy::new(|| {
}],
ipv4_external_reach: vec![],
ext_ipv4_reach: vec![],
ipv4_router_id: None,
ipv6_addrs: vec![],
ipv6_reach: vec![],
ipv6_router_id: None,
unknown: vec![],
},
)),
Expand Down
Loading

0 comments on commit 542dd70

Please sign in to comment.