diff --git a/Cargo.toml b/Cargo.toml index 166cd429..c8967b3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "holo-bfd", + "holo-bgp", "holo-cli", "holo-daemon", "holo-interface", diff --git a/README.md b/README.md index 0558af9c..c20e1d21 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,30 @@ Holo supports the following IETF RFCs and Internet drafts: * RFC 5882 - Generic Application of Bidirectional Forwarding Detection (BFD) * RFC 5883 - Bidirectional Forwarding Detection (BFD) for Multihop Paths +##### BGP + +* RFC 1997 - BGP Communities Attribute +* RFC 2385 - Protection of BGP Sessions via the TCP MD5 Signature Option +* RFC 2545 - Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing +* RFC 2918 - Route Refresh Capability for BGP-4 +* RFC 4271 - A Border Gateway Protocol 4 (BGP-4) +* RFC 4360 - BGP Extended Communities Attribute +* RFC 4486 - Subcodes for BGP Cease Notification Message +* RFC 4760 - Multiprotocol Extensions for BGP-4 +* RFC 5082 - The Generalized TTL Security Mechanism (GTSM) +* RFC 5492 - Capabilities Advertisement with BGP-4 +* RFC 5668 - 4-Octet AS Specific BGP Extended Community +* RFC 5701 - IPv6 Address Specific BGP Extended Community Attribute +* RFC 6286 - Autonomous-System-Wide Unique BGP Identifier for BGP-4 +* RFC 6608 - Subcodes for BGP Finite State Machine Error +* RFC 6793 - BGP Support for Four-Octet Autonomous System (AS) Number Space +* RFC 7606 - Revised Error Handling for BGP UPDATE Messages +* RFC 7607 - Codification of AS 0 Processing +* RFC 8092 - BGP Large Communities Attribute +* RFC 8212 - Default External BGP (EBGP) Route Propagation Behavior without Policies +* RFC 8642 - Policy Behavior for Well-Known BGP Communities +* RFC 9072 - Extended Optional Parameters Length for BGP OPEN Message + ##### MPLS LDP * RFC 5036 - LDP Specification @@ -192,6 +216,8 @@ Holo supports the following IETF RFCs and Internet drafts: | ietf-bfd-ip-mh@2022-09-22 | 100.00% | 100.00% | - | 100.00% | [100.00%](http://westphal.com.br/holo/ietf-bfd-ip-mh.html) | | ietf-bfd-ip-sh@2022-09-22 | 100.00% | 100.00% | - | 100.00% | [100.00%](http://westphal.com.br/holo/ietf-bfd-ip-sh.html) | | ietf-bfd@2022-09-22 | 100.00% | 100.00% | - | - | [100.00%](http://westphal.com.br/holo/ietf-bfd.html) | +| ietf-bgp-policy@2023-07-05 | 100.00% | - | - | - | [100.00%](http://westphal.com.br/holo/ietf-bgp-policy.html) | +| ietf-bgp@2023-07-05 | 39.43% | 93.33% | - | - | [67.62%](http://westphal.com.br/holo/ietf-bgp.html) | | ietf-interfaces@2018-01-09 | 100.00% | 0.00% | - | - | [22.22%](http://westphal.com.br/holo/ietf-interfaces.html) | | ietf-ip@2018-01-09 | 17.39% | 0.00% | - | - | [13.33%](http://westphal.com.br/holo/ietf-ip.html) | | ietf-ipv4-unicast-routing@2018-03-13 | 100.00% | 100.00% | - | - | [100.00%](http://westphal.com.br/holo/ietf-ipv4-unicast-routing.html) | diff --git a/holo-bgp/Cargo.toml b/holo-bgp/Cargo.toml new file mode 100644 index 00000000..9fc83c49 --- /dev/null +++ b/holo-bgp/Cargo.toml @@ -0,0 +1,53 @@ +[package] +name = "holo-bgp" +version.workspace = true +authors.workspace = true +license.workspace = true +edition.workspace = true + +[dependencies] +async-trait.workspace = true +bitflags.workspace = true +bytes.workspace = true +chrono.workspace = true +derive-new.workspace = true +enum-as-inner.workspace = true +generational-arena.workspace = true +ipnetwork.workspace = true +itertools.workspace = true +libc.workspace = true +num-derive.workspace = true +num-traits.workspace = true +rand.workspace = true +serde.workspace = true +serde_json.workspace = true +tokio.workspace = true +tracing.workspace = true +yang2.workspace = true + +holo-northbound = { path = "../holo-northbound" } +holo-protocol = { path = "../holo-protocol" } +holo-utils = { path = "../holo-utils" } +holo-yang = { path = "../holo-yang" } + +[dev-dependencies] +criterion.workspace = true + +holo-bgp = { path = ".", features = ["testing"] } +holo-protocol = { path = "../holo-protocol", features = ["testing"] } +holo-utils = { path = "../holo-utils", features = ["testing"] } + +[lints] +workspace = true + +[features] +default = [] +testing = [] + +[[bench]] +name = "msg_encoding" +harness = false + +[[bench]] +name = "msg_decoding" +harness = false diff --git a/holo-bgp/LICENSE b/holo-bgp/LICENSE new file mode 100644 index 00000000..4481fc10 --- /dev/null +++ b/holo-bgp/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-bgp/benches/msg_decoding.rs b/holo-bgp/benches/msg_decoding.rs new file mode 100644 index 00000000..d79ac600 --- /dev/null +++ b/holo-bgp/benches/msg_decoding.rs @@ -0,0 +1,30 @@ +#![feature(lazy_cell)] + +use std::hint::black_box; + +use criterion::{criterion_group, criterion_main, Criterion}; +use holo_bgp::packet::message::Message; + +fn msg_decode(n: u64) { + let bytes = vec![ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x3d, 0x01, 0x04, 0x00, 0x01, 0x00, 0xb4, + 0x01, 0x01, 0x01, 0x01, 0x20, 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, + 0x01, 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, 0x02, 0x02, 0x02, + 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x01, 0x00, 0x0e, 0x02, 0x02, 0x46, + 0x00, + ]; + + for _ in 0..n { + let _msg = Message::decode(&bytes).unwrap(); + } +} + +fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("Message decode", |b| { + b.iter(|| msg_decode(black_box(10000))) + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/holo-bgp/benches/msg_encoding.rs b/holo-bgp/benches/msg_encoding.rs new file mode 100644 index 00000000..d3af3b99 --- /dev/null +++ b/holo-bgp/benches/msg_encoding.rs @@ -0,0 +1,48 @@ +#![feature(lazy_cell)] + +use std::hint::black_box; +use std::net::Ipv4Addr; +use std::str::FromStr; +use std::sync::LazyLock as Lazy; + +use criterion::{criterion_group, criterion_main, Criterion}; +use holo_bgp::packet::message::{Capability, Message, OpenMsg, BGP_VERSION}; +use holo_bgp::packet::{Afi, Safi}; + +static MESSAGE: Lazy = Lazy::new(|| { + Message::Open(OpenMsg { + version: BGP_VERSION, + my_as: 1, + holdtime: 180, + identifier: Ipv4Addr::from_str("1.1.1.1").unwrap(), + capabilities: [ + Capability::MultiProtocol { + afi: Afi::Ipv4, + safi: Safi::Unicast, + }, + Capability::MultiProtocol { + afi: Afi::Ipv6, + safi: Safi::Unicast, + }, + Capability::FourOctetAsNumber { asn: 65550 }, + Capability::RouteRefresh, + Capability::EnhancedRouteRefresh, + ] + .into(), + }) +}); + +fn msg_encode(n: u64) { + for _ in 0..n { + MESSAGE.encode(); + } +} + +fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("Message encode", |b| { + b.iter(|| msg_encode(black_box(10000))) + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/holo-bgp/src/debug.rs b/holo-bgp/src/debug.rs new file mode 100644 index 00000000..f661a816 --- /dev/null +++ b/holo-bgp/src/debug.rs @@ -0,0 +1,137 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::net::IpAddr; + +use tracing::{debug, debug_span}; + +use crate::neighbor::fsm; +use crate::packet::message::Message; + +// BGP debug messages. +#[derive(Debug)] +pub enum Debug<'a> { + InstanceCreate, + InstanceDelete, + InstanceStart, + InstanceStop(InstanceInactiveReason), + InstanceStatusCheck(&'a str), + NbrFsmEvent(&'a IpAddr, &'a fsm::Event), + NbrFsmTransition(&'a IpAddr, &'a fsm::State, &'a fsm::State), + NbrMsgRx(&'a IpAddr, &'a Message), + NbrMsgTx(&'a IpAddr, &'a Message), +} + +// Reason why an BGP instance is inactive. +#[derive(Debug)] +pub enum InstanceInactiveReason { + AdminDown, + MissingRouterId, +} + +// ===== impl Debug ===== + +impl<'a> Debug<'a> { + // Log debug message using the tracing API. + pub(crate) fn log(&self) { + match self { + Debug::InstanceCreate + | Debug::InstanceDelete + | Debug::InstanceStart => { + // Parent span(s): bgp-instance + debug!("{}", self); + } + Debug::InstanceStop(reason) => { + // Parent span(s): bgp-instance + debug!(%reason, "{}", self); + } + Debug::InstanceStatusCheck(status) => { + // Parent span(s): bgp-instance + debug!(%status, "{}", self); + } + Debug::NbrFsmEvent(nbr_addr, event) => { + // Parent span(s): bgp-instance + debug_span!("neighbor", %nbr_addr).in_scope(|| { + debug_span!("fsm").in_scope(|| { + debug!(?event, "{}", self); + }) + }); + } + Debug::NbrFsmTransition(nbr_addr, old_state, new_state) => { + // Parent span(s): bgp-instance + debug_span!("neighbor", %nbr_addr).in_scope(|| { + debug_span!("fsm").in_scope(|| { + debug!(?old_state, ?new_state, "{}", self); + }) + }); + } + Debug::NbrMsgRx(nbr_addr, msg) => { + // Parent span(s): bgp-instance + debug_span!("neighbor", %nbr_addr).in_scope(|| { + debug_span!("input").in_scope(|| { + let data = serde_json::to_string(&msg).unwrap(); + debug!(%data, "{}", self); + }) + }); + } + Debug::NbrMsgTx(nbr_addr, msg) => { + // Parent span(s): bgp-instance + debug_span!("neighbor", %nbr_addr).in_scope(|| { + debug_span!("output").in_scope(|| { + let data = serde_json::to_string(&msg).unwrap(); + debug!(%data, "{}", self); + }) + }); + } + } + } +} + +impl<'a> std::fmt::Display for Debug<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Debug::InstanceCreate => { + write!(f, "instance created") + } + Debug::InstanceDelete => { + write!(f, "instance deleted") + } + Debug::InstanceStart => { + write!(f, "starting instance") + } + Debug::InstanceStop(..) => { + write!(f, "stopping instance") + } + Debug::InstanceStatusCheck(..) => { + write!(f, "checking instance status") + } + Debug::NbrFsmEvent(..) => { + write!(f, "event") + } + Debug::NbrFsmTransition(..) => { + write!(f, "state transition") + } + Debug::NbrMsgRx(..) | Debug::NbrMsgTx(..) => { + write!(f, "message") + } + } + } +} + +// ===== impl InstanceInactiveReason ===== + +impl std::fmt::Display for InstanceInactiveReason { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + InstanceInactiveReason::AdminDown => { + write!(f, "administrative status down") + } + InstanceInactiveReason::MissingRouterId => { + write!(f, "missing router-id") + } + } + } +} diff --git a/holo-bgp/src/error.rs b/holo-bgp/src/error.rs new file mode 100644 index 00000000..82f091fc --- /dev/null +++ b/holo-bgp/src/error.rs @@ -0,0 +1,220 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::net::{IpAddr, Ipv4Addr}; + +use serde::{Deserialize, Serialize}; +use tracing::{error, warn, warn_span}; + +use crate::packet::error::DecodeError; + +// BGP errors. +#[derive(Debug)] +pub enum Error { + // I/O errors + IoError(IoError), + // Network input + NbrRxError(NbrRxError), + // Message processing + NbrBadAs(IpAddr, u32, u32), + NbrBadIdentifier(IpAddr, Ipv4Addr), + // Other + InstanceStartError(Box), +} + +// BGP I/O errors. +#[derive(Debug)] +pub enum IoError { + TcpSocketError(std::io::Error), + TcpAcceptError(std::io::Error), + TcpConnectError(std::io::Error), + TcpInfoError(std::io::Error), + TcpAuthError(std::io::Error), + TcpRecvError(std::io::Error), + TcpSendError(std::io::Error), +} + +// Neighbor RX errors. +#[derive(Debug)] +#[derive(Deserialize, Serialize)] +pub enum NbrRxError { + TcpConnClosed(IpAddr), + MsgDecodeError(IpAddr, DecodeError), +} + +// ===== impl Error ===== + +impl Error { + pub(crate) fn log(&self) { + match self { + Error::IoError(error) => { + error.log(); + } + Error::NbrRxError(error) => { + error.log(); + } + Error::NbrBadAs(addr, received, expected) => { + warn_span!("neighbor", %addr).in_scope(|| { + warn!(%received, %expected, "{}", self); + }); + } + Error::NbrBadIdentifier(addr, identifier) => { + warn_span!("neighbor", %addr).in_scope(|| { + warn!(%identifier, "{}", self); + }); + } + Error::InstanceStartError(error) => { + error!(error = %with_source(error), "{}", self); + } + } + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Error::IoError(error) => error.fmt(f), + Error::NbrRxError(error) => error.fmt(f), + Error::NbrBadAs(..) => { + write!(f, "bad peer AS") + } + Error::NbrBadIdentifier(..) => { + write!(f, "BGP identifier conflict") + } + Error::InstanceStartError(..) => { + write!(f, "failed to start instance") + } + } + } +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Error::IoError(error) => Some(error), + Error::NbrRxError(error) => Some(error), + Error::InstanceStartError(error) => Some(error), + _ => None, + } + } +} + +impl From for Error { + fn from(error: IoError) -> Error { + Error::IoError(error) + } +} + +// ===== impl IoError ===== + +impl IoError { + pub(crate) fn log(&self) { + match self { + IoError::TcpSocketError(error) + | IoError::TcpAcceptError(error) + | IoError::TcpConnectError(error) + | IoError::TcpAuthError(error) + | IoError::TcpInfoError(error) + | IoError::TcpRecvError(error) + | IoError::TcpSendError(error) => { + warn!(error = %with_source(error), "{}", self); + } + } + } +} + +impl std::fmt::Display for IoError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + IoError::TcpSocketError(..) => { + write!(f, "failed to create TCP socket") + } + IoError::TcpAcceptError(..) => { + write!(f, "failed to accept connection request") + } + IoError::TcpConnectError(..) => { + write!(f, "failed to establish TCP connection") + } + IoError::TcpAuthError(..) => { + write!(f, "failed to set TCP authentication option") + } + IoError::TcpInfoError(..) => { + write!(f, "failed to fetch address and port information from the socket") + } + IoError::TcpRecvError(..) => { + write!(f, "failed to read TCP data") + } + IoError::TcpSendError(..) => { + write!(f, "failed to send TCP data") + } + } + } +} + +impl std::error::Error for IoError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + IoError::TcpSocketError(error) + | IoError::TcpAcceptError(error) + | IoError::TcpConnectError(error) + | IoError::TcpAuthError(error) + | IoError::TcpInfoError(error) + | IoError::TcpRecvError(error) + | IoError::TcpSendError(error) => Some(error), + } + } +} + +// ===== impl NbrRxError ===== + +impl NbrRxError { + pub(crate) fn log(&self) { + match self { + NbrRxError::TcpConnClosed(addr) => { + warn_span!("neighbor", %addr).in_scope(|| { + warn!("{}", self); + }); + } + NbrRxError::MsgDecodeError(addr, error) => { + warn_span!("neighbor", %addr).in_scope(|| { + warn!(error = %with_source(error), "{}", self); + }); + } + } + } +} + +impl std::fmt::Display for NbrRxError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + NbrRxError::TcpConnClosed(..) => { + write!(f, "connection closed by remote end") + } + NbrRxError::MsgDecodeError(..) => { + write!(f, "failed to decode BGP message") + } + } + } +} + +impl std::error::Error for NbrRxError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + NbrRxError::MsgDecodeError(_, error) => Some(error), + _ => None, + } + } +} + +// ===== global functions ===== + +fn with_source(error: E) -> String { + if let Some(source) = error.source() { + format!("{} ({})", error, with_source(source)) + } else { + error.to_string() + } +} diff --git a/holo-bgp/src/events.rs b/holo-bgp/src/events.rs new file mode 100644 index 00000000..50ea4390 --- /dev/null +++ b/holo-bgp/src/events.rs @@ -0,0 +1,143 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::net::IpAddr; + +use chrono::Utc; +use holo_utils::ip::IpAddrKind; +use holo_utils::socket::{TcpConnInfo, TcpStream}; + +use crate::debug::Debug; +use crate::error::{Error, IoError, NbrRxError}; +use crate::instance::InstanceUpView; +use crate::neighbor::{fsm, Neighbors}; +use crate::network; +use crate::packet::message::Message; + +// ===== TCP connection request ===== + +pub(crate) fn process_tcp_accept( + instance: &mut InstanceUpView<'_>, + neighbors: &mut Neighbors, + stream: TcpStream, + conn_info: TcpConnInfo, +) -> Result<(), Error> { + // Lookup neighbor. + let Some(nbr) = neighbors.get_mut(&conn_info.remote_addr) else { + return Ok(()); + }; + + // Initialize the accepted stream. + network::accepted_stream_init( + &stream, + nbr.remote_addr.address_family(), + nbr.tx_ttl(), + nbr.config.transport.ttl_security, + nbr.config.transport.tcp_mss, + ) + .map_err(IoError::TcpSocketError)?; + + // Invoke FSM event. + nbr.fsm_event(instance, fsm::Event::Connected(stream, conn_info)); + + Ok(()) +} + +// ===== TCP connection established ===== + +pub(crate) fn process_tcp_connect( + instance: &mut InstanceUpView<'_>, + neighbors: &mut Neighbors, + stream: TcpStream, + conn_info: TcpConnInfo, +) -> Result<(), Error> { + // Lookup neighbor. + let Some(nbr) = neighbors.get_mut(&conn_info.remote_addr) else { + return Ok(()); + }; + nbr.tasks.connect = None; + + // Invoke FSM event. + nbr.fsm_event(instance, fsm::Event::Connected(stream, conn_info)); + + Ok(()) +} + +// ===== neighbor message receipt ===== + +pub(crate) fn process_nbr_msg( + instance: &mut InstanceUpView<'_>, + neighbors: &mut Neighbors, + nbr_addr: IpAddr, + msg: Result, +) -> Result<(), Error> { + // Lookup neighbor. + let Some(nbr) = neighbors.get_mut(&nbr_addr) else { + return Ok(()); + }; + + // Process received message. + match msg { + Ok(msg) => { + Debug::NbrMsgRx(&nbr.remote_addr, &msg).log(); + + // Update statistics. + nbr.statistics.msgs_rcvd.update(&msg); + + match msg { + Message::Open(msg) => { + nbr.fsm_event(instance, fsm::Event::RcvdOpen(msg)); + } + Message::Update(_msg) => { + // TODO: process update. + + nbr.fsm_event(instance, fsm::Event::RcvdUpdate); + } + Message::Notification(msg) => { + // Keep track of the last received notification. + nbr.notification_rcvd = Some((Utc::now(), msg.clone())); + + nbr.fsm_event(instance, fsm::Event::RcvdNotif(msg)); + } + Message::Keepalive(_) => { + nbr.fsm_event(instance, fsm::Event::RcvdKalive); + } + Message::RouteRefresh(_msg) => { + // TODO: process route refresh + } + } + } + Err(error) => match error { + NbrRxError::TcpConnClosed(_) => { + nbr.fsm_event(instance, fsm::Event::ConnFail); + } + NbrRxError::MsgDecodeError(_, error) => { + nbr.fsm_event(instance, fsm::Event::RcvdError(error)); + } + }, + } + + Ok(()) +} + +// ===== neighbor expired timeout ===== + +pub(crate) fn process_nbr_timer( + instance: &mut InstanceUpView<'_>, + neighbors: &mut Neighbors, + nbr_addr: IpAddr, + timer: fsm::Timer, +) -> Result<(), Error> { + // Lookup neighbor. + let Some(nbr) = neighbors.get_mut(&nbr_addr) else { + return Ok(()); + }; + + // Invoke FSM event. + nbr.fsm_event(instance, fsm::Event::Timer(timer)); + + Ok(()) +} diff --git a/holo-bgp/src/instance.rs b/holo-bgp/src/instance.rs new file mode 100644 index 00000000..eef2a96f --- /dev/null +++ b/holo-bgp/src/instance.rs @@ -0,0 +1,398 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::net::Ipv4Addr; +use std::sync::Arc; + +use async_trait::async_trait; +use holo_protocol::{ + InstanceChannelsTx, InstanceShared, MessageReceiver, ProtocolInstance, +}; +use holo_utils::ibus::IbusMsg; +use holo_utils::ip::AddressFamily; +use holo_utils::protocol::Protocol; +use holo_utils::socket::TcpListener; +use holo_utils::task::Task; +use holo_utils::{Receiver, Sender}; +use tokio::sync::mpsc; + +use crate::debug::{Debug, InstanceInactiveReason}; +use crate::error::{Error, IoError}; +use crate::neighbor::{fsm, Neighbors}; +use crate::northbound::configuration::InstanceCfg; +use crate::packet::message::NotificationMsg; +use crate::packet::{CeaseSubcode, ErrorCode}; +use crate::tasks::messages::input::{ + NbrRxMsg, NbrTimerMsg, TcpAcceptMsg, TcpConnectMsg, +}; +use crate::tasks::messages::{ProtocolInputMsg, ProtocolOutputMsg}; +use crate::{events, network, southbound, tasks}; + +#[derive(Debug)] +pub struct Instance { + // Instance name. + pub name: String, + // Instance system data. + pub system: InstanceSys, + // Instance configuration data. + pub config: InstanceCfg, + // Instance state data. + pub state: Option, + // Instance neighbors. + pub neighbors: Neighbors, + // Instance Tx channels. + pub tx: InstanceChannelsTx, + // Shared data. + pub shared: InstanceShared, +} + +#[derive(Debug, Default)] +pub struct InstanceSys { + pub router_id: Option, +} + +#[derive(Debug)] +pub struct InstanceState { + // Instance Router ID. + pub router_id: Ipv4Addr, + // TCP listening sockets. + pub listening_sockets: Vec, +} + +#[derive(Debug)] +pub struct TcpListenerTask { + pub af: AddressFamily, + pub socket: Arc, + _task: Task<()>, +} + +#[derive(Clone, Debug)] +pub struct ProtocolInputChannelsTx { + // TCP accept event. + pub tcp_accept: Sender, + // TCP connect event. + pub tcp_connect: Sender, + // TCP neighbor message. + pub nbr_msg_rx: Sender, + // Neighbor timeout event. + pub nbr_timer: Sender, +} + +#[derive(Debug)] +pub struct ProtocolInputChannelsRx { + // TCP accept event. + pub tcp_accept: Receiver, + // TCP connect event. + pub tcp_connect: Receiver, + // TCP neighbor message. + pub nbr_msg_rx: Receiver, + // Neighbor timeout event. + pub nbr_timer: Receiver, +} + +pub struct InstanceUpView<'a> { + pub name: &'a str, + pub system: &'a InstanceSys, + pub config: &'a InstanceCfg, + pub state: &'a mut InstanceState, + pub tx: &'a InstanceChannelsTx, + pub shared: &'a InstanceShared, +} + +// ===== impl Instance ===== + +impl Instance { + // Checks if the instance needs to be started or stopped in response to a + // northbound or southbound event. + // + // Note: Router-ID updates are ignored if the instance is already active. + pub(crate) async fn update(&mut self) { + let router_id = self.get_router_id(); + + match self.is_ready(router_id) { + Ok(()) if !self.is_active() => { + self.start(router_id.unwrap()).await; + } + Err(reason) if self.is_active() => { + self.stop(reason); + } + _ => (), + } + } + + // Starts the BGP instance. + async fn start(&mut self, router_id: Ipv4Addr) { + Debug::InstanceStart.log(); + + match InstanceState::new(router_id, &self.tx.protocol_input).await { + Ok(state) => { + // Store instance initial state. + self.state = Some(state); + } + Err(error) => { + Error::InstanceStartError(Box::new(error)).log(); + } + } + } + + // Stops the BGP instance. + fn stop(&mut self, reason: InstanceInactiveReason) { + let Some((mut instance, neighbors)) = self.as_up() else { + return; + }; + + Debug::InstanceStop(reason).log(); + + // Stop neighbors. + let error_code = ErrorCode::Cease; + let error_subcode = CeaseSubcode::AdministrativeShutdown; + for nbr in neighbors.values_mut() { + let msg = NotificationMsg::new(error_code, error_subcode); + nbr.fsm_event(&mut instance, fsm::Event::Stop(Some(msg))); + } + + // Clear instance state. + self.state = None; + } + + // Returns whether the BGP instance is operational. + fn is_active(&self) -> bool { + self.state.is_some() + } + + // Returns whether the instance is ready for BGP operation. + fn is_ready( + &self, + router_id: Option, + ) -> Result<(), InstanceInactiveReason> { + if router_id.is_none() { + return Err(InstanceInactiveReason::MissingRouterId); + } + + Ok(()) + } + + // Retrieves the Router ID from configuration or system information. + // Prioritizes the configured Router ID, using the system's Router ID as a + // fallback. + fn get_router_id(&self) -> Option { + self.config.identifier.or(self.system.router_id) + } + + // Returns a view struct for the instance if it is operational. + pub(crate) fn as_up( + &mut self, + ) -> Option<(InstanceUpView<'_>, &mut Neighbors)> { + if let Some(state) = &mut self.state { + let instance = InstanceUpView { + name: &self.name, + system: &self.system, + config: &self.config, + state, + tx: &self.tx, + shared: &self.shared, + }; + Some((instance, &mut self.neighbors)) + } else { + None + } + } +} + +#[async_trait] +impl ProtocolInstance for Instance { + const PROTOCOL: Protocol = Protocol::BGP; + + type ProtocolInputMsg = ProtocolInputMsg; + type ProtocolOutputMsg = ProtocolOutputMsg; + type ProtocolInputChannelsTx = ProtocolInputChannelsTx; + type ProtocolInputChannelsRx = ProtocolInputChannelsRx; + + async fn new( + name: String, + shared: InstanceShared, + tx: InstanceChannelsTx, + ) -> Instance { + Debug::InstanceCreate.log(); + + Instance { + name, + system: Default::default(), + config: Default::default(), + state: None, + neighbors: Default::default(), + tx, + shared, + } + } + + async fn shutdown(mut self) { + // Ensure instance is disabled before exiting. + self.stop(InstanceInactiveReason::AdminDown); + Debug::InstanceDelete.log(); + } + + async fn process_ibus_msg(&mut self, msg: IbusMsg) { + if let Err(error) = process_ibus_msg(self, msg).await { + error.log(); + } + } + + fn process_protocol_msg(&mut self, msg: ProtocolInputMsg) { + // Ignore event if the instance isn't active. + if let Some((mut instance, neighbors)) = self.as_up() { + if let Err(error) = + process_protocol_msg(&mut instance, neighbors, msg) + { + error.log(); + } + } + } + + fn protocol_input_channels( + ) -> (ProtocolInputChannelsTx, ProtocolInputChannelsRx) { + let (tcp_acceptp, tcp_acceptc) = mpsc::channel(4); + let (tcp_connectp, tcp_connectc) = mpsc::channel(4); + let (nbr_msg_rxp, nbr_msg_rxc) = mpsc::channel(4); + let (nbr_timerp, nbr_timerc) = mpsc::channel(4); + + let tx = ProtocolInputChannelsTx { + tcp_accept: tcp_acceptp, + tcp_connect: tcp_connectp, + nbr_msg_rx: nbr_msg_rxp, + nbr_timer: nbr_timerp, + }; + let rx = ProtocolInputChannelsRx { + tcp_accept: tcp_acceptc, + tcp_connect: tcp_connectc, + nbr_msg_rx: nbr_msg_rxc, + nbr_timer: nbr_timerc, + }; + + (tx, rx) + } + + #[cfg(feature = "testing")] + fn test_dir() -> String { + format!("{}/tests/conformance", env!("CARGO_MANIFEST_DIR"),) + } +} + +// ===== impl InstanceState ===== + +impl InstanceState { + async fn new( + router_id: Ipv4Addr, + proto_input_tx: &ProtocolInputChannelsTx, + ) -> Result { + let mut listening_sockets = Vec::new(); + + // Create TCP listeners. + for af in [AddressFamily::Ipv4, AddressFamily::Ipv6] { + let socket = network::listen_socket(af) + .map(Arc::new) + .map_err(IoError::TcpSocketError)?; + let task = tasks::tcp_listener(&socket, &proto_input_tx.tcp_accept); + listening_sockets.push(TcpListenerTask { + af, + socket, + _task: task, + }); + } + + Ok(InstanceState { + router_id, + listening_sockets, + }) + } +} + +// ===== impl ProtocolInputChannelsRx ===== + +#[async_trait] +impl MessageReceiver for ProtocolInputChannelsRx { + async fn recv(&mut self) -> Option { + tokio::select! { + msg = self.tcp_accept.recv() => { + msg.map(ProtocolInputMsg::TcpAccept) + } + msg = self.tcp_connect.recv() => { + msg.map(ProtocolInputMsg::TcpConnect) + } + msg = self.nbr_msg_rx.recv() => { + msg.map(ProtocolInputMsg::NbrRx) + } + msg = self.nbr_timer.recv() => { + msg.map(ProtocolInputMsg::NbrTimer) + } + } + } +} + +// ===== helper functions ===== + +async fn process_ibus_msg( + instance: &mut Instance, + msg: IbusMsg, +) -> Result<(), Error> { + match msg { + // Router ID update notification. + IbusMsg::RouterIdUpdate(router_id) => { + southbound::rx::process_router_id_update(instance, router_id).await; + } + // Ignore other events. + _ => {} + } + + Ok(()) +} + +fn process_protocol_msg( + instance: &mut InstanceUpView<'_>, + neighbors: &mut Neighbors, + msg: ProtocolInputMsg, +) -> Result<(), Error> { + match msg { + // Accepted TCP connection request. + ProtocolInputMsg::TcpAccept(mut msg) => { + events::process_tcp_accept( + instance, + neighbors, + msg.stream(), + msg.conn_info, + )?; + } + // Established TCP connection. + ProtocolInputMsg::TcpConnect(mut msg) => { + events::process_tcp_connect( + instance, + neighbors, + msg.stream(), + msg.conn_info, + )?; + } + // Received message from neighbor. + ProtocolInputMsg::NbrRx(msg) => { + events::process_nbr_msg( + instance, + neighbors, + msg.nbr_addr, + msg.msg, + )?; + } + // Neighbor's timeout has expired. + ProtocolInputMsg::NbrTimer(msg) => { + events::process_nbr_timer( + instance, + neighbors, + msg.nbr_addr, + msg.timer, + )?; + } + } + + Ok(()) +} diff --git a/holo-bgp/src/lib.rs b/holo-bgp/src/lib.rs new file mode 100644 index 00000000..9694167b --- /dev/null +++ b/holo-bgp/src/lib.rs @@ -0,0 +1,23 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +#![cfg_attr( + feature = "testing", + allow(dead_code, unused_variables, unused_imports) +)] +#![feature(let_chains, lazy_cell)] + +pub mod debug; +pub mod error; +pub mod events; +pub mod instance; +pub mod neighbor; +pub mod network; +pub mod northbound; +pub mod packet; +pub mod rib; +pub mod southbound; +pub mod tasks; diff --git a/holo-bgp/src/neighbor.rs b/holo-bgp/src/neighbor.rs new file mode 100644 index 00000000..7338dcfe --- /dev/null +++ b/holo-bgp/src/neighbor.rs @@ -0,0 +1,801 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::collections::{BTreeMap, BTreeSet}; +use std::net::{IpAddr, Ipv4Addr}; +use std::sync::atomic::{self, AtomicU32}; +use std::sync::Arc; +use std::time::Duration; + +use chrono::{DateTime, Utc}; +use holo_utils::socket::{TcpConnInfo, TcpStream, TTL_MAX}; +use holo_utils::task::{IntervalTask, Task, TimeoutTask}; +use holo_utils::{Sender, UnboundedSender}; +use tokio::sync::mpsc; + +use crate::debug::Debug; +use crate::error::Error; +use crate::instance::InstanceUpView; +use crate::northbound::configuration::{InstanceCfg, NeighborCfg}; +use crate::northbound::AfiSafi; +use crate::packet::message::{ + Capability, KeepaliveMsg, Message, NotificationMsg, OpenMsg, +}; +use crate::packet::{ + Afi, ErrorCode, FsmErrorSubcode, Safi, AS_TRANS, BGP_VERSION, +}; +use crate::tasks; +use crate::tasks::messages::input::{NbrRxMsg, NbrTimerMsg, TcpConnectMsg}; +use crate::tasks::messages::output::NbrTxMsg; +#[cfg(feature = "testing")] +use crate::tasks::messages::ProtocolOutputMsg; + +// Large hold-time used during session initialization. +const LARGE_HOLDTIME: u16 = 240; + +// BGP neighbor. +#[derive(Debug)] +pub struct Neighbor { + pub remote_addr: IpAddr, + pub config: NeighborCfg, + pub state: fsm::State, + pub peer_type: PeerType, + pub conn_info: Option, + pub identifier: Option, + pub holdtime_nego: Option, + pub capabilities_adv: BTreeSet, + pub capabilities_rcvd: BTreeSet, + pub capabilities_nego: BTreeSet, + pub notification_sent: Option<(DateTime, NotificationMsg)>, + pub notification_rcvd: Option<(DateTime, NotificationMsg)>, + pub last_established: Option>, + pub statistics: NeighborStatistics, + pub tasks: NeighborTasks, + pub msg_txp: Option>, +} + +// BGP peer type. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum PeerType { + Internal, + External, +} + +// Neighbor statistics. +#[derive(Debug, Default)] +pub struct NeighborStatistics { + pub established_transitions: u32, + pub msgs_rcvd: MessageStatistics, + pub msgs_sent: MessageStatistics, + pub erroneous_updates_withdrawn: u32, + pub erroneous_updates_attribute_discarded: u32, + pub in_update_elapsed_time: Duration, +} + +// Inbound and outbound message counters. +#[derive(Debug, Default)] +pub struct MessageStatistics { + pub total: Arc, + pub updates: u32, + pub notifications: u32, + pub route_refreshes: u32, +} + +// Neighbor tasks. +#[derive(Debug, Default)] +pub struct NeighborTasks { + pub autostart: Option, + pub connect: Option>, + pub connect_retry: Option, + pub tcp_rx: Option>, + pub keepalive: Option, + pub holdtime: Option, +} + +// Type aliases. +pub type Neighbors = BTreeMap; + +// Finite State Machine. +pub mod fsm { + use holo_utils::socket::{TcpConnInfo, TcpStream}; + use serde::{Deserialize, Serialize}; + + use crate::packet::error::DecodeError; + use crate::packet::message::{NotificationMsg, OpenMsg}; + + // FSM states. + #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] + pub enum State { + Idle, + Connect, + Active, + OpenSent, + OpenConfirm, + Established, + } + + // FSM events. + // + // The original RFC FSM events are listed above each event for clarity. + #[derive(Debug)] + pub enum Event { + // ManualStart + // ManualStart_with_PassiveTcpEstablishment + Start, + // ManualStop + Stop(Option), + // Tcp_CR_Acked + // TcpConnectionConfirmed + Connected(TcpStream, TcpConnInfo), + // TcpConnectionFails + ConnFail, + // BGPHeaderErr + // BGPOpenMsgErr + // UpdateMsgErr + RcvdError(DecodeError), + // BGPOpen + RcvdOpen(OpenMsg), + // NotifMsg + RcvdNotif(NotificationMsg), + // KeepAliveMsg + RcvdKalive, + // UpdateMsg + RcvdUpdate, + // ConnectRetryTimer_Expires + // HoldTimer_Expires + // AutomaticStart + // AutomaticStart_with_PassiveTcpEstablishment + Timer(Timer), + } + + // BGP timers. + // + // Note: KEEPALIVE messages are sent independently, separate from the FSM. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[derive(Deserialize, Serialize)] + pub enum Timer { + ConnectRetry, + Hold, + AutoStart, + } +} + +// ===== impl Neighbor ===== + +impl Neighbor { + // Creates a new neighbor in the Idle state with default configuration. + pub(crate) fn new(remote_addr: IpAddr, peer_type: PeerType) -> Neighbor { + Neighbor { + remote_addr, + config: Default::default(), + state: fsm::State::Idle, + peer_type, + conn_info: None, + identifier: None, + holdtime_nego: None, + capabilities_adv: Default::default(), + capabilities_rcvd: Default::default(), + capabilities_nego: Default::default(), + notification_sent: None, + notification_rcvd: None, + last_established: None, + statistics: Default::default(), + tasks: Default::default(), + msg_txp: None, + } + } + + // Injects an event into the neighbor's FSM. + pub(crate) fn fsm_event( + &mut self, + instance: &mut InstanceUpView<'_>, + event: fsm::Event, + ) { + Debug::NbrFsmEvent(&self.remote_addr, &event).log(); + + // Process FSM event. + let next_state = match self.state { + // Idle state + fsm::State::Idle => match event { + fsm::Event::Start + | fsm::Event::Timer(fsm::Timer::AutoStart) => { + self.connect_retry_start( + &instance.tx.protocol_input.nbr_timer, + ); + if self.config.transport.passive_mode { + Some(fsm::State::Active) + } else { + self.connect(&instance.tx.protocol_input.tcp_connect); + Some(fsm::State::Connect) + } + } + _ => None, + }, + // Connect state + fsm::State::Connect => match event { + fsm::Event::Start => None, + fsm::Event::Stop(_) => { + self.session_close(None); + Some(fsm::State::Idle) + } + fsm::Event::Connected(stream, conn_info) => { + self.connect_retry_stop(); + self.connection_setup( + stream, + conn_info, + &instance.tx.protocol_input.nbr_msg_rx, + #[cfg(feature = "testing")] + &instance.tx.protocol_output, + ); + self.open_send(instance.config, instance.state.router_id); + self.holdtime_start( + LARGE_HOLDTIME, + &instance.tx.protocol_input.nbr_timer, + ); + Some(fsm::State::OpenSent) + } + fsm::Event::ConnFail => { + self.session_close(None); + Some(fsm::State::Idle) + } + fsm::Event::RcvdError(error) => { + let msg = NotificationMsg::from(error); + self.session_close(Some(msg)); + Some(fsm::State::Idle) + } + fsm::Event::Timer(fsm::Timer::ConnectRetry) => { + self.connect(&instance.tx.protocol_input.tcp_connect); + self.connect_retry_start( + &instance.tx.protocol_input.nbr_timer, + ); + None + } + _ => { + // FSM error. + self.session_close(None); + Some(fsm::State::Idle) + } + }, + // Active state + fsm::State::Active => match event { + fsm::Event::Start => None, + fsm::Event::Stop(_) => { + self.session_close(None); + Some(fsm::State::Idle) + } + fsm::Event::Connected(stream, conn_info) => { + self.connect_retry_stop(); + self.connection_setup( + stream, + conn_info, + &instance.tx.protocol_input.nbr_msg_rx, + #[cfg(feature = "testing")] + &instance.tx.protocol_output, + ); + self.open_send(instance.config, instance.state.router_id); + self.holdtime_start( + LARGE_HOLDTIME, + &instance.tx.protocol_input.nbr_timer, + ); + Some(fsm::State::OpenSent) + } + fsm::Event::ConnFail => { + self.session_close(None); + Some(fsm::State::Idle) + } + fsm::Event::RcvdError(error) => { + let msg = NotificationMsg::from(error); + self.session_close(Some(msg)); + Some(fsm::State::Idle) + } + fsm::Event::Timer(fsm::Timer::ConnectRetry) => { + self.connect(&instance.tx.protocol_input.tcp_connect); + self.connect_retry_start( + &instance.tx.protocol_input.nbr_timer, + ); + Some(fsm::State::Connect) + } + _ => { + // FSM error. + self.session_close(None); + Some(fsm::State::Idle) + } + }, + // OpenSent state + fsm::State::OpenSent => match event { + fsm::Event::Start => None, + fsm::Event::Stop(msg) => { + self.session_close(msg); + Some(fsm::State::Idle) + } + fsm::Event::ConnFail => { + self.session_close(None); + self.connect_retry_start( + &instance.tx.protocol_input.nbr_timer, + ); + Some(fsm::State::Active) + } + fsm::Event::RcvdError(error) => { + let msg = NotificationMsg::from(error); + self.session_close(Some(msg)); + Some(fsm::State::Idle) + } + fsm::Event::RcvdOpen(msg) => { + let next_state = self.open_process(instance, msg); + Some(next_state) + } + fsm::Event::Timer(fsm::Timer::Hold) => { + let error_code = ErrorCode::HoldTimerExpired; + let error_subcode = 0; + let msg = NotificationMsg::new(error_code, error_subcode); + self.session_close(Some(msg)); + Some(fsm::State::Idle) + } + _ => { + // FSM error. + let error_code = ErrorCode::FiniteStateMachineError; + let error_subcode = + FsmErrorSubcode::UnexpectedMessageInOpenSent; + let msg = NotificationMsg::new(error_code, error_subcode); + self.session_close(Some(msg)); + Some(fsm::State::Idle) + } + }, + // OpenConfirm state + fsm::State::OpenConfirm => match event { + fsm::Event::Start => None, + fsm::Event::Stop(msg) => { + self.session_close(msg); + Some(fsm::State::Idle) + } + fsm::Event::ConnFail => { + self.session_close(None); + Some(fsm::State::Idle) + } + fsm::Event::RcvdError(error) => { + let msg = NotificationMsg::from(error); + self.session_close(Some(msg)); + Some(fsm::State::Idle) + } + fsm::Event::RcvdOpen(_msg) => { + // TODO: collision detection + Some(fsm::State::Idle) + } + fsm::Event::RcvdNotif(_) => { + self.session_close(None); + Some(fsm::State::Idle) + } + fsm::Event::RcvdKalive => { + self.holdtime_restart(); + Some(fsm::State::Established) + } + fsm::Event::Timer(fsm::Timer::Hold) => { + let error_code = ErrorCode::HoldTimerExpired; + let error_subcode = 0; + let msg = NotificationMsg::new(error_code, error_subcode); + self.session_close(Some(msg)); + Some(fsm::State::Idle) + } + _ => { + // FSM error. + let error_code = ErrorCode::FiniteStateMachineError; + let error_subcode = + FsmErrorSubcode::UnexpectedMessageInOpenConfirm; + let msg = NotificationMsg::new(error_code, error_subcode); + self.session_close(Some(msg)); + Some(fsm::State::Idle) + } + }, + // Established state + fsm::State::Established => match event { + fsm::Event::Start => None, + fsm::Event::Stop(msg) => { + self.session_close(msg); + Some(fsm::State::Idle) + } + fsm::Event::ConnFail => { + self.session_close(None); + Some(fsm::State::Idle) + } + fsm::Event::RcvdError(error) => { + let msg = NotificationMsg::from(error); + self.session_close(Some(msg)); + Some(fsm::State::Idle) + } + fsm::Event::RcvdNotif(_) => { + self.session_close(None); + Some(fsm::State::Idle) + } + fsm::Event::RcvdKalive | fsm::Event::RcvdUpdate => { + self.holdtime_restart(); + None + } + fsm::Event::Timer(fsm::Timer::Hold) => { + let error_code = ErrorCode::HoldTimerExpired; + let error_subcode = 0; + let msg = NotificationMsg::new(error_code, error_subcode); + self.session_close(Some(msg)); + Some(fsm::State::Idle) + } + _ => { + // FSM error. + let error_code = ErrorCode::FiniteStateMachineError; + let error_subcode = + FsmErrorSubcode::UnexpectedMessageInEstablished; + let msg = NotificationMsg::new(error_code, error_subcode); + self.session_close(Some(msg)); + Some(fsm::State::Idle) + } + }, + }; + + // Change to next FSM state when applicable. + if let Some(next_state) = next_state + && self.state != next_state + { + // Schedule auto-start unless the peer has been manually disabled. + if next_state == fsm::State::Idle && self.config.enabled { + self.autostart_start(&instance.tx.protocol_input.nbr_timer); + } else { + self.autostart_stop(); + } + + self.fsm_state_change(next_state); + } + } + + // Updates the neighbor's FSM state. + fn fsm_state_change(&mut self, next_state: fsm::State) { + Debug::NbrFsmTransition(&self.remote_addr, &self.state, &next_state) + .log(); + + // Keep track of the time that the BGP session last transitioned in or + // out of the Established state. + if self.state == fsm::State::Established + || next_state == fsm::State::Established + { + self.last_established = Some(Utc::now()); + } + + if next_state == fsm::State::Established { + // Update statistics. + self.statistics.established_transitions += 1; + + // Compute the negotiated capabilities. + self.capabilities_nego = self + .capabilities_adv + .intersection(&self.capabilities_rcvd) + .cloned() + .collect(); + } + + self.state = next_state; + } + + // Sets up the connection for the BGP neighbor, spawning necessary tasks for + // TCP communication. + fn connection_setup( + &mut self, + stream: TcpStream, + conn_info: TcpConnInfo, + nbr_msg_rxp: &Sender, + #[cfg(feature = "testing")] proto_output_tx: &Sender, + ) { + // Store TCP connection information. + self.conn_info = Some(conn_info); + + // Split TCP stream into two halves. + let (read_half, write_half) = stream.into_split(); + + // Spawn neighbor TCP Tx/Rx tasks. + let (msg_txp, msg_txc) = mpsc::unbounded_channel(); + let mut tx_task = tasks::nbr_tx( + self, + write_half, + msg_txc, + #[cfg(feature = "testing")] + proto_output_tx, + ); + let tcp_rx_task = tasks::nbr_rx(self, read_half, nbr_msg_rxp); + self.tasks.tcp_rx = Some(tcp_rx_task); + self.msg_txp = Some(msg_txp); + + // No need to keep track of the Tx task since it gracefully exits as + // soon as the tx end of its mpsc channel is dropped. This ensures that + // messages sent during neighbor shutdown will be delivered. + tx_task.detach(); + } + + // Closes the BGP session, performing necessary cleanup and releasing resources. + fn session_close(&mut self, send_notif: Option) { + // Send a notification message. + if self.state >= fsm::State::OpenSent + && let Some(msg) = send_notif + { + self.message_send(Message::Notification(msg)); + } + + // Set the ConnectRetryTimer to zero. + self.connect_retry_stop(); + + // Release all resources. + self.conn_info = None; + self.identifier = None; + self.holdtime_nego = None; + self.capabilities_adv.clear(); + self.capabilities_rcvd.clear(); + self.capabilities_nego.clear(); + self.tasks = Default::default(); + self.msg_txp = None; + } + + // Enqueues a BGP message for transmission. + fn message_send(&mut self, msg: Message) { + Debug::NbrMsgTx(&self.remote_addr, &msg).log(); + + // Update statistics. + self.statistics.msgs_sent.update(&msg); + + // Keep track of the last sent notification. + if let Message::Notification(msg) = &msg { + self.notification_sent = Some((Utc::now(), msg.clone())); + } + + // Ignore any possible error as the connection might have gone down + // already. + let nbr_addr = self.remote_addr; + let msg = NbrTxMsg { nbr_addr, msg }; + let _ = self.msg_txp.as_ref().unwrap().send(msg); + } + + // Sends a BGP OPEN message based on the local configuration. + fn open_send(&mut self, instance_cfg: &InstanceCfg, identifier: Ipv4Addr) { + // Base capabilities. + let mut capabilities: BTreeSet<_> = [ + Capability::RouteRefresh, + Capability::FourOctetAsNumber { + asn: instance_cfg.asn, + }, + ] + .into(); + + // Multiprotocol capabilities. + if let Some(afi_safi) = self.config.afi_safi.get(&AfiSafi::Ipv4Unicast) + && afi_safi.enabled + { + capabilities.insert(Capability::MultiProtocol { + afi: Afi::Ipv4, + safi: Safi::Unicast, + }); + } + if let Some(afi_safi) = self.config.afi_safi.get(&AfiSafi::Ipv6Unicast) + && afi_safi.enabled + { + capabilities.insert(Capability::MultiProtocol { + afi: Afi::Ipv6, + safi: Safi::Unicast, + }); + } + + // Keep track of the advertised capabilities. + self.capabilities_adv = capabilities.clone(); + + // Fill-in and send message. + let msg = Message::Open(OpenMsg { + version: BGP_VERSION, + my_as: instance_cfg.asn.try_into().unwrap_or(AS_TRANS), + holdtime: self.config.timers.holdtime, + identifier, + capabilities, + }); + self.message_send(msg); + } + + // Processes the received OPEN message while in the OpenSent state. + fn open_process( + &mut self, + instance: &InstanceUpView<'_>, + msg: OpenMsg, + ) -> fsm::State { + use crate::packet::OpenMessageErrorSubcode as ErrorSubcode; + + // Validate the received message. + if let Err(error) = self.open_validate(instance, &msg) { + error.log(); + + // Close the session. + let msg = match error { + Error::NbrBadAs(..) => { + let error_code = ErrorCode::OpenMessageError; + let error_subcode = ErrorSubcode::BadPeerAs; + let msg = NotificationMsg::new(error_code, error_subcode); + Some(msg) + } + Error::NbrBadIdentifier(..) => { + let error_code = ErrorCode::OpenMessageError; + let error_subcode = ErrorSubcode::BadBgpIdentifier; + let msg = NotificationMsg::new(error_code, error_subcode); + Some(msg) + } + _ => None, + }; + self.session_close(msg); + + // Transition to the Idle state. + return fsm::State::Idle; + } + + // Calculate negotiated hold-time. + let holdtime_nego = + std::cmp::min(msg.holdtime, self.config.timers.holdtime); + + // Set the ConnectRetryTimer to zero. + self.connect_retry_stop(); + + // Send Keepalive message. + self.message_send(Message::Keepalive(KeepaliveMsg {})); + + // Start Keepalive interval and session hold timer. + if holdtime_nego != 0 { + self.keepalive_interval_start(holdtime_nego); + self.holdtime_start( + holdtime_nego, + &instance.tx.protocol_input.nbr_timer, + ); + } else { + self.holdtime_stop(); + } + + // Keep track of the received data. + self.identifier = Some(msg.identifier); + self.holdtime_nego = (holdtime_nego != 0).then_some(holdtime_nego); + self.capabilities_rcvd = msg.capabilities; + + // TODO: collision detection + + // Transition to the OpenConfirm state. + fsm::State::OpenConfirm + } + + // Performs semantic validation of the received BGP OPEN message. + // Syntactic errors are detected during the decoding phase. + fn open_validate( + &self, + instance: &InstanceUpView<'_>, + msg: &OpenMsg, + ) -> Result<(), Error> { + // Validate ASN. + if self.config.peer_as != msg.real_as() { + return Err(Error::NbrBadAs( + self.remote_addr, + msg.real_as(), + self.config.peer_as, + )); + } + + // Validate BGP identifier for internal peers. + if self.peer_type == PeerType::Internal + && msg.identifier == instance.config.identifier.unwrap() + { + return Err(Error::NbrBadIdentifier( + self.remote_addr, + msg.identifier, + )); + } + + Ok(()) + } + + // Returns the neighbor's Tx-TTL value based on the peer type and + // configuration. + pub(crate) fn tx_ttl(&self) -> u8 { + match self.peer_type { + PeerType::Internal => TTL_MAX, + PeerType::External => { + if self.config.transport.ttl_security.is_some() { + TTL_MAX + } else if self.config.transport.ebgp_multihop_enabled + && let Some(ttl) = self.config.transport.ebgp_multihop_ttl + { + ttl + } else { + 1 + } + } + } + } + + // Starts the auto-start timer. + fn autostart_start(&mut self, nbr_timerp: &Sender) { + let idle_hold_time = 1; + let task = tasks::nbr_timer( + self, + fsm::Timer::AutoStart, + idle_hold_time, + nbr_timerp, + ); + self.tasks.autostart = Some(task); + } + + // Stops the auto-start timer. + fn autostart_stop(&mut self) { + self.tasks.autostart = None; + } + + // Starts a TCP connection task to the neighbor's remote address. + fn connect(&mut self, tcp_connectp: &Sender) { + let task = tasks::tcp_connect(self, tcp_connectp); + self.tasks.connect = Some(task); + } + + // Starts the Keepalive TX interval. + fn keepalive_interval_start(&mut self, holdtime_nego: u16) { + let interval = + self.config.timers.keepalive.unwrap_or(holdtime_nego / 3); + let task = tasks::nbr_kalive_interval(self, interval); + self.tasks.keepalive = Some(task); + } + + // Starts the session hold timer. + fn holdtime_start( + &mut self, + seconds: u16, + nbr_timerp: &Sender, + ) { + let task = + tasks::nbr_timer(self, fsm::Timer::Hold, seconds, nbr_timerp); + self.tasks.holdtime = Some(task); + } + + // Restarts the session hold timer if the negotiated HoldTime value is + // non-zero. + fn holdtime_restart(&mut self) { + if let Some(holdtime) = self.tasks.holdtime.as_mut() { + holdtime.reset(None); + } + } + + // Stops the session hold timer. + fn holdtime_stop(&mut self) { + self.tasks.holdtime = None; + } + + // Starts the connect retry timer. + fn connect_retry_start(&mut self, nbr_timerp: &Sender) { + let task = tasks::nbr_timer( + self, + fsm::Timer::ConnectRetry, + self.config.timers.connect_retry_interval, + nbr_timerp, + ); + self.tasks.connect_retry = Some(task); + } + + // Stops the connect retry timer. + fn connect_retry_stop(&mut self) { + self.tasks.connect_retry = None; + } +} + +// ===== impl MessageStatistics ===== + +impl MessageStatistics { + pub(crate) fn update(&mut self, msg: &Message) { + self.total.fetch_add(1, atomic::Ordering::Relaxed); + match msg { + Message::Update(_) => { + self.updates += 1; + } + Message::Notification(_) => { + self.notifications += 1; + } + Message::RouteRefresh(_) => { + self.route_refreshes += 1; + } + _ => {} + } + } +} diff --git a/holo-bgp/src/network.rs b/holo-bgp/src/network.rs new file mode 100644 index 00000000..3a519fab --- /dev/null +++ b/holo-bgp/src/network.rs @@ -0,0 +1,281 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::net::{IpAddr, SocketAddr}; +use std::sync::Arc; + +use holo_utils::ip::{AddressFamily, IpAddrExt, IpAddrKind}; +use holo_utils::socket::{ + OwnedReadHalf, OwnedWriteHalf, SocketExt, TcpConnInfo, TcpListener, + TcpSocket, TcpSocketExt, TcpStream, TcpStreamExt, TTL_MAX, +}; +use holo_utils::{capabilities, Sender, UnboundedReceiver}; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::sync::mpsc::error::SendError; + +use crate::error::{Error, IoError, NbrRxError}; +use crate::packet::message::Message; +use crate::tasks::messages::input::{NbrRxMsg, TcpAcceptMsg}; +use crate::tasks::messages::output::NbrTxMsg; + +const BGP_PORT: u16 = 179; + +// ===== global functions ===== + +pub(crate) fn listen_socket( + af: AddressFamily, +) -> Result { + #[cfg(not(feature = "testing"))] + { + // Create TCP socket. + let socket = socket(af)?; + + // Bind socket. + let sockaddr = SocketAddr::from((IpAddr::unspecified(af), BGP_PORT)); + socket.set_reuseaddr(true)?; + capabilities::raise(|| socket.bind(sockaddr))?; + + // GTSM Procedure: set TTL to max for outgoing packets. + match af { + AddressFamily::Ipv4 => { + socket.set_ipv4_ttl(TTL_MAX)?; + } + AddressFamily::Ipv6 => { + socket.set_ipv6_unicast_hops(TTL_MAX)?; + } + } + + // Convert the socket into a TcpListener. + let socket = socket.listen(4096)?; + + Ok(socket) + } + #[cfg(feature = "testing")] + { + Ok(TcpListener {}) + } +} + +pub(crate) fn listen_socket_md5sig_update( + socket: &TcpListener, + nbr_addr: &IpAddr, + password: Option<&str>, +) { + #[cfg(not(feature = "testing"))] + { + if let Err(error) = socket.set_md5sig(nbr_addr, password) { + IoError::TcpAuthError(error).log(); + } + } +} + +#[cfg(not(feature = "testing"))] +pub(crate) async fn listen_loop( + listener: Arc, + tcp_acceptp: Sender, +) -> Result<(), SendError> { + loop { + match listener.accept().await { + Ok((stream, _)) => match stream.conn_info() { + Ok(conn_info) => { + let msg = TcpAcceptMsg { + stream: Some(stream), + conn_info, + }; + tcp_acceptp.send(msg).await?; + } + Err(error) => { + IoError::TcpInfoError(error).log(); + } + }, + Err(error) => { + IoError::TcpAcceptError(error).log(); + } + } + } +} + +pub(crate) fn accepted_stream_init( + stream: &TcpStream, + af: AddressFamily, + ttl: u8, + ttl_security: Option, + tcp_mss: Option, +) -> Result<(), std::io::Error> { + #[cfg(not(feature = "testing"))] + { + // Set TTL. + match af { + AddressFamily::Ipv4 => stream.set_ipv4_ttl(ttl)?, + AddressFamily::Ipv6 => stream.set_ipv6_unicast_hops(ttl)?, + } + + // Set TTL security check. + if let Some(ttl_security_hops) = ttl_security { + let ttl = TTL_MAX - ttl_security_hops + 1; + match af { + AddressFamily::Ipv4 => stream.set_ipv4_minttl(ttl)?, + AddressFamily::Ipv6 => stream.set_ipv6_min_hopcount(ttl)?, + } + } + + // Set the TCP Maximum Segment Size. + if let Some(tcp_mss) = tcp_mss { + stream.set_mss(tcp_mss.into())?; + } + } + + Ok(()) +} + +#[cfg(not(feature = "testing"))] +pub(crate) async fn connect( + remote_addr: IpAddr, + local_addr: Option, + ttl: u8, + ttl_security: Option, + tcp_mss: Option, + tcp_password: &Option, +) -> Result<(TcpStream, TcpConnInfo), Error> { + let af = remote_addr.address_family(); + + // Create TCP socket. + let socket = socket(af).map_err(IoError::TcpSocketError)?; + + // Bind socket. + if let Some(local_addr) = local_addr { + let sockaddr = SocketAddr::from((local_addr, 0)); + socket + .set_reuseaddr(true) + .map_err(IoError::TcpSocketError)?; + capabilities::raise(|| socket.bind(sockaddr)) + .map_err(IoError::TcpSocketError)?; + } + + // Set TTL. + match af { + AddressFamily::Ipv4 => socket.set_ipv4_ttl(ttl), + AddressFamily::Ipv6 => socket.set_ipv6_unicast_hops(ttl), + } + .map_err(IoError::TcpSocketError)?; + + // Set TTL security check. + if let Some(ttl_security_hops) = ttl_security { + let ttl = TTL_MAX - ttl_security_hops + 1; + match af { + AddressFamily::Ipv4 => socket.set_ipv4_minttl(ttl), + AddressFamily::Ipv6 => socket.set_ipv6_min_hopcount(ttl), + } + .map_err(IoError::TcpSocketError)?; + } + + // Set the TCP Maximum Segment Size. + if let Some(tcp_mss) = tcp_mss { + socket + .set_mss(tcp_mss.into()) + .map_err(IoError::TcpSocketError)?; + } + + // Set the TCP MD5 password. + if let Some(tcp_password) = tcp_password { + socket + .set_md5sig(&remote_addr, Some(tcp_password)) + .map_err(IoError::TcpAuthError)?; + } + + // Connect to remote address on the BGP port. + let sockaddr = SocketAddr::from((remote_addr, BGP_PORT)); + let stream = socket + .connect(sockaddr) + .await + .map_err(IoError::TcpConnectError)?; + + // Obtain TCP connection address/port information. + let conn_info = stream.conn_info().map_err(IoError::TcpInfoError)?; + + Ok((stream, conn_info)) +} + +#[cfg(not(feature = "testing"))] +pub(crate) async fn nbr_write_loop( + mut stream: OwnedWriteHalf, + mut nbr_msg_txc: UnboundedReceiver, +) { + while let Some(NbrTxMsg { msg, .. }) = nbr_msg_txc.recv().await { + let buf = msg.encode(); + if let Err(error) = stream.write_all(&buf).await { + IoError::TcpSendError(error).log(); + } + } +} + +#[cfg(not(feature = "testing"))] +pub(crate) async fn nbr_read_loop( + mut stream: OwnedReadHalf, + nbr_addr: IpAddr, + nbr_msg_rxp: Sender, +) -> Result<(), SendError> { + const BUF_SIZE: usize = 65535; + let mut buf = [0; BUF_SIZE]; + let mut data = Vec::with_capacity(BUF_SIZE); + + loop { + // Read data from the network. + match stream.read(&mut buf).await { + Ok(0) => { + // Notify that the connection was closed by the remote end. + let msg = NbrRxMsg { + nbr_addr, + msg: Err(NbrRxError::TcpConnClosed(nbr_addr)), + }; + nbr_msg_rxp.send(msg).await?; + return Ok(()); + } + Ok(num_bytes) => data.extend_from_slice(&buf[..num_bytes]), + Err(error) => { + IoError::TcpRecvError(error).log(); + continue; + } + }; + + // Decode message(s). + while let Some(msg_size) = Message::get_message_len(&data) { + let msg = Message::decode(&data[0..msg_size]) + .map_err(|error| NbrRxError::MsgDecodeError(nbr_addr, error)); + data.drain(..msg_size); + + // Notify that the BGP message was received. + let msg = NbrRxMsg { nbr_addr, msg }; + nbr_msg_rxp.send(msg).await?; + } + } +} + +// ===== helper functions ===== + +#[cfg(not(feature = "testing"))] +fn socket(af: AddressFamily) -> Result { + let socket = match af { + AddressFamily::Ipv4 => TcpSocket::new_v4()?, + AddressFamily::Ipv6 => { + let socket = TcpSocket::new_v6()?; + socket.set_ipv6_only(true)?; + socket + } + }; + + // Set socket options. + match af { + AddressFamily::Ipv4 => { + socket.set_ipv4_tos(libc::IPTOS_PREC_INTERNETCONTROL)?; + } + AddressFamily::Ipv6 => { + socket.set_ipv6_tclass(libc::IPTOS_PREC_INTERNETCONTROL)?; + } + } + + Ok(socket) +} diff --git a/holo-bgp/src/northbound/configuration.rs b/holo-bgp/src/northbound/configuration.rs new file mode 100644 index 00000000..afae3ac7 --- /dev/null +++ b/holo-bgp/src/northbound/configuration.rs @@ -0,0 +1,1499 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::collections::BTreeMap; +use std::net::{IpAddr, Ipv4Addr}; +use std::sync::LazyLock as Lazy; + +use async_trait::async_trait; +use enum_as_inner::EnumAsInner; +use holo_northbound::configuration::{ + Callbacks, CallbacksBuilder, Provider, ValidationCallbacks, + ValidationCallbacksBuilder, +}; +use holo_northbound::paths::control_plane_protocol::bgp; +use holo_utils::ip::IpAddrKind; +use holo_utils::policy::{ApplyPolicyCfg, DefaultPolicyType}; +use holo_utils::yang::DataNodeRefExt; +use holo_yang::TryFromYang; + +use crate::instance::Instance; +use crate::neighbor::{fsm, Neighbor, PeerType}; +use crate::network; +use crate::northbound::AfiSafi; +use crate::packet::message::NotificationMsg; +use crate::packet::{CeaseSubcode, ErrorCode}; + +#[derive(Debug, Default, EnumAsInner)] +pub enum ListEntry { + #[default] + None, + AfiSafi(AfiSafi), + Neighbor(IpAddr), + NeighborAfiSafi(IpAddr, AfiSafi), +} + +#[derive(Debug)] +pub enum Resource {} + +#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] +pub enum Event { + InstanceUpdate, + NeighborUpdate(IpAddr), + NeighborReset(IpAddr, NotificationMsg), + NeighborUpdateAuth(IpAddr), +} + +pub static VALIDATION_CALLBACKS: Lazy = + Lazy::new(load_validation_callbacks); +pub static CALLBACKS: Lazy> = Lazy::new(load_callbacks); + +// ===== configuration structs ===== + +#[derive(Debug)] +pub struct InstanceCfg { + pub asn: u32, + pub identifier: Option, + pub distance_external: u8, + pub distance_internal: u8, + pub multipath: InstanceMultipathCfg, + pub route_selection: RouteSelectionCfg, + pub apply_policy: ApplyPolicyCfg, + pub afi_safi: BTreeMap, +} + +#[derive(Debug)] +pub struct InstanceMultipathCfg { + pub enabled: bool, + pub ebgp_allow_multiple_as: bool, + pub ebgp_maximum_paths: u32, + pub ibgp_maximum_paths: u32, +} + +#[derive(Debug)] +pub struct InstanceAfiSafiCfg { + pub enabled: bool, + pub multipath: InstanceMultipathCfg, + pub route_selection: RouteSelectionCfg, + pub prefix_limit: PrefixLimitCfg, + pub send_default_route: bool, + pub apply_policy: ApplyPolicyCfg, +} + +#[derive(Debug)] +pub struct NeighborCfg { + pub enabled: bool, + pub peer_as: u32, + pub local_as: Option, + pub private_as_remove: Option, + pub timers: NeighborTimersCfg, + pub transport: NeighborTransportCfg, + pub treat_as_withdraw: bool, + pub log_neighbor_state_changes: bool, + pub as_path_options: AsPathOptions, + pub multipath: NeighborMultipathCfg, + pub apply_policy: ApplyPolicyCfg, + pub prefix_limit: PrefixLimitCfg, + pub afi_safi: BTreeMap, +} + +#[derive(Debug)] +pub struct NeighborMultipathCfg { + pub enabled: bool, + pub ebgp_allow_multiple_as: bool, +} + +#[derive(Debug)] +pub struct NeighborTimersCfg { + pub connect_retry_interval: u16, + pub holdtime: u16, + pub keepalive: Option, + pub min_as_orig_interval: Option, + pub min_route_adv_interval: Option, +} + +#[derive(Debug)] +pub struct NeighborTransportCfg { + // TODO: this can be an interface name too. + pub local_addr: Option, + pub tcp_mss: Option, + pub ebgp_multihop_enabled: bool, + pub ebgp_multihop_ttl: Option, + pub passive_mode: bool, + pub ttl_security: Option, + pub secure_session_enabled: bool, + pub md5_key: Option, +} + +#[derive(Debug)] +pub struct NeighborAfiSafiCfg { + pub enabled: bool, + pub multipath: NeighborMultipathCfg, + pub prefix_limit: PrefixLimitCfg, + pub send_default_route: bool, + pub apply_policy: ApplyPolicyCfg, +} + +#[derive(Debug)] +pub struct RouteSelectionCfg { + pub always_compare_med: bool, + pub ignore_as_path_length: bool, + pub external_compare_router_id: bool, + pub ignore_next_hop_igp_metric: bool, + pub enable_med: bool, +} + +#[derive(Debug)] +pub struct PrefixLimitCfg { + pub max_prefixes: Option, + pub warning_threshold_pct: Option, + pub teardown: bool, + pub idle_time: Option, +} + +#[derive(Debug)] +pub struct AsPathOptions { + pub allow_own_as: u8, + pub replace_peer_as: bool, + pub disable_peer_as_filter: bool, +} + +#[derive(Debug)] +pub enum PrivateAsRemove { + RemoveAll, + ReplaceAll, +} + +// ===== callbacks ===== + +fn load_callbacks() -> Callbacks { + CallbacksBuilder::::default() + .path(bgp::global::PATH) + .create_apply(|_instance, _args| { + }) + .delete_apply(|_instance, _args| { + }) + .path(bgp::global::r#as::PATH) + .modify_apply(|instance, args| { + let asn = args.dnode.get_u32(); + instance.config.asn = asn; + + let event_queue = args.event_queue; + event_queue.insert(Event::InstanceUpdate); + }) + .path(bgp::global::identifier::PATH) + .modify_apply(|instance, args| { + let identifier = args.dnode.get_ipv4(); + instance.config.identifier = Some(identifier); + + let event_queue = args.event_queue; + event_queue.insert(Event::InstanceUpdate); + }) + .delete_apply(|instance, args| { + instance.config.identifier = None; + + let event_queue = args.event_queue; + event_queue.insert(Event::InstanceUpdate); + }) + .path(bgp::global::distance::external::PATH) + .modify_apply(|instance, args| { + let distance = args.dnode.get_u8(); + instance.config.distance_external = distance; + }) + .path(bgp::global::distance::internal::PATH) + .modify_apply(|instance, args| { + let distance = args.dnode.get_u8(); + instance.config.distance_internal = distance; + }) + .path(bgp::global::use_multiple_paths::enabled::PATH) + .modify_apply(|instance, args| { + let enabled = args.dnode.get_bool(); + instance.config.multipath.enabled = enabled; + }) + .path(bgp::global::use_multiple_paths::ebgp::allow_multiple_as::PATH) + .modify_apply(|instance, args| { + let allow = args.dnode.get_bool(); + instance.config.multipath.ebgp_allow_multiple_as = allow; + }) + .path(bgp::global::use_multiple_paths::ebgp::maximum_paths::PATH) + .modify_apply(|instance, args| { + let max = args.dnode.get_u32(); + instance.config.multipath.ebgp_maximum_paths = max; + }) + .path(bgp::global::use_multiple_paths::ibgp::maximum_paths::PATH) + .modify_apply(|instance, args| { + let max = args.dnode.get_u32(); + instance.config.multipath.ibgp_maximum_paths = max; + }) + .path(bgp::global::route_selection_options::always_compare_med::PATH) + .modify_apply(|instance, args| { + let compare = args.dnode.get_bool(); + instance.config.route_selection.always_compare_med = compare; + }) + .path(bgp::global::route_selection_options::ignore_as_path_length::PATH) + .modify_apply(|instance, args| { + let ignore = args.dnode.get_bool(); + instance.config.route_selection.ignore_as_path_length = ignore; + }) + .path(bgp::global::route_selection_options::external_compare_router_id::PATH) + .modify_apply(|instance, args| { + let compare = args.dnode.get_bool(); + instance.config.route_selection.external_compare_router_id = compare; + }) + .path(bgp::global::route_selection_options::ignore_next_hop_igp_metric::PATH) + .modify_apply(|instance, args| { + let ignore = args.dnode.get_bool(); + instance.config.route_selection.ignore_next_hop_igp_metric = ignore; + }) + .path(bgp::global::route_selection_options::enable_med::PATH) + .modify_apply(|instance, args| { + let enable = args.dnode.get_bool(); + instance.config.route_selection.enable_med = enable; + }) + .path(bgp::global::afi_safis::afi_safi::PATH) + .create_apply(|instance, args| { + let afi_safi = args.dnode.get_string_relative("./name").unwrap(); + let afi_safi = AfiSafi::try_from_yang(&afi_safi).unwrap(); + instance.config.afi_safi.insert(afi_safi, Default::default()); + }) + .delete_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + + instance.config.afi_safi.remove(&afi_safi); + }) + .lookup(|_instance, _list_entry, dnode| { + let afi_safi = dnode.get_string_relative("./name").unwrap(); + let afi_safi = AfiSafi::try_from_yang(&afi_safi).unwrap(); + ListEntry::AfiSafi(afi_safi) + }) + .path(bgp::global::afi_safis::afi_safi::enabled::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let enabled = args.dnode.get_bool(); + afi_safi.enabled = enabled; + }) + .path(bgp::global::afi_safis::afi_safi::route_selection_options::always_compare_med::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let compare = args.dnode.get_bool(); + afi_safi.route_selection.always_compare_med = compare; + }) + .path(bgp::global::afi_safis::afi_safi::route_selection_options::ignore_as_path_length::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let ignore = args.dnode.get_bool(); + afi_safi.route_selection.ignore_as_path_length = ignore; + }) + .path(bgp::global::afi_safis::afi_safi::route_selection_options::external_compare_router_id::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let compare = args.dnode.get_bool(); + afi_safi.route_selection.external_compare_router_id = compare; + }) + .path(bgp::global::afi_safis::afi_safi::route_selection_options::ignore_next_hop_igp_metric::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let ignore = args.dnode.get_bool(); + afi_safi.route_selection.ignore_next_hop_igp_metric = ignore; + }) + .path(bgp::global::afi_safis::afi_safi::route_selection_options::enable_med::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let enable = args.dnode.get_bool(); + afi_safi.route_selection.enable_med = enable; + }) + .path(bgp::global::afi_safis::afi_safi::use_multiple_paths::enabled::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let enabled = args.dnode.get_bool(); + afi_safi.multipath.enabled = enabled; + }) + .path(bgp::global::afi_safis::afi_safi::use_multiple_paths::ebgp::allow_multiple_as::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let allow = args.dnode.get_bool(); + afi_safi.multipath.ebgp_allow_multiple_as = allow; + }) + .path(bgp::global::afi_safis::afi_safi::use_multiple_paths::ebgp::maximum_paths::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let max = args.dnode.get_u32(); + afi_safi.multipath.ebgp_maximum_paths = max; + }) + .path(bgp::global::afi_safis::afi_safi::use_multiple_paths::ibgp::maximum_paths::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let max = args.dnode.get_u32(); + afi_safi.multipath.ibgp_maximum_paths = max; + }) + .path(bgp::global::afi_safis::afi_safi::apply_policy::import_policy::PATH) + .create_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let policy = args.dnode.get_string(); + afi_safi.apply_policy.import_policy.insert(policy); + }) + .delete_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let policy = args.dnode.get_string(); + afi_safi.apply_policy.import_policy.remove(&policy); + }) + .path(bgp::global::afi_safis::afi_safi::apply_policy::default_import_policy::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let default = args.dnode.get_string(); + let default = DefaultPolicyType::try_from_yang(&default).unwrap(); + afi_safi.apply_policy.default_import_policy = default; + }) + .path(bgp::global::afi_safis::afi_safi::apply_policy::export_policy::PATH) + .create_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let policy = args.dnode.get_string(); + afi_safi.apply_policy.export_policy.insert(policy); + }) + .delete_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let policy = args.dnode.get_string(); + afi_safi.apply_policy.export_policy.remove(&policy); + }) + .path(bgp::global::afi_safis::afi_safi::apply_policy::default_export_policy::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let default = args.dnode.get_string(); + let default = DefaultPolicyType::try_from_yang(&default).unwrap(); + afi_safi.apply_policy.default_export_policy = default; + }) + .path(bgp::global::afi_safis::afi_safi::ipv4_unicast::prefix_limit::max_prefixes::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let max = args.dnode.get_u32(); + afi_safi.prefix_limit.max_prefixes = Some(max); + }) + .delete_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + afi_safi.prefix_limit.max_prefixes = None; + }) + .path(bgp::global::afi_safis::afi_safi::ipv4_unicast::prefix_limit::warning_threshold_pct::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let threshold = args.dnode.get_u8(); + afi_safi.prefix_limit.warning_threshold_pct = Some(threshold); + }) + .delete_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + afi_safi.prefix_limit.warning_threshold_pct = None; + }) + .path(bgp::global::afi_safis::afi_safi::ipv4_unicast::prefix_limit::teardown::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let teardown = args.dnode.get_bool(); + afi_safi.prefix_limit.teardown = teardown; + }) + .path(bgp::global::afi_safis::afi_safi::ipv4_unicast::prefix_limit::idle_time::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let idle_time = args.dnode.get_string(); + let idle_time: u32 = idle_time.parse().unwrap(); + afi_safi.prefix_limit.idle_time = Some(idle_time); + }) + .delete_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + afi_safi.prefix_limit.idle_time = None; + }) + .path(bgp::global::afi_safis::afi_safi::ipv4_unicast::send_default_route::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let send = args.dnode.get_bool(); + afi_safi.send_default_route = send; + }) + .path(bgp::global::afi_safis::afi_safi::ipv6_unicast::prefix_limit::max_prefixes::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let max = args.dnode.get_u32(); + afi_safi.prefix_limit.max_prefixes = Some(max); + }) + .delete_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + afi_safi.prefix_limit.max_prefixes = None; + }) + .path(bgp::global::afi_safis::afi_safi::ipv6_unicast::prefix_limit::warning_threshold_pct::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let threshold = args.dnode.get_u8(); + afi_safi.prefix_limit.warning_threshold_pct = Some(threshold); + }) + .delete_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + afi_safi.prefix_limit.warning_threshold_pct = None; + }) + .path(bgp::global::afi_safis::afi_safi::ipv6_unicast::prefix_limit::teardown::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let teardown = args.dnode.get_bool(); + afi_safi.prefix_limit.teardown = teardown; + }) + .path(bgp::global::afi_safis::afi_safi::ipv6_unicast::prefix_limit::idle_time::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let idle_time = args.dnode.get_string(); + let idle_time: u32 = idle_time.parse().unwrap(); + afi_safi.prefix_limit.idle_time = Some(idle_time); + }) + .delete_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + afi_safi.prefix_limit.idle_time = None; + }) + .path(bgp::global::afi_safis::afi_safi::ipv6_unicast::send_default_route::PATH) + .modify_apply(|instance, args| { + let afi_safi = args.list_entry.into_afi_safi().unwrap(); + let afi_safi = instance.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let send = args.dnode.get_bool(); + afi_safi.send_default_route = send; + }) + .path(bgp::global::apply_policy::import_policy::PATH) + .create_apply(|instance, args| { + let policy = args.dnode.get_string(); + instance.config.apply_policy.import_policy.insert(policy); + }) + .delete_apply(|instance, args| { + let policy = args.dnode.get_string(); + instance.config.apply_policy.import_policy.remove(&policy); + }) + .path(bgp::global::apply_policy::default_import_policy::PATH) + .modify_apply(|instance, args| { + let default = args.dnode.get_string(); + let default = DefaultPolicyType::try_from_yang(&default).unwrap(); + instance.config.apply_policy.default_import_policy = default; + }) + .path(bgp::global::apply_policy::export_policy::PATH) + .create_apply(|instance, args| { + let policy = args.dnode.get_string(); + instance.config.apply_policy.export_policy.insert(policy); + }) + .delete_apply(|instance, args| { + let policy = args.dnode.get_string(); + instance.config.apply_policy.export_policy.remove(&policy); + }) + .path(bgp::global::apply_policy::default_export_policy::PATH) + .modify_apply(|instance, args| { + let default = args.dnode.get_string(); + let default = DefaultPolicyType::try_from_yang(&default).unwrap(); + instance.config.apply_policy.default_export_policy = default; + }) + .path(bgp::neighbors::neighbor::PATH) + .create_apply(|instance, args| { + let nbr_addr = args.dnode.get_ip_relative("./remote-address").unwrap(); + let peer_as = args.dnode.get_u32_relative("./peer-as").unwrap(); + + let peer_type = if instance.config.asn == peer_as { + PeerType::Internal + } else { + PeerType::External + }; + let nbr = Neighbor::new(nbr_addr, peer_type); + instance.neighbors.insert(nbr_addr, nbr); + + let event_queue = args.event_queue; + event_queue.insert(Event::NeighborUpdate(nbr_addr)); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + + instance.neighbors.remove(&nbr_addr); + + // TODO: neighbor delete event + // TODO: unset md5 password + }) + .lookup(|_instance, _list_entry, dnode| { + let nbr_addr = dnode.get_ip_relative("./remote-address").unwrap(); + ListEntry::Neighbor(nbr_addr) + }) + .path(bgp::neighbors::neighbor::enabled::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let enabled = args.dnode.get_bool(); + nbr.config.enabled = enabled; + }) + .path(bgp::neighbors::neighbor::peer_as::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let asn = args.dnode.get_u32(); + nbr.config.peer_as = asn; + nbr.peer_type = if instance.config.asn == nbr.config.peer_as { + PeerType::Internal + } else { + PeerType::External + }; + + let event_queue = args.event_queue; + let msg = NotificationMsg::new( + ErrorCode::Cease, + CeaseSubcode::OtherConfigurationChange, + ); + event_queue.insert(Event::NeighborReset(nbr.remote_addr, msg)); + }) + .path(bgp::neighbors::neighbor::local_as::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let asn = args.dnode.get_u32(); + nbr.config.local_as = Some(asn); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + nbr.config.local_as = None; + }) + .path(bgp::neighbors::neighbor::remove_private_as::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let private_as_remove = args.dnode.get_string(); + let private_as_remove = PrivateAsRemove::try_from_yang(&private_as_remove).unwrap(); + nbr.config.private_as_remove = Some(private_as_remove); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + nbr.config.private_as_remove = None; + }) + .path(bgp::neighbors::neighbor::description::PATH) + .modify_apply(|_instance, _args| { + // Nothing to do. + }) + .delete_apply(|_instance, _args| { + // Nothing to do. + }) + .path(bgp::neighbors::neighbor::timers::connect_retry_interval::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let interval = args.dnode.get_u16(); + nbr.config.timers.connect_retry_interval = interval; + }) + .path(bgp::neighbors::neighbor::timers::hold_time::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let holdtime = args.dnode.get_u16(); + nbr.config.timers.holdtime = holdtime; + }) + .path(bgp::neighbors::neighbor::timers::keepalive::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let keepalive = args.dnode.get_u16(); + nbr.config.timers.keepalive = Some(keepalive); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + nbr.config.timers.keepalive = None; + }) + .path(bgp::neighbors::neighbor::timers::min_as_origination_interval::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let interval = args.dnode.get_u16(); + nbr.config.timers.min_as_orig_interval = Some(interval); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + nbr.config.timers.min_as_orig_interval = None; + }) + .path(bgp::neighbors::neighbor::timers::min_route_advertisement_interval::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let interval = args.dnode.get_u16(); + nbr.config.timers.min_route_adv_interval = Some(interval); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + nbr.config.timers.min_route_adv_interval = None; + }) + .path(bgp::neighbors::neighbor::transport::local_address::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let addr = args.dnode.get_ip(); + nbr.config.transport.local_addr = Some(addr); + + let event_queue = args.event_queue; + let msg = NotificationMsg::new( + ErrorCode::Cease, + CeaseSubcode::OtherConfigurationChange, + ); + event_queue.insert(Event::NeighborReset(nbr.remote_addr, msg)); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + nbr.config.transport.local_addr = None; + + let event_queue = args.event_queue; + let msg = NotificationMsg::new( + ErrorCode::Cease, + CeaseSubcode::OtherConfigurationChange, + ); + event_queue.insert(Event::NeighborReset(nbr.remote_addr, msg)); + }) + .path(bgp::neighbors::neighbor::transport::tcp_mss::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let tcp_mss = args.dnode.get_u16(); + nbr.config.transport.tcp_mss = Some(tcp_mss); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + nbr.config.transport.tcp_mss = None; + }) + .path(bgp::neighbors::neighbor::transport::ebgp_multihop::enabled::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let enabled = args.dnode.get_bool(); + nbr.config.transport.ebgp_multihop_enabled = enabled; + + let event_queue = args.event_queue; + let msg = NotificationMsg::new( + ErrorCode::Cease, + CeaseSubcode::OtherConfigurationChange, + ); + event_queue.insert(Event::NeighborReset(nbr.remote_addr, msg)); + }) + .path(bgp::neighbors::neighbor::transport::ebgp_multihop::multihop_ttl::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let ttl = args.dnode.get_u8(); + nbr.config.transport.ebgp_multihop_ttl = Some(ttl); + + let event_queue = args.event_queue; + let msg = NotificationMsg::new( + ErrorCode::Cease, + CeaseSubcode::OtherConfigurationChange, + ); + event_queue.insert(Event::NeighborReset(nbr.remote_addr, msg)); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + nbr.config.transport.ebgp_multihop_ttl = None; + + let event_queue = args.event_queue; + let msg = NotificationMsg::new( + ErrorCode::Cease, + CeaseSubcode::OtherConfigurationChange, + ); + event_queue.insert(Event::NeighborReset(nbr.remote_addr, msg)); + }) + .path(bgp::neighbors::neighbor::transport::passive_mode::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let passive_mode = args.dnode.get_bool(); + nbr.config.transport.passive_mode = passive_mode; + }) + .path(bgp::neighbors::neighbor::transport::ttl_security::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let ttl_security = args.dnode.get_u8(); + nbr.config.transport.ttl_security = Some(ttl_security); + + let event_queue = args.event_queue; + let msg = NotificationMsg::new( + ErrorCode::Cease, + CeaseSubcode::OtherConfigurationChange, + ); + event_queue.insert(Event::NeighborReset(nbr.remote_addr, msg)); + }) + .path(bgp::neighbors::neighbor::transport::secure_session::enabled::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let enabled = args.dnode.get_bool(); + nbr.config.transport.secure_session_enabled = enabled; + + let event_queue = args.event_queue; + let msg = NotificationMsg::new( + ErrorCode::Cease, + CeaseSubcode::OtherConfigurationChange, + ); + event_queue.insert(Event::NeighborReset(nbr.remote_addr, msg)); + event_queue.insert(Event::NeighborUpdateAuth(nbr.remote_addr)); + }) + .path(bgp::neighbors::neighbor::transport::secure_session::options::md5_key_string::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let keychain = args.dnode.get_string(); + nbr.config.transport.md5_key = Some(keychain); + + let event_queue = args.event_queue; + let msg = NotificationMsg::new( + ErrorCode::Cease, + CeaseSubcode::OtherConfigurationChange, + ); + event_queue.insert(Event::NeighborReset(nbr.remote_addr, msg)); + event_queue.insert(Event::NeighborUpdateAuth(nbr.remote_addr)); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + nbr.config.transport.md5_key = None; + + let event_queue = args.event_queue; + let msg = NotificationMsg::new( + ErrorCode::Cease, + CeaseSubcode::OtherConfigurationChange, + ); + event_queue.insert(Event::NeighborReset(nbr.remote_addr, msg)); + event_queue.insert(Event::NeighborUpdateAuth(nbr.remote_addr)); + }) + .path(bgp::neighbors::neighbor::treat_as_withdraw::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let treat_as_withdraw = args.dnode.get_bool(); + nbr.config.treat_as_withdraw = treat_as_withdraw; + }) + .path(bgp::neighbors::neighbor::logging_options::log_neighbor_state_changes::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let log = args.dnode.get_bool(); + nbr.config.log_neighbor_state_changes = log; + }) + .path(bgp::neighbors::neighbor::as_path_options::allow_own_as::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let allow = args.dnode.get_u8(); + nbr.config.as_path_options.allow_own_as = allow; + }) + .path(bgp::neighbors::neighbor::as_path_options::replace_peer_as::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let replace = args.dnode.get_bool(); + nbr.config.as_path_options.replace_peer_as = replace; + }) + .path(bgp::neighbors::neighbor::as_path_options::disable_peer_as_filter::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let disable = args.dnode.get_bool(); + nbr.config.as_path_options.disable_peer_as_filter = disable; + }) + .path(bgp::neighbors::neighbor::use_multiple_paths::enabled::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let enabled = args.dnode.get_bool(); + nbr.config.multipath.enabled = enabled; + }) + .path(bgp::neighbors::neighbor::use_multiple_paths::ebgp::allow_multiple_as::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let allow = args.dnode.get_bool(); + nbr.config.multipath.ebgp_allow_multiple_as = allow; + }) + .path(bgp::neighbors::neighbor::apply_policy::import_policy::PATH) + .create_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let policy = args.dnode.get_string(); + nbr.config.apply_policy.import_policy.insert(policy); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let policy = args.dnode.get_string(); + nbr.config.apply_policy.import_policy.remove(&policy); + }) + .path(bgp::neighbors::neighbor::apply_policy::default_import_policy::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let default = args.dnode.get_string(); + let default = DefaultPolicyType::try_from_yang(&default).unwrap(); + nbr.config.apply_policy.default_import_policy = default; + }) + .path(bgp::neighbors::neighbor::apply_policy::export_policy::PATH) + .create_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let policy = args.dnode.get_string(); + nbr.config.apply_policy.export_policy.insert(policy); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let policy = args.dnode.get_string(); + nbr.config.apply_policy.export_policy.remove(&policy); + }) + .path(bgp::neighbors::neighbor::apply_policy::default_export_policy::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let default = args.dnode.get_string(); + let default = DefaultPolicyType::try_from_yang(&default).unwrap(); + nbr.config.apply_policy.default_export_policy = default; + }) + .path(bgp::neighbors::neighbor::prefix_limit::max_prefixes::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let max = args.dnode.get_u32(); + nbr.config.prefix_limit.max_prefixes = Some(max); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + nbr.config.prefix_limit.max_prefixes = None; + }) + .path(bgp::neighbors::neighbor::prefix_limit::warning_threshold_pct::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let threshold = args.dnode.get_u8(); + nbr.config.prefix_limit.warning_threshold_pct = Some(threshold); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + nbr.config.prefix_limit.warning_threshold_pct = None; + }) + .path(bgp::neighbors::neighbor::prefix_limit::teardown::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let teardown = args.dnode.get_bool(); + nbr.config.prefix_limit.teardown = teardown; + }) + .path(bgp::neighbors::neighbor::prefix_limit::idle_time::PATH) + .modify_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let idle_time = args.dnode.get_string(); + let idle_time: u32 = idle_time.parse().unwrap(); + nbr.config.prefix_limit.idle_time = Some(idle_time); + }) + .delete_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + nbr.config.prefix_limit.idle_time = None; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::PATH) + .create_apply(|instance, args| { + let nbr_addr = args.list_entry.into_neighbor().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + + let afi_safi = args.dnode.get_string_relative("./name").unwrap(); + let afi_safi = AfiSafi::try_from_yang(&afi_safi).unwrap(); + nbr.config.afi_safi.insert(afi_safi, Default::default()); + }) + .delete_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + nbr.config.afi_safi.remove(&afi_safi); + }) + .lookup(|_instance, list_entry, dnode| { + let nbr_addr = list_entry.into_neighbor().unwrap(); + let afi_safi = dnode.get_string_relative("./name").unwrap(); + let afi_safi = AfiSafi::try_from_yang(&afi_safi).unwrap(); + ListEntry::NeighborAfiSafi(nbr_addr, afi_safi) + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::enabled::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let enabled = args.dnode.get_bool(); + afi_safi.enabled = enabled; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::apply_policy::import_policy::PATH) + .create_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let policy = args.dnode.get_string(); + afi_safi.apply_policy.import_policy.insert(policy); + }) + .delete_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let policy = args.dnode.get_string(); + afi_safi.apply_policy.import_policy.remove(&policy); + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::apply_policy::default_import_policy::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let default = args.dnode.get_string(); + let default = DefaultPolicyType::try_from_yang(&default).unwrap(); + afi_safi.apply_policy.default_import_policy = default; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::apply_policy::export_policy::PATH) + .create_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let policy = args.dnode.get_string(); + afi_safi.apply_policy.export_policy.insert(policy); + }) + .delete_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let policy = args.dnode.get_string(); + afi_safi.apply_policy.export_policy.remove(&policy); + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::apply_policy::default_export_policy::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let default = args.dnode.get_string(); + let default = DefaultPolicyType::try_from_yang(&default).unwrap(); + afi_safi.apply_policy.default_export_policy = default; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::ipv4_unicast::prefix_limit::max_prefixes::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let max = args.dnode.get_u32(); + afi_safi.prefix_limit.max_prefixes = Some(max); + }) + .delete_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + afi_safi.prefix_limit.max_prefixes = None; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::ipv4_unicast::prefix_limit::warning_threshold_pct::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let threshold = args.dnode.get_u8(); + afi_safi.prefix_limit.warning_threshold_pct = Some(threshold); + }) + .delete_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + afi_safi.prefix_limit.warning_threshold_pct = None; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::ipv4_unicast::prefix_limit::teardown::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let teardown = args.dnode.get_bool(); + afi_safi.prefix_limit.teardown = teardown; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::ipv4_unicast::prefix_limit::idle_time::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let idle_time = args.dnode.get_string(); + let idle_time: u32 = idle_time.parse().unwrap(); + afi_safi.prefix_limit.idle_time = Some(idle_time); + }) + .delete_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + afi_safi.prefix_limit.idle_time = None; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::ipv4_unicast::send_default_route::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let send = args.dnode.get_bool(); + afi_safi.send_default_route = send; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::ipv6_unicast::prefix_limit::max_prefixes::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let max = args.dnode.get_u32(); + afi_safi.prefix_limit.max_prefixes = Some(max); + }) + .delete_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + afi_safi.prefix_limit.max_prefixes = None; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::ipv6_unicast::prefix_limit::warning_threshold_pct::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let threshold = args.dnode.get_u8(); + afi_safi.prefix_limit.warning_threshold_pct = Some(threshold); + }) + .delete_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + afi_safi.prefix_limit.warning_threshold_pct = None; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::ipv6_unicast::prefix_limit::teardown::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let teardown = args.dnode.get_bool(); + afi_safi.prefix_limit.teardown = teardown; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::ipv6_unicast::prefix_limit::idle_time::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let idle_time = args.dnode.get_string(); + let idle_time: u32 = idle_time.parse().unwrap(); + afi_safi.prefix_limit.idle_time = Some(idle_time); + }) + .delete_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + afi_safi.prefix_limit.idle_time = None; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::ipv6_unicast::send_default_route::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let send = args.dnode.get_bool(); + afi_safi.send_default_route = send; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::use_multiple_paths::enabled::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let enabled = args.dnode.get_bool(); + afi_safi.multipath.enabled = enabled; + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::use_multiple_paths::ebgp::allow_multiple_as::PATH) + .modify_apply(|instance, args| { + let (nbr_addr, afi_safi) = args.list_entry.into_neighbor_afi_safi().unwrap(); + let nbr = instance.neighbors.get_mut(&nbr_addr).unwrap(); + let afi_safi = nbr.config.afi_safi.get_mut(&afi_safi).unwrap(); + + let allow = args.dnode.get_bool(); + afi_safi.multipath.ebgp_allow_multiple_as = allow; + }) + .build() +} + +fn load_validation_callbacks() -> ValidationCallbacks { + ValidationCallbacksBuilder::default().build() +} + +// ===== impl Instance ===== + +#[async_trait] +impl Provider for Instance { + type ListEntry = ListEntry; + type Event = Event; + type Resource = Resource; + + fn validation_callbacks() -> Option<&'static ValidationCallbacks> { + Some(&VALIDATION_CALLBACKS) + } + + fn callbacks() -> Option<&'static Callbacks> { + Some(&CALLBACKS) + } + + async fn process_event(&mut self, event: Event) { + match event { + Event::InstanceUpdate => self.update().await, + Event::NeighborUpdate(nbr_addr) => { + let Some((mut instance, neighbors)) = self.as_up() else { + return; + }; + let nbr = neighbors.get_mut(&nbr_addr).unwrap(); + + if nbr.config.enabled { + nbr.fsm_event(&mut instance, fsm::Event::Start); + } else { + let error_code = ErrorCode::Cease; + let error_subcode = CeaseSubcode::AdministrativeShutdown; + let msg = NotificationMsg::new(error_code, error_subcode); + nbr.fsm_event(&mut instance, fsm::Event::Stop(Some(msg))); + } + } + Event::NeighborReset(nbr_addr, msg) => { + let Some((mut instance, neighbors)) = self.as_up() else { + return; + }; + let nbr = neighbors.get_mut(&nbr_addr).unwrap(); + + nbr.fsm_event(&mut instance, fsm::Event::Stop(Some(msg))); + } + Event::NeighborUpdateAuth(nbr_addr) => { + let Some((instance, neighbors)) = self.as_up() else { + return; + }; + let nbr = neighbors.get_mut(&nbr_addr).unwrap(); + + // Get neighbor password. + let key = if nbr.config.transport.secure_session_enabled + && let Some(key) = &nbr.config.transport.md5_key + { + Some(key.clone()) + } else { + None + }; + + // Set/unset password in the listening sockets. + for listener in + instance.state.listening_sockets.iter().filter(|listener| { + listener.af == nbr_addr.address_family() + }) + { + network::listen_socket_md5sig_update( + &listener.socket, + &nbr_addr, + key.as_deref(), + ); + } + } + } + } +} + +// ===== configuration defaults ===== + +impl Default for InstanceCfg { + fn default() -> InstanceCfg { + let distance_external = bgp::global::distance::external::DFLT; + let distance_internal = bgp::global::distance::internal::DFLT; + + InstanceCfg { + asn: 0, + identifier: None, + distance_external, + distance_internal, + multipath: Default::default(), + route_selection: Default::default(), + apply_policy: Default::default(), + afi_safi: Default::default(), + } + } +} + +impl Default for InstanceMultipathCfg { + fn default() -> InstanceMultipathCfg { + let enabled = bgp::global::use_multiple_paths::enabled::DFLT; + let ebgp_allow_multiple_as = + bgp::global::use_multiple_paths::ebgp::allow_multiple_as::DFLT; + let ebgp_maximum_paths = + bgp::global::use_multiple_paths::ebgp::maximum_paths::DFLT; + let ibgp_maximum_paths = + bgp::global::use_multiple_paths::ibgp::maximum_paths::DFLT; + + InstanceMultipathCfg { + enabled, + ebgp_allow_multiple_as, + ebgp_maximum_paths, + ibgp_maximum_paths, + } + } +} + +impl Default for InstanceAfiSafiCfg { + fn default() -> InstanceAfiSafiCfg { + // TODO: fetch defaults from YANG module + InstanceAfiSafiCfg { + enabled: false, + multipath: Default::default(), + route_selection: Default::default(), + prefix_limit: Default::default(), + send_default_route: false, + apply_policy: Default::default(), + } + } +} + +impl Default for NeighborCfg { + fn default() -> NeighborCfg { + let enabled = bgp::neighbors::neighbor::enabled::DFLT; + let treat_as_withdraw = + bgp::neighbors::neighbor::treat_as_withdraw::DFLT; + let log_neighbor_state_changes = + bgp::neighbors::neighbor::logging_options::log_neighbor_state_changes::DFLT; + + NeighborCfg { + enabled, + peer_as: 0, + local_as: None, + private_as_remove: None, + timers: Default::default(), + transport: Default::default(), + treat_as_withdraw, + log_neighbor_state_changes, + as_path_options: Default::default(), + multipath: Default::default(), + apply_policy: Default::default(), + prefix_limit: Default::default(), + afi_safi: Default::default(), + } + } +} + +impl Default for NeighborMultipathCfg { + fn default() -> NeighborMultipathCfg { + // TODO: fetch defaults from YANG module + NeighborMultipathCfg { + enabled: false, + ebgp_allow_multiple_as: false, + } + } +} + +impl Default for NeighborTimersCfg { + fn default() -> NeighborTimersCfg { + let connect_retry_interval = + bgp::neighbors::neighbor::timers::connect_retry_interval::DFLT; + let holdtime = bgp::neighbors::neighbor::timers::hold_time::DFLT; + + NeighborTimersCfg { + connect_retry_interval, + holdtime, + keepalive: None, + min_as_orig_interval: None, + min_route_adv_interval: None, + } + } +} + +impl Default for NeighborTransportCfg { + fn default() -> NeighborTransportCfg { + let ebgp_multihop_enabled = + bgp::neighbors::neighbor::transport::ebgp_multihop::enabled::DFLT; + let passive_mode = + bgp::neighbors::neighbor::transport::passive_mode::DFLT; + let secure_session_enabled = + bgp::neighbors::neighbor::transport::secure_session::enabled::DFLT; + + NeighborTransportCfg { + local_addr: None, + tcp_mss: None, + ebgp_multihop_enabled, + ebgp_multihop_ttl: None, + passive_mode, + ttl_security: None, + secure_session_enabled, + md5_key: None, + } + } +} + +impl Default for NeighborAfiSafiCfg { + fn default() -> NeighborAfiSafiCfg { + let enabled = + bgp::neighbors::neighbor::afi_safis::afi_safi::enabled::DFLT; + + NeighborAfiSafiCfg { + enabled, + multipath: Default::default(), + prefix_limit: Default::default(), + send_default_route: false, + apply_policy: Default::default(), + } + } +} + +impl Default for RouteSelectionCfg { + fn default() -> RouteSelectionCfg { + // TODO: fetch defaults from YANG module + RouteSelectionCfg { + always_compare_med: false, + ignore_as_path_length: false, + external_compare_router_id: true, + ignore_next_hop_igp_metric: false, + enable_med: false, + } + } +} + +impl Default for PrefixLimitCfg { + fn default() -> PrefixLimitCfg { + // TODO: fetch defaults from YANG module + PrefixLimitCfg { + max_prefixes: None, + warning_threshold_pct: None, + teardown: false, + idle_time: None, + } + } +} + +impl Default for AsPathOptions { + fn default() -> AsPathOptions { + // TODO: fetch defaults from YANG module + AsPathOptions { + allow_own_as: 0, + replace_peer_as: false, + disable_peer_as_filter: false, + } + } +} diff --git a/holo-bgp/src/northbound/mod.rs b/holo-bgp/src/northbound/mod.rs new file mode 100644 index 00000000..9a2cc1b5 --- /dev/null +++ b/holo-bgp/src/northbound/mod.rs @@ -0,0 +1,58 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +pub mod configuration; +pub mod rpc; +pub mod state; +pub mod yang; + +use holo_northbound::ProviderBase; +use holo_utils::protocol::Protocol; +use holo_yang::ToYang; +use num_derive::{FromPrimitive, ToPrimitive}; +use tracing::{debug_span, Span}; + +use crate::instance::Instance; +use crate::packet::{Afi, Safi}; + +// Configurable (AFI,SAFI) tuples. +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[derive(FromPrimitive, ToPrimitive)] +pub enum AfiSafi { + Ipv4Unicast, + Ipv6Unicast, +} + +// ===== impl Instance ===== + +impl ProviderBase for Instance { + fn yang_modules() -> &'static [&'static str] { + &["ietf-bgp", "holo-bgp"] + } + + fn top_level_node(&self) -> String { + format!( + "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='{}'][name='main']/ietf-bgp:bgp", + Protocol::BGP.to_yang(), + ) + } + + fn debug_span(name: &str) -> Span { + debug_span!("bgp-instance", %name) + } +} + +// ===== impl AfiSafi ===== + +impl AfiSafi { + pub(crate) fn from_tuple(afi: Afi, safi: Safi) -> Option { + match (afi, safi) { + (Afi::Ipv4, Safi::Unicast) => Some(AfiSafi::Ipv4Unicast), + (Afi::Ipv6, Safi::Unicast) => Some(AfiSafi::Ipv6Unicast), + _ => None, + } + } +} diff --git a/holo-bgp/src/northbound/rpc.rs b/holo-bgp/src/northbound/rpc.rs new file mode 100644 index 00000000..6cdb875f --- /dev/null +++ b/holo-bgp/src/northbound/rpc.rs @@ -0,0 +1,30 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::sync::LazyLock as Lazy; + +use holo_northbound::rpc::{Callbacks, CallbacksBuilder, Provider}; + +//use holo_utils::yang::DataNodeRefExt; +//use yang2::data::Data; +use crate::instance::Instance; + +pub static CALLBACKS: Lazy> = Lazy::new(load_callbacks); + +// ===== callbacks ===== + +fn load_callbacks() -> Callbacks { + // TODO: YANG actions are not supported yet. + CallbacksBuilder::::default().build() +} + +// ===== impl Instance ===== + +impl Provider for Instance { + fn callbacks() -> Option<&'static Callbacks> { + Some(&CALLBACKS) + } +} diff --git a/holo-bgp/src/northbound/state.rs b/holo-bgp/src/northbound/state.rs new file mode 100644 index 00000000..59009b21 --- /dev/null +++ b/holo-bgp/src/northbound/state.rs @@ -0,0 +1,1532 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::sync::{atomic, LazyLock as Lazy}; + +use enum_as_inner::EnumAsInner; +use holo_northbound::paths::control_plane_protocol::bgp; +use holo_northbound::state::{ + Callbacks, CallbacksBuilder, ListEntryKind, NodeAttributes, Provider, +}; +use holo_yang::ToYang; +use itertools::Itertools; + +use crate::instance::Instance; +use crate::neighbor::Neighbor; +use crate::northbound::AfiSafi; +use crate::packet::message::{AddPathTuple, Capability}; + +pub static CALLBACKS: Lazy> = Lazy::new(load_callbacks); + +#[derive(Debug, Default, EnumAsInner)] +pub enum ListEntry<'a> { + #[default] + None, + Neighbor(&'a Neighbor), + CapabilityAdv(usize, &'a Capability), + CapabilityRcvd(usize, &'a Capability), + CapabilityNego(String), + AddPathTuple(&'a AddPathTuple), +} + +// ===== callbacks ===== + +fn load_callbacks() -> Callbacks { + { + {} + } + CallbacksBuilder::::default() + .path(bgp::global::afi_safis::afi_safi::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::global::afi_safis::afi_safi::statistics::total_paths::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::global::afi_safis::afi_safi::statistics::total_prefixes::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::global::afi_safis::afi_safi::apply_policy::import_policy::PATH) + .get_iterate(|_instance, _args| { + // No operational data under this list. + None + }) + .path(bgp::global::afi_safis::afi_safi::apply_policy::export_policy::PATH) + .get_iterate(|_instance, _args| { + // No operational data under this list. + None + }) + .path(bgp::global::afi_safis::afi_safi::ipv4_unicast::prefix_limit::prefix_limit_exceeded::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::global::afi_safis::afi_safi::ipv6_unicast::prefix_limit::prefix_limit_exceeded::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::global::apply_policy::import_policy::PATH) + .get_iterate(|_instance, _args| { + // No operational data under this list. + None + }) + .path(bgp::global::apply_policy::export_policy::PATH) + .get_iterate(|_instance, _args| { + // No operational data under this list. + None + }) + .path(bgp::global::statistics::total_paths::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::global::statistics::total_prefixes::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::neighbors::neighbor::PATH) + .get_iterate(|instance, _args| { + let iter = instance + .neighbors + .values() + .map(ListEntry::Neighbor); + Some(Box::new(iter)) + }) + .path(bgp::neighbors::neighbor::local_address::PATH) + .get_element_ip(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.conn_info.as_ref().map(|conn_info| conn_info.local_addr) + }) + .path(bgp::neighbors::neighbor::local_port::PATH) + .get_element_u16(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.conn_info.as_ref().map(|conn_info| conn_info.local_port) + }) + .path(bgp::neighbors::neighbor::remote_port::PATH) + .get_element_u16(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.conn_info.as_ref().map(|conn_info| conn_info.remote_port) + }) + .path(bgp::neighbors::neighbor::peer_type::PATH) + .get_element_string(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + Some(nbr.peer_type.to_yang()) + }) + .path(bgp::neighbors::neighbor::identifier::PATH) + .get_element_ipv4(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.identifier + }) + .path(bgp::neighbors::neighbor::dynamically_configured::PATH) + .get_element_empty(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::neighbors::neighbor::timers::negotiated_hold_time::PATH) + .get_element_u16(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.holdtime_nego + }) + .path(bgp::neighbors::neighbor::apply_policy::import_policy::PATH) + .get_iterate(|_instance, _args| { + // No operational data under this list. + None + }) + .path(bgp::neighbors::neighbor::apply_policy::export_policy::PATH) + .get_iterate(|_instance, _args| { + // No operational data under this list. + None + }) + .path(bgp::neighbors::neighbor::prefix_limit::prefix_limit_exceeded::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::active::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::prefixes::received::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::prefixes::sent::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::prefixes::installed::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::apply_policy::import_policy::PATH) + .get_iterate(|_instance, _args| { + // No operational data under this list. + None + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::apply_policy::export_policy::PATH) + .get_iterate(|_instance, _args| { + // No operational data under this list. + None + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::ipv4_unicast::prefix_limit::prefix_limit_exceeded::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::neighbors::neighbor::afi_safis::afi_safi::ipv6_unicast::prefix_limit::prefix_limit_exceeded::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::neighbors::neighbor::last_established::PATH) + .attributes(NodeAttributes::TIME) + .get_element_date_and_time(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.last_established + }) + .path(bgp::neighbors::neighbor::capabilities::advertised_capabilities::PATH) + .get_iterate(|_instance, args| { + let nbr = args.parent_list_entry.as_neighbor().unwrap(); + let iter = nbr + .capabilities_adv + .iter() + .enumerate() + .map(|(index, cap)| ListEntry::CapabilityAdv(index, cap)); + Some(Box::new(iter)) + }) + .path(bgp::neighbors::neighbor::capabilities::advertised_capabilities::name::PATH) + .get_element_string(|_instance, args| { + let (_, cap) = args.list_entry.as_capability_adv().unwrap(); + Some(cap.to_yang()) + }) + .path(bgp::neighbors::neighbor::capabilities::advertised_capabilities::value::mpbgp::afi::PATH) + .get_element_string(|_instance, args| { + let (_, cap) = args.list_entry.as_capability_adv().unwrap(); + cap.as_multi_protocol().map(|(afi, _)| afi.to_yang()) + }) + .path(bgp::neighbors::neighbor::capabilities::advertised_capabilities::value::mpbgp::safi::PATH) + .get_element_string(|_instance, args| { + let (_, cap) = args.list_entry.as_capability_adv().unwrap(); + cap.as_multi_protocol().map(|(_, safi)| safi.to_yang()) + }) + .path(bgp::neighbors::neighbor::capabilities::advertised_capabilities::value::mpbgp::name::PATH) + .get_element_string(|_instance, args| { + let (_, cap) = args.list_entry.as_capability_adv().unwrap(); + cap.as_multi_protocol() + .and_then(|(afi, safi)| AfiSafi::from_tuple(*afi, *safi)) + .map(|afi_safi| afi_safi.to_yang()) + }) + .path(bgp::neighbors::neighbor::capabilities::advertised_capabilities::value::asn32::r#as::PATH) + .get_element_u32(|_instance, args| { + let (_, cap) = args.list_entry.as_capability_adv().unwrap(); + cap.as_four_octet_as_number().copied() + }) + .path(bgp::neighbors::neighbor::capabilities::advertised_capabilities::value::add_paths::afi_safis::PATH) + .get_iterate(|_instance, args| { + let (_, cap) = args.parent_list_entry.as_capability_adv().unwrap(); + if let Capability::AddPath(cap) = cap { + let iter = cap.iter().map(ListEntry::AddPathTuple); + Some(Box::new(iter)) + } else { + None + } + }) + .path(bgp::neighbors::neighbor::capabilities::advertised_capabilities::value::add_paths::afi_safis::afi::PATH) + .get_element_string(|_instance, args| { + let ap = args.list_entry.as_add_path_tuple().unwrap(); + Some(ap.afi.to_yang()) + }) + .path(bgp::neighbors::neighbor::capabilities::advertised_capabilities::value::add_paths::afi_safis::safi::PATH) + .get_element_string(|_instance, args| { + let ap = args.list_entry.as_add_path_tuple().unwrap(); + Some(ap.safi.to_yang()) + }) + .path(bgp::neighbors::neighbor::capabilities::advertised_capabilities::value::add_paths::afi_safis::mode::PATH) + .get_element_string(|_instance, args| { + let ap = args.list_entry.as_add_path_tuple().unwrap(); + Some(ap.mode.to_yang()) + }) + .path(bgp::neighbors::neighbor::capabilities::received_capabilities::PATH) + .get_iterate(|_instance, args| { + let nbr = args.parent_list_entry.as_neighbor().unwrap(); + let iter = nbr + .capabilities_rcvd + .iter() + .enumerate() + .map(|(index, cap)| ListEntry::CapabilityRcvd(index, cap)); + Some(Box::new(iter)) + }) + .path(bgp::neighbors::neighbor::capabilities::received_capabilities::name::PATH) + .get_element_string(|_instance, args| { + let (_, cap) = args.list_entry.as_capability_rcvd().unwrap(); + Some(cap.to_yang()) + }) + .path(bgp::neighbors::neighbor::capabilities::received_capabilities::value::mpbgp::afi::PATH) + .get_element_string(|_instance, args| { + let (_, cap) = args.list_entry.as_capability_rcvd().unwrap(); + cap.as_multi_protocol().map(|(afi, _)| afi.to_yang()) + }) + .path(bgp::neighbors::neighbor::capabilities::received_capabilities::value::mpbgp::safi::PATH) + .get_element_string(|_instance, args| { + let (_, cap) = args.list_entry.as_capability_rcvd().unwrap(); + cap.as_multi_protocol().map(|(_, safi)| safi.to_yang()) + }) + .path(bgp::neighbors::neighbor::capabilities::received_capabilities::value::mpbgp::name::PATH) + .get_element_string(|_instance, args| { + let (_, cap) = args.list_entry.as_capability_rcvd().unwrap(); + cap.as_multi_protocol() + .and_then(|(afi, safi)| AfiSafi::from_tuple(*afi, *safi)) + .map(|afi_safi| afi_safi.to_yang()) + }) + .path(bgp::neighbors::neighbor::capabilities::received_capabilities::value::asn32::r#as::PATH) + .get_element_u32(|_instance, args| { + let (_, cap) = args.list_entry.as_capability_rcvd().unwrap(); + cap.as_four_octet_as_number().copied() + }) + .path(bgp::neighbors::neighbor::capabilities::received_capabilities::value::add_paths::afi_safis::PATH) + .get_iterate(|_instance, args| { + let (_, cap) = args.parent_list_entry.as_capability_rcvd().unwrap(); + if let Capability::AddPath(cap) = cap { + let iter = cap.iter().map(ListEntry::AddPathTuple); + Some(Box::new(iter)) + } else { + None + } + }) + .path(bgp::neighbors::neighbor::capabilities::received_capabilities::value::add_paths::afi_safis::afi::PATH) + .get_element_string(|_instance, args| { + let ap = args.list_entry.as_add_path_tuple().unwrap(); + Some(ap.afi.to_yang()) + }) + .path(bgp::neighbors::neighbor::capabilities::received_capabilities::value::add_paths::afi_safis::safi::PATH) + .get_element_string(|_instance, args| { + let ap = args.list_entry.as_add_path_tuple().unwrap(); + Some(ap.safi.to_yang()) + }) + .path(bgp::neighbors::neighbor::capabilities::received_capabilities::value::add_paths::afi_safis::mode::PATH) + .get_element_string(|_instance, args| { + let ap = args.list_entry.as_add_path_tuple().unwrap(); + Some(ap.mode.to_yang()) + }) + .path(bgp::neighbors::neighbor::capabilities::negotiated_capabilities::PATH) + .get_iterate(|_instance, args| { + let nbr = args.parent_list_entry.as_neighbor().unwrap(); + let iter = nbr + .capabilities_adv + .iter() + .map(|cap| cap.to_yang()) + .dedup() + .map(ListEntry::CapabilityNego); + Some(Box::new(iter)) + }) + .get_element_string(|_instance, args| { + let cap = args.list_entry.as_capability_nego().unwrap(); + Some(cap.clone()) + }) + .path(bgp::neighbors::neighbor::errors::received::last_notification::PATH) + .attributes(NodeAttributes::TIME) + .get_element_date_and_time(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.notification_rcvd.as_ref().map(|(time, _)| *time) + }) + .path(bgp::neighbors::neighbor::errors::received::last_error::PATH) + .get_element_string(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.notification_rcvd.as_ref().map(|(_, notif)| notif.to_yang()) + }) + .path(bgp::neighbors::neighbor::errors::received::last_error_code::PATH) + .get_element_u8(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.notification_rcvd.as_ref().map(|(_, notif)| notif.error_code) + }) + .path(bgp::neighbors::neighbor::errors::received::last_error_subcode::PATH) + .get_element_u8(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.notification_rcvd.as_ref().map(|(_, notif)| notif.error_subcode) + }) + .path(bgp::neighbors::neighbor::errors::received::last_error_data::PATH) + .get_element_binary(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.notification_rcvd.as_ref().map(|(_, notif)| notif.data.clone()) + }) + .path(bgp::neighbors::neighbor::errors::sent::last_notification::PATH) + .attributes(NodeAttributes::TIME) + .get_element_date_and_time(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.notification_sent.as_ref().map(|(time, _)| *time) + }) + .path(bgp::neighbors::neighbor::errors::sent::last_error::PATH) + .get_element_string(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.notification_sent.as_ref().map(|(_, notif)| notif.to_yang()) + }) + .path(bgp::neighbors::neighbor::errors::sent::last_error_code::PATH) + .get_element_u8(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.notification_sent.as_ref().map(|(_, notif)| notif.error_code) + }) + .path(bgp::neighbors::neighbor::errors::sent::last_error_subcode::PATH) + .get_element_u8(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.notification_sent.as_ref().map(|(_, notif)| notif.error_code) + }) + .path(bgp::neighbors::neighbor::errors::sent::last_error_data::PATH) + .get_element_binary(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + nbr.notification_sent.as_ref().map(|(_, notif)| notif.data.clone()) + }) + .path(bgp::neighbors::neighbor::session_state::PATH) + .get_element_string(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + Some(nbr.state.to_yang()) + }) + .path(bgp::neighbors::neighbor::statistics::established_transitions::PATH) + .attributes(NodeAttributes::COUNTER) + .get_element_u32(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + Some(nbr.statistics.established_transitions) + }) + .path(bgp::neighbors::neighbor::statistics::messages::total_received::PATH) + .attributes(NodeAttributes::COUNTER) + .get_element_u32(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + Some(nbr.statistics.msgs_rcvd.total.load(atomic::Ordering::Relaxed)) + }) + .path(bgp::neighbors::neighbor::statistics::messages::total_sent::PATH) + .attributes(NodeAttributes::COUNTER) + .get_element_u32(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + Some(nbr.statistics.msgs_sent.total.load(atomic::Ordering::Relaxed)) + }) + .path(bgp::neighbors::neighbor::statistics::messages::updates_received::PATH) + .attributes(NodeAttributes::COUNTER) + .get_element_u32(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + Some(nbr.statistics.msgs_rcvd.updates) + }) + .path(bgp::neighbors::neighbor::statistics::messages::updates_sent::PATH) + .attributes(NodeAttributes::COUNTER) + .get_element_u32(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + Some(nbr.statistics.msgs_sent.updates) + }) + .path(bgp::neighbors::neighbor::statistics::messages::erroneous_updates_withdrawn::PATH) + .attributes(NodeAttributes::COUNTER) + .get_element_u32(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + Some(nbr.statistics.erroneous_updates_withdrawn) + }) + .path(bgp::neighbors::neighbor::statistics::messages::erroneous_updates_attribute_discarded::PATH) + .attributes(NodeAttributes::COUNTER) + .get_element_u32(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + Some(nbr.statistics.erroneous_updates_attribute_discarded) + }) + .path(bgp::neighbors::neighbor::statistics::messages::in_update_elapsed_time::PATH) + .attributes(NodeAttributes::COUNTER) + .get_element_u32(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + Some(nbr.statistics.in_update_elapsed_time.as_secs() as u32) + }) + .path(bgp::neighbors::neighbor::statistics::messages::notifications_received::PATH) + .attributes(NodeAttributes::COUNTER) + .get_element_u32(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + Some(nbr.statistics.msgs_rcvd.notifications) + }) + .path(bgp::neighbors::neighbor::statistics::messages::notifications_sent::PATH) + .attributes(NodeAttributes::COUNTER) + .get_element_u32(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + Some(nbr.statistics.msgs_sent.notifications) + }) + .path(bgp::neighbors::neighbor::statistics::messages::route_refreshes_received::PATH) + .attributes(NodeAttributes::COUNTER) + .get_element_u32(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + Some(nbr.statistics.msgs_rcvd.route_refreshes) + }) + .path(bgp::neighbors::neighbor::statistics::messages::route_refreshes_sent::PATH) + .attributes(NodeAttributes::COUNTER) + .get_element_u32(|_instance, args| { + let nbr = args.list_entry.as_neighbor().unwrap(); + Some(nbr.statistics.msgs_sent.route_refreshes) + }) + .path(bgp::neighbors::neighbor::statistics::queues::input::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::neighbors::neighbor::statistics::queues::output::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::origin::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::as_path::segment::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::as_path::segment::r#type::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::as_path::segment::member::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::next_hop::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::link_local_next_hop::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::med::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::local_pref::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::as4_path::segment::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::as4_path::segment::r#type::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::as4_path::segment::member::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::aggregator::r#as::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::aggregator::identifier::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::aggregator4::as4::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::aggregator4::identifier::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::atomic_aggregate::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::originator_id::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::attr_sets::attr_set::attributes::cluster_list::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::communities::community::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::communities::community::community::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::ext_communities::ext_community::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::ext_communities::ext_community::ext_community::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::ext_communities::ext_community::ext_community_raw::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::ipv6_ext_communities::ipv6_ext_community::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::ipv6_ext_communities::ipv6_ext_community::ipv6_ext_community::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::ipv6_ext_communities::ipv6_ext_community::ipv6_ext_community_raw::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::large_communities::large_community::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::large_communities::large_community::large_community::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::attr_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::ext_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::large_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::last_modified::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::eligible_route::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::ineligible_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::unknown_attributes::unknown_attribute::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::unknown_attributes::unknown_attribute::optional::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::unknown_attributes::unknown_attribute::transitive::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::unknown_attributes::unknown_attribute::partial::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::unknown_attributes::unknown_attribute::extended::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::unknown_attributes::unknown_attribute::attr_len::PATH) + .get_element_u16(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::unknown_attributes::unknown_attribute::attr_value::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::loc_rib::routes::route::reject_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::attr_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::ext_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::large_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::last_modified::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::eligible_route::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::ineligible_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::unknown_attributes::unknown_attribute::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::unknown_attributes::unknown_attribute::optional::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::unknown_attributes::unknown_attribute::transitive::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::unknown_attributes::unknown_attribute::partial::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::unknown_attributes::unknown_attribute::extended::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::unknown_attributes::unknown_attribute::attr_len::PATH) + .get_element_u16(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::unknown_attributes::unknown_attribute::attr_value::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::reject_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::attr_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::ext_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::large_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::last_modified::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::eligible_route::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::ineligible_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::best_path::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::unknown_attributes::unknown_attribute::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::unknown_attributes::unknown_attribute::optional::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::unknown_attributes::unknown_attribute::transitive::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::unknown_attributes::unknown_attribute::partial::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::unknown_attributes::unknown_attribute::extended::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::unknown_attributes::unknown_attribute::attr_len::PATH) + .get_element_u16(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::unknown_attributes::unknown_attribute::attr_value::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::reject_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::attr_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::ext_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::large_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::last_modified::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::eligible_route::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::ineligible_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::unknown_attributes::unknown_attribute::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::unknown_attributes::unknown_attribute::optional::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::unknown_attributes::unknown_attribute::transitive::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::unknown_attributes::unknown_attribute::partial::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::unknown_attributes::unknown_attribute::extended::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::unknown_attributes::unknown_attribute::attr_len::PATH) + .get_element_u16(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::unknown_attributes::unknown_attribute::attr_value::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::reject_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::attr_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::ext_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::large_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::last_modified::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::eligible_route::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::ineligible_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::unknown_attributes::unknown_attribute::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::unknown_attributes::unknown_attribute::optional::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::unknown_attributes::unknown_attribute::transitive::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::unknown_attributes::unknown_attribute::partial::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::unknown_attributes::unknown_attribute::extended::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::unknown_attributes::unknown_attribute::attr_len::PATH) + .get_element_u16(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::unknown_attributes::unknown_attribute::attr_value::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv4_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::reject_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::attr_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::ext_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::large_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::last_modified::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::eligible_route::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::ineligible_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::unknown_attributes::unknown_attribute::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::unknown_attributes::unknown_attribute::optional::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::unknown_attributes::unknown_attribute::transitive::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::unknown_attributes::unknown_attribute::partial::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::unknown_attributes::unknown_attribute::extended::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::unknown_attributes::unknown_attribute::attr_len::PATH) + .get_element_u16(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::unknown_attributes::unknown_attribute::attr_value::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::loc_rib::routes::route::reject_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::attr_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::ext_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::large_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::last_modified::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::eligible_route::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::ineligible_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::unknown_attributes::unknown_attribute::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::unknown_attributes::unknown_attribute::optional::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::unknown_attributes::unknown_attribute::transitive::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::unknown_attributes::unknown_attribute::partial::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::unknown_attributes::unknown_attribute::extended::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::unknown_attributes::unknown_attribute::attr_len::PATH) + .get_element_u16(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::unknown_attributes::unknown_attribute::attr_value::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_pre::routes::route::reject_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::attr_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::ext_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::large_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::last_modified::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::eligible_route::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::ineligible_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::best_path::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::unknown_attributes::unknown_attribute::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::unknown_attributes::unknown_attribute::optional::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::unknown_attributes::unknown_attribute::transitive::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::unknown_attributes::unknown_attribute::partial::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::unknown_attributes::unknown_attribute::extended::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::unknown_attributes::unknown_attribute::attr_len::PATH) + .get_element_u16(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::unknown_attributes::unknown_attribute::attr_value::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_in_post::routes::route::reject_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::attr_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::ext_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::large_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::last_modified::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::eligible_route::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::ineligible_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::unknown_attributes::unknown_attribute::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::unknown_attributes::unknown_attribute::optional::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::unknown_attributes::unknown_attribute::transitive::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::unknown_attributes::unknown_attribute::partial::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::unknown_attributes::unknown_attribute::extended::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::unknown_attributes::unknown_attribute::attr_len::PATH) + .get_element_u16(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::unknown_attributes::unknown_attribute::attr_value::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_pre::routes::route::reject_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::attr_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::ext_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::large_community_index::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::last_modified::PATH) + .get_element_u32(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::eligible_route::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::ineligible_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::unknown_attributes::unknown_attribute::PATH) + .get_iterate(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::unknown_attributes::unknown_attribute::optional::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::unknown_attributes::unknown_attribute::transitive::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::unknown_attributes::unknown_attribute::partial::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::unknown_attributes::unknown_attribute::extended::PATH) + .get_element_bool(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::unknown_attributes::unknown_attribute::attr_len::PATH) + .get_element_u16(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::unknown_attributes::unknown_attribute::attr_value::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .path(bgp::rib::afi_safis::afi_safi::ipv6_unicast::neighbors::neighbor::adj_rib_out_post::routes::route::reject_reason::PATH) + .get_element_string(|_instance, _args| { + // TODO: implement me! + None + }) + .build() +} + +// ===== impl Instance ===== + +impl Provider for Instance { + const STATE_PATH: &'static str = "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-bgp:bgp'][name='test']/ietf-bgp:bgp"; + + type ListEntry<'a> = ListEntry<'a>; + + fn callbacks() -> Option<&'static Callbacks> { + Some(&CALLBACKS) + } +} + +// ===== impl ListEntry ===== + +impl<'a> ListEntryKind for ListEntry<'a> { + fn get_keys(&self) -> Option { + match self { + ListEntry::None => None, + ListEntry::Neighbor(nbr) => { + use bgp::neighbors::neighbor::list_keys; + let keys = list_keys(nbr.remote_addr); + Some(keys) + } + ListEntry::CapabilityAdv(index, cap) => { + use bgp::neighbors::neighbor::capabilities::advertised_capabilities::list_keys; + let keys = list_keys(cap.code() as u8, index); + Some(keys) + } + ListEntry::CapabilityRcvd(index, cap) => { + use bgp::neighbors::neighbor::capabilities::received_capabilities::list_keys; + let keys = list_keys(cap.code() as u8, index); + Some(keys) + } + ListEntry::CapabilityNego(_) | ListEntry::AddPathTuple(_) => { + // Keyless list. + None + } + } + } +} diff --git a/holo-bgp/src/northbound/yang.rs b/holo-bgp/src/northbound/yang.rs new file mode 100644 index 00000000..6209a055 --- /dev/null +++ b/holo-bgp/src/northbound/yang.rs @@ -0,0 +1,283 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use holo_yang::{ToYang, TryFromYang}; +use num_traits::FromPrimitive; + +use crate::neighbor::{fsm, PeerType}; +use crate::northbound::configuration::PrivateAsRemove; +use crate::northbound::AfiSafi; +use crate::packet::message::{Capability, NotificationMsg}; +use crate::packet::{ + AddPathMode, CeaseSubcode, ErrorCode, FsmErrorSubcode, + MessageHeaderErrorSubcode, OpenMessageErrorSubcode, + RouteRefreshErrorSubcode, Safi, UpdateMessageErrorSubcode, +}; + +// ===== ToYang implementations ===== + +impl ToYang for Safi { + fn to_yang(&self) -> String { + match self { + Safi::Unicast => "unicast-safi".to_owned(), + Safi::Multicast => "multicast-safi".to_owned(), + Safi::LabeledUnicast => "labeled-unicast-safi".to_owned(), + Safi::MulticastVpn => "multicast-vpn-safi".to_owned(), + Safi::Pseudowire => "pseudowire-safi".to_owned(), + Safi::TunnelEncap => "tunnel-encap-safi".to_owned(), + Safi::McastVpls => "mcast-vpls-safi".to_owned(), + Safi::Tunnel => "tunnel-safi".to_owned(), + Safi::Vpls => "vpls-safi".to_owned(), + Safi::Mdt => "mdt-safi".to_owned(), + Safi::V4OverV6 => "v4-over-v6-safi".to_owned(), + Safi::V6OverV4 => "v6-over-v4-safi".to_owned(), + Safi::L1VpnAutoDiscovery => "l1-vpn-auto-discovery-safi".to_owned(), + Safi::Evpn => "evpn-safi".to_owned(), + Safi::BgpLs => "bgp-ls-safi".to_owned(), + Safi::BgpLsVpn => "bgp-ls-vpn-safi".to_owned(), + Safi::SrTe => "sr-te-safi".to_owned(), + Safi::SdWanCapabilities => "sd-wan-capabilities-safi".to_owned(), + Safi::LabeledVpn => "labeled-vpn-safi".to_owned(), + Safi::MulticastMplsVpn => "multicast-mpls-vpn-safi".to_owned(), + Safi::RouteTarget => "route-target-safi".to_owned(), + Safi::Ipv4FlowSpec => "ipv4-flow-spec-safi".to_owned(), + Safi::Vpnv4FlowSpec => "vpnv4-flow-spec-safi".to_owned(), + Safi::VpnAutoDiscovery => "vpn-auto-discovery-safi".to_owned(), + } + } +} + +impl ToYang for AfiSafi { + fn to_yang(&self) -> String { + match self { + AfiSafi::Ipv4Unicast => "iana-bgp-types:ipv4-unicast".to_owned(), + AfiSafi::Ipv6Unicast => "iana-bgp-types:ipv6-unicast".to_owned(), + } + } +} + +impl ToYang for AddPathMode { + fn to_yang(&self) -> String { + match self { + AddPathMode::Receive => "receive".to_owned(), + AddPathMode::Send => "send".to_owned(), + AddPathMode::ReceiveSend => "receive-send".to_owned(), + } + } +} + +impl ToYang for Capability { + fn to_yang(&self) -> String { + match self { + Capability::MultiProtocol { .. } => { + "iana-bgp-types:mp-bgp".to_owned() + } + Capability::FourOctetAsNumber { .. } => { + "iana-bgp-types:asn32".to_owned() + } + Capability::AddPath { .. } => "holo-bgp:add-paths".to_owned(), + Capability::RouteRefresh => { + "iana-bgp-types:route-refresh".to_owned() + } + Capability::EnhancedRouteRefresh => { + "holo-bgp:enhanced-route-refresh".to_owned() + } + } + } +} + +impl ToYang for NotificationMsg { + fn to_yang(&self) -> String { + let Some(error_code) = ErrorCode::from_u8(self.error_code) else { + return "holo-bgp:unknown-error".to_owned(); + }; + let identity = match error_code { + ErrorCode::MessageHeaderError => { + use MessageHeaderErrorSubcode as ErrorSubcode; + match ErrorSubcode::from_u8(self.error_subcode) { + Some(ErrorSubcode::Unspecific) => { + "message-header-unspecific" + } + Some(ErrorSubcode::ConnectionNotSynchronized) => { + "message-header-connection-not-synchronized" + } + Some(ErrorSubcode::BadMessageLength) => { + "message-header-bad-message-length" + } + Some(ErrorSubcode::BadMessageType) => { + "message-header-bad-message-type" + } + None => "message-header-error", + } + } + ErrorCode::OpenMessageError => { + use OpenMessageErrorSubcode as ErrorSubcode; + match ErrorSubcode::from_u8(self.error_subcode) { + Some(ErrorSubcode::Unspecific) => "open-message-unspecific", + Some(ErrorSubcode::UnsupportedVersionNumber) => { + "open-unsupported-version-number" + } + Some(ErrorSubcode::BadPeerAs) => "open-bad-peer-as", + Some(ErrorSubcode::BadBgpIdentifier) => "open-bad-bgp-id", + Some(ErrorSubcode::UnsupportedOptParam) => { + "open-unsupported-optional-parameter" + } + Some(ErrorSubcode::UnacceptableHoldTime) => { + "open-unacceptable-hold-time" + } + Some(ErrorSubcode::UnsupportedCapability) => { + "open-unsupported-capability" + } + Some(ErrorSubcode::RoleMismatch) => "open-role-mismatch", + None => "open-message-error", + } + } + ErrorCode::UpdateMessageError => { + use UpdateMessageErrorSubcode as ErrorSubcode; + match ErrorSubcode::from_u8(self.error_subcode) { + Some(ErrorSubcode::Unspecific) => "update-unspecific", + Some(ErrorSubcode::MalformedAttributeList) => { + "update-malformed-attribute-list" + } + Some(ErrorSubcode::UnrecognizedWellKnownAttribute) => { + "update-unrecognized-well-known-attribute" + } + Some(ErrorSubcode::MissingWellKnownAttribute) => { + "update-missing-well-known-attribute" + } + Some(ErrorSubcode::AttributeFlagsError) => { + "update-attribute-flags-error" + } + Some(ErrorSubcode::AttributeLengthError) => { + "update-attribute-length-error" + } + Some(ErrorSubcode::InvalidOriginAttribute) => { + "update-invalid-origin-attribute" + } + Some(ErrorSubcode::InvalidNexthopAttribute) => { + "update-invalid-next-hop-attribute" + } + Some(ErrorSubcode::OptionalAttributeError) => { + "open-optional-attribute-error" + } + Some(ErrorSubcode::InvalidNetworkField) => { + "open-invalid-network-field" + } + Some(ErrorSubcode::MalformedAsPath) => { + "open-malformed-as-path" + } + None => "update-message-error", + } + } + ErrorCode::HoldTimerExpired => "hold-timer-expired-error", + ErrorCode::FiniteStateMachineError => { + use FsmErrorSubcode as ErrorSubcode; + match ErrorSubcode::from_u8(self.error_subcode) { + Some(ErrorSubcode::UnexpectedMessageInOpenSent) => { + "fsm-error-unexpected-in-opensent" + } + Some(ErrorSubcode::UnexpectedMessageInOpenConfirm) => { + "fsm-error-unexpected-in-openconfirm" + } + Some(ErrorSubcode::UnexpectedMessageInEstablished) => { + "fsm-error-unexpected-in-established" + } + None => "fsm-error", + } + } + ErrorCode::Cease => { + use CeaseSubcode as ErrorSubcode; + match ErrorSubcode::from_u8(self.error_subcode) { + Some(ErrorSubcode::MaximumNumberofPrefixesReached) => { + "cease-max-prefixes" + } + Some(ErrorSubcode::AdministrativeShutdown) => { + "cease-admin-shutdown" + } + Some(ErrorSubcode::PeerDeConfigured) => { + "cease-peer-deconfigured" + } + Some(ErrorSubcode::AdministrativeReset) => { + "cease-admin-reset" + } + Some(ErrorSubcode::ConnectionRejected) => { + "cease-connection-rejected" + } + Some(ErrorSubcode::OtherConfigurationChange) => { + "cease-other-configuration-change" + } + Some(ErrorSubcode::ConnectionCollisionResolution) => { + "cease-connection-collision" + } + Some(ErrorSubcode::OutOfResources) => { + "cease-out-of-resources" + } + Some(ErrorSubcode::HardReset) => "cease-hard-reset", + Some(ErrorSubcode::BfdDown) => "cease-bfd-down", + None => "cease", + } + } + ErrorCode::RouteRefreshMessageError => { + use RouteRefreshErrorSubcode as ErrorSubcode; + match ErrorSubcode::from_u8(self.error_subcode) { + Some(ErrorSubcode::InvalidMessageLength) => { + "route-refresh-invalid-message-length" + } + None => "route-refresh-message-error", + } + } + }; + format!("iana-bgp-notification:{}", identity) + } +} + +impl ToYang for fsm::State { + fn to_yang(&self) -> String { + match self { + fsm::State::Idle => "idle".to_owned(), + fsm::State::Connect => "connect".to_owned(), + fsm::State::Active => "active".to_owned(), + fsm::State::OpenSent => "opensent".to_owned(), + fsm::State::OpenConfirm => "openconfirm".to_owned(), + fsm::State::Established => "established".to_owned(), + } + } +} + +impl ToYang for PeerType { + fn to_yang(&self) -> String { + match self { + PeerType::Internal => "internal".to_owned(), + PeerType::External => "external".to_owned(), + } + } +} + +// ===== TryFromYang implementations ===== + +impl TryFromYang for AfiSafi { + fn try_from_yang(value: &str) -> Option { + match value { + "iana-bgp-types:ipv4-unicast" => Some(AfiSafi::Ipv4Unicast), + "iana-bgp-types:ipv6-unicast" => Some(AfiSafi::Ipv6Unicast), + _ => None, + } + } +} + +impl TryFromYang for PrivateAsRemove { + fn try_from_yang(value: &str) -> Option { + match value { + "iana-bgp-types:private-as-remove-all" => { + Some(PrivateAsRemove::RemoveAll) + } + "iana-bgp-types:private-as-replace-all" => { + Some(PrivateAsRemove::ReplaceAll) + } + _ => None, + } + } +} diff --git a/holo-bgp/src/packet/attribute.rs b/holo-bgp/src/packet/attribute.rs new file mode 100644 index 00000000..49ef3497 --- /dev/null +++ b/holo-bgp/src/packet/attribute.rs @@ -0,0 +1,13 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Deserialize, Serialize)] +pub enum Attribute { + Dummy, +} diff --git a/holo-bgp/src/packet/error.rs b/holo-bgp/src/packet/error.rs new file mode 100644 index 00000000..7a5875f9 --- /dev/null +++ b/holo-bgp/src/packet/error.rs @@ -0,0 +1,179 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +//use std::net::{IpAddr, Ipv4Addr}; + +use serde::{Deserialize, Serialize}; + +// Type aliases. +pub type DecodeResult = Result; + +// BGP message decoding errors. +#[derive(Debug)] +#[derive(Deserialize, Serialize)] +pub enum DecodeError { + MessageHeader(MessageHeaderError), + OpenMessage(OpenMessageError), + UpdateMessage(UpdateMessageError), +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Deserialize, Serialize)] +pub enum MessageHeaderError { + ConnectionNotSynchronized, + BadMessageLength(u16), + BadMessageType(u8), +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Deserialize, Serialize)] +pub enum OpenMessageError { + UnsupportedVersion(u8), + BadPeerAs, + BadBgpIdentifier, + UnsupportedOptParam, + UnacceptableHoldTime, + UnsupportedCapability, + MalformedOptParam, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Deserialize, Serialize)] +pub enum UpdateMessageError { + MalformedAttributeList, + UnrecognizedWellKnownAttribute(), + MissingWellKnownAttribute(), + AttributeFlagsError(), + AttributeLengthError(), + InvalidOriginAttribute(), + InvalidNexthopAttribute(), + OptionalAttributeError(), + InvalidNetworkField, + MalformedAsPath, +} + +// ===== impl DecodeError ===== + +impl std::fmt::Display for DecodeError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + DecodeError::MessageHeader(error) => error.fmt(f), + DecodeError::OpenMessage(error) => error.fmt(f), + DecodeError::UpdateMessage(error) => error.fmt(f), + } + } +} + +impl std::error::Error for DecodeError {} + +impl From for DecodeError { + fn from(error: MessageHeaderError) -> DecodeError { + DecodeError::MessageHeader(error) + } +} + +impl From for DecodeError { + fn from(error: OpenMessageError) -> DecodeError { + DecodeError::OpenMessage(error) + } +} + +impl From for DecodeError { + fn from(error: UpdateMessageError) -> DecodeError { + DecodeError::UpdateMessage(error) + } +} + +// ===== impl MessageHeaderError ===== + +impl std::fmt::Display for MessageHeaderError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + MessageHeaderError::ConnectionNotSynchronized => { + write!(f, "Connection not synchronized") + } + MessageHeaderError::BadMessageLength(len) => { + write!(f, "Invalid message length: {}", len) + } + MessageHeaderError::BadMessageType(msg_type) => { + write!(f, "Invalid message type: {}", msg_type) + } + } + } +} + +// ===== impl OpenMessageError ===== + +impl std::fmt::Display for OpenMessageError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "OPEN message error: ")?; + + match self { + OpenMessageError::UnsupportedVersion(version) => { + write!(f, "unsupported version number: {}", version) + } + OpenMessageError::BadPeerAs => { + write!(f, "bad peer AS") + } + OpenMessageError::BadBgpIdentifier => { + write!(f, "bad BGP identifier") + } + OpenMessageError::UnsupportedOptParam => { + write!(f, "unsupported optional parameter") + } + OpenMessageError::UnacceptableHoldTime => { + write!(f, "unacceptable hold time") + } + OpenMessageError::UnsupportedCapability => { + write!(f, "unsupported capability") + } + OpenMessageError::MalformedOptParam => { + write!(f, "malformed optional parameter") + } + } + } +} + +// ===== impl UpdateMessageError ===== + +impl std::fmt::Display for UpdateMessageError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "UPDATE message error: ")?; + + match self { + UpdateMessageError::MalformedAttributeList => { + write!(f, "malformed attribute list") + } + UpdateMessageError::UnrecognizedWellKnownAttribute(..) => { + write!(f, "unrecognized well-known attribute") + } + UpdateMessageError::MissingWellKnownAttribute(..) => { + write!(f, "missing well-known attribute") + } + UpdateMessageError::AttributeFlagsError(..) => { + write!(f, "attribute flags error") + } + UpdateMessageError::AttributeLengthError(..) => { + write!(f, "attribute length error") + } + UpdateMessageError::InvalidOriginAttribute(..) => { + write!(f, "invalid ORIGIN attribute") + } + UpdateMessageError::InvalidNexthopAttribute(..) => { + write!(f, "invalid NEXT_HOP attribute") + } + UpdateMessageError::OptionalAttributeError(..) => { + write!(f, "optional attribute error") + } + UpdateMessageError::InvalidNetworkField => { + write!(f, "invalid network field") + } + UpdateMessageError::MalformedAsPath => { + write!(f, "malformed AS_PATH") + } + } + } +} diff --git a/holo-bgp/src/packet/message.rs b/holo-bgp/src/packet/message.rs new file mode 100644 index 00000000..f05be027 --- /dev/null +++ b/holo-bgp/src/packet/message.rs @@ -0,0 +1,907 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::collections::BTreeSet; +use std::net::{IpAddr, Ipv4Addr}; + +use bytes::{Buf, BufMut, Bytes, BytesMut}; +use enum_as_inner::EnumAsInner; +use holo_utils::bytes::{BytesExt, BytesMutExt, TLS_BUF}; +use holo_utils::ip::{Ipv4AddrExt, Ipv4NetworkExt}; +use ipnetwork::{Ipv4Network, Ipv6Network}; +use num_traits::{FromPrimitive, ToPrimitive}; +use serde::{Deserialize, Serialize}; + +use crate::packet::attribute::Attribute; +use crate::packet::error::{ + DecodeError, DecodeResult, MessageHeaderError, OpenMessageError, + UpdateMessageError, +}; +use crate::packet::{ + AddPathMode, Afi, CapabilityCode, ErrorCode, MessageHeaderErrorSubcode, + MessageType, OpenMessageErrorSubcode, OpenParamType, Safi, + UpdateMessageErrorSubcode, BGP_VERSION, +}; + +// +// BGP message. +// +// Encoding format (message header): +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// + + +// | | +// + + +// | Marker | +// + + +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Length | Type | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Deserialize, Serialize)] +pub enum Message { + Open(OpenMsg), + Update(UpdateMsg), + Notification(NotificationMsg), + Keepalive(KeepaliveMsg), + RouteRefresh(RouteRefreshMsg), +} + +// +// OPEN Message. +// +// Encoding format (message body): +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+ +// | Version | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | My Autonomous System | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Hold Time | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | BGP Identifier | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Opt Parm Len | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// | Optional Parameters (variable) | +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Encoding format (optional parameter): +// +// 0 1 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-... +// | Parm. Type | Parm. Length | Parameter Value (variable) +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-... +// +#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Deserialize, Serialize)] +pub struct OpenMsg { + pub version: u8, + pub my_as: u16, + pub holdtime: u16, + pub identifier: Ipv4Addr, + pub capabilities: BTreeSet, +} +// +// Capabilities Optional Parameter. +// +// Encoding format: +// +// +------------------------------+ +// | Capability Code (1 octet) | +// +------------------------------+ +// | Capability Length (1 octet) | +// +------------------------------+ +// | Capability Value (variable) | +// ~ ~ +// +------------------------------+ +// +#[derive(Clone, Debug, EnumAsInner, Eq, Ord, PartialEq, PartialOrd)] +#[derive(Deserialize, Serialize)] +pub enum Capability { + MultiProtocol { afi: Afi, safi: Safi }, + FourOctetAsNumber { asn: u32 }, + AddPath(BTreeSet), + RouteRefresh, + EnhancedRouteRefresh, +} + +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[derive(Deserialize, Serialize)] +pub struct AddPathTuple { + pub afi: Afi, + pub safi: Safi, + pub mode: AddPathMode, +} + +// +// UPDATE Message. +// +// Encoding format (message body): +// +// +-----------------------------------------------------+ +// | Withdrawn Routes Length (2 octets) | +// +-----------------------------------------------------+ +// | Withdrawn Routes (variable) | +// +-----------------------------------------------------+ +// | Total Path Attribute Length (2 octets) | +// +-----------------------------------------------------+ +// | Path Attributes (variable) | +// +-----------------------------------------------------+ +// | Network Layer Reachability Information (variable) | +// +-----------------------------------------------------+ +// +#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Deserialize, Serialize)] +pub struct UpdateMsg { + pub unreach: Option<(Safi, Nlri)>, + pub reach: Option<(Safi, Nlri, Option)>, + pub attributes: Vec, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Deserialize, Serialize)] +pub enum Nlri { + Ipv4(Vec), + Ipv6(Vec), +} + +// +// NOTIFICATION Message. +// +// Encoding format (message body): +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Error code | Error subcode | Data (variable) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[derive(Deserialize, Serialize)] +pub struct NotificationMsg { + pub error_code: u8, + pub error_subcode: u8, + pub data: Vec, +} + +// +// KEEPALIVE Message. +// +// A KEEPALIVE message consists of only the message header and has a length of +// 19 octets. +// +#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Deserialize, Serialize)] +pub struct KeepaliveMsg {} + +// +// Route-REFRESH Message. +// +// Encoding format (message body): +// +// 0 7 15 23 31 +// +-------+-------+-------+-------+ +// | AFI | Res. | SAFI | +// +-------+-------+-------+-------+ +// +#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Deserialize, Serialize)] +pub struct RouteRefreshMsg { + pub afi: u16, + pub safi: u8, +} + +// ===== impl Message ===== + +impl Message { + pub const MIN_LEN: u16 = 19; + pub const MAX_LEN: u16 = 4096; + const MSG_LEN_POS: std::ops::Range = 16..18; + + // Encodes BGP message into a bytes buffer. + pub fn encode(&self) -> Bytes { + TLS_BUF.with(|buf| { + let mut buf = buf.borrow_mut(); + buf.clear(); + + // Marker field. + buf.put_u128(u128::MAX); + // The length field will be initialized later. + buf.put_u16(0); + + // Message type and body. + match self { + Message::Open(msg) => msg.encode(&mut buf), + Message::Update(msg) => msg.encode(&mut buf), + Message::Notification(msg) => msg.encode(&mut buf), + Message::Keepalive(msg) => msg.encode(&mut buf), + Message::RouteRefresh(msg) => msg.encode(&mut buf), + } + + // Rewrite message length. + let msg_len = buf.len() as u16; + buf[Self::MSG_LEN_POS].copy_from_slice(&msg_len.to_be_bytes()); + + buf.clone().freeze() + }) + } + + // Decode buffer into a BGP message. + // + // This function panics if the provided buffer doesn't contain an entire + // message. + pub fn decode(data: &[u8]) -> DecodeResult { + let mut buf = Bytes::copy_from_slice(data); + + // Parse and validate marker. + let marker = buf.get_u128(); + if marker != u128::MAX { + return Err(MessageHeaderError::ConnectionNotSynchronized.into()); + } + + // Parse and validate message length. + let msg_len = buf.get_u16(); + if msg_len < Self::MIN_LEN || msg_len > Self::MAX_LEN { + return Err(MessageHeaderError::BadMessageLength(msg_len).into()); + } + + // Parse message type. + let msg_type = buf.get_u8(); + + // Parse message body. + match MessageType::from_u8(msg_type) { + Some(MessageType::Open) => { + let msg = OpenMsg::decode(&mut buf, msg_len)?; + Ok(Message::Open(msg)) + } + Some(MessageType::Update) => { + let msg = UpdateMsg::decode(&mut buf, msg_len)?; + Ok(Message::Update(msg)) + } + Some(MessageType::Notification) => { + let msg = NotificationMsg::decode(&mut buf, msg_len)?; + Ok(Message::Notification(msg)) + } + Some(MessageType::Keepalive) => { + let msg = KeepaliveMsg::decode(&mut buf, msg_len)?; + Ok(Message::Keepalive(msg)) + } + Some(MessageType::RouteRefresh) => { + let msg = RouteRefreshMsg::decode(&mut buf, msg_len)?; + Ok(Message::RouteRefresh(msg)) + } + None => Err(MessageHeaderError::BadMessageType(msg_type).into()), + } + } + + // Parses the given buffer to determine if it contains a complete BGP + // message, and returns the length of the message if successful. + pub fn get_message_len(data: &[u8]) -> Option { + // Validate that the buffer contains sufficient space for at least the + // message header. + let buf_size = data.len(); + if buf_size < Self::MIN_LEN as usize { + return None; + } + + // Ensure the buffer is big enough to hold the entire message. + let mut buf = Bytes::copy_from_slice(&data[0..Self::MIN_LEN as usize]); + let _marker = buf.get_u128(); + let msg_len = buf.get_u16(); + if msg_len < Self::MIN_LEN || msg_len as usize > buf_size { + return None; + } + + // Return the message size. + Some(msg_len as usize) + } +} + +// ===== impl OpenMsg ===== + +impl OpenMsg { + const MIN_LEN: u16 = 29; + + fn encode(&self, buf: &mut BytesMut) { + buf.put_u8(MessageType::Open as u8); + buf.put_u8(self.version); + buf.put_u16(self.my_as); + buf.put_u16(self.holdtime); + buf.put_ipv4(&self.identifier); + + // Capabilities. + let opt_param_len_pos = buf.len(); + buf.put_u8(0); + for capability in &self.capabilities { + buf.put_u8(OpenParamType::Capabilities as u8); + + // The "Parm. Length" field will be initialized later. + let param_len_pos = buf.len(); + buf.put_u8(0); + + // Encode individual capability. + capability.encode(buf); + + // Rewrite the "Parm. Length" field. + let param_len = buf.len() - param_len_pos - 1; + buf[param_len_pos] = param_len as u8; + } + + // Rewrite the "Opt Parm Len" field. + let opt_param_len = buf.len() - opt_param_len_pos - 1; + buf[opt_param_len_pos] = opt_param_len as u8; + } + + fn decode(buf: &mut Bytes, msg_len: u16) -> DecodeResult { + if msg_len < Self::MIN_LEN { + return Err(MessageHeaderError::BadMessageLength(msg_len).into()); + } + + // Parse and validate BGP version. + let version = buf.get_u8(); + if version != BGP_VERSION { + return Err( + OpenMessageError::UnsupportedVersion(BGP_VERSION).into() + ); + } + + // Parse and validate ASN. + let my_as = buf.get_u16(); + if my_as == 0 { + return Err(OpenMessageError::BadPeerAs.into()); + } + + // Parse and validate hold time. + let holdtime = buf.get_u16(); + if holdtime == 1 || holdtime == 2 { + return Err(OpenMessageError::UnacceptableHoldTime.into()); + } + + // Parse and validate BGP identifier. + let identifier = buf.get_ipv4(); + if identifier.is_unspecified() + || identifier.is_multicast() + || identifier.is_broadcast() + { + return Err(OpenMessageError::BadBgpIdentifier.into()); + } + + // Parse and validate optional parameters. + let mut capabilities = BTreeSet::new(); + let opt_param_len = buf.get_u8(); + if opt_param_len as usize > buf.remaining() { + return Err(OpenMessageError::MalformedOptParam.into()); + } + let mut buf_opts = buf.copy_to_bytes(opt_param_len as usize); + while buf_opts.remaining() > 0 { + if buf_opts.remaining() < 2 { + return Err(OpenMessageError::MalformedOptParam.into()); + } + let param_type = buf_opts.get_u8(); + let param_len = buf_opts.get_u8(); + if param_len as usize > buf_opts.remaining() { + return Err(OpenMessageError::MalformedOptParam.into()); + } + let mut buf_param_value = + buf_opts.copy_to_bytes(param_len as usize); + + // Parse and validate capabilities. + match OpenParamType::from_u8(param_type) { + Some(OpenParamType::Capabilities) => { + while buf_param_value.remaining() > 0 { + if let Some(cap) = + Capability::decode(&mut buf_param_value)? + { + capabilities.insert(cap); + } + } + } + None => { + return Err(OpenMessageError::UnsupportedOptParam.into()); + } + } + } + + Ok(OpenMsg { + version, + my_as, + holdtime, + identifier, + capabilities, + }) + } + + pub fn real_as(&self) -> u32 { + self.capabilities + .iter() + .find_map(|cap| { + if let Capability::FourOctetAsNumber { asn } = cap { + Some(*asn) + } else { + None + } + }) + .unwrap_or(self.my_as as u32) + } +} + +// ===== impl Capability ===== + +impl Capability { + fn encode(&self, buf: &mut BytesMut) { + let start_pos = buf.len(); + + match self { + Capability::MultiProtocol { afi, safi } => { + buf.put_u8(CapabilityCode::MultiProtocol as u8); + buf.put_u8(0); + buf.put_u16(*afi as u16); + buf.put_u8(0); + buf.put_u8(*safi as u8); + } + Capability::FourOctetAsNumber { asn } => { + buf.put_u8(CapabilityCode::FourOctetAsNumber as u8); + buf.put_u8(0); + buf.put_u32(*asn); + } + Capability::AddPath(tuples) => { + buf.put_u8(CapabilityCode::AddPath as u8); + buf.put_u8(0); + for tuple in tuples { + buf.put_u16(tuple.afi as u16); + buf.put_u8(tuple.safi as u8); + buf.put_u8(tuple.mode as u8); + } + } + Capability::RouteRefresh => { + buf.put_u8(CapabilityCode::RouteRefresh as u8); + buf.put_u8(0); + } + Capability::EnhancedRouteRefresh => { + buf.put_u8(CapabilityCode::EnhancedRouteRefresh as u8); + buf.put_u8(0); + } + } + + // Rewrite the "Capability Length" field. + let cap_len = buf.len() - start_pos - 2; + buf[start_pos + 1] = cap_len as u8; + } + + fn decode(buf: &mut Bytes) -> DecodeResult> { + if buf.remaining() < 2 { + return Err(OpenMessageError::MalformedOptParam.into()); + } + let cap_type = buf.get_u8(); + let cap_len = buf.get_u8(); + if cap_len as usize > buf.remaining() { + return Err(OpenMessageError::MalformedOptParam.into()); + } + + let mut buf_cap = buf.copy_to_bytes(cap_len as usize); + let cap = match CapabilityCode::from_u8(cap_type) { + Some(CapabilityCode::MultiProtocol) => { + if cap_len != 4 { + return Err(OpenMessageError::MalformedOptParam.into()); + } + + let afi = buf_cap.get_u16(); + let Some(afi) = Afi::from_u16(afi) else { + // Ignore unknown AFI. + return Ok(None); + }; + let _reserved = buf_cap.get_u8(); + let safi = buf_cap.get_u8(); + let Some(safi) = Safi::from_u8(safi) else { + // Ignore unknown SAFI. + return Ok(None); + }; + + Capability::MultiProtocol { afi, safi } + } + Some(CapabilityCode::FourOctetAsNumber) => { + if cap_len != 4 { + return Err(OpenMessageError::MalformedOptParam.into()); + } + + let asn = buf_cap.get_u32(); + Capability::FourOctetAsNumber { asn } + } + Some(CapabilityCode::AddPath) => { + if cap_len % 4 != 0 { + return Err(OpenMessageError::MalformedOptParam.into()); + } + + let mut tuples = BTreeSet::new(); + while buf_cap.remaining() > 0 { + let afi = buf_cap.get_u16(); + let Some(afi) = Afi::from_u16(afi) else { + // Ignore unknown AFI. + return Ok(None); + }; + let safi = buf_cap.get_u8(); + let Some(safi) = Safi::from_u8(safi) else { + // Ignore unknown SAFI. + return Ok(None); + }; + let mode = buf_cap.get_u8(); + let Some(mode) = AddPathMode::from_u8(mode) else { + // Ignore unknown value. + return Ok(None); + }; + tuples.insert(AddPathTuple { afi, safi, mode }); + } + Capability::AddPath(tuples) + } + Some(CapabilityCode::RouteRefresh) => { + if cap_len != 0 { + return Err(OpenMessageError::MalformedOptParam.into()); + } + + Capability::RouteRefresh + } + Some(CapabilityCode::EnhancedRouteRefresh) => { + if cap_len != 0 { + return Err(OpenMessageError::MalformedOptParam.into()); + } + + Capability::EnhancedRouteRefresh + } + _ => { + // Ignore unknown capability. + return Ok(None); + } + }; + + Ok(Some(cap)) + } + + pub fn code(&self) -> CapabilityCode { + match self { + Capability::MultiProtocol { .. } => CapabilityCode::MultiProtocol, + Capability::FourOctetAsNumber { .. } => { + CapabilityCode::FourOctetAsNumber + } + Capability::AddPath { .. } => CapabilityCode::AddPath, + Capability::RouteRefresh => CapabilityCode::RouteRefresh, + Capability::EnhancedRouteRefresh => { + CapabilityCode::EnhancedRouteRefresh + } + } + } +} + +// ===== impl UpdateMsg ===== + +impl UpdateMsg { + const MIN_LEN: u16 = 23; + + fn encode(&self, buf: &mut BytesMut) { + buf.put_u8(MessageType::Update as u8); + + // Withdrawn Routes. + let start_pos = buf.len(); + buf.put_u16(0); + if let Some(unreach) = &self.unreach + && unreach.0 == Safi::Unicast + && let Nlri::Ipv4(prefixes) = &unreach.1 + { + // Encode prefixes. + for prefix in prefixes { + let plen = prefix.prefix(); + let prefix_bytes = prefix.ip().octets(); + let plen_wire = prefix_wire_len(plen); + buf.put_u8(plen); + buf.put(&prefix_bytes[0..plen_wire]); + } + + // Rewrite the "Withdrawn Routes Length" field. + let len = (buf.len() - start_pos - 2) as u16; + buf[start_pos..start_pos + 2].copy_from_slice(&len.to_be_bytes()); + } + + // Path Attributes. + // TODO + buf.put_u16(0); + + // Network Layer Reachability Information. + if let Some(reach) = &self.reach + && reach.0 == Safi::Unicast + && let Nlri::Ipv4(prefixes) = &reach.1 + { + // Encode prefixes. + for prefix in prefixes { + let plen = prefix.prefix(); + let prefix_bytes = prefix.ip().octets(); + let plen_wire = prefix_wire_len(plen); + buf.put_u8(plen); + buf.put(&prefix_bytes[0..plen_wire]); + } + } + } + + fn decode(buf: &mut Bytes, msg_len: u16) -> DecodeResult { + if msg_len < Self::MIN_LEN { + return Err(MessageHeaderError::BadMessageLength(msg_len).into()); + } + + let mut unreach = None; + let mut reach = None; + let mut attributes = Vec::new(); + + // Withdrawn Routes. + let wdraw_len = buf.get_u16(); + let mut buf_wdraw = buf.copy_to_bytes(wdraw_len as usize); + let mut prefixes = Vec::new(); + while buf_wdraw.remaining() > 0 { + // Parse prefix length. + let plen = buf_wdraw.get_u8(); + let plen_wire = prefix_wire_len(plen); + if plen_wire > buf_wdraw.remaining() + || plen > Ipv4Network::MAX_PREFIXLEN + { + return Err(UpdateMessageError::InvalidNetworkField.into()); + } + + // Parse prefix. + let mut prefix_bytes = vec![0; plen_wire]; + buf_wdraw.copy_to_slice(&mut prefix_bytes); + let prefix = Ipv4Addr::from_slice(&prefix_bytes); + let prefix = Ipv4Network::new(prefix, plen) + .map(|prefix| prefix.apply_mask()) + .map_err(|_| UpdateMessageError::InvalidNetworkField)?; + + prefixes.push(prefix); + } + if !prefixes.is_empty() { + unreach = Some((Safi::Unicast, Nlri::Ipv4(prefixes))); + } + + // Path Attributes. + let attr_len = buf.get_u16(); + let mut buf_attr = buf.copy_to_bytes(attr_len as usize); + // TODO + + // Network Layer Reachability Information. + let mut prefixes = Vec::new(); + while buf.remaining() > 0 { + // Parse prefix length. + let plen = buf.get_u8(); + let plen_wire = prefix_wire_len(plen); + if plen_wire > buf.remaining() || plen > Ipv4Network::MAX_PREFIXLEN + { + return Err(UpdateMessageError::InvalidNetworkField.into()); + } + + // Parse prefix. + let mut prefix_bytes = vec![0; plen_wire]; + buf.copy_to_slice(&mut prefix_bytes); + let prefix = Ipv4Addr::from_slice(&prefix_bytes); + let prefix = Ipv4Network::new(prefix, plen) + .map(|prefix| prefix.apply_mask()) + .map_err(|_| UpdateMessageError::InvalidNetworkField)?; + + prefixes.push(prefix); + } + if !prefixes.is_empty() { + reach = Some((Safi::Unicast, Nlri::Ipv4(prefixes), None)); + } + + Ok(UpdateMsg { + unreach, + reach, + attributes, + }) + } +} + +// ===== impl NotificationMsg ===== + +impl NotificationMsg { + const MIN_LEN: u16 = 21; + + pub(crate) fn new( + error_code: impl ToPrimitive, + error_subcode: impl ToPrimitive, + ) -> Self { + NotificationMsg { + error_code: error_code.to_u8().unwrap(), + error_subcode: error_subcode.to_u8().unwrap(), + data: Default::default(), + } + } + + pub(crate) fn new_with_data( + error_code: impl Into, + error_subcode: impl Into, + data: Vec, + ) -> Self { + NotificationMsg { + error_code: error_code.into(), + error_subcode: error_subcode.into(), + data, + } + } + + fn encode(&self, buf: &mut BytesMut) { + buf.put_u8(MessageType::Notification as u8); + buf.put_u8(self.error_code); + buf.put_u8(self.error_subcode); + buf.put_slice(&self.data); + } + + fn decode(buf: &mut Bytes, msg_len: u16) -> DecodeResult { + if msg_len < Self::MIN_LEN { + return Err(MessageHeaderError::BadMessageLength(msg_len).into()); + } + + let error_code = buf.get_u8(); + let error_subcode = buf.get_u8(); + let data_len = msg_len - Self::MIN_LEN; + let data = buf.copy_to_bytes(data_len as usize).to_vec(); + + Ok(NotificationMsg { + error_code, + error_subcode, + data, + }) + } +} + +impl From for NotificationMsg { + fn from(error: DecodeError) -> NotificationMsg { + let error_code; + let error_subcode; + let data = vec![]; + + match error { + DecodeError::MessageHeader(error) => { + error_code = ErrorCode::MessageHeaderError as u8; + error_subcode = match error { + MessageHeaderError::ConnectionNotSynchronized => { + MessageHeaderErrorSubcode::ConnectionNotSynchronized + } + MessageHeaderError::BadMessageLength(..) => { + MessageHeaderErrorSubcode::BadMessageLength + } + MessageHeaderError::BadMessageType(..) => { + MessageHeaderErrorSubcode::BadMessageType + } + } as u8; + } + DecodeError::OpenMessage(error) => { + error_code = ErrorCode::OpenMessageError as u8; + error_subcode = match error { + OpenMessageError::UnsupportedVersion(..) => { + OpenMessageErrorSubcode::UnsupportedVersionNumber + } + OpenMessageError::BadPeerAs => { + OpenMessageErrorSubcode::BadPeerAs + } + OpenMessageError::BadBgpIdentifier => { + OpenMessageErrorSubcode::BadBgpIdentifier + } + OpenMessageError::UnsupportedOptParam => { + OpenMessageErrorSubcode::UnsupportedOptParam + } + OpenMessageError::UnacceptableHoldTime => { + OpenMessageErrorSubcode::UnacceptableHoldTime + } + OpenMessageError::UnsupportedCapability => { + OpenMessageErrorSubcode::UnsupportedCapability + } + OpenMessageError::MalformedOptParam => { + OpenMessageErrorSubcode::Unspecific + } + } as u8; + } + DecodeError::UpdateMessage(error) => { + error_code = ErrorCode::UpdateMessageError as u8; + error_subcode = match error { + UpdateMessageError::MalformedAttributeList => { + UpdateMessageErrorSubcode::MalformedAttributeList + } + UpdateMessageError::UnrecognizedWellKnownAttribute(..) => { + UpdateMessageErrorSubcode::UnrecognizedWellKnownAttribute + } + UpdateMessageError::MissingWellKnownAttribute(..) => { + UpdateMessageErrorSubcode::MissingWellKnownAttribute + } + UpdateMessageError::AttributeFlagsError(..) => { + UpdateMessageErrorSubcode::AttributeFlagsError + } + UpdateMessageError::AttributeLengthError(..) => { + UpdateMessageErrorSubcode::AttributeLengthError + } + UpdateMessageError::InvalidOriginAttribute(..) => { + UpdateMessageErrorSubcode::InvalidOriginAttribute + } + UpdateMessageError::InvalidNexthopAttribute(..) => { + UpdateMessageErrorSubcode::InvalidNexthopAttribute + } + UpdateMessageError::OptionalAttributeError(..) => { + UpdateMessageErrorSubcode::OptionalAttributeError + } + UpdateMessageError::InvalidNetworkField => { + UpdateMessageErrorSubcode::InvalidNetworkField + } + UpdateMessageError::MalformedAsPath => { + UpdateMessageErrorSubcode::MalformedAsPath + } + } as u8; + } + } + + // TODO: set notification data. + + NotificationMsg { + error_code, + error_subcode, + data, + } + } +} + +// ===== impl KeepaliveMsg ===== + +impl KeepaliveMsg { + const LEN: u16 = 19; + + fn encode(&self, buf: &mut BytesMut) { + buf.put_u8(MessageType::Keepalive as u8); + } + + fn decode(_buf: &mut Bytes, msg_len: u16) -> DecodeResult { + if msg_len != Self::LEN { + return Err(MessageHeaderError::BadMessageLength(msg_len).into()); + } + + // A KEEPALIVE message consists of only the message header. + Ok(KeepaliveMsg {}) + } +} + +// ===== impl RouteRefreshMsg ===== + +impl RouteRefreshMsg { + const LEN: u16 = 23; + + fn encode(&self, buf: &mut BytesMut) { + buf.put_u8(MessageType::RouteRefresh as u8); + buf.put_u16(self.afi); + buf.put_u8(0); + buf.put_u8(self.safi); + } + + fn decode(buf: &mut Bytes, msg_len: u16) -> DecodeResult { + if msg_len != Self::LEN { + return Err(MessageHeaderError::BadMessageLength(msg_len).into()); + } + + let afi = buf.get_u16(); + let _reserved = buf.get_u8(); + let safi = buf.get_u8(); + Ok(RouteRefreshMsg { afi, safi }) + } +} + +// ===== helper functions ===== + +// Calculate the number of bytes required to encode a prefix. +fn prefix_wire_len(len: u8) -> usize { + (len as usize + 7) / 8 +} diff --git a/holo-bgp/src/packet/mod.rs b/holo-bgp/src/packet/mod.rs new file mode 100644 index 00000000..8f8a9e62 --- /dev/null +++ b/holo-bgp/src/packet/mod.rs @@ -0,0 +1,244 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +pub mod attribute; +pub mod error; +pub mod message; + +use holo_utils::ip::AddressFamily; +use num_derive::{FromPrimitive, ToPrimitive}; +use serde::{Deserialize, Serialize}; + +pub const BGP_VERSION: u8 = 4; +pub const AS_TRANS: u16 = 23456; + +// BGP Message Types. +// +// IANA registry: +// https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-1 +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(FromPrimitive, ToPrimitive)] +#[derive(Deserialize, Serialize)] +pub enum MessageType { + Open = 1, + Update = 2, + Notification = 3, + Keepalive = 4, + // RFC 2918 + RouteRefresh = 5, +} + +// BGP OPEN Optional Parameter Types. +// +// IANA registry: +// https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-11 +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(FromPrimitive, ToPrimitive)] +#[derive(Deserialize, Serialize)] +pub enum OpenParamType { + // RFC5492 + Capabilities = 2, +} + +// Capability Codes. +// +// IANA registry: +// https://www.iana.org/assignments/capability-codes/capability-codes.xhtml#capability-codes-2 +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(FromPrimitive, ToPrimitive)] +#[derive(Deserialize, Serialize)] +pub enum CapabilityCode { + // RFC 2858 + MultiProtocol = 1, + // RFC 2918 + RouteRefresh = 2, + // RFC 5291 + OutboundRouteFiltering = 3, + // RFC 8950 + ExtendedNextHop = 5, + // RFC 8654 + ExtendedMessage = 6, + // RFC 8205 + BgpSec = 7, + // RFC 8277 + MultipleLabels = 8, + // RFC 9234 + BgpRole = 9, + // RFC 4724 + GracefulRestart = 64, + // RFC 6793 + FourOctetAsNumber = 65, + // RFC7911 + AddPath = 69, + // RFC7313 + EnhancedRouteRefresh = 70, +} + +// Send/Receive value for a per-AFI/SAFI instance of the ADD-PATH Capability. +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[derive(FromPrimitive, ToPrimitive)] +#[derive(Deserialize, Serialize)] +pub enum AddPathMode { + Receive = 1, + Send = 2, + ReceiveSend = 3, +} + +// BGP Error (Notification) Codes. +// +// IANA registry: +// https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-3 +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(FromPrimitive, ToPrimitive)] +#[derive(Deserialize, Serialize)] +pub enum ErrorCode { + MessageHeaderError = 1, + OpenMessageError = 2, + UpdateMessageError = 3, + HoldTimerExpired = 4, + FiniteStateMachineError = 5, + Cease = 6, + // RFC 7313 + RouteRefreshMessageError = 7, +} + +// Message Header Error subcodes. +// +// IANA registry: +// https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-5 +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(FromPrimitive, ToPrimitive)] +#[derive(Deserialize, Serialize)] +pub enum MessageHeaderErrorSubcode { + Unspecific = 0, + ConnectionNotSynchronized = 1, + BadMessageLength = 2, + BadMessageType = 3, +} + +// OPEN Message Error subcodes. +// +// IANA registry: +// https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-6 +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(FromPrimitive, ToPrimitive)] +#[derive(Deserialize, Serialize)] +pub enum OpenMessageErrorSubcode { + Unspecific = 0, + UnsupportedVersionNumber = 1, + BadPeerAs = 2, + BadBgpIdentifier = 3, + UnsupportedOptParam = 4, + UnacceptableHoldTime = 6, + // RFC 5492 + UnsupportedCapability = 7, + // RFC 9234 + RoleMismatch = 11, +} + +// UPDATE Message Error subcodes. +// +// IANA registry: +// https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-7 +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(FromPrimitive, ToPrimitive)] +#[derive(Deserialize, Serialize)] +pub enum UpdateMessageErrorSubcode { + Unspecific = 0, + MalformedAttributeList = 1, + UnrecognizedWellKnownAttribute = 2, + MissingWellKnownAttribute = 3, + AttributeFlagsError = 4, + AttributeLengthError = 5, + InvalidOriginAttribute = 6, + InvalidNexthopAttribute = 8, + OptionalAttributeError = 9, + InvalidNetworkField = 10, + MalformedAsPath = 11, +} + +// BGP Finite State Machine Error Subcodes. +// +// IANA registry: +// https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-finite-state-machine-error-subcodes +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(FromPrimitive, ToPrimitive)] +#[derive(Deserialize, Serialize)] +pub enum FsmErrorSubcode { + UnexpectedMessageInOpenSent = 1, + UnexpectedMessageInOpenConfirm = 2, + UnexpectedMessageInEstablished = 3, +} + +// BGP Cease NOTIFICATION message subcodes. +// +// IANA registry: +// https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-8 +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(FromPrimitive, ToPrimitive)] +#[derive(Deserialize, Serialize)] +pub enum CeaseSubcode { + MaximumNumberofPrefixesReached = 1, + AdministrativeShutdown = 2, + PeerDeConfigured = 3, + AdministrativeReset = 4, + ConnectionRejected = 5, + OtherConfigurationChange = 6, + ConnectionCollisionResolution = 7, + OutOfResources = 8, + // RFC 8538 + HardReset = 9, + // RFC 9384 + BfdDown = 10, +} + +// BGP ROUTE-REFRESH Message Error subcodes. +// +// IANA registry: +// https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#route-refresh-error-subcodes +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(FromPrimitive, ToPrimitive)] +#[derive(Deserialize, Serialize)] +pub enum RouteRefreshErrorSubcode { + InvalidMessageLength = 1, +} + +// Address Family identifiers (AFI). +pub type Afi = AddressFamily; + +// Subsequent Address Family Identifiers (SAFI). +// +// IANA registry: +// https://www.iana.org/assignments/safi-namespace/safi-namespace.xhtml#safi-namespace-2 +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[derive(FromPrimitive, ToPrimitive)] +#[derive(Deserialize, Serialize)] +pub enum Safi { + Unicast = 1, + Multicast = 2, + LabeledUnicast = 4, + MulticastVpn = 5, + Pseudowire = 6, + TunnelEncap = 7, + McastVpls = 8, + Tunnel = 64, + Vpls = 65, + Mdt = 66, + V4OverV6 = 67, + V6OverV4 = 68, + L1VpnAutoDiscovery = 69, + Evpn = 70, + BgpLs = 71, + BgpLsVpn = 72, + SrTe = 73, + SdWanCapabilities = 74, + LabeledVpn = 128, + MulticastMplsVpn = 129, + RouteTarget = 132, + Ipv4FlowSpec = 133, + Vpnv4FlowSpec = 134, + VpnAutoDiscovery = 140, +} diff --git a/holo-bgp/src/rib.rs b/holo-bgp/src/rib.rs new file mode 100644 index 00000000..18b53243 --- /dev/null +++ b/holo-bgp/src/rib.rs @@ -0,0 +1,5 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// diff --git a/holo-bgp/src/southbound/mod.rs b/holo-bgp/src/southbound/mod.rs new file mode 100644 index 00000000..8bd8abf6 --- /dev/null +++ b/holo-bgp/src/southbound/mod.rs @@ -0,0 +1,8 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +pub mod rx; +pub mod tx; diff --git a/holo-bgp/src/southbound/rx.rs b/holo-bgp/src/southbound/rx.rs new file mode 100644 index 00000000..bb652e1c --- /dev/null +++ b/holo-bgp/src/southbound/rx.rs @@ -0,0 +1,19 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::net::Ipv4Addr; + +use crate::instance::Instance; + +// ===== global functions ===== + +pub(crate) async fn process_router_id_update( + instance: &mut Instance, + router_id: Option, +) { + instance.system.router_id = router_id; + instance.update().await; +} diff --git a/holo-bgp/src/southbound/tx.rs b/holo-bgp/src/southbound/tx.rs new file mode 100644 index 00000000..18b53243 --- /dev/null +++ b/holo-bgp/src/southbound/tx.rs @@ -0,0 +1,5 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// diff --git a/holo-bgp/src/tasks.rs b/holo-bgp/src/tasks.rs new file mode 100644 index 00000000..072f7e1b --- /dev/null +++ b/holo-bgp/src/tasks.rs @@ -0,0 +1,354 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::sync::{atomic, Arc}; +use std::time::Duration; + +use holo_utils::socket::{OwnedReadHalf, OwnedWriteHalf, TcpListener}; +use holo_utils::task::{IntervalTask, Task, TimeoutTask}; +use holo_utils::{Sender, UnboundedReceiver}; +use tokio::time::sleep; +use tracing::{debug_span, Instrument}; + +use crate::debug::Debug; +use crate::neighbor::{fsm, Neighbor}; +use crate::network; +use crate::packet::message::{KeepaliveMsg, Message}; + +// +// BGP tasks diagram: +// +--------------+ +// | northbound | +// +--------------+ +// | ^ +// | | +// northbound_rx (1x) V | (1x) northbound_tx +// +--------------+ +// | | +// tcp_listener (1x) -> | instance | +// tcp_connect (Nx) -> | | -> (Nx) nbr_tx +// nbr_rx (Nx) -> | | -> (Nx) nbr_kalive_interval +// nbr_timer (Nx) -> | | +// | | +// +--------------+ +// ibus_tx (1x) | ^ (1x) ibus_rx +// | | +// V | +// +--------------+ +// | ibus | +// +--------------+ +// + +// BGP inter-task message types. +pub mod messages { + use std::net::IpAddr; + + use holo_utils::socket::{TcpConnInfo, TcpStream}; + use serde::{Deserialize, Serialize}; + + use crate::error::NbrRxError; + use crate::neighbor::fsm; + use crate::packet::message::Message; + + // Type aliases. + pub type ProtocolInputMsg = input::ProtocolMsg; + pub type ProtocolOutputMsg = output::ProtocolMsg; + + // Input messages (child task -> main task). + pub mod input { + use super::*; + + #[derive(Debug, Deserialize, Serialize)] + pub enum ProtocolMsg { + TcpAccept(TcpAcceptMsg), + TcpConnect(TcpConnectMsg), + NbrRx(NbrRxMsg), + NbrTimer(NbrTimerMsg), + } + + #[derive(Debug, Deserialize, Serialize)] + pub struct TcpAcceptMsg { + #[serde(skip)] + pub stream: Option, + pub conn_info: TcpConnInfo, + } + + #[derive(Debug, Deserialize, Serialize)] + pub struct TcpConnectMsg { + #[serde(skip)] + pub stream: Option, + pub conn_info: TcpConnInfo, + } + + #[derive(Debug, Deserialize, Serialize)] + pub struct NbrRxMsg { + pub nbr_addr: IpAddr, + pub msg: Result, + } + + #[derive(Debug, Deserialize, Serialize)] + pub struct NbrTimerMsg { + pub nbr_addr: IpAddr, + pub timer: fsm::Timer, + } + + impl TcpAcceptMsg { + pub(crate) fn stream(&mut self) -> TcpStream { + #[cfg(not(feature = "testing"))] + { + self.stream.take().unwrap() + } + #[cfg(feature = "testing")] + { + Default::default() + } + } + } + + impl TcpConnectMsg { + pub(crate) fn stream(&mut self) -> TcpStream { + #[cfg(not(feature = "testing"))] + { + self.stream.take().unwrap() + } + #[cfg(feature = "testing")] + { + Default::default() + } + } + } + } + + // Output messages (main task -> child task). + pub mod output { + use super::*; + + #[derive(Debug, Serialize)] + pub enum ProtocolMsg { + NbrTx(NbrTxMsg), + } + + #[derive(Debug, Serialize)] + pub struct NbrTxMsg { + pub nbr_addr: IpAddr, + pub msg: Message, + } + } +} + +// ===== BGP tasks ===== + +// TCP listening task. +pub(crate) fn tcp_listener( + session_socket: &Arc, + tcp_acceptp: &Sender, +) -> Task<()> { + #[cfg(not(feature = "testing"))] + { + let span1 = debug_span!("session"); + let _span1_guard = span1.enter(); + let span2 = debug_span!("input"); + let _span2_guard = span2.enter(); + + let session_socket = session_socket.clone(); + let tcp_acceptp = tcp_acceptp.clone(); + Task::spawn( + async move { + let _ = network::listen_loop(session_socket, tcp_acceptp).await; + } + .in_current_span(), + ) + } + #[cfg(feature = "testing")] + { + Task::spawn(async move { std::future::pending().await }) + } +} + +// TCP connect task. +pub(crate) fn tcp_connect( + nbr: &Neighbor, + tcp_connectp: &Sender, +) -> Task<()> { + #[cfg(not(feature = "testing"))] + { + let span = debug_span!("neighbor", addr = %nbr.remote_addr); + let _span_guard = span.enter(); + + let remote_addr = nbr.remote_addr; + let local_addr = nbr.config.transport.local_addr; + let ttl = nbr.tx_ttl(); + let ttl_security = nbr.config.transport.ttl_security; + let tcp_mss = nbr.config.transport.tcp_mss; + let tcp_password = nbr.config.transport.md5_key.clone(); + let tcp_connectp = tcp_connectp.clone(); + Task::spawn( + async move { + loop { + let result = network::connect( + remote_addr, + local_addr, + ttl, + ttl_security, + tcp_mss, + &tcp_password, + ) + .await; + + match result { + Ok((stream, conn_info)) => { + // Send message to the parent BGP task. + let msg = messages::input::TcpConnectMsg { + stream: Some(stream), + conn_info, + }; + let _ = tcp_connectp.send(msg).await; + return; + } + Err(error) => { + error.log(); + // Wait one second before trying again. + sleep(Duration::from_secs(1)).await; + } + } + } + } + .in_current_span(), + ) + } + #[cfg(feature = "testing")] + { + Task::spawn(async move { std::future::pending().await }) + } +} + +// Neighbor TCP Rx task. +pub(crate) fn nbr_rx( + nbr: &Neighbor, + read_half: OwnedReadHalf, + nbr_msg_rxp: &Sender, +) -> Task<()> { + #[cfg(not(feature = "testing"))] + { + let span1 = debug_span!("neighbor", addr = %nbr.remote_addr); + let _span1_guard = span1.enter(); + let span2 = debug_span!("input"); + let _span2_guard = span2.enter(); + + let nbr_addr = nbr.remote_addr; + let nbr_msg_rxp = nbr_msg_rxp.clone(); + Task::spawn( + async move { + let _ = + network::nbr_read_loop(read_half, nbr_addr, nbr_msg_rxp) + .await; + } + .in_current_span(), + ) + } + #[cfg(feature = "testing")] + { + Task::spawn(async move { std::future::pending().await }) + } +} + +// Neighbor TCP Tx task. +#[cfg_attr(not(feature = "testing"), allow(unused_mut))] +pub(crate) fn nbr_tx( + nbr: &Neighbor, + write_half: OwnedWriteHalf, + mut msg_txc: UnboundedReceiver, + #[cfg(feature = "testing")] proto_output_tx: &Sender< + messages::ProtocolOutputMsg, + >, +) -> Task<()> { + #[cfg(not(feature = "testing"))] + { + let span1 = debug_span!("neighbor", addr = %nbr.remote_addr); + let _span1_guard = span1.enter(); + let span2 = debug_span!("output"); + let _span2_guard = span2.enter(); + + Task::spawn( + async move { + network::nbr_write_loop(write_half, msg_txc).await; + } + .in_current_span(), + ) + } + #[cfg(feature = "testing")] + { + let proto_output_tx = proto_output_tx.clone(); + Task::spawn(async move { + // Relay message to the test framework. + while let Some(msg) = msg_txc.recv().await { + let msg = messages::ProtocolOutputMsg::NbrTx(msg); + let _ = proto_output_tx.send(msg).await; + } + }) + } +} + +// Neighbor timer task. +pub(crate) fn nbr_timer( + nbr: &Neighbor, + timer: fsm::Timer, + seconds: u16, + nbr_timerp: &Sender, +) -> TimeoutTask { + #[cfg(not(feature = "testing"))] + { + let nbr_timerp = nbr_timerp.clone(); + let nbr_addr = nbr.remote_addr; + + TimeoutTask::new( + Duration::from_secs(seconds.into()), + move || async move { + let msg = messages::input::NbrTimerMsg { nbr_addr, timer }; + let _ = nbr_timerp.send(msg).await; + }, + ) + } + #[cfg(feature = "testing")] + { + TimeoutTask {} + } +} + +// Send periodic keepalive messages. +pub(crate) fn nbr_kalive_interval( + nbr: &Neighbor, + interval: u16, +) -> IntervalTask { + #[cfg(not(feature = "testing"))] + { + let msg_txp = nbr.msg_txp.as_ref().unwrap().clone(); + let nbr_addr = nbr.remote_addr; + let msg_counter = nbr.statistics.msgs_sent.total.clone(); + + IntervalTask::new( + Duration::from_secs(interval.into()), + false, + move || { + let msg_txp = msg_txp.clone(); + let msg_counter = msg_counter.clone(); + + async move { + let msg = Message::Keepalive(KeepaliveMsg {}); + Debug::NbrMsgTx(&nbr_addr, &msg).log(); + + let msg = messages::output::NbrTxMsg { nbr_addr, msg }; + let _ = msg_txp.send(msg); + msg_counter.fetch_add(1, atomic::Ordering::Relaxed); + } + }, + ) + } + #[cfg(feature = "testing")] + { + IntervalTask {} + } +} diff --git a/holo-bgp/tests/mod.rs b/holo-bgp/tests/mod.rs new file mode 100644 index 00000000..982a3849 --- /dev/null +++ b/holo-bgp/tests/mod.rs @@ -0,0 +1,9 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +#![feature(lazy_cell)] + +mod packet; diff --git a/holo-bgp/tests/packet/keepalive.rs b/holo-bgp/tests/packet/keepalive.rs new file mode 100644 index 00000000..9218733b --- /dev/null +++ b/holo-bgp/tests/packet/keepalive.rs @@ -0,0 +1,33 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::sync::LazyLock as Lazy; + +use holo_bgp::packet::message::{KeepaliveMsg, Message}; + +use super::{test_decode_msg, test_encode_msg}; + +static KEEPALIVE1: Lazy<(Vec, Message)> = Lazy::new(|| { + ( + vec![ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x13, 0x04, + ], + Message::Keepalive(KeepaliveMsg {}), + ) +}); + +#[test] +fn test_encode_keepalive1() { + let (ref bytes, ref msg) = *KEEPALIVE1; + test_encode_msg(bytes, msg); +} + +#[test] +fn test_decode_keepalive1() { + let (ref bytes, ref msg) = *KEEPALIVE1; + test_decode_msg(bytes, msg); +} diff --git a/holo-bgp/tests/packet/mod.rs b/holo-bgp/tests/packet/mod.rs new file mode 100644 index 00000000..54765ca5 --- /dev/null +++ b/holo-bgp/tests/packet/mod.rs @@ -0,0 +1,29 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +mod keepalive; +mod notification; +mod open; +mod route_refresh; +mod update; + +use holo_bgp::packet::message::Message; + +// +// Helper functions. +// + +fn test_encode_msg(bytes_expected: &[u8], msg: &Message) { + let bytes_actual = msg.encode(); + println!("{:#04x?}", bytes_actual.as_ref()); + assert_eq!(bytes_expected, bytes_actual.as_ref()); +} + +fn test_decode_msg(bytes: &[u8], msg_expected: &Message) { + //let _msg_size = Message::get_msg_size(&bytes).unwrap(); + let msg_actual = Message::decode(&bytes).unwrap(); + assert_eq!(*msg_expected, msg_actual); +} diff --git a/holo-bgp/tests/packet/notification.rs b/holo-bgp/tests/packet/notification.rs new file mode 100644 index 00000000..fd773de7 --- /dev/null +++ b/holo-bgp/tests/packet/notification.rs @@ -0,0 +1,39 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::sync::LazyLock as Lazy; + +use holo_bgp::packet::message::{Message, NotificationMsg}; +use holo_bgp::packet::{ErrorCode, MessageHeaderErrorSubcode}; + +use super::{test_decode_msg, test_encode_msg}; + +static NOTIFICATION1: Lazy<(Vec, Message)> = Lazy::new(|| { + ( + vec![ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x17, 0x03, 0x01, 0x02, 0xff, + 0xff, + ], + Message::Notification(NotificationMsg { + error_code: ErrorCode::MessageHeaderError as u8, + error_subcode: MessageHeaderErrorSubcode::BadMessageLength as u8, + data: vec![0xff, 0xff], + }), + ) +}); + +#[test] +fn test_encode_notification1() { + let (ref bytes, ref msg) = *NOTIFICATION1; + test_encode_msg(bytes, msg); +} + +#[test] +fn test_decode_notification1() { + let (ref bytes, ref msg) = *NOTIFICATION1; + test_decode_msg(bytes, msg); +} diff --git a/holo-bgp/tests/packet/open.rs b/holo-bgp/tests/packet/open.rs new file mode 100644 index 00000000..e1ff2d58 --- /dev/null +++ b/holo-bgp/tests/packet/open.rs @@ -0,0 +1,122 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::net::Ipv4Addr; +use std::str::FromStr; +use std::sync::LazyLock as Lazy; + +use holo_bgp::packet::message::{Capability, Message, OpenMsg}; +use holo_bgp::packet::{Afi, Safi, BGP_VERSION}; + +use super::{test_decode_msg, test_encode_msg}; + +static OPEN1: Lazy<(Vec, Message)> = Lazy::new(|| { + ( + vec![ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x00, 0x01, + 0x00, 0xb4, 0x01, 0x01, 0x01, 0x01, 0x00, + ], + Message::Open(OpenMsg { + version: BGP_VERSION, + my_as: 1, + holdtime: 180, + identifier: Ipv4Addr::from_str("1.1.1.1").unwrap(), + capabilities: [].into(), + }), + ) +}); + +static OPEN2: Lazy<(Vec, Message)> = Lazy::new(|| { + ( + vec![ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x25, 0x01, 0x04, 0x00, 0x01, + 0x00, 0xb4, 0x01, 0x01, 0x01, 0x01, 0x08, 0x02, 0x06, 0x01, 0x04, + 0x00, 0x01, 0x00, 0x01, + ], + Message::Open(OpenMsg { + version: BGP_VERSION, + my_as: 1, + holdtime: 180, + identifier: Ipv4Addr::from_str("1.1.1.1").unwrap(), + capabilities: [Capability::MultiProtocol { + afi: Afi::Ipv4, + safi: Safi::Unicast, + }] + .into(), + }), + ) +}); + +static OPEN3: Lazy<(Vec, Message)> = Lazy::new(|| { + ( + vec![ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3d, 0x01, 0x04, 0x00, 0x01, + 0x00, 0xb4, 0x01, 0x01, 0x01, 0x01, 0x20, 0x02, 0x06, 0x01, 0x04, + 0x00, 0x01, 0x00, 0x01, 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, + 0x01, 0x02, 0x06, 0x41, 0x04, 0x00, 0x01, 0x00, 0x0e, 0x02, 0x02, + 0x02, 0x00, 0x02, 0x02, 0x46, 0x00, + ], + Message::Open(OpenMsg { + version: BGP_VERSION, + my_as: 1, + holdtime: 180, + identifier: Ipv4Addr::from_str("1.1.1.1").unwrap(), + capabilities: [ + Capability::MultiProtocol { + afi: Afi::Ipv4, + safi: Safi::Unicast, + }, + Capability::MultiProtocol { + afi: Afi::Ipv6, + safi: Safi::Unicast, + }, + Capability::FourOctetAsNumber { asn: 65550 }, + Capability::RouteRefresh, + Capability::EnhancedRouteRefresh, + ] + .into(), + }), + ) +}); + +#[test] +fn test_encode_open1() { + let (ref bytes, ref msg) = *OPEN1; + test_encode_msg(bytes, msg); +} + +#[test] +fn test_decode_open1() { + let (ref bytes, ref msg) = *OPEN1; + test_decode_msg(bytes, msg); +} + +#[test] +fn test_encode_open2() { + let (ref bytes, ref msg) = *OPEN2; + test_encode_msg(bytes, msg); +} + +#[test] +fn test_decode_open2() { + let (ref bytes, ref msg) = *OPEN2; + test_decode_msg(bytes, msg); +} + +#[test] +fn test_encode_open3() { + let (ref bytes, ref msg) = *OPEN3; + test_encode_msg(bytes, msg); +} + +#[test] +fn test_decode_open3() { + let (ref bytes, ref msg) = *OPEN3; + test_decode_msg(bytes, msg); +} diff --git a/holo-bgp/tests/packet/route_refresh.rs b/holo-bgp/tests/packet/route_refresh.rs new file mode 100644 index 00000000..f1637898 --- /dev/null +++ b/holo-bgp/tests/packet/route_refresh.rs @@ -0,0 +1,38 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::sync::LazyLock as Lazy; + +use holo_bgp::packet::message::{Message, RouteRefreshMsg}; +use holo_bgp::packet::{Afi, Safi}; + +use super::{test_decode_msg, test_encode_msg}; + +static ROUTE_REFRESH1: Lazy<(Vec, Message)> = Lazy::new(|| { + ( + vec![ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x17, 0x05, 0x00, 0x01, 0x00, + 0x01, + ], + Message::RouteRefresh(RouteRefreshMsg { + afi: Afi::Ipv4 as u16, + safi: Safi::Unicast as u8, + }), + ) +}); + +#[test] +fn test_encode_route_refresh1() { + let (ref bytes, ref msg) = *ROUTE_REFRESH1; + test_encode_msg(bytes, msg); +} + +#[test] +fn test_decode_route_refresh1() { + let (ref bytes, ref msg) = *ROUTE_REFRESH1; + test_decode_msg(bytes, msg); +} diff --git a/holo-bgp/tests/packet/update.rs b/holo-bgp/tests/packet/update.rs new file mode 100644 index 00000000..4de9432e --- /dev/null +++ b/holo-bgp/tests/packet/update.rs @@ -0,0 +1,82 @@ +// +// Copyright (c) The Holo Core Contributors +// +// SPDX-License-Identifier: MIT +// + +use std::str::FromStr; +use std::sync::LazyLock as Lazy; + +use holo_bgp::packet::message::{Message, Nlri, UpdateMsg}; +use holo_bgp::packet::Safi; +use ipnetwork::Ipv4Network; + +use super::{test_decode_msg, test_encode_msg}; + +static UPDATE1: Lazy<(Vec, Message)> = Lazy::new(|| { + ( + vec![ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x17, 0x02, 0x00, 0x00, 0x00, + 0x00, + ], + Message::Update(UpdateMsg { + unreach: None, + reach: None, + attributes: vec![], + }), + ) +}); + +static UPDATE2: Lazy<(Vec, Message)> = Lazy::new(|| { + ( + vec![ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x29, 0x02, 0x00, 0x08, 0x18, + 0x0a, 0x00, 0x01, 0x18, 0x0a, 0x00, 0x02, 0x00, 0x00, 0x20, 0x0a, + 0x00, 0xff, 0x01, 0x20, 0x0a, 0x00, 0xff, 0x02, + ], + Message::Update(UpdateMsg { + unreach: Some(( + Safi::Unicast, + Nlri::Ipv4(vec![ + Ipv4Network::from_str("10.0.1.0/24").unwrap(), + Ipv4Network::from_str("10.0.2.0/24").unwrap(), + ]), + )), + reach: Some(( + Safi::Unicast, + Nlri::Ipv4(vec![ + Ipv4Network::from_str("10.0.255.1/32").unwrap(), + Ipv4Network::from_str("10.0.255.2/32").unwrap(), + ]), + None, + )), + attributes: vec![], + }), + ) +}); + +#[test] +fn test_encode_update1() { + let (ref bytes, ref msg) = *UPDATE1; + test_encode_msg(bytes, msg); +} + +#[test] +fn test_decode_update1() { + let (ref bytes, ref msg) = *UPDATE1; + test_decode_msg(bytes, msg); +} + +#[test] +fn test_encode_update2() { + let (ref bytes, ref msg) = *UPDATE2; + test_encode_msg(bytes, msg); +} + +#[test] +fn test_decode_update2() { + let (ref bytes, ref msg) = *UPDATE2; + test_decode_msg(bytes, msg); +} diff --git a/holo-daemon/Cargo.toml b/holo-daemon/Cargo.toml index a7ac75ae..29822530 100644 --- a/holo-daemon/Cargo.toml +++ b/holo-daemon/Cargo.toml @@ -32,6 +32,7 @@ yang2.workspace = true holo-interface = { path = "../holo-interface" } holo-bfd = { path = "../holo-bfd", optional = true } +holo-bgp = { path = "../holo-bgp", optional = true } holo-keychain = { path = "../holo-keychain" } holo-ldp = { path = "../holo-ldp", optional = true } holo-northbound = { path = "../holo-northbound" } @@ -54,8 +55,9 @@ name = "holod" path = "src/main.rs" [features] -default = ["bfd", "ldp", "ospf", "rip"] +default = ["bfd", "bgp", "ldp", "ospf", "rip"] bfd = ["holo-bfd"] +bgp = ["holo-bgp"] ldp = ["holo-ldp"] ospf = ["holo-ospf"] rip = ["holo-rip"] diff --git a/holo-daemon/src/northbound/yang.rs b/holo-daemon/src/northbound/yang.rs index dc02f1e9..32ceaca7 100644 --- a/holo-daemon/src/northbound/yang.rs +++ b/holo-daemon/src/northbound/yang.rs @@ -18,8 +18,13 @@ pub(crate) fn create_context() { let mut modules = Vec::new(); // Add data type modules. - for module_name in ["iana-if-type", "ietf-routing-types", "ietf-bfd-types"] - { + for module_name in [ + "iana-if-type", + "iana-bgp-notification", + "iana-bgp-types", + "ietf-routing-types", + "ietf-bfd-types", + ] { modules.push(module_name); } @@ -35,6 +40,11 @@ pub(crate) fn create_context() { use holo_bfd::master::Master; modules_add::(&mut modules); } + #[cfg(feature = "bgp")] + { + use holo_bgp::instance::Instance; + modules_add::(&mut modules); + } #[cfg(feature = "ldp")] { use holo_ldp::instance::Instance; diff --git a/holo-policy/src/northbound/configuration.rs b/holo-policy/src/northbound/configuration.rs index cb7553a6..0438850c 100644 --- a/holo-policy/src/northbound/configuration.rs +++ b/holo-policy/src/northbound/configuration.rs @@ -210,6 +210,114 @@ fn load_callbacks() -> Callbacks { let event_queue = args.event_queue; event_queue.insert(Event::MatchSetsUpdate); }) + .path(routing_policy::defined_sets::bgp_defined_sets::as_path_sets::as_path_set::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .lookup(|_master, _list_entry, _dnode| { + // TODO: implement me! + todo!(); + }) + .path(routing_policy::defined_sets::bgp_defined_sets::as_path_sets::as_path_set::member::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::defined_sets::bgp_defined_sets::community_sets::community_set::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .lookup(|_master, _list_entry, _dnode| { + // TODO: implement me! + todo!(); + }) + .path(routing_policy::defined_sets::bgp_defined_sets::community_sets::community_set::member::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::defined_sets::bgp_defined_sets::ext_community_sets::ext_community_set::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .lookup(|_master, _list_entry, _dnode| { + // TODO: implement me! + todo!(); + }) + .path(routing_policy::defined_sets::bgp_defined_sets::ext_community_sets::ext_community_set::member::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::defined_sets::bgp_defined_sets::ipv6_ext_community_sets::ipv6_ext_community_set::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .lookup(|_master, _list_entry, _dnode| { + // TODO: implement me! + todo!(); + }) + .path(routing_policy::defined_sets::bgp_defined_sets::ipv6_ext_community_sets::ipv6_ext_community_set::member::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::defined_sets::bgp_defined_sets::large_community_sets::large_community_set::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .lookup(|_master, _list_entry, _dnode| { + // TODO: implement me! + todo!(); + }) + .path(routing_policy::defined_sets::bgp_defined_sets::large_community_sets::large_community_set::member::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::defined_sets::bgp_defined_sets::next_hop_sets::next_hop_set::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .lookup(|_master, _list_entry, _dnode| { + // TODO: implement me! + todo!(); + }) + .path(routing_policy::defined_sets::bgp_defined_sets::next_hop_sets::next_hop_set::next_hop::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) .path(routing_policy::policy_definitions::policy_definition::PATH) .create_apply(|master, args| { let name = args.dnode.get_string_relative("./name").unwrap(); @@ -455,6 +563,252 @@ fn load_callbacks() -> Callbacks { let event_queue = args.event_queue; event_queue.insert(Event::PolicyChange(policy.name.clone())); }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::local_pref::value::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::local_pref::eq::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::local_pref::lt_or_eq::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::local_pref::gt_or_eq::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::med::value::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::med::eq::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::med::lt_or_eq::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::med::gt_or_eq::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::origin_eq::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_afi_safi::afi_safi_in::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_afi_safi::match_set_options::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_neighbor::neighbor_eq::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_neighbor::match_set_options::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::route_type::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::community_count::community_count::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::community_count::eq::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::community_count::lt_or_eq::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::community_count::gt_or_eq::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::as_path_length::as_path_length::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::as_path_length::eq::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::as_path_length::lt_or_eq::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::as_path_length::gt_or_eq::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_community_set::community_set::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_community_set::match_set_options::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_ext_community_set::ext_community_set::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_ext_community_set::ext_community_match_kind::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_ext_community_set::match_set_options::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_ipv6_ext_community_set::ipv6_ext_community_set::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_ipv6_ext_community_set::ipv6_ext_community_match_kind::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_ipv6_ext_community_set::match_set_options::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_large_community_set::large_community_set::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_large_community_set::match_set_options::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_as_path_set::as_path_set::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_as_path_set::match_set_options::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_next_hop_set::next_hop_set::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_next_hop_set::match_set_options::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::policy_result::PATH) .modify_apply(|master, args| { let (policy_name, stmt_name) = args.list_entry.into_policy_stmt().unwrap(); @@ -637,6 +991,132 @@ fn load_callbacks() -> Callbacks { let event_queue = args.event_queue; event_queue.insert(Event::PolicyChange(policy.name.clone())); }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_route_origin::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_local_pref::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_next_hop::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_med::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_as_path_prepend::repeat_n::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_as_path_prepend::asn::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_community::options::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_community::communities::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_community::community_set_ref::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_ext_community::options::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_ext_community::communities::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_ext_community::ext_community_set_ref::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_ipv6_ext_community::options::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_ipv6_ext_community::communities::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_ipv6_ext_community::ipv6_ext_community_set_ref::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_large_community::options::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_large_community::communities::PATH) + .create_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_large_community::large_community_set_ref::PATH) + .modify_apply(|_master, _args| { + // TODO: implement me! + }) + .delete_apply(|_master, _args| { + // TODO: implement me! + }) .build() } diff --git a/holo-policy/src/northbound/mod.rs b/holo-policy/src/northbound/mod.rs index 322ebe1e..e9251e1f 100644 --- a/holo-policy/src/northbound/mod.rs +++ b/holo-policy/src/northbound/mod.rs @@ -17,7 +17,7 @@ use crate::Master; impl ProviderBase for Master { fn yang_modules() -> &'static [&'static str] { - &["ietf-routing-policy"] + &["ietf-routing-policy", "ietf-bgp-policy"] } fn top_level_node(&self) -> String { diff --git a/holo-policy/src/northbound/state.rs b/holo-policy/src/northbound/state.rs index 94e2fdb7..fd578557 100644 --- a/holo-policy/src/northbound/state.rs +++ b/holo-policy/src/northbound/state.rs @@ -56,6 +56,66 @@ fn load_callbacks() -> Callbacks { // No operational data under this list. None }) + .path(routing_policy::defined_sets::bgp_defined_sets::as_path_sets::as_path_set::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::defined_sets::bgp_defined_sets::as_path_sets::as_path_set::member::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::defined_sets::bgp_defined_sets::community_sets::community_set::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::defined_sets::bgp_defined_sets::community_sets::community_set::member::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::defined_sets::bgp_defined_sets::ext_community_sets::ext_community_set::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::defined_sets::bgp_defined_sets::ext_community_sets::ext_community_set::member::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::defined_sets::bgp_defined_sets::ipv6_ext_community_sets::ipv6_ext_community_set::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::defined_sets::bgp_defined_sets::ipv6_ext_community_sets::ipv6_ext_community_set::member::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::defined_sets::bgp_defined_sets::large_community_sets::large_community_set::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::defined_sets::bgp_defined_sets::large_community_sets::large_community_set::member::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::defined_sets::bgp_defined_sets::next_hop_sets::next_hop_set::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::defined_sets::bgp_defined_sets::next_hop_sets::next_hop_set::next_hop::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) .path(routing_policy::policy_definitions::policy_definition::PATH) .get_iterate(|_master, _args| { // No operational data under this list. @@ -71,6 +131,41 @@ fn load_callbacks() -> Callbacks { // No operational data under this list. None }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_afi_safi::afi_safi_in::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::conditions::bgp_conditions::match_neighbor::neighbor_eq::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_as_path_prepend::asn::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_community::communities::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_ext_community::communities::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_ipv6_ext_community::communities::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) + .path(routing_policy::policy_definitions::policy_definition::statements::statement::actions::bgp_actions::set_large_community::communities::PATH) + .get_iterate(|_master, _args| { + // No operational data under this list. + None + }) .build() } diff --git a/holo-routing/Cargo.toml b/holo-routing/Cargo.toml index 5209204c..cca0e03f 100644 --- a/holo-routing/Cargo.toml +++ b/holo-routing/Cargo.toml @@ -22,6 +22,7 @@ tracing.workspace = true yang2.workspace = true holo-bfd = { path = "../holo-bfd" } +holo-bgp = { path = "../holo-bgp" } holo-ldp = { path = "../holo-ldp" } holo-northbound = { path = "../holo-northbound" } holo-ospf = { path = "../holo-ospf" } diff --git a/holo-routing/src/northbound/configuration.rs b/holo-routing/src/northbound/configuration.rs index 99f271be..9a0ce0b8 100644 --- a/holo-routing/src/northbound/configuration.rs +++ b/holo-routing/src/northbound/configuration.rs @@ -660,6 +660,7 @@ impl Provider for Master { fn nested_callbacks() -> Option> { let keys = [ holo_bfd::northbound::configuration::CALLBACKS.keys(), + holo_bgp::northbound::configuration::CALLBACKS.keys(), holo_ldp::northbound::configuration::CALLBACKS.keys(), holo_ospf::northbound::configuration::CALLBACKS_OSPFV2.keys(), holo_ospf::northbound::configuration::CALLBACKS_OSPFV3.keys(), @@ -717,6 +718,18 @@ impl Provider for Master { // Nothing to do, the BFD task runs permanently. return; } + Protocol::BGP => { + use holo_bgp::instance::Instance; + + spawn_protocol_task::( + name, + &self.nb_tx, + &self.ibus_tx, + Default::default(), + self.shared.clone(), + Some(event_recorder_config), + ) + } Protocol::DIRECT => { // This protocol type can not be configured. unreachable!() diff --git a/holo-routing/src/northbound/rpc.rs b/holo-routing/src/northbound/rpc.rs index c15368b9..93068a27 100644 --- a/holo-routing/src/northbound/rpc.rs +++ b/holo-routing/src/northbound/rpc.rs @@ -15,6 +15,7 @@ use crate::Master; impl Provider for Master { fn nested_callbacks() -> Option> { let keys = [ + holo_bgp::northbound::rpc::CALLBACKS.keys(), holo_ldp::northbound::rpc::CALLBACKS.keys(), holo_ospf::northbound::rpc::CALLBACKS_OSPFV2.keys(), holo_ospf::northbound::rpc::CALLBACKS_OSPFV3.keys(), @@ -62,6 +63,9 @@ fn find_instance( rpc: DataNodeRef<'_>, ) -> Result<(Protocol, Option), String> { let (protocol, name) = match rpc.schema().module().name() { + "ietf-bgp" => { + todo!() + } "ietf-mpls-ldp" => { let protocol = Protocol::LDP; let name = match rpc.path().as_ref() { diff --git a/holo-routing/src/northbound/state.rs b/holo-routing/src/northbound/state.rs index 40ea8edb..0fad2387 100644 --- a/holo-routing/src/northbound/state.rs +++ b/holo-routing/src/northbound/state.rs @@ -393,6 +393,7 @@ impl Provider for Master { fn nested_callbacks() -> Option> { let keys = [ holo_bfd::northbound::state::CALLBACKS.keys(), + holo_bgp::northbound::state::CALLBACKS.keys(), holo_ldp::northbound::state::CALLBACKS.keys(), holo_ospf::northbound::state::CALLBACKS_OSPFV2.keys(), holo_ospf::northbound::state::CALLBACKS_OSPFV3.keys(), diff --git a/holo-tools/yang-coverage.sh b/holo-tools/yang-coverage.sh index 1a368d3e..622a9e13 100755 --- a/holo-tools/yang-coverage.sh +++ b/holo-tools/yang-coverage.sh @@ -14,6 +14,8 @@ cargo run --bin yang_coverage --\ -m ietf-bfd\ -m ietf-bfd-ip-mh\ -m ietf-bfd-ip-sh\ + -m ietf-bgp\ + -m ietf-bgp-policy\ -m ietf-mpls-ldp\ -m ietf-ospf\ -m ietf-ospf-sr\ diff --git a/holo-utils/src/policy.rs b/holo-utils/src/policy.rs index 706620ee..9d1ecef7 100644 --- a/holo-utils/src/policy.rs +++ b/holo-utils/src/policy.rs @@ -19,6 +19,25 @@ use crate::protocol::Protocol; // Type aliases. pub type Policies = BTreeMap>; +// Routing policy configuration. +#[derive(Clone, Debug, Default)] +pub struct ApplyPolicyCfg { + // TODO: "ordered-by user" + pub import_policy: BTreeSet, + pub default_import_policy: DefaultPolicyType, + // TODO: "ordered-by user" + pub export_policy: BTreeSet, + pub default_export_policy: DefaultPolicyType, +} + +// Default policy type. +#[derive(Clone, Copy, Debug, Default)] +pub enum DefaultPolicyType { + AcceptRoute, + #[default] + RejectRoute, +} + // Route type. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] #[derive(Deserialize, Serialize)] @@ -139,6 +158,7 @@ pub struct Policy { // Name of the policy. pub name: String, // List of statements. + // TODO: "ordered-by user" pub stmts: BTreeMap, } @@ -207,6 +227,18 @@ pub enum PolicyAction { SetAppTag(u32), } +// ===== impl DefaultPolicyType ===== + +impl TryFromYang for DefaultPolicyType { + fn try_from_yang(value: &str) -> Option { + match value { + "accept-route" => Some(DefaultPolicyType::AcceptRoute), + "reject-route" => Some(DefaultPolicyType::RejectRoute), + _ => None, + } + } +} + // ===== impl RouteType ===== impl TryFromYang for RouteType { diff --git a/holo-utils/src/protocol.rs b/holo-utils/src/protocol.rs index 37b5f6a6..7b98c98d 100644 --- a/holo-utils/src/protocol.rs +++ b/holo-utils/src/protocol.rs @@ -16,6 +16,7 @@ use serde::{Deserialize, Serialize}; #[serde(rename_all = "lowercase")] pub enum Protocol { BFD, + BGP, DIRECT, LDP, OSPFV2, @@ -31,6 +32,7 @@ impl std::fmt::Display for Protocol { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Protocol::BFD => write!(f, "bfd"), + Protocol::BGP => write!(f, "bgp"), Protocol::DIRECT => write!(f, "direct"), Protocol::LDP => write!(f, "ldp"), Protocol::OSPFV2 => write!(f, "ospfv2"), @@ -48,6 +50,7 @@ impl FromStr for Protocol { fn from_str(s: &str) -> Result { match s.to_lowercase().as_ref() { "bfd" => Ok(Protocol::BFD), + "bgp" => Ok(Protocol::BGP), "direct" => Ok(Protocol::DIRECT), "ldp" => Ok(Protocol::LDP), "ospfv2" => Ok(Protocol::OSPFV2), @@ -64,6 +67,7 @@ impl ToYang for Protocol { fn to_yang(&self) -> String { match self { Protocol::BFD => "ietf-bfd-types:bfdv1".to_owned(), + Protocol::BGP => "ietf-bgp:bgp".to_owned(), Protocol::DIRECT => "ietf-routing:direct".to_owned(), Protocol::LDP => "ietf-mpls-ldp:mpls-ldp".to_owned(), Protocol::OSPFV2 => "ietf-ospf:ospfv2".to_owned(), @@ -79,6 +83,7 @@ impl TryFromYang for Protocol { fn try_from_yang(identity: &str) -> Option { match identity { "ietf-bfd-types:bfdv1" => Some(Protocol::BFD), + "ietf-bgp:bgp" => Some(Protocol::BGP), "ietf-routing:direct" => Some(Protocol::DIRECT), "ietf-mpls-ldp:mpls-ldp" => Some(Protocol::LDP), "ietf-ospf:ospfv2" => Some(Protocol::OSPFV2), diff --git a/holo-yang/modules/augmentations/holo-bgp.yang b/holo-yang/modules/augmentations/holo-bgp.yang new file mode 100644 index 00000000..96ccb62d --- /dev/null +++ b/holo-yang/modules/augmentations/holo-bgp.yang @@ -0,0 +1,78 @@ +module holo-bgp { + yang-version 1.1; + namespace "http://holo-routing.org/yang/holo-bgp"; + prefix holo-bgp; + + import ietf-routing { + prefix rt; + } + + import iana-bgp-types { + prefix bt; + } + + import iana-bgp-notification { + prefix bn; + } + + import ietf-bgp { + prefix bgp; + } + + organization + "Holo Routing Stack"; + + description + "This module defines augment statements for the ietf-bgp + module."; + + /* + * Identities. + */ + + identity unknown-error { + base bn:bgp-notification; + description + "Unknown error code"; + } + + identity graceful-restart { + base bt:bgp-capability; + description + "Graceful restart functionality"; + reference + "RFC 4724: Graceful Restart Mechanism for BGP."; + } + + identity add-paths { + base bt:bgp-capability; + description + "Advertisement of multiple paths for the same address prefix + without the new paths implicitly replacing any previous + ones."; + reference + "RFC 7911: Advertisement of Multiple Paths in BGP."; + } + + identity enhanced-route-refresh { + base bt:bgp-capability; + description + "The BGP enhanced route-refresh functionality"; + reference + "RFC 7313: Enhanced Route Refresh Capability for BGP-4"; + } + + /* + * Augmentations. + */ + + augment "/rt:routing/rt:control-plane-protocols/" + + "rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/" + + "bgp:transport/bgp:secure-session/bgp:options/bgp:option/bgp:md5" { + leaf md5-key-string { + type string; + description + "Key string in ASCII format."; + } + } +} diff --git a/holo-yang/modules/deviations/ietf-bgp-holo-deviations.yang b/holo-yang/modules/deviations/ietf-bgp-holo-deviations.yang new file mode 100644 index 00000000..4f2fbf68 --- /dev/null +++ b/holo-yang/modules/deviations/ietf-bgp-holo-deviations.yang @@ -0,0 +1,4832 @@ +module ietf-bgp-holo-deviations { + yang-version 1.1; + namespace "http://holo-routing.org/yang/ietf-bgp-holo-deviations"; + prefix ietf-bgp-holo-deviations; + + import ietf-routing { + prefix rt; + } + + import ietf-bgp { + prefix bgp; + } + + organization + "Holo Routing Stack"; + + description + "This module defines deviation statements for the ietf-bgp + module."; + + /* + * Default values + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:distance/bgp:external" { + deviate add { + default "20"; + } + } + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:distance/bgp:internal" { + deviate add { + default "200"; + } + } + + /* + * Other deviations + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:peer-as" { + deviate add { + mandatory "true"; + } + } + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:session-state" { + deviate add { + config "false"; + } + } + + /* + * Not supported nodes + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:identifier" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:distance" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:distance/bgp:external" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:distance/bgp:internal" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:confederation" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:confederation/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:confederation/bgp:identifier" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:confederation/bgp:member-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:use-multiple-paths" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:use-multiple-paths/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:use-multiple-paths/bgp:ebgp" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:use-multiple-paths/bgp:ebgp/bgp:allow-multiple-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:use-multiple-paths/bgp:ebgp/bgp:maximum-paths" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:use-multiple-paths/bgp:ibgp" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:use-multiple-paths/bgp:ibgp/bgp:maximum-paths" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:route-selection-options" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:route-selection-options/bgp:always-compare-med" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:route-selection-options/bgp:ignore-as-path-length" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:route-selection-options/bgp:external-compare-router-id" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:route-selection-options/bgp:advertise-inactive-routes" { + deviate not-supported; + } + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:route-selection-options/bgp:enable-aigp" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:route-selection-options/bgp:ignore-next-hop-igp-metric" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:route-selection-options/bgp:enable-med" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:route-selection-options/bgp:med-plus-igp" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:route-selection-options/bgp:med-plus-igp/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:route-selection-options/bgp:med-plus-igp/bgp:igp-multiplier" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:route-selection-options/bgp:med-plus-igp/bgp:med-multiplier" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:name" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:statistics" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:statistics/bgp:total-paths" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:statistics/bgp:total-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:route-selection-options" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:route-selection-options/bgp:always-compare-med" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:route-selection-options/bgp:ignore-as-path-length" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:route-selection-options/bgp:external-compare-router-id" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:route-selection-options/bgp:advertise-inactive-routes" { + deviate not-supported; + } + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:route-selection-options/bgp:enable-aigp" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:route-selection-options/bgp:ignore-next-hop-igp-metric" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:route-selection-options/bgp:enable-med" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:route-selection-options/bgp:med-plus-igp" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:route-selection-options/bgp:med-plus-igp/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:route-selection-options/bgp:med-plus-igp/bgp:igp-multiplier" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:route-selection-options/bgp:med-plus-igp/bgp:med-multiplier" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths/bgp:ebgp" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths/bgp:ebgp/bgp:allow-multiple-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths/bgp:ebgp/bgp:maximum-paths" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths/bgp:ibgp" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths/bgp:ibgp/bgp:maximum-paths" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy/bgp:import-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy/bgp:default-import-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy/bgp:export-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy/bgp:default-export-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:send-default-route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:send-default-route" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:apply-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:apply-policy/bgp:import-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:apply-policy/bgp:default-import-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:apply-policy/bgp:export-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:apply-policy/bgp:default-export-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:statistics" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:statistics/bgp:total-paths" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:global/bgp:statistics/bgp:total-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:remote-address" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:peer-group" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:local-address" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:local-port" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:remote-port" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:peer-type" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:identifier" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:dynamically-configured" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:local-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:remove-private-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:description" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:timers" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:timers/bgp:connect-retry-interval" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:timers/bgp:hold-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:timers/bgp:negotiated-hold-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:timers/bgp:keepalive" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:timers/bgp:min-as-origination-interval" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:timers/bgp:min-route-advertisement-interval" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:local-address" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:tcp-mss" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:mtu-discovery" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:ebgp-multihop" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:ebgp-multihop/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:ebgp-multihop/bgp:multihop-ttl" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:passive-mode" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:secure-session" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:secure-session/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:secure-session/bgp:options" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:secure-session/bgp:options/bgp:option" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:secure-session/bgp:options/bgp:option/bgp:ao" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:secure-session/bgp:options/bgp:option/bgp:ao/bgp:ao-keychain" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:secure-session/bgp:options/bgp:option/bgp:md5" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:secure-session/bgp:options/bgp:option/bgp:md5/bgp:md5-keychain" { + deviate not-supported; + } + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:secure-session/bgp:options/bgp:option/bgp:ipsec" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:transport/bgp:secure-session/bgp:options/bgp:option/bgp:ipsec/bgp:sa" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:treat-as-withdraw" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:logging-options" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:logging-options/bgp:log-neighbor-state-changes" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:route-reflector" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:route-reflector/bgp:cluster-id" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:route-reflector/bgp:client" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:as-path-options" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:as-path-options/bgp:allow-own-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:as-path-options/bgp:replace-peer-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:as-path-options/bgp:disable-peer-as-filter" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:use-multiple-paths" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:use-multiple-paths/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:use-multiple-paths/bgp:ebgp" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:use-multiple-paths/bgp:ebgp/bgp:allow-multiple-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:apply-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:apply-policy/bgp:import-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:apply-policy/bgp:default-import-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:apply-policy/bgp:export-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:apply-policy/bgp:default-export-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:name" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:active" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:prefixes/bgp:received" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:prefixes/bgp:sent" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:prefixes/bgp:installed" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy/bgp:import-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy/bgp:default-import-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy/bgp:export-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy/bgp:default-export-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:send-default-route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:send-default-route" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths/bgp:ebgp" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths/bgp:ebgp/bgp:allow-multiple-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:last-established" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:code" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:name" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:mpbgp" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:mpbgp/bgp:afi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:mpbgp/bgp:safi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:mpbgp/bgp:name" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:graceful-restart" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:graceful-restart/bgp:flags" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:graceful-restart/bgp:unknown-flags" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:graceful-restart/bgp:restart-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:graceful-restart/bgp:afi-safis" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:graceful-restart/bgp:afi-safis/bgp:afi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:graceful-restart/bgp:afi-safis/bgp:safi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:graceful-restart/bgp:afi-safis/bgp:afi-safi-flags" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:graceful-restart/bgp:afi-safis/bgp:afi-safi-unknown-flags" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:asn32" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:asn32/bgp:as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:add-paths" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:add-paths/bgp:afi-safis" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:add-paths/bgp:afi-safis/bgp:afi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:add-paths/bgp:afi-safis/bgp:safi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:advertised-capabilities/bgp:value/bgp:add-paths/bgp:afi-safis/bgp:mode" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:code" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:name" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:mpbgp" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:mpbgp/bgp:afi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:mpbgp/bgp:safi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:mpbgp/bgp:name" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:graceful-restart" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:graceful-restart/bgp:flags" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:graceful-restart/bgp:unknown-flags" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:graceful-restart/bgp:restart-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:graceful-restart/bgp:afi-safis" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:graceful-restart/bgp:afi-safis/bgp:afi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:graceful-restart/bgp:afi-safis/bgp:safi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:graceful-restart/bgp:afi-safis/bgp:afi-safi-flags" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:graceful-restart/bgp:afi-safis/bgp:afi-safi-unknown-flags" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:asn32" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:asn32/bgp:as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:add-paths" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:add-paths/bgp:afi-safis" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:add-paths/bgp:afi-safis/bgp:afi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:add-paths/bgp:afi-safis/bgp:safi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:received-capabilities/bgp:value/bgp:add-paths/bgp:afi-safis/bgp:mode" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:capabilities/bgp:negotiated-capabilities" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:received" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:received/bgp:last-notification" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:received/bgp:last-error" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:received/bgp:last-error-code" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:received/bgp:last-error-subcode" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:received/bgp:last-encapsulated-error" { + deviate not-supported; + } + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:received/bgp:last-encapsulated-error-code" { + deviate not-supported; + } + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:received/bgp:last-encapsulated-error-subcode" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:received/bgp:last-error-data" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:sent" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:sent/bgp:last-notification" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:sent/bgp:last-error" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:sent/bgp:last-error-code" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:sent/bgp:last-error-subcode" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:sent/bgp:last-encapsulated-error" { + deviate not-supported; + } + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:sent/bgp:last-encapsulated-error-code" { + deviate not-supported; + } + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:sent/bgp:last-encapsulated-error-subcode" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:errors/bgp:sent/bgp:last-error-data" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:established-transitions" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:messages" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:messages/bgp:total-received" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:messages/bgp:total-sent" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:messages/bgp:updates-received" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:messages/bgp:updates-sent" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:messages/bgp:erroneous-updates-withdrawn" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:messages/bgp:erroneous-updates-attribute-discarded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:messages/bgp:in-update-elapsed-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:messages/bgp:notifications-received" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:messages/bgp:notifications-sent" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:messages/bgp:route-refreshes-received" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:messages/bgp:route-refreshes-sent" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:queues" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:queues/bgp:input" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:statistics/bgp:queues/bgp:output" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:name" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:peer-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:local-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:remove-private-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:description" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:timers" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:timers/bgp:connect-retry-interval" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:timers/bgp:hold-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:timers/bgp:negotiated-hold-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:timers/bgp:keepalive" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:timers/bgp:min-as-origination-interval" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:timers/bgp:min-route-advertisement-interval" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:local-address" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:tcp-mss" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:mtu-discovery" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:ebgp-multihop" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:ebgp-multihop/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:ebgp-multihop/bgp:multihop-ttl" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:passive-mode" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:secure-session" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:secure-session/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:secure-session/bgp:options" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:secure-session/bgp:options/bgp:option" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:secure-session/bgp:options/bgp:option/bgp:ao" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:secure-session/bgp:options/bgp:option/bgp:ao/bgp:ao-keychain" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:secure-session/bgp:options/bgp:option/bgp:md5" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:secure-session/bgp:options/bgp:option/bgp:md5/bgp:md5-keychain" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:secure-session/bgp:options/bgp:option/bgp:ipsec" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:transport/bgp:secure-session/bgp:options/bgp:option/bgp:ipsec/bgp:sa" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:treat-as-withdraw" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:logging-options" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:logging-options/bgp:log-neighbor-state-changes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:route-reflector" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:route-reflector/bgp:cluster-id" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:route-reflector/bgp:client" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:as-path-options" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:as-path-options/bgp:allow-own-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:as-path-options/bgp:replace-peer-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:as-path-options/bgp:disable-peer-as-filter" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:use-multiple-paths" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:use-multiple-paths/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:use-multiple-paths/bgp:ebgp" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:use-multiple-paths/bgp:ebgp/bgp:allow-multiple-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:apply-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:apply-policy/bgp:import-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:apply-policy/bgp:default-import-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:apply-policy/bgp:export-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:apply-policy/bgp:default-export-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:dynamic-peers" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:dynamic-peers/bgp:dynamic-peer-list" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:dynamic-peers/bgp:dynamic-peer-list/bgp:prefix" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:name" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths/bgp:enabled" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths/bgp:ebgp" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:use-multiple-paths/bgp:ebgp/bgp:allow-multiple-as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy/bgp:import-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy/bgp:default-import-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy/bgp:export-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:apply-policy/bgp:default-export-policy" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:send-default-route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:send-default-route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-labeled-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-labeled-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-unicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv4-multicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l3vpn-ipv6-multicast/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-vpls/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:max-prefixes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:warning-threshold-pct" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:teardown" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:idle-time" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:peer-groups/bgp:peer-group/bgp:afi-safis/bgp:afi-safi/bgp:l2vpn-evpn/bgp:prefix-limit/bgp:prefix-limit-exceeded" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:origin" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:as-path" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:as-path/bgp:segment" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:as-path/bgp:segment/bgp:type" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:as-path/bgp:segment/bgp:member" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:next-hop" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:link-local-next-hop" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:med" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:local-pref" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:as4-path" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:as4-path/bgp:segment" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:as4-path/bgp:segment/bgp:type" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:as4-path/bgp:segment/bgp:member" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:aggregator" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:aggregator/bgp:as" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:aggregator/bgp:identifier" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:aggregator4" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:aggregator4/bgp:as4" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:aggregator4/bgp:identifier" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:atomic-aggregate" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:originator-id" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:cluster-list" { + deviate not-supported; + } + */ + + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:attr-sets/bgp:attr-set/bgp:attributes/bgp:aigp-metric" { + deviate not-supported; + } + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:communities" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:communities/bgp:community" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:communities/bgp:community/bgp:index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:communities/bgp:community/bgp:community" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:ext-communities" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:ext-communities/bgp:ext-community" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:ext-communities/bgp:ext-community/bgp:index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:ext-communities/bgp:ext-community/bgp:ext-community" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:ext-communities/bgp:ext-community/bgp:ext-community-raw" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:ipv6-ext-communities" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:ipv6-ext-communities/bgp:ipv6-ext-community" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:ipv6-ext-communities/bgp:ipv6-ext-community/bgp:index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:ipv6-ext-communities/bgp:ipv6-ext-community/bgp:ipv6-ext-community" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:ipv6-ext-communities/bgp:ipv6-ext-community/bgp:ipv6-ext-community-raw" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:large-communities" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:large-communities/bgp:large-community" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:large-communities/bgp:large-community/bgp:index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:large-communities/bgp:large-community/bgp:large-community" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:name" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:prefix" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:origin" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:path-id" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:attr-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:ext-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:large-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:last-modified" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:eligible-route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:ineligible-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-type" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:optional" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:transitive" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:partial" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:extended" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-len" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-value" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:reject-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:neighbor-address" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:prefix" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:path-id" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:attr-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:ext-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:large-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:last-modified" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:eligible-route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:ineligible-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-type" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:optional" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:transitive" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:partial" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:extended" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-len" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-value" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:reject-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:prefix" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:path-id" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:attr-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:ext-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:large-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:last-modified" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:eligible-route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:ineligible-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:best-path" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-type" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:optional" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:transitive" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:partial" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:extended" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-len" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-value" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:reject-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:prefix" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:path-id" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:attr-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:ext-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:large-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:last-modified" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:eligible-route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:ineligible-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-type" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:optional" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:transitive" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:partial" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:extended" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-len" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-value" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:reject-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:prefix" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:path-id" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:attr-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:ext-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:large-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:last-modified" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:eligible-route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:ineligible-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-type" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:optional" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:transitive" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:partial" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:extended" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-len" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-value" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv4-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:reject-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:prefix" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:origin" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:path-id" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:attr-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:ext-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:large-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:last-modified" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:eligible-route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:ineligible-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-type" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:optional" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:transitive" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:partial" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:extended" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-len" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-value" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:loc-rib/bgp:routes/bgp:route/bgp:reject-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:neighbor-address" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:prefix" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:path-id" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:attr-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:ext-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:large-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:last-modified" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:eligible-route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:ineligible-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-type" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:optional" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:transitive" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:partial" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:extended" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-len" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-value" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-pre/bgp:routes/bgp:route/bgp:reject-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:prefix" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:path-id" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:attr-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:ext-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:large-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:last-modified" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:eligible-route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:ineligible-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:best-path" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-type" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:optional" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:transitive" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:partial" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:extended" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-len" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-value" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-in-post/bgp:routes/bgp:route/bgp:reject-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:prefix" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:path-id" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:attr-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:ext-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:large-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:last-modified" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:eligible-route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:ineligible-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-type" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:optional" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:transitive" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:partial" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:extended" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-len" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-value" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-pre/bgp:routes/bgp:route/bgp:reject-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:prefix" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:path-id" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:attr-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:ext-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:large-community-index" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:last-modified" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:eligible-route" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:ineligible-reason" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-type" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:optional" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:transitive" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:partial" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:extended" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-len" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:unknown-attributes/bgp:unknown-attribute/bgp:attr-value" { + deviate not-supported; + } + */ + + /* + deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/bgp:bgp/bgp:rib/bgp:afi-safis/bgp:afi-safi/bgp:ipv6-unicast/bgp:neighbors/bgp:neighbor/bgp:adj-rib-out-post/bgp:routes/bgp:route/bgp:reject-reason" { + deviate not-supported; + } + */ +} diff --git a/holo-yang/src/lib.rs b/holo-yang/src/lib.rs index 160013c4..c1d99cc4 100644 --- a/holo-yang/src/lib.rs +++ b/holo-yang/src/lib.rs @@ -114,11 +114,15 @@ pub static YANG_EMBEDDED_MODULES: Lazy = Lazy::new(|| { EmbeddedModuleKey::new("ietf-tcp-common", Some("2023-04-17"), None, None) => include_str!("../modules/ietf/ietf-tcp-common@2023-04-17.yang"), // IETF Holo augmentations + EmbeddedModuleKey::new("holo-bgp", None, None, None) => + include_str!("../modules/augmentations/holo-bgp.yang"), EmbeddedModuleKey::new("holo-ospf", None, None, None) => include_str!("../modules/augmentations/holo-ospf.yang"), EmbeddedModuleKey::new("holo-ospf-dev", None, None, None) => include_str!("../modules/augmentations/holo-ospf-dev.yang"), // IETF Holo deviations + EmbeddedModuleKey::new("ietf-bgp-holo-deviations", None, None, None) => + include_str!("../modules/deviations/ietf-bgp-holo-deviations.yang"), EmbeddedModuleKey::new("ietf-mpls-ldp-holo-deviations", None, None, None) => include_str!("../modules/deviations/ietf-mpls-ldp-holo-deviations.yang"), EmbeddedModuleKey::new("ietf-interfaces-holo-deviations", None, None, None) => @@ -156,10 +160,14 @@ pub static YANG_IMPLEMENTED_MODULES: Lazy> = Lazy::new(|| { vec![ "iana-if-type", + "iana-bgp-notification", + "iana-bgp-types", "ietf-bfd-ip-mh", "ietf-bfd-ip-sh", "ietf-bfd-types", "ietf-bfd", + "ietf-bgp", + "ietf-bgp-policy", "ietf-routing-types", "ietf-interfaces", "ietf-ip", @@ -177,6 +185,8 @@ pub static YANG_IMPLEMENTED_MODULES: Lazy> = "ietf-ospf-sr", "ietf-ospfv3-extended-lsa", "ietf-rip", + "ietf-tcp", + "holo-bgp", "holo-ospf", "holo-ospf-dev", ] @@ -186,6 +196,10 @@ pub static YANG_IMPLEMENTED_MODULES: Lazy> = pub static YANG_FEATURES: Lazy>> = Lazy::new(|| { hashmap! { + "iana-bgp-types" => vec![ + "route-refresh", + "ttl-security", + ], "ietf-bfd-types" => vec![ "client-base-cfg-parms", "single-minimum-interval",