From 7f4733700a21d6a8885ed37091a604ed26c84b45 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Mon, 8 Jul 2024 22:38:31 -0300 Subject: [PATCH] system: introduce the `holo-system` component Introduce `holo-system`, implementing the following subset of the ietf-system YANG module: module: ietf-system +--rw system | +--rw contact? string | +--rw hostname? inet:domain-name | +--rw location? string +--ro system-state +--ro platform | +--ro os-name? string | +--ro os-release? string | +--ro os-version? string | +--ro machine? string +--ro clock +--ro current-datetime? yang:date-and-time +--ro boot-datetime? yang:date-and-time The main motivation for this component is to provide a centralized place for storing hostname information and sharing it with protocol instances (both IS-IS and OSPF have TLVs for flooding hostname information). Additionally, including the hostname in the configuration is necessary for implementing a persistent hostname in holo-cli. Closes #20 Signed-off-by: Renato Westphal --- Cargo.toml | 1 + README.md | 1 + holo-daemon/Cargo.toml | 3 + holo-daemon/src/northbound/core.rs | 14 +- holo-daemon/src/northbound/yang.rs | 3 + holo-system/Cargo.toml | 24 + holo-system/LICENSE | 19 + holo-system/src/ibus.rs | 38 + holo-system/src/lib.rs | 81 ++ holo-system/src/northbound/configuration.rs | 103 +++ holo-system/src/northbound/mod.rs | 32 + holo-system/src/northbound/state.rs | 69 ++ holo-tools/yang-coverage.sh | 3 +- holo-utils/src/ibus.rs | 4 + holo-yang/Cargo.toml | 2 +- .../ietf-system-holo-deviations.yang | 234 ++++++ .../ietf/iana-crypt-hash@2014-08-06.yang | 99 +++ .../modules/ietf/ietf-system@2014-08-06.yang | 711 ++++++++++++++++++ holo-yang/src/lib.rs | 7 + 19 files changed, 1445 insertions(+), 3 deletions(-) create mode 100644 holo-system/Cargo.toml create mode 100644 holo-system/LICENSE create mode 100644 holo-system/src/ibus.rs create mode 100644 holo-system/src/lib.rs create mode 100644 holo-system/src/northbound/configuration.rs create mode 100644 holo-system/src/northbound/mod.rs create mode 100644 holo-system/src/northbound/state.rs create mode 100644 holo-yang/modules/deviations/ietf-system-holo-deviations.yang create mode 100644 holo-yang/modules/ietf/iana-crypt-hash@2014-08-06.yang create mode 100644 holo-yang/modules/ietf/ietf-system@2014-08-06.yang diff --git a/Cargo.toml b/Cargo.toml index 9c6736da..a00bbdc8 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-yang", diff --git a/README.md b/README.md index bbc14874..677079f2 100644 --- a/README.md +++ b/README.md @@ -234,6 +234,7 @@ Holo supports the following IETF RFCs and Internet drafts: | ietf-routing@2018-03-13 | 100.00% | 85.71% | - | - | [92.31%](http://westphal.com.br/holo/ietf-routing.html) | | 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-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-daemon/Cargo.toml b/holo-daemon/Cargo.toml index b49adc4b..ff1e6ca5 100644 --- a/holo-daemon/Cargo.toml +++ b/holo-daemon/Cargo.toml @@ -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-yang = { path = "../holo-yang" } @@ -61,6 +62,7 @@ default = [ "keychain", "policy", "routing", + "system", # Protocols "bfd", "bgp", @@ -74,6 +76,7 @@ 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 = ["dep:holo-bfd", "holo-routing/bfd"] diff --git a/holo-daemon/src/northbound/core.rs b/holo-daemon/src/northbound/core.rs index 228b3ae1..24dfa9da 100644 --- a/holo-daemon/src/northbound/core.rs +++ b/holo-daemon/src/northbound/core.rs @@ -638,7 +638,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; // Start holo-interface. #[cfg(feature = "interface")] @@ -673,6 +674,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/yang.rs b/holo-daemon/src/northbound/yang.rs index d16a691f..9d6577e4 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-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/yang-coverage.sh b/holo-tools/yang-coverage.sh index 446bd24b..3cf60949 100755 --- a/holo-tools/yang-coverage.sh +++ b/holo-tools/yang-coverage.sh @@ -22,4 +22,5 @@ cargo run --bin yang_coverage --\ -m ietf-ospf\ -m ietf-ospf-sr-mpls\ -m ietf-ospfv3-extended-lsa\ - -m ietf-rip + -m ietf-rip\ + -m ietf-system 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-yang/Cargo.toml b/holo-yang/Cargo.toml index 29fdce3d..c853e57c 100644 --- a/holo-yang/Cargo.toml +++ b/holo-yang/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "holo-yang" -version = "0.5.0" +version = "0.5.1" authors.workspace = true license.workspace = true edition.workspace = true diff --git a/holo-yang/modules/deviations/ietf-system-holo-deviations.yang b/holo-yang/modules/deviations/ietf-system-holo-deviations.yang new file mode 100644 index 00000000..0bc13fa5 --- /dev/null +++ b/holo-yang/modules/deviations/ietf-system-holo-deviations.yang @@ -0,0 +1,234 @@ +module ietf-system-holo-deviations { + yang-version 1.1; + namespace "http://holo-routing.org/yang/ietf-system-holo-deviations"; + prefix ietf-system-holo-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-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 7e1d1a92..b433482e 100644 --- a/holo-yang/src/lib.rs +++ b/holo-yang/src/lib.rs @@ -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) => @@ -103,6 +105,8 @@ pub static YANG_EMBEDDED_MODULES: Lazy = Lazy::new(|| { 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) => @@ -151,6 +155,8 @@ pub static YANG_EMBEDDED_MODULES: Lazy = Lazy::new(|| { include_str!("../modules/deviations/ietf-ospfv3-extended-lsa-holo-deviations.yang"), EmbeddedModuleKey::new("ietf-rip-holo-deviations", None, None, None) => include_str!("../modules/deviations/ietf-rip-holo-deviations.yang"), + EmbeddedModuleKey::new("ietf-system-holo-deviations", None, None, None) => + include_str!("../modules/deviations/ietf-system-holo-deviations.yang"), EmbeddedModuleKey::new("ietf-routing-holo-deviations", None, None, None) => include_str!("../modules/deviations/ietf-routing-holo-deviations.yang"), EmbeddedModuleKey::new("ietf-ipv6-unicast-routing-holo-deviations", None, None, None) => @@ -201,6 +207,7 @@ pub static YANG_IMPLEMENTED_MODULES: Lazy> = "ietf-ospf-sr-mpls", "ietf-ospfv3-extended-lsa", "ietf-rip", + "ietf-system", "ietf-tcp", // IETF Holo augmentations "holo-bgp",