diff --git a/Cargo.toml b/Cargo.toml index 35ebdb4d..0ec0e308 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "holo-protocol", "holo-rip", "holo-routing", + "holo-system", "holo-tools", "holo-utils", "holo-vrrp", @@ -49,14 +50,14 @@ itertools = "0.10" libc = "0.2" maplit = "1.0" md5 = "0.7" -nix = "0.26" +nix = { version = "0.29", features = ["fs", "net", "socket", "uio", "user"] } netlink-packet-core = "0.7" netlink-packet-route = "0.17" netlink-sys = "0.8" num-derive = "0.4" num-traits = "0.2" pickledb = "0.5" -prefix-trie = { version = "0.4.1", features = ["ipnetwork"] } +prefix-trie = { version = "0.4.1", default-features = false, features = ["ipnetwork"] } prost = "0.12" rand = "0.8.5" regex = "1.10" @@ -74,7 +75,7 @@ tonic = { version = "0.11", features = ["tls"] } tonic-build = "0.11" tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } -yang2 = { version = "0.13", features = ["bundled"] } +yang3 = { version = "0.5", features = ["bundled"] } [workspace.lints.rust] rust_2018_idioms = { level = "warn", priority = -1 } @@ -83,6 +84,7 @@ unsafe_code = "forbid" [workspace.lints.clippy] borrowed_box = "allow" manual_range_contains = "allow" +single_match = "allow" too_many_arguments = "allow" [profile.release] diff --git a/INSTALL.md b/INSTALL.md index 52cb51e3..cbf452ea 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -17,7 +17,7 @@ $ git clone https://github.com/holo-routing/holo-cli.git 3. Install build dependencies: -Holo requires a few dependencies for building and embedding the libyang2 library. +Holo requires a few dependencies for building and embedding the libyang library. You can install them using your system's package manager. For example, on Debian-based systems: ``` diff --git a/README.md b/README.md index 3c54be23..ba4de707 100644 --- a/README.md +++ b/README.md @@ -239,6 +239,7 @@ Holo supports the following IETF RFCs and Internet drafts: | ietf-segment-routing-mpls@2021-05-26 | 62.50% | 0.00% | - | 23.53% | [32.76%](http://westphal.com.br/holo/ietf-segment-routing-mpls.html) | | ietf-segment-routing@2021-05-26 | 100.00% | - | - | - | [100.00%](http://westphal.com.br/holo/ietf-segment-routing.html) | | ietf-vrrp@2018-03-13 | 25.53% | 40.00% | - | 25.00% | [31.73%](http://westphal.com.br/holo/ietf-vrrp@2018-03-13.coverage.md) | +| ietf-system@2014-08-06 | 26.67% | 60.00% | 0.00% | - | [38.24%](http://westphal.com.br/holo/ietf-system@2014-08-06.coverage.md) | ## Funding diff --git a/holo-bfd/Cargo.toml b/holo-bfd/Cargo.toml index ab69ffe9..20318258 100644 --- a/holo-bfd/Cargo.toml +++ b/holo-bfd/Cargo.toml @@ -25,7 +25,7 @@ serde_json.workspace = true socket2.workspace = true tokio.workspace = true tracing.workspace = true -yang2.workspace = true +yang3.workspace = true holo-northbound = { path = "../holo-northbound" } holo-protocol = { path = "../holo-protocol" } diff --git a/holo-bfd/src/network.rs b/holo-bfd/src/network.rs index 9945e7bf..399ccc89 100644 --- a/holo-bfd/src/network.rs +++ b/holo-bfd/src/network.rs @@ -214,7 +214,7 @@ pub(crate) async fn read_loop( Ok(msg) => { // Retrieve source and destination addresses. let src = get_packet_src(msg.address.as_ref()); - let dst = get_packet_dst(msg.cmsgs()); + let dst = get_packet_dst(msg.cmsgs().unwrap()); Ok((src, dst, msg.bytes)) } Err(errno) => Err(errno.into()), diff --git a/holo-bfd/src/northbound/notification.rs b/holo-bfd/src/northbound/notification.rs index 96b5a8d0..43979ae4 100644 --- a/holo-bfd/src/northbound/notification.rs +++ b/holo-bfd/src/northbound/notification.rs @@ -44,7 +44,8 @@ fn state_change_singlehop( time_of_last_state_change: sess .statistics .last_state_change_time - .as_ref(), + .as_ref() + .map(Cow::Borrowed), dest_addr: Some(Cow::Borrowed(dst)), source_addr: sess.config.src.as_ref().map(Cow::Borrowed), session_index: Some(sess.id as u32), @@ -71,7 +72,8 @@ fn state_change_multihop( time_of_last_state_change: sess .statistics .last_state_change_time - .as_ref(), + .as_ref() + .map(Cow::Borrowed), dest_addr: Some(Cow::Borrowed(dst)), source_addr: Some(Cow::Borrowed(src)), session_index: Some(sess.id as u32), diff --git a/holo-bfd/src/northbound/state.rs b/holo-bfd/src/northbound/state.rs index cde5e2f9..10850621 100644 --- a/holo-bfd/src/northbound/state.rs +++ b/holo-bfd/src/northbound/state.rs @@ -111,9 +111,9 @@ fn load_callbacks() -> Callbacks { use bfd::ip_mh::session_groups::session_group::sessions::session_statistics::SessionStatistics; let sess = args.list_entry.as_session().unwrap(); Box::new(SessionStatistics { - create_time: Some(&sess.statistics.create_time).ignore_in_testing(), - last_down_time: sess.statistics.last_down_time.as_ref().ignore_in_testing(), - last_up_time: sess.statistics.last_up_time.as_ref().ignore_in_testing(), + create_time: Some(Cow::Borrowed(&sess.statistics.create_time)).ignore_in_testing(), + last_down_time: sess.statistics.last_down_time.as_ref().map(Cow::Borrowed).ignore_in_testing(), + last_up_time: sess.statistics.last_up_time.as_ref().map(Cow::Borrowed).ignore_in_testing(), down_count: Some(sess.statistics.down_count).ignore_in_testing(), admin_down_count: Some(sess.statistics.admin_down_count).ignore_in_testing(), receive_packet_count: Some(sess.statistics.rx_packet_count).ignore_in_testing(), @@ -176,9 +176,9 @@ fn load_callbacks() -> Callbacks { use bfd::ip_sh::sessions::session::session_statistics::SessionStatistics; let sess = args.list_entry.as_session().unwrap(); Box::new(SessionStatistics { - create_time: Some(&sess.statistics.create_time).ignore_in_testing(), - last_down_time: sess.statistics.last_down_time.as_ref().ignore_in_testing(), - last_up_time: sess.statistics.last_up_time.as_ref().ignore_in_testing(), + create_time: Some(Cow::Borrowed(&sess.statistics.create_time)).ignore_in_testing(), + last_down_time: sess.statistics.last_down_time.as_ref().map(Cow::Borrowed).ignore_in_testing(), + last_up_time: sess.statistics.last_up_time.as_ref().map(Cow::Borrowed).ignore_in_testing(), down_count: Some(sess.statistics.down_count).ignore_in_testing(), admin_down_count: Some(sess.statistics.admin_down_count).ignore_in_testing(), receive_packet_count: Some(sess.statistics.rx_packet_count).ignore_in_testing(), diff --git a/holo-bgp/Cargo.toml b/holo-bgp/Cargo.toml index 3ed58b4e..8532bff3 100644 --- a/holo-bgp/Cargo.toml +++ b/holo-bgp/Cargo.toml @@ -26,7 +26,7 @@ serde_json.workspace = true serde_with.workspace = true tokio.workspace = true tracing.workspace = true -yang2.workspace = true +yang3.workspace = true holo-northbound = { path = "../holo-northbound" } holo-protocol = { path = "../holo-protocol" } diff --git a/holo-bgp/src/northbound/notification.rs b/holo-bgp/src/northbound/notification.rs index 360a2321..eae0b7d1 100644 --- a/holo-bgp/src/northbound/notification.rs +++ b/holo-bgp/src/northbound/notification.rs @@ -42,7 +42,7 @@ pub(crate) fn backward_transition( notification_received: nbr.notification_rcvd.as_ref().map( |(time, notif)| { Box::new(NotificationReceived { - last_notification: Some(time), + last_notification: Some(Cow::Borrowed(time)), last_error: Some(notif.to_yang()), last_error_code: Some(notif.error_code), last_error_subcode: Some(notif.error_subcode), @@ -52,7 +52,7 @@ pub(crate) fn backward_transition( notification_sent: nbr.notification_sent.as_ref().map( |(time, notif)| { Box::new(NotificationSent { - last_notification: Some(time), + last_notification: Some(Cow::Borrowed(time)), last_error: Some(notif.to_yang()), last_error_code: Some(notif.error_code), last_error_subcode: Some(notif.error_subcode), diff --git a/holo-bgp/src/northbound/rpc.rs b/holo-bgp/src/northbound/rpc.rs index d92ca4ff..f05988fc 100644 --- a/holo-bgp/src/northbound/rpc.rs +++ b/holo-bgp/src/northbound/rpc.rs @@ -9,7 +9,7 @@ use std::sync::LazyLock as Lazy; use holo_northbound::rpc::{Callbacks, CallbacksBuilder, Provider}; use holo_northbound::yang::control_plane_protocol::bgp; use holo_utils::yang::DataNodeRefExt; -use yang2::data::Data; +use yang3::data::Data; use crate::instance::Instance; diff --git a/holo-bgp/src/northbound/state.rs b/holo-bgp/src/northbound/state.rs index 4e1a4ddd..7890f2f4 100644 --- a/holo-bgp/src/northbound/state.rs +++ b/holo-bgp/src/northbound/state.rs @@ -127,7 +127,7 @@ fn load_callbacks() -> Callbacks { identifier: nbr.identifier.map(Cow::Owned), dynamically_configured: None, session_state: Some(nbr.state.to_yang()), - last_established: nbr.last_established.as_ref().ignore_in_testing(), + last_established: nbr.last_established.as_ref().map(Cow::Borrowed).ignore_in_testing(), }) }) .path(bgp::neighbors::neighbor::timers::PATH) @@ -298,7 +298,7 @@ fn load_callbacks() -> Callbacks { let mut last_error_subcode = None; let mut last_error_data = None; if let Some((time, notif)) = &nbr.notification_rcvd { - last_notification = Some(time); + last_notification = Some(Cow::Borrowed(time)); last_error = Some(notif.to_yang()); last_error_code = Some(notif.error_code); last_error_subcode = Some(notif.error_subcode); @@ -322,7 +322,7 @@ fn load_callbacks() -> Callbacks { let mut last_error_subcode = None; let mut last_error_data = None; if let Some((time, notif)) = &nbr.notification_sent { - last_notification = Some(time); + last_notification = Some(Cow::Borrowed(time)); last_error = Some(notif.to_yang()); last_error_code = Some(notif.error_code); last_error_subcode = Some(notif.error_subcode); diff --git a/holo-daemon/Cargo.toml b/holo-daemon/Cargo.toml index 5e54c346..06cb0165 100644 --- a/holo-daemon/Cargo.toml +++ b/holo-daemon/Cargo.toml @@ -6,7 +6,7 @@ license.workspace = true edition.workspace = true [dependencies] -console-subscriber = "0.3" +console-subscriber = { version = "0.3", optional = true } prost-types = "0.12" toml = "0.5" tokio-uring = { version = "0.5", optional = true } @@ -28,7 +28,7 @@ tokio.workspace = true tonic.workspace = true tracing.workspace = true tracing-subscriber.workspace = true -yang2.workspace = true +yang3.workspace = true holo-interface = { path = "../holo-interface", optional = true } holo-bfd = { path = "../holo-bfd", optional = true } @@ -41,6 +41,7 @@ holo-policy = { path = "../holo-policy", optional = true } holo-protocol = { path = "../holo-protocol" } holo-rip = { path = "../holo-rip", optional = true } holo-routing = { path = "../holo-routing", optional = true } +holo-system = { path = "../holo-system", optional = true } holo-utils = { path = "../holo-utils" } holo-vrrp = { path = "../holo-vrrp", optional = true } holo-yang = { path = "../holo-yang" } @@ -62,6 +63,7 @@ default = [ "keychain", "policy", "routing", + "system", # Protocols "bfd", "bgp", @@ -72,10 +74,11 @@ default = [ ] # Base components -interface = ["holo-interface"] -keychain = ["holo-keychain"] -policy = ["holo-policy", "holo-routing"] -routing = ["holo-routing", "holo-interface"] +interface = ["dep:holo-interface"] +keychain = ["dep:holo-keychain"] +policy = ["dep:holo-policy", "dep:holo-routing"] +routing = ["dep:holo-routing", "dep:holo-interface"] +system = ["dep:holo-system"] # Protocols bfd = ["holo-bfd", "holo-routing/bfd"] @@ -85,5 +88,7 @@ ospf = ["holo-ospf", "holo-routing/ospf"] rip = ["holo-rip", "holo-routing/rip"] vrrp = ["holo-vrrp", "holo-interface/vrrp"] + # Other features -io_uring = ["tokio-uring"] +tokio_console = ["dep:console-subscriber"] +io_uring = ["dep:tokio-uring"] diff --git a/holo-daemon/holod.toml b/holo-daemon/holod.toml index b2cf1ae0..7a6c229a 100644 --- a/holo-daemon/holod.toml +++ b/holo-daemon/holod.toml @@ -47,11 +47,6 @@ database_path = "/var/run/holo/holo.db" # Sets whether or not an event’s source code file path and line number are displayed show_source = false -# Instrumentation using tokio-console (a diagnostics and debugging tool) -[tokio_console] - # Enable or disable - enabled = false - # Event recorder (useful for bug reporting) [event_recorder] # Enable or disable the event recorder diff --git a/holo-daemon/src/config.rs b/holo-daemon/src/config.rs index df9c6726..386f8966 100644 --- a/holo-daemon/src/config.rs +++ b/holo-daemon/src/config.rs @@ -16,7 +16,6 @@ pub struct Config { pub group: String, pub database_path: String, pub logging: Logging, - pub tokio_console: TokioConsole, pub event_recorder: event_recorder::Config, pub plugins: Plugins, } @@ -73,12 +72,6 @@ pub enum LoggingFmtStyle { Pretty, } -#[derive(Debug, Default, Deserialize)] -#[serde(default, deny_unknown_fields)] -pub struct TokioConsole { - pub enabled: bool, -} - #[derive(Debug, Default, Deserialize)] #[serde(default, deny_unknown_fields)] pub struct Plugins { @@ -139,7 +132,6 @@ impl Default for Config { group: "holo".to_owned(), database_path: "/var/run/holo/holo.db".to_owned(), logging: Default::default(), - tokio_console: Default::default(), event_recorder: Default::default(), plugins: Default::default(), } diff --git a/holo-daemon/src/main.rs b/holo-daemon/src/main.rs index e874a1a9..76ebacd1 100644 --- a/holo-daemon/src/main.rs +++ b/holo-daemon/src/main.rs @@ -23,7 +23,7 @@ use tracing_appender::rolling; use tracing_subscriber::prelude::*; use tracing_subscriber::Layer; -fn init_tracing(config: &config::Logging, tokio_console: bool) { +fn init_tracing(config: &config::Logging) { // Enable logging to journald. let journald = config.journald.enabled.then(|| { tracing_journald::layer().expect("couldn't connect to journald") @@ -78,29 +78,38 @@ fn init_tracing(config: &config::Logging, tokio_console: bool) { layer.with_filter(log_level_filter) }); - // Enable tokio-console instrumentation. - let console = tokio_console.then(console_subscriber::spawn); - // Configure the tracing fmt layer. - let env_filter = tracing_subscriber::EnvFilter::builder() - .with_default_directive("holo=debug".parse().unwrap()) - .from_env_lossy(); - let env_filter = match tokio_console { - true => { - // Enable targets needed by the console. - env_filter - .add_directive("tokio=trace".parse().unwrap()) - .add_directive("runtime=trace".parse().unwrap()) - } - false => env_filter, - }; - tracing_subscriber::registry() - .with(env_filter) - .with(journald) - .with(file) - .with(stdout) - .with(console) - .init(); + #[cfg(feature = "tokio_console")] + { + // Enable tokio-console instrumentation. + let console = console_subscriber::spawn(); + let env_filter = tracing_subscriber::EnvFilter::builder() + .with_default_directive("holo=debug".parse().unwrap()) + .from_env_lossy(); + // Enable targets needed by the console. + let env_filter = env_filter + .add_directive("tokio=trace".parse().unwrap()) + .add_directive("runtime=trace".parse().unwrap()); + tracing_subscriber::registry() + .with(env_filter) + .with(journald) + .with(file) + .with(stdout) + .with(console) + .init(); + } + #[cfg(not(feature = "tokio_console"))] + { + let env_filter = tracing_subscriber::EnvFilter::builder() + .with_default_directive("holo=debug".parse().unwrap()) + .from_env_lossy(); + tracing_subscriber::registry() + .with(env_filter) + .with(journald) + .with(file) + .with(stdout) + .init(); + } } fn init_db>( @@ -174,7 +183,7 @@ fn main() { } // Initialize tracing. - init_tracing(&config.logging, config.tokio_console.enabled); + init_tracing(&config.logging); // Initialize non-volatile storage. let db = init_db(&config.database_path) diff --git a/holo-daemon/src/northbound/client/api.rs b/holo-daemon/src/northbound/client/api.rs index f0a41bfc..99453ef5 100644 --- a/holo-daemon/src/northbound/client/api.rs +++ b/holo-daemon/src/northbound/client/api.rs @@ -5,7 +5,7 @@ // use holo_utils::Responder; -use yang2::data::{DataDiff, DataTree}; +use yang3::data::{DataDiff, DataTree}; use crate::northbound::core::Transaction; use crate::northbound::Result; diff --git a/holo-daemon/src/northbound/client/gnmi.rs b/holo-daemon/src/northbound/client/gnmi.rs index e4689fe1..f2f31cb5 100644 --- a/holo-daemon/src/northbound/client/gnmi.rs +++ b/holo-daemon/src/northbound/client/gnmi.rs @@ -14,8 +14,8 @@ use tokio_stream::wrappers::ReceiverStream; use tonic::transport::{Server, ServerTlsConfig}; use tonic::{Request, Response, Status, Streaming}; use tracing::{debug, debug_span, error, trace}; -use yang2::data::{Data, DataFormat, DataPrinterFlags, DataTree}; -use yang2::schema::SchemaNodeKind; +use yang3::data::{Data, DataFormat, DataPrinterFlags, DataTree}; +use yang3::schema::SchemaNodeKind; use crate::config; use crate::northbound::client::api; diff --git a/holo-daemon/src/northbound/client/grpc.rs b/holo-daemon/src/northbound/client/grpc.rs index 2712a774..2ad1a097 100644 --- a/holo-daemon/src/northbound/client/grpc.rs +++ b/holo-daemon/src/northbound/client/grpc.rs @@ -14,7 +14,7 @@ use tokio::sync::oneshot; use tonic::transport::{Server, ServerTlsConfig}; use tonic::{Request, Response, Status}; use tracing::{debug, debug_span, error, trace}; -use yang2::data::{ +use yang3::data::{ Data, DataDiff, DataFormat, DataOperation, DataParserFlags, DataPrinterFlags, DataTree, DataValidationFlags, }; @@ -98,6 +98,7 @@ impl proto::Northbound for NorthboundService { let data_type = api::DataType::try_from(grpc_request.r#type)?; let encoding = proto::Encoding::try_from(grpc_request.encoding) .map_err(|_| Status::invalid_argument("Invalid data encoding"))?; + let with_defaults = grpc_request.with_defaults; let path = (!grpc_request.path.is_empty()).then_some(grpc_request.path); let nb_request = api::client::Request::Get(api::client::GetRequest { data_type, @@ -110,20 +111,14 @@ impl proto::Northbound for NorthboundService { let nb_response = responder_rx.await.unwrap()?; // Convert and relay northbound response to the gRPC client. - let data = nb_response - .dtree - .print_string( - DataFormat::from(encoding), - DataPrinterFlags::WITH_SIBLINGS, - ) - .map_err(|error| Status::internal(error.to_string()))? - .unwrap_or_default(); + let mut printer_flags = DataPrinterFlags::WITH_SIBLINGS; + if with_defaults { + printer_flags.insert(DataPrinterFlags::WD_ALL); + } + let data = data_tree_init(&nb_response.dtree, encoding, printer_flags)?; let grpc_response = proto::GetResponse { timestamp: get_timestamp(), - data: Some(proto::DataTree { - encoding: encoding as i32, - data, - }), + data: Some(data), }; Ok(Response::new(grpc_response)) } @@ -132,7 +127,6 @@ impl proto::Northbound for NorthboundService { &self, grpc_request: Request, ) -> Result, Status> { - let yang_ctx = YANG_CTX.get().unwrap(); let grpc_request = grpc_request.into_inner(); debug_span!("northbound").in_scope(|| { debug_span!("client", name = "grpc").in_scope(|| { @@ -145,19 +139,10 @@ impl proto::Northbound for NorthboundService { let (responder_tx, responder_rx) = oneshot::channel(); // Convert and relay gRPC request to the northbound. - let config_tree = grpc_request.config.ok_or_else(|| { + let config = grpc_request.config.ok_or_else(|| { Status::invalid_argument("Missing 'config' field") })?; - let encoding = proto::Encoding::try_from(config_tree.encoding) - .map_err(|_| Status::invalid_argument("Invalid data encoding"))?; - let config = DataTree::parse_string( - yang_ctx, - &config_tree.data, - DataFormat::from(encoding), - DataParserFlags::empty(), - DataValidationFlags::NO_STATE, - ) - .map_err(|error| Status::invalid_argument(error.to_string()))?; + let config = data_tree_get(&config)?; let nb_request = api::client::Request::Validate(api::client::ValidateRequest { config, @@ -177,7 +162,6 @@ impl proto::Northbound for NorthboundService { &self, grpc_request: Request, ) -> Result, Status> { - let yang_ctx = YANG_CTX.get().unwrap(); let grpc_request = grpc_request.into_inner(); debug_span!("northbound").in_scope(|| { debug_span!("client", name = "grpc").in_scope(|| { @@ -190,11 +174,9 @@ impl proto::Northbound for NorthboundService { let (responder_tx, responder_rx) = oneshot::channel(); // Convert and relay gRPC request to the northbound. - let config_tree = grpc_request.config.ok_or_else(|| { + let config = grpc_request.config.ok_or_else(|| { Status::invalid_argument("Missing 'config' field") })?; - let encoding = proto::Encoding::try_from(config_tree.encoding) - .map_err(|_| Status::invalid_argument("Invalid data encoding"))?; let operation = proto::commit_request::Operation::try_from(grpc_request.operation) .map_err(|_| { @@ -202,37 +184,15 @@ impl proto::Northbound for NorthboundService { })?; let config = match operation { proto::commit_request::Operation::Merge => { - let config = DataTree::parse_string( - yang_ctx, - &config_tree.data, - DataFormat::from(encoding), - DataParserFlags::empty(), - DataValidationFlags::NO_STATE, - ) - .map_err(|error| Status::invalid_argument(error.to_string()))?; + let config = data_tree_get(&config)?; api::CommitConfiguration::Merge(config) } proto::commit_request::Operation::Replace => { - let config = DataTree::parse_string( - yang_ctx, - &config_tree.data, - DataFormat::from(encoding), - DataParserFlags::empty(), - DataValidationFlags::NO_STATE, - ) - .map_err(|error| Status::invalid_argument(error.to_string()))?; + let config = data_tree_get(&config)?; api::CommitConfiguration::Replace(config) } proto::commit_request::Operation::Change => { - let diff = DataDiff::parse_string( - yang_ctx, - &config_tree.data, - DataFormat::from(encoding), - DataParserFlags::NO_VALIDATION, - DataValidationFlags::NO_STATE - | DataValidationFlags::PRESENT, - ) - .map_err(|error| Status::invalid_argument(error.to_string()))?; + let diff = data_diff_get(&config)?; api::CommitConfiguration::Change(diff) } }; @@ -260,7 +220,6 @@ impl proto::Northbound for NorthboundService { &self, grpc_request: Request, ) -> Result, Status> { - let yang_ctx = YANG_CTX.get().unwrap(); let grpc_request = grpc_request.into_inner(); debug_span!("northbound").in_scope(|| { debug_span!("client", name = "grpc").in_scope(|| { @@ -278,13 +237,7 @@ impl proto::Northbound for NorthboundService { .ok_or_else(|| Status::invalid_argument("Missing 'data' field"))?; let encoding = proto::Encoding::try_from(data.encoding) .map_err(|_| Status::invalid_argument("Invalid data encoding"))?; - let data = DataTree::parse_op_string( - yang_ctx, - &data.data, - DataFormat::from(encoding), - DataOperation::RpcYang, - ) - .map_err(|error| Status::invalid_argument(error.to_string()))?; + let data = rpc_get(&data)?; let nb_request = api::client::Request::Execute(api::client::ExecuteRequest { data, @@ -296,20 +249,9 @@ impl proto::Northbound for NorthboundService { let nb_response = responder_rx.await.unwrap()?; // Convert and relay northbound response to the gRPC client. - let data = nb_response - .data - .print_string( - DataFormat::from(encoding), - DataPrinterFlags::WITH_SIBLINGS, - ) - .map_err(|error| Status::internal(error.to_string()))? - .unwrap_or_default(); - let grpc_response = proto::ExecuteResponse { - data: Some(proto::DataTree { - encoding: encoding as i32, - data, - }), - }; + let printer_flags = DataPrinterFlags::WITH_SIBLINGS; + let data = data_tree_init(&nb_response.data, encoding, printer_flags)?; + let grpc_response = proto::ExecuteResponse { data: Some(data) }; Ok(Response::new(grpc_response)) } @@ -389,19 +331,11 @@ impl proto::Northbound for NorthboundService { // Convert and relay northbound response to the gRPC client. let encoding = proto::Encoding::try_from(grpc_request.encoding) .map_err(|_| Status::invalid_argument("Invalid data encoding"))?; - let config = nb_response - .dtree - .print_string( - DataFormat::from(encoding), - DataPrinterFlags::WITH_SIBLINGS, - ) - .map_err(|error| Status::internal(error.to_string()))? - .unwrap_or_default(); + let printer_flags = DataPrinterFlags::WITH_SIBLINGS; + let config = + data_tree_init(&nb_response.dtree, encoding, printer_flags)?; let grpc_response = proto::GetTransactionResponse { - config: Some(proto::DataTree { - encoding: encoding as i32, - data: config, - }), + config: Some(config), }; Ok(Response::new(grpc_response)) } @@ -472,7 +406,7 @@ impl TryFrom for api::DataType { } } -// ===== global functions ===== +// ===== helper functions ===== fn get_timestamp() -> i64 { SystemTime::now() @@ -481,6 +415,124 @@ fn get_timestamp() -> i64 { .as_secs() as i64 } +fn data_tree_init( + dtree: &DataTree, + encoding: proto::Encoding, + printer_flags: DataPrinterFlags, +) -> Result { + let data_format = DataFormat::from(encoding); + let data = match data_format { + DataFormat::JSON | DataFormat::XML => { + let string = dtree + .print_string(data_format, printer_flags) + .map_err(|error| Status::internal(error.to_string()))? + .unwrap_or_default(); + proto::data_tree::Data::DataString(string) + } + DataFormat::LYB => { + let bytes = dtree + .print_bytes(data_format, printer_flags) + .map_err(|error| Status::internal(error.to_string()))? + .unwrap_or_default(); + proto::data_tree::Data::DataBytes(bytes) + } + }; + + Ok(proto::DataTree { + encoding: encoding as i32, + data: Some(data), + }) +} + +fn data_tree_get(data_tree: &proto::DataTree) -> Result { + let yang_ctx = YANG_CTX.get().unwrap(); + let encoding = proto::Encoding::try_from(data_tree.encoding) + .map_err(|_| Status::invalid_argument("Invalid data encoding"))?; + let data_format = DataFormat::from(encoding); + let parser_flags = DataParserFlags::empty(); + let validation_flags = DataValidationFlags::NO_STATE; + let data = data_tree + .data + .as_ref() + .ok_or_else(|| Status::invalid_argument("Missing 'data' field"))?; + match data { + proto::data_tree::Data::DataString(data) => DataTree::parse_string( + yang_ctx, + data, + data_format, + parser_flags, + validation_flags, + ), + proto::data_tree::Data::DataBytes(data) => DataTree::parse_string( + yang_ctx, + data, + data_format, + parser_flags, + validation_flags, + ), + } + .map_err(|error| Status::invalid_argument(error.to_string())) +} + +fn data_diff_get(data_tree: &proto::DataTree) -> Result { + let yang_ctx = YANG_CTX.get().unwrap(); + let encoding = proto::Encoding::try_from(data_tree.encoding) + .map_err(|_| Status::invalid_argument("Invalid data encoding"))?; + let data_format = DataFormat::from(encoding); + let parser_flags = DataParserFlags::NO_VALIDATION; + let validation_flags = + DataValidationFlags::NO_STATE | DataValidationFlags::PRESENT; + let data = data_tree + .data + .as_ref() + .ok_or_else(|| Status::invalid_argument("Missing 'data' field"))?; + match data { + proto::data_tree::Data::DataString(data) => DataDiff::parse_string( + yang_ctx, + data, + data_format, + parser_flags, + validation_flags, + ), + proto::data_tree::Data::DataBytes(data) => DataDiff::parse_string( + yang_ctx, + data, + data_format, + parser_flags, + validation_flags, + ), + } + .map_err(|error| Status::invalid_argument(error.to_string())) +} + +fn rpc_get(data_tree: &proto::DataTree) -> Result { + let yang_ctx = YANG_CTX.get().unwrap(); + let encoding = proto::Encoding::try_from(data_tree.encoding) + .map_err(|_| Status::invalid_argument("Invalid data encoding"))?; + let data_format = DataFormat::from(encoding); + let data = data_tree + .data + .as_ref() + .ok_or_else(|| Status::invalid_argument("Missing 'data' field"))?; + match data { + proto::data_tree::Data::DataString(data) => DataTree::parse_op_string( + yang_ctx, + data, + data_format, + DataOperation::RpcYang, + ), + proto::data_tree::Data::DataBytes(data) => DataTree::parse_op_string( + yang_ctx, + data, + data_format, + DataOperation::RpcYang, + ), + } + .map_err(|error| Status::invalid_argument(error.to_string())) +} + +// ===== global functions ===== + pub(crate) fn start( config: &config::Grpc, request_tx: Sender, diff --git a/holo-daemon/src/northbound/core.rs b/holo-daemon/src/northbound/core.rs index 04c326ca..8ce98099 100644 --- a/holo-daemon/src/northbound/core.rs +++ b/holo-daemon/src/northbound/core.rs @@ -25,7 +25,7 @@ use pickledb::PickleDb; use serde::{Deserialize, Serialize}; use tokio::sync::{broadcast, mpsc, oneshot}; use tracing::{debug, error, info, instrument, trace, warn}; -use yang2::data::{ +use yang3::data::{ Data, DataDiffFlags, DataFormat, DataPrinterFlags, DataTree, DataValidationFlags, }; @@ -517,12 +517,20 @@ impl Northbound { // Gets a full or partial copy of the running configuration. fn get_configuration(&self, path: Option<&str>) -> Result { match path { - Some(path) => self - .running_config - .find_path(path) - .map_err(Error::YangInvalidPath)? - .duplicate(true) - .map_err(Error::YangInternal), + Some(path) => { + let yang_ctx = YANG_CTX.get().unwrap(); + let mut dtree = DataTree::new(yang_ctx); + for dnode in self + .running_config + .find_xpath(path) + .map_err(Error::YangInvalidPath)? + { + let subtree = + dnode.duplicate(true).map_err(Error::YangInternal)?; + dtree.merge(&subtree).map_err(Error::YangInternal)?; + } + Ok(dtree) + } None => { self.running_config.duplicate().map_err(Error::YangInternal) } @@ -631,7 +639,8 @@ fn start_providers( let ibus_rx_routing = ibus_tx.subscribe(); let ibus_rx_interface = ibus_tx.subscribe(); let ibus_rx_keychain = ibus_tx.subscribe(); - let ibus_rx_policy = ibus_rx; + let ibus_rx_policy = ibus_tx.subscribe(); + let ibus_rx_system = ibus_rx; let shared = InstanceShared { db: Some(db), @@ -673,6 +682,17 @@ fn start_providers( providers.push(daemon_tx); } + // Start holo-system. + #[cfg(feature = "system")] + { + let daemon_tx = holo_system::start( + provider_tx.clone(), + ibus_tx.clone(), + ibus_rx_system, + ); + providers.push(daemon_tx); + } + // Start holo-routing. #[cfg(feature = "routing")] { diff --git a/holo-daemon/src/northbound/error.rs b/holo-daemon/src/northbound/error.rs index b0d5cefd..8d85db40 100644 --- a/holo-daemon/src/northbound/error.rs +++ b/holo-daemon/src/northbound/error.rs @@ -16,9 +16,9 @@ pub type Result = std::result::Result; // #[derive(Debug)] pub enum Error { - YangInvalidPath(yang2::Error), - YangInvalidData(yang2::Error), - YangInternal(yang2::Error), + YangInvalidPath(yang3::Error), + YangInvalidData(yang3::Error), + YangInternal(yang3::Error), TransactionValidation(northbound::error::Error), TransactionPreparation(northbound::error::Error), TransactionIdNotFound(u32), diff --git a/holo-daemon/src/northbound/yang.rs b/holo-daemon/src/northbound/yang.rs index 42428cba..6b2eb26b 100644 --- a/holo-daemon/src/northbound/yang.rs +++ b/holo-daemon/src/northbound/yang.rs @@ -38,6 +38,9 @@ pub(crate) fn create_context() { #[cfg(feature = "policy")] modules_add::(&mut modules); + #[cfg(feature = "system")] + modules_add::(&mut modules); + // Add protocol modules based on enabled features. #[cfg(feature = "bfd")] { diff --git a/holo-interface/Cargo.toml b/holo-interface/Cargo.toml index 623974a2..1647af4c 100644 --- a/holo-interface/Cargo.toml +++ b/holo-interface/Cargo.toml @@ -21,7 +21,7 @@ regex.workspace = true rtnetlink.workspace = true tokio.workspace = true tracing.workspace = true -yang2.workspace = true +yang3.workspace = true holo-northbound = { path = "../holo-northbound" } holo-protocol = { path = "../holo-protocol" } diff --git a/holo-interface/src/netlink.rs b/holo-interface/src/netlink.rs index 5548b71e..7dd6b032 100644 --- a/holo-interface/src/netlink.rs +++ b/holo-interface/src/netlink.rs @@ -4,8 +4,6 @@ // SPDX-License-Identifier: MIT // -#![allow(clippy::single_match)] - use std::net::{Ipv4Addr, Ipv6Addr}; use capctl::caps::CapState; diff --git a/holo-keychain/Cargo.toml b/holo-keychain/Cargo.toml index a89a8e53..770dad1c 100644 --- a/holo-keychain/Cargo.toml +++ b/holo-keychain/Cargo.toml @@ -12,7 +12,7 @@ derive-new.workspace = true enum-as-inner.workspace = true tokio.workspace = true tracing.workspace = true -yang2.workspace = true +yang3.workspace = true holo-northbound = { path = "../holo-northbound" } holo-utils = { path = "../holo-utils" } diff --git a/holo-keychain/src/northbound/state.rs b/holo-keychain/src/northbound/state.rs index 589d0909..6a9bdde5 100644 --- a/holo-keychain/src/northbound/state.rs +++ b/holo-keychain/src/northbound/state.rs @@ -4,6 +4,7 @@ // SPDX-License-Identifier: MIT // +use std::borrow::Cow; use std::sync::LazyLock as Lazy; use enum_as_inner::EnumAsInner; @@ -40,7 +41,10 @@ fn load_callbacks() -> Callbacks { let keychain = args.list_entry.as_keychain().unwrap(); Box::new(KeyChain { name: keychain.name.as_str().into(), - last_modified_timestamp: keychain.last_modified.as_ref(), + last_modified_timestamp: keychain + .last_modified + .as_ref() + .map(Cow::Borrowed), }) }) .path(key_chains::key_chain::key::PATH) diff --git a/holo-ldp/Cargo.toml b/holo-ldp/Cargo.toml index 989f91e4..d8e032c2 100644 --- a/holo-ldp/Cargo.toml +++ b/holo-ldp/Cargo.toml @@ -24,7 +24,7 @@ serde_with.workspace = true socket2.workspace = true tokio.workspace = true tracing.workspace = true -yang2.workspace = true +yang3.workspace = true holo-northbound = { path = "../holo-northbound" } holo-protocol = { path = "../holo-protocol" } diff --git a/holo-ldp/src/northbound/rpc.rs b/holo-ldp/src/northbound/rpc.rs index 2076ffea..25326ebd 100644 --- a/holo-ldp/src/northbound/rpc.rs +++ b/holo-ldp/src/northbound/rpc.rs @@ -10,7 +10,7 @@ use std::sync::LazyLock as Lazy; use holo_northbound::rpc::{Callbacks, CallbacksBuilder, Provider}; use holo_northbound::yang; use holo_utils::yang::DataNodeRefExt; -use yang2::data::Data; +use yang3::data::Data; use crate::discovery; use crate::instance::{Instance, InstanceUpView}; diff --git a/holo-ldp/src/northbound/state.rs b/holo-ldp/src/northbound/state.rs index f4155f0a..72c46a08 100644 --- a/holo-ldp/src/northbound/state.rs +++ b/holo-ldp/src/northbound/state.rs @@ -211,7 +211,7 @@ fn load_callbacks() -> Callbacks { use mpls_ldp::discovery::interfaces::interface::address_families::ipv4::hello_adjacencies::hello_adjacency::statistics::Statistics; let adj = args.list_entry.as_interface_adj().unwrap(); Box::new(Statistics { - discontinuity_time: Some(&adj.discontinuity_time).ignore_in_testing(), + discontinuity_time: Some(Cow::Borrowed(&adj.discontinuity_time)).ignore_in_testing(), hello_received: Some(adj.hello_rcvd).ignore_in_testing(), hello_dropped: Some(adj.hello_dropped).ignore_in_testing(), }) @@ -256,7 +256,7 @@ fn load_callbacks() -> Callbacks { use mpls_ldp::discovery::targeted::address_families::ipv4::hello_adjacencies::hello_adjacency::statistics::Statistics; let adj = args.list_entry.as_targeted_nbr_adj().unwrap(); Box::new(Statistics { - discontinuity_time: Some(&adj.discontinuity_time).ignore_in_testing(), + discontinuity_time: Some(Cow::Borrowed(&adj.discontinuity_time)).ignore_in_testing(), hello_received: Some(adj.hello_rcvd).ignore_in_testing(), hello_dropped: Some(adj.hello_dropped).ignore_in_testing(), }) @@ -318,7 +318,7 @@ fn load_callbacks() -> Callbacks { use mpls_ldp::peers::peer::address_families::ipv4::hello_adjacencies::hello_adjacency::statistics::Statistics; let adj = args.list_entry.as_neighbor_adj().unwrap(); Box::new(Statistics { - discontinuity_time: Some(&adj.discontinuity_time).ignore_in_testing(), + discontinuity_time: Some(Cow::Borrowed(&adj.discontinuity_time)).ignore_in_testing(), hello_received: Some(adj.hello_rcvd).ignore_in_testing(), hello_dropped: Some(adj.hello_dropped).ignore_in_testing(), }) @@ -388,7 +388,7 @@ fn load_callbacks() -> Callbacks { let total_labels = nbr.rcvd_mappings.len(); let total_fec_label_bindings = nbr.rcvd_mappings.keys().map(|prefix| instance.state.as_ref().unwrap().fecs.get(prefix).unwrap()).filter(|fec| fec.is_nbr_nexthop(nbr)).count(); Box::new(Statistics { - discontinuity_time: nbr.statistics.discontinuity_time.as_ref().ignore_in_testing(), + discontinuity_time: nbr.statistics.discontinuity_time.as_ref().map(Cow::Borrowed).ignore_in_testing(), total_addresses: Some(total_addresses.saturating_into()), total_labels: Some(total_labels.saturating_into()), total_fec_label_bindings: Some(total_fec_label_bindings.saturating_into()), diff --git a/holo-northbound/Cargo.toml b/holo-northbound/Cargo.toml index 2cec32d9..18760f31 100644 --- a/holo-northbound/Cargo.toml +++ b/holo-northbound/Cargo.toml @@ -17,7 +17,7 @@ serde.workspace = true serde_json.workspace = true tokio.workspace = true tracing.workspace = true -yang2.workspace = true +yang3.workspace = true holo-utils = { path = "../holo-utils" } holo-yang = { path = "../holo-yang" } @@ -28,7 +28,7 @@ holo-utils = { path = "../holo-utils" } [build-dependencies] check_keyword.workspace = true convert_case.workspace = true -yang2.workspace = true +yang3.workspace = true holo-yang = { path = "../holo-yang" } [lints] diff --git a/holo-northbound/build.rs b/holo-northbound/build.rs index 0a99d620..2869f292 100644 --- a/holo-northbound/build.rs +++ b/holo-northbound/build.rs @@ -14,7 +14,7 @@ use check_keyword::CheckKeyword; use convert_case::{Boundary, Case, Casing}; use holo_yang as yang; use holo_yang::YANG_IMPLEMENTED_MODULES; -use yang2::schema::{ +use yang3::schema::{ DataValue, DataValueType, SchemaLeafType, SchemaNode, SchemaNodeKind, SchemaPathFormat, }; @@ -28,8 +28,8 @@ use chrono::{DateTime, Utc}; use holo_yang::{YangObject, YangPath, YANG_CTX}; use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network}; use itertools::Itertools; -use yang2::data::DataNodeRef; -use yang2::schema::SchemaModule; +use yang3::data::DataNodeRef; +use yang3::schema::SchemaModule; fn binary_to_yang(value: &[u8]) -> String { use base64::Engine; @@ -399,7 +399,7 @@ fn leaf_typedef_map(leaf_type: &SchemaLeafType<'_>) -> Option<&'static str> { Some("ip-prefix") => Some("Cow<'a, IpNetwork>"), Some("ipv4-prefix") => Some("Cow<'a, Ipv4Network>"), Some("ipv6-prefix") => Some("Cow<'a, Ipv6Network>"), - Some("date-and-time") => Some("&'a DateTime"), + Some("date-and-time") => Some("Cow<'a, DateTime>"), Some("timer-value-seconds16") => Some("Cow<'a, Duration>"), Some("timer-value-seconds32") => Some("Cow<'a, Duration>"), Some("timer-value-milliseconds") => Some("Cow<'a, Duration>"), @@ -552,15 +552,11 @@ fn generate_module(output: &mut String, snode: &SchemaNode<'_>, level: usize) { } // Iterate over child nodes. - if let Some(actions) = snode.actions() { - for snode in actions { - generate_module(output, &snode, level + 1); - } + for snode in snode.actions() { + generate_module(output, &snode, level + 1); } - if let Some(notifications) = snode.notifications() { - for snode in notifications { - generate_module(output, &snode, level + 1); - } + for snode in snode.notifications() { + generate_module(output, &snode, level + 1); } for snode in snode.children().filter(|snode| snode.is_status_current()) { writeln!(output).unwrap(); diff --git a/holo-northbound/src/api.rs b/holo-northbound/src/api.rs index 625d717f..d02c7903 100644 --- a/holo-northbound/src/api.rs +++ b/holo-northbound/src/api.rs @@ -9,7 +9,7 @@ use std::sync::Arc; use holo_utils::Responder; use serde::{Deserialize, Serialize}; -use yang2::data::DataTree; +use yang3::data::DataTree; use crate::configuration::{CommitPhase, ConfigChanges}; use crate::error::Error; diff --git a/holo-northbound/src/configuration.rs b/holo-northbound/src/configuration.rs index c4736860..4bddd0e6 100644 --- a/holo-northbound/src/configuration.rs +++ b/holo-northbound/src/configuration.rs @@ -12,8 +12,8 @@ use holo_utils::yang::SchemaNodeExt; use holo_yang::YangPath; use serde::{Deserialize, Serialize}; use tokio::sync::oneshot; -use yang2::data::{Data, DataDiff, DataDiffOp, DataNodeRef, DataTree}; -use yang2::schema::SchemaNodeKind; +use yang3::data::{Data, DataDiff, DataDiffOp, DataNodeRef, DataTree}; +use yang3::schema::SchemaNodeKind; use crate::debug::Debug; use crate::error::Error; diff --git a/holo-northbound/src/error.rs b/holo-northbound/src/error.rs index a49fc87f..0dfaf36d 100644 --- a/holo-northbound/src/error.rs +++ b/holo-northbound/src/error.rs @@ -14,8 +14,8 @@ pub enum Error { RpcNotFound, RpcRelay(String), RpcCallback(String), - YangInvalidPath(yang2::Error), - YangInvalidData(yang2::Error), + YangInvalidPath(yang3::Error), + YangInvalidData(yang3::Error), } // ===== impl Error ===== diff --git a/holo-northbound/src/lib.rs b/holo-northbound/src/lib.rs index b85af914..822f5b52 100644 --- a/holo-northbound/src/lib.rs +++ b/holo-northbound/src/lib.rs @@ -24,7 +24,7 @@ use derive_new::new; use holo_utils::{Receiver, Sender, UnboundedReceiver, UnboundedSender}; use serde::{Deserialize, Serialize}; use tracing::Span; -use yang2::schema::{DataValueType, SchemaNode, SchemaNodeKind}; +use yang3::schema::{DataValueType, SchemaNode, SchemaNodeKind}; use crate::debug::Debug; diff --git a/holo-northbound/src/notification.rs b/holo-northbound/src/notification.rs index 90a427ec..e7363245 100644 --- a/holo-northbound/src/notification.rs +++ b/holo-northbound/src/notification.rs @@ -5,7 +5,7 @@ // use holo_yang::{YangObject, YANG_CTX}; -use yang2::data::DataTree; +use yang3::data::DataTree; use crate::api::provider::Notification; use crate::NbProviderSender; diff --git a/holo-northbound/src/rpc.rs b/holo-northbound/src/rpc.rs index f2919eb3..61fffd30 100644 --- a/holo-northbound/src/rpc.rs +++ b/holo-northbound/src/rpc.rs @@ -11,8 +11,8 @@ use std::pin::Pin; use holo_utils::yang::SchemaNodeExt; use holo_yang::YangPath; use tokio::sync::oneshot; -use yang2::data::{DataNodeRef, DataTree}; -use yang2::schema::SchemaNodeKind; +use yang3::data::{DataNodeRef, DataTree}; +use yang3::schema::SchemaNodeKind; use crate::debug::Debug; use crate::error::Error; diff --git a/holo-northbound/src/state.rs b/holo-northbound/src/state.rs index eb75a57b..29af0947 100644 --- a/holo-northbound/src/state.rs +++ b/holo-northbound/src/state.rs @@ -11,8 +11,8 @@ use derive_new::new; use holo_utils::yang::SchemaNodeExt; use holo_yang::{YangObject, YangPath, YANG_CTX}; use tokio::sync::oneshot; -use yang2::data::{DataNodeRef, DataTree}; -use yang2::schema::{SchemaModule, SchemaNode, SchemaNodeKind}; +use yang3::data::{DataNodeRef, DataTree}; +use yang3::schema::{SchemaModule, SchemaNode, SchemaNodeKind}; use crate::error::Error; use crate::{api, CallbackKey, CallbackOp, NbDaemonSender, ProviderBase}; diff --git a/holo-ospf/Cargo.toml b/holo-ospf/Cargo.toml index 08579d34..21569b02 100644 --- a/holo-ospf/Cargo.toml +++ b/holo-ospf/Cargo.toml @@ -33,7 +33,7 @@ smallvec.workspace = true socket2.workspace = true tokio.workspace = true tracing.workspace = true -yang2.workspace = true +yang3.workspace = true holo-northbound = { path = "../holo-northbound" } holo-protocol = { path = "../holo-protocol" } diff --git a/holo-ospf/src/network.rs b/holo-ospf/src/network.rs index cc2ef95b..eb16e425 100644 --- a/holo-ospf/src/network.rs +++ b/holo-ospf/src/network.rs @@ -212,7 +212,7 @@ where .address .as_ref() .map(|addr| V::src_from_sockaddr(addr)); - let dst = V::get_cmsg_data(msg.cmsgs()); + let dst = V::get_cmsg_data(msg.cmsgs().unwrap()); Ok((src, dst, msg.bytes)) } Err(errno) => Err(errno.into()), diff --git a/holo-ospf/src/northbound/configuration.rs b/holo-ospf/src/northbound/configuration.rs index 06cca84e..641e05b3 100644 --- a/holo-ospf/src/northbound/configuration.rs +++ b/holo-ospf/src/northbound/configuration.rs @@ -21,7 +21,7 @@ use holo_utils::ibus::IbusMsg; use holo_utils::ip::{AddressFamily, IpAddrKind, IpNetworkKind}; use holo_utils::yang::DataNodeRefExt; use holo_yang::{ToYang, TryFromYang}; -use yang2::data::Data; +use yang3::data::Data; use crate::area::{self, AreaType}; use crate::collections::{AreaIndex, InterfaceIndex}; diff --git a/holo-ospf/src/northbound/rpc.rs b/holo-ospf/src/northbound/rpc.rs index 9c50f882..b5ff5a61 100644 --- a/holo-ospf/src/northbound/rpc.rs +++ b/holo-ospf/src/northbound/rpc.rs @@ -9,7 +9,7 @@ use std::sync::LazyLock as Lazy; use holo_northbound::rpc::{Callbacks, CallbacksBuilder, Provider}; use holo_northbound::yang; use holo_utils::yang::DataNodeRefExt; -use yang2::data::Data; +use yang3::data::Data; use crate::instance::{Instance, InstanceArenas, InstanceUpView}; use crate::neighbor::nsm; diff --git a/holo-ospf/src/northbound/state.rs b/holo-ospf/src/northbound/state.rs index 09c133a1..35aaa3da 100644 --- a/holo-ospf/src/northbound/state.rs +++ b/holo-ospf/src/northbound/state.rs @@ -5,6 +5,7 @@ // use std::borrow::Cow; +use std::collections::BTreeMap; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::sync::LazyLock as Lazy; use std::time::Instant; @@ -18,6 +19,7 @@ use holo_utils::ip::IpAddrKind; use holo_utils::num::SaturatingInto; use holo_utils::option::OptionExt; use holo_utils::protocol::Protocol; +use holo_utils::sr::IgpAlgoType; use holo_yang::{ToYang, ToYangBits}; use num_traits::FromPrimitive; @@ -75,8 +77,10 @@ pub enum ListEntry<'a, V: Version> { // OSPFv3 Ospfv3RouterLsaLink(&'a ospfv3::packet::lsa::LsaRouterLink), Ospfv3LinkLsaPrefix(&'a ospfv3::packet::lsa::LsaLinkPrefix), + Ospfv3AdjSids(&'a Vec), Ospfv3AdjSid(&'a ospfv3::packet::lsa::AdjSid), Ospfv3IntraAreaLsaPrefix(&'a ospfv3::packet::lsa::LsaIntraAreaPrefixEntry), + Ospfv3PrefixSids(&'a BTreeMap), Ospfv3PrefixSid(&'a ospfv3::packet::lsa::PrefixSid), Ospfv3LinkLocalAddr(IpAddr), } @@ -161,7 +165,7 @@ where let mut as_scope_lsa_count = None; let mut as_scope_lsa_chksum_sum = None; if let Some(state) = &instance.state { - discontinuity_time = Some(&state.discontinuity_time).ignore_in_testing(); + discontinuity_time = Some(Cow::Borrowed(&state.discontinuity_time)).ignore_in_testing(); originate_new_lsa_count = Some(state.orig_lsa_count).ignore_in_testing(); rx_new_lsas_count = Some(state.rx_lsa_count).ignore_in_testing(); as_scope_lsa_count = Some(state.lsdb.lsa_count()); @@ -299,7 +303,7 @@ where use ospf::areas::area::statistics::Statistics; let area = args.list_entry.as_area().unwrap(); Box::new(Statistics { - discontinuity_time: Some(&area.state.discontinuity_time).ignore_in_testing(), + discontinuity_time: Some(Cow::Borrowed(&area.state.discontinuity_time)).ignore_in_testing(), spf_runs_count: Some(area.state.spf_run_count).ignore_in_testing(), abr_count: Some(area.abr_count() as _), asbr_count: Some(area.asbr_count() as _), @@ -403,7 +407,7 @@ where use ospf::areas::area::interfaces::interface::statistics::Statistics; let iface = args.list_entry.as_interface().unwrap(); Box::new(Statistics { - discontinuity_time: Some(&iface.state.discontinuity_time).ignore_in_testing(), + discontinuity_time: Some(Cow::Borrowed(&iface.state.discontinuity_time)).ignore_in_testing(), if_event_count: Some(iface.state.event_count).ignore_in_testing(), link_scope_lsa_count: Some(iface.state.lsdb.lsa_count()), link_scope_lsa_cksum_sum: Some(iface.state.lsdb.cksum_sum()).ignore_in_testing(), @@ -481,7 +485,7 @@ where use ospf::areas::area::interfaces::interface::neighbors::neighbor::statistics::Statistics; let (_, nbr) = args.list_entry.as_neighbor().unwrap(); Box::new(Statistics { - discontinuity_time: Some(&nbr.discontinuity_time).ignore_in_testing(), + discontinuity_time: Some(Cow::Borrowed(&nbr.discontinuity_time)).ignore_in_testing(), nbr_event_count: Some(nbr.event_count).ignore_in_testing(), nbr_retrans_qlen: Some(nbr.lists.ls_rxmt.len() as u32), }) @@ -1958,28 +1962,23 @@ fn load_callbacks_ospfv3() -> Callbacks> { value: Some(tlv.value.as_ref()), }) }) - .path(ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv3::body::e_as_external::e_external_tlvs::external_prefix_tlv::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::PATH) + .path(ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv3::body::e_as_external::e_external_tlvs::external_prefix_tlv::sub_tlvs::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::PATH) .get_iterate(|_instance, args| { - let lse: &LsaEntry = args.parent_list_entry.as_as_lsa().unwrap(); - let lsa = &lse.data; - if let Some(lsa_body) = lsa.body.as_ext_as_external() { - let iter = lsa_body.prefix_sids.values().map(ListEntry::Ospfv3PrefixSid); - Some(Box::new(iter)) - } else { - None - } + let prefix_sids = args.parent_list_entry.as_ospfv3_prefix_sids()?; + let iter = prefix_sids.values().map(ListEntry::Ospfv3PrefixSid); + Some(Box::new(iter)) }) .get_object(|_instance, args| { - use ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv3::body::e_as_external::e_external_tlvs::external_prefix_tlv::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::PrefixSidSubTlv; + use ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv3::body::e_as_external::e_external_tlvs::external_prefix_tlv::sub_tlvs::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::PrefixSidSubTlv; let prefix_sid = args.list_entry.as_ospfv3_prefix_sid().unwrap(); Box::new(PrefixSidSubTlv { algorithm: Some(prefix_sid.algo.to_yang()), sid: Some(prefix_sid.sid.value()), }) }) - .path(ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv3::body::e_as_external::e_external_tlvs::external_prefix_tlv::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::ospfv3_prefix_sid_flags::PATH) + .path(ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv3::body::e_as_external::e_external_tlvs::external_prefix_tlv::sub_tlvs::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::ospfv3_prefix_sid_flags::PATH) .get_object(|_instance, args| { - use ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv3::body::e_as_external::e_external_tlvs::external_prefix_tlv::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::ospfv3_prefix_sid_flags::Ospfv3PrefixSidFlags; + use ospf::database::as_scope_lsa_type::as_scope_lsas::as_scope_lsa::ospfv3::body::e_as_external::e_external_tlvs::external_prefix_tlv::sub_tlvs::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::ospfv3_prefix_sid_flags::Ospfv3PrefixSidFlags; let prefix_sid = args.list_entry.as_ospfv3_prefix_sid().unwrap(); let iter = prefix_sid.flags.to_yang_bits().into_iter().map(Cow::Borrowed); Box::new(Ospfv3PrefixSidFlags { @@ -2390,7 +2389,7 @@ fn load_callbacks_ospfv3() -> Callbacks> { .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::sub_tlvs::PATH) .get_iterate(|_instance, args| { let tlv = args.parent_list_entry.as_ospfv3_router_lsa_link().unwrap(); - let iter = tlv.unknown_stlvs.iter().map(ListEntry::UnknownTlv); + let iter = tlv.unknown_stlvs.iter().map(ListEntry::UnknownTlv).chain(std::iter::once(ListEntry::Ospfv3AdjSids(&tlv.adj_sids))); Some(Box::new(iter)) }) .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::sub_tlvs::unknown_sub_tlv::PATH) @@ -2403,37 +2402,37 @@ fn load_callbacks_ospfv3() -> Callbacks> { value: Some(tlv.value.as_ref()), }) }) - .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::adj_sid_sub_tlvs::adj_sid_sub_tlv::PATH) + .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::sub_tlvs::adj_sid_sub_tlvs::adj_sid_sub_tlv::PATH) .get_iterate(|_instance, args| { - let rtr_link = args.parent_list_entry.as_ospfv3_router_lsa_link().unwrap(); - let iter = rtr_link.adj_sids.iter().filter(|adj_sid| adj_sid.nbr_router_id.is_none()).map(ListEntry::Ospfv3AdjSid); + let adj_sids = args.parent_list_entry.as_ospfv3_adj_sids()?; + let iter = adj_sids.iter().filter(|adj_sid| adj_sid.nbr_router_id.is_none()).map(ListEntry::Ospfv3AdjSid); Some(Box::new(iter)) }) .get_object(|_instance, args| { - use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::adj_sid_sub_tlvs::adj_sid_sub_tlv::AdjSidSubTlv; + use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::sub_tlvs::adj_sid_sub_tlvs::adj_sid_sub_tlv::AdjSidSubTlv; let adj_sid = args.list_entry.as_ospfv3_adj_sid().unwrap(); Box::new(AdjSidSubTlv { weight: Some(adj_sid.weight), sid: Some(adj_sid.sid.value()), }) }) - .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::adj_sid_sub_tlvs::adj_sid_sub_tlv::adj_sid_flags::PATH) + .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::sub_tlvs::adj_sid_sub_tlvs::adj_sid_sub_tlv::adj_sid_flags::PATH) .get_object(|_instance, args| { - use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::adj_sid_sub_tlvs::adj_sid_sub_tlv::adj_sid_flags::AdjSidFlags; + use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::sub_tlvs::adj_sid_sub_tlvs::adj_sid_sub_tlv::adj_sid_flags::AdjSidFlags; let adj_sid = args.list_entry.as_ospfv3_adj_sid().unwrap(); let iter = adj_sid.flags.to_yang_bits().into_iter().map(Cow::Borrowed); Box::new(AdjSidFlags { flags: Some(Box::new(iter)), }) }) - .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::lan_adj_sid_sub_tlvs::lan_adj_sid_sub_tlv::PATH) + .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::sub_tlvs::lan_adj_sid_sub_tlvs::lan_adj_sid_sub_tlv::PATH) .get_iterate(|_instance, args| { - let rtr_link = args.parent_list_entry.as_ospfv3_router_lsa_link().unwrap(); - let iter = rtr_link.adj_sids.iter().filter(|adj_sid| adj_sid.nbr_router_id.is_some()).map(ListEntry::Ospfv3AdjSid); + let adj_sids = args.parent_list_entry.as_ospfv3_adj_sids()?; + let iter = adj_sids.iter().filter(|adj_sid| adj_sid.nbr_router_id.is_some()).map(ListEntry::Ospfv3AdjSid); Some(Box::new(iter)) }) .get_object(|_instance, args| { - use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::lan_adj_sid_sub_tlvs::lan_adj_sid_sub_tlv::LanAdjSidSubTlv; + use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::sub_tlvs::lan_adj_sid_sub_tlvs::lan_adj_sid_sub_tlv::LanAdjSidSubTlv; let adj_sid = args.list_entry.as_ospfv3_adj_sid().unwrap(); Box::new(LanAdjSidSubTlv { weight: Some(adj_sid.weight), @@ -2441,9 +2440,9 @@ fn load_callbacks_ospfv3() -> Callbacks> { sid: Some(adj_sid.sid.value()), }) }) - .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::lan_adj_sid_sub_tlvs::lan_adj_sid_sub_tlv::lan_adj_sid_flags::PATH) + .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::sub_tlvs::lan_adj_sid_sub_tlvs::lan_adj_sid_sub_tlv::lan_adj_sid_flags::PATH) .get_object(|_instance, args| { - use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::lan_adj_sid_sub_tlvs::lan_adj_sid_sub_tlv::lan_adj_sid_flags::LanAdjSidFlags; + use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_router::e_router_tlvs::link_tlv::sub_tlvs::lan_adj_sid_sub_tlvs::lan_adj_sid_sub_tlv::lan_adj_sid_flags::LanAdjSidFlags; let adj_sid = args.list_entry.as_ospfv3_adj_sid().unwrap(); let iter = adj_sid.flags.to_yang_bits().into_iter().map(Cow::Borrowed); Box::new(LanAdjSidFlags { @@ -2548,8 +2547,8 @@ fn load_callbacks_ospfv3() -> Callbacks> { .get_iterate(|_instance, args| { let lse: &LsaEntry = args.parent_list_entry.as_area_lsa().unwrap(); let lsa = &lse.data; - if let Some(lsa_body) = lsa.body.as_ext_inter_area_router() { - let iter = lsa_body.unknown_stlvs.iter().map(ListEntry::UnknownTlv); + if let Some(lsa_body) = lsa.body.as_ext_inter_area_prefix() { + let iter = lsa_body.unknown_stlvs.iter().map(ListEntry::UnknownTlv).chain(std::iter::once(ListEntry::Ospfv3PrefixSids(&lsa_body.prefix_sids))); Some(Box::new(iter)) } else { None @@ -2565,28 +2564,23 @@ fn load_callbacks_ospfv3() -> Callbacks> { value: Some(tlv.value.as_ref()), }) }) - .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_inter_area_prefix::e_inter_prefix_tlvs::inter_prefix_tlv::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::PATH) + .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_inter_area_prefix::e_inter_prefix_tlvs::inter_prefix_tlv::sub_tlvs::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::PATH) .get_iterate(|_instance, args| { - let lse: &LsaEntry = args.parent_list_entry.as_area_lsa().unwrap(); - let lsa = &lse.data; - if let Some(lsa_body) = lsa.body.as_ext_inter_area_prefix() { - let iter = lsa_body.prefix_sids.values().map(ListEntry::Ospfv3PrefixSid); - Some(Box::new(iter)) - } else { - None - } + let prefix_sids = args.parent_list_entry.as_ospfv3_prefix_sids()?; + let iter = prefix_sids.values().map(ListEntry::Ospfv3PrefixSid); + Some(Box::new(iter)) }) .get_object(|_instance, args| { - use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_inter_area_prefix::e_inter_prefix_tlvs::inter_prefix_tlv::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::PrefixSidSubTlv; + use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_inter_area_prefix::e_inter_prefix_tlvs::inter_prefix_tlv::sub_tlvs::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::PrefixSidSubTlv; let prefix_sid = args.list_entry.as_ospfv3_prefix_sid().unwrap(); Box::new(PrefixSidSubTlv { algorithm: Some(prefix_sid.algo.to_yang()), sid: Some(prefix_sid.sid.value()), }) }) - .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_inter_area_prefix::e_inter_prefix_tlvs::inter_prefix_tlv::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::ospfv3_prefix_sid_flags::PATH) + .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_inter_area_prefix::e_inter_prefix_tlvs::inter_prefix_tlv::sub_tlvs::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::ospfv3_prefix_sid_flags::PATH) .get_object(|_instance, args| { - use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_inter_area_prefix::e_inter_prefix_tlvs::inter_prefix_tlv::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::ospfv3_prefix_sid_flags::Ospfv3PrefixSidFlags; + use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_inter_area_prefix::e_inter_prefix_tlvs::inter_prefix_tlv::sub_tlvs::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::ospfv3_prefix_sid_flags::Ospfv3PrefixSidFlags; let prefix_sid = args.list_entry.as_ospfv3_prefix_sid().unwrap(); let iter = prefix_sid.flags.to_yang_bits().into_iter().map(Cow::Borrowed); Box::new(Ospfv3PrefixSidFlags { @@ -2726,7 +2720,7 @@ fn load_callbacks_ospfv3() -> Callbacks> { .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_intra_area_prefix::e_intra_prefix_tlvs::intra_prefix_tlv::sub_tlvs::PATH) .get_iterate(|_instance, args| { let prefix = args.parent_list_entry.as_ospfv3_intra_area_lsa_prefix().unwrap(); - let iter = prefix.unknown_stlvs.iter().map(ListEntry::UnknownTlv); + let iter = prefix.unknown_stlvs.iter().map(ListEntry::UnknownTlv).chain(std::iter::once(ListEntry::Ospfv3PrefixSids(&prefix.prefix_sids))); Some(Box::new(iter)) }) .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_intra_area_prefix::e_intra_prefix_tlvs::intra_prefix_tlv::sub_tlvs::unknown_sub_tlv::PATH) @@ -2739,23 +2733,23 @@ fn load_callbacks_ospfv3() -> Callbacks> { value: Some(tlv.value.as_ref()), }) }) - .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_intra_area_prefix::e_intra_prefix_tlvs::intra_prefix_tlv::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::PATH) + .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_intra_area_prefix::e_intra_prefix_tlvs::intra_prefix_tlv::sub_tlvs::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::PATH) .get_iterate(|_instance, args| { - let prefix = args.parent_list_entry.as_ospfv3_intra_area_lsa_prefix().unwrap(); - let iter = prefix.prefix_sids.values().map(ListEntry::Ospfv3PrefixSid); + let prefix_sids = args.parent_list_entry.as_ospfv3_prefix_sids()?; + let iter = prefix_sids.values().map(ListEntry::Ospfv3PrefixSid); Some(Box::new(iter)) }) .get_object(|_instance, args| { - use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_intra_area_prefix::e_intra_prefix_tlvs::intra_prefix_tlv::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::PrefixSidSubTlv; + use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_intra_area_prefix::e_intra_prefix_tlvs::intra_prefix_tlv::sub_tlvs::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::PrefixSidSubTlv; let prefix_sid = args.list_entry.as_ospfv3_prefix_sid().unwrap(); Box::new(PrefixSidSubTlv { algorithm: Some(prefix_sid.algo.to_yang()), sid: Some(prefix_sid.sid.value()), }) }) - .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_intra_area_prefix::e_intra_prefix_tlvs::intra_prefix_tlv::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::ospfv3_prefix_sid_flags::PATH) + .path(ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_intra_area_prefix::e_intra_prefix_tlvs::intra_prefix_tlv::sub_tlvs::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::ospfv3_prefix_sid_flags::PATH) .get_object(|_instance, args| { - use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_intra_area_prefix::e_intra_prefix_tlvs::intra_prefix_tlv::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::ospfv3_prefix_sid_flags::Ospfv3PrefixSidFlags; + use ospf::areas::area::database::area_scope_lsa_type::area_scope_lsas::area_scope_lsa::ospfv3::body::e_intra_area_prefix::e_intra_prefix_tlvs::intra_prefix_tlv::sub_tlvs::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::ospfv3_prefix_sid_flags::Ospfv3PrefixSidFlags; let prefix_sid = args.list_entry.as_ospfv3_prefix_sid().unwrap(); let iter = prefix_sid.flags.to_yang_bits().into_iter().map(Cow::Borrowed); Box::new(Ospfv3PrefixSidFlags { @@ -3082,10 +3076,10 @@ fn load_callbacks_ospfv3() -> Callbacks> { value: Some(tlv.value.as_ref()), }) }) - .path(ospf::areas::area::interfaces::interface::database::link_scope_lsa_type::link_scope_lsas::link_scope_lsa::ospfv3::body::e_link::e_link_tlvs::intra_prefix_tlv::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::PATH) + .path(ospf::areas::area::interfaces::interface::database::link_scope_lsa_type::link_scope_lsas::link_scope_lsa::ospfv3::body::e_link::e_link_tlvs::intra_prefix_tlv::sub_tlvs::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::PATH) .get_iterate(|_instance, _args| None) .get_object(|_instance, _args| unreachable!()) - .path(ospf::areas::area::interfaces::interface::database::link_scope_lsa_type::link_scope_lsas::link_scope_lsa::ospfv3::body::e_link::e_link_tlvs::intra_prefix_tlv::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::ospfv3_prefix_sid_flags::PATH) + .path(ospf::areas::area::interfaces::interface::database::link_scope_lsa_type::link_scope_lsas::link_scope_lsa::ospfv3::body::e_link::e_link_tlvs::intra_prefix_tlv::sub_tlvs::prefix_sid_sub_tlvs::prefix_sid_sub_tlv::ospfv3_prefix_sid_flags::PATH) .get_object(|_instance, _args| unreachable!()) .path(ospf::areas::area::interfaces::interface::database::link_scope_lsa_type::link_scope_lsas::link_scope_lsa::ospfv3::body::e_link::e_link_tlvs::ipv6_link_local_addr_tlv::PATH) .get_object(|_instance, args| { diff --git a/holo-ospf/src/ospfv2/network.rs b/holo-ospf/src/ospfv2/network.rs index 4e3d7dec..dfb9442a 100644 --- a/holo-ospf/src/ospfv2/network.rs +++ b/holo-ospf/src/ospfv2/network.rs @@ -147,7 +147,7 @@ impl NetworkVersion for Ospfv2 { } fn src_from_sockaddr(sockaddr: &SockaddrIn) -> Ipv4Addr { - Ipv4Addr::from(sockaddr.ip()) + sockaddr.ip() } fn validate_ip_hdr(buf: &mut Bytes) -> DecodeResult<()> { diff --git a/holo-policy/Cargo.toml b/holo-policy/Cargo.toml index cda5c469..71385e1c 100644 --- a/holo-policy/Cargo.toml +++ b/holo-policy/Cargo.toml @@ -11,7 +11,7 @@ derive-new.workspace = true enum-as-inner.workspace = true tokio.workspace = true tracing.workspace = true -yang2.workspace = true +yang3.workspace = true holo-northbound = { path = "../holo-northbound" } holo-utils = { path = "../holo-utils" } diff --git a/holo-protocol/Cargo.toml b/holo-protocol/Cargo.toml index 395e07f5..2dff9b45 100644 --- a/holo-protocol/Cargo.toml +++ b/holo-protocol/Cargo.toml @@ -13,7 +13,7 @@ serde_json.workspace = true tokio.workspace = true tracing.workspace = true tracing-subscriber.workspace = true -yang2.workspace = true +yang3.workspace = true holo-northbound = { path = "../holo-northbound" } holo-utils = { path = "../holo-utils" } diff --git a/holo-protocol/src/test/stub/collector.rs b/holo-protocol/src/test/stub/collector.rs index dc01bbc1..0b3224d5 100644 --- a/holo-protocol/src/test/stub/collector.rs +++ b/holo-protocol/src/test/stub/collector.rs @@ -9,7 +9,7 @@ use std::sync::{Arc, Mutex}; use holo_northbound::NbProviderReceiver; use holo_utils::ibus::IbusReceiver; use holo_utils::Receiver; -use yang2::data::{Data, DataFormat, DataPrinterFlags}; +use yang3::data::{Data, DataFormat, DataPrinterFlags}; use crate::ProtocolInstance; diff --git a/holo-protocol/src/test/stub/northbound.rs b/holo-protocol/src/test/stub/northbound.rs index fc31793f..3ae8b1e1 100644 --- a/holo-protocol/src/test/stub/northbound.rs +++ b/holo-protocol/src/test/stub/northbound.rs @@ -10,7 +10,7 @@ use holo_northbound::configuration::{self, CommitPhase, ConfigChanges}; use holo_northbound::{api, NbDaemonSender}; use holo_yang::YANG_CTX; use tokio::sync::oneshot; -use yang2::data::{ +use yang3::data::{ Data, DataDiff, DataDiffFlags, DataFormat, DataOperation, DataParserFlags, DataPrinterFlags, DataTree, DataValidationFlags, }; diff --git a/holo-rip/Cargo.toml b/holo-rip/Cargo.toml index ca115a5d..b537a276 100644 --- a/holo-rip/Cargo.toml +++ b/holo-rip/Cargo.toml @@ -24,7 +24,7 @@ serde.workspace = true serde_json.workspace = true tokio.workspace = true tracing.workspace = true -yang2.workspace = true +yang3.workspace = true holo-northbound = { path = "../holo-northbound" } holo-protocol = { path = "../holo-protocol" } diff --git a/holo-rip/src/northbound/state.rs b/holo-rip/src/northbound/state.rs index b8446b11..78bd3ed4 100644 --- a/holo-rip/src/northbound/state.rs +++ b/holo-rip/src/northbound/state.rs @@ -114,7 +114,9 @@ where updates_sent = Some(iface.state.statistics.updates_sent); } Box::new(Statistics { - discontinuity_time: discontinuity_time.ignore_in_testing(), + discontinuity_time: discontinuity_time + .map(Cow::Borrowed) + .ignore_in_testing(), bad_packets_rcvd: bad_packets_rcvd.ignore_in_testing(), bad_routes_rcvd: bad_routes_rcvd.ignore_in_testing(), updates_sent: updates_sent.ignore_in_testing(), @@ -137,7 +139,9 @@ where responses_sent = Some(instance.state.statistics.responses_sent); } Box::new(Statistics { - discontinuity_time: discontinuity_time.ignore_in_testing(), + discontinuity_time: discontinuity_time + .map(Cow::Borrowed) + .ignore_in_testing(), requests_rcvd: requests_rcvd.ignore_in_testing(), requests_sent: requests_sent.ignore_in_testing(), responses_rcvd: responses_rcvd.ignore_in_testing(), @@ -167,7 +171,8 @@ fn load_callbacks_ripv2() -> Callbacks> { let nbr = args.list_entry.as_ipv4_neighbor().unwrap(); Box::new(Neighbor { ipv4_address: Cow::Borrowed(&nbr.addr), - last_update: Some(&nbr.last_update).ignore_in_testing(), + last_update: Some(Cow::Borrowed(&nbr.last_update)) + .ignore_in_testing(), bad_packets_rcvd: Some(nbr.bad_packets_rcvd) .ignore_in_testing(), bad_routes_rcvd: Some(nbr.bad_routes_rcvd).ignore_in_testing(), @@ -229,7 +234,8 @@ fn load_callbacks_ripng() -> Callbacks> { let nbr = args.list_entry.as_ipv6_neighbor().unwrap(); Box::new(Neighbor { ipv6_address: Cow::Borrowed(&nbr.addr), - last_update: Some(&nbr.last_update).ignore_in_testing(), + last_update: Some(Cow::Borrowed(&nbr.last_update)) + .ignore_in_testing(), bad_packets_rcvd: Some(nbr.bad_packets_rcvd) .ignore_in_testing(), bad_routes_rcvd: Some(nbr.bad_routes_rcvd).ignore_in_testing(), diff --git a/holo-routing/Cargo.toml b/holo-routing/Cargo.toml index 39d1ae5b..d0dbfc89 100644 --- a/holo-routing/Cargo.toml +++ b/holo-routing/Cargo.toml @@ -19,7 +19,7 @@ regex.workspace = true rtnetlink.workspace = true tokio.workspace = true tracing.workspace = true -yang2.workspace = true +yang3.workspace = true holo-northbound = { path = "../holo-northbound" } holo-protocol = { path = "../holo-protocol" } @@ -36,8 +36,8 @@ holo-rip = { path = "../holo-rip", optional = true } workspace = true [features] -bfd = ["holo-bfd"] -bgp = ["holo-bgp"] -ldp = ["holo-ldp"] -ospf = ["holo-ospf"] -rip = ["holo-rip"] +bfd = ["dep:holo-bfd"] +bgp = ["dep:holo-bgp"] +ldp = ["dep:holo-ldp"] +ospf = ["dep:holo-ospf"] +rip = ["dep:holo-rip"] diff --git a/holo-routing/src/northbound/rpc.rs b/holo-routing/src/northbound/rpc.rs index f281c4ee..b4ea1c96 100644 --- a/holo-routing/src/northbound/rpc.rs +++ b/holo-routing/src/northbound/rpc.rs @@ -9,7 +9,7 @@ use holo_northbound::yang::control_plane_protocol; use holo_northbound::{CallbackKey, NbDaemonSender}; use holo_utils::protocol::Protocol; use holo_utils::yang::DataNodeRefExt; -use yang2::data::DataNodeRef; +use yang3::data::DataNodeRef; use crate::Master; diff --git a/holo-routing/src/northbound/state.rs b/holo-routing/src/northbound/state.rs index 9c743d5e..68cfd1be 100644 --- a/holo-routing/src/northbound/state.rs +++ b/holo-routing/src/northbound/state.rs @@ -154,7 +154,7 @@ fn load_callbacks() -> Callbacks { route_preference, source_protocol, active: route.flags.contains(RouteFlags::ACTIVE).then_some(()), - last_updated: Some(&route.last_updated), + last_updated: Some(Cow::Borrowed(&route.last_updated)), ipv4_destination_prefix: dest.as_ipv4().copied().map(Cow::Borrowed), ipv6_destination_prefix: dest.as_ipv6().copied().map(Cow::Borrowed), mpls_enabled: None, diff --git a/holo-routing/src/rib.rs b/holo-routing/src/rib.rs index ca5e29f7..6ae9e15a 100644 --- a/holo-routing/src/rib.rs +++ b/holo-routing/src/rib.rs @@ -11,9 +11,7 @@ use bitflags::bitflags; use chrono::{DateTime, Utc}; use derive_new::new; use holo_utils::ibus::IbusSender; -use holo_utils::ip::{ - AddressFamily, IpNetworkExt, Ipv4NetworkExt, Ipv6NetworkExt, -}; +use holo_utils::ip::{AddressFamily, IpNetworkExt, Ipv4AddrExt, Ipv6AddrExt}; use holo_utils::mpls::Label; use holo_utils::protocol::Protocol; use holo_utils::southbound::{ @@ -497,16 +495,12 @@ impl Rib { fn prefix_longest_match(&self, addr: &IpAddr) -> Option<&Route> { let lpm = match addr { IpAddr::V4(addr) => { - let prefix = - Ipv4Network::new(*addr, Ipv4Network::MAX_PREFIXLEN) - .unwrap(); + let prefix = addr.to_host_prefix(); let (_, lpm) = self.ipv4.get_lpm(&prefix)?; lpm } IpAddr::V6(addr) => { - let prefix = - Ipv6Network::new(*addr, Ipv6Network::MAX_PREFIXLEN) - .unwrap(); + let prefix = addr.to_host_prefix(); let (_, lpm) = self.ipv6.get_lpm(&prefix)?; lpm } diff --git a/holo-system/Cargo.toml b/holo-system/Cargo.toml new file mode 100644 index 00000000..d96dfe8a --- /dev/null +++ b/holo-system/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "holo-system" +version.workspace = true +authors.workspace = true +license.workspace = true +edition.workspace = true + +[dependencies] +sysinfo = "0.30" + +async-trait.workspace = true +capctl.workspace = true +chrono.workspace = true +derive-new.workspace = true +tokio.workspace = true +tracing.workspace = true +yang3.workspace = true + +holo-northbound = { path = "../holo-northbound" } +holo-utils = { path = "../holo-utils" } +holo-yang = { path = "../holo-yang" } + +[lints] +workspace = true diff --git a/holo-system/LICENSE b/holo-system/LICENSE new file mode 100644 index 00000000..4481fc10 --- /dev/null +++ b/holo-system/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2023 The Holo Core Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/holo-system/src/ibus.rs b/holo-system/src/ibus.rs new file mode 100644 index 00000000..622b3c05 --- /dev/null +++ b/holo-system/src/ibus.rs @@ -0,0 +1,38 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use holo_utils::ibus::{IbusMsg, IbusSender}; + +use crate::Master; + +// ===== global functions ===== + +pub(crate) fn process_msg(master: &mut Master, msg: IbusMsg) { + match msg { + IbusMsg::HostnameQuery => { + notify_hostname_update( + &master.ibus_tx, + master.config.hostname.clone(), + ); + } + // Ignore other events. + _ => {} + } +} + +pub(crate) fn notify_hostname_update( + ibus_tx: &IbusSender, + hostname: Option, +) { + let msg = IbusMsg::HostnameUpdate(hostname); + notify(ibus_tx, msg); +} + +// ===== helper functions ===== + +fn notify(ibus_tx: &IbusSender, msg: IbusMsg) { + let _ = ibus_tx.send(msg); +} diff --git a/holo-system/src/lib.rs b/holo-system/src/lib.rs new file mode 100644 index 00000000..4c84d04c --- /dev/null +++ b/holo-system/src/lib.rs @@ -0,0 +1,81 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +#![feature(let_chains)] + +mod ibus; +pub mod northbound; + +use holo_northbound::{ + process_northbound_msg, NbDaemonReceiver, NbDaemonSender, NbProviderSender, + ProviderBase, +}; +use holo_utils::ibus::{IbusReceiver, IbusSender}; +use northbound::configuration::SystemCfg; +use tokio::sync::mpsc; +use tracing::Instrument; + +#[derive(Debug)] +pub struct Master { + // Northbound Tx channel. + pub nb_tx: NbProviderSender, + // Internal bus Tx channel. + pub ibus_tx: IbusSender, + // System configuration. + pub config: SystemCfg, +} + +// ===== impl Master ===== + +impl Master { + async fn run( + &mut self, + mut nb_rx: NbDaemonReceiver, + mut ibus_rx: IbusReceiver, + ) { + let mut resources = vec![]; + + loop { + tokio::select! { + Some(request) = nb_rx.recv() => { + process_northbound_msg( + self, + &mut resources, + request, + ) + .await; + } + Ok(msg) = ibus_rx.recv() => { + ibus::process_msg(self, msg); + } + } + } + } +} + +// ===== global functions ===== + +pub fn start( + nb_tx: NbProviderSender, + ibus_tx: IbusSender, + ibus_rx: IbusReceiver, +) -> NbDaemonSender { + let (nb_daemon_tx, nb_daemon_rx) = mpsc::channel(4); + + tokio::spawn(async move { + let mut master = Master { + nb_tx, + ibus_tx, + config: Default::default(), + }; + + // Run task main loop. + let span = Master::debug_span(""); + master.run(nb_daemon_rx, ibus_rx).instrument(span).await; + }); + + nb_daemon_tx +} diff --git a/holo-system/src/northbound/configuration.rs b/holo-system/src/northbound/configuration.rs new file mode 100644 index 00000000..dc3d13d7 --- /dev/null +++ b/holo-system/src/northbound/configuration.rs @@ -0,0 +1,103 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::sync::LazyLock as Lazy; + +use async_trait::async_trait; +use holo_northbound::configuration::{ + self, Callbacks, CallbacksBuilder, Provider, +}; +use holo_northbound::yang::system; +use holo_utils::yang::DataNodeRefExt; + +use crate::{ibus, Master}; + +static CALLBACKS: Lazy> = + Lazy::new(load_callbacks); + +#[derive(Debug, Default)] +pub enum ListEntry { + #[default] + None, +} + +#[derive(Debug)] +pub enum Resource {} + +#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] +pub enum Event { + HostnameChange, +} + +// ===== configuration structs ===== + +#[derive(Debug, Default)] +pub struct SystemCfg { + pub contact: Option, + pub hostname: Option, + pub location: Option, +} + +// ===== callbacks ===== + +fn load_callbacks() -> Callbacks { + CallbacksBuilder::::default() + .path(system::contact::PATH) + .modify_apply(|master, args| { + let contact = args.dnode.get_string(); + master.config.contact = Some(contact); + }) + .delete_apply(|master, _args| { + master.config.contact = None; + }) + .path(system::hostname::PATH) + .modify_apply(|master, args| { + let hostname = args.dnode.get_string(); + master.config.hostname = Some(hostname); + + let event_queue = args.event_queue; + event_queue.insert(Event::HostnameChange); + }) + .delete_apply(|master, args| { + master.config.hostname = None; + + let event_queue = args.event_queue; + event_queue.insert(Event::HostnameChange); + }) + .path(system::location::PATH) + .modify_apply(|master, args| { + let location = args.dnode.get_string(); + master.config.location = Some(location); + }) + .delete_apply(|master, _args| { + master.config.location = None; + }) + .build() +} + +// ===== impl Master ===== + +#[async_trait] +impl Provider for Master { + type ListEntry = ListEntry; + type Event = Event; + type Resource = Resource; + + fn callbacks() -> Option<&'static Callbacks> { + Some(&CALLBACKS) + } + + async fn process_event(&mut self, event: Event) { + match event { + Event::HostnameChange => { + ibus::notify_hostname_update( + &self.ibus_tx, + self.config.hostname.clone(), + ); + } + } + } +} diff --git a/holo-system/src/northbound/mod.rs b/holo-system/src/northbound/mod.rs new file mode 100644 index 00000000..186dc898 --- /dev/null +++ b/holo-system/src/northbound/mod.rs @@ -0,0 +1,32 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +pub mod configuration; +pub mod state; + +use holo_northbound::{rpc, ProviderBase}; +use tracing::{debug_span, Span}; + +use crate::Master; + +// ===== impl Master ===== + +impl ProviderBase for Master { + fn yang_modules() -> &'static [&'static str] { + &["ietf-system"] + } + + fn top_level_node(&self) -> String { + "/ietf-system:system".to_owned() + } + + fn debug_span(_name: &str) -> Span { + debug_span!("system") + } +} + +// No RPC/Actions to implement. +impl rpc::Provider for Master {} diff --git a/holo-system/src/northbound/state.rs b/holo-system/src/northbound/state.rs new file mode 100644 index 00000000..052f3d6f --- /dev/null +++ b/holo-system/src/northbound/state.rs @@ -0,0 +1,69 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::borrow::Cow; +use std::sync::LazyLock as Lazy; + +use chrono::{DateTime, Utc}; +use holo_northbound::state::{ + Callbacks, CallbacksBuilder, ListEntryKind, Provider, +}; +use holo_northbound::yang::system_state; +use sysinfo::System; + +use crate::Master; + +pub static CALLBACKS: Lazy> = Lazy::new(load_callbacks); + +#[derive(Debug, Default)] +pub enum ListEntry { + #[default] + None, +} + +// ===== callbacks ===== + +fn load_callbacks() -> Callbacks { + CallbacksBuilder::::default() + .path(system_state::platform::PATH) + .get_object(|_context, _args| { + use system_state::platform::Platform; + Box::new(Platform { + os_name: System::name().map(Cow::Owned), + os_release: System::kernel_version().map(Cow::Owned), + os_version: System::os_version().map(Cow::Owned), + machine: System::cpu_arch().map(Cow::Owned), + }) + }) + .path(system_state::clock::PATH) + .get_object(|_context, _args| { + use system_state::clock::Clock; + let time_now = Utc::now(); + let time_boot = + DateTime::from_timestamp(System::boot_time() as i64, 0); + Box::new(Clock { + current_datetime: Some(Cow::Owned(time_now)), + boot_datetime: time_boot.map(Cow::Owned), + }) + }) + .build() +} + +// ===== impl Master ===== + +impl Provider for Master { + const STATE_PATH: &'static str = "/ietf-system:system-state"; + + type ListEntry<'a> = ListEntry; + + fn callbacks() -> Option<&'static Callbacks> { + Some(&CALLBACKS) + } +} + +// ===== impl ListEntry ===== + +impl ListEntryKind for ListEntry {} diff --git a/holo-tools/Cargo.toml b/holo-tools/Cargo.toml index 5045752b..d700a3e4 100644 --- a/holo-tools/Cargo.toml +++ b/holo-tools/Cargo.toml @@ -13,7 +13,7 @@ num-traits.workspace = true serde_json.workspace = true similar.workspace = true tokio.workspace = true -yang2.workspace = true +yang3.workspace = true holo-bfd = { path = "../holo-bfd", features = ["testing"] } holo-bgp = { path = "../holo-bgp", features = ["testing"] } diff --git a/holo-tools/src/yang_callbacks.rs b/holo-tools/src/yang_callbacks.rs index 8c457db5..915a5cd5 100644 --- a/holo-tools/src/yang_callbacks.rs +++ b/holo-tools/src/yang_callbacks.rs @@ -9,8 +9,8 @@ use clap::{App, Arg}; use convert_case::{Boundary, Case, Casing}; use holo_northbound::CallbackOp; use holo_yang as yang; -use yang2::context::Context; -use yang2::schema::{SchemaModule, SchemaNode, SchemaNodeKind}; +use yang3::context::Context; +use yang3::schema::{SchemaModule, SchemaNode, SchemaNodeKind}; fn snode_module(snode: &SchemaNode<'_>) -> String { let snodes = snode.inclusive_ancestors().collect::>(); diff --git a/holo-tools/src/yang_coverage.rs b/holo-tools/src/yang_coverage.rs index c64e86e5..cdd66db8 100644 --- a/holo-tools/src/yang_coverage.rs +++ b/holo-tools/src/yang_coverage.rs @@ -9,8 +9,8 @@ use std::collections::BTreeMap; use clap::{App, Arg}; use holo_yang as yang; use num_traits::cast::AsPrimitive; -use yang2::context::Context; -use yang2::schema::{SchemaNodeKind, SchemaOutputFormat, SchemaPrinterFlags}; +use yang3::context::Context; +use yang3::schema::{SchemaNodeKind, SchemaOutputFormat, SchemaPrinterFlags}; #[derive(Debug, Default)] struct NodeCounters { diff --git a/holo-tools/src/yang_deviations.rs b/holo-tools/src/yang_deviations.rs index 9a86b90c..15edf1aa 100644 --- a/holo-tools/src/yang_deviations.rs +++ b/holo-tools/src/yang_deviations.rs @@ -6,7 +6,7 @@ use clap::{App, Arg}; use holo_yang as yang; -use yang2::schema::SchemaNode; +use yang3::schema::SchemaNode; // Generate fully-prefixed schema path. fn gen_fully_prefixed_path(snode: &SchemaNode<'_>) -> String { @@ -58,10 +58,10 @@ fn main() { // Header. println!( "\ - module {}-holo-deviations {{\ + module holo-{}-deviations {{\ \n yang-version 1.1;\ - \n namespace \"http://holo-routing.org/yang/{}-holo-deviations\";\ - \n prefix {}-holo-deviations;\ + \n namespace \"http://holo-routing.org/yang/holo-{}-deviations\";\ + \n prefix holo-{}-deviations;\ \n\ \n import {} {{\ \n prefix {};\ diff --git a/holo-utils/Cargo.toml b/holo-utils/Cargo.toml index 514d22c9..9a9f71ab 100644 --- a/holo-utils/Cargo.toml +++ b/holo-utils/Cargo.toml @@ -28,7 +28,7 @@ serde_json.workspace = true socket2.workspace = true tokio.workspace = true tracing.workspace = true -yang2.workspace = true +yang3.workspace = true holo-yang = { path = "../holo-yang" } diff --git a/holo-utils/src/ibus.rs b/holo-utils/src/ibus.rs index 49b7e013..389b06bd 100644 --- a/holo-utils/src/ibus.rs +++ b/holo-utils/src/ibus.rs @@ -44,6 +44,10 @@ pub enum IbusMsg { sess_key: bfd::SessionKey, state: bfd::State, }, + // Query the current hostname. + HostnameQuery, + // Hostname update notification. + HostnameUpdate(Option), // Request to dump information about all interfaces. InterfaceDump, // Query information about a specific interface. diff --git a/holo-utils/src/ip.rs b/holo-utils/src/ip.rs index c3fabb62..c6a93bbd 100644 --- a/holo-utils/src/ip.rs +++ b/holo-utils/src/ip.rs @@ -38,6 +38,9 @@ pub trait IpAddrExt { // Returns true if this is an usable address. fn is_usable(&self) -> bool; + // Converts this IP address into a host prefix network. + fn to_host_prefix(&self) -> IpNetwork; + // Returns an unspecified address of the given address family. fn unspecified(af: AddressFamily) -> IpAddr; } @@ -48,6 +51,9 @@ pub trait Ipv4AddrExt { // Returns true if this is an usable address. fn is_usable(&self) -> bool; + + // Converts this IPv4 address into a host prefix network. + fn to_host_prefix(&self) -> Ipv4Network; } // Extension methods for Ipv6Addr. @@ -56,6 +62,9 @@ pub trait Ipv6AddrExt { // Returns true if this is an usable address. fn is_usable(&self) -> bool; + + // Converts this IPv6 address into a host prefix network. + fn to_host_prefix(&self) -> Ipv6Network; } // Extension methods for IpNetwork. @@ -238,6 +247,13 @@ impl IpAddrExt for IpAddr { !(self.is_loopback() || self.is_multicast() || self.is_unspecified()) } + fn to_host_prefix(&self) -> IpNetwork { + match self { + IpAddr::V4(addr) => addr.to_host_prefix().into(), + IpAddr::V6(addr) => addr.to_host_prefix().into(), + } + } + fn unspecified(af: AddressFamily) -> IpAddr { match af { AddressFamily::Ipv4 => IpAddr::V4(Ipv4Addr::UNSPECIFIED), @@ -274,6 +290,10 @@ impl Ipv4AddrExt for Ipv4Addr { || self.is_multicast() || self.is_unspecified()) } + + fn to_host_prefix(&self) -> Ipv4Network { + Ipv4Network::new(*self, Ipv4Network::MAX_PREFIXLEN).unwrap() + } } impl IpAddrKind for Ipv4Addr { @@ -301,6 +321,10 @@ impl Ipv6AddrExt for Ipv6Addr { fn is_usable(&self) -> bool { !(self.is_loopback() || self.is_multicast() || self.is_unspecified()) } + + fn to_host_prefix(&self) -> Ipv6Network { + Ipv6Network::new(*self, Ipv6Network::MAX_PREFIXLEN).unwrap() + } } impl IpAddrKind for Ipv6Addr { diff --git a/holo-utils/src/yang.rs b/holo-utils/src/yang.rs index a174260d..c809a0b5 100644 --- a/holo-utils/src/yang.rs +++ b/holo-utils/src/yang.rs @@ -10,9 +10,9 @@ use std::str::FromStr; use holo_yang::TryFromYang; use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network}; -use yang2::context::Context; -use yang2::data::{Data, DataNodeRef}; -use yang2::schema::{DataValue, SchemaNode, SchemaPathFormat}; +use yang3::context::Context; +use yang3::data::{Data, DataNodeRef}; +use yang3::schema::{DataValue, SchemaNode, SchemaPathFormat}; use crate::ip::AddressFamily; @@ -72,18 +72,14 @@ impl ContextExt for Context { fn cache_data_paths(&self) { for snode in self.traverse() { snode.cache_data_path(); - if let Some(actions) = snode.actions() { - for action in actions { - for snode in action.traverse() { - snode.cache_data_path(); - } + for action in snode.actions() { + for snode in action.traverse() { + snode.cache_data_path(); } } - if let Some(notifications) = snode.notifications() { - for notification in notifications { - for snode in notification.traverse() { - snode.cache_data_path(); - } + for notification in snode.notifications() { + for snode in notification.traverse() { + snode.cache_data_path(); } } } diff --git a/holo-yang/Cargo.toml b/holo-yang/Cargo.toml index fdeef09b..c098a06c 100644 --- a/holo-yang/Cargo.toml +++ b/holo-yang/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "holo-yang" -version = "0.4.2" +version = "0.5.3" authors.workspace = true license.workspace = true edition.workspace = true @@ -11,7 +11,7 @@ description = "YANG module of Holo Routing, including embedded YANG models and u maplit.workspace = true serde.workspace = true tracing.workspace = true -yang2.workspace = true +yang3.workspace = true [lints] workspace = true diff --git a/holo-yang/modules/deviations/ietf-bgp-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-bgp-deviations.yang similarity index 99% rename from holo-yang/modules/deviations/ietf-bgp-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-bgp-deviations.yang index c54d4868..1c19ed8b 100644 --- a/holo-yang/modules/deviations/ietf-bgp-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-bgp-deviations.yang @@ -1,7 +1,7 @@ -module ietf-bgp-holo-deviations { +module holo-ietf-bgp-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-bgp-holo-deviations"; - prefix ietf-bgp-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-bgp-deviations"; + prefix holo-ietf-bgp-deviations; import ietf-routing { prefix rt; diff --git a/holo-yang/modules/deviations/ietf-if-extensions-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-if-extensions-deviations.yang similarity index 74% rename from holo-yang/modules/deviations/ietf-if-extensions-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-if-extensions-deviations.yang index f598ee60..5c874952 100644 --- a/holo-yang/modules/deviations/ietf-if-extensions-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-if-extensions-deviations.yang @@ -1,7 +1,7 @@ -module ietf-if-extensions-holo-deviations { +module holo-ietf-if-extensions-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-if-extensions-holo-deviations"; - prefix ietf-if-extensions-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-if-extensions-deviations"; + prefix holo-ietf-if-extensions-deviations; import ietf-interfaces { prefix if; diff --git a/holo-yang/modules/deviations/ietf-if-vlan-encapsulation-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-if-vlan-encapsulation-deviations.yang similarity index 87% rename from holo-yang/modules/deviations/ietf-if-vlan-encapsulation-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-if-vlan-encapsulation-deviations.yang index cfaeb083..18391c50 100644 --- a/holo-yang/modules/deviations/ietf-if-vlan-encapsulation-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-if-vlan-encapsulation-deviations.yang @@ -1,7 +1,7 @@ -module ietf-if-vlan-encapsulation-holo-deviations { +module holo-ietf-if-vlan-encapsulation-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-if-vlan-encapsulation-holo-deviations"; - prefix ietf-if-vlan-encapsulation-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-if-vlan-encapsulation-deviations"; + prefix holo-ietf-if-vlan-encapsulation-deviations; import ietf-interfaces { prefix if; diff --git a/holo-yang/modules/deviations/ietf-interfaces-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-interfaces-deviations.yang similarity index 86% rename from holo-yang/modules/deviations/ietf-interfaces-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-interfaces-deviations.yang index 088b91f8..069e3f89 100644 --- a/holo-yang/modules/deviations/ietf-interfaces-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-interfaces-deviations.yang @@ -1,7 +1,7 @@ -module ietf-interfaces-holo-deviations { +module holo-ietf-interfaces-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-interfaces-holo-deviations"; - prefix ietf-interfaces-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-interfaces-deviations"; + prefix holo-ietf-interfaces-deviations; import ietf-interfaces { prefix if; diff --git a/holo-yang/modules/deviations/ietf-ip-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-ip-deviations.yang similarity index 94% rename from holo-yang/modules/deviations/ietf-ip-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-ip-deviations.yang index 9fd39817..16e3b859 100644 --- a/holo-yang/modules/deviations/ietf-ip-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-ip-deviations.yang @@ -1,7 +1,7 @@ -module ietf-ip-holo-deviations { +module holo-ietf-ip-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-ip-holo-deviations"; - prefix ietf-ip-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-ip-deviations"; + prefix holo-ietf-ip-deviations; import ietf-interfaces { prefix if; diff --git a/holo-yang/modules/deviations/ietf-ipv6-unicast-routing-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-ipv6-unicast-routing-deviations.yang similarity index 95% rename from holo-yang/modules/deviations/ietf-ipv6-unicast-routing-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-ipv6-unicast-routing-deviations.yang index abffeb1b..0d6451b9 100644 --- a/holo-yang/modules/deviations/ietf-ipv6-unicast-routing-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-ipv6-unicast-routing-deviations.yang @@ -1,7 +1,7 @@ -module ietf-ipv6-unicast-routing-holo-deviations { +module holo-ietf-ipv6-unicast-routing-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-ipv6-unicast-routing-holo-deviations"; - prefix ietf-ipv6-unicast-routing-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-ipv6-unicast-routing-deviations"; + prefix holo-ietf-ipv6-unicast-routing-deviations; import ietf-interfaces { prefix if; diff --git a/holo-yang/modules/deviations/ietf-key-chain-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-key-chain-deviations.yang similarity index 97% rename from holo-yang/modules/deviations/ietf-key-chain-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-key-chain-deviations.yang index a1dba067..34c48480 100644 --- a/holo-yang/modules/deviations/ietf-key-chain-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-key-chain-deviations.yang @@ -1,7 +1,7 @@ -module ietf-key-chain-holo-deviations { +module holo-ietf-key-chain-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-key-chain-holo-deviations"; - prefix ietf-key-chain-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-key-chain-deviations"; + prefix holo-ietf-key-chain-deviations; import ietf-key-chain { prefix key-chain; diff --git a/holo-yang/modules/deviations/ietf-mpls-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-mpls-deviations.yang similarity index 96% rename from holo-yang/modules/deviations/ietf-mpls-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-mpls-deviations.yang index e2e68c3d..63746326 100644 --- a/holo-yang/modules/deviations/ietf-mpls-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-mpls-deviations.yang @@ -1,7 +1,7 @@ -module ietf-mpls-holo-deviations { +module holo-ietf-mpls-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-mpls-holo-deviations"; - prefix ietf-mpls-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-mpls-deviations"; + prefix holo-ietf-mpls-deviations; import ietf-routing { prefix rt; diff --git a/holo-yang/modules/deviations/ietf-mpls-ldp-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-mpls-ldp-deviations.yang similarity index 96% rename from holo-yang/modules/deviations/ietf-mpls-ldp-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-mpls-ldp-deviations.yang index 7eaa2232..bff564ae 100644 --- a/holo-yang/modules/deviations/ietf-mpls-ldp-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-mpls-ldp-deviations.yang @@ -1,7 +1,7 @@ -module ietf-mpls-ldp-holo-deviations { +module holo-ietf-mpls-ldp-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-mpls-ldp-holo-deviations"; - prefix ietf-mpls-ldp-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-mpls-ldp-deviations"; + prefix holo-ietf-mpls-ldp-deviations; import ietf-routing { prefix rt; diff --git a/holo-yang/modules/deviations/ietf-ospf-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-ospf-deviations.yang similarity index 99% rename from holo-yang/modules/deviations/ietf-ospf-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-ospf-deviations.yang index 6a9e65ff..78387dc6 100644 --- a/holo-yang/modules/deviations/ietf-ospf-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-ospf-deviations.yang @@ -1,7 +1,7 @@ -module ietf-ospf-holo-deviations { +module holo-ietf-ospf-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-ospf-holo-deviations"; - prefix ietf-ospf-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-ospf-deviations"; + prefix holo-ietf-ospf-deviations; import ietf-routing { prefix rt; diff --git a/holo-yang/modules/deviations/ietf-ospf-sr-mpls-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-ospf-sr-mpls-deviations.yang similarity index 99% rename from holo-yang/modules/deviations/ietf-ospf-sr-mpls-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-ospf-sr-mpls-deviations.yang index 439fe875..f62d4bdc 100644 --- a/holo-yang/modules/deviations/ietf-ospf-sr-mpls-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-ospf-sr-mpls-deviations.yang @@ -1,7 +1,7 @@ -module ietf-ospf-sr-mpls-holo-deviations { +module holo-ietf-ospf-sr-mpls-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-ospf-sr-mpls-holo-deviations"; - prefix ietf-ospf-sr-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-ospf-sr-mpls-deviations"; + prefix holo-ietf-ospf-sr-deviations; import ietf-routing { prefix rt; diff --git a/holo-yang/modules/deviations/ietf-ospfv3-extended-lsa-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-ospfv3-extended-lsa-deviations.yang similarity index 98% rename from holo-yang/modules/deviations/ietf-ospfv3-extended-lsa-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-ospfv3-extended-lsa-deviations.yang index 76bf0e52..99b64dca 100644 --- a/holo-yang/modules/deviations/ietf-ospfv3-extended-lsa-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-ospfv3-extended-lsa-deviations.yang @@ -1,7 +1,7 @@ -module ietf-ospfv3-extended-lsa-holo-deviations { +module holo-ietf-ospfv3-extended-lsa-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-ospfv3-extended-lsa-holo-deviations"; - prefix ietf-ospfv3-extended-lsa-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-ospfv3-extended-lsa-deviations"; + prefix holo-ietf-ospfv3-extended-lsa-deviations; import ietf-routing { prefix rt; diff --git a/holo-yang/modules/deviations/ietf-rip-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-rip-deviations.yang similarity index 97% rename from holo-yang/modules/deviations/ietf-rip-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-rip-deviations.yang index a9178812..01e579b1 100644 --- a/holo-yang/modules/deviations/ietf-rip-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-rip-deviations.yang @@ -1,7 +1,7 @@ -module ietf-rip-holo-deviations { +module holo-ietf-rip-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-rip-holo-deviations"; - prefix ietf-rip-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-rip-deviations"; + prefix holo-ietf-rip-deviations; import ietf-routing { prefix rt; @@ -368,6 +368,12 @@ module ietf-rip-holo-deviations { } */ + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/rip:rip/rip:interfaces/rip:interface/rip:timers" { + deviate delete { + must 'invalid-interval >= (update-interval * 3)'; + } + } + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/rip:rip/rip:interfaces/rip:interface/rip:timers/rip:update-interval" { deviate not-supported; } diff --git a/holo-yang/modules/deviations/ietf-routing-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-routing-deviations.yang similarity index 75% rename from holo-yang/modules/deviations/ietf-routing-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-routing-deviations.yang index d26fe5f3..3554080d 100644 --- a/holo-yang/modules/deviations/ietf-routing-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-routing-deviations.yang @@ -1,7 +1,7 @@ -module ietf-routing-holo-deviations { +module holo-ietf-routing-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-routing-holo-deviations"; - prefix ietf-routing-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-routing-deviations"; + prefix holo-ietf-routing-deviations; import ietf-routing { prefix rt; diff --git a/holo-yang/modules/deviations/ietf-routing-policy-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-routing-policy-deviations.yang similarity index 84% rename from holo-yang/modules/deviations/ietf-routing-policy-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-routing-policy-deviations.yang index c3a14ad6..56964577 100644 --- a/holo-yang/modules/deviations/ietf-routing-policy-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-routing-policy-deviations.yang @@ -1,7 +1,7 @@ -module ietf-routing-policy-holo-deviations { +module holo-ietf-routing-policy-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-routing-policy-holo-deviations"; - prefix ietf-routing-policy-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-routing-policy-deviations"; + prefix holo-ietf-routing-policy-deviations; import ietf-routing-policy { prefix rt-pol; diff --git a/holo-yang/modules/deviations/ietf-segment-routing-mpls-holo-deviations.yang b/holo-yang/modules/deviations/holo-ietf-segment-routing-mpls-deviations.yang similarity index 97% rename from holo-yang/modules/deviations/ietf-segment-routing-mpls-holo-deviations.yang rename to holo-yang/modules/deviations/holo-ietf-segment-routing-mpls-deviations.yang index 8dd2f05e..65c7cf4b 100644 --- a/holo-yang/modules/deviations/ietf-segment-routing-mpls-holo-deviations.yang +++ b/holo-yang/modules/deviations/holo-ietf-segment-routing-mpls-deviations.yang @@ -1,7 +1,7 @@ -module ietf-segment-routing-mpls-holo-deviations { +module holo-ietf-segment-routing-mpls-deviations { yang-version 1.1; - namespace "http://holo-routing.org/yang/ietf-segment-routing-mpls-holo-deviations"; - prefix ietf-segment-routing-mpls-holo-deviations; + namespace "http://holo-routing.org/yang/holo-ietf-segment-routing-mpls-deviations"; + prefix holo-ietf-segment-routing-mpls-deviations; import ietf-routing { prefix rt; diff --git a/holo-yang/modules/deviations/holo-ietf-system-deviations.yang b/holo-yang/modules/deviations/holo-ietf-system-deviations.yang new file mode 100644 index 00000000..531aad5f --- /dev/null +++ b/holo-yang/modules/deviations/holo-ietf-system-deviations.yang @@ -0,0 +1,234 @@ +module holo-ietf-system-deviations { + yang-version 1.1; + namespace "http://holo-routing.org/yang/holo-ietf-system-deviations"; + prefix holo-ietf-system-deviations; + + import ietf-system { + prefix sys; + } + + organization + "Holo Routing Stack"; + + description + "This module defines deviation statements for the ietf-system + module."; + + /* + deviation "/sys:system" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system/sys:contact" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system/sys:hostname" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system/sys:location" { + deviate not-supported; + } + */ + + deviation "/sys:system/sys:clock" { + deviate not-supported; + } + + /* + deviation "/sys:system/sys:clock/sys:timezone" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system/sys:clock/sys:timezone/sys:timezone-utc-offset" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system/sys:clock/sys:timezone/sys:timezone-utc-offset/sys:timezone-utc-offset" { + deviate not-supported; + } + */ + + deviation "/sys:system/sys:dns-resolver" { + deviate not-supported; + } + + /* + deviation "/sys:system/sys:dns-resolver/sys:search" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system/sys:dns-resolver/sys:server" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system/sys:dns-resolver/sys:server/sys:name" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system/sys:dns-resolver/sys:server/sys:transport" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system/sys:dns-resolver/sys:server/sys:transport/sys:udp-and-tcp" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system/sys:dns-resolver/sys:server/sys:transport/sys:udp-and-tcp/sys:udp-and-tcp" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system/sys:dns-resolver/sys:server/sys:transport/sys:udp-and-tcp/sys:udp-and-tcp/sys:address" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system/sys:dns-resolver/sys:options" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system/sys:dns-resolver/sys:options/sys:timeout" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system/sys:dns-resolver/sys:options/sys:attempts" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system-state" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system-state/sys:platform" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system-state/sys:platform/sys:os-name" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system-state/sys:platform/sys:os-release" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system-state/sys:platform/sys:os-version" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system-state/sys:platform/sys:machine" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system-state/sys:clock" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system-state/sys:clock/sys:current-datetime" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system-state/sys:clock/sys:boot-datetime" { + deviate not-supported; + } + */ + + deviation "/sys:set-current-datetime" { + deviate not-supported; + } + + /* + deviation "/sys:set-current-datetime/sys:input" { + deviate not-supported; + } + */ + + /* + deviation "/sys:set-current-datetime/sys:input/sys:current-datetime" { + deviate not-supported; + } + */ + + /* + deviation "/sys:set-current-datetime/sys:output" { + deviate not-supported; + } + */ + + deviation "/sys:system-restart" { + deviate not-supported; + } + + /* + deviation "/sys:system-restart/sys:input" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system-restart/sys:output" { + deviate not-supported; + } + */ + + deviation "/sys:system-shutdown" { + deviate not-supported; + } + + /* + deviation "/sys:system-shutdown/sys:input" { + deviate not-supported; + } + */ + + /* + deviation "/sys:system-shutdown/sys:output" { + deviate not-supported; + } + */ +} diff --git a/holo-yang/modules/ietf/iana-crypt-hash@2014-08-06.yang b/holo-yang/modules/ietf/iana-crypt-hash@2014-08-06.yang new file mode 100644 index 00000000..fc4544a8 --- /dev/null +++ b/holo-yang/modules/ietf/iana-crypt-hash@2014-08-06.yang @@ -0,0 +1,99 @@ +module iana-crypt-hash { + namespace "urn:ietf:params:xml:ns:yang:iana-crypt-hash"; + prefix ianach; + organization "IANA"; + contact + " Internet Assigned Numbers Authority + Postal: ICANN + 12025 Waterfront Drive, Suite 300 + Los Angeles, CA 90094-2536 + United States + Tel: +1 310 301 5800 + E-Mail: iana@iana.org>"; + description + "This YANG module defines a type for storing passwords + using a hash function and features to indicate which hash + functions are supported by an implementation. + The latest revision of this YANG module can be obtained from + the IANA web site. + Requests for new values should be made to IANA via + email (iana@iana.org). + Copyright (c) 2014 IETF Trust and the persons identified as + authors of the code. All rights reserved. + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + The initial version of this YANG module is part of RFC 7317; + see the RFC itself for full legal notices."; + revision 2014-08-06 { + description + "Initial revision."; + reference + "RFC 7317: A YANG Data Model for System Management"; + } + typedef crypt-hash { + type string { + pattern + '$0$.*' + + '|$1$[a-zA-Z0-9./]{1,8}$[a-zA-Z0-9./]{22}' + + '|$5$(rounds=\d+$)?[a-zA-Z0-9./]{1,16}$[a-zA-Z0-9./]{43}' + + '|$6$(rounds=\d+$)?[a-zA-Z0-9./]{1,16}$[a-zA-Z0-9./]{86}'; + } + description + "The crypt-hash type is used to store passwords using + a hash function. The algorithms for applying the hash + function and encoding the result are implemented in + various UNIX systems as the function crypt(3). + A value of this type matches one of the forms: + $0$ + $$$ + $$$$ + The '$0$' prefix signals that the value is clear text. When + such a value is received by the server, a hash value is + calculated, and the string '$$$' or + $$$$ is prepended to the result. This + value is stored in the configuration data store. + If a value starting with '$$', where is not '0', is + received, the server knows that the value already represents a + hashed value and stores it 'as is' in the data store. + When a server needs to verify a password given by a user, it + finds the stored password hash string for that user, extracts + the salt, and calculates the hash with the salt and given + password as input. If the calculated hash value is the same + as the stored value, the password given by the client is + accepted. + This type defines the following hash functions: + id | hash function | feature + ---+---------------+------------------- + 1 | MD5 | crypt-hash-md5 + 5 | SHA-256 | crypt-hash-sha-256 + 6 | SHA-512 | crypt-hash-sha-512 + The server indicates support for the different hash functions + by advertising the corresponding feature."; + reference + "IEEE Std 1003.1-2008 - crypt() function + RFC 1321: The MD5 Message-Digest Algorithm + FIPS.180-4.2012: Secure Hash Standard (SHS)"; + } + feature crypt-hash-md5 { + description + "Indicates that the device supports the MD5 + hash function in 'crypt-hash' values."; + reference "RFC 1321: The MD5 Message-Digest Algorithm"; + } + feature crypt-hash-sha-256 { + description + "Indicates that the device supports the SHA-256 + hash function in 'crypt-hash' values."; + reference "FIPS.180-4.2012: Secure Hash Standard (SHS)"; + } + feature crypt-hash-sha-512 { + description + "Indicates that the device supports the SHA-512 + hash function in 'crypt-hash' values."; + reference "FIPS.180-4.2012: Secure Hash Standard (SHS)"; + } +} diff --git a/holo-yang/modules/ietf/ietf-ospf-sr-mpls@2024-01-18.yang b/holo-yang/modules/ietf/ietf-ospf-sr-mpls@2024-06-19.yang similarity index 98% rename from holo-yang/modules/ietf/ietf-ospf-sr-mpls@2024-01-18.yang rename to holo-yang/modules/ietf/ietf-ospf-sr-mpls@2024-06-19.yang index 140baecb..bbd5bc2e 100644 --- a/holo-yang/modules/ietf/ietf-ospf-sr-mpls@2024-01-18.yang +++ b/holo-yang/modules/ietf/ietf-ospf-sr-mpls@2024-06-19.yang @@ -42,7 +42,7 @@ module ietf-ospf-sr-mpls { import ietf-ospfv3-extended-lsa { prefix ospfv3-e-lsa; reference - "RFC XXXX - YANG Data Model for OSPFv3 Extended LSAs"; + "RFC 9587 - YANG Data Model for OSPFv3 Extended LSAs"; } organization @@ -97,7 +97,7 @@ module ietf-ospf-sr-mpls { reference "RFC XXXX"; - revision 2024-01-18 { + revision 2024-06-19 { description "Initial revision."; reference @@ -1203,7 +1203,8 @@ module ietf-ospf-sr-mpls { + "ospf:link-scope-lsas/ospf:link-scope-lsa/" + "ospf:version/ospf:ospfv3/ospf:ospfv3/" + "ospf:body/ospfv3-e-lsa:e-link/" - + "ospfv3-e-lsa:e-link-tlvs/ospfv3-e-lsa:intra-prefix-tlv" { + + "ospfv3-e-lsa:e-link-tlvs/ospfv3-e-lsa:intra-prefix-tlv/" + + "ospfv3-e-lsa:sub-tlvs" { when "derived-from(/rt:routing/rt:control-plane-protocols/" + "rt:control-plane-protocol/rt:type, 'ospf:ospfv3')" { description @@ -1222,7 +1223,8 @@ module ietf-ospf-sr-mpls { + "ospf:area-scope-lsa/ospf:version/ospf:ospfv3/" + "ospf:ospfv3/ospf:body/ospfv3-e-lsa:e-intra-area-prefix/" + "ospfv3-e-lsa:e-intra-prefix-tlvs/" - + "ospfv3-e-lsa:intra-prefix-tlv" { + + "ospfv3-e-lsa:intra-prefix-tlv/" + + "ospfv3-e-lsa:sub-tlvs" { when "derived-from(/rt:routing/rt:control-plane-protocols/" + "rt:control-plane-protocol/rt:type, 'ospf:ospfv3')" { description @@ -1243,7 +1245,8 @@ module ietf-ospf-sr-mpls { + "ospf:area-scope-lsa/ospf:version/ospf:ospfv3/" + "ospf:ospfv3/ospf:body/ospfv3-e-lsa:e-inter-area-prefix/" + "ospfv3-e-lsa:e-inter-prefix-tlvs/" - + "ospfv3-e-lsa:inter-prefix-tlv" { + + "ospfv3-e-lsa:inter-prefix-tlv/" + + "ospfv3-e-lsa:sub-tlvs" { when "derived-from(/rt:routing/rt:control-plane-protocols/" + "rt:control-plane-protocol/rt:type, 'ospf:ospfv3')" { description @@ -1264,7 +1267,8 @@ module ietf-ospf-sr-mpls { + "ospf:as-scope-lsa/ospf:version/ospf:ospfv3/" + "ospf:ospfv3/ospf:body/ospfv3-e-lsa:e-as-external/" + "ospfv3-e-lsa:e-external-tlvs/" - + "ospfv3-e-lsa:external-prefix-tlv" { + + "ospfv3-e-lsa:external-prefix-tlv/" + + "ospfv3-e-lsa:sub-tlvs" { when "derived-from(/rt:routing/rt:control-plane-protocols/" + "rt:control-plane-protocol/rt:type, 'ospf:ospfv3')" { description @@ -1282,7 +1286,8 @@ module ietf-ospf-sr-mpls { + "ospf:area-scope-lsa/ospf:version/ospf:ospfv3/" + "ospf:ospfv3/ospf:body/ospfv3-e-lsa:e-nssa/" + "ospfv3-e-lsa:e-external-tlvs/" - + "ospfv3-e-lsa:external-prefix-tlv" { + + "ospfv3-e-lsa:external-prefix-tlv/" + + "ospfv3-e-lsa:sub-tlvs" { when "derived-from(/rt:routing/rt:control-plane-protocols/" + "rt:control-plane-protocol/rt:type, 'ospf:ospfv3')" { description @@ -1292,6 +1297,7 @@ module ietf-ospf-sr-mpls { description "OSPFv3 Area-Scoped External Prefix TLV."; } + /* Adj-SID sub-TLV */ augment "/rt:routing/" @@ -1300,7 +1306,8 @@ module ietf-ospf-sr-mpls { + "ospf:area-scope-lsa-type/ospf:area-scope-lsas/" + "ospf:area-scope-lsa/ospf:version/ospf:ospfv3/" + "ospf:ospfv3/ospf:body/ospfv3-e-lsa:e-router/" - + "ospfv3-e-lsa:e-router-tlvs/ospfv3-e-lsa:link-tlv" { + + "ospfv3-e-lsa:e-router-tlvs/ospfv3-e-lsa:link-tlv/" + + "ospfv3-e-lsa:sub-tlvs" { when "derived-from(/rt:routing/rt:control-plane-protocols/" + "rt:control-plane-protocol/rt:type, 'ospf:ospfv3')" { description diff --git a/holo-yang/modules/ietf/ietf-system@2014-08-06.yang b/holo-yang/modules/ietf/ietf-system@2014-08-06.yang new file mode 100644 index 00000000..a8d9e089 --- /dev/null +++ b/holo-yang/modules/ietf/ietf-system@2014-08-06.yang @@ -0,0 +1,711 @@ +module ietf-system { + namespace "urn:ietf:params:xml:ns:yang:ietf-system"; + prefix "sys"; + import ietf-yang-types { + prefix yang; + } + import ietf-inet-types { + prefix inet; + } + import ietf-netconf-acm { + prefix nacm; + } + import iana-crypt-hash { + prefix ianach; + } + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + contact + "WG Web: + WG List: + WG Chair: Thomas Nadeau + + WG Chair: Juergen Schoenwaelder + + Editor: Andy Bierman + + Editor: Martin Bjorklund + "; + description + "This module contains a collection of YANG definitions for the + configuration and identification of some common system + properties within a device containing a NETCONF server. This + includes data node definitions for system identification, + time-of-day management, user management, DNS resolver + configuration, and some protocol operations for system + management. + Copyright (c) 2014 IETF Trust and the persons identified as + authors of the code. All rights reserved. + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + This version of this YANG module is part of RFC 7317; see + the RFC itself for full legal notices."; + revision 2014-08-06 { + description + "Initial revision."; + reference + "RFC 7317: A YANG Data Model for System Management"; + } + /* + * Typedefs + */ + typedef timezone-name { + type string; + description + "A time zone name as used by the Time Zone Database, + sometimes referred to as the 'Olson Database'. + The exact set of valid values is an implementation-specific + matter. Client discovery of the exact set of time zone names + for a particular server is out of scope."; + reference + "RFC 6557: Procedures for Maintaining the Time Zone Database"; + } + /* + * Features + */ + feature radius { + description + "Indicates that the device can be configured as a RADIUS + client."; + reference + "RFC 2865: Remote Authentication Dial In User Service (RADIUS)"; + } + feature authentication { + description + "Indicates that the device supports configuration of + user authentication."; + } + feature local-users { + if-feature authentication; + description + "Indicates that the device supports configuration of + local user authentication."; + } + feature radius-authentication { + if-feature radius; + if-feature authentication; + description + "Indicates that the device supports configuration of user + authentication over RADIUS."; + reference + "RFC 2865: Remote Authentication Dial In User Service (RADIUS) + RFC 5607: Remote Authentication Dial-In User Service (RADIUS) + Authorization for Network Access Server (NAS) + Management"; + } + feature ntp { + description + "Indicates that the device can be configured to use one or + more NTP servers to set the system date and time."; + } + feature ntp-udp-port { + if-feature ntp; + description + "Indicates that the device supports the configuration of + the UDP port for NTP servers. + This is a 'feature', since many implementations do not support + any port other than the default port."; + } + feature timezone-name { + description + "Indicates that the local time zone on the device + can be configured to use the TZ database + to set the time zone and manage daylight saving time."; + reference + "RFC 6557: Procedures for Maintaining the Time Zone Database"; + } + feature dns-udp-tcp-port { + description + "Indicates that the device supports the configuration of + the UDP and TCP port for DNS servers. + This is a 'feature', since many implementations do not support + any port other than the default port."; + } + /* + * Identities + */ + identity authentication-method { + description + "Base identity for user authentication methods."; + } + identity radius { + base authentication-method; + description + "Indicates user authentication using RADIUS."; + reference + "RFC 2865: Remote Authentication Dial In User Service (RADIUS) + RFC 5607: Remote Authentication Dial-In User Service (RADIUS) + Authorization for Network Access Server (NAS) + Management"; + } + identity local-users { + base authentication-method; + description + "Indicates password-based authentication of locally + configured users."; + } + identity radius-authentication-type { + description + "Base identity for RADIUS authentication types."; + } + identity radius-pap { + base radius-authentication-type; + description + "The device requests Password Authentication Protocol (PAP) + authentication from the RADIUS server."; + reference + "RFC 2865: Remote Authentication Dial In User Service (RADIUS)"; + } + identity radius-chap { + base radius-authentication-type; + description + "The device requests Challenge Handshake Authentication + Protocol (CHAP) authentication from the RADIUS server."; + reference + "RFC 2865: Remote Authentication Dial In User Service (RADIUS)"; + } + /* + * Configuration data nodes + */ + container system { + description + "System group configuration."; + leaf contact { + type string; + description + "The administrator contact information for the system. + A server implementation MAY map this leaf to the sysContact + MIB object. Such an implementation needs to use some + mechanism to handle the differences in size and characters + allowed between this leaf and sysContact. The definition of + such a mechanism is outside the scope of this document."; + reference + "RFC 3418: Management Information Base (MIB) for the + Simple Network Management Protocol (SNMP) + SNMPv2-MIB.sysContact"; + } + leaf hostname { + type inet:domain-name; + description + "The name of the host. This name can be a single domain + label or the fully qualified domain name of the host."; + } + leaf location { + type string; + description + "The system location. + A server implementation MAY map this leaf to the sysLocation + MIB object. Such an implementation needs to use some + mechanism to handle the differences in size and characters + allowed between this leaf and sysLocation. The definition + of such a mechanism is outside the scope of this document."; + reference + "RFC 3418: Management Information Base (MIB) for the + Simple Network Management Protocol (SNMP) + SNMPv2-MIB.sysLocation"; + } + container clock { + description + "Configuration of the system date and time properties."; + choice timezone { + description + "The system time zone information."; + case timezone-name { + if-feature timezone-name; + leaf timezone-name { + type timezone-name; + description + "The TZ database name to use for the system, such + as 'Europe/Stockholm'."; + } + } + case timezone-utc-offset { + leaf timezone-utc-offset { + type int16 { + range "-1500 .. 1500"; + } + units "minutes"; + description + "The number of minutes to add to UTC time to + identify the time zone for this system. For example, + 'UTC - 8:00 hours' would be represented as '-480'. + Note that automatic daylight saving time adjustment + is not provided if this object is used."; + } + } + } + } + container ntp { + if-feature ntp; + presence + "Enables the NTP client unless the 'enabled' leaf + (which defaults to 'true') is set to 'false'"; + description + "Configuration of the NTP client."; + leaf enabled { + type boolean; + default true; + description + "Indicates that the system should attempt to + synchronize the system clock with an NTP server + from the 'ntp/server' list."; + } + list server { + key name; + description + "List of NTP servers to use for system clock + synchronization. If '/system/ntp/enabled' + is 'true', then the system will attempt to + contact and utilize the specified NTP servers."; + leaf name { + type string; + description + "An arbitrary name for the NTP server."; + } + choice transport { + mandatory true; + description + "The transport-protocol-specific parameters for this + server."; + case udp { + container udp { + description + "Contains UDP-specific configuration parameters + for NTP."; + leaf address { + type inet:host; + mandatory true; + description + "The address of the NTP server."; + } + leaf port { + if-feature ntp-udp-port; + type inet:port-number; + default 123; + description + "The port number of the NTP server."; + } + } + } + } + leaf association-type { + type enumeration { + enum server { + description + "Use client association mode. This device + will not provide synchronization to the + configured NTP server."; + } + enum peer { + description + "Use symmetric active association mode. + This device may provide synchronization + to the configured NTP server."; + } + enum pool { + description + "Use client association mode with one or + more of the NTP servers found by DNS + resolution of the domain name given by + the 'address' leaf. This device will not + provide synchronization to the servers."; + } + } + default server; + description + "The desired association type for this NTP server."; + } + leaf iburst { + type boolean; + default false; + description + "Indicates whether this server should enable burst + synchronization or not."; + } + leaf prefer { + type boolean; + default false; + description + "Indicates whether this server should be preferred + or not."; + } + } + } + container dns-resolver { + description + "Configuration of the DNS resolver."; + leaf-list search { + type inet:domain-name; + ordered-by user; + description + "An ordered list of domains to search when resolving + a host name."; + } + list server { + key name; + ordered-by user; + description + "List of the DNS servers that the resolver should query. + When the resolver is invoked by a calling application, it + sends the query to the first name server in this list. If + no response has been received within 'timeout' seconds, + the resolver continues with the next server in the list. + If no response is received from any server, the resolver + continues with the first server again. When the resolver + has traversed the list 'attempts' times without receiving + any response, it gives up and returns an error to the + calling application. + Implementations MAY limit the number of entries in this + list."; + leaf name { + type string; + description + "An arbitrary name for the DNS server."; + } + choice transport { + mandatory true; + description + "The transport-protocol-specific parameters for this + server."; + case udp-and-tcp { + container udp-and-tcp { + description + "Contains UDP- and TCP-specific configuration + parameters for DNS."; + reference + "RFC 1035: Domain Names - Implementation and + Specification + RFC 5966: DNS Transport over TCP - Implementation + Requirements"; + leaf address { + type inet:ip-address; + mandatory true; + description + "The address of the DNS server."; + } + leaf port { + if-feature dns-udp-tcp-port; + type inet:port-number; + default 53; + description + "The UDP and TCP port number of the DNS server."; + } + } + } + } + } + container options { + description + "Resolver options. The set of available options has been + limited to those that are generally available across + different resolver implementations and generally useful."; + leaf timeout { + type uint8 { + range "1..max"; + } + units "seconds"; + default "5"; + description + "The amount of time the resolver will wait for a + response from each remote name server before + retrying the query via a different name server."; + } + leaf attempts { + type uint8 { + range "1..max"; + } + default "2"; + description + "The number of times the resolver will send a query to + all of its name servers before giving up and returning + an error to the calling application."; + } + } + } + container radius { + if-feature radius; + description + "Configuration of the RADIUS client."; + list server { + key name; + ordered-by user; + description + "List of RADIUS servers used by the device. + When the RADIUS client is invoked by a calling + application, it sends the query to the first server in + this list. If no response has been received within + 'timeout' seconds, the client continues with the next + server in the list. If no response is received from any + server, the client continues with the first server again. + When the client has traversed the list 'attempts' times + without receiving any response, it gives up and returns an + error to the calling application."; + leaf name { + type string; + description + "An arbitrary name for the RADIUS server."; + } + choice transport { + mandatory true; + description + "The transport-protocol-specific parameters for this + server."; + case udp { + container udp { + description + "Contains UDP-specific configuration parameters + for RADIUS."; + leaf address { + type inet:host; + mandatory true; + description + "The address of the RADIUS server."; + } + leaf authentication-port { + type inet:port-number; + default "1812"; + description + "The port number of the RADIUS server."; + } + leaf shared-secret { + type string; + mandatory true; + nacm:default-deny-all; + description + "The shared secret, which is known to both the + RADIUS client and server."; + reference + "RFC 2865: Remote Authentication Dial In User + Service (RADIUS)"; + } + } + } + } + leaf authentication-type { + type identityref { + base radius-authentication-type; + } + default radius-pap; + description + "The authentication type requested from the RADIUS + server."; + } + } + container options { + description + "RADIUS client options."; + leaf timeout { + type uint8 { + range "1..max"; + } + units "seconds"; + default "5"; + description + "The number of seconds the device will wait for a + response from each RADIUS server before trying with a + different server."; + } + leaf attempts { + type uint8 { + range "1..max"; + } + default "2"; + description + "The number of times the device will send a query to + all of its RADIUS servers before giving up."; + } + } + } + container authentication { + nacm:default-deny-write; + if-feature authentication; + description + "The authentication configuration subtree."; + leaf-list user-authentication-order { + type identityref { + base authentication-method; + } + must '(. != "sys:radius" or ../../radius/server)' { + error-message + "When 'radius' is used, a RADIUS server" + + " must be configured."; + description + "When 'radius' is used as an authentication method, + a RADIUS server must be configured."; + } + ordered-by user; + description + "When the device authenticates a user with a password, + it tries the authentication methods in this leaf-list in + order. If authentication with one method fails, the next + method is used. If no method succeeds, the user is + denied access. + An empty user-authentication-order leaf-list still allows + authentication of users using mechanisms that do not + involve a password. + If the 'radius-authentication' feature is advertised by + the NETCONF server, the 'radius' identity can be added to + this list. + If the 'local-users' feature is advertised by the + NETCONF server, the 'local-users' identity can be + added to this list."; + } + list user { + if-feature local-users; + key name; + description + "The list of local users configured on this device."; + leaf name { + type string; + description + "The user name string identifying this entry."; + } + leaf password { + type ianach:crypt-hash; + description + "The password for this entry."; + } + list authorized-key { + key name; + description + "A list of public SSH keys for this user. These keys + are allowed for SSH authentication, as described in + RFC 4253."; + reference + "RFC 4253: The Secure Shell (SSH) Transport Layer + Protocol"; + leaf name { + type string; + description + "An arbitrary name for the SSH key."; + } + leaf algorithm { + type string; + mandatory true; + description + "The public key algorithm name for this SSH key. + Valid values are the values in the IANA 'Secure Shell + (SSH) Protocol Parameters' registry, Public Key + Algorithm Names."; + reference + "IANA 'Secure Shell (SSH) Protocol Parameters' + registry, Public Key Algorithm Names"; + } + leaf key-data { + type binary; + mandatory true; + description + "The binary public key data for this SSH key, as + specified by RFC 4253, Section 6.6, i.e.: + string certificate or public key format + identifier + byte[n] key/certificate data."; + reference + "RFC 4253: The Secure Shell (SSH) Transport Layer + Protocol"; + } + } + } + } + } + /* + * Operational state data nodes + */ + container system-state { + config false; + description + "System group operational state."; + container platform { + description + "Contains vendor-specific information for + identifying the system platform and operating system."; + reference + "IEEE Std 1003.1-2008 - sys/utsname.h"; + leaf os-name { + type string; + description + "The name of the operating system in use - + for example, 'Linux'."; + reference + "IEEE Std 1003.1-2008 - utsname.sysname"; + } + leaf os-release { + type string; + description + "The current release level of the operating + system in use. This string MAY indicate + the OS source code revision."; + reference + "IEEE Std 1003.1-2008 - utsname.release"; + } + leaf os-version { + type string; + description + "The current version level of the operating + system in use. This string MAY indicate + the specific OS build date and target variant + information."; + reference + "IEEE Std 1003.1-2008 - utsname.version"; + } + leaf machine { + type string; + description + "A vendor-specific identifier string representing + the hardware in use."; + reference + "IEEE Std 1003.1-2008 - utsname.machine"; + } + } + container clock { + description + "Monitoring of the system date and time properties."; + leaf current-datetime { + type yang:date-and-time; + description + "The current system date and time."; + } + leaf boot-datetime { + type yang:date-and-time; + description + "The system date and time when the system last restarted."; + } + } + } + rpc set-current-datetime { + nacm:default-deny-all; + description + "Set the /system-state/clock/current-datetime leaf + to the specified value. + If the system is using NTP (i.e., /system/ntp/enabled + is set to 'true'), then this operation will fail with + error-tag 'operation-failed' and error-app-tag value of + 'ntp-active'."; + input { + leaf current-datetime { + type yang:date-and-time; + mandatory true; + description + "The current system date and time."; + } + } + } + rpc system-restart { + nacm:default-deny-all; + description + "Request that the entire system be restarted immediately. + A server SHOULD send an rpc reply to the client before + restarting the system."; + } + rpc system-shutdown { + nacm:default-deny-all; + description + "Request that the entire system be shut down immediately. + A server SHOULD send an rpc reply to the client before + shutting down the system."; + } +} diff --git a/holo-yang/src/lib.rs b/holo-yang/src/lib.rs index 5167e0f2..1c7953a1 100644 --- a/holo-yang/src/lib.rs +++ b/holo-yang/src/lib.rs @@ -11,10 +11,10 @@ use std::collections::HashMap; use std::sync::{Arc, LazyLock as Lazy, OnceLock}; use maplit::hashmap; -use yang2::context::{ +use yang3::context::{ Context, ContextFlags, EmbeddedModuleKey, EmbeddedModules, }; -use yang2::data::DataNodeRef; +use yang3::data::DataNodeRef; // Global YANG context. pub static YANG_CTX: OnceLock> = OnceLock::new(); @@ -39,6 +39,8 @@ pub static YANG_EMBEDDED_MODULES: Lazy = Lazy::new(|| { include_str!("../modules/ietf/iana-bgp-rib-types@2023-07-05.yang"), EmbeddedModuleKey::new("iana-bgp-types", Some("2023-07-05"), None, None) => include_str!("../modules/ietf/iana-bgp-types@2023-07-05.yang"), + EmbeddedModuleKey::new("iana-crypt-hash", Some("2014-08-06"), None, None) => + include_str!("../modules/ietf/iana-crypt-hash@2014-08-06.yang"), EmbeddedModuleKey::new("iana-if-type", Some("2017-01-19"), None, None) => include_str!("../modules/ietf/iana-if-type@2017-01-19.yang"), EmbeddedModuleKey::new("iana-routing-types", Some("2018-10-29"), None, None) => @@ -97,12 +99,14 @@ pub static YANG_EMBEDDED_MODULES: Lazy = Lazy::new(|| { include_str!("../modules/ietf/ietf-netconf-acm@2018-02-14.yang"), EmbeddedModuleKey::new("ietf-ospf", Some("2022-10-19"), None, None) => include_str!("../modules/ietf/ietf-ospf@2022-10-19.yang"), - EmbeddedModuleKey::new("ietf-ospf-sr-mpls", Some("2024-01-18"), None, None) => - include_str!("../modules/ietf/ietf-ospf-sr-mpls@2024-01-18.yang"), + EmbeddedModuleKey::new("ietf-ospf-sr-mpls", Some("2024-06-19"), None, None) => + include_str!("../modules/ietf/ietf-ospf-sr-mpls@2024-06-19.yang"), EmbeddedModuleKey::new("ietf-ospfv3-extended-lsa", Some("2024-06-07"), None, None) => include_str!("../modules/ietf/ietf-ospfv3-extended-lsa@2024-06-07.yang"), EmbeddedModuleKey::new("ietf-rip", Some("2020-02-20"), None, None) => include_str!("../modules/ietf/ietf-rip@2020-02-20.yang"), + EmbeddedModuleKey::new("ietf-system", Some("2014-08-06"), None, None) => + include_str!("../modules/ietf/ietf-system@2014-08-06.yang"), EmbeddedModuleKey::new("ietf-routing", Some("2018-03-13"), None, None) => include_str!("../modules/ietf/ietf-routing@2018-03-13.yang"), EmbeddedModuleKey::new("ietf-routing-policy", Some("2021-10-11"), None, None) => @@ -165,6 +169,7 @@ pub static YANG_EMBEDDED_MODULES: Lazy = Lazy::new(|| { include_str!("../modules/deviations/ietf-segment-routing-mpls-holo-deviations.yang"), EmbeddedModuleKey::new("ietf-vrrp-holo-deviations", None, None, None) => include_str!("../modules/deviations/ietf-vrrp-holo-deviations.yang"), + } }); @@ -207,6 +212,7 @@ pub static YANG_IMPLEMENTED_MODULES: Lazy> = "ietf-ospf-sr-mpls", "ietf-ospfv3-extended-lsa", "ietf-rip", + "ietf-system", "ietf-tcp", "ietf-vrrp", // IETF Holo augmentations @@ -355,7 +361,7 @@ pub fn load_module(ctx: &mut Context, name: &str) { // Loads a YANG deviations module. pub fn load_deviations(ctx: &mut Context, name: &str) { - let name = format!("{}-holo-deviations", name); + let name = format!("holo-{}-deviations", name); // Ignore errors since the deviation module might not exist. let _ = ctx.load_module(&name, None, &[]); } diff --git a/holo-yang/src/serde/data_tree.rs b/holo-yang/src/serde/data_tree.rs index 671a6fe8..3402abc7 100644 --- a/holo-yang/src/serde/data_tree.rs +++ b/holo-yang/src/serde/data_tree.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use serde::{Deserialize, Serializer}; -use yang2::data::{ +use yang3::data::{ Data, DataFormat, DataParserFlags, DataPrinterFlags, DataTree, DataValidationFlags, }; diff --git a/proto/holo.proto b/proto/holo.proto index 1aa0768a..985c0f7d 100644 --- a/proto/holo.proto +++ b/proto/holo.proto @@ -93,8 +93,11 @@ message GetRequest { // Encoding to be used. Encoding encoding = 2; + // Include implicit default nodes. + bool with_defaults = 3; + // Requested YANG path. - string path = 3; + string path = 4; } message GetResponse { @@ -239,6 +242,13 @@ enum Encoding { // YANG instance data. message DataTree { + // The encoding format of the data. Encoding encoding = 1; - string data = 2; + + oneof data { + // Data in string format, used for JSON or XML encodings. + string data_string = 2; + // Data in binary format, used for LYB encoding. + bytes data_bytes = 3; + } }