Skip to content

Commit 38a15c7

Browse files
committed
isis: implement route redistribution
This adds basic support for route redistribution from other protocols. Currently, we cannot apply routing policies to filter or modify the redistributed routes. This will be implemented in a separate commit. Signed-off-by: Renato Westphal <[email protected]>
1 parent cc25679 commit 38a15c7

File tree

21 files changed

+3766
-10
lines changed

21 files changed

+3766
-10
lines changed

holo-isis/src/instance.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use holo_utils::ibus::IbusMsg;
2020
use holo_utils::protocol::Protocol;
2121
use holo_utils::task::TimeoutTask;
2222
use holo_utils::{Receiver, Sender, UnboundedReceiver, UnboundedSender};
23-
use ipnetwork::IpNetwork;
23+
use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network};
2424
use tokio::sync::mpsc;
2525

2626
use crate::adjacency::{Adjacency, AdjacencyState};
@@ -33,7 +33,7 @@ use crate::interface::CircuitIdAllocator;
3333
use crate::lsdb::{LspEntry, LspLogEntry};
3434
use crate::northbound::configuration::InstanceCfg;
3535
use crate::packet::{LevelNumber, LevelType, Levels, SystemId};
36-
use crate::route::{Route, RouteFlags};
36+
use crate::route::{Route, RouteFlags, RouteSys};
3737
use crate::spf::{SpfLogEntry, SpfScheduler, Vertex, VertexId};
3838
use crate::tasks::messages::input::{
3939
AdjHoldTimerMsg, DisElectionMsg, LspDeleteMsg, LspOriginateMsg,
@@ -65,6 +65,9 @@ pub struct Instance {
6565
pub struct InstanceSys {
6666
// System Router ID.
6767
pub router_id: Option<Ipv4Addr>,
68+
// Redistributed routes.
69+
pub ipv4_routes: Levels<BTreeMap<Ipv4Network, RouteSys>>,
70+
pub ipv6_routes: Levels<BTreeMap<Ipv6Network, RouteSys>>,
6871
}
6972

7073
#[derive(Debug)]
@@ -609,6 +612,14 @@ async fn process_ibus_msg(
609612
IbusMsg::InterfaceAddressDel(msg) => {
610613
southbound::rx::process_addr_del(instance, msg);
611614
}
615+
// Route redistribute update notification.
616+
IbusMsg::RouteRedistributeAdd(msg) => {
617+
southbound::rx::process_route_add(instance, msg);
618+
}
619+
// Route redistribute delete notification.
620+
IbusMsg::RouteRedistributeDel(msg) => {
621+
southbound::rx::process_route_del(instance, msg);
622+
}
612623
// Keychain update event.
613624
IbusMsg::KeychainUpd(keychain) => {
614625
// Update the local copy of the keychain.

holo-isis/src/lsdb.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,54 @@ fn lsp_build_tlvs(
422422
}
423423
}
424424

425+
// Add redistributed routes.
426+
if instance.config.is_af_enabled(AddressFamily::Ipv4) {
427+
for (prefix, route) in instance.system.ipv4_routes.get(level) {
428+
let prefix = prefix.apply_mask();
429+
if metric_type.is_standard_enabled() {
430+
ipv4_external_reach.insert(
431+
prefix,
432+
Ipv4Reach {
433+
up_down: false,
434+
ie_bit: false,
435+
metric: std::cmp::min(route.metric, MAX_NARROW_METRIC)
436+
as u8,
437+
metric_delay: None,
438+
metric_expense: None,
439+
metric_error: None,
440+
prefix,
441+
},
442+
);
443+
}
444+
if metric_type.is_wide_enabled() {
445+
ext_ipv4_reach.insert(
446+
prefix,
447+
ExtIpv4Reach {
448+
metric: route.metric,
449+
up_down: false,
450+
prefix,
451+
sub_tlvs: Default::default(),
452+
},
453+
);
454+
}
455+
}
456+
}
457+
if instance.config.is_af_enabled(AddressFamily::Ipv6) {
458+
for (prefix, route) in instance.system.ipv6_routes.get(level) {
459+
let prefix = prefix.apply_mask();
460+
ipv6_reach.insert(
461+
prefix,
462+
Ipv6Reach {
463+
metric: route.metric,
464+
up_down: false,
465+
external: true,
466+
prefix,
467+
sub_tlvs: Default::default(),
468+
},
469+
);
470+
}
471+
}
472+
425473
// In an L1/L2 router, propagate L1 IP reachability to L2 for inter-area
426474
// routing.
427475
if level == LevelNumber::L2 && instance.config.level_type == LevelType::All

holo-isis/src/northbound/configuration.rs

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// See: https://nlnet.nl/NGI0
88
//
99

10-
use std::collections::{BTreeMap, BTreeSet};
10+
use std::collections::{BTreeMap, BTreeSet, HashMap};
1111
use std::net::{Ipv4Addr, Ipv6Addr};
1212
use std::sync::LazyLock as Lazy;
1313

@@ -21,6 +21,7 @@ use holo_northbound::yang::control_plane_protocol::isis;
2121
use holo_utils::crypto::CryptoAlgo;
2222
use holo_utils::ip::AddressFamily;
2323
use holo_utils::keychain::{Key, Keychains};
24+
use holo_utils::protocol::Protocol;
2425
use holo_utils::yang::DataNodeRefExt;
2526
use holo_yang::TryFromYang;
2627

@@ -42,6 +43,7 @@ pub enum ListEntry {
4243
#[default]
4344
None,
4445
AddressFamily(AddressFamily),
46+
Redistribution(AddressFamily, LevelNumber, Protocol),
4547
Interface(InterfaceIndex),
4648
InterfaceAddressFamily(InterfaceIndex, AddressFamily),
4749
}
@@ -67,6 +69,8 @@ pub enum Event {
6769
RerunSpf,
6870
ReinstallRoutes,
6971
OverloadChange(bool),
72+
RedistributeAdd(AddressFamily, Protocol),
73+
RedistributeDelete(AddressFamily, LevelNumber, Protocol),
7074
}
7175

7276
pub static VALIDATION_CALLBACKS: Lazy<ValidationCallbacks> =
@@ -114,6 +118,7 @@ pub struct BierIsisCfg {
114118
#[derive(Debug)]
115119
pub struct AddressFamilyCfg {
116120
pub enabled: bool,
121+
pub redistribution: HashMap<(LevelNumber, Protocol), RedistributionCfg>,
117122
}
118123

119124
#[derive(Debug)]
@@ -129,6 +134,9 @@ pub enum MetricType {
129134
Both,
130135
}
131136

137+
#[derive(Debug, Default)]
138+
pub struct RedistributionCfg {}
139+
132140
#[derive(Debug)]
133141
pub struct InterfaceCfg {
134142
pub enabled: bool,
@@ -482,6 +490,37 @@ fn load_callbacks() -> Callbacks<Instance> {
482490
event_queue.insert(Event::ReoriginateLsps(LevelNumber::L1));
483491
event_queue.insert(Event::ReoriginateLsps(LevelNumber::L2));
484492
})
493+
.path(isis::address_families::address_family_list::redistribution::PATH)
494+
.create_apply(|instance, args| {
495+
let af = args.list_entry.into_address_family().unwrap();
496+
let af_cfg = instance.config.afs.get_mut(&af).unwrap();
497+
498+
let level = args.dnode.get_string_relative("./level").unwrap();
499+
let level = LevelNumber::try_from_yang(&level).unwrap();
500+
let protocol = args.dnode.get_string_relative("./type").unwrap();
501+
let protocol = Protocol::try_from_yang(&protocol).unwrap();
502+
af_cfg.redistribution.insert((level, protocol), Default::default());
503+
504+
let event_queue = args.event_queue;
505+
event_queue.insert(Event::RedistributeAdd(af, protocol));
506+
})
507+
.delete_apply(|instance, args| {
508+
let (af, level, protocol) = args.list_entry.into_redistribution().unwrap();
509+
let af_cfg = instance.config.afs.get_mut(&af).unwrap();
510+
511+
af_cfg.redistribution.remove(&(level, protocol));
512+
513+
let event_queue = args.event_queue;
514+
event_queue.insert(Event::RedistributeDelete(af, level, protocol));
515+
})
516+
.lookup(|_instance, list_entry, dnode| {
517+
let af = list_entry.into_address_family().unwrap();
518+
let level = dnode.get_string_relative("./level").unwrap();
519+
let level = LevelNumber::try_from_yang(&level).unwrap();
520+
let protocol = dnode.get_string_relative("./type").unwrap();
521+
let protocol = Protocol::try_from_yang(&protocol).unwrap();
522+
ListEntry::Redistribution(af, level, protocol)
523+
})
485524
.path(isis::mpls::te_rid::ipv4_router_id::PATH)
486525
.modify_apply(|instance, args| {
487526
let addr = args.dnode.get_ipv4();
@@ -1359,6 +1398,33 @@ impl Provider for Instance {
13591398
notification::database_overload(&instance, overload_status);
13601399
}
13611400
}
1401+
Event::RedistributeAdd(af, protocol) => {
1402+
// Subscribe to route redistribution for the given protocol and
1403+
// address family.
1404+
self.tx.ibus.route_redistribute_sub(protocol, Some(af));
1405+
}
1406+
Event::RedistributeDelete(af, level, protocol) => {
1407+
// Unsubscribe from route redistribution for the given protocol
1408+
// and address family.
1409+
self.tx.ibus.route_redistribute_unsub(protocol, Some(af));
1410+
1411+
// Remove redistributed routes.
1412+
match af {
1413+
AddressFamily::Ipv4 => {
1414+
let routes = self.system.ipv4_routes.get_mut(level);
1415+
routes.retain(|_, route| route.protocol != protocol);
1416+
}
1417+
AddressFamily::Ipv6 => {
1418+
let routes = self.system.ipv6_routes.get_mut(level);
1419+
routes.retain(|_, route| route.protocol != protocol);
1420+
}
1421+
}
1422+
1423+
// Schedule LSP reorigination.
1424+
if let Some((mut instance, _)) = self.as_up() {
1425+
instance.schedule_lsp_origination(level);
1426+
}
1427+
}
13621428
}
13631429
}
13641430
}
@@ -1547,7 +1613,10 @@ impl Default for AddressFamilyCfg {
15471613
let enabled =
15481614
isis::address_families::address_family_list::enabled::DFLT;
15491615

1550-
AddressFamilyCfg { enabled }
1616+
AddressFamilyCfg {
1617+
enabled,
1618+
redistribution: Default::default(),
1619+
}
15511620
}
15521621
}
15531622

holo-isis/src/northbound/yang.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::interface::InterfaceType;
1818
use crate::lsdb::LspLogReason;
1919
use crate::northbound::configuration::MetricType;
2020
use crate::packet::consts::LspFlags;
21-
use crate::packet::{AreaAddr, LanId, LevelType, LspId, SystemId};
21+
use crate::packet::{AreaAddr, LanId, LevelNumber, LevelType, LspId, SystemId};
2222
use crate::spf;
2323
use crate::spf::SpfType;
2424

@@ -191,6 +191,16 @@ impl ToYang for SpfType {
191191

192192
// ===== TryFromYang implementations =====
193193

194+
impl TryFromYang for LevelNumber {
195+
fn try_from_yang(value: &str) -> Option<LevelNumber> {
196+
match value {
197+
"1" => Some(LevelNumber::L1),
198+
"2" => Some(LevelNumber::L2),
199+
_ => None,
200+
}
201+
}
202+
}
203+
194204
impl TryFromYang for LevelType {
195205
fn try_from_yang(value: &str) -> Option<LevelType> {
196206
match value {

holo-isis/src/packet/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub struct LevelTypeIterator {
3434
}
3535

3636
// Represents a single IS-IS level.
37-
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
37+
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
3838
#[derive(Deserialize, Serialize)]
3939
pub enum LevelNumber {
4040
L1 = 1,

holo-isis/src/route.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ use std::net::IpAddr;
1010
use bitflags::bitflags;
1111
use derive_new::new;
1212
use holo_utils::ip::{AddressFamily, IpNetworkKind};
13-
use holo_utils::southbound::IsisRouteType;
13+
use holo_utils::protocol::Protocol;
14+
use holo_utils::southbound::{IsisRouteType, RouteOpaqueAttrs};
1415
use ipnetwork::IpNetwork;
1516

1617
use crate::collections::{InterfaceIndex, Interfaces};
@@ -48,6 +49,15 @@ pub struct Nexthop {
4849
pub addr: IpAddr,
4950
}
5051

52+
// Route redistributed from the global RIB.
53+
#[derive(Clone, Debug)]
54+
pub struct RouteSys {
55+
pub protocol: Protocol,
56+
pub metric: u32,
57+
pub tag: Option<u32>,
58+
pub opaque_attrs: RouteOpaqueAttrs,
59+
}
60+
5161
// ===== impl Route =====
5262

5363
impl Route {

0 commit comments

Comments
 (0)