Skip to content

Commit

Permalink
isis: implement hello PDU padding
Browse files Browse the repository at this point in the history
Implement padding for Hello PDUs in accordance with the base IS-IS
specification. Hello PDUs are padded using the maximum of the link MTU
or the LSP MTU. This ensures that the maximum-sized LSP can traverse the
link, and also serves as an implicit MTU check between neighbors.

Conditional padding as implemented by other vendors isn't supported
yet.

Signed-off-by: Renato Westphal <[email protected]>
  • Loading branch information
rwestphal committed Jan 7, 2025
1 parent 42e248a commit d410b46
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 4 deletions.
11 changes: 9 additions & 2 deletions holo-isis/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,8 @@ impl Interface {
);
}

Pdu::Hello(Hello::new(
// Generate Hello PDU.
let mut hello = Hello::new(
level,
circuit_type,
source,
Expand All @@ -506,7 +507,13 @@ impl Interface {
ipv4_addrs,
ipv6_addrs,
),
))
);
if self.config.hello_padding {
let max_size =
std::cmp::max(self.iso_mtu() as u16, instance.config.lsp_mtu);
hello.add_padding(max_size);
}
Pdu::Hello(hello)
}

pub(crate) fn hello_interval_start(
Expand Down
4 changes: 4 additions & 0 deletions holo-isis/src/northbound/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,10 @@ fn load_callbacks() -> Callbacks<Instance> {

let hello_padding = args.dnode.get_bool();
iface.config.hello_padding = hello_padding;

let event_queue = args.event_queue;
event_queue.insert(Event::InterfaceUpdateHelloInterval(iface_idx, LevelNumber::L1));
event_queue.insert(Event::InterfaceUpdateHelloInterval(iface_idx, LevelNumber::L2));
})
.path(isis::interfaces::interface::interface_type::PATH)
.modify_apply(|instance, args| {
Expand Down
37 changes: 36 additions & 1 deletion holo-isis/src/packet/pdu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::packet::tlv::{
Ipv4Reach, Ipv4ReachTlv, Ipv6AddressesTlv, Ipv6Reach, Ipv6ReachTlv,
IsReach, IsReachTlv, LspBufferSizeTlv, LspEntriesTlv, LspEntry,
NeighborsTlv, PaddingTlv, ProtocolsSupportedTlv, Tlv, UnknownTlv,
TLV_HDR_SIZE,
TLV_HDR_SIZE, TLV_MAX_LEN,
};
use crate::packet::{AreaAddr, LanId, LevelNumber, LevelType, LspId, SystemId};

Expand Down Expand Up @@ -480,6 +480,41 @@ impl Hello {
pdu_encode_end(buf, len_pos)
})
}

pub(crate) fn add_padding(&mut self, max_size: u16) {
// Compute the total length of existing TLVs.
let mut total_tlv_len = 0;
if let Some(tlv) = &self.tlvs.protocols_supported {
total_tlv_len += tlv.len();
}
for tlv in &self.tlvs.area_addrs {
total_tlv_len += tlv.len();
}
for tlv in &self.tlvs.neighbors {
total_tlv_len += tlv.len();
}
for tlv in &self.tlvs.ipv4_addrs {
total_tlv_len += tlv.len();
}
for tlv in &self.tlvs.ipv6_addrs {
total_tlv_len += tlv.len();
}

// Calculate the total padding required.
let mut rem_padding = max_size as usize
- Header::fixed_header_length(self.hdr.pdu_type) as usize
- total_tlv_len;

// Add as many Padding TLVs as necessary.
while rem_padding >= 2 {
let padding_len =
std::cmp::min(rem_padding - TLV_HDR_SIZE, TLV_MAX_LEN);
self.tlvs.padding.push(PaddingTlv {
length: padding_len as u8,
});
rem_padding -= TLV_HDR_SIZE + padding_len;
}
}
}

impl HelloTlvs {
Expand Down
12 changes: 11 additions & 1 deletion holo-isis/src/southbound/rx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub(crate) fn process_iface_update(
let iface_idx = iface.index;

// Update interface data.
let old_mtu = iface.system.mtu;
iface.system.flags = msg.flags;
iface.system.mtu = Some(msg.mtu);
iface.system.mac_addr = Some(msg.mac_address);
Expand All @@ -48,9 +49,18 @@ pub(crate) fn process_iface_update(
.interfaces
.update_ifindex(iface_idx, Some(msg.ifindex));
}
let iface = &mut arenas.interfaces[iface_idx];

// Update the padding used in Hello PDUs if the MTU has changed.
if iface.config.hello_padding
&& iface.system.mtu != old_mtu
&& iface.state.active
&& !iface.is_passive()
{
iface.hello_interval_start(&instance, LevelType::All);
}

// Check if IS-IS needs to be activated or deactivated on this interface.
let iface = &mut arenas.interfaces[iface_idx];
iface.update(&mut instance, &mut arenas.adjacencies)?;

Ok(())
Expand Down

0 comments on commit d410b46

Please sign in to comment.