holo_yang/
lib.rs

1//
2// Copyright (c) The Holo Core Contributors
3//
4// SPDX-License-Identifier: MIT
5//
6
7pub mod serde;
8
9use std::borrow::Cow;
10use std::collections::HashMap;
11use std::sync::{Arc, LazyLock as Lazy, OnceLock};
12
13use maplit::hashmap;
14use yang3::context::{
15    Context, ContextFlags, EmbeddedModuleKey, EmbeddedModules,
16};
17use yang3::data::DataNodeRef;
18
19// Global YANG context.
20pub static YANG_CTX: OnceLock<Arc<Context>> = OnceLock::new();
21
22// List of embedded YANG modules.
23//
24// All implemented or imported modules need to be specified here. Holo by
25// default doesn't support loading YANG modules from the filesystem.
26pub static YANG_EMBEDDED_MODULES: Lazy<EmbeddedModules> = Lazy::new(|| {
27    hashmap! {
28        // IEEE modules
29        EmbeddedModuleKey::new("ieee802-dot1q-types", Some("2022-01-19"), None, None) =>
30            include_str!("../modules/ieee/ieee802-dot1q-types@2022-01-19.yang"),
31        // IETF modules
32        EmbeddedModuleKey::new("iana-bfd-types", Some("2021-10-21"), None, None) =>
33            include_str!("../modules/ietf/iana-bfd-types@2021-10-21.yang"),
34        EmbeddedModuleKey::new("iana-bgp-community-types", Some("2023-07-05"), None, None) =>
35            include_str!("../modules/ietf/iana-bgp-community-types@2023-07-05.yang"),
36        EmbeddedModuleKey::new("iana-bgp-notification", Some("2023-07-05"), None, None) =>
37            include_str!("../modules/ietf/iana-bgp-notification@2023-07-05.yang"),
38        EmbeddedModuleKey::new("iana-bgp-rib-types", Some("2023-07-05"), None, None) =>
39            include_str!("../modules/ietf/iana-bgp-rib-types@2023-07-05.yang"),
40        EmbeddedModuleKey::new("iana-bgp-types", Some("2023-07-05"), None, None) =>
41            include_str!("../modules/ietf/iana-bgp-types@2023-07-05.yang"),
42        EmbeddedModuleKey::new("iana-crypt-hash", Some("2014-08-06"), None, None) =>
43            include_str!("../modules/ietf/iana-crypt-hash@2014-08-06.yang"),
44        EmbeddedModuleKey::new("iana-if-type", Some("2017-01-19"), None, None) =>
45            include_str!("../modules/ietf/iana-if-type@2017-01-19.yang"),
46        EmbeddedModuleKey::new("iana-routing-types", Some("2018-10-29"), None, None) =>
47            include_str!("../modules/ietf/iana-routing-types@2018-10-29.yang"),
48        EmbeddedModuleKey::new("ietf-bfd-ip-mh", Some("2022-09-22"), None, None) =>
49            include_str!("../modules/ietf/ietf-bfd-ip-mh@2022-09-22.yang"),
50        EmbeddedModuleKey::new("ietf-bfd-ip-sh", Some("2022-09-22"), None, None) =>
51            include_str!("../modules/ietf/ietf-bfd-ip-sh@2022-09-22.yang"),
52        EmbeddedModuleKey::new("ietf-bfd-types", Some("2022-09-22"), None, None) =>
53            include_str!("../modules/ietf/ietf-bfd-types@2022-09-22.yang"),
54        EmbeddedModuleKey::new("ietf-bfd", Some("2022-09-22"), None, None) =>
55            include_str!("../modules/ietf/ietf-bfd@2022-09-22.yang"),
56        EmbeddedModuleKey::new("ietf-bier", Some("2023-09-16"), None, None) =>
57            include_str!("../modules/ietf/ietf-bier@2023-09-16.yang"),
58        EmbeddedModuleKey::new("ietf-bgp", Some("2023-07-05"), None, None) =>
59            include_str!("../modules/ietf/ietf-bgp@2023-07-05.yang"),
60        EmbeddedModuleKey::new("ietf-bgp", Some("2023-07-05"), Some("ietf-bgp-capabilities"), Some("2023-07-05")) =>
61            include_str!("../modules/ietf/ietf-bgp-capabilities@2023-07-05.yang"),
62        EmbeddedModuleKey::new("ietf-bgp", Some("2023-07-05"), Some("ietf-bgp-common"), Some("2023-07-05")) =>
63            include_str!("../modules/ietf/ietf-bgp-common@2023-07-05.yang"),
64        EmbeddedModuleKey::new("ietf-bgp", Some("2023-07-05"), Some("ietf-bgp-common-multiprotocol"), Some("2023-07-05")) =>
65            include_str!("../modules/ietf/ietf-bgp-common-multiprotocol@2023-07-05.yang"),
66        EmbeddedModuleKey::new("ietf-bgp", Some("2023-07-05"), Some("ietf-bgp-common-structure"), Some("2023-07-05")) =>
67            include_str!("../modules/ietf/ietf-bgp-common-structure@2023-07-05.yang"),
68        EmbeddedModuleKey::new("ietf-bgp", Some("2023-07-05"), Some("ietf-bgp-neighbor"), Some("2023-07-05")) =>
69            include_str!("../modules/ietf/ietf-bgp-neighbor@2023-07-05.yang"),
70        EmbeddedModuleKey::new("ietf-bgp", Some("2023-07-05"), Some("ietf-bgp-rib"), Some("2023-07-05")) =>
71            include_str!("../modules/ietf/ietf-bgp-rib@2023-07-05.yang"),
72        EmbeddedModuleKey::new("ietf-bgp", Some("2023-07-05"), Some("ietf-bgp-rib-attributes"), Some("2023-07-05")) =>
73            include_str!("../modules/ietf/ietf-bgp-rib-attributes@2023-07-05.yang"),
74        EmbeddedModuleKey::new("ietf-bgp", Some("2023-07-05"), Some("ietf-bgp-rib-tables"), Some("2023-07-05")) =>
75            include_str!("../modules/ietf/ietf-bgp-rib-tables@2023-07-05.yang"),
76        EmbeddedModuleKey::new("ietf-bgp-policy", Some("2023-07-05"), None, None) =>
77            include_str!("../modules/ietf/ietf-bgp-policy@2023-07-05.yang"),
78        EmbeddedModuleKey::new("ietf-if-extensions", Some("2023-01-26"), None, None) =>
79            include_str!("../modules/ietf/ietf-if-extensions@2023-01-26.yang"),
80        EmbeddedModuleKey::new("ietf-if-vlan-encapsulation", Some("2023-01-26"), None, None) =>
81            include_str!("../modules/ietf/ietf-if-vlan-encapsulation@2023-01-26.yang"),
82        EmbeddedModuleKey::new("ietf-interfaces", Some("2018-02-20"), None, None) =>
83            include_str!("../modules/ietf/ietf-interfaces@2018-02-20.yang"),
84        EmbeddedModuleKey::new("ietf-ip", Some("2018-02-22"), None, None) =>
85            include_str!("../modules/ietf/ietf-ip@2018-02-22.yang"),
86        EmbeddedModuleKey::new("ietf-ipv4-unicast-routing", Some("2018-03-13"), None, None) =>
87            include_str!("../modules/ietf/ietf-ipv4-unicast-routing@2018-03-13.yang"),
88        EmbeddedModuleKey::new("ietf-ipv6-unicast-routing", Some("2018-03-13"), None, None) =>
89            include_str!("../modules/ietf/ietf-ipv6-unicast-routing@2018-03-13.yang"),
90        EmbeddedModuleKey::new("ietf-ipv6-unicast-routing", Some("2018-03-13"), Some("ietf-ipv6-router-advertisements"), Some("2018-03-13")) =>
91            include_str!("../modules/ietf/ietf-ipv6-router-advertisements@2018-03-13.yang"),
92        EmbeddedModuleKey::new("ietf-isis", Some("2022-10-19"), None, None) =>
93            include_str!("../modules/ietf/ietf-isis@2022-10-19.yang"),
94        EmbeddedModuleKey::new("ietf-key-chain", Some("2017-06-15"), None, None) =>
95            include_str!("../modules/ietf/ietf-key-chain@2017-06-15.yang"),
96        EmbeddedModuleKey::new("ietf-mpls", Some("2020-12-18"), None, None) =>
97            include_str!("../modules/ietf/ietf-mpls@2020-12-18.yang"),
98        EmbeddedModuleKey::new("ietf-mpls-ldp", Some("2022-03-14"), None, None) =>
99            include_str!("../modules/ietf/ietf-mpls-ldp@2022-03-14.yang"),
100        EmbeddedModuleKey::new("ietf-netconf-acm", Some("2018-02-14"), None, None) =>
101            include_str!("../modules/ietf/ietf-netconf-acm@2018-02-14.yang"),
102        EmbeddedModuleKey::new("ietf-ospf", Some("2022-10-19"), None, None) =>
103            include_str!("../modules/ietf/ietf-ospf@2022-10-19.yang"),
104        EmbeddedModuleKey::new("ietf-ospf-sr-mpls", Some("2024-06-19"), None, None) =>
105            include_str!("../modules/ietf/ietf-ospf-sr-mpls@2024-06-19.yang"),
106        EmbeddedModuleKey::new("ietf-ospfv3-extended-lsa", Some("2024-06-07"), None, None) =>
107            include_str!("../modules/ietf/ietf-ospfv3-extended-lsa@2024-06-07.yang"),
108        EmbeddedModuleKey::new("ietf-rip", Some("2020-02-20"), None, None) =>
109            include_str!("../modules/ietf/ietf-rip@2020-02-20.yang"),
110        EmbeddedModuleKey::new("ietf-system", Some("2014-08-06"), None, None) =>
111            include_str!("../modules/ietf/ietf-system@2014-08-06.yang"),
112        EmbeddedModuleKey::new("ietf-routing", Some("2018-03-13"), None, None) =>
113            include_str!("../modules/ietf/ietf-routing@2018-03-13.yang"),
114        EmbeddedModuleKey::new("ietf-routing-policy", Some("2021-10-11"), None, None) =>
115            include_str!("../modules/ietf/ietf-routing-policy@2021-10-11.yang"),
116        EmbeddedModuleKey::new("ietf-routing-types", Some("2017-12-04"), None, None) =>
117            include_str!("../modules/ietf/ietf-routing-types@2017-12-04.yang"),
118        EmbeddedModuleKey::new("ietf-segment-routing-common", Some("2021-05-26"), None, None) =>
119            include_str!("../modules/ietf/ietf-segment-routing-common@2021-05-26.yang"),
120        EmbeddedModuleKey::new("ietf-segment-routing-mpls", Some("2021-05-26"), None, None) =>
121            include_str!("../modules/ietf/ietf-segment-routing-mpls@2021-05-26.yang"),
122        EmbeddedModuleKey::new("ietf-segment-routing", Some("2021-05-26"), None, None) =>
123            include_str!("../modules/ietf/ietf-segment-routing@2021-05-26.yang"),
124        EmbeddedModuleKey::new("ietf-tcp", Some("2022-09-11"), None, None) =>
125            include_str!("../modules/ietf/ietf-tcp@2022-09-11.yang"),
126        EmbeddedModuleKey::new("ietf-tcp-common", Some("2023-04-17"), None, None) =>
127            include_str!("../modules/ietf/ietf-tcp-common@2023-04-17.yang"),
128        // IETF Holo augmentations
129        EmbeddedModuleKey::new("holo-bgp", None, None, None) =>
130            include_str!("../modules/augmentations/holo-bgp.yang"),
131        EmbeddedModuleKey::new("holo-ospf", None, None, None) =>
132            include_str!("../modules/augmentations/holo-ospf.yang"),
133        EmbeddedModuleKey::new("holo-ospf-dev", None, None, None) =>
134            include_str!("../modules/augmentations/holo-ospf-dev.yang"),
135        EmbeddedModuleKey::new("holo-routing", None, None, None) =>
136            include_str!("../modules/augmentations/holo-routing.yang"),
137        // IETF Holo deviations
138        EmbeddedModuleKey::new("holo-ietf-bgp-deviations", None, None, None) =>
139            include_str!("../modules/deviations/holo-ietf-bgp-deviations.yang"),
140        EmbeddedModuleKey::new("holo-ietf-bier-deviations", None, None, None) =>
141            include_str!("../modules/deviations/holo-ietf-bier-deviations.yang"),
142        EmbeddedModuleKey::new("holo-ietf-mpls-ldp-deviations", None, None, None) =>
143            include_str!("../modules/deviations/holo-ietf-mpls-ldp-deviations.yang"),
144        EmbeddedModuleKey::new("holo-ietf-if-extensions-deviations", None, None, None) =>
145            include_str!("../modules/deviations/holo-ietf-if-extensions-deviations.yang"),
146        EmbeddedModuleKey::new("holo-ietf-if-vlan-encapsulation-deviations", None, None, None) =>
147            include_str!("../modules/deviations/holo-ietf-if-vlan-encapsulation-deviations.yang"),
148        EmbeddedModuleKey::new("holo-ietf-interfaces-deviations", None, None, None) =>
149            include_str!("../modules/deviations/holo-ietf-interfaces-deviations.yang"),
150        EmbeddedModuleKey::new("holo-ietf-ip-deviations", None, None, None) =>
151            include_str!("../modules/deviations/holo-ietf-ip-deviations.yang"),
152        EmbeddedModuleKey::new("holo-ietf-mpls-deviations", None, None, None) =>
153            include_str!("../modules/deviations/holo-ietf-mpls-deviations.yang"),
154        EmbeddedModuleKey::new("holo-ietf-key-chain-deviations", None, None, None) =>
155            include_str!("../modules/deviations/holo-ietf-key-chain-deviations.yang"),
156        EmbeddedModuleKey::new("holo-ietf-ospf-deviations", None, None, None) =>
157            include_str!("../modules/deviations/holo-ietf-ospf-deviations.yang"),
158        EmbeddedModuleKey::new("holo-ietf-ospf-sr-mpls-deviations", None, None, None) =>
159            include_str!("../modules/deviations/holo-ietf-ospf-sr-mpls-deviations.yang"),
160        EmbeddedModuleKey::new("holo-ietf-ospfv3-extended-lsa-deviations", None, None, None) =>
161            include_str!("../modules/deviations/holo-ietf-ospfv3-extended-lsa-deviations.yang"),
162        EmbeddedModuleKey::new("holo-ietf-rip-deviations", None, None, None) =>
163            include_str!("../modules/deviations/holo-ietf-rip-deviations.yang"),
164        EmbeddedModuleKey::new("holo-ietf-system-deviations", None, None, None) =>
165            include_str!("../modules/deviations/holo-ietf-system-deviations.yang"),
166        EmbeddedModuleKey::new("holo-ietf-routing-deviations", None, None, None) =>
167            include_str!("../modules/deviations/holo-ietf-routing-deviations.yang"),
168        EmbeddedModuleKey::new("holo-ietf-ipv6-unicast-routing-deviations", None, None, None) =>
169            include_str!("../modules/deviations/holo-ietf-ipv6-unicast-routing-deviations.yang"),
170        EmbeddedModuleKey::new("holo-ietf-routing-policy-deviations", None, None, None) =>
171            include_str!("../modules/deviations/holo-ietf-routing-policy-deviations.yang"),
172        EmbeddedModuleKey::new("holo-ietf-segment-routing-mpls-deviations", None, None, None) =>
173            include_str!("../modules/deviations/holo-ietf-segment-routing-mpls-deviations.yang"),
174    }
175});
176
177// All modules currently implemented.
178//
179// The list includes modules that define YANG identities that can be
180// instantiated.
181pub static YANG_IMPLEMENTED_MODULES: Lazy<Vec<&'static str>> =
182    Lazy::new(|| {
183        vec![
184            // IEEE modules
185            "ieee802-dot1q-types",
186            // IETF modules
187            "iana-if-type",
188            "iana-bgp-notification",
189            "iana-bgp-rib-types",
190            "iana-bgp-types",
191            "ietf-bfd-ip-mh",
192            "ietf-bfd-ip-sh",
193            "ietf-bfd-types",
194            "ietf-bfd",
195            "ietf-bgp",
196            "ietf-bgp-policy",
197            "ietf-bier",
198            "ietf-routing-types",
199            "ietf-if-extensions",
200            "ietf-if-vlan-encapsulation",
201            "ietf-interfaces",
202            "ietf-ip",
203            "ietf-key-chain",
204            "ietf-routing",
205            "ietf-routing-policy",
206            "ietf-ipv4-unicast-routing",
207            "ietf-ipv6-unicast-routing",
208            "ietf-segment-routing",
209            "ietf-segment-routing-common",
210            "ietf-segment-routing-mpls",
211            "ietf-mpls",
212            "ietf-mpls-ldp",
213            "ietf-ospf",
214            "ietf-ospf-sr-mpls",
215            "ietf-ospfv3-extended-lsa",
216            "ietf-rip",
217            "ietf-system",
218            "ietf-tcp",
219            // IETF Holo augmentations
220            "holo-bgp",
221            "holo-ospf",
222            "holo-ospf-dev",
223            "holo-routing",
224        ]
225    });
226
227// All features currently supported.
228pub static YANG_FEATURES: Lazy<HashMap<&'static str, Vec<&'static str>>> =
229    Lazy::new(|| {
230        hashmap! {
231            "iana-bgp-types" => vec![
232                "clear-neighbors",
233                "route-refresh",
234                "ttl-security",
235            ],
236            "ietf-bfd-types" => vec![
237                "client-base-cfg-parms",
238                "single-minimum-interval",
239            ],
240            "ietf-key-chain" => vec![
241                "hex-key-string",
242                "independent-send-accept-lifetime",
243            ],
244            "ietf-if-extensions" => vec![
245                "sub-interfaces",
246            ],
247            "ietf-ospf" => vec![
248                "bfd",
249                "explicit-router-id",
250                "graceful-restart",
251                "ietf-spf-delay",
252                "key-chain",
253                "max-ecmp",
254                "mtu-ignore",
255                "ospfv3-authentication-trailer",
256                "stub-router",
257            ],
258            "ietf-rip" => vec![
259                "explicit-neighbors",
260                "global-statistics",
261                "interface-statistics",
262            ],
263            "ietf-segment-routing-common" => vec![
264                "sid-last-hop-behavior",
265            ],
266        }
267    });
268
269//
270// YANG conversion traits.
271//
272
273pub trait ToYang {
274    // Return YANG textual representation of the value.
275    fn to_yang(&self) -> Cow<'static, str>;
276}
277
278pub trait ToYangBits {
279    // Return vector representing YANG bit set.
280    fn to_yang_bits(&self) -> Vec<&'static str>;
281}
282
283pub trait TryFromYang: Sized {
284    // Construct value from YANG identity or enum value.
285    fn try_from_yang(identity: &str) -> Option<Self>;
286}
287
288// A trait representing YANG objects (containers or lists).
289//
290// This trait is automatically implemented for all structs generated from
291// YANG definitions at build-time.
292pub trait YangObject {
293    // Initialize a given YANG data node with attributes from the current
294    // object.
295    fn into_data_node(self: Box<Self>, dnode: &mut DataNodeRef<'_, '_>);
296
297    // Return the keys of the list, or an empty string for containers or keyless
298    // lists.
299    fn list_keys(&self) -> String {
300        String::new()
301    }
302}
303
304//
305// YANG path type.
306//
307// Instances of this structure are created automatically at build-time, and
308// their use should be preferred over regular strings for extra type safety.
309//
310#[derive(Clone, Copy, Debug)]
311pub struct YangPath(&'static str);
312
313// ===== impl YangPath =====
314
315impl YangPath {
316    pub const fn new(path: &'static str) -> YangPath {
317        YangPath(path)
318    }
319
320    pub fn as_str(&self) -> &'static str {
321        self.0
322    }
323}
324
325impl std::fmt::Display for YangPath {
326    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
327        write!(f, "{}", self.0)
328    }
329}
330
331impl AsRef<str> for YangPath {
332    fn as_ref(&self) -> &str {
333        self.0
334    }
335}
336
337// ===== global functions =====
338
339// Creates empty YANG context.
340pub fn new_context() -> Context {
341    let mut ctx = Context::new(
342        ContextFlags::NO_YANGLIBRARY | ContextFlags::DISABLE_SEARCHDIRS,
343    )
344    .expect("Failed to create YANG context");
345    ctx.set_embedded_modules(&YANG_EMBEDDED_MODULES);
346    ctx
347}
348
349// Loads a YANG module.
350pub fn load_module(ctx: &mut Context, name: &str) {
351    let features = YANG_FEATURES
352        .get(name)
353        .map(|features| features.as_slice())
354        .unwrap_or_else(|| &[]);
355    if let Err(error) = ctx.load_module(name, None, features) {
356        panic!("failed to load YANG module: {}", error);
357    }
358}
359
360// Loads a YANG deviations module.
361pub fn load_deviations(ctx: &mut Context, name: &str) {
362    let name = format!("holo-{}-deviations", name);
363    // Ignore errors since the deviation module might not exist.
364    let _ = ctx.load_module(&name, None, &[]);
365}